/** * Remote-agent config — ONE per Nebula installation. * * How to reach the user's machine describes the INSTALLATION, not a browser: * which loopback port here their sshd is reverse-forwarded to, their username * on that machine, its sshd port, an optional jump host. It used to live only * in browser localStorage, where two failures followed: * - a fresh browser minted a NEW random port and silently orphaned the * tunnel the user had already built (lab report: "tunnel not detected"); * - a fresh browser re-prompted the whole setup dialog for a tunnel that * was up and working — and "fresh" includes merely a second ORIGIN, since * localhost:3000 and localhost:8867 have separate localStorage. * The server owns it now; browsers mirror it (same pattern as bindings). */ export interface RemoteAgentConfig { /** Reverse-channel port on THIS host (the -R target). */ port?: number; /** Username on the user's machine, for the ssh hop back. */ user?: string; /** sshd port on the user's machine (macOS policy often forces 2222). */ localSshPort?: number; /** Optional ProxyJump host shown in the tunnel command. */ jumpHost?: string; /** Nebula URL as seen FROM the user's machine (their -L forward). */ localUrl?: string; } /** Field-level patch; null means "erase this field". */ export type RemoteAgentConfigPatch = { [K in keyof RemoteAgentConfig]?: RemoteAgentConfig[K] | null; }; export declare class RemoteAgentConfigStore { private file; private config; private loaded; constructor(file?: string); private ensureLoaded; private persist; get(): RemoteAgentConfig; /** * The installation port, generating one on first use. A valid `claim` is * adopted ONLY when none is stored — the first browser to sync keeps the * port its user already built a tunnel for; later browsers converge. */ ensurePort(claim?: number): number; /** * Adopt a browser's local values for whatever this installation does NOT * know yet, and return the effective config. Stored truth always wins, so * one browser's stale copy can never overwrite a working setup. */ claim(claimed: RemoteAgentConfig): RemoteAgentConfig; /** * Explicit override (setup dialog). Merges: omitted fields keep their * stored value, `null` erases, invalid values are ignored rather than * stored — a typo must not break a working installation. */ patch(fields: RemoteAgentConfigPatch): RemoteAgentConfig; } export declare const remoteAgentConfig: RemoteAgentConfigStore;