adhdev 1.0.82-rc.24 → 1.0.82-rc.25

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/guardian-artifact.ts","../src/server.ts","../src/runtime.ts","../src/upgrade-lease.ts","../src/storage.ts","../src/session-diagnostics.ts","../src/session-lifecycle.ts","../src/session-protocol.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { randomUUID } from 'crypto';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n SessionHostClient,\n formatRuntimeOwner,\n getDefaultSessionHostEndpoint,\n resolveAttachableRuntimeRecord,\n resolveInstanceConfigDir,\n resolveRuntimeRecord,\n resolveSessionHostIpcKey,\n type SessionHostEvent,\n type SessionHostRecord,\n} from '@adhdev/session-host-core';\nimport { resolveGuardianArtifact, type GuardianArtifactPins } from './guardian-artifact.js';\nimport { SessionHostServer } from './server.js';\n\nexport { SessionHostServer } from './server.js';\nexport type { SessionHostServerOptions } from './server.js';\nexport { resolveGuardianArtifact } from './guardian-artifact.js';\nexport type { GuardianArtifactPins } from './guardian-artifact.js';\nexport type { HostUpgradeBinding } from './upgrade-lease.js';\n\nconst SESSION_HOST_APP_NAME = process.env.ADHDEV_SESSION_HOST_NAME || 'adhdev';\n\n// Instance identity comes from the parent daemon's pinned env\n// (ADHDEV_CONFIG_DIR — see managed-host buildEnv). The endpoint, pid file, and\n// storage root all derive from that ONE resolution so the host process lives\n// entirely inside its own instance's namespace: two simultaneous instances\n// (stable/preview/standalone/custom) can never attach to, kill, or persist\n// over each other's session host. The default instance yields the legacy\n// un-suffixed socket and `<home>/.adhdev` paths, byte-identical to before.\nconst INSTANCE_CONFIG_DIR = resolveInstanceConfigDir(process.env);\nconst INSTANCE_IPC_KEY = resolveSessionHostIpcKey(INSTANCE_CONFIG_DIR);\n\nfunction getSessionHostEndpoint() {\n return getDefaultSessionHostEndpoint(SESSION_HOST_APP_NAME, { ipcKey: INSTANCE_IPC_KEY });\n}\n\nfunction getSessionHostStorageRoot(): string {\n return path.join(INSTANCE_CONFIG_DIR, 'session-host', SESSION_HOST_APP_NAME);\n}\n\nfunction getSessionHostPidFile(appName: string): string {\n const dir = INSTANCE_CONFIG_DIR;\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n return path.join(dir, `${appName}-session-host.pid`);\n}\n\nfunction writeSessionHostPid(appName: string): void {\n fs.writeFileSync(getSessionHostPidFile(appName), String(process.pid), 'utf8');\n}\n\nfunction removeSessionHostPid(appName: string): void {\n try {\n fs.unlinkSync(getSessionHostPidFile(appName));\n } catch {\n // noop\n }\n}\n\nfunction parseArgs(argv: string[]) {\n const [command, ...rest] = argv;\n const readOnly = rest.includes('--read-only');\n const takeover = rest.includes('--takeover');\n const showAll = rest.includes('--all');\n const positional = rest.filter((arg) => arg !== '--read-only' && arg !== '--takeover' && arg !== '--all');\n return {\n command: command || 'serve',\n positional,\n readOnly,\n takeover,\n showAll,\n };\n}\n\nasync function runServer(): Promise<void> {\n let upgradeBinding;\n const pinFile = process.env.ADHDEV_WORKER_GUARDIAN_PINS_FILE;\n if (pinFile) {\n const stat = fs.lstatSync(pinFile);\n if (process.platform !== 'darwin' || fs.realpathSync(pinFile) !== pinFile || !stat.isFile() || stat.uid !== process.getuid?.() || (stat.mode & 0o077)) throw new Error('guardian_launch_pins_untrusted');\n const pins = JSON.parse(fs.readFileSync(pinFile, 'utf8')) as GuardianArtifactPins;\n if (pins.nodePath !== fs.realpathSync(process.execPath) || pins.hostEntryPath !== fs.realpathSync(process.argv[1]) ||\n pins.stateDir !== path.join(INSTANCE_CONFIG_DIR, 'session-host')) throw new Error('guardian_launch_executable_or_instance_mismatch');\n upgradeBinding = resolveGuardianArtifact(pins);\n }\n const server = new SessionHostServer({\n appName: SESSION_HOST_APP_NAME,\n upgradeBinding,\n endpoint: getSessionHostEndpoint(),\n storageRootDir: getSessionHostStorageRoot(),\n });\n if (!upgradeBinding) writeSessionHostPid(SESSION_HOST_APP_NAME);\n await server.start();\n if (upgradeBinding) writeSessionHostPid(SESSION_HOST_APP_NAME);\n\n process.on('SIGINT', async () => {\n await server.stop();\n removeSessionHostPid(SESSION_HOST_APP_NAME);\n process.exit(0);\n });\n\n process.on('SIGTERM', async () => {\n await server.stop();\n removeSessionHostPid(SESSION_HOST_APP_NAME);\n process.exit(0);\n });\n\n // Fallback: flush persistence on any exit (covers Windows where SIGTERM is unsupported)\n process.on('exit', () => {\n server.flushAllPersistence();\n removeSessionHostPid(SESSION_HOST_APP_NAME);\n });\n\n // Keep the host alive; IPC transport wiring comes next.\n await new Promise<void>(() => {});\n}\n\nasync function listRuntimes(showAll = false): Promise<void> {\n const client = new SessionHostClient({ endpoint: getSessionHostEndpoint() });\n try {\n const response = await client.request<SessionHostRecord[]>({\n type: 'list_sessions',\n payload: {},\n });\n if (!response.success) {\n throw new Error(response.error || 'Failed to list runtimes');\n }\n const runtimes = (response.result || []).filter((runtime: SessionHostRecord) => showAll || runtime.lifecycle !== 'stopped');\n if (runtimes.length === 0) {\n console.log('No runtimes.');\n return;\n }\n console.log('runtimeKey\\tlifecycle\\towner\\tworkspace\\tid\\tdisplayName');\n for (const runtime of runtimes) {\n console.log([\n runtime.runtimeKey,\n runtime.lifecycle,\n formatRuntimeOwner(runtime),\n runtime.workspaceLabel,\n runtime.sessionId,\n runtime.displayName,\n ].join('\\t'));\n }\n } finally {\n await client.close().catch(() => {});\n }\n}\n\nasync function attachRuntime(target: string, readOnly = false, takeover = false): Promise<void> {\n const client = new SessionHostClient({ endpoint: getSessionHostEndpoint() });\n const clientId = `local-terminal-${process.pid}-${randomUUID().slice(0, 8)}`;\n let lastSeq = 0;\n let restoredRawMode = false;\n let runtimeId = '';\n let localReadOnly = readOnly;\n\n const cleanup = async () => {\n process.stdout.off('resize', handleResize);\n process.stdin.off('data', handleInput);\n process.stdin.pause();\n if (process.stdin.isTTY && restoredRawMode) {\n process.stdin.setRawMode(false);\n }\n await client.request({\n type: 'release_write',\n payload: {\n sessionId: runtimeId,\n clientId,\n },\n }).catch(() => ({ success: false }));\n await client.request({\n type: 'detach_session',\n payload: {\n sessionId: runtimeId,\n clientId,\n },\n }).catch(() => ({ success: false }));\n await client.close().catch(() => {});\n };\n\n const handleResize = () => {\n void client.request({\n type: 'resize_session',\n payload: {\n sessionId: runtimeId,\n cols: process.stdout.columns || 80,\n rows: process.stdout.rows || 24,\n },\n }).catch(() => ({ success: false }));\n };\n\n const sendInputWithTakeover = async (data: string) => {\n let response = await client.request({\n type: 'send_input',\n payload: {\n sessionId: runtimeId,\n clientId,\n data,\n },\n });\n if (!response.success && response.error?.startsWith('Write owned by ')) {\n const ownerResponse = await client.request<SessionHostRecord>({\n type: 'acquire_write',\n payload: {\n sessionId: runtimeId,\n clientId,\n ownerType: 'user',\n force: true,\n },\n });\n if (ownerResponse.success && ownerResponse.result) {\n response = await client.request({\n type: 'send_input',\n payload: {\n sessionId: runtimeId,\n clientId,\n data,\n },\n });\n if (response.success) {\n process.stderr.write(`Took control of ${ownerResponse.result.runtimeKey}.\\n`);\n }\n }\n }\n return response;\n };\n\n const handleInput = (chunk: Buffer) => {\n if (!localReadOnly && chunk.length === 1 && chunk[0] === 0x1d) {\n void cleanup().finally(() => process.exit(0));\n return;\n }\n if (localReadOnly) return;\n void sendInputWithTakeover(chunk.toString('utf8')).catch(() => ({ success: false }));\n };\n\n try {\n if (readOnly && takeover) {\n throw new Error('Use either --read-only or --takeover, not both');\n }\n\n const listResponse = await client.request<SessionHostRecord[]>({\n type: 'list_sessions',\n payload: {},\n });\n if (!listResponse.success || !listResponse.result) {\n throw new Error(listResponse.error || 'Failed to list runtimes');\n }\n let runtimeRecord = resolveAttachableRuntimeRecord(listResponse.result, target);\n runtimeId = runtimeRecord.sessionId;\n\n if (runtimeRecord.lifecycle === 'interrupted' && !readOnly) {\n const resumeResponse = await client.request<SessionHostRecord>({\n type: 'resume_session',\n payload: {\n sessionId: runtimeId,\n },\n });\n if (resumeResponse.success && resumeResponse.result) {\n runtimeRecord = resumeResponse.result;\n } else {\n process.stderr.write(\n `Runtime ${runtimeRecord.runtimeKey} could not be resumed automatically: ${resumeResponse.error || 'unknown error'}\\n`,\n );\n }\n }\n\n let effectiveReadOnly = readOnly;\n if (!effectiveReadOnly && runtimeRecord.writeOwner && runtimeRecord.writeOwner.clientId !== clientId && !takeover) {\n process.stderr.write(\n `Runtime ${runtimeRecord.runtimeKey} is currently owned by ${runtimeRecord.writeOwner.clientId}; first input will take control here.\\n`,\n );\n }\n localReadOnly = effectiveReadOnly;\n\n const attachResponse = await client.request<SessionHostRecord>({\n type: 'attach_session',\n payload: {\n sessionId: runtimeId,\n clientId,\n clientType: 'local-terminal',\n readOnly: effectiveReadOnly,\n },\n });\n if (!attachResponse.success) {\n throw new Error(attachResponse.error || `Failed to attach runtime ${runtimeId}`);\n }\n const attachedRecord = attachResponse.result || null;\n\n if (!effectiveReadOnly && takeover) {\n const ownerResponse = await client.request<SessionHostRecord>({\n type: 'acquire_write',\n payload: {\n sessionId: runtimeId,\n clientId,\n ownerType: 'user',\n force: takeover,\n },\n });\n if (!ownerResponse.success) {\n throw new Error(ownerResponse.error || `Failed to acquire write owner for runtime ${runtimeId}`);\n }\n }\n\n const snapshotResponse = await client.request<{ seq: number; text: string; truncated: boolean; cols?: number; rows?: number }>({\n type: 'get_snapshot',\n payload: { sessionId: runtimeId },\n });\n if (!snapshotResponse.success) {\n throw new Error(snapshotResponse.error || `Failed to read runtime snapshot ${runtimeId}`);\n }\n lastSeq = snapshotResponse.result?.seq || 0;\n if (snapshotResponse.result?.text) {\n process.stdout.write(snapshotResponse.result.text);\n }\n if (attachedRecord?.lifecycle === 'stopped' || attachedRecord?.lifecycle === 'failed' || attachedRecord?.lifecycle === 'interrupted') {\n process.stderr.write(`Runtime ${attachedRecord.runtimeKey} is already ${attachedRecord.lifecycle}. Detached after snapshot.\\n`);\n await cleanup();\n return;\n }\n\n const stopSignals = ['SIGINT', 'SIGTERM', 'SIGHUP'] as const;\n const signalHandlers = stopSignals.map((signal) => {\n const handler = () => {\n void cleanup().finally(() => process.exit(0));\n };\n process.on(signal, handler);\n return { signal, handler };\n });\n\n const unsubscribe = client.onEvent((event: SessionHostEvent) => {\n if (!('sessionId' in event)) return;\n if (event.sessionId !== runtimeId) return;\n if (event.type === 'session_output') {\n if (event.seq <= lastSeq) return;\n lastSeq = event.seq;\n process.stdout.write(event.data);\n return;\n }\n if (event.type === 'session_exit') {\n void cleanup().finally(() => {\n for (const { signal, handler } of signalHandlers) {\n process.off(signal, handler);\n }\n unsubscribe();\n process.exit(event.exitCode ?? 0);\n });\n }\n });\n\n process.stdout.on('resize', handleResize);\n process.stdin.on('data', handleInput);\n process.stdin.resume();\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n restoredRawMode = true;\n }\n handleResize();\n if (!effectiveReadOnly) {\n process.stderr.write(`Attached to runtime ${attachedRecord?.runtimeKey || runtimeId}. Press Ctrl+] to detach.\\n`);\n } else {\n process.stderr.write(`Attached to runtime ${attachedRecord?.runtimeKey || runtimeId} (read-only).\\n`);\n }\n await new Promise<void>(() => {});\n } catch (error) {\n await cleanup().catch(() => {});\n throw error;\n }\n}\n\nasync function main(): Promise<void> {\n const { command, positional, readOnly, takeover, showAll } = parseArgs(process.argv.slice(2));\n if (command === 'serve') {\n await runServer();\n return;\n }\n if (command === 'list') {\n await listRuntimes(showAll);\n return;\n }\n if (command === 'attach') {\n const target = positional[0];\n if (!target) {\n throw new Error('runtime target is required: adhdev-sessiond attach <runtimeId|runtimeKey>');\n }\n await attachRuntime(target, readOnly, takeover);\n return;\n }\n if (command === 'resume') {\n const target = positional[0];\n if (!target) {\n throw new Error('runtime target is required: adhdev-sessiond resume <runtimeId|runtimeKey>');\n }\n const client = new SessionHostClient({ endpoint: getSessionHostEndpoint() });\n try {\n const listResponse = await client.request<SessionHostRecord[]>({ type: 'list_sessions', payload: {} });\n if (!listResponse.success || !listResponse.result) {\n throw new Error(listResponse.error || 'Failed to list runtimes');\n }\n const runtimeRecord = resolveRuntimeRecord(listResponse.result, target);\n const resumeResponse = await client.request<SessionHostRecord>({\n type: 'resume_session',\n payload: {\n sessionId: runtimeRecord.sessionId,\n },\n });\n if (!resumeResponse.success || !resumeResponse.result) {\n throw new Error(resumeResponse.error || `Failed to resume runtime ${runtimeRecord.runtimeKey}`);\n }\n console.log(`Resumed ${resumeResponse.result.runtimeKey} (${resumeResponse.result.sessionId})`);\n } finally {\n await client.close().catch(() => {});\n }\n return;\n }\n throw new Error(`Unknown command: ${command}`);\n}\n\n// Swallowing uncaught exceptions keeps a transient native fault (e.g. node-pty on\n// Windows) from killing sessions that are otherwise healthy. Swallowing them\n// *without limit* turns a permanently broken process into a zombie service that\n// still holds the socket and pid file while failing every request. So the intent\n// is preserved with a bound: tolerate bursts, exit once the process is clearly\n// wedged rather than pretending to serve.\nconst UNCAUGHT_EXCEPTION_WINDOW_MS = 60_000;\nconst UNCAUGHT_EXCEPTION_LIMIT = 10;\n\nexport function createUncaughtExceptionLimiter(\n windowMs = UNCAUGHT_EXCEPTION_WINDOW_MS,\n limit = UNCAUGHT_EXCEPTION_LIMIT,\n) {\n // null (not 0) marks \"no window yet\" — 0 is a valid timestamp, and using it as\n // the sentinel would reset the window on every call in a 0-based clock.\n let windowStartedAt: number | null = null;\n let countInWindow = 0;\n return function shouldExit(now: number): { exit: boolean; countInWindow: number } {\n if (windowStartedAt === null || now - windowStartedAt > windowMs) {\n windowStartedAt = now;\n countInWindow = 0;\n }\n countInWindow += 1;\n return { exit: countInWindow > limit, countInWindow };\n };\n}\n\nif (require.main === module) {\n const shouldExitOnUncaught = createUncaughtExceptionLimiter();\n\n process.on('uncaughtException', (err) => {\n console.error(`[session-host] Uncaught exception: ${err?.message}\\n${err?.stack || ''}`);\n const { exit, countInWindow } = shouldExitOnUncaught(Date.now());\n if (!exit) return;\n // Repeated faults in one window: the process is wedged, not hiccuping.\n console.error(\n `[session-host] ${countInWindow} uncaught exceptions within ` +\n `${UNCAUGHT_EXCEPTION_WINDOW_MS / 1000}s (limit ${UNCAUGHT_EXCEPTION_LIMIT}); shutting down.`,\n );\n removeSessionHostPid(SESSION_HOST_APP_NAME);\n process.exit(1);\n });\n process.on('unhandledRejection', (reason: any) => {\n console.error(`[session-host] Unhandled rejection: ${reason?.message || reason}`);\n });\n\n void main().catch((error) => {\n console.error(error instanceof Error ? error.message : error);\n process.exit(1);\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { createHash } from 'node:crypto';\nimport type { HostUpgradeBinding } from './upgrade-lease.js';\nconst sha = (b: string | Buffer) => createHash('sha256').update(b).digest('hex');\nexport interface GuardianArtifactPins {\n packageRoot: string;\n manifestPath: string;\n manifestSha256: string;\n version: string;\n commit: string;\n nodePath: string;\n daemonEntryPath: string;\n cliEntryPath: string;\n hostEntryPath: string;\n stateDir: string;\n}\n/** The manifest pin must come from the supervisor's immutable artifact plan. */\nexport function resolveGuardianArtifact(pins: GuardianArtifactPins): HostUpgradeBinding {\n if (process.platform !== 'darwin') throw new Error('guardian_artifact_platform_unsupported');\n const root = fs.realpathSync(pins.packageRoot);\n const regular = (file: string) => {\n if (!path.isAbsolute(file) || fs.realpathSync(file) !== file || !fs.lstatSync(file).isFile()) throw new Error('guardian_artifact_path_untrusted');\n return file;\n };\n const manifestPath = regular(pins.manifestPath);\n if (path.relative(root, manifestPath).startsWith('..')) throw new Error('guardian_artifact_manifest_escape');\n const bytes = fs.readFileSync(manifestPath);\n if (!/^[a-f0-9]{64}$/.test(pins.manifestSha256) || sha(bytes) !== pins.manifestSha256) throw new Error('guardian_artifact_manifest_pin_mismatch');\n const m = JSON.parse(String(bytes));\n if (m.schema !== 1 || m.protocol !== 1 || m.platform !== 'darwin' || m.arch !== process.arch || m.version !== pins.version || m.commit !== pins.commit) throw new Error('guardian_artifact_build_mismatch');\n const packageBytes=fs.readFileSync(regular(path.join(root,'package.json')));\n if (sha(packageBytes)!==m.packageJsonSha256 || JSON.parse(String(packageBytes)).version!==pins.version) throw new Error('guardian_artifact_package_version_mismatch');\n const expected = { daemon:pins.daemonEntryPath, cli:pins.cliEntryPath, host:pins.hostEntryPath };\n for (const kind of ['daemon','cli','host','helper'] as const) {\n const entry = m.files?.[kind];\n if (typeof entry?.path !== 'string' || path.isAbsolute(entry.path) || !/^[a-f0-9]{64}$/.test(entry.sha256 ?? '')) throw new Error('guardian_artifact_entry_untrusted');\n const file = path.resolve(root, entry.path);\n if (path.relative(root,file).startsWith('..') || (kind !== 'helper' && file !== expected[kind]) || sha(fs.readFileSync(regular(file))) !== entry.sha256) throw new Error('guardian_artifact_payload_pin_mismatch');\n }\n if (sha(fs.readFileSync(regular(pins.nodePath))) !== m.nodeSha256) throw new Error('guardian_artifact_node_pin_mismatch');\n const helperStat=fs.lstatSync(path.resolve(root,m.files.helper.path));\n if (helperStat.mode & 0o222) throw new Error('guardian_artifact_helper_writable');\n return { helperFileIdentity:JSON.stringify([helperStat.dev,helperStat.ino,helperStat.uid,helperStat.mode,helperStat.size]), helperPath:path.resolve(root,m.files.helper.path), helperSha256:m.files.helper.sha256, stateDir:pins.stateDir, helperProtocol:1 };\n}\n","import { EventEmitter } from 'events';\nimport * as fs from 'fs';\nimport * as net from 'net';\nimport * as path from 'node:path';\nimport {\n SessionHostRegistry,\n classifyTermination,\n createLineParser,\n createResponseEnvelope,\n getDefaultSessionHostEndpoint,\n isTerminalRecord,\n} from '@adhdev/session-host-core';\nimport type {\n CreateSessionPayload,\n SessionAttachedClient,\n SessionHostDiagnostics,\n SessionHostEndpoint,\n SessionHostEvent,\n SessionHostLogEntry,\n SessionHostPruneDuplicatesResult,\n SessionHostRecord,\n SessionHostRequestEnvelope,\n SessionHostRequestTrace,\n SessionHostRequest,\n SessionHostRuntimeTransition,\n SessionHostResponse,\n SessionTermination,\n} from '@adhdev/session-host-core';\nimport { PtySessionRuntime } from './runtime.js';\nimport { HostUpgradeLease, type HostUpgradeBinding } from './upgrade-lease.js';\nimport { SessionHostStorage } from './storage.js';\nimport {\n buildHostDiagnostics,\n pushRecent,\n} from './session-diagnostics.js';\nimport {\n buildPayloadFromRecord,\n buildRecoveredRecord,\n planDuplicatePrune,\n} from './session-lifecycle.js';\nimport {\n getRequestClientId,\n getRequestSessionId,\n mergeRuntimeSnapshot,\n} from './session-protocol.js';\n\nexport interface SessionHostServerOptions {\n endpoint?: SessionHostEndpoint;\n /** Opt-in pinned native binding; absent hosts cannot attest an upgrade idle lease. */\n upgradeBinding?: HostUpgradeBinding;\n appName?: string;\n /** Explicit session-host state root (runtime records + tombstones). */\n storageRootDir?: string;\n}\n\nexport class SessionHostServer extends EventEmitter {\n readonly endpoint: SessionHostEndpoint;\n readonly registry = new SessionHostRegistry();\n private runtimes = new Map<string, PtySessionRuntime>();\n private readonly storage: SessionHostStorage;\n private readonly upgradeLease: HostUpgradeLease | null;\n private restorePending = true;\n private mutatingRequests = 0;\n private endpointInode: bigint | null = null;\n private ipcServer: net.Server | null = null;\n private sockets = new Set<net.Socket>();\n // Tracks which sessionIds each socket has subscribed to (via create/attach).\n // Used to avoid broadcasting session-specific events to uninterested sockets.\n private socketSessions = new Map<net.Socket, Set<string>>();\n private persistTimers = new Map<string, NodeJS.Timeout>();\n private readonly startedAt = Date.now();\n private recentLogs: SessionHostLogEntry[] = [];\n private recentRequests: SessionHostRequestTrace[] = [];\n private recentTransitions: SessionHostRuntimeTransition[] = [];\n private exitWaiters = new Map<string, Array<(exitCode: number | null) => void>>();\n private lastNoOutputInputWarnAt = new Map<string, number>();\n // Records the most recent explicit stop/delete/restart/prune request per\n // session so the termination diagnostic can attribute the exit to it.\n private stopRequests = new Map<string, SessionTermination['requestedStop']>();\n // Shutdown is driven by independent SIGINT/SIGTERM handlers, so stop() can be\n // entered twice. Cache the in-flight promise and hand it to every later caller\n // instead of re-running flushAllPersistence()/runtime.stop() on already-cleared state.\n private stopPromise: Promise<void> | null = null;\n\n constructor(options: SessionHostServerOptions = {}) {\n super();\n this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || 'adhdev');\n if (options.upgradeBinding) {\n const relative = options.storageRootDir && path.relative(options.upgradeBinding.stateDir, options.storageRootDir);\n if (this.endpoint.kind !== 'unix' || !options.storageRootDir || !path.isAbsolute(options.storageRootDir) ||\n !path.isAbsolute(options.upgradeBinding.stateDir) || relative === '..' || relative?.startsWith(`..${path.sep}`) || path.isAbsolute(relative || '')) {\n throw new Error('native_host_instance_storage_binding_required');\n }\n }\n this.upgradeLease = options.upgradeBinding\n ? new HostUpgradeLease(options.upgradeBinding, this.endpoint.path) : null;\n this.storage = new SessionHostStorage({\n appName: options.appName || 'adhdev',\n rootDir: options.storageRootDir,\n });\n }\n\n async start(): Promise<void> {\n if (this.upgradeLease) {\n await this.upgradeLease.start();\n // A stale socket requires separate native ownership recovery; never unlink on assertion.\n if (fs.existsSync(this.endpoint.path)) {\n await this.upgradeLease.close();\n throw new Error('native_host_endpoint_owner_unproved');\n }\n }\n if (!this.upgradeLease && this.endpoint.kind === 'unix') {\n try {\n fs.unlinkSync(this.endpoint.path);\n } catch {\n // noop\n }\n }\n\n this.ipcServer = net.createServer((socket) => {\n this.sockets.add(socket);\n // PARSER-EOF-FLUSH: hold the parser reference so `end()` is reachable.\n // Passing `createLineParser(...)` inline to `socket.on('data', ...)` threw\n // the handle away, which left the decoder's EOF flush permanently\n // unreachable — bytes held back as an incomplete UTF-8 sequence when the\n // peer disconnected simply vanished with the decoder.\n const parser = createLineParser((envelope) => {\n if (envelope.kind !== 'request') return;\n void this.handleIncomingRequest(socket, envelope);\n });\n const flushParser = () => {\n // The remainder is by definition a PARTIAL line — envelopes are\n // newline-framed, so an unterminated tail is a truncated transmission,\n // not a message. It is logged, never parsed: JSON.parse on a\n // half-written envelope inside a socket-close handler would raise an\n // uncaught exception and turn a peer that died mid-write into a crash\n // of the daemon observing it. That refusal is the original author's\n // design, preserved here.\n let remainder = '';\n try {\n remainder = parser.end();\n } catch {\n return;\n }\n if (!remainder.trim()) return;\n this.recordHostLog(\n 'warn',\n `session host discarded ${remainder.length} bytes of an incomplete IPC frame at EOF`,\n );\n };\n const removeSocket = () => {\n this.sockets.delete(socket);\n this.socketSessions.delete(socket);\n };\n // Flush before the socket bookkeeping so the remainder is reported even\n // if a later handler throws. `end()` clears its own buffer, so the\n // close-after-end sequence flushes once and then sees an empty tail.\n socket.on('close', () => {\n flushParser();\n removeSocket();\n });\n socket.on('end', () => {\n flushParser();\n removeSocket();\n });\n socket.on('error', () => {\n flushParser();\n removeSocket();\n try {\n socket.destroy();\n } catch {\n // noop\n }\n });\n socket.on('data', parser);\n });\n\n try {\n await new Promise<void>((resolve, reject) => {\n this.ipcServer?.once('listening', () => resolve());\n this.ipcServer?.once('error', reject);\n this.ipcServer?.listen(this.endpoint.path);\n });\n } catch (error) {\n await this.upgradeLease?.close();\n throw error;\n }\n\n if (this.upgradeLease && this.endpoint.kind === 'unix') {\n fs.chmodSync(this.endpoint.path, 0o600);\n this.endpointInode = fs.lstatSync(this.endpoint.path, { bigint: true }).ino;\n }\n this.recordHostLog('info', `session host endpoint ready: ${this.endpoint.path}`);\n // Do not block readiness on restoring/resuming persisted runtimes.\n // Startup callers only need the IPC endpoint to accept connections.\n setTimeout(() => {\n try {\n if (!this.upgradeLease?.proof().held) this.restorePersistedRuntimes();\n } catch (error: any) {\n this.recordHostLog('error', `session host restore failed: ${error?.message || String(error)}`);\n } finally { this.restorePending = false; }\n }, 0);\n }\n\n async stop(): Promise<void> {\n if (this.stopPromise) return this.stopPromise;\n this.stopPromise = this.runStop();\n return this.stopPromise;\n }\n\n private async runStop(): Promise<void> {\n this.flushAllPersistence();\n for (const runtime of this.runtimes.values()) {\n try {\n runtime.stop();\n } catch {\n // noop\n }\n }\n this.runtimes.clear();\n for (const timer of this.persistTimers.values()) {\n clearTimeout(timer);\n }\n this.persistTimers.clear();\n for (const socket of this.sockets) {\n socket.destroy();\n }\n this.sockets.clear();\n this.socketSessions.clear();\n if (this.ipcServer) {\n const server = this.ipcServer;\n this.ipcServer = null;\n await new Promise<void>((resolve) => server.close(() => resolve()));\n }\n if (this.endpoint.kind === 'unix') {\n try {\n if (!this.upgradeLease || fs.lstatSync(this.endpoint.path, { bigint: true }).ino === this.endpointInode) fs.unlinkSync(this.endpoint.path);\n } catch {\n // A replacement endpoint belongs to someone else.\n }\n }\n await this.upgradeLease?.close();\n this.removeAllListeners();\n }\n\n async handleRequest(request: SessionHostRequest): Promise<SessionHostResponse> {\n const readOnly = ['get_upgrade_lease', 'acquire_upgrade_lease', 'release_upgrade_lease', 'get_host_diagnostics', 'list_sessions', 'get_snapshot', 'get_terminal_snapshot'].includes(request.type);\n let counted = false;\n try {\n if (!readOnly) {\n this.upgradeLease?.assertMutable();\n this.mutatingRequests++;\n counted = true;\n }\n switch (request.type) {\n case 'get_upgrade_lease':\n if (!this.upgradeLease) throw new Error('native_host_upgrade_binding_unavailable');\n return { success: true, result: this.upgradeLease.proof() };\n case 'acquire_upgrade_lease':\n if (!this.upgradeLease) throw new Error('native_host_upgrade_binding_unavailable');\n return { success: true, result: this.upgradeLease.acquire(request.payload,\n !this.restorePending && this.mutatingRequests === 0 && this.runtimes.size === 0 &&\n this.registry.listSessions().length === 0 && !this.storage.hasRuntimeEntries()) };\n case 'release_upgrade_lease':\n if (!this.upgradeLease) throw new Error('native_host_upgrade_binding_unavailable');\n return { success: true, result: this.upgradeLease.release(request.payload) };\n case 'create_session': {\n const record = this.registry.createSession(request.payload);\n this.schedulePersist(record.sessionId);\n this.emitEvent({ type: 'session_created', sessionId: record.sessionId, record });\n this.recordRuntimeTransition(record.sessionId, 'create_session', 'starting', `provider=${record.providerType}`, true);\n try {\n const startedRecord = this.startRuntime(record, request.payload, 'session_started');\n return { success: true, result: startedRecord };\n } catch (error: any) {\n this.registry.markStopped(record.sessionId, 'failed');\n this.persistNow(record.sessionId);\n this.recordRuntimeTransition(record.sessionId, 'create_session_failed', 'failed', undefined, false, error?.message || String(error));\n return { success: false, error: error?.message || String(error) };\n }\n }\n case 'list_sessions':\n return { success: true, result: this.registry.listSessions() };\n case 'attach_session': {\n const record = this.registry.attachClient(request.payload);\n this.schedulePersist(record.sessionId);\n const client = record.attachedClients.find(item => item.clientId === request.payload.clientId);\n if (client) {\n this.emitEvent({ type: 'client_attached', sessionId: record.sessionId, client });\n }\n this.recordRuntimeTransition(record.sessionId, 'attach_client', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n case 'detach_session': {\n const record = this.registry.detachClient(request.payload);\n this.schedulePersist(record.sessionId);\n this.emitEvent({ type: 'client_detached', sessionId: record.sessionId, clientId: request.payload.clientId });\n this.recordRuntimeTransition(record.sessionId, 'detach_client', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n case 'acquire_write': {\n const record = this.registry.acquireWrite(request.payload);\n this.persistNow(record.sessionId);\n this.emitEvent({ type: 'write_owner_changed', sessionId: record.sessionId, owner: record.writeOwner });\n this.recordRuntimeTransition(record.sessionId, 'acquire_write', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n case 'release_write': {\n const record = this.registry.releaseWrite(request.payload);\n this.persistNow(record.sessionId);\n this.emitEvent({ type: 'write_owner_changed', sessionId: record.sessionId, owner: record.writeOwner });\n this.recordRuntimeTransition(record.sessionId, 'release_write', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n case 'get_snapshot':\n return { success: true, result: await this.getSnapshotForRequest(request.payload.sessionId, request.payload.sinceSeq) };\n case 'get_terminal_snapshot':\n return { success: true, result: await this.requireRuntime(request.payload.sessionId).getTerminalSnapshot() };\n case 'get_host_diagnostics':\n return { success: true, result: this.getHostDiagnostics(request.payload) };\n case 'clear_session_buffer': {\n const record = this.registry.clearBuffer(request.payload.sessionId);\n this.persistNow(record.sessionId);\n this.emitEvent({ type: 'session_cleared', sessionId: record.sessionId });\n this.recordRuntimeTransition(record.sessionId, 'clear_buffer', record.lifecycle, undefined, true);\n return { success: true, result: record };\n }\n case 'update_session_meta': {\n const record = this.registry.updateSessionMeta(\n request.payload.sessionId,\n request.payload.meta || {},\n request.payload.replace === true,\n );\n this.persistNow(record.sessionId);\n this.recordRuntimeTransition(record.sessionId, 'update_meta', record.lifecycle, undefined, true);\n return { success: true, result: record };\n }\n case 'send_input': {\n const client = this.getAttachedClient(request.payload.sessionId, request.payload.clientId);\n if (client?.readOnly) {\n return { success: false, error: `Client ${request.payload.clientId} is read-only` };\n }\n const session = this.registry.getSession(request.payload.sessionId);\n if (session?.writeOwner && session.writeOwner.clientId !== request.payload.clientId) {\n return { success: false, error: `Write owned by ${session.writeOwner.clientId}` };\n }\n const runtime = this.requireRuntime(request.payload.sessionId);\n const beforeSnapshotSeq = this.registry.getSnapshot(request.payload.sessionId)?.seq ?? 0;\n runtime.write(request.payload.data);\n this.scheduleNoOutputInputDiagnostic({\n sessionId: request.payload.sessionId,\n clientId: request.payload.clientId,\n input: request.payload.data,\n beforeSnapshotSeq,\n });\n return { success: true, result: this.registry.getSession(request.payload.sessionId) };\n }\n case 'resize_session': {\n this.requireRuntime(request.payload.sessionId).resize(request.payload.cols, request.payload.rows);\n const record = this.registry.getSession(request.payload.sessionId);\n if (record) {\n this.registry.restoreSession(\n {\n ...record,\n meta: {\n ...(record.meta || {}),\n sessionHostCols: request.payload.cols,\n sessionHostRows: request.payload.rows,\n },\n },\n this.registry.getSnapshot(request.payload.sessionId),\n );\n }\n this.schedulePersist(request.payload.sessionId);\n this.emitEvent({\n type: 'session_resized',\n sessionId: request.payload.sessionId,\n cols: request.payload.cols,\n rows: request.payload.rows,\n });\n return { success: true, result: this.registry.getSession(request.payload.sessionId) };\n }\n case 'stop_session': {\n this.stopRequests.set(request.payload.sessionId, 'stop');\n this.registry.setLifecycle(request.payload.sessionId, 'stopping');\n this.persistNow(request.payload.sessionId);\n this.requireRuntime(request.payload.sessionId).stop();\n this.emitEvent({ type: 'session_stopped', sessionId: request.payload.sessionId });\n this.recordRuntimeTransition(request.payload.sessionId, 'stop_session', 'stopping', undefined, true);\n return { success: true, result: this.registry.getSession(request.payload.sessionId) };\n }\n case 'delete_session': {\n const record = this.registry.getSession(request.payload.sessionId);\n if (!record) return { success: false, error: `Unknown session: ${request.payload.sessionId}` };\n if (this.runtimes.has(record.sessionId)) {\n if (!request.payload.force) {\n return { success: false, error: `Session ${record.sessionId} is still running; pass force to stop and delete it` };\n }\n this.stopRequests.set(record.sessionId, 'delete');\n this.registry.setLifecycle(record.sessionId, 'stopping');\n this.persistNow(record.sessionId);\n this.requireRuntime(record.sessionId).stop();\n await this.waitForRuntimeExit(record.sessionId).catch((error: any) => {\n this.recordRuntimeTransition(record.sessionId, 'delete_session_timeout', 'stopping', undefined, false, error?.message || String(error));\n });\n }\n this.registry.deleteSession(record.sessionId);\n this.storage.remove(record.sessionId);\n this.storage.removeTombstone(record.sessionId);\n this.stopRequests.delete(record.sessionId);\n this.emitEvent({ type: 'session_deleted', sessionId: record.sessionId });\n this.recordRuntimeTransition(record.sessionId, 'delete_session', record.lifecycle, undefined, true);\n return { success: true, result: { sessionId: record.sessionId, deleted: true } };\n }\n case 'resume_session': {\n const existing = this.registry.getSession(request.payload.sessionId);\n if (!existing) {\n return { success: false, error: `Unknown session: ${request.payload.sessionId}` };\n }\n if (this.runtimes.has(request.payload.sessionId)) {\n return { success: true, result: existing };\n }\n const resumed = this.startRuntime(existing, buildPayloadFromRecord(existing), 'session_resumed');\n this.recordRuntimeTransition(request.payload.sessionId, 'resume_session', resumed.lifecycle, undefined, true);\n return { success: true, result: resumed };\n }\n case 'restart_session': {\n const restarted = await this.restartRuntime(request.payload.sessionId);\n return { success: true, result: restarted };\n }\n case 'prune_duplicate_sessions': {\n const result = await this.pruneDuplicateSessions(request.payload);\n return { success: true, result };\n }\n case 'send_signal': {\n const runtime = this.requireRuntime(request.payload.sessionId);\n runtime.sendSignal(request.payload.signal);\n const record = this.registry.getSession(request.payload.sessionId);\n this.recordRuntimeTransition(request.payload.sessionId, 'send_signal', record?.lifecycle, request.payload.signal, true);\n return { success: true, result: record };\n }\n case 'force_detach_client': {\n const session = this.registry.getSession(request.payload.sessionId);\n if (session?.writeOwner?.clientId === request.payload.clientId) {\n const released = this.registry.releaseWrite({\n sessionId: request.payload.sessionId,\n clientId: request.payload.clientId,\n });\n this.emitEvent({ type: 'write_owner_changed', sessionId: released.sessionId, owner: released.writeOwner });\n }\n const record = this.registry.detachClient({\n sessionId: request.payload.sessionId,\n clientId: request.payload.clientId,\n });\n this.schedulePersist(record.sessionId);\n this.emitEvent({ type: 'client_detached', sessionId: record.sessionId, clientId: request.payload.clientId });\n this.recordRuntimeTransition(record.sessionId, 'force_detach_client', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n default:\n return { success: false, error: `Unsupported session host request: ${(request as { type?: string })?.type || 'unknown'}` };\n }\n } catch (error: any) {\n return { success: false, error: error?.message || String(error) };\n } finally {\n if (counted) this.mutatingRequests--;\n }\n }\n\n private requireRuntime(sessionId: string): PtySessionRuntime {\n const runtime = this.runtimes.get(sessionId);\n if (!runtime) throw new Error(`Runtime not found for session: ${sessionId}`);\n return runtime;\n }\n\n private getAttachedClient(sessionId: string, clientId: string): SessionAttachedClient | null {\n const session = this.registry.getSession(sessionId);\n return session?.attachedClients.find((client) => client.clientId === clientId) || null;\n }\n\n private emitEvent(event: SessionHostEvent): void {\n // Diagnostic-only events are stored locally (recentLogs/Requests/Transitions)\n // and accessible via get_host_diagnostics. Broadcasting them to every socket\n // creates O(N²) traffic when many CLI sessions are active.\n const diagnosticOnly = event.type === 'request_trace'\n || event.type === 'runtime_transition'\n || event.type === 'host_log';\n if (!diagnosticOnly) {\n const targetSessionId = 'sessionId' in event ? (event as { sessionId: string }).sessionId : null;\n for (const socket of [...this.sockets]) {\n // If the event is session-specific, only send to sockets subscribed to that session.\n if (targetSessionId && event.type === 'session_output') {\n const sessions = this.socketSessions.get(socket);\n if (!sessions?.has(targetSessionId)) continue;\n } else if (targetSessionId && this.socketSessions.size > 0) {\n const sessions = this.socketSessions.get(socket);\n if (sessions && !sessions.has(targetSessionId)) continue;\n }\n this.writeEnvelopeSafely(socket, {\n kind: 'event',\n event,\n });\n }\n }\n this.emit('event', event);\n }\n\n private subscribeSocketToSession(socket: net.Socket, sessionId: string): void {\n let sessions = this.socketSessions.get(socket);\n if (!sessions) {\n sessions = new Set();\n this.socketSessions.set(socket, sessions);\n }\n sessions.add(sessionId);\n }\n\n private async handleIncomingRequest(socket: net.Socket, envelope: SessionHostRequestEnvelope): Promise<void> {\n const sessionId = getRequestSessionId(envelope.request);\n if (sessionId && (envelope.request.type === 'create_session' || envelope.request.type === 'attach_session')) {\n this.subscribeSocketToSession(socket, sessionId);\n }\n const startedAt = Date.now();\n const response = await this.handleRequest(envelope.request);\n if (sessionId && envelope.request.type === 'create_session' && response.success) {\n // sessionId may have been auto-generated — subscribe to whatever was actually created\n const createdId = (response.result as { sessionId?: string } | undefined)?.sessionId;\n if (createdId && createdId !== sessionId) this.subscribeSocketToSession(socket, createdId);\n }\n this.recordRequestTrace({\n timestamp: startedAt,\n requestId: envelope.requestId,\n type: envelope.request.type,\n sessionId: getRequestSessionId(envelope.request),\n clientId: getRequestClientId(envelope.request),\n success: response.success,\n durationMs: Math.max(0, Date.now() - startedAt),\n error: response.success ? undefined : response.error,\n });\n this.writeEnvelopeSafely(socket, createResponseEnvelope(envelope.requestId, response));\n }\n\n private writeEnvelopeSafely(socket: net.Socket, envelope: SessionHostRequestEnvelope | ReturnType<typeof createResponseEnvelope> | { kind: 'event'; event: SessionHostEvent }): void {\n if (socket.destroyed || !socket.writable || socket.writableEnded) {\n this.sockets.delete(socket);\n return;\n }\n const payload = `${JSON.stringify(envelope)}\\n`;\n try {\n socket.write(payload, (error?: Error | null) => {\n if (!error) return;\n this.sockets.delete(socket);\n try {\n socket.destroy();\n } catch {\n // noop\n }\n });\n } catch {\n this.sockets.delete(socket);\n try {\n socket.destroy();\n } catch {\n // noop\n }\n }\n }\n\n private schedulePersist(sessionId: string): void {\n const existing = this.persistTimers.get(sessionId);\n if (existing) clearTimeout(existing);\n this.persistTimers.set(sessionId, setTimeout(() => {\n this.persistTimers.delete(sessionId);\n this.persistNow(sessionId);\n }, 200));\n }\n\n /**\n * @param allowTerminal - write even if the record is terminal. Only the exit\n * handler sets this, to stamp the final terminated record for the brief\n * post-mortem window before cleanup.\n */\n private persistNow(sessionId: string, allowTerminal = false): void {\n const record = this.registry.getSession(sessionId);\n if (!record) return;\n // Never write a live file for an already-terminated record. A persist can\n // land after the exit handler stamped the termination — e.g. a PTY onData\n // debounce (schedulePersist) that raced handleRuntimeExit. Writing here\n // recreates the file after storage.remove() deleted it, resurrecting a\n // self-contradictory record (lifecycle:'stopping' + termination stamped\n // 'stopped') that then surfaces as a live attach target for a PID that\n // already exited.\n //\n // Keyed on the record itself rather than a \"removed sessions\" set on\n // purpose: a restart reuses the same sessionId (restartRuntime stops and\n // relaunches in place), so a sticky per-id block would permanently stop\n // persisting the restarted live session. A terminal record naturally\n // stops being terminal once the session is running again.\n if (!allowTerminal && isTerminalRecord(record)) return;\n const snapshot = this.getSnapshot(sessionId);\n try {\n this.storage.save(record, snapshot);\n } catch (error: any) {\n const code = typeof error?.code === 'string' ? error.code : 'persist_failed';\n console.error(`[session-host] Persist failed for ${sessionId}: ${code}: ${error?.message || error}`);\n }\n }\n\n private getHostDiagnostics(payload?: { includeSessions?: boolean; limit?: number }): SessionHostDiagnostics {\n return buildHostDiagnostics({\n payload,\n hostStartedAt: this.startedAt,\n endpointPath: this.endpoint.path,\n runtimeCount: this.runtimes.size,\n sessions: this.registry.listSessions(),\n recentLogs: this.recentLogs,\n recentRequests: this.recentRequests,\n recentTransitions: this.recentTransitions,\n });\n }\n\n private recordHostLog(\n level: SessionHostLogEntry['level'],\n message: string,\n sessionId?: string,\n data?: Record<string, unknown>,\n ): void {\n const entry: SessionHostLogEntry = {\n timestamp: Date.now(),\n level,\n message,\n sessionId,\n data,\n };\n pushRecent(this.recentLogs, entry);\n this.emitEvent({ type: 'host_log', entry });\n this.emit('log', `[${level}] ${message}`);\n }\n\n private recordRequestTrace(trace: SessionHostRequestTrace): void {\n pushRecent(this.recentRequests, trace);\n this.emitEvent({ type: 'request_trace', trace });\n if (!trace.success) {\n this.recordHostLog(\n 'warn',\n `request ${trace.type} failed after ${trace.durationMs}ms${trace.error ? `: ${trace.error}` : ''}`,\n trace.sessionId,\n { requestId: trace.requestId, clientId: trace.clientId },\n );\n }\n }\n\n private scheduleNoOutputInputDiagnostic(params: {\n sessionId: string;\n clientId: string;\n input: string;\n beforeSnapshotSeq: number;\n }): void {\n if (!params.input || /^\\x1b/.test(params.input)) {\n return;\n }\n\n const hasPotentialEcho = /[^\\x00-\\x1F\\x7F]/.test(params.input);\n if (!hasPotentialEcho && params.input !== '\\r' && params.input !== '\\n') {\n return;\n }\n\n setTimeout(() => {\n let afterSnapshotSeq = params.beforeSnapshotSeq;\n try {\n afterSnapshotSeq = this.registry.getSnapshot(params.sessionId)?.seq ?? params.beforeSnapshotSeq;\n } catch {\n return;\n }\n if (afterSnapshotSeq > params.beforeSnapshotSeq) {\n return;\n }\n\n const now = Date.now();\n const lastWarnAt = this.lastNoOutputInputWarnAt.get(params.sessionId) || 0;\n if (now - lastWarnAt < 10_000) {\n return;\n }\n this.lastNoOutputInputWarnAt.set(params.sessionId, now);\n const record = this.registry.getSession(params.sessionId);\n this.recordHostLog(\n 'warn',\n 'send_input produced no terminal output after PTY write; runtime may be ignoring stdin or stuck in a hidden input reader',\n params.sessionId,\n {\n clientId: params.clientId,\n inputLength: params.input.length,\n beforeSnapshotSeq: params.beforeSnapshotSeq,\n afterSnapshotSeq,\n lifecycle: record?.lifecycle,\n osPid: record?.osPid,\n providerType: record?.providerType,\n },\n );\n this.recordRuntimeTransition(\n params.sessionId,\n 'send_input_no_output_after_write',\n record?.lifecycle,\n `clientId=${params.clientId} inputLength=${params.input.length} seq=${params.beforeSnapshotSeq}`,\n false,\n 'no terminal output after PTY write',\n );\n }, 250);\n }\n\n private recordRuntimeTransition(\n sessionId: string,\n action: string,\n lifecycle?: SessionHostRuntimeTransition['lifecycle'],\n detail?: string,\n success = true,\n error?: string,\n ): void {\n const transition: SessionHostRuntimeTransition = {\n timestamp: Date.now(),\n sessionId,\n action,\n lifecycle,\n detail,\n success,\n error,\n };\n pushRecent(this.recentTransitions, transition);\n this.emitEvent({ type: 'runtime_transition', transition });\n }\n\n private waitForRuntimeExit(sessionId: string, timeoutMs = 5_000): Promise<number | null> {\n if (!this.runtimes.has(sessionId)) {\n return Promise.resolve(this.registry.getSession(sessionId)?.lifecycle === 'failed' ? 1 : 0);\n }\n return new Promise<number | null>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const waiters = this.exitWaiters.get(sessionId) || [];\n this.exitWaiters.set(sessionId, waiters.filter((waiter) => waiter !== onExit));\n reject(new Error(`Timed out waiting for runtime ${sessionId} to exit`));\n }, timeoutMs);\n const onExit = (exitCode: number | null) => {\n clearTimeout(timeout);\n resolve(exitCode);\n };\n const waiters = this.exitWaiters.get(sessionId) || [];\n waiters.push(onExit);\n this.exitWaiters.set(sessionId, waiters);\n });\n }\n\n private resolveExitWaiters(sessionId: string, exitCode: number | null): void {\n const waiters = this.exitWaiters.get(sessionId);\n if (!waiters?.length) return;\n this.exitWaiters.delete(sessionId);\n for (const waiter of waiters) {\n try {\n waiter(exitCode);\n } catch {\n // noop\n }\n }\n }\n\n // Synchronous, best-effort variant for background/periodic persistence\n // (persistNow, called from many sync contexts). Uses getSnapshotTextSync()\n // rather than waiting for in-flight PTY writes to flush — see that method's\n // doc. Interactive requests must use getSnapshotForRequest() instead.\n private getSnapshot(sessionId: string, sinceSeq?: number) {\n const snapshot = this.registry.getSnapshot(sessionId, sinceSeq);\n const record = this.registry.getSession(sessionId);\n const runtimeText = typeof sinceSeq === 'number'\n ? ''\n : (this.runtimes.get(sessionId)?.getSnapshotTextSync?.() || '');\n return mergeRuntimeSnapshot(snapshot, record, { sinceSeq, runtimeText });\n }\n\n // Flush-aware variant for the interactive `get_snapshot` IPC request (the\n // dashboard's runtime_snapshot seed). Awaits any PTY chunk still queued in\n // the xterm mirror's WriteBuffer before reading, so the response reflects\n // everything written so far rather than racing an in-flight parse. See\n // PtySessionRuntime.flushPendingWrites() for why that race existed.\n private async getSnapshotForRequest(sessionId: string, sinceSeq?: number) {\n const snapshot = this.registry.getSnapshot(sessionId, sinceSeq);\n const record = this.registry.getSession(sessionId);\n const runtimeText = typeof sinceSeq === 'number'\n ? ''\n : ((await this.runtimes.get(sessionId)?.getSnapshotText?.()) || '');\n return mergeRuntimeSnapshot(snapshot, record, { sinceSeq, runtimeText });\n }\n\n flushAllPersistence(): void {\n for (const sessionId of this.runtimes.keys()) {\n this.persistNow(sessionId);\n }\n for (const record of this.registry.listSessions()) {\n this.persistNow(record.sessionId);\n }\n }\n\n private async restartRuntime(sessionId: string): Promise<SessionHostRecord> {\n const existing = this.registry.getSession(sessionId);\n if (!existing) {\n throw new Error(`Unknown session: ${sessionId}`);\n }\n\n if (this.runtimes.has(sessionId)) {\n this.stopRequests.set(sessionId, 'restart');\n this.registry.setLifecycle(sessionId, 'stopping');\n this.persistNow(sessionId);\n this.recordRuntimeTransition(sessionId, 'restart_requested', 'stopping', undefined, true);\n this.requireRuntime(sessionId).stop();\n await this.waitForRuntimeExit(sessionId);\n }\n\n const latest = this.registry.getSession(sessionId) || existing;\n const restarted = this.startRuntime(latest, buildPayloadFromRecord(latest), 'session_resumed');\n this.recordRuntimeTransition(sessionId, 'restart_completed', restarted.lifecycle, undefined, true);\n return restarted;\n }\n\n private async pruneDuplicateSessions(payload?: {\n providerType?: string;\n workspace?: string;\n dryRun?: boolean;\n }): Promise<SessionHostPruneDuplicatesResult> {\n const providerFilter = typeof payload?.providerType === 'string' ? payload.providerType.trim() : '';\n const workspaceFilter = typeof payload?.workspace === 'string' ? payload.workspace.trim() : '';\n const dryRun = payload?.dryRun === true;\n\n const { duplicateGroups, keptSessionIds, duplicateRecords } = planDuplicatePrune(\n this.registry.listSessions(),\n { providerFilter, workspaceFilter },\n );\n\n const prunedSessionIds: string[] = [];\n if (!dryRun) {\n for (const duplicate of duplicateRecords) {\n await this.pruneDuplicateRuntime(duplicate);\n prunedSessionIds.push(duplicate.sessionId);\n }\n }\n\n this.recordHostLog(\n dryRun ? 'info' : 'warn',\n `${dryRun ? 'session host dry-run found' : 'session host pruned'} ${duplicateGroups.length} duplicate group(s)`,\n undefined,\n {\n providerType: providerFilter || undefined,\n workspace: workspaceFilter || undefined,\n dryRun,\n prunedSessionIds,\n keptSessionIds,\n },\n );\n\n return {\n duplicateGroupCount: duplicateGroups.length,\n keptSessionIds,\n prunedSessionIds,\n groups: duplicateGroups,\n };\n }\n\n private restorePersistedRuntimes(): void {\n const states = this.storage.loadAll();\n let skippedAutoResumeSessions = 0;\n for (const persisted of states) {\n const { recoveredRecord, wasLiveRuntime, hadRecoveryInterest } = buildRecoveredRecord(persisted);\n this.registry.restoreSession(recoveredRecord, persisted.snapshot);\n this.storage.save(recoveredRecord, persisted.snapshot);\n if (wasLiveRuntime && hadRecoveryInterest) {\n skippedAutoResumeSessions += 1;\n }\n }\n\n if (skippedAutoResumeSessions > 0) {\n this.recordHostLog('warn', `session host restored ${skippedAutoResumeSessions} live runtime snapshot(s) without auto-resume`);\n }\n }\n\n private async pruneDuplicateRuntime(record: SessionHostRecord): Promise<void> {\n const providerSessionId = typeof record.meta?.providerSessionId === 'string'\n ? String(record.meta.providerSessionId)\n : undefined;\n this.recordRuntimeTransition(\n record.sessionId,\n 'prune_duplicate_session',\n record.lifecycle,\n providerSessionId ? `providerSessionId=${providerSessionId}` : undefined,\n true,\n );\n\n if (this.runtimes.has(record.sessionId)) {\n this.stopRequests.set(record.sessionId, 'prune');\n this.registry.setLifecycle(record.sessionId, 'stopping');\n this.persistNow(record.sessionId);\n this.requireRuntime(record.sessionId).stop();\n await this.waitForRuntimeExit(record.sessionId).catch((error: any) => {\n this.recordRuntimeTransition(record.sessionId, 'prune_duplicate_timeout', 'stopping', undefined, false, error?.message || String(error));\n });\n }\n\n const pendingPersistTimer = this.persistTimers.get(record.sessionId);\n if (pendingPersistTimer) {\n clearTimeout(pendingPersistTimer);\n this.persistTimers.delete(record.sessionId);\n }\n this.registry.deleteSession(record.sessionId);\n this.storage.remove(record.sessionId);\n this.storage.removeTombstone(record.sessionId);\n this.stopRequests.delete(record.sessionId);\n }\n\n private startRuntime(\n record: SessionHostRecord,\n payload: CreateSessionPayload,\n startEventType: 'session_started' | 'session_resumed',\n ): SessionHostRecord {\n const runtime = new PtySessionRuntime({\n sessionId: record.sessionId,\n payload,\n onData: (data) => {\n const { seq } = this.registry.appendOutput(record.sessionId, data);\n this.schedulePersist(record.sessionId);\n this.emitEvent({ type: 'session_output', sessionId: record.sessionId, seq, data });\n },\n onExit: (exitCode, signal) => this.handleRuntimeExit(record, exitCode, signal),\n });\n\n this.registry.setLifecycle(record.sessionId, 'starting');\n const pid = runtime.start();\n this.runtimes.set(record.sessionId, runtime);\n const startedRecord = this.registry.markStarted(record.sessionId, pid);\n this.persistNow(record.sessionId);\n this.emitEvent({ type: startEventType, sessionId: record.sessionId, pid });\n this.recordRuntimeTransition(record.sessionId, startEventType, startedRecord.lifecycle, `pid=${pid}`, true);\n return startedRecord;\n }\n\n /**\n * Handle a PTY termination: classify the (exitCode, signal) pair, stamp the\n * record + tombstone, emit exactly one structured diagnostic, and schedule\n * cleanup of the live persistence file (the tombstone is retained).\n */\n private handleRuntimeExit(record: SessionHostRecord, exitCode: number | null, signal: number | null): SessionTermination {\n // Capture pre-termination context BEFORE mutating the record.\n const priorRecord = this.registry.getSession(record.sessionId);\n const termination = classifyTermination({\n exitCode,\n signal,\n osPid: priorRecord?.osPid,\n previousLifecycle: priorRecord?.lifecycle,\n lastOutputAt: priorRecord?.lastActivityAt,\n requestedStop: this.stopRequests.get(record.sessionId),\n terminatedAt: Date.now(),\n });\n this.stopRequests.delete(record.sessionId);\n\n this.registry.markStopped(record.sessionId, termination.lifecycle, termination);\n this.runtimes.delete(record.sessionId);\n this.resolveExitWaiters(record.sessionId, exitCode);\n const pendingPersistTimer = this.persistTimers.get(record.sessionId);\n if (pendingPersistTimer) {\n clearTimeout(pendingPersistTimer);\n this.persistTimers.delete(record.sessionId);\n }\n this.persistNow(record.sessionId, true);\n // Persist a tombstone that survives live-record cleanup so the termination\n // stays inspectable after the 5s removal below.\n this.storage.saveTombstone(record.sessionId, termination);\n this.emitEvent({ type: 'session_exit', sessionId: record.sessionId, exitCode, signal, termination });\n const summary = `reason=${termination.reason} exitCode=${termination.exitCode === null ? 'unknown' : termination.exitCode} signal=${termination.signal ?? 'none'}`;\n // Exactly one structured, secret-free termination diagnostic.\n this.recordHostLog(\n termination.lifecycle === 'stopped' ? 'info' : 'warn',\n `session terminated: ${summary}`,\n record.sessionId,\n {\n runtimeKey: record.runtimeKey,\n providerType: record.providerType,\n osPid: termination.osPid,\n exitCode: termination.exitCode,\n signal: termination.signal,\n reason: termination.reason,\n previousLifecycle: termination.previousLifecycle,\n lifecycle: termination.lifecycle,\n lastOutputAt: termination.lastOutputAt,\n requestedStop: termination.requestedStop,\n },\n );\n this.recordRuntimeTransition(\n record.sessionId,\n 'session_exit',\n termination.lifecycle,\n summary,\n termination.lifecycle === 'stopped',\n termination.lifecycle === 'stopped' ? undefined : summary,\n );\n // Clean up the live persistence file after a brief delay (allow post-mortem\n // reads). The tombstone written above is retained. The registry entry is\n // dropped in the same tick as the file so the record can no longer be\n // served — and so no persist can find it and recreate the file (see\n // resurrection RCA: a persist landing after storage.remove() but finding\n // the record still registered recreates a stale live file).\n setTimeout(() => {\n // A restart reuses the sessionId: restartRuntime() stops the runtime,\n // which schedules this cleanup, then relaunches in place. If the session\n // is live again by the time this fires, it belongs to the new runtime —\n // deleting it would unregister and unpersist a running session.\n const current = this.registry.getSession(record.sessionId);\n if (current && !isTerminalRecord(current)) return;\n this.registry.deleteSession(record.sessionId);\n this.storage.remove(record.sessionId);\n }, 5_000).unref?.();\n return termination;\n }\n}\n","import * as fs from 'fs';\nimport * as os from 'os';\nimport * as pty from 'node-pty';\nimport type { IPty } from 'node-pty';\nimport type { CreateSessionPayload, SessionTerminalSnapshot } from '@adhdev/session-host-core';\nimport {\n sanitizeSpawnEnv,\n ensureNodePtySpawnHelperPermissions,\n resolveSessionHostCols,\n resolveSessionHostRows,\n spawnCliChild,\n} from '@adhdev/session-host-core';\n\ntype TerminalMirrorHandle = {\n // `onProcessed` fires once this chunk has actually been parsed into the\n // buffer. xterm.js's write() is asynchronous (WriteBuffer defers to a\n // setTimeout/microtask — see @xterm/xterm's common/input/WriteBuffer.ts):\n // without waiting for this callback, a snapshot read that races an\n // in-flight write observes a buffer that is missing the just-written data\n // (stale, not corrupted) rather than the just-appended text. See\n // PtySessionRuntime.flushPendingWrites().\n write(data: string | Uint8Array, onProcessed?: () => void): void;\n resize(cols: number, rows: number): void;\n formatVT(): string;\n formatPlainText(): string;\n getCursorPosition(): { col: number; row: number };\n dispose(): void;\n};\n\ntype GhosttyTerminalHandle = {\n write(data: string | Uint8Array, onProcessed?: () => void): void;\n resize(cols: number, rows: number): void;\n formatVT(): string;\n formatPlainText(options?: { trim?: boolean }): string;\n getCursorPosition(): { col: number; row: number };\n dispose(): void;\n};\n\ntype GhosttyBinding = {\n createTerminal(options: { cols: number; rows: number; scrollback: number }): GhosttyTerminalHandle;\n};\n\ntype XtermBufferLine = {\n translateToString(trimRight?: boolean): string;\n};\n\ntype XtermBuffer = {\n length: number;\n viewportY: number;\n cursorX?: number;\n cursorY?: number;\n getLine(index: number): XtermBufferLine | undefined;\n};\n\ntype XtermTerminal = {\n buffer: { active: XtermBuffer };\n loadAddon(addon: { activate(terminal: XtermTerminal): void }): void;\n write(data: string, callback?: () => void): void;\n resize(cols: number, rows: number): void;\n dispose(): void;\n};\n\ntype XtermCtor = new (options: { cols: number; rows: number; scrollback: number }) => XtermTerminal;\n\ntype XtermSerializeAddon = {\n serialize(options?: { range?: { start: number; end: number }; scrollback?: number; excludeModes?: boolean }): string;\n dispose(): void;\n};\n\nlet terminalMirrorFactory:\n | ((options: { cols: number; rows: number; scrollback: number }) => TerminalMirrorHandle)\n | null\n | undefined;\nlet terminalMirrorWarning: string | null = null;\nlet terminalMirrorBackendLogged = false;\n\nensureNodePtySpawnHelperPermissions((msg: string) => console.log(`[session-host] ${msg}`));\n\nfunction logTerminalMirrorBackend(message: string, level: 'info' | 'warn' = 'info'): void {\n if (terminalMirrorBackendLogged) return;\n terminalMirrorBackendLogged = true;\n const prefix = '[session-host]';\n if (level === 'warn') console.warn(`${prefix} ${message}`);\n else console.log(`${prefix} ${message}`);\n}\n\nexport interface PtyRuntimeOptions {\n sessionId: string;\n payload: CreateSessionPayload;\n onData: (data: string) => void;\n onExit: (exitCode: number | null, signal: number | null) => void;\n}\n\n// Use shared spawn env sanitizer — alias for backward compat within this file\nconst buildRuntimeEnv = sanitizeSpawnEnv;\n\nfunction computeTerminalQueryTail(buffer: string): string {\n const prefixes = ['\\x1b[6n', '\\x1b[?6n'];\n const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;\n const start = Math.max(0, buffer.length - maxLength);\n for (let i = start; i < buffer.length; i++) {\n const suffix = buffer.slice(i);\n if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {\n return suffix;\n }\n }\n return '';\n}\n\nfunction formatXtermViewportPlain(terminal: XtermTerminal, rows: number): string {\n const buffer = terminal.buffer.active;\n const start = Math.max(0, buffer.viewportY || 0);\n const end = Math.max(start, Math.min(buffer.length || 0, start + Math.max(1, rows | 0)));\n const lines: string[] = [];\n\n for (let i = start; i < end; i++) {\n const line = buffer.getLine(i);\n const raw = line ? line.translateToString(false) : '';\n lines.push(raw.replace(/\\s+$/, ''));\n }\n\n let first = 0;\n let last = lines.length;\n while (first < last && !lines[first]?.trim()) first++;\n while (last > first && !lines[last - 1]?.trim()) last--;\n // Use CRLF row boundaries for unambiguous terminal replay regardless of the\n // browser xterm convertEol setting. CRLF is always explicit; bare LF depends\n // on convertEol being true to reset the cursor column, which is not guaranteed\n // for all xterm consumer configurations.\n return lines.slice(first, last).join('\\r\\n');\n}\n\nfunction createXtermSerializeAddon(terminal: XtermTerminal): XtermSerializeAddon | null {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const mod = require('@xterm/addon-serialize');\n const SerializeAddon = mod.SerializeAddon || mod.default?.SerializeAddon || mod.default;\n if (!SerializeAddon) return null;\n const addon = new SerializeAddon() as XtermSerializeAddon & { activate(terminal: XtermTerminal): void };\n terminal.loadAddon(addon);\n return addon;\n } catch {\n return null;\n }\n}\n\nfunction formatCursorRestore(terminal: XtermTerminal, rows: number): string {\n const buffer = terminal.buffer.active;\n const row = Math.max(0, Math.min(Math.max(0, rows | 0) - 1, buffer.cursorY || 0));\n const col = Math.max(0, buffer.cursorX || 0);\n return `\\x1b[${row + 1};${col + 1}H`;\n}\n\nfunction serializeXtermViewport(terminal: XtermTerminal, serializer: XtermSerializeAddon, rows: number): string {\n const buffer = terminal.buffer.active;\n const start = Math.max(0, buffer.viewportY || 0);\n const end = Math.max(start, Math.min(Math.max(0, buffer.length || 0) - 1, start + Math.max(1, rows | 0) - 1));\n if (end < start) return '';\n const viewport = serializer.serialize({\n range: { start, end },\n excludeModes: true,\n });\n // Range serialization reproduces the visible cells, but leaves the replay cursor\n // at the end of the serialized viewport. CLIs like Claude frequently update the\n // current status line with relative cursor movement; if the dashboard seeds a\n // snapshot and then receives an incremental update, that update must continue\n // from the live cursor row, not from the next line after the viewport replay.\n return `${viewport}${formatCursorRestore(terminal, rows)}`;\n}\n\nfunction createXtermMirror(options: { cols: number; rows: number; scrollback: number }): TerminalMirrorHandle {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const mod = require('@xterm/xterm');\n const Terminal = (mod.Terminal || mod.default?.Terminal || mod.default) as XtermCtor | undefined;\n if (!Terminal) {\n throw new Error('@xterm/xterm Terminal export not found');\n }\n\n let currentRows = Math.max(1, options.rows | 0);\n const terminal = new Terminal({\n cols: Math.max(1, options.cols | 0),\n rows: currentRows,\n scrollback: Math.max(0, options.scrollback | 0),\n });\n const serializer = createXtermSerializeAddon(terminal);\n\n return {\n write(data: string | Uint8Array, onProcessed?: () => void): void {\n if (!data) {\n // Nothing to parse, but the caller (PtySessionRuntime.flushPendingWrites)\n // still needs its completion signal so an empty chunk cannot wedge a flush.\n onProcessed?.();\n return;\n }\n terminal.write(typeof data === 'string' ? data : Buffer.from(data).toString('utf8'), onProcessed);\n },\n resize(cols: number, rows: number): void {\n currentRows = Math.max(1, rows | 0);\n terminal.resize(Math.max(1, cols | 0), currentRows);\n },\n formatVT(): string {\n if (serializer) return serializeXtermViewport(terminal, serializer, currentRows);\n return formatXtermViewportPlain(terminal, currentRows);\n },\n formatPlainText(): string {\n return formatXtermViewportPlain(terminal, currentRows).replace(/\\r\\n/g, '\\n');\n },\n getCursorPosition(): { col: number; row: number } {\n const buffer = terminal.buffer.active;\n return {\n col: Math.max(0, buffer.cursorX || 0),\n row: Math.max(0, buffer.cursorY || 0),\n };\n },\n dispose(): void {\n serializer?.dispose();\n terminal.dispose();\n },\n };\n}\n\nfunction normalizeGhosttyBinding(mod: any): GhosttyBinding | null {\n const raw = mod?.default?.createTerminal ? mod.default : mod?.createTerminal ? mod : null;\n if (!raw) return null;\n\n // Keep Ghostty as the authoritative emulator for terminal query responses, but use\n // xterm's serialized active viewport for UI seeding. Ghostty's formatter serializes\n // scrollback before the active viewport; after full-screen Claude Code redraws (for\n // example `/status` -> Esc), replaying that as a fresh terminal seed makes stale\n // splash-screen rows visible as duplicated logos. xterm's serialize addon gives us\n // the viewport-only seed without dropping SGR color/style or CRLF row movement.\n return {\n createTerminal(options: { cols: number; rows: number; scrollback: number }): GhosttyTerminalHandle {\n const handle = raw.createTerminal(options) as any;\n const viewportSnapshot = createXtermMirror(options);\n return {\n write(data: string | Uint8Array, onProcessed?: () => void): void {\n // `handle` (native ghostty) writes synchronously; `viewportSnapshot`\n // (xterm mirror) is the one whose write is asynchronous and is also\n // the sole source of formatVT()/formatPlainText() output above — so\n // completion must be reported only once ITS write has been parsed,\n // not immediately after this call returns.\n handle.write(data);\n viewportSnapshot.write(data, onProcessed);\n },\n resize(cols: number, rows: number): void {\n handle.resize(cols, rows);\n viewportSnapshot.resize(cols, rows);\n },\n formatVT(): string {\n return viewportSnapshot.formatVT();\n },\n formatPlainText(): string {\n return viewportSnapshot.formatPlainText();\n },\n getCursorPosition(): { col: number; row: number } {\n if (typeof handle.getCursorPosition === 'function') return handle.getCursorPosition() as { col: number; row: number };\n return viewportSnapshot.getCursorPosition();\n },\n dispose(): void {\n handle.dispose();\n viewportSnapshot.dispose();\n },\n };\n },\n };\n}\n\nexport const __testing = {\n createXtermMirror,\n formatXtermViewportPlain,\n serializeXtermViewport,\n};\n\nfunction getTerminalMirrorFactory(): (options: { cols: number; rows: number; scrollback: number }) => TerminalMirrorHandle {\n if (terminalMirrorFactory) return terminalMirrorFactory;\n if (terminalMirrorFactory === null) {\n throw new Error(terminalMirrorWarning || 'No terminal mirror backend available');\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const ghosttyMod = require('@adhdev/ghostty-vt-node');\n const binding = normalizeGhosttyBinding(ghosttyMod);\n if (!binding) {\n throw new Error('@adhdev/ghostty-vt-node does not export createTerminal()');\n }\n terminalMirrorFactory = (options) => binding.createTerminal(options);\n logTerminalMirrorBackend('terminal mirror backend=ghostty-vt');\n return terminalMirrorFactory;\n } catch (ghosttyError: any) {\n try {\n terminalMirrorFactory = createXtermMirror;\n terminalMirrorWarning = `Ghostty VT unavailable; falling back to xterm mirror (${ghosttyError?.message || String(ghosttyError)})`;\n logTerminalMirrorBackend(terminalMirrorWarning, 'warn');\n return terminalMirrorFactory;\n } catch (xtermError: any) {\n terminalMirrorFactory = null;\n terminalMirrorWarning = `No terminal mirror backend available (ghostty: ${ghosttyError?.message || String(ghosttyError)}; xterm: ${xtermError?.message || String(xtermError)})`;\n logTerminalMirrorBackend(terminalMirrorWarning, 'warn');\n throw new Error(terminalMirrorWarning);\n }\n }\n}\n\nexport class PtySessionRuntime {\n readonly sessionId: string;\n readonly payload: CreateSessionPayload;\n private cols: number;\n private rows: number;\n\n private ptyProcess: IPty | null = null;\n private screenMirror: TerminalMirrorHandle | null = null;\n private pendingQueryScanTail = '';\n private terminalModeScanTail = '';\n private altScreen = false;\n private pasteMode = false;\n private scrollRegion: { top: number; bot: number };\n private onDataCallback: (data: string) => void;\n private onExitCallback: (exitCode: number | null, signal: number | null) => void;\n /** Count of screenMirror.write() calls whose completion callback has not fired yet. */\n private pendingWriteCount = 0;\n /** Resolved (and cleared) once pendingWriteCount reaches 0. See flushPendingWrites(). */\n private snapshotWaiters: Array<() => void> = [];\n\n constructor(options: PtyRuntimeOptions) {\n this.sessionId = options.sessionId;\n this.payload = options.payload;\n this.cols = resolveSessionHostCols(options.payload.cols);\n this.rows = resolveSessionHostRows(options.payload.rows);\n this.scrollRegion = { top: 0, bot: this.rows - 1 };\n this.onDataCallback = options.onData;\n this.onExitCallback = options.onExit;\n }\n\n start(): number {\n if (this.ptyProcess) return this.ptyProcess.pid;\n\n const command = this.payload.launchCommand.command;\n const args = this.payload.launchCommand.args || [];\n const env = buildRuntimeEnv(process.env, this.payload.launchCommand.env);\n\n // Validate workspace directory — an invalid cwd causes a native crash on Windows\n // (node-pty error code 267: ERROR_DIRECTORY) that bypasses JS try/catch\n let cwd = this.payload.workspace || process.cwd();\n if (cwd) {\n try {\n const stat = fs.statSync(cwd);\n if (!stat.isDirectory()) cwd = os.homedir();\n } catch {\n cwd = os.homedir();\n }\n }\n\n const spawnRuntime = () => pty.spawn(command, args, {\n name: 'xterm-256color',\n cols: this.cols,\n rows: this.rows,\n cwd,\n env,\n });\n // User terminals share this host. Only agent workload categories acquire\n // the policy; a plain shell (or unknown category) keeps its priority.\n this.ptyProcess = this.payload.category === 'cli' || this.payload.category === 'acp'\n ? spawnCliChild(spawnRuntime, env)\n : spawnRuntime();\n this.screenMirror = getTerminalMirrorFactory()({\n cols: this.cols,\n rows: this.rows,\n scrollback: 32768,\n });\n\n this.ptyProcess.onData((data: string) => {\n this.trackTerminalModes(data);\n this.onDataCallback(data);\n // `screenMirror.write()` is backed by xterm.js's WriteBuffer (see\n // TerminalMirrorHandle's `write` doc), which is asynchronous: it defers\n // parsing to a later tick even though this call returns immediately.\n // Reads that depend on `data` having been fully parsed must wait for the\n // completion callback rather than running synchronously right after\n // write():\n // - getSnapshotText()/getTerminalSnapshot() (formatVT/formatPlainText)\n // always read the xterm mirror, ghostty-backed or not, so an\n // in-flight get_snapshot IPC request racing a queued write got a\n // STALE/incomplete viewport (missing the just-written tail).\n // - respondToTerminalQueries()'s DSR (`\\x1b[6n`) reply reads\n // getCursorPosition(), which is the (synchronous) native ghostty\n // cursor when that backend is active, but falls back to the same\n // async xterm mirror when it is not (see normalizeGhosttyBinding\n // below). On the xterm-only fallback, replying synchronously here\n // reported a STALE cursor column to the PTY process for any DSR\n // query issued while a write was still queued — plausibly drifting\n // a CLI's own redraw math out of sync with the real terminal column\n // position (each wide/CJK cell advances the cursor by 2, so a stale\n // reply skews layout most visibly around wide characters).\n this.pendingWriteCount += 1;\n this.screenMirror?.write(data, () => {\n this.pendingWriteCount = Math.max(0, this.pendingWriteCount - 1);\n this.respondToTerminalQueries(data);\n this.flushSnapshotWaiters();\n });\n });\n\n this.ptyProcess.onExit(({ exitCode, signal }) => {\n this.ptyProcess = null;\n this.screenMirror?.dispose();\n this.screenMirror = null;\n this.pendingQueryScanTail = '';\n this.terminalModeScanTail = '';\n this.pendingWriteCount = 0;\n // No more write() callbacks will ever fire for a disposed mirror — release\n // any waiter now so flushPendingWrites() cannot hang past process exit.\n this.flushSnapshotWaiters();\n // Preserve the nullable/unknown exitCode and signal exactly as node-pty\n // reports them: a signal-terminated process arrives as exitCode=null and\n // must stay distinguishable from a clean exit 0.\n this.onExitCallback(\n typeof exitCode === 'number' ? exitCode : null,\n typeof signal === 'number' ? signal : null,\n );\n });\n\n return this.ptyProcess.pid;\n }\n\n write(data: string): void {\n if (!this.ptyProcess) throw new Error(`Session not running: ${this.sessionId}`);\n this.ptyProcess.write(data);\n }\n\n resize(cols: number, rows: number): void {\n if (!this.ptyProcess) throw new Error(`Session not running: ${this.sessionId}`);\n this.ptyProcess.resize(cols, rows);\n this.cols = Math.max(1, cols | 0);\n this.rows = Math.max(1, rows | 0);\n this.scrollRegion = {\n top: Math.min(this.scrollRegion.top, this.rows - 1),\n bot: Math.min(Math.max(this.scrollRegion.top, this.scrollRegion.bot), this.rows - 1),\n };\n this.screenMirror?.resize(cols, rows);\n }\n\n stop(): void {\n if (!this.ptyProcess) return;\n this.ptyProcess.kill();\n }\n\n sendSignal(signal: string): void {\n if (!this.ptyProcess) throw new Error(`Session not running: ${this.sessionId}`);\n const normalized = String(signal || '').trim().toUpperCase();\n if (!normalized) throw new Error('signal is required');\n\n try {\n process.kill(this.ptyProcess.pid, normalized as NodeJS.Signals);\n } catch {\n if (normalized === 'SIGTERM' || normalized === 'SIGKILL') {\n this.ptyProcess.kill();\n return;\n }\n throw new Error(`Unsupported signal for runtime ${this.sessionId}: ${normalized}`);\n }\n }\n\n /**\n * Resolves once every screenMirror.write() call made so far has had its\n * completion callback fire (i.e. the xterm mirror's WriteBuffer has fully\n * parsed all currently-queued PTY chunks). Callers that read the mirror's\n * text/cursor state — getSnapshotText(), getTerminalSnapshot() — must await\n * this first, otherwise they can observe a buffer missing the most recently\n * written chunk (stale/incomplete text, not corrupted text: see\n * TerminalMirrorHandle's `write` doc for why the read races the write).\n */\n flushPendingWrites(): Promise<void> {\n if (this.pendingWriteCount <= 0) return Promise.resolve();\n return new Promise((resolve) => {\n this.snapshotWaiters.push(resolve);\n });\n }\n\n private flushSnapshotWaiters(): void {\n if (this.pendingWriteCount > 0 || this.snapshotWaiters.length === 0) return;\n const waiters = this.snapshotWaiters;\n this.snapshotWaiters = [];\n for (const resolve of waiters) resolve();\n }\n\n async getSnapshotText(): Promise<string> {\n await this.flushPendingWrites();\n return this.screenMirror?.formatVT() || '';\n }\n\n /**\n * Best-effort, non-flushing read of the same text as getSnapshotText(),\n * for callers that persist periodically in the background (persistNow) and\n * must stay synchronous rather than awaiting in-flight PTY writes. A\n * restore-on-restart read of this can be briefly behind the live viewport\n * by at most one already-queued chunk; that trade-off is acceptable for a\n * background persistence snapshot but not for an interactive get_snapshot\n * request, which should use getSnapshotText() instead.\n */\n getSnapshotTextSync(): string {\n return this.screenMirror?.formatVT() || '';\n }\n\n async getTerminalSnapshot(): Promise<SessionTerminalSnapshot> {\n if (!this.ptyProcess || !this.screenMirror) {\n throw new Error(`Session not running: ${this.sessionId}`);\n }\n await this.flushPendingWrites();\n if (!this.ptyProcess || !this.screenMirror) {\n throw new Error(`Session not running: ${this.sessionId}`);\n }\n const cursor = this.screenMirror.getCursorPosition();\n return {\n text: this.screenMirror.formatPlainText(),\n state: {\n cursor: {\n row: Math.max(0, cursor.row | 0),\n col: Math.max(0, cursor.col | 0),\n },\n altScreen: this.altScreen,\n pasteMode: this.pasteMode,\n rawMode: true,\n scrollRegion: { ...this.scrollRegion },\n cols: this.cols,\n rows: this.rows,\n },\n };\n }\n\n private trackTerminalModes(data: string): void {\n if (!data) return;\n const combined = this.terminalModeScanTail + data;\n const privateMode = /\\x1b\\[\\?([0-9;]*)([hl])/g;\n let privateMatch: RegExpExecArray | null;\n while ((privateMatch = privateMode.exec(combined)) !== null) {\n const enabled = privateMatch[2] === 'h';\n for (const mode of privateMatch[1].split(';')) {\n if (mode === '47' || mode === '1047' || mode === '1049') this.altScreen = enabled;\n if (mode === '2004') this.pasteMode = enabled;\n }\n }\n\n const scrollRegion = /\\x1b\\[(\\d*)(?:;(\\d*))?r/g;\n let scrollMatch: RegExpExecArray | null;\n while ((scrollMatch = scrollRegion.exec(combined)) !== null) {\n const top = scrollMatch[1] ? Number.parseInt(scrollMatch[1], 10) - 1 : 0;\n const bot = scrollMatch[2] ? Number.parseInt(scrollMatch[2], 10) - 1 : this.rows - 1;\n this.scrollRegion = {\n top: Math.max(0, Math.min(this.rows - 1, top)),\n bot: Math.max(0, Math.min(this.rows - 1, bot)),\n };\n if (this.scrollRegion.bot < this.scrollRegion.top) {\n this.scrollRegion = { top: 0, bot: this.rows - 1 };\n }\n }\n\n const lastEscape = combined.lastIndexOf('\\x1b');\n this.terminalModeScanTail = lastEscape >= 0 && combined.length - lastEscape < 64\n ? combined.slice(lastEscape)\n : '';\n }\n\n private respondToTerminalQueries(data: string): void {\n if (!this.ptyProcess || !this.screenMirror || !data) return;\n\n const combined = this.pendingQueryScanTail + data;\n const regex = /\\x1b\\[(\\?)?6n/g;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(combined)) !== null) {\n const cursor = this.screenMirror.getCursorPosition();\n const row = Math.max(1, (cursor.row | 0) + 1);\n const col = Math.max(1, (cursor.col | 0) + 1);\n const response = match[1]\n ? `\\x1b[?${row};${col}R`\n : `\\x1b[${row};${col}R`;\n this.ptyProcess.write(response);\n }\n\n this.pendingQueryScanTail = computeTerminalQueryTail(combined);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { createHash, randomUUID } from 'node:crypto';\nimport { execFileSync, spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';\n\nexport interface HostUpgradeBinding {\n /** Trusted packaged helper; supplied hash must come from an immutable artifact pin. */\n helperPath: string;\n helperSha256: string;\n helperProtocol?: 1;\n helperFileIdentity?: string;\n stateDir: string;\n}\ninterface LeaseState {\n schema: 1;\n endpoint: string;\n epoch: number;\n held: boolean;\n owner: string | null;\n tokenHash: string | null;\n}\nexport interface HostLeaseRequest {\n bootId: string;\n epoch: number;\n owner: string;\n token: string;\n}\nconst digest = (value: string | Buffer) => createHash('sha256').update(value).digest('hex');\n\n/** Host-owned durable idle admission fence, opt-in until packaging is supported. */\nexport class HostUpgradeLease {\n readonly bootId = randomUUID();\n private child: ChildProcessWithoutNullStreams | null = null;\n private state: LeaseState;\n private healthy = false;\n private poisoned = false;\n private readonly journal: string;\n constructor(private readonly binding: HostUpgradeBinding, private readonly endpoint: string) {\n if (process.platform !== 'darwin') throw new Error('native_host_upgrade_platform_unproved');\n this.journal = path.join(binding.stateDir, 'upgrade-lease.json');\n this.state = { schema: 1, endpoint, epoch: 0, held: false, owner: null, tokenHash: null };\n }\n async start(): Promise<void> {\n if (this.child && this.child.exitCode === null && this.child.signalCode === null) throw new Error('native_host_binding_already_started');\n fs.mkdirSync(this.binding.stateDir, { recursive: true, mode: 0o700 });\n const dir = fs.lstatSync(this.binding.stateDir);\n if (!dir.isDirectory() || dir.isSymbolicLink() || dir.uid !== process.getuid?.() || (dir.mode & 0o077)) {\n throw new Error('native_host_state_directory_untrusted');\n }\n if (this.binding.helperFileIdentity && this.fileIdentity() !== this.binding.helperFileIdentity) throw new Error('native_host_helper_file_identity_changed');\n if (fs.realpathSync(this.binding.helperPath) !== this.binding.helperPath ||\n digest(fs.readFileSync(this.binding.helperPath)) !== this.binding.helperSha256) {\n throw new Error('native_host_helper_pin_mismatch');\n }\n if (this.binding.helperProtocol === 1 && String(execFileSync(this.binding.helperPath, ['--attest'], { stdio: 'pipe', windowsHide: true })).trim() !== 'adhdev-host-guardian/1') throw new Error('native_host_helper_protocol_mismatch');\n if (this.binding.helperFileIdentity && this.fileIdentity() !== this.binding.helperFileIdentity) throw new Error('native_host_helper_file_identity_changed');\n const lockPath = path.join(this.binding.stateDir, 'instance.lock');\n const priorLock = fs.existsSync(lockPath);\n const child = spawn(this.binding.helperPath, [lockPath], { stdio: 'pipe', windowsHide: true });\n this.child = child;\n child.on('exit', () => { this.healthy = false; });\n child.on('error', () => { this.healthy = false; });\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => { child.stdin.end(); reject(new Error('native_host_lock_timeout')); }, 3000);\n child.once('error', error => { clearTimeout(timer); reject(error); });\n child.once('exit', () => { clearTimeout(timer); reject(new Error('native_host_instance_locked')); });\n child.stdout.once('data', data => {\n clearTimeout(timer);\n if (String(data) !== 'LOCKED\\n') { child.stdin.end(); reject(new Error('native_host_lock_protocol')); return; }\n this.healthy = true; resolve();\n });\n });\n try {\n if (this.binding.helperFileIdentity && (this.fileIdentity() !== this.binding.helperFileIdentity || digest(fs.readFileSync(this.binding.helperPath)) !== this.binding.helperSha256)) throw new Error('native_host_helper_file_identity_changed');\n if (fs.existsSync(this.journal)) {\n const stat = fs.lstatSync(this.journal);\n if (!stat.isFile() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o077)) throw new Error('native_host_lease_untrusted');\n const value = JSON.parse(fs.readFileSync(this.journal, 'utf8')) as LeaseState;\n if (value.schema !== 1 || value.endpoint !== this.endpoint || !Number.isSafeInteger(value.epoch) || value.epoch < 0 ||\n typeof value.held !== 'boolean' || (value.held ? typeof value.owner !== 'string' || typeof value.tokenHash !== 'string' || !/^[a-f0-9]{64}$/.test(value.tokenHash) : value.owner !== null || value.tokenHash !== null)) throw new Error('native_host_lease_corrupt');\n this.state = value;\n } else {\n if (priorLock) throw new Error('native_host_lease_journal_missing');\n this.persist(this.state);\n }\n } catch (error) { await this.close(); throw error; }\n }\n private fileIdentity(): string {\n const s=fs.lstatSync(this.binding.helperPath);\n return JSON.stringify([s.dev,s.ino,s.uid,s.mode,s.size]);\n }\n private persist(value: LeaseState): void {\n const tmp = `${this.journal}.${randomUUID()}.tmp`;\n try {\n const fd = fs.openSync(tmp, 'wx', 0o600);\n try { fs.writeFileSync(fd, JSON.stringify(value)); fs.fsyncSync(fd); } finally { fs.closeSync(fd); }\n fs.renameSync(tmp, this.journal);\n const dir = fs.openSync(this.binding.stateDir, 'r');\n try { fs.fsyncSync(dir); } finally { fs.closeSync(dir); }\n this.state = value;\n } catch (error) {\n // Rename may already have committed: forbid every operation until restart reloads it.\n this.poisoned = true;\n throw error;\n }\n }\n assertHealthy(): void {\n if (this.binding.helperFileIdentity && this.fileIdentity() !== this.binding.helperFileIdentity) throw new Error('native_host_helper_file_identity_changed');\n if (!this.healthy || this.child?.exitCode !== null || this.child?.signalCode !== null || this.poisoned) throw new Error('native_host_lock_or_storage_unavailable');\n }\n assertMutable(): void {\n this.assertHealthy();\n if (this.state.held) throw new Error('native_host_idle_lease_held');\n }\n proof() {\n this.assertHealthy();\n return { bootId: this.bootId, pid: process.pid, endpoint: this.endpoint, epoch: this.state.epoch, held: this.state.held, owner: this.state.owner };\n }\n private validate(request: HostLeaseRequest): void {\n this.assertHealthy();\n if (request.bootId !== this.bootId || request.epoch !== this.state.epoch || !Number.isSafeInteger(request.epoch) ||\n typeof request.owner !== 'string' || !/^[a-zA-Z0-9_-]{8,128}$/.test(request.owner) || typeof request.token !== 'string' || !/^[a-f0-9]{64}$/.test(request.token)) throw new Error('native_host_lease_identity_mismatch');\n }\n acquire(request: HostLeaseRequest, idle: boolean) {\n this.validate(request);\n if (this.state.held) {\n if (this.state.owner !== request.owner || this.state.tokenHash !== digest(request.token)) throw new Error('native_host_lease_owned');\n return this.proof(); // Lost acquire ACK / authenticated reattach after host restart.\n }\n if (!idle) throw new Error('native_host_not_proven_idle');\n this.persist({ ...this.state, held: true, owner: request.owner, tokenHash: digest(request.token) });\n return this.proof();\n }\n release(request: HostLeaseRequest) {\n this.validate(request);\n if (!this.state.held || this.state.owner !== request.owner || this.state.tokenHash !== digest(request.token)) throw new Error('native_host_lease_owned');\n this.persist({ ...this.state, epoch: this.state.epoch + 1, held: false, owner: null, tokenHash: null });\n return this.proof();\n }\n async close(): Promise<void> {\n this.healthy = false;\n const child = this.child;\n this.child = null;\n if (!child || child.exitCode !== null || child.signalCode !== null) return;\n await new Promise<void>(resolve => { child.once('exit', () => resolve()); child.stdin.end(); });\n }\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { resolveInstanceConfigDir } from '@adhdev/session-host-core';\nimport type { SessionBufferSnapshot, SessionHostRecord, SessionTermination } from '@adhdev/session-host-core';\n\nexport interface PersistedRuntimeState {\n record: SessionHostRecord;\n snapshot: SessionBufferSnapshot;\n updatedAt: number;\n}\n\nexport interface PersistedTombstone {\n sessionId: string;\n termination: SessionTermination;\n updatedAt: number;\n}\n\ninterface SessionHostStorageOptions {\n appName?: string;\n /**\n * Explicit storage root (the instance's session-host state dir). Defaults to\n * `<instanceConfigDir>/session-host/<appName>` — derived from\n * ADHDEV_CONFIG_DIR so each daemon instance persists its own runtime records\n * and tombstones. The default instance resolves to `<home>/.adhdev`,\n * byte-identical to the pre-instance layout.\n */\n rootDir?: string;\n}\n\nexport class SessionHostStorage {\n private readonly rootDir: string;\n private readonly runtimesDir: string;\n private readonly tombstonesDir: string;\n\n constructor(options: SessionHostStorageOptions = {}) {\n const appName = options.appName || 'adhdev';\n this.rootDir = options.rootDir\n || path.join(resolveInstanceConfigDir(process.env), 'session-host', appName);\n this.runtimesDir = path.join(this.rootDir, 'runtimes');\n this.tombstonesDir = path.join(this.rootDir, 'tombstones');\n }\n\n /** Unknown/corrupt recovery files also veto idle admission; reads names only. */\n hasRuntimeEntries(): boolean {\n if (!fs.existsSync(this.runtimesDir)) return false;\n const stat = fs.lstatSync(this.runtimesDir);\n if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error('native_host_runtime_storage_untrusted');\n return fs.readdirSync(this.runtimesDir).length > 0;\n }\n\n loadAll(): PersistedRuntimeState[] {\n if (!fs.existsSync(this.runtimesDir)) return [];\n const entries = fs.readdirSync(this.runtimesDir, { withFileTypes: true });\n const states: PersistedRuntimeState[] = [];\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith('.json')) continue;\n const fullPath = path.join(this.runtimesDir, entry.name);\n try {\n const parsed = JSON.parse(fs.readFileSync(fullPath, 'utf8')) as PersistedRuntimeState;\n if (parsed?.record?.sessionId) {\n states.push(parsed);\n }\n } catch {\n // Ignore malformed snapshots; host should still boot.\n }\n }\n return states.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));\n }\n\n save(record: SessionHostRecord, snapshot: SessionBufferSnapshot): void {\n fs.mkdirSync(this.runtimesDir, { recursive: true });\n const filePath = path.join(this.runtimesDir, `${record.sessionId}.json`);\n const payload: PersistedRuntimeState = {\n record,\n snapshot,\n updatedAt: Date.now(),\n };\n fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf8');\n }\n\n remove(sessionId: string): void {\n const filePath = path.join(this.runtimesDir, `${sessionId}.json`);\n try {\n fs.unlinkSync(filePath);\n } catch {\n // File may not exist — ignore.\n }\n }\n\n /**\n * Persist a compact termination tombstone. Kept in a separate directory from\n * live runtimes so it survives the post-exit cleanup of the runtime file and\n * remains inspectable for post-mortem diagnostics.\n */\n saveTombstone(sessionId: string, termination: SessionTermination): void {\n fs.mkdirSync(this.tombstonesDir, { recursive: true });\n const filePath = path.join(this.tombstonesDir, `${sessionId}.json`);\n const payload: PersistedTombstone = {\n sessionId,\n termination,\n updatedAt: Date.now(),\n };\n fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf8');\n }\n\n loadTombstone(sessionId: string): PersistedTombstone | null {\n const filePath = path.join(this.tombstonesDir, `${sessionId}.json`);\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as PersistedTombstone;\n return parsed?.sessionId ? parsed : null;\n } catch {\n return null;\n }\n }\n\n loadAllTombstones(): PersistedTombstone[] {\n if (!fs.existsSync(this.tombstonesDir)) return [];\n const entries = fs.readdirSync(this.tombstonesDir, { withFileTypes: true });\n const states: PersistedTombstone[] = [];\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith('.json')) continue;\n const fullPath = path.join(this.tombstonesDir, entry.name);\n try {\n const parsed = JSON.parse(fs.readFileSync(fullPath, 'utf8')) as PersistedTombstone;\n if (parsed?.sessionId) states.push(parsed);\n } catch {\n // Ignore malformed tombstones.\n }\n }\n return states.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));\n }\n\n removeTombstone(sessionId: string): void {\n const filePath = path.join(this.tombstonesDir, `${sessionId}.json`);\n try {\n fs.unlinkSync(filePath);\n } catch {\n // File may not exist — ignore.\n }\n }\n}\n","import * as path from 'path';\nimport {\n SESSION_HOST_SUPPORTED_REQUEST_TYPES,\n} from '@adhdev/session-host-core';\nimport type {\n SessionHostDiagnostics,\n SessionHostLogEntry,\n SessionHostRecord,\n SessionHostRequestTrace,\n SessionHostRuntimeTransition,\n} from '@adhdev/session-host-core';\n\nexport const MAX_RECENT_DIAGNOSTICS = 200;\n\n/**\n * Absolute path of the running host script, for `SessionHostDiagnostics.hostEntryPath`.\n *\n * `process.argv[1]` is what the parent daemon actually spawned\n * (`spawn(node, [entry])` in managed-host's `spawnHost`), so it is exactly the\n * value a client wants to compare against its own `resolveEntry()`. It is used\n * in preference to `__filename` because the shipped artifact is a single\n * bundled file whose `__filename` is the same path anyway, while `argv[1]`\n * additionally survives the ESM build with no CJS-only globals.\n *\n * Returns undefined rather than guessing when argv[1] is absent (e.g. an\n * embedded/test host), so callers see \"unknown\" instead of a wrong path.\n */\nfunction resolveHostEntryPath(): string | undefined {\n const entry = process.argv[1];\n if (typeof entry !== 'string' || !entry.trim()) return undefined;\n try {\n return path.resolve(entry);\n } catch {\n return entry;\n }\n}\n\nexport function pushRecent<T>(bucket: T[], entry: T, max = MAX_RECENT_DIAGNOSTICS): void {\n bucket.push(entry);\n if (bucket.length > max) {\n bucket.splice(0, bucket.length - max);\n }\n}\n\nexport function getSessionHostRecoveryLabel(record: SessionHostRecord): string | null {\n const recoveryState = typeof record.meta?.runtimeRecoveryState === 'string'\n ? String(record.meta.runtimeRecoveryState).trim()\n : '';\n if (!recoveryState) return null;\n if (recoveryState === 'auto_resumed') return 'restored after restart';\n if (recoveryState === 'resume_failed') return 'restore failed';\n if (recoveryState === 'host_restart_interrupted') return 'host restart interrupted';\n if (recoveryState === 'orphan_snapshot') return 'snapshot recovered';\n return recoveryState.replace(/_/g, ' ');\n}\n\nexport function getSessionSurfaceKind(\n record: SessionHostRecord,\n): 'live_runtime' | 'recovery_snapshot' | 'inactive_record' {\n if (['starting', 'running', 'stopping', 'interrupted'].includes(record.lifecycle)) {\n return 'live_runtime';\n }\n if ((record.lifecycle === 'stopped' || record.lifecycle === 'failed') && (record.meta?.restoredFromStorage === true || getSessionHostRecoveryLabel(record))) {\n return 'recovery_snapshot';\n }\n return 'inactive_record';\n}\n\nexport function annotateSessionSurface(record: SessionHostRecord): SessionHostRecord {\n return {\n ...record,\n surfaceKind: getSessionSurfaceKind(record),\n };\n}\n\nexport function sanitizeDiagnosticsRecord(record: SessionHostRecord): SessionHostRecord {\n return {\n ...record,\n launchCommand: {\n command: record.launchCommand.command,\n args: Array.isArray(record.launchCommand.args) ? [...record.launchCommand.args] : [],\n },\n };\n}\n\nexport interface BuildHostDiagnosticsParams {\n payload?: { includeSessions?: boolean; limit?: number };\n hostStartedAt: number;\n endpointPath: string;\n runtimeCount: number;\n sessions: SessionHostRecord[];\n recentLogs: SessionHostLogEntry[];\n recentRequests: SessionHostRequestTrace[];\n recentTransitions: SessionHostRuntimeTransition[];\n}\n\nexport function buildHostDiagnostics(params: BuildHostDiagnosticsParams): SessionHostDiagnostics {\n const limit = Math.max(1, Math.min(200, Number(params.payload?.limit) || 50));\n const allSessions = params.payload?.includeSessions === false\n ? undefined\n : params.sessions\n .map((record) => annotateSessionSurface(record))\n .map((record) => sanitizeDiagnosticsRecord(record));\n const liveRuntimes = allSessions?.filter((record) => record.surfaceKind === 'live_runtime');\n const recoverySnapshots = allSessions?.filter((record) => record.surfaceKind === 'recovery_snapshot').slice(0, limit);\n const inactiveRecords = allSessions?.filter((record) => record.surfaceKind === 'inactive_record').slice(0, limit);\n const sessions = allSessions\n ? [\n ...(liveRuntimes || []),\n ...(recoverySnapshots || []),\n ...(inactiveRecords || []),\n ]\n : undefined;\n return {\n hostStartedAt: params.hostStartedAt,\n endpoint: params.endpointPath,\n // Self-reported so a client can tell WHICH install this host runs from\n // without needing process-inspection privileges. See SessionHostDiagnostics.\n hostEntryPath: resolveHostEntryPath(),\n runtimeCount: params.runtimeCount,\n supportedRequestTypes: [...SESSION_HOST_SUPPORTED_REQUEST_TYPES],\n sessions,\n liveRuntimes,\n recoverySnapshots,\n inactiveRecords,\n recentLogs: params.recentLogs.slice(-limit),\n recentRequests: params.recentRequests.slice(-limit),\n recentTransitions: params.recentTransitions.slice(-limit),\n };\n}\n","import {\n replayLaunchEnv,\n resolveSessionHostCols,\n resolveSessionHostRows,\n} from '@adhdev/session-host-core';\nimport type {\n CreateSessionPayload,\n SessionHostDuplicateSessionGroup,\n SessionHostRecord,\n} from '@adhdev/session-host-core';\nimport type { PersistedRuntimeState } from './storage.js';\n\nexport function compareDuplicateCandidates(a: SessionHostRecord, b: SessionHostRecord): number {\n const score = (record: SessionHostRecord) => {\n const lifecycleScore = record.lifecycle === 'running'\n ? 4\n : record.lifecycle === 'starting'\n ? 3\n : record.lifecycle === 'stopping'\n ? 2\n : record.lifecycle === 'interrupted'\n ? 1\n : 0;\n return [\n lifecycleScore,\n record.writeOwner ? 1 : 0,\n Array.isArray(record.attachedClients) ? record.attachedClients.length : 0,\n record.lastActivityAt || 0,\n record.startedAt || 0,\n record.createdAt || 0,\n ];\n };\n\n const aScore = score(a);\n const bScore = score(b);\n for (let i = 0; i < aScore.length; i += 1) {\n if (aScore[i] === bScore[i]) continue;\n return bScore[i] - aScore[i];\n }\n return 0;\n}\n\nexport interface DuplicatePrunePlan {\n duplicateGroups: SessionHostDuplicateSessionGroup[];\n keptSessionIds: string[];\n // Records to prune, in group order. Only populated for non-dry-run callers.\n duplicateRecords: SessionHostRecord[];\n}\n\nexport function planDuplicatePrune(\n sessions: SessionHostRecord[],\n filters: { providerFilter: string; workspaceFilter: string },\n): DuplicatePrunePlan {\n const candidates = sessions\n .filter((record) => ['starting', 'running', 'stopping', 'interrupted'].includes(record.lifecycle))\n .filter((record) => !filters.providerFilter || record.providerType === filters.providerFilter)\n .filter((record) => !filters.workspaceFilter || record.workspace === filters.workspaceFilter);\n\n const groups = new Map<string, SessionHostRecord[]>();\n for (const record of candidates) {\n const providerSessionId = typeof record.meta?.providerSessionId === 'string'\n ? String(record.meta.providerSessionId).trim()\n : '';\n if (!providerSessionId) continue;\n const bindingKey = `${record.providerType}::${record.workspace}::${providerSessionId}`;\n const bucket = groups.get(bindingKey) || [];\n bucket.push(record);\n groups.set(bindingKey, bucket);\n }\n\n const duplicateGroups: SessionHostDuplicateSessionGroup[] = [];\n const keptSessionIds: string[] = [];\n const duplicateRecords: SessionHostRecord[] = [];\n\n for (const [bindingKey, records] of groups.entries()) {\n if (records.length < 2) continue;\n const sorted = [...records].sort((a, b) => compareDuplicateCandidates(a, b));\n const kept = sorted[0];\n const duplicates = sorted.slice(1);\n const providerSessionId = typeof kept.meta?.providerSessionId === 'string'\n ? String(kept.meta.providerSessionId)\n : '';\n duplicateGroups.push({\n bindingKey,\n providerType: kept.providerType,\n workspace: kept.workspace,\n providerSessionId,\n keptSessionId: kept.sessionId,\n prunedSessionIds: duplicates.map((record) => record.sessionId),\n });\n keptSessionIds.push(kept.sessionId);\n for (const duplicate of duplicates) {\n duplicateRecords.push(duplicate);\n }\n }\n\n return { duplicateGroups, keptSessionIds, duplicateRecords };\n}\n\nexport function buildPayloadFromRecord(record: SessionHostRecord): CreateSessionPayload {\n return {\n sessionId: record.sessionId,\n runtimeKey: record.runtimeKey,\n displayName: record.displayName,\n providerType: record.providerType,\n category: record.category,\n workspace: record.workspace,\n launchCommand: { ...record.launchCommand, env: replayLaunchEnv(record.launchCommand), envMode: 'launch_overrides' },\n cols: resolveSessionHostCols(typeof record.meta?.sessionHostCols === 'number' ? record.meta.sessionHostCols as number : undefined),\n rows: resolveSessionHostRows(typeof record.meta?.sessionHostRows === 'number' ? record.meta.sessionHostRows as number : undefined),\n meta: record.meta,\n };\n}\n\nexport interface RecoveredRuntimeState {\n recoveredRecord: SessionHostRecord;\n wasLiveRuntime: boolean;\n hadRecoveryInterest: boolean;\n}\n\nexport function buildRecoveredRecord(persisted: PersistedRuntimeState): RecoveredRuntimeState {\n const wasLiveRuntime = !['stopped', 'failed'].includes(persisted.record.lifecycle);\n const hadAttachedClients = Array.isArray(persisted.record.attachedClients) && persisted.record.attachedClients.length > 0;\n const hadWriteOwner = !!persisted.record.writeOwner;\n const hadRecoveryInterest = hadAttachedClients || hadWriteOwner;\n const recoveredRecord: SessionHostRecord = {\n ...persisted.record,\n attachedClients: [],\n writeOwner: null,\n lifecycle: wasLiveRuntime ? 'stopped' : persisted.record.lifecycle,\n lastActivityAt: Date.now(),\n meta: {\n ...(persisted.record.meta || {}),\n restoredFromStorage: true,\n runtimeRecoveryState: wasLiveRuntime ? 'orphan_snapshot' : 'snapshot',\n runtimeHadAttachedClientsAtCrash: hadAttachedClients,\n runtimeHadWriteOwnerAtCrash: hadWriteOwner,\n runtimeAutoResumeSkipped: wasLiveRuntime && hadRecoveryInterest,\n },\n };\n return { recoveredRecord, wasLiveRuntime, hadRecoveryInterest };\n}\n","import type {\n SessionBufferSnapshot,\n SessionHostRecord,\n SessionHostRequest,\n} from '@adhdev/session-host-core';\n\nexport function getRequestSessionId(request: SessionHostRequest): string | undefined {\n const payload = (request as { payload?: Record<string, unknown> }).payload;\n return typeof payload?.sessionId === 'string' ? payload.sessionId : undefined;\n}\n\nexport function getRequestClientId(request: SessionHostRequest): string | undefined {\n const payload = (request as { payload?: Record<string, unknown> }).payload;\n return typeof payload?.clientId === 'string' ? payload.clientId : undefined;\n}\n\n// Merges the registry buffer snapshot with the live runtime's rendered viewport\n// text. For incremental reads (sinceSeq provided) the buffer snapshot is\n// authoritative and the runtime viewport is not overlaid.\nexport function mergeRuntimeSnapshot(\n base: SessionBufferSnapshot,\n record: SessionHostRecord | null | undefined,\n opts: { sinceSeq?: number; runtimeText: string },\n): SessionBufferSnapshot {\n const cols = typeof record?.meta?.sessionHostCols === 'number' ? (record.meta.sessionHostCols as number) : 80;\n const rows = typeof record?.meta?.sessionHostRows === 'number' ? (record.meta.sessionHostRows as number) : 24;\n if (typeof opts.sinceSeq === 'number' || !opts.runtimeText) {\n return {\n ...base,\n text: withReplayResyncPreamble(base.text, opts.sinceSeq),\n cols,\n rows,\n };\n }\n return {\n ...base,\n text: opts.runtimeText,\n truncated: false,\n cols,\n rows,\n };\n}\n\n/** Erase the whole screen and home the cursor. */\nconst REPLAY_RESYNC_PREAMBLE = '\\x1b[2J\\x1b[H';\n\n/**\n * TRIM-BOUNDARY defence, paired with `SessionRingBuffer`'s head repair.\n *\n * `sinceSeq: 0` (\"Load older terminal output\") takes the raw ring-buffer\n * branch above, so the browser xterm parses bytes that begin wherever eviction\n * happened to cut. The buffer now strips a torn *prefix*, but it cannot\n * conjure back state that was evicted rather than damaged: when the cut lands\n * after the session's opening `\\x1b[2J\\x1b[H`, the retained head is perfectly\n * well-formed text and no repair at that layer applies, yet the receiving\n * terminal was never told to clear or home. Output then lands wherever the\n * cursor already was, which is the large blank band at the top of the reported\n * screenshot.\n *\n * So put the terminal into a known state before replaying into it. This is\n * only correct for a from-scratch replay: an incremental `sinceSeq: N` read is\n * a delta appended to what the client already shows, and clearing there would\n * erase the scrollback the client is extending. `sinceSeq: 0` is the\n * \"give me everything you still have\" request, and `undefined` reaches this\n * branch only when the runtime viewport was unavailable — a full read too.\n */\nfunction withReplayResyncPreamble(text: string, sinceSeq?: number): string {\n if (typeof sinceSeq === 'number' && sinceSeq > 0) return text;\n if (!text) return text;\n if (text.startsWith(REPLAY_RESYNC_PREAMBLE)) return text;\n return `${REPLAY_RESYNC_PREAMBLE}${text}`;\n}\n"],"mappings":"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","names":["fs","path","import_session_host_core","fs","path","import_session_host_core","fs","resolve","fs","path","import_node_crypto","resolve","fs","path","import_session_host_core","path","import_session_host_core","import_session_host_core","relative","resolve","waiters"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/guardian-artifact.ts","../src/server.ts","../src/runtime.ts","../src/upgrade-lease.ts","../src/storage.ts","../src/session-diagnostics.ts","../src/session-lifecycle.ts","../src/session-protocol.ts","../src/threadpool-watchdog.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { randomUUID } from 'crypto';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n SessionHostClient,\n formatRuntimeOwner,\n getDefaultSessionHostEndpoint,\n resolveAttachableRuntimeRecord,\n resolveInstanceConfigDir,\n resolveRuntimeRecord,\n resolveSessionHostIpcKey,\n type SessionHostEvent,\n type SessionHostRecord,\n} from '@adhdev/session-host-core';\nimport { resolveGuardianArtifact, type GuardianArtifactPins } from './guardian-artifact.js';\nimport { SessionHostServer } from './server.js';\nimport { startThreadpoolWatchdog, writeStderrLineSync } from './threadpool-watchdog.js';\n\nexport { SessionHostServer } from './server.js';\nexport { startThreadpoolWatchdog } from './threadpool-watchdog.js';\nexport type { SessionHostServerOptions } from './server.js';\nexport { resolveGuardianArtifact } from './guardian-artifact.js';\nexport type { GuardianArtifactPins } from './guardian-artifact.js';\nexport type { HostUpgradeBinding } from './upgrade-lease.js';\n\nconst SESSION_HOST_APP_NAME = process.env.ADHDEV_SESSION_HOST_NAME || 'adhdev';\nconst SHUTDOWN_DEADLINE_MS = 10_000;\n\n// Instance identity comes from the parent daemon's pinned env\n// (ADHDEV_CONFIG_DIR — see managed-host buildEnv). The endpoint, pid file, and\n// storage root all derive from that ONE resolution so the host process lives\n// entirely inside its own instance's namespace: two simultaneous instances\n// (stable/preview/standalone/custom) can never attach to, kill, or persist\n// over each other's session host. The default instance yields the legacy\n// un-suffixed socket and `<home>/.adhdev` paths, byte-identical to before.\nconst INSTANCE_CONFIG_DIR = resolveInstanceConfigDir(process.env);\nconst INSTANCE_IPC_KEY = resolveSessionHostIpcKey(INSTANCE_CONFIG_DIR);\n\nfunction getSessionHostEndpoint() {\n return getDefaultSessionHostEndpoint(SESSION_HOST_APP_NAME, { ipcKey: INSTANCE_IPC_KEY });\n}\n\nfunction getSessionHostStorageRoot(): string {\n return path.join(INSTANCE_CONFIG_DIR, 'session-host', SESSION_HOST_APP_NAME);\n}\n\nfunction getSessionHostPidFile(appName: string): string {\n const dir = INSTANCE_CONFIG_DIR;\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n return path.join(dir, `${appName}-session-host.pid`);\n}\n\nfunction writeSessionHostPid(appName: string): void {\n fs.writeFileSync(getSessionHostPidFile(appName), String(process.pid), 'utf8');\n}\n\nfunction removeSessionHostPid(appName: string): void {\n try {\n fs.unlinkSync(getSessionHostPidFile(appName));\n } catch {\n // noop\n }\n}\n\nfunction parseArgs(argv: string[]) {\n const [command, ...rest] = argv;\n const readOnly = rest.includes('--read-only');\n const takeover = rest.includes('--takeover');\n const showAll = rest.includes('--all');\n const positional = rest.filter((arg) => arg !== '--read-only' && arg !== '--takeover' && arg !== '--all');\n return {\n command: command || 'serve',\n positional,\n readOnly,\n takeover,\n showAll,\n };\n}\n\nasync function runServer(): Promise<void> {\n let upgradeBinding;\n const pinFile = process.env.ADHDEV_WORKER_GUARDIAN_PINS_FILE;\n if (pinFile) {\n const stat = fs.lstatSync(pinFile);\n if (process.platform !== 'darwin' || fs.realpathSync(pinFile) !== pinFile || !stat.isFile() || stat.uid !== process.getuid?.() || (stat.mode & 0o077)) throw new Error('guardian_launch_pins_untrusted');\n const pins = JSON.parse(fs.readFileSync(pinFile, 'utf8')) as GuardianArtifactPins;\n if (pins.nodePath !== fs.realpathSync(process.execPath) || pins.hostEntryPath !== fs.realpathSync(process.argv[1]) ||\n pins.stateDir !== path.join(INSTANCE_CONFIG_DIR, 'session-host')) throw new Error('guardian_launch_executable_or_instance_mismatch');\n upgradeBinding = resolveGuardianArtifact(pins);\n }\n const server = new SessionHostServer({\n appName: SESSION_HOST_APP_NAME,\n upgradeBinding,\n endpoint: getSessionHostEndpoint(),\n storageRootDir: getSessionHostStorageRoot(),\n });\n if (!upgradeBinding) writeSessionHostPid(SESSION_HOST_APP_NAME);\n await server.start();\n if (upgradeBinding) writeSessionHostPid(SESSION_HOST_APP_NAME);\n\n const shutdown = async () => {\n // A wedged thread pool can leave stop() pending forever; the 2026-10-21\n // host ignored SIGTERM this way and needed SIGKILL. Exit regardless.\n const deadline = setTimeout(() => {\n writeStderrLineSync(`[session-host] stop() did not finish within ${SHUTDOWN_DEADLINE_MS / 1000}s; exiting anyway.`);\n removeSessionHostPid(SESSION_HOST_APP_NAME);\n process.exit(1);\n }, SHUTDOWN_DEADLINE_MS);\n deadline.unref?.();\n await server.stop();\n removeSessionHostPid(SESSION_HOST_APP_NAME);\n process.exit(0);\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n // Exiting ends every hosted session, but in this state none of them can take\n // input anyway; the daemon respawns the host as soon as the socket drops.\n startThreadpoolWatchdog({\n onStall: (stalledForMs) => {\n writeStderrLineSync(\n `[session-host] libuv thread pool made no progress for ${Math.round(stalledForMs / 1000)}s ` +\n '(PTY writes cannot complete); exiting so the daemon respawns the host.',\n );\n try {\n server.flushAllPersistence();\n } catch {\n // noop — exiting regardless\n }\n removeSessionHostPid(SESSION_HOST_APP_NAME);\n process.exit(1);\n },\n });\n\n // Fallback: flush persistence on any exit (covers Windows where SIGTERM is unsupported)\n process.on('exit', () => {\n server.flushAllPersistence();\n removeSessionHostPid(SESSION_HOST_APP_NAME);\n });\n\n // Keep the host alive; IPC transport wiring comes next.\n await new Promise<void>(() => {});\n}\n\nasync function listRuntimes(showAll = false): Promise<void> {\n const client = new SessionHostClient({ endpoint: getSessionHostEndpoint() });\n try {\n const response = await client.request<SessionHostRecord[]>({\n type: 'list_sessions',\n payload: {},\n });\n if (!response.success) {\n throw new Error(response.error || 'Failed to list runtimes');\n }\n const runtimes = (response.result || []).filter((runtime: SessionHostRecord) => showAll || runtime.lifecycle !== 'stopped');\n if (runtimes.length === 0) {\n console.log('No runtimes.');\n return;\n }\n console.log('runtimeKey\\tlifecycle\\towner\\tworkspace\\tid\\tdisplayName');\n for (const runtime of runtimes) {\n console.log([\n runtime.runtimeKey,\n runtime.lifecycle,\n formatRuntimeOwner(runtime),\n runtime.workspaceLabel,\n runtime.sessionId,\n runtime.displayName,\n ].join('\\t'));\n }\n } finally {\n await client.close().catch(() => {});\n }\n}\n\nasync function attachRuntime(target: string, readOnly = false, takeover = false): Promise<void> {\n const client = new SessionHostClient({ endpoint: getSessionHostEndpoint() });\n const clientId = `local-terminal-${process.pid}-${randomUUID().slice(0, 8)}`;\n let lastSeq = 0;\n let restoredRawMode = false;\n let runtimeId = '';\n let localReadOnly = readOnly;\n\n const cleanup = async () => {\n process.stdout.off('resize', handleResize);\n process.stdin.off('data', handleInput);\n process.stdin.pause();\n if (process.stdin.isTTY && restoredRawMode) {\n process.stdin.setRawMode(false);\n }\n await client.request({\n type: 'release_write',\n payload: {\n sessionId: runtimeId,\n clientId,\n },\n }).catch(() => ({ success: false }));\n await client.request({\n type: 'detach_session',\n payload: {\n sessionId: runtimeId,\n clientId,\n },\n }).catch(() => ({ success: false }));\n await client.close().catch(() => {});\n };\n\n const handleResize = () => {\n void client.request({\n type: 'resize_session',\n payload: {\n sessionId: runtimeId,\n cols: process.stdout.columns || 80,\n rows: process.stdout.rows || 24,\n },\n }).catch(() => ({ success: false }));\n };\n\n const sendInputWithTakeover = async (data: string) => {\n let response = await client.request({\n type: 'send_input',\n payload: {\n sessionId: runtimeId,\n clientId,\n data,\n },\n });\n if (!response.success && response.error?.startsWith('Write owned by ')) {\n const ownerResponse = await client.request<SessionHostRecord>({\n type: 'acquire_write',\n payload: {\n sessionId: runtimeId,\n clientId,\n ownerType: 'user',\n force: true,\n },\n });\n if (ownerResponse.success && ownerResponse.result) {\n response = await client.request({\n type: 'send_input',\n payload: {\n sessionId: runtimeId,\n clientId,\n data,\n },\n });\n if (response.success) {\n process.stderr.write(`Took control of ${ownerResponse.result.runtimeKey}.\\n`);\n }\n }\n }\n return response;\n };\n\n const handleInput = (chunk: Buffer) => {\n if (!localReadOnly && chunk.length === 1 && chunk[0] === 0x1d) {\n void cleanup().finally(() => process.exit(0));\n return;\n }\n if (localReadOnly) return;\n void sendInputWithTakeover(chunk.toString('utf8')).catch(() => ({ success: false }));\n };\n\n try {\n if (readOnly && takeover) {\n throw new Error('Use either --read-only or --takeover, not both');\n }\n\n const listResponse = await client.request<SessionHostRecord[]>({\n type: 'list_sessions',\n payload: {},\n });\n if (!listResponse.success || !listResponse.result) {\n throw new Error(listResponse.error || 'Failed to list runtimes');\n }\n let runtimeRecord = resolveAttachableRuntimeRecord(listResponse.result, target);\n runtimeId = runtimeRecord.sessionId;\n\n if (runtimeRecord.lifecycle === 'interrupted' && !readOnly) {\n const resumeResponse = await client.request<SessionHostRecord>({\n type: 'resume_session',\n payload: {\n sessionId: runtimeId,\n },\n });\n if (resumeResponse.success && resumeResponse.result) {\n runtimeRecord = resumeResponse.result;\n } else {\n process.stderr.write(\n `Runtime ${runtimeRecord.runtimeKey} could not be resumed automatically: ${resumeResponse.error || 'unknown error'}\\n`,\n );\n }\n }\n\n let effectiveReadOnly = readOnly;\n if (!effectiveReadOnly && runtimeRecord.writeOwner && runtimeRecord.writeOwner.clientId !== clientId && !takeover) {\n process.stderr.write(\n `Runtime ${runtimeRecord.runtimeKey} is currently owned by ${runtimeRecord.writeOwner.clientId}; first input will take control here.\\n`,\n );\n }\n localReadOnly = effectiveReadOnly;\n\n const attachResponse = await client.request<SessionHostRecord>({\n type: 'attach_session',\n payload: {\n sessionId: runtimeId,\n clientId,\n clientType: 'local-terminal',\n readOnly: effectiveReadOnly,\n },\n });\n if (!attachResponse.success) {\n throw new Error(attachResponse.error || `Failed to attach runtime ${runtimeId}`);\n }\n const attachedRecord = attachResponse.result || null;\n\n if (!effectiveReadOnly && takeover) {\n const ownerResponse = await client.request<SessionHostRecord>({\n type: 'acquire_write',\n payload: {\n sessionId: runtimeId,\n clientId,\n ownerType: 'user',\n force: takeover,\n },\n });\n if (!ownerResponse.success) {\n throw new Error(ownerResponse.error || `Failed to acquire write owner for runtime ${runtimeId}`);\n }\n }\n\n const snapshotResponse = await client.request<{ seq: number; text: string; truncated: boolean; cols?: number; rows?: number }>({\n type: 'get_snapshot',\n payload: { sessionId: runtimeId },\n });\n if (!snapshotResponse.success) {\n throw new Error(snapshotResponse.error || `Failed to read runtime snapshot ${runtimeId}`);\n }\n lastSeq = snapshotResponse.result?.seq || 0;\n if (snapshotResponse.result?.text) {\n process.stdout.write(snapshotResponse.result.text);\n }\n if (attachedRecord?.lifecycle === 'stopped' || attachedRecord?.lifecycle === 'failed' || attachedRecord?.lifecycle === 'interrupted') {\n process.stderr.write(`Runtime ${attachedRecord.runtimeKey} is already ${attachedRecord.lifecycle}. Detached after snapshot.\\n`);\n await cleanup();\n return;\n }\n\n const stopSignals = ['SIGINT', 'SIGTERM', 'SIGHUP'] as const;\n const signalHandlers = stopSignals.map((signal) => {\n const handler = () => {\n void cleanup().finally(() => process.exit(0));\n };\n process.on(signal, handler);\n return { signal, handler };\n });\n\n const unsubscribe = client.onEvent((event: SessionHostEvent) => {\n if (!('sessionId' in event)) return;\n if (event.sessionId !== runtimeId) return;\n if (event.type === 'session_output') {\n if (event.seq <= lastSeq) return;\n lastSeq = event.seq;\n process.stdout.write(event.data);\n return;\n }\n if (event.type === 'session_exit') {\n void cleanup().finally(() => {\n for (const { signal, handler } of signalHandlers) {\n process.off(signal, handler);\n }\n unsubscribe();\n process.exit(event.exitCode ?? 0);\n });\n }\n });\n\n process.stdout.on('resize', handleResize);\n process.stdin.on('data', handleInput);\n process.stdin.resume();\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n restoredRawMode = true;\n }\n handleResize();\n if (!effectiveReadOnly) {\n process.stderr.write(`Attached to runtime ${attachedRecord?.runtimeKey || runtimeId}. Press Ctrl+] to detach.\\n`);\n } else {\n process.stderr.write(`Attached to runtime ${attachedRecord?.runtimeKey || runtimeId} (read-only).\\n`);\n }\n await new Promise<void>(() => {});\n } catch (error) {\n await cleanup().catch(() => {});\n throw error;\n }\n}\n\nasync function main(): Promise<void> {\n const { command, positional, readOnly, takeover, showAll } = parseArgs(process.argv.slice(2));\n if (command === 'serve') {\n await runServer();\n return;\n }\n if (command === 'list') {\n await listRuntimes(showAll);\n return;\n }\n if (command === 'attach') {\n const target = positional[0];\n if (!target) {\n throw new Error('runtime target is required: adhdev-sessiond attach <runtimeId|runtimeKey>');\n }\n await attachRuntime(target, readOnly, takeover);\n return;\n }\n if (command === 'resume') {\n const target = positional[0];\n if (!target) {\n throw new Error('runtime target is required: adhdev-sessiond resume <runtimeId|runtimeKey>');\n }\n const client = new SessionHostClient({ endpoint: getSessionHostEndpoint() });\n try {\n const listResponse = await client.request<SessionHostRecord[]>({ type: 'list_sessions', payload: {} });\n if (!listResponse.success || !listResponse.result) {\n throw new Error(listResponse.error || 'Failed to list runtimes');\n }\n const runtimeRecord = resolveRuntimeRecord(listResponse.result, target);\n const resumeResponse = await client.request<SessionHostRecord>({\n type: 'resume_session',\n payload: {\n sessionId: runtimeRecord.sessionId,\n },\n });\n if (!resumeResponse.success || !resumeResponse.result) {\n throw new Error(resumeResponse.error || `Failed to resume runtime ${runtimeRecord.runtimeKey}`);\n }\n console.log(`Resumed ${resumeResponse.result.runtimeKey} (${resumeResponse.result.sessionId})`);\n } finally {\n await client.close().catch(() => {});\n }\n return;\n }\n throw new Error(`Unknown command: ${command}`);\n}\n\n// Swallowing uncaught exceptions keeps a transient native fault (e.g. node-pty on\n// Windows) from killing sessions that are otherwise healthy. Swallowing them\n// *without limit* turns a permanently broken process into a zombie service that\n// still holds the socket and pid file while failing every request. So the intent\n// is preserved with a bound: tolerate bursts, exit once the process is clearly\n// wedged rather than pretending to serve.\nconst UNCAUGHT_EXCEPTION_WINDOW_MS = 60_000;\nconst UNCAUGHT_EXCEPTION_LIMIT = 10;\n\nexport function createUncaughtExceptionLimiter(\n windowMs = UNCAUGHT_EXCEPTION_WINDOW_MS,\n limit = UNCAUGHT_EXCEPTION_LIMIT,\n) {\n // null (not 0) marks \"no window yet\" — 0 is a valid timestamp, and using it as\n // the sentinel would reset the window on every call in a 0-based clock.\n let windowStartedAt: number | null = null;\n let countInWindow = 0;\n return function shouldExit(now: number): { exit: boolean; countInWindow: number } {\n if (windowStartedAt === null || now - windowStartedAt > windowMs) {\n windowStartedAt = now;\n countInWindow = 0;\n }\n countInWindow += 1;\n return { exit: countInWindow > limit, countInWindow };\n };\n}\n\nif (require.main === module) {\n const shouldExitOnUncaught = createUncaughtExceptionLimiter();\n\n process.on('uncaughtException', (err) => {\n console.error(`[session-host] Uncaught exception: ${err?.message}\\n${err?.stack || ''}`);\n const { exit, countInWindow } = shouldExitOnUncaught(Date.now());\n if (!exit) return;\n // Repeated faults in one window: the process is wedged, not hiccuping.\n console.error(\n `[session-host] ${countInWindow} uncaught exceptions within ` +\n `${UNCAUGHT_EXCEPTION_WINDOW_MS / 1000}s (limit ${UNCAUGHT_EXCEPTION_LIMIT}); shutting down.`,\n );\n removeSessionHostPid(SESSION_HOST_APP_NAME);\n process.exit(1);\n });\n process.on('unhandledRejection', (reason: any) => {\n console.error(`[session-host] Unhandled rejection: ${reason?.message || reason}`);\n });\n\n void main().catch((error) => {\n console.error(error instanceof Error ? error.message : error);\n process.exit(1);\n });\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { createHash } from 'node:crypto';\nimport type { HostUpgradeBinding } from './upgrade-lease.js';\nconst sha = (b: string | Buffer) => createHash('sha256').update(b).digest('hex');\nexport interface GuardianArtifactPins {\n packageRoot: string;\n manifestPath: string;\n manifestSha256: string;\n version: string;\n commit: string;\n nodePath: string;\n daemonEntryPath: string;\n cliEntryPath: string;\n hostEntryPath: string;\n stateDir: string;\n}\n/** The manifest pin must come from the supervisor's immutable artifact plan. */\nexport function resolveGuardianArtifact(pins: GuardianArtifactPins): HostUpgradeBinding {\n if (process.platform !== 'darwin') throw new Error('guardian_artifact_platform_unsupported');\n const root = fs.realpathSync(pins.packageRoot);\n const regular = (file: string) => {\n if (!path.isAbsolute(file) || fs.realpathSync(file) !== file || !fs.lstatSync(file).isFile()) throw new Error('guardian_artifact_path_untrusted');\n return file;\n };\n const manifestPath = regular(pins.manifestPath);\n if (path.relative(root, manifestPath).startsWith('..')) throw new Error('guardian_artifact_manifest_escape');\n const bytes = fs.readFileSync(manifestPath);\n if (!/^[a-f0-9]{64}$/.test(pins.manifestSha256) || sha(bytes) !== pins.manifestSha256) throw new Error('guardian_artifact_manifest_pin_mismatch');\n const m = JSON.parse(String(bytes));\n if (m.schema !== 1 || m.protocol !== 1 || m.platform !== 'darwin' || m.arch !== process.arch || m.version !== pins.version || m.commit !== pins.commit) throw new Error('guardian_artifact_build_mismatch');\n const packageBytes=fs.readFileSync(regular(path.join(root,'package.json')));\n if (sha(packageBytes)!==m.packageJsonSha256 || JSON.parse(String(packageBytes)).version!==pins.version) throw new Error('guardian_artifact_package_version_mismatch');\n const expected = { daemon:pins.daemonEntryPath, cli:pins.cliEntryPath, host:pins.hostEntryPath };\n for (const kind of ['daemon','cli','host','helper'] as const) {\n const entry = m.files?.[kind];\n if (typeof entry?.path !== 'string' || path.isAbsolute(entry.path) || !/^[a-f0-9]{64}$/.test(entry.sha256 ?? '')) throw new Error('guardian_artifact_entry_untrusted');\n const file = path.resolve(root, entry.path);\n if (path.relative(root,file).startsWith('..') || (kind !== 'helper' && file !== expected[kind]) || sha(fs.readFileSync(regular(file))) !== entry.sha256) throw new Error('guardian_artifact_payload_pin_mismatch');\n }\n if (sha(fs.readFileSync(regular(pins.nodePath))) !== m.nodeSha256) throw new Error('guardian_artifact_node_pin_mismatch');\n const helperStat=fs.lstatSync(path.resolve(root,m.files.helper.path));\n if (helperStat.mode & 0o222) throw new Error('guardian_artifact_helper_writable');\n return { helperFileIdentity:JSON.stringify([helperStat.dev,helperStat.ino,helperStat.uid,helperStat.mode,helperStat.size]), helperPath:path.resolve(root,m.files.helper.path), helperSha256:m.files.helper.sha256, stateDir:pins.stateDir, helperProtocol:1 };\n}\n","import { EventEmitter } from 'events';\nimport * as fs from 'fs';\nimport * as net from 'net';\nimport * as path from 'node:path';\nimport {\n SessionHostRegistry,\n classifyTermination,\n createLineParser,\n createResponseEnvelope,\n getDefaultSessionHostEndpoint,\n isTerminalRecord,\n} from '@adhdev/session-host-core';\nimport type {\n CreateSessionPayload,\n SessionAttachedClient,\n SessionHostDiagnostics,\n SessionHostEndpoint,\n SessionHostEvent,\n SessionHostLogEntry,\n SessionHostPruneDuplicatesResult,\n SessionHostRecord,\n SessionHostRequestEnvelope,\n SessionHostRequestTrace,\n SessionHostRequest,\n SessionHostRuntimeTransition,\n SessionHostResponse,\n SessionTermination,\n} from '@adhdev/session-host-core';\nimport { PtySessionRuntime } from './runtime.js';\nimport { HostUpgradeLease, type HostUpgradeBinding } from './upgrade-lease.js';\nimport { SessionHostStorage } from './storage.js';\nimport {\n buildHostDiagnostics,\n pushRecent,\n} from './session-diagnostics.js';\nimport {\n buildPayloadFromRecord,\n buildRecoveredRecord,\n planDuplicatePrune,\n} from './session-lifecycle.js';\nimport {\n getRequestClientId,\n getRequestSessionId,\n mergeRuntimeSnapshot,\n} from './session-protocol.js';\n\nexport interface SessionHostServerOptions {\n endpoint?: SessionHostEndpoint;\n /** Opt-in pinned native binding; absent hosts cannot attest an upgrade idle lease. */\n upgradeBinding?: HostUpgradeBinding;\n appName?: string;\n /** Explicit session-host state root (runtime records + tombstones). */\n storageRootDir?: string;\n}\n\nexport class SessionHostServer extends EventEmitter {\n readonly endpoint: SessionHostEndpoint;\n readonly registry = new SessionHostRegistry();\n private runtimes = new Map<string, PtySessionRuntime>();\n private readonly storage: SessionHostStorage;\n private readonly upgradeLease: HostUpgradeLease | null;\n private restorePending = true;\n private mutatingRequests = 0;\n private endpointInode: bigint | null = null;\n private ipcServer: net.Server | null = null;\n private sockets = new Set<net.Socket>();\n // Tracks which sessionIds each socket has subscribed to (via create/attach).\n // Used to avoid broadcasting session-specific events to uninterested sockets.\n private socketSessions = new Map<net.Socket, Set<string>>();\n private persistTimers = new Map<string, NodeJS.Timeout>();\n private readonly startedAt = Date.now();\n private recentLogs: SessionHostLogEntry[] = [];\n private recentRequests: SessionHostRequestTrace[] = [];\n private recentTransitions: SessionHostRuntimeTransition[] = [];\n private exitWaiters = new Map<string, Array<(exitCode: number | null) => void>>();\n private lastNoOutputInputWarnAt = new Map<string, number>();\n // Records the most recent explicit stop/delete/restart/prune request per\n // session so the termination diagnostic can attribute the exit to it.\n private stopRequests = new Map<string, SessionTermination['requestedStop']>();\n // Shutdown is driven by independent SIGINT/SIGTERM handlers, so stop() can be\n // entered twice. Cache the in-flight promise and hand it to every later caller\n // instead of re-running flushAllPersistence()/runtime.stop() on already-cleared state.\n private stopPromise: Promise<void> | null = null;\n\n constructor(options: SessionHostServerOptions = {}) {\n super();\n this.endpoint = options.endpoint || getDefaultSessionHostEndpoint(options.appName || 'adhdev');\n if (options.upgradeBinding) {\n const relative = options.storageRootDir && path.relative(options.upgradeBinding.stateDir, options.storageRootDir);\n if (this.endpoint.kind !== 'unix' || !options.storageRootDir || !path.isAbsolute(options.storageRootDir) ||\n !path.isAbsolute(options.upgradeBinding.stateDir) || relative === '..' || relative?.startsWith(`..${path.sep}`) || path.isAbsolute(relative || '')) {\n throw new Error('native_host_instance_storage_binding_required');\n }\n }\n this.upgradeLease = options.upgradeBinding\n ? new HostUpgradeLease(options.upgradeBinding, this.endpoint.path) : null;\n this.storage = new SessionHostStorage({\n appName: options.appName || 'adhdev',\n rootDir: options.storageRootDir,\n });\n }\n\n async start(): Promise<void> {\n if (this.upgradeLease) {\n await this.upgradeLease.start();\n // A stale socket requires separate native ownership recovery; never unlink on assertion.\n if (fs.existsSync(this.endpoint.path)) {\n await this.upgradeLease.close();\n throw new Error('native_host_endpoint_owner_unproved');\n }\n }\n if (!this.upgradeLease && this.endpoint.kind === 'unix') {\n try {\n fs.unlinkSync(this.endpoint.path);\n } catch {\n // noop\n }\n }\n\n this.ipcServer = net.createServer((socket) => {\n this.sockets.add(socket);\n // PARSER-EOF-FLUSH: hold the parser reference so `end()` is reachable.\n // Passing `createLineParser(...)` inline to `socket.on('data', ...)` threw\n // the handle away, which left the decoder's EOF flush permanently\n // unreachable — bytes held back as an incomplete UTF-8 sequence when the\n // peer disconnected simply vanished with the decoder.\n const parser = createLineParser((envelope) => {\n if (envelope.kind !== 'request') return;\n void this.handleIncomingRequest(socket, envelope);\n });\n const flushParser = () => {\n // The remainder is by definition a PARTIAL line — envelopes are\n // newline-framed, so an unterminated tail is a truncated transmission,\n // not a message. It is logged, never parsed: JSON.parse on a\n // half-written envelope inside a socket-close handler would raise an\n // uncaught exception and turn a peer that died mid-write into a crash\n // of the daemon observing it. That refusal is the original author's\n // design, preserved here.\n let remainder = '';\n try {\n remainder = parser.end();\n } catch {\n return;\n }\n if (!remainder.trim()) return;\n this.recordHostLog(\n 'warn',\n `session host discarded ${remainder.length} bytes of an incomplete IPC frame at EOF`,\n );\n };\n const removeSocket = () => {\n this.sockets.delete(socket);\n this.socketSessions.delete(socket);\n };\n // Flush before the socket bookkeeping so the remainder is reported even\n // if a later handler throws. `end()` clears its own buffer, so the\n // close-after-end sequence flushes once and then sees an empty tail.\n socket.on('close', () => {\n flushParser();\n removeSocket();\n });\n socket.on('end', () => {\n flushParser();\n removeSocket();\n });\n socket.on('error', () => {\n flushParser();\n removeSocket();\n try {\n socket.destroy();\n } catch {\n // noop\n }\n });\n socket.on('data', parser);\n });\n\n try {\n await new Promise<void>((resolve, reject) => {\n this.ipcServer?.once('listening', () => resolve());\n this.ipcServer?.once('error', reject);\n this.ipcServer?.listen(this.endpoint.path);\n });\n } catch (error) {\n await this.upgradeLease?.close();\n throw error;\n }\n\n if (this.upgradeLease && this.endpoint.kind === 'unix') {\n fs.chmodSync(this.endpoint.path, 0o600);\n this.endpointInode = fs.lstatSync(this.endpoint.path, { bigint: true }).ino;\n }\n this.recordHostLog('info', `session host endpoint ready: ${this.endpoint.path}`);\n // Do not block readiness on restoring/resuming persisted runtimes.\n // Startup callers only need the IPC endpoint to accept connections.\n setTimeout(() => {\n try {\n if (!this.upgradeLease?.proof().held) this.restorePersistedRuntimes();\n } catch (error: any) {\n this.recordHostLog('error', `session host restore failed: ${error?.message || String(error)}`);\n } finally { this.restorePending = false; }\n }, 0);\n }\n\n async stop(): Promise<void> {\n if (this.stopPromise) return this.stopPromise;\n this.stopPromise = this.runStop();\n return this.stopPromise;\n }\n\n private async runStop(): Promise<void> {\n this.flushAllPersistence();\n for (const runtime of this.runtimes.values()) {\n try {\n runtime.stop();\n } catch {\n // noop\n }\n }\n this.runtimes.clear();\n for (const timer of this.persistTimers.values()) {\n clearTimeout(timer);\n }\n this.persistTimers.clear();\n for (const socket of this.sockets) {\n socket.destroy();\n }\n this.sockets.clear();\n this.socketSessions.clear();\n if (this.ipcServer) {\n const server = this.ipcServer;\n this.ipcServer = null;\n await new Promise<void>((resolve) => server.close(() => resolve()));\n }\n if (this.endpoint.kind === 'unix') {\n try {\n if (!this.upgradeLease || fs.lstatSync(this.endpoint.path, { bigint: true }).ino === this.endpointInode) fs.unlinkSync(this.endpoint.path);\n } catch {\n // A replacement endpoint belongs to someone else.\n }\n }\n await this.upgradeLease?.close();\n this.removeAllListeners();\n }\n\n async handleRequest(request: SessionHostRequest): Promise<SessionHostResponse> {\n const readOnly = ['get_upgrade_lease', 'acquire_upgrade_lease', 'release_upgrade_lease', 'get_host_diagnostics', 'list_sessions', 'get_snapshot', 'get_terminal_snapshot'].includes(request.type);\n let counted = false;\n try {\n if (!readOnly) {\n this.upgradeLease?.assertMutable();\n this.mutatingRequests++;\n counted = true;\n }\n switch (request.type) {\n case 'get_upgrade_lease':\n if (!this.upgradeLease) throw new Error('native_host_upgrade_binding_unavailable');\n return { success: true, result: this.upgradeLease.proof() };\n case 'acquire_upgrade_lease':\n if (!this.upgradeLease) throw new Error('native_host_upgrade_binding_unavailable');\n return { success: true, result: this.upgradeLease.acquire(request.payload,\n !this.restorePending && this.mutatingRequests === 0 && this.runtimes.size === 0 &&\n this.registry.listSessions().length === 0 && !this.storage.hasRuntimeEntries()) };\n case 'release_upgrade_lease':\n if (!this.upgradeLease) throw new Error('native_host_upgrade_binding_unavailable');\n return { success: true, result: this.upgradeLease.release(request.payload) };\n case 'create_session': {\n const record = this.registry.createSession(request.payload);\n this.schedulePersist(record.sessionId);\n this.emitEvent({ type: 'session_created', sessionId: record.sessionId, record });\n this.recordRuntimeTransition(record.sessionId, 'create_session', 'starting', `provider=${record.providerType}`, true);\n try {\n const startedRecord = this.startRuntime(record, request.payload, 'session_started');\n return { success: true, result: startedRecord };\n } catch (error: any) {\n this.registry.markStopped(record.sessionId, 'failed');\n this.persistNow(record.sessionId);\n this.recordRuntimeTransition(record.sessionId, 'create_session_failed', 'failed', undefined, false, error?.message || String(error));\n return { success: false, error: error?.message || String(error) };\n }\n }\n case 'list_sessions':\n return { success: true, result: this.registry.listSessions() };\n case 'attach_session': {\n const record = this.registry.attachClient(request.payload);\n this.schedulePersist(record.sessionId);\n const client = record.attachedClients.find(item => item.clientId === request.payload.clientId);\n if (client) {\n this.emitEvent({ type: 'client_attached', sessionId: record.sessionId, client });\n }\n this.recordRuntimeTransition(record.sessionId, 'attach_client', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n case 'detach_session': {\n const record = this.registry.detachClient(request.payload);\n this.schedulePersist(record.sessionId);\n this.emitEvent({ type: 'client_detached', sessionId: record.sessionId, clientId: request.payload.clientId });\n this.recordRuntimeTransition(record.sessionId, 'detach_client', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n case 'acquire_write': {\n const record = this.registry.acquireWrite(request.payload);\n this.persistNow(record.sessionId);\n this.emitEvent({ type: 'write_owner_changed', sessionId: record.sessionId, owner: record.writeOwner });\n this.recordRuntimeTransition(record.sessionId, 'acquire_write', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n case 'release_write': {\n const record = this.registry.releaseWrite(request.payload);\n this.persistNow(record.sessionId);\n this.emitEvent({ type: 'write_owner_changed', sessionId: record.sessionId, owner: record.writeOwner });\n this.recordRuntimeTransition(record.sessionId, 'release_write', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n case 'get_snapshot':\n return { success: true, result: await this.getSnapshotForRequest(request.payload.sessionId, request.payload.sinceSeq) };\n case 'get_terminal_snapshot':\n return { success: true, result: await this.requireRuntime(request.payload.sessionId).getTerminalSnapshot() };\n case 'get_host_diagnostics':\n return { success: true, result: this.getHostDiagnostics(request.payload) };\n case 'clear_session_buffer': {\n const record = this.registry.clearBuffer(request.payload.sessionId);\n this.persistNow(record.sessionId);\n this.emitEvent({ type: 'session_cleared', sessionId: record.sessionId });\n this.recordRuntimeTransition(record.sessionId, 'clear_buffer', record.lifecycle, undefined, true);\n return { success: true, result: record };\n }\n case 'update_session_meta': {\n const record = this.registry.updateSessionMeta(\n request.payload.sessionId,\n request.payload.meta || {},\n request.payload.replace === true,\n );\n this.persistNow(record.sessionId);\n this.recordRuntimeTransition(record.sessionId, 'update_meta', record.lifecycle, undefined, true);\n return { success: true, result: record };\n }\n case 'send_input': {\n const client = this.getAttachedClient(request.payload.sessionId, request.payload.clientId);\n if (client?.readOnly) {\n return { success: false, error: `Client ${request.payload.clientId} is read-only` };\n }\n const session = this.registry.getSession(request.payload.sessionId);\n if (session?.writeOwner && session.writeOwner.clientId !== request.payload.clientId) {\n return { success: false, error: `Write owned by ${session.writeOwner.clientId}` };\n }\n const runtime = this.requireRuntime(request.payload.sessionId);\n const beforeSnapshotSeq = this.registry.getSnapshot(request.payload.sessionId)?.seq ?? 0;\n runtime.write(request.payload.data);\n this.scheduleNoOutputInputDiagnostic({\n sessionId: request.payload.sessionId,\n clientId: request.payload.clientId,\n input: request.payload.data,\n beforeSnapshotSeq,\n });\n return { success: true, result: this.registry.getSession(request.payload.sessionId) };\n }\n case 'resize_session': {\n this.requireRuntime(request.payload.sessionId).resize(request.payload.cols, request.payload.rows);\n const record = this.registry.getSession(request.payload.sessionId);\n if (record) {\n this.registry.restoreSession(\n {\n ...record,\n meta: {\n ...(record.meta || {}),\n sessionHostCols: request.payload.cols,\n sessionHostRows: request.payload.rows,\n },\n },\n this.registry.getSnapshot(request.payload.sessionId),\n );\n }\n this.schedulePersist(request.payload.sessionId);\n this.emitEvent({\n type: 'session_resized',\n sessionId: request.payload.sessionId,\n cols: request.payload.cols,\n rows: request.payload.rows,\n });\n return { success: true, result: this.registry.getSession(request.payload.sessionId) };\n }\n case 'stop_session': {\n this.stopRequests.set(request.payload.sessionId, 'stop');\n this.registry.setLifecycle(request.payload.sessionId, 'stopping');\n this.persistNow(request.payload.sessionId);\n this.requireRuntime(request.payload.sessionId).stop();\n this.emitEvent({ type: 'session_stopped', sessionId: request.payload.sessionId });\n this.recordRuntimeTransition(request.payload.sessionId, 'stop_session', 'stopping', undefined, true);\n return { success: true, result: this.registry.getSession(request.payload.sessionId) };\n }\n case 'delete_session': {\n const record = this.registry.getSession(request.payload.sessionId);\n if (!record) return { success: false, error: `Unknown session: ${request.payload.sessionId}` };\n if (this.runtimes.has(record.sessionId)) {\n if (!request.payload.force) {\n return { success: false, error: `Session ${record.sessionId} is still running; pass force to stop and delete it` };\n }\n this.stopRequests.set(record.sessionId, 'delete');\n this.registry.setLifecycle(record.sessionId, 'stopping');\n this.persistNow(record.sessionId);\n this.requireRuntime(record.sessionId).stop();\n await this.waitForRuntimeExit(record.sessionId).catch((error: any) => {\n this.recordRuntimeTransition(record.sessionId, 'delete_session_timeout', 'stopping', undefined, false, error?.message || String(error));\n });\n }\n this.registry.deleteSession(record.sessionId);\n this.storage.remove(record.sessionId);\n this.storage.removeTombstone(record.sessionId);\n this.stopRequests.delete(record.sessionId);\n this.emitEvent({ type: 'session_deleted', sessionId: record.sessionId });\n this.recordRuntimeTransition(record.sessionId, 'delete_session', record.lifecycle, undefined, true);\n return { success: true, result: { sessionId: record.sessionId, deleted: true } };\n }\n case 'resume_session': {\n const existing = this.registry.getSession(request.payload.sessionId);\n if (!existing) {\n return { success: false, error: `Unknown session: ${request.payload.sessionId}` };\n }\n if (this.runtimes.has(request.payload.sessionId)) {\n return { success: true, result: existing };\n }\n const resumed = this.startRuntime(existing, buildPayloadFromRecord(existing), 'session_resumed');\n this.recordRuntimeTransition(request.payload.sessionId, 'resume_session', resumed.lifecycle, undefined, true);\n return { success: true, result: resumed };\n }\n case 'restart_session': {\n const restarted = await this.restartRuntime(request.payload.sessionId);\n return { success: true, result: restarted };\n }\n case 'prune_duplicate_sessions': {\n const result = await this.pruneDuplicateSessions(request.payload);\n return { success: true, result };\n }\n case 'send_signal': {\n const runtime = this.requireRuntime(request.payload.sessionId);\n runtime.sendSignal(request.payload.signal);\n const record = this.registry.getSession(request.payload.sessionId);\n this.recordRuntimeTransition(request.payload.sessionId, 'send_signal', record?.lifecycle, request.payload.signal, true);\n return { success: true, result: record };\n }\n case 'force_detach_client': {\n const session = this.registry.getSession(request.payload.sessionId);\n if (session?.writeOwner?.clientId === request.payload.clientId) {\n const released = this.registry.releaseWrite({\n sessionId: request.payload.sessionId,\n clientId: request.payload.clientId,\n });\n this.emitEvent({ type: 'write_owner_changed', sessionId: released.sessionId, owner: released.writeOwner });\n }\n const record = this.registry.detachClient({\n sessionId: request.payload.sessionId,\n clientId: request.payload.clientId,\n });\n this.schedulePersist(record.sessionId);\n this.emitEvent({ type: 'client_detached', sessionId: record.sessionId, clientId: request.payload.clientId });\n this.recordRuntimeTransition(record.sessionId, 'force_detach_client', record.lifecycle, request.payload.clientId, true);\n return { success: true, result: record };\n }\n default:\n return { success: false, error: `Unsupported session host request: ${(request as { type?: string })?.type || 'unknown'}` };\n }\n } catch (error: any) {\n return { success: false, error: error?.message || String(error) };\n } finally {\n if (counted) this.mutatingRequests--;\n }\n }\n\n private requireRuntime(sessionId: string): PtySessionRuntime {\n const runtime = this.runtimes.get(sessionId);\n if (!runtime) throw new Error(`Runtime not found for session: ${sessionId}`);\n return runtime;\n }\n\n private getAttachedClient(sessionId: string, clientId: string): SessionAttachedClient | null {\n const session = this.registry.getSession(sessionId);\n return session?.attachedClients.find((client) => client.clientId === clientId) || null;\n }\n\n private emitEvent(event: SessionHostEvent): void {\n // Diagnostic-only events are stored locally (recentLogs/Requests/Transitions)\n // and accessible via get_host_diagnostics. Broadcasting them to every socket\n // creates O(N²) traffic when many CLI sessions are active.\n const diagnosticOnly = event.type === 'request_trace'\n || event.type === 'runtime_transition'\n || event.type === 'host_log';\n if (!diagnosticOnly) {\n const targetSessionId = 'sessionId' in event ? (event as { sessionId: string }).sessionId : null;\n for (const socket of [...this.sockets]) {\n // If the event is session-specific, only send to sockets subscribed to that session.\n if (targetSessionId && event.type === 'session_output') {\n const sessions = this.socketSessions.get(socket);\n if (!sessions?.has(targetSessionId)) continue;\n } else if (targetSessionId && this.socketSessions.size > 0) {\n const sessions = this.socketSessions.get(socket);\n if (sessions && !sessions.has(targetSessionId)) continue;\n }\n this.writeEnvelopeSafely(socket, {\n kind: 'event',\n event,\n });\n }\n }\n this.emit('event', event);\n }\n\n private subscribeSocketToSession(socket: net.Socket, sessionId: string): void {\n let sessions = this.socketSessions.get(socket);\n if (!sessions) {\n sessions = new Set();\n this.socketSessions.set(socket, sessions);\n }\n sessions.add(sessionId);\n }\n\n private async handleIncomingRequest(socket: net.Socket, envelope: SessionHostRequestEnvelope): Promise<void> {\n const sessionId = getRequestSessionId(envelope.request);\n if (sessionId && (envelope.request.type === 'create_session' || envelope.request.type === 'attach_session')) {\n this.subscribeSocketToSession(socket, sessionId);\n }\n const startedAt = Date.now();\n const response = await this.handleRequest(envelope.request);\n if (sessionId && envelope.request.type === 'create_session' && response.success) {\n // sessionId may have been auto-generated — subscribe to whatever was actually created\n const createdId = (response.result as { sessionId?: string } | undefined)?.sessionId;\n if (createdId && createdId !== sessionId) this.subscribeSocketToSession(socket, createdId);\n }\n this.recordRequestTrace({\n timestamp: startedAt,\n requestId: envelope.requestId,\n type: envelope.request.type,\n sessionId: getRequestSessionId(envelope.request),\n clientId: getRequestClientId(envelope.request),\n success: response.success,\n durationMs: Math.max(0, Date.now() - startedAt),\n error: response.success ? undefined : response.error,\n });\n this.writeEnvelopeSafely(socket, createResponseEnvelope(envelope.requestId, response));\n }\n\n private writeEnvelopeSafely(socket: net.Socket, envelope: SessionHostRequestEnvelope | ReturnType<typeof createResponseEnvelope> | { kind: 'event'; event: SessionHostEvent }): void {\n if (socket.destroyed || !socket.writable || socket.writableEnded) {\n this.sockets.delete(socket);\n return;\n }\n const payload = `${JSON.stringify(envelope)}\\n`;\n try {\n socket.write(payload, (error?: Error | null) => {\n if (!error) return;\n this.sockets.delete(socket);\n try {\n socket.destroy();\n } catch {\n // noop\n }\n });\n } catch {\n this.sockets.delete(socket);\n try {\n socket.destroy();\n } catch {\n // noop\n }\n }\n }\n\n private schedulePersist(sessionId: string): void {\n const existing = this.persistTimers.get(sessionId);\n if (existing) clearTimeout(existing);\n this.persistTimers.set(sessionId, setTimeout(() => {\n this.persistTimers.delete(sessionId);\n this.persistNow(sessionId);\n }, 200));\n }\n\n /**\n * @param allowTerminal - write even if the record is terminal. Only the exit\n * handler sets this, to stamp the final terminated record for the brief\n * post-mortem window before cleanup.\n */\n private persistNow(sessionId: string, allowTerminal = false): void {\n const record = this.registry.getSession(sessionId);\n if (!record) return;\n // Never write a live file for an already-terminated record. A persist can\n // land after the exit handler stamped the termination — e.g. a PTY onData\n // debounce (schedulePersist) that raced handleRuntimeExit. Writing here\n // recreates the file after storage.remove() deleted it, resurrecting a\n // self-contradictory record (lifecycle:'stopping' + termination stamped\n // 'stopped') that then surfaces as a live attach target for a PID that\n // already exited.\n //\n // Keyed on the record itself rather than a \"removed sessions\" set on\n // purpose: a restart reuses the same sessionId (restartRuntime stops and\n // relaunches in place), so a sticky per-id block would permanently stop\n // persisting the restarted live session. A terminal record naturally\n // stops being terminal once the session is running again.\n if (!allowTerminal && isTerminalRecord(record)) return;\n const snapshot = this.getSnapshot(sessionId);\n try {\n this.storage.save(record, snapshot);\n } catch (error: any) {\n const code = typeof error?.code === 'string' ? error.code : 'persist_failed';\n console.error(`[session-host] Persist failed for ${sessionId}: ${code}: ${error?.message || error}`);\n }\n }\n\n private getHostDiagnostics(payload?: { includeSessions?: boolean; limit?: number }): SessionHostDiagnostics {\n return buildHostDiagnostics({\n payload,\n hostStartedAt: this.startedAt,\n endpointPath: this.endpoint.path,\n runtimeCount: this.runtimes.size,\n sessions: this.registry.listSessions(),\n recentLogs: this.recentLogs,\n recentRequests: this.recentRequests,\n recentTransitions: this.recentTransitions,\n });\n }\n\n private recordHostLog(\n level: SessionHostLogEntry['level'],\n message: string,\n sessionId?: string,\n data?: Record<string, unknown>,\n ): void {\n const entry: SessionHostLogEntry = {\n timestamp: Date.now(),\n level,\n message,\n sessionId,\n data,\n };\n pushRecent(this.recentLogs, entry);\n this.emitEvent({ type: 'host_log', entry });\n this.emit('log', `[${level}] ${message}`);\n }\n\n private recordRequestTrace(trace: SessionHostRequestTrace): void {\n pushRecent(this.recentRequests, trace);\n this.emitEvent({ type: 'request_trace', trace });\n if (!trace.success) {\n this.recordHostLog(\n 'warn',\n `request ${trace.type} failed after ${trace.durationMs}ms${trace.error ? `: ${trace.error}` : ''}`,\n trace.sessionId,\n { requestId: trace.requestId, clientId: trace.clientId },\n );\n }\n }\n\n private scheduleNoOutputInputDiagnostic(params: {\n sessionId: string;\n clientId: string;\n input: string;\n beforeSnapshotSeq: number;\n }): void {\n if (!params.input || /^\\x1b/.test(params.input)) {\n return;\n }\n\n const hasPotentialEcho = /[^\\x00-\\x1F\\x7F]/.test(params.input);\n if (!hasPotentialEcho && params.input !== '\\r' && params.input !== '\\n') {\n return;\n }\n\n setTimeout(() => {\n let afterSnapshotSeq = params.beforeSnapshotSeq;\n try {\n afterSnapshotSeq = this.registry.getSnapshot(params.sessionId)?.seq ?? params.beforeSnapshotSeq;\n } catch {\n return;\n }\n if (afterSnapshotSeq > params.beforeSnapshotSeq) {\n return;\n }\n\n const now = Date.now();\n const lastWarnAt = this.lastNoOutputInputWarnAt.get(params.sessionId) || 0;\n if (now - lastWarnAt < 10_000) {\n return;\n }\n this.lastNoOutputInputWarnAt.set(params.sessionId, now);\n const record = this.registry.getSession(params.sessionId);\n this.recordHostLog(\n 'warn',\n 'send_input produced no terminal output after PTY write; runtime may be ignoring stdin or stuck in a hidden input reader',\n params.sessionId,\n {\n clientId: params.clientId,\n inputLength: params.input.length,\n beforeSnapshotSeq: params.beforeSnapshotSeq,\n afterSnapshotSeq,\n lifecycle: record?.lifecycle,\n osPid: record?.osPid,\n providerType: record?.providerType,\n },\n );\n this.recordRuntimeTransition(\n params.sessionId,\n 'send_input_no_output_after_write',\n record?.lifecycle,\n `clientId=${params.clientId} inputLength=${params.input.length} seq=${params.beforeSnapshotSeq}`,\n false,\n 'no terminal output after PTY write',\n );\n }, 250);\n }\n\n private recordRuntimeTransition(\n sessionId: string,\n action: string,\n lifecycle?: SessionHostRuntimeTransition['lifecycle'],\n detail?: string,\n success = true,\n error?: string,\n ): void {\n const transition: SessionHostRuntimeTransition = {\n timestamp: Date.now(),\n sessionId,\n action,\n lifecycle,\n detail,\n success,\n error,\n };\n pushRecent(this.recentTransitions, transition);\n this.emitEvent({ type: 'runtime_transition', transition });\n }\n\n private waitForRuntimeExit(sessionId: string, timeoutMs = 5_000): Promise<number | null> {\n if (!this.runtimes.has(sessionId)) {\n return Promise.resolve(this.registry.getSession(sessionId)?.lifecycle === 'failed' ? 1 : 0);\n }\n return new Promise<number | null>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const waiters = this.exitWaiters.get(sessionId) || [];\n this.exitWaiters.set(sessionId, waiters.filter((waiter) => waiter !== onExit));\n reject(new Error(`Timed out waiting for runtime ${sessionId} to exit`));\n }, timeoutMs);\n const onExit = (exitCode: number | null) => {\n clearTimeout(timeout);\n resolve(exitCode);\n };\n const waiters = this.exitWaiters.get(sessionId) || [];\n waiters.push(onExit);\n this.exitWaiters.set(sessionId, waiters);\n });\n }\n\n private resolveExitWaiters(sessionId: string, exitCode: number | null): void {\n const waiters = this.exitWaiters.get(sessionId);\n if (!waiters?.length) return;\n this.exitWaiters.delete(sessionId);\n for (const waiter of waiters) {\n try {\n waiter(exitCode);\n } catch {\n // noop\n }\n }\n }\n\n // Synchronous, best-effort variant for background/periodic persistence\n // (persistNow, called from many sync contexts). Uses getSnapshotTextSync()\n // rather than waiting for in-flight PTY writes to flush — see that method's\n // doc. Interactive requests must use getSnapshotForRequest() instead.\n private getSnapshot(sessionId: string, sinceSeq?: number) {\n const snapshot = this.registry.getSnapshot(sessionId, sinceSeq);\n const record = this.registry.getSession(sessionId);\n const runtimeText = typeof sinceSeq === 'number'\n ? ''\n : (this.runtimes.get(sessionId)?.getSnapshotTextSync?.() || '');\n return mergeRuntimeSnapshot(snapshot, record, { sinceSeq, runtimeText });\n }\n\n // Flush-aware variant for the interactive `get_snapshot` IPC request (the\n // dashboard's runtime_snapshot seed). Awaits any PTY chunk still queued in\n // the xterm mirror's WriteBuffer before reading, so the response reflects\n // everything written so far rather than racing an in-flight parse. See\n // PtySessionRuntime.flushPendingWrites() for why that race existed.\n private async getSnapshotForRequest(sessionId: string, sinceSeq?: number) {\n const snapshot = this.registry.getSnapshot(sessionId, sinceSeq);\n const record = this.registry.getSession(sessionId);\n const runtimeText = typeof sinceSeq === 'number'\n ? ''\n : ((await this.runtimes.get(sessionId)?.getSnapshotText?.()) || '');\n return mergeRuntimeSnapshot(snapshot, record, { sinceSeq, runtimeText });\n }\n\n flushAllPersistence(): void {\n for (const sessionId of this.runtimes.keys()) {\n this.persistNow(sessionId);\n }\n for (const record of this.registry.listSessions()) {\n this.persistNow(record.sessionId);\n }\n }\n\n private async restartRuntime(sessionId: string): Promise<SessionHostRecord> {\n const existing = this.registry.getSession(sessionId);\n if (!existing) {\n throw new Error(`Unknown session: ${sessionId}`);\n }\n\n if (this.runtimes.has(sessionId)) {\n this.stopRequests.set(sessionId, 'restart');\n this.registry.setLifecycle(sessionId, 'stopping');\n this.persistNow(sessionId);\n this.recordRuntimeTransition(sessionId, 'restart_requested', 'stopping', undefined, true);\n this.requireRuntime(sessionId).stop();\n await this.waitForRuntimeExit(sessionId);\n }\n\n const latest = this.registry.getSession(sessionId) || existing;\n const restarted = this.startRuntime(latest, buildPayloadFromRecord(latest), 'session_resumed');\n this.recordRuntimeTransition(sessionId, 'restart_completed', restarted.lifecycle, undefined, true);\n return restarted;\n }\n\n private async pruneDuplicateSessions(payload?: {\n providerType?: string;\n workspace?: string;\n dryRun?: boolean;\n }): Promise<SessionHostPruneDuplicatesResult> {\n const providerFilter = typeof payload?.providerType === 'string' ? payload.providerType.trim() : '';\n const workspaceFilter = typeof payload?.workspace === 'string' ? payload.workspace.trim() : '';\n const dryRun = payload?.dryRun === true;\n\n const { duplicateGroups, keptSessionIds, duplicateRecords } = planDuplicatePrune(\n this.registry.listSessions(),\n { providerFilter, workspaceFilter },\n );\n\n const prunedSessionIds: string[] = [];\n if (!dryRun) {\n for (const duplicate of duplicateRecords) {\n await this.pruneDuplicateRuntime(duplicate);\n prunedSessionIds.push(duplicate.sessionId);\n }\n }\n\n this.recordHostLog(\n dryRun ? 'info' : 'warn',\n `${dryRun ? 'session host dry-run found' : 'session host pruned'} ${duplicateGroups.length} duplicate group(s)`,\n undefined,\n {\n providerType: providerFilter || undefined,\n workspace: workspaceFilter || undefined,\n dryRun,\n prunedSessionIds,\n keptSessionIds,\n },\n );\n\n return {\n duplicateGroupCount: duplicateGroups.length,\n keptSessionIds,\n prunedSessionIds,\n groups: duplicateGroups,\n };\n }\n\n private restorePersistedRuntimes(): void {\n const states = this.storage.loadAll();\n let skippedAutoResumeSessions = 0;\n for (const persisted of states) {\n const { recoveredRecord, wasLiveRuntime, hadRecoveryInterest } = buildRecoveredRecord(persisted);\n this.registry.restoreSession(recoveredRecord, persisted.snapshot);\n this.storage.save(recoveredRecord, persisted.snapshot);\n if (wasLiveRuntime && hadRecoveryInterest) {\n skippedAutoResumeSessions += 1;\n }\n }\n\n if (skippedAutoResumeSessions > 0) {\n this.recordHostLog('warn', `session host restored ${skippedAutoResumeSessions} live runtime snapshot(s) without auto-resume`);\n }\n }\n\n private async pruneDuplicateRuntime(record: SessionHostRecord): Promise<void> {\n const providerSessionId = typeof record.meta?.providerSessionId === 'string'\n ? String(record.meta.providerSessionId)\n : undefined;\n this.recordRuntimeTransition(\n record.sessionId,\n 'prune_duplicate_session',\n record.lifecycle,\n providerSessionId ? `providerSessionId=${providerSessionId}` : undefined,\n true,\n );\n\n if (this.runtimes.has(record.sessionId)) {\n this.stopRequests.set(record.sessionId, 'prune');\n this.registry.setLifecycle(record.sessionId, 'stopping');\n this.persistNow(record.sessionId);\n this.requireRuntime(record.sessionId).stop();\n await this.waitForRuntimeExit(record.sessionId).catch((error: any) => {\n this.recordRuntimeTransition(record.sessionId, 'prune_duplicate_timeout', 'stopping', undefined, false, error?.message || String(error));\n });\n }\n\n const pendingPersistTimer = this.persistTimers.get(record.sessionId);\n if (pendingPersistTimer) {\n clearTimeout(pendingPersistTimer);\n this.persistTimers.delete(record.sessionId);\n }\n this.registry.deleteSession(record.sessionId);\n this.storage.remove(record.sessionId);\n this.storage.removeTombstone(record.sessionId);\n this.stopRequests.delete(record.sessionId);\n }\n\n private startRuntime(\n record: SessionHostRecord,\n payload: CreateSessionPayload,\n startEventType: 'session_started' | 'session_resumed',\n ): SessionHostRecord {\n const runtime = new PtySessionRuntime({\n sessionId: record.sessionId,\n payload,\n onData: (data) => {\n const { seq } = this.registry.appendOutput(record.sessionId, data);\n this.schedulePersist(record.sessionId);\n this.emitEvent({ type: 'session_output', sessionId: record.sessionId, seq, data });\n },\n onExit: (exitCode, signal) => this.handleRuntimeExit(record, exitCode, signal),\n });\n\n this.registry.setLifecycle(record.sessionId, 'starting');\n const pid = runtime.start();\n this.runtimes.set(record.sessionId, runtime);\n const startedRecord = this.registry.markStarted(record.sessionId, pid);\n this.persistNow(record.sessionId);\n this.emitEvent({ type: startEventType, sessionId: record.sessionId, pid });\n this.recordRuntimeTransition(record.sessionId, startEventType, startedRecord.lifecycle, `pid=${pid}`, true);\n return startedRecord;\n }\n\n /**\n * Handle a PTY termination: classify the (exitCode, signal) pair, stamp the\n * record + tombstone, emit exactly one structured diagnostic, and schedule\n * cleanup of the live persistence file (the tombstone is retained).\n */\n private handleRuntimeExit(record: SessionHostRecord, exitCode: number | null, signal: number | null): SessionTermination {\n // Capture pre-termination context BEFORE mutating the record.\n const priorRecord = this.registry.getSession(record.sessionId);\n const termination = classifyTermination({\n exitCode,\n signal,\n osPid: priorRecord?.osPid,\n previousLifecycle: priorRecord?.lifecycle,\n lastOutputAt: priorRecord?.lastActivityAt,\n requestedStop: this.stopRequests.get(record.sessionId),\n terminatedAt: Date.now(),\n });\n this.stopRequests.delete(record.sessionId);\n\n this.registry.markStopped(record.sessionId, termination.lifecycle, termination);\n this.runtimes.delete(record.sessionId);\n this.resolveExitWaiters(record.sessionId, exitCode);\n const pendingPersistTimer = this.persistTimers.get(record.sessionId);\n if (pendingPersistTimer) {\n clearTimeout(pendingPersistTimer);\n this.persistTimers.delete(record.sessionId);\n }\n this.persistNow(record.sessionId, true);\n // Persist a tombstone that survives live-record cleanup so the termination\n // stays inspectable after the 5s removal below.\n this.storage.saveTombstone(record.sessionId, termination);\n this.emitEvent({ type: 'session_exit', sessionId: record.sessionId, exitCode, signal, termination });\n const summary = `reason=${termination.reason} exitCode=${termination.exitCode === null ? 'unknown' : termination.exitCode} signal=${termination.signal ?? 'none'}`;\n // Exactly one structured, secret-free termination diagnostic.\n this.recordHostLog(\n termination.lifecycle === 'stopped' ? 'info' : 'warn',\n `session terminated: ${summary}`,\n record.sessionId,\n {\n runtimeKey: record.runtimeKey,\n providerType: record.providerType,\n osPid: termination.osPid,\n exitCode: termination.exitCode,\n signal: termination.signal,\n reason: termination.reason,\n previousLifecycle: termination.previousLifecycle,\n lifecycle: termination.lifecycle,\n lastOutputAt: termination.lastOutputAt,\n requestedStop: termination.requestedStop,\n },\n );\n this.recordRuntimeTransition(\n record.sessionId,\n 'session_exit',\n termination.lifecycle,\n summary,\n termination.lifecycle === 'stopped',\n termination.lifecycle === 'stopped' ? undefined : summary,\n );\n // Clean up the live persistence file after a brief delay (allow post-mortem\n // reads). The tombstone written above is retained. The registry entry is\n // dropped in the same tick as the file so the record can no longer be\n // served — and so no persist can find it and recreate the file (see\n // resurrection RCA: a persist landing after storage.remove() but finding\n // the record still registered recreates a stale live file).\n setTimeout(() => {\n // A restart reuses the sessionId: restartRuntime() stops the runtime,\n // which schedules this cleanup, then relaunches in place. If the session\n // is live again by the time this fires, it belongs to the new runtime —\n // deleting it would unregister and unpersist a running session.\n const current = this.registry.getSession(record.sessionId);\n if (current && !isTerminalRecord(current)) return;\n this.registry.deleteSession(record.sessionId);\n this.storage.remove(record.sessionId);\n }, 5_000).unref?.();\n return termination;\n }\n}\n","import * as fs from 'fs';\nimport * as os from 'os';\nimport * as pty from 'node-pty';\nimport type { IPty } from 'node-pty';\nimport type { CreateSessionPayload, SessionTerminalSnapshot } from '@adhdev/session-host-core';\nimport {\n sanitizeSpawnEnv,\n ensureNodePtySpawnHelperPermissions,\n resolveSessionHostCols,\n resolveSessionHostRows,\n spawnCliChild,\n} from '@adhdev/session-host-core';\n\ntype TerminalMirrorHandle = {\n // `onProcessed` fires once this chunk has actually been parsed into the\n // buffer. xterm.js's write() is asynchronous (WriteBuffer defers to a\n // setTimeout/microtask — see @xterm/xterm's common/input/WriteBuffer.ts):\n // without waiting for this callback, a snapshot read that races an\n // in-flight write observes a buffer that is missing the just-written data\n // (stale, not corrupted) rather than the just-appended text. See\n // PtySessionRuntime.flushPendingWrites().\n write(data: string | Uint8Array, onProcessed?: () => void): void;\n resize(cols: number, rows: number): void;\n formatVT(): string;\n formatPlainText(): string;\n getCursorPosition(): { col: number; row: number };\n dispose(): void;\n};\n\ntype GhosttyTerminalHandle = {\n write(data: string | Uint8Array, onProcessed?: () => void): void;\n resize(cols: number, rows: number): void;\n formatVT(): string;\n formatPlainText(options?: { trim?: boolean }): string;\n getCursorPosition(): { col: number; row: number };\n dispose(): void;\n};\n\ntype GhosttyBinding = {\n createTerminal(options: { cols: number; rows: number; scrollback: number }): GhosttyTerminalHandle;\n};\n\ntype XtermBufferLine = {\n translateToString(trimRight?: boolean): string;\n};\n\ntype XtermBuffer = {\n length: number;\n viewportY: number;\n cursorX?: number;\n cursorY?: number;\n getLine(index: number): XtermBufferLine | undefined;\n};\n\ntype XtermTerminal = {\n buffer: { active: XtermBuffer };\n loadAddon(addon: { activate(terminal: XtermTerminal): void }): void;\n write(data: string, callback?: () => void): void;\n resize(cols: number, rows: number): void;\n dispose(): void;\n};\n\ntype XtermCtor = new (options: { cols: number; rows: number; scrollback: number }) => XtermTerminal;\n\ntype XtermSerializeAddon = {\n serialize(options?: { range?: { start: number; end: number }; scrollback?: number; excludeModes?: boolean }): string;\n dispose(): void;\n};\n\nlet terminalMirrorFactory:\n | ((options: { cols: number; rows: number; scrollback: number }) => TerminalMirrorHandle)\n | null\n | undefined;\nlet terminalMirrorWarning: string | null = null;\nlet terminalMirrorBackendLogged = false;\n\nensureNodePtySpawnHelperPermissions((msg: string) => console.log(`[session-host] ${msg}`));\n\nfunction logTerminalMirrorBackend(message: string, level: 'info' | 'warn' = 'info'): void {\n if (terminalMirrorBackendLogged) return;\n terminalMirrorBackendLogged = true;\n const prefix = '[session-host]';\n if (level === 'warn') console.warn(`${prefix} ${message}`);\n else console.log(`${prefix} ${message}`);\n}\n\nexport interface PtyRuntimeOptions {\n sessionId: string;\n payload: CreateSessionPayload;\n onData: (data: string) => void;\n onExit: (exitCode: number | null, signal: number | null) => void;\n}\n\n// Use shared spawn env sanitizer — alias for backward compat within this file\nconst buildRuntimeEnv = sanitizeSpawnEnv;\n\nfunction computeTerminalQueryTail(buffer: string): string {\n const prefixes = ['\\x1b[6n', '\\x1b[?6n'];\n const maxLength = prefixes.reduce((n, value) => Math.max(n, value.length), 0) - 1;\n const start = Math.max(0, buffer.length - maxLength);\n for (let i = start; i < buffer.length; i++) {\n const suffix = buffer.slice(i);\n if (prefixes.some((pattern) => suffix.length < pattern.length && pattern.startsWith(suffix))) {\n return suffix;\n }\n }\n return '';\n}\n\nfunction formatXtermViewportPlain(terminal: XtermTerminal, rows: number): string {\n const buffer = terminal.buffer.active;\n const start = Math.max(0, buffer.viewportY || 0);\n const end = Math.max(start, Math.min(buffer.length || 0, start + Math.max(1, rows | 0)));\n const lines: string[] = [];\n\n for (let i = start; i < end; i++) {\n const line = buffer.getLine(i);\n const raw = line ? line.translateToString(false) : '';\n lines.push(raw.replace(/\\s+$/, ''));\n }\n\n let first = 0;\n let last = lines.length;\n while (first < last && !lines[first]?.trim()) first++;\n while (last > first && !lines[last - 1]?.trim()) last--;\n // Use CRLF row boundaries for unambiguous terminal replay regardless of the\n // browser xterm convertEol setting. CRLF is always explicit; bare LF depends\n // on convertEol being true to reset the cursor column, which is not guaranteed\n // for all xterm consumer configurations.\n return lines.slice(first, last).join('\\r\\n');\n}\n\nfunction createXtermSerializeAddon(terminal: XtermTerminal): XtermSerializeAddon | null {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const mod = require('@xterm/addon-serialize');\n const SerializeAddon = mod.SerializeAddon || mod.default?.SerializeAddon || mod.default;\n if (!SerializeAddon) return null;\n const addon = new SerializeAddon() as XtermSerializeAddon & { activate(terminal: XtermTerminal): void };\n terminal.loadAddon(addon);\n return addon;\n } catch {\n return null;\n }\n}\n\nfunction formatCursorRestore(terminal: XtermTerminal, rows: number): string {\n const buffer = terminal.buffer.active;\n const row = Math.max(0, Math.min(Math.max(0, rows | 0) - 1, buffer.cursorY || 0));\n const col = Math.max(0, buffer.cursorX || 0);\n return `\\x1b[${row + 1};${col + 1}H`;\n}\n\nfunction serializeXtermViewport(terminal: XtermTerminal, serializer: XtermSerializeAddon, rows: number): string {\n const buffer = terminal.buffer.active;\n const start = Math.max(0, buffer.viewportY || 0);\n const end = Math.max(start, Math.min(Math.max(0, buffer.length || 0) - 1, start + Math.max(1, rows | 0) - 1));\n if (end < start) return '';\n const viewport = serializer.serialize({\n range: { start, end },\n excludeModes: true,\n });\n // Range serialization reproduces the visible cells, but leaves the replay cursor\n // at the end of the serialized viewport. CLIs like Claude frequently update the\n // current status line with relative cursor movement; if the dashboard seeds a\n // snapshot and then receives an incremental update, that update must continue\n // from the live cursor row, not from the next line after the viewport replay.\n return `${viewport}${formatCursorRestore(terminal, rows)}`;\n}\n\nfunction createXtermMirror(options: { cols: number; rows: number; scrollback: number }): TerminalMirrorHandle {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const mod = require('@xterm/xterm');\n const Terminal = (mod.Terminal || mod.default?.Terminal || mod.default) as XtermCtor | undefined;\n if (!Terminal) {\n throw new Error('@xterm/xterm Terminal export not found');\n }\n\n let currentRows = Math.max(1, options.rows | 0);\n const terminal = new Terminal({\n cols: Math.max(1, options.cols | 0),\n rows: currentRows,\n scrollback: Math.max(0, options.scrollback | 0),\n });\n const serializer = createXtermSerializeAddon(terminal);\n\n return {\n write(data: string | Uint8Array, onProcessed?: () => void): void {\n if (!data) {\n // Nothing to parse, but the caller (PtySessionRuntime.flushPendingWrites)\n // still needs its completion signal so an empty chunk cannot wedge a flush.\n onProcessed?.();\n return;\n }\n terminal.write(typeof data === 'string' ? data : Buffer.from(data).toString('utf8'), onProcessed);\n },\n resize(cols: number, rows: number): void {\n currentRows = Math.max(1, rows | 0);\n terminal.resize(Math.max(1, cols | 0), currentRows);\n },\n formatVT(): string {\n if (serializer) return serializeXtermViewport(terminal, serializer, currentRows);\n return formatXtermViewportPlain(terminal, currentRows);\n },\n formatPlainText(): string {\n return formatXtermViewportPlain(terminal, currentRows).replace(/\\r\\n/g, '\\n');\n },\n getCursorPosition(): { col: number; row: number } {\n const buffer = terminal.buffer.active;\n return {\n col: Math.max(0, buffer.cursorX || 0),\n row: Math.max(0, buffer.cursorY || 0),\n };\n },\n dispose(): void {\n serializer?.dispose();\n terminal.dispose();\n },\n };\n}\n\nfunction normalizeGhosttyBinding(mod: any): GhosttyBinding | null {\n const raw = mod?.default?.createTerminal ? mod.default : mod?.createTerminal ? mod : null;\n if (!raw) return null;\n\n // Keep Ghostty as the authoritative emulator for terminal query responses, but use\n // xterm's serialized active viewport for UI seeding. Ghostty's formatter serializes\n // scrollback before the active viewport; after full-screen Claude Code redraws (for\n // example `/status` -> Esc), replaying that as a fresh terminal seed makes stale\n // splash-screen rows visible as duplicated logos. xterm's serialize addon gives us\n // the viewport-only seed without dropping SGR color/style or CRLF row movement.\n return {\n createTerminal(options: { cols: number; rows: number; scrollback: number }): GhosttyTerminalHandle {\n const handle = raw.createTerminal(options) as any;\n const viewportSnapshot = createXtermMirror(options);\n return {\n write(data: string | Uint8Array, onProcessed?: () => void): void {\n // `handle` (native ghostty) writes synchronously; `viewportSnapshot`\n // (xterm mirror) is the one whose write is asynchronous and is also\n // the sole source of formatVT()/formatPlainText() output above — so\n // completion must be reported only once ITS write has been parsed,\n // not immediately after this call returns.\n handle.write(data);\n viewportSnapshot.write(data, onProcessed);\n },\n resize(cols: number, rows: number): void {\n handle.resize(cols, rows);\n viewportSnapshot.resize(cols, rows);\n },\n formatVT(): string {\n return viewportSnapshot.formatVT();\n },\n formatPlainText(): string {\n return viewportSnapshot.formatPlainText();\n },\n getCursorPosition(): { col: number; row: number } {\n if (typeof handle.getCursorPosition === 'function') return handle.getCursorPosition() as { col: number; row: number };\n return viewportSnapshot.getCursorPosition();\n },\n dispose(): void {\n handle.dispose();\n viewportSnapshot.dispose();\n },\n };\n },\n };\n}\n\nexport const __testing = {\n createXtermMirror,\n formatXtermViewportPlain,\n serializeXtermViewport,\n};\n\nfunction getTerminalMirrorFactory(): (options: { cols: number; rows: number; scrollback: number }) => TerminalMirrorHandle {\n if (terminalMirrorFactory) return terminalMirrorFactory;\n if (terminalMirrorFactory === null) {\n throw new Error(terminalMirrorWarning || 'No terminal mirror backend available');\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const ghosttyMod = require('@adhdev/ghostty-vt-node');\n const binding = normalizeGhosttyBinding(ghosttyMod);\n if (!binding) {\n throw new Error('@adhdev/ghostty-vt-node does not export createTerminal()');\n }\n terminalMirrorFactory = (options) => binding.createTerminal(options);\n logTerminalMirrorBackend('terminal mirror backend=ghostty-vt');\n return terminalMirrorFactory;\n } catch (ghosttyError: any) {\n try {\n terminalMirrorFactory = createXtermMirror;\n terminalMirrorWarning = `Ghostty VT unavailable; falling back to xterm mirror (${ghosttyError?.message || String(ghosttyError)})`;\n logTerminalMirrorBackend(terminalMirrorWarning, 'warn');\n return terminalMirrorFactory;\n } catch (xtermError: any) {\n terminalMirrorFactory = null;\n terminalMirrorWarning = `No terminal mirror backend available (ghostty: ${ghosttyError?.message || String(ghosttyError)}; xterm: ${xtermError?.message || String(xtermError)})`;\n logTerminalMirrorBackend(terminalMirrorWarning, 'warn');\n throw new Error(terminalMirrorWarning);\n }\n }\n}\n\nexport class PtySessionRuntime {\n readonly sessionId: string;\n readonly payload: CreateSessionPayload;\n private cols: number;\n private rows: number;\n\n private ptyProcess: IPty | null = null;\n private screenMirror: TerminalMirrorHandle | null = null;\n private pendingQueryScanTail = '';\n private terminalModeScanTail = '';\n private altScreen = false;\n private pasteMode = false;\n private scrollRegion: { top: number; bot: number };\n private onDataCallback: (data: string) => void;\n private onExitCallback: (exitCode: number | null, signal: number | null) => void;\n /** Count of screenMirror.write() calls whose completion callback has not fired yet. */\n private pendingWriteCount = 0;\n /** Resolved (and cleared) once pendingWriteCount reaches 0. See flushPendingWrites(). */\n private snapshotWaiters: Array<() => void> = [];\n\n constructor(options: PtyRuntimeOptions) {\n this.sessionId = options.sessionId;\n this.payload = options.payload;\n this.cols = resolveSessionHostCols(options.payload.cols);\n this.rows = resolveSessionHostRows(options.payload.rows);\n this.scrollRegion = { top: 0, bot: this.rows - 1 };\n this.onDataCallback = options.onData;\n this.onExitCallback = options.onExit;\n }\n\n start(): number {\n if (this.ptyProcess) return this.ptyProcess.pid;\n\n const command = this.payload.launchCommand.command;\n const args = this.payload.launchCommand.args || [];\n const env = buildRuntimeEnv(process.env, this.payload.launchCommand.env);\n\n // Validate workspace directory — an invalid cwd causes a native crash on Windows\n // (node-pty error code 267: ERROR_DIRECTORY) that bypasses JS try/catch\n let cwd = this.payload.workspace || process.cwd();\n if (cwd) {\n try {\n const stat = fs.statSync(cwd);\n if (!stat.isDirectory()) cwd = os.homedir();\n } catch {\n cwd = os.homedir();\n }\n }\n\n const spawnRuntime = () => pty.spawn(command, args, {\n name: 'xterm-256color',\n cols: this.cols,\n rows: this.rows,\n cwd,\n env,\n });\n // User terminals share this host. Only agent workload categories acquire\n // the policy; a plain shell (or unknown category) keeps its priority.\n this.ptyProcess = this.payload.category === 'cli' || this.payload.category === 'acp'\n ? spawnCliChild(spawnRuntime, env)\n : spawnRuntime();\n this.screenMirror = getTerminalMirrorFactory()({\n cols: this.cols,\n rows: this.rows,\n scrollback: 32768,\n });\n\n this.ptyProcess.onData((data: string) => {\n this.trackTerminalModes(data);\n this.onDataCallback(data);\n // `screenMirror.write()` is backed by xterm.js's WriteBuffer (see\n // TerminalMirrorHandle's `write` doc), which is asynchronous: it defers\n // parsing to a later tick even though this call returns immediately.\n // Reads that depend on `data` having been fully parsed must wait for the\n // completion callback rather than running synchronously right after\n // write():\n // - getSnapshotText()/getTerminalSnapshot() (formatVT/formatPlainText)\n // always read the xterm mirror, ghostty-backed or not, so an\n // in-flight get_snapshot IPC request racing a queued write got a\n // STALE/incomplete viewport (missing the just-written tail).\n // - respondToTerminalQueries()'s DSR (`\\x1b[6n`) reply reads\n // getCursorPosition(), which is the (synchronous) native ghostty\n // cursor when that backend is active, but falls back to the same\n // async xterm mirror when it is not (see normalizeGhosttyBinding\n // below). On the xterm-only fallback, replying synchronously here\n // reported a STALE cursor column to the PTY process for any DSR\n // query issued while a write was still queued — plausibly drifting\n // a CLI's own redraw math out of sync with the real terminal column\n // position (each wide/CJK cell advances the cursor by 2, so a stale\n // reply skews layout most visibly around wide characters).\n this.pendingWriteCount += 1;\n this.screenMirror?.write(data, () => {\n this.pendingWriteCount = Math.max(0, this.pendingWriteCount - 1);\n this.respondToTerminalQueries(data);\n this.flushSnapshotWaiters();\n });\n });\n\n this.ptyProcess.onExit(({ exitCode, signal }) => {\n this.ptyProcess = null;\n this.screenMirror?.dispose();\n this.screenMirror = null;\n this.pendingQueryScanTail = '';\n this.terminalModeScanTail = '';\n this.pendingWriteCount = 0;\n // No more write() callbacks will ever fire for a disposed mirror — release\n // any waiter now so flushPendingWrites() cannot hang past process exit.\n this.flushSnapshotWaiters();\n // Preserve the nullable/unknown exitCode and signal exactly as node-pty\n // reports them: a signal-terminated process arrives as exitCode=null and\n // must stay distinguishable from a clean exit 0.\n this.onExitCallback(\n typeof exitCode === 'number' ? exitCode : null,\n typeof signal === 'number' ? signal : null,\n );\n });\n\n return this.ptyProcess.pid;\n }\n\n write(data: string): void {\n if (!this.ptyProcess) throw new Error(`Session not running: ${this.sessionId}`);\n this.ptyProcess.write(data);\n }\n\n resize(cols: number, rows: number): void {\n if (!this.ptyProcess) throw new Error(`Session not running: ${this.sessionId}`);\n this.ptyProcess.resize(cols, rows);\n this.cols = Math.max(1, cols | 0);\n this.rows = Math.max(1, rows | 0);\n this.scrollRegion = {\n top: Math.min(this.scrollRegion.top, this.rows - 1),\n bot: Math.min(Math.max(this.scrollRegion.top, this.scrollRegion.bot), this.rows - 1),\n };\n this.screenMirror?.resize(cols, rows);\n }\n\n stop(): void {\n if (!this.ptyProcess) return;\n this.ptyProcess.kill();\n }\n\n sendSignal(signal: string): void {\n if (!this.ptyProcess) throw new Error(`Session not running: ${this.sessionId}`);\n const normalized = String(signal || '').trim().toUpperCase();\n if (!normalized) throw new Error('signal is required');\n\n try {\n process.kill(this.ptyProcess.pid, normalized as NodeJS.Signals);\n } catch {\n if (normalized === 'SIGTERM' || normalized === 'SIGKILL') {\n this.ptyProcess.kill();\n return;\n }\n throw new Error(`Unsupported signal for runtime ${this.sessionId}: ${normalized}`);\n }\n }\n\n /**\n * Resolves once every screenMirror.write() call made so far has had its\n * completion callback fire (i.e. the xterm mirror's WriteBuffer has fully\n * parsed all currently-queued PTY chunks). Callers that read the mirror's\n * text/cursor state — getSnapshotText(), getTerminalSnapshot() — must await\n * this first, otherwise they can observe a buffer missing the most recently\n * written chunk (stale/incomplete text, not corrupted text: see\n * TerminalMirrorHandle's `write` doc for why the read races the write).\n */\n flushPendingWrites(): Promise<void> {\n if (this.pendingWriteCount <= 0) return Promise.resolve();\n return new Promise((resolve) => {\n this.snapshotWaiters.push(resolve);\n });\n }\n\n private flushSnapshotWaiters(): void {\n if (this.pendingWriteCount > 0 || this.snapshotWaiters.length === 0) return;\n const waiters = this.snapshotWaiters;\n this.snapshotWaiters = [];\n for (const resolve of waiters) resolve();\n }\n\n async getSnapshotText(): Promise<string> {\n await this.flushPendingWrites();\n return this.screenMirror?.formatVT() || '';\n }\n\n /**\n * Best-effort, non-flushing read of the same text as getSnapshotText(),\n * for callers that persist periodically in the background (persistNow) and\n * must stay synchronous rather than awaiting in-flight PTY writes. A\n * restore-on-restart read of this can be briefly behind the live viewport\n * by at most one already-queued chunk; that trade-off is acceptable for a\n * background persistence snapshot but not for an interactive get_snapshot\n * request, which should use getSnapshotText() instead.\n */\n getSnapshotTextSync(): string {\n return this.screenMirror?.formatVT() || '';\n }\n\n async getTerminalSnapshot(): Promise<SessionTerminalSnapshot> {\n if (!this.ptyProcess || !this.screenMirror) {\n throw new Error(`Session not running: ${this.sessionId}`);\n }\n await this.flushPendingWrites();\n if (!this.ptyProcess || !this.screenMirror) {\n throw new Error(`Session not running: ${this.sessionId}`);\n }\n const cursor = this.screenMirror.getCursorPosition();\n return {\n text: this.screenMirror.formatPlainText(),\n state: {\n cursor: {\n row: Math.max(0, cursor.row | 0),\n col: Math.max(0, cursor.col | 0),\n },\n altScreen: this.altScreen,\n pasteMode: this.pasteMode,\n rawMode: true,\n scrollRegion: { ...this.scrollRegion },\n cols: this.cols,\n rows: this.rows,\n },\n };\n }\n\n private trackTerminalModes(data: string): void {\n if (!data) return;\n const combined = this.terminalModeScanTail + data;\n const privateMode = /\\x1b\\[\\?([0-9;]*)([hl])/g;\n let privateMatch: RegExpExecArray | null;\n while ((privateMatch = privateMode.exec(combined)) !== null) {\n const enabled = privateMatch[2] === 'h';\n for (const mode of privateMatch[1].split(';')) {\n if (mode === '47' || mode === '1047' || mode === '1049') this.altScreen = enabled;\n if (mode === '2004') this.pasteMode = enabled;\n }\n }\n\n const scrollRegion = /\\x1b\\[(\\d*)(?:;(\\d*))?r/g;\n let scrollMatch: RegExpExecArray | null;\n while ((scrollMatch = scrollRegion.exec(combined)) !== null) {\n const top = scrollMatch[1] ? Number.parseInt(scrollMatch[1], 10) - 1 : 0;\n const bot = scrollMatch[2] ? Number.parseInt(scrollMatch[2], 10) - 1 : this.rows - 1;\n this.scrollRegion = {\n top: Math.max(0, Math.min(this.rows - 1, top)),\n bot: Math.max(0, Math.min(this.rows - 1, bot)),\n };\n if (this.scrollRegion.bot < this.scrollRegion.top) {\n this.scrollRegion = { top: 0, bot: this.rows - 1 };\n }\n }\n\n const lastEscape = combined.lastIndexOf('\\x1b');\n this.terminalModeScanTail = lastEscape >= 0 && combined.length - lastEscape < 64\n ? combined.slice(lastEscape)\n : '';\n }\n\n private respondToTerminalQueries(data: string): void {\n if (!this.ptyProcess || !this.screenMirror || !data) return;\n\n const combined = this.pendingQueryScanTail + data;\n const regex = /\\x1b\\[(\\?)?6n/g;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(combined)) !== null) {\n const cursor = this.screenMirror.getCursorPosition();\n const row = Math.max(1, (cursor.row | 0) + 1);\n const col = Math.max(1, (cursor.col | 0) + 1);\n const response = match[1]\n ? `\\x1b[?${row};${col}R`\n : `\\x1b[${row};${col}R`;\n this.ptyProcess.write(response);\n }\n\n this.pendingQueryScanTail = computeTerminalQueryTail(combined);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { createHash, randomUUID } from 'node:crypto';\nimport { execFileSync, spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';\n\nexport interface HostUpgradeBinding {\n /** Trusted packaged helper; supplied hash must come from an immutable artifact pin. */\n helperPath: string;\n helperSha256: string;\n helperProtocol?: 1;\n helperFileIdentity?: string;\n stateDir: string;\n}\ninterface LeaseState {\n schema: 1;\n endpoint: string;\n epoch: number;\n held: boolean;\n owner: string | null;\n tokenHash: string | null;\n}\nexport interface HostLeaseRequest {\n bootId: string;\n epoch: number;\n owner: string;\n token: string;\n}\nconst digest = (value: string | Buffer) => createHash('sha256').update(value).digest('hex');\n\n/** Host-owned durable idle admission fence, opt-in until packaging is supported. */\nexport class HostUpgradeLease {\n readonly bootId = randomUUID();\n private child: ChildProcessWithoutNullStreams | null = null;\n private state: LeaseState;\n private healthy = false;\n private poisoned = false;\n private readonly journal: string;\n constructor(private readonly binding: HostUpgradeBinding, private readonly endpoint: string) {\n if (process.platform !== 'darwin') throw new Error('native_host_upgrade_platform_unproved');\n this.journal = path.join(binding.stateDir, 'upgrade-lease.json');\n this.state = { schema: 1, endpoint, epoch: 0, held: false, owner: null, tokenHash: null };\n }\n async start(): Promise<void> {\n if (this.child && this.child.exitCode === null && this.child.signalCode === null) throw new Error('native_host_binding_already_started');\n fs.mkdirSync(this.binding.stateDir, { recursive: true, mode: 0o700 });\n const dir = fs.lstatSync(this.binding.stateDir);\n if (!dir.isDirectory() || dir.isSymbolicLink() || dir.uid !== process.getuid?.() || (dir.mode & 0o077)) {\n throw new Error('native_host_state_directory_untrusted');\n }\n if (this.binding.helperFileIdentity && this.fileIdentity() !== this.binding.helperFileIdentity) throw new Error('native_host_helper_file_identity_changed');\n if (fs.realpathSync(this.binding.helperPath) !== this.binding.helperPath ||\n digest(fs.readFileSync(this.binding.helperPath)) !== this.binding.helperSha256) {\n throw new Error('native_host_helper_pin_mismatch');\n }\n if (this.binding.helperProtocol === 1 && String(execFileSync(this.binding.helperPath, ['--attest'], { stdio: 'pipe', windowsHide: true })).trim() !== 'adhdev-host-guardian/1') throw new Error('native_host_helper_protocol_mismatch');\n if (this.binding.helperFileIdentity && this.fileIdentity() !== this.binding.helperFileIdentity) throw new Error('native_host_helper_file_identity_changed');\n const lockPath = path.join(this.binding.stateDir, 'instance.lock');\n const priorLock = fs.existsSync(lockPath);\n const child = spawn(this.binding.helperPath, [lockPath], { stdio: 'pipe', windowsHide: true });\n this.child = child;\n child.on('exit', () => { this.healthy = false; });\n child.on('error', () => { this.healthy = false; });\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => { child.stdin.end(); reject(new Error('native_host_lock_timeout')); }, 3000);\n child.once('error', error => { clearTimeout(timer); reject(error); });\n child.once('exit', () => { clearTimeout(timer); reject(new Error('native_host_instance_locked')); });\n child.stdout.once('data', data => {\n clearTimeout(timer);\n if (String(data) !== 'LOCKED\\n') { child.stdin.end(); reject(new Error('native_host_lock_protocol')); return; }\n this.healthy = true; resolve();\n });\n });\n try {\n if (this.binding.helperFileIdentity && (this.fileIdentity() !== this.binding.helperFileIdentity || digest(fs.readFileSync(this.binding.helperPath)) !== this.binding.helperSha256)) throw new Error('native_host_helper_file_identity_changed');\n if (fs.existsSync(this.journal)) {\n const stat = fs.lstatSync(this.journal);\n if (!stat.isFile() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o077)) throw new Error('native_host_lease_untrusted');\n const value = JSON.parse(fs.readFileSync(this.journal, 'utf8')) as LeaseState;\n if (value.schema !== 1 || value.endpoint !== this.endpoint || !Number.isSafeInteger(value.epoch) || value.epoch < 0 ||\n typeof value.held !== 'boolean' || (value.held ? typeof value.owner !== 'string' || typeof value.tokenHash !== 'string' || !/^[a-f0-9]{64}$/.test(value.tokenHash) : value.owner !== null || value.tokenHash !== null)) throw new Error('native_host_lease_corrupt');\n this.state = value;\n } else {\n if (priorLock) throw new Error('native_host_lease_journal_missing');\n this.persist(this.state);\n }\n } catch (error) { await this.close(); throw error; }\n }\n private fileIdentity(): string {\n const s=fs.lstatSync(this.binding.helperPath);\n return JSON.stringify([s.dev,s.ino,s.uid,s.mode,s.size]);\n }\n private persist(value: LeaseState): void {\n const tmp = `${this.journal}.${randomUUID()}.tmp`;\n try {\n const fd = fs.openSync(tmp, 'wx', 0o600);\n try { fs.writeFileSync(fd, JSON.stringify(value)); fs.fsyncSync(fd); } finally { fs.closeSync(fd); }\n fs.renameSync(tmp, this.journal);\n const dir = fs.openSync(this.binding.stateDir, 'r');\n try { fs.fsyncSync(dir); } finally { fs.closeSync(dir); }\n this.state = value;\n } catch (error) {\n // Rename may already have committed: forbid every operation until restart reloads it.\n this.poisoned = true;\n throw error;\n }\n }\n assertHealthy(): void {\n if (this.binding.helperFileIdentity && this.fileIdentity() !== this.binding.helperFileIdentity) throw new Error('native_host_helper_file_identity_changed');\n if (!this.healthy || this.child?.exitCode !== null || this.child?.signalCode !== null || this.poisoned) throw new Error('native_host_lock_or_storage_unavailable');\n }\n assertMutable(): void {\n this.assertHealthy();\n if (this.state.held) throw new Error('native_host_idle_lease_held');\n }\n proof() {\n this.assertHealthy();\n return { bootId: this.bootId, pid: process.pid, endpoint: this.endpoint, epoch: this.state.epoch, held: this.state.held, owner: this.state.owner };\n }\n private validate(request: HostLeaseRequest): void {\n this.assertHealthy();\n if (request.bootId !== this.bootId || request.epoch !== this.state.epoch || !Number.isSafeInteger(request.epoch) ||\n typeof request.owner !== 'string' || !/^[a-zA-Z0-9_-]{8,128}$/.test(request.owner) || typeof request.token !== 'string' || !/^[a-f0-9]{64}$/.test(request.token)) throw new Error('native_host_lease_identity_mismatch');\n }\n acquire(request: HostLeaseRequest, idle: boolean) {\n this.validate(request);\n if (this.state.held) {\n if (this.state.owner !== request.owner || this.state.tokenHash !== digest(request.token)) throw new Error('native_host_lease_owned');\n return this.proof(); // Lost acquire ACK / authenticated reattach after host restart.\n }\n if (!idle) throw new Error('native_host_not_proven_idle');\n this.persist({ ...this.state, held: true, owner: request.owner, tokenHash: digest(request.token) });\n return this.proof();\n }\n release(request: HostLeaseRequest) {\n this.validate(request);\n if (!this.state.held || this.state.owner !== request.owner || this.state.tokenHash !== digest(request.token)) throw new Error('native_host_lease_owned');\n this.persist({ ...this.state, epoch: this.state.epoch + 1, held: false, owner: null, tokenHash: null });\n return this.proof();\n }\n async close(): Promise<void> {\n this.healthy = false;\n const child = this.child;\n this.child = null;\n if (!child || child.exitCode !== null || child.signalCode !== null) return;\n await new Promise<void>(resolve => { child.once('exit', () => resolve()); child.stdin.end(); });\n }\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { resolveInstanceConfigDir } from '@adhdev/session-host-core';\nimport type { SessionBufferSnapshot, SessionHostRecord, SessionTermination } from '@adhdev/session-host-core';\n\nexport interface PersistedRuntimeState {\n record: SessionHostRecord;\n snapshot: SessionBufferSnapshot;\n updatedAt: number;\n}\n\nexport interface PersistedTombstone {\n sessionId: string;\n termination: SessionTermination;\n updatedAt: number;\n}\n\ninterface SessionHostStorageOptions {\n appName?: string;\n /**\n * Explicit storage root (the instance's session-host state dir). Defaults to\n * `<instanceConfigDir>/session-host/<appName>` — derived from\n * ADHDEV_CONFIG_DIR so each daemon instance persists its own runtime records\n * and tombstones. The default instance resolves to `<home>/.adhdev`,\n * byte-identical to the pre-instance layout.\n */\n rootDir?: string;\n}\n\nexport class SessionHostStorage {\n private readonly rootDir: string;\n private readonly runtimesDir: string;\n private readonly tombstonesDir: string;\n\n constructor(options: SessionHostStorageOptions = {}) {\n const appName = options.appName || 'adhdev';\n this.rootDir = options.rootDir\n || path.join(resolveInstanceConfigDir(process.env), 'session-host', appName);\n this.runtimesDir = path.join(this.rootDir, 'runtimes');\n this.tombstonesDir = path.join(this.rootDir, 'tombstones');\n }\n\n /** Unknown/corrupt recovery files also veto idle admission; reads names only. */\n hasRuntimeEntries(): boolean {\n if (!fs.existsSync(this.runtimesDir)) return false;\n const stat = fs.lstatSync(this.runtimesDir);\n if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error('native_host_runtime_storage_untrusted');\n return fs.readdirSync(this.runtimesDir).length > 0;\n }\n\n loadAll(): PersistedRuntimeState[] {\n if (!fs.existsSync(this.runtimesDir)) return [];\n const entries = fs.readdirSync(this.runtimesDir, { withFileTypes: true });\n const states: PersistedRuntimeState[] = [];\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith('.json')) continue;\n const fullPath = path.join(this.runtimesDir, entry.name);\n try {\n const parsed = JSON.parse(fs.readFileSync(fullPath, 'utf8')) as PersistedRuntimeState;\n if (parsed?.record?.sessionId) {\n states.push(parsed);\n }\n } catch {\n // Ignore malformed snapshots; host should still boot.\n }\n }\n return states.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));\n }\n\n save(record: SessionHostRecord, snapshot: SessionBufferSnapshot): void {\n fs.mkdirSync(this.runtimesDir, { recursive: true });\n const filePath = path.join(this.runtimesDir, `${record.sessionId}.json`);\n const payload: PersistedRuntimeState = {\n record,\n snapshot,\n updatedAt: Date.now(),\n };\n fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf8');\n }\n\n remove(sessionId: string): void {\n const filePath = path.join(this.runtimesDir, `${sessionId}.json`);\n try {\n fs.unlinkSync(filePath);\n } catch {\n // File may not exist — ignore.\n }\n }\n\n /**\n * Persist a compact termination tombstone. Kept in a separate directory from\n * live runtimes so it survives the post-exit cleanup of the runtime file and\n * remains inspectable for post-mortem diagnostics.\n */\n saveTombstone(sessionId: string, termination: SessionTermination): void {\n fs.mkdirSync(this.tombstonesDir, { recursive: true });\n const filePath = path.join(this.tombstonesDir, `${sessionId}.json`);\n const payload: PersistedTombstone = {\n sessionId,\n termination,\n updatedAt: Date.now(),\n };\n fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf8');\n }\n\n loadTombstone(sessionId: string): PersistedTombstone | null {\n const filePath = path.join(this.tombstonesDir, `${sessionId}.json`);\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as PersistedTombstone;\n return parsed?.sessionId ? parsed : null;\n } catch {\n return null;\n }\n }\n\n loadAllTombstones(): PersistedTombstone[] {\n if (!fs.existsSync(this.tombstonesDir)) return [];\n const entries = fs.readdirSync(this.tombstonesDir, { withFileTypes: true });\n const states: PersistedTombstone[] = [];\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith('.json')) continue;\n const fullPath = path.join(this.tombstonesDir, entry.name);\n try {\n const parsed = JSON.parse(fs.readFileSync(fullPath, 'utf8')) as PersistedTombstone;\n if (parsed?.sessionId) states.push(parsed);\n } catch {\n // Ignore malformed tombstones.\n }\n }\n return states.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));\n }\n\n removeTombstone(sessionId: string): void {\n const filePath = path.join(this.tombstonesDir, `${sessionId}.json`);\n try {\n fs.unlinkSync(filePath);\n } catch {\n // File may not exist — ignore.\n }\n }\n}\n","import * as path from 'path';\nimport {\n SESSION_HOST_SUPPORTED_REQUEST_TYPES,\n} from '@adhdev/session-host-core';\nimport type {\n SessionHostDiagnostics,\n SessionHostLogEntry,\n SessionHostRecord,\n SessionHostRequestTrace,\n SessionHostRuntimeTransition,\n} from '@adhdev/session-host-core';\n\nexport const MAX_RECENT_DIAGNOSTICS = 200;\n\n/**\n * Absolute path of the running host script, for `SessionHostDiagnostics.hostEntryPath`.\n *\n * `process.argv[1]` is what the parent daemon actually spawned\n * (`spawn(node, [entry])` in managed-host's `spawnHost`), so it is exactly the\n * value a client wants to compare against its own `resolveEntry()`. It is used\n * in preference to `__filename` because the shipped artifact is a single\n * bundled file whose `__filename` is the same path anyway, while `argv[1]`\n * additionally survives the ESM build with no CJS-only globals.\n *\n * Returns undefined rather than guessing when argv[1] is absent (e.g. an\n * embedded/test host), so callers see \"unknown\" instead of a wrong path.\n */\nfunction resolveHostEntryPath(): string | undefined {\n const entry = process.argv[1];\n if (typeof entry !== 'string' || !entry.trim()) return undefined;\n try {\n return path.resolve(entry);\n } catch {\n return entry;\n }\n}\n\nexport function pushRecent<T>(bucket: T[], entry: T, max = MAX_RECENT_DIAGNOSTICS): void {\n bucket.push(entry);\n if (bucket.length > max) {\n bucket.splice(0, bucket.length - max);\n }\n}\n\nexport function getSessionHostRecoveryLabel(record: SessionHostRecord): string | null {\n const recoveryState = typeof record.meta?.runtimeRecoveryState === 'string'\n ? String(record.meta.runtimeRecoveryState).trim()\n : '';\n if (!recoveryState) return null;\n if (recoveryState === 'auto_resumed') return 'restored after restart';\n if (recoveryState === 'resume_failed') return 'restore failed';\n if (recoveryState === 'host_restart_interrupted') return 'host restart interrupted';\n if (recoveryState === 'orphan_snapshot') return 'snapshot recovered';\n return recoveryState.replace(/_/g, ' ');\n}\n\nexport function getSessionSurfaceKind(\n record: SessionHostRecord,\n): 'live_runtime' | 'recovery_snapshot' | 'inactive_record' {\n if (['starting', 'running', 'stopping', 'interrupted'].includes(record.lifecycle)) {\n return 'live_runtime';\n }\n if ((record.lifecycle === 'stopped' || record.lifecycle === 'failed') && (record.meta?.restoredFromStorage === true || getSessionHostRecoveryLabel(record))) {\n return 'recovery_snapshot';\n }\n return 'inactive_record';\n}\n\nexport function annotateSessionSurface(record: SessionHostRecord): SessionHostRecord {\n return {\n ...record,\n surfaceKind: getSessionSurfaceKind(record),\n };\n}\n\nexport function sanitizeDiagnosticsRecord(record: SessionHostRecord): SessionHostRecord {\n return {\n ...record,\n launchCommand: {\n command: record.launchCommand.command,\n args: Array.isArray(record.launchCommand.args) ? [...record.launchCommand.args] : [],\n },\n };\n}\n\nexport interface BuildHostDiagnosticsParams {\n payload?: { includeSessions?: boolean; limit?: number };\n hostStartedAt: number;\n endpointPath: string;\n runtimeCount: number;\n sessions: SessionHostRecord[];\n recentLogs: SessionHostLogEntry[];\n recentRequests: SessionHostRequestTrace[];\n recentTransitions: SessionHostRuntimeTransition[];\n}\n\nexport function buildHostDiagnostics(params: BuildHostDiagnosticsParams): SessionHostDiagnostics {\n const limit = Math.max(1, Math.min(200, Number(params.payload?.limit) || 50));\n const allSessions = params.payload?.includeSessions === false\n ? undefined\n : params.sessions\n .map((record) => annotateSessionSurface(record))\n .map((record) => sanitizeDiagnosticsRecord(record));\n const liveRuntimes = allSessions?.filter((record) => record.surfaceKind === 'live_runtime');\n const recoverySnapshots = allSessions?.filter((record) => record.surfaceKind === 'recovery_snapshot').slice(0, limit);\n const inactiveRecords = allSessions?.filter((record) => record.surfaceKind === 'inactive_record').slice(0, limit);\n const sessions = allSessions\n ? [\n ...(liveRuntimes || []),\n ...(recoverySnapshots || []),\n ...(inactiveRecords || []),\n ]\n : undefined;\n return {\n hostStartedAt: params.hostStartedAt,\n endpoint: params.endpointPath,\n // Self-reported so a client can tell WHICH install this host runs from\n // without needing process-inspection privileges. See SessionHostDiagnostics.\n hostEntryPath: resolveHostEntryPath(),\n runtimeCount: params.runtimeCount,\n supportedRequestTypes: [...SESSION_HOST_SUPPORTED_REQUEST_TYPES],\n sessions,\n liveRuntimes,\n recoverySnapshots,\n inactiveRecords,\n recentLogs: params.recentLogs.slice(-limit),\n recentRequests: params.recentRequests.slice(-limit),\n recentTransitions: params.recentTransitions.slice(-limit),\n };\n}\n","import {\n replayLaunchEnv,\n resolveSessionHostCols,\n resolveSessionHostRows,\n} from '@adhdev/session-host-core';\nimport type {\n CreateSessionPayload,\n SessionHostDuplicateSessionGroup,\n SessionHostRecord,\n} from '@adhdev/session-host-core';\nimport type { PersistedRuntimeState } from './storage.js';\n\nexport function compareDuplicateCandidates(a: SessionHostRecord, b: SessionHostRecord): number {\n const score = (record: SessionHostRecord) => {\n const lifecycleScore = record.lifecycle === 'running'\n ? 4\n : record.lifecycle === 'starting'\n ? 3\n : record.lifecycle === 'stopping'\n ? 2\n : record.lifecycle === 'interrupted'\n ? 1\n : 0;\n return [\n lifecycleScore,\n record.writeOwner ? 1 : 0,\n Array.isArray(record.attachedClients) ? record.attachedClients.length : 0,\n record.lastActivityAt || 0,\n record.startedAt || 0,\n record.createdAt || 0,\n ];\n };\n\n const aScore = score(a);\n const bScore = score(b);\n for (let i = 0; i < aScore.length; i += 1) {\n if (aScore[i] === bScore[i]) continue;\n return bScore[i] - aScore[i];\n }\n return 0;\n}\n\nexport interface DuplicatePrunePlan {\n duplicateGroups: SessionHostDuplicateSessionGroup[];\n keptSessionIds: string[];\n // Records to prune, in group order. Only populated for non-dry-run callers.\n duplicateRecords: SessionHostRecord[];\n}\n\nexport function planDuplicatePrune(\n sessions: SessionHostRecord[],\n filters: { providerFilter: string; workspaceFilter: string },\n): DuplicatePrunePlan {\n const candidates = sessions\n .filter((record) => ['starting', 'running', 'stopping', 'interrupted'].includes(record.lifecycle))\n .filter((record) => !filters.providerFilter || record.providerType === filters.providerFilter)\n .filter((record) => !filters.workspaceFilter || record.workspace === filters.workspaceFilter);\n\n const groups = new Map<string, SessionHostRecord[]>();\n for (const record of candidates) {\n const providerSessionId = typeof record.meta?.providerSessionId === 'string'\n ? String(record.meta.providerSessionId).trim()\n : '';\n if (!providerSessionId) continue;\n const bindingKey = `${record.providerType}::${record.workspace}::${providerSessionId}`;\n const bucket = groups.get(bindingKey) || [];\n bucket.push(record);\n groups.set(bindingKey, bucket);\n }\n\n const duplicateGroups: SessionHostDuplicateSessionGroup[] = [];\n const keptSessionIds: string[] = [];\n const duplicateRecords: SessionHostRecord[] = [];\n\n for (const [bindingKey, records] of groups.entries()) {\n if (records.length < 2) continue;\n const sorted = [...records].sort((a, b) => compareDuplicateCandidates(a, b));\n const kept = sorted[0];\n const duplicates = sorted.slice(1);\n const providerSessionId = typeof kept.meta?.providerSessionId === 'string'\n ? String(kept.meta.providerSessionId)\n : '';\n duplicateGroups.push({\n bindingKey,\n providerType: kept.providerType,\n workspace: kept.workspace,\n providerSessionId,\n keptSessionId: kept.sessionId,\n prunedSessionIds: duplicates.map((record) => record.sessionId),\n });\n keptSessionIds.push(kept.sessionId);\n for (const duplicate of duplicates) {\n duplicateRecords.push(duplicate);\n }\n }\n\n return { duplicateGroups, keptSessionIds, duplicateRecords };\n}\n\nexport function buildPayloadFromRecord(record: SessionHostRecord): CreateSessionPayload {\n return {\n sessionId: record.sessionId,\n runtimeKey: record.runtimeKey,\n displayName: record.displayName,\n providerType: record.providerType,\n category: record.category,\n workspace: record.workspace,\n launchCommand: { ...record.launchCommand, env: replayLaunchEnv(record.launchCommand), envMode: 'launch_overrides' },\n cols: resolveSessionHostCols(typeof record.meta?.sessionHostCols === 'number' ? record.meta.sessionHostCols as number : undefined),\n rows: resolveSessionHostRows(typeof record.meta?.sessionHostRows === 'number' ? record.meta.sessionHostRows as number : undefined),\n meta: record.meta,\n };\n}\n\nexport interface RecoveredRuntimeState {\n recoveredRecord: SessionHostRecord;\n wasLiveRuntime: boolean;\n hadRecoveryInterest: boolean;\n}\n\nexport function buildRecoveredRecord(persisted: PersistedRuntimeState): RecoveredRuntimeState {\n const wasLiveRuntime = !['stopped', 'failed'].includes(persisted.record.lifecycle);\n const hadAttachedClients = Array.isArray(persisted.record.attachedClients) && persisted.record.attachedClients.length > 0;\n const hadWriteOwner = !!persisted.record.writeOwner;\n const hadRecoveryInterest = hadAttachedClients || hadWriteOwner;\n const recoveredRecord: SessionHostRecord = {\n ...persisted.record,\n attachedClients: [],\n writeOwner: null,\n lifecycle: wasLiveRuntime ? 'stopped' : persisted.record.lifecycle,\n lastActivityAt: Date.now(),\n meta: {\n ...(persisted.record.meta || {}),\n restoredFromStorage: true,\n runtimeRecoveryState: wasLiveRuntime ? 'orphan_snapshot' : 'snapshot',\n runtimeHadAttachedClientsAtCrash: hadAttachedClients,\n runtimeHadWriteOwnerAtCrash: hadWriteOwner,\n runtimeAutoResumeSkipped: wasLiveRuntime && hadRecoveryInterest,\n },\n };\n return { recoveredRecord, wasLiveRuntime, hadRecoveryInterest };\n}\n","import type {\n SessionBufferSnapshot,\n SessionHostRecord,\n SessionHostRequest,\n} from '@adhdev/session-host-core';\n\nexport function getRequestSessionId(request: SessionHostRequest): string | undefined {\n const payload = (request as { payload?: Record<string, unknown> }).payload;\n return typeof payload?.sessionId === 'string' ? payload.sessionId : undefined;\n}\n\nexport function getRequestClientId(request: SessionHostRequest): string | undefined {\n const payload = (request as { payload?: Record<string, unknown> }).payload;\n return typeof payload?.clientId === 'string' ? payload.clientId : undefined;\n}\n\n// Merges the registry buffer snapshot with the live runtime's rendered viewport\n// text. For incremental reads (sinceSeq provided) the buffer snapshot is\n// authoritative and the runtime viewport is not overlaid.\nexport function mergeRuntimeSnapshot(\n base: SessionBufferSnapshot,\n record: SessionHostRecord | null | undefined,\n opts: { sinceSeq?: number; runtimeText: string },\n): SessionBufferSnapshot {\n const cols = typeof record?.meta?.sessionHostCols === 'number' ? (record.meta.sessionHostCols as number) : 80;\n const rows = typeof record?.meta?.sessionHostRows === 'number' ? (record.meta.sessionHostRows as number) : 24;\n if (typeof opts.sinceSeq === 'number' || !opts.runtimeText) {\n return {\n ...base,\n text: withReplayResyncPreamble(base.text, opts.sinceSeq),\n cols,\n rows,\n };\n }\n return {\n ...base,\n text: opts.runtimeText,\n truncated: false,\n cols,\n rows,\n };\n}\n\n/** Erase the whole screen and home the cursor. */\nconst REPLAY_RESYNC_PREAMBLE = '\\x1b[2J\\x1b[H';\n\n/**\n * TRIM-BOUNDARY defence, paired with `SessionRingBuffer`'s head repair.\n *\n * `sinceSeq: 0` (\"Load older terminal output\") takes the raw ring-buffer\n * branch above, so the browser xterm parses bytes that begin wherever eviction\n * happened to cut. The buffer now strips a torn *prefix*, but it cannot\n * conjure back state that was evicted rather than damaged: when the cut lands\n * after the session's opening `\\x1b[2J\\x1b[H`, the retained head is perfectly\n * well-formed text and no repair at that layer applies, yet the receiving\n * terminal was never told to clear or home. Output then lands wherever the\n * cursor already was, which is the large blank band at the top of the reported\n * screenshot.\n *\n * So put the terminal into a known state before replaying into it. This is\n * only correct for a from-scratch replay: an incremental `sinceSeq: N` read is\n * a delta appended to what the client already shows, and clearing there would\n * erase the scrollback the client is extending. `sinceSeq: 0` is the\n * \"give me everything you still have\" request, and `undefined` reaches this\n * branch only when the runtime viewport was unavailable — a full read too.\n */\nfunction withReplayResyncPreamble(text: string, sinceSeq?: number): string {\n if (typeof sinceSeq === 'number' && sinceSeq > 0) return text;\n if (!text) return text;\n if (text.startsWith(REPLAY_RESYNC_PREAMBLE)) return text;\n return `${REPLAY_RESYNC_PREAMBLE}${text}`;\n}\n","import * as fs from 'fs';\nimport * as os from 'os';\n\n/**\n * Detects a wedged libuv thread pool and reports it once.\n *\n * node-pty writes to the PTY with `fs.write`, which runs on the libuv thread\n * pool. On 2026-10-21 a preview host was found with every pool request\n * (`fs.*`, `crypto.pbkdf2`, `dns.lookup`) never completing while the main loop\n * still served IPC: the host acknowledged every `send_input`, the PTY write\n * queue grew without draining, and no hosted session could receive input for\n * hours. Nothing in that state recovers on its own, and a host that answers\n * IPC never looks dead to the daemon, so the host has to notice it itself.\n *\n * One probe is in flight at a time. A probe that does not complete within\n * `stallMs` means the pool is not making progress; `onStall` fires once and\n * the watchdog stops. Timers are unref'd so the watchdog never keeps the\n * process alive.\n */\nexport interface ThreadpoolWatchdogOptions {\n /** How often to start a probe when none is in flight. */\n intervalMs?: number;\n /** How long one probe may stay in flight before the pool counts as wedged. */\n stallMs?: number;\n /** A thread-pool operation that calls `done` when it completes. */\n probe?: (done: () => void) => void;\n onStall: (stalledForMs: number) => void;\n now?: () => number;\n}\n\nexport interface ThreadpoolWatchdog {\n stop(): void;\n /** Runs one check immediately; exposed for tests. */\n tick(): void;\n}\n\nexport const THREADPOOL_WATCHDOG_INTERVAL_MS = 15_000;\n// Long enough that a pool saturated by legitimate work (large snapshot reads,\n// a slow disk) is not mistaken for a wedge.\nexport const THREADPOOL_WATCHDOG_STALL_MS = 120_000;\n\nfunction defaultProbe(done: () => void): void {\n fs.stat(os.tmpdir(), () => done());\n}\n\nexport function startThreadpoolWatchdog(options: ThreadpoolWatchdogOptions): ThreadpoolWatchdog {\n const intervalMs = options.intervalMs ?? THREADPOOL_WATCHDOG_INTERVAL_MS;\n const stallMs = options.stallMs ?? THREADPOOL_WATCHDOG_STALL_MS;\n const probe = options.probe ?? defaultProbe;\n const now = options.now ?? Date.now;\n let inFlightSince: number | null = null;\n let stopped = false;\n\n const tick = (): void => {\n if (stopped) return;\n if (inFlightSince !== null) {\n const stalledForMs = now() - inFlightSince;\n if (stalledForMs >= stallMs) {\n stopped = true;\n clearInterval(timer);\n options.onStall(stalledForMs);\n }\n return;\n }\n const startedAt = now();\n inFlightSince = startedAt;\n probe(() => {\n if (inFlightSince === startedAt) inFlightSince = null;\n });\n };\n\n const timer = setInterval(tick, intervalMs);\n timer.unref?.();\n return {\n stop() {\n stopped = true;\n clearInterval(timer);\n },\n tick,\n };\n}\n\n/**\n * Writes one line to stderr synchronously. `console.error` can silently drop\n * output once stderr's stream has errored (the wedged host's log file stopped\n * growing after a disk-full spell), and the last line before exit must land.\n */\nexport function writeStderrLineSync(line: string): void {\n try {\n fs.writeSync(2, `${line}\\n`);\n } catch {\n // noop — nothing else can report it\n }\n}\n"],"mappings":"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","names":["fs","path","import_session_host_core","fs","path","import_session_host_core","fs","stat","resolve","fs","path","import_node_crypto","resolve","stat","fs","path","import_session_host_core","stat","path","import_session_host_core","import_session_host_core","relative","resolve","waiters","fs","os","stat"]}