@particle-academy/fancy-term-host 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-2DQJKTG5.js → chunk-WMP4YLM5.js} +27 -7
- package/dist/chunk-WMP4YLM5.js.map +1 -0
- package/dist/index.cjs +34 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/pty-host.cjs +22 -1
- package/dist/pty-host.cjs.map +1 -1
- package/dist/pty-host.js +5 -2
- package/dist/pty-host.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-2DQJKTG5.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/osc7.ts","../src/shells.ts","../src/manager.ts","../src/sessions.ts","../src/host-protocol.ts","../src/host-client.ts","../src/host-locate.ts","../src/host-lifecycle.ts","../src/host-script.ts"],"names":["fs","path","os","crypto","EventEmitter","deps","spawn","zlib","SCROLLBACK_MAX","client","net","fileURLToPath"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * OSC-7 cwd reporting (Tier 1.5).\n *\n * A shell that emits OSC-7 tells the terminal its current working directory on\n * every prompt:\n *\n * ESC ] 7 ; file://HOST/PATH (BEL | ESC \\)\n *\n * We scan raw pty output for these and parse out an absolute filesystem path so\n * a fresh shell spawned on resume can start where the old one left off. The\n * sequence is terminated by either BEL (\\x07) or ST (ESC \\, i.e. \\x1b\\x5c).\n *\n * Path forms handled:\n * file:///home/user/proj → /home/user/proj\n * file://hostname/home/user/proj → /home/user/proj (host ignored)\n * file:///C:/Users/me/proj → C:\\Users\\me\\proj (Windows drive)\n * percent-encoded segments (%20) → decoded\n */\n\nconst OSC7_RE = /\\x1b\\]7;([^\\x07\\x1b]*)(?:\\x07|\\x1b\\\\)/g;\n\n/**\n * Parse a `file://...` URL from an OSC-7 payload into a local filesystem path.\n * Returns null when the payload isn't a usable file URL.\n */\nexport function parseFileUrl(payload: string): string | null {\n if (!payload.startsWith('file://')) return null;\n let rest = payload.slice('file://'.length);\n\n // Strip the authority (host) up to the first '/'. `file:///path` has an\n // empty authority; `file://host/path` carries one we don't need.\n const slash = rest.indexOf('/');\n if (slash === -1) return null;\n let pathPart = rest.slice(slash); // includes the leading '/'\n\n let decoded: string;\n try {\n decoded = decodeURIComponent(pathPart);\n } catch {\n decoded = pathPart; // malformed %-escape — use as-is rather than drop\n }\n\n // Windows drive paths arrive as \"/C:/Users/...\". Drop the leading slash and\n // flip to backslashes so the value matches what node-pty/Electron expect as\n // a cwd on Windows.\n const winDrive = /^\\/([A-Za-z]):(.*)$/.exec(decoded);\n if (winDrive) {\n return `${winDrive[1]}:${winDrive[2]}`.replace(/\\//g, '\\\\');\n }\n\n return decoded;\n}\n\n/**\n * Scan a chunk of pty output and return the LAST cwd reported via OSC-7, or\n * null when the chunk contains no (parseable) OSC-7 sequence. We take the last\n * one because a single chunk can carry several prompts; the most recent wins.\n */\nexport function scanOsc7Cwd(chunk: string): string | null {\n if (chunk.indexOf('\\x1b]7;') === -1) return null; // fast bail\n let last: string | null = null;\n OSC7_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = OSC7_RE.exec(chunk))) {\n const cwd = parseFileUrl(m[1]);\n if (cwd) last = cwd;\n }\n return last;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport crypto from 'node:crypto';\nimport type { SettingsProvider } from './ports';\n\n/**\n * Shell detection + default-shell resolution for the terminal subsystem.\n *\n * Mirrors main/editors.ts: probe well-known install paths, return what's\n * actually present. Ids line up with fancy-term's BUILTIN_SHELLS so the\n * renderer can map detections straight onto ShellProfile entries\n * (cmd · powershell · pwsh · git-bash · bash · zsh · wsl).\n *\n * Default policy (Windows): Git Bash when detected — it's the shell the\n * Tynn toolchain assumes — then pwsh, then Windows PowerShell, then cmd.\n * On macOS/Linux the user's $SHELL wins, falling back to bash.\n */\n\nexport interface ShellInfo {\n /** Stable id, matches fancy-term BUILTIN_SHELLS where possible. */\n id: string;\n /** Display label, e.g. \"Git Bash\". */\n label: string;\n /** Absolute executable path (or bare command when resolved via PATH). */\n command: string;\n /** Default args for an interactive session. */\n args: string[];\n}\n\nfunction firstExisting(paths: string[]): string | null {\n for (const p of paths) {\n try {\n if (p && fs.existsSync(p)) return p;\n } catch {\n /* permission race — treat as absent */\n }\n }\n return null;\n}\n\nfunction windowsCandidates(): Array<Omit<ShellInfo, 'command'> & { paths: string[] }> {\n const programFiles = process.env.ProgramFiles ?? 'C:\\\\Program Files';\n const programFilesX86 =\n process.env['ProgramFiles(x86)'] ?? 'C:\\\\Program Files (x86)';\n const localAppData = process.env.LOCALAPPDATA ?? '';\n const systemRoot = process.env.SystemRoot ?? 'C:\\\\Windows';\n\n return [\n {\n id: 'git-bash',\n label: 'Git Bash',\n args: ['--login', '-i'],\n paths: [\n path.join(programFiles, 'Git', 'bin', 'bash.exe'),\n path.join(programFilesX86, 'Git', 'bin', 'bash.exe'),\n localAppData\n ? path.join(localAppData, 'Programs', 'Git', 'bin', 'bash.exe')\n : '',\n ],\n },\n {\n id: 'pwsh',\n label: 'PowerShell 7',\n args: ['-NoLogo'],\n paths: [\n path.join(programFiles, 'PowerShell', '7', 'pwsh.exe'),\n localAppData\n ? path.join(localAppData, 'Microsoft', 'WindowsApps', 'pwsh.exe')\n : '',\n ],\n },\n {\n id: 'powershell',\n label: 'Windows PowerShell',\n args: ['-NoLogo'],\n paths: [\n path.join(\n systemRoot,\n 'System32',\n 'WindowsPowerShell',\n 'v1.0',\n 'powershell.exe',\n ),\n ],\n },\n {\n id: 'cmd',\n label: 'Command Prompt',\n args: [],\n paths: [process.env.COMSPEC ?? path.join(systemRoot, 'System32', 'cmd.exe')],\n },\n {\n id: 'wsl',\n label: 'WSL',\n args: [],\n paths: [path.join(systemRoot, 'System32', 'wsl.exe')],\n },\n ];\n}\n\nfunction unixCandidates(): Array<Omit<ShellInfo, 'command'> & { paths: string[] }> {\n return [\n {\n id: 'zsh',\n label: 'zsh',\n args: ['-l'],\n paths: ['/bin/zsh', '/usr/bin/zsh', '/usr/local/bin/zsh', '/opt/homebrew/bin/zsh'],\n },\n {\n id: 'bash',\n label: 'bash',\n args: ['-l'],\n paths: ['/bin/bash', '/usr/bin/bash', '/usr/local/bin/bash'],\n },\n {\n id: 'fish',\n label: 'fish',\n args: ['-l'],\n paths: ['/usr/bin/fish', '/usr/local/bin/fish', '/opt/homebrew/bin/fish'],\n },\n ];\n}\n\nexport function detectShells(): ShellInfo[] {\n const candidates =\n process.platform === 'win32' ? windowsCandidates() : unixCandidates();\n const found: ShellInfo[] = [];\n for (const c of candidates) {\n const command = firstExisting(c.paths);\n if (command) found.push({ id: c.id, label: c.label, command, args: c.args });\n }\n\n // Unix: surface the user's login shell even if it isn't in the probe\n // list (e.g. a Homebrew bash that lives somewhere exotic).\n if (process.platform !== 'win32') {\n const login = process.env.SHELL;\n if (login && !found.some((s) => s.command === login) && fs.existsSync(login)) {\n found.unshift({\n id: path.basename(login),\n label: path.basename(login),\n command: login,\n args: ['-l'],\n });\n }\n }\n return found;\n}\n\n/** Default policy: Git Bash > pwsh > powershell > cmd (win); $SHELL > bash (unix). */\nexport function defaultShellId(detected: ShellInfo[]): string | null {\n const order =\n process.platform === 'win32'\n ? ['git-bash', 'pwsh', 'powershell', 'cmd']\n : detected.map((s) => s.id); // unix list is already priority-ordered\n for (const id of order) {\n if (detected.some((s) => s.id === id)) return id;\n }\n return detected[0]?.id ?? null;\n}\n\n/**\n * Split a manual \"executable line\" into command + args. Honors double\n * quotes around the executable path (\"C:\\Program Files\\Git\\bin\\bash.exe\"\n * --login -i). Single-token lines pass through untouched.\n */\nexport function parseCommandLine(line: string): { command: string; args: string[] } {\n const trimmed = line.trim();\n if (!trimmed) return { command: '', args: [] };\n const tokens: string[] = [];\n const re = /\"([^\"]*)\"|(\\S+)/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(trimmed))) tokens.push(m[1] ?? m[2]);\n return { command: tokens[0] ?? '', args: tokens.slice(1) };\n}\n\n/** Coarse shell family, derived from the executable name, used to decide which\n * OSC-7 prompt hook (if any) we can inject. */\nexport type ShellKind = 'powershell' | 'bash' | 'zsh' | 'fish' | 'cmd' | 'other';\n\nexport function shellKind(command: string): ShellKind {\n const base = path.basename(command).toLowerCase();\n if (base.includes('pwsh') || base.includes('powershell')) return 'powershell';\n if (base.startsWith('zsh')) return 'zsh';\n if (base.startsWith('bash')) return 'bash';\n if (base.startsWith('fish')) return 'fish';\n if (base.startsWith('cmd')) return 'cmd';\n return 'other';\n}\n\n/** The spawn additions (env + extra args) a shell needs to emit OSC-7 cwd. */\nexport interface CwdHook {\n /** Extra env entries to merge into the pty's environment. */\n env: Record<string, string>;\n /** Extra args to APPEND to the shell's launch args (PowerShell needs these). */\n args: string[];\n}\n\n/** Short, stable per-user dir under the OS temp root that holds generated\n * prompt shims (zsh rc, fish conf, PowerShell profile). Per-user so two users\n * on a shared box don't read each other's shims. Created lazily. */\nfunction hookDir(): string {\n const seed = `${os.userInfo().username}|${os.hostname()}`;\n const hash = crypto.createHash('sha1').update(seed).digest('hex').slice(0, 12);\n const dir = path.join(os.tmpdir(), 'fancy-term-host', hash);\n fs.mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/** Best-effort write; a failed shim just means the shell degrades to static cwd. */\nfunction writeShim(file: string, contents: string): boolean {\n try {\n fs.writeFileSync(file, contents, 'utf8');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Build the spawn additions (env + args) that make a shell emit OSC-7 cwd\n * reports on every prompt, so resumed terminals know where they were\n * (Tier 1.5). Gated by the `track_cwd` setting (default ON). Returns an empty\n * hook when tracking is off or the shell genuinely can't be hooked — the\n * manager then degrades to the static cwd.\n *\n * Coverage (all overlay, never clobber the user's own prompt/rc):\n * - **bash** — prepend an OSC-7 `printf` to `PROMPT_COMMAND` (env only). The\n * portable, reliable case (Git Bash on Windows, bash on POSIX).\n * - **zsh** — point `ZDOTDIR` at a generated dir whose `.zshrc` sources the\n * user's real `.zshrc`, restores `ZDOTDIR`, then registers a `precmd`\n * emitter; `.zshenv` sources the user's real `.zshenv` first.\n * - **fish** — prepend a generated dir to `XDG_DATA_DIRS` carrying a\n * `fish/vendor_conf.d/osc7.fish` that hooks `--on-event fish_prompt`\n * (vendor conf overlays the user's config rather than replacing it).\n * - **PowerShell (pwsh/powershell)** — write a profile shim that wraps any\n * existing `prompt` and emits OSC-7, dot-sourced via appended\n * `-NoExit -Command \". '<shim>'\"` args (PS has no env-var prompt hook).\n * - **cmd.exe (best-effort)** — set `PROMPT` to emit OSC-7 via the `$E`\n * escape before the normal `$P$G`. Renders only where the console honors\n * VT sequences in the prompt; otherwise degrades to static cwd.\n *\n * The emitted payload is always `file:///<path>` (empty authority, forward\n * slashes / Windows drive) so it round-trips through {@link scanOsc7Cwd}.\n */\nexport function cwdHookSpawn(command: string, settings: SettingsProvider): CwdHook {\n const empty: CwdHook = { env: {}, args: [] };\n if (settings.get('track_cwd') === 'off') return empty;\n\n const kind = shellKind(command);\n const host = os.hostname();\n\n if (kind === 'bash') {\n // Emit from PROMPT_COMMAND; $PWD is absolute → file:///$PWD. PREPEND so\n // any existing PROMPT_COMMAND still runs. Single-quoted → expands at\n // prompt time, not now.\n const emit = `printf '\\\\033]7;file://${host}%s\\\\033\\\\\\\\' \"$PWD\"`;\n const prev = process.env.PROMPT_COMMAND ? '; ' + process.env.PROMPT_COMMAND : '';\n return { env: { PROMPT_COMMAND: `${emit}${prev}` }, args: [] };\n }\n\n if (kind === 'zsh') {\n const orig = process.env.ZDOTDIR || os.homedir();\n const dir = hookDir();\n // .zshenv runs for every invocation and is read from ZDOTDIR — source\n // the user's first so their environment survives.\n const okEnv = writeShim(\n path.join(dir, '.zshenv'),\n `# fancy-term-host (generated)\\n[ -f \"${orig}/.zshenv\" ] && source \"${orig}/.zshenv\"\\n`,\n );\n // .zshrc: restore ZDOTDIR for the user's environment, source their rc,\n // then register the OSC-7 precmd (appended → their prompt survives).\n const okRc = writeShim(\n path.join(dir, '.zshrc'),\n `# fancy-term-host (generated)\\n` +\n `ZDOTDIR=\"${orig}\"\\n` +\n `[ -f \"${orig}/.zshrc\" ] && source \"${orig}/.zshrc\"\\n` +\n `__fth_osc7() { printf '\\\\033]7;file://%s\\\\033\\\\\\\\' \"$PWD\" }\\n` +\n `typeset -ga precmd_functions\\n` +\n `precmd_functions+=(__fth_osc7)\\n`,\n );\n return okEnv && okRc ? { env: { ZDOTDIR: dir }, args: [] } : empty;\n }\n\n if (kind === 'fish') {\n const dir = hookDir();\n const confDir = path.join(dir, 'fish', 'vendor_conf.d');\n try {\n fs.mkdirSync(confDir, { recursive: true });\n } catch {\n return empty;\n }\n const ok = writeShim(\n path.join(confDir, 'osc7.fish'),\n `# fancy-term-host (generated)\\n` +\n `function __fth_osc7 --on-event fish_prompt\\n` +\n ` printf '\\\\x1b]7;file://%s\\\\x1b\\\\\\\\' \"$PWD\"\\n` +\n `end\\n`,\n );\n if (!ok) return empty;\n const existing = process.env.XDG_DATA_DIRS || '/usr/local/share:/usr/share';\n return { env: { XDG_DATA_DIRS: `${dir}${path.delimiter}${existing}` }, args: [] };\n }\n\n if (kind === 'powershell') {\n const dir = hookDir();\n const shim = path.join(dir, 'osc7-profile.ps1');\n // Wrap any existing prompt; emit file:///<forward-slashed path>. Use the\n // filesystem ProviderPath so non-filesystem locations don't poison it.\n const ok = writeShim(\n shim,\n `# fancy-term-host (generated)\\n` +\n `$global:__fthPrev = $function:prompt\\n` +\n `function global:prompt {\\n` +\n ` $p = ($PWD.ProviderPath -replace '\\\\\\\\','/')\\n` +\n ` [Console]::Write(\"$([char]27)]7;file:///$p$([char]27)\\\\\")\\n` +\n ` if ($global:__fthPrev) { & $global:__fthPrev } else { \"PS $($PWD.ProviderPath)> \" }\\n` +\n `}\\n`,\n );\n if (!ok) return empty;\n return { env: {}, args: ['-NoExit', '-Command', `. '${shim}'`] };\n }\n\n if (kind === 'cmd') {\n // Best-effort: $E = ESC in cmd's PROMPT. Emit OSC-7 (file:///$P, the\n // current path) then ST, then the normal $P$G. Only honored where the\n // console interprets VT sequences in the prompt.\n return { env: { PROMPT: `$E]7;file:///$P$E\\\\$P$G` }, args: [] };\n }\n\n return empty;\n}\n\n/**\n * Back-compat env-only view of {@link cwdHookSpawn} — returns just the env\n * additions. Shells that also need launch args (PowerShell) are only fully\n * hooked via `cwdHookSpawn`; callers using this alone get the env half.\n */\nexport function cwdHookEnv(\n command: string,\n settings: SettingsProvider,\n): Record<string, string> {\n return cwdHookSpawn(command, settings).env;\n}\n\n/**\n * Resolve the user's configured default shell to a concrete spawn target.\n * Reads the `terminal_shell` setting (a detected id, or 'custom' paired\n * with `terminal_custom_cmd`). Anything unresolvable falls back to the\n * detection-based default so the terminal always opens SOMETHING.\n */\nexport function resolveDefaultShell(settings: SettingsProvider): {\n command: string;\n args: string[];\n} {\n const detected = detectShells();\n const terminalShell = settings.get('terminal_shell');\n\n if (terminalShell === 'custom') {\n const parsed = parseCommandLine(settings.get('terminal_custom_cmd') ?? '');\n if (parsed.command) return parsed;\n }\n\n const pick =\n detected.find((s) => s.id === terminalShell) ??\n detected.find((s) => s.id === defaultShellId(detected));\n if (pick) return { command: pick.command, args: pick.args };\n\n // Nothing detected (bare container?) — legacy platform fallbacks.\n if (process.platform === 'win32') {\n return { command: process.env.COMSPEC ?? 'cmd.exe', args: [] };\n }\n return { command: process.env.SHELL ?? '/bin/bash', args: [] };\n}\n","import { spawn, IPty } from 'node-pty';\nimport { EventEmitter } from 'node:events';\nimport { scanOsc7Cwd } from './osc7';\nimport { cwdHookSpawn } from './shells';\nimport type { PtyBackend } from './backend';\nimport type { CreateTerminalOpts, TerminalInfo, AttachResult } from './types';\nimport type { SettingsProvider } from './ports';\nimport type { SnapshotStore } from './sessions';\n\nexport type { CreateTerminalOpts, TerminalInfo, AttachResult } from './types';\n\n/**\n * Centralised PTY manager. Owns every spawned pty, routes I/O to/from\n * the renderer via the events on this emitter, and cleans up on close.\n *\n * Why an emitter, not direct IPC: the manager doesn't know which\n * BrowserWindow is hosting a terminal — that's the IPC layer's job. The\n * manager just emits `data:<id>` and `exit:<id>` and lets ipc.ts wire\n * them to the right webContents.\n *\n * RUNTIME-AGNOSTIC: this module imports neither `electron` nor `../db`. The\n * settings (for the OSC-7 cwd hook) + snapshot store (for cold-spawn restore)\n * are injected via BackendDeps, and the live cwd learned from OSC-7 is EMITTED\n * as a `'cwd'` event rather than written to the DB directly. Genie's adapter\n * subscribes to `'cwd'` → `updateTerminalSpec({ live_cwd })`.\n */\n\n/** ~1 MB per pty. Enough for an hour of typical dev output without runaway memory. */\nconst SCROLLBACK_MAX = 1_000_000;\n\n/** Debounce window for emitting an OSC-7 cwd change (the adapter persists it). */\nconst CWD_PERSIST_DEBOUNCE_MS = 750;\n\n/**\n * Dependencies the in-process backend needs that used to be direct `../db` /\n * `electron` reaches: a SettingsProvider (cwd-hook gating) and a SnapshotStore\n * (cold-spawn restore). Injected by the composition root via\n * configureInProcessBackend; defaults are inert so a test/pre-config load is\n * harmless (no settings → cwd hook degrades to {}, no-op snapshot store → no\n * restore), preserving the historical \"db not ready → best-effort\" behaviour.\n */\nexport interface BackendDeps {\n settings: SettingsProvider;\n snapshots: SnapshotStore;\n}\n\nconst inertDeps: BackendDeps = {\n settings: { get: () => undefined },\n snapshots: {\n writeSnapshot: () => null,\n readSnapshot: () => null,\n deleteSnapshot: () => {},\n },\n};\n\n/**\n * InProcessBackend — node-pty instances owned directly by the Electron main\n * process. This is the historical TerminalManager body verbatim; it now also\n * formally implements the PtyBackend interface so the IPC layer can hold it\n * behind that abstraction interchangeably with the Tier 3 HostClient.\n *\n * EventEmitter gives us the `on('data'|'exit', …)` half of PtyBackend for free.\n */\nclass InProcessBackend extends EventEmitter implements PtyBackend {\n constructor(private deps: BackendDeps = inertDeps) {\n super();\n }\n\n /** Swap injected deps (only used if configure lands after lazy construction). */\n setDeps(deps: BackendDeps): void {\n this.deps = deps;\n }\n\n private readonly ptys = new Map<string, IPty>();\n private readonly scrollback = new Map<string, string>();\n private readonly shells = new Map<string, string>();\n /** Last cwd reported by each pty via OSC-7 (in-memory, authoritative). */\n private readonly liveCwd = new Map<string, string>();\n /** Pending debounced cwd-persist timers, keyed by terminal id. */\n private readonly cwdTimers = new Map<string, NodeJS.Timeout>();\n /**\n * Tier 2: ids that must keep their pty alive even with zero attached\n * windows (a disabled-but-retained terminal — e.g. a dev server the user\n * suspended). The IPC layer consults this in detachOwner: a retained id is\n * left running on the last detach instead of killed, so re-enable reattaches\n * to the LIVE session (scrollback replays) rather than spawning fresh.\n * Insertion order is preserved so the cap can evict the oldest if needed.\n */\n private readonly retained = new Set<string>();\n\n /**\n * Spawn a new pty for the given id, OR return the existing one if a\n * window has already attached. Idempotent: a Stage window can attach\n * to a spec that TheFloor is already running and get the same live\n * shell + a buffered scrollback to catch up.\n */\n create(opts: CreateTerminalOpts): AttachResult {\n const existing = this.ptys.get(opts.id);\n if (existing) {\n return {\n id: opts.id,\n pid: existing.pid,\n shell: this.shells.get(opts.id) ?? existing.process,\n existing: true,\n scrollback: this.scrollback.get(opts.id) ?? '',\n };\n }\n const shell = opts.shell ?? defaultShell();\n const baseArgs = opts.args ?? defaultShellArgs(shell);\n // Inject the OSC-7 prompt hook (gated by the track_cwd setting) so the\n // shell reports its cwd on every prompt. Returns an empty hook when\n // tracking is off or the shell can't be hooked — degrade silently. Some\n // shells (PowerShell) need APPENDED launch args, not just env, to load\n // their generated prompt shim.\n const hook = cwdHookSpawn(shell, this.deps.settings);\n const args = hook.args.length ? [...baseArgs, ...hook.args] : baseArgs;\n const env = {\n ...process.env,\n ...hook.env,\n ...(opts.env ?? {}),\n } as Record<string, string>;\n // Most TUI apps key off TERM to decide whether to emit ANSI / use the\n // alt screen. xterm.js handles xterm-256color cleanly; without this,\n // some apps degrade to dumb mode.\n env.TERM = env.TERM || 'xterm-256color';\n\n const pty = spawn(shell, args, {\n name: 'xterm-color',\n cwd: opts.cwd,\n cols: opts.cols ?? 80,\n rows: opts.rows ?? 24,\n env,\n });\n\n this.ptys.set(opts.id, pty);\n this.shells.set(opts.id, shell);\n this.scrollback.set(opts.id, '');\n\n pty.onData((data) => {\n const buf = this.scrollback.get(opts.id) ?? '';\n const next = buf + data;\n this.scrollback.set(\n opts.id,\n next.length > SCROLLBACK_MAX ? next.slice(-SCROLLBACK_MAX) : next,\n );\n // Tier 1.5: watch for OSC-7 cwd reports and persist the latest,\n // debounced. The in-memory map is authoritative; the spec row is a\n // durable mirror for the next launch.\n const cwd = scanOsc7Cwd(data);\n if (cwd && cwd !== this.liveCwd.get(opts.id)) {\n this.liveCwd.set(opts.id, cwd);\n this.scheduleCwdPersist(opts.id, cwd);\n }\n this.emit('data', opts.id, data);\n });\n pty.onExit(({ exitCode, signal }) => {\n this.cleanupCwd(opts.id);\n this.ptys.delete(opts.id);\n this.scrollback.delete(opts.id);\n this.shells.delete(opts.id);\n // A dead pty can't be retained — drop the flag so the cap frees up.\n this.retained.delete(opts.id);\n this.emit('exit', opts.id, { exitCode, signal });\n });\n\n // Cold spawn: surface any previous-session snapshot so the renderer can\n // replay history + divider + reset before this fresh shell takes over.\n const snap = this.deps.snapshots.readSnapshot(opts.id);\n\n return {\n id: opts.id,\n pid: pty.pid,\n shell,\n existing: false,\n scrollback: '',\n snapshot: snap ?? undefined,\n };\n }\n\n private scheduleCwdPersist(id: string, cwd: string): void {\n const existing = this.cwdTimers.get(id);\n if (existing) clearTimeout(existing);\n const t = setTimeout(() => {\n this.cwdTimers.delete(id);\n this.emit('cwd', id, cwd);\n }, CWD_PERSIST_DEBOUNCE_MS);\n // Don't let a pending cwd-write hold the process open at quit.\n if (typeof t.unref === 'function') t.unref();\n this.cwdTimers.set(id, t);\n }\n\n private cleanupCwd(id: string): void {\n const t = this.cwdTimers.get(id);\n if (t) {\n clearTimeout(t);\n this.cwdTimers.delete(id);\n }\n // Flush the last known cwd synchronously so a quit right after a `cd`\n // doesn't lose it. The adapter persists on the `cwd` event.\n const cwd = this.liveCwd.get(id);\n if (cwd) this.emit('cwd', id, cwd);\n this.liveCwd.delete(id);\n }\n\n /** Last cwd reported by this pty via OSC-7, or undefined when unknown. */\n getLiveCwd(id: string): string | undefined {\n return this.liveCwd.get(id);\n }\n\n write(id: string, data: string): boolean {\n const pty = this.ptys.get(id);\n if (!pty) return false;\n pty.write(data);\n return true;\n }\n\n resize(id: string, cols: number, rows: number): boolean {\n const pty = this.ptys.get(id);\n if (!pty) return false;\n // pty.resize throws when called with non-positive dims (and xterm-fit\n // can produce 0×0 transiently during layout). Clamp defensively.\n pty.resize(Math.max(1, cols | 0), Math.max(1, rows | 0));\n return true;\n }\n\n kill(id: string): boolean {\n const pty = this.ptys.get(id);\n if (!pty) return false;\n try {\n pty.kill();\n } catch {\n /* already exited */\n }\n this.cleanupCwd(id);\n this.ptys.delete(id);\n this.scrollback.delete(id);\n this.shells.delete(id);\n // An explicit kill (delete) also clears any retained flag.\n this.retained.delete(id);\n return true;\n }\n\n killAll(): void {\n for (const id of Array.from(this.ptys.keys())) {\n this.kill(id);\n }\n }\n\n list(): TerminalInfo[] {\n return Array.from(this.ptys.entries()).map(([id, pty]) => ({\n id,\n pid: pty.pid,\n shell: this.shells.get(id) ?? pty.process,\n }));\n }\n\n isLive(id: string): boolean {\n return this.ptys.has(id);\n }\n\n // --- Tier 2: retained-PTY (disabled-not-deleted) -----------------------\n\n /**\n * Mark/unmark a terminal as retained. A retained terminal's pty is kept\n * alive by the IPC layer even when its last window detaches. Returns the\n * resulting retained-id set size. Retaining a terminal that isn't live is\n * harmless (the flag simply has no pty to protect yet).\n */\n setRetained(id: string, retained: boolean): void {\n if (retained) this.retained.add(id);\n else this.retained.delete(id);\n }\n\n isRetained(id: string): boolean {\n return this.retained.has(id);\n }\n\n /** Number of currently-retained terminals (for the resource cap). */\n retainedCount(): number {\n return this.retained.size;\n }\n\n /** Snapshot of retained ids in insertion order (oldest first). */\n retainedIds(): string[] {\n return Array.from(this.retained);\n }\n\n /**\n * Buffered scrollback for a live pty (raw ANSI text), or undefined when the\n * id has no pty. Tier 2 uses this to serialize a windowless retained pty at\n * quit so its post-disable output still lands in a snapshot (T2→T1 degrade).\n */\n getScrollback(id: string): string | undefined {\n return this.scrollback.get(id);\n }\n}\n\n/** Back-compat alias. The class was renamed InProcessBackend in Tier 3; existing\n * imports of `TerminalManager` as a TYPE keep working. */\nexport type TerminalManager = InProcessBackend;\n\n/**\n * Injected dependencies for the in-process backend, set ONCE by the composition\n * root (genie-adapter.ts) before the backend is first constructed. Defaults are\n * inert so a test/pre-config load is harmless. Stored module-side rather than\n * threaded through every call site because the backend is a lazy singleton.\n */\nlet configuredDeps: BackendDeps = inertDeps;\n\n/**\n * Wire the in-process backend's settings + snapshot store. Must be called by the\n * adapter at app-ready, before any terminal is created. Idempotent if the\n * singleton hasn't been built yet; if it already exists this updates the deps it\n * uses (the adapter calls this exactly once, before first use).\n */\nexport function configureInProcessBackend(deps: BackendDeps): void {\n configuredDeps = deps;\n if (inProcess) inProcess.setDeps(deps);\n}\n\n/**\n * In-process backend singleton. Created lazily so importing this module from a\n * test context doesn't attempt to load node-pty before vi.mock has had a chance\n * to substitute it. This is ALSO the Tier 1/Tier 2 fallback floor: the quit-time\n * snapshot helpers reach for the in-process scrollback through it.\n */\nlet inProcess: InProcessBackend | null = null;\nexport function inProcessBackend(): InProcessBackend {\n if (!inProcess) inProcess = new InProcessBackend(configuredDeps);\n return inProcess;\n}\n\n/**\n * The ACTIVE backend the IPC layer talks to. Defaults to the in-process backend;\n * Tier 3 swaps in a HostClient at startup via setActiveBackend() when the\n * detached pty-host is available. Everything in ipc.ts / T1 / T2 goes through\n * here, oblivious to which concrete backend is mounted.\n */\nlet active: PtyBackend | null = null;\nexport function terminalManager(): PtyBackend {\n if (!active) active = inProcessBackend();\n return active;\n}\n\n/**\n * Subscribers that want to follow whichever backend is active (the IPC layer's\n * data/exit fan-out). Re-bound on every backend swap so events always come from\n * the LIVE backend, not a stale one left behind after a fallback.\n */\ninterface BackendEventHandlers {\n onData: (id: string, data: string) => void;\n onExit: (id: string, payload: { exitCode: number; signal?: number }) => void;\n}\nlet eventHandlers: BackendEventHandlers | null = null;\n/** Backends already wired to the fan-out, so a fallback back to a previously\n * active backend doesn't double-subscribe (which would duplicate every byte). */\nconst boundBackends = new WeakSet<PtyBackend>();\n\nfunction bindEvents(backend: PtyBackend): void {\n if (!eventHandlers) return;\n if (boundBackends.has(backend)) return;\n boundBackends.add(backend);\n backend.on('data', eventHandlers.onData);\n backend.on('exit', eventHandlers.onExit);\n}\n\n/**\n * Register the data/exit fan-out once. Binds to the current active backend and\n * is automatically re-bound to any backend swapped in via setActiveBackend, so\n * the IPC layer never has to know the backend changed underneath it.\n */\nexport function subscribeBackendEvents(handlers: BackendEventHandlers): void {\n eventHandlers = handlers;\n bindEvents(terminalManager());\n}\n\n/**\n * Swap the active backend (Tier 3 connect/spawn success → HostClient). Idempotent\n * and safe to call before any pty exists. Passing null reverts to the in-process\n * backend — used by the graceful-fallback path when the host dies mid-session.\n * Re-binds the IPC event fan-out to the new backend.\n */\nexport function setActiveBackend(backend: PtyBackend | null): void {\n const next = backend ?? inProcessBackend();\n if (next === active) return;\n active = next;\n bindEvents(active);\n}\n\nexport function defaultShell(): string {\n if (process.platform === 'win32') {\n // PowerShell wins for TUI compatibility (ConPTY support + full ANSI).\n // cmd.exe stays as fallback if pwsh isn't present in PATH.\n return process.env.COMSPEC ?? 'cmd.exe';\n }\n return process.env.SHELL ?? '/bin/bash';\n}\n\nfunction defaultShellArgs(shell: string): string[] {\n const base = shell.toLowerCase();\n if (base.endsWith('powershell.exe') || base.endsWith('pwsh.exe')) {\n return ['-NoLogo'];\n }\n return [];\n}\n","import path from 'node:path';\nimport fs from 'node:fs';\nimport zlib from 'node:zlib';\nimport type { SnapshotStoreConfig } from './ports';\n\n/**\n * Terminal session snapshots (Tier 1 persistence).\n *\n * A snapshot is the renderer's xterm SerializeAddon output — a clean ANSI\n * reconstruction of the visible buffer + scrollback. We persist it so that\n * after a full app quit + relaunch the terminal can replay its history,\n * draw a \"— previous session —\" divider, reset, then start a fresh shell.\n *\n * On-disk shape, per terminal id, at `<baseDir>/sessions/<id>.snap`:\n *\n * [1 byte magic] 0x01 = encrypted, 0x00 = plaintext fallback\n * [gzip payload] gzip( utf8( serialized ) ) (encrypted as a whole when magic=0x01)\n *\n * Encryption posture mirrors the GitHub token storage (main/github/storage.ts):\n * the injected Encryptor wraps the OS keychain (DPAPI / Keychain / libsecret via\n * Electron `safeStorage` in Genie's adapter). When the OS can't encrypt (rare;\n * headless Linux without libsecret) we fall back to writing the gzip payload in\n * the clear with the 0x00 marker and log ONCE — a terminal scrollback is far less\n * sensitive than an auth token, and a non-functional resume would be worse than a\n * plaintext scrollback on disk.\n *\n * Every read path tolerates missing / truncated / corrupt files by returning\n * null — a bad snapshot must never block a terminal from spawning.\n *\n * RUNTIME-AGNOSTIC: this module imports neither `electron` nor `../db`. The\n * baseDir + Encryptor are injected via SnapshotStoreConfig (Genie's adapter\n * supplies `app.getPath('userData')` + a safeStorage-backed Encryptor). The\n * `createSnapshotStore(config)` factory returns the read/write/delete trio bound\n * to that config.\n */\n\n/** Trim snapshots to this many bytes of serialized text, keeping the TAIL\n * (most-recent output). ~256 KB is plenty for a screen + deep scrollback and\n * bounds both disk and the replay write. */\nconst MAX_SERIALIZED_BYTES = 256 * 1024;\n\nconst MAGIC_ENCRYPTED = 0x01;\nconst MAGIC_PLAINTEXT = 0x00;\n\n/** Log the encryption-unavailable fallback at most once per process. */\nlet warnedNoEncryption = false;\n\nexport interface SnapshotRead {\n serialized: string;\n /** Epoch ms the file was last written (from its mtime). */\n savedAt: number;\n}\n\n/** Keep the last N bytes of a UTF-8 string without splitting a surrogate pair\n * at the cut boundary. */\nfunction trimTail(serialized: string): string {\n const buf = Buffer.from(serialized, 'utf8');\n if (buf.length <= MAX_SERIALIZED_BYTES) return serialized;\n // Decode the tail slice; Buffer→string on a mid-codepoint boundary yields a\n // replacement char rather than corruption, which xterm renders harmlessly.\n return buf.subarray(buf.length - MAX_SERIALIZED_BYTES).toString('utf8');\n}\n\n/**\n * The snapshot persistence surface (T1). Returned by createSnapshotStore so the\n * core can read/write/delete snapshots without knowing where the bytes live or\n * how they're encrypted.\n */\nexport interface SnapshotStore {\n /**\n * Persist a snapshot for `id`. Returns the on-disk byte size (so the caller\n * can record `snapshot_bytes`), or null when nothing was written (empty\n * input or an I/O error — never throws).\n */\n writeSnapshot(id: string, serialized: string): number | null;\n /**\n * Read a snapshot for `id`, or null when absent / unreadable / corrupt.\n * Never throws.\n */\n readSnapshot(id: string): SnapshotRead | null;\n /** Best-effort delete. Never throws; a missing file is success. */\n deleteSnapshot(id: string): void;\n}\n\n/**\n * Build a SnapshotStore bound to the given base directory + Encryptor. All the\n * gzip / trim / `.plain`-fallback / read-tolerates-corrupt logic is UNCHANGED\n * from the original module — only `app.getPath` → `config.baseDir` and\n * `safeStorage.*` → `config.encryptor.*`.\n */\nexport function createSnapshotStore(config: SnapshotStoreConfig): SnapshotStore {\n const { encryptor } = config;\n\n function sessionsDir(): string {\n const dir = path.join(config.baseDir, 'sessions');\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n return dir;\n }\n\n function snapPath(id: string): string {\n // ids are renderer-minted ulids (see lib/genie.ts) — alnum, no\n // separators — but guard anyway so a hostile/garbage id can never\n // escape the dir.\n const safe = id.replace(/[^A-Za-z0-9_-]/g, '');\n return path.join(sessionsDir(), `${safe}.snap`);\n }\n\n function encryptionAvailable(): boolean {\n try {\n return encryptor.isAvailable();\n } catch {\n return false;\n }\n }\n\n function writeSnapshot(id: string, serialized: string): number | null {\n try {\n if (!serialized) return null;\n const trimmed = trimTail(serialized);\n const gz = zlib.gzipSync(Buffer.from(trimmed, 'utf8'));\n\n let body: Buffer;\n let magic: number;\n if (encryptionAvailable()) {\n magic = MAGIC_ENCRYPTED;\n body = encryptor.encrypt(Buffer.from(gz.toString('base64'), 'utf8'));\n } else {\n if (!warnedNoEncryption) {\n warnedNoEncryption = true;\n // eslint-disable-next-line no-console\n console.warn(\n '[sessions] OS encryption unavailable — writing terminal ' +\n 'snapshots as plaintext gzip. Install libsecret/gnome-keyring ' +\n 'on Linux to encrypt them at rest.',\n );\n }\n magic = MAGIC_PLAINTEXT;\n body = gz;\n }\n\n const out = Buffer.concat([Buffer.from([magic]), body]);\n // Atomic-ish write: tmp + rename so a crash mid-write can't leave a\n // half-file that the next read would mistake for a real snapshot.\n const target = snapPath(id);\n const tmp = `${target}.tmp`;\n fs.writeFileSync(tmp, out);\n fs.renameSync(tmp, target);\n return out.length;\n } catch {\n return null;\n }\n }\n\n function readSnapshot(id: string): SnapshotRead | null {\n try {\n const file = snapPath(id);\n const stat = fs.statSync(file); // throws if missing → caught → null\n const raw = fs.readFileSync(file);\n if (raw.length < 2) return null;\n\n const magic = raw[0];\n const body = raw.subarray(1);\n\n let gz: Buffer;\n if (magic === MAGIC_ENCRYPTED) {\n if (!encryptionAvailable()) return null;\n const b64 = encryptor.decrypt(body).toString('utf8');\n gz = Buffer.from(b64, 'base64');\n } else if (magic === MAGIC_PLAINTEXT) {\n gz = body;\n } else {\n return null; // unknown format\n }\n\n const serialized = zlib.gunzipSync(gz).toString('utf8');\n return { serialized, savedAt: stat.mtimeMs };\n } catch {\n return null;\n }\n }\n\n function deleteSnapshot(id: string): void {\n try {\n fs.rmSync(snapPath(id), { force: true });\n } catch {\n /* ignore */\n }\n }\n\n return { writeSnapshot, readSnapshot, deleteSnapshot };\n}\n","/**\n * Pty-host wire protocol (Tier 3).\n *\n * The detached pty-host (main/terminal/pty-host.ts) and the in-app HostClient\n * (main/terminal/host-client.ts) talk over a local IPC transport — a named pipe\n * on Windows, a unix domain socket on POSIX — using a tiny length-prefixed JSON\n * framing so there's no heavy dependency. This module is PURE (no electron, no\n * node-pty, no net): just the message shapes + the encode/decode for the framing,\n * so it can be imported by both ends AND unit-tested in isolation.\n *\n * Framing: each message is `[4-byte big-endian uint32 length][utf8 JSON body]`.\n * The length prefix is the byte length of the JSON body. A FrameDecoder buffers\n * partial reads and yields whole messages as they complete — TCP/pipe streams\n * don't preserve message boundaries, so we can't assume one `data` event == one\n * message.\n */\n\n/**\n * Protocol version. Bumped whenever the message shapes change in a way that\n * makes an old host incompatible with a new client (or vice-versa). The client\n * refuses to attach to a host whose pidfile reports a different version and\n * spawns a fresh host instead — see host-client.ts connect-or-spawn.\n */\nexport const PROTOCOL_VERSION = 1;\n\n/** Requests the client sends to the host. `seq` correlates a reply. */\nexport type ClientMessage =\n | { kind: 'hello'; seq: number; protocolVersion: number }\n | {\n kind: 'create';\n seq: number;\n opts: {\n id: string;\n cwd: string;\n shell?: string;\n args?: string[];\n cols?: number;\n rows?: number;\n env?: Record<string, string>;\n };\n }\n | { kind: 'write'; id: string; data: string }\n | { kind: 'resize'; id: string; cols: number; rows: number }\n | { kind: 'kill'; id: string }\n | { kind: 'list'; seq: number }\n | { kind: 'set-retained'; id: string; retained: boolean }\n | { kind: 'get-scrollback'; seq: number; id: string }\n | { kind: 'ping'; seq: number };\n\n/** Pushes + replies the host sends to the client. */\nexport type HostMessage =\n | { kind: 'hello-ok'; seq: number; protocolVersion: number; pid: number }\n | {\n kind: 'created';\n seq: number;\n result: {\n id: string;\n pid: number;\n shell: string;\n existing: boolean;\n scrollback: string;\n };\n }\n | {\n kind: 'list-result';\n seq: number;\n terminals: Array<{ id: string; pid: number; shell: string }>;\n }\n | { kind: 'scrollback-result'; seq: number; scrollback: string | null }\n | { kind: 'pong'; seq: number }\n | { kind: 'data'; id: string; data: string }\n | { kind: 'exit'; id: string; exitCode: number; signal?: number };\n\nexport type Frame = ClientMessage | HostMessage;\n\nconst LENGTH_BYTES = 4;\n\n/** Encode a message as a length-prefixed JSON frame ready for the socket. */\nexport function encodeFrame(msg: Frame): Buffer {\n const body = Buffer.from(JSON.stringify(msg), 'utf8');\n const header = Buffer.allocUnsafe(LENGTH_BYTES);\n header.writeUInt32BE(body.length, 0);\n return Buffer.concat([header, body]);\n}\n\n/**\n * Streaming frame decoder. Feed it raw socket chunks via `push`; it returns the\n * complete messages that became available (zero or more), buffering any partial\n * tail until the rest arrives. One decoder per socket.\n *\n * Resilient by design: a malformed JSON body is skipped (the frame is consumed\n * but yields nothing) rather than throwing — a corrupt frame must not wedge the\n * whole stream. An absurd length prefix (> MAX_FRAME) is treated as a desync and\n * the buffer is reset; the caller can decide whether to drop the connection.\n */\nexport class FrameDecoder {\n private buffer: Buffer = Buffer.alloc(0);\n\n /** Hard cap on a single frame (16 MB). Guards against a runaway/garbage\n * length prefix allocating unbounded memory. node-pty data chunks are tiny;\n * a serialized scrollback is bounded well under this. */\n static readonly MAX_FRAME = 16 * 1024 * 1024;\n\n /** True when the last push hit an oversized/desynced frame. The caller\n * should drop the connection — the stream can't be trusted to realign. */\n desynced = false;\n\n push(chunk: Buffer): Frame[] {\n this.buffer = this.buffer.length ? Buffer.concat([this.buffer, chunk]) : chunk;\n const out: Frame[] = [];\n for (;;) {\n if (this.buffer.length < LENGTH_BYTES) break;\n const len = this.buffer.readUInt32BE(0);\n if (len > FrameDecoder.MAX_FRAME) {\n // Desync / garbage. Reset and flag — realigning a length-prefixed\n // stream after a bad prefix isn't possible without a sentinel.\n this.desynced = true;\n this.buffer = Buffer.alloc(0);\n break;\n }\n if (this.buffer.length < LENGTH_BYTES + len) break; // wait for more\n const body = this.buffer.subarray(LENGTH_BYTES, LENGTH_BYTES + len);\n this.buffer = this.buffer.subarray(LENGTH_BYTES + len);\n try {\n out.push(JSON.parse(body.toString('utf8')) as Frame);\n } catch {\n /* skip a corrupt frame; the framing itself is still aligned */\n }\n }\n return out;\n }\n}\n","import net from 'node:net';\nimport { EventEmitter } from 'node:events';\nimport type { PtyBackend } from './backend';\nimport type { CreateTerminalOpts, TerminalInfo, AttachResult } from './types';\nimport {\n encodeFrame,\n FrameDecoder,\n PROTOCOL_VERSION,\n type ClientMessage,\n type HostMessage,\n} from './host-protocol';\nimport type { SnapshotStore } from './sessions';\n\n/**\n * HostClient — the Tier 3 PtyBackend that proxies every call to the DETACHED\n * pty-host over a local socket (named pipe on Windows, unix domain socket on\n * POSIX). The real node-pty instances live in the host, so they survive a full\n * quit of the Electron app; the client just relays create/write/resize/kill and\n * fans the host's pushed `data`/`exit` messages out to subscribers.\n *\n * Design constraints that shape this:\n *\n * • ipc.ts calls are SYNCHRONOUS (create returns an AttachResult, write returns\n * a boolean) because the in-process backend is synchronous. We can't make the\n * socket round-trip synchronous, so the client keeps a LOCAL MIRROR of host\n * state — known terminal ids, their pid/shell, retained flags, and a local\n * scrollback ring fed from pushed `data` — and answers create/list/isLive/\n * scrollback from that mirror immediately. The actual create request is sent\n * fire-and-forget AFTER seeding the mirror; the host echoes the real pid via\n * a `created` reply which we reconcile. This keeps the existing IPC contract\n * intact without rewriting it async.\n *\n * • On connect we `hello` (version handshake) then `list` + `get-scrollback`\n * for each live host pty, seeding the mirror so a reattach-after-quit replays\n * the host's retained history into the renderer exactly like a warm rejoin.\n *\n * Connection failures surface via the `error` event; the lifecycle layer\n * (background.ts) catches a failed connect/spawn and falls back to the in-process\n * backend with a non-fatal toast.\n */\n\nconst SCROLLBACK_MAX = 1_000_000;\n\ninterface MirrorEntry {\n pid: number;\n shell: string;\n scrollback: string;\n}\n\nexport class HostClient extends EventEmitter implements PtyBackend {\n private socket: net.Socket | null = null;\n private readonly decoder = new FrameDecoder();\n private seq = 0;\n private readonly pending = new Map<number, (msg: HostMessage) => void>();\n\n private readonly mirror = new Map<string, MirrorEntry>();\n private readonly retained = new Set<string>();\n /** Host pid, learned from hello-ok — surfaced for diagnostics. */\n hostPid = 0;\n private connected = false;\n\n private constructor(\n private readonly socketPath: string,\n private readonly snapshots: SnapshotStore,\n ) {\n super();\n }\n\n /**\n * Connect to a running host at `socketPath`, perform the version handshake,\n * and seed the local mirror from the host's live ptys (list + per-pty\n * scrollback). Resolves to a ready client, or rejects on connect failure /\n * version mismatch / timeout — the caller then falls back to in-process.\n *\n * `snapshots` is the injected snapshot store used by cold-create to surface\n * any on-disk previous-session snapshot (was a direct `./sessions` import).\n */\n static connect(\n socketPath: string,\n snapshots: SnapshotStore,\n timeoutMs = 3000,\n ): Promise<HostClient> {\n return new Promise<HostClient>((resolve, reject) => {\n const client = new HostClient(socketPath, snapshots);\n const sock = net.createConnection(socketPath);\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n try {\n sock.destroy();\n } catch {\n /* ignore */\n }\n reject(new Error('pty-host connect timeout'));\n }, timeoutMs);\n\n sock.on('error', (err) => {\n if (settled) {\n client.handleSocketError(err);\n return;\n }\n settled = true;\n clearTimeout(timer);\n reject(err);\n });\n\n sock.once('connect', async () => {\n client.socket = sock;\n client.wireSocket(sock);\n try {\n const hello = (await client.request({\n kind: 'hello',\n seq: client.nextSeq(),\n protocolVersion: PROTOCOL_VERSION,\n })) as Extract<HostMessage, { kind: 'hello-ok' }>;\n if (hello.protocolVersion !== PROTOCOL_VERSION) {\n throw new Error(\n `pty-host protocol mismatch: host=${hello.protocolVersion} client=${PROTOCOL_VERSION}`,\n );\n }\n client.hostPid = hello.pid;\n client.connected = true;\n await client.seedFromHost();\n settled = true;\n clearTimeout(timer);\n resolve(client);\n } catch (err) {\n settled = true;\n clearTimeout(timer);\n try {\n sock.destroy();\n } catch {\n /* ignore */\n }\n reject(err as Error);\n }\n });\n });\n }\n\n private wireSocket(sock: net.Socket): void {\n sock.on('data', (chunk: Buffer) => {\n const frames = this.decoder.push(chunk);\n if (this.decoder.desynced) {\n this.handleSocketError(new Error('pty-host stream desync'));\n return;\n }\n for (const frame of frames) this.handleHostMessage(frame as HostMessage);\n });\n sock.on('close', () => {\n if (this.connected) {\n this.connected = false;\n this.emit('error', new Error('pty-host connection closed'));\n }\n });\n }\n\n private handleSocketError(err: Error): void {\n if (!this.connected) return;\n this.connected = false;\n this.emit('error', err);\n }\n\n private handleHostMessage(msg: HostMessage): void {\n switch (msg.kind) {\n case 'data': {\n const entry = this.mirror.get(msg.id);\n if (entry) {\n const next = entry.scrollback + msg.data;\n entry.scrollback =\n next.length > SCROLLBACK_MAX ? next.slice(-SCROLLBACK_MAX) : next;\n }\n this.emit('data', msg.id, msg.data);\n return;\n }\n case 'exit': {\n this.mirror.delete(msg.id);\n this.retained.delete(msg.id);\n this.emit('exit', msg.id, {\n exitCode: msg.exitCode,\n signal: msg.signal,\n });\n return;\n }\n default: {\n // Replies carry a seq — resolve the matching pending request.\n const seq = (msg as { seq?: number }).seq;\n if (seq != null) {\n const resolver = this.pending.get(seq);\n if (resolver) {\n this.pending.delete(seq);\n resolver(msg);\n }\n }\n }\n }\n }\n\n private nextSeq(): number {\n return ++this.seq;\n }\n\n /** Send a request and await the correlated reply. */\n private request(msg: ClientMessage & { seq: number }): Promise<HostMessage> {\n return new Promise<HostMessage>((resolve, reject) => {\n if (!this.socket) {\n reject(new Error('pty-host not connected'));\n return;\n }\n this.pending.set(msg.seq, resolve);\n try {\n this.socket.write(encodeFrame(msg));\n } catch (err) {\n this.pending.delete(msg.seq);\n reject(err as Error);\n }\n });\n }\n\n /** Fire-and-forget send for messages with no reply (write/resize/kill/…). */\n private send(msg: ClientMessage): void {\n if (!this.socket) return;\n try {\n this.socket.write(encodeFrame(msg));\n } catch {\n /* surfaced via the socket error/close handlers */\n }\n }\n\n /** Seed the local mirror from the host's live ptys after a (re)connect. */\n private async seedFromHost(): Promise<void> {\n const listed = (await this.request({\n kind: 'list',\n seq: this.nextSeq(),\n })) as Extract<HostMessage, { kind: 'list-result' }>;\n for (const t of listed.terminals) {\n const sb = (await this.request({\n kind: 'get-scrollback',\n seq: this.nextSeq(),\n id: t.id,\n })) as Extract<HostMessage, { kind: 'scrollback-result' }>;\n this.mirror.set(t.id, {\n pid: t.pid,\n shell: t.shell,\n scrollback: sb.scrollback ?? '',\n });\n }\n }\n\n /** Ids the host currently has live — used by the lifecycle layer to drive\n * the reattach (renderer remounts these specs, replaying host scrollback). */\n liveIds(): string[] {\n return Array.from(this.mirror.keys());\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n /** Disconnect WITHOUT killing host ptys (before-quit leave-running). */\n disconnect(): void {\n this.connected = false;\n if (this.socket) {\n try {\n this.socket.end();\n } catch {\n /* ignore */\n }\n this.socket = null;\n }\n }\n\n // --- PtyBackend ---------------------------------------------------------\n\n create(opts: CreateTerminalOpts): AttachResult {\n const existing = this.mirror.get(opts.id);\n if (existing) {\n // Warm rejoin from the mirror — the host already runs this pty and we\n // hold its replayed scrollback. No new spawn request.\n return {\n id: opts.id,\n pid: existing.pid,\n shell: existing.shell,\n existing: true,\n scrollback: existing.scrollback,\n };\n }\n // Cold create: seed the mirror immediately (pid 0 until the host echoes\n // the real one), fire the create request, and surface any on-disk\n // snapshot exactly like the in-process backend does on a cold spawn.\n this.mirror.set(opts.id, { pid: 0, shell: opts.shell ?? '', scrollback: '' });\n this.request({ kind: 'create', seq: this.nextSeq(), opts })\n .then((reply) => {\n if (reply.kind !== 'created') return;\n const entry = this.mirror.get(opts.id);\n if (entry) {\n entry.pid = reply.result.pid;\n entry.shell = reply.result.shell;\n }\n })\n .catch(() => {\n /* connection error surfaces via the error event → fallback */\n });\n const snap = this.snapshots.readSnapshot(opts.id);\n return {\n id: opts.id,\n pid: 0,\n shell: opts.shell ?? '',\n existing: false,\n scrollback: '',\n snapshot: snap ?? undefined,\n };\n }\n\n write(id: string, data: string): boolean {\n if (!this.mirror.has(id)) return false;\n this.send({ kind: 'write', id, data });\n return true;\n }\n\n resize(id: string, cols: number, rows: number): boolean {\n if (!this.mirror.has(id)) return false;\n this.send({\n kind: 'resize',\n id,\n cols: Math.max(1, cols | 0),\n rows: Math.max(1, rows | 0),\n });\n return true;\n }\n\n kill(id: string): boolean {\n const had = this.mirror.delete(id);\n this.retained.delete(id);\n this.send({ kind: 'kill', id });\n return had;\n }\n\n /**\n * NO-OP for the host backend. The whole point of Tier 3 is that ptys survive\n * a full quit, so the before-quit teardown must NOT kill them. The lifecycle\n * layer disconnects the client and leaves the host running instead.\n */\n killAll(): void {\n /* intentionally empty — host ptys survive quit */\n }\n\n list(): TerminalInfo[] {\n return Array.from(this.mirror.entries()).map(([id, e]) => ({\n id,\n pid: e.pid,\n shell: e.shell,\n }));\n }\n\n isLive(id: string): boolean {\n return this.mirror.has(id);\n }\n\n setRetained(id: string, retained: boolean): void {\n if (retained) this.retained.add(id);\n else this.retained.delete(id);\n this.send({ kind: 'set-retained', id, retained });\n }\n\n isRetained(id: string): boolean {\n return this.retained.has(id);\n }\n\n retainedCount(): number {\n return this.retained.size;\n }\n\n retainedIds(): string[] {\n return Array.from(this.retained);\n }\n\n getScrollback(id: string): string | undefined {\n return this.mirror.get(id)?.scrollback;\n }\n}\n","import path from 'node:path';\nimport os from 'node:os';\nimport fs from 'node:fs';\nimport crypto from 'node:crypto';\nimport { PROTOCOL_VERSION } from './host-protocol';\n\n/**\n * Path + pidfile resolution for the detached pty-host (Tier 3).\n *\n * Kept ELECTRON-FREE on the resolution side that the host itself uses (the host\n * is a plain node process — no `app`), so the userData path is passed IN. The\n * in-app side (host-client lifecycle) imports `app` separately and feeds it here.\n */\n\nexport interface Pidfile {\n pid: number;\n socketPath: string;\n protocolVersion: number;\n startedAt: number;\n}\n\n/** Short, stable per-user hash so two OS users don't collide on the Windows\n * pipe name (the pipe namespace is machine-global). */\nexport function userHash(): string {\n const seed = `${os.userInfo().username}|${os.hostname()}`;\n return crypto.createHash('sha1').update(seed).digest('hex').slice(0, 12);\n}\n\n/**\n * The local IPC transport address.\n * • Windows: a named pipe `\\\\.\\pipe\\genie-ptyhost-<userhash>`. The default\n * Windows pipe ACL is per-logon-session, so another user on the same machine\n * can't open it — that's our ACL. (Documented; we don't tighten further.)\n * • POSIX: a unix domain socket under userData (preferred — survives /tmp\n * cleaners and is per-user by directory perms) named `ptyhost.sock`.\n */\nexport function socketPathFor(userDataDir: string): string {\n if (process.platform === 'win32') {\n return `\\\\\\\\.\\\\pipe\\\\genie-ptyhost-${userHash()}`;\n }\n // Keep the path short — unix socket paths have a ~104-char limit. userData is\n // typically well under that; fall back to os.tmpdir() if it's pathologically\n // long.\n const candidate = path.join(userDataDir, 'ptyhost.sock');\n if (candidate.length < 100) return candidate;\n return path.join(os.tmpdir(), `genie-ptyhost-${userHash()}.sock`);\n}\n\nexport function pidfilePath(userDataDir: string): string {\n return path.join(userDataDir, 'ptyhost.json');\n}\n\nexport function writePidfile(userDataDir: string, pf: Pidfile): void {\n const target = pidfilePath(userDataDir);\n const tmp = `${target}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify(pf));\n fs.renameSync(tmp, target);\n}\n\nexport function readPidfile(userDataDir: string): Pidfile | null {\n try {\n const raw = fs.readFileSync(pidfilePath(userDataDir), 'utf8');\n const pf = JSON.parse(raw) as Pidfile;\n if (\n typeof pf.pid !== 'number' ||\n typeof pf.socketPath !== 'string' ||\n typeof pf.protocolVersion !== 'number'\n ) {\n return null;\n }\n return pf;\n } catch {\n return null;\n }\n}\n\nexport function deletePidfile(userDataDir: string): void {\n try {\n fs.rmSync(pidfilePath(userDataDir), { force: true });\n } catch {\n /* ignore */\n }\n}\n\n/** True when a process with `pid` is alive (signal 0 probes without killing). */\nexport function isPidAlive(pid: number): boolean {\n if (!pid || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n // EPERM = exists but not ours (still \"alive\"); ESRCH = gone.\n return (err as NodeJS.ErrnoException).code === 'EPERM';\n }\n}\n\n/**\n * Decide whether an existing pidfile points at a usable host.\n * Usable = pid alive AND protocol versions match. A stale/dead/mismatched\n * pidfile means we must spawn a fresh host.\n */\nexport function pidfileUsable(pf: Pidfile | null): boolean {\n if (!pf) return false;\n if (pf.protocolVersion !== PROTOCOL_VERSION) return false;\n if (!isPidAlive(pf.pid)) return false;\n return true;\n}\n\n/**\n * Resolve the compiled pty-host script on disk, trying multiple candidate paths\n * so it works in BOTH `npm run dev` (script at app/pty-host.js next to\n * background.js) AND a packaged asar build. node-pty's native binding can't load\n * from inside an asar, so the host (which requires node-pty) must run UNPACKED —\n * `app.asar.unpacked/...`. We try the unpacked path first, then the in-asar path,\n * then a dev-relative path. Returns the first that exists, or null.\n *\n * `dirname` is main/background's __dirname (the directory the compiled main\n * bundle lives in). The host script is emitted alongside it as `pty-host.js`.\n */\nexport function resolveHostScript(dirname: string): string | null {\n const candidates = [\n // Packaged: node-pty must be unpacked, so run the host from the unpacked\n // tree too (its require('node-pty') resolves to the unpacked .node).\n dirname.includes(`app.asar${path.sep}`) || dirname.includes('app.asar/')\n ? dirname.replace(\n /app\\.asar([\\\\/])/,\n `app.asar.unpacked$1`,\n ) + path.sep + 'pty-host.js'\n : '',\n // Same dir as the compiled main bundle (dev: app/pty-host.js).\n path.join(dirname, 'pty-host.js'),\n // Defensive: a sibling unpacked dir computed from the asar path.\n path.join(dirname.replace('app.asar', 'app.asar.unpacked'), 'pty-host.js'),\n ].filter(Boolean);\n\n for (const c of candidates) {\n try {\n if (fs.existsSync(c)) return c;\n } catch {\n /* keep trying */\n }\n }\n return null;\n}\n","import {\n readPidfile,\n pidfileUsable,\n deletePidfile,\n} from './host-locate';\nimport { HostClient } from './host-client';\nimport { setActiveBackend, inProcessBackend } from './manager';\nimport type { SettingsProvider, HostSpawner } from './ports';\nimport type { SnapshotStore } from './sessions';\nimport type { HostStatus } from './backend';\n\n/**\n * Tier 3 lifecycle: decide the backend at app-ready, manage the detached\n * pty-host, and handle graceful fallback.\n *\n * The flow (initTerminalBackend):\n * 1. If the `detached_terminals` setting is OFF (the default — see below) →\n * use the in-process backend. Done. This is today's T1/T2 behaviour.\n * 2. ON → try to CONNECT to an existing host (pidfile alive + version match +\n * socket reachable). Success → HostClient, reattach existing ptys.\n * 3. No usable host → SPAWN one detached, await its pidfile, then connect.\n * 4. Any failure (spawn, timeout, version mismatch, socket error) → fall back\n * to the in-process backend and surface a NON-FATAL toast. The app stays\n * fully functional.\n *\n * SETTING DEFAULT — `detached_terminals` defaults OFF.\n * Rationale: T3 is the heaviest tier and its #1 risk is the dev-vs-packaged\n * host-script path. Shipping it default-ON would put every user on an\n * unproven detached process the first launch after upgrade. Default-OFF means\n * the proven in-process T1/T2 path remains the out-of-box experience; users\n * opt in via Settings → Terminal → \"Keep terminals running after quit\".\n *\n * RUNTIME-AGNOSTIC: this module imports neither `electron` nor `../db`. The\n * connect-or-spawn-or-fallback LOGIC is core; the Electron specifics are\n * injected:\n * - HostSpawner — resolveHostScript / spawnDetached / userDataDir\n * (was app.getPath + child_process.spawn with execPath +\n * ELECTRON_RUN_AS_NODE).\n * - SettingsProvider — the `detached_terminals` read (was getAllSettings).\n * - SnapshotStore — passed to HostClient for cold-create snapshot probe.\n * - onHostStatus — the fallback toast sink, emits `host-status` instead of\n * a direct BrowserWindow broadcast.\n * Genie's adapter (genie-adapter.ts) supplies all four via configureHostLifecycle.\n */\n\ninterface HostLifecycleDeps {\n spawner: HostSpawner;\n settings: SettingsProvider;\n snapshots: SnapshotStore;\n onHostStatus: (status: HostStatus) => void;\n}\n\nlet deps: HostLifecycleDeps | null = null;\n\n/**\n * Wire the host lifecycle's injected ports. Called once by the adapter at\n * app-ready, before initTerminalBackend. NEVER configured = in-process only\n * (detachedEnabled below returns false defensively).\n */\nexport function configureHostLifecycle(d: HostLifecycleDeps): void {\n deps = d;\n}\n\nlet client: HostClient | null = null;\nlet usingHost = false;\n\n/** Emit the fallback host-status (was a direct BrowserWindow broadcast). */\nfunction status(message: string, level: 'info' | 'warn' = 'warn'): void {\n deps?.onHostStatus({ message, level });\n}\n\nfunction detachedEnabled(): boolean {\n try {\n return deps?.settings.get('detached_terminals') === 'on';\n } catch {\n return false;\n }\n}\n\n/** True when the active backend is the detached host (diagnostics + before-quit). */\nexport function isHostBacked(): boolean {\n return usingHost && !!client && client.isConnected();\n}\n\nexport function getHostClient(): HostClient | null {\n return client;\n}\n\n/** Poll for the pidfile to appear + become usable, up to `timeoutMs`. */\nasync function awaitUsableHost(userData: string, timeoutMs = 4000): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const pf = readPidfile(userData);\n if (pidfileUsable(pf)) return true;\n await new Promise((r) => setTimeout(r, 100));\n }\n return false;\n}\n\n/**\n * Initialise the terminal backend at app-ready. Returns the list of host pty ids\n * that should be reattached by the renderer (empty for the in-process path or a\n * cold host). NEVER throws — every failure degrades to in-process.\n */\nexport async function initTerminalBackend(): Promise<{\n host: boolean;\n reattachIds: string[];\n}> {\n // Ensure the in-process backend is the active default before anything.\n setActiveBackend(inProcessBackend());\n\n if (!deps || !detachedEnabled()) {\n return { host: false, reattachIds: [] };\n }\n const { spawner, snapshots } = deps;\n\n const userData = spawner.userDataDir();\n try {\n const hostScript = spawner.resolveHostScript();\n\n // 1) Try an existing host.\n let pf = readPidfile(userData);\n if (!pidfileUsable(pf)) {\n // Stale / dead / version-mismatch → clear it and spawn fresh.\n deletePidfile(userData);\n if (!hostScript) {\n // Can't find the compiled host script (packaging risk). Stay\n // in-process with a clear toast.\n status(\n 'Detached terminals unavailable (host not found) — using in-process. Sessions won\\'t survive a full quit.',\n );\n return { host: false, reattachIds: [] };\n }\n spawner.spawnDetached(hostScript, { GENIE_USERDATA: userData });\n const up = await awaitUsableHost(userData);\n if (!up) {\n status(\n 'Detached terminals unavailable (host didn\\'t start) — using in-process. Sessions won\\'t survive a full quit.',\n );\n return { host: false, reattachIds: [] };\n }\n pf = readPidfile(userData);\n }\n\n if (!pf) {\n status(\n 'Detached terminals unavailable — using in-process. Sessions won\\'t survive a full quit.',\n );\n return { host: false, reattachIds: [] };\n }\n\n // 2) Connect.\n client = await HostClient.connect(pf.socketPath, snapshots);\n client.on('error', onHostError);\n setActiveBackend(client);\n usingHost = true;\n return { host: true, reattachIds: client.liveIds() };\n } catch (err) {\n // 3) Any failure → fall back to in-process, app stays functional.\n // eslint-disable-next-line no-console\n console.error('[host-lifecycle] falling back to in-process:', err);\n try {\n client?.disconnect();\n } catch {\n /* ignore */\n }\n client = null;\n usingHost = false;\n setActiveBackend(inProcessBackend());\n status(\n 'Detached terminals unavailable — using in-process. Sessions won\\'t survive a full quit.',\n );\n return { host: false, reattachIds: [] };\n }\n}\n\n/**\n * Host connection dropped mid-session (host crashed / was killed). Fall back to\n * the in-process backend so future create()s work, and toast. Existing windows'\n * ptys are gone, but the app keeps running; a remount spawns fresh in-process.\n */\nfunction onHostError(err: Error): void {\n if (!usingHost) return;\n // eslint-disable-next-line no-console\n console.error('[host-lifecycle] host connection lost:', err.message);\n usingHost = false;\n client = null;\n setActiveBackend(inProcessBackend());\n status(\n 'Detached terminal host stopped — switched to in-process. Open terminals may need reopening.',\n );\n}\n\n/**\n * before-quit, host-backed: DO NOT kill the host ptys. Snapshot (T1) already ran\n * via the normal before-quit path; here we just disconnect the client and leave\n * the host running so the next launch reattaches.\n */\nexport function disconnectHostLeaveRunning(): void {\n if (client) {\n try {\n client.disconnect();\n } catch {\n /* ignore */\n }\n }\n}\n","import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { resolveHostScript } from './host-locate';\n\n/**\n * Absolute path to the bundled detached pty-host script (Tier 3), so a\n * `HostSpawner` can launch it as a detached child without knowing this\n * package's dist layout:\n *\n * ```ts\n * import { spawn } from 'node:child_process';\n * import { ptyHostScriptPath } from '@particle-academy/fancy-term-host';\n *\n * const child = spawn(process.execPath, [ptyHostScriptPath(), userDataDir], {\n * detached: true, stdio: 'ignore',\n * });\n * child.unref();\n * ```\n *\n * The host script is emitted alongside this module in `dist/` as\n * `pty-host.js`. Works in both the ESM and CJS builds (esbuild fills in\n * `import.meta.url` for the CJS output; `__dirname` is used when present).\n */\nexport function ptyHostScriptPath(): string {\n const here =\n typeof __dirname !== 'undefined'\n ? __dirname\n : path.dirname(fileURLToPath(import.meta.url));\n // Reuse host-locate's candidate logic (handles dev/packaged layouts); fall\n // back to the expected emitted location if the existence probe misses.\n return resolveHostScript(here) ?? path.join(here, 'pty-host.js');\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/osc7.ts","../src/cwd.ts","../src/shells.ts","../src/manager.ts","../src/sessions.ts","../src/host-protocol.ts","../src/host-client.ts","../src/host-locate.ts","../src/host-lifecycle.ts","../src/host-script.ts"],"names":["existsSync","statSync","os","fs","path","crypto","EventEmitter","deps","spawn","zlib","SCROLLBACK_MAX","client","net","fileURLToPath"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * OSC-7 cwd reporting (Tier 1.5).\n *\n * A shell that emits OSC-7 tells the terminal its current working directory on\n * every prompt:\n *\n * ESC ] 7 ; file://HOST/PATH (BEL | ESC \\)\n *\n * We scan raw pty output for these and parse out an absolute filesystem path so\n * a fresh shell spawned on resume can start where the old one left off. The\n * sequence is terminated by either BEL (\\x07) or ST (ESC \\, i.e. \\x1b\\x5c).\n *\n * Path forms handled:\n * file:///home/user/proj → /home/user/proj\n * file://hostname/home/user/proj → /home/user/proj (host ignored)\n * file:///C:/Users/me/proj → C:\\Users\\me\\proj (Windows drive)\n * percent-encoded segments (%20) → decoded\n */\n\nconst OSC7_RE = /\\x1b\\]7;([^\\x07\\x1b]*)(?:\\x07|\\x1b\\\\)/g;\n\n/**\n * Parse a `file://...` URL from an OSC-7 payload into a local filesystem path.\n * Returns null when the payload isn't a usable file URL.\n */\nexport function parseFileUrl(payload: string): string | null {\n if (!payload.startsWith('file://')) return null;\n let rest = payload.slice('file://'.length);\n\n // Strip the authority (host) up to the first '/'. `file:///path` has an\n // empty authority; `file://host/path` carries one we don't need.\n const slash = rest.indexOf('/');\n if (slash === -1) return null;\n let pathPart = rest.slice(slash); // includes the leading '/'\n\n let decoded: string;\n try {\n decoded = decodeURIComponent(pathPart);\n } catch {\n decoded = pathPart; // malformed %-escape — use as-is rather than drop\n }\n\n // Windows drive paths arrive as \"/C:/Users/...\". Drop the leading slash and\n // flip to backslashes so the value matches what node-pty/Electron expect as\n // a cwd on Windows.\n const winDrive = /^\\/([A-Za-z]):(.*)$/.exec(decoded);\n if (winDrive) {\n return `${winDrive[1]}:${winDrive[2]}`.replace(/\\//g, '\\\\');\n }\n\n return decoded;\n}\n\n/**\n * Scan a chunk of pty output and return the LAST cwd reported via OSC-7, or\n * null when the chunk contains no (parseable) OSC-7 sequence. We take the last\n * one because a single chunk can carry several prompts; the most recent wins.\n */\nexport function scanOsc7Cwd(chunk: string): string | null {\n if (chunk.indexOf('\\x1b]7;') === -1) return null; // fast bail\n let last: string | null = null;\n OSC7_RE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = OSC7_RE.exec(chunk))) {\n const cwd = parseFileUrl(m[1]);\n if (cwd) last = cwd;\n }\n return last;\n}\n","/**\n * Spawn-cwd normalization (Tier 1.5 companion to osc7.ts).\n *\n * Git Bash / MSYS reports `$PWD` in MSYS form (`/c/Users/me`), not native\n * Windows (`C:\\Users\\me`). The OSC-7 hook emits that raw, and `parseFileUrl`\n * only converts the drive-colon form (`/C:/...`), so an MSYS path flows through\n * unchanged. Handing `/c/Users/me` to node-pty as a working dir makes Windows\n * fail with ERROR_DIRECTORY (error code 267) — terminal creation crashes.\n *\n * Two small, OS-agnostic helpers fix this at the source:\n * - `toNativeCwd` converts an MSYS path to native Windows form (no-op on\n * POSIX, or when already native).\n * - `resolveSpawnCwd` native-converts the requested dir AND validates it,\n * falling back to the home directory so a stale/foreign/deleted cwd can\n * never crash spawn.\n *\n * Used at both spawn sites (manager.ts, pty-host.ts) and at the OSC-7 capture\n * so the persisted `live_cwd` is already a valid native path.\n */\n\nimport { existsSync, statSync } from 'node:fs';\nimport os from 'node:os';\n\n/**\n * Convert an MSYS/Git-Bash cwd to a native Windows path.\n * /c/Users/me -> C:\\Users\\me\n * /d/work -> D:\\work\n * /c -> C:\\ (bare drive root)\n * No-op on non-win32, on an empty string, or on an already-native path.\n */\nexport function toNativeCwd(p: string): string {\n if (process.platform !== 'win32' || !p) return p;\n const m = /^\\/([A-Za-z])\\/(.*)$/.exec(p);\n if (m) return `${m[1].toUpperCase()}:\\\\${m[2].replace(/\\//g, '\\\\')}`;\n const root = /^\\/([A-Za-z])\\/?$/.exec(p);\n if (root) return `${root[1].toUpperCase()}:\\\\`;\n return p;\n}\n\n/**\n * Resolve the directory a pty should actually spawn in. Prefer the requested\n * dir (native-converted); if it isn't an existing directory, fall back to the\n * home directory — so a stale, foreign, or deleted cwd can't crash spawn.\n */\nexport function resolveSpawnCwd(requested: string | undefined | null): string {\n if (requested) {\n const native = toNativeCwd(requested);\n try {\n if (existsSync(native) && statSync(native).isDirectory()) return native;\n } catch {\n /* fall through to home */\n }\n }\n return os.homedir();\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport crypto from 'node:crypto';\nimport type { SettingsProvider } from './ports';\n\n/**\n * Shell detection + default-shell resolution for the terminal subsystem.\n *\n * Mirrors main/editors.ts: probe well-known install paths, return what's\n * actually present. Ids line up with fancy-term's BUILTIN_SHELLS so the\n * renderer can map detections straight onto ShellProfile entries\n * (cmd · powershell · pwsh · git-bash · bash · zsh · wsl).\n *\n * Default policy (Windows): Git Bash when detected — it's the shell the\n * Tynn toolchain assumes — then pwsh, then Windows PowerShell, then cmd.\n * On macOS/Linux the user's $SHELL wins, falling back to bash.\n */\n\nexport interface ShellInfo {\n /** Stable id, matches fancy-term BUILTIN_SHELLS where possible. */\n id: string;\n /** Display label, e.g. \"Git Bash\". */\n label: string;\n /** Absolute executable path (or bare command when resolved via PATH). */\n command: string;\n /** Default args for an interactive session. */\n args: string[];\n}\n\nfunction firstExisting(paths: string[]): string | null {\n for (const p of paths) {\n try {\n if (p && fs.existsSync(p)) return p;\n } catch {\n /* permission race — treat as absent */\n }\n }\n return null;\n}\n\nfunction windowsCandidates(): Array<Omit<ShellInfo, 'command'> & { paths: string[] }> {\n const programFiles = process.env.ProgramFiles ?? 'C:\\\\Program Files';\n const programFilesX86 =\n process.env['ProgramFiles(x86)'] ?? 'C:\\\\Program Files (x86)';\n const localAppData = process.env.LOCALAPPDATA ?? '';\n const systemRoot = process.env.SystemRoot ?? 'C:\\\\Windows';\n\n return [\n {\n id: 'git-bash',\n label: 'Git Bash',\n args: ['--login', '-i'],\n paths: [\n path.join(programFiles, 'Git', 'bin', 'bash.exe'),\n path.join(programFilesX86, 'Git', 'bin', 'bash.exe'),\n localAppData\n ? path.join(localAppData, 'Programs', 'Git', 'bin', 'bash.exe')\n : '',\n ],\n },\n {\n id: 'pwsh',\n label: 'PowerShell 7',\n args: ['-NoLogo'],\n paths: [\n path.join(programFiles, 'PowerShell', '7', 'pwsh.exe'),\n localAppData\n ? path.join(localAppData, 'Microsoft', 'WindowsApps', 'pwsh.exe')\n : '',\n ],\n },\n {\n id: 'powershell',\n label: 'Windows PowerShell',\n args: ['-NoLogo'],\n paths: [\n path.join(\n systemRoot,\n 'System32',\n 'WindowsPowerShell',\n 'v1.0',\n 'powershell.exe',\n ),\n ],\n },\n {\n id: 'cmd',\n label: 'Command Prompt',\n args: [],\n paths: [process.env.COMSPEC ?? path.join(systemRoot, 'System32', 'cmd.exe')],\n },\n {\n id: 'wsl',\n label: 'WSL',\n args: [],\n paths: [path.join(systemRoot, 'System32', 'wsl.exe')],\n },\n ];\n}\n\nfunction unixCandidates(): Array<Omit<ShellInfo, 'command'> & { paths: string[] }> {\n return [\n {\n id: 'zsh',\n label: 'zsh',\n args: ['-l'],\n paths: ['/bin/zsh', '/usr/bin/zsh', '/usr/local/bin/zsh', '/opt/homebrew/bin/zsh'],\n },\n {\n id: 'bash',\n label: 'bash',\n args: ['-l'],\n paths: ['/bin/bash', '/usr/bin/bash', '/usr/local/bin/bash'],\n },\n {\n id: 'fish',\n label: 'fish',\n args: ['-l'],\n paths: ['/usr/bin/fish', '/usr/local/bin/fish', '/opt/homebrew/bin/fish'],\n },\n ];\n}\n\nexport function detectShells(): ShellInfo[] {\n const candidates =\n process.platform === 'win32' ? windowsCandidates() : unixCandidates();\n const found: ShellInfo[] = [];\n for (const c of candidates) {\n const command = firstExisting(c.paths);\n if (command) found.push({ id: c.id, label: c.label, command, args: c.args });\n }\n\n // Unix: surface the user's login shell even if it isn't in the probe\n // list (e.g. a Homebrew bash that lives somewhere exotic).\n if (process.platform !== 'win32') {\n const login = process.env.SHELL;\n if (login && !found.some((s) => s.command === login) && fs.existsSync(login)) {\n found.unshift({\n id: path.basename(login),\n label: path.basename(login),\n command: login,\n args: ['-l'],\n });\n }\n }\n return found;\n}\n\n/** Default policy: Git Bash > pwsh > powershell > cmd (win); $SHELL > bash (unix). */\nexport function defaultShellId(detected: ShellInfo[]): string | null {\n const order =\n process.platform === 'win32'\n ? ['git-bash', 'pwsh', 'powershell', 'cmd']\n : detected.map((s) => s.id); // unix list is already priority-ordered\n for (const id of order) {\n if (detected.some((s) => s.id === id)) return id;\n }\n return detected[0]?.id ?? null;\n}\n\n/**\n * Split a manual \"executable line\" into command + args. Honors double\n * quotes around the executable path (\"C:\\Program Files\\Git\\bin\\bash.exe\"\n * --login -i). Single-token lines pass through untouched.\n */\nexport function parseCommandLine(line: string): { command: string; args: string[] } {\n const trimmed = line.trim();\n if (!trimmed) return { command: '', args: [] };\n const tokens: string[] = [];\n const re = /\"([^\"]*)\"|(\\S+)/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(trimmed))) tokens.push(m[1] ?? m[2]);\n return { command: tokens[0] ?? '', args: tokens.slice(1) };\n}\n\n/** Coarse shell family, derived from the executable name, used to decide which\n * OSC-7 prompt hook (if any) we can inject. */\nexport type ShellKind = 'powershell' | 'bash' | 'zsh' | 'fish' | 'cmd' | 'other';\n\nexport function shellKind(command: string): ShellKind {\n const base = path.basename(command).toLowerCase();\n if (base.includes('pwsh') || base.includes('powershell')) return 'powershell';\n if (base.startsWith('zsh')) return 'zsh';\n if (base.startsWith('bash')) return 'bash';\n if (base.startsWith('fish')) return 'fish';\n if (base.startsWith('cmd')) return 'cmd';\n return 'other';\n}\n\n/** The spawn additions (env + extra args) a shell needs to emit OSC-7 cwd. */\nexport interface CwdHook {\n /** Extra env entries to merge into the pty's environment. */\n env: Record<string, string>;\n /** Extra args to APPEND to the shell's launch args (PowerShell needs these). */\n args: string[];\n}\n\n/** Short, stable per-user dir under the OS temp root that holds generated\n * prompt shims (zsh rc, fish conf, PowerShell profile). Per-user so two users\n * on a shared box don't read each other's shims. Created lazily. */\nfunction hookDir(): string {\n const seed = `${os.userInfo().username}|${os.hostname()}`;\n const hash = crypto.createHash('sha1').update(seed).digest('hex').slice(0, 12);\n const dir = path.join(os.tmpdir(), 'fancy-term-host', hash);\n fs.mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/** Best-effort write; a failed shim just means the shell degrades to static cwd. */\nfunction writeShim(file: string, contents: string): boolean {\n try {\n fs.writeFileSync(file, contents, 'utf8');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Build the spawn additions (env + args) that make a shell emit OSC-7 cwd\n * reports on every prompt, so resumed terminals know where they were\n * (Tier 1.5). Gated by the `track_cwd` setting (default ON). Returns an empty\n * hook when tracking is off or the shell genuinely can't be hooked — the\n * manager then degrades to the static cwd.\n *\n * Coverage (all overlay, never clobber the user's own prompt/rc):\n * - **bash** — prepend an OSC-7 `printf` to `PROMPT_COMMAND` (env only). The\n * portable, reliable case (Git Bash on Windows, bash on POSIX).\n * - **zsh** — point `ZDOTDIR` at a generated dir whose `.zshrc` sources the\n * user's real `.zshrc`, restores `ZDOTDIR`, then registers a `precmd`\n * emitter; `.zshenv` sources the user's real `.zshenv` first.\n * - **fish** — prepend a generated dir to `XDG_DATA_DIRS` carrying a\n * `fish/vendor_conf.d/osc7.fish` that hooks `--on-event fish_prompt`\n * (vendor conf overlays the user's config rather than replacing it).\n * - **PowerShell (pwsh/powershell)** — write a profile shim that wraps any\n * existing `prompt` and emits OSC-7, dot-sourced via appended\n * `-NoExit -Command \". '<shim>'\"` args (PS has no env-var prompt hook).\n * - **cmd.exe (best-effort)** — set `PROMPT` to emit OSC-7 via the `$E`\n * escape before the normal `$P$G`. Renders only where the console honors\n * VT sequences in the prompt; otherwise degrades to static cwd.\n *\n * The emitted payload is always `file:///<path>` (empty authority, forward\n * slashes / Windows drive) so it round-trips through {@link scanOsc7Cwd}.\n */\nexport function cwdHookSpawn(command: string, settings: SettingsProvider): CwdHook {\n const empty: CwdHook = { env: {}, args: [] };\n if (settings.get('track_cwd') === 'off') return empty;\n\n const kind = shellKind(command);\n const host = os.hostname();\n\n if (kind === 'bash') {\n // Emit from PROMPT_COMMAND; $PWD is absolute → file:///$PWD. PREPEND so\n // any existing PROMPT_COMMAND still runs. Single-quoted → expands at\n // prompt time, not now.\n const emit = `printf '\\\\033]7;file://${host}%s\\\\033\\\\\\\\' \"$PWD\"`;\n const prev = process.env.PROMPT_COMMAND ? '; ' + process.env.PROMPT_COMMAND : '';\n return { env: { PROMPT_COMMAND: `${emit}${prev}` }, args: [] };\n }\n\n if (kind === 'zsh') {\n const orig = process.env.ZDOTDIR || os.homedir();\n const dir = hookDir();\n // .zshenv runs for every invocation and is read from ZDOTDIR — source\n // the user's first so their environment survives.\n const okEnv = writeShim(\n path.join(dir, '.zshenv'),\n `# fancy-term-host (generated)\\n[ -f \"${orig}/.zshenv\" ] && source \"${orig}/.zshenv\"\\n`,\n );\n // .zshrc: restore ZDOTDIR for the user's environment, source their rc,\n // then register the OSC-7 precmd (appended → their prompt survives).\n const okRc = writeShim(\n path.join(dir, '.zshrc'),\n `# fancy-term-host (generated)\\n` +\n `ZDOTDIR=\"${orig}\"\\n` +\n `[ -f \"${orig}/.zshrc\" ] && source \"${orig}/.zshrc\"\\n` +\n `__fth_osc7() { printf '\\\\033]7;file://%s\\\\033\\\\\\\\' \"$PWD\" }\\n` +\n `typeset -ga precmd_functions\\n` +\n `precmd_functions+=(__fth_osc7)\\n`,\n );\n return okEnv && okRc ? { env: { ZDOTDIR: dir }, args: [] } : empty;\n }\n\n if (kind === 'fish') {\n const dir = hookDir();\n const confDir = path.join(dir, 'fish', 'vendor_conf.d');\n try {\n fs.mkdirSync(confDir, { recursive: true });\n } catch {\n return empty;\n }\n const ok = writeShim(\n path.join(confDir, 'osc7.fish'),\n `# fancy-term-host (generated)\\n` +\n `function __fth_osc7 --on-event fish_prompt\\n` +\n ` printf '\\\\x1b]7;file://%s\\\\x1b\\\\\\\\' \"$PWD\"\\n` +\n `end\\n`,\n );\n if (!ok) return empty;\n const existing = process.env.XDG_DATA_DIRS || '/usr/local/share:/usr/share';\n return { env: { XDG_DATA_DIRS: `${dir}${path.delimiter}${existing}` }, args: [] };\n }\n\n if (kind === 'powershell') {\n const dir = hookDir();\n const shim = path.join(dir, 'osc7-profile.ps1');\n // Wrap any existing prompt; emit file:///<forward-slashed path>. Use the\n // filesystem ProviderPath so non-filesystem locations don't poison it.\n const ok = writeShim(\n shim,\n `# fancy-term-host (generated)\\n` +\n `$global:__fthPrev = $function:prompt\\n` +\n `function global:prompt {\\n` +\n ` $p = ($PWD.ProviderPath -replace '\\\\\\\\','/')\\n` +\n ` [Console]::Write(\"$([char]27)]7;file:///$p$([char]27)\\\\\")\\n` +\n ` if ($global:__fthPrev) { & $global:__fthPrev } else { \"PS $($PWD.ProviderPath)> \" }\\n` +\n `}\\n`,\n );\n if (!ok) return empty;\n return { env: {}, args: ['-NoExit', '-Command', `. '${shim}'`] };\n }\n\n if (kind === 'cmd') {\n // Best-effort: $E = ESC in cmd's PROMPT. Emit OSC-7 (file:///$P, the\n // current path) then ST, then the normal $P$G. Only honored where the\n // console interprets VT sequences in the prompt.\n return { env: { PROMPT: `$E]7;file:///$P$E\\\\$P$G` }, args: [] };\n }\n\n return empty;\n}\n\n/**\n * Back-compat env-only view of {@link cwdHookSpawn} — returns just the env\n * additions. Shells that also need launch args (PowerShell) are only fully\n * hooked via `cwdHookSpawn`; callers using this alone get the env half.\n */\nexport function cwdHookEnv(\n command: string,\n settings: SettingsProvider,\n): Record<string, string> {\n return cwdHookSpawn(command, settings).env;\n}\n\n/**\n * Resolve the user's configured default shell to a concrete spawn target.\n * Reads the `terminal_shell` setting (a detected id, or 'custom' paired\n * with `terminal_custom_cmd`). Anything unresolvable falls back to the\n * detection-based default so the terminal always opens SOMETHING.\n */\nexport function resolveDefaultShell(settings: SettingsProvider): {\n command: string;\n args: string[];\n} {\n const detected = detectShells();\n const terminalShell = settings.get('terminal_shell');\n\n if (terminalShell === 'custom') {\n const parsed = parseCommandLine(settings.get('terminal_custom_cmd') ?? '');\n if (parsed.command) return parsed;\n }\n\n const pick =\n detected.find((s) => s.id === terminalShell) ??\n detected.find((s) => s.id === defaultShellId(detected));\n if (pick) return { command: pick.command, args: pick.args };\n\n // Nothing detected (bare container?) — legacy platform fallbacks.\n if (process.platform === 'win32') {\n return { command: process.env.COMSPEC ?? 'cmd.exe', args: [] };\n }\n return { command: process.env.SHELL ?? '/bin/bash', args: [] };\n}\n","import { spawn, IPty } from 'node-pty';\nimport { EventEmitter } from 'node:events';\nimport { scanOsc7Cwd } from './osc7';\nimport { resolveSpawnCwd, toNativeCwd } from './cwd';\nimport { cwdHookSpawn } from './shells';\nimport type { PtyBackend } from './backend';\nimport type { CreateTerminalOpts, TerminalInfo, AttachResult } from './types';\nimport type { SettingsProvider } from './ports';\nimport type { SnapshotStore } from './sessions';\n\nexport type { CreateTerminalOpts, TerminalInfo, AttachResult } from './types';\n\n/**\n * Centralised PTY manager. Owns every spawned pty, routes I/O to/from\n * the renderer via the events on this emitter, and cleans up on close.\n *\n * Why an emitter, not direct IPC: the manager doesn't know which\n * BrowserWindow is hosting a terminal — that's the IPC layer's job. The\n * manager just emits `data:<id>` and `exit:<id>` and lets ipc.ts wire\n * them to the right webContents.\n *\n * RUNTIME-AGNOSTIC: this module imports neither `electron` nor `../db`. The\n * settings (for the OSC-7 cwd hook) + snapshot store (for cold-spawn restore)\n * are injected via BackendDeps, and the live cwd learned from OSC-7 is EMITTED\n * as a `'cwd'` event rather than written to the DB directly. Genie's adapter\n * subscribes to `'cwd'` → `updateTerminalSpec({ live_cwd })`.\n */\n\n/** ~1 MB per pty. Enough for an hour of typical dev output without runaway memory. */\nconst SCROLLBACK_MAX = 1_000_000;\n\n/** Debounce window for emitting an OSC-7 cwd change (the adapter persists it). */\nconst CWD_PERSIST_DEBOUNCE_MS = 750;\n\n/**\n * Dependencies the in-process backend needs that used to be direct `../db` /\n * `electron` reaches: a SettingsProvider (cwd-hook gating) and a SnapshotStore\n * (cold-spawn restore). Injected by the composition root via\n * configureInProcessBackend; defaults are inert so a test/pre-config load is\n * harmless (no settings → cwd hook degrades to {}, no-op snapshot store → no\n * restore), preserving the historical \"db not ready → best-effort\" behaviour.\n */\nexport interface BackendDeps {\n settings: SettingsProvider;\n snapshots: SnapshotStore;\n}\n\nconst inertDeps: BackendDeps = {\n settings: { get: () => undefined },\n snapshots: {\n writeSnapshot: () => null,\n readSnapshot: () => null,\n deleteSnapshot: () => {},\n },\n};\n\n/**\n * InProcessBackend — node-pty instances owned directly by the Electron main\n * process. This is the historical TerminalManager body verbatim; it now also\n * formally implements the PtyBackend interface so the IPC layer can hold it\n * behind that abstraction interchangeably with the Tier 3 HostClient.\n *\n * EventEmitter gives us the `on('data'|'exit', …)` half of PtyBackend for free.\n */\nclass InProcessBackend extends EventEmitter implements PtyBackend {\n constructor(private deps: BackendDeps = inertDeps) {\n super();\n }\n\n /** Swap injected deps (only used if configure lands after lazy construction). */\n setDeps(deps: BackendDeps): void {\n this.deps = deps;\n }\n\n private readonly ptys = new Map<string, IPty>();\n private readonly scrollback = new Map<string, string>();\n private readonly shells = new Map<string, string>();\n /** Last cwd reported by each pty via OSC-7 (in-memory, authoritative). */\n private readonly liveCwd = new Map<string, string>();\n /** Pending debounced cwd-persist timers, keyed by terminal id. */\n private readonly cwdTimers = new Map<string, NodeJS.Timeout>();\n /**\n * Tier 2: ids that must keep their pty alive even with zero attached\n * windows (a disabled-but-retained terminal — e.g. a dev server the user\n * suspended). The IPC layer consults this in detachOwner: a retained id is\n * left running on the last detach instead of killed, so re-enable reattaches\n * to the LIVE session (scrollback replays) rather than spawning fresh.\n * Insertion order is preserved so the cap can evict the oldest if needed.\n */\n private readonly retained = new Set<string>();\n\n /**\n * Spawn a new pty for the given id, OR return the existing one if a\n * window has already attached. Idempotent: a Stage window can attach\n * to a spec that TheFloor is already running and get the same live\n * shell + a buffered scrollback to catch up.\n */\n create(opts: CreateTerminalOpts): AttachResult {\n const existing = this.ptys.get(opts.id);\n if (existing) {\n return {\n id: opts.id,\n pid: existing.pid,\n shell: this.shells.get(opts.id) ?? existing.process,\n existing: true,\n scrollback: this.scrollback.get(opts.id) ?? '',\n };\n }\n const shell = opts.shell ?? defaultShell();\n const baseArgs = opts.args ?? defaultShellArgs(shell);\n // Inject the OSC-7 prompt hook (gated by the track_cwd setting) so the\n // shell reports its cwd on every prompt. Returns an empty hook when\n // tracking is off or the shell can't be hooked — degrade silently. Some\n // shells (PowerShell) need APPENDED launch args, not just env, to load\n // their generated prompt shim.\n const hook = cwdHookSpawn(shell, this.deps.settings);\n const args = hook.args.length ? [...baseArgs, ...hook.args] : baseArgs;\n const env = {\n ...process.env,\n ...hook.env,\n ...(opts.env ?? {}),\n } as Record<string, string>;\n // Most TUI apps key off TERM to decide whether to emit ANSI / use the\n // alt screen. xterm.js handles xterm-256color cleanly; without this,\n // some apps degrade to dumb mode.\n env.TERM = env.TERM || 'xterm-256color';\n\n const pty = spawn(shell, args, {\n name: 'xterm-color',\n // Native-convert + validate the requested dir; a stale/foreign/MSYS\n // cwd (e.g. Git Bash's /c/Users/me) would otherwise crash spawn with\n // Windows ERROR_DIRECTORY (267). Falls back to home if unusable.\n cwd: resolveSpawnCwd(opts.cwd),\n cols: opts.cols ?? 80,\n rows: opts.rows ?? 24,\n env,\n });\n\n this.ptys.set(opts.id, pty);\n this.shells.set(opts.id, shell);\n this.scrollback.set(opts.id, '');\n\n pty.onData((data) => {\n const buf = this.scrollback.get(opts.id) ?? '';\n const next = buf + data;\n this.scrollback.set(\n opts.id,\n next.length > SCROLLBACK_MAX ? next.slice(-SCROLLBACK_MAX) : next,\n );\n // Tier 1.5: watch for OSC-7 cwd reports and persist the latest,\n // debounced. The in-memory map is authoritative; the spec row is a\n // durable mirror for the next launch.\n const raw = scanOsc7Cwd(data);\n // Normalize an MSYS-form report (/c/Users/me) to native before we\n // store/emit it, so the persisted live_cwd is a valid spawn cwd next\n // launch — not a path that would crash with ERROR_DIRECTORY (267).\n const cwd = raw ? toNativeCwd(raw) : null;\n if (cwd && cwd !== this.liveCwd.get(opts.id)) {\n this.liveCwd.set(opts.id, cwd);\n this.scheduleCwdPersist(opts.id, cwd);\n }\n this.emit('data', opts.id, data);\n });\n pty.onExit(({ exitCode, signal }) => {\n this.cleanupCwd(opts.id);\n this.ptys.delete(opts.id);\n this.scrollback.delete(opts.id);\n this.shells.delete(opts.id);\n // A dead pty can't be retained — drop the flag so the cap frees up.\n this.retained.delete(opts.id);\n this.emit('exit', opts.id, { exitCode, signal });\n });\n\n // Cold spawn: surface any previous-session snapshot so the renderer can\n // replay history + divider + reset before this fresh shell takes over.\n const snap = this.deps.snapshots.readSnapshot(opts.id);\n\n return {\n id: opts.id,\n pid: pty.pid,\n shell,\n existing: false,\n scrollback: '',\n snapshot: snap ?? undefined,\n };\n }\n\n private scheduleCwdPersist(id: string, cwd: string): void {\n const existing = this.cwdTimers.get(id);\n if (existing) clearTimeout(existing);\n const t = setTimeout(() => {\n this.cwdTimers.delete(id);\n this.emit('cwd', id, cwd);\n }, CWD_PERSIST_DEBOUNCE_MS);\n // Don't let a pending cwd-write hold the process open at quit.\n if (typeof t.unref === 'function') t.unref();\n this.cwdTimers.set(id, t);\n }\n\n private cleanupCwd(id: string): void {\n const t = this.cwdTimers.get(id);\n if (t) {\n clearTimeout(t);\n this.cwdTimers.delete(id);\n }\n // Flush the last known cwd synchronously so a quit right after a `cd`\n // doesn't lose it. The adapter persists on the `cwd` event.\n const cwd = this.liveCwd.get(id);\n if (cwd) this.emit('cwd', id, cwd);\n this.liveCwd.delete(id);\n }\n\n /** Last cwd reported by this pty via OSC-7, or undefined when unknown. */\n getLiveCwd(id: string): string | undefined {\n return this.liveCwd.get(id);\n }\n\n write(id: string, data: string): boolean {\n const pty = this.ptys.get(id);\n if (!pty) return false;\n pty.write(data);\n return true;\n }\n\n resize(id: string, cols: number, rows: number): boolean {\n const pty = this.ptys.get(id);\n if (!pty) return false;\n // pty.resize throws when called with non-positive dims (and xterm-fit\n // can produce 0×0 transiently during layout). Clamp defensively.\n pty.resize(Math.max(1, cols | 0), Math.max(1, rows | 0));\n return true;\n }\n\n kill(id: string): boolean {\n const pty = this.ptys.get(id);\n if (!pty) return false;\n try {\n pty.kill();\n } catch {\n /* already exited */\n }\n this.cleanupCwd(id);\n this.ptys.delete(id);\n this.scrollback.delete(id);\n this.shells.delete(id);\n // An explicit kill (delete) also clears any retained flag.\n this.retained.delete(id);\n return true;\n }\n\n killAll(): void {\n for (const id of Array.from(this.ptys.keys())) {\n this.kill(id);\n }\n }\n\n list(): TerminalInfo[] {\n return Array.from(this.ptys.entries()).map(([id, pty]) => ({\n id,\n pid: pty.pid,\n shell: this.shells.get(id) ?? pty.process,\n }));\n }\n\n isLive(id: string): boolean {\n return this.ptys.has(id);\n }\n\n // --- Tier 2: retained-PTY (disabled-not-deleted) -----------------------\n\n /**\n * Mark/unmark a terminal as retained. A retained terminal's pty is kept\n * alive by the IPC layer even when its last window detaches. Returns the\n * resulting retained-id set size. Retaining a terminal that isn't live is\n * harmless (the flag simply has no pty to protect yet).\n */\n setRetained(id: string, retained: boolean): void {\n if (retained) this.retained.add(id);\n else this.retained.delete(id);\n }\n\n isRetained(id: string): boolean {\n return this.retained.has(id);\n }\n\n /** Number of currently-retained terminals (for the resource cap). */\n retainedCount(): number {\n return this.retained.size;\n }\n\n /** Snapshot of retained ids in insertion order (oldest first). */\n retainedIds(): string[] {\n return Array.from(this.retained);\n }\n\n /**\n * Buffered scrollback for a live pty (raw ANSI text), or undefined when the\n * id has no pty. Tier 2 uses this to serialize a windowless retained pty at\n * quit so its post-disable output still lands in a snapshot (T2→T1 degrade).\n */\n getScrollback(id: string): string | undefined {\n return this.scrollback.get(id);\n }\n}\n\n/** Back-compat alias. The class was renamed InProcessBackend in Tier 3; existing\n * imports of `TerminalManager` as a TYPE keep working. */\nexport type TerminalManager = InProcessBackend;\n\n/**\n * Injected dependencies for the in-process backend, set ONCE by the composition\n * root (genie-adapter.ts) before the backend is first constructed. Defaults are\n * inert so a test/pre-config load is harmless. Stored module-side rather than\n * threaded through every call site because the backend is a lazy singleton.\n */\nlet configuredDeps: BackendDeps = inertDeps;\n\n/**\n * Wire the in-process backend's settings + snapshot store. Must be called by the\n * adapter at app-ready, before any terminal is created. Idempotent if the\n * singleton hasn't been built yet; if it already exists this updates the deps it\n * uses (the adapter calls this exactly once, before first use).\n */\nexport function configureInProcessBackend(deps: BackendDeps): void {\n configuredDeps = deps;\n if (inProcess) inProcess.setDeps(deps);\n}\n\n/**\n * In-process backend singleton. Created lazily so importing this module from a\n * test context doesn't attempt to load node-pty before vi.mock has had a chance\n * to substitute it. This is ALSO the Tier 1/Tier 2 fallback floor: the quit-time\n * snapshot helpers reach for the in-process scrollback through it.\n */\nlet inProcess: InProcessBackend | null = null;\nexport function inProcessBackend(): InProcessBackend {\n if (!inProcess) inProcess = new InProcessBackend(configuredDeps);\n return inProcess;\n}\n\n/**\n * The ACTIVE backend the IPC layer talks to. Defaults to the in-process backend;\n * Tier 3 swaps in a HostClient at startup via setActiveBackend() when the\n * detached pty-host is available. Everything in ipc.ts / T1 / T2 goes through\n * here, oblivious to which concrete backend is mounted.\n */\nlet active: PtyBackend | null = null;\nexport function terminalManager(): PtyBackend {\n if (!active) active = inProcessBackend();\n return active;\n}\n\n/**\n * Subscribers that want to follow whichever backend is active (the IPC layer's\n * data/exit fan-out). Re-bound on every backend swap so events always come from\n * the LIVE backend, not a stale one left behind after a fallback.\n */\ninterface BackendEventHandlers {\n onData: (id: string, data: string) => void;\n onExit: (id: string, payload: { exitCode: number; signal?: number }) => void;\n}\nlet eventHandlers: BackendEventHandlers | null = null;\n/** Backends already wired to the fan-out, so a fallback back to a previously\n * active backend doesn't double-subscribe (which would duplicate every byte). */\nconst boundBackends = new WeakSet<PtyBackend>();\n\nfunction bindEvents(backend: PtyBackend): void {\n if (!eventHandlers) return;\n if (boundBackends.has(backend)) return;\n boundBackends.add(backend);\n backend.on('data', eventHandlers.onData);\n backend.on('exit', eventHandlers.onExit);\n}\n\n/**\n * Register the data/exit fan-out once. Binds to the current active backend and\n * is automatically re-bound to any backend swapped in via setActiveBackend, so\n * the IPC layer never has to know the backend changed underneath it.\n */\nexport function subscribeBackendEvents(handlers: BackendEventHandlers): void {\n eventHandlers = handlers;\n bindEvents(terminalManager());\n}\n\n/**\n * Swap the active backend (Tier 3 connect/spawn success → HostClient). Idempotent\n * and safe to call before any pty exists. Passing null reverts to the in-process\n * backend — used by the graceful-fallback path when the host dies mid-session.\n * Re-binds the IPC event fan-out to the new backend.\n */\nexport function setActiveBackend(backend: PtyBackend | null): void {\n const next = backend ?? inProcessBackend();\n if (next === active) return;\n active = next;\n bindEvents(active);\n}\n\nexport function defaultShell(): string {\n if (process.platform === 'win32') {\n // PowerShell wins for TUI compatibility (ConPTY support + full ANSI).\n // cmd.exe stays as fallback if pwsh isn't present in PATH.\n return process.env.COMSPEC ?? 'cmd.exe';\n }\n return process.env.SHELL ?? '/bin/bash';\n}\n\nfunction defaultShellArgs(shell: string): string[] {\n const base = shell.toLowerCase();\n if (base.endsWith('powershell.exe') || base.endsWith('pwsh.exe')) {\n return ['-NoLogo'];\n }\n return [];\n}\n","import path from 'node:path';\nimport fs from 'node:fs';\nimport zlib from 'node:zlib';\nimport type { SnapshotStoreConfig } from './ports';\n\n/**\n * Terminal session snapshots (Tier 1 persistence).\n *\n * A snapshot is the renderer's xterm SerializeAddon output — a clean ANSI\n * reconstruction of the visible buffer + scrollback. We persist it so that\n * after a full app quit + relaunch the terminal can replay its history,\n * draw a \"— previous session —\" divider, reset, then start a fresh shell.\n *\n * On-disk shape, per terminal id, at `<baseDir>/sessions/<id>.snap`:\n *\n * [1 byte magic] 0x01 = encrypted, 0x00 = plaintext fallback\n * [gzip payload] gzip( utf8( serialized ) ) (encrypted as a whole when magic=0x01)\n *\n * Encryption posture mirrors the GitHub token storage (main/github/storage.ts):\n * the injected Encryptor wraps the OS keychain (DPAPI / Keychain / libsecret via\n * Electron `safeStorage` in Genie's adapter). When the OS can't encrypt (rare;\n * headless Linux without libsecret) we fall back to writing the gzip payload in\n * the clear with the 0x00 marker and log ONCE — a terminal scrollback is far less\n * sensitive than an auth token, and a non-functional resume would be worse than a\n * plaintext scrollback on disk.\n *\n * Every read path tolerates missing / truncated / corrupt files by returning\n * null — a bad snapshot must never block a terminal from spawning.\n *\n * RUNTIME-AGNOSTIC: this module imports neither `electron` nor `../db`. The\n * baseDir + Encryptor are injected via SnapshotStoreConfig (Genie's adapter\n * supplies `app.getPath('userData')` + a safeStorage-backed Encryptor). The\n * `createSnapshotStore(config)` factory returns the read/write/delete trio bound\n * to that config.\n */\n\n/** Trim snapshots to this many bytes of serialized text, keeping the TAIL\n * (most-recent output). ~256 KB is plenty for a screen + deep scrollback and\n * bounds both disk and the replay write. */\nconst MAX_SERIALIZED_BYTES = 256 * 1024;\n\nconst MAGIC_ENCRYPTED = 0x01;\nconst MAGIC_PLAINTEXT = 0x00;\n\n/** Log the encryption-unavailable fallback at most once per process. */\nlet warnedNoEncryption = false;\n\nexport interface SnapshotRead {\n serialized: string;\n /** Epoch ms the file was last written (from its mtime). */\n savedAt: number;\n}\n\n/** Keep the last N bytes of a UTF-8 string without splitting a surrogate pair\n * at the cut boundary. */\nfunction trimTail(serialized: string): string {\n const buf = Buffer.from(serialized, 'utf8');\n if (buf.length <= MAX_SERIALIZED_BYTES) return serialized;\n // Decode the tail slice; Buffer→string on a mid-codepoint boundary yields a\n // replacement char rather than corruption, which xterm renders harmlessly.\n return buf.subarray(buf.length - MAX_SERIALIZED_BYTES).toString('utf8');\n}\n\n/**\n * The snapshot persistence surface (T1). Returned by createSnapshotStore so the\n * core can read/write/delete snapshots without knowing where the bytes live or\n * how they're encrypted.\n */\nexport interface SnapshotStore {\n /**\n * Persist a snapshot for `id`. Returns the on-disk byte size (so the caller\n * can record `snapshot_bytes`), or null when nothing was written (empty\n * input or an I/O error — never throws).\n */\n writeSnapshot(id: string, serialized: string): number | null;\n /**\n * Read a snapshot for `id`, or null when absent / unreadable / corrupt.\n * Never throws.\n */\n readSnapshot(id: string): SnapshotRead | null;\n /** Best-effort delete. Never throws; a missing file is success. */\n deleteSnapshot(id: string): void;\n}\n\n/**\n * Build a SnapshotStore bound to the given base directory + Encryptor. All the\n * gzip / trim / `.plain`-fallback / read-tolerates-corrupt logic is UNCHANGED\n * from the original module — only `app.getPath` → `config.baseDir` and\n * `safeStorage.*` → `config.encryptor.*`.\n */\nexport function createSnapshotStore(config: SnapshotStoreConfig): SnapshotStore {\n const { encryptor } = config;\n\n function sessionsDir(): string {\n const dir = path.join(config.baseDir, 'sessions');\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n return dir;\n }\n\n function snapPath(id: string): string {\n // ids are renderer-minted ulids (see lib/genie.ts) — alnum, no\n // separators — but guard anyway so a hostile/garbage id can never\n // escape the dir.\n const safe = id.replace(/[^A-Za-z0-9_-]/g, '');\n return path.join(sessionsDir(), `${safe}.snap`);\n }\n\n function encryptionAvailable(): boolean {\n try {\n return encryptor.isAvailable();\n } catch {\n return false;\n }\n }\n\n function writeSnapshot(id: string, serialized: string): number | null {\n try {\n if (!serialized) return null;\n const trimmed = trimTail(serialized);\n const gz = zlib.gzipSync(Buffer.from(trimmed, 'utf8'));\n\n let body: Buffer;\n let magic: number;\n if (encryptionAvailable()) {\n magic = MAGIC_ENCRYPTED;\n body = encryptor.encrypt(Buffer.from(gz.toString('base64'), 'utf8'));\n } else {\n if (!warnedNoEncryption) {\n warnedNoEncryption = true;\n // eslint-disable-next-line no-console\n console.warn(\n '[sessions] OS encryption unavailable — writing terminal ' +\n 'snapshots as plaintext gzip. Install libsecret/gnome-keyring ' +\n 'on Linux to encrypt them at rest.',\n );\n }\n magic = MAGIC_PLAINTEXT;\n body = gz;\n }\n\n const out = Buffer.concat([Buffer.from([magic]), body]);\n // Atomic-ish write: tmp + rename so a crash mid-write can't leave a\n // half-file that the next read would mistake for a real snapshot.\n const target = snapPath(id);\n const tmp = `${target}.tmp`;\n fs.writeFileSync(tmp, out);\n fs.renameSync(tmp, target);\n return out.length;\n } catch {\n return null;\n }\n }\n\n function readSnapshot(id: string): SnapshotRead | null {\n try {\n const file = snapPath(id);\n const stat = fs.statSync(file); // throws if missing → caught → null\n const raw = fs.readFileSync(file);\n if (raw.length < 2) return null;\n\n const magic = raw[0];\n const body = raw.subarray(1);\n\n let gz: Buffer;\n if (magic === MAGIC_ENCRYPTED) {\n if (!encryptionAvailable()) return null;\n const b64 = encryptor.decrypt(body).toString('utf8');\n gz = Buffer.from(b64, 'base64');\n } else if (magic === MAGIC_PLAINTEXT) {\n gz = body;\n } else {\n return null; // unknown format\n }\n\n const serialized = zlib.gunzipSync(gz).toString('utf8');\n return { serialized, savedAt: stat.mtimeMs };\n } catch {\n return null;\n }\n }\n\n function deleteSnapshot(id: string): void {\n try {\n fs.rmSync(snapPath(id), { force: true });\n } catch {\n /* ignore */\n }\n }\n\n return { writeSnapshot, readSnapshot, deleteSnapshot };\n}\n","/**\n * Pty-host wire protocol (Tier 3).\n *\n * The detached pty-host (main/terminal/pty-host.ts) and the in-app HostClient\n * (main/terminal/host-client.ts) talk over a local IPC transport — a named pipe\n * on Windows, a unix domain socket on POSIX — using a tiny length-prefixed JSON\n * framing so there's no heavy dependency. This module is PURE (no electron, no\n * node-pty, no net): just the message shapes + the encode/decode for the framing,\n * so it can be imported by both ends AND unit-tested in isolation.\n *\n * Framing: each message is `[4-byte big-endian uint32 length][utf8 JSON body]`.\n * The length prefix is the byte length of the JSON body. A FrameDecoder buffers\n * partial reads and yields whole messages as they complete — TCP/pipe streams\n * don't preserve message boundaries, so we can't assume one `data` event == one\n * message.\n */\n\n/**\n * Protocol version. Bumped whenever the message shapes change in a way that\n * makes an old host incompatible with a new client (or vice-versa). The client\n * refuses to attach to a host whose pidfile reports a different version and\n * spawns a fresh host instead — see host-client.ts connect-or-spawn.\n */\nexport const PROTOCOL_VERSION = 1;\n\n/** Requests the client sends to the host. `seq` correlates a reply. */\nexport type ClientMessage =\n | { kind: 'hello'; seq: number; protocolVersion: number }\n | {\n kind: 'create';\n seq: number;\n opts: {\n id: string;\n cwd: string;\n shell?: string;\n args?: string[];\n cols?: number;\n rows?: number;\n env?: Record<string, string>;\n };\n }\n | { kind: 'write'; id: string; data: string }\n | { kind: 'resize'; id: string; cols: number; rows: number }\n | { kind: 'kill'; id: string }\n | { kind: 'list'; seq: number }\n | { kind: 'set-retained'; id: string; retained: boolean }\n | { kind: 'get-scrollback'; seq: number; id: string }\n | { kind: 'ping'; seq: number };\n\n/** Pushes + replies the host sends to the client. */\nexport type HostMessage =\n | { kind: 'hello-ok'; seq: number; protocolVersion: number; pid: number }\n | {\n kind: 'created';\n seq: number;\n result: {\n id: string;\n pid: number;\n shell: string;\n existing: boolean;\n scrollback: string;\n };\n }\n | {\n kind: 'list-result';\n seq: number;\n terminals: Array<{ id: string; pid: number; shell: string }>;\n }\n | { kind: 'scrollback-result'; seq: number; scrollback: string | null }\n | { kind: 'pong'; seq: number }\n | { kind: 'data'; id: string; data: string }\n | { kind: 'exit'; id: string; exitCode: number; signal?: number };\n\nexport type Frame = ClientMessage | HostMessage;\n\nconst LENGTH_BYTES = 4;\n\n/** Encode a message as a length-prefixed JSON frame ready for the socket. */\nexport function encodeFrame(msg: Frame): Buffer {\n const body = Buffer.from(JSON.stringify(msg), 'utf8');\n const header = Buffer.allocUnsafe(LENGTH_BYTES);\n header.writeUInt32BE(body.length, 0);\n return Buffer.concat([header, body]);\n}\n\n/**\n * Streaming frame decoder. Feed it raw socket chunks via `push`; it returns the\n * complete messages that became available (zero or more), buffering any partial\n * tail until the rest arrives. One decoder per socket.\n *\n * Resilient by design: a malformed JSON body is skipped (the frame is consumed\n * but yields nothing) rather than throwing — a corrupt frame must not wedge the\n * whole stream. An absurd length prefix (> MAX_FRAME) is treated as a desync and\n * the buffer is reset; the caller can decide whether to drop the connection.\n */\nexport class FrameDecoder {\n private buffer: Buffer = Buffer.alloc(0);\n\n /** Hard cap on a single frame (16 MB). Guards against a runaway/garbage\n * length prefix allocating unbounded memory. node-pty data chunks are tiny;\n * a serialized scrollback is bounded well under this. */\n static readonly MAX_FRAME = 16 * 1024 * 1024;\n\n /** True when the last push hit an oversized/desynced frame. The caller\n * should drop the connection — the stream can't be trusted to realign. */\n desynced = false;\n\n push(chunk: Buffer): Frame[] {\n this.buffer = this.buffer.length ? Buffer.concat([this.buffer, chunk]) : chunk;\n const out: Frame[] = [];\n for (;;) {\n if (this.buffer.length < LENGTH_BYTES) break;\n const len = this.buffer.readUInt32BE(0);\n if (len > FrameDecoder.MAX_FRAME) {\n // Desync / garbage. Reset and flag — realigning a length-prefixed\n // stream after a bad prefix isn't possible without a sentinel.\n this.desynced = true;\n this.buffer = Buffer.alloc(0);\n break;\n }\n if (this.buffer.length < LENGTH_BYTES + len) break; // wait for more\n const body = this.buffer.subarray(LENGTH_BYTES, LENGTH_BYTES + len);\n this.buffer = this.buffer.subarray(LENGTH_BYTES + len);\n try {\n out.push(JSON.parse(body.toString('utf8')) as Frame);\n } catch {\n /* skip a corrupt frame; the framing itself is still aligned */\n }\n }\n return out;\n }\n}\n","import net from 'node:net';\nimport { EventEmitter } from 'node:events';\nimport type { PtyBackend } from './backend';\nimport type { CreateTerminalOpts, TerminalInfo, AttachResult } from './types';\nimport {\n encodeFrame,\n FrameDecoder,\n PROTOCOL_VERSION,\n type ClientMessage,\n type HostMessage,\n} from './host-protocol';\nimport type { SnapshotStore } from './sessions';\n\n/**\n * HostClient — the Tier 3 PtyBackend that proxies every call to the DETACHED\n * pty-host over a local socket (named pipe on Windows, unix domain socket on\n * POSIX). The real node-pty instances live in the host, so they survive a full\n * quit of the Electron app; the client just relays create/write/resize/kill and\n * fans the host's pushed `data`/`exit` messages out to subscribers.\n *\n * Design constraints that shape this:\n *\n * • ipc.ts calls are SYNCHRONOUS (create returns an AttachResult, write returns\n * a boolean) because the in-process backend is synchronous. We can't make the\n * socket round-trip synchronous, so the client keeps a LOCAL MIRROR of host\n * state — known terminal ids, their pid/shell, retained flags, and a local\n * scrollback ring fed from pushed `data` — and answers create/list/isLive/\n * scrollback from that mirror immediately. The actual create request is sent\n * fire-and-forget AFTER seeding the mirror; the host echoes the real pid via\n * a `created` reply which we reconcile. This keeps the existing IPC contract\n * intact without rewriting it async.\n *\n * • On connect we `hello` (version handshake) then `list` + `get-scrollback`\n * for each live host pty, seeding the mirror so a reattach-after-quit replays\n * the host's retained history into the renderer exactly like a warm rejoin.\n *\n * Connection failures surface via the `error` event; the lifecycle layer\n * (background.ts) catches a failed connect/spawn and falls back to the in-process\n * backend with a non-fatal toast.\n */\n\nconst SCROLLBACK_MAX = 1_000_000;\n\ninterface MirrorEntry {\n pid: number;\n shell: string;\n scrollback: string;\n}\n\nexport class HostClient extends EventEmitter implements PtyBackend {\n private socket: net.Socket | null = null;\n private readonly decoder = new FrameDecoder();\n private seq = 0;\n private readonly pending = new Map<number, (msg: HostMessage) => void>();\n\n private readonly mirror = new Map<string, MirrorEntry>();\n private readonly retained = new Set<string>();\n /** Host pid, learned from hello-ok — surfaced for diagnostics. */\n hostPid = 0;\n private connected = false;\n\n private constructor(\n private readonly socketPath: string,\n private readonly snapshots: SnapshotStore,\n ) {\n super();\n }\n\n /**\n * Connect to a running host at `socketPath`, perform the version handshake,\n * and seed the local mirror from the host's live ptys (list + per-pty\n * scrollback). Resolves to a ready client, or rejects on connect failure /\n * version mismatch / timeout — the caller then falls back to in-process.\n *\n * `snapshots` is the injected snapshot store used by cold-create to surface\n * any on-disk previous-session snapshot (was a direct `./sessions` import).\n */\n static connect(\n socketPath: string,\n snapshots: SnapshotStore,\n timeoutMs = 3000,\n ): Promise<HostClient> {\n return new Promise<HostClient>((resolve, reject) => {\n const client = new HostClient(socketPath, snapshots);\n const sock = net.createConnection(socketPath);\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n try {\n sock.destroy();\n } catch {\n /* ignore */\n }\n reject(new Error('pty-host connect timeout'));\n }, timeoutMs);\n\n sock.on('error', (err) => {\n if (settled) {\n client.handleSocketError(err);\n return;\n }\n settled = true;\n clearTimeout(timer);\n reject(err);\n });\n\n sock.once('connect', async () => {\n client.socket = sock;\n client.wireSocket(sock);\n try {\n const hello = (await client.request({\n kind: 'hello',\n seq: client.nextSeq(),\n protocolVersion: PROTOCOL_VERSION,\n })) as Extract<HostMessage, { kind: 'hello-ok' }>;\n if (hello.protocolVersion !== PROTOCOL_VERSION) {\n throw new Error(\n `pty-host protocol mismatch: host=${hello.protocolVersion} client=${PROTOCOL_VERSION}`,\n );\n }\n client.hostPid = hello.pid;\n client.connected = true;\n await client.seedFromHost();\n settled = true;\n clearTimeout(timer);\n resolve(client);\n } catch (err) {\n settled = true;\n clearTimeout(timer);\n try {\n sock.destroy();\n } catch {\n /* ignore */\n }\n reject(err as Error);\n }\n });\n });\n }\n\n private wireSocket(sock: net.Socket): void {\n sock.on('data', (chunk: Buffer) => {\n const frames = this.decoder.push(chunk);\n if (this.decoder.desynced) {\n this.handleSocketError(new Error('pty-host stream desync'));\n return;\n }\n for (const frame of frames) this.handleHostMessage(frame as HostMessage);\n });\n sock.on('close', () => {\n if (this.connected) {\n this.connected = false;\n this.emit('error', new Error('pty-host connection closed'));\n }\n });\n }\n\n private handleSocketError(err: Error): void {\n if (!this.connected) return;\n this.connected = false;\n this.emit('error', err);\n }\n\n private handleHostMessage(msg: HostMessage): void {\n switch (msg.kind) {\n case 'data': {\n const entry = this.mirror.get(msg.id);\n if (entry) {\n const next = entry.scrollback + msg.data;\n entry.scrollback =\n next.length > SCROLLBACK_MAX ? next.slice(-SCROLLBACK_MAX) : next;\n }\n this.emit('data', msg.id, msg.data);\n return;\n }\n case 'exit': {\n this.mirror.delete(msg.id);\n this.retained.delete(msg.id);\n this.emit('exit', msg.id, {\n exitCode: msg.exitCode,\n signal: msg.signal,\n });\n return;\n }\n default: {\n // Replies carry a seq — resolve the matching pending request.\n const seq = (msg as { seq?: number }).seq;\n if (seq != null) {\n const resolver = this.pending.get(seq);\n if (resolver) {\n this.pending.delete(seq);\n resolver(msg);\n }\n }\n }\n }\n }\n\n private nextSeq(): number {\n return ++this.seq;\n }\n\n /** Send a request and await the correlated reply. */\n private request(msg: ClientMessage & { seq: number }): Promise<HostMessage> {\n return new Promise<HostMessage>((resolve, reject) => {\n if (!this.socket) {\n reject(new Error('pty-host not connected'));\n return;\n }\n this.pending.set(msg.seq, resolve);\n try {\n this.socket.write(encodeFrame(msg));\n } catch (err) {\n this.pending.delete(msg.seq);\n reject(err as Error);\n }\n });\n }\n\n /** Fire-and-forget send for messages with no reply (write/resize/kill/…). */\n private send(msg: ClientMessage): void {\n if (!this.socket) return;\n try {\n this.socket.write(encodeFrame(msg));\n } catch {\n /* surfaced via the socket error/close handlers */\n }\n }\n\n /** Seed the local mirror from the host's live ptys after a (re)connect. */\n private async seedFromHost(): Promise<void> {\n const listed = (await this.request({\n kind: 'list',\n seq: this.nextSeq(),\n })) as Extract<HostMessage, { kind: 'list-result' }>;\n for (const t of listed.terminals) {\n const sb = (await this.request({\n kind: 'get-scrollback',\n seq: this.nextSeq(),\n id: t.id,\n })) as Extract<HostMessage, { kind: 'scrollback-result' }>;\n this.mirror.set(t.id, {\n pid: t.pid,\n shell: t.shell,\n scrollback: sb.scrollback ?? '',\n });\n }\n }\n\n /** Ids the host currently has live — used by the lifecycle layer to drive\n * the reattach (renderer remounts these specs, replaying host scrollback). */\n liveIds(): string[] {\n return Array.from(this.mirror.keys());\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n /** Disconnect WITHOUT killing host ptys (before-quit leave-running). */\n disconnect(): void {\n this.connected = false;\n if (this.socket) {\n try {\n this.socket.end();\n } catch {\n /* ignore */\n }\n this.socket = null;\n }\n }\n\n // --- PtyBackend ---------------------------------------------------------\n\n create(opts: CreateTerminalOpts): AttachResult {\n const existing = this.mirror.get(opts.id);\n if (existing) {\n // Warm rejoin from the mirror — the host already runs this pty and we\n // hold its replayed scrollback. No new spawn request.\n return {\n id: opts.id,\n pid: existing.pid,\n shell: existing.shell,\n existing: true,\n scrollback: existing.scrollback,\n };\n }\n // Cold create: seed the mirror immediately (pid 0 until the host echoes\n // the real one), fire the create request, and surface any on-disk\n // snapshot exactly like the in-process backend does on a cold spawn.\n this.mirror.set(opts.id, { pid: 0, shell: opts.shell ?? '', scrollback: '' });\n this.request({ kind: 'create', seq: this.nextSeq(), opts })\n .then((reply) => {\n if (reply.kind !== 'created') return;\n const entry = this.mirror.get(opts.id);\n if (entry) {\n entry.pid = reply.result.pid;\n entry.shell = reply.result.shell;\n }\n })\n .catch(() => {\n /* connection error surfaces via the error event → fallback */\n });\n const snap = this.snapshots.readSnapshot(opts.id);\n return {\n id: opts.id,\n pid: 0,\n shell: opts.shell ?? '',\n existing: false,\n scrollback: '',\n snapshot: snap ?? undefined,\n };\n }\n\n write(id: string, data: string): boolean {\n if (!this.mirror.has(id)) return false;\n this.send({ kind: 'write', id, data });\n return true;\n }\n\n resize(id: string, cols: number, rows: number): boolean {\n if (!this.mirror.has(id)) return false;\n this.send({\n kind: 'resize',\n id,\n cols: Math.max(1, cols | 0),\n rows: Math.max(1, rows | 0),\n });\n return true;\n }\n\n kill(id: string): boolean {\n const had = this.mirror.delete(id);\n this.retained.delete(id);\n this.send({ kind: 'kill', id });\n return had;\n }\n\n /**\n * NO-OP for the host backend. The whole point of Tier 3 is that ptys survive\n * a full quit, so the before-quit teardown must NOT kill them. The lifecycle\n * layer disconnects the client and leaves the host running instead.\n */\n killAll(): void {\n /* intentionally empty — host ptys survive quit */\n }\n\n list(): TerminalInfo[] {\n return Array.from(this.mirror.entries()).map(([id, e]) => ({\n id,\n pid: e.pid,\n shell: e.shell,\n }));\n }\n\n isLive(id: string): boolean {\n return this.mirror.has(id);\n }\n\n setRetained(id: string, retained: boolean): void {\n if (retained) this.retained.add(id);\n else this.retained.delete(id);\n this.send({ kind: 'set-retained', id, retained });\n }\n\n isRetained(id: string): boolean {\n return this.retained.has(id);\n }\n\n retainedCount(): number {\n return this.retained.size;\n }\n\n retainedIds(): string[] {\n return Array.from(this.retained);\n }\n\n getScrollback(id: string): string | undefined {\n return this.mirror.get(id)?.scrollback;\n }\n}\n","import path from 'node:path';\nimport os from 'node:os';\nimport fs from 'node:fs';\nimport crypto from 'node:crypto';\nimport { PROTOCOL_VERSION } from './host-protocol';\n\n/**\n * Path + pidfile resolution for the detached pty-host (Tier 3).\n *\n * Kept ELECTRON-FREE on the resolution side that the host itself uses (the host\n * is a plain node process — no `app`), so the userData path is passed IN. The\n * in-app side (host-client lifecycle) imports `app` separately and feeds it here.\n */\n\nexport interface Pidfile {\n pid: number;\n socketPath: string;\n protocolVersion: number;\n startedAt: number;\n}\n\n/** Short, stable per-user hash so two OS users don't collide on the Windows\n * pipe name (the pipe namespace is machine-global). */\nexport function userHash(): string {\n const seed = `${os.userInfo().username}|${os.hostname()}`;\n return crypto.createHash('sha1').update(seed).digest('hex').slice(0, 12);\n}\n\n/**\n * The local IPC transport address.\n * • Windows: a named pipe `\\\\.\\pipe\\genie-ptyhost-<userhash>`. The default\n * Windows pipe ACL is per-logon-session, so another user on the same machine\n * can't open it — that's our ACL. (Documented; we don't tighten further.)\n * • POSIX: a unix domain socket under userData (preferred — survives /tmp\n * cleaners and is per-user by directory perms) named `ptyhost.sock`.\n */\nexport function socketPathFor(userDataDir: string): string {\n if (process.platform === 'win32') {\n return `\\\\\\\\.\\\\pipe\\\\genie-ptyhost-${userHash()}`;\n }\n // Keep the path short — unix socket paths have a ~104-char limit. userData is\n // typically well under that; fall back to os.tmpdir() if it's pathologically\n // long.\n const candidate = path.join(userDataDir, 'ptyhost.sock');\n if (candidate.length < 100) return candidate;\n return path.join(os.tmpdir(), `genie-ptyhost-${userHash()}.sock`);\n}\n\nexport function pidfilePath(userDataDir: string): string {\n return path.join(userDataDir, 'ptyhost.json');\n}\n\nexport function writePidfile(userDataDir: string, pf: Pidfile): void {\n const target = pidfilePath(userDataDir);\n const tmp = `${target}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify(pf));\n fs.renameSync(tmp, target);\n}\n\nexport function readPidfile(userDataDir: string): Pidfile | null {\n try {\n const raw = fs.readFileSync(pidfilePath(userDataDir), 'utf8');\n const pf = JSON.parse(raw) as Pidfile;\n if (\n typeof pf.pid !== 'number' ||\n typeof pf.socketPath !== 'string' ||\n typeof pf.protocolVersion !== 'number'\n ) {\n return null;\n }\n return pf;\n } catch {\n return null;\n }\n}\n\nexport function deletePidfile(userDataDir: string): void {\n try {\n fs.rmSync(pidfilePath(userDataDir), { force: true });\n } catch {\n /* ignore */\n }\n}\n\n/** True when a process with `pid` is alive (signal 0 probes without killing). */\nexport function isPidAlive(pid: number): boolean {\n if (!pid || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n // EPERM = exists but not ours (still \"alive\"); ESRCH = gone.\n return (err as NodeJS.ErrnoException).code === 'EPERM';\n }\n}\n\n/**\n * Decide whether an existing pidfile points at a usable host.\n * Usable = pid alive AND protocol versions match. A stale/dead/mismatched\n * pidfile means we must spawn a fresh host.\n */\nexport function pidfileUsable(pf: Pidfile | null): boolean {\n if (!pf) return false;\n if (pf.protocolVersion !== PROTOCOL_VERSION) return false;\n if (!isPidAlive(pf.pid)) return false;\n return true;\n}\n\n/**\n * Resolve the compiled pty-host script on disk, trying multiple candidate paths\n * so it works in BOTH `npm run dev` (script at app/pty-host.js next to\n * background.js) AND a packaged asar build. node-pty's native binding can't load\n * from inside an asar, so the host (which requires node-pty) must run UNPACKED —\n * `app.asar.unpacked/...`. We try the unpacked path first, then the in-asar path,\n * then a dev-relative path. Returns the first that exists, or null.\n *\n * `dirname` is main/background's __dirname (the directory the compiled main\n * bundle lives in). The host script is emitted alongside it as `pty-host.js`.\n */\nexport function resolveHostScript(dirname: string): string | null {\n const candidates = [\n // Packaged: node-pty must be unpacked, so run the host from the unpacked\n // tree too (its require('node-pty') resolves to the unpacked .node).\n dirname.includes(`app.asar${path.sep}`) || dirname.includes('app.asar/')\n ? dirname.replace(\n /app\\.asar([\\\\/])/,\n `app.asar.unpacked$1`,\n ) + path.sep + 'pty-host.js'\n : '',\n // Same dir as the compiled main bundle (dev: app/pty-host.js).\n path.join(dirname, 'pty-host.js'),\n // Defensive: a sibling unpacked dir computed from the asar path.\n path.join(dirname.replace('app.asar', 'app.asar.unpacked'), 'pty-host.js'),\n ].filter(Boolean);\n\n for (const c of candidates) {\n try {\n if (fs.existsSync(c)) return c;\n } catch {\n /* keep trying */\n }\n }\n return null;\n}\n","import {\n readPidfile,\n pidfileUsable,\n deletePidfile,\n} from './host-locate';\nimport { HostClient } from './host-client';\nimport { setActiveBackend, inProcessBackend } from './manager';\nimport type { SettingsProvider, HostSpawner } from './ports';\nimport type { SnapshotStore } from './sessions';\nimport type { HostStatus } from './backend';\n\n/**\n * Tier 3 lifecycle: decide the backend at app-ready, manage the detached\n * pty-host, and handle graceful fallback.\n *\n * The flow (initTerminalBackend):\n * 1. If the `detached_terminals` setting is OFF (the default — see below) →\n * use the in-process backend. Done. This is today's T1/T2 behaviour.\n * 2. ON → try to CONNECT to an existing host (pidfile alive + version match +\n * socket reachable). Success → HostClient, reattach existing ptys.\n * 3. No usable host → SPAWN one detached, await its pidfile, then connect.\n * 4. Any failure (spawn, timeout, version mismatch, socket error) → fall back\n * to the in-process backend and surface a NON-FATAL toast. The app stays\n * fully functional.\n *\n * SETTING DEFAULT — `detached_terminals` defaults OFF.\n * Rationale: T3 is the heaviest tier and its #1 risk is the dev-vs-packaged\n * host-script path. Shipping it default-ON would put every user on an\n * unproven detached process the first launch after upgrade. Default-OFF means\n * the proven in-process T1/T2 path remains the out-of-box experience; users\n * opt in via Settings → Terminal → \"Keep terminals running after quit\".\n *\n * RUNTIME-AGNOSTIC: this module imports neither `electron` nor `../db`. The\n * connect-or-spawn-or-fallback LOGIC is core; the Electron specifics are\n * injected:\n * - HostSpawner — resolveHostScript / spawnDetached / userDataDir\n * (was app.getPath + child_process.spawn with execPath +\n * ELECTRON_RUN_AS_NODE).\n * - SettingsProvider — the `detached_terminals` read (was getAllSettings).\n * - SnapshotStore — passed to HostClient for cold-create snapshot probe.\n * - onHostStatus — the fallback toast sink, emits `host-status` instead of\n * a direct BrowserWindow broadcast.\n * Genie's adapter (genie-adapter.ts) supplies all four via configureHostLifecycle.\n */\n\ninterface HostLifecycleDeps {\n spawner: HostSpawner;\n settings: SettingsProvider;\n snapshots: SnapshotStore;\n onHostStatus: (status: HostStatus) => void;\n}\n\nlet deps: HostLifecycleDeps | null = null;\n\n/**\n * Wire the host lifecycle's injected ports. Called once by the adapter at\n * app-ready, before initTerminalBackend. NEVER configured = in-process only\n * (detachedEnabled below returns false defensively).\n */\nexport function configureHostLifecycle(d: HostLifecycleDeps): void {\n deps = d;\n}\n\nlet client: HostClient | null = null;\nlet usingHost = false;\n\n/** Emit the fallback host-status (was a direct BrowserWindow broadcast). */\nfunction status(message: string, level: 'info' | 'warn' = 'warn'): void {\n deps?.onHostStatus({ message, level });\n}\n\nfunction detachedEnabled(): boolean {\n try {\n return deps?.settings.get('detached_terminals') === 'on';\n } catch {\n return false;\n }\n}\n\n/** True when the active backend is the detached host (diagnostics + before-quit). */\nexport function isHostBacked(): boolean {\n return usingHost && !!client && client.isConnected();\n}\n\nexport function getHostClient(): HostClient | null {\n return client;\n}\n\n/** Poll for the pidfile to appear + become usable, up to `timeoutMs`. */\nasync function awaitUsableHost(userData: string, timeoutMs = 4000): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const pf = readPidfile(userData);\n if (pidfileUsable(pf)) return true;\n await new Promise((r) => setTimeout(r, 100));\n }\n return false;\n}\n\n/**\n * Initialise the terminal backend at app-ready. Returns the list of host pty ids\n * that should be reattached by the renderer (empty for the in-process path or a\n * cold host). NEVER throws — every failure degrades to in-process.\n */\nexport async function initTerminalBackend(): Promise<{\n host: boolean;\n reattachIds: string[];\n}> {\n // Ensure the in-process backend is the active default before anything.\n setActiveBackend(inProcessBackend());\n\n if (!deps || !detachedEnabled()) {\n return { host: false, reattachIds: [] };\n }\n const { spawner, snapshots } = deps;\n\n const userData = spawner.userDataDir();\n try {\n const hostScript = spawner.resolveHostScript();\n\n // 1) Try an existing host.\n let pf = readPidfile(userData);\n if (!pidfileUsable(pf)) {\n // Stale / dead / version-mismatch → clear it and spawn fresh.\n deletePidfile(userData);\n if (!hostScript) {\n // Can't find the compiled host script (packaging risk). Stay\n // in-process with a clear toast.\n status(\n 'Detached terminals unavailable (host not found) — using in-process. Sessions won\\'t survive a full quit.',\n );\n return { host: false, reattachIds: [] };\n }\n spawner.spawnDetached(hostScript, { GENIE_USERDATA: userData });\n const up = await awaitUsableHost(userData);\n if (!up) {\n status(\n 'Detached terminals unavailable (host didn\\'t start) — using in-process. Sessions won\\'t survive a full quit.',\n );\n return { host: false, reattachIds: [] };\n }\n pf = readPidfile(userData);\n }\n\n if (!pf) {\n status(\n 'Detached terminals unavailable — using in-process. Sessions won\\'t survive a full quit.',\n );\n return { host: false, reattachIds: [] };\n }\n\n // 2) Connect.\n client = await HostClient.connect(pf.socketPath, snapshots);\n client.on('error', onHostError);\n setActiveBackend(client);\n usingHost = true;\n return { host: true, reattachIds: client.liveIds() };\n } catch (err) {\n // 3) Any failure → fall back to in-process, app stays functional.\n // eslint-disable-next-line no-console\n console.error('[host-lifecycle] falling back to in-process:', err);\n try {\n client?.disconnect();\n } catch {\n /* ignore */\n }\n client = null;\n usingHost = false;\n setActiveBackend(inProcessBackend());\n status(\n 'Detached terminals unavailable — using in-process. Sessions won\\'t survive a full quit.',\n );\n return { host: false, reattachIds: [] };\n }\n}\n\n/**\n * Host connection dropped mid-session (host crashed / was killed). Fall back to\n * the in-process backend so future create()s work, and toast. Existing windows'\n * ptys are gone, but the app keeps running; a remount spawns fresh in-process.\n */\nfunction onHostError(err: Error): void {\n if (!usingHost) return;\n // eslint-disable-next-line no-console\n console.error('[host-lifecycle] host connection lost:', err.message);\n usingHost = false;\n client = null;\n setActiveBackend(inProcessBackend());\n status(\n 'Detached terminal host stopped — switched to in-process. Open terminals may need reopening.',\n );\n}\n\n/**\n * before-quit, host-backed: DO NOT kill the host ptys. Snapshot (T1) already ran\n * via the normal before-quit path; here we just disconnect the client and leave\n * the host running so the next launch reattaches.\n */\nexport function disconnectHostLeaveRunning(): void {\n if (client) {\n try {\n client.disconnect();\n } catch {\n /* ignore */\n }\n }\n}\n","import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { resolveHostScript } from './host-locate';\n\n/**\n * Absolute path to the bundled detached pty-host script (Tier 3), so a\n * `HostSpawner` can launch it as a detached child without knowing this\n * package's dist layout:\n *\n * ```ts\n * import { spawn } from 'node:child_process';\n * import { ptyHostScriptPath } from '@particle-academy/fancy-term-host';\n *\n * const child = spawn(process.execPath, [ptyHostScriptPath(), userDataDir], {\n * detached: true, stdio: 'ignore',\n * });\n * child.unref();\n * ```\n *\n * The host script is emitted alongside this module in `dist/` as\n * `pty-host.js`. Works in both the ESM and CJS builds (esbuild fills in\n * `import.meta.url` for the CJS output; `__dirname` is used when present).\n */\nexport function ptyHostScriptPath(): string {\n const here =\n typeof __dirname !== 'undefined'\n ? __dirname\n : path.dirname(fileURLToPath(import.meta.url));\n // Reuse host-locate's candidate logic (handles dev/packaged layouts); fall\n // back to the expected emitted location if the existence probe misses.\n return resolveHostScript(here) ?? path.join(here, 'pty-host.js');\n}\n"]}
|