@ai-matrx/coding-sessions 0.1.81 → 0.1.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/engine/index.cjs +257 -81
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.cts +1 -1
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/index.js +250 -74
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/worker.js +13 -1
- package/dist/engine/worker.js.map +1 -1
- package/dist/{index-RYOb-YZT.d.cts → index-DQ0teQvw.d.cts} +18 -0
- package/dist/{index-RYOb-YZT.d.ts → index-DQ0teQvw.d.ts} +18 -0
- package/dist/index.cjs +21 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +21 -3
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +62 -8
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +18 -0
- package/dist/react/index.d.ts +18 -0
- package/dist/react/index.js +62 -8
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +266 -90
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +258 -82
- package/dist/server/index.js.map +1 -1
- package/dist/ui/assets/index-C-_1qjy9.css +2 -0
- package/dist/ui/assets/index-CmFgFvLa.js +69 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/index-B3Ic2ziA.js +0 -69
- package/dist/ui/assets/index-BAkpc01s.css +0 -2
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/index.ts","../../src/engine/index.ts","../../src/engine/raw-backup.ts","../../src/normalize/claude.ts","../../src/normalize/codex.ts","../../src/normalize/lines.ts","../../src/types.ts","../../src/provider-health.ts","../../src/engine/clean-env.ts","../../src/engine/files.ts","../../src/engine/activity.ts","../../src/engine/preferences.ts","../../src/engine/search.ts","../../src/engine/store.ts","../../src/engine/user-defaults.ts","../../src/server/bridge.ts"],"sourcesContent":["/**\n * `@ai-matrx/coding-sessions/server` — the local host.\n *\n * HTTP + WebSocket on 127.0.0.1 ONLY, guarded by a per-launch random token:\n * serves the built UI and bridges it to the engine. Nothing listens on a\n * public interface; a page on another origin can neither call the API (token\n * and Origin both checked) nor read the token (it only ever appears in the URL\n * the host prints for the person who launched it).\n */\n\nimport { randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport http from \"node:http\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { WebSocketServer, type WebSocket } from \"ws\";\n\nimport {\n createCodingSessionsEngine,\n type CodingSessionsEngine,\n type CodingSessionsEngineOptions,\n} from \"../engine/index\";\nimport { createHostBridge, type HostBridge } from \"./bridge\";\n\nexport { createHostBridge, BRIDGE_METHODS, BridgeError } from \"./bridge\";\nexport type { HostBridge, BridgeableEngine } from \"./bridge\";\n\nexport interface CodingSessionsHostOptions extends CodingSessionsEngineOptions {\n /** Port on 127.0.0.1. `0` picks a free one. Default 4789. */\n port?: number | undefined;\n /** The access token; a fresh random one per launch when omitted. */\n token?: string | undefined;\n /** Directory of the built UI. Default: this package's `dist/ui`. */\n uiDir?: string | undefined;\n /** Use an engine you already built (tests, a desktop shell). */\n engine?: CodingSessionsEngine | undefined;\n}\n\nexport interface CodingSessionsHost {\n url: string;\n port: number;\n token: string;\n engine: CodingSessionsEngine;\n close(): Promise<void>;\n}\n\nconst HOST = \"127.0.0.1\";\n\nconst MIME: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".json\": \"application/json\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff2\": \"font/woff2\",\n \".map\": \"application/json\",\n};\n\nfunction moduleDir(): string {\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\nexport function defaultUiDir(): string | null {\n for (const candidate of [\n path.resolve(moduleDir(), \"..\", \"ui\"),\n path.resolve(moduleDir(), \"..\", \"..\", \"dist\", \"ui\"),\n ]) {\n if (existsSync(path.join(candidate, \"index.html\"))) return candidate;\n }\n return null;\n}\n\nfunction tokensMatch(expected: string, given: string | null): boolean {\n if (!given) return false;\n const a = Buffer.from(expected);\n const b = Buffer.from(given);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nconst NO_UI_PAGE = `<!doctype html><meta charset=\"utf-8\"><title>Coding sessions</title>\n<body style=\"font:15px system-ui;padding:48px;max-width:560px\">\n<h1 style=\"font-size:20px\">The coding sessions screen has not been built yet.</h1>\n<p>The local host is running, but its web page is missing from this install. Build the package\n(<code>pnpm --filter @ai-matrx/coding-sessions build</code>) and reload.</p></body>`;\n\nasync function serveStatic(\n uiDir: string | null,\n req: http.IncomingMessage,\n res: http.ServerResponse,\n): Promise<void> {\n const url = new URL(req.url ?? \"/\", `http://${HOST}`);\n if (!uiDir) {\n res.writeHead(503, { \"content-type\": \"text/html; charset=utf-8\" });\n res.end(NO_UI_PAGE);\n return;\n }\n const requested = decodeURIComponent(url.pathname);\n let file = path.resolve(uiDir, `.${requested}`);\n if (!file.startsWith(uiDir)) {\n res.writeHead(403).end();\n return;\n }\n const stat = await fs.stat(file).catch(() => null);\n if (!stat || stat.isDirectory()) file = path.join(uiDir, \"index.html\");\n const body = await fs.readFile(file).catch(() => null);\n if (!body) {\n res.writeHead(404).end();\n return;\n }\n const ext = path.extname(file);\n res.writeHead(200, {\n \"content-type\": MIME[ext] ?? \"application/octet-stream\",\n \"cache-control\": ext === \".html\" ? \"no-store\" : \"public, max-age=31536000, immutable\",\n \"x-content-type-options\": \"nosniff\",\n \"referrer-policy\": \"no-referrer\",\n });\n res.end(body);\n}\n\ninterface ClientMessage {\n id?: unknown;\n method?: unknown;\n args?: unknown;\n}\n\nfunction attachSocket(socket: WebSocket, bridge: HostBridge): void {\n const unsubscribe = bridge.subscribe((event) => {\n if (socket.readyState === socket.OPEN) socket.send(JSON.stringify({ event }));\n });\n socket.on(\"message\", (data) => {\n let message: ClientMessage;\n try {\n message = JSON.parse(String(data)) as ClientMessage;\n } catch {\n return;\n }\n const id = typeof message.id === \"number\" || typeof message.id === \"string\" ? message.id : null;\n if (id === null || typeof message.method !== \"string\") return;\n const args = Array.isArray(message.args) ? message.args : [];\n bridge.handle(message.method, args).then(\n (result) => {\n if (socket.readyState === socket.OPEN) socket.send(JSON.stringify({ id, ok: true, result: result ?? null }));\n },\n (error: unknown) => {\n if (socket.readyState === socket.OPEN) {\n socket.send(\n JSON.stringify({ id, ok: false, error: error instanceof Error ? error.message : String(error) }),\n );\n }\n },\n );\n });\n socket.on(\"close\", unsubscribe);\n}\n\nexport async function startCodingSessionsHost(\n options: CodingSessionsHostOptions = {},\n): Promise<CodingSessionsHost> {\n const token = options.token ?? randomBytes(24).toString(\"base64url\");\n const engine = options.engine ?? (await createCodingSessionsEngine(options));\n const bridge = createHostBridge(engine);\n const uiDir = options.uiDir ?? defaultUiDir();\n let port = options.port ?? 4789;\n\n const allowedOrigin = (origin: string | undefined): boolean => {\n if (!origin) return true; // non-browser clients (tests, a desktop shell)\n return origin === `http://${HOST}:${port}` || origin === `http://localhost:${port}`;\n };\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url ?? \"/\", `http://${HOST}`);\n if (url.pathname === \"/health\") {\n res.writeHead(200, { \"content-type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, service: \"@ai-matrx/coding-sessions\" }));\n return;\n }\n if (req.method !== \"GET\" && req.method !== \"HEAD\") {\n res.writeHead(405).end();\n return;\n }\n serveStatic(uiDir, req, res).catch(() => {\n if (!res.headersSent) res.writeHead(500);\n res.end();\n });\n });\n\n const wss = new WebSocketServer({ noServer: true, maxPayload: 4 * 1024 * 1024 });\n server.on(\"upgrade\", (req, socket, head) => {\n const url = new URL(req.url ?? \"/\", `http://${HOST}`);\n if (\n url.pathname !== \"/ws\" ||\n !tokensMatch(token, url.searchParams.get(\"token\")) ||\n !allowedOrigin(req.headers.origin)\n ) {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\nConnection: close\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n wss.handleUpgrade(req, socket, head, (ws) => attachSocket(ws, bridge));\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(port, HOST, () => {\n server.off(\"error\", reject);\n const address = server.address();\n if (address && typeof address === \"object\") port = address.port;\n resolve();\n });\n });\n\n const url = `http://${HOST}:${port}/?token=${encodeURIComponent(token)}`;\n return {\n url,\n port,\n token,\n engine,\n async close() {\n for (const client of wss.clients) client.terminate();\n await new Promise<void>((resolve) => wss.close(() => resolve()));\n await new Promise<void>((resolve) => server.close(() => resolve()));\n if (!options.engine) await engine.dispose();\n },\n };\n}\n","/**\n * `@ai-matrx/coding-sessions/engine` — drive the user's own Claude Code and\n * Codex on their own subscription logins, through Paperclip's MIT driver\n * packages, with every fix the 2026-09-27 spike found built in:\n *\n * - each run's driver lives in a forked worker with an ALLOWLISTED\n * environment (`clean-env.ts`), so a host running inside a Claude Code\n * session never leaks `CLAUDE_CODE_*` / `ANTHROPIC_BASE_URL` into the CLI;\n * - Claude runs on the CLI engine with the user's text as the whole prompt;\n * - no Paperclip skill is mounted and no skill-list prompt is appended\n * (`paperclipRuntimeSkills: []`), and a shim strips `PAPERCLIP_*` and\n * Paperclip's `--add-dir` before exec'ing the real CLI;\n * - Codex runs against the user's real `~/.codex`, so sessions appear in\n * their own history and no copy of their login is ever made;\n * - the driver's scratch state goes to this package's data dir, never\n * `~/.paperclip`, and its auth-cache vend is switched off;\n * - stop kills the CLI's process group (the driver ignores `signal`) and the\n * run is recorded as stopped even when Codex exits 0;\n * - a resume the driver would silently replace with a FRESH session is\n * refused and reported, and the driver may never delete the user's own\n * session files.\n */\n\nimport { execFile, fork, type ChildProcess } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { accessSync, constants as fsConstants, existsSync } from \"node:fs\";\nimport { formatFileSize } from \"@ai-matrx/kit/format\";\nimport { createRawBackupScheduler, type RawBackupSink } from \"./raw-backup\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { createClaudeNormalizer } from \"../normalize/claude\";\nimport { createCodexStreamNormalizer } from \"../normalize/codex\";\nimport { createLineSplitter } from \"../normalize/lines\";\nimport {\n PROVIDER_LABEL,\n isTerminalRunStatus,\n type Billing,\n type CodingEvent,\n type CodingProvider,\n type CodingSession,\n type CodingSessionsApi,\n type DiscoveredSession,\n type ProviderStatus,\n type RecentFolder,\n type RunRecord,\n type RunStatus,\n type RunUsage,\n type SendResult,\n type SessionHistory,\n type StartInput,\n type TakeoverInput,\n type TranscriptItem,\n} from \"../types\";\nimport {\n classifyProviderError,\n describeProblem,\n problemFromQuota,\n problemStillApplies,\n} from \"../provider-health\";\nimport type { ModelOption, OpenTarget, ProviderProblem, QuotaWindow } from \"../types\";\nimport { buildCleanEnv } from \"./clean-env\";\nimport {\n defaultProviderHomes,\n discoverLocalSessions,\n findSessionFile,\n readSessionFile,\n sessionActivity,\n type ProviderHomes,\n} from \"./files\";\nimport { PreferenceStore } from \"./preferences\";\nimport { searchLocalChats } from \"./search\";\nimport { RunIndex, type Identity } from \"./store\";\nimport { EFFORT_LEVELS, userDefaults } from \"./user-defaults\";\n\nexport { buildCleanEnv, isAllowedEnvName } from \"./clean-env\";\n/** Largest transcript Full Download hands to a page in one message (the file stays on disk). */\nexport const RAW_TRANSCRIPT_MAX_BYTES = 200 * 1_048_576;\n\nexport { createRawBackupScheduler, createAiMatrxRawBackupSink } from \"./raw-backup\";\nexport type { RawBackupPolicy, RawBackupSink } from \"./raw-backup\";\nexport { discoverLocalSessions, findSessionFile, readSessionFile, defaultProviderHomes, sessionActivity } from \"./files\";\nexport { describeActivity, findDrivingProcess, endsWithOpenToolCall, listProcesses } from \"./activity\";\nexport type { ProviderHomes } from \"./files\";\nexport { searchLocalChats, snippetAround } from \"./search\";\nexport { claudeDefaults, codexDefaults, EFFORT_LEVELS } from \"./user-defaults\";\nexport { PreferenceStore } from \"./preferences\";\n\nexport interface CodingSessionsEngineOptions {\n /** Where the run index and the driver's scratch state live. Default `~/.matrx/coding-sessions`. */\n dataDir?: string | undefined;\n /** The environment the clean one is built FROM. Default `process.env`. */\n hostEnv?: NodeJS.ProcessEnv | undefined;\n /** Explicit CLI paths; default: found on the clean PATH. */\n commands?: Partial<Record<CodingProvider, string>> | undefined;\n /** Where the providers keep their sessions. Default: the user's own homes. */\n homes?: ProviderHomes | undefined;\n /** Ask the drivers for usage windows during `providers()` (Codex). Default true. */\n quota?: boolean | undefined;\n /**\n * Where an opted-in owner's full transcripts are backed up (the host's AI\n * Matrx sign-in). Absent → nothing is ever uploaded. The sink's policy is\n * asked before every upload; with backup off not one byte leaves.\n */\n rawBackup?: RawBackupSink | undefined;\n /** Receives raw provider stdout per run — used to capture test fixtures. */\n onRawOutput?: ((runId: string, provider: CodingProvider, chunk: string) => void) | undefined;\n}\n\nexport interface CodingSessionsEngine extends CodingSessionsApi {\n subscribe(listener: (event: CodingEvent) => void): () => void;\n /** Stop every live run and wait for the index to be written. */\n dispose(): Promise<void>;\n readonly dataDir: string;\n}\n\ninterface WorkerMessage {\n kind: string;\n [key: string]: unknown;\n}\n\ninterface LiveRun {\n run: RunRecord;\n child: ChildProcess;\n pgid: number | null;\n stopRequested: boolean;\n killTimer: NodeJS.Timeout | null;\n stderrTail: string;\n refusals: string[];\n /** The provider file's size when this run began (history reads stop there). */\n fileOffset: number | null;\n /** Items this run produced, for a history read that lands mid-run. */\n items: { seq: number; item: TranscriptItem }[];\n}\n\nfunction moduleDir(): string {\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\nfunction resolveWorkerPath(): string {\n const dir = moduleDir();\n // This module is bundled into BOTH dist/engine and dist/server, so the\n // worker is either beside it or in the sibling engine directory.\n for (const candidate of [\n path.join(dir, \"worker.js\"),\n path.join(dir, \"worker.ts\"),\n path.join(dir, \"..\", \"engine\", \"worker.js\"),\n path.join(dir, \"..\", \"engine\", \"worker.ts\"),\n ]) {\n if (existsSync(candidate)) return candidate;\n }\n throw new Error(`[coding-sessions] The driver worker is missing next to ${dir}.`);\n}\n\n/**\n * The shim must be EXECUTABLE, and npm does not preserve the executable bit of\n * a non-`bin` file in a tarball (the packed-tarball canary caught exactly\n * that). So the engine installs its own copy into its data dir, mode 0755,\n * rewriting it only when the packaged source changed.\n */\nasync function installShim(dataDir: string): Promise<string> {\n const source = path.resolve(moduleDir(), \"..\", \"..\", \"bin\", \"cli-shim.sh\");\n if (!existsSync(source)) throw new Error(`[coding-sessions] The CLI shim is missing at ${source}.`);\n const body = await fs.readFile(source, \"utf8\");\n const target = path.join(dataDir, \"bin\", \"cli-shim.sh\");\n const current = await fs.readFile(target, \"utf8\").catch(() => null);\n if (current !== body) {\n await fs.mkdir(path.dirname(target), { recursive: true });\n await fs.writeFile(target, body, { mode: 0o755 });\n }\n await fs.chmod(target, 0o755);\n return target;\n}\n\nfunction whichOnPath(name: string, pathValue: string): string | null {\n for (const dir of pathValue.split(path.delimiter)) {\n if (!dir) continue;\n const candidate = path.join(dir, name);\n try {\n accessSync(candidate, fsConstants.X_OK);\n return candidate;\n } catch {\n /* keep looking */\n }\n }\n return null;\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nfunction titleFrom(prompt: string): string {\n const flat = prompt.replace(/\\s+/g, \" \").trim();\n return flat.length > 80 ? `${flat.slice(0, 79)}…` : flat || \"New session\";\n}\n\nfunction capitalize(value: string | null | undefined): string | null {\n if (!value) return null;\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction asUsage(value: unknown): RunUsage | null {\n if (typeof value !== \"object\" || value === null) return null;\n const v = value as Record<string, unknown>;\n const n = (x: unknown) => (typeof x === \"number\" && Number.isFinite(x) ? x : 0);\n return {\n inputTokens: n(v.inputTokens),\n outputTokens: n(v.outputTokens),\n cachedInputTokens: n(v.cachedInputTokens),\n };\n}\n\nfunction asBilling(value: unknown): Billing | null {\n if (value === \"subscription\" || value === \"api\") return value;\n if (typeof value === \"string\") return \"unknown\";\n return null;\n}\n\n/**\n * The status the screen shows: what the provider's own auth check says, then\n * — for a provider that looks ready — any usage limit or expired sign-in a run\n * reported (until a run succeeds) or a full quota window.\n */\nexport function describeProviderStatus(\n provider: CodingProvider,\n probe: Record<string, unknown> | undefined,\n lastProblem: ProviderProblem | null = null,\n quota: QuotaWindow[] = [],\n): ProviderStatus {\n const base = describeAuthStatus(provider, probe);\n const withQuota = { ...base, quota };\n if (!base.installed || !base.loggedIn) return { ...withQuota, ready: false, lastProblem };\n const current =\n (lastProblem && problemStillApplies(lastProblem) ? lastProblem : null) ?? problemFromQuota(quota);\n if (!current) return { ...withQuota, ready: true, lastProblem: null };\n const words = describeProblem(provider, current);\n return { ...withQuota, ready: false, lastProblem: current, problem: words.problem, fix: words.fix };\n}\n\nfunction describeAuthStatus(\n provider: CodingProvider,\n probe: Record<string, unknown> | undefined,\n): ProviderStatus {\n const label = PROVIDER_LABEL[provider];\n const installed = probe?.installed === true;\n const version = typeof probe?.version === \"string\" ? probe.version : null;\n const base: ProviderStatus = {\n provider,\n label,\n installed,\n version,\n loggedIn: false,\n billing: \"unknown\",\n plan: null,\n account: null,\n problem: null,\n fix: null,\n ready: false,\n lastProblem: null,\n quota: [],\n };\n if (!installed) {\n return {\n ...base,\n problem: `${label} isn't installed on this computer.`,\n fix:\n provider === \"claude\"\n ? \"Install Claude Code from claude.com/code and sign in once, then check again.\"\n : \"Install Codex from openai.com/codex and sign in once, then check again.\",\n };\n }\n const auth = (probe?.auth ?? null) as Record<string, unknown> | null;\n if (provider === \"claude\") {\n if (!auth || auth.loggedIn !== true) {\n return {\n ...base,\n problem: \"Claude Code is installed but not signed in.\",\n fix: \"Open Claude Code once and sign in with your Claude account, then check again.\",\n };\n }\n const subscription = auth.authMethod === \"claude.ai\";\n return {\n ...base,\n loggedIn: true,\n billing: subscription ? \"subscription\" : \"api\",\n plan: subscription ? capitalize(typeof auth.subscriptionType === \"string\" ? auth.subscriptionType : null) : null,\n };\n }\n if (!auth || auth.loggedIn !== true) {\n return {\n ...base,\n problem: \"Codex is installed but not signed in.\",\n fix: \"Open Codex once and sign in with your ChatGPT account, then check again.\",\n };\n }\n const apiKey = auth.apiKey === true;\n return {\n ...base,\n loggedIn: true,\n billing: apiKey ? \"api\" : \"subscription\",\n plan: capitalize(typeof auth.planType === \"string\" ? auth.planType : null),\n account: typeof auth.email === \"string\" ? auth.email : null,\n };\n}\n\nexport async function createCodingSessionsEngine(\n options: CodingSessionsEngineOptions = {},\n): Promise<CodingSessionsEngine> {\n const dataDir = options.dataDir ?? path.join(os.homedir(), \".matrx\", \"coding-sessions\");\n const stateDir = path.join(dataDir, \"paperclip-state\");\n const homes = options.homes ?? defaultProviderHomes();\n const index = new RunIndex(dataDir);\n await index.load();\n const preferences = new PreferenceStore(dataDir);\n await preferences.load();\n await fs.mkdir(stateDir, { recursive: true });\n const identity: Identity = await index.identity();\n const backups = options.rawBackup\n ? createRawBackupScheduler({\n sink: options.rawBackup,\n findFile: (provider, providerSessionId) => findSessionFile(provider, providerSessionId, homes),\n onError: (error) => console.warn(\"[coding-sessions] raw transcript backup failed:\", error),\n })\n : null;\n /** Last `updatedAt` seen per discovered chat — a change is a turn that ended elsewhere. */\n const discoveredSeen = new Map<string, string>();\n\n // Last usage-limit / sign-in failure per provider, remembered across restarts.\n const healthFile = path.join(dataDir, \"provider-health.json\");\n let health: Partial<Record<CodingProvider, ProviderProblem>> = {};\n try {\n health = JSON.parse(await fs.readFile(healthFile, \"utf8\")) as typeof health;\n } catch {\n health = {};\n }\n const saveHealth = () =>\n fs.writeFile(healthFile, JSON.stringify(health), { mode: 0o600 }).catch(() => undefined);\n function noteRunOutcome(provider: CodingProvider, status: RunStatus, texts: string[]): void {\n if (status === \"completed\") {\n if (health[provider]) {\n delete health[provider];\n void saveHealth();\n }\n return;\n }\n if (status !== \"failed\") return;\n for (const text of texts) {\n const problem = classifyProviderError(text);\n if (problem) {\n health[provider] = problem;\n void saveHealth();\n return;\n }\n }\n }\n\n const workerEnv = buildCleanEnv(options.hostEnv ?? process.env, {\n // The driver's scratch state (prompt bundle, per-run MCP config) lives in\n // OUR data dir; nothing is ever written under ~/.paperclip.\n PAPERCLIP_HOME: stateDir,\n // The Codex driver otherwise \"vends\" cached copies of the user's login.\n PAPERCLIP_CODEX_AUTH_CACHE: \"0\",\n // Marks the forked process as a driver worker (see worker.ts).\n MATRX_CODING_SESSIONS_WORKER: \"1\",\n });\n const commandFor = (provider: CodingProvider): string | null =>\n options.commands?.[provider] ?? whichOnPath(provider, workerEnv.PATH ?? \"\");\n\n const workerPath = resolveWorkerPath();\n const shimPath = await installShim(dataDir);\n const listeners = new Set<(event: CodingEvent) => void>();\n const live = new Map<string, LiveRun>();\n const seqBySession = new Map<string, number>();\n\n function emit(event: CodingEvent): void {\n for (const listener of listeners) {\n try {\n listener(event);\n } catch {\n /* one bad listener never starves the rest */\n }\n }\n }\n\n function saveSession(session: CodingSession): CodingSession {\n index.putSession(session);\n emit({ type: \"session\", session });\n return session;\n }\n\n function saveRun(run: RunRecord): RunRecord {\n index.putRun(run);\n emit({ type: \"run\", run });\n if (backups && isTerminalRunStatus(run.status)) {\n const providerSessionId = index.session(run.sessionId)?.providerSessionId;\n if (providerSessionId) void backups.notify(run.provider, providerSessionId);\n }\n return run;\n }\n\n function emitItem(liveRun: LiveRun, item: TranscriptItem): void {\n const sessionId = liveRun.run.sessionId;\n const seq = (seqBySession.get(sessionId) ?? 0) + 1;\n seqBySession.set(sessionId, seq);\n liveRun.items.push({ seq, item });\n emit({ type: \"item\", sessionId, runId: liveRun.run.runId, seq, item });\n }\n\n // A run the index says is live, with no process behind it, died with the\n // previous host. Say so rather than showing it spinning forever.\n for (const run of index.allRuns()) {\n if (!isTerminalRunStatus(run.status)) {\n index.putRun({\n ...run,\n status: \"failed\",\n endedAt: run.endedAt ?? nowIso(),\n error: \"The app closed while this run was in progress, so it did not finish.\",\n });\n const session = index.session(run.sessionId);\n if (session && session.lastRunId === run.runId) {\n index.putSession({ ...session, lastRunStatus: \"failed\" });\n }\n }\n }\n\n function forkWorker(): ChildProcess {\n return fork(workerPath, [], {\n env: workerEnv,\n cwd: dataDir,\n stdio: [\"ignore\", \"pipe\", \"pipe\", \"ipc\"],\n serialization: \"json\",\n });\n }\n\n function ourPids(): Set<number> {\n const pids = new Set<number>();\n for (const liveRun of live.values()) {\n if (liveRun.pgid !== null) pids.add(liveRun.pgid);\n if (liveRun.child.pid !== undefined) pids.add(liveRun.child.pid);\n }\n return pids;\n }\n\n function activeRunFor(sessionId: string): LiveRun | null {\n for (const liveRun of live.values()) if (liveRun.run.sessionId === sessionId) return liveRun;\n return null;\n }\n\n async function startRun(session: CodingSession, prompt: string): Promise<RunRecord> {\n const provider = session.provider;\n const realCommand = commandFor(provider);\n const runId = randomUUID();\n // No model picked: the person's OWN default. The Claude driver would\n // otherwise force its built-in model over the one they chose in Claude\n // Code; Codex already falls back to its own config when none is passed.\n const model =\n session.model ?? (provider === \"claude\" ? ((await userDefaults(provider, session.cwd)).model ?? null) : null);\n const run: RunRecord = {\n runId,\n sessionId: session.id,\n provider,\n cwd: session.cwd,\n prompt,\n model,\n status: \"starting\",\n startedAt: nowIso(),\n endedAt: null,\n error: null,\n usage: null,\n costUsd: null,\n billing: null,\n };\n saveRun(run);\n saveSession({\n ...session,\n lastRunId: runId,\n lastRunStatus: \"starting\",\n updatedAt: run.startedAt,\n });\n\n if (!realCommand) {\n const failed = saveRun({\n ...run,\n status: \"failed\",\n endedAt: nowIso(),\n error: `${PROVIDER_LABEL[provider]} isn't installed on this computer.`,\n });\n const current = index.session(session.id);\n if (current) saveSession({ ...current, lastRunStatus: \"failed\" });\n return failed;\n }\n\n let fileOffset: number | null = null;\n if (session.providerSessionId) {\n const file = await findSessionFile(provider, session.providerSessionId, homes);\n if (file) fileOffset = (await fs.stat(file).catch(() => null))?.size ?? null;\n }\n\n const child = forkWorker();\n const liveRun: LiveRun = {\n run,\n child,\n pgid: null,\n stopRequested: false,\n killTimer: null,\n stderrTail: \"\",\n refusals: [],\n fileOffset,\n items: [],\n };\n live.set(runId, liveRun);\n emitItem(liveRun, { kind: \"user\", id: `run-${runId}`, text: prompt, at: run.startedAt });\n\n const splitter = createLineSplitter();\n const claude = provider === \"claude\" ? createClaudeNormalizer() : null;\n const codex = provider === \"codex\" ? createCodexStreamNormalizer(runId.slice(0, 8)) : null;\n let knownProviderSession = session.providerSessionId;\n\n const consume = (values: unknown[]) => {\n for (const value of values) {\n const items = claude ? claude.push(value) : codex ? codex.push(value) : [];\n const sid = claude?.sessionId ?? codex?.sessionId ?? null;\n if (sid && sid !== knownProviderSession) {\n knownProviderSession = sid;\n const current = index.session(session.id);\n if (current) saveSession({ ...current, providerSessionId: sid });\n }\n for (const item of items) emitItem(liveRun, item);\n }\n };\n\n const settle = (patch: Partial<RunRecord>) => {\n if (liveRun.killTimer) clearTimeout(liveRun.killTimer);\n live.delete(runId);\n const final = saveRun({ ...liveRun.run, ...patch, endedAt: nowIso() });\n liveRun.run = final;\n noteRunOutcome(provider, final.status, [\n final.error ?? \"\",\n ...liveRun.items.flatMap((entry) => (entry.item.kind === \"error\" ? [entry.item.text] : [])),\n ]);\n const current = index.session(session.id);\n if (current) {\n const [next, ...rest] = current.queued;\n saveSession({ ...current, lastRunStatus: final.status, updatedAt: final.endedAt ?? nowIso() });\n if (next !== undefined) {\n const updated = index.session(session.id);\n if (updated) {\n const trimmed = saveSession({ ...updated, queued: rest });\n void startRun(trimmed, next);\n }\n }\n }\n void pruneDriverScratch();\n };\n\n let settled = false;\n child.on(\"message\", (raw) => {\n const message = raw as WorkerMessage;\n switch (message.kind) {\n case \"log\": {\n const chunk = String(message.chunk ?? \"\");\n if (message.stream === \"stdout\") {\n options.onRawOutput?.(runId, provider, chunk);\n const { values } = splitter.push(chunk);\n consume(values);\n } else {\n liveRun.stderrTail = (liveRun.stderrTail + chunk).slice(-4000);\n }\n return;\n }\n case \"spawn\": {\n const pgid =\n typeof message.processGroupId === \"number\"\n ? message.processGroupId\n : typeof message.pid === \"number\"\n ? message.pid\n : null;\n liveRun.pgid = pgid;\n if (liveRun.stopRequested) {\n killGroup(liveRun);\n return;\n }\n liveRun.run = saveRun({ ...liveRun.run, status: \"running\" });\n const current = index.session(session.id);\n if (current) saveSession({ ...current, lastRunStatus: \"running\" });\n return;\n }\n case \"refused\": {\n liveRun.refusals.push(`${String(message.op)}: ${String(message.target)}`);\n if (message.op === \"config-guard\") {\n emitItem(liveRun, {\n kind: \"notice\",\n id: \"config-guard\",\n level: \"warning\",\n text: \"The Codex driver has changed, so this run could not stop it from rewriting your ~/.codex/config.toml. Its contents are kept; update AI Matrx to restore the protection.\",\n });\n return;\n }\n if (message.op === \"delete\" || message.op === \"remove\") {\n emitItem(liveRun, {\n kind: \"notice\",\n id: `refused-${liveRun.refusals.length}`,\n level: \"warning\",\n text: \"The driver tried to delete part of your saved chat history. That was blocked; your history is untouched.\",\n });\n }\n return;\n }\n case \"result\": {\n consume(splitter.flush().values);\n settled = true;\n const result = (message.result ?? {}) as Record<string, unknown>;\n const usage = asUsage(result.usage);\n const billing = asBilling(result.billingType);\n const costUsd = typeof result.costUsd === \"number\" ? result.costUsd : null;\n if (liveRun.stopRequested) {\n // Codex exits 0 when its process group is killed; the host knows\n // better — the person pressed Stop.\n settle({ status: \"stopped\", usage, billing, costUsd, error: null });\n return;\n }\n if (message.refusedFreshSession === true) {\n settle({\n status: \"failed\",\n usage,\n billing,\n costUsd,\n error:\n `${PROVIDER_LABEL[provider]} could not reopen this chat, and would have started a new, empty one instead. ` +\n \"Nothing was sent. The chat may have been deleted or moved on this computer.\",\n });\n return;\n }\n const exitCode = typeof result.exitCode === \"number\" ? result.exitCode : null;\n const errorMessage = typeof result.errorMessage === \"string\" ? result.errorMessage : null;\n if (exitCode === 0 && !errorMessage && result.timedOut !== true) {\n settle({ status: \"completed\", usage, billing, costUsd, error: null });\n } else {\n const tail = liveRun.stderrTail.trim().split(\"\\n\").slice(-6).join(\"\\n\");\n settle({\n status: \"failed\",\n usage,\n billing,\n costUsd,\n error:\n errorMessage ??\n (tail || `${PROVIDER_LABEL[provider]} exited with code ${exitCode ?? \"unknown\"}.`),\n });\n }\n return;\n }\n case \"fatal\": {\n settled = true;\n settle({\n status: liveRun.stopRequested ? \"stopped\" : \"failed\",\n error: liveRun.stopRequested ? null : String(message.message ?? \"The driver failed.\"),\n });\n return;\n }\n default:\n return;\n }\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n liveRun.stderrTail = (liveRun.stderrTail + chunk.toString(\"utf8\")).slice(-4000);\n });\n child.on(\"exit\", (code, signal) => {\n if (settled) return;\n settled = true;\n settle({\n status: liveRun.stopRequested ? \"stopped\" : \"failed\",\n error: liveRun.stopRequested\n ? null\n : `The driver process ended unexpectedly (${signal ?? `code ${code ?? \"unknown\"}`}). ${liveRun.stderrTail.trim().split(\"\\n\").slice(-3).join(\" \")}`.trim(),\n });\n });\n\n child.send({\n kind: \"run\",\n provider,\n runId,\n cwd: session.cwd,\n prompt,\n model,\n effort: session.effort ?? null,\n resumeSessionId: session.providerSessionId,\n shimPath,\n realCommand,\n identity,\n });\n return run;\n }\n\n function killGroup(liveRun: LiveRun): void {\n const target = liveRun.pgid;\n if (target === null) return;\n try {\n process.kill(-target, \"SIGTERM\");\n } catch {\n /* already gone */\n }\n liveRun.killTimer = setTimeout(() => {\n try {\n process.kill(-target, \"SIGKILL\");\n } catch {\n /* already gone */\n }\n }, 3000);\n }\n\n async function pruneDriverScratch(): Promise<void> {\n // The Claude driver writes a per-run MCP config under its state dir; it is\n // empty (no Paperclip MCP servers) and never read again.\n const runsDir = path.join(\n stateDir,\n \"instances\",\n \"default\",\n \"companies\",\n identity.companyId,\n \"agents\",\n identity.agentId,\n \"claude-runtime\",\n \"runs\",\n );\n const entries = await fs.readdir(runsDir).catch(() => [] as string[]);\n await Promise.all(\n entries\n .filter((name) => !live.has(name))\n .map((name) => fs.rm(path.join(runsDir, name), { recursive: true, force: true }).catch(() => undefined)),\n );\n }\n\n async function probe(): Promise<Record<string, Record<string, unknown>>> {\n return new Promise((resolve) => {\n const child = forkWorker();\n let answered = false;\n const timer = setTimeout(() => {\n if (answered) return;\n answered = true;\n child.kill(\"SIGKILL\");\n resolve({});\n }, 20000);\n child.on(\"message\", (raw) => {\n const message = raw as WorkerMessage;\n if (message.kind === \"probe-result\" && !answered) {\n answered = true;\n clearTimeout(timer);\n resolve({\n claude: (message.claude ?? {}) as Record<string, unknown>,\n codex: (message.codex ?? {}) as Record<string, unknown>,\n });\n }\n });\n child.on(\"exit\", () => {\n if (answered) return;\n answered = true;\n clearTimeout(timer);\n resolve({});\n });\n child.send({\n kind: \"probe\",\n commands: { claude: commandFor(\"claude\"), codex: commandFor(\"codex\") },\n quota: options.quota !== false,\n });\n });\n }\n\n function newSession(input: {\n provider: CodingProvider;\n cwd: string;\n title: string;\n model: string | null;\n effort?: string | null;\n origin: CodingSession[\"origin\"];\n providerSessionId: string | null;\n }): CodingSession {\n const at = nowIso();\n return {\n id: randomUUID(),\n provider: input.provider,\n providerSessionId: input.providerSessionId,\n cwd: input.cwd,\n title: input.title,\n model: input.model,\n effort: input.effort ?? null,\n origin: input.origin,\n createdAt: at,\n updatedAt: at,\n lastRunId: null,\n lastRunStatus: null,\n queued: [],\n };\n }\n\n function resolveFolder(raw: string): string | null {\n const trimmed = raw.trim();\n if (!trimmed) return null;\n return path.resolve(trimmed.replace(/^~(?=$|\\/)/, os.homedir()));\n }\n\n async function checkFolder(raw: string): Promise<import(\"../types\").FolderCheck> {\n const target = resolveFolder(raw);\n if (!target) return { path: \"\", exists: false, isDirectory: false };\n const stat = await fs.stat(target).catch(() => null);\n return { path: target, exists: stat !== null, isDirectory: stat?.isDirectory() === true };\n }\n\n async function assertFolder(cwd: string): Promise<string> {\n const resolved = path.resolve(cwd.replace(/^~(?=$|\\/)/, os.homedir()));\n const stat = await fs.stat(resolved).catch(() => null);\n if (!stat?.isDirectory()) {\n throw new Error(`The folder ${resolved} doesn't exist on this computer.`);\n }\n return resolved;\n }\n\n const engine: CodingSessionsEngine = {\n dataDir,\n\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n\n async providers() {\n const result = await probe();\n return Promise.all(\n ([\"claude\", \"codex\"] as const).map(async (provider) => {\n const probeResult = result[provider];\n const quota = Array.isArray(probeResult?.quota) ? (probeResult.quota as QuotaWindow[]) : [];\n const status = describeProviderStatus(provider, probeResult, health[provider] ?? null, quota);\n const models = Array.isArray(probeResult?.models) ? (probeResult.models as ModelOption[]) : [];\n const mine = await userDefaults(provider, null);\n // With no model of their own, Claude runs on the driver's built-in\n // default; Codex omits the flag and uses the CLI's own.\n const driverDefault =\n provider === \"claude\" && typeof probeResult?.driverDefaultModel === \"string\"\n ? probeResult.driverDefaultModel\n : null;\n return {\n ...status,\n models,\n efforts: EFFORT_LEVELS[provider],\n defaultModel: mine.model\n ? { id: mine.model, source: \"settings\" as const }\n : driverDefault\n ? { id: driverDefault, source: \"driver\" as const }\n : null,\n defaultEffort: mine.effort,\n };\n }),\n );\n },\n\n async discoverSessions(opts) {\n const found = await discoverLocalSessions({ limit: opts?.limit, homes, excludePids: ourPids() });\n if (backups) {\n for (const chat of found) {\n const key = `${chat.provider}:${chat.providerSessionId}`;\n const previous = discoveredSeen.get(key);\n discoveredSeen.set(key, chat.updatedAt);\n // Only a CHANGE since this engine last looked — never a first-sight\n // sweep of someone's whole history.\n if (previous !== undefined && previous !== chat.updatedAt) {\n void backups.notify(chat.provider, chat.providerSessionId);\n }\n }\n }\n return found;\n },\n\n async recentFolders(): Promise<RecentFolder[]> {\n const seen = new Map<string, string>();\n for (const session of index.sessions()) {\n if (!seen.has(session.cwd)) seen.set(session.cwd, session.updatedAt);\n }\n const discovered: DiscoveredSession[] = await discoverLocalSessions({ limit: 80, homes });\n for (const d of discovered) {\n if (d.cwd && !seen.has(d.cwd)) seen.set(d.cwd, d.updatedAt);\n }\n const folders = [...seen.entries()]\n .sort((a, b) => b[1].localeCompare(a[1]))\n .slice(0, 12);\n return Promise.all(\n folders.map(async ([folder, lastUsedAt]) => ({\n path: folder,\n lastUsedAt,\n exists: (await fs.stat(folder).catch(() => null))?.isDirectory() === true,\n })),\n );\n },\n\n async listSessions() {\n return index.sessions();\n },\n\n async listRuns(sessionId) {\n const session = index.session(sessionId);\n return session ? index.runs(session.id) : [];\n },\n\n async history(sessionId, options): Promise<SessionHistory> {\n const session = index.session(sessionId);\n if (!session) {\n return { items: [], truncated: false, unavailable: \"This session is not in the list anymore.\", seq: 0 };\n }\n const active = activeRunFor(session.id);\n let base: SessionHistory = { items: [], truncated: false, unavailable: null, seq: 0 };\n if (session.providerSessionId) {\n const file = await findSessionFile(session.provider, session.providerSessionId, homes);\n if (file) {\n const endOffset = active ? (active.fileOffset ?? 0) : undefined;\n base = await readSessionFile(session.provider, file, endOffset, options?.maxBytes);\n } else if (!active) {\n base = {\n items: [],\n truncated: false,\n unavailable: `${PROVIDER_LABEL[session.provider]} has no saved transcript for this chat on this computer.`,\n seq: 0,\n };\n }\n }\n // Taken synchronously right before answering, so a live item is either\n // in this answer (seq ≤ answer.seq) or arrives after it.\n const liveItems = active ? active.items : [];\n return {\n ...base,\n items: [...base.items, ...liveItems.map((entry) => entry.item)],\n seq: seqBySession.get(session.id) ?? 0,\n };\n },\n\n async checkFolder(raw) {\n return checkFolder(raw);\n },\n\n async createFolder(raw) {\n const target = resolveFolder(raw);\n if (!target) throw new Error(\"Type a folder path first.\");\n await fs.mkdir(target, { recursive: true });\n return checkFolder(target);\n },\n\n async sessionActivity(provider, providerSessionId) {\n // A session WE are driving is not \"live elsewhere\".\n for (const liveRun of live.values()) {\n const session = index.session(liveRun.run.sessionId);\n if (session?.providerSessionId === providerSessionId) return null;\n }\n // Our own finished runs wrote the file too; those writes are not evidence.\n let ownWritesUntilMs: number | undefined;\n const ours = index.session(providerSessionId);\n if (ours) {\n for (const run of index.runs(ours.id)) {\n const ended = run.endedAt ? Date.parse(run.endedAt) + 5000 : undefined;\n if (ended !== undefined && (ownWritesUntilMs === undefined || ended > ownWritesUntilMs)) ownWritesUntilMs = ended;\n }\n }\n return sessionActivity(provider, providerSessionId, { homes, excludePids: ourPids(), ownWritesUntilMs });\n },\n\n async readTranscript(provider, providerSessionId, options) {\n const file = await findSessionFile(provider, providerSessionId, homes);\n if (!file) {\n return {\n items: [],\n truncated: false,\n unavailable: `${PROVIDER_LABEL[provider]} has no saved transcript for this chat on this computer.`,\n seq: 0,\n };\n }\n return readSessionFile(provider, file, undefined, options?.maxBytes);\n },\n\n async readRawTranscript(provider, providerSessionId) {\n const file = await findSessionFile(provider, providerSessionId, homes);\n if (!file) {\n return {\n available: false,\n reason: `${PROVIDER_LABEL[provider]} has no saved transcript for this chat on this computer.`,\n };\n }\n const stat = await fs.stat(file);\n if (stat.size > RAW_TRANSCRIPT_MAX_BYTES) {\n return {\n available: false,\n reason: `This transcript is ${formatFileSize(stat.size)}, larger than the ${formatFileSize(RAW_TRANSCRIPT_MAX_BYTES)} this page can hand over. It is at ${file}.`,\n };\n }\n const content = await fs.readFile(file, \"utf8\");\n return { available: true, fileName: path.basename(file), bytes: stat.size, content };\n },\n\n async start(input: StartInput): Promise<SendResult> {\n const prompt = input.prompt.trim();\n if (!prompt) throw new Error(\"Type what you want done before starting.\");\n const cwd = await assertFolder(input.cwd);\n const session = saveSession(\n newSession({\n provider: input.provider,\n cwd,\n title: titleFrom(prompt),\n model: input.model?.trim() || null,\n effort: input.effort?.trim() || null,\n origin: \"started\",\n providerSessionId: null,\n }),\n );\n const run = await startRun(session, prompt);\n return { session: index.session(session.id) ?? session, run, queued: false };\n },\n\n async takeover(input: TakeoverInput) {\n const existing = index.session(input.providerSessionId);\n if (existing) return existing;\n const cwd = await assertFolder(input.cwd);\n return saveSession(\n newSession({\n provider: input.provider,\n cwd,\n title: input.title?.trim() || \"Taken-over chat\",\n model: null,\n origin: \"takeover\",\n providerSessionId: input.providerSessionId,\n }),\n );\n },\n\n async send(sessionId, rawPrompt): Promise<SendResult> {\n const prompt = rawPrompt.trim();\n if (!prompt) throw new Error(\"Type a message before sending.\");\n const session = index.session(sessionId);\n if (!session) throw new Error(\"This session is not in the list anymore.\");\n if (activeRunFor(session.id)) {\n const queued = saveSession({ ...session, queued: [...session.queued, prompt] });\n return { session: queued, run: null, queued: true };\n }\n if (!session.providerSessionId && session.lastRunId) {\n // The first run never reported a session id (it failed before the\n // provider started a chat), so there is nothing to continue.\n const run = await startRun(session, prompt);\n return { session: index.session(session.id) ?? session, run, queued: false };\n }\n const run = await startRun(session, prompt);\n return { session: index.session(session.id) ?? session, run, queued: false };\n },\n\n async stop(runId) {\n const liveRun = live.get(runId);\n if (!liveRun) return index.run(runId);\n liveRun.stopRequested = true;\n if (liveRun.pgid !== null) {\n killGroup(liveRun);\n } else {\n // Not spawned yet: the worker is still preparing. End it; the CLI\n // never started.\n liveRun.child.kill(\"SIGTERM\");\n }\n return liveRun.run;\n },\n\n async chatPreferences() {\n return preferences.all();\n },\n\n async setChatPreference(key, patch) {\n const all = preferences.set(key, patch ?? {});\n emit({ type: \"preferences\", preferences: all });\n return all;\n },\n\n async searchChats(query, opts) {\n return searchLocalChats(String(query ?? \"\"), { homes, cursor: opts?.cursor, limit: opts?.limit });\n },\n\n async openFolder(raw, target) {\n const folder = await assertFolder(String(raw ?? \"\"));\n await openFolderIn(folder, target);\n },\n\n async setSessionOptions(sessionId, opts) {\n const session = index.session(sessionId);\n if (!session) throw new Error(\"This session is not in the list anymore.\");\n const next = { ...session };\n if (opts && \"model\" in opts) next.model = typeof opts.model === \"string\" && opts.model.trim() ? opts.model.trim() : null;\n if (opts && \"effort\" in opts) next.effort = typeof opts.effort === \"string\" && opts.effort.trim() ? opts.effort.trim() : null;\n return saveSession(next);\n },\n\n async dispose() {\n for (const liveRun of live.values()) {\n liveRun.stopRequested = true;\n if (liveRun.pgid !== null) killGroup(liveRun);\n else liveRun.child.kill(\"SIGTERM\");\n }\n const deadline = Date.now() + 5000;\n while (live.size > 0 && Date.now() < deadline) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n await index.flush();\n await preferences.flush();\n },\n };\n\n return engine;\n}\n\nconst OPEN_APP: Record<Exclude<OpenTarget, \"finder\">, { app: string; label: string }> = {\n vscode: { app: \"Visual Studio Code\", label: \"VS Code\" },\n cursor: { app: \"Cursor\", label: \"Cursor\" },\n terminal: { app: \"Terminal\", label: \"Terminal\" },\n};\n\n/** Open a folder in Finder or an app (macOS `open`; Finder-only elsewhere). */\nfunction openFolderIn(folder: string, target: OpenTarget): Promise<void> {\n const mac = process.platform === \"darwin\";\n let command: string;\n let args: string[];\n if (target === \"finder\") {\n command = mac ? \"open\" : process.platform === \"win32\" ? \"explorer\" : \"xdg-open\";\n args = [folder];\n } else {\n const app = OPEN_APP[target];\n if (!app) return Promise.reject(new Error(\"That app can't open folders from here.\"));\n if (!mac) return Promise.reject(new Error(`Opening ${app.label} from here works on a Mac only.`));\n command = \"open\";\n args = [\"-a\", app.app, folder];\n }\n return new Promise((resolve, reject) => {\n execFile(command, args, { timeout: 10_000 }, (error) => {\n if (!error) return resolve();\n const label = target === \"finder\" ? \"the folder\" : (OPEN_APP[target]?.label ?? target);\n reject(\n new Error(\n target === \"finder\"\n ? `Couldn't open ${label}: ${error.message}`\n : `${label} isn't installed on this computer, or it couldn't open this folder.`,\n ),\n );\n });\n });\n}\n\nexport type { RunStatus };\n","/**\n * AUTOMATIC RAW BACKUP — the engine uploads a chat's full provider file after\n * its runs end, but ONLY when the owner opted in.\n *\n * The cloud keeps a coding chat's text and tool names; the full transcript is\n * the provider's own file on this computer. When the Feature Knob\n * `coding_session_bridge.raw_transcript_backup` resolves on for the owner, the\n * host's sink uploads that file through the server's one door.\n *\n * Guarantees (proven in `raw-backup.test.ts`):\n * - the sink's policy is asked FIRST; with `enabled: false` the file is not\n * even read for upload and nothing is sent;\n * - at most one upload per chat per `debounceSeconds`, plus one trailing upload\n * so the final state is always backed up;\n * - an unchanged file (by SHA-256, including the server's stored one) is never\n * sent twice.\n *\n * The engine holds no cloud credentials: a host that can reach AI Matrx passes\n * a sink (`createAiMatrxRawBackupSink`); without one nothing is ever uploaded.\n */\n\nimport { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\n\nimport type { CodingProvider } from \"../types\";\n\nexport interface RawBackupPolicy {\n enabled: boolean;\n debounceSeconds: number;\n backupSha256?: string | null;\n}\n\nexport interface RawBackupSink {\n policy(provider: CodingProvider, providerSessionId: string): Promise<RawBackupPolicy>;\n upload(provider: CodingProvider, providerSessionId: string, content: Buffer): Promise<void>;\n}\n\ninterface ChatState {\n lastUploadAt: number | null;\n lastSha: string | null;\n trailing: Promise<void> | null;\n}\n\nexport interface RawBackupScheduler {\n notify(provider: CodingProvider, providerSessionId: string): Promise<void>;\n idle(): Promise<void>;\n}\n\nexport function createRawBackupScheduler(options: {\n sink: RawBackupSink;\n findFile: (provider: CodingProvider, providerSessionId: string) => Promise<string | null>;\n now?: () => number;\n sleep?: (ms: number) => Promise<void>;\n onError?: (error: unknown) => void;\n}): RawBackupScheduler {\n const now = options.now ?? (() => Date.now());\n const sleep = options.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));\n const chats = new Map<string, ChatState>();\n\n async function uploadNow(state: ChatState, provider: CodingProvider, id: string, policy: RawBackupPolicy) {\n const file = await options.findFile(provider, id);\n if (!file) return;\n const content = await fs.readFile(file);\n const sha = createHash(\"sha256\").update(content).digest(\"hex\");\n if (sha === state.lastSha || sha === policy.backupSha256) {\n state.lastSha = sha;\n return;\n }\n await options.sink.upload(provider, id, content);\n state.lastUploadAt = now();\n state.lastSha = sha;\n }\n\n async function notify(provider: CodingProvider, providerSessionId: string): Promise<void> {\n const key = `${provider}:${providerSessionId}`;\n const state = chats.get(key) ?? { lastUploadAt: null, lastSha: null, trailing: null };\n chats.set(key, state);\n if (state.trailing) return; // the trailing upload carries this change\n try {\n const policy = await options.sink.policy(provider, providerSessionId);\n if (!policy.enabled) return;\n const windowMs = Math.max(1, policy.debounceSeconds) * 1000;\n const elapsed = state.lastUploadAt === null ? Infinity : now() - state.lastUploadAt;\n if (elapsed >= windowMs) {\n await uploadNow(state, provider, providerSessionId, policy);\n return;\n }\n state.trailing = (async () => {\n try {\n await sleep(windowMs - elapsed);\n const again = await options.sink.policy(provider, providerSessionId);\n if (again.enabled) await uploadNow(state, provider, providerSessionId, again);\n } catch (error) {\n options.onError?.(error);\n } finally {\n state.trailing = null;\n }\n })();\n } catch (error) {\n options.onError?.(error);\n }\n }\n\n return {\n notify,\n async idle() {\n await Promise.all([...chats.values()].map((s) => s.trailing).filter(Boolean));\n },\n };\n}\n\nconst SERVER_PROVIDER: Record<CodingProvider, string> = { claude: \"claude_code\", codex: \"codex\" };\n\n/**\n * The sink a host with an AI Matrx sign-in passes to the engine: the server's\n * backup-policy answer, then its one upload door.\n */\nexport function createAiMatrxRawBackupSink(options: {\n baseUrl: string;\n accessToken: () => Promise<string | null>;\n organizationId?: () => Promise<string | null>;\n fetch?: typeof fetch;\n}): RawBackupSink {\n const doFetch = options.fetch ?? fetch;\n async function headers(extra: Record<string, string> = {}): Promise<Record<string, string> | null> {\n const token = await options.accessToken();\n if (!token) return null;\n const org = options.organizationId ? await options.organizationId() : null;\n return { Authorization: `Bearer ${token}`, ...(org ? { \"X-Organization-Id\": org } : {}), ...extra };\n }\n const base = options.baseUrl.replace(/\\/$/, \"\");\n return {\n async policy(provider, providerSessionId) {\n const auth = await headers();\n if (!auth) return { enabled: false, debounceSeconds: 0 };\n const query = new URLSearchParams({ provider: SERVER_PROVIDER[provider], provider_session_id: providerSessionId });\n const response = await doFetch(`${base}/coding-sessions/raw-transcripts/backup-policy?${query}`, { headers: auth });\n if (!response.ok) throw new Error(`backup policy answered HTTP ${response.status}`);\n const body = (await response.json()) as { enabled?: boolean; debounce_seconds?: number; backup_sha256?: string | null };\n return {\n enabled: body.enabled === true,\n debounceSeconds: Number(body.debounce_seconds ?? 0),\n backupSha256: body.backup_sha256 ?? null,\n };\n },\n async upload(provider, providerSessionId, content) {\n const auth = await headers({ \"Content-Type\": \"application/x-ndjson\" });\n if (!auth) return;\n const query = new URLSearchParams({ provider: SERVER_PROVIDER[provider], provider_session_id: providerSessionId });\n const response = await doFetch(`${base}/coding-sessions/raw-transcripts/backup?${query}`, {\n method: \"POST\",\n headers: auth,\n body: new Uint8Array(content),\n });\n if (!response.ok) throw new Error(`backup upload answered HTTP ${response.status}`);\n },\n };\n}\n","/**\n * Claude Code → `TranscriptItem`.\n *\n * ONE normalizer reads both of Claude's shapes, because they are the same\n * shape: `claude --print --output-format stream-json` lines (live) and the\n * entries of the user's own session file `~/.claude/projects/<cwd>/<id>.jsonl`\n * (history) both carry `{ type: \"assistant\" | \"user\", message: { content } }`.\n * The live stream adds `system`/`stream_event`/`result`; the file adds its own\n * bookkeeping entries (titles, attachments, snapshots), which are skipped.\n *\n * Block identity: an assistant message arrives as several lines sharing one\n * `message.id`, one content block per line, in block order — the same order\n * the partial-message `content_block_start.index` counts. So a text block's id\n * is `<message id>:<index>` on both paths, and a streamed draft is replaced by\n * its final text rather than duplicated.\n */\n\nimport type { RunUsage, TranscriptItem } from \"../types\";\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\n/** User-role text Claude Code writes that the person never typed. */\nconst SYNTHETIC_USER_PREFIXES = [\n \"<command-name>\",\n \"<command-message>\",\n \"<command-args>\",\n \"<local-command-stdout>\",\n \"<local-command-stderr>\",\n \"<local-command-caveat>\",\n \"<system-reminder>\",\n \"<bash-input>\",\n \"<bash-stdout>\",\n \"<bash-stderr>\",\n \"<user-memory-input>\",\n \"<task-notification>\",\n \"Caveat: The messages below were generated by the user while running local commands\",\n \"[Request interrupted by user\",\n];\n\nexport function isSyntheticClaudeUserText(text: string): boolean {\n const trimmed = text.trimStart();\n return SYNTHETIC_USER_PREFIXES.some((prefix) => trimmed.startsWith(prefix));\n}\n\nfunction toolResultText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .map((block) => {\n if (!isObject(block)) return \"\";\n if (block.type === \"text\") return str(block.text) ?? \"\";\n if (block.type === \"image\") return \"[image]\";\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n return content === undefined || content === null ? \"\" : JSON.stringify(content);\n}\n\nexport interface ClaudeNormalizer {\n /** Feed one parsed JSON line; returns the items it produced (often none). */\n push(entry: unknown): TranscriptItem[];\n /** The Claude session id, once a line has carried it. */\n readonly sessionId: string | null;\n}\n\nexport function createClaudeNormalizer(): ClaudeNormalizer {\n let sessionId: string | null = null;\n let streamingMessageId: string | null = null;\n const blockCounters = new Map<string, number>();\n let userCounter = 0;\n let noticeCounter = 0;\n\n function nextBlockIndex(messageId: string): number {\n const index = blockCounters.get(messageId) ?? 0;\n blockCounters.set(messageId, index + 1);\n return index;\n }\n\n function pushAssistant(entry: Json): TranscriptItem[] {\n const message = isObject(entry.message) ? entry.message : null;\n if (!message) return [];\n const messageId = str(message.id) ?? str(entry.uuid) ?? `assistant-${blockCounters.size}`;\n const content = Array.isArray(message.content) ? message.content : [];\n const items: TranscriptItem[] = [];\n for (const block of content) {\n if (!isObject(block)) continue;\n const index = nextBlockIndex(messageId);\n const id = `${messageId}:${index}`;\n if (block.type === \"text\") {\n const text = str(block.text) ?? \"\";\n if (text.length > 0) items.push({ kind: \"text\", id, text });\n } else if (block.type === \"thinking\") {\n // Claude Code writes thinking blocks with an EMPTY text and only a\n // signature unless thinking display is on; an empty aside is noise.\n const text = str(block.thinking) ?? \"\";\n if (text.trim().length > 0) items.push({ kind: \"reasoning\", id, text });\n } else if (block.type === \"tool_use\" || block.type === \"server_tool_use\") {\n items.push({\n kind: \"tool-call\",\n id: str(block.id) ?? id,\n name: str(block.name) ?? \"tool\",\n input: block.input ?? null,\n });\n }\n }\n return items;\n }\n\n function pushUser(entry: Json): TranscriptItem[] {\n if (entry.isMeta === true || entry.isCompactSummary === true) return [];\n const message = isObject(entry.message) ? entry.message : null;\n if (!message) return [];\n const at = str(entry.timestamp);\n const content = message.content;\n if (typeof content === \"string\") {\n if (isSyntheticClaudeUserText(content) || content.trim().length === 0) return [];\n userCounter += 1;\n return [{ kind: \"user\", id: str(entry.uuid) ?? `user-${userCounter}`, text: content, at }];\n }\n if (!Array.isArray(content)) return [];\n const items: TranscriptItem[] = [];\n const typed: string[] = [];\n for (const block of content) {\n if (!isObject(block)) continue;\n if (block.type === \"tool_result\") {\n items.push({\n kind: \"tool-result\",\n id: str(block.tool_use_id) ?? \"unknown\",\n output: toolResultText(block.content),\n isError: block.is_error === true,\n });\n } else if (block.type === \"text\") {\n const text = str(block.text) ?? \"\";\n if (text.trim().length > 0 && !isSyntheticClaudeUserText(text)) typed.push(text);\n }\n }\n if (typed.length > 0) {\n userCounter += 1;\n items.unshift({\n kind: \"user\",\n id: str(entry.uuid) ?? `user-${userCounter}`,\n text: typed.join(\"\\n\\n\"),\n at,\n });\n }\n return items;\n }\n\n function pushStreamEvent(entry: Json): TranscriptItem[] {\n const event = isObject(entry.event) ? entry.event : null;\n if (!event) return [];\n if (event.type === \"message_start\" && isObject(event.message)) {\n streamingMessageId = str(event.message.id);\n return [];\n }\n if (event.type === \"content_block_delta\" && streamingMessageId !== null) {\n const delta = isObject(event.delta) ? event.delta : null;\n if (delta?.type === \"text_delta\") {\n const text = str(delta.text) ?? \"\";\n if (text.length === 0) return [];\n return [{ kind: \"text-delta\", id: `${streamingMessageId}:${num(event.index)}`, text }];\n }\n }\n return [];\n }\n\n function pushResult(entry: Json): TranscriptItem[] {\n const items: TranscriptItem[] = [];\n const usage = isObject(entry.usage) ? entry.usage : null;\n if (usage) {\n const runUsage: RunUsage = {\n inputTokens: num(usage.input_tokens) + num(usage.cache_creation_input_tokens),\n outputTokens: num(usage.output_tokens),\n cachedInputTokens: num(usage.cache_read_input_tokens),\n };\n const cost = typeof entry.total_cost_usd === \"number\" ? entry.total_cost_usd : null;\n items.push({ kind: \"usage\", usage: runUsage, costUsd: cost });\n }\n if (entry.is_error === true || (typeof entry.subtype === \"string\" && entry.subtype !== \"success\")) {\n const text =\n str(entry.result) ??\n (Array.isArray(entry.errors) ? entry.errors.map(String).join(\"\\n\") : null) ??\n `Claude Code stopped with \"${String(entry.subtype)}\".`;\n noticeCounter += 1;\n items.push({ kind: \"error\", id: `claude-result-${noticeCounter}`, text });\n }\n return items;\n }\n\n return {\n get sessionId() {\n return sessionId;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n const lineSession = str(raw.session_id) ?? str(raw.sessionId);\n if (lineSession && sessionId === null) sessionId = lineSession;\n if (raw.isSidechain === true) return [];\n switch (raw.type) {\n case \"assistant\":\n return pushAssistant(raw);\n case \"user\":\n return pushUser(raw);\n case \"stream_event\":\n return pushStreamEvent(raw);\n case \"result\":\n return pushResult(raw);\n case \"system\":\n if (raw.subtype === \"compact_boundary\") {\n noticeCounter += 1;\n return [\n {\n kind: \"notice\",\n id: `claude-compact-${noticeCounter}`,\n level: \"info\",\n text: \"Claude Code summarized the earlier part of this conversation to make room.\",\n },\n ];\n }\n return [];\n default:\n return [];\n }\n },\n };\n}\n","/**\n * Codex → `TranscriptItem`, from its two different shapes:\n *\n * - the LIVE stream (`codex exec --json`): `thread.started`, `item.started` /\n * `item.completed` for agent messages, commands, file changes, MCP calls,\n * web searches and plans, then `turn.completed` with usage;\n * - the user's own saved rollout file (`~/.codex/sessions/**\\/rollout-*.jsonl`):\n * `session_meta`, `event_msg` (the person's words, verbatim) and\n * `response_item` (assistant messages, tool calls and their outputs).\n *\n * Codex numbers stream items `item_0, item_1, …` again on every run, so live\n * ids carry a per-run prefix; rollout items carry globally unique call ids.\n */\n\nimport type { RunUsage, TranscriptItem } from \"../types\";\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\nfunction codexUsage(usage: Json): RunUsage {\n return {\n inputTokens: num(usage.input_tokens),\n outputTokens: num(usage.output_tokens),\n cachedInputTokens: num(usage.cached_input_tokens),\n };\n}\n\n/** Human names for Codex's item kinds, so a tool card reads like a sentence. */\nfunction toolCall(id: string, item: Json): TranscriptItem | null {\n switch (item.type) {\n case \"command_execution\":\n return { kind: \"tool-call\", id, name: \"Shell\", input: { command: str(item.command) ?? \"\" } };\n case \"file_change\":\n return { kind: \"tool-call\", id, name: \"Edit files\", input: { changes: item.changes ?? [] } };\n case \"mcp_tool_call\": {\n const server = str(item.server) ?? \"mcp\";\n const tool = str(item.tool) ?? \"tool\";\n return { kind: \"tool-call\", id, name: `${server}.${tool}`, input: item.arguments ?? null };\n }\n case \"web_search\":\n return { kind: \"tool-call\", id, name: \"Web search\", input: { query: str(item.query) ?? \"\" } };\n case \"todo_list\":\n return { kind: \"tool-call\", id, name: \"Plan\", input: { items: item.items ?? [] } };\n default:\n return null;\n }\n}\n\nfunction toolResult(id: string, item: Json): TranscriptItem | null {\n switch (item.type) {\n case \"command_execution\": {\n const exit = typeof item.exit_code === \"number\" ? item.exit_code : null;\n const output = str(item.aggregated_output) ?? \"\";\n return {\n kind: \"tool-result\",\n id,\n output: exit !== null && exit !== 0 ? `${output}\\n(exit code ${exit})`.trim() : output,\n isError: (exit !== null && exit !== 0) || item.status === \"failed\",\n };\n }\n case \"file_change\":\n return {\n kind: \"tool-result\",\n id,\n output: item.status === \"failed\" ? \"The file change failed.\" : \"Applied.\",\n isError: item.status === \"failed\",\n };\n case \"mcp_tool_call\": {\n const error = isObject(item.error) ? str(item.error.message) : str(item.error);\n return {\n kind: \"tool-result\",\n id,\n output: error ?? (item.result === undefined ? \"\" : JSON.stringify(item.result)),\n isError: error !== null || item.status === \"failed\",\n };\n }\n case \"web_search\":\n case \"todo_list\":\n return { kind: \"tool-result\", id, output: \"\", isError: false };\n default:\n return null;\n }\n}\n\nexport interface CodexStreamNormalizer {\n push(entry: unknown): TranscriptItem[];\n readonly sessionId: string | null;\n}\n\n/** The live `codex exec --json` stream. `runPrefix` keeps ids unique per run. */\nexport function createCodexStreamNormalizer(runPrefix: string): CodexStreamNormalizer {\n let sessionId: string | null = null;\n const started = new Set<string>();\n let counter = 0;\n\n return {\n get sessionId() {\n return sessionId;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n switch (raw.type) {\n case \"thread.started\":\n sessionId = str(raw.thread_id) ?? sessionId;\n return [];\n case \"item.started\":\n case \"item.updated\":\n case \"item.completed\": {\n const item = isObject(raw.item) ? raw.item : null;\n if (!item) return [];\n const id = `${runPrefix}:${str(item.id) ?? `item-${counter++}`}`;\n const completed = raw.type === \"item.completed\";\n if (item.type === \"agent_message\") {\n if (!completed) return [];\n const text = str(item.text) ?? \"\";\n return text ? [{ kind: \"text\", id, text }] : [];\n }\n if (item.type === \"reasoning\") {\n if (!completed) return [];\n const text = str(item.text) ?? \"\";\n return text.trim() ? [{ kind: \"reasoning\", id, text }] : [];\n }\n if (item.type === \"error\") {\n if (!completed) return [];\n // An `error` ITEM is a non-fatal warning (the run continues); a\n // fatal failure arrives as `turn.failed` or a top-level `error`.\n return [{ kind: \"notice\", id, level: \"warning\", text: str(item.message) ?? \"Codex warning.\" }];\n }\n const items: TranscriptItem[] = [];\n if (!started.has(id)) {\n const call = toolCall(id, item);\n if (call) {\n started.add(id);\n items.push(call);\n }\n }\n if (completed) {\n const result = toolResult(id, item);\n if (result) items.push(result);\n }\n return items;\n }\n case \"turn.completed\":\n return isObject(raw.usage)\n ? [{ kind: \"usage\", usage: codexUsage(raw.usage), costUsd: null }]\n : [];\n case \"turn.failed\": {\n const error = isObject(raw.error) ? str(raw.error.message) : null;\n counter += 1;\n return [{ kind: \"error\", id: `${runPrefix}:failed-${counter}`, text: error ?? \"Codex reported that the turn failed.\" }];\n }\n case \"error\":\n counter += 1;\n return [{ kind: \"error\", id: `${runPrefix}:error-${counter}`, text: str(raw.message) ?? \"Codex reported an error.\" }];\n default:\n return [];\n }\n },\n };\n}\n\nfunction contentText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .map((block) => (isObject(block) ? (str(block.text) ?? \"\") : \"\"))\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction parseArguments(raw: unknown): unknown {\n if (typeof raw !== \"string\") return raw ?? null;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n}\n\nfunction shellName(name: string): string {\n return name === \"shell\" || name === \"exec_command\" || name === \"local_shell\" ? \"Shell\" : name;\n}\n\n/**\n * The Codex app prepends ambient context to what the person typed\n * (`<in-app-browser-context …>…</in-app-browser-context>\\n## My request:\\n…`).\n * It is not their words; a title or a transcript bubble shows only theirs.\n */\nexport function stripCodexInjectedContext(text: string): string {\n let out = text;\n const leading = /^\\s*<([a-z][\\w-]*)(?:\\s[^>]*)?>[\\s\\S]*?<\\/\\1>/i;\n for (let i = 0; i < 8 && leading.test(out); i += 1) out = out.replace(leading, \"\");\n return out.replace(/^\\s*#{1,6}\\s*My request:\\s*/i, \"\").trim() || text.trim();\n}\n\n/** Text of a rollout `item_completed` item's `content` blocks. */\nfunction itemText(content: unknown): string {\n if (!Array.isArray(content)) return \"\";\n return content\n .map((block) => (isObject(block) ? (str(block.text) ?? \"\") : \"\"))\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction commandLine(command: unknown): string {\n if (Array.isArray(command)) {\n // [\"/bin/zsh\", \"-lc\", \"ls -la\"] → \"ls -la\": the shell wrapper is noise.\n const last = command[command.length - 1];\n if (command.length >= 3 && typeof last === \"string\") return last;\n return command.map(String).join(\" \");\n }\n return typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Current Codex (0.15x) records each turn TWICE in a rollout: the model-level\n * `response_item`s (where a shell command is a JavaScript `exec` snippet) and\n * the app-level `event_msg: item_completed` items the Codex app itself renders\n * (UserMessage, AgentMessage, CommandExecution, FileChange, …). The app-level\n * items read the way a person thinks about the work, so once a file shows it\n * has them, they are the transcript and the response_items are skipped.\n * Older rollouts have only response_items plus `event_msg: user_message`.\n */\nfunction rolloutItem(item: Json, fallbackId: string, at: string | null): TranscriptItem[] {\n const id = str(item.id) ?? fallbackId;\n switch (item.type) {\n case \"UserMessage\": {\n const text = stripCodexInjectedContext(itemText(item.content));\n return text.trim() ? [{ kind: \"user\", id, text, at }] : [];\n }\n case \"AgentMessage\": {\n const text = itemText(item.content);\n return text ? [{ kind: \"text\", id, text }] : [];\n }\n case \"Reasoning\": {\n const text = Array.isArray(item.summary_text) ? item.summary_text.map(String).join(\"\\n\") : \"\";\n return text.trim() ? [{ kind: \"reasoning\", id, text }] : [];\n }\n case \"CommandExecution\": {\n const exit = typeof item.exit_code === \"number\" ? item.exit_code : null;\n const output = str(item.aggregated_output) ?? str(item.formatted_output) ?? str(item.stdout) ?? \"\";\n const failed = (exit !== null && exit !== 0) || item.status === \"failed\";\n return [\n { kind: \"tool-call\", id, name: \"Shell\", input: { command: commandLine(item.command) } },\n {\n kind: \"tool-result\",\n id,\n output: failed && exit !== null ? `${output}\\n(exit code ${exit})`.trim() : output,\n isError: failed,\n },\n ];\n }\n case \"FileChange\":\n return [\n { kind: \"tool-call\", id, name: \"Edit files\", input: { changes: item.changes ?? null } },\n { kind: \"tool-result\", id, output: item.status === \"failed\" ? \"The file change failed.\" : \"Applied.\", isError: item.status === \"failed\" },\n ];\n case \"McpToolCall\": {\n const name = `${str(item.server) ?? \"mcp\"}.${str(item.tool) ?? \"tool\"}`;\n const error = isObject(item.error) ? str(item.error.message) : str(item.error);\n return [\n { kind: \"tool-call\", id, name, input: item.arguments ?? null },\n {\n kind: \"tool-result\",\n id,\n output: error ?? (item.result === undefined ? \"\" : JSON.stringify(item.result)),\n isError: error !== null || item.status === \"failed\",\n },\n ];\n }\n case \"WebSearch\":\n return [\n { kind: \"tool-call\", id, name: \"Web search\", input: { query: str(item.query) ?? \"\" } },\n { kind: \"tool-result\", id, output: \"\", isError: false },\n ];\n default:\n return [];\n }\n}\n\nexport interface CodexRolloutNormalizer {\n push(entry: unknown): TranscriptItem[];\n readonly sessionId: string | null;\n readonly cwd: string | null;\n}\n\n/** The user's saved rollout file. */\nexport function createCodexRolloutNormalizer(): CodexRolloutNormalizer {\n let sessionId: string | null = null;\n let cwd: string | null = null;\n let counter = 0;\n let appItems = false;\n\n return {\n get sessionId() {\n return sessionId;\n },\n get cwd() {\n return cwd;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n const payload = isObject(raw.payload) ? raw.payload : null;\n if (!payload) return [];\n const at = str(raw.timestamp);\n counter += 1;\n const fallbackId = `rollout-${typeof raw.ordinal === \"number\" ? raw.ordinal : counter}`;\n if (raw.type === \"session_meta\") {\n sessionId = str(payload.id) ?? sessionId;\n cwd = str(payload.cwd) ?? cwd;\n return [];\n }\n if (raw.type === \"event_msg\") {\n if (payload.type === \"item_completed\" && isObject(payload.item)) {\n appItems = true;\n return rolloutItem(payload.item, fallbackId, at);\n }\n if (payload.type === \"user_message\" && !appItems) {\n const text = stripCodexInjectedContext(str(payload.message) ?? \"\");\n return text.trim() ? [{ kind: \"user\", id: fallbackId, text, at }] : [];\n }\n return [];\n }\n if (raw.type === \"compacted\") {\n return [\n {\n kind: \"notice\",\n id: fallbackId,\n level: \"info\",\n text: \"Codex summarized the earlier part of this conversation to make room.\",\n },\n ];\n }\n if (raw.type !== \"response_item\" || appItems) return [];\n switch (payload.type) {\n case \"message\": {\n if (payload.role !== \"assistant\") return [];\n const text = contentText(payload.content);\n return text ? [{ kind: \"text\", id: str(payload.id) ?? fallbackId, text }] : [];\n }\n case \"reasoning\": {\n const summary = Array.isArray(payload.summary)\n ? payload.summary.map((part) => (isObject(part) ? (str(part.text) ?? \"\") : \"\")).join(\"\\n\")\n : \"\";\n return summary.trim()\n ? [{ kind: \"reasoning\", id: str(payload.id) ?? fallbackId, text: summary }]\n : [];\n }\n case \"function_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: shellName(str(payload.name) ?? \"tool\"),\n input: parseArguments(payload.arguments),\n },\n ];\n case \"custom_tool_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: shellName(str(payload.name) ?? \"tool\"),\n input: payload.input ?? null,\n },\n ];\n case \"local_shell_call\": {\n const action = isObject(payload.action) ? payload.action : {};\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: \"Shell\",\n input: { command: action.command ?? null },\n },\n ];\n }\n case \"web_search_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.id) ?? fallbackId,\n name: \"Web search\",\n input: payload.action ?? null,\n },\n { kind: \"tool-result\", id: str(payload.id) ?? fallbackId, output: \"\", isError: false },\n ];\n case \"function_call_output\":\n case \"custom_tool_call_output\":\n case \"local_shell_call_output\": {\n const output = payload.output;\n const text =\n typeof output === \"string\"\n ? output\n : isObject(output)\n ? (str(output.content) ?? JSON.stringify(output))\n : contentText(output);\n return [\n {\n kind: \"tool-result\",\n id: str(payload.call_id) ?? fallbackId,\n output: text,\n isError: isObject(output) && output.success === false,\n },\n ];\n }\n default:\n return [];\n }\n },\n };\n}\n","/**\n * Stdout arrives in arbitrary chunks; the providers write one JSON object per\n * line. This turns chunks into parsed lines, keeping a partial tail between\n * chunks, and reports (never throws on) a line that is not JSON — the CLIs do\n * print plain-text warnings on stdout now and then.\n */\n\nexport interface LineSplitter {\n push(chunk: string): { values: unknown[]; nonJson: string[] };\n /** Whatever is left when the stream ends. */\n flush(): { values: unknown[]; nonJson: string[] };\n}\n\nfunction parseLines(lines: string[]): { values: unknown[]; nonJson: string[] } {\n const values: unknown[] = [];\n const nonJson: string[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (!trimmed.startsWith(\"{\")) {\n nonJson.push(trimmed);\n continue;\n }\n try {\n values.push(JSON.parse(trimmed) as unknown);\n } catch {\n nonJson.push(trimmed);\n }\n }\n return { values, nonJson };\n}\n\nexport function createLineSplitter(): LineSplitter {\n let buffer = \"\";\n return {\n push(chunk) {\n buffer += chunk;\n const parts = buffer.split(\"\\n\");\n buffer = parts.pop() ?? \"\";\n return parseLines(parts);\n },\n flush() {\n const rest = buffer;\n buffer = \"\";\n return parseLines([rest]);\n },\n };\n}\n\n/** Parse a whole JSONL text (a fixture, or a provider file read in one go). */\nexport function parseJsonl(text: string): unknown[] {\n return parseLines(text.split(\"\\n\")).values;\n}\n","/**\n * The public contract of `@ai-matrx/coding-sessions`, shared by the engine\n * (Node), the local host (Node) and the UI (browser). Pure types — nothing here\n * touches Node or the DOM, and every value is JSON-serializable because it\n * crosses a transport (WebSocket today, desktop IPC later).\n */\n\n/** The coding agents this package drives. \"coding session\" is the canonical\n * platform term (chat.coding_session, the Coding Session Bridge). */\nexport type CodingProvider = \"claude\" | \"codex\";\n\nexport const CODING_PROVIDERS: readonly CodingProvider[] = [\"claude\", \"codex\"];\n\nexport const PROVIDER_LABEL: Record<CodingProvider, string> = {\n claude: \"Claude Code\",\n codex: \"Codex\",\n};\n\nexport type Billing = \"subscription\" | \"api\" | \"unknown\";\n\n/** What `providers()` answers for one provider, in plain terms. */\nexport interface ProviderStatus {\n provider: CodingProvider;\n label: string;\n installed: boolean;\n version: string | null;\n loggedIn: boolean;\n billing: Billing;\n /** \"Max\", \"Pro\", \"Plus\", … when the provider reports a plan. */\n plan: string | null;\n /** The signed-in account label, when the provider reports one. */\n account: string | null;\n /** A plain-English sentence for the screen when it is not ready. */\n problem: string | null;\n /** A plain-English fix for `problem`. */\n fix: string | null;\n /** Installed, signed in, and no known usage limit or expired sign-in. */\n ready: boolean;\n /** The last usage-limit or sign-in failure a run reported, until a run succeeds. */\n lastProblem: ProviderProblem | null;\n /** Usage windows, when the provider exposes them (Codex does; see FEATURE.md). */\n quota: QuotaWindow[];\n /** Models the driver knows for this provider (the person may type any other). */\n models?: ModelOption[] | undefined;\n /** Reasoning-effort levels this provider accepts, lowest first. */\n efforts?: string[] | undefined;\n /**\n * The model a run uses when none is picked, and where that comes from: the\n * person's own settings (`~/.claude/settings.json`, `~/.codex/config.toml`)\n * or the driver's built-in default.\n */\n defaultModel?: { id: string; source: \"settings\" | \"driver\" } | null | undefined;\n /** The effort a run uses when none is picked (the person's own settings). */\n defaultEffort?: string | null | undefined;\n}\n\nexport interface ModelOption {\n id: string;\n label: string;\n}\n\n/**\n * The person's own organisation of their chats — a rename, a pin, a hide. Kept\n * in this package's data dir, keyed by `chatKey()`; the providers' own files\n * are NEVER touched (a rename here does not rename the chat in Claude Code).\n */\nexport interface ChatPreference {\n /** Shown instead of the chat's own title. */\n title?: string | null | undefined;\n pinned?: boolean | undefined;\n /** Hidden from the lists (still found by search, restorable). */\n hidden?: boolean | undefined;\n updatedAt?: string | undefined;\n}\n\n/** The one key a chat's preference lives under, for ours and discovered alike. */\nexport function chatKey(provider: CodingProvider, providerSessionId: string | null, sessionId?: string | null): string {\n return providerSessionId ? `${provider}:${providerSessionId}` : `session:${sessionId ?? \"\"}`;\n}\n\n/** One chat that matched a search. */\nexport interface ChatSearchHit {\n provider: CodingProvider;\n providerSessionId: string;\n title: string;\n cwd: string | null;\n updatedAt: string;\n /** Where the words were found. */\n where: \"title\" | \"content\";\n /** A short excerpt around the first match in the conversation. */\n snippet: string | null;\n}\n\nexport interface ChatSearchResult {\n query: string;\n hits: ChatSearchHit[];\n /** How many chats were read, newest first, starting from the cursor. */\n scanned: number;\n /** How many chats exist on this computer. */\n total: number;\n /** Pass back to keep searching older chats; null when every chat was read. */\n nextCursor: number | null;\n}\n\n/** Where \"Open folder\" can open a session's folder. */\nexport type OpenTarget = \"finder\" | \"vscode\" | \"cursor\" | \"terminal\";\n\nexport interface ProviderProblem {\n kind: \"usage-limit\" | \"signed-out\";\n /** The provider's own words, verbatim. */\n message: string;\n /** When a usage limit lifts: ISO when parseable, else the provider's phrase. */\n until: string | null;\n at: string;\n}\n\nexport interface QuotaWindow {\n label: string;\n usedPercent: number | null;\n resetsAt: string | null;\n valueLabel: string | null;\n}\n\n/** An existing local Claude Code or Codex chat, found on disk (metadata only). */\nexport interface DiscoveredSession {\n provider: CodingProvider;\n providerSessionId: string;\n cwd: string | null;\n title: string;\n updatedAt: string;\n /** Where it was started, when the provider records it (\"cli\", \"vscode\", \"exec\", …). */\n source: string | null;\n /** Set when the chat looks live somewhere else right now (see `ActiveElsewhere`). */\n activeElsewhere: ActiveElsewhere | null;\n}\n\n/**\n * Evidence that a chat is being driven somewhere else RIGHT NOW. Taking it\n * over then puts two agents on one conversation, so the screen warns and asks —\n * it never blocks (validation offers, never blocks).\n */\nexport interface ActiveElsewhere {\n /** How we know, strongest first. */\n reason: \"process\" | \"recent-write\" | \"open-tool-call\";\n /** One plain sentence for the screen. */\n message: string;\n}\n\nexport type RunStatus = \"starting\" | \"running\" | \"completed\" | \"stopped\" | \"failed\";\n\nexport const TERMINAL_RUN_STATUSES: readonly RunStatus[] = [\"completed\", \"stopped\", \"failed\"];\n\nexport function isTerminalRunStatus(status: RunStatus): boolean {\n return TERMINAL_RUN_STATUSES.includes(status);\n}\n\nexport interface RunUsage {\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens: number;\n}\n\n/** One turn: one prompt sent to one provider process. */\nexport interface RunRecord {\n runId: string;\n /** Our session id (`CodingSession.id`). */\n sessionId: string;\n provider: CodingProvider;\n cwd: string;\n prompt: string;\n model: string | null;\n status: RunStatus;\n startedAt: string;\n endedAt: string | null;\n /** The real error, verbatim from the provider or the driver, when failed. */\n error: string | null;\n usage: RunUsage | null;\n costUsd: number | null;\n billing: Billing | null;\n}\n\n/** How a session came to be listed here. */\nexport type SessionOrigin = \"started\" | \"takeover\";\n\n/** A conversation driven from here. Its transcript lives in the provider's own\n * files; this is only the index row. */\nexport interface CodingSession {\n /** Our stable id. */\n id: string;\n provider: CodingProvider;\n /** The provider's own session/thread id — null until the first run reports it. */\n providerSessionId: string | null;\n cwd: string;\n title: string;\n model: string | null;\n /** Reasoning effort for the next run; null = the provider's own default. */\n effort?: string | null | undefined;\n origin: SessionOrigin;\n createdAt: string;\n updatedAt: string;\n /** The live or most recent run. */\n lastRunId: string | null;\n lastRunStatus: RunStatus | null;\n /** Prompts waiting for the active run to finish, oldest first. */\n queued: string[];\n}\n\n/**\n * One normalized transcript item — the same shape from Claude and Codex, from\n * a live stream and from a provider's saved session file.\n */\nexport type TranscriptItem =\n | { kind: \"user\"; id: string; text: string; at: string | null }\n | { kind: \"text\"; id: string; text: string }\n | { kind: \"text-delta\"; id: string; text: string }\n | { kind: \"reasoning\"; id: string; text: string }\n | { kind: \"tool-call\"; id: string; name: string; input: unknown }\n | { kind: \"tool-result\"; id: string; output: string; isError: boolean }\n | { kind: \"usage\"; usage: RunUsage; costUsd: number | null }\n | { kind: \"notice\"; id: string; level: \"info\" | \"warning\"; text: string }\n | { kind: \"error\"; id: string; text: string };\n\n/** Everything the engine pushes to a listener. */\nexport type CodingEvent =\n | { type: \"session\"; session: CodingSession }\n | { type: \"run\"; run: RunRecord }\n | { type: \"preferences\"; preferences: Record<string, ChatPreference> }\n | {\n type: \"item\";\n sessionId: string;\n runId: string;\n /** Monotonic per session; a history read reports the last `seq` it includes. */\n seq: number;\n item: TranscriptItem;\n };\n\n/** A transcript read back from the provider's own file. */\nexport interface SessionHistory {\n items: TranscriptItem[];\n /** True when the file was larger than the read budget and only its end was read. */\n truncated: boolean;\n /** Plain-English reason when history could not be read (never thrown at the UI). */\n unavailable: string | null;\n /** The last live item `seq` this read already contains; apply only newer ones. */\n seq: number;\n}\n\nexport interface StartInput {\n provider: CodingProvider;\n cwd: string;\n prompt: string;\n model?: string | null | undefined;\n effort?: string | null | undefined;\n}\n\nexport interface TakeoverInput {\n provider: CodingProvider;\n providerSessionId: string;\n cwd: string;\n title?: string | undefined;\n}\n\nexport interface SendResult {\n session: CodingSession;\n /** The run that started, or null when the prompt was queued behind a live run. */\n run: RunRecord | null;\n queued: boolean;\n}\n\nexport interface FolderCheck {\n /** The absolute path the check resolved. */\n path: string;\n exists: boolean;\n /** False when something that is NOT a folder sits at the path. */\n isDirectory: boolean;\n}\n\n/** A folder the New session flow offers (from discovered and driven sessions). */\nexport interface RecentFolder {\n path: string;\n lastUsedAt: string;\n exists: boolean;\n}\n\n/**\n * THE ENGINE CONTRACT — what the UI can ask for, independent of transport.\n * The WebSocket host implements it over the wire; a desktop app implements it\n * over IPC; the UI never knows which.\n */\nexport interface CodingSessionsApi {\n providers(): Promise<ProviderStatus[]>;\n discoverSessions(options?: { limit?: number }): Promise<DiscoveredSession[]>;\n recentFolders(): Promise<RecentFolder[]>;\n listSessions(): Promise<CodingSession[]>;\n listRuns(sessionId: string): Promise<RunRecord[]>;\n /** `maxBytes` reads more of a long chat's file (\"Show earlier\"). */\n history(sessionId: string, options?: HistoryOptions): Promise<SessionHistory>;\n /** Read-only transcript of a chat found on disk, before taking it over. */\n readTranscript(provider: CodingProvider, providerSessionId: string, options?: HistoryOptions): Promise<SessionHistory>;\n /**\n * FULL DOWNLOAD: the provider's own complete transcript file for this chat,\n * byte for byte (every tool input and output). AI Matrx's cloud keeps only\n * text and tool names, so this computer is the first place the full file\n * lives. `available: false` carries the sentence saying why.\n */\n readRawTranscript(provider: CodingProvider, providerSessionId: string): Promise<RawTranscript>;\n /** Does this folder exist here? `~` is the person's home. */\n checkFolder(path: string): Promise<FolderCheck>;\n /** Create a folder (and any missing parents), then report on it. */\n createFolder(path: string): Promise<FolderCheck>;\n /** Fresh check: is this chat live somewhere else right now? null when not. */\n sessionActivity(provider: CodingProvider, providerSessionId: string): Promise<ActiveElsewhere | null>;\n start(input: StartInput): Promise<SendResult>;\n takeover(input: TakeoverInput): Promise<CodingSession>;\n send(sessionId: string, prompt: string): Promise<SendResult>;\n stop(runId: string): Promise<RunRecord | null>;\n /** The person's renames, pins and hides, by `chatKey()`. */\n chatPreferences(): Promise<Record<string, ChatPreference>>;\n /** Merge a change into one chat's preference; `null` fields clear. Returns them all. */\n setChatPreference(key: string, patch: ChatPreference): Promise<Record<string, ChatPreference>>;\n /** Find chats by title and by what was said in them, newest first, within a time budget. */\n searchChats(query: string, options?: { cursor?: number; limit?: number }): Promise<ChatSearchResult>;\n /** Open a folder in Finder, VS Code, Cursor or Terminal. */\n openFolder(path: string, target: OpenTarget): Promise<void>;\n /** Change the model or effort the NEXT run of a session uses. */\n setSessionOptions(sessionId: string, options: { model?: string | null; effort?: string | null }): Promise<CodingSession>;\n}\n\nexport type RawTranscript =\n | { available: true; fileName: string; bytes: number; content: string }\n | { available: false; reason: string };\n\nexport interface HistoryOptions {\n /** Read up to this many bytes from the end of the file (default 24 MB). */\n maxBytes?: number | undefined;\n}\n\nexport type CodingSessionsMethod = keyof CodingSessionsApi;\n\n/** The transport the UI talks through (WebSocket, IPC, in-process). */\nexport interface CodingSessionsTransport {\n call<M extends CodingSessionsMethod>(\n method: M,\n ...args: Parameters<CodingSessionsApi[M]>\n ): ReturnType<CodingSessionsApi[M]>;\n subscribe(listener: (event: CodingEvent) => void): () => void;\n /** Connection state, for an honest banner. */\n status(): TransportStatus;\n onStatus(listener: (status: TransportStatus) => void): () => void;\n}\n\nexport type TransportStatus =\n | { state: \"connecting\" }\n | { state: \"open\" }\n | { state: \"closed\"; reason: string };\n","/**\n * USAGE LIMITS AND EXPIRED SIGN-INS, in plain English.\n *\n * A provider can be installed and signed in and still unable to run: the\n * ChatGPT or Claude plan hit its usage limit, or the saved login expired.\n * Runs report that in the provider's own words; this turns those words into\n * a remembered, honest status. Built from the real texts captured on\n * 2026-09-27 (Codex usage limit, Codex refresh failure).\n */\n\nimport { PROVIDER_LABEL, type CodingProvider, type ProviderProblem, type QuotaWindow } from \"./types\";\n\nconst USAGE_LIMIT = [\n /hit your usage limit/i,\n /usage limit (?:reached|exceeded)/i,\n /\\blimit reached\\b/i,\n /you'?ve hit your limit/i,\n /rate limit/i,\n /quota (?:exceeded|exhausted)/i,\n /purchase more credits/i,\n];\n\nconst SIGNED_OUT = [\n /access token could not be refreshed/i,\n /please sign in again/i,\n /(?:not|no longer) (?:logged|signed) in/i,\n /please run \\/login/i,\n /invalid api key/i,\n /oauth token (?:has )?expired/i,\n /authentication_error/i,\n /401 unauthorized/i,\n];\n\n/** \"Oct 4th, 2026 8:34 AM\" → ISO. null when the phrase is not a date. */\nexport function parseLimitDate(phrase: string): string | null {\n const cleaned = phrase.replace(/(\\d{1,2})(st|nd|rd|th)\\b/gi, \"$1\").replace(/[.,]\\s*$/, \"\").trim();\n const ms = Date.parse(cleaned);\n return Number.isNaN(ms) ? null : new Date(ms).toISOString();\n}\n\nfunction limitPhrase(text: string): string | null {\n const match =\n /try again (?:at|after|on) ([^\\n]+?)(?:\\.\\s|\\.$|$)/i.exec(text) ??\n /resets? (?:at |on )?([^\\n∙·|]+?)(?:\\.\\s|\\.$|$|\\s*[∙·|])/i.exec(text);\n return match?.[1]?.trim() ?? null;\n}\n\nexport function classifyProviderError(text: string, at = new Date().toISOString()): ProviderProblem | null {\n const trimmed = text.trim();\n if (!trimmed) return null;\n if (SIGNED_OUT.some((re) => re.test(trimmed))) {\n return { kind: \"signed-out\", message: trimmed, until: null, at };\n }\n if (USAGE_LIMIT.some((re) => re.test(trimmed))) {\n const phrase = limitPhrase(trimmed);\n return { kind: \"usage-limit\", message: trimmed, until: phrase ? (parseLimitDate(phrase) ?? phrase) : null, at };\n }\n return null;\n}\n\n/** A usage limit whose reset time has passed no longer applies. */\nexport function problemStillApplies(problem: ProviderProblem, now = Date.now()): boolean {\n if (problem.kind !== \"usage-limit\" || !problem.until) return true;\n const ms = Date.parse(problem.until);\n return Number.isNaN(ms) || ms > now;\n}\n\nexport function formatUntil(until: string | null): string | null {\n if (!until) return null;\n const ms = Date.parse(until);\n if (Number.isNaN(ms)) return until;\n return new Date(ms).toLocaleString(undefined, { month: \"short\", day: \"numeric\", hour: \"numeric\", minute: \"2-digit\" });\n}\n\n/** A full quota window (100% used) is a usage limit even before a run hits it. */\nexport function problemFromQuota(windows: readonly QuotaWindow[], at = new Date().toISOString()): ProviderProblem | null {\n const full = windows.find((w) => typeof w.usedPercent === \"number\" && w.usedPercent >= 100);\n if (!full) return null;\n return {\n kind: \"usage-limit\",\n message: `${full.label} is used up.`,\n until: full.resetsAt,\n at,\n };\n}\n\nexport function describeProblem(provider: CodingProvider, problem: ProviderProblem): { problem: string; fix: string } {\n const label = PROVIDER_LABEL[provider];\n if (problem.kind === \"signed-out\") {\n return {\n problem: `${label} — sign-in expired.`,\n fix: `Open ${label} and sign in again, then check again.`,\n };\n }\n const until = formatUntil(problem.until);\n return {\n problem: until ? `${label} — usage limit reached until ${until}.` : `${label} — usage limit reached.`,\n fix: until\n ? `It lifts on its own then, or add more usage in your ${provider === \"codex\" ? \"ChatGPT\" : \"Claude\"} account.`\n : `Wait for it to reset, or add more usage in your ${provider === \"codex\" ? \"ChatGPT\" : \"Claude\"} account.`,\n };\n}\n","/**\n * THE CLEAN ENVIRONMENT — built from an ALLOWLIST, never a denylist.\n *\n * The process that hosts this package is often itself running inside a Claude\n * Code or Codex session. Those sessions export variables (`CLAUDE_CODE_*`,\n * `CLAUDECODE`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_AUTH_TOKEN`, `CODEX_*`,\n * `OTEL_*`, `GIT_EDITOR`, …) that make a child CLI talk to the wrong endpoint,\n * bill the wrong account, or believe it is a sub-agent. A denylist is always one\n * variable behind the next CLI release; an allowlist cannot be. The spike ran\n * under `env -i` for this reason, and this is that guarantee in code.\n *\n * API keys are deliberately NOT allowed through: the whole point is the user's\n * own subscription login. A host that truly wants API billing passes a key in\n * `extra` on purpose, and `providers()` then reports \"API\" honestly.\n */\n\nimport os from \"node:os\";\nimport path from \"node:path\";\n\n/** Exact names that pass through. */\nconst ALLOWED_NAMES = new Set([\n \"HOME\",\n \"USER\",\n \"LOGNAME\",\n \"SHELL\",\n \"TMPDIR\",\n \"LANG\",\n \"TZ\",\n \"SSH_AUTH_SOCK\",\n \"HTTP_PROXY\",\n \"HTTPS_PROXY\",\n \"NO_PROXY\",\n \"http_proxy\",\n \"https_proxy\",\n \"no_proxy\",\n \"SSL_CERT_FILE\",\n \"NODE_EXTRA_CA_CERTS\",\n]);\n\n/** Prefixes that pass through (locale only). */\nconst ALLOWED_PREFIXES = [\"LC_\"];\n\n/**\n * Where the CLIs are commonly installed. A host launched from a GUI or a\n * launchd agent often has a bare PATH; without these the CLIs look\n * \"not installed\" when they are.\n */\nfunction wellKnownBinDirs(home: string): string[] {\n return [\n path.join(home, \".local\", \"bin\"),\n path.join(home, \".claude\", \"local\"),\n path.join(home, \".npm-global\", \"bin\"),\n path.join(home, \".bun\", \"bin\"),\n path.join(home, \".volta\", \"bin\"),\n \"/opt/homebrew/bin\",\n \"/usr/local/bin\",\n \"/usr/bin\",\n \"/bin\",\n \"/usr/sbin\",\n \"/sbin\",\n ];\n}\n\nexport function isAllowedEnvName(name: string): boolean {\n return ALLOWED_NAMES.has(name) || ALLOWED_PREFIXES.some((prefix) => name.startsWith(prefix));\n}\n\n/**\n * Build the environment for a driver worker (and therefore for the CLI it\n * launches) from the host's environment.\n */\nexport function buildCleanEnv(\n hostEnv: NodeJS.ProcessEnv,\n extra: Record<string, string> = {},\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [name, value] of Object.entries(hostEnv)) {\n if (typeof value !== \"string\") continue;\n if (isAllowedEnvName(name)) out[name] = value;\n }\n const home = out.HOME ?? os.homedir();\n out.HOME = home;\n const hostPath = (hostEnv.PATH ?? \"\").split(path.delimiter).filter(Boolean);\n const merged: string[] = [];\n for (const dir of [...hostPath, ...wellKnownBinDirs(home)]) {\n if (!merged.includes(dir)) merged.push(dir);\n }\n out.PATH = merged.join(path.delimiter);\n for (const [name, value] of Object.entries(extra)) out[name] = value;\n return out;\n}\n","/**\n * Reading the providers' OWN files — cheaply, and never copying them.\n *\n * A heavy user has tens of gigabytes here (this Mac: 38 GB of Codex rollouts\n * across ~6,800 files, 18 GB of Claude sessions across ~1,900). Discovery\n * therefore stats every file (cheap) but READS only the head and tail of the\n * few newest, and a transcript read is capped with the cap announced.\n */\n\nimport { createReadStream } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nimport { createClaudeNormalizer } from \"../normalize/claude\";\nimport { createCodexRolloutNormalizer } from \"../normalize/codex\";\nimport { parseJsonl } from \"../normalize/lines\";\nimport { describeActivity, listProcesses, type ProcessRow } from \"./activity\";\nimport type {\n ActiveElsewhere,\n CodingProvider,\n DiscoveredSession,\n SessionHistory,\n TranscriptItem,\n} from \"../types\";\n\nexport interface ProviderHomes {\n claudeProjects: string;\n codexSessions: string;\n codexIndex: string;\n}\n\nexport function defaultProviderHomes(home = os.homedir()): ProviderHomes {\n return {\n claudeProjects: path.join(home, \".claude\", \"projects\"),\n codexSessions: path.join(home, \".codex\", \"sessions\"),\n codexIndex: path.join(home, \".codex\", \"session_index.jsonl\"),\n };\n}\n\ninterface FileCandidate {\n provider: CodingProvider;\n file: string;\n id: string;\n mtimeMs: number;\n size: number;\n}\n\nconst UUIDISH = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\.jsonl$/i;\n\nasync function safeReaddir(dir: string): Promise<import(\"node:fs\").Dirent[]> {\n try {\n return await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return [];\n }\n}\n\nasync function statCandidate(\n provider: CodingProvider,\n file: string,\n): Promise<FileCandidate | null> {\n const match = UUIDISH.exec(file);\n if (!match?.[1]) return null;\n try {\n const stat = await fs.stat(file);\n return { provider, file, id: match[1], mtimeMs: stat.mtimeMs, size: stat.size };\n } catch {\n return null;\n }\n}\n\nasync function claudeCandidates(root: string): Promise<FileCandidate[]> {\n const out: FileCandidate[] = [];\n for (const project of await safeReaddir(root)) {\n if (!project.isDirectory()) continue;\n const dir = path.join(root, project.name);\n const entries = await safeReaddir(dir);\n const stats = await Promise.all(\n entries\n .filter((e) => e.isFile() && e.name.endsWith(\".jsonl\"))\n .map((e) => statCandidate(\"claude\", path.join(dir, e.name))),\n );\n for (const s of stats) if (s) out.push(s);\n }\n return out;\n}\n\nasync function codexCandidates(root: string): Promise<FileCandidate[]> {\n const out: FileCandidate[] = [];\n for (const year of await safeReaddir(root)) {\n if (!year.isDirectory()) continue;\n for (const month of await safeReaddir(path.join(root, year.name))) {\n if (!month.isDirectory()) continue;\n for (const day of await safeReaddir(path.join(root, year.name, month.name))) {\n if (!day.isDirectory()) continue;\n const dir = path.join(root, year.name, month.name, day.name);\n const entries = await safeReaddir(dir);\n const stats = await Promise.all(\n entries\n .filter((e) => e.isFile() && e.name.startsWith(\"rollout-\") && e.name.endsWith(\".jsonl\"))\n .map((e) => statCandidate(\"codex\", path.join(dir, e.name))),\n );\n for (const s of stats) if (s) out.push(s);\n }\n }\n }\n return out;\n}\n\n/** Read `length` bytes at `start` as UTF-8. */\nasync function readSlice(file: string, start: number, length: number): Promise<string> {\n const handle = await fs.open(file, \"r\");\n try {\n const buffer = Buffer.alloc(length);\n const { bytesRead } = await handle.read(buffer, 0, length, start);\n return buffer.subarray(0, bytesRead).toString(\"utf8\");\n } finally {\n await handle.close();\n }\n}\n\n/** Complete lines only: drop a partial first line (tail reads) and a partial last line. */\nfunction completeLines(text: string, droppedFirst: boolean): string {\n let body = text;\n if (droppedFirst) {\n const nl = body.indexOf(\"\\n\");\n body = nl >= 0 ? body.slice(nl + 1) : \"\";\n }\n const last = body.lastIndexOf(\"\\n\");\n return last >= 0 ? body.slice(0, last) : body;\n}\n\nconst HEAD_BYTES = 256 * 1024;\nconst TAIL_BYTES = 128 * 1024;\n\nfunction oneLine(text: string, max = 140): string {\n const flat = text.replace(/\\s+/g, \" \").trim();\n return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;\n}\n\nasync function describeClaude(candidate: FileCandidate): Promise<DiscoveredSession | null> {\n const head = parseJsonl(completeLines(await readSlice(candidate.file, 0, HEAD_BYTES), false));\n const tailStart = Math.max(0, candidate.size - TAIL_BYTES);\n const tail =\n tailStart > 0\n ? parseJsonl(completeLines(await readSlice(candidate.file, tailStart, TAIL_BYTES), true))\n : head;\n\n let cwd: string | null = null;\n let firstPrompt: string | null = null;\n let entrypoint: string | null = null;\n const normalizer = createClaudeNormalizer();\n for (const entry of head) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const e = entry as Record<string, unknown>;\n if (!cwd && typeof e.cwd === \"string\") cwd = e.cwd;\n if (!entrypoint && typeof e.entrypoint === \"string\") entrypoint = e.entrypoint;\n if (firstPrompt === null) {\n for (const item of normalizer.push(entry)) {\n if (item.kind === \"user\") {\n firstPrompt = item.text;\n break;\n }\n }\n }\n if (cwd && firstPrompt !== null) break;\n }\n\n const titles: Record<string, string | null> = { custom: null, ai: null, agent: null, summary: null, last: null };\n for (const entry of [...head, ...tail]) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const e = entry as Record<string, unknown>;\n if (e.type === \"custom-title\" && typeof e.customTitle === \"string\") titles.custom = e.customTitle;\n if (e.type === \"ai-title\" && typeof e.aiTitle === \"string\") titles.ai = e.aiTitle;\n if (e.type === \"agent-name\" && typeof e.agentName === \"string\") titles.agent = e.agentName;\n if (e.type === \"summary\" && typeof e.summary === \"string\") titles.summary = e.summary;\n if (e.type === \"last-prompt\" && typeof e.lastPrompt === \"string\") titles.last = e.lastPrompt;\n }\n const title = titles.custom ?? titles.ai ?? titles.agent ?? titles.summary ?? firstPrompt ?? titles.last;\n // A file with no conversation in it (a session that only ran start-up hooks)\n // is not a chat anyone can take over.\n if (!title) return null;\n return {\n provider: \"claude\",\n providerSessionId: candidate.id,\n cwd,\n title: oneLine(title),\n updatedAt: new Date(candidate.mtimeMs).toISOString(),\n source: entrypoint,\n activeElsewhere: null,\n };\n}\n\nasync function readCodexIndex(file: string): Promise<Map<string, string>> {\n const names = new Map<string, string>();\n let text: string;\n try {\n const stat = await fs.stat(file);\n const budget = 4 * 1024 * 1024;\n text =\n stat.size <= budget\n ? await fs.readFile(file, \"utf8\")\n : completeLines(await readSlice(file, stat.size - budget, budget), true);\n } catch {\n return names;\n }\n for (const entry of parseJsonl(text)) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const e = entry as Record<string, unknown>;\n if (typeof e.id === \"string\" && typeof e.thread_name === \"string\" && e.thread_name.trim()) {\n names.set(e.id, e.thread_name);\n }\n }\n return names;\n}\n\nasync function describeCodex(\n candidate: FileCandidate,\n names: Map<string, string>,\n): Promise<DiscoveredSession | null> {\n const head = parseJsonl(completeLines(await readSlice(candidate.file, 0, HEAD_BYTES), false));\n let cwd: string | null = null;\n let source: string | null = null;\n let isSubAgent = false;\n let firstPrompt: string | null = null;\n const normalizer = createCodexRolloutNormalizer();\n for (const entry of head) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const e = entry as Record<string, unknown>;\n if (e.type === \"session_meta\" && typeof e.payload === \"object\" && e.payload !== null) {\n const p = e.payload as Record<string, unknown>;\n cwd = typeof p.cwd === \"string\" ? p.cwd : cwd;\n source = typeof p.source === \"string\" ? p.source : typeof p.originator === \"string\" ? p.originator : null;\n if (typeof p.parent_thread_id === \"string\" && p.parent_thread_id) isSubAgent = true;\n if (p.thread_source === \"subagent\" || p.thread_source === \"sub_agent\") isSubAgent = true;\n }\n if (firstPrompt === null) {\n for (const item of normalizer.push(entry)) {\n if (item.kind === \"user\") {\n firstPrompt = item.text;\n break;\n }\n }\n }\n }\n // A sub-agent thread belongs to its parent conversation; taking it over on\n // its own would answer a question nobody in this chat asked.\n if (isSubAgent) return null;\n const title = names.get(candidate.id) ?? firstPrompt;\n if (!title) return null;\n return {\n provider: \"codex\",\n providerSessionId: candidate.id,\n cwd,\n title: oneLine(title),\n updatedAt: new Date(candidate.mtimeMs).toISOString(),\n source,\n activeElsewhere: null,\n };\n}\n\nexport interface DiscoverOptions {\n limit?: number | undefined;\n homes?: ProviderHomes | undefined;\n /** Processes that are OUR runs (never \"live elsewhere\"). */\n excludePids?: ReadonlySet<number> | undefined;\n}\n\nasync function readTail(file: string, size: number): Promise<unknown[]> {\n const start = Math.max(0, size - TAIL_BYTES);\n return parseJsonl(completeLines(await readSlice(file, start, Math.min(size, TAIL_BYTES)), start > 0));\n}\n\nasync function activityFor(\n candidate: FileCandidate,\n processes: readonly ProcessRow[],\n excludePids: ReadonlySet<number> | undefined,\n ownWritesUntilMs?: number | undefined,\n): Promise<ActiveElsewhere | null> {\n return describeActivity({\n ownWritesUntilMs,\n provider: candidate.provider,\n providerSessionId: candidate.id,\n mtimeMs: candidate.mtimeMs,\n now: Date.now(),\n processes,\n excludePids,\n tail: () => readTail(candidate.file, candidate.size).catch(() => []),\n });\n}\n\n/** Fresh \"is it live elsewhere?\" for one session (the preview and the takeover confirm). */\nexport async function sessionActivity(\n provider: CodingProvider,\n providerSessionId: string,\n options: {\n homes?: ProviderHomes | undefined;\n excludePids?: ReadonlySet<number> | undefined;\n ownWritesUntilMs?: number | undefined;\n } = {},\n): Promise<ActiveElsewhere | null> {\n const file = await findSessionFile(provider, providerSessionId, options.homes);\n const processes = await listProcesses();\n if (!file) {\n return describeActivity({\n provider,\n providerSessionId,\n mtimeMs: 0,\n now: Date.now(),\n processes,\n excludePids: options.excludePids,\n tail: async () => [],\n });\n }\n const candidate = await statCandidate(provider, file);\n if (!candidate) return null;\n return activityFor(candidate, processes, options.excludePids, options.ownWritesUntilMs);\n}\n\n/** Recent existing local Claude Code and Codex chats, newest first (metadata only). */\nexport async function discoverLocalSessions(options: DiscoverOptions = {}): Promise<DiscoveredSession[]> {\n const limit = options.limit ?? 60;\n const homes = options.homes ?? defaultProviderHomes();\n const [claude, codex, names] = await Promise.all([\n claudeCandidates(homes.claudeProjects),\n codexCandidates(homes.codexSessions),\n readCodexIndex(homes.codexIndex),\n ]);\n const candidates = [...claude, ...codex].sort((a, b) => b.mtimeMs - a.mtimeMs);\n const processes = await listProcesses();\n const out: DiscoveredSession[] = [];\n // Describe in small batches, newest first, until the page is full.\n for (let i = 0; i < candidates.length && out.length < limit; i += 12) {\n const batch = candidates.slice(i, i + 12);\n const described = await Promise.all(\n batch.map(async (c) => {\n const d = await (c.provider === \"claude\" ? describeClaude(c) : describeCodex(c, names)).catch(() => null);\n if (!d) return null;\n return { ...d, activeElsewhere: await activityFor(c, processes, options.excludePids).catch(() => null) };\n }),\n );\n for (const d of described) if (d && out.length < limit) out.push(d);\n }\n return out;\n}\n\n/** Where a provider keeps one session's transcript, or null when it has none on disk. */\nexport async function findSessionFile(\n provider: CodingProvider,\n providerSessionId: string,\n homes: ProviderHomes = defaultProviderHomes(),\n): Promise<string | null> {\n if (!/^[0-9a-f-]{36}$/i.test(providerSessionId)) return null;\n const candidates =\n provider === \"claude\"\n ? await claudeCandidates(homes.claudeProjects)\n : await codexCandidates(homes.codexSessions);\n const hits = candidates.filter((c) => c.id === providerSessionId).sort((a, b) => b.mtimeMs - a.mtimeMs);\n return hits[0]?.file ?? null;\n}\n\nexport const HISTORY_BUDGET = 24 * 1024 * 1024;\n/** \"Show earlier\" never reads more than this at once. */\nexport const MAX_HISTORY_BUDGET = 256 * 1024 * 1024;\n\n/**\n * Read a transcript from the provider's own file, up to `endOffset` bytes (the\n * file's size when a run started, so a live run's lines are not read twice).\n */\nexport async function readSessionFile(\n provider: CodingProvider,\n file: string,\n endOffset?: number | undefined,\n maxBytes: number = HISTORY_BUDGET,\n): Promise<SessionHistory> {\n let size: number;\n try {\n size = (await fs.stat(file)).size;\n } catch {\n return {\n items: [],\n truncated: false,\n unavailable: \"The saved transcript for this chat could not be found on this computer.\",\n seq: 0,\n };\n }\n const end = Math.min(size, endOffset ?? size);\n const start = Math.max(0, end - Math.max(1024 * 1024, Math.min(maxBytes, MAX_HISTORY_BUDGET)));\n const items: TranscriptItem[] = [];\n const normalizer = provider === \"claude\" ? createClaudeNormalizer() : createCodexRolloutNormalizer();\n let droppedFirst = start > 0;\n let carry = \"\";\n await new Promise<void>((resolve, reject) => {\n const stream = createReadStream(file, { start, end: Math.max(start, end - 1), encoding: \"utf8\" });\n stream.on(\"data\", (chunk) => {\n const text = carry + String(chunk);\n const lines = text.split(\"\\n\");\n carry = lines.pop() ?? \"\";\n if (droppedFirst) {\n lines.shift();\n droppedFirst = false;\n }\n for (const value of parseJsonl(lines.join(\"\\n\"))) items.push(...normalizer.push(value));\n });\n stream.on(\"end\", () => {\n for (const value of parseJsonl(carry)) items.push(...normalizer.push(value));\n resolve();\n });\n stream.on(\"error\", reject);\n });\n // Live-only kinds never come from a saved file; usage is per run, not history.\n return {\n items: items.filter((item) => item.kind !== \"usage\" && item.kind !== \"text-delta\"),\n truncated: start > 0,\n unavailable: null,\n seq: 0,\n };\n}\n\n/** Every session file on this computer, newest first (a stat each; nothing read). */\nexport async function listSessionFiles(homes: ProviderHomes = defaultProviderHomes()): Promise<FileCandidate[]> {\n const [claude, codex] = await Promise.all([\n claudeCandidates(homes.claudeProjects),\n codexCandidates(homes.codexSessions),\n ]);\n return [...claude, ...codex].sort((a, b) => b.mtimeMs - a.mtimeMs);\n}\n\n/** Title, folder and time for one file (null for sub-agent and hook-only files). */\nexport async function describeSessionFile(\n candidate: FileCandidate,\n codexNames: Map<string, string>,\n): Promise<DiscoveredSession | null> {\n return (candidate.provider === \"claude\" ? describeClaude(candidate) : describeCodex(candidate, codexNames)).catch(\n () => null,\n );\n}\n\nexport { readCodexIndex };\nexport type { FileCandidate };\n","/**\n * IS THIS CHAT LIVE SOMEWHERE ELSE RIGHT NOW?\n *\n * Taking over a chat that another Claude Code or Codex is still driving puts\n * two agents on one conversation. We cannot know for certain, so we look for\n * evidence, strongest first, and the screen WARNS and asks — it never blocks\n * (the platform law: validation offers, never blocks).\n *\n * 1. a process whose arguments carry the session id — `claude --resume <id>`,\n * `--resume=<id>`, `codex exec … resume <id>` (one `ps` per check);\n * 2. the session file was written in the last two minutes;\n * 3. the file's last step is a tool call that never got its result, and the\n * file changed in the last fifteen minutes (an abandoned crash from last\n * week is not \"running\").\n */\n\nimport { execFile } from \"node:child_process\";\n\nimport { createClaudeNormalizer } from \"../normalize/claude\";\nimport { createCodexRolloutNormalizer } from \"../normalize/codex\";\nimport { PROVIDER_LABEL, type ActiveElsewhere, type CodingProvider, type TranscriptItem } from \"../types\";\n\nexport const RECENT_WRITE_MS = 2 * 60 * 1000;\nexport const OPEN_TOOL_WINDOW_MS = 15 * 60 * 1000;\n\nexport interface ProcessRow {\n pid: number;\n args: string;\n}\n\n/** Every process's pid and full argument line. Empty (never throws) when `ps` is unavailable. */\nexport function listProcesses(): Promise<ProcessRow[]> {\n return new Promise((resolve) => {\n execFile(\"ps\", [\"-axww\", \"-o\", \"pid=,args=\"], { maxBuffer: 64 * 1024 * 1024, timeout: 5000 }, (error, stdout) => {\n if (error) {\n resolve([]);\n return;\n }\n const rows: ProcessRow[] = [];\n for (const line of String(stdout).split(\"\\n\")) {\n const match = /^\\s*(\\d+)\\s+(.*)$/.exec(line);\n if (match?.[1] && match[2]) rows.push({ pid: Number(match[1]), args: match[2] });\n }\n resolve(rows);\n });\n });\n}\n\n/** A process driving this session: its args name the id, and it is not one of ours. */\nexport function findDrivingProcess(\n processes: readonly ProcessRow[],\n providerSessionId: string,\n excludePids: ReadonlySet<number> = new Set(),\n): ProcessRow | null {\n for (const row of processes) {\n if (excludePids.has(row.pid) || row.pid === process.pid) continue;\n if (!row.args.includes(providerSessionId)) continue;\n // Our own `ps`/`pgrep` and editors viewing the file are not drivers.\n if (/(^|\\/)(ps|pgrep|grep|rg|tail|less|cat)\\b/.test(row.args.split(\" \")[0] ?? \"\")) continue;\n return row;\n }\n return null;\n}\n\n/** True when the last meaningful item is a tool call with no result yet. */\nexport function endsWithOpenToolCall(provider: CodingProvider, entries: readonly unknown[]): boolean {\n const normalizer = provider === \"claude\" ? createClaudeNormalizer() : createCodexRolloutNormalizer();\n const items: TranscriptItem[] = [];\n for (const entry of entries) items.push(...normalizer.push(entry));\n const meaningful = items.filter((i) => i.kind !== \"usage\" && i.kind !== \"notice\" && i.kind !== \"text-delta\");\n const last = meaningful[meaningful.length - 1];\n if (!last || last.kind !== \"tool-call\") return false;\n return !items.some((i) => i.kind === \"tool-result\" && i.id === last.id);\n}\n\nexport function describeActivity(input: {\n provider: CodingProvider;\n providerSessionId: string;\n mtimeMs: number;\n now: number;\n processes: readonly ProcessRow[];\n excludePids?: ReadonlySet<number> | undefined;\n /** Writes at or before this time were OURS (our own run just ended), so\n * they are not evidence of another driver. */\n ownWritesUntilMs?: number | undefined;\n /** Parsed tail of the session file; only consulted when recent enough. */\n tail: () => Promise<readonly unknown[]>;\n}): Promise<ActiveElsewhere | null> {\n const label = PROVIDER_LABEL[input.provider];\n const driver = findDrivingProcess(input.processes, input.providerSessionId, input.excludePids);\n if (driver) {\n return Promise.resolve({\n reason: \"process\",\n message: `This chat is running right now in ${label} — an open ${label} process is using it.`,\n });\n }\n if (input.ownWritesUntilMs !== undefined && input.mtimeMs <= input.ownWritesUntilMs) return Promise.resolve(null);\n const age = input.now - input.mtimeMs;\n if (age <= RECENT_WRITE_MS) {\n return Promise.resolve({\n reason: \"recent-write\",\n message: `This chat was active in ${label} less than two minutes ago and may still be running there.`,\n });\n }\n if (age > OPEN_TOOL_WINDOW_MS) return Promise.resolve(null);\n return input.tail().then((entries) =>\n endsWithOpenToolCall(input.provider, entries)\n ? {\n reason: \"open-tool-call\" as const,\n message: `This chat may still be running in ${label}: its last step started and has not finished.`,\n }\n : null,\n );\n}\n","/**\n * The person's renames, pins and hides — one small JSON file in this package's\n * data dir, keyed by `chatKey()`. The providers' own files are never touched.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { ChatPreference } from \"../types\";\n\nexport class PreferenceStore {\n private data: Record<string, ChatPreference> = {};\n private writing: Promise<void> = Promise.resolve();\n\n constructor(private readonly dir: string) {}\n\n get file(): string {\n return path.join(this.dir, \"preferences.json\");\n }\n\n async load(): Promise<void> {\n try {\n const parsed = JSON.parse(await fs.readFile(this.file, \"utf8\")) as unknown;\n this.data = typeof parsed === \"object\" && parsed !== null ? (parsed as Record<string, ChatPreference>) : {};\n } catch {\n this.data = {};\n }\n }\n\n all(): Record<string, ChatPreference> {\n return { ...this.data };\n }\n\n get(key: string): ChatPreference | null {\n return this.data[key] ?? null;\n }\n\n /** Merge `patch`; a null/false/empty field is removed, an empty preference deleted. */\n set(key: string, patch: ChatPreference): Record<string, ChatPreference> {\n if (!key || key.length > 200) throw new Error(\"That chat can't be found.\");\n const next: ChatPreference = { ...this.data[key] };\n if (\"title\" in patch) {\n const title = typeof patch.title === \"string\" ? patch.title.replace(/\\s+/g, \" \").trim().slice(0, 200) : \"\";\n if (title) next.title = title;\n else delete next.title;\n }\n if (\"pinned\" in patch) {\n if (patch.pinned === true) next.pinned = true;\n else delete next.pinned;\n }\n if (\"hidden\" in patch) {\n if (patch.hidden === true) next.hidden = true;\n else delete next.hidden;\n }\n delete next.updatedAt;\n if (Object.keys(next).length === 0) delete this.data[key];\n else this.data[key] = { ...next, updatedAt: new Date().toISOString() };\n this.persist();\n return this.all();\n }\n\n private persist(): void {\n const snapshot = JSON.stringify(this.data, null, 1);\n this.writing = this.writing\n .then(async () => {\n await fs.mkdir(this.dir, { recursive: true });\n const tmp = `${this.file}.${randomUUID()}.tmp`;\n await fs.writeFile(tmp, snapshot, { mode: 0o600 });\n await fs.rename(tmp, this.file);\n })\n .catch(() => {\n /* the next write retries with everything */\n });\n }\n\n async flush(): Promise<void> {\n await this.writing;\n }\n}\n","/**\n * SEARCH — by title and by what was said, across every Claude Code and Codex\n * chat on this computer, newest first.\n *\n * A heavy user has tens of gigabytes of session files, so a search is a\n * PAGE: it reads chats newest-first until it has `limit` hits or its time\n * budget is spent, and says exactly how far it got (`scanned` of `total`,\n * `nextCursor` to keep going). It never claims \"no results\" for chats it did\n * not read.\n *\n * A match must be in the conversation — a message, a tool call or its output,\n * exactly as the transcript shows it — not in bookkeeping (ids, tool\n * catalogues, hook output), so \"type\" does not match every line of every file.\n */\n\nimport { createReadStream } from \"node:fs\";\n\nimport { createClaudeNormalizer } from \"../normalize/claude\";\nimport { createCodexRolloutNormalizer } from \"../normalize/codex\";\nimport type { ChatSearchHit, ChatSearchResult, CodingProvider, TranscriptItem } from \"../types\";\nimport {\n defaultProviderHomes,\n describeSessionFile,\n listSessionFiles,\n readCodexIndex,\n type FileCandidate,\n type ProviderHomes,\n} from \"./files\";\n\nexport interface SearchOptions {\n homes?: ProviderHomes | undefined;\n cursor?: number | undefined;\n limit?: number | undefined;\n /** Stop reading after this long and hand back a cursor. Default 3.5 s. */\n budgetMs?: number | undefined;\n}\n\n/**\n * The first conversation text in one saved line that contains `needle`: the\n * line goes through the SAME normalizer the transcript uses, so only what the\n * screen would show can match — a message, a tool's input or output — never\n * tool catalogues, hook output or ids.\n */\nfunction findInLine(provider: CodingProvider, value: unknown, needle: string): string | null {\n const items: TranscriptItem[] =\n provider === \"claude\" ? createClaudeNormalizer().push(value) : createCodexRolloutNormalizer().push(value);\n for (const item of items) {\n let text: string | null = null;\n switch (item.kind) {\n case \"user\":\n case \"text\":\n case \"reasoning\":\n case \"notice\":\n case \"error\":\n text = item.text;\n break;\n case \"tool-call\":\n text = typeof item.input === \"string\" ? item.input : JSON.stringify(item.input ?? \"\");\n break;\n case \"tool-result\":\n text = item.output;\n break;\n default:\n text = null;\n }\n if (text && text.toLowerCase().includes(needle)) return text;\n }\n return null;\n}\n\n/** ~140 characters around the first match, on one line. */\nexport function snippetAround(text: string, needle: string, width = 140): string {\n const flat = text.replace(/\\s+/g, \" \").trim();\n const at = flat.toLowerCase().indexOf(needle);\n if (at < 0) return flat.slice(0, width);\n const before = Math.floor((width - needle.length) / 3);\n const start = Math.max(0, at - before);\n const end = Math.min(flat.length, start + width);\n return `${start > 0 ? \"…\" : \"\"}${flat.slice(start, end)}${end < flat.length ? \"…\" : \"\"}`;\n}\n\n/**\n * Read one file until the first line whose CONVERSATION contains the query.\n * Returns that excerpt, or null.\n *\n * The hot path never decodes UTF-8: each chunk is read as latin1 (one char\n * per byte, so offsets stay byte offsets), lower-cased natively, and searched\n * for the query as it appears inside a JSON string (`raw`: quotes and\n * backslashes escaped). An ASCII query only ever matches ASCII bytes, so the\n * latin1 reading cannot invent or hide a match. Only\n * a line that matches there is decoded, parsed, and checked for the query in\n * its conversation (not its bookkeeping). A query with non-ASCII letters\n * takes the decoded path, which is exact but slower.\n */\nconst TIMED_OUT = Symbol(\"timed-out\");\n\nasync function scanFile(\n provider: CodingProvider,\n file: string,\n needle: string,\n raw: string,\n deadline: number,\n): Promise<string | null | typeof TIMED_OUT> {\n const ascii = /^[\\x00-\\x7f]*$/.test(raw);\n return new Promise((resolve) => {\n let carry: Buffer = Buffer.alloc(0);\n let done = false;\n const stream = createReadStream(file, { highWaterMark: 4 * 1024 * 1024 });\n const finish = (value: string | null | typeof TIMED_OUT) => {\n if (done) return;\n done = true;\n stream.destroy();\n resolve(value);\n };\n const verify = (line: Buffer): string | null => {\n try {\n const hit = findInLine(provider, JSON.parse(line.toString(\"utf8\")), needle);\n return hit === null ? null : snippetAround(hit, needle);\n } catch {\n return null;\n }\n };\n /** Search `block` (complete lines only); the first verified hit, else null. */\n const searchBlock = (block: Buffer): string | null => {\n if (!ascii) {\n for (const line of block.toString(\"utf8\").split(\"\\n\")) {\n if (line.toLowerCase().includes(raw)) {\n const hit = verify(Buffer.from(line, \"utf8\"));\n if (hit !== null) return hit;\n }\n }\n return null;\n }\n const lower = block.toString(\"latin1\").toLowerCase();\n let from = 0;\n for (;;) {\n const at = lower.indexOf(raw, from);\n if (at < 0) return null;\n const start = block.lastIndexOf(10, at) + 1;\n let end = block.indexOf(10, at);\n if (end < 0) end = block.length;\n const hit = verify(block.subarray(start, end));\n if (hit !== null) return hit;\n from = end + 1;\n }\n };\n stream.on(\"data\", (chunk) => {\n const data = carry.length ? Buffer.concat([carry, chunk as Buffer]) : (chunk as Buffer);\n const lastNewline = data.lastIndexOf(10);\n if (lastNewline < 0) {\n carry = data;\n return;\n }\n carry = Buffer.from(data.subarray(lastNewline + 1));\n const hit = searchBlock(data.subarray(0, lastNewline));\n if (hit !== null) return finish(hit);\n // A single file never overruns the whole search's budget.\n if (Date.now() > deadline) finish(TIMED_OUT);\n });\n stream.on(\"end\", () => finish(carry.length ? searchBlock(carry) : null));\n stream.on(\"error\", () => finish(null));\n });\n}\n\n/** The file list, reused briefly: a search typed letter by letter should not stat 9,000 files each time. */\nlet listed: { at: number; homes: ProviderHomes; files: FileCandidate[] } | null = null;\nasync function sessionFiles(homes: ProviderHomes): Promise<FileCandidate[]> {\n if (listed && listed.homes === homes && Date.now() - listed.at < 20_000) return listed.files;\n const files = await listSessionFiles(homes);\n listed = { at: Date.now(), homes, files };\n return files;\n}\n\nexport async function searchLocalChats(query: string, options: SearchOptions = {}): Promise<ChatSearchResult> {\n const needle = query.replace(/\\s+/g, \" \").trim().toLowerCase();\n const homes = options.homes ?? defaultProviderHomes();\n const files: FileCandidate[] = await sessionFiles(homes);\n const cursor = Math.max(0, Math.min(options.cursor ?? 0, files.length));\n if (needle.length < 2) return { query, hits: [], scanned: 0, total: files.length, nextCursor: null };\n\n const raw = JSON.stringify(needle).slice(1, -1);\n const limit = Math.max(1, Math.min(options.limit ?? 30, 100));\n const deadline = Date.now() + (options.budgetMs ?? 3500);\n const names = await readCodexIndex(homes.codexIndex);\n const hits: ChatSearchHit[] = [];\n\n let i = cursor;\n for (; i < files.length && hits.length < limit && Date.now() < deadline; i += 1) {\n const candidate = files[i] as FileCandidate;\n const named = candidate.provider === \"codex\" ? names.get(candidate.id) : undefined;\n const nameHit = named !== undefined && named.toLowerCase().includes(needle);\n const scanned = nameHit ? null : await scanFile(candidate.provider, candidate.file, needle, raw, deadline);\n // A file cut off by the budget is NOT counted as read: the cursor resumes at it.\n // (Unless it is the page's first file — a file too big for one budget is\n // skipped rather than stalling every page on it.)\n if (scanned === TIMED_OUT) {\n if (i === cursor) i += 1;\n break;\n }\n const snippet = scanned;\n if (!nameHit && snippet === null) continue;\n const described = await describeSessionFile(candidate, names);\n if (!described) continue; // sub-agent and hook-only files are not chats\n hits.push({\n provider: described.provider,\n providerSessionId: described.providerSessionId,\n title: described.title,\n cwd: described.cwd,\n updatedAt: described.updatedAt,\n where: nameHit || described.title.toLowerCase().includes(needle) ? \"title\" : \"content\",\n snippet,\n });\n }\n return {\n query,\n hits,\n scanned: i - cursor,\n total: files.length,\n nextCursor: i < files.length ? i : null,\n };\n}\n","/**\n * The small local index: which sessions were driven from here and their runs,\n * so the list survives a restart. Transcripts are NEVER copied here — they stay\n * in the providers' own files. One JSON file, written atomically.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { CodingSession, RunRecord } from \"../types\";\n\ninterface IndexFile {\n version: 1;\n sessions: CodingSession[];\n runs: RunRecord[];\n}\n\nconst MAX_RUNS = 2000;\n\nexport interface Identity {\n companyId: string;\n agentId: string;\n}\n\nexport class RunIndex {\n private data: IndexFile = { version: 1, sessions: [], runs: [] };\n private writing: Promise<void> = Promise.resolve();\n\n constructor(private readonly dir: string) {}\n\n get file(): string {\n return path.join(this.dir, \"index.json\");\n }\n\n async load(): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true });\n try {\n const parsed = JSON.parse(await fs.readFile(this.file, \"utf8\")) as Partial<IndexFile>;\n this.data = {\n version: 1,\n sessions: Array.isArray(parsed.sessions) ? parsed.sessions : [],\n runs: Array.isArray(parsed.runs) ? parsed.runs : [],\n };\n } catch {\n this.data = { version: 1, sessions: [], runs: [] };\n }\n }\n\n sessions(): CodingSession[] {\n return [...this.data.sessions].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));\n }\n\n session(id: string): CodingSession | null {\n return (\n this.data.sessions.find((s) => s.id === id) ??\n this.data.sessions.find((s) => s.providerSessionId === id) ??\n null\n );\n }\n\n runs(sessionId: string): RunRecord[] {\n return this.data.runs.filter((r) => r.sessionId === sessionId);\n }\n\n run(runId: string): RunRecord | null {\n return this.data.runs.find((r) => r.runId === runId) ?? null;\n }\n\n allRuns(): RunRecord[] {\n return this.data.runs;\n }\n\n putSession(session: CodingSession): void {\n const at = this.data.sessions.findIndex((s) => s.id === session.id);\n if (at >= 0) this.data.sessions[at] = session;\n else this.data.sessions.push(session);\n this.persist();\n }\n\n putRun(run: RunRecord): void {\n const at = this.data.runs.findIndex((r) => r.runId === run.runId);\n if (at >= 0) this.data.runs[at] = run;\n else this.data.runs.push(run);\n if (this.data.runs.length > MAX_RUNS) this.data.runs.splice(0, this.data.runs.length - MAX_RUNS);\n this.persist();\n }\n\n /** Serialize writes; each writes the whole index to a temp file, then renames. */\n private persist(): void {\n const snapshot = JSON.stringify(this.data, null, 1);\n this.writing = this.writing.then(async () => {\n const tmp = `${this.file}.${randomUUID()}.tmp`;\n await fs.writeFile(tmp, snapshot, { mode: 0o600 });\n await fs.rename(tmp, this.file);\n }).catch(() => {\n /* the next write retries with the full index */\n });\n }\n\n async flush(): Promise<void> {\n await this.writing;\n }\n\n /** A stable Paperclip agent/company identity for this install, so the\n * driver's scratch state is reused rather than growing per run. */\n async identity(): Promise<Identity> {\n const file = path.join(this.dir, \"identity.json\");\n try {\n const parsed = JSON.parse(await fs.readFile(file, \"utf8\")) as Partial<Identity>;\n if (typeof parsed.companyId === \"string\" && typeof parsed.agentId === \"string\") {\n return { companyId: parsed.companyId, agentId: parsed.agentId };\n }\n } catch {\n /* first run */\n }\n const identity = { companyId: randomUUID(), agentId: randomUUID() };\n await fs.writeFile(file, JSON.stringify(identity), { mode: 0o600 });\n return identity;\n }\n}\n","/**\n * The person's OWN defaults — the model and effort their Claude Code and Codex\n * use when nothing is picked. The Claude driver otherwise forces its built-in\n * default (`claude-opus-5`) onto every run, silently overriding the model the\n * person chose in Claude Code itself; the engine passes theirs instead.\n * Read-only: these files are never written.\n */\n\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nimport type { CodingProvider } from \"../types\";\n\nexport interface UserDefaults {\n model: string | null;\n effort: string | null;\n}\n\nasync function readJson(file: string): Promise<Record<string, unknown> | null> {\n try {\n const parsed = JSON.parse(await fs.readFile(file, \"utf8\")) as unknown;\n return typeof parsed === \"object\" && parsed !== null ? (parsed as Record<string, unknown>) : null;\n } catch {\n return null;\n }\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value.trim() : null;\n}\n\n/** Claude Code's precedence: the folder's local settings, its shared settings, then the person's. */\nexport async function claudeDefaults(cwd: string | null, home = os.homedir()): Promise<UserDefaults> {\n const files = [\n ...(cwd ? [path.join(cwd, \".claude\", \"settings.local.json\"), path.join(cwd, \".claude\", \"settings.json\")] : []),\n path.join(home, \".claude\", \"settings.json\"),\n ];\n let model: string | null = null;\n let effort: string | null = null;\n for (const file of files) {\n const settings = await readJson(file);\n if (!settings) continue;\n model ??= str(settings.model);\n effort ??= str(settings.effortLevel);\n if (model && effort) break;\n }\n return { model, effort };\n}\n\n/** Codex's top-level `model` and `model_reasoning_effort` from `~/.codex/config.toml`. */\nexport async function codexDefaults(home = os.homedir()): Promise<UserDefaults> {\n let text: string;\n try {\n text = await fs.readFile(path.join(home, \".codex\", \"config.toml\"), \"utf8\");\n } catch {\n return { model: null, effort: null };\n }\n const values: Record<string, string> = {};\n for (const raw of text.split(\"\\n\")) {\n const line = raw.trim();\n if (line.startsWith(\"[\")) break; // top-level keys only\n const match = /^([A-Za-z0-9_]+)\\s*=\\s*\"([^\"]*)\"/.exec(line);\n if (match?.[1] && match[2] !== undefined) values[match[1]] = match[2];\n }\n return { model: str(values.model), effort: str(values.model_reasoning_effort) };\n}\n\nexport function userDefaults(provider: CodingProvider, cwd: string | null): Promise<UserDefaults> {\n return provider === \"claude\" ? claudeDefaults(cwd) : codexDefaults();\n}\n\n/** Effort levels each CLI accepts, lowest first (`claude --help`, the Codex driver's docs). */\nexport const EFFORT_LEVELS: Record<CodingProvider, string[]> = {\n claude: [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"],\n codex: [\"low\", \"medium\", \"high\", \"xhigh\"],\n};\n","/**\n * THE HOST BRIDGE — the one seam between the engine and any transport.\n *\n * The WebSocket host below is one adapter; a desktop app replaces it with IPC\n * by calling `handle()` and `subscribe()` from its own message channel. The UI\n * talks to a `CodingSessionsTransport` and never learns which one it got, and\n * the engine never learns there is a transport at all.\n */\n\nimport type { CodingEvent, CodingSessionsApi, CodingSessionsMethod } from \"../types\";\n\n/** Every method a client may call — an allowlist, so a crafted message cannot\n * reach `dispose` or anything else on the engine object. */\nexport const BRIDGE_METHODS: readonly CodingSessionsMethod[] = [\n \"providers\",\n \"discoverSessions\",\n \"recentFolders\",\n \"listSessions\",\n \"listRuns\",\n \"history\",\n \"readTranscript\",\n \"readRawTranscript\",\n \"sessionActivity\",\n \"checkFolder\",\n \"createFolder\",\n \"start\",\n \"takeover\",\n \"send\",\n \"stop\",\n \"chatPreferences\",\n \"setChatPreference\",\n \"searchChats\",\n \"openFolder\",\n \"setSessionOptions\",\n];\n\nexport interface HostBridge {\n handle(method: string, args: unknown[]): Promise<unknown>;\n subscribe(listener: (event: CodingEvent) => void): () => void;\n}\n\nexport interface BridgeableEngine extends CodingSessionsApi {\n subscribe(listener: (event: CodingEvent) => void): () => void;\n}\n\nexport class BridgeError extends Error {\n constructor(\n message: string,\n readonly code: \"unknown_method\" | \"bad_arguments\" | \"failed\",\n ) {\n super(message);\n this.name = \"BridgeError\";\n }\n}\n\nexport function createHostBridge(engine: BridgeableEngine): HostBridge {\n return {\n async handle(method, args) {\n if (!(BRIDGE_METHODS as readonly string[]).includes(method)) {\n throw new BridgeError(`Unknown method \"${method}\".`, \"unknown_method\");\n }\n if (!Array.isArray(args)) throw new BridgeError(\"Arguments must be a list.\", \"bad_arguments\");\n const fn = engine[method as CodingSessionsMethod] as (...a: unknown[]) => Promise<unknown>;\n try {\n return await fn.apply(engine, args);\n } catch (error) {\n throw new BridgeError(error instanceof Error ? error.message : String(error), \"failed\");\n }\n },\n subscribe(listener) {\n return engine.subscribe(listener);\n },\n };\n}\n"],"mappings":"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","names":["existsSync","fs","path","fileURLToPath","execFile","randomUUID","fs","os","path","isObject","str","num","fs","os","path","os","path","fs","fs","path","createReadStream","createReadStream","randomUUID","fs","path","fs","os","path","str","path","fs","os","randomUUID","options","run","execFile","moduleDir","path","fileURLToPath","existsSync","fs","url"]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/index.ts","../../src/engine/index.ts","../../src/engine/raw-backup.ts","../../src/normalize/claude.ts","../../src/normalize/codex.ts","../../src/normalize/lines.ts","../../src/types.ts","../../src/provider-health.ts","../../src/engine/binaries.ts","../../src/engine/clean-env.ts","../../src/engine/files.ts","../../src/engine/activity.ts","../../src/engine/preferences.ts","../../src/engine/search.ts","../../src/engine/store.ts","../../src/engine/user-defaults.ts","../../src/server/bridge.ts"],"sourcesContent":["/**\n * `@ai-matrx/coding-sessions/server` — the local host.\n *\n * HTTP + WebSocket on 127.0.0.1 ONLY, guarded by a per-launch random token:\n * serves the built UI and bridges it to the engine. Nothing listens on a\n * public interface; a page on another origin can neither call the API (token\n * and Origin both checked) nor read the token (it only ever appears in the URL\n * the host prints for the person who launched it).\n */\n\nimport { randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport http from \"node:http\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { WebSocketServer, type WebSocket } from \"ws\";\n\nimport {\n createCodingSessionsEngine,\n type CodingSessionsEngine,\n type CodingSessionsEngineOptions,\n} from \"../engine/index\";\nimport { createHostBridge, type HostBridge } from \"./bridge\";\n\nexport { createHostBridge, BRIDGE_METHODS, BridgeError } from \"./bridge\";\nexport type { HostBridge, BridgeableEngine } from \"./bridge\";\n\nexport interface CodingSessionsHostOptions extends CodingSessionsEngineOptions {\n /** Port on 127.0.0.1. `0` picks a free one. Default 4789. */\n port?: number | undefined;\n /** The access token; a fresh random one per launch when omitted. */\n token?: string | undefined;\n /** Directory of the built UI. Default: this package's `dist/ui`. */\n uiDir?: string | undefined;\n /** Use an engine you already built (tests, a desktop shell). */\n engine?: CodingSessionsEngine | undefined;\n}\n\nexport interface CodingSessionsHost {\n url: string;\n port: number;\n token: string;\n engine: CodingSessionsEngine;\n close(): Promise<void>;\n}\n\nconst HOST = \"127.0.0.1\";\n\nconst MIME: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".json\": \"application/json\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff2\": \"font/woff2\",\n \".map\": \"application/json\",\n};\n\nfunction moduleDir(): string {\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\nexport function defaultUiDir(): string | null {\n for (const candidate of [\n path.resolve(moduleDir(), \"..\", \"ui\"),\n path.resolve(moduleDir(), \"..\", \"..\", \"dist\", \"ui\"),\n ]) {\n if (existsSync(path.join(candidate, \"index.html\"))) return candidate;\n }\n return null;\n}\n\nfunction tokensMatch(expected: string, given: string | null): boolean {\n if (!given) return false;\n const a = Buffer.from(expected);\n const b = Buffer.from(given);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nconst NO_UI_PAGE = `<!doctype html><meta charset=\"utf-8\"><title>Coding sessions</title>\n<body style=\"font:15px system-ui;padding:48px;max-width:560px\">\n<h1 style=\"font-size:20px\">The coding sessions screen has not been built yet.</h1>\n<p>The local host is running, but its web page is missing from this install. Build the package\n(<code>pnpm --filter @ai-matrx/coding-sessions build</code>) and reload.</p></body>`;\n\nasync function serveStatic(\n uiDir: string | null,\n req: http.IncomingMessage,\n res: http.ServerResponse,\n): Promise<void> {\n const url = new URL(req.url ?? \"/\", `http://${HOST}`);\n if (!uiDir) {\n res.writeHead(503, { \"content-type\": \"text/html; charset=utf-8\" });\n res.end(NO_UI_PAGE);\n return;\n }\n const requested = decodeURIComponent(url.pathname);\n let file = path.resolve(uiDir, `.${requested}`);\n if (!file.startsWith(uiDir)) {\n res.writeHead(403).end();\n return;\n }\n const stat = await fs.stat(file).catch(() => null);\n if (!stat || stat.isDirectory()) file = path.join(uiDir, \"index.html\");\n const body = await fs.readFile(file).catch(() => null);\n if (!body) {\n res.writeHead(404).end();\n return;\n }\n const ext = path.extname(file);\n res.writeHead(200, {\n \"content-type\": MIME[ext] ?? \"application/octet-stream\",\n \"cache-control\": ext === \".html\" ? \"no-store\" : \"public, max-age=31536000, immutable\",\n \"x-content-type-options\": \"nosniff\",\n \"referrer-policy\": \"no-referrer\",\n });\n res.end(body);\n}\n\ninterface ClientMessage {\n id?: unknown;\n method?: unknown;\n args?: unknown;\n}\n\nfunction attachSocket(socket: WebSocket, bridge: HostBridge): void {\n const unsubscribe = bridge.subscribe((event) => {\n if (socket.readyState === socket.OPEN) socket.send(JSON.stringify({ event }));\n });\n socket.on(\"message\", (data) => {\n let message: ClientMessage;\n try {\n message = JSON.parse(String(data)) as ClientMessage;\n } catch {\n return;\n }\n const id = typeof message.id === \"number\" || typeof message.id === \"string\" ? message.id : null;\n if (id === null || typeof message.method !== \"string\") return;\n const args = Array.isArray(message.args) ? message.args : [];\n bridge.handle(message.method, args).then(\n (result) => {\n if (socket.readyState === socket.OPEN) socket.send(JSON.stringify({ id, ok: true, result: result ?? null }));\n },\n (error: unknown) => {\n if (socket.readyState === socket.OPEN) {\n socket.send(\n JSON.stringify({ id, ok: false, error: error instanceof Error ? error.message : String(error) }),\n );\n }\n },\n );\n });\n socket.on(\"close\", unsubscribe);\n}\n\nexport async function startCodingSessionsHost(\n options: CodingSessionsHostOptions = {},\n): Promise<CodingSessionsHost> {\n const token = options.token ?? randomBytes(24).toString(\"base64url\");\n const engine = options.engine ?? (await createCodingSessionsEngine(options));\n const bridge = createHostBridge(engine);\n const uiDir = options.uiDir ?? defaultUiDir();\n let port = options.port ?? 4789;\n\n const allowedOrigin = (origin: string | undefined): boolean => {\n if (!origin) return true; // non-browser clients (tests, a desktop shell)\n return origin === `http://${HOST}:${port}` || origin === `http://localhost:${port}`;\n };\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url ?? \"/\", `http://${HOST}`);\n if (url.pathname === \"/health\") {\n res.writeHead(200, { \"content-type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, service: \"@ai-matrx/coding-sessions\" }));\n return;\n }\n if (req.method !== \"GET\" && req.method !== \"HEAD\") {\n res.writeHead(405).end();\n return;\n }\n serveStatic(uiDir, req, res).catch(() => {\n if (!res.headersSent) res.writeHead(500);\n res.end();\n });\n });\n\n const wss = new WebSocketServer({ noServer: true, maxPayload: 4 * 1024 * 1024 });\n server.on(\"upgrade\", (req, socket, head) => {\n const url = new URL(req.url ?? \"/\", `http://${HOST}`);\n if (\n url.pathname !== \"/ws\" ||\n !tokensMatch(token, url.searchParams.get(\"token\")) ||\n !allowedOrigin(req.headers.origin)\n ) {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\nConnection: close\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n wss.handleUpgrade(req, socket, head, (ws) => attachSocket(ws, bridge));\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(port, HOST, () => {\n server.off(\"error\", reject);\n const address = server.address();\n if (address && typeof address === \"object\") port = address.port;\n resolve();\n });\n });\n\n const url = `http://${HOST}:${port}/?token=${encodeURIComponent(token)}`;\n return {\n url,\n port,\n token,\n engine,\n async close() {\n for (const client of wss.clients) client.terminate();\n await new Promise<void>((resolve) => wss.close(() => resolve()));\n await new Promise<void>((resolve) => server.close(() => resolve()));\n if (!options.engine) await engine.dispose();\n },\n };\n}\n","/**\n * `@ai-matrx/coding-sessions/engine` — drive the user's own Claude Code and\n * Codex on their own subscription logins, through Paperclip's MIT driver\n * packages, with every fix the 2026-09-27 spike found built in:\n *\n * - each run's driver lives in a forked worker with an ALLOWLISTED\n * environment (`clean-env.ts`), so a host running inside a Claude Code\n * session never leaks `CLAUDE_CODE_*` / `ANTHROPIC_BASE_URL` into the CLI;\n * - Claude runs on the CLI engine with the user's text as the whole prompt;\n * - no Paperclip skill is mounted and no skill-list prompt is appended\n * (`paperclipRuntimeSkills: []`), and a shim strips `PAPERCLIP_*` and\n * Paperclip's `--add-dir` before exec'ing the real CLI;\n * - Codex runs against the user's real `~/.codex`, so sessions appear in\n * their own history and no copy of their login is ever made;\n * - the driver's scratch state goes to this package's data dir, never\n * `~/.paperclip`, and its auth-cache vend is switched off;\n * - stop kills the CLI's process group (the driver ignores `signal`) and the\n * run is recorded as stopped even when Codex exits 0;\n * - a resume the driver would silently replace with a FRESH session is\n * refused and reported, and the driver may never delete the user's own\n * session files.\n */\n\nimport { execFile, fork, type ChildProcess } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { formatFileSize } from \"@ai-matrx/kit/format\";\nimport { createRawBackupScheduler, type RawBackupSink } from \"./raw-backup\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { createClaudeNormalizer } from \"../normalize/claude\";\nimport { createCodexStreamNormalizer } from \"../normalize/codex\";\nimport { createLineSplitter } from \"../normalize/lines\";\nimport {\n PROVIDER_LABEL,\n isTerminalRunStatus,\n type Billing,\n type CodingEvent,\n type CodingProvider,\n type CodingSession,\n type CodingSessionsApi,\n type DiscoveredSession,\n type ProviderStatus,\n type RecentFolder,\n type RunRecord,\n type RunStatus,\n type RunUsage,\n type SendResult,\n type SessionHistory,\n type StartInput,\n type TakeoverInput,\n type TranscriptItem,\n} from \"../types\";\nimport {\n classifyProviderError,\n describeProblem,\n problemFromQuota,\n problemStillApplies,\n} from \"../provider-health\";\nimport type { ModelOption, OpenTarget, ProviderBinary, ProviderProblem, QuotaWindow } from \"../types\";\nimport { resolveBinary } from \"./binaries\";\nimport { buildCleanEnv } from \"./clean-env\";\nimport {\n defaultProviderHomes,\n discoverLocalSessions,\n findSessionFile,\n readSessionFile,\n sessionActivity,\n type ProviderHomes,\n} from \"./files\";\nimport { PreferenceStore } from \"./preferences\";\nimport { searchLocalChats } from \"./search\";\nimport { RunIndex, type Identity } from \"./store\";\nimport { EFFORT_LEVELS, userDefaults } from \"./user-defaults\";\n\nexport { buildCleanEnv, isAllowedEnvName } from \"./clean-env\";\n/** Largest transcript Full Download hands to a page in one message (the file stays on disk). */\nexport const RAW_TRANSCRIPT_MAX_BYTES = 200 * 1_048_576;\n\nexport { createRawBackupScheduler, createAiMatrxRawBackupSink } from \"./raw-backup\";\nexport type { RawBackupPolicy, RawBackupSink } from \"./raw-backup\";\nexport { discoverLocalSessions, findSessionFile, readSessionFile, defaultProviderHomes, sessionActivity } from \"./files\";\nexport { describeActivity, findDrivingProcess, endsWithOpenToolCall, listProcesses } from \"./activity\";\nexport type { ProviderHomes } from \"./files\";\nexport { searchLocalChats, snippetAround } from \"./search\";\nexport { claudeDefaults, codexDefaults, EFFORT_LEVELS } from \"./user-defaults\";\nexport { PreferenceStore } from \"./preferences\";\n\nexport interface CodingSessionsEngineOptions {\n /** Where the run index and the driver's scratch state live. Default `~/.matrx/coding-sessions`. */\n dataDir?: string | undefined;\n /** The environment the clean one is built FROM. Default `process.env`. */\n hostEnv?: NodeJS.ProcessEnv | undefined;\n /** Explicit CLI paths; default: found on the clean PATH. */\n commands?: Partial<Record<CodingProvider, string>> | undefined;\n /** Where the providers keep their sessions. Default: the user's own homes. */\n homes?: ProviderHomes | undefined;\n /** Ask the drivers for usage windows during `providers()` (Codex). Default true. */\n quota?: boolean | undefined;\n /**\n * Where an opted-in owner's full transcripts are backed up (the host's AI\n * Matrx sign-in). Absent → nothing is ever uploaded. The sink's policy is\n * asked before every upload; with backup off not one byte leaves.\n */\n rawBackup?: RawBackupSink | undefined;\n /** Receives raw provider stdout per run — used to capture test fixtures. */\n onRawOutput?: ((runId: string, provider: CodingProvider, chunk: string) => void) | undefined;\n}\n\nexport interface CodingSessionsEngine extends CodingSessionsApi {\n subscribe(listener: (event: CodingEvent) => void): () => void;\n /** Stop every live run and wait for the index to be written. */\n dispose(): Promise<void>;\n readonly dataDir: string;\n}\n\ninterface WorkerMessage {\n kind: string;\n [key: string]: unknown;\n}\n\ninterface LiveRun {\n run: RunRecord;\n child: ChildProcess;\n pgid: number | null;\n stopRequested: boolean;\n killTimer: NodeJS.Timeout | null;\n stderrTail: string;\n refusals: string[];\n /** The provider file's size when this run began (history reads stop there). */\n fileOffset: number | null;\n /** Items this run produced, for a history read that lands mid-run. */\n items: { seq: number; item: TranscriptItem }[];\n}\n\nfunction moduleDir(): string {\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\nfunction resolveWorkerPath(): string {\n const dir = moduleDir();\n // This module is bundled into BOTH dist/engine and dist/server, so the\n // worker is either beside it or in the sibling engine directory.\n for (const candidate of [\n path.join(dir, \"worker.js\"),\n path.join(dir, \"worker.ts\"),\n path.join(dir, \"..\", \"engine\", \"worker.js\"),\n path.join(dir, \"..\", \"engine\", \"worker.ts\"),\n ]) {\n if (existsSync(candidate)) return candidate;\n }\n throw new Error(`[coding-sessions] The driver worker is missing next to ${dir}.`);\n}\n\n/**\n * The shim must be EXECUTABLE, and npm does not preserve the executable bit of\n * a non-`bin` file in a tarball (the packed-tarball canary caught exactly\n * that). So the engine installs its own copy into its data dir, mode 0755,\n * rewriting it only when the packaged source changed.\n */\nasync function installShim(dataDir: string): Promise<string> {\n const source = path.resolve(moduleDir(), \"..\", \"..\", \"bin\", \"cli-shim.sh\");\n if (!existsSync(source)) throw new Error(`[coding-sessions] The CLI shim is missing at ${source}.`);\n const body = await fs.readFile(source, \"utf8\");\n const target = path.join(dataDir, \"bin\", \"cli-shim.sh\");\n const current = await fs.readFile(target, \"utf8\").catch(() => null);\n if (current !== body) {\n await fs.mkdir(path.dirname(target), { recursive: true });\n await fs.writeFile(target, body, { mode: 0o755 });\n }\n await fs.chmod(target, 0o755);\n return target;\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nfunction titleFrom(prompt: string): string {\n const flat = prompt.replace(/\\s+/g, \" \").trim();\n return flat.length > 80 ? `${flat.slice(0, 79)}…` : flat || \"New session\";\n}\n\nfunction capitalize(value: string | null | undefined): string | null {\n if (!value) return null;\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction asUsage(value: unknown): RunUsage | null {\n if (typeof value !== \"object\" || value === null) return null;\n const v = value as Record<string, unknown>;\n const n = (x: unknown) => (typeof x === \"number\" && Number.isFinite(x) ? x : 0);\n return {\n inputTokens: n(v.inputTokens),\n outputTokens: n(v.outputTokens),\n cachedInputTokens: n(v.cachedInputTokens),\n };\n}\n\nfunction asBilling(value: unknown): Billing | null {\n if (value === \"subscription\" || value === \"api\") return value;\n if (typeof value === \"string\") return \"unknown\";\n return null;\n}\n\n/**\n * The status the screen shows: what the provider's own auth check says, then\n * — for a provider that looks ready — any usage limit or expired sign-in a run\n * reported (until a run succeeds) or a full quota window.\n */\nexport function describeProviderStatus(\n provider: CodingProvider,\n probe: Record<string, unknown> | undefined,\n lastProblem: ProviderProblem | null = null,\n quota: QuotaWindow[] = [],\n): ProviderStatus {\n const base = describeAuthStatus(provider, probe);\n const withQuota = { ...base, quota };\n if (!base.installed || !base.loggedIn) return { ...withQuota, ready: false, lastProblem };\n const current =\n (lastProblem && problemStillApplies(lastProblem) ? lastProblem : null) ?? problemFromQuota(quota);\n if (!current) return { ...withQuota, ready: true, lastProblem: null };\n const words = describeProblem(provider, current);\n return { ...withQuota, ready: false, lastProblem: current, problem: words.problem, fix: words.fix };\n}\n\nfunction describeAuthStatus(\n provider: CodingProvider,\n probe: Record<string, unknown> | undefined,\n): ProviderStatus {\n const label = PROVIDER_LABEL[provider];\n const installed = probe?.installed === true;\n const binary = (probe?.binary ?? null) as ProviderBinary | null;\n const version = binary?.version ?? (typeof probe?.version === \"string\" ? probe.version : null);\n const base: ProviderStatus = {\n provider,\n label,\n installed,\n version,\n binary,\n loggedIn: false,\n billing: \"unknown\",\n plan: null,\n account: null,\n problem: null,\n fix: null,\n ready: false,\n lastProblem: null,\n quota: [],\n };\n if (!installed) {\n return {\n ...base,\n problem: `${label} isn't installed on this computer.`,\n fix:\n provider === \"claude\"\n ? \"Install Claude Code from claude.com/code and sign in once, then check again.\"\n : \"Install Codex from openai.com/codex and sign in once, then check again.\",\n };\n }\n const auth = (probe?.auth ?? null) as Record<string, unknown> | null;\n if (provider === \"claude\") {\n if (!auth || auth.loggedIn !== true) {\n return {\n ...base,\n problem: \"Claude Code is installed but not signed in.\",\n fix: \"Open Claude Code once and sign in with your Claude account, then check again.\",\n };\n }\n const subscription = auth.authMethod === \"claude.ai\";\n return {\n ...base,\n loggedIn: true,\n billing: subscription ? \"subscription\" : \"api\",\n plan: subscription ? capitalize(typeof auth.subscriptionType === \"string\" ? auth.subscriptionType : null) : null,\n };\n }\n if (!auth || auth.loggedIn !== true) {\n return {\n ...base,\n problem: \"Codex is installed but not signed in.\",\n fix: \"Open Codex once and sign in with your ChatGPT account, then check again.\",\n };\n }\n const apiKey = auth.apiKey === true;\n return {\n ...base,\n loggedIn: true,\n billing: apiKey ? \"api\" : \"subscription\",\n plan: capitalize(typeof auth.planType === \"string\" ? auth.planType : null),\n account: typeof auth.email === \"string\" ? auth.email : null,\n };\n}\n\nexport async function createCodingSessionsEngine(\n options: CodingSessionsEngineOptions = {},\n): Promise<CodingSessionsEngine> {\n const dataDir = options.dataDir ?? path.join(os.homedir(), \".matrx\", \"coding-sessions\");\n const stateDir = path.join(dataDir, \"paperclip-state\");\n const homes = options.homes ?? defaultProviderHomes();\n const index = new RunIndex(dataDir);\n await index.load();\n const preferences = new PreferenceStore(dataDir);\n await preferences.load();\n await fs.mkdir(stateDir, { recursive: true });\n const identity: Identity = await index.identity();\n const backups = options.rawBackup\n ? createRawBackupScheduler({\n sink: options.rawBackup,\n findFile: (provider, providerSessionId) => findSessionFile(provider, providerSessionId, homes),\n onError: (error) => console.warn(\"[coding-sessions] raw transcript backup failed:\", error),\n })\n : null;\n /** Last `updatedAt` seen per discovered chat — a change is a turn that ended elsewhere. */\n const discoveredSeen = new Map<string, string>();\n\n // Last usage-limit / sign-in failure per provider, remembered across restarts.\n const healthFile = path.join(dataDir, \"provider-health.json\");\n let health: Partial<Record<CodingProvider, ProviderProblem>> = {};\n try {\n health = JSON.parse(await fs.readFile(healthFile, \"utf8\")) as typeof health;\n } catch {\n health = {};\n }\n const saveHealth = () =>\n fs.writeFile(healthFile, JSON.stringify(health), { mode: 0o600 }).catch(() => undefined);\n function noteRunOutcome(provider: CodingProvider, status: RunStatus, texts: string[]): void {\n if (status === \"completed\") {\n if (health[provider]) {\n delete health[provider];\n void saveHealth();\n }\n return;\n }\n if (status !== \"failed\") return;\n for (const text of texts) {\n const problem = classifyProviderError(text);\n if (problem) {\n health[provider] = problem;\n void saveHealth();\n return;\n }\n }\n }\n\n const workerEnv = buildCleanEnv(options.hostEnv ?? process.env, {\n // The driver's scratch state (prompt bundle, per-run MCP config) lives in\n // OUR data dir; nothing is ever written under ~/.paperclip.\n PAPERCLIP_HOME: stateDir,\n // The Codex driver otherwise \"vends\" cached copies of the user's login.\n PAPERCLIP_CODEX_AUTH_CACHE: \"0\",\n // Marks the forked process as a driver worker (see worker.ts).\n MATRX_CODING_SESSIONS_WORKER: \"1\",\n });\n // THE CLI EACH RUN USES: the newest copy on this computer (desktop app,\n // PATH, npm global), re-checked every few minutes so an app update is\n // picked up without a restart. A host-set command always wins.\n const binaryHome = options.hostEnv?.HOME ?? os.homedir();\n const binaryCache = new Map<CodingProvider, { at: number; value: Promise<ProviderBinary | null> }>();\n function binaryFor(provider: CodingProvider, fresh = false): Promise<ProviderBinary | null> {\n const cached = binaryCache.get(provider);\n if (cached && !fresh && Date.now() - cached.at < 5 * 60_000) return cached.value;\n const forced = options.commands?.[provider];\n const value = resolveBinary(provider, {\n env: workerEnv,\n home: binaryHome,\n forced,\n // A forced command needs no discovery to run; the status check still\n // looks, so it can say when a newer copy exists.\n discover: !forced || fresh,\n }).catch(() => (forced ? { path: forced, version: null, source: \"configured\" as const, sourceLabel: \"set by host\", newer: null } : null));\n if (!forced || !fresh) binaryCache.set(provider, { at: Date.now(), value });\n return value;\n }\n const commandFor = async (provider: CodingProvider): Promise<string | null> => (await binaryFor(provider))?.path ?? null;\n\n const workerPath = resolveWorkerPath();\n const shimPath = await installShim(dataDir);\n const listeners = new Set<(event: CodingEvent) => void>();\n const live = new Map<string, LiveRun>();\n const seqBySession = new Map<string, number>();\n\n function emit(event: CodingEvent): void {\n for (const listener of listeners) {\n try {\n listener(event);\n } catch {\n /* one bad listener never starves the rest */\n }\n }\n }\n\n function saveSession(session: CodingSession): CodingSession {\n index.putSession(session);\n emit({ type: \"session\", session });\n return session;\n }\n\n function saveRun(run: RunRecord): RunRecord {\n index.putRun(run);\n emit({ type: \"run\", run });\n if (backups && isTerminalRunStatus(run.status)) {\n const providerSessionId = index.session(run.sessionId)?.providerSessionId;\n if (providerSessionId) void backups.notify(run.provider, providerSessionId);\n }\n return run;\n }\n\n function emitItem(liveRun: LiveRun, item: TranscriptItem): void {\n const sessionId = liveRun.run.sessionId;\n const seq = (seqBySession.get(sessionId) ?? 0) + 1;\n seqBySession.set(sessionId, seq);\n liveRun.items.push({ seq, item });\n emit({ type: \"item\", sessionId, runId: liveRun.run.runId, seq, item });\n }\n\n // A run the index says is live, with no process behind it, died with the\n // previous host. Say so rather than showing it spinning forever.\n for (const run of index.allRuns()) {\n if (!isTerminalRunStatus(run.status)) {\n index.putRun({\n ...run,\n status: \"failed\",\n endedAt: run.endedAt ?? nowIso(),\n error: \"The app closed while this run was in progress, so it did not finish.\",\n });\n const session = index.session(run.sessionId);\n if (session && session.lastRunId === run.runId) {\n index.putSession({ ...session, lastRunStatus: \"failed\" });\n }\n }\n }\n\n function forkWorker(): ChildProcess {\n return fork(workerPath, [], {\n env: workerEnv,\n cwd: dataDir,\n stdio: [\"ignore\", \"pipe\", \"pipe\", \"ipc\"],\n serialization: \"json\",\n });\n }\n\n function ourPids(): Set<number> {\n const pids = new Set<number>();\n for (const liveRun of live.values()) {\n if (liveRun.pgid !== null) pids.add(liveRun.pgid);\n if (liveRun.child.pid !== undefined) pids.add(liveRun.child.pid);\n }\n return pids;\n }\n\n function activeRunFor(sessionId: string): LiveRun | null {\n for (const liveRun of live.values()) if (liveRun.run.sessionId === sessionId) return liveRun;\n return null;\n }\n\n async function startRun(session: CodingSession, prompt: string): Promise<RunRecord> {\n const provider = session.provider;\n const realCommand = await commandFor(provider);\n const runId = randomUUID();\n // No model picked: the person's OWN default. The Claude driver would\n // otherwise force its built-in model over the one they chose in Claude\n // Code; Codex already falls back to its own config when none is passed.\n const model =\n session.model ?? (provider === \"claude\" ? ((await userDefaults(provider, session.cwd)).model ?? null) : null);\n const run: RunRecord = {\n runId,\n sessionId: session.id,\n provider,\n cwd: session.cwd,\n prompt,\n model,\n status: \"starting\",\n startedAt: nowIso(),\n endedAt: null,\n error: null,\n usage: null,\n costUsd: null,\n billing: null,\n };\n saveRun(run);\n saveSession({\n ...session,\n lastRunId: runId,\n lastRunStatus: \"starting\",\n updatedAt: run.startedAt,\n });\n\n if (!realCommand) {\n const failed = saveRun({\n ...run,\n status: \"failed\",\n endedAt: nowIso(),\n error: `${PROVIDER_LABEL[provider]} isn't installed on this computer.`,\n });\n const current = index.session(session.id);\n if (current) saveSession({ ...current, lastRunStatus: \"failed\" });\n return failed;\n }\n\n let fileOffset: number | null = null;\n if (session.providerSessionId) {\n const file = await findSessionFile(provider, session.providerSessionId, homes);\n if (file) fileOffset = (await fs.stat(file).catch(() => null))?.size ?? null;\n }\n\n const child = forkWorker();\n const liveRun: LiveRun = {\n run,\n child,\n pgid: null,\n stopRequested: false,\n killTimer: null,\n stderrTail: \"\",\n refusals: [],\n fileOffset,\n items: [],\n };\n live.set(runId, liveRun);\n emitItem(liveRun, { kind: \"user\", id: `run-${runId}`, text: prompt, at: run.startedAt });\n\n const splitter = createLineSplitter();\n const claude = provider === \"claude\" ? createClaudeNormalizer() : null;\n const codex = provider === \"codex\" ? createCodexStreamNormalizer(runId.slice(0, 8)) : null;\n let knownProviderSession = session.providerSessionId;\n\n const consume = (values: unknown[]) => {\n for (const value of values) {\n const items = claude ? claude.push(value) : codex ? codex.push(value) : [];\n const sid = claude?.sessionId ?? codex?.sessionId ?? null;\n if (sid && sid !== knownProviderSession) {\n knownProviderSession = sid;\n const current = index.session(session.id);\n if (current) saveSession({ ...current, providerSessionId: sid });\n }\n for (const item of items) emitItem(liveRun, item);\n }\n };\n\n const settle = (patch: Partial<RunRecord>) => {\n if (liveRun.killTimer) clearTimeout(liveRun.killTimer);\n live.delete(runId);\n const final = saveRun({ ...liveRun.run, ...patch, endedAt: nowIso() });\n liveRun.run = final;\n noteRunOutcome(provider, final.status, [\n final.error ?? \"\",\n ...liveRun.items.flatMap((entry) => (entry.item.kind === \"error\" ? [entry.item.text] : [])),\n ]);\n const current = index.session(session.id);\n if (current) {\n const [next, ...rest] = current.queued;\n saveSession({ ...current, lastRunStatus: final.status, updatedAt: final.endedAt ?? nowIso() });\n if (next !== undefined) {\n const updated = index.session(session.id);\n if (updated) {\n const trimmed = saveSession({ ...updated, queued: rest });\n void startRun(trimmed, next);\n }\n }\n }\n void pruneDriverScratch();\n };\n\n let settled = false;\n child.on(\"message\", (raw) => {\n const message = raw as WorkerMessage;\n switch (message.kind) {\n case \"log\": {\n const chunk = String(message.chunk ?? \"\");\n if (message.stream === \"stdout\") {\n options.onRawOutput?.(runId, provider, chunk);\n const { values } = splitter.push(chunk);\n consume(values);\n } else {\n liveRun.stderrTail = (liveRun.stderrTail + chunk).slice(-4000);\n }\n return;\n }\n case \"spawn\": {\n const pgid =\n typeof message.processGroupId === \"number\"\n ? message.processGroupId\n : typeof message.pid === \"number\"\n ? message.pid\n : null;\n liveRun.pgid = pgid;\n if (liveRun.stopRequested) {\n killGroup(liveRun);\n return;\n }\n liveRun.run = saveRun({ ...liveRun.run, status: \"running\" });\n const current = index.session(session.id);\n if (current) saveSession({ ...current, lastRunStatus: \"running\" });\n return;\n }\n case \"refused\": {\n liveRun.refusals.push(`${String(message.op)}: ${String(message.target)}`);\n if (message.op === \"config-guard\") {\n emitItem(liveRun, {\n kind: \"notice\",\n id: \"config-guard\",\n level: \"warning\",\n text: \"The Codex driver has changed, so this run could not stop it from rewriting your ~/.codex/config.toml. Its contents are kept; update AI Matrx to restore the protection.\",\n });\n return;\n }\n if (message.op === \"delete\" || message.op === \"remove\") {\n emitItem(liveRun, {\n kind: \"notice\",\n id: `refused-${liveRun.refusals.length}`,\n level: \"warning\",\n text: \"The driver tried to delete part of your saved chat history. That was blocked; your history is untouched.\",\n });\n }\n return;\n }\n case \"result\": {\n consume(splitter.flush().values);\n settled = true;\n const result = (message.result ?? {}) as Record<string, unknown>;\n const usage = asUsage(result.usage);\n const billing = asBilling(result.billingType);\n const costUsd = typeof result.costUsd === \"number\" ? result.costUsd : null;\n if (liveRun.stopRequested) {\n // Codex exits 0 when its process group is killed; the host knows\n // better — the person pressed Stop.\n settle({ status: \"stopped\", usage, billing, costUsd, error: null });\n return;\n }\n if (message.refusedFreshSession === true) {\n settle({\n status: \"failed\",\n usage,\n billing,\n costUsd,\n error:\n `${PROVIDER_LABEL[provider]} could not reopen this chat, and would have started a new, empty one instead. ` +\n \"Nothing was sent. The chat may have been deleted or moved on this computer.\",\n });\n return;\n }\n const exitCode = typeof result.exitCode === \"number\" ? result.exitCode : null;\n const errorMessage = typeof result.errorMessage === \"string\" ? result.errorMessage : null;\n if (exitCode === 0 && !errorMessage && result.timedOut !== true) {\n settle({ status: \"completed\", usage, billing, costUsd, error: null });\n } else {\n const tail = liveRun.stderrTail.trim().split(\"\\n\").slice(-6).join(\"\\n\");\n settle({\n status: \"failed\",\n usage,\n billing,\n costUsd,\n error:\n errorMessage ??\n (tail || `${PROVIDER_LABEL[provider]} exited with code ${exitCode ?? \"unknown\"}.`),\n });\n }\n return;\n }\n case \"fatal\": {\n settled = true;\n settle({\n status: liveRun.stopRequested ? \"stopped\" : \"failed\",\n error: liveRun.stopRequested ? null : String(message.message ?? \"The driver failed.\"),\n });\n return;\n }\n default:\n return;\n }\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n liveRun.stderrTail = (liveRun.stderrTail + chunk.toString(\"utf8\")).slice(-4000);\n });\n child.on(\"exit\", (code, signal) => {\n if (settled) return;\n settled = true;\n settle({\n status: liveRun.stopRequested ? \"stopped\" : \"failed\",\n error: liveRun.stopRequested\n ? null\n : `The driver process ended unexpectedly (${signal ?? `code ${code ?? \"unknown\"}`}). ${liveRun.stderrTail.trim().split(\"\\n\").slice(-3).join(\" \")}`.trim(),\n });\n });\n\n child.send({\n kind: \"run\",\n provider,\n runId,\n cwd: session.cwd,\n prompt,\n model,\n effort: session.effort ?? null,\n resumeSessionId: session.providerSessionId,\n shimPath,\n realCommand,\n identity,\n });\n return run;\n }\n\n function killGroup(liveRun: LiveRun): void {\n const target = liveRun.pgid;\n if (target === null) return;\n try {\n process.kill(-target, \"SIGTERM\");\n } catch {\n /* already gone */\n }\n liveRun.killTimer = setTimeout(() => {\n try {\n process.kill(-target, \"SIGKILL\");\n } catch {\n /* already gone */\n }\n }, 3000);\n }\n\n async function pruneDriverScratch(): Promise<void> {\n // The Claude driver writes a per-run MCP config under its state dir; it is\n // empty (no Paperclip MCP servers) and never read again.\n const runsDir = path.join(\n stateDir,\n \"instances\",\n \"default\",\n \"companies\",\n identity.companyId,\n \"agents\",\n identity.agentId,\n \"claude-runtime\",\n \"runs\",\n );\n const entries = await fs.readdir(runsDir).catch(() => [] as string[]);\n await Promise.all(\n entries\n .filter((name) => !live.has(name))\n .map((name) => fs.rm(path.join(runsDir, name), { recursive: true, force: true }).catch(() => undefined)),\n );\n }\n\n async function probe(): Promise<Record<string, Record<string, unknown>>> {\n const [claudeBinary, codexBinary] = await Promise.all([binaryFor(\"claude\", true), binaryFor(\"codex\", true)]);\n return new Promise((resolve) => {\n const child = forkWorker();\n let answered = false;\n const timer = setTimeout(() => {\n if (answered) return;\n answered = true;\n child.kill(\"SIGKILL\");\n resolve({});\n }, 20000);\n child.on(\"message\", (raw) => {\n const message = raw as WorkerMessage;\n if (message.kind === \"probe-result\" && !answered) {\n answered = true;\n clearTimeout(timer);\n resolve({\n claude: { ...((message.claude ?? {}) as Record<string, unknown>), binary: claudeBinary },\n codex: { ...((message.codex ?? {}) as Record<string, unknown>), binary: codexBinary },\n });\n }\n });\n child.on(\"exit\", () => {\n if (answered) return;\n answered = true;\n clearTimeout(timer);\n resolve({});\n });\n child.send({\n kind: \"probe\",\n commands: { claude: claudeBinary?.path ?? null, codex: codexBinary?.path ?? null },\n quota: options.quota !== false,\n });\n });\n }\n\n function newSession(input: {\n provider: CodingProvider;\n cwd: string;\n title: string;\n model: string | null;\n effort?: string | null;\n origin: CodingSession[\"origin\"];\n providerSessionId: string | null;\n }): CodingSession {\n const at = nowIso();\n return {\n id: randomUUID(),\n provider: input.provider,\n providerSessionId: input.providerSessionId,\n cwd: input.cwd,\n title: input.title,\n model: input.model,\n effort: input.effort ?? null,\n origin: input.origin,\n createdAt: at,\n updatedAt: at,\n lastRunId: null,\n lastRunStatus: null,\n queued: [],\n };\n }\n\n function resolveFolder(raw: string): string | null {\n const trimmed = raw.trim();\n if (!trimmed) return null;\n return path.resolve(trimmed.replace(/^~(?=$|\\/)/, os.homedir()));\n }\n\n async function checkFolder(raw: string): Promise<import(\"../types\").FolderCheck> {\n const target = resolveFolder(raw);\n if (!target) return { path: \"\", exists: false, isDirectory: false };\n const stat = await fs.stat(target).catch(() => null);\n return { path: target, exists: stat !== null, isDirectory: stat?.isDirectory() === true };\n }\n\n async function assertFolder(cwd: string): Promise<string> {\n const resolved = path.resolve(cwd.replace(/^~(?=$|\\/)/, os.homedir()));\n const stat = await fs.stat(resolved).catch(() => null);\n if (!stat?.isDirectory()) {\n throw new Error(`The folder ${resolved} doesn't exist on this computer.`);\n }\n return resolved;\n }\n\n const engine: CodingSessionsEngine = {\n dataDir,\n\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n\n async providers() {\n const result = await probe();\n return Promise.all(\n ([\"claude\", \"codex\"] as const).map(async (provider) => {\n const probeResult = result[provider];\n const quota = Array.isArray(probeResult?.quota) ? (probeResult.quota as QuotaWindow[]) : [];\n const status = describeProviderStatus(provider, probeResult, health[provider] ?? null, quota);\n const models = Array.isArray(probeResult?.models) ? (probeResult.models as ModelOption[]) : [];\n const mine = await userDefaults(provider, null);\n // With no model of their own, Claude runs on the driver's built-in\n // default; Codex omits the flag and uses the CLI's own.\n const driverDefault =\n provider === \"claude\" && typeof probeResult?.driverDefaultModel === \"string\"\n ? probeResult.driverDefaultModel\n : null;\n return {\n ...status,\n models,\n efforts: EFFORT_LEVELS[provider],\n defaultModel: mine.model\n ? { id: mine.model, source: \"settings\" as const }\n : driverDefault\n ? { id: driverDefault, source: \"driver\" as const }\n : null,\n defaultEffort: mine.effort,\n };\n }),\n );\n },\n\n async discoverSessions(opts) {\n const found = await discoverLocalSessions({ limit: opts?.limit, homes, excludePids: ourPids() });\n if (backups) {\n for (const chat of found) {\n const key = `${chat.provider}:${chat.providerSessionId}`;\n const previous = discoveredSeen.get(key);\n discoveredSeen.set(key, chat.updatedAt);\n // Only a CHANGE since this engine last looked — never a first-sight\n // sweep of someone's whole history.\n if (previous !== undefined && previous !== chat.updatedAt) {\n void backups.notify(chat.provider, chat.providerSessionId);\n }\n }\n }\n return found;\n },\n\n async recentFolders(): Promise<RecentFolder[]> {\n const seen = new Map<string, string>();\n for (const session of index.sessions()) {\n if (!seen.has(session.cwd)) seen.set(session.cwd, session.updatedAt);\n }\n const discovered: DiscoveredSession[] = await discoverLocalSessions({ limit: 80, homes });\n for (const d of discovered) {\n if (d.cwd && !seen.has(d.cwd)) seen.set(d.cwd, d.updatedAt);\n }\n const folders = [...seen.entries()]\n .sort((a, b) => b[1].localeCompare(a[1]))\n .slice(0, 12);\n return Promise.all(\n folders.map(async ([folder, lastUsedAt]) => ({\n path: folder,\n lastUsedAt,\n exists: (await fs.stat(folder).catch(() => null))?.isDirectory() === true,\n })),\n );\n },\n\n async listSessions() {\n return index.sessions();\n },\n\n async listRuns(sessionId) {\n const session = index.session(sessionId);\n return session ? index.runs(session.id) : [];\n },\n\n async history(sessionId, options): Promise<SessionHistory> {\n const session = index.session(sessionId);\n if (!session) {\n return { items: [], truncated: false, unavailable: \"This session is not in the list anymore.\", seq: 0 };\n }\n const active = activeRunFor(session.id);\n let base: SessionHistory = { items: [], truncated: false, unavailable: null, seq: 0 };\n if (session.providerSessionId) {\n const file = await findSessionFile(session.provider, session.providerSessionId, homes);\n if (file) {\n const endOffset = active ? (active.fileOffset ?? 0) : undefined;\n base = await readSessionFile(session.provider, file, endOffset, options?.maxBytes);\n } else if (!active) {\n base = {\n items: [],\n truncated: false,\n unavailable: `${PROVIDER_LABEL[session.provider]} has no saved transcript for this chat on this computer.`,\n seq: 0,\n };\n }\n }\n // Taken synchronously right before answering, so a live item is either\n // in this answer (seq ≤ answer.seq) or arrives after it.\n const liveItems = active ? active.items : [];\n return {\n ...base,\n items: [...base.items, ...liveItems.map((entry) => entry.item)],\n seq: seqBySession.get(session.id) ?? 0,\n };\n },\n\n async checkFolder(raw) {\n return checkFolder(raw);\n },\n\n async createFolder(raw) {\n const target = resolveFolder(raw);\n if (!target) throw new Error(\"Type a folder path first.\");\n await fs.mkdir(target, { recursive: true });\n return checkFolder(target);\n },\n\n async sessionActivity(provider, providerSessionId) {\n // A session WE are driving is not \"live elsewhere\".\n for (const liveRun of live.values()) {\n const session = index.session(liveRun.run.sessionId);\n if (session?.providerSessionId === providerSessionId) return null;\n }\n // Our own finished runs wrote the file too; those writes are not evidence.\n let ownWritesUntilMs: number | undefined;\n const ours = index.session(providerSessionId);\n if (ours) {\n for (const run of index.runs(ours.id)) {\n const ended = run.endedAt ? Date.parse(run.endedAt) + 5000 : undefined;\n if (ended !== undefined && (ownWritesUntilMs === undefined || ended > ownWritesUntilMs)) ownWritesUntilMs = ended;\n }\n }\n return sessionActivity(provider, providerSessionId, { homes, excludePids: ourPids(), ownWritesUntilMs });\n },\n\n async readTranscript(provider, providerSessionId, options) {\n const file = await findSessionFile(provider, providerSessionId, homes);\n if (!file) {\n return {\n items: [],\n truncated: false,\n unavailable: `${PROVIDER_LABEL[provider]} has no saved transcript for this chat on this computer.`,\n seq: 0,\n };\n }\n return readSessionFile(provider, file, undefined, options?.maxBytes);\n },\n\n async readRawTranscript(provider, providerSessionId) {\n const file = await findSessionFile(provider, providerSessionId, homes);\n if (!file) {\n return {\n available: false,\n reason: `${PROVIDER_LABEL[provider]} has no saved transcript for this chat on this computer.`,\n };\n }\n const stat = await fs.stat(file);\n if (stat.size > RAW_TRANSCRIPT_MAX_BYTES) {\n return {\n available: false,\n reason: `This transcript is ${formatFileSize(stat.size)}, larger than the ${formatFileSize(RAW_TRANSCRIPT_MAX_BYTES)} this page can hand over. It is at ${file}.`,\n };\n }\n const content = await fs.readFile(file, \"utf8\");\n return { available: true, fileName: path.basename(file), bytes: stat.size, content };\n },\n\n async start(input: StartInput): Promise<SendResult> {\n const prompt = input.prompt.trim();\n if (!prompt) throw new Error(\"Type what you want done before starting.\");\n const cwd = await assertFolder(input.cwd);\n const session = saveSession(\n newSession({\n provider: input.provider,\n cwd,\n title: titleFrom(prompt),\n model: input.model?.trim() || null,\n effort: input.effort?.trim() || null,\n origin: \"started\",\n providerSessionId: null,\n }),\n );\n const run = await startRun(session, prompt);\n return { session: index.session(session.id) ?? session, run, queued: false };\n },\n\n async takeover(input: TakeoverInput) {\n const existing = index.session(input.providerSessionId);\n if (existing) return existing;\n const cwd = await assertFolder(input.cwd);\n return saveSession(\n newSession({\n provider: input.provider,\n cwd,\n title: input.title?.trim() || \"Taken-over chat\",\n model: null,\n origin: \"takeover\",\n providerSessionId: input.providerSessionId,\n }),\n );\n },\n\n async send(sessionId, rawPrompt): Promise<SendResult> {\n const prompt = rawPrompt.trim();\n if (!prompt) throw new Error(\"Type a message before sending.\");\n const session = index.session(sessionId);\n if (!session) throw new Error(\"This session is not in the list anymore.\");\n if (activeRunFor(session.id)) {\n const queued = saveSession({ ...session, queued: [...session.queued, prompt] });\n return { session: queued, run: null, queued: true };\n }\n if (!session.providerSessionId && session.lastRunId) {\n // The first run never reported a session id (it failed before the\n // provider started a chat), so there is nothing to continue.\n const run = await startRun(session, prompt);\n return { session: index.session(session.id) ?? session, run, queued: false };\n }\n const run = await startRun(session, prompt);\n return { session: index.session(session.id) ?? session, run, queued: false };\n },\n\n async stop(runId) {\n const liveRun = live.get(runId);\n if (!liveRun) return index.run(runId);\n liveRun.stopRequested = true;\n if (liveRun.pgid !== null) {\n killGroup(liveRun);\n } else {\n // Not spawned yet: the worker is still preparing. End it; the CLI\n // never started.\n liveRun.child.kill(\"SIGTERM\");\n }\n return liveRun.run;\n },\n\n async chatPreferences() {\n return preferences.all();\n },\n\n async setChatPreference(key, patch) {\n const all = preferences.set(key, patch ?? {});\n emit({ type: \"preferences\", preferences: all });\n return all;\n },\n\n async searchChats(query, opts) {\n return searchLocalChats(String(query ?? \"\"), { homes, cursor: opts?.cursor, limit: opts?.limit });\n },\n\n async openFolder(raw, target) {\n const folder = await assertFolder(String(raw ?? \"\"));\n await openFolderIn(folder, target);\n },\n\n async setSessionOptions(sessionId, opts) {\n const session = index.session(sessionId);\n if (!session) throw new Error(\"This session is not in the list anymore.\");\n const next = { ...session };\n if (opts && \"model\" in opts) next.model = typeof opts.model === \"string\" && opts.model.trim() ? opts.model.trim() : null;\n if (opts && \"effort\" in opts) next.effort = typeof opts.effort === \"string\" && opts.effort.trim() ? opts.effort.trim() : null;\n return saveSession(next);\n },\n\n async dispose() {\n for (const liveRun of live.values()) {\n liveRun.stopRequested = true;\n if (liveRun.pgid !== null) killGroup(liveRun);\n else liveRun.child.kill(\"SIGTERM\");\n }\n const deadline = Date.now() + 5000;\n while (live.size > 0 && Date.now() < deadline) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n await index.flush();\n await preferences.flush();\n },\n };\n\n return engine;\n}\n\nconst OPEN_APP: Record<Exclude<OpenTarget, \"finder\">, { app: string; label: string }> = {\n vscode: { app: \"Visual Studio Code\", label: \"VS Code\" },\n cursor: { app: \"Cursor\", label: \"Cursor\" },\n terminal: { app: \"Terminal\", label: \"Terminal\" },\n};\n\n/** Open a folder in Finder or an app (macOS `open`; Finder-only elsewhere). */\nfunction openFolderIn(folder: string, target: OpenTarget): Promise<void> {\n const mac = process.platform === \"darwin\";\n let command: string;\n let args: string[];\n if (target === \"finder\") {\n command = mac ? \"open\" : process.platform === \"win32\" ? \"explorer\" : \"xdg-open\";\n args = [folder];\n } else {\n const app = OPEN_APP[target];\n if (!app) return Promise.reject(new Error(\"That app can't open folders from here.\"));\n if (!mac) return Promise.reject(new Error(`Opening ${app.label} from here works on a Mac only.`));\n command = \"open\";\n args = [\"-a\", app.app, folder];\n }\n return new Promise((resolve, reject) => {\n execFile(command, args, { timeout: 10_000 }, (error) => {\n if (!error) return resolve();\n const label = target === \"finder\" ? \"the folder\" : (OPEN_APP[target]?.label ?? target);\n reject(\n new Error(\n target === \"finder\"\n ? `Couldn't open ${label}: ${error.message}`\n : `${label} isn't installed on this computer, or it couldn't open this folder.`,\n ),\n );\n });\n });\n}\n\nexport type { RunStatus };\n","/**\n * AUTOMATIC RAW BACKUP — the engine uploads a chat's full provider file after\n * its runs end, but ONLY when the owner opted in.\n *\n * The cloud keeps a coding chat's text and tool names; the full transcript is\n * the provider's own file on this computer. When the Feature Knob\n * `coding_session_bridge.raw_transcript_backup` resolves on for the owner, the\n * host's sink uploads that file through the server's one door.\n *\n * Guarantees (proven in `raw-backup.test.ts`):\n * - the sink's policy is asked FIRST; with `enabled: false` the file is not\n * even read for upload and nothing is sent;\n * - at most one upload per chat per `debounceSeconds`, plus one trailing upload\n * so the final state is always backed up;\n * - an unchanged file (by SHA-256, including the server's stored one) is never\n * sent twice.\n *\n * The engine holds no cloud credentials: a host that can reach AI Matrx passes\n * a sink (`createAiMatrxRawBackupSink`); without one nothing is ever uploaded.\n */\n\nimport { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\n\nimport type { CodingProvider } from \"../types\";\n\nexport interface RawBackupPolicy {\n enabled: boolean;\n debounceSeconds: number;\n backupSha256?: string | null;\n}\n\nexport interface RawBackupSink {\n policy(provider: CodingProvider, providerSessionId: string): Promise<RawBackupPolicy>;\n upload(provider: CodingProvider, providerSessionId: string, content: Buffer): Promise<void>;\n}\n\ninterface ChatState {\n lastUploadAt: number | null;\n lastSha: string | null;\n trailing: Promise<void> | null;\n}\n\nexport interface RawBackupScheduler {\n notify(provider: CodingProvider, providerSessionId: string): Promise<void>;\n idle(): Promise<void>;\n}\n\nexport function createRawBackupScheduler(options: {\n sink: RawBackupSink;\n findFile: (provider: CodingProvider, providerSessionId: string) => Promise<string | null>;\n now?: () => number;\n sleep?: (ms: number) => Promise<void>;\n onError?: (error: unknown) => void;\n}): RawBackupScheduler {\n const now = options.now ?? (() => Date.now());\n const sleep = options.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));\n const chats = new Map<string, ChatState>();\n\n async function uploadNow(state: ChatState, provider: CodingProvider, id: string, policy: RawBackupPolicy) {\n const file = await options.findFile(provider, id);\n if (!file) return;\n const content = await fs.readFile(file);\n const sha = createHash(\"sha256\").update(content).digest(\"hex\");\n if (sha === state.lastSha || sha === policy.backupSha256) {\n state.lastSha = sha;\n return;\n }\n await options.sink.upload(provider, id, content);\n state.lastUploadAt = now();\n state.lastSha = sha;\n }\n\n async function notify(provider: CodingProvider, providerSessionId: string): Promise<void> {\n const key = `${provider}:${providerSessionId}`;\n const state = chats.get(key) ?? { lastUploadAt: null, lastSha: null, trailing: null };\n chats.set(key, state);\n if (state.trailing) return; // the trailing upload carries this change\n try {\n const policy = await options.sink.policy(provider, providerSessionId);\n if (!policy.enabled) return;\n const windowMs = Math.max(1, policy.debounceSeconds) * 1000;\n const elapsed = state.lastUploadAt === null ? Infinity : now() - state.lastUploadAt;\n if (elapsed >= windowMs) {\n await uploadNow(state, provider, providerSessionId, policy);\n return;\n }\n state.trailing = (async () => {\n try {\n await sleep(windowMs - elapsed);\n const again = await options.sink.policy(provider, providerSessionId);\n if (again.enabled) await uploadNow(state, provider, providerSessionId, again);\n } catch (error) {\n options.onError?.(error);\n } finally {\n state.trailing = null;\n }\n })();\n } catch (error) {\n options.onError?.(error);\n }\n }\n\n return {\n notify,\n async idle() {\n await Promise.all([...chats.values()].map((s) => s.trailing).filter(Boolean));\n },\n };\n}\n\nconst SERVER_PROVIDER: Record<CodingProvider, string> = { claude: \"claude_code\", codex: \"codex\" };\n\n/**\n * The sink a host with an AI Matrx sign-in passes to the engine: the server's\n * backup-policy answer, then its one upload door.\n */\nexport function createAiMatrxRawBackupSink(options: {\n baseUrl: string;\n accessToken: () => Promise<string | null>;\n organizationId?: () => Promise<string | null>;\n fetch?: typeof fetch;\n}): RawBackupSink {\n const doFetch = options.fetch ?? fetch;\n async function headers(extra: Record<string, string> = {}): Promise<Record<string, string> | null> {\n const token = await options.accessToken();\n if (!token) return null;\n const org = options.organizationId ? await options.organizationId() : null;\n return { Authorization: `Bearer ${token}`, ...(org ? { \"X-Organization-Id\": org } : {}), ...extra };\n }\n const base = options.baseUrl.replace(/\\/$/, \"\");\n return {\n async policy(provider, providerSessionId) {\n const auth = await headers();\n if (!auth) return { enabled: false, debounceSeconds: 0 };\n const query = new URLSearchParams({ provider: SERVER_PROVIDER[provider], provider_session_id: providerSessionId });\n const response = await doFetch(`${base}/coding-sessions/raw-transcripts/backup-policy?${query}`, { headers: auth });\n if (!response.ok) throw new Error(`backup policy answered HTTP ${response.status}`);\n const body = (await response.json()) as { enabled?: boolean; debounce_seconds?: number; backup_sha256?: string | null };\n return {\n enabled: body.enabled === true,\n debounceSeconds: Number(body.debounce_seconds ?? 0),\n backupSha256: body.backup_sha256 ?? null,\n };\n },\n async upload(provider, providerSessionId, content) {\n const auth = await headers({ \"Content-Type\": \"application/x-ndjson\" });\n if (!auth) return;\n const query = new URLSearchParams({ provider: SERVER_PROVIDER[provider], provider_session_id: providerSessionId });\n const response = await doFetch(`${base}/coding-sessions/raw-transcripts/backup?${query}`, {\n method: \"POST\",\n headers: auth,\n body: new Uint8Array(content),\n });\n if (!response.ok) throw new Error(`backup upload answered HTTP ${response.status}`);\n },\n };\n}\n","/**\n * Claude Code → `TranscriptItem`.\n *\n * ONE normalizer reads both of Claude's shapes, because they are the same\n * shape: `claude --print --output-format stream-json` lines (live) and the\n * entries of the user's own session file `~/.claude/projects/<cwd>/<id>.jsonl`\n * (history) both carry `{ type: \"assistant\" | \"user\", message: { content } }`.\n * The live stream adds `system`/`stream_event`/`result`; the file adds its own\n * bookkeeping entries (titles, attachments, snapshots), which are skipped.\n *\n * Block identity: an assistant message arrives as several lines sharing one\n * `message.id`, one content block per line, in block order — the same order\n * the partial-message `content_block_start.index` counts. So a text block's id\n * is `<message id>:<index>` on both paths, and a streamed draft is replaced by\n * its final text rather than duplicated.\n */\n\nimport type { RunUsage, TranscriptItem } from \"../types\";\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\n/** User-role text Claude Code writes that the person never typed. */\nconst SYNTHETIC_USER_PREFIXES = [\n \"<command-name>\",\n \"<command-message>\",\n \"<command-args>\",\n \"<local-command-stdout>\",\n \"<local-command-stderr>\",\n \"<local-command-caveat>\",\n \"<system-reminder>\",\n \"<bash-input>\",\n \"<bash-stdout>\",\n \"<bash-stderr>\",\n \"<user-memory-input>\",\n \"<task-notification>\",\n \"Caveat: The messages below were generated by the user while running local commands\",\n \"[Request interrupted by user\",\n];\n\nexport function isSyntheticClaudeUserText(text: string): boolean {\n const trimmed = text.trimStart();\n return SYNTHETIC_USER_PREFIXES.some((prefix) => trimmed.startsWith(prefix));\n}\n\nfunction toolResultText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .map((block) => {\n if (!isObject(block)) return \"\";\n if (block.type === \"text\") return str(block.text) ?? \"\";\n if (block.type === \"image\") return \"[image]\";\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n return content === undefined || content === null ? \"\" : JSON.stringify(content);\n}\n\nexport interface ClaudeNormalizer {\n /** Feed one parsed JSON line; returns the items it produced (often none). */\n push(entry: unknown): TranscriptItem[];\n /** The Claude session id, once a line has carried it. */\n readonly sessionId: string | null;\n}\n\nexport function createClaudeNormalizer(): ClaudeNormalizer {\n let sessionId: string | null = null;\n let streamingMessageId: string | null = null;\n const blockCounters = new Map<string, number>();\n let userCounter = 0;\n let noticeCounter = 0;\n\n function nextBlockIndex(messageId: string): number {\n const index = blockCounters.get(messageId) ?? 0;\n blockCounters.set(messageId, index + 1);\n return index;\n }\n\n function pushAssistant(entry: Json): TranscriptItem[] {\n const message = isObject(entry.message) ? entry.message : null;\n if (!message) return [];\n const messageId = str(message.id) ?? str(entry.uuid) ?? `assistant-${blockCounters.size}`;\n const content = Array.isArray(message.content) ? message.content : [];\n const items: TranscriptItem[] = [];\n for (const block of content) {\n if (!isObject(block)) continue;\n const index = nextBlockIndex(messageId);\n const id = `${messageId}:${index}`;\n if (block.type === \"text\") {\n const text = str(block.text) ?? \"\";\n if (text.length > 0) items.push({ kind: \"text\", id, text });\n } else if (block.type === \"thinking\") {\n // Claude Code writes thinking blocks with an EMPTY text and only a\n // signature unless thinking display is on; an empty aside is noise.\n const text = str(block.thinking) ?? \"\";\n if (text.trim().length > 0) items.push({ kind: \"reasoning\", id, text });\n } else if (block.type === \"tool_use\" || block.type === \"server_tool_use\") {\n items.push({\n kind: \"tool-call\",\n id: str(block.id) ?? id,\n name: str(block.name) ?? \"tool\",\n input: block.input ?? null,\n });\n }\n }\n return items;\n }\n\n function pushUser(entry: Json): TranscriptItem[] {\n if (entry.isMeta === true || entry.isCompactSummary === true) return [];\n const message = isObject(entry.message) ? entry.message : null;\n if (!message) return [];\n const at = str(entry.timestamp);\n const content = message.content;\n if (typeof content === \"string\") {\n if (isSyntheticClaudeUserText(content) || content.trim().length === 0) return [];\n userCounter += 1;\n return [{ kind: \"user\", id: str(entry.uuid) ?? `user-${userCounter}`, text: content, at }];\n }\n if (!Array.isArray(content)) return [];\n const items: TranscriptItem[] = [];\n const typed: string[] = [];\n for (const block of content) {\n if (!isObject(block)) continue;\n if (block.type === \"tool_result\") {\n items.push({\n kind: \"tool-result\",\n id: str(block.tool_use_id) ?? \"unknown\",\n output: toolResultText(block.content),\n isError: block.is_error === true,\n });\n } else if (block.type === \"text\") {\n const text = str(block.text) ?? \"\";\n if (text.trim().length > 0 && !isSyntheticClaudeUserText(text)) typed.push(text);\n }\n }\n if (typed.length > 0) {\n userCounter += 1;\n items.unshift({\n kind: \"user\",\n id: str(entry.uuid) ?? `user-${userCounter}`,\n text: typed.join(\"\\n\\n\"),\n at,\n });\n }\n return items;\n }\n\n function pushStreamEvent(entry: Json): TranscriptItem[] {\n const event = isObject(entry.event) ? entry.event : null;\n if (!event) return [];\n if (event.type === \"message_start\" && isObject(event.message)) {\n streamingMessageId = str(event.message.id);\n return [];\n }\n if (event.type === \"content_block_delta\" && streamingMessageId !== null) {\n const delta = isObject(event.delta) ? event.delta : null;\n if (delta?.type === \"text_delta\") {\n const text = str(delta.text) ?? \"\";\n if (text.length === 0) return [];\n return [{ kind: \"text-delta\", id: `${streamingMessageId}:${num(event.index)}`, text }];\n }\n }\n return [];\n }\n\n function pushResult(entry: Json): TranscriptItem[] {\n const items: TranscriptItem[] = [];\n const usage = isObject(entry.usage) ? entry.usage : null;\n if (usage) {\n const runUsage: RunUsage = {\n inputTokens: num(usage.input_tokens) + num(usage.cache_creation_input_tokens),\n outputTokens: num(usage.output_tokens),\n cachedInputTokens: num(usage.cache_read_input_tokens),\n };\n const cost = typeof entry.total_cost_usd === \"number\" ? entry.total_cost_usd : null;\n items.push({ kind: \"usage\", usage: runUsage, costUsd: cost });\n }\n if (entry.is_error === true || (typeof entry.subtype === \"string\" && entry.subtype !== \"success\")) {\n const text =\n str(entry.result) ??\n (Array.isArray(entry.errors) ? entry.errors.map(String).join(\"\\n\") : null) ??\n `Claude Code stopped with \"${String(entry.subtype)}\".`;\n noticeCounter += 1;\n items.push({ kind: \"error\", id: `claude-result-${noticeCounter}`, text });\n }\n return items;\n }\n\n return {\n get sessionId() {\n return sessionId;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n const lineSession = str(raw.session_id) ?? str(raw.sessionId);\n if (lineSession && sessionId === null) sessionId = lineSession;\n if (raw.isSidechain === true) return [];\n switch (raw.type) {\n case \"assistant\":\n return pushAssistant(raw);\n case \"user\":\n return pushUser(raw);\n case \"stream_event\":\n return pushStreamEvent(raw);\n case \"result\":\n return pushResult(raw);\n case \"system\":\n if (raw.subtype === \"compact_boundary\") {\n noticeCounter += 1;\n return [\n {\n kind: \"notice\",\n id: `claude-compact-${noticeCounter}`,\n level: \"info\",\n text: \"Claude Code summarized the earlier part of this conversation to make room.\",\n },\n ];\n }\n return [];\n default:\n return [];\n }\n },\n };\n}\n","/**\n * Codex → `TranscriptItem`, from its two different shapes:\n *\n * - the LIVE stream (`codex exec --json`): `thread.started`, `item.started` /\n * `item.completed` for agent messages, commands, file changes, MCP calls,\n * web searches and plans, then `turn.completed` with usage;\n * - the user's own saved rollout file (`~/.codex/sessions/**\\/rollout-*.jsonl`):\n * `session_meta`, `event_msg` (the person's words, verbatim) and\n * `response_item` (assistant messages, tool calls and their outputs).\n *\n * Codex numbers stream items `item_0, item_1, …` again on every run, so live\n * ids carry a per-run prefix; rollout items carry globally unique call ids.\n */\n\nimport type { RunUsage, TranscriptItem } from \"../types\";\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\nfunction codexUsage(usage: Json): RunUsage {\n return {\n inputTokens: num(usage.input_tokens),\n outputTokens: num(usage.output_tokens),\n cachedInputTokens: num(usage.cached_input_tokens),\n };\n}\n\n/** Human names for Codex's item kinds, so a tool card reads like a sentence. */\nfunction toolCall(id: string, item: Json): TranscriptItem | null {\n switch (item.type) {\n case \"command_execution\":\n return { kind: \"tool-call\", id, name: \"Shell\", input: { command: str(item.command) ?? \"\" } };\n case \"file_change\":\n return { kind: \"tool-call\", id, name: \"Edit files\", input: { changes: item.changes ?? [] } };\n case \"mcp_tool_call\": {\n const server = str(item.server) ?? \"mcp\";\n const tool = str(item.tool) ?? \"tool\";\n return { kind: \"tool-call\", id, name: `${server}.${tool}`, input: item.arguments ?? null };\n }\n case \"web_search\":\n return { kind: \"tool-call\", id, name: \"Web search\", input: { query: str(item.query) ?? \"\" } };\n case \"todo_list\":\n return { kind: \"tool-call\", id, name: \"Plan\", input: { items: item.items ?? [] } };\n default:\n return null;\n }\n}\n\nfunction toolResult(id: string, item: Json): TranscriptItem | null {\n switch (item.type) {\n case \"command_execution\": {\n const exit = typeof item.exit_code === \"number\" ? item.exit_code : null;\n const output = str(item.aggregated_output) ?? \"\";\n return {\n kind: \"tool-result\",\n id,\n output: exit !== null && exit !== 0 ? `${output}\\n(exit code ${exit})`.trim() : output,\n isError: (exit !== null && exit !== 0) || item.status === \"failed\",\n };\n }\n case \"file_change\":\n return {\n kind: \"tool-result\",\n id,\n output: item.status === \"failed\" ? \"The file change failed.\" : \"Applied.\",\n isError: item.status === \"failed\",\n };\n case \"mcp_tool_call\": {\n const error = isObject(item.error) ? str(item.error.message) : str(item.error);\n return {\n kind: \"tool-result\",\n id,\n output: error ?? (item.result === undefined ? \"\" : JSON.stringify(item.result)),\n isError: error !== null || item.status === \"failed\",\n };\n }\n case \"web_search\":\n case \"todo_list\":\n return { kind: \"tool-result\", id, output: \"\", isError: false };\n default:\n return null;\n }\n}\n\nexport interface CodexStreamNormalizer {\n push(entry: unknown): TranscriptItem[];\n readonly sessionId: string | null;\n}\n\n/** The live `codex exec --json` stream. `runPrefix` keeps ids unique per run. */\nexport function createCodexStreamNormalizer(runPrefix: string): CodexStreamNormalizer {\n let sessionId: string | null = null;\n const started = new Set<string>();\n let counter = 0;\n\n return {\n get sessionId() {\n return sessionId;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n switch (raw.type) {\n case \"thread.started\":\n sessionId = str(raw.thread_id) ?? sessionId;\n return [];\n case \"item.started\":\n case \"item.updated\":\n case \"item.completed\": {\n const item = isObject(raw.item) ? raw.item : null;\n if (!item) return [];\n const id = `${runPrefix}:${str(item.id) ?? `item-${counter++}`}`;\n const completed = raw.type === \"item.completed\";\n if (item.type === \"agent_message\") {\n if (!completed) return [];\n const text = str(item.text) ?? \"\";\n return text ? [{ kind: \"text\", id, text }] : [];\n }\n if (item.type === \"reasoning\") {\n if (!completed) return [];\n const text = str(item.text) ?? \"\";\n return text.trim() ? [{ kind: \"reasoning\", id, text }] : [];\n }\n if (item.type === \"error\") {\n if (!completed) return [];\n // An `error` ITEM is a non-fatal warning (the run continues); a\n // fatal failure arrives as `turn.failed` or a top-level `error`.\n return [{ kind: \"notice\", id, level: \"warning\", text: str(item.message) ?? \"Codex warning.\" }];\n }\n const items: TranscriptItem[] = [];\n if (!started.has(id)) {\n const call = toolCall(id, item);\n if (call) {\n started.add(id);\n items.push(call);\n }\n }\n if (completed) {\n const result = toolResult(id, item);\n if (result) items.push(result);\n }\n return items;\n }\n case \"turn.completed\":\n return isObject(raw.usage)\n ? [{ kind: \"usage\", usage: codexUsage(raw.usage), costUsd: null }]\n : [];\n case \"turn.failed\": {\n const error = isObject(raw.error) ? str(raw.error.message) : null;\n counter += 1;\n return [{ kind: \"error\", id: `${runPrefix}:failed-${counter}`, text: error ?? \"Codex reported that the turn failed.\" }];\n }\n case \"error\":\n counter += 1;\n return [{ kind: \"error\", id: `${runPrefix}:error-${counter}`, text: str(raw.message) ?? \"Codex reported an error.\" }];\n default:\n return [];\n }\n },\n };\n}\n\nfunction contentText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .map((block) => (isObject(block) ? (str(block.text) ?? \"\") : \"\"))\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction parseArguments(raw: unknown): unknown {\n if (typeof raw !== \"string\") return raw ?? null;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n}\n\nfunction shellName(name: string): string {\n return name === \"shell\" || name === \"exec_command\" || name === \"local_shell\" ? \"Shell\" : name;\n}\n\n/**\n * The Codex app prepends ambient context to what the person typed\n * (`<in-app-browser-context …>…</in-app-browser-context>\\n## My request:\\n…`).\n * It is not their words; a title or a transcript bubble shows only theirs.\n */\nexport function stripCodexInjectedContext(text: string): string {\n let out = text;\n const leading = /^\\s*<([a-z][\\w-]*)(?:\\s[^>]*)?>[\\s\\S]*?<\\/\\1>/i;\n for (let i = 0; i < 8 && leading.test(out); i += 1) out = out.replace(leading, \"\");\n return out.replace(/^\\s*#{1,6}\\s*My request:\\s*/i, \"\").trim() || text.trim();\n}\n\n/** Text of a rollout `item_completed` item's `content` blocks. */\nfunction itemText(content: unknown): string {\n if (!Array.isArray(content)) return \"\";\n return content\n .map((block) => (isObject(block) ? (str(block.text) ?? \"\") : \"\"))\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction commandLine(command: unknown): string {\n if (Array.isArray(command)) {\n // [\"/bin/zsh\", \"-lc\", \"ls -la\"] → \"ls -la\": the shell wrapper is noise.\n const last = command[command.length - 1];\n if (command.length >= 3 && typeof last === \"string\") return last;\n return command.map(String).join(\" \");\n }\n return typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Current Codex (0.15x) records each turn TWICE in a rollout: the model-level\n * `response_item`s (where a shell command is a JavaScript `exec` snippet) and\n * the app-level `event_msg: item_completed` items the Codex app itself renders\n * (UserMessage, AgentMessage, CommandExecution, FileChange, …). The app-level\n * items read the way a person thinks about the work, so once a file shows it\n * has them, they are the transcript and the response_items are skipped.\n * Older rollouts have only response_items plus `event_msg: user_message`.\n */\nfunction rolloutItem(item: Json, fallbackId: string, at: string | null): TranscriptItem[] {\n const id = str(item.id) ?? fallbackId;\n switch (item.type) {\n case \"UserMessage\": {\n const text = stripCodexInjectedContext(itemText(item.content));\n return text.trim() ? [{ kind: \"user\", id, text, at }] : [];\n }\n case \"AgentMessage\": {\n const text = itemText(item.content);\n return text ? [{ kind: \"text\", id, text }] : [];\n }\n case \"Reasoning\": {\n const text = Array.isArray(item.summary_text) ? item.summary_text.map(String).join(\"\\n\") : \"\";\n return text.trim() ? [{ kind: \"reasoning\", id, text }] : [];\n }\n case \"CommandExecution\": {\n const exit = typeof item.exit_code === \"number\" ? item.exit_code : null;\n const output = str(item.aggregated_output) ?? str(item.formatted_output) ?? str(item.stdout) ?? \"\";\n const failed = (exit !== null && exit !== 0) || item.status === \"failed\";\n return [\n { kind: \"tool-call\", id, name: \"Shell\", input: { command: commandLine(item.command) } },\n {\n kind: \"tool-result\",\n id,\n output: failed && exit !== null ? `${output}\\n(exit code ${exit})`.trim() : output,\n isError: failed,\n },\n ];\n }\n case \"FileChange\":\n return [\n { kind: \"tool-call\", id, name: \"Edit files\", input: { changes: item.changes ?? null } },\n { kind: \"tool-result\", id, output: item.status === \"failed\" ? \"The file change failed.\" : \"Applied.\", isError: item.status === \"failed\" },\n ];\n case \"McpToolCall\": {\n const name = `${str(item.server) ?? \"mcp\"}.${str(item.tool) ?? \"tool\"}`;\n const error = isObject(item.error) ? str(item.error.message) : str(item.error);\n return [\n { kind: \"tool-call\", id, name, input: item.arguments ?? null },\n {\n kind: \"tool-result\",\n id,\n output: error ?? (item.result === undefined ? \"\" : JSON.stringify(item.result)),\n isError: error !== null || item.status === \"failed\",\n },\n ];\n }\n case \"WebSearch\":\n return [\n { kind: \"tool-call\", id, name: \"Web search\", input: { query: str(item.query) ?? \"\" } },\n { kind: \"tool-result\", id, output: \"\", isError: false },\n ];\n default:\n return [];\n }\n}\n\nexport interface CodexRolloutNormalizer {\n push(entry: unknown): TranscriptItem[];\n readonly sessionId: string | null;\n readonly cwd: string | null;\n}\n\n/** The user's saved rollout file. */\nexport function createCodexRolloutNormalizer(): CodexRolloutNormalizer {\n let sessionId: string | null = null;\n let cwd: string | null = null;\n let counter = 0;\n let appItems = false;\n\n return {\n get sessionId() {\n return sessionId;\n },\n get cwd() {\n return cwd;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n const payload = isObject(raw.payload) ? raw.payload : null;\n if (!payload) return [];\n const at = str(raw.timestamp);\n counter += 1;\n const fallbackId = `rollout-${typeof raw.ordinal === \"number\" ? raw.ordinal : counter}`;\n if (raw.type === \"session_meta\") {\n sessionId = str(payload.id) ?? sessionId;\n cwd = str(payload.cwd) ?? cwd;\n return [];\n }\n if (raw.type === \"event_msg\") {\n if (payload.type === \"item_completed\" && isObject(payload.item)) {\n appItems = true;\n return rolloutItem(payload.item, fallbackId, at);\n }\n if (payload.type === \"user_message\" && !appItems) {\n const text = stripCodexInjectedContext(str(payload.message) ?? \"\");\n return text.trim() ? [{ kind: \"user\", id: fallbackId, text, at }] : [];\n }\n return [];\n }\n if (raw.type === \"compacted\") {\n return [\n {\n kind: \"notice\",\n id: fallbackId,\n level: \"info\",\n text: \"Codex summarized the earlier part of this conversation to make room.\",\n },\n ];\n }\n if (raw.type !== \"response_item\" || appItems) return [];\n switch (payload.type) {\n case \"message\": {\n if (payload.role !== \"assistant\") return [];\n const text = contentText(payload.content);\n return text ? [{ kind: \"text\", id: str(payload.id) ?? fallbackId, text }] : [];\n }\n case \"reasoning\": {\n const summary = Array.isArray(payload.summary)\n ? payload.summary.map((part) => (isObject(part) ? (str(part.text) ?? \"\") : \"\")).join(\"\\n\")\n : \"\";\n return summary.trim()\n ? [{ kind: \"reasoning\", id: str(payload.id) ?? fallbackId, text: summary }]\n : [];\n }\n case \"function_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: shellName(str(payload.name) ?? \"tool\"),\n input: parseArguments(payload.arguments),\n },\n ];\n case \"custom_tool_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: shellName(str(payload.name) ?? \"tool\"),\n input: payload.input ?? null,\n },\n ];\n case \"local_shell_call\": {\n const action = isObject(payload.action) ? payload.action : {};\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: \"Shell\",\n input: { command: action.command ?? null },\n },\n ];\n }\n case \"web_search_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.id) ?? fallbackId,\n name: \"Web search\",\n input: payload.action ?? null,\n },\n { kind: \"tool-result\", id: str(payload.id) ?? fallbackId, output: \"\", isError: false },\n ];\n case \"function_call_output\":\n case \"custom_tool_call_output\":\n case \"local_shell_call_output\": {\n const output = payload.output;\n const text =\n typeof output === \"string\"\n ? output\n : isObject(output)\n ? (str(output.content) ?? JSON.stringify(output))\n : contentText(output);\n return [\n {\n kind: \"tool-result\",\n id: str(payload.call_id) ?? fallbackId,\n output: text,\n isError: isObject(output) && output.success === false,\n },\n ];\n }\n default:\n return [];\n }\n },\n };\n}\n","/**\n * Stdout arrives in arbitrary chunks; the providers write one JSON object per\n * line. This turns chunks into parsed lines, keeping a partial tail between\n * chunks, and reports (never throws on) a line that is not JSON — the CLIs do\n * print plain-text warnings on stdout now and then.\n */\n\nexport interface LineSplitter {\n push(chunk: string): { values: unknown[]; nonJson: string[] };\n /** Whatever is left when the stream ends. */\n flush(): { values: unknown[]; nonJson: string[] };\n}\n\nfunction parseLines(lines: string[]): { values: unknown[]; nonJson: string[] } {\n const values: unknown[] = [];\n const nonJson: string[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (!trimmed.startsWith(\"{\")) {\n nonJson.push(trimmed);\n continue;\n }\n try {\n values.push(JSON.parse(trimmed) as unknown);\n } catch {\n nonJson.push(trimmed);\n }\n }\n return { values, nonJson };\n}\n\nexport function createLineSplitter(): LineSplitter {\n let buffer = \"\";\n return {\n push(chunk) {\n buffer += chunk;\n const parts = buffer.split(\"\\n\");\n buffer = parts.pop() ?? \"\";\n return parseLines(parts);\n },\n flush() {\n const rest = buffer;\n buffer = \"\";\n return parseLines([rest]);\n },\n };\n}\n\n/** Parse a whole JSONL text (a fixture, or a provider file read in one go). */\nexport function parseJsonl(text: string): unknown[] {\n return parseLines(text.split(\"\\n\")).values;\n}\n","/**\n * The public contract of `@ai-matrx/coding-sessions`, shared by the engine\n * (Node), the local host (Node) and the UI (browser). Pure types — nothing here\n * touches Node or the DOM, and every value is JSON-serializable because it\n * crosses a transport (WebSocket today, desktop IPC later).\n */\n\n/** The coding agents this package drives. \"coding session\" is the canonical\n * platform term (chat.coding_session, the Coding Session Bridge). */\nexport type CodingProvider = \"claude\" | \"codex\";\n\nexport const CODING_PROVIDERS: readonly CodingProvider[] = [\"claude\", \"codex\"];\n\nexport const PROVIDER_LABEL: Record<CodingProvider, string> = {\n claude: \"Claude Code\",\n codex: \"Codex\",\n};\n\nexport type Billing = \"subscription\" | \"api\" | \"unknown\";\n\n/** Where the CLI a provider runs came from. */\nexport type BinarySource = \"desktop-app\" | \"path\" | \"npm-global\" | \"configured\";\n\n/** The exact CLI runs use: the newest copy on this computer (or the host's pick). */\nexport interface ProviderBinary {\n path: string;\n version: string | null;\n source: BinarySource;\n /** \"from ChatGPT app\", \"from PATH\", … */\n sourceLabel: string;\n /** A newer copy than the one in use, when one exists. */\n newer: { path: string; version: string; sourceLabel: string } | null;\n}\n\n/** What `providers()` answers for one provider, in plain terms. */\nexport interface ProviderStatus {\n provider: CodingProvider;\n label: string;\n installed: boolean;\n version: string | null;\n loggedIn: boolean;\n billing: Billing;\n /** \"Max\", \"Pro\", \"Plus\", … when the provider reports a plan. */\n plan: string | null;\n /** The signed-in account label, when the provider reports one. */\n account: string | null;\n /** A plain-English sentence for the screen when it is not ready. */\n problem: string | null;\n /** A plain-English fix for `problem`. */\n fix: string | null;\n /** Installed, signed in, and no known usage limit or expired sign-in. */\n ready: boolean;\n /** The last usage-limit or sign-in failure a run reported, until a run succeeds. */\n lastProblem: ProviderProblem | null;\n /** Usage windows, when the provider exposes them (Codex does; see FEATURE.md). */\n quota: QuotaWindow[];\n /** Models the driver knows for this provider (the person may type any other). */\n models?: ModelOption[] | undefined;\n /** Reasoning-effort levels this provider accepts, lowest first. */\n efforts?: string[] | undefined;\n /**\n * The model a run uses when none is picked, and where that comes from: the\n * person's own settings (`~/.claude/settings.json`, `~/.codex/config.toml`)\n * or the driver's built-in default.\n */\n defaultModel?: { id: string; source: \"settings\" | \"driver\" } | null | undefined;\n /** The effort a run uses when none is picked (the person's own settings). */\n defaultEffort?: string | null | undefined;\n /** Which CLI runs use, and its version. */\n binary?: ProviderBinary | null | undefined;\n}\n\nexport interface ModelOption {\n id: string;\n label: string;\n}\n\n/**\n * The person's own organisation of their chats — a rename, a pin, a hide. Kept\n * in this package's data dir, keyed by `chatKey()`; the providers' own files\n * are NEVER touched (a rename here does not rename the chat in Claude Code).\n */\nexport interface ChatPreference {\n /** Shown instead of the chat's own title. */\n title?: string | null | undefined;\n pinned?: boolean | undefined;\n /** Hidden from the lists (still found by search, restorable). */\n hidden?: boolean | undefined;\n updatedAt?: string | undefined;\n}\n\n/** The one key a chat's preference lives under, for ours and discovered alike. */\nexport function chatKey(provider: CodingProvider, providerSessionId: string | null, sessionId?: string | null): string {\n return providerSessionId ? `${provider}:${providerSessionId}` : `session:${sessionId ?? \"\"}`;\n}\n\n/** One chat that matched a search. */\nexport interface ChatSearchHit {\n provider: CodingProvider;\n providerSessionId: string;\n title: string;\n cwd: string | null;\n updatedAt: string;\n /** Where the words were found. */\n where: \"title\" | \"content\";\n /** A short excerpt around the first match in the conversation. */\n snippet: string | null;\n}\n\nexport interface ChatSearchResult {\n query: string;\n hits: ChatSearchHit[];\n /** How many chats were read, newest first, starting from the cursor. */\n scanned: number;\n /** How many chats exist on this computer. */\n total: number;\n /** Pass back to keep searching older chats; null when every chat was read. */\n nextCursor: number | null;\n}\n\n/** Where \"Open folder\" can open a session's folder. */\nexport type OpenTarget = \"finder\" | \"vscode\" | \"cursor\" | \"terminal\";\n\nexport interface ProviderProblem {\n kind: \"usage-limit\" | \"signed-out\";\n /** The provider's own words, verbatim. */\n message: string;\n /** When a usage limit lifts: ISO when parseable, else the provider's phrase. */\n until: string | null;\n at: string;\n}\n\nexport interface QuotaWindow {\n label: string;\n usedPercent: number | null;\n resetsAt: string | null;\n valueLabel: string | null;\n}\n\n/** An existing local Claude Code or Codex chat, found on disk (metadata only). */\nexport interface DiscoveredSession {\n provider: CodingProvider;\n providerSessionId: string;\n cwd: string | null;\n title: string;\n updatedAt: string;\n /** Where it was started, when the provider records it (\"cli\", \"vscode\", \"exec\", …). */\n source: string | null;\n /** Set when the chat looks live somewhere else right now (see `ActiveElsewhere`). */\n activeElsewhere: ActiveElsewhere | null;\n}\n\n/**\n * Evidence that a chat is being driven somewhere else RIGHT NOW. Taking it\n * over then puts two agents on one conversation, so the screen warns and asks —\n * it never blocks (validation offers, never blocks).\n */\nexport interface ActiveElsewhere {\n /** How we know, strongest first. */\n reason: \"process\" | \"recent-write\" | \"open-tool-call\";\n /** One plain sentence for the screen. */\n message: string;\n}\n\nexport type RunStatus = \"starting\" | \"running\" | \"completed\" | \"stopped\" | \"failed\";\n\nexport const TERMINAL_RUN_STATUSES: readonly RunStatus[] = [\"completed\", \"stopped\", \"failed\"];\n\nexport function isTerminalRunStatus(status: RunStatus): boolean {\n return TERMINAL_RUN_STATUSES.includes(status);\n}\n\nexport interface RunUsage {\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens: number;\n}\n\n/** One turn: one prompt sent to one provider process. */\nexport interface RunRecord {\n runId: string;\n /** Our session id (`CodingSession.id`). */\n sessionId: string;\n provider: CodingProvider;\n cwd: string;\n prompt: string;\n model: string | null;\n status: RunStatus;\n startedAt: string;\n endedAt: string | null;\n /** The real error, verbatim from the provider or the driver, when failed. */\n error: string | null;\n usage: RunUsage | null;\n costUsd: number | null;\n billing: Billing | null;\n}\n\n/** How a session came to be listed here. */\nexport type SessionOrigin = \"started\" | \"takeover\";\n\n/** A conversation driven from here. Its transcript lives in the provider's own\n * files; this is only the index row. */\nexport interface CodingSession {\n /** Our stable id. */\n id: string;\n provider: CodingProvider;\n /** The provider's own session/thread id — null until the first run reports it. */\n providerSessionId: string | null;\n cwd: string;\n title: string;\n model: string | null;\n /** Reasoning effort for the next run; null = the provider's own default. */\n effort?: string | null | undefined;\n origin: SessionOrigin;\n createdAt: string;\n updatedAt: string;\n /** The live or most recent run. */\n lastRunId: string | null;\n lastRunStatus: RunStatus | null;\n /** Prompts waiting for the active run to finish, oldest first. */\n queued: string[];\n}\n\n/**\n * One normalized transcript item — the same shape from Claude and Codex, from\n * a live stream and from a provider's saved session file.\n */\nexport type TranscriptItem =\n | { kind: \"user\"; id: string; text: string; at: string | null }\n | { kind: \"text\"; id: string; text: string }\n | { kind: \"text-delta\"; id: string; text: string }\n | { kind: \"reasoning\"; id: string; text: string }\n | { kind: \"tool-call\"; id: string; name: string; input: unknown }\n | { kind: \"tool-result\"; id: string; output: string; isError: boolean }\n | { kind: \"usage\"; usage: RunUsage; costUsd: number | null }\n | { kind: \"notice\"; id: string; level: \"info\" | \"warning\"; text: string }\n | { kind: \"error\"; id: string; text: string };\n\n/** Everything the engine pushes to a listener. */\nexport type CodingEvent =\n | { type: \"session\"; session: CodingSession }\n | { type: \"run\"; run: RunRecord }\n | { type: \"preferences\"; preferences: Record<string, ChatPreference> }\n | {\n type: \"item\";\n sessionId: string;\n runId: string;\n /** Monotonic per session; a history read reports the last `seq` it includes. */\n seq: number;\n item: TranscriptItem;\n };\n\n/** A transcript read back from the provider's own file. */\nexport interface SessionHistory {\n items: TranscriptItem[];\n /** True when the file was larger than the read budget and only its end was read. */\n truncated: boolean;\n /** Plain-English reason when history could not be read (never thrown at the UI). */\n unavailable: string | null;\n /** The last live item `seq` this read already contains; apply only newer ones. */\n seq: number;\n}\n\nexport interface StartInput {\n provider: CodingProvider;\n cwd: string;\n prompt: string;\n model?: string | null | undefined;\n effort?: string | null | undefined;\n}\n\nexport interface TakeoverInput {\n provider: CodingProvider;\n providerSessionId: string;\n cwd: string;\n title?: string | undefined;\n}\n\nexport interface SendResult {\n session: CodingSession;\n /** The run that started, or null when the prompt was queued behind a live run. */\n run: RunRecord | null;\n queued: boolean;\n}\n\nexport interface FolderCheck {\n /** The absolute path the check resolved. */\n path: string;\n exists: boolean;\n /** False when something that is NOT a folder sits at the path. */\n isDirectory: boolean;\n}\n\n/** A folder the New session flow offers (from discovered and driven sessions). */\nexport interface RecentFolder {\n path: string;\n lastUsedAt: string;\n exists: boolean;\n}\n\n/**\n * THE ENGINE CONTRACT — what the UI can ask for, independent of transport.\n * The WebSocket host implements it over the wire; a desktop app implements it\n * over IPC; the UI never knows which.\n */\nexport interface CodingSessionsApi {\n providers(): Promise<ProviderStatus[]>;\n discoverSessions(options?: { limit?: number }): Promise<DiscoveredSession[]>;\n recentFolders(): Promise<RecentFolder[]>;\n listSessions(): Promise<CodingSession[]>;\n listRuns(sessionId: string): Promise<RunRecord[]>;\n /** `maxBytes` reads more of a long chat's file (\"Show earlier\"). */\n history(sessionId: string, options?: HistoryOptions): Promise<SessionHistory>;\n /** Read-only transcript of a chat found on disk, before taking it over. */\n readTranscript(provider: CodingProvider, providerSessionId: string, options?: HistoryOptions): Promise<SessionHistory>;\n /**\n * FULL DOWNLOAD: the provider's own complete transcript file for this chat,\n * byte for byte (every tool input and output). AI Matrx's cloud keeps only\n * text and tool names, so this computer is the first place the full file\n * lives. `available: false` carries the sentence saying why.\n */\n readRawTranscript(provider: CodingProvider, providerSessionId: string): Promise<RawTranscript>;\n /** Does this folder exist here? `~` is the person's home. */\n checkFolder(path: string): Promise<FolderCheck>;\n /** Create a folder (and any missing parents), then report on it. */\n createFolder(path: string): Promise<FolderCheck>;\n /** Fresh check: is this chat live somewhere else right now? null when not. */\n sessionActivity(provider: CodingProvider, providerSessionId: string): Promise<ActiveElsewhere | null>;\n start(input: StartInput): Promise<SendResult>;\n takeover(input: TakeoverInput): Promise<CodingSession>;\n send(sessionId: string, prompt: string): Promise<SendResult>;\n stop(runId: string): Promise<RunRecord | null>;\n /** The person's renames, pins and hides, by `chatKey()`. */\n chatPreferences(): Promise<Record<string, ChatPreference>>;\n /** Merge a change into one chat's preference; `null` fields clear. Returns them all. */\n setChatPreference(key: string, patch: ChatPreference): Promise<Record<string, ChatPreference>>;\n /** Find chats by title and by what was said in them, newest first, within a time budget. */\n searchChats(query: string, options?: { cursor?: number; limit?: number }): Promise<ChatSearchResult>;\n /** Open a folder in Finder, VS Code, Cursor or Terminal. */\n openFolder(path: string, target: OpenTarget): Promise<void>;\n /** Change the model or effort the NEXT run of a session uses. */\n setSessionOptions(sessionId: string, options: { model?: string | null; effort?: string | null }): Promise<CodingSession>;\n}\n\nexport type RawTranscript =\n | { available: true; fileName: string; bytes: number; content: string }\n | { available: false; reason: string };\n\nexport interface HistoryOptions {\n /** Read up to this many bytes from the end of the file (default 24 MB). */\n maxBytes?: number | undefined;\n}\n\nexport type CodingSessionsMethod = keyof CodingSessionsApi;\n\n/** The transport the UI talks through (WebSocket, IPC, in-process). */\nexport interface CodingSessionsTransport {\n call<M extends CodingSessionsMethod>(\n method: M,\n ...args: Parameters<CodingSessionsApi[M]>\n ): ReturnType<CodingSessionsApi[M]>;\n subscribe(listener: (event: CodingEvent) => void): () => void;\n /** Connection state, for an honest banner. */\n status(): TransportStatus;\n onStatus(listener: (status: TransportStatus) => void): () => void;\n}\n\nexport type TransportStatus =\n | { state: \"connecting\" }\n | { state: \"open\" }\n | { state: \"closed\"; reason: string };\n","/**\n * USAGE LIMITS AND EXPIRED SIGN-INS, in plain English.\n *\n * A provider can be installed and signed in and still unable to run: the\n * ChatGPT or Claude plan hit its usage limit, or the saved login expired.\n * Runs report that in the provider's own words; this turns those words into\n * a remembered, honest status. Built from the real texts captured on\n * 2026-09-27 (Codex usage limit, Codex refresh failure).\n */\n\nimport { PROVIDER_LABEL, type CodingProvider, type ProviderProblem, type QuotaWindow } from \"./types\";\n\nconst USAGE_LIMIT = [\n /hit your usage limit/i,\n /usage limit (?:reached|exceeded)/i,\n /\\blimit reached\\b/i,\n /you'?ve hit your limit/i,\n /rate limit/i,\n /quota (?:exceeded|exhausted)/i,\n /purchase more credits/i,\n];\n\nconst SIGNED_OUT = [\n /access token could not be refreshed/i,\n /please sign in again/i,\n /(?:not|no longer) (?:logged|signed) in/i,\n /please run \\/login/i,\n /invalid api key/i,\n /oauth token (?:has )?expired/i,\n /authentication_error/i,\n /401 unauthorized/i,\n];\n\n/** \"Oct 4th, 2026 8:34 AM\" → ISO. null when the phrase is not a date. */\nexport function parseLimitDate(phrase: string): string | null {\n const cleaned = phrase.replace(/(\\d{1,2})(st|nd|rd|th)\\b/gi, \"$1\").replace(/[.,]\\s*$/, \"\").trim();\n const ms = Date.parse(cleaned);\n return Number.isNaN(ms) ? null : new Date(ms).toISOString();\n}\n\nfunction limitPhrase(text: string): string | null {\n const match =\n /try again (?:at|after|on) ([^\\n]+?)(?:\\.\\s|\\.$|$)/i.exec(text) ??\n /resets? (?:at |on )?([^\\n∙·|]+?)(?:\\.\\s|\\.$|$|\\s*[∙·|])/i.exec(text);\n return match?.[1]?.trim() ?? null;\n}\n\nexport function classifyProviderError(text: string, at = new Date().toISOString()): ProviderProblem | null {\n const trimmed = text.trim();\n if (!trimmed) return null;\n if (SIGNED_OUT.some((re) => re.test(trimmed))) {\n return { kind: \"signed-out\", message: trimmed, until: null, at };\n }\n if (USAGE_LIMIT.some((re) => re.test(trimmed))) {\n const phrase = limitPhrase(trimmed);\n return { kind: \"usage-limit\", message: trimmed, until: phrase ? (parseLimitDate(phrase) ?? phrase) : null, at };\n }\n return null;\n}\n\n/** A usage limit whose reset time has passed no longer applies. */\nexport function problemStillApplies(problem: ProviderProblem, now = Date.now()): boolean {\n if (problem.kind !== \"usage-limit\" || !problem.until) return true;\n const ms = Date.parse(problem.until);\n return Number.isNaN(ms) || ms > now;\n}\n\nexport function formatUntil(until: string | null): string | null {\n if (!until) return null;\n const ms = Date.parse(until);\n if (Number.isNaN(ms)) return until;\n return new Date(ms).toLocaleString(undefined, { month: \"short\", day: \"numeric\", hour: \"numeric\", minute: \"2-digit\" });\n}\n\n/** A full quota window (100% used) is a usage limit even before a run hits it. */\nexport function problemFromQuota(windows: readonly QuotaWindow[], at = new Date().toISOString()): ProviderProblem | null {\n const full = windows.find((w) => typeof w.usedPercent === \"number\" && w.usedPercent >= 100);\n if (!full) return null;\n return {\n kind: \"usage-limit\",\n message: `${full.label} is used up.`,\n until: full.resetsAt,\n at,\n };\n}\n\nexport function describeProblem(provider: CodingProvider, problem: ProviderProblem): { problem: string; fix: string } {\n const label = PROVIDER_LABEL[provider];\n if (problem.kind === \"signed-out\") {\n return {\n problem: `${label} — sign-in expired.`,\n fix: `Open ${label} and sign in again, then check again.`,\n };\n }\n const until = formatUntil(problem.until);\n return {\n problem: until ? `${label} — usage limit reached until ${until}.` : `${label} — usage limit reached.`,\n fix: until\n ? `It lifts on its own then, or add more usage in your ${provider === \"codex\" ? \"ChatGPT\" : \"Claude\"} account.`\n : `Wait for it to reset, or add more usage in your ${provider === \"codex\" ? \"ChatGPT\" : \"Claude\"} account.`,\n };\n}\n\n/**\n * A run refused because the CHOSEN MODEL is not available — to this account,\n * or to this version of the CLI. It is about the model, not the provider, so\n * the screen offers the model picker rather than a provider-wide warning.\n * Built from the real Codex text captured 2026-10-01\n * (fixtures/codex-model-unsupported.error.txt) and Claude Code's wording.\n */\nconst MODEL_UNAVAILABLE = [\n /model is not supported when using codex/i,\n /\\bmodel[\\s:'\"`][^.\\n]{0,80}\\b(?:not supported|does not exist|not available|not found)\\b/i,\n /\\bmodel_not_found\\b/i,\n /issue with the selected model/i,\n /may not exist or you may not have access to it/i,\n];\n\nexport const MODEL_UNAVAILABLE_LABEL = \"Model not available on this account\";\n\nexport function isModelUnavailable(text: string | null | undefined): boolean {\n const trimmed = (text ?? \"\").trim();\n return trimmed !== \"\" && MODEL_UNAVAILABLE.some((re) => re.test(trimmed));\n}\n\n/** What the screen says for a failed run: a short label for a known class, else the text itself. */\nexport function runErrorLabel(text: string): string {\n return isModelUnavailable(text) ? MODEL_UNAVAILABLE_LABEL : text;\n}\n","/**\n * WHICH `codex` / `claude` RUNS — the newest one on this computer.\n *\n * A person often has several copies: the CLI on PATH (Homebrew, npm, the\n * native installer) and the one bundled inside the desktop app (ChatGPT ships\n * Codex; Claude ships Claude Code). They drift. On 2026-10-01 the PATH Codex\n * was 0.157.1 while ChatGPT's bundled one was 0.159.2, and only the newer one\n * accepted the model the person had configured — the old one answered every\n * run with \"model is not supported\". So every candidate is collected, each\n * one's version read, and the highest wins.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { accessSync, constants as fsConstants, readdirSync, readFileSync, realpathSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nimport type { BinarySource, CodingProvider, ProviderBinary } from \"../types\";\n\nexport interface BinaryCandidate {\n path: string;\n source: BinarySource;\n version: string | null;\n}\n\nexport interface DiscoveryOptions {\n env: NodeJS.ProcessEnv;\n platform?: NodeJS.Platform;\n home?: string;\n /** Where desktop apps live. Default `/Applications` and `~/Applications`. */\n applications?: string[];\n}\n\nconst SOURCE_LABEL: Record<CodingProvider, Record<BinarySource, string>> = {\n codex: { \"desktop-app\": \"from ChatGPT app\", path: \"from PATH\", \"npm-global\": \"from npm\", configured: \"set by host\" },\n claude: { \"desktop-app\": \"from Claude app\", path: \"from PATH\", \"npm-global\": \"from npm\", configured: \"set by host\" },\n};\n\nexport function sourceLabel(provider: CodingProvider, source: BinarySource): string {\n return SOURCE_LABEL[provider][source];\n}\n\n/** \"codex-cli 0.159.2\" / \"2.1.284 (Claude Code)\" → \"0.159.2\". */\nexport function parseVersion(text: string | null | undefined): string | null {\n const match = /(\\d+)\\.(\\d+)\\.(\\d+)(?:[-.][0-9A-Za-z.]+)?/.exec(text ?? \"\");\n return match ? match[0] : null;\n}\n\n/** Numeric compare of the dotted parts; a pre-release sorts below its release. */\nexport function compareVersions(a: string, b: string): number {\n const [aCore = \"\", aPre] = a.split(\"-\", 2);\n const [bCore = \"\", bPre] = b.split(\"-\", 2);\n const pa = aCore.split(\".\").map((n) => Number.parseInt(n, 10) || 0);\n const pb = bCore.split(\".\").map((n) => Number.parseInt(n, 10) || 0);\n for (let i = 0; i < Math.max(pa.length, pb.length); i++) {\n const d = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (d !== 0) return d < 0 ? -1 : 1;\n }\n if (aPre && !bPre) return -1;\n if (!aPre && bPre) return 1;\n return 0;\n}\n\n/**\n * The highest version wins. A candidate whose version could not be read ranks\n * below every readable one; ties keep the earlier candidate (desktop app,\n * then PATH order, then npm).\n */\nexport function pickBinary<T extends BinaryCandidate>(candidates: readonly T[]): T | null {\n let best: T | null = null;\n for (const c of candidates) {\n if (!best) {\n best = c;\n continue;\n }\n if (c.version && (!best.version || compareVersions(c.version, best.version) > 0)) best = c;\n }\n return best;\n}\n\nfunction executable(file: string): boolean {\n try {\n accessSync(file, fsConstants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction exeName(name: string, platform: NodeJS.Platform): string[] {\n return platform === \"win32\" ? [`${name}.exe`, `${name}.cmd`, name] : [name];\n}\n\n/** Every executable `name` on PATH, in PATH order (`which -a`). */\nexport function allOnPath(name: string, pathValue: string, platform: NodeJS.Platform = process.platform): string[] {\n const found: string[] = [];\n for (const dir of pathValue.split(path.delimiter)) {\n if (!dir) continue;\n for (const file of exeName(name, platform)) {\n const candidate = path.join(dir, file);\n if (executable(candidate)) {\n found.push(candidate);\n break;\n }\n }\n }\n return found;\n}\n\nfunction desktopAppCandidates(\n provider: CodingProvider,\n platform: NodeJS.Platform,\n home: string,\n applications: string[],\n): string[] {\n if (platform !== \"darwin\") return [];\n if (provider === \"codex\") {\n return applications.map((apps) =>\n path.join(apps, \"ChatGPT.app\", \"Contents\", \"Resources\", \"codex-cli\", \"bin\", \"codex\"),\n );\n }\n // Claude's desktop app keeps each Claude Code it has downloaded in its own\n // version folder.\n const root = path.join(home, \"Library\", \"Application Support\", \"Claude\", \"claude-code\");\n let versions: string[] = [];\n try {\n versions = readdirSync(root);\n } catch {\n return [];\n }\n return versions.map((v) => path.join(root, v, \"claude.app\", \"Contents\", \"MacOS\", \"claude\"));\n}\n\nfunction npmGlobalPrefix(env: NodeJS.ProcessEnv): Promise<string | null> {\n const fromEnv = env.npm_config_prefix ?? env.NPM_CONFIG_PREFIX;\n if (fromEnv) return Promise.resolve(fromEnv);\n const npm = allOnPath(\"npm\", env.PATH ?? \"\")[0];\n if (!npm) return Promise.resolve(null);\n return new Promise((resolve) => {\n const child = execFile(npm, [\"prefix\", \"-g\"], { timeout: 5000, env }, (error, stdout) => {\n resolve(error ? null : String(stdout).trim() || null);\n });\n child.stdin?.end();\n });\n}\n\n/** The version a bundled copy declares on disk, without running it. */\nfunction declaredVersion(provider: CodingProvider, source: BinarySource, file: string): string | null {\n if (source !== \"desktop-app\") return null;\n if (provider === \"codex\") {\n try {\n const pkg = JSON.parse(readFileSync(path.join(path.dirname(path.dirname(file)), \"codex-package.json\"), \"utf8\")) as {\n version?: unknown;\n };\n return typeof pkg.version === \"string\" ? parseVersion(pkg.version) : null;\n } catch {\n return null;\n }\n }\n // …/claude-code/<version>/claude.app/Contents/MacOS/claude\n return parseVersion(path.basename(path.resolve(file, \"..\", \"..\", \"..\", \"..\")));\n}\n\n/** `<cli> --version`, stdin closed (Codex waits on an open one). */\nexport function runVersion(file: string, env: NodeJS.ProcessEnv): Promise<string | null> {\n return new Promise((resolve) => {\n const child = execFile(file, [\"--version\"], { timeout: 8000, env }, (error, stdout) => {\n resolve(error ? null : parseVersion(String(stdout)));\n });\n child.stdin?.end();\n });\n}\n\n/** Every copy of the CLI on this computer, deduplicated by real path. */\nexport async function discoverBinaries(provider: CodingProvider, options: DiscoveryOptions): Promise<BinaryCandidate[]> {\n const platform = options.platform ?? process.platform;\n const home = options.home ?? options.env.HOME ?? os.homedir();\n const listed: { path: string; source: BinarySource }[] = [\n ...desktopAppCandidates(provider, platform, home, options.applications ?? [\"/Applications\", path.join(home, \"Applications\")]).filter(executable).map((p) => ({ path: p, source: \"desktop-app\" as const })),\n ...allOnPath(provider, options.env.PATH ?? \"\", platform).map((p) => ({ path: p, source: \"path\" as const })),\n ];\n const prefix = await npmGlobalPrefix(options.env);\n if (prefix) {\n const dir = platform === \"win32\" ? prefix : path.join(prefix, \"bin\");\n for (const file of exeName(provider, platform)) {\n const candidate = path.join(dir, file);\n if (executable(candidate)) {\n listed.push({ path: candidate, source: \"npm-global\" });\n break;\n }\n }\n }\n const seen = new Set<string>();\n const unique = listed.filter((c) => {\n let real = c.path;\n try {\n real = realpathSync(c.path);\n } catch {\n /* keep the listed path */\n }\n if (seen.has(real)) return false;\n seen.add(real);\n return true;\n });\n return Promise.all(\n unique.map(async (c) => ({\n ...c,\n version: declaredVersion(provider, c.source, c.path) ?? (await runVersion(c.path, options.env)),\n })),\n );\n}\n\n/**\n * The binary runs use. `forced` (the host's `commands` option) always wins,\n * but a newer copy elsewhere is still reported as `newer`.\n */\nexport async function resolveBinary(\n provider: CodingProvider,\n options: DiscoveryOptions & { forced?: string | null | undefined; discover?: boolean },\n): Promise<ProviderBinary | null> {\n const candidates = options.discover === false ? [] : await discoverBinaries(provider, options);\n const best = pickBinary(candidates);\n const inUse: BinaryCandidate | null = options.forced\n ? {\n path: options.forced,\n source: \"configured\",\n version:\n candidates.find((c) => c.path === options.forced)?.version ??\n (options.discover === false ? null : await runVersion(options.forced, options.env)),\n }\n : best;\n if (!inUse) return null;\n const newer =\n best && best.path !== inUse.path && best.version && (!inUse.version || compareVersions(best.version, inUse.version) > 0)\n ? { path: best.path, version: best.version, sourceLabel: sourceLabel(provider, best.source) }\n : null;\n return {\n path: inUse.path,\n version: inUse.version,\n source: inUse.source,\n sourceLabel: sourceLabel(provider, inUse.source),\n newer,\n };\n}\n","/**\n * THE CLEAN ENVIRONMENT — built from an ALLOWLIST, never a denylist.\n *\n * The process that hosts this package is often itself running inside a Claude\n * Code or Codex session. Those sessions export variables (`CLAUDE_CODE_*`,\n * `CLAUDECODE`, `ANTHROPIC_BASE_URL`, `ANTHROPIC_AUTH_TOKEN`, `CODEX_*`,\n * `OTEL_*`, `GIT_EDITOR`, …) that make a child CLI talk to the wrong endpoint,\n * bill the wrong account, or believe it is a sub-agent. A denylist is always one\n * variable behind the next CLI release; an allowlist cannot be. The spike ran\n * under `env -i` for this reason, and this is that guarantee in code.\n *\n * API keys are deliberately NOT allowed through: the whole point is the user's\n * own subscription login. A host that truly wants API billing passes a key in\n * `extra` on purpose, and `providers()` then reports \"API\" honestly.\n */\n\nimport os from \"node:os\";\nimport path from \"node:path\";\n\n/** Exact names that pass through. */\nconst ALLOWED_NAMES = new Set([\n \"HOME\",\n \"USER\",\n \"LOGNAME\",\n \"SHELL\",\n \"TMPDIR\",\n \"LANG\",\n \"TZ\",\n \"SSH_AUTH_SOCK\",\n \"HTTP_PROXY\",\n \"HTTPS_PROXY\",\n \"NO_PROXY\",\n \"http_proxy\",\n \"https_proxy\",\n \"no_proxy\",\n \"SSL_CERT_FILE\",\n \"NODE_EXTRA_CA_CERTS\",\n]);\n\n/** Prefixes that pass through (locale only). */\nconst ALLOWED_PREFIXES = [\"LC_\"];\n\n/**\n * Where the CLIs are commonly installed. A host launched from a GUI or a\n * launchd agent often has a bare PATH; without these the CLIs look\n * \"not installed\" when they are.\n */\nfunction wellKnownBinDirs(home: string): string[] {\n return [\n path.join(home, \".local\", \"bin\"),\n path.join(home, \".claude\", \"local\"),\n path.join(home, \".npm-global\", \"bin\"),\n path.join(home, \".bun\", \"bin\"),\n path.join(home, \".volta\", \"bin\"),\n \"/opt/homebrew/bin\",\n \"/usr/local/bin\",\n \"/usr/bin\",\n \"/bin\",\n \"/usr/sbin\",\n \"/sbin\",\n ];\n}\n\nexport function isAllowedEnvName(name: string): boolean {\n return ALLOWED_NAMES.has(name) || ALLOWED_PREFIXES.some((prefix) => name.startsWith(prefix));\n}\n\n/**\n * Build the environment for a driver worker (and therefore for the CLI it\n * launches) from the host's environment.\n */\nexport function buildCleanEnv(\n hostEnv: NodeJS.ProcessEnv,\n extra: Record<string, string> = {},\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [name, value] of Object.entries(hostEnv)) {\n if (typeof value !== \"string\") continue;\n if (isAllowedEnvName(name)) out[name] = value;\n }\n const home = out.HOME ?? os.homedir();\n out.HOME = home;\n const hostPath = (hostEnv.PATH ?? \"\").split(path.delimiter).filter(Boolean);\n const merged: string[] = [];\n for (const dir of [...hostPath, ...wellKnownBinDirs(home)]) {\n if (!merged.includes(dir)) merged.push(dir);\n }\n out.PATH = merged.join(path.delimiter);\n for (const [name, value] of Object.entries(extra)) out[name] = value;\n return out;\n}\n","/**\n * Reading the providers' OWN files — cheaply, and never copying them.\n *\n * A heavy user has tens of gigabytes here (this Mac: 38 GB of Codex rollouts\n * across ~6,800 files, 18 GB of Claude sessions across ~1,900). Discovery\n * therefore stats every file (cheap) but READS only the head and tail of the\n * few newest, and a transcript read is capped with the cap announced.\n */\n\nimport { createReadStream } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nimport { createClaudeNormalizer } from \"../normalize/claude\";\nimport { createCodexRolloutNormalizer } from \"../normalize/codex\";\nimport { parseJsonl } from \"../normalize/lines\";\nimport { describeActivity, listProcesses, type ProcessRow } from \"./activity\";\nimport type {\n ActiveElsewhere,\n CodingProvider,\n DiscoveredSession,\n SessionHistory,\n TranscriptItem,\n} from \"../types\";\n\nexport interface ProviderHomes {\n claudeProjects: string;\n codexSessions: string;\n codexIndex: string;\n}\n\nexport function defaultProviderHomes(home = os.homedir()): ProviderHomes {\n return {\n claudeProjects: path.join(home, \".claude\", \"projects\"),\n codexSessions: path.join(home, \".codex\", \"sessions\"),\n codexIndex: path.join(home, \".codex\", \"session_index.jsonl\"),\n };\n}\n\ninterface FileCandidate {\n provider: CodingProvider;\n file: string;\n id: string;\n mtimeMs: number;\n size: number;\n}\n\nconst UUIDISH = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\.jsonl$/i;\n\nasync function safeReaddir(dir: string): Promise<import(\"node:fs\").Dirent[]> {\n try {\n return await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return [];\n }\n}\n\nasync function statCandidate(\n provider: CodingProvider,\n file: string,\n): Promise<FileCandidate | null> {\n const match = UUIDISH.exec(file);\n if (!match?.[1]) return null;\n try {\n const stat = await fs.stat(file);\n return { provider, file, id: match[1], mtimeMs: stat.mtimeMs, size: stat.size };\n } catch {\n return null;\n }\n}\n\nasync function claudeCandidates(root: string): Promise<FileCandidate[]> {\n const out: FileCandidate[] = [];\n for (const project of await safeReaddir(root)) {\n if (!project.isDirectory()) continue;\n const dir = path.join(root, project.name);\n const entries = await safeReaddir(dir);\n const stats = await Promise.all(\n entries\n .filter((e) => e.isFile() && e.name.endsWith(\".jsonl\"))\n .map((e) => statCandidate(\"claude\", path.join(dir, e.name))),\n );\n for (const s of stats) if (s) out.push(s);\n }\n return out;\n}\n\nasync function codexCandidates(root: string): Promise<FileCandidate[]> {\n const out: FileCandidate[] = [];\n for (const year of await safeReaddir(root)) {\n if (!year.isDirectory()) continue;\n for (const month of await safeReaddir(path.join(root, year.name))) {\n if (!month.isDirectory()) continue;\n for (const day of await safeReaddir(path.join(root, year.name, month.name))) {\n if (!day.isDirectory()) continue;\n const dir = path.join(root, year.name, month.name, day.name);\n const entries = await safeReaddir(dir);\n const stats = await Promise.all(\n entries\n .filter((e) => e.isFile() && e.name.startsWith(\"rollout-\") && e.name.endsWith(\".jsonl\"))\n .map((e) => statCandidate(\"codex\", path.join(dir, e.name))),\n );\n for (const s of stats) if (s) out.push(s);\n }\n }\n }\n return out;\n}\n\n/** Read `length` bytes at `start` as UTF-8. */\nasync function readSlice(file: string, start: number, length: number): Promise<string> {\n const handle = await fs.open(file, \"r\");\n try {\n const buffer = Buffer.alloc(length);\n const { bytesRead } = await handle.read(buffer, 0, length, start);\n return buffer.subarray(0, bytesRead).toString(\"utf8\");\n } finally {\n await handle.close();\n }\n}\n\n/** Complete lines only: drop a partial first line (tail reads) and a partial last line. */\nfunction completeLines(text: string, droppedFirst: boolean): string {\n let body = text;\n if (droppedFirst) {\n const nl = body.indexOf(\"\\n\");\n body = nl >= 0 ? body.slice(nl + 1) : \"\";\n }\n const last = body.lastIndexOf(\"\\n\");\n return last >= 0 ? body.slice(0, last) : body;\n}\n\nconst HEAD_BYTES = 256 * 1024;\nconst TAIL_BYTES = 128 * 1024;\n\nfunction oneLine(text: string, max = 140): string {\n const flat = text.replace(/\\s+/g, \" \").trim();\n return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;\n}\n\nasync function describeClaude(candidate: FileCandidate): Promise<DiscoveredSession | null> {\n const head = parseJsonl(completeLines(await readSlice(candidate.file, 0, HEAD_BYTES), false));\n const tailStart = Math.max(0, candidate.size - TAIL_BYTES);\n const tail =\n tailStart > 0\n ? parseJsonl(completeLines(await readSlice(candidate.file, tailStart, TAIL_BYTES), true))\n : head;\n\n let cwd: string | null = null;\n let firstPrompt: string | null = null;\n let entrypoint: string | null = null;\n const normalizer = createClaudeNormalizer();\n for (const entry of head) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const e = entry as Record<string, unknown>;\n if (!cwd && typeof e.cwd === \"string\") cwd = e.cwd;\n if (!entrypoint && typeof e.entrypoint === \"string\") entrypoint = e.entrypoint;\n if (firstPrompt === null) {\n for (const item of normalizer.push(entry)) {\n if (item.kind === \"user\") {\n firstPrompt = item.text;\n break;\n }\n }\n }\n if (cwd && firstPrompt !== null) break;\n }\n\n const titles: Record<string, string | null> = { custom: null, ai: null, agent: null, summary: null, last: null };\n for (const entry of [...head, ...tail]) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const e = entry as Record<string, unknown>;\n if (e.type === \"custom-title\" && typeof e.customTitle === \"string\") titles.custom = e.customTitle;\n if (e.type === \"ai-title\" && typeof e.aiTitle === \"string\") titles.ai = e.aiTitle;\n if (e.type === \"agent-name\" && typeof e.agentName === \"string\") titles.agent = e.agentName;\n if (e.type === \"summary\" && typeof e.summary === \"string\") titles.summary = e.summary;\n if (e.type === \"last-prompt\" && typeof e.lastPrompt === \"string\") titles.last = e.lastPrompt;\n }\n const title = titles.custom ?? titles.ai ?? titles.agent ?? titles.summary ?? firstPrompt ?? titles.last;\n // A file with no conversation in it (a session that only ran start-up hooks)\n // is not a chat anyone can take over.\n if (!title) return null;\n return {\n provider: \"claude\",\n providerSessionId: candidate.id,\n cwd,\n title: oneLine(title),\n updatedAt: new Date(candidate.mtimeMs).toISOString(),\n source: entrypoint,\n activeElsewhere: null,\n };\n}\n\nasync function readCodexIndex(file: string): Promise<Map<string, string>> {\n const names = new Map<string, string>();\n let text: string;\n try {\n const stat = await fs.stat(file);\n const budget = 4 * 1024 * 1024;\n text =\n stat.size <= budget\n ? await fs.readFile(file, \"utf8\")\n : completeLines(await readSlice(file, stat.size - budget, budget), true);\n } catch {\n return names;\n }\n for (const entry of parseJsonl(text)) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const e = entry as Record<string, unknown>;\n if (typeof e.id === \"string\" && typeof e.thread_name === \"string\" && e.thread_name.trim()) {\n names.set(e.id, e.thread_name);\n }\n }\n return names;\n}\n\nasync function describeCodex(\n candidate: FileCandidate,\n names: Map<string, string>,\n): Promise<DiscoveredSession | null> {\n const head = parseJsonl(completeLines(await readSlice(candidate.file, 0, HEAD_BYTES), false));\n let cwd: string | null = null;\n let source: string | null = null;\n let isSubAgent = false;\n let firstPrompt: string | null = null;\n const normalizer = createCodexRolloutNormalizer();\n for (const entry of head) {\n if (typeof entry !== \"object\" || entry === null) continue;\n const e = entry as Record<string, unknown>;\n if (e.type === \"session_meta\" && typeof e.payload === \"object\" && e.payload !== null) {\n const p = e.payload as Record<string, unknown>;\n cwd = typeof p.cwd === \"string\" ? p.cwd : cwd;\n source = typeof p.source === \"string\" ? p.source : typeof p.originator === \"string\" ? p.originator : null;\n if (typeof p.parent_thread_id === \"string\" && p.parent_thread_id) isSubAgent = true;\n if (p.thread_source === \"subagent\" || p.thread_source === \"sub_agent\") isSubAgent = true;\n }\n if (firstPrompt === null) {\n for (const item of normalizer.push(entry)) {\n if (item.kind === \"user\") {\n firstPrompt = item.text;\n break;\n }\n }\n }\n }\n // A sub-agent thread belongs to its parent conversation; taking it over on\n // its own would answer a question nobody in this chat asked.\n if (isSubAgent) return null;\n const title = names.get(candidate.id) ?? firstPrompt;\n if (!title) return null;\n return {\n provider: \"codex\",\n providerSessionId: candidate.id,\n cwd,\n title: oneLine(title),\n updatedAt: new Date(candidate.mtimeMs).toISOString(),\n source,\n activeElsewhere: null,\n };\n}\n\nexport interface DiscoverOptions {\n limit?: number | undefined;\n homes?: ProviderHomes | undefined;\n /** Processes that are OUR runs (never \"live elsewhere\"). */\n excludePids?: ReadonlySet<number> | undefined;\n}\n\nasync function readTail(file: string, size: number): Promise<unknown[]> {\n const start = Math.max(0, size - TAIL_BYTES);\n return parseJsonl(completeLines(await readSlice(file, start, Math.min(size, TAIL_BYTES)), start > 0));\n}\n\nasync function activityFor(\n candidate: FileCandidate,\n processes: readonly ProcessRow[],\n excludePids: ReadonlySet<number> | undefined,\n ownWritesUntilMs?: number | undefined,\n): Promise<ActiveElsewhere | null> {\n return describeActivity({\n ownWritesUntilMs,\n provider: candidate.provider,\n providerSessionId: candidate.id,\n mtimeMs: candidate.mtimeMs,\n now: Date.now(),\n processes,\n excludePids,\n tail: () => readTail(candidate.file, candidate.size).catch(() => []),\n });\n}\n\n/** Fresh \"is it live elsewhere?\" for one session (the preview and the takeover confirm). */\nexport async function sessionActivity(\n provider: CodingProvider,\n providerSessionId: string,\n options: {\n homes?: ProviderHomes | undefined;\n excludePids?: ReadonlySet<number> | undefined;\n ownWritesUntilMs?: number | undefined;\n } = {},\n): Promise<ActiveElsewhere | null> {\n const file = await findSessionFile(provider, providerSessionId, options.homes);\n const processes = await listProcesses();\n if (!file) {\n return describeActivity({\n provider,\n providerSessionId,\n mtimeMs: 0,\n now: Date.now(),\n processes,\n excludePids: options.excludePids,\n tail: async () => [],\n });\n }\n const candidate = await statCandidate(provider, file);\n if (!candidate) return null;\n return activityFor(candidate, processes, options.excludePids, options.ownWritesUntilMs);\n}\n\n/** Recent existing local Claude Code and Codex chats, newest first (metadata only). */\nexport async function discoverLocalSessions(options: DiscoverOptions = {}): Promise<DiscoveredSession[]> {\n const limit = options.limit ?? 60;\n const homes = options.homes ?? defaultProviderHomes();\n const [claude, codex, names] = await Promise.all([\n claudeCandidates(homes.claudeProjects),\n codexCandidates(homes.codexSessions),\n readCodexIndex(homes.codexIndex),\n ]);\n const candidates = [...claude, ...codex].sort((a, b) => b.mtimeMs - a.mtimeMs);\n const processes = await listProcesses();\n const out: DiscoveredSession[] = [];\n // Describe in small batches, newest first, until the page is full.\n for (let i = 0; i < candidates.length && out.length < limit; i += 12) {\n const batch = candidates.slice(i, i + 12);\n const described = await Promise.all(\n batch.map(async (c) => {\n const d = await (c.provider === \"claude\" ? describeClaude(c) : describeCodex(c, names)).catch(() => null);\n if (!d) return null;\n return { ...d, activeElsewhere: await activityFor(c, processes, options.excludePids).catch(() => null) };\n }),\n );\n for (const d of described) if (d && out.length < limit) out.push(d);\n }\n return out;\n}\n\n/** Where a provider keeps one session's transcript, or null when it has none on disk. */\nexport async function findSessionFile(\n provider: CodingProvider,\n providerSessionId: string,\n homes: ProviderHomes = defaultProviderHomes(),\n): Promise<string | null> {\n if (!/^[0-9a-f-]{36}$/i.test(providerSessionId)) return null;\n const candidates =\n provider === \"claude\"\n ? await claudeCandidates(homes.claudeProjects)\n : await codexCandidates(homes.codexSessions);\n const hits = candidates.filter((c) => c.id === providerSessionId).sort((a, b) => b.mtimeMs - a.mtimeMs);\n return hits[0]?.file ?? null;\n}\n\nexport const HISTORY_BUDGET = 24 * 1024 * 1024;\n/** \"Show earlier\" never reads more than this at once. */\nexport const MAX_HISTORY_BUDGET = 256 * 1024 * 1024;\n\n/**\n * Read a transcript from the provider's own file, up to `endOffset` bytes (the\n * file's size when a run started, so a live run's lines are not read twice).\n */\nexport async function readSessionFile(\n provider: CodingProvider,\n file: string,\n endOffset?: number | undefined,\n maxBytes: number = HISTORY_BUDGET,\n): Promise<SessionHistory> {\n let size: number;\n try {\n size = (await fs.stat(file)).size;\n } catch {\n return {\n items: [],\n truncated: false,\n unavailable: \"The saved transcript for this chat could not be found on this computer.\",\n seq: 0,\n };\n }\n const end = Math.min(size, endOffset ?? size);\n const start = Math.max(0, end - Math.max(1024 * 1024, Math.min(maxBytes, MAX_HISTORY_BUDGET)));\n const items: TranscriptItem[] = [];\n const normalizer = provider === \"claude\" ? createClaudeNormalizer() : createCodexRolloutNormalizer();\n let droppedFirst = start > 0;\n let carry = \"\";\n await new Promise<void>((resolve, reject) => {\n const stream = createReadStream(file, { start, end: Math.max(start, end - 1), encoding: \"utf8\" });\n stream.on(\"data\", (chunk) => {\n const text = carry + String(chunk);\n const lines = text.split(\"\\n\");\n carry = lines.pop() ?? \"\";\n if (droppedFirst) {\n lines.shift();\n droppedFirst = false;\n }\n for (const value of parseJsonl(lines.join(\"\\n\"))) items.push(...normalizer.push(value));\n });\n stream.on(\"end\", () => {\n for (const value of parseJsonl(carry)) items.push(...normalizer.push(value));\n resolve();\n });\n stream.on(\"error\", reject);\n });\n // Live-only kinds never come from a saved file; usage is per run, not history.\n return {\n items: items.filter((item) => item.kind !== \"usage\" && item.kind !== \"text-delta\"),\n truncated: start > 0,\n unavailable: null,\n seq: 0,\n };\n}\n\n/** Every session file on this computer, newest first (a stat each; nothing read). */\nexport async function listSessionFiles(homes: ProviderHomes = defaultProviderHomes()): Promise<FileCandidate[]> {\n const [claude, codex] = await Promise.all([\n claudeCandidates(homes.claudeProjects),\n codexCandidates(homes.codexSessions),\n ]);\n return [...claude, ...codex].sort((a, b) => b.mtimeMs - a.mtimeMs);\n}\n\n/** Title, folder and time for one file (null for sub-agent and hook-only files). */\nexport async function describeSessionFile(\n candidate: FileCandidate,\n codexNames: Map<string, string>,\n): Promise<DiscoveredSession | null> {\n return (candidate.provider === \"claude\" ? describeClaude(candidate) : describeCodex(candidate, codexNames)).catch(\n () => null,\n );\n}\n\nexport { readCodexIndex };\nexport type { FileCandidate };\n","/**\n * IS THIS CHAT LIVE SOMEWHERE ELSE RIGHT NOW?\n *\n * Taking over a chat that another Claude Code or Codex is still driving puts\n * two agents on one conversation. We cannot know for certain, so we look for\n * evidence, strongest first, and the screen WARNS and asks — it never blocks\n * (the platform law: validation offers, never blocks).\n *\n * 1. a process whose arguments carry the session id — `claude --resume <id>`,\n * `--resume=<id>`, `codex exec … resume <id>` (one `ps` per check);\n * 2. the session file was written in the last two minutes;\n * 3. the file's last step is a tool call that never got its result, and the\n * file changed in the last fifteen minutes (an abandoned crash from last\n * week is not \"running\").\n */\n\nimport { execFile } from \"node:child_process\";\n\nimport { createClaudeNormalizer } from \"../normalize/claude\";\nimport { createCodexRolloutNormalizer } from \"../normalize/codex\";\nimport { PROVIDER_LABEL, type ActiveElsewhere, type CodingProvider, type TranscriptItem } from \"../types\";\n\nexport const RECENT_WRITE_MS = 2 * 60 * 1000;\nexport const OPEN_TOOL_WINDOW_MS = 15 * 60 * 1000;\n\nexport interface ProcessRow {\n pid: number;\n args: string;\n}\n\n/** Every process's pid and full argument line. Empty (never throws) when `ps` is unavailable. */\nexport function listProcesses(): Promise<ProcessRow[]> {\n return new Promise((resolve) => {\n execFile(\"ps\", [\"-axww\", \"-o\", \"pid=,args=\"], { maxBuffer: 64 * 1024 * 1024, timeout: 5000 }, (error, stdout) => {\n if (error) {\n resolve([]);\n return;\n }\n const rows: ProcessRow[] = [];\n for (const line of String(stdout).split(\"\\n\")) {\n const match = /^\\s*(\\d+)\\s+(.*)$/.exec(line);\n if (match?.[1] && match[2]) rows.push({ pid: Number(match[1]), args: match[2] });\n }\n resolve(rows);\n });\n });\n}\n\n/** A process driving this session: its args name the id, and it is not one of ours. */\nexport function findDrivingProcess(\n processes: readonly ProcessRow[],\n providerSessionId: string,\n excludePids: ReadonlySet<number> = new Set(),\n): ProcessRow | null {\n for (const row of processes) {\n if (excludePids.has(row.pid) || row.pid === process.pid) continue;\n if (!row.args.includes(providerSessionId)) continue;\n // Our own `ps`/`pgrep` and editors viewing the file are not drivers.\n if (/(^|\\/)(ps|pgrep|grep|rg|tail|less|cat)\\b/.test(row.args.split(\" \")[0] ?? \"\")) continue;\n return row;\n }\n return null;\n}\n\n/** True when the last meaningful item is a tool call with no result yet. */\nexport function endsWithOpenToolCall(provider: CodingProvider, entries: readonly unknown[]): boolean {\n const normalizer = provider === \"claude\" ? createClaudeNormalizer() : createCodexRolloutNormalizer();\n const items: TranscriptItem[] = [];\n for (const entry of entries) items.push(...normalizer.push(entry));\n const meaningful = items.filter((i) => i.kind !== \"usage\" && i.kind !== \"notice\" && i.kind !== \"text-delta\");\n const last = meaningful[meaningful.length - 1];\n if (!last || last.kind !== \"tool-call\") return false;\n return !items.some((i) => i.kind === \"tool-result\" && i.id === last.id);\n}\n\nexport function describeActivity(input: {\n provider: CodingProvider;\n providerSessionId: string;\n mtimeMs: number;\n now: number;\n processes: readonly ProcessRow[];\n excludePids?: ReadonlySet<number> | undefined;\n /** Writes at or before this time were OURS (our own run just ended), so\n * they are not evidence of another driver. */\n ownWritesUntilMs?: number | undefined;\n /** Parsed tail of the session file; only consulted when recent enough. */\n tail: () => Promise<readonly unknown[]>;\n}): Promise<ActiveElsewhere | null> {\n const label = PROVIDER_LABEL[input.provider];\n const driver = findDrivingProcess(input.processes, input.providerSessionId, input.excludePids);\n if (driver) {\n return Promise.resolve({\n reason: \"process\",\n message: `This chat is running right now in ${label} — an open ${label} process is using it.`,\n });\n }\n if (input.ownWritesUntilMs !== undefined && input.mtimeMs <= input.ownWritesUntilMs) return Promise.resolve(null);\n const age = input.now - input.mtimeMs;\n if (age <= RECENT_WRITE_MS) {\n return Promise.resolve({\n reason: \"recent-write\",\n message: `This chat was active in ${label} less than two minutes ago and may still be running there.`,\n });\n }\n if (age > OPEN_TOOL_WINDOW_MS) return Promise.resolve(null);\n return input.tail().then((entries) =>\n endsWithOpenToolCall(input.provider, entries)\n ? {\n reason: \"open-tool-call\" as const,\n message: `This chat may still be running in ${label}: its last step started and has not finished.`,\n }\n : null,\n );\n}\n","/**\n * The person's renames, pins and hides — one small JSON file in this package's\n * data dir, keyed by `chatKey()`. The providers' own files are never touched.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { ChatPreference } from \"../types\";\n\nexport class PreferenceStore {\n private data: Record<string, ChatPreference> = {};\n private writing: Promise<void> = Promise.resolve();\n\n constructor(private readonly dir: string) {}\n\n get file(): string {\n return path.join(this.dir, \"preferences.json\");\n }\n\n async load(): Promise<void> {\n try {\n const parsed = JSON.parse(await fs.readFile(this.file, \"utf8\")) as unknown;\n this.data = typeof parsed === \"object\" && parsed !== null ? (parsed as Record<string, ChatPreference>) : {};\n } catch {\n this.data = {};\n }\n }\n\n all(): Record<string, ChatPreference> {\n return { ...this.data };\n }\n\n get(key: string): ChatPreference | null {\n return this.data[key] ?? null;\n }\n\n /** Merge `patch`; a null/false/empty field is removed, an empty preference deleted. */\n set(key: string, patch: ChatPreference): Record<string, ChatPreference> {\n if (!key || key.length > 200) throw new Error(\"That chat can't be found.\");\n const next: ChatPreference = { ...this.data[key] };\n if (\"title\" in patch) {\n const title = typeof patch.title === \"string\" ? patch.title.replace(/\\s+/g, \" \").trim().slice(0, 200) : \"\";\n if (title) next.title = title;\n else delete next.title;\n }\n if (\"pinned\" in patch) {\n if (patch.pinned === true) next.pinned = true;\n else delete next.pinned;\n }\n if (\"hidden\" in patch) {\n if (patch.hidden === true) next.hidden = true;\n else delete next.hidden;\n }\n delete next.updatedAt;\n if (Object.keys(next).length === 0) delete this.data[key];\n else this.data[key] = { ...next, updatedAt: new Date().toISOString() };\n this.persist();\n return this.all();\n }\n\n private persist(): void {\n const snapshot = JSON.stringify(this.data, null, 1);\n this.writing = this.writing\n .then(async () => {\n await fs.mkdir(this.dir, { recursive: true });\n const tmp = `${this.file}.${randomUUID()}.tmp`;\n await fs.writeFile(tmp, snapshot, { mode: 0o600 });\n await fs.rename(tmp, this.file);\n })\n .catch(() => {\n /* the next write retries with everything */\n });\n }\n\n async flush(): Promise<void> {\n await this.writing;\n }\n}\n","/**\n * SEARCH — by title and by what was said, across every Claude Code and Codex\n * chat on this computer, newest first.\n *\n * A heavy user has tens of gigabytes of session files, so a search is a\n * PAGE: it reads chats newest-first until it has `limit` hits or its time\n * budget is spent, and says exactly how far it got (`scanned` of `total`,\n * `nextCursor` to keep going). It never claims \"no results\" for chats it did\n * not read.\n *\n * A match must be in the conversation — a message, a tool call or its output,\n * exactly as the transcript shows it — not in bookkeeping (ids, tool\n * catalogues, hook output), so \"type\" does not match every line of every file.\n */\n\nimport { createReadStream } from \"node:fs\";\n\nimport { createClaudeNormalizer } from \"../normalize/claude\";\nimport { createCodexRolloutNormalizer } from \"../normalize/codex\";\nimport type { ChatSearchHit, ChatSearchResult, CodingProvider, TranscriptItem } from \"../types\";\nimport {\n defaultProviderHomes,\n describeSessionFile,\n listSessionFiles,\n readCodexIndex,\n type FileCandidate,\n type ProviderHomes,\n} from \"./files\";\n\nexport interface SearchOptions {\n homes?: ProviderHomes | undefined;\n cursor?: number | undefined;\n limit?: number | undefined;\n /** Stop reading after this long and hand back a cursor. Default 3.5 s. */\n budgetMs?: number | undefined;\n}\n\n/**\n * The first conversation text in one saved line that contains `needle`: the\n * line goes through the SAME normalizer the transcript uses, so only what the\n * screen would show can match — a message, a tool's input or output — never\n * tool catalogues, hook output or ids.\n */\nfunction findInLine(provider: CodingProvider, value: unknown, needle: string): string | null {\n const items: TranscriptItem[] =\n provider === \"claude\" ? createClaudeNormalizer().push(value) : createCodexRolloutNormalizer().push(value);\n for (const item of items) {\n let text: string | null = null;\n switch (item.kind) {\n case \"user\":\n case \"text\":\n case \"reasoning\":\n case \"notice\":\n case \"error\":\n text = item.text;\n break;\n case \"tool-call\":\n text = typeof item.input === \"string\" ? item.input : JSON.stringify(item.input ?? \"\");\n break;\n case \"tool-result\":\n text = item.output;\n break;\n default:\n text = null;\n }\n if (text && text.toLowerCase().includes(needle)) return text;\n }\n return null;\n}\n\n/** ~140 characters around the first match, on one line. */\nexport function snippetAround(text: string, needle: string, width = 140): string {\n const flat = text.replace(/\\s+/g, \" \").trim();\n const at = flat.toLowerCase().indexOf(needle);\n if (at < 0) return flat.slice(0, width);\n const before = Math.floor((width - needle.length) / 3);\n const start = Math.max(0, at - before);\n const end = Math.min(flat.length, start + width);\n return `${start > 0 ? \"…\" : \"\"}${flat.slice(start, end)}${end < flat.length ? \"…\" : \"\"}`;\n}\n\n/**\n * Read one file until the first line whose CONVERSATION contains the query.\n * Returns that excerpt, or null.\n *\n * The hot path never decodes UTF-8: each chunk is read as latin1 (one char\n * per byte, so offsets stay byte offsets), lower-cased natively, and searched\n * for the query as it appears inside a JSON string (`raw`: quotes and\n * backslashes escaped). An ASCII query only ever matches ASCII bytes, so the\n * latin1 reading cannot invent or hide a match. Only\n * a line that matches there is decoded, parsed, and checked for the query in\n * its conversation (not its bookkeeping). A query with non-ASCII letters\n * takes the decoded path, which is exact but slower.\n */\nconst TIMED_OUT = Symbol(\"timed-out\");\n\nasync function scanFile(\n provider: CodingProvider,\n file: string,\n needle: string,\n raw: string,\n deadline: number,\n): Promise<string | null | typeof TIMED_OUT> {\n const ascii = /^[\\x00-\\x7f]*$/.test(raw);\n return new Promise((resolve) => {\n let carry: Buffer = Buffer.alloc(0);\n let done = false;\n const stream = createReadStream(file, { highWaterMark: 4 * 1024 * 1024 });\n const finish = (value: string | null | typeof TIMED_OUT) => {\n if (done) return;\n done = true;\n stream.destroy();\n resolve(value);\n };\n const verify = (line: Buffer): string | null => {\n try {\n const hit = findInLine(provider, JSON.parse(line.toString(\"utf8\")), needle);\n return hit === null ? null : snippetAround(hit, needle);\n } catch {\n return null;\n }\n };\n /** Search `block` (complete lines only); the first verified hit, else null. */\n const searchBlock = (block: Buffer): string | null => {\n if (!ascii) {\n for (const line of block.toString(\"utf8\").split(\"\\n\")) {\n if (line.toLowerCase().includes(raw)) {\n const hit = verify(Buffer.from(line, \"utf8\"));\n if (hit !== null) return hit;\n }\n }\n return null;\n }\n const lower = block.toString(\"latin1\").toLowerCase();\n let from = 0;\n for (;;) {\n const at = lower.indexOf(raw, from);\n if (at < 0) return null;\n const start = block.lastIndexOf(10, at) + 1;\n let end = block.indexOf(10, at);\n if (end < 0) end = block.length;\n const hit = verify(block.subarray(start, end));\n if (hit !== null) return hit;\n from = end + 1;\n }\n };\n stream.on(\"data\", (chunk) => {\n const data = carry.length ? Buffer.concat([carry, chunk as Buffer]) : (chunk as Buffer);\n const lastNewline = data.lastIndexOf(10);\n if (lastNewline < 0) {\n carry = data;\n return;\n }\n carry = Buffer.from(data.subarray(lastNewline + 1));\n const hit = searchBlock(data.subarray(0, lastNewline));\n if (hit !== null) return finish(hit);\n // A single file never overruns the whole search's budget.\n if (Date.now() > deadline) finish(TIMED_OUT);\n });\n stream.on(\"end\", () => finish(carry.length ? searchBlock(carry) : null));\n stream.on(\"error\", () => finish(null));\n });\n}\n\n/** The file list, reused briefly: a search typed letter by letter should not stat 9,000 files each time. */\nlet listed: { at: number; homes: ProviderHomes; files: FileCandidate[] } | null = null;\nasync function sessionFiles(homes: ProviderHomes): Promise<FileCandidate[]> {\n if (listed && listed.homes === homes && Date.now() - listed.at < 20_000) return listed.files;\n const files = await listSessionFiles(homes);\n listed = { at: Date.now(), homes, files };\n return files;\n}\n\nexport async function searchLocalChats(query: string, options: SearchOptions = {}): Promise<ChatSearchResult> {\n const needle = query.replace(/\\s+/g, \" \").trim().toLowerCase();\n const homes = options.homes ?? defaultProviderHomes();\n const files: FileCandidate[] = await sessionFiles(homes);\n const cursor = Math.max(0, Math.min(options.cursor ?? 0, files.length));\n if (needle.length < 2) return { query, hits: [], scanned: 0, total: files.length, nextCursor: null };\n\n const raw = JSON.stringify(needle).slice(1, -1);\n const limit = Math.max(1, Math.min(options.limit ?? 30, 100));\n const deadline = Date.now() + (options.budgetMs ?? 3500);\n const names = await readCodexIndex(homes.codexIndex);\n const hits: ChatSearchHit[] = [];\n\n let i = cursor;\n for (; i < files.length && hits.length < limit && Date.now() < deadline; i += 1) {\n const candidate = files[i] as FileCandidate;\n const named = candidate.provider === \"codex\" ? names.get(candidate.id) : undefined;\n const nameHit = named !== undefined && named.toLowerCase().includes(needle);\n const scanned = nameHit ? null : await scanFile(candidate.provider, candidate.file, needle, raw, deadline);\n // A file cut off by the budget is NOT counted as read: the cursor resumes at it.\n // (Unless it is the page's first file — a file too big for one budget is\n // skipped rather than stalling every page on it.)\n if (scanned === TIMED_OUT) {\n if (i === cursor) i += 1;\n break;\n }\n const snippet = scanned;\n if (!nameHit && snippet === null) continue;\n const described = await describeSessionFile(candidate, names);\n if (!described) continue; // sub-agent and hook-only files are not chats\n hits.push({\n provider: described.provider,\n providerSessionId: described.providerSessionId,\n title: described.title,\n cwd: described.cwd,\n updatedAt: described.updatedAt,\n where: nameHit || described.title.toLowerCase().includes(needle) ? \"title\" : \"content\",\n snippet,\n });\n }\n return {\n query,\n hits,\n scanned: i - cursor,\n total: files.length,\n nextCursor: i < files.length ? i : null,\n };\n}\n","/**\n * The small local index: which sessions were driven from here and their runs,\n * so the list survives a restart. Transcripts are NEVER copied here — they stay\n * in the providers' own files. One JSON file, written atomically.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { CodingSession, RunRecord } from \"../types\";\n\ninterface IndexFile {\n version: 1;\n sessions: CodingSession[];\n runs: RunRecord[];\n}\n\nconst MAX_RUNS = 2000;\n\nexport interface Identity {\n companyId: string;\n agentId: string;\n}\n\nexport class RunIndex {\n private data: IndexFile = { version: 1, sessions: [], runs: [] };\n private writing: Promise<void> = Promise.resolve();\n\n constructor(private readonly dir: string) {}\n\n get file(): string {\n return path.join(this.dir, \"index.json\");\n }\n\n async load(): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true });\n try {\n const parsed = JSON.parse(await fs.readFile(this.file, \"utf8\")) as Partial<IndexFile>;\n this.data = {\n version: 1,\n sessions: Array.isArray(parsed.sessions) ? parsed.sessions : [],\n runs: Array.isArray(parsed.runs) ? parsed.runs : [],\n };\n } catch {\n this.data = { version: 1, sessions: [], runs: [] };\n }\n }\n\n sessions(): CodingSession[] {\n return [...this.data.sessions].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));\n }\n\n session(id: string): CodingSession | null {\n return (\n this.data.sessions.find((s) => s.id === id) ??\n this.data.sessions.find((s) => s.providerSessionId === id) ??\n null\n );\n }\n\n runs(sessionId: string): RunRecord[] {\n return this.data.runs.filter((r) => r.sessionId === sessionId);\n }\n\n run(runId: string): RunRecord | null {\n return this.data.runs.find((r) => r.runId === runId) ?? null;\n }\n\n allRuns(): RunRecord[] {\n return this.data.runs;\n }\n\n putSession(session: CodingSession): void {\n const at = this.data.sessions.findIndex((s) => s.id === session.id);\n if (at >= 0) this.data.sessions[at] = session;\n else this.data.sessions.push(session);\n this.persist();\n }\n\n putRun(run: RunRecord): void {\n const at = this.data.runs.findIndex((r) => r.runId === run.runId);\n if (at >= 0) this.data.runs[at] = run;\n else this.data.runs.push(run);\n if (this.data.runs.length > MAX_RUNS) this.data.runs.splice(0, this.data.runs.length - MAX_RUNS);\n this.persist();\n }\n\n /** Serialize writes; each writes the whole index to a temp file, then renames. */\n private persist(): void {\n const snapshot = JSON.stringify(this.data, null, 1);\n this.writing = this.writing.then(async () => {\n const tmp = `${this.file}.${randomUUID()}.tmp`;\n await fs.writeFile(tmp, snapshot, { mode: 0o600 });\n await fs.rename(tmp, this.file);\n }).catch(() => {\n /* the next write retries with the full index */\n });\n }\n\n async flush(): Promise<void> {\n await this.writing;\n }\n\n /** A stable Paperclip agent/company identity for this install, so the\n * driver's scratch state is reused rather than growing per run. */\n async identity(): Promise<Identity> {\n const file = path.join(this.dir, \"identity.json\");\n try {\n const parsed = JSON.parse(await fs.readFile(file, \"utf8\")) as Partial<Identity>;\n if (typeof parsed.companyId === \"string\" && typeof parsed.agentId === \"string\") {\n return { companyId: parsed.companyId, agentId: parsed.agentId };\n }\n } catch {\n /* first run */\n }\n const identity = { companyId: randomUUID(), agentId: randomUUID() };\n await fs.writeFile(file, JSON.stringify(identity), { mode: 0o600 });\n return identity;\n }\n}\n","/**\n * The person's OWN defaults — the model and effort their Claude Code and Codex\n * use when nothing is picked. The Claude driver otherwise forces its built-in\n * default (`claude-opus-5`) onto every run, silently overriding the model the\n * person chose in Claude Code itself; the engine passes theirs instead.\n * Read-only: these files are never written.\n */\n\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nimport type { CodingProvider } from \"../types\";\n\nexport interface UserDefaults {\n model: string | null;\n effort: string | null;\n}\n\nasync function readJson(file: string): Promise<Record<string, unknown> | null> {\n try {\n const parsed = JSON.parse(await fs.readFile(file, \"utf8\")) as unknown;\n return typeof parsed === \"object\" && parsed !== null ? (parsed as Record<string, unknown>) : null;\n } catch {\n return null;\n }\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value.trim() : null;\n}\n\n/** Claude Code's precedence: the folder's local settings, its shared settings, then the person's. */\nexport async function claudeDefaults(cwd: string | null, home = os.homedir()): Promise<UserDefaults> {\n const files = [\n ...(cwd ? [path.join(cwd, \".claude\", \"settings.local.json\"), path.join(cwd, \".claude\", \"settings.json\")] : []),\n path.join(home, \".claude\", \"settings.json\"),\n ];\n let model: string | null = null;\n let effort: string | null = null;\n for (const file of files) {\n const settings = await readJson(file);\n if (!settings) continue;\n model ??= str(settings.model);\n effort ??= str(settings.effortLevel);\n if (model && effort) break;\n }\n return { model, effort };\n}\n\n/** Codex's top-level `model` and `model_reasoning_effort` from `~/.codex/config.toml`. */\nexport async function codexDefaults(home = os.homedir()): Promise<UserDefaults> {\n let text: string;\n try {\n text = await fs.readFile(path.join(home, \".codex\", \"config.toml\"), \"utf8\");\n } catch {\n return { model: null, effort: null };\n }\n const values: Record<string, string> = {};\n for (const raw of text.split(\"\\n\")) {\n const line = raw.trim();\n if (line.startsWith(\"[\")) break; // top-level keys only\n const match = /^([A-Za-z0-9_]+)\\s*=\\s*\"([^\"]*)\"/.exec(line);\n if (match?.[1] && match[2] !== undefined) values[match[1]] = match[2];\n }\n return { model: str(values.model), effort: str(values.model_reasoning_effort) };\n}\n\nexport function userDefaults(provider: CodingProvider, cwd: string | null): Promise<UserDefaults> {\n return provider === \"claude\" ? claudeDefaults(cwd) : codexDefaults();\n}\n\n/** Effort levels each CLI accepts, lowest first (`claude --help`, the Codex driver's docs). */\nexport const EFFORT_LEVELS: Record<CodingProvider, string[]> = {\n claude: [\"low\", \"medium\", \"high\", \"xhigh\", \"max\"],\n codex: [\"low\", \"medium\", \"high\", \"xhigh\"],\n};\n","/**\n * THE HOST BRIDGE — the one seam between the engine and any transport.\n *\n * The WebSocket host below is one adapter; a desktop app replaces it with IPC\n * by calling `handle()` and `subscribe()` from its own message channel. The UI\n * talks to a `CodingSessionsTransport` and never learns which one it got, and\n * the engine never learns there is a transport at all.\n */\n\nimport type { CodingEvent, CodingSessionsApi, CodingSessionsMethod } from \"../types\";\n\n/** Every method a client may call — an allowlist, so a crafted message cannot\n * reach `dispose` or anything else on the engine object. */\nexport const BRIDGE_METHODS: readonly CodingSessionsMethod[] = [\n \"providers\",\n \"discoverSessions\",\n \"recentFolders\",\n \"listSessions\",\n \"listRuns\",\n \"history\",\n \"readTranscript\",\n \"readRawTranscript\",\n \"sessionActivity\",\n \"checkFolder\",\n \"createFolder\",\n \"start\",\n \"takeover\",\n \"send\",\n \"stop\",\n \"chatPreferences\",\n \"setChatPreference\",\n \"searchChats\",\n \"openFolder\",\n \"setSessionOptions\",\n];\n\nexport interface HostBridge {\n handle(method: string, args: unknown[]): Promise<unknown>;\n subscribe(listener: (event: CodingEvent) => void): () => void;\n}\n\nexport interface BridgeableEngine extends CodingSessionsApi {\n subscribe(listener: (event: CodingEvent) => void): () => void;\n}\n\nexport class BridgeError extends Error {\n constructor(\n message: string,\n readonly code: \"unknown_method\" | \"bad_arguments\" | \"failed\",\n ) {\n super(message);\n this.name = \"BridgeError\";\n }\n}\n\nexport function createHostBridge(engine: BridgeableEngine): HostBridge {\n return {\n async handle(method, args) {\n if (!(BRIDGE_METHODS as readonly string[]).includes(method)) {\n throw new BridgeError(`Unknown method \"${method}\".`, \"unknown_method\");\n }\n if (!Array.isArray(args)) throw new BridgeError(\"Arguments must be a list.\", \"bad_arguments\");\n const fn = engine[method as CodingSessionsMethod] as (...a: unknown[]) => Promise<unknown>;\n try {\n return await fn.apply(engine, args);\n } catch (error) {\n throw new BridgeError(error instanceof Error ? error.message : String(error), \"failed\");\n }\n },\n subscribe(listener) {\n return engine.subscribe(listener);\n },\n };\n}\n"],"mappings":"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","names":["existsSync","fs","path","fileURLToPath","execFile","randomUUID","fs","os","path","isObject","str","num","listed","os","path","fs","os","path","execFile","execFile","os","path","fs","fs","path","createReadStream","createReadStream","randomUUID","fs","path","fs","os","path","str","path","fs","os","randomUUID","options","run","execFile","moduleDir","path","fileURLToPath","existsSync","fs","url"]}
|