/** * desktop/src/server-config.ts — build the env overrides fed to the backend's * loadConfig() for the embedded server. * * Starts from a COPY of the ambient env (never mutates it) and pins the four * values the desktop shell controls: PORT (the free port we already resolved), * BIND_HOST (private 127.0.0.1 by default; 0.0.0.0 only when LAN sharing is on), * SHELL_PATH (platform-aware default so Windows gets PowerShell), and USE_TMUX * (forced off on Windows — tmux is a *nix keepalive; elsewhere respect the * ambient env, defaulting to auto-detect). Every other ambient var passes through * untouched. */ import type { DesktopPrefs } from './types.js' import { defaultShellForPlatform } from './shell.js' /** Loopback bind host — private mode; the window connects here and always passes Origin checks. */ const PRIVATE_BIND_HOST = '127.0.0.1' /** Wildcard bind host — LAN sharing (phones/tablets reconnect); opt-in, no auth. */ const LAN_BIND_HOST = '0.0.0.0' /** tmux is a *nix keepalive, so Windows forces it off outright. */ const TMUX_OFF = '0' /** * Everywhere else the desktop shell auto-detects (loadConfig's 'auto' → is the tmux * binary present?), which is what the standalone server already did. * * It used to default OFF, and that quietly broke the app's whole premise. Without * tmux the shell is a direct child of the embedded server, so quitting the app — * including the tray "Quit", including a logout — kills every session with it. The * point of this app is to hand Claude Code a task, walk away, and reconnect from * another device; a session that cannot survive the window closing does not do that. * With tmux the node-pty process is only a tmux CLIENT, so shutdown detaches and the * shell keeps running (see SessionManager.shutdown). * * An explicit ambient USE_TMUX still wins, so USE_TMUX=0 remains the way to opt out. */ const TMUX_AUTO = 'auto' export interface ServerEnvInput { readonly prefs: DesktopPrefs readonly port: number readonly platform: NodeJS.Platform readonly env: NodeJS.ProcessEnv } /** * Produce the env-override object for loadConfig(). Immutable: input.env is * spread into a NEW object and is never mutated. */ export function buildServerEnv(input: ServerEnvInput): Record { const { prefs, port, platform, env } = input return { ...env, PORT: String(port), BIND_HOST: prefs.lanSharing ? LAN_BIND_HOST : PRIVATE_BIND_HOST, SHELL_PATH: prefs.shellPath ?? defaultShellForPlatform(platform, env), USE_TMUX: platform === 'win32' ? TMUX_OFF : (env.USE_TMUX ?? TMUX_AUTO), } }