@jentrix/runner 0.5.11 → 0.5.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-QBB7WO4L.js +7 -0
- package/dist/{chunk-EZMRE63D.js.map → chunk-QBB7WO4L.js.map} +1 -1
- package/dist/{local-probes-24XPDSVY.js → local-probes-373TWNQP.js} +5 -2
- package/dist/local-probes-373TWNQP.js.map +7 -0
- package/dist/runner-cli.js +15 -7
- package/dist/runner-cli.js.map +2 -2
- package/dist/{session-host-EOS67U2J.js → session-host-X4B43PJJ.js} +8 -3
- package/dist/{session-host-EOS67U2J.js.map → session-host-X4B43PJJ.js.map} +2 -2
- package/dist/workflow-runner.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-EZMRE63D.js +0 -7
- package/dist/local-probes-24XPDSVY.js.map +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../lib/session-host.ts", "../lib/session-auth.ts", "../lib/session-bridge.ts", "../lib/session-events.ts", "../lib/session-usage.ts", "../lib/session-claude-transcript.ts", "../lib/session-claude-timing.ts", "../lib/session-codex-events.ts", "../lib/session-codex-hooks.ts", "../lib/session-redact.ts", "../lib/session-spool.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * M20.1 \u00A715 \u2014 the connected-session HOST: the runner-side orchestration that\n * launches (or drives) the interactive provider with capture running beside\n * it. Invoked by `stacks-runner session-run --plan-stdin`; the CLI (which may\n * not import provider SDKs \u2014 LRO-AC14) hands it a transient plan over stdin.\n *\n * Claude: the provider's own interactive UI runs untouched; a temp\n * hooks-settings file makes the SUPPORTED lifecycle hooks append their stdin\n * JSON to the session's hooks file via `stacks-runner session-hook`, giving\n * the bridge the TRUSTED `session_id` + `transcript_path` (AC17) and the\n * transcript tail to map. Hooks never carry credentials or transcript content\n * in argv.\n *\n * Codex: plugin watch mode consumes the supported lifecycle hook ledger for\n * one exact task id. `jentrix session codex` remains the SDK-driven terminal\n * fallback, with every `runStreamed` event mapped deterministically.\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport {\n appendFileSync,\n existsSync,\n mkdirSync,\n readFileSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline\";\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\n\nimport {\n createConfigBearerSource,\n isUnauthorizedishError,\n staticBearerSource,\n type SessionBearerSource,\n} from \"./session-auth.js\";\nimport { SessionBridge, type SessionCallTool } from \"./session-bridge.js\";\nimport {\n mapClaudeTranscriptLine,\n openingPromptOf,\n} from \"./session-claude-transcript.js\";\nimport { ClaudeTimingTracker } from \"./session-claude-timing.js\";\nimport { mapCodexThreadEvent } from \"./session-codex-events.js\";\nimport { mapCodexHook } from \"./session-codex-hooks.js\";\nimport { createSessionRedactor } from \"./session-redact.js\";\nimport { readHookLines } from \"./session-hook-log.js\";\nimport {\n markHostExited,\n markHostFlushed,\n markHostTranscript,\n SessionSpool,\n writeHostMarker,\n} from \"./session-spool.js\";\nimport { RUNNER_VERSION } from \"./version.js\";\n\nexport interface SessionRunPlan {\n protocolVersion: 1;\n sessionId: string;\n provider: \"claude\" | \"codex\";\n jentrixBaseUrl: string;\n mcpUrl: string;\n /** Transient human credential \u2014 held in memory only, never persisted. */\n bearer: string;\n /**\n * The CLI config file the bearer's OAuth rotations persist to. When set,\n * the host resolves its bearer through it (and can rotate) instead of\n * holding the spawn-time snapshot \u2014 a `tmo_` token is revoked the moment\n * any concurrent CLI call rotates, which is how a live capture-off host\n * lost its whole usage rollup (2026-08-08). Absent = PAT/static behavior.\n */\n configPath?: string | null;\n repoRoot: string;\n installationId: string;\n /**\n * \"launch\" (default) starts the provider; \"watch\" attaches BESIDE an\n * already-running provider session (the /jentrix-connect flow): no spawn,\n * hook + transcript polling only, ends on the SessionEnd hook.\n */\n mode?: \"launch\" | \"watch\";\n /** Watch mode: exact provider task id used to filter a shared hook ledger. */\n providerSessionId?: string | null;\n /** Watch mode: provider-global lifecycle ledger directory. */\n hookDir?: string | null;\n resumeProviderSessionId?: string | null;\n /** Watch mode: the trusted transcript path from the lifecycle hook. */\n transcriptPath?: string | null;\n /**\n * Watch mode: capture begins AT the attach point by default (\u00A715.2 \u2014 the\n * tail starts at the transcript's current end); true reads from byte 0 so\n * prior VISIBLE history enters the trace (`--import-history`).\n */\n importHistory?: boolean;\n /**\n * Jentrix MVP (stacks-mvp PRD \u00A76): false = TRACE capture OFF \u2014 the host\n * still heartbeats and aggregates provider usage receipts, but spools and\n * uploads NO trace parts and submits NO manifest. Default true (the 0.4.x\n * behavior); `jentrix align` sets false unless --capture re-enables it.\n */\n captureTrace?: boolean;\n executablePath?: string | null;\n spoolRoot?: string | null;\n}\n\nexport function defaultSpoolRoot(): string {\n return join(homedir(), \".config\", \"stacks\", \"session-spool\");\n}\n\n/** Config-following bearer when the plan names the CLI config; static else. */\nfunction bearerSourceOf(\n plan: Pick<SessionRunPlan, \"bearer\" | \"configPath\">,\n log: (line: string) => void,\n): SessionBearerSource {\n return plan.configPath\n ? createConfigBearerSource({\n configPath: plan.configPath,\n fallback: plan.bearer,\n log,\n })\n : staticBearerSource(plan.bearer);\n}\n\n/**\n * One-shot MCP call carrying the bearer AND the session-correlation header.\n * The bearer comes from a source (not a snapshot): a `tmo_` access token is\n * revoked the moment any concurrent CLI call rotates it, so each attempt\n * resolves the CURRENT bearer, and one unauthorized failure gets one retry\n * after asking the source to refresh (2026-08-08 capture-off finding).\n */\nexport function sessionCallTool(\n mcpUrl: string,\n bearerSource: SessionBearerSource,\n sessionId: string,\n): SessionCallTool {\n const attempt = async (\n bearer: string,\n name: string,\n args: Record<string, unknown>,\n ): Promise<Record<string, unknown>> => {\n const transport = new StreamableHTTPClientTransport(new URL(mcpUrl), {\n requestInit: {\n headers: {\n Authorization: `Bearer ${bearer}`,\n \"X-Stacks-Session-Id\": sessionId,\n },\n },\n });\n const client = new Client({\n name: \"stacks-session-host\",\n version: RUNNER_VERSION,\n });\n await client.connect(transport, { timeout: 60_000 });\n try {\n const res = await client.callTool({ name, arguments: args }, undefined, {\n timeout: 60_000,\n });\n if (res.isError) {\n const text =\n Array.isArray(res.content) &&\n res.content[0] &&\n \"text\" in res.content[0]\n ? (res.content[0] as { text: string }).text\n : JSON.stringify(res.content);\n throw new Error(`${name} failed: ${text}`);\n }\n return (res.structuredContent ?? {}) as Record<string, unknown>;\n } finally {\n await client.close();\n }\n };\n return async (name, args) => {\n const bearer = bearerSource.get();\n try {\n return await attempt(bearer, name, args);\n } catch (error) {\n if (!isUnauthorizedishError(error)) throw error;\n const next = await bearerSource.refresh(bearer);\n if (!next || next === bearer) throw error;\n return attempt(next, name, args);\n }\n };\n}\n\n// The hook log moved to its own module so the `session-hook` verb \u2014 a Claude\n// Code lifecycle hook, on the operator's critical path \u2014 can append a line\n// without loading this file's MCP client and transports (P5). Re-exported here\n// so every existing importer is unchanged; `readHookLines` is also imported\n// above, because the watch loop below calls it.\nexport {\n appendHookEvent,\n readHookLines,\n safeParse,\n type HookLine,\n} from \"./session-hook-log.js\";\n\n/** The Claude hooks-settings document (temp file, referenced by --settings). */\nexport function claudeHookSettings(\n runnerBin: string,\n sessionDir: string,\n): Record<string, unknown> {\n const hook = (event: string) => [\n {\n hooks: [\n {\n type: \"command\",\n // argv carries only the runner binary, the session DIRECTORY, and\n // the event name \u2014 never credentials or transcript content (\u00A715.1).\n command: `${runnerBin} session-hook --dir ${JSON.stringify(sessionDir)} --event ${event}`,\n },\n ],\n },\n ];\n return {\n hooks: {\n SessionStart: hook(\"SessionStart\"),\n UserPromptSubmit: hook(\"UserPromptSubmit\"),\n Stop: hook(\"Stop\"),\n SessionEnd: hook(\"SessionEnd\"),\n },\n };\n}\n\ninterface HostDeps {\n spawnImpl?: typeof spawn;\n fetchImpl?: typeof fetch;\n /** Injectable MCP caller (integration tests); default opens a transport. */\n callTool?: SessionCallTool;\n log?: (line: string) => void;\n}\n\nasync function endRepoState(repoRoot: string): Promise<{\n branch: string | null;\n head: string | null;\n dirty: boolean | null;\n}> {\n const run = (args: string[]) =>\n new Promise<{ code: number; stdout: string }>((resolve) => {\n const child = spawn(\"git\", args, { cwd: repoRoot });\n let stdout = \"\";\n child.stdout?.on(\"data\", (chunk: Buffer) => (stdout += String(chunk)));\n child.once(\"error\", () => resolve({ code: 1, stdout: \"\" }));\n child.once(\"exit\", (code) => resolve({ code: code ?? 1, stdout }));\n });\n const [branch, head, status] = await Promise.all([\n run([\"symbolic-ref\", \"--short\", \"-q\", \"HEAD\"]),\n run([\"rev-parse\", \"HEAD\"]),\n run([\"status\", \"--porcelain\"]),\n ]);\n return {\n branch: branch.code === 0 ? branch.stdout.trim() || null : null,\n head: head.code === 0 ? head.stdout.trim() || null : null,\n dirty: status.code === 0 ? status.stdout.trim().length > 0 : null,\n };\n}\n\n/**\n * Run a lifecycle-watched session. Claude launch/watch uses hooks plus its\n * supported transcript; Codex watch mode consumes only the trusted plugin\n * hook ledger. Returns non-zero while capture is pending (\u00A720).\n */\nexport async function runClaudeSessionHost(\n plan: SessionRunPlan,\n deps: HostDeps = {},\n): Promise<number> {\n const log = deps.log ?? ((line: string) => process.stderr.write(`${line}\\n`));\n const spoolRoot = plan.spoolRoot ?? defaultSpoolRoot();\n const spool = new SessionSpool(spoolRoot, plan.sessionId);\n const sessionDir = spool.directory;\n // AGE-929: local liveness marker \u2014 `jentrix session status` probes this pid.\n writeHostMarker(sessionDir, {\n pid: process.pid,\n provider: plan.provider,\n mode: plan.mode === \"watch\" ? \"watch\" : \"launch\",\n captureTrace: plan.captureTrace !== false,\n // F1/P3: the transcript this host is bound to \u2014 what a compaction hook\n // matches on to find its session without guessing from cwd.\n ...(plan.transcriptPath ? { transcriptPath: plan.transcriptPath } : {}),\n });\n const traceCapture = plan.captureTrace !== false;\n const bearerSource = bearerSourceOf(plan, log);\n const bridge = new SessionBridge({\n jentrixBaseUrl: plan.jentrixBaseUrl,\n bearer: () => bearerSource.get(),\n onUnauthorized: (failed) => bearerSource.refresh(failed),\n sessionId: plan.sessionId,\n provider: plan.provider,\n spool,\n redactor: createSessionRedactor({ homedir: homedir() }),\n callTool:\n deps.callTool ??\n sessionCallTool(plan.mcpUrl, bearerSource, plan.sessionId),\n fetchImpl: deps.fetchImpl,\n traceCapture,\n log,\n });\n bridge.recordCapabilities(\n plan.provider === \"codex\"\n ? {\n provider: \"codex\",\n providerVersion: null,\n observable: [\n \"session\",\n \"user_message\",\n \"assistant_message\",\n \"tool_call\",\n \"tool_result\",\n ],\n notObservable: [\"command\", \"file_change\", \"plan\", \"usage\", \"error\"],\n }\n : {\n provider: \"claude\",\n providerVersion: null,\n observable: [\n \"session\",\n \"user_message\",\n \"assistant_message\",\n \"tool_call\",\n \"tool_result\",\n \"usage\",\n \"error\",\n ],\n notObservable: [\"command\", \"file_change\", \"plan\"],\n },\n );\n bridge.startObserving();\n\n const watch = plan.mode === \"watch\";\n let child: ChildProcess | null = null;\n if (!watch) {\n const runnerBin = process.argv[1] ?? \"stacks-runner\";\n const settingsPath = join(sessionDir, \"claude-hooks.json\");\n writeFileSync(\n settingsPath,\n JSON.stringify(claudeHookSettings(runnerBin, sessionDir), null, 2),\n { mode: 0o600 },\n );\n const args = [\"--settings\", settingsPath];\n if (plan.resumeProviderSessionId) {\n args.push(\"--resume\", plan.resumeProviderSessionId);\n }\n child = (deps.spawnImpl ?? spawn)(plan.executablePath ?? \"claude\", args, {\n cwd: plan.repoRoot,\n stdio: \"inherit\",\n });\n }\n\n const hookDir = plan.hookDir ?? sessionDir;\n let hookOffset = 0;\n if (watch && plan.hookDir && !plan.importHistory) {\n try {\n hookOffset = readFileSync(join(hookDir, \"hooks.ndjson\"), \"utf8\").length;\n } catch {\n // The first post-attach hook creates the ledger.\n }\n }\n let transcriptPath: string | null = watch\n ? (plan.transcriptPath ?? null)\n : null;\n let transcriptOffset = 0;\n // control-room AC3.7 \u2014 one tracker per host, pairing observed transcript\n // timestamps into the provider-turn and tool intervals the usage aggregator\n // sums. Held here (not in the bridge) so the pairing rule stays a pure,\n // separately-tested module.\n const timing = new ClaudeTimingTracker();\n // AGE-957: a transcript path that never appears means the host observes\n // NOTHING (no events, no usage receipts) \u2014 track it, warn once after the\n // grace window, and stamp host.json so `session status` can say so.\n let transcriptSeen = false;\n let transcriptWarned = false;\n const hostStartedMs = Date.now();\n const noteTranscriptSeen = () => {\n if (!transcriptSeen) {\n transcriptSeen = true;\n markHostTranscript(sessionDir, true);\n }\n };\n if (watch && transcriptPath && !plan.importHistory) {\n // Capture begins at attachment (\u00A715.2): start the tail at the CURRENT\n // end of the transcript. `--import-history` reads from byte 0 instead.\n try {\n transcriptOffset = statSync(transcriptPath).size;\n noteTranscriptSeen();\n } catch {\n // no transcript yet \u2014 everything it gains is post-attach anyway\n }\n }\n let bound = watch; // watch mode attaches an ALREADY-bound provider session\n let sessionEnded = false;\n let lastPeriodicFlushAt = 0;\n // Taxonomy AC5.1 (D9) \u2014 the opening-prompt request `jentrix align` drops at\n // align-confirm. Attempted at most every 30s; filed EXACTLY once (the\n // filed-marker survives restarts, and the server dedupes by checksum\n // besides). Works with TRACE capture off \u2014 this never touches the spool.\n let lastPromptAttemptAt = 0;\n const promptRedactor = createSessionRedactor({ homedir: homedir() });\n const fileOpeningPrompt = async (): Promise<void> => {\n const requestPath = join(sessionDir, \"prompt-request.json\");\n const filedPath = join(sessionDir, \"prompt-filed.json\");\n if (!existsSync(requestPath)) return;\n if (existsSync(filedPath)) {\n try {\n unlinkSync(requestPath);\n } catch {\n // best-effort \u2014 the filed marker already guards re-filing\n }\n return;\n }\n if (!transcriptPath || plan.provider !== \"claude\") return;\n const nowMs = Date.now();\n if (nowMs - lastPromptAttemptAt < 30_000) return;\n lastPromptAttemptAt = nowMs;\n let prompt: string | null = null;\n try {\n prompt = openingPromptOf(readFileSync(transcriptPath, \"utf8\"));\n } catch {\n return; // absent transcript \u2192 no artifact, no error (D9); retry later\n }\n if (!prompt) return; // no visible user prompt yet \u2014 the transcript grows\n // Redact FIRST (a marker split at the cap is harmless; a secret split at\n // the cap is not), then bound to D9's 64 KB.\n let body = promptRedactor.text(prompt);\n while (Buffer.byteLength(body, \"utf8\") > 64 * 1024) {\n body = body.slice(0, -1024);\n }\n const post = async (bearer: string) =>\n (deps.fetchImpl ?? fetch)(\n new URL(\n `/api/agent-sessions/${plan.sessionId}/artifacts`,\n plan.jentrixBaseUrl,\n ),\n {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${bearer}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n kind: \"prompt\",\n title: \"Opening prompt\",\n body,\n }),\n },\n );\n try {\n let response = await post(bearerSource.get());\n if (response.status === 401) {\n const next = await bearerSource.refresh(bearerSource.get());\n if (next) response = await post(next);\n }\n if (!response.ok) return; // retried on a later poll; never an error\n const payload = (await response.json().catch(() => ({}))) as {\n artifactId?: string;\n deduped?: boolean;\n };\n writeFileSync(\n filedPath,\n JSON.stringify({\n artifactId: payload.artifactId ?? null,\n filedAt: new Date().toISOString(),\n }),\n { mode: 0o600 },\n );\n try {\n unlinkSync(requestPath);\n } catch {\n // the filed marker guards re-filing\n }\n log(\n `Opening prompt filed as artifact ${payload.artifactId ?? \"(unknown)\"}${payload.deduped ? \" (already stored)\" : \"\"}`,\n );\n } catch {\n // network loss: retry on a later poll \u2014 a mint-class convenience must\n // never cost the session anything\n }\n };\n\n const poll = async (): Promise<void> => {\n // `jentrix session end` hands a live host the end request through the\n // spool dir \u2014 the host owns the manifest, so the CLI defers to it\n // instead of racing a direct server-side completion (F-4 follow-through).\n const endRequestPath = join(sessionDir, \"end-request.json\");\n if (!sessionEnded && existsSync(endRequestPath)) {\n try {\n unlinkSync(endRequestPath);\n } catch {\n // best-effort \u2014 a leftover marker must not end a future resume\n }\n sessionEnded = true;\n }\n const { lines, offset } = readHookLines(hookDir, hookOffset);\n hookOffset = offset;\n for (const line of lines) {\n if (\n plan.provider === \"codex\" &&\n line.payload.session_id !== plan.providerSessionId\n ) {\n continue;\n }\n if (plan.provider === \"codex\") {\n const mapped = mapCodexHook(line.event, line.payload);\n if (mapped.modelId) bridge.observeModel(mapped.modelId);\n for (const event of mapped.events) bridge.record(event);\n }\n if (line.event === \"SessionStart\" && line.payload.session_id && !bound) {\n bound = true;\n transcriptPath = line.payload.transcript_path ?? null;\n try {\n // Trusted lifecycle context \u2192 late provider-ID binding (AC17).\n await bridge.tool(\"attach_agent_session\", {\n sessionId: plan.sessionId,\n provider: plan.provider,\n connection: { kind: \"local\", installationId: plan.installationId },\n providerSessionId: line.payload.session_id,\n idempotencyKey: `bind:${plan.sessionId}:${line.payload.session_id}`,\n });\n log(\n `Capture connected \u00B7 provider session ${line.payload.session_id}`,\n );\n } catch (error) {\n log(\n `capture: provider binding failed (${error instanceof Error ? error.message : \"unknown\"})`,\n );\n }\n }\n if (line.event === \"SessionEnd\" || line.event === \"Stop\") {\n await bridge.flushParts().catch(() => undefined);\n markHostFlushed(sessionDir, bridge.ackedPartCount);\n }\n if (line.event === \"SessionEnd\") sessionEnded = true;\n }\n if (plan.provider === \"claude\" && transcriptPath) {\n try {\n const size = statSync(transcriptPath).size;\n noteTranscriptSeen();\n if (size > transcriptOffset) {\n // BYTE offsets throughout \u2014 a character-indexed slice misaligns\n // the tail on any multibyte content.\n const buffer = readFileSync(transcriptPath);\n const body = buffer.subarray(transcriptOffset).toString(\"utf8\");\n transcriptOffset = buffer.byteLength;\n for (const rawLine of body.split(\"\\n\").filter(Boolean)) {\n const mapped = mapClaudeTranscriptLine(rawLine);\n if (mapped.unrecognized) bridge.countUnrecognized();\n if (mapped.modelId) bridge.observeModel(mapped.modelId);\n if (mapped.timing) {\n // control-room AC3.7: pair observed timestamps into the\n // intervals the usage aggregator has always known how to sum.\n for (const interval of timing.observe(mapped.timing)) {\n bridge.recordInterval(interval);\n }\n }\n for (const event of mapped.events) bridge.record(event);\n }\n }\n } catch {\n // transcript may rotate; next poll retries. But NEVER having seen it\n // is a different animal (AGE-957): warn once + stamp the marker so\n // the silence is visible instead of reading as a healthy host.\n if (\n !transcriptSeen &&\n !transcriptWarned &&\n Date.now() - hostStartedMs > 60_000\n ) {\n transcriptWarned = true;\n markHostTranscript(sessionDir, false);\n log(\n `capture: transcript never appeared at ${transcriptPath} \u2014 observing no events; usage will be unavailable. End the session and re-align to rebind.`,\n );\n }\n }\n }\n // TPM Slice 2 (AC2.5): `jentrix align --task <other>` asks the live host\n // to flush a usage receipt onto the OLD alignment before the server\n // closes its interval \u2014 the end-request.json idiom, acked by DELETING\n // the marker only after the server acknowledged the beat. Runs AFTER the\n // transcript tail above so the flush carries everything observed so far.\n // A failed post keeps the marker; the CLI's bounded wait times out and\n // discloses that the smear stays bounded by one beat window.\n const flushRequestPath = join(sessionDir, \"flush-request.json\");\n if (existsSync(flushRequestPath)) {\n const acked = await bridge.flushUsageNow().catch(() => false);\n if (acked) {\n try {\n unlinkSync(flushRequestPath);\n } catch {\n // unremovable marker: the CLI times out and proceeds \u2014 harmless\n }\n }\n }\n await fileOpeningPrompt();\n // Detached watch capture uploads as it goes (bounded to one flush per\n // 15s window) so `session end` finds little left to converge; the spool\n // advances past acked slots, so a flushed part number is never reused.\n const nowMs = Date.now();\n if (!sessionEnded && nowMs - lastPeriodicFlushAt >= 15_000) {\n lastPeriodicFlushAt = nowMs;\n await bridge.flushParts().catch(() => undefined);\n // Stamp the ack state so `session status` can tell an empty spool\n // (everything acknowledged) from a spool that never captured.\n markHostFlushed(sessionDir, bridge.ackedPartCount);\n }\n await bridge.maybeHeartbeat();\n };\n\n const timer = setInterval(() => {\n void poll();\n }, 2_000);\n\n const exitCode = await (watch\n ? // Watch mode: live capture beside the operator's own provider process.\n // End signals: the SessionEnd lifecycle hook, an end request from\n // `jentrix session end`, or a heartbeat 409 (session terminal\n // server-side \u2014 the out-of-band case the hooks can never deliver).\n new Promise<number>((resolve) => {\n const check = setInterval(() => {\n if (sessionEnded || bridge.sessionInactive) {\n clearInterval(check);\n resolve(0);\n }\n }, 1_000);\n })\n : new Promise<number>((resolve) => {\n child!.once(\"error\", () => resolve(1));\n child!.once(\"exit\", (code, signal) =>\n resolve(code ?? (signal ? 130 : 0)),\n );\n }));\n clearInterval(timer);\n await poll().catch(() => undefined);\n await bridge.flushParts().catch(() => undefined);\n // control-room AC3.7: a tool that never returned is a NAMED gap, not a\n // silently shorter total \u2014 the aggregator degrades coverage to PARTIAL on\n // an interval with no terminal event, which is the honest reading.\n for (const id of timing.unclosedToolIds()) {\n bridge.recordUnclosedInterval(\"tool\", id);\n }\n\n const end = await endRepoState(plan.repoRoot);\n const result = await bridge\n .complete({\n outcome: exitCode === 0 ? \"COMPLETED\" : \"INTERRUPTED\",\n end,\n })\n .catch((error) => {\n log(\n `capture: completion failed (${error instanceof Error ? error.message : \"unknown\"}) \u2014 spool retained for retry`,\n );\n return null;\n });\n if (!result) {\n markHostExited(sessionDir, 1);\n return 1;\n }\n // AGE-649: the closing output is named in the same line as the summary, so an\n // operator can see whether it was stored without opening the session page.\n const output = result.finalResponseArtifactId\n ? ` \u00B7 output ${result.finalResponseArtifactId}`\n : \" \u00B7 output not observed\";\n log(\n !traceCapture\n ? `Session ${plan.sessionId} closed \u00B7 TRACE capture off (typed artifacts only) \u00B7 summary ${result.summaryArtifactId ?? \"\u2014\"}${output}`\n : result.captureComplete\n ? `Session ${plan.sessionId} closed \u00B7 capture complete \u00B7 summary ${result.summaryArtifactId ?? \"\u2014\"}${output}`\n : `Session ${plan.sessionId} closed \u00B7 CAPTURE PENDING (${result.pendingParts} part(s)) \u2014 re-run \\`jentrix session status ${plan.sessionId}\\``,\n );\n // Capture-off is a deliberate mode, not capture debt \u2014 never exit non-zero\n // for the transcript that was intentionally not recorded.\n const finalCode =\n result.captureComplete || !traceCapture ? exitCode : exitCode || 1;\n markHostExited(sessionDir, finalCode);\n return finalCode;\n}\n\n/**\n * Run a CODEX session: a persistent SDK Thread driven as a terminal REPL \u2014\n * `runStreamed` per turn, structured events mapped deterministically, resume\n * through `resumeThread` (\u00A715.2).\n */\nexport async function runCodexSessionHost(\n plan: SessionRunPlan,\n deps: HostDeps = {},\n): Promise<number> {\n const log = deps.log ?? ((line: string) => process.stderr.write(`${line}\\n`));\n const spoolRoot = plan.spoolRoot ?? defaultSpoolRoot();\n const spool = new SessionSpool(spoolRoot, plan.sessionId);\n // AGE-929: local liveness marker \u2014 `jentrix session status` probes this pid.\n writeHostMarker(spool.directory, {\n pid: process.pid,\n provider: \"codex\",\n mode: \"launch\",\n });\n const codexBearerSource = bearerSourceOf(plan, log);\n const bridge = new SessionBridge({\n jentrixBaseUrl: plan.jentrixBaseUrl,\n bearer: () => codexBearerSource.get(),\n onUnauthorized: (failed) => codexBearerSource.refresh(failed),\n sessionId: plan.sessionId,\n provider: \"codex\",\n spool,\n redactor: createSessionRedactor({ homedir: homedir() }),\n callTool: sessionCallTool(plan.mcpUrl, codexBearerSource, plan.sessionId),\n fetchImpl: deps.fetchImpl,\n log,\n });\n bridge.recordCapabilities({\n provider: \"codex\",\n providerVersion: null,\n observable: [\n \"session\",\n \"assistant_message\",\n \"tool_call\",\n \"command\",\n \"file_change\",\n \"usage\",\n \"error\",\n ],\n notObservable: [\"plan\", \"tool_result\"],\n });\n bridge.startObserving();\n\n // Provider SDK loaded lazily so probe/setup paths never touch it.\n const { Codex } = (await import(\"@openai/codex-sdk\")) as {\n Codex: new (opts?: Record<string, unknown>) => {\n startThread(opts?: Record<string, unknown>): CodexThreadLike;\n resumeThread(id: string, opts?: Record<string, unknown>): CodexThreadLike;\n };\n };\n interface CodexThreadLike {\n id?: string | null;\n runStreamed(\n prompt: string,\n ): Promise<{ events: AsyncIterable<Record<string, unknown>> }>;\n }\n const codex = new Codex(\n plan.executablePath ? { codexPathOverride: plan.executablePath } : {},\n );\n const thread = plan.resumeProviderSessionId\n ? codex.resumeThread(plan.resumeProviderSessionId, {\n workingDirectory: plan.repoRoot,\n skipGitRepoCheck: true,\n })\n : codex.startThread({\n workingDirectory: plan.repoRoot,\n skipGitRepoCheck: true,\n });\n\n let bound = Boolean(plan.resumeProviderSessionId);\n // TPM Slice 2 (AC2.4): the model the runtime last named via turn_context;\n // null until one is observed \u2014 Codex receipts then stay in the null-model\n // bucket rather than carrying a guess.\n let currentModel: string | null = null;\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n const ask = (prompt: string) =>\n new Promise<string | null>((resolve) => {\n rl.question(prompt, (answer) => resolve(answer));\n rl.once(\"close\", () => resolve(null));\n });\n\n log(\"Codex connected session \u2014 empty line or Ctrl-D ends the session.\");\n let outcome: \"COMPLETED\" | \"INTERRUPTED\" = \"COMPLETED\";\n try {\n for (;;) {\n const input = await ask(\"codex> \");\n if (input === null || input.trim() === \"\") break;\n const turnId = `turn:${Date.now()}`;\n bridge.markTurnStarted(turnId);\n bridge.record({ kind: \"user_message\", payload: { text: input } });\n try {\n const { events } = await thread.runStreamed(input);\n for await (const raw of events) {\n const mapped = mapCodexThreadEvent(raw);\n if (mapped.unrecognized) bridge.countUnrecognized();\n // TPM Slice 2 (AC2.4): a turn_context names the model for the\n // turns that follow \u2014 observed, and stamped onto their receipts.\n if (mapped.modelId) {\n currentModel = mapped.modelId;\n bridge.observeModel(mapped.modelId);\n }\n if (mapped.threadId && !bound) {\n bound = true;\n try {\n await bridge.tool(\"attach_agent_session\", {\n sessionId: plan.sessionId,\n provider: \"codex\",\n connection: {\n kind: \"local\",\n installationId: plan.installationId,\n },\n providerSessionId: mapped.threadId,\n idempotencyKey: `bind:${plan.sessionId}:${mapped.threadId}`,\n });\n log(`Capture connected \u00B7 provider thread ${mapped.threadId}`);\n } catch (error) {\n log(\n `capture: provider binding failed (${error instanceof Error ? error.message : \"unknown\"})`,\n );\n }\n }\n if (mapped.event) {\n const recorded = bridge.record({\n ...mapped.event,\n at: new Date().toISOString(),\n payload:\n mapped.event.kind === \"usage\"\n ? {\n ...(mapped.event.payload as object),\n turnId,\n // TPM Slice 2 (AC2.4): the model the runtime last named\n // for this thread rides the receipt \u2014 absent when no\n // turn_context was ever observed (null-model bucket,\n // disclosed, never guessed).\n ...(currentModel ? { modelId: currentModel } : {}),\n }\n : mapped.event.payload,\n });\n if (\n recorded.kind === \"assistant_message\" &&\n typeof (recorded.payload as { text?: string })?.text === \"string\"\n ) {\n process.stdout.write(\n `${(recorded.payload as { text: string }).text}\\n`,\n );\n }\n }\n }\n } catch (error) {\n outcome = \"INTERRUPTED\";\n bridge.recordGap(\n `provider turn failed: ${error instanceof Error ? error.message : \"unknown\"}`,\n );\n log(\"codex turn failed \u2014 session will close as INTERRUPTED\");\n break;\n }\n bridge.markTurnEnded(turnId);\n await bridge.flushParts().catch(() => undefined);\n await bridge.maybeHeartbeat();\n }\n } finally {\n rl.close();\n }\n\n const end = await endRepoState(plan.repoRoot);\n const result = await bridge.complete({ outcome, end }).catch(() => null);\n if (!result) {\n markHostExited(spool.directory, 1);\n return 1;\n }\n log(\n result.captureComplete\n ? `Session ${plan.sessionId} closed \u00B7 capture complete \u00B7 output ${result.finalResponseArtifactId ?? \"not observed\"}`\n : `Session ${plan.sessionId} closed \u00B7 CAPTURE PENDING (${result.pendingParts} part(s))`,\n );\n const finalCode = result.captureComplete ? 0 : 1;\n markHostExited(spool.directory, finalCode);\n return finalCode;\n}\n\nexport async function runSessionHost(\n plan: SessionRunPlan,\n deps: HostDeps = {},\n): Promise<number> {\n return plan.mode === \"watch\" || plan.provider === \"claude\"\n ? runClaudeSessionHost(plan, deps)\n : runCodexSessionHost(plan, deps);\n}\n", "/**\n * Session-host bearer resolution (capture-off telemetry loss, 2026-08-08).\n *\n * The host used to hold the ONE bearer its plan was built with. An OAuth\n * access token (`tmo_`) lives \u22641h and is revoked the instant any concurrent\n * CLI invocation rotates the refresh token \u2014 live evidence (session\n * cmsk80my000ib04jvsrvlzf9q): host spawned 10:24:26 with the freshest token,\n * a `jentrix push` rotated at 10:26:49, the host's completion 401'd at\n * 10:26:55 and the whole usage rollup died with it.\n *\n * Fix: the host resolves its bearer through the SAME config file the CLI\n * persists rotations to. Dependency firewall: this MIRRORS the CLI's\n * `saveOAuthSession` read-merge-atomic-rename and `refreshAccessToken`\n * (cli/src/config.ts, cli/src/oauth.ts) \u2014 it never imports them. Server-side\n * rotation is single-use and a replayed refresh token is a benign\n * `invalid_grant` (no family revocation), so the loser of a concurrent\n * refresh race re-reads the file and adopts the winner's tokens; both sides\n * write atomically, so neither corrupts the other.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n mkdirSync,\n readFileSync,\n renameSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nexport interface SessionBearerSource {\n /** The bearer to use for the NEXT request (freshest known). */\n get(): string;\n /**\n * Called after an unauthorized response with the bearer that failed.\n * Returns a DIFFERENT bearer to retry with, or null when no recovery\n * exists (bare PAT, no oauth record, refresh refused and nobody else\n * rotated).\n */\n refresh(failedBearer: string): Promise<string | null>;\n}\n\n/** A bare PAT (or a plan with no configPath): no rotation, no recovery. */\nexport function staticBearerSource(bearer: string): SessionBearerSource {\n return { get: () => bearer, refresh: async () => null };\n}\n\ninterface OAuthRecord {\n refreshToken: string;\n expiresAt: string;\n clientId: string;\n tokenEndpoint: string;\n scope?: string;\n}\n\ninterface ConfigShape {\n token?: string;\n oauth?: OAuthRecord;\n [key: string]: unknown;\n}\n\nfunction readConfig(configPath: string): ConfigShape | null {\n try {\n const parsed: unknown = JSON.parse(readFileSync(configPath, \"utf8\"));\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed))\n return null;\n return parsed as ConfigShape;\n } catch {\n return null;\n }\n}\n\n/** Mirror of the CLI's 0600 tmp + `wx` + rename atomic config write. */\nfunction writeConfig(configPath: string, config: ConfigShape): void {\n mkdirSync(dirname(configPath), { recursive: true });\n const tmp = `${configPath}.tmp.${process.pid}.${randomBytes(6).toString(\"hex\")}`;\n writeFileSync(tmp, `${JSON.stringify(config, null, 2)}\\n`, {\n mode: 0o600,\n flag: \"wx\",\n });\n chmodSync(tmp, 0o600);\n renameSync(tmp, configPath);\n}\n\nfunction oauthRecordOf(config: ConfigShape | null): OAuthRecord | null {\n const oauth = config?.oauth;\n if (\n oauth &&\n typeof oauth.refreshToken === \"string\" &&\n oauth.refreshToken.length > 0 &&\n typeof oauth.tokenEndpoint === \"string\" &&\n typeof oauth.clientId === \"string\"\n ) {\n return oauth;\n }\n return null;\n}\n\n/**\n * F3: a refresh-produced bearer failing again THIS soon after its mint means\n * the endpoint rejects the whole chain (wrong deployment), not that the token\n * expired \u2014 access tokens live ~1h, heartbeats come every 30s. Well inside\n * expiry, well past a couple of beats.\n */\nconst FRESH_BEARER_WINDOW_MS = 120_000;\n\nexport function createConfigBearerSource(opts: {\n configPath: string;\n /** The plan's spawn-time bearer \u2014 used only until the config file yields one. */\n fallback: string;\n fetchImpl?: typeof fetch;\n log?: (line: string) => void;\n /** Injectable clock (tests). */\n now?: () => number;\n}): SessionBearerSource {\n const doFetch = opts.fetchImpl ?? fetch;\n const log = opts.log ?? (() => undefined);\n const now = opts.now ?? Date.now;\n // One refresh in flight per process \u2014 concurrent heartbeat/flush/completion\n // failures share the same recovery instead of racing the single-use grant.\n let pending: Promise<string | null> | null = null;\n // F3 (OAuth chain starvation): the bearer this source last produced, and\n // when. When THAT token comes back as the failed bearer within the fresh\n // window, the endpoint \u2014 not the token \u2014 is wrong (a host posting to\n // deployment B with deployment A's chain), and refreshing again only\n // rotates the SHARED CLI chain out from under a healthy sibling host every\n // heartbeat. Halt refreshes permanently instead.\n let lastProduced: { bearer: string; at: number } | null = null;\n let halted = false;\n\n const get = (): string => {\n const token = readConfig(opts.configPath)?.token;\n return typeof token === \"string\" && token.length > 0\n ? token\n : opts.fallback;\n };\n\n const refreshOnce = async (failedBearer: string): Promise<string | null> => {\n // Someone else (the CLI, or a sibling failure path here) already rotated.\n const current = get();\n if (current !== failedBearer) return current;\n\n const config = readConfig(opts.configPath);\n const oauth = oauthRecordOf(config);\n if (!oauth) return null;\n\n try {\n const res = await doFetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: oauth.refreshToken,\n client_id: oauth.clientId,\n }).toString(),\n });\n if (!res.ok) throw new Error(`token endpoint ${res.status}`);\n const pair = (await res.json()) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n if (!pair.access_token || !pair.refresh_token) {\n throw new Error(\"token endpoint returned no pair\");\n }\n const expiresAt = new Date(\n Date.now() + (pair.expires_in ?? 3600) * 1000,\n ).toISOString();\n // Read-merge-write so a concurrent writer's other fields survive.\n writeConfig(opts.configPath, {\n ...(readConfig(opts.configPath) ?? {}),\n token: pair.access_token,\n oauth: {\n refreshToken: pair.refresh_token,\n expiresAt,\n clientId: oauth.clientId,\n tokenEndpoint: oauth.tokenEndpoint,\n ...(pair.scope ? { scope: pair.scope } : {}),\n },\n });\n log(\"bearer refreshed (session host rotated the OAuth token)\");\n return pair.access_token;\n } catch (error) {\n // Lost the single-use race (invalid_grant) or the endpoint failed \u2014\n // adopt whatever a concurrent winner persisted, else give up honestly.\n const after = get();\n if (after !== failedBearer) {\n log(\"bearer refreshed by a concurrent process \u2014 adopted\");\n return after;\n }\n log(\n `bearer refresh failed (${error instanceof Error ? error.message : String(error)})`,\n );\n return null;\n }\n };\n\n return {\n get,\n refresh: (failedBearer) => {\n if (halted) return Promise.resolve(null);\n if (\n lastProduced !== null &&\n failedBearer === lastProduced.bearer &&\n now() - lastProduced.at < FRESH_BEARER_WINDOW_MS\n ) {\n halted = true;\n log(\n \"bearer halt: a freshly refreshed token was still unauthorized \u2014 the endpoint rejects this credential's whole chain (wrong deployment for this bearer?). Halting token rotation so sibling hosts keep theirs; end this host and re-align against the right deployment.\",\n );\n return Promise.resolve(null);\n }\n if (!pending) {\n pending = refreshOnce(failedBearer)\n .then((produced) => {\n if (produced !== null) {\n lastProduced = { bearer: produced, at: now() };\n }\n return produced;\n })\n .finally(() => {\n pending = null;\n });\n }\n return pending;\n },\n };\n}\n\n/**\n * Matches the transport/tool errors an expired or revoked bearer produces:\n * the SDK's StreamableHTTPError (code 401), \"Unauthorized\", and the server's\n * withMcpAuth JSON (`invalid_token` / \"No authorization provided\").\n */\nexport function isUnauthorizedishError(e: unknown): boolean {\n if (typeof e === \"object\" && e !== null) {\n const rec = e as { code?: unknown; status?: unknown };\n if (rec.code === 401 || rec.status === 401) return true;\n }\n const message = e instanceof Error ? e.message : String(e);\n return /\\b401\\b|unauthorized|invalid_token|no authorization/i.test(message);\n}\n", "/**\n * M20.1 \u00A78.4/\u00A720 \u2014 the local session bridge: the crash-safe capture loop that\n * runs BESIDE the interactive provider. It spools redacted events locally,\n * uploads TRACE parts with retry, heartbeats at most every 30 seconds, and\n * closes the session with a server-verified manifest + the \u00A712.5 usage\n * rollup. Network loss keeps the spool and marks capture pending \u2014 it can\n * never silently become \"complete\" (AC22).\n *\n * Every effectful edge (fetch, MCP tool call, clocks) is injected so the\n * fault-injection tests (provider exit, network loss, duplicate events,\n * retry) run with zero real sockets.\n */\n\nimport { unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport type { SessionEvent, SessionEventKind } from \"./session-events.js\";\nimport { serializeSessionEvent } from \"./session-events.js\";\nimport type { SessionRedactor } from \"./session-redact.js\";\nimport type { SessionSpool } from \"./session-spool.js\";\nimport {\n aggregateSessionUsage,\n type LifecycleInterval,\n type ObservedRange,\n type UsageReceipt,\n} from \"./session-usage.js\";\n\nexport type SessionCallTool = (\n name: string,\n args: Record<string, unknown>,\n) => Promise<Record<string, unknown>>;\n\n/**\n * AGE-649 \u2014 the bound on the stored final response. Mirrors\n * MAX_TYPED_ARTIFACT_BYTES in src/server/agent-sessions/ingestion.ts across the\n * dependency firewall (the runner package cannot import from the app), so the\n * artifact is truncated with a visible notice HERE rather than refused there at\n * the moment the session is closing.\n */\nexport const MAX_FINAL_RESPONSE_BYTES = 2 * 1024 * 1024;\n\nexport interface SessionBridgeDeps {\n jentrixBaseUrl: string;\n /**\n * Transient bearer for REST heartbeat/ingestion \u2014 NEVER persisted here. A\n * function form resolves the CURRENT token per request (OAuth rotation\n * revokes the old one mid-session \u2014 the 2026-08-08 capture-off finding).\n */\n bearer: string | (() => string);\n /**\n * Called with the bearer that just got a 401 \u2014 gives the host's bearer\n * source a chance to rotate/adopt before the next request. Fire-and-forget\n * from the silent paths (heartbeat, part upload).\n */\n onUnauthorized?: (failedBearer: string) => Promise<unknown>;\n sessionId: string;\n provider: \"claude\" | \"codex\";\n spool: SessionSpool;\n redactor: SessionRedactor;\n callTool: SessionCallTool;\n fetchImpl?: typeof fetch;\n monotonic?: () => number;\n wallClock?: () => Date;\n /**\n * Jentrix MVP (PRD \u00A76): false = TRACE capture OFF \u2014 events are still\n * observed (usage receipts, timing, heartbeats) but nothing is spooled or\n * uploaded and completion submits no manifest. Default true.\n */\n traceCapture?: boolean;\n log?: (line: string) => void;\n}\n\nexport const HEARTBEAT_MIN_INTERVAL_MS = 30_000;\n\nexport interface CapabilitySnapshot {\n provider: \"claude\" | \"codex\";\n providerVersion: string | null;\n /** Event classes this provider/mode can emit; the rest are not_observable. */\n observable: SessionEventKind[];\n notObservable: SessionEventKind[];\n}\n\nexport class SessionBridge {\n private sequence = 0;\n private readonly receipts: UsageReceipt[] = [];\n private readonly providerTurns = new Map<string, LifecycleInterval>();\n private readonly toolIntervals = new Map<string, LifecycleInterval>();\n private readonly observedRanges: ObservedRange[] = [];\n /**\n * control-room AC2.1/AC2.2 \u2014 the LAST model the provider was observed\n * running. Last, not first: a session may legitimately switch models\n * mid-flight and the model that ran is the one that ran. Null until a line\n * names one; the heartbeat then omits the field entirely, so an unobserved\n * model can never overwrite a proven one server-side.\n */\n private observedModelId: string | null = null;\n private observingSince: number | null = null;\n private readonly ackedParts = new Map<number, string>();\n private readonly terminalParts = new Set<number>();\n private lastHeartbeatAt = 0;\n private unrecognizedEvents = 0;\n private capability: CapabilitySnapshot | null = null;\n private inactive = false;\n /**\n * AGE-649 \u2014 the newest non-empty assistant message observed, kept so the\n * session's own OUTPUT survives the close. Held in memory only: this is a\n * projection of an event the host already sees, never a second capture\n * channel, and it is recorded even when TRACE capture is off (which is the\n * whole point \u2014 capture-off is the MVP default, and without this a closed\n * session keeps its telemetry and loses what it actually concluded).\n */\n private lastAssistantMessage: {\n text: string;\n at: string;\n sequence: number;\n } | null = null;\n\n /**\n * True after a heartbeat came back 409 SESSION_NOT_ACTIVE \u2014 the session is\n * terminal server-side. The watch host uses this as its end signal when no\n * lifecycle hook can reach it; network loss never sets it.\n */\n get sessionInactive(): boolean {\n return this.inactive;\n }\n\n /** Heartbeat-refusal statuses already logged \u2014 one warning per status. */\n private warnedHeartbeatStatuses = new Set<number>();\n\n /** Server-acknowledged parts so far \u2014 the host stamps this into host.json. */\n get ackedPartCount(): number {\n return this.ackedParts.size;\n }\n\n constructor(private readonly deps: SessionBridgeDeps) {}\n\n /** The injected MCP tool caller (host convenience \u2014 same credential). */\n get tool(): SessionCallTool {\n return this.deps.callTool;\n }\n\n private now(): number {\n return (this.deps.monotonic ?? (() => performance.now()))();\n }\n\n private wall(): Date {\n return (this.deps.wallClock ?? (() => new Date()))();\n }\n\n private fetch(): typeof fetch {\n return this.deps.fetchImpl ?? fetch;\n }\n\n /** Begin (or resume) continuous observation \u2014 opens an observed range. */\n startObserving(): void {\n if (this.observingSince === null) this.observingSince = this.now();\n }\n\n /** A capture gap (stream drop, provider restart): closes the range. */\n recordGap(reason: string): void {\n if (this.observingSince !== null) {\n this.observedRanges.push({ from: this.observingSince, to: this.now() });\n this.observingSince = null;\n }\n this.record({ kind: \"error\", payload: { captureGap: reason } });\n }\n\n /** Record the provider capability snapshot (\u00A715.3) as an observable event. */\n recordCapabilities(snapshot: CapabilitySnapshot): void {\n this.capability = snapshot;\n this.record({ kind: \"session\", payload: { capabilities: snapshot } });\n }\n\n get capabilities(): CapabilitySnapshot | null {\n return this.capability;\n }\n\n countUnrecognized(): void {\n this.unrecognizedEvents += 1;\n }\n\n /**\n * Append one observable event: sequence + wall timestamp stamped here, the\n * whole line REDACTED before it becomes durable, usage receipts collected\n * for the rollup (deduped downstream by provider event identity).\n */\n record(\n event: Omit<SessionEvent, \"sequence\" | \"version\" | \"at\" | \"provider\"> & {\n at?: string;\n providerEventId?: string;\n },\n ): SessionEvent {\n const full: SessionEvent = {\n version: 1,\n sequence: this.sequence++,\n at: event.at ?? this.wall().toISOString(),\n provider: this.deps.provider,\n ...(event.providerEventId\n ? { providerEventId: event.providerEventId }\n : {}),\n kind: event.kind,\n payload: this.deps.redactor.value(event.payload),\n };\n if (this.deps.traceCapture !== false) {\n this.deps.spool.append(\n this.deps.redactor.text(serializeSessionEvent(full)),\n );\n }\n if (full.kind === \"assistant_message\") {\n // Read off the REDACTED payload, so the text kept here has already been\n // through the local pass \u2014 exactly like a spooled part.\n const text = (full.payload as { text?: unknown })?.text;\n if (typeof text === \"string\" && text.trim().length > 0) {\n this.lastAssistantMessage = {\n text,\n at: full.at,\n sequence: full.sequence,\n };\n }\n }\n if (full.kind === \"usage\") {\n const payload = full.payload as {\n kind?: \"delta\" | \"cumulative\";\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n reasoningOutputTokens?: number;\n modelId?: string | null;\n turnId?: string | null;\n };\n if (\n (payload?.kind === \"delta\" || payload?.kind === \"cumulative\") &&\n typeof payload.inputTokens === \"number\" &&\n typeof payload.outputTokens === \"number\"\n ) {\n this.receipts.push({\n eventId: full.providerEventId ?? `seq:${full.sequence}`,\n turnId: payload.turnId ?? null,\n kind: payload.kind,\n inputTokens: payload.inputTokens,\n outputTokens: payload.outputTokens,\n ...(typeof payload.cacheReadTokens === \"number\"\n ? { cacheReadTokens: payload.cacheReadTokens }\n : {}),\n ...(typeof payload.cacheCreationTokens === \"number\"\n ? { cacheCreationTokens: payload.cacheCreationTokens }\n : {}),\n // TPM Slice 2 (AC2.4/AC2.7): the receipt's own model and reasoning\n // split, when the mapper reported them \u2014 grouped receipts, never\n // estimates.\n ...(typeof payload.reasoningOutputTokens === \"number\"\n ? { reasoningOutputTokens: payload.reasoningOutputTokens }\n : {}),\n ...(typeof payload.modelId === \"string\" && payload.modelId.trim()\n ? { modelId: payload.modelId.trim() }\n : {}),\n at: this.now(),\n });\n // Durable telemetry: a host that dies before completing (crash,\n // revoked bearer) must not take the usage rollup with it \u2014 `stacks\n // session end`'s server-side fallback submits this snapshot\n // (2026-08-08 capture-off finding: all-null tokens after host death).\n this.persistUsageSnapshot();\n }\n }\n return full;\n }\n\n /** Best-effort spool-side snapshot of the current rollup (provider receipts). */\n private persistUsageSnapshot(): void {\n try {\n writeFileSync(\n join(this.deps.spool.directory, \"usage.json\"),\n JSON.stringify({\n rollup: this.usageRollup(),\n updatedAt: this.wall().toISOString(),\n }),\n { mode: 0o600 },\n );\n } catch {\n // Telemetry durability is best-effort \u2014 never fail capture over it.\n }\n }\n\n /** Record the model a transcript line named (pure accumulation, no I/O). */\n observeModel(modelId: string): void {\n const next = modelId.trim();\n if (next) this.observedModelId = next;\n }\n\n /** What the host has observed running, for tests and the close-time record. */\n get modelId(): string | null {\n return this.observedModelId;\n }\n\n /**\n * control-room AC3.7 \u2014 record an interval whose bounds were OBSERVED rather\n * than measured on this process's clock. The Claude path replays timestamps\n * the transcript already carries, so `this.now()` (which the mark* pair\n * below uses for the live Codex path) would time the tail, not the turn.\n */\n recordInterval(interval: {\n kind: \"turn\" | \"tool\";\n id: string;\n startedAt: number;\n endedAt: number;\n }): void {\n const target =\n interval.kind === \"turn\" ? this.providerTurns : this.toolIntervals;\n target.set(interval.id, {\n id: interval.id,\n startedAt: interval.startedAt,\n endedAt: interval.endedAt,\n });\n }\n\n /**\n * An interval opened and never closed \u2014 a tool that never returned, a host\n * killed mid-turn. Recorded WITHOUT an end so `aggregateSessionUsage` names\n * the gap and degrades coverage to PARTIAL, instead of the total quietly\n * omitting it and reading as complete.\n */\n recordUnclosedInterval(kind: \"turn\" | \"tool\", id: string): void {\n const target = kind === \"turn\" ? this.providerTurns : this.toolIntervals;\n if (!target.has(id)) target.set(id, { id, startedAt: 0, endedAt: null });\n }\n\n markTurnStarted(id: string): void {\n this.providerTurns.set(id, { id, startedAt: this.now(), endedAt: null });\n }\n\n markTurnEnded(id: string): void {\n const turn = this.providerTurns.get(id);\n if (turn) turn.endedAt = this.now();\n }\n\n markToolStarted(id: string): void {\n this.toolIntervals.set(id, { id, startedAt: this.now(), endedAt: null });\n }\n\n markToolEnded(id: string): void {\n const interval = this.toolIntervals.get(id);\n if (interval) interval.endedAt = this.now();\n }\n\n /** The current REST bearer (function form resolves per request). */\n private bearerOf(): string {\n return typeof this.deps.bearer === \"function\"\n ? this.deps.bearer()\n : this.deps.bearer;\n }\n\n /** \u2264 one heartbeat per 30s window (AC42); failures are silent (retry next). */\n async maybeHeartbeat(): Promise<void> {\n const now = this.now();\n if (now - this.lastHeartbeatAt < HEARTBEAT_MIN_INTERVAL_MS) return;\n await this.postHeartbeat(now);\n }\n\n /**\n * TPM Slice 2 (AC2.5): the flush receipt \u2014 an immediate beat that ignores\n * the 30-second window, posted before a task-changing re-align so the OLD\n * alignment's open interval absorbs everything observed so far. Host-side\n * ordering only: a killed host's mid-switch smear stays bounded by one\n * beat window, which the CLI disclosure names.\n */\n async flushUsageNow(): Promise<boolean> {\n return this.postHeartbeat(this.now());\n }\n\n /** @returns true when the server acknowledged the beat (HTTP ok). */\n private async postHeartbeat(now: number): Promise<boolean> {\n this.lastHeartbeatAt = now;\n const bearer = this.bearerOf();\n try {\n const response = await this.fetch()(\n new URL(\"/api/agent-sessions/heartbeat\", this.deps.jentrixBaseUrl),\n {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${bearer}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n sessionId: this.deps.sessionId,\n // control-room AC2.1: the heartbeat is the host's \"what I\n // observed\" channel. No new timer, no new route, no new tool \u2014\n // and host-attested by construction, since the route writes only\n // the authenticated operator's own open session.\n ...(this.observedModelId ? { modelId: this.observedModelId } : {}),\n // control-room AC4.1: the LIVE usage receipt on the same beat.\n // Sent only once a receipt has actually been observed \u2014 an empty\n // rollup would overwrite the session's totals with nulls and\n // report UNAVAILABLE for a session that had already reported.\n ...(this.receipts.length > 0 ? { usage: this.usageRollup() } : {}),\n }),\n },\n );\n if (response.status === 401) {\n // A rotated-away bearer must not silently kill liveness until the\n // sweep interrupts the session \u2014 ask the source to recover so the\n // NEXT window heartbeats with a live token.\n void this.deps.onUnauthorized?.(bearer)?.catch(() => undefined);\n }\n if (response.status === 409) {\n const body = await response.text().catch(() => \"\");\n if (body.includes(\"SESSION_NOT_ACTIVE\")) this.inactive = true;\n }\n if (\n !response.ok &&\n response.status !== 401 &&\n response.status !== 409 &&\n !this.warnedHeartbeatStatuses.has(response.status)\n ) {\n // A silently-refused beat is how a live session gets swept\n // INTERRUPTED \u2014 say it ONCE per distinct status, not every 30s.\n this.warnedHeartbeatStatuses.add(response.status);\n this.deps.log?.(\n `capture: heartbeat rejected (HTTP ${response.status}) \u2014 liveness at risk; the sweep may interrupt this session`,\n );\n }\n return response.ok;\n } catch {\n // Offline: the sweep may interrupt server-side; reconnection resumes.\n return false;\n }\n }\n\n /**\n * Upload every pending spool part. Returns the still-pending count \u2014 a\n * non-zero result is \"capture pending\", printed prominently and encoded in\n * the CLI exit code (\u00A720). A redacted-slot refusal (terminal, \u00A712.3) keeps\n * the local file forever and is reported as a named gap.\n */\n async flushParts(): Promise<{ pending: number; terminal: number }> {\n // Capture off: nothing was spooled, nothing to upload \u2014 by design.\n if (this.deps.traceCapture === false) return { pending: 0, terminal: 0 };\n let pending = 0;\n for (const part of this.deps.spool.pendingParts()) {\n if (this.terminalParts.has(part.part)) continue;\n const bearer = this.bearerOf();\n try {\n const response = await this.fetch()(\n new URL(\n `/api/agent-sessions/${this.deps.sessionId}/parts`,\n this.deps.jentrixBaseUrl,\n ),\n {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${bearer}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n part: part.part,\n body: this.deps.spool.readPart(part.part),\n }),\n },\n );\n if (response.ok) {\n const ack = (await response.json()) as { checksum?: string };\n const acked =\n typeof ack.checksum === \"string\" ? ack.checksum : part.checksum;\n // Record the ACKNOWLEDGED (stored) checksum into the manifest first,\n // then delete the spool file \u2014 never on anything but a genuine ack.\n this.ackedParts.set(part.part, acked);\n this.deps.spool.deleteAcknowledged(part.part, acked, { force: true });\n // The slot is spent server-side; new events open the next part.\n this.deps.spool.advancePast(part.part);\n continue;\n }\n if (response.status === 401) {\n void this.deps.onUnauthorized?.(bearer)?.catch(() => undefined);\n }\n const body = await response.text().catch(() => \"\");\n if (\n response.status === 409 &&\n body.includes(\"ARTIFACT_PART_REDACTED\")\n ) {\n // Terminal slot: keep the local spool (operator deletion only) and\n // stop retrying \u2014 the summary names the gap.\n this.terminalParts.add(part.part);\n this.deps.log?.(\n `trace part ${part.part}: slot terminally redacted \u2014 local spool retained`,\n );\n continue;\n }\n pending += 1;\n } catch {\n pending += 1; // network loss: retry later, spool intact (AC22)\n }\n }\n return { pending, terminal: this.terminalParts.size };\n }\n\n /**\n * AGE-649 \u2014 push the session's FINAL RESPONSE as a typed artifact.\n *\n * Why this exists: with TRACE capture off (the MVP default) a closed session\n * keeps its telemetry and its typed artifacts, and nothing at all holds what\n * the agent concluded. The RUN_SUMMARY cannot carry it \u2014 that document is a\n * deterministic server projection and model prose is banned from it (M20.1\n * AC31) \u2014 so the output lands as its own artifact, on the same typed-push\n * boundary an operator's `jentrix push report` uses. One ingestion function,\n * both redaction passes, checksum after redaction.\n *\n * Ordering is load-bearing: `COMPLETED` is a SEALED status for typed pushes,\n * so this runs BEFORE `complete_agent_session`, never after.\n *\n * Absence stays absence. A session where the host observed no assistant text\n * (capture never bound, a Codex thread that only ran tools) gets NO artifact\n * rather than an empty one \u2014 the same rule the usage rollup follows for\n * tokens. Failure never fails the close: the artifact is a bonus record, and\n * losing it must not cost the operator their session completion.\n *\n * @returns the artifact id, or null when there was nothing to push.\n */\n async pushFinalResponse(): Promise<string | null> {\n const last = this.lastAssistantMessage;\n if (!last) return null;\n const body = this.finalResponseBody(last);\n const bearer = this.bearerOf();\n try {\n const response = await this.fetch()(\n new URL(\n `/api/agent-sessions/${this.deps.sessionId}/artifacts`,\n this.deps.jentrixBaseUrl,\n ),\n {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${bearer}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n // `report` \u2192 REPORT \u2192 the Execution layer, which is the session's\n // own layer. No new push kind and no new ArtifactType: the seven\n // kinds are frozen vocabulary and this is a report the agent wrote.\n kind: \"report\",\n title: `Final response \u2014 session ${this.deps.sessionId.slice(-8)}`,\n body,\n }),\n },\n );\n if (response.ok) {\n const ack = (await response.json().catch(() => null)) as {\n artifactId?: string;\n } | null;\n return ack?.artifactId ?? null;\n }\n if (response.status === 401) {\n void this.deps.onUnauthorized?.(bearer)?.catch(() => undefined);\n }\n this.deps.log?.(\n `final response: not stored (HTTP ${response.status}) \u2014 the session's closing output was not captured`,\n );\n return null;\n } catch (error) {\n this.deps.log?.(\n `final response: not stored (${error instanceof Error ? error.message : \"unknown\"}) \u2014 the session's closing output was not captured`,\n );\n return null;\n }\n }\n\n /**\n * The stored document. Self-describing on purpose: a reader has to be able to\n * tell this apart from the RUN_SUMMARY sitting beside it, and has to know it\n * is verbatim provider output rather than anything the server derived.\n *\n * Bounded here as well as server-side, and a truncation SAYS so \u2014 an artifact\n * silently missing its tail is worse than one that names the cut.\n */\n private finalResponseBody(last: {\n text: string;\n at: string;\n sequence: number;\n }): string {\n const header = [\n `# Final response \u2014 session ${this.deps.sessionId}`,\n \"\",\n `The last assistant message this session's host observed before close (event ${last.sequence}, ${last.at}).`,\n \"Verbatim provider output \u2014 redacted on this machine and again on arrival.\",\n \"This is model prose, not a server projection: the RUN_SUMMARY artifact is the deterministic record of what the session did.\",\n \"\",\n \"---\",\n \"\",\n ].join(\"\\n\");\n const room = MAX_FINAL_RESPONSE_BYTES - Buffer.byteLength(header, \"utf8\");\n if (Buffer.byteLength(last.text, \"utf8\") <= room) return header + last.text;\n const notice = \"\\n\\n[truncated \u2014 the response exceeded the artifact limit]\";\n const kept = Buffer.from(last.text, \"utf8\")\n .subarray(0, Math.max(0, room - Buffer.byteLength(notice, \"utf8\")))\n .toString(\"utf8\")\n // A byte-slice can cut a multi-byte character in half; drop the\n // replacement char it decodes to rather than storing mojibake.\n .replace(/\uFFFD+$/, \"\");\n return header + kept + notice;\n }\n\n /** The \u00A712.5 rollup over everything observed so far. */\n usageRollup() {\n const ranges = [...this.observedRanges];\n if (this.observingSince !== null) {\n ranges.push({ from: this.observingSince, to: this.now() });\n }\n const rollup = aggregateSessionUsage({\n receipts: this.receipts,\n observedRanges: ranges,\n providerTurns: [...this.providerTurns.values()],\n toolIntervals: [...this.toolIntervals.values()],\n });\n // The server's SessionUsageSchema bounds missingRanges to 200 entries of\n // \u2264400 chars. An UNBOUNDED list (one entry per receipt-less turn \u2014 a\n // long session crosses 200 easily) made every usage-bearing heartbeat\n // fail schema validation SILENTLY: heartbeatAt froze while part uploads\n // kept landing, and the sweep interrupted a perfectly live session\n // (observed 2026-08-20, three sweeps in one run). Cap here at the source\n // \u2014 the tail collapses into one honest summary entry.\n if (rollup.missingRanges.length > 200) {\n const dropped = rollup.missingRanges.length - 199;\n rollup.missingRanges = [\n ...rollup.missingRanges.slice(0, 199),\n `\u2026and ${dropped} more missing ranges (capped at the schema's 200)`,\n ];\n }\n rollup.missingRanges = rollup.missingRanges.map((r) => r.slice(0, 400));\n return rollup;\n }\n\n /**\n * Close the session: final flush, server-verified manifest from the ACKED\n * checksums, rollup, then `complete_agent_session` under CAS. Returns the\n * server's verdict plus the local pending count \u2014 the CLI exits non-zero\n * while anything is pending (\u00A720).\n */\n async complete(opts: {\n outcome: \"COMPLETED\" | \"INTERRUPTED\" | \"CANCELLED\";\n end: { branch: string | null; head: string | null; dirty: boolean | null };\n captureError?: string | null;\n }): Promise<{\n status: string;\n captureComplete: boolean;\n summaryArtifactId: string | null;\n /** AGE-649 \u2014 null when the host observed no assistant text to store. */\n finalResponseArtifactId: string | null;\n pendingParts: number;\n }> {\n const { pending } = await this.flushParts();\n // AGE-649: BEFORE the completion call \u2014 `COMPLETED` seals the session\n // against typed pushes, so there is no \"after\" for this.\n const finalResponseArtifactId = await this.pushFinalResponse();\n const rollup = this.usageRollup();\n const current = (await this.deps.callTool(\"get_agent_session\", {\n sessionId: this.deps.sessionId,\n })) as { updatedAt?: string };\n const traceOff = this.deps.traceCapture === false;\n // Capture-off (PRD \u00A76): no manifest is submitted \u2014 captureComplete stays\n // false with an honest reason, never a vacuous \"complete\" over a\n // transcript that was deliberately not recorded.\n const manifest = traceOff\n ? undefined\n : {\n parts: [...this.ackedParts.entries()]\n .sort(([a], [b]) => a - b)\n .map(([part, checksum]) => ({ part, checksum })),\n };\n // AGE-958: the healthy capture-off default is a STATUS, not an error \u2014\n // the server records captureError null and derives OFF_BY_DESIGN; sending\n // prose here made every monitor watching `captureError != null` alert on\n // the designed path.\n const captureError =\n opts.captureError ??\n (traceOff\n ? null\n : pending > 0\n ? `capture pending: ${pending} trace part(s) not yet acknowledged`\n : this.unrecognizedEvents > 0\n ? `${this.unrecognizedEvents} provider event(s) had shapes this adapter does not observe`\n : null);\n const result = (await this.deps.callTool(\"complete_agent_session\", {\n sessionId: this.deps.sessionId,\n outcome: opts.outcome,\n endBranch: opts.end.branch,\n endHead: opts.end.head,\n endDirty: opts.end.dirty,\n captureError,\n ...(manifest ? { manifest } : {}),\n usage: {\n inputTokens: rollup.inputTokens,\n outputTokens: rollup.outputTokens,\n cacheReadTokens: rollup.cacheReadTokens,\n cacheCreationTokens: rollup.cacheCreationTokens,\n // TPM Slice 2 (AC2.6/AC2.7): the close corrects session TOTALS \u2014\n // reasoning included, perModel deliberately NOT sent (the server\n // writes no segments at close; residuals stay disclosed).\n reasoningOutputTokens: rollup.reasoningOutputTokens,\n providerActiveDurationMs: rollup.providerActiveDurationMs,\n toolDurationMs: rollup.toolDurationMs,\n coverage: rollup.coverage,\n ...(rollup.missingRanges.length\n ? { missingRanges: rollup.missingRanges.slice(0, 200) }\n : {}),\n },\n expectedUpdatedAt: current.updatedAt,\n })) as {\n status?: string;\n captureComplete?: boolean;\n summaryArtifactId?: string | null;\n };\n // The rollup reached the server \u2014 the durable snapshot has done its job.\n try {\n unlinkSync(join(this.deps.spool.directory, \"usage.json\"));\n } catch {\n // Absent (no receipts) or unremovable \u2014 either way not worth failing.\n }\n return {\n status: result.status ?? opts.outcome,\n captureComplete: Boolean(result.captureComplete),\n summaryArtifactId: result.summaryArtifactId ?? null,\n finalResponseArtifactId,\n pendingParts: pending,\n };\n }\n}\n", "/**\n * M20.1 \u00A712.1 \u2014 the observable-event envelope (version 1). An EVIDENCE\n * serialization, not a workflow state machine: adapters map only observable\n * provider event SHAPES onto it; consumers rely on the small common envelope\n * and treat provider-native detail as opaque versioned payload.\n */\n\nexport const SESSION_EVENT_VERSION = 1 as const;\n\nexport type SessionEventKind =\n | \"session\"\n | \"user_message\"\n | \"assistant_message\"\n | \"tool_call\"\n | \"tool_result\"\n | \"command\"\n | \"file_change\"\n | \"plan\"\n | \"usage\"\n | \"error\";\n\nexport interface SessionEvent {\n version: typeof SESSION_EVENT_VERSION;\n /** Monotonic per-session sequence, assigned by the local bridge. */\n sequence: number;\n /** UTC ISO timestamp for display/audit (durations use the monotonic clock). */\n at: string;\n provider: \"claude\" | \"codex\";\n providerEventId?: string;\n kind: SessionEventKind;\n payload: unknown;\n}\n\nexport const SESSION_EVENT_KINDS: readonly SessionEventKind[] = [\n \"session\",\n \"user_message\",\n \"assistant_message\",\n \"tool_call\",\n \"tool_result\",\n \"command\",\n \"file_change\",\n \"plan\",\n \"usage\",\n \"error\",\n];\n\n/** One NDJSON line (the spool/TRACE serialization). Deterministic key order. */\nexport function serializeSessionEvent(event: SessionEvent): string {\n return `${JSON.stringify({\n version: event.version,\n sequence: event.sequence,\n at: event.at,\n provider: event.provider,\n ...(event.providerEventId ? { providerEventId: event.providerEventId } : {}),\n kind: event.kind,\n payload: event.payload,\n })}\\n`;\n}\n\n/** Parse one spool line back; null for anything that is not a v1 envelope. */\nexport function parseSessionEvent(line: string): SessionEvent | null {\n try {\n const parsed = JSON.parse(line) as SessionEvent;\n if (\n parsed?.version !== SESSION_EVENT_VERSION ||\n typeof parsed.sequence !== \"number\" ||\n typeof parsed.at !== \"string\" ||\n (parsed.provider !== \"claude\" && parsed.provider !== \"codex\") ||\n !SESSION_EVENT_KINDS.includes(parsed.kind)\n ) {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n", "/**\n * M20.1 \u00A712.5 \u2014 the PURE session usage/timing aggregator. Provider-reported\n * receipts only; NOTHING is ever estimated from characters, bytes, price\n * tables, or another tokenizer (AC35). Durations come from paired monotonic\n * lifecycle events; wall time is the SERVER's (never computed here).\n *\n * Coverage semantics (rule 9):\n * COMPLETE \u2014 every observable provider turn carried a usable receipt and\n * every measured interval closed;\n * PARTIAL \u2014 something is missing, and every gap is NAMED;\n * UNAVAILABLE \u2014 the runtime exposed no usable receipts at all.\n */\n\nexport interface UsageReceipt {\n /** Provider event/turn identity \u2014 the dedupe key (rule 2/5, AC38). */\n eventId: string;\n /** The provider turn this receipt belongs to, when known. */\n turnId?: string | null;\n /**\n * \"delta\" \u2014 tokens for one turn; \"cumulative\" \u2014 the provider reports thread\n * totals, and only a continuous-capture delta between two acknowledged\n * cumulative receipts may contribute (rule 3, AC37/AC46).\n */\n kind: \"delta\" | \"cumulative\";\n inputTokens: number;\n outputTokens: number;\n /**\n * Disjoint subsets of inputTokens (AGE-938). Absent = this receipt did not\n * report the field (an old transcript format, or a provider without the\n * concept) \u2014 distinct from a reported 0.\n */\n cacheReadTokens?: number | null;\n cacheCreationTokens?: number | null;\n /**\n * TPM Slice 2 (AC2.7): reasoning tokens as a SUBSET of outputTokens.\n * Absent = the provider does not split this out (Claude transcripts).\n */\n reasoningOutputTokens?: number | null;\n /**\n * TPM Slice 2 (AC2.4): the model that produced this receipt, as the\n * provider named it (Claude: message.model on the same transcript entry;\n * Codex: turn_context.model when the stream reports one). Absent = never\n * observed for this receipt \u2014 grouped under the null-model bucket.\n */\n modelId?: string | null;\n /** Monotonic ms when the receipt was observed. */\n at: number;\n}\n\nexport interface LifecycleInterval {\n id: string;\n startedAt: number;\n /** Missing = the terminal event was never observed (rule 7). */\n endedAt?: number | null;\n}\n\n/** A continuous-capture window on the monotonic clock (rule 3). */\nexport interface ObservedRange {\n from: number;\n to: number;\n}\n\n/** TPM Slice 2 (AC2.4): the cumulative rollup for ONE model bucket. */\nexport interface PerModelUsage {\n /** Null = receipts whose model was never observed. */\n modelId: string | null;\n inputTokens: number | null;\n outputTokens: number | null;\n cacheReadTokens: number | null;\n cacheCreationTokens: number | null;\n reasoningOutputTokens: number | null;\n}\n\nexport interface SessionUsageRollup {\n inputTokens: number | null;\n outputTokens: number | null;\n /** Null when NO receipt reported the field \u2014 never a fabricated 0. */\n cacheReadTokens: number | null;\n cacheCreationTokens: number | null;\n /** TPM Slice 2 (AC2.7): subset of outputTokens; null = never reported. */\n reasoningOutputTokens: number | null;\n providerActiveDurationMs: number | null;\n toolDurationMs: number | null;\n coverage: \"COMPLETE\" | \"PARTIAL\" | \"UNAVAILABLE\";\n missingRanges: string[];\n /**\n * TPM Slice 2 (AC2.4): the same receipts GROUPED by the model that\n * produced them \u2014 the fact the pipeline used to throw away. Empty when no\n * receipt was usable. Sums here always equal the totals above: every\n * usable receipt lands in exactly one bucket (null model included).\n */\n perModel: PerModelUsage[];\n}\n\nfunction insideOneRange(\n ranges: ObservedRange[],\n from: number,\n to: number,\n): boolean {\n return ranges.some((r) => r.from <= from && to <= r.to);\n}\n\nexport function aggregateSessionUsage(input: {\n receipts: UsageReceipt[];\n /** Continuous capture windows; a cumulative delta must sit inside ONE. */\n observedRanges: ObservedRange[];\n providerTurns: LifecycleInterval[];\n toolIntervals: LifecycleInterval[];\n}): SessionUsageRollup {\n const missing: string[] = [];\n\n // Rule 2/5 (AC38): one receipt contributes at most once \u2014 dedupe by identity.\n const seen = new Set<string>();\n const receipts = input.receipts\n .filter((r) => {\n if (seen.has(r.eventId)) return false;\n seen.add(r.eventId);\n return true;\n })\n .sort((a, b) => a.at - b.at);\n\n let inputTokens = 0;\n let outputTokens = 0;\n let usable = 0;\n const receiptTurnIds = new Set<string>();\n\n // AGE-938: field-level reporting \u2014 a cache sum surfaces only when at least\n // one receipt actually carried the field, else it stays null.\n let cacheReadTokens = 0;\n let cacheReadReported = false;\n let cacheCreationTokens = 0;\n let cacheCreationReported = false;\n // TPM Slice 2 (AC2.7): reasoning rides the same field-level honesty.\n let reasoningOutputTokens = 0;\n let reasoningReported = false;\n\n // TPM Slice 2 (AC2.4): the same contributions, grouped by producing model.\n // Every usable contribution lands in exactly one bucket (null = the model\n // was never observed for the receipt), so \u03A3 buckets \u2261 the totals above.\n interface Bucket {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheReadReported: boolean;\n cacheCreationTokens: number;\n cacheCreationReported: boolean;\n reasoningOutputTokens: number;\n reasoningReported: boolean;\n }\n const buckets = new Map<string | null, Bucket>();\n interface Contribution {\n modelId: string | null;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n reasoningOutputTokens?: number;\n }\n const contribute = (c: Contribution): void => {\n inputTokens += c.inputTokens;\n outputTokens += c.outputTokens;\n const bucket =\n buckets.get(c.modelId) ??\n ({\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheReadReported: false,\n cacheCreationTokens: 0,\n cacheCreationReported: false,\n reasoningOutputTokens: 0,\n reasoningReported: false,\n } satisfies Bucket);\n bucket.inputTokens += c.inputTokens;\n bucket.outputTokens += c.outputTokens;\n if (typeof c.cacheReadTokens === \"number\") {\n cacheReadTokens += c.cacheReadTokens;\n cacheReadReported = true;\n bucket.cacheReadTokens += c.cacheReadTokens;\n bucket.cacheReadReported = true;\n }\n if (typeof c.cacheCreationTokens === \"number\") {\n cacheCreationTokens += c.cacheCreationTokens;\n cacheCreationReported = true;\n bucket.cacheCreationTokens += c.cacheCreationTokens;\n bucket.cacheCreationReported = true;\n }\n if (typeof c.reasoningOutputTokens === \"number\") {\n reasoningOutputTokens += c.reasoningOutputTokens;\n reasoningReported = true;\n bucket.reasoningOutputTokens += c.reasoningOutputTokens;\n bucket.reasoningReported = true;\n }\n buckets.set(c.modelId, bucket);\n usable += 1;\n };\n const modelOf = (receipt: UsageReceipt): string | null =>\n receipt.modelId?.trim() || null;\n\n let cumulativeBaseline: UsageReceipt | null = null;\n for (const receipt of receipts) {\n if (receipt.turnId) receiptTurnIds.add(receipt.turnId);\n if (receipt.kind === \"delta\") {\n contribute({\n modelId: modelOf(receipt),\n inputTokens: receipt.inputTokens,\n outputTokens: receipt.outputTokens,\n ...(typeof receipt.cacheReadTokens === \"number\"\n ? { cacheReadTokens: receipt.cacheReadTokens }\n : {}),\n ...(typeof receipt.cacheCreationTokens === \"number\"\n ? { cacheCreationTokens: receipt.cacheCreationTokens }\n : {}),\n ...(typeof receipt.reasoningOutputTokens === \"number\"\n ? { reasoningOutputTokens: receipt.reasoningOutputTokens }\n : {}),\n });\n continue;\n }\n // Cumulative: a delta needs an acknowledged baseline AND continuous\n // capture across the whole interval between the two receipts (rule 3).\n if (cumulativeBaseline === null) {\n cumulativeBaseline = receipt;\n missing.push(\n `cumulative receipt ${receipt.eventId} established a baseline only \u2014 the thread total before it is not attributable to this session`,\n );\n continue;\n }\n if (!insideOneRange(input.observedRanges, cumulativeBaseline.at, receipt.at)) {\n missing.push(\n `cumulative interval ${cumulativeBaseline.eventId}\u2192${receipt.eventId} crossed an unobserved range and was not counted`,\n );\n cumulativeBaseline = receipt; // becomes the next baseline\n continue;\n }\n const dIn = receipt.inputTokens - cumulativeBaseline.inputTokens;\n const dOut = receipt.outputTokens - cumulativeBaseline.outputTokens;\n if (dIn < 0 || dOut < 0) {\n missing.push(\n `cumulative receipt ${receipt.eventId} regressed below its baseline and was not counted`,\n );\n cumulativeBaseline = receipt;\n continue;\n }\n // Cache/reasoning deltas count only when BOTH endpoints reported the\n // field and the delta is non-negative \u2014 a regressing counter on an\n // otherwise valid interval reads as unreported for that interval, never\n // as negative usage. The interval's spend belongs to the LATER receipt's\n // model \u2014 the model that was running when the total grew.\n contribute({\n modelId: modelOf(receipt),\n inputTokens: dIn,\n outputTokens: dOut,\n ...(typeof receipt.cacheReadTokens === \"number\" &&\n typeof cumulativeBaseline.cacheReadTokens === \"number\" &&\n receipt.cacheReadTokens >= cumulativeBaseline.cacheReadTokens\n ? {\n cacheReadTokens:\n receipt.cacheReadTokens - cumulativeBaseline.cacheReadTokens,\n }\n : {}),\n ...(typeof receipt.cacheCreationTokens === \"number\" &&\n typeof cumulativeBaseline.cacheCreationTokens === \"number\" &&\n receipt.cacheCreationTokens >= cumulativeBaseline.cacheCreationTokens\n ? {\n cacheCreationTokens:\n receipt.cacheCreationTokens -\n cumulativeBaseline.cacheCreationTokens,\n }\n : {}),\n ...(typeof receipt.reasoningOutputTokens === \"number\" &&\n typeof cumulativeBaseline.reasoningOutputTokens === \"number\" &&\n receipt.reasoningOutputTokens >= cumulativeBaseline.reasoningOutputTokens\n ? {\n reasoningOutputTokens:\n receipt.reasoningOutputTokens -\n cumulativeBaseline.reasoningOutputTokens,\n }\n : {}),\n });\n cumulativeBaseline = receipt;\n }\n\n const perModel: PerModelUsage[] = [...buckets.entries()].map(\n ([modelId, bucket]) => ({\n modelId,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n cacheReadTokens: bucket.cacheReadReported ? bucket.cacheReadTokens : null,\n cacheCreationTokens: bucket.cacheCreationReported\n ? bucket.cacheCreationTokens\n : null,\n reasoningOutputTokens: bucket.reasoningReported\n ? bucket.reasoningOutputTokens\n : null,\n }),\n );\n\n // Rule 7: paired monotonic intervals; unmatched terminals are NAMED.\n function sumIntervals(\n intervals: LifecycleInterval[],\n label: string,\n ): { total: number | null; complete: boolean } {\n let total = 0;\n let closed = 0;\n for (const interval of intervals) {\n if (interval.endedAt == null) {\n missing.push(`${label} interval ${interval.id} never observed its terminal event`);\n continue;\n }\n total += Math.max(0, interval.endedAt - interval.startedAt);\n closed += 1;\n }\n if (intervals.length === 0) return { total: null, complete: true };\n return { total, complete: closed === intervals.length };\n }\n const provider = sumIntervals(input.providerTurns, \"provider turn\");\n const tool = sumIntervals(input.toolIntervals, \"tool\");\n\n // Rule 9: COMPLETE needs a usable receipt for every observable provider turn.\n const turnsWithoutReceipts = input.providerTurns.filter(\n (t) => !receiptTurnIds.has(t.id),\n );\n for (const turn of turnsWithoutReceipts) {\n missing.push(`provider turn ${turn.id} carried no usable usage receipt`);\n }\n\n if (usable === 0) {\n return {\n inputTokens: null,\n outputTokens: null,\n cacheReadTokens: null,\n cacheCreationTokens: null,\n reasoningOutputTokens: null,\n providerActiveDurationMs: provider.total,\n toolDurationMs: tool.total,\n coverage: \"UNAVAILABLE\",\n missingRanges: missing,\n perModel: [],\n };\n }\n const complete =\n missing.length === 0 && provider.complete && tool.complete;\n return {\n inputTokens,\n outputTokens,\n cacheReadTokens: cacheReadReported ? cacheReadTokens : null,\n cacheCreationTokens: cacheCreationReported ? cacheCreationTokens : null,\n reasoningOutputTokens: reasoningReported ? reasoningOutputTokens : null,\n providerActiveDurationMs: provider.total,\n toolDurationMs: tool.total,\n coverage: complete ? \"COMPLETE\" : \"PARTIAL\",\n missingRanges: missing,\n perModel,\n };\n}\n", "/**\n * M20.1 \u00A715.1 \u2014 Claude Code capture: a PURE, DETERMINISTIC mapper from the\n * transcript entries the SUPPORTED hook surface names (`transcript_path` is a\n * documented lifecycle-hook payload) onto the v1 SessionEvent envelope.\n *\n * Only OBSERVABLE shapes are mapped \u2014 visible user/assistant messages, tool\n * calls/results, and usage receipts. Anything unrecognized maps to null and\n * is counted by the capability snapshot rather than guessed at (\u00A715.3). No\n * semantic classification happens here (frozen decision 19).\n */\n\nimport type { TimingLine } from \"./session-claude-timing.js\";\nimport type { SessionEvent } from \"./session-events.js\";\nimport { SESSION_EVENT_VERSION } from \"./session-events.js\";\n\ninterface ClaudeContentBlock {\n type?: string;\n text?: string;\n id?: string;\n name?: string;\n input?: unknown;\n tool_use_id?: string;\n content?: unknown;\n is_error?: boolean;\n}\n\ninterface ClaudeTranscriptEntry {\n type?: string;\n uuid?: string;\n timestamp?: string;\n /** True on subagent (sidechain) entries \u2014 not the operator's own turn. */\n isSidechain?: boolean;\n message?: {\n role?: string;\n /**\n * control-room AC2.1 \u2014 the model the provider ACTUALLY ran, as Claude Code\n * stamps it on every assistant entry. Free: the host already tails this\n * file, and nothing else in the record knows which model produced the work.\n */\n model?: string;\n content?: ClaudeContentBlock[] | string;\n usage?: {\n input_tokens?: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n output_tokens?: number;\n };\n };\n}\n\nexport interface MappedTranscriptLine {\n events: Array<Omit<SessionEvent, \"sequence\">>;\n /** True when the line held a shape this adapter does not observe. */\n unrecognized: boolean;\n /**\n * The model this line names, when it named one (assistant entries only).\n * Reported, never accumulated \u2014 this mapper stays pure and per-line; the\n * bridge decides what \"the session's model\" is.\n */\n modelId?: string;\n /**\n * control-room AC3.7 \u2014 what this line contributes to interval timing.\n * Reported per line for the same reason as `modelId`: pairing is cross-line\n * state, and it lives in ClaudeTimingTracker, not in this mapper.\n */\n timing?: TimingLine;\n}\n\nfunction baseEvent(\n entry: ClaudeTranscriptEntry,\n kind: SessionEvent[\"kind\"],\n payload: unknown,\n idSuffix = \"\",\n): Omit<SessionEvent, \"sequence\"> {\n return {\n version: SESSION_EVENT_VERSION,\n at: entry.timestamp ?? new Date(0).toISOString(),\n provider: \"claude\",\n ...(entry.uuid ? { providerEventId: `${entry.uuid}${idSuffix}` } : {}),\n kind,\n payload,\n };\n}\n\nfunction textOf(content: ClaudeContentBlock[] | string | undefined): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .filter((block) => block.type === \"text\" && typeof block.text === \"string\")\n .map((block) => block.text)\n .join(\"\\n\");\n}\n\n/** Map ONE transcript JSONL line. Deterministic; never throws. */\nexport function mapClaudeTranscriptLine(line: string): MappedTranscriptLine {\n let entry: ClaudeTranscriptEntry;\n try {\n entry = JSON.parse(line) as ClaudeTranscriptEntry;\n } catch {\n return { events: [], unrecognized: true };\n }\n if (entry?.type !== \"user\" && entry?.type !== \"assistant\") {\n // summary/meta/system lines are not observable conversation events.\n return { events: [], unrecognized: false };\n }\n const events: Array<Omit<SessionEvent, \"sequence\">> = [];\n const content = entry.message?.content;\n\n if (entry.type === \"user\") {\n const blocks = Array.isArray(content) ? content : [];\n const toolResults = blocks.filter((b) => b.type === \"tool_result\");\n for (const block of toolResults) {\n events.push(\n baseEvent(\n entry,\n \"tool_result\",\n {\n toolUseId: block.tool_use_id ?? null,\n isError: Boolean(block.is_error),\n content: block.content ?? null,\n },\n `:result:${block.tool_use_id ?? \"\"}`,\n ),\n );\n }\n const text = textOf(content);\n if (text) {\n events.push(baseEvent(entry, \"user_message\", { text }));\n }\n return {\n events,\n unrecognized: false,\n ...timingOf(entry, {\n toolEnds: toolResults\n .map((block) => block.tool_use_id)\n .filter((id): id is string => typeof id === \"string\"),\n }),\n };\n }\n\n // assistant\n const modelId =\n typeof entry.message?.model === \"string\" && entry.message.model.trim()\n ? entry.message.model.trim()\n : undefined;\n const blocks = Array.isArray(content) ? content : [];\n const text = textOf(content);\n if (text) {\n events.push(baseEvent(entry, \"assistant_message\", { text }));\n }\n for (const block of blocks) {\n if (block.type === \"tool_use\") {\n events.push(\n baseEvent(\n entry,\n \"tool_call\",\n { toolUseId: block.id ?? null, name: block.name ?? null, input: block.input ?? null },\n `:tool:${block.id ?? \"\"}`,\n ),\n );\n }\n }\n const usage = entry.message?.usage;\n if (\n usage &&\n (typeof usage.input_tokens === \"number\" ||\n typeof usage.cache_creation_input_tokens === \"number\" ||\n typeof usage.cache_read_input_tokens === \"number\" ||\n typeof usage.output_tokens === \"number\")\n ) {\n // Claude reports PER-TURN usage \u2014 a delta receipt keyed by the entry uuid.\n // Anthropic's input_tokens EXCLUDES cache tokens (siblings, not a subset \u2014\n // unlike OpenAI's cached_input_tokens), so total input is the three summed.\n // The cache split rides along (AGE-938) \u2014 but only when the entry actually\n // carried a cache field, so an old transcript format stays \"unreported\"\n // rather than claiming a measured zero.\n const hasCacheFields =\n typeof usage.cache_read_input_tokens === \"number\" ||\n typeof usage.cache_creation_input_tokens === \"number\";\n events.push(\n baseEvent(\n entry,\n \"usage\",\n {\n kind: \"delta\",\n inputTokens:\n (usage.input_tokens ?? 0) +\n (usage.cache_creation_input_tokens ?? 0) +\n (usage.cache_read_input_tokens ?? 0),\n outputTokens: usage.output_tokens ?? 0,\n ...(hasCacheFields\n ? {\n cacheReadTokens: usage.cache_read_input_tokens ?? 0,\n cacheCreationTokens: usage.cache_creation_input_tokens ?? 0,\n }\n : {}),\n // TPM Slice 2 (AC2.4): the model that produced THIS receipt \u2014 the\n // same entry stamps both, which is what makes per-model grouping a\n // grouped receipt rather than an estimate. Anthropic does not split\n // reasoning tokens out, so no reasoningOutputTokens here (absent,\n // never 0).\n ...(modelId ? { modelId } : {}),\n },\n \":usage\",\n ),\n );\n }\n return {\n events,\n unrecognized: false,\n ...(modelId ? { modelId } : {}),\n ...timingOf(entry, {\n toolStarts: blocks\n .filter((block) => block.type === \"tool_use\")\n .map((block) => block.id)\n .filter((id): id is string => typeof id === \"string\"),\n }),\n };\n}\n\n/**\n * The timing contribution of one entry, or nothing when the entry carries no\n * parseable timestamp. An unparseable timestamp yields NO interval rather than\n * an epoch-zero one \u2014 a fabricated 56-year duration is worse than a named gap.\n */\nfunction timingOf(\n entry: ClaudeTranscriptEntry,\n parts: { toolStarts?: string[]; toolEnds?: string[] },\n): { timing: TimingLine } | Record<string, never> {\n const at = entry.timestamp ? Date.parse(entry.timestamp) : NaN;\n if (!Number.isFinite(at)) return {};\n return {\n timing: {\n at,\n id: entry.uuid ?? String(at),\n role: entry.type === \"assistant\" ? \"assistant\" : \"user\",\n ...(parts.toolStarts?.length ? { toolStarts: parts.toolStarts } : {}),\n ...(parts.toolEnds?.length ? { toolEnds: parts.toolEnds } : {}),\n },\n };\n}\n\n/**\n * Taxonomy AC5.1 (D9) \u2014 the session's OPENING user prompt: the first\n * non-sidechain user entry with visible text, read from the transcript's own\n * head (the transcript begins at session start even when capture attached\n * later). Null when no such entry exists yet \u2014 the caller retries while the\n * transcript grows and files nothing on a session whose transcript never\n * appears. Pure and deterministic; never throws.\n */\nexport function openingPromptOf(transcript: string): string | null {\n for (const line of transcript.split(\"\\n\")) {\n if (!line.trim()) continue;\n let entry: ClaudeTranscriptEntry;\n try {\n entry = JSON.parse(line) as ClaudeTranscriptEntry;\n } catch {\n continue;\n }\n if (entry?.type !== \"user\" || entry.isSidechain) continue;\n const text = textOf(entry.message?.content);\n if (text.trim()) return text;\n }\n return null;\n}\n", "/**\n * Jentrix MVP Control Room \u2014 04-2 timing (control-room PRD AC3.6/AC3.7).\n *\n * `providerActiveDurationMs` and `toolDurationMs` are null on every session\n * row ever written, and the reason is locatable rather than mysterious:\n * `aggregateSessionUsage` returns null for an EMPTY interval list\n * (session-usage.ts), and the only caller of the bridge's interval marks is\n * the CODEX interactive host. The Claude transcript-tailing path \u2014 the only\n * one the MVP actually uses \u2014 never marked an interval, so both columns were\n * structurally null.\n *\n * The gap report offered \"populate or drop the columns\". Dropping was refused\n * on evidence (17 files read them, and the schema is shared with the parent\n * deployment), so this module populates them. It is the pairing half only: the\n * aggregator already knew how to sum intervals.\n *\n * Both figures are MEASURED from timestamps the transcript already carries,\n * never derived by subtraction:\n *\n * \u2022 toolDurationMs \u2014 each `tool_use` block paired with the\n * `tool_result` that answers it.\n * \u2022 providerActiveDurationMs \u2014 each assistant entry paired with whatever\n * handed it control: the user message that prompted\n * it, or the tool result that unblocked it.\n *\n * \"Turn duration minus tool time\" would have been the easy definition and a\n * dishonest one \u2014 it goes negative under parallel tools and reports queueing\n * as generation. Measuring each generation segment where it actually begins\n * costs one more piece of state and answers the question that was asked.\n *\n * PURE and DETERMINISTIC: no I/O, no clock. The wall-clock timestamps in the\n * transcript ARE the right clock here \u2014 this is a replay of recorded events,\n * not a live measurement, and the aggregator clamps each pair at zero.\n */\n\nexport type ObservedIntervalKind = \"turn\" | \"tool\";\n\nexport interface ObservedInterval {\n kind: ObservedIntervalKind;\n /** Stable per-interval id \u2014 the aggregator dedupes and names gaps by it. */\n id: string;\n startedAt: number;\n endedAt: number;\n}\n\n/** What one mapped transcript line contributes to timing. */\nexport interface TimingLine {\n /** Epoch ms parsed from the entry's own timestamp. */\n at: number;\n role: \"user\" | \"assistant\";\n /** `tool_use` block ids this assistant entry opened. */\n toolStarts?: readonly string[];\n /** `tool_use_id`s this user entry answered. */\n toolEnds?: readonly string[];\n /** The entry's uuid \u2014 used to name the generation segment. */\n id: string;\n}\n\n/**\n * Pairs transcript lines into closed intervals as they stream past.\n *\n * Stateful by necessity (pairing is cross-line) but I/O-free and clock-free,\n * so the whole rule is unit-testable from a list of lines.\n */\nexport class ClaudeTimingTracker {\n /**\n * When the provider was last handed control: the newest user message or\n * tool result. Null before the first one \u2014 an assistant entry with no\n * preceding boundary (a resumed transcript whose head we never saw) yields\n * NO interval rather than an invented one starting at zero.\n */\n private boundaryAt: number | null = null;\n private readonly openTools = new Map<string, number>();\n\n /** Feed one line; returns every interval this line CLOSED. */\n observe(line: TimingLine): ObservedInterval[] {\n const closed: ObservedInterval[] = [];\n\n for (const toolUseId of line.toolEnds ?? []) {\n const startedAt = this.openTools.get(toolUseId);\n if (startedAt === undefined) continue; // opened before we were watching\n this.openTools.delete(toolUseId);\n closed.push({\n kind: \"tool\",\n id: `tool:${toolUseId}`,\n startedAt,\n endedAt: line.at,\n });\n }\n\n if (line.role === \"assistant\") {\n if (this.boundaryAt !== null) {\n closed.push({\n kind: \"turn\",\n id: `turn:${line.id}`,\n startedAt: this.boundaryAt,\n endedAt: line.at,\n });\n }\n for (const toolUseId of line.toolStarts ?? []) {\n this.openTools.set(toolUseId, line.at);\n }\n // An assistant entry that called tools does NOT hand control back to the\n // provider \u2014 the tools run next, and their results are the boundary that\n // does. Without this, the wait for a tool would be billed as generation.\n this.boundaryAt = (line.toolStarts?.length ?? 0) > 0 ? null : line.at;\n return closed;\n }\n\n // A user entry always hands control to the provider: a typed message, or\n // a tool result that unblocks the turn already in flight.\n this.boundaryAt = line.at;\n return closed;\n }\n\n /**\n * Tool calls still open at close \u2014 a killed host, a tool that never\n * returned. Reported so the aggregator can NAME the gap and degrade\n * coverage to PARTIAL rather than quietly summing a shorter total.\n */\n unclosedToolIds(): string[] {\n return [...this.openTools.keys()].map((id) => `tool:${id}`);\n }\n}\n", "/**\n * M20.1 \u00A715.2 \u2014 Codex capture: a PURE, DETERMINISTIC mapper from the\n * SUPPORTED SDK/app-server thread event stream (the same `runStreamed` events\n * the runner's provider adapter consumes) onto the v1 SessionEvent envelope.\n * Only observable shapes are mapped; unrecognized events surface through the\n * capability snapshot, never through guessing (\u00A715.3). No private session\n * files are ever parsed (PRD \u00A78.3).\n */\n\nimport type { SessionEvent } from \"./session-events.js\";\nimport { SESSION_EVENT_VERSION } from \"./session-events.js\";\n\ninterface CodexThreadEvent {\n type?: string;\n thread_id?: string;\n item?: {\n id?: string;\n type?: string;\n text?: string;\n command?: string;\n aggregated_output?: string;\n exit_code?: number;\n changes?: unknown;\n name?: string;\n arguments?: unknown;\n result?: unknown;\n status?: string;\n };\n usage?: {\n input_tokens?: number;\n cached_input_tokens?: number;\n output_tokens?: number;\n /** TPM Slice 2 (AC2.7): subset of output_tokens, when reported. */\n reasoning_output_tokens?: number;\n };\n /** TPM Slice 2 (AC2.4): app-server turn context \u2014 names the model PER TURN. */\n model?: string;\n turn_context?: { model?: string };\n error?: { message?: string };\n}\n\nexport interface MappedCodexEvent {\n event: Omit<SessionEvent, \"sequence\"> | null;\n /** The provider thread id when this event carries it (thread.started). */\n threadId?: string;\n /**\n * TPM Slice 2 (AC2.4): the model this event names, when it names one (a\n * turn_context event). Reported, never accumulated \u2014 the host decides what\n * \"the current model\" is, exactly like the Claude mapper's per-line report.\n */\n modelId?: string;\n unrecognized: boolean;\n}\n\nfunction make(\n kind: SessionEvent[\"kind\"],\n payload: unknown,\n providerEventId?: string,\n): Omit<SessionEvent, \"sequence\"> {\n return {\n version: SESSION_EVENT_VERSION,\n at: new Date(0).toISOString(), // stamped by the bridge at observation time\n provider: \"codex\",\n ...(providerEventId ? { providerEventId } : {}),\n kind,\n payload,\n };\n}\n\n/** Map one Codex thread event. Deterministic; never throws. */\nexport function mapCodexThreadEvent(raw: unknown): MappedCodexEvent {\n const event = (raw ?? {}) as CodexThreadEvent;\n switch (event.type) {\n case \"thread.started\":\n return {\n event: make(\"session\", { threadId: event.thread_id ?? null }),\n ...(event.thread_id ? { threadId: event.thread_id } : {}),\n unrecognized: false,\n };\n case \"turn.started\":\n return { event: null, unrecognized: false };\n case \"turn_context\": {\n // TPM Slice 2 (AC2.4): the model can change mid-session and this event\n // is where the runtime says so. Observable-shape mapping only \u2014 when\n // the SDK stream never emits it, nothing here fires and Codex receipts\n // stay in the null-model bucket, disclosed rather than guessed.\n const model = (event.turn_context?.model ?? event.model)?.trim();\n return {\n event: null,\n ...(model ? { modelId: model } : {}),\n unrecognized: false,\n };\n }\n case \"turn.completed\":\n // OpenAI's input_tokens INCLUDES cached (cached_input_tokens is a\n // subset \u2192 cacheReadTokens). Codex has no cache-creation concept, so\n // that field is never emitted here (unreported, not zero) \u2014 AGE-938.\n return {\n event: event.usage\n ? make(\"usage\", {\n kind: \"delta\",\n inputTokens: event.usage.input_tokens ?? 0,\n outputTokens: event.usage.output_tokens ?? 0,\n ...(typeof event.usage.cached_input_tokens === \"number\"\n ? { cacheReadTokens: event.usage.cached_input_tokens }\n : {}),\n // TPM Slice 2 (AC2.7): real spend visibility OpenAI reports\n // and Anthropic does not split out \u2014 mapped only when present.\n ...(typeof event.usage.reasoning_output_tokens === \"number\"\n ? {\n reasoningOutputTokens:\n event.usage.reasoning_output_tokens,\n }\n : {}),\n })\n : null,\n unrecognized: false,\n };\n case \"turn.failed\":\n return {\n event: make(\"error\", {\n message: event.error?.message ?? \"turn failed\",\n }),\n unrecognized: false,\n };\n case \"item.completed\": {\n const item = event.item ?? {};\n const id = item.id;\n switch (item.type) {\n case \"agent_message\":\n return {\n event: make(\"assistant_message\", { text: item.text ?? \"\" }, id),\n unrecognized: false,\n };\n case \"command_execution\":\n return {\n event: make(\n \"command\",\n {\n command: item.command ?? null,\n exitCode: item.exit_code ?? null,\n output: item.aggregated_output ?? null,\n },\n id,\n ),\n unrecognized: false,\n };\n case \"file_change\":\n return {\n event: make(\"file_change\", { changes: item.changes ?? null }, id),\n unrecognized: false,\n };\n case \"mcp_tool_call\":\n return {\n event: make(\n \"tool_call\",\n {\n name: item.name ?? null,\n input: item.arguments ?? null,\n status: item.status ?? null,\n },\n id,\n ),\n unrecognized: false,\n };\n case \"reasoning\":\n // Hidden reasoning is deliberately NOT captured (PRD \u00A75 non-goal).\n return { event: null, unrecognized: false };\n default:\n return { event: null, unrecognized: true };\n }\n }\n default:\n return { event: null, unrecognized: true };\n }\n}\n", "/** Pure mapping from supported Codex lifecycle hook payloads to session events. */\n\nimport type { SessionEventKind } from \"./session-events.js\";\n\nexport interface MappedCodexHook {\n events: Array<{ kind: SessionEventKind; payload: unknown }>;\n modelId: string | null;\n}\n\nfunction text(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value : null;\n}\n\nexport function mapCodexHook(\n event: string,\n payload: Record<string, unknown>,\n): MappedCodexHook {\n const modelId = text(payload.model);\n switch (event) {\n case \"SessionStart\":\n case \"SessionEnd\":\n case \"PreCompact\":\n case \"PostCompact\":\n return {\n events: [\n {\n kind: \"session\",\n payload: {\n lifecycle: event,\n sessionId: payload.session_id ?? null,\n },\n },\n ],\n modelId,\n };\n case \"UserPromptSubmit\": {\n const prompt = text(payload.prompt);\n return {\n events: prompt\n ? [{ kind: \"user_message\", payload: { text: prompt } }]\n : [],\n modelId,\n };\n }\n case \"PostToolUse\": {\n const name = text(payload.tool_name) ?? \"unknown\";\n const events: MappedCodexHook[\"events\"] = [\n {\n kind: \"tool_call\",\n payload: { name, input: payload.tool_input ?? null },\n },\n ];\n if (\"tool_response\" in payload) {\n events.push({\n kind: \"tool_result\",\n payload: { name, result: payload.tool_response },\n });\n }\n return { events, modelId };\n }\n case \"Stop\": {\n const message = text(payload.last_assistant_message);\n return {\n events: message\n ? [{ kind: \"assistant_message\", payload: { text: message } }]\n : [],\n modelId,\n };\n }\n default:\n return { events: [], modelId };\n }\n}\n", "/**\n * M20.1 \u00A712.2 \u2014 LOCAL redaction, applied BEFORE any content reaches the\n * durable spool, upload, checksum input, or diagnostics. The server re-redacts\n * at ingestion (defense in depth) \u2014 this pass is the one that keeps a secret\n * from ever being durably written on the operator's machine.\n *\n * MIRROR of `src/server/credentials/redact.ts` (the runner sits outside the\n * app's dependency firewall; contracts are mirrored, not imported \u2014 keep the\n * pattern lists in lockstep). Adds the two client-only concerns the server\n * cannot know: configured secret ENV VALUES and home-directory prefixes.\n */\n\nexport const REDACTED = \"\u2039redacted\u203A\";\n\n// Mirrored from src/server/credentials/redact.ts \u2014 keep in lockstep.\nconst SECRET_PATTERNS: RegExp[] = [\n /\\btm[or]?_[A-Za-z0-9_-]{16,}\\b/g,\n /\\bgh[posru]_[A-Za-z0-9]{20,}\\b/g,\n /\\bgithub_pat_[A-Za-z0-9_]{20,}\\b/g,\n /\\bwhsec_[A-Za-z0-9]{16,}\\b/g,\n /\\b(?:AKIA|ASIA)[A-Z0-9]{16}\\b/g,\n /\\bxox[abpsr]-[A-Za-z0-9-]{10,}\\b/g,\n /\\bAIza[A-Za-z0-9_-]{30,}\\b/g,\n /\\bsk-ant-[A-Za-z0-9_-]{20,}\\b/g,\n /\\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\\b/g,\n /\\b[rs]k_(?:live|test)_[A-Za-z0-9]{16,}\\b/g,\n /-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/g,\n /\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/g,\n /\\b(Authorization\\s*[:=]\\s*Bearer\\s+)[A-Za-z0-9._~+/=-]{12,}/gi,\n];\n\n/** Env names whose VALUES are scrubbed wherever they appear (PRD \u00A712.2). */\nconst SECRET_ENV_NAMES = [\n \"STACKS_TOKEN\",\n \"STACKS_BOOTSTRAP_TOKEN\",\n \"STACKS_WEBHOOK_SECRET\",\n \"STACKS_WORKLOAD_SVID\",\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n \"GITHUB_TOKEN\",\n \"AWS_SECRET_ACCESS_KEY\",\n \"R2_SECRET_ACCESS_KEY\",\n];\n\nexport interface SessionRedactor {\n text(input: string): string;\n value(input: unknown): unknown;\n}\n\n/**\n * Build a redactor bound to the current process env + home directory. The\n * literal set is resolved ONCE so every spool write pays only string work.\n * Home-directory prefixes are scrubbed to `~` where the absolute path is not\n * evidence (PRD \u00A712.2) \u2014 repository identity is the normalized owner/name.\n */\nexport function createSessionRedactor(opts: {\n env?: Record<string, string | undefined>;\n homedir?: string | null;\n literals?: string[];\n} = {}): SessionRedactor {\n const env = opts.env ?? process.env;\n const literals = [\n ...(opts.literals ?? []),\n ...SECRET_ENV_NAMES.map((name) => env[name]).filter(\n (v): v is string => typeof v === \"string\" && v.length >= 6,\n ),\n ];\n const home = opts.homedir?.replace(/\\/$/, \"\");\n\n function text(input: string): string {\n let out = input;\n for (const literal of literals) {\n out = out.split(literal).join(REDACTED);\n }\n for (const pattern of SECRET_PATTERNS) {\n out = out.replace(pattern, REDACTED);\n }\n if (home && home.length > 1) {\n out = out.split(home).join(\"~\");\n }\n return out;\n }\n\n function value(input: unknown): unknown {\n if (typeof input === \"string\") return text(input);\n if (Array.isArray(input)) return input.map(value);\n if (input && typeof input === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(input as Record<string, unknown>)) {\n out[k] = value(v);\n }\n return out;\n }\n return input;\n }\n\n return { text, value };\n}\n", "/**\n * M20.1 \u00A712.3 \u2014 the crash-safe local spool. Every event line is REDACTED\n * before it is appended (the caller passes lines through the session\n * redactor first); files are mode-0600 under a mode-0700 session directory.\n *\n * Deletion contract (AC22/AC23 + the amended \u00A712.3): a part file is deleted\n * ONLY when the server acknowledged that exact content \u2014 the acknowledgement\n * carries the STORED checksum, and a redacted-slot refusal or CONFLICT keeps\n * the file. Losing the network never loses evidence; the CLI reports pending\n * parts and retries with the same part numbers.\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n appendFileSync,\n closeSync,\n mkdirSync,\n openSync,\n readdirSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n writeSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * M20.1 follow-up (AGE-929): the LOCAL liveness marker `jentrix session status`\n * reads. The server cannot see the local capture leg \u2014 a bound session whose\n * host died reads healthy until the abandonment sweep \u2014 so the host marks its\n * own lifecycle in the spool directory: `host.json` written at start, stamped\n * with the exit at clean shutdown. A crash leaves the start marker with no\n * exit; the CLI detects that shape by probing the recorded pid.\n * The CLI mirrors this file's shape rather than importing it (dependency\n * firewall \u2014 the CLI never imports the runner package).\n */\nexport interface SessionHostMarker {\n pid: number;\n startedAt: string;\n provider: string;\n mode: string;\n /**\n * Whether THIS host runs TRACE capture (AGE-956): `mode` describes how the\n * host attaches (watch/launch), never what it collects, and the CLI's\n * align must report capture truthfully from the live host's actual state \u2014\n * marker existence alone reads capture-blind.\n */\n captureTrace?: boolean;\n /**\n * AGE-957: whether the host has EVER successfully stat'ed its transcript\n * path. False after the grace window means the host is observing nothing\n * (no events, no usage receipts) \u2014 `session status` surfaces it instead of\n * letting a dead tail read as healthy silence.\n */\n transcriptSeen?: boolean;\n /**\n * WHICH transcript this host watches (2026-08-11 gap report F1/P3). Two\n * things need it. `transcriptSeen: true` only reports that the host found A\n * transcript, so proving it found THIS session's needs the path recorded.\n * And a compaction hook, whose cwd is the SESSION's directory and not\n * necessarily the aligned checkout, resolves its Jentrix session by matching\n * the hook payload's transcript_path against this field \u2014 a provable link\n * where a cwd match is a guess.\n */\n transcriptPath?: string;\n /**\n * Cumulative server-acknowledged part count + when the last flush ran \u2014\n * an empty spool is ambiguous (nothing captured vs everything flushed);\n * this stamp is how `session status` tells the two apart.\n */\n ackedParts?: number;\n lastFlushAt?: string;\n exitedAt?: string;\n exitCode?: number;\n}\n\nexport function writeHostMarker(\n sessionDir: string,\n marker: Pick<\n SessionHostMarker,\n \"pid\" | \"provider\" | \"mode\" | \"captureTrace\" | \"transcriptPath\"\n >,\n): void {\n mkdirSync(sessionDir, { recursive: true, mode: 0o700 });\n const body: SessionHostMarker = {\n ...marker,\n startedAt: new Date().toISOString(),\n };\n writeFileSync(join(sessionDir, \"host.json\"), JSON.stringify(body), {\n mode: 0o600,\n });\n}\n\n/** Stamp whether the transcript path has ever been seen (AGE-957). */\nexport function markHostTranscript(sessionDir: string, seen: boolean): void {\n const path = join(sessionDir, \"host.json\");\n let marker: SessionHostMarker;\n try {\n marker = JSON.parse(readFileSync(path, \"utf8\")) as SessionHostMarker;\n } catch {\n return; // no start marker to stamp \u2014 best-effort\n }\n marker.transcriptSeen = seen;\n writeFileSync(path, JSON.stringify(marker), { mode: 0o600 });\n}\n\nexport function markHostFlushed(sessionDir: string, ackedParts: number): void {\n const path = join(sessionDir, \"host.json\");\n let marker: SessionHostMarker;\n try {\n marker = JSON.parse(readFileSync(path, \"utf8\")) as SessionHostMarker;\n } catch {\n return; // no start marker to stamp \u2014 best-effort\n }\n marker.ackedParts = ackedParts;\n marker.lastFlushAt = new Date().toISOString();\n writeFileSync(path, JSON.stringify(marker), { mode: 0o600 });\n}\n\nexport function markHostExited(sessionDir: string, exitCode: number): void {\n const path = join(sessionDir, \"host.json\");\n let marker: SessionHostMarker;\n try {\n marker = JSON.parse(readFileSync(path, \"utf8\")) as SessionHostMarker;\n } catch {\n return; // no start marker to stamp \u2014 best-effort\n }\n marker.exitedAt = new Date().toISOString();\n marker.exitCode = exitCode;\n writeFileSync(path, JSON.stringify(marker), { mode: 0o600 });\n}\n\n/** Rotate a part before it crosses the server's inline ingestion cap. */\nexport const SPOOL_PART_ROTATE_BYTES = 6 * 1024 * 1024;\n\nconst PART_FILE = /^part-(\\d{6})\\.ndjson$/;\n\nexport interface SpoolPart {\n part: number;\n path: string;\n byteSize: number;\n /** sha256 over the part's redacted NDJSON text \u2014 the convergence identity. */\n checksum: string;\n}\n\nexport class SessionSpool {\n private readonly dir: string;\n private currentPart: number;\n\n constructor(root: string, sessionId: string) {\n this.dir = join(root, sessionId);\n mkdirSync(this.dir, { recursive: true, mode: 0o700 });\n const existing = this.listPartNumbers();\n this.currentPart = existing.length ? Math.max(...existing) : 0;\n }\n\n get directory(): string {\n return this.dir;\n }\n\n private partPath(part: number): string {\n return join(this.dir, `part-${String(part).padStart(6, \"0\")}.ndjson`);\n }\n\n private listPartNumbers(): number[] {\n return readdirSync(this.dir)\n .map((name) => PART_FILE.exec(name))\n .filter((m): m is RegExpExecArray => m !== null)\n .map((m) => Number(m[1]));\n }\n\n /**\n * Append one ALREADY-REDACTED NDJSON line durably (0600, fsync'd). Rotates\n * to the next part when the current one would cross the ingestion cap.\n */\n append(redactedLine: string): void {\n const path = this.partPath(this.currentPart);\n let size = 0;\n try {\n size = statSync(path).size;\n } catch {\n // first line of a new part\n }\n if (\n size > 0 &&\n size + Buffer.byteLength(redactedLine) > SPOOL_PART_ROTATE_BYTES\n ) {\n this.currentPart += 1;\n }\n const target = this.partPath(this.currentPart);\n const fd = openSync(target, \"a\", 0o600);\n try {\n writeSync(fd, redactedLine);\n } finally {\n closeSync(fd);\n }\n }\n\n /**\n * Advance past a flushed (acked + deleted) part. Ingestion slots are\n * append-only \u2014 same part + different checksum is a permanent CONFLICT \u2014\n * so a slot the server acknowledged must never be reused for new events.\n */\n advancePast(part: number): void {\n if (part >= this.currentPart) this.currentPart = part + 1;\n }\n\n /** Cheap append without rotation checks (tests / recovery merges). */\n appendRaw(part: number, redactedLine: string): void {\n appendFileSync(this.partPath(part), redactedLine, { mode: 0o600 });\n if (part > this.currentPart) this.currentPart = part;\n }\n\n /** Every pending part with its convergence checksum, ordered by number. */\n pendingParts(): SpoolPart[] {\n return this.listPartNumbers()\n .sort((a, b) => a - b)\n .map((part) => {\n const path = this.partPath(part);\n const body = readFileSync(path, \"utf8\");\n return {\n part,\n path,\n byteSize: Buffer.byteLength(body),\n checksum: createHash(\"sha256\").update(body, \"utf8\").digest(\"hex\"),\n };\n });\n }\n\n /** Read one part's redacted text for upload. */\n readPart(part: number): string {\n return readFileSync(this.partPath(part), \"utf8\");\n }\n\n /**\n * Delete a part ONLY on a server acknowledgement of this exact content.\n * `acknowledgedChecksum` is the STORED checksum from the server's ack; when\n * the server's re-redaction changed the bytes, the caller records the acked\n * checksum into its manifest first, then confirms deletion explicitly with\n * `force`. An audit stub can never satisfy this \u2014 a refusal keeps the file.\n */\n deleteAcknowledged(\n part: number,\n acknowledgedChecksum: string,\n opts: { force?: boolean } = {},\n ): boolean {\n const path = this.partPath(part);\n let body: string;\n try {\n body = readFileSync(path, \"utf8\");\n } catch {\n return false; // already gone\n }\n const localChecksum = createHash(\"sha256\")\n .update(body, \"utf8\")\n .digest(\"hex\");\n if (localChecksum !== acknowledgedChecksum && !opts.force) {\n return false;\n }\n // Atomic-ish removal: rename first so a crash mid-delete never leaves a\n // half-truncated live part.\n const tomb = `${path}.acked`;\n renameSync(path, tomb);\n unlinkSync(tomb);\n return true;\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * M20.1 \u00A715 \u2014 the connected-session HOST: the runner-side orchestration that\n * launches (or drives) the interactive provider with capture running beside\n * it. Invoked by `stacks-runner session-run --plan-stdin`; the CLI (which may\n * not import provider SDKs \u2014 LRO-AC14) hands it a transient plan over stdin.\n *\n * Claude: the provider's own interactive UI runs untouched; a temp\n * hooks-settings file makes the SUPPORTED lifecycle hooks append their stdin\n * JSON to the session's hooks file via `stacks-runner session-hook`, giving\n * the bridge the TRUSTED `session_id` + `transcript_path` (AC17) and the\n * transcript tail to map. Hooks never carry credentials or transcript content\n * in argv.\n *\n * Codex: plugin watch mode consumes the supported lifecycle hook ledger for\n * one exact task id. `jentrix session codex` remains the SDK-driven terminal\n * fallback, with every `runStreamed` event mapped deterministically.\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport {\n appendFileSync,\n existsSync,\n mkdirSync,\n readFileSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline\";\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\n\nimport {\n createConfigBearerSource,\n isUnauthorizedishError,\n staticBearerSource,\n type SessionBearerSource,\n} from \"./session-auth.js\";\nimport { SessionBridge, type SessionCallTool } from \"./session-bridge.js\";\nimport {\n mapClaudeTranscriptLine,\n openingPromptOf,\n} from \"./session-claude-transcript.js\";\nimport { ClaudeTimingTracker } from \"./session-claude-timing.js\";\nimport { mapCodexThreadEvent } from \"./session-codex-events.js\";\nimport { mapCodexHook } from \"./session-codex-hooks.js\";\nimport { createSessionRedactor } from \"./session-redact.js\";\nimport { readHookLines } from \"./session-hook-log.js\";\nimport {\n markHostExited,\n markHostFlushed,\n markHostTranscript,\n SessionSpool,\n writeHostMarker,\n} from \"./session-spool.js\";\nimport { RUNNER_VERSION } from \"./version.js\";\n\nexport interface SessionRunPlan {\n protocolVersion: 1;\n sessionId: string;\n provider: \"claude\" | \"codex\";\n jentrixBaseUrl: string;\n mcpUrl: string;\n /** Transient human credential \u2014 held in memory only, never persisted. */\n bearer: string;\n /**\n * The CLI config file the bearer's OAuth rotations persist to. When set,\n * the host resolves its bearer through it (and can rotate) instead of\n * holding the spawn-time snapshot \u2014 a `tmo_` token is revoked the moment\n * any concurrent CLI call rotates, which is how a live capture-off host\n * lost its whole usage rollup (2026-08-08). Absent = PAT/static behavior.\n */\n configPath?: string | null;\n repoRoot: string;\n installationId: string;\n /**\n * \"launch\" (default) starts the provider; \"watch\" attaches BESIDE an\n * already-running provider session (the /jentrix-connect flow): no spawn,\n * hook + transcript polling only, ends on the SessionEnd hook.\n */\n mode?: \"launch\" | \"watch\";\n /** Watch mode: exact provider task id used to filter a shared hook ledger. */\n providerSessionId?: string | null;\n /** Watch mode: provider-global lifecycle ledger directory. */\n hookDir?: string | null;\n resumeProviderSessionId?: string | null;\n /** Watch mode: the trusted transcript path from the lifecycle hook. */\n transcriptPath?: string | null;\n /**\n * Watch mode: capture begins AT the attach point by default (\u00A715.2 \u2014 the\n * tail starts at the transcript's current end); true reads from byte 0 so\n * prior VISIBLE history enters the trace (`--import-history`).\n */\n importHistory?: boolean;\n /**\n * Jentrix MVP (stacks-mvp PRD \u00A76): false = TRACE capture OFF \u2014 the host\n * still heartbeats and aggregates provider usage receipts, but spools and\n * uploads NO trace parts and submits NO manifest. Default true (the 0.4.x\n * behavior); `jentrix align` sets false unless --capture re-enables it.\n */\n captureTrace?: boolean;\n executablePath?: string | null;\n spoolRoot?: string | null;\n}\n\nexport function defaultSpoolRoot(): string {\n return join(homedir(), \".config\", \"stacks\", \"session-spool\");\n}\n\n/** Config-following bearer when the plan names the CLI config; static else. */\nfunction bearerSourceOf(\n plan: Pick<SessionRunPlan, \"bearer\" | \"configPath\">,\n log: (line: string) => void,\n): SessionBearerSource {\n return plan.configPath\n ? createConfigBearerSource({\n configPath: plan.configPath,\n fallback: plan.bearer,\n log,\n })\n : staticBearerSource(plan.bearer);\n}\n\n/**\n * One-shot MCP call carrying the bearer AND the session-correlation header.\n * The bearer comes from a source (not a snapshot): a `tmo_` access token is\n * revoked the moment any concurrent CLI call rotates it, so each attempt\n * resolves the CURRENT bearer, and one unauthorized failure gets one retry\n * after asking the source to refresh (2026-08-08 capture-off finding).\n */\nexport function sessionCallTool(\n mcpUrl: string,\n bearerSource: SessionBearerSource,\n sessionId: string,\n): SessionCallTool {\n const attempt = async (\n bearer: string,\n name: string,\n args: Record<string, unknown>,\n ): Promise<Record<string, unknown>> => {\n const transport = new StreamableHTTPClientTransport(new URL(mcpUrl), {\n requestInit: {\n headers: {\n Authorization: `Bearer ${bearer}`,\n \"X-Stacks-Session-Id\": sessionId,\n },\n },\n });\n const client = new Client({\n name: \"stacks-session-host\",\n version: RUNNER_VERSION,\n });\n await client.connect(transport, { timeout: 60_000 });\n try {\n const res = await client.callTool({ name, arguments: args }, undefined, {\n timeout: 60_000,\n });\n if (res.isError) {\n const text =\n Array.isArray(res.content) &&\n res.content[0] &&\n \"text\" in res.content[0]\n ? (res.content[0] as { text: string }).text\n : JSON.stringify(res.content);\n throw new Error(`${name} failed: ${text}`);\n }\n return (res.structuredContent ?? {}) as Record<string, unknown>;\n } finally {\n await client.close();\n }\n };\n return async (name, args) => {\n const bearer = bearerSource.get();\n try {\n return await attempt(bearer, name, args);\n } catch (error) {\n if (!isUnauthorizedishError(error)) throw error;\n const next = await bearerSource.refresh(bearer);\n if (!next || next === bearer) throw error;\n return attempt(next, name, args);\n }\n };\n}\n\n// The hook log moved to its own module so the `session-hook` verb \u2014 a Claude\n// Code lifecycle hook, on the operator's critical path \u2014 can append a line\n// without loading this file's MCP client and transports (P5). Re-exported here\n// so every existing importer is unchanged; `readHookLines` is also imported\n// above, because the watch loop below calls it.\nexport {\n appendHookEvent,\n readHookLines,\n safeParse,\n type HookLine,\n} from \"./session-hook-log.js\";\n\n/** The Claude hooks-settings document (temp file, referenced by --settings). */\nexport function claudeHookSettings(\n runnerBin: string,\n sessionDir: string,\n): Record<string, unknown> {\n const hook = (event: string) => [\n {\n hooks: [\n {\n type: \"command\",\n // argv carries only the runner binary, the session DIRECTORY, and\n // the event name \u2014 never credentials or transcript content (\u00A715.1).\n command: `${runnerBin} session-hook --dir ${JSON.stringify(sessionDir)} --event ${event}`,\n },\n ],\n },\n ];\n return {\n hooks: {\n SessionStart: hook(\"SessionStart\"),\n UserPromptSubmit: hook(\"UserPromptSubmit\"),\n Stop: hook(\"Stop\"),\n SessionEnd: hook(\"SessionEnd\"),\n },\n };\n}\n\ninterface HostDeps {\n spawnImpl?: typeof spawn;\n fetchImpl?: typeof fetch;\n /** Injectable MCP caller (integration tests); default opens a transport. */\n callTool?: SessionCallTool;\n log?: (line: string) => void;\n}\n\nasync function endRepoState(repoRoot: string): Promise<{\n branch: string | null;\n head: string | null;\n dirty: boolean | null;\n}> {\n const run = (args: string[]) =>\n new Promise<{ code: number; stdout: string }>((resolve) => {\n const child = spawn(\"git\", args, { cwd: repoRoot });\n let stdout = \"\";\n child.stdout?.on(\"data\", (chunk: Buffer) => (stdout += String(chunk)));\n child.once(\"error\", () => resolve({ code: 1, stdout: \"\" }));\n child.once(\"exit\", (code) => resolve({ code: code ?? 1, stdout }));\n });\n const [branch, head, status] = await Promise.all([\n run([\"symbolic-ref\", \"--short\", \"-q\", \"HEAD\"]),\n run([\"rev-parse\", \"HEAD\"]),\n run([\"status\", \"--porcelain\"]),\n ]);\n return {\n branch: branch.code === 0 ? branch.stdout.trim() || null : null,\n head: head.code === 0 ? head.stdout.trim() || null : null,\n dirty: status.code === 0 ? status.stdout.trim().length > 0 : null,\n };\n}\n\n/**\n * Run a lifecycle-watched session. Claude launch/watch uses hooks plus its\n * supported transcript; Codex watch mode consumes only the trusted plugin\n * hook ledger. Returns non-zero while capture is pending (\u00A720).\n */\nexport async function runClaudeSessionHost(\n plan: SessionRunPlan,\n deps: HostDeps = {},\n): Promise<number> {\n const log = deps.log ?? ((line: string) => process.stderr.write(`${line}\\n`));\n const spoolRoot = plan.spoolRoot ?? defaultSpoolRoot();\n const spool = new SessionSpool(spoolRoot, plan.sessionId);\n const sessionDir = spool.directory;\n // AGE-929: local liveness marker \u2014 `jentrix session status` probes this pid.\n writeHostMarker(sessionDir, {\n pid: process.pid,\n provider: plan.provider,\n mode: plan.mode === \"watch\" ? \"watch\" : \"launch\",\n captureTrace: plan.captureTrace !== false,\n // F1/P3: the transcript this host is bound to \u2014 what a compaction hook\n // matches on to find its session without guessing from cwd.\n ...(plan.transcriptPath ? { transcriptPath: plan.transcriptPath } : {}),\n });\n const traceCapture = plan.captureTrace !== false;\n const bearerSource = bearerSourceOf(plan, log);\n const bridge = new SessionBridge({\n jentrixBaseUrl: plan.jentrixBaseUrl,\n bearer: () => bearerSource.get(),\n onUnauthorized: (failed) => bearerSource.refresh(failed),\n sessionId: plan.sessionId,\n provider: plan.provider,\n spool,\n redactor: createSessionRedactor({ homedir: homedir() }),\n callTool:\n deps.callTool ??\n sessionCallTool(plan.mcpUrl, bearerSource, plan.sessionId),\n fetchImpl: deps.fetchImpl,\n traceCapture,\n log,\n });\n bridge.recordCapabilities(\n plan.provider === \"codex\"\n ? {\n provider: \"codex\",\n providerVersion: null,\n observable: [\n \"session\",\n \"user_message\",\n \"assistant_message\",\n \"tool_call\",\n \"tool_result\",\n ],\n notObservable: [\"command\", \"file_change\", \"plan\", \"usage\", \"error\"],\n }\n : {\n provider: \"claude\",\n providerVersion: null,\n observable: [\n \"session\",\n \"user_message\",\n \"assistant_message\",\n \"tool_call\",\n \"tool_result\",\n \"usage\",\n \"error\",\n ],\n notObservable: [\"command\", \"file_change\", \"plan\"],\n },\n );\n bridge.startObserving();\n\n const watch = plan.mode === \"watch\";\n let child: ChildProcess | null = null;\n if (!watch) {\n const runnerBin = process.argv[1] ?? \"stacks-runner\";\n const settingsPath = join(sessionDir, \"claude-hooks.json\");\n writeFileSync(\n settingsPath,\n JSON.stringify(claudeHookSettings(runnerBin, sessionDir), null, 2),\n { mode: 0o600 },\n );\n const args = [\"--settings\", settingsPath];\n if (plan.resumeProviderSessionId) {\n args.push(\"--resume\", plan.resumeProviderSessionId);\n }\n child = (deps.spawnImpl ?? spawn)(plan.executablePath ?? \"claude\", args, {\n cwd: plan.repoRoot,\n stdio: \"inherit\",\n });\n }\n\n const hookDir = plan.hookDir ?? sessionDir;\n let hookOffset = 0;\n if (watch && plan.hookDir && !plan.importHistory) {\n try {\n hookOffset = readFileSync(join(hookDir, \"hooks.ndjson\"), \"utf8\").length;\n } catch {\n // The first post-attach hook creates the ledger.\n }\n }\n let transcriptPath: string | null = watch\n ? (plan.transcriptPath ?? null)\n : null;\n let transcriptOffset = 0;\n // control-room AC3.7 \u2014 one tracker per host, pairing observed transcript\n // timestamps into the provider-turn and tool intervals the usage aggregator\n // sums. Held here (not in the bridge) so the pairing rule stays a pure,\n // separately-tested module.\n const timing = new ClaudeTimingTracker();\n // AGE-957: a transcript path that never appears means the host observes\n // NOTHING (no events, no usage receipts) \u2014 track it, warn once after the\n // grace window, and stamp host.json so `session status` can say so.\n let transcriptSeen = false;\n let transcriptWarned = false;\n const hostStartedMs = Date.now();\n const noteTranscriptSeen = () => {\n if (!transcriptSeen) {\n transcriptSeen = true;\n markHostTranscript(sessionDir, true);\n }\n };\n if (watch && transcriptPath && !plan.importHistory) {\n // Capture begins at attachment (\u00A715.2): start the tail at the CURRENT\n // end of the transcript. `--import-history` reads from byte 0 instead.\n try {\n transcriptOffset = statSync(transcriptPath).size;\n noteTranscriptSeen();\n } catch {\n // no transcript yet \u2014 everything it gains is post-attach anyway\n }\n }\n let bound = watch; // watch mode attaches an ALREADY-bound provider session\n let sessionEnded = false;\n let lastPeriodicFlushAt = 0;\n // Taxonomy AC5.1 (D9) \u2014 the opening-prompt request `jentrix align` drops at\n // align-confirm. Attempted at most every 30s; filed EXACTLY once (the\n // filed-marker survives restarts, and the server dedupes by checksum\n // besides). Works with TRACE capture off \u2014 this never touches the spool.\n let lastPromptAttemptAt = 0;\n const promptRedactor = createSessionRedactor({ homedir: homedir() });\n const fileOpeningPrompt = async (): Promise<void> => {\n const requestPath = join(sessionDir, \"prompt-request.json\");\n const filedPath = join(sessionDir, \"prompt-filed.json\");\n if (!existsSync(requestPath)) return;\n if (existsSync(filedPath)) {\n try {\n unlinkSync(requestPath);\n } catch {\n // best-effort \u2014 the filed marker already guards re-filing\n }\n return;\n }\n if (!transcriptPath || plan.provider !== \"claude\") return;\n const nowMs = Date.now();\n if (nowMs - lastPromptAttemptAt < 30_000) return;\n lastPromptAttemptAt = nowMs;\n let prompt: string | null = null;\n try {\n prompt = openingPromptOf(readFileSync(transcriptPath, \"utf8\"));\n } catch {\n return; // absent transcript \u2192 no artifact, no error (D9); retry later\n }\n if (!prompt) return; // no visible user prompt yet \u2014 the transcript grows\n // Redact FIRST (a marker split at the cap is harmless; a secret split at\n // the cap is not), then bound to D9's 64 KB.\n let body = promptRedactor.text(prompt);\n while (Buffer.byteLength(body, \"utf8\") > 64 * 1024) {\n body = body.slice(0, -1024);\n }\n const post = async (bearer: string) =>\n (deps.fetchImpl ?? fetch)(\n new URL(\n `/api/agent-sessions/${plan.sessionId}/artifacts`,\n plan.jentrixBaseUrl,\n ),\n {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${bearer}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n kind: \"prompt\",\n title: \"Opening prompt\",\n body,\n }),\n },\n );\n try {\n let response = await post(bearerSource.get());\n if (response.status === 401) {\n const next = await bearerSource.refresh(bearerSource.get());\n if (next) response = await post(next);\n }\n if (!response.ok) return; // retried on a later poll; never an error\n const payload = (await response.json().catch(() => ({}))) as {\n artifactId?: string;\n deduped?: boolean;\n };\n writeFileSync(\n filedPath,\n JSON.stringify({\n artifactId: payload.artifactId ?? null,\n filedAt: new Date().toISOString(),\n }),\n { mode: 0o600 },\n );\n try {\n unlinkSync(requestPath);\n } catch {\n // the filed marker guards re-filing\n }\n log(\n `Opening prompt filed as artifact ${payload.artifactId ?? \"(unknown)\"}${payload.deduped ? \" (already stored)\" : \"\"}`,\n );\n } catch {\n // network loss: retry on a later poll \u2014 a mint-class convenience must\n // never cost the session anything\n }\n };\n\n const poll = async (): Promise<void> => {\n // `jentrix session end` hands a live host the end request through the\n // spool dir \u2014 the host owns the manifest, so the CLI defers to it\n // instead of racing a direct server-side completion (F-4 follow-through).\n const endRequestPath = join(sessionDir, \"end-request.json\");\n if (!sessionEnded && existsSync(endRequestPath)) {\n try {\n unlinkSync(endRequestPath);\n } catch {\n // best-effort \u2014 a leftover marker must not end a future resume\n }\n sessionEnded = true;\n }\n const { lines, offset } = readHookLines(hookDir, hookOffset);\n hookOffset = offset;\n for (const line of lines) {\n if (\n plan.provider === \"codex\" &&\n line.payload.session_id !== plan.providerSessionId\n ) {\n continue;\n }\n if (plan.provider === \"codex\") {\n const mapped = mapCodexHook(line.event, line.payload);\n if (mapped.modelId) bridge.observeModel(mapped.modelId);\n for (const event of mapped.events) bridge.record(event);\n }\n if (line.event === \"SessionStart\" && line.payload.session_id && !bound) {\n bound = true;\n transcriptPath = line.payload.transcript_path ?? null;\n try {\n // Trusted lifecycle context \u2192 late provider-ID binding (AC17).\n await bridge.tool(\"attach_agent_session\", {\n sessionId: plan.sessionId,\n provider: plan.provider,\n connection: { kind: \"local\", installationId: plan.installationId },\n providerSessionId: line.payload.session_id,\n idempotencyKey: `bind:${plan.sessionId}:${line.payload.session_id}`,\n });\n log(\n `Capture connected \u00B7 provider session ${line.payload.session_id}`,\n );\n } catch (error) {\n log(\n `capture: provider binding failed (${error instanceof Error ? error.message : \"unknown\"})`,\n );\n }\n }\n if (line.event === \"SessionEnd\" || line.event === \"Stop\") {\n await bridge.flushParts().catch(() => undefined);\n markHostFlushed(sessionDir, bridge.ackedPartCount);\n }\n if (line.event === \"SessionEnd\") sessionEnded = true;\n }\n if (plan.provider === \"claude\" && transcriptPath) {\n try {\n const size = statSync(transcriptPath).size;\n noteTranscriptSeen();\n if (size > transcriptOffset) {\n // BYTE offsets throughout \u2014 a character-indexed slice misaligns\n // the tail on any multibyte content.\n const buffer = readFileSync(transcriptPath);\n const body = buffer.subarray(transcriptOffset).toString(\"utf8\");\n transcriptOffset = buffer.byteLength;\n for (const rawLine of body.split(\"\\n\").filter(Boolean)) {\n const mapped = mapClaudeTranscriptLine(rawLine);\n if (mapped.unrecognized) bridge.countUnrecognized();\n if (mapped.modelId) bridge.observeModel(mapped.modelId);\n if (mapped.timing) {\n // control-room AC3.7: pair observed timestamps into the\n // intervals the usage aggregator has always known how to sum.\n for (const interval of timing.observe(mapped.timing)) {\n bridge.recordInterval(interval);\n }\n }\n for (const event of mapped.events) bridge.record(event);\n }\n }\n } catch {\n // transcript may rotate; next poll retries. But NEVER having seen it\n // is a different animal (AGE-957): warn once + stamp the marker so\n // the silence is visible instead of reading as a healthy host.\n if (\n !transcriptSeen &&\n !transcriptWarned &&\n Date.now() - hostStartedMs > 60_000\n ) {\n transcriptWarned = true;\n markHostTranscript(sessionDir, false);\n log(\n `capture: transcript never appeared at ${transcriptPath} \u2014 observing no events; usage will be unavailable. End the session and re-align to rebind.`,\n );\n }\n }\n }\n // TPM Slice 2 (AC2.5): `jentrix align --task <other>` asks the live host\n // to flush a usage receipt onto the OLD alignment before the server\n // closes its interval \u2014 the end-request.json idiom, acked by DELETING\n // the marker only after the server acknowledged the beat. Runs AFTER the\n // transcript tail above so the flush carries everything observed so far.\n // A failed post keeps the marker; the CLI's bounded wait times out and\n // discloses that the smear stays bounded by one beat window.\n const flushRequestPath = join(sessionDir, \"flush-request.json\");\n if (existsSync(flushRequestPath)) {\n const acked = await bridge.flushUsageNow().catch(() => false);\n if (acked) {\n try {\n unlinkSync(flushRequestPath);\n } catch {\n // unremovable marker: the CLI times out and proceeds \u2014 harmless\n }\n }\n }\n await fileOpeningPrompt();\n // Detached watch capture uploads as it goes (bounded to one flush per\n // 15s window) so `session end` finds little left to converge; the spool\n // advances past acked slots, so a flushed part number is never reused.\n const nowMs = Date.now();\n if (!sessionEnded && nowMs - lastPeriodicFlushAt >= 15_000) {\n lastPeriodicFlushAt = nowMs;\n await bridge.flushParts().catch(() => undefined);\n // Stamp the ack state so `session status` can tell an empty spool\n // (everything acknowledged) from a spool that never captured.\n markHostFlushed(sessionDir, bridge.ackedPartCount);\n }\n await bridge.maybeHeartbeat();\n };\n\n const timer = setInterval(() => {\n void poll();\n }, 2_000);\n\n const exitCode = await (watch\n ? // Watch mode: live capture beside the operator's own provider process.\n // End signals: the SessionEnd lifecycle hook, an end request from\n // `jentrix session end`, or a heartbeat 409 (session terminal\n // server-side \u2014 the out-of-band case the hooks can never deliver).\n new Promise<number>((resolve) => {\n const check = setInterval(() => {\n if (sessionEnded || bridge.sessionInactive) {\n clearInterval(check);\n resolve(0);\n }\n }, 1_000);\n })\n : new Promise<number>((resolve) => {\n child!.once(\"error\", () => resolve(1));\n child!.once(\"exit\", (code, signal) =>\n resolve(code ?? (signal ? 130 : 0)),\n );\n }));\n clearInterval(timer);\n await poll().catch(() => undefined);\n await bridge.flushParts().catch(() => undefined);\n // control-room AC3.7: a tool that never returned is a NAMED gap, not a\n // silently shorter total \u2014 the aggregator degrades coverage to PARTIAL on\n // an interval with no terminal event, which is the honest reading.\n for (const id of timing.unclosedToolIds()) {\n bridge.recordUnclosedInterval(\"tool\", id);\n }\n\n const end = await endRepoState(plan.repoRoot);\n const result = await bridge\n .complete({\n outcome: exitCode === 0 ? \"COMPLETED\" : \"INTERRUPTED\",\n end,\n })\n .catch((error) => {\n log(\n `capture: completion failed (${error instanceof Error ? error.message : \"unknown\"}) \u2014 spool retained for retry`,\n );\n return null;\n });\n if (!result) {\n markHostExited(sessionDir, 1);\n return 1;\n }\n // AGE-649: the closing output is named in the same line as the summary, so an\n // operator can see whether it was stored without opening the session page.\n const output = result.finalResponseArtifactId\n ? ` \u00B7 output ${result.finalResponseArtifactId}`\n : \" \u00B7 output not observed\";\n log(\n !traceCapture\n ? `Session ${plan.sessionId} closed \u00B7 TRACE capture off (typed artifacts only) \u00B7 summary ${result.summaryArtifactId ?? \"\u2014\"}${output}`\n : result.captureComplete\n ? `Session ${plan.sessionId} closed \u00B7 capture complete \u00B7 summary ${result.summaryArtifactId ?? \"\u2014\"}${output}`\n : `Session ${plan.sessionId} closed \u00B7 CAPTURE PENDING (${result.pendingParts} part(s)) \u2014 re-run \\`jentrix session status ${plan.sessionId}\\``,\n );\n // Capture-off is a deliberate mode, not capture debt \u2014 never exit non-zero\n // for the transcript that was intentionally not recorded.\n const finalCode =\n result.captureComplete || !traceCapture ? exitCode : exitCode || 1;\n markHostExited(sessionDir, finalCode);\n return finalCode;\n}\n\n/**\n * Run a CODEX session: a persistent SDK Thread driven as a terminal REPL \u2014\n * `runStreamed` per turn, structured events mapped deterministically, resume\n * through `resumeThread` (\u00A715.2).\n */\nexport async function runCodexSessionHost(\n plan: SessionRunPlan,\n deps: HostDeps = {},\n): Promise<number> {\n const log = deps.log ?? ((line: string) => process.stderr.write(`${line}\\n`));\n const spoolRoot = plan.spoolRoot ?? defaultSpoolRoot();\n const spool = new SessionSpool(spoolRoot, plan.sessionId);\n // AGE-929: local liveness marker \u2014 `jentrix session status` probes this pid.\n writeHostMarker(spool.directory, {\n pid: process.pid,\n provider: \"codex\",\n mode: \"launch\",\n });\n const codexBearerSource = bearerSourceOf(plan, log);\n const bridge = new SessionBridge({\n jentrixBaseUrl: plan.jentrixBaseUrl,\n bearer: () => codexBearerSource.get(),\n onUnauthorized: (failed) => codexBearerSource.refresh(failed),\n sessionId: plan.sessionId,\n provider: \"codex\",\n spool,\n redactor: createSessionRedactor({ homedir: homedir() }),\n callTool: sessionCallTool(plan.mcpUrl, codexBearerSource, plan.sessionId),\n fetchImpl: deps.fetchImpl,\n log,\n });\n bridge.recordCapabilities({\n provider: \"codex\",\n providerVersion: null,\n observable: [\n \"session\",\n \"assistant_message\",\n \"tool_call\",\n \"command\",\n \"file_change\",\n \"usage\",\n \"error\",\n ],\n notObservable: [\"plan\", \"tool_result\"],\n });\n bridge.startObserving();\n\n // Provider SDK loaded lazily so probe/setup paths never touch it.\n const { Codex } = (await import(\"@openai/codex-sdk\")) as {\n Codex: new (opts?: Record<string, unknown>) => {\n startThread(opts?: Record<string, unknown>): CodexThreadLike;\n resumeThread(id: string, opts?: Record<string, unknown>): CodexThreadLike;\n };\n };\n interface CodexThreadLike {\n id?: string | null;\n runStreamed(\n prompt: string,\n ): Promise<{ events: AsyncIterable<Record<string, unknown>> }>;\n }\n const codex = new Codex(\n plan.executablePath ? { codexPathOverride: plan.executablePath } : {},\n );\n const thread = plan.resumeProviderSessionId\n ? codex.resumeThread(plan.resumeProviderSessionId, {\n workingDirectory: plan.repoRoot,\n skipGitRepoCheck: true,\n })\n : codex.startThread({\n workingDirectory: plan.repoRoot,\n skipGitRepoCheck: true,\n });\n\n let bound = Boolean(plan.resumeProviderSessionId);\n // TPM Slice 2 (AC2.4): the model the runtime last named via turn_context;\n // null until one is observed \u2014 Codex receipts then stay in the null-model\n // bucket rather than carrying a guess.\n let currentModel: string | null = null;\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n const ask = (prompt: string) =>\n new Promise<string | null>((resolve) => {\n rl.question(prompt, (answer) => resolve(answer));\n rl.once(\"close\", () => resolve(null));\n });\n\n log(\"Codex connected session \u2014 empty line or Ctrl-D ends the session.\");\n let outcome: \"COMPLETED\" | \"INTERRUPTED\" = \"COMPLETED\";\n try {\n for (;;) {\n const input = await ask(\"codex> \");\n if (input === null || input.trim() === \"\") break;\n const turnId = `turn:${Date.now()}`;\n bridge.markTurnStarted(turnId);\n bridge.record({ kind: \"user_message\", payload: { text: input } });\n try {\n const { events } = await thread.runStreamed(input);\n for await (const raw of events) {\n const mapped = mapCodexThreadEvent(raw);\n if (mapped.unrecognized) bridge.countUnrecognized();\n // TPM Slice 2 (AC2.4): a turn_context names the model for the\n // turns that follow \u2014 observed, and stamped onto their receipts.\n if (mapped.modelId) {\n currentModel = mapped.modelId;\n bridge.observeModel(mapped.modelId);\n }\n if (mapped.threadId && !bound) {\n bound = true;\n try {\n await bridge.tool(\"attach_agent_session\", {\n sessionId: plan.sessionId,\n provider: \"codex\",\n connection: {\n kind: \"local\",\n installationId: plan.installationId,\n },\n providerSessionId: mapped.threadId,\n idempotencyKey: `bind:${plan.sessionId}:${mapped.threadId}`,\n });\n log(`Capture connected \u00B7 provider thread ${mapped.threadId}`);\n } catch (error) {\n log(\n `capture: provider binding failed (${error instanceof Error ? error.message : \"unknown\"})`,\n );\n }\n }\n if (mapped.event) {\n const recorded = bridge.record({\n ...mapped.event,\n at: new Date().toISOString(),\n payload:\n mapped.event.kind === \"usage\"\n ? {\n ...(mapped.event.payload as object),\n turnId,\n // TPM Slice 2 (AC2.4): the model the runtime last named\n // for this thread rides the receipt \u2014 absent when no\n // turn_context was ever observed (null-model bucket,\n // disclosed, never guessed).\n ...(currentModel ? { modelId: currentModel } : {}),\n }\n : mapped.event.payload,\n });\n if (\n recorded.kind === \"assistant_message\" &&\n typeof (recorded.payload as { text?: string })?.text === \"string\"\n ) {\n process.stdout.write(\n `${(recorded.payload as { text: string }).text}\\n`,\n );\n }\n }\n }\n } catch (error) {\n outcome = \"INTERRUPTED\";\n bridge.recordGap(\n `provider turn failed: ${error instanceof Error ? error.message : \"unknown\"}`,\n );\n log(\"codex turn failed \u2014 session will close as INTERRUPTED\");\n break;\n }\n bridge.markTurnEnded(turnId);\n await bridge.flushParts().catch(() => undefined);\n await bridge.maybeHeartbeat();\n }\n } finally {\n rl.close();\n }\n\n const end = await endRepoState(plan.repoRoot);\n const result = await bridge.complete({ outcome, end }).catch(() => null);\n if (!result) {\n markHostExited(spool.directory, 1);\n return 1;\n }\n log(\n result.captureComplete\n ? `Session ${plan.sessionId} closed \u00B7 capture complete \u00B7 output ${result.finalResponseArtifactId ?? \"not observed\"}`\n : `Session ${plan.sessionId} closed \u00B7 CAPTURE PENDING (${result.pendingParts} part(s))`,\n );\n const finalCode = result.captureComplete ? 0 : 1;\n markHostExited(spool.directory, finalCode);\n return finalCode;\n}\n\nexport async function runSessionHost(\n plan: SessionRunPlan,\n deps: HostDeps = {},\n): Promise<number> {\n return plan.mode === \"watch\" || plan.provider === \"claude\"\n ? runClaudeSessionHost(plan, deps)\n : runCodexSessionHost(plan, deps);\n}\n", "/**\n * Session-host bearer resolution (capture-off telemetry loss, 2026-08-08).\n *\n * The host used to hold the ONE bearer its plan was built with. An OAuth\n * access token (`tmo_`) lives \u22641h and is revoked the instant any concurrent\n * CLI invocation rotates the refresh token \u2014 live evidence (session\n * cmsk80my000ib04jvsrvlzf9q): host spawned 10:24:26 with the freshest token,\n * a `jentrix push` rotated at 10:26:49, the host's completion 401'd at\n * 10:26:55 and the whole usage rollup died with it.\n *\n * Fix: the host resolves its bearer through the SAME config file the CLI\n * persists rotations to. Dependency firewall: this MIRRORS the CLI's\n * `saveOAuthSession` read-merge-atomic-rename and `refreshAccessToken`\n * (cli/src/config.ts, cli/src/oauth.ts) \u2014 it never imports them. Server-side\n * rotation is single-use and a replayed refresh token is a benign\n * `invalid_grant` (no family revocation), so the loser of a concurrent\n * refresh race re-reads the file and adopts the winner's tokens; both sides\n * write atomically, so neither corrupts the other.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n mkdirSync,\n readFileSync,\n renameSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nexport interface SessionBearerSource {\n /** The bearer to use for the NEXT request (freshest known). */\n get(): string;\n /**\n * Called after an unauthorized response with the bearer that failed.\n * Returns a DIFFERENT bearer to retry with, or null when no recovery\n * exists (bare PAT, no oauth record, refresh refused and nobody else\n * rotated).\n */\n refresh(failedBearer: string): Promise<string | null>;\n}\n\n/** A bare PAT (or a plan with no configPath): no rotation, no recovery. */\nexport function staticBearerSource(bearer: string): SessionBearerSource {\n return { get: () => bearer, refresh: async () => null };\n}\n\ninterface OAuthRecord {\n refreshToken: string;\n expiresAt: string;\n clientId: string;\n tokenEndpoint: string;\n scope?: string;\n}\n\ninterface ConfigShape {\n token?: string;\n oauth?: OAuthRecord;\n [key: string]: unknown;\n}\n\nfunction readConfig(configPath: string): ConfigShape | null {\n try {\n const parsed: unknown = JSON.parse(readFileSync(configPath, \"utf8\"));\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed))\n return null;\n return parsed as ConfigShape;\n } catch {\n return null;\n }\n}\n\n/** Mirror of the CLI's 0600 tmp + `wx` + rename atomic config write. */\nfunction writeConfig(configPath: string, config: ConfigShape): void {\n mkdirSync(dirname(configPath), { recursive: true });\n const tmp = `${configPath}.tmp.${process.pid}.${randomBytes(6).toString(\"hex\")}`;\n writeFileSync(tmp, `${JSON.stringify(config, null, 2)}\\n`, {\n mode: 0o600,\n flag: \"wx\",\n });\n chmodSync(tmp, 0o600);\n renameSync(tmp, configPath);\n}\n\nfunction oauthRecordOf(config: ConfigShape | null): OAuthRecord | null {\n const oauth = config?.oauth;\n if (\n oauth &&\n typeof oauth.refreshToken === \"string\" &&\n oauth.refreshToken.length > 0 &&\n typeof oauth.tokenEndpoint === \"string\" &&\n typeof oauth.clientId === \"string\"\n ) {\n return oauth;\n }\n return null;\n}\n\n/**\n * F3: a refresh-produced bearer failing again THIS soon after its mint means\n * the endpoint rejects the whole chain (wrong deployment), not that the token\n * expired \u2014 access tokens live ~1h, heartbeats come every 30s. Well inside\n * expiry, well past a couple of beats.\n */\nconst FRESH_BEARER_WINDOW_MS = 120_000;\n\nexport function createConfigBearerSource(opts: {\n configPath: string;\n /** The plan's spawn-time bearer \u2014 used only until the config file yields one. */\n fallback: string;\n fetchImpl?: typeof fetch;\n log?: (line: string) => void;\n /** Injectable clock (tests). */\n now?: () => number;\n}): SessionBearerSource {\n const doFetch = opts.fetchImpl ?? fetch;\n const log = opts.log ?? (() => undefined);\n const now = opts.now ?? Date.now;\n // One refresh in flight per process \u2014 concurrent heartbeat/flush/completion\n // failures share the same recovery instead of racing the single-use grant.\n let pending: Promise<string | null> | null = null;\n // F3 (OAuth chain starvation): the bearer this source last produced, and\n // when. When THAT token comes back as the failed bearer within the fresh\n // window, the endpoint \u2014 not the token \u2014 is wrong (a host posting to\n // deployment B with deployment A's chain), and refreshing again only\n // rotates the SHARED CLI chain out from under a healthy sibling host every\n // heartbeat. Halt refreshes permanently instead.\n let lastProduced: { bearer: string; at: number } | null = null;\n let halted = false;\n\n const get = (): string => {\n const token = readConfig(opts.configPath)?.token;\n return typeof token === \"string\" && token.length > 0\n ? token\n : opts.fallback;\n };\n\n const refreshOnce = async (failedBearer: string): Promise<string | null> => {\n // Someone else (the CLI, or a sibling failure path here) already rotated.\n const current = get();\n if (current !== failedBearer) return current;\n\n const config = readConfig(opts.configPath);\n const oauth = oauthRecordOf(config);\n if (!oauth) return null;\n\n try {\n const res = await doFetch(oauth.tokenEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: oauth.refreshToken,\n client_id: oauth.clientId,\n }).toString(),\n });\n if (!res.ok) throw new Error(`token endpoint ${res.status}`);\n const pair = (await res.json()) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n scope?: string;\n };\n if (!pair.access_token || !pair.refresh_token) {\n throw new Error(\"token endpoint returned no pair\");\n }\n const expiresAt = new Date(\n Date.now() + (pair.expires_in ?? 3600) * 1000,\n ).toISOString();\n // Read-merge-write so a concurrent writer's other fields survive.\n writeConfig(opts.configPath, {\n ...(readConfig(opts.configPath) ?? {}),\n token: pair.access_token,\n oauth: {\n refreshToken: pair.refresh_token,\n expiresAt,\n clientId: oauth.clientId,\n tokenEndpoint: oauth.tokenEndpoint,\n ...(pair.scope ? { scope: pair.scope } : {}),\n },\n });\n log(\"bearer refreshed (session host rotated the OAuth token)\");\n return pair.access_token;\n } catch (error) {\n // Lost the single-use race (invalid_grant) or the endpoint failed \u2014\n // adopt whatever a concurrent winner persisted, else give up honestly.\n const after = get();\n if (after !== failedBearer) {\n log(\"bearer refreshed by a concurrent process \u2014 adopted\");\n return after;\n }\n log(\n `bearer refresh failed (${error instanceof Error ? error.message : String(error)})`,\n );\n return null;\n }\n };\n\n return {\n get,\n refresh: (failedBearer) => {\n if (halted) return Promise.resolve(null);\n if (\n lastProduced !== null &&\n failedBearer === lastProduced.bearer &&\n now() - lastProduced.at < FRESH_BEARER_WINDOW_MS\n ) {\n halted = true;\n log(\n \"bearer halt: a freshly refreshed token was still unauthorized \u2014 the endpoint rejects this credential's whole chain (wrong deployment for this bearer?). Halting token rotation so sibling hosts keep theirs; end this host and re-align against the right deployment.\",\n );\n return Promise.resolve(null);\n }\n if (!pending) {\n pending = refreshOnce(failedBearer)\n .then((produced) => {\n if (produced !== null) {\n lastProduced = { bearer: produced, at: now() };\n }\n return produced;\n })\n .finally(() => {\n pending = null;\n });\n }\n return pending;\n },\n };\n}\n\n/**\n * Matches the transport/tool errors an expired or revoked bearer produces:\n * the SDK's StreamableHTTPError (code 401), \"Unauthorized\", and the server's\n * withMcpAuth JSON (`invalid_token` / \"No authorization provided\").\n */\nexport function isUnauthorizedishError(e: unknown): boolean {\n if (typeof e === \"object\" && e !== null) {\n const rec = e as { code?: unknown; status?: unknown };\n if (rec.code === 401 || rec.status === 401) return true;\n }\n const message = e instanceof Error ? e.message : String(e);\n return /\\b401\\b|unauthorized|invalid_token|no authorization/i.test(message);\n}\n", "/**\n * M20.1 \u00A78.4/\u00A720 \u2014 the local session bridge: the crash-safe capture loop that\n * runs BESIDE the interactive provider. It spools redacted events locally,\n * uploads TRACE parts with retry, heartbeats at most every 30 seconds, and\n * closes the session with a server-verified manifest + the \u00A712.5 usage\n * rollup. Network loss keeps the spool and marks capture pending \u2014 it can\n * never silently become \"complete\" (AC22).\n *\n * Every effectful edge (fetch, MCP tool call, clocks) is injected so the\n * fault-injection tests (provider exit, network loss, duplicate events,\n * retry) run with zero real sockets.\n */\n\nimport { unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport type { SessionEvent, SessionEventKind } from \"./session-events.js\";\nimport { serializeSessionEvent } from \"./session-events.js\";\nimport type { SessionRedactor } from \"./session-redact.js\";\nimport type { SessionSpool } from \"./session-spool.js\";\nimport {\n aggregateSessionUsage,\n type LifecycleInterval,\n type ObservedRange,\n type UsageReceipt,\n} from \"./session-usage.js\";\n\nexport type SessionCallTool = (\n name: string,\n args: Record<string, unknown>,\n) => Promise<Record<string, unknown>>;\n\n/**\n * AGE-649 \u2014 the bound on the stored final response. Mirrors\n * MAX_TYPED_ARTIFACT_BYTES in src/server/agent-sessions/ingestion.ts across the\n * dependency firewall (the runner package cannot import from the app), so the\n * artifact is truncated with a visible notice HERE rather than refused there at\n * the moment the session is closing.\n */\nexport const MAX_FINAL_RESPONSE_BYTES = 2 * 1024 * 1024;\n\nexport interface SessionBridgeDeps {\n jentrixBaseUrl: string;\n /**\n * Transient bearer for REST heartbeat/ingestion \u2014 NEVER persisted here. A\n * function form resolves the CURRENT token per request (OAuth rotation\n * revokes the old one mid-session \u2014 the 2026-08-08 capture-off finding).\n */\n bearer: string | (() => string);\n /**\n * Called with the bearer that just got a 401 \u2014 gives the host's bearer\n * source a chance to rotate/adopt before the next request. Fire-and-forget\n * from the silent paths (heartbeat, part upload).\n */\n onUnauthorized?: (failedBearer: string) => Promise<unknown>;\n sessionId: string;\n provider: \"claude\" | \"codex\";\n spool: SessionSpool;\n redactor: SessionRedactor;\n callTool: SessionCallTool;\n fetchImpl?: typeof fetch;\n monotonic?: () => number;\n wallClock?: () => Date;\n /**\n * Jentrix MVP (PRD \u00A76): false = TRACE capture OFF \u2014 events are still\n * observed (usage receipts, timing, heartbeats) but nothing is spooled or\n * uploaded and completion submits no manifest. Default true.\n */\n traceCapture?: boolean;\n log?: (line: string) => void;\n}\n\nexport const HEARTBEAT_MIN_INTERVAL_MS = 30_000;\n\nexport interface CapabilitySnapshot {\n provider: \"claude\" | \"codex\";\n providerVersion: string | null;\n /** Event classes this provider/mode can emit; the rest are not_observable. */\n observable: SessionEventKind[];\n notObservable: SessionEventKind[];\n}\n\nexport class SessionBridge {\n private sequence = 0;\n private readonly receipts: UsageReceipt[] = [];\n private readonly providerTurns = new Map<string, LifecycleInterval>();\n private readonly toolIntervals = new Map<string, LifecycleInterval>();\n private readonly observedRanges: ObservedRange[] = [];\n /**\n * control-room AC2.1/AC2.2 \u2014 the LAST model the provider was observed\n * running. Last, not first: a session may legitimately switch models\n * mid-flight and the model that ran is the one that ran. Null until a line\n * names one; the heartbeat then omits the field entirely, so an unobserved\n * model can never overwrite a proven one server-side.\n */\n private observedModelId: string | null = null;\n private observingSince: number | null = null;\n private readonly ackedParts = new Map<number, string>();\n private readonly terminalParts = new Set<number>();\n private lastHeartbeatAt = 0;\n private unrecognizedEvents = 0;\n private capability: CapabilitySnapshot | null = null;\n private inactive = false;\n /**\n * AGE-649 \u2014 the newest non-empty assistant message observed, kept so the\n * session's own OUTPUT survives the close. Held in memory only: this is a\n * projection of an event the host already sees, never a second capture\n * channel, and it is recorded even when TRACE capture is off (which is the\n * whole point \u2014 capture-off is the MVP default, and without this a closed\n * session keeps its telemetry and loses what it actually concluded).\n */\n private lastAssistantMessage: {\n text: string;\n at: string;\n sequence: number;\n } | null = null;\n\n /**\n * True after a heartbeat came back 409 SESSION_NOT_ACTIVE \u2014 the session is\n * terminal server-side. The watch host uses this as its end signal when no\n * lifecycle hook can reach it; network loss never sets it.\n */\n get sessionInactive(): boolean {\n return this.inactive;\n }\n\n /** Heartbeat-refusal statuses already logged \u2014 one warning per status. */\n private warnedHeartbeatStatuses = new Set<number>();\n\n /** Server-acknowledged parts so far \u2014 the host stamps this into host.json. */\n get ackedPartCount(): number {\n return this.ackedParts.size;\n }\n\n constructor(private readonly deps: SessionBridgeDeps) {}\n\n /** The injected MCP tool caller (host convenience \u2014 same credential). */\n get tool(): SessionCallTool {\n return this.deps.callTool;\n }\n\n private now(): number {\n return (this.deps.monotonic ?? (() => performance.now()))();\n }\n\n private wall(): Date {\n return (this.deps.wallClock ?? (() => new Date()))();\n }\n\n private fetch(): typeof fetch {\n return this.deps.fetchImpl ?? fetch;\n }\n\n /** Begin (or resume) continuous observation \u2014 opens an observed range. */\n startObserving(): void {\n if (this.observingSince === null) this.observingSince = this.now();\n }\n\n /** A capture gap (stream drop, provider restart): closes the range. */\n recordGap(reason: string): void {\n if (this.observingSince !== null) {\n this.observedRanges.push({ from: this.observingSince, to: this.now() });\n this.observingSince = null;\n }\n this.record({ kind: \"error\", payload: { captureGap: reason } });\n }\n\n /** Record the provider capability snapshot (\u00A715.3) as an observable event. */\n recordCapabilities(snapshot: CapabilitySnapshot): void {\n this.capability = snapshot;\n this.record({ kind: \"session\", payload: { capabilities: snapshot } });\n }\n\n get capabilities(): CapabilitySnapshot | null {\n return this.capability;\n }\n\n countUnrecognized(): void {\n this.unrecognizedEvents += 1;\n }\n\n /**\n * Append one observable event: sequence + wall timestamp stamped here, the\n * whole line REDACTED before it becomes durable, usage receipts collected\n * for the rollup (deduped downstream by provider event identity).\n */\n record(\n event: Omit<SessionEvent, \"sequence\" | \"version\" | \"at\" | \"provider\"> & {\n at?: string;\n providerEventId?: string;\n },\n ): SessionEvent {\n const full: SessionEvent = {\n version: 1,\n sequence: this.sequence++,\n at: event.at ?? this.wall().toISOString(),\n provider: this.deps.provider,\n ...(event.providerEventId\n ? { providerEventId: event.providerEventId }\n : {}),\n kind: event.kind,\n payload: this.deps.redactor.value(event.payload),\n };\n if (this.deps.traceCapture !== false) {\n this.deps.spool.append(\n this.deps.redactor.text(serializeSessionEvent(full)),\n );\n }\n if (full.kind === \"assistant_message\") {\n // Read off the REDACTED payload, so the text kept here has already been\n // through the local pass \u2014 exactly like a spooled part.\n const text = (full.payload as { text?: unknown })?.text;\n if (typeof text === \"string\" && text.trim().length > 0) {\n this.lastAssistantMessage = {\n text,\n at: full.at,\n sequence: full.sequence,\n };\n }\n }\n if (full.kind === \"usage\") {\n const payload = full.payload as {\n kind?: \"delta\" | \"cumulative\";\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n reasoningOutputTokens?: number;\n modelId?: string | null;\n turnId?: string | null;\n };\n if (\n (payload?.kind === \"delta\" || payload?.kind === \"cumulative\") &&\n typeof payload.inputTokens === \"number\" &&\n typeof payload.outputTokens === \"number\"\n ) {\n this.receipts.push({\n eventId: full.providerEventId ?? `seq:${full.sequence}`,\n turnId: payload.turnId ?? null,\n kind: payload.kind,\n inputTokens: payload.inputTokens,\n outputTokens: payload.outputTokens,\n ...(typeof payload.cacheReadTokens === \"number\"\n ? { cacheReadTokens: payload.cacheReadTokens }\n : {}),\n ...(typeof payload.cacheCreationTokens === \"number\"\n ? { cacheCreationTokens: payload.cacheCreationTokens }\n : {}),\n // TPM Slice 2 (AC2.4/AC2.7): the receipt's own model and reasoning\n // split, when the mapper reported them \u2014 grouped receipts, never\n // estimates.\n ...(typeof payload.reasoningOutputTokens === \"number\"\n ? { reasoningOutputTokens: payload.reasoningOutputTokens }\n : {}),\n ...(typeof payload.modelId === \"string\" && payload.modelId.trim()\n ? { modelId: payload.modelId.trim() }\n : {}),\n at: this.now(),\n });\n // Durable telemetry: a host that dies before completing (crash,\n // revoked bearer) must not take the usage rollup with it \u2014 `stacks\n // session end`'s server-side fallback submits this snapshot\n // (2026-08-08 capture-off finding: all-null tokens after host death).\n this.persistUsageSnapshot();\n }\n }\n return full;\n }\n\n /** Best-effort spool-side snapshot of the current rollup (provider receipts). */\n private persistUsageSnapshot(): void {\n try {\n writeFileSync(\n join(this.deps.spool.directory, \"usage.json\"),\n JSON.stringify({\n rollup: this.usageRollup(),\n updatedAt: this.wall().toISOString(),\n }),\n { mode: 0o600 },\n );\n } catch {\n // Telemetry durability is best-effort \u2014 never fail capture over it.\n }\n }\n\n /** Record the model a transcript line named (pure accumulation, no I/O). */\n observeModel(modelId: string): void {\n const next = modelId.trim();\n if (next) this.observedModelId = next;\n }\n\n /** What the host has observed running, for tests and the close-time record. */\n get modelId(): string | null {\n return this.observedModelId;\n }\n\n /**\n * control-room AC3.7 \u2014 record an interval whose bounds were OBSERVED rather\n * than measured on this process's clock. The Claude path replays timestamps\n * the transcript already carries, so `this.now()` (which the mark* pair\n * below uses for the live Codex path) would time the tail, not the turn.\n */\n recordInterval(interval: {\n kind: \"turn\" | \"tool\";\n id: string;\n startedAt: number;\n endedAt: number;\n }): void {\n const target =\n interval.kind === \"turn\" ? this.providerTurns : this.toolIntervals;\n target.set(interval.id, {\n id: interval.id,\n startedAt: interval.startedAt,\n endedAt: interval.endedAt,\n });\n }\n\n /**\n * An interval opened and never closed \u2014 a tool that never returned, a host\n * killed mid-turn. Recorded WITHOUT an end so `aggregateSessionUsage` names\n * the gap and degrades coverage to PARTIAL, instead of the total quietly\n * omitting it and reading as complete.\n */\n recordUnclosedInterval(kind: \"turn\" | \"tool\", id: string): void {\n const target = kind === \"turn\" ? this.providerTurns : this.toolIntervals;\n if (!target.has(id)) target.set(id, { id, startedAt: 0, endedAt: null });\n }\n\n markTurnStarted(id: string): void {\n this.providerTurns.set(id, { id, startedAt: this.now(), endedAt: null });\n }\n\n markTurnEnded(id: string): void {\n const turn = this.providerTurns.get(id);\n if (turn) turn.endedAt = this.now();\n }\n\n markToolStarted(id: string): void {\n this.toolIntervals.set(id, { id, startedAt: this.now(), endedAt: null });\n }\n\n markToolEnded(id: string): void {\n const interval = this.toolIntervals.get(id);\n if (interval) interval.endedAt = this.now();\n }\n\n /** The current REST bearer (function form resolves per request). */\n private bearerOf(): string {\n return typeof this.deps.bearer === \"function\"\n ? this.deps.bearer()\n : this.deps.bearer;\n }\n\n /** \u2264 one heartbeat per 30s window (AC42); failures are silent (retry next). */\n async maybeHeartbeat(): Promise<void> {\n const now = this.now();\n if (now - this.lastHeartbeatAt < HEARTBEAT_MIN_INTERVAL_MS) return;\n await this.postHeartbeat(now);\n }\n\n /**\n * TPM Slice 2 (AC2.5): the flush receipt \u2014 an immediate beat that ignores\n * the 30-second window, posted before a task-changing re-align so the OLD\n * alignment's open interval absorbs everything observed so far. Host-side\n * ordering only: a killed host's mid-switch smear stays bounded by one\n * beat window, which the CLI disclosure names.\n */\n async flushUsageNow(): Promise<boolean> {\n return this.postHeartbeat(this.now());\n }\n\n /** @returns true when the server acknowledged the beat (HTTP ok). */\n private async postHeartbeat(now: number): Promise<boolean> {\n this.lastHeartbeatAt = now;\n const bearer = this.bearerOf();\n try {\n const response = await this.fetch()(\n new URL(\"/api/agent-sessions/heartbeat\", this.deps.jentrixBaseUrl),\n {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${bearer}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n sessionId: this.deps.sessionId,\n // control-room AC2.1: the heartbeat is the host's \"what I\n // observed\" channel. No new timer, no new route, no new tool \u2014\n // and host-attested by construction, since the route writes only\n // the authenticated operator's own open session.\n ...(this.observedModelId ? { modelId: this.observedModelId } : {}),\n // control-room AC4.1: the LIVE usage receipt on the same beat.\n // Sent only once a receipt has actually been observed \u2014 an empty\n // rollup would overwrite the session's totals with nulls and\n // report UNAVAILABLE for a session that had already reported.\n ...(this.receipts.length > 0 ? { usage: this.usageRollup() } : {}),\n }),\n },\n );\n if (response.status === 401) {\n // A rotated-away bearer must not silently kill liveness until the\n // sweep interrupts the session \u2014 ask the source to recover so the\n // NEXT window heartbeats with a live token.\n void this.deps.onUnauthorized?.(bearer)?.catch(() => undefined);\n }\n if (response.status === 409) {\n const body = await response.text().catch(() => \"\");\n if (body.includes(\"SESSION_NOT_ACTIVE\")) this.inactive = true;\n }\n if (\n !response.ok &&\n response.status !== 401 &&\n response.status !== 409 &&\n !this.warnedHeartbeatStatuses.has(response.status)\n ) {\n // A silently-refused beat is how a live session gets swept\n // INTERRUPTED \u2014 say it ONCE per distinct status, not every 30s.\n this.warnedHeartbeatStatuses.add(response.status);\n this.deps.log?.(\n `capture: heartbeat rejected (HTTP ${response.status}) \u2014 liveness at risk; the sweep may interrupt this session`,\n );\n }\n return response.ok;\n } catch {\n // Offline: the sweep may interrupt server-side; reconnection resumes.\n return false;\n }\n }\n\n /**\n * Upload every pending spool part. Returns the still-pending count \u2014 a\n * non-zero result is \"capture pending\", printed prominently and encoded in\n * the CLI exit code (\u00A720). A redacted-slot refusal (terminal, \u00A712.3) keeps\n * the local file forever and is reported as a named gap.\n */\n async flushParts(): Promise<{ pending: number; terminal: number }> {\n // Capture off: nothing was spooled, nothing to upload \u2014 by design.\n if (this.deps.traceCapture === false) return { pending: 0, terminal: 0 };\n let pending = 0;\n for (const part of this.deps.spool.pendingParts()) {\n if (this.terminalParts.has(part.part)) continue;\n const bearer = this.bearerOf();\n try {\n const response = await this.fetch()(\n new URL(\n `/api/agent-sessions/${this.deps.sessionId}/parts`,\n this.deps.jentrixBaseUrl,\n ),\n {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${bearer}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n part: part.part,\n body: this.deps.spool.readPart(part.part),\n }),\n },\n );\n if (response.ok) {\n const ack = (await response.json()) as { checksum?: string };\n const acked =\n typeof ack.checksum === \"string\" ? ack.checksum : part.checksum;\n // Record the ACKNOWLEDGED (stored) checksum into the manifest first,\n // then delete the spool file \u2014 never on anything but a genuine ack.\n this.ackedParts.set(part.part, acked);\n this.deps.spool.deleteAcknowledged(part.part, acked, { force: true });\n // The slot is spent server-side; new events open the next part.\n this.deps.spool.advancePast(part.part);\n continue;\n }\n if (response.status === 401) {\n void this.deps.onUnauthorized?.(bearer)?.catch(() => undefined);\n }\n const body = await response.text().catch(() => \"\");\n if (\n response.status === 409 &&\n body.includes(\"ARTIFACT_PART_REDACTED\")\n ) {\n // Terminal slot: keep the local spool (operator deletion only) and\n // stop retrying \u2014 the summary names the gap.\n this.terminalParts.add(part.part);\n this.deps.log?.(\n `trace part ${part.part}: slot terminally redacted \u2014 local spool retained`,\n );\n continue;\n }\n pending += 1;\n } catch {\n pending += 1; // network loss: retry later, spool intact (AC22)\n }\n }\n return { pending, terminal: this.terminalParts.size };\n }\n\n /**\n * AGE-649 \u2014 push the session's FINAL RESPONSE as a typed artifact.\n *\n * Why this exists: with TRACE capture off (the MVP default) a closed session\n * keeps its telemetry and its typed artifacts, and nothing at all holds what\n * the agent concluded. The RUN_SUMMARY cannot carry it \u2014 that document is a\n * deterministic server projection and model prose is banned from it (M20.1\n * AC31) \u2014 so the output lands as its own artifact, on the same typed-push\n * boundary an operator's `jentrix push report` uses. One ingestion function,\n * both redaction passes, checksum after redaction.\n *\n * Ordering is load-bearing: `COMPLETED` is a SEALED status for typed pushes,\n * so this runs BEFORE `complete_agent_session`, never after.\n *\n * Absence stays absence. A session where the host observed no assistant text\n * (capture never bound, a Codex thread that only ran tools) gets NO artifact\n * rather than an empty one \u2014 the same rule the usage rollup follows for\n * tokens. Failure never fails the close: the artifact is a bonus record, and\n * losing it must not cost the operator their session completion.\n *\n * @returns the artifact id, or null when there was nothing to push.\n */\n async pushFinalResponse(): Promise<string | null> {\n const last = this.lastAssistantMessage;\n if (!last) return null;\n const body = this.finalResponseBody(last);\n const bearer = this.bearerOf();\n try {\n const response = await this.fetch()(\n new URL(\n `/api/agent-sessions/${this.deps.sessionId}/artifacts`,\n this.deps.jentrixBaseUrl,\n ),\n {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${bearer}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n // `report` \u2192 REPORT \u2192 the Execution layer, which is the session's\n // own layer. No new push kind and no new ArtifactType: the seven\n // kinds are frozen vocabulary and this is a report the agent wrote.\n kind: \"report\",\n title: `Final response \u2014 session ${this.deps.sessionId.slice(-8)}`,\n body,\n }),\n },\n );\n if (response.ok) {\n const ack = (await response.json().catch(() => null)) as {\n artifactId?: string;\n } | null;\n return ack?.artifactId ?? null;\n }\n if (response.status === 401) {\n void this.deps.onUnauthorized?.(bearer)?.catch(() => undefined);\n }\n this.deps.log?.(\n `final response: not stored (HTTP ${response.status}) \u2014 the session's closing output was not captured`,\n );\n return null;\n } catch (error) {\n this.deps.log?.(\n `final response: not stored (${error instanceof Error ? error.message : \"unknown\"}) \u2014 the session's closing output was not captured`,\n );\n return null;\n }\n }\n\n /**\n * The stored document. Self-describing on purpose: a reader has to be able to\n * tell this apart from the RUN_SUMMARY sitting beside it, and has to know it\n * is verbatim provider output rather than anything the server derived.\n *\n * Bounded here as well as server-side, and a truncation SAYS so \u2014 an artifact\n * silently missing its tail is worse than one that names the cut.\n */\n private finalResponseBody(last: {\n text: string;\n at: string;\n sequence: number;\n }): string {\n const header = [\n `# Final response \u2014 session ${this.deps.sessionId}`,\n \"\",\n `The last assistant message this session's host observed before close (event ${last.sequence}, ${last.at}).`,\n \"Verbatim provider output \u2014 redacted on this machine and again on arrival.\",\n \"This is model prose, not a server projection: the RUN_SUMMARY artifact is the deterministic record of what the session did.\",\n \"\",\n \"---\",\n \"\",\n ].join(\"\\n\");\n const room = MAX_FINAL_RESPONSE_BYTES - Buffer.byteLength(header, \"utf8\");\n if (Buffer.byteLength(last.text, \"utf8\") <= room) return header + last.text;\n const notice = \"\\n\\n[truncated \u2014 the response exceeded the artifact limit]\";\n const kept = Buffer.from(last.text, \"utf8\")\n .subarray(0, Math.max(0, room - Buffer.byteLength(notice, \"utf8\")))\n .toString(\"utf8\")\n // A byte-slice can cut a multi-byte character in half; drop the\n // replacement char it decodes to rather than storing mojibake.\n .replace(/\uFFFD+$/, \"\");\n return header + kept + notice;\n }\n\n /** The \u00A712.5 rollup over everything observed so far. */\n usageRollup() {\n const ranges = [...this.observedRanges];\n if (this.observingSince !== null) {\n ranges.push({ from: this.observingSince, to: this.now() });\n }\n const rollup = aggregateSessionUsage({\n receipts: this.receipts,\n observedRanges: ranges,\n providerTurns: [...this.providerTurns.values()],\n toolIntervals: [...this.toolIntervals.values()],\n });\n // The server's SessionUsageSchema bounds missingRanges to 200 entries of\n // \u2264400 chars. An UNBOUNDED list (one entry per receipt-less turn \u2014 a\n // long session crosses 200 easily) made every usage-bearing heartbeat\n // fail schema validation SILENTLY: heartbeatAt froze while part uploads\n // kept landing, and the sweep interrupted a perfectly live session\n // (observed 2026-08-20, three sweeps in one run). Cap here at the source\n // \u2014 the tail collapses into one honest summary entry.\n if (rollup.missingRanges.length > 200) {\n const dropped = rollup.missingRanges.length - 199;\n rollup.missingRanges = [\n ...rollup.missingRanges.slice(0, 199),\n `\u2026and ${dropped} more missing ranges (capped at the schema's 200)`,\n ];\n }\n rollup.missingRanges = rollup.missingRanges.map((r) => r.slice(0, 400));\n return rollup;\n }\n\n /**\n * Close the session: final flush, server-verified manifest from the ACKED\n * checksums, rollup, then `complete_agent_session` under CAS. Returns the\n * server's verdict plus the local pending count \u2014 the CLI exits non-zero\n * while anything is pending (\u00A720).\n */\n async complete(opts: {\n outcome: \"COMPLETED\" | \"INTERRUPTED\" | \"CANCELLED\";\n end: { branch: string | null; head: string | null; dirty: boolean | null };\n captureError?: string | null;\n }): Promise<{\n status: string;\n captureComplete: boolean;\n summaryArtifactId: string | null;\n /** AGE-649 \u2014 null when the host observed no assistant text to store. */\n finalResponseArtifactId: string | null;\n pendingParts: number;\n }> {\n const { pending } = await this.flushParts();\n // AGE-649: BEFORE the completion call \u2014 `COMPLETED` seals the session\n // against typed pushes, so there is no \"after\" for this.\n const finalResponseArtifactId = await this.pushFinalResponse();\n const rollup = this.usageRollup();\n const current = (await this.deps.callTool(\"get_agent_session\", {\n sessionId: this.deps.sessionId,\n })) as { updatedAt?: string };\n const traceOff = this.deps.traceCapture === false;\n // Capture-off (PRD \u00A76): no manifest is submitted \u2014 captureComplete stays\n // false with an honest reason, never a vacuous \"complete\" over a\n // transcript that was deliberately not recorded.\n const manifest = traceOff\n ? undefined\n : {\n parts: [...this.ackedParts.entries()]\n .sort(([a], [b]) => a - b)\n .map(([part, checksum]) => ({ part, checksum })),\n };\n // AGE-958: the healthy capture-off default is a STATUS, not an error \u2014\n // the server records captureError null and derives OFF_BY_DESIGN; sending\n // prose here made every monitor watching `captureError != null` alert on\n // the designed path.\n const captureError =\n opts.captureError ??\n (traceOff\n ? null\n : pending > 0\n ? `capture pending: ${pending} trace part(s) not yet acknowledged`\n : this.unrecognizedEvents > 0\n ? `${this.unrecognizedEvents} provider event(s) had shapes this adapter does not observe`\n : null);\n const result = (await this.deps.callTool(\"complete_agent_session\", {\n sessionId: this.deps.sessionId,\n outcome: opts.outcome,\n endBranch: opts.end.branch,\n endHead: opts.end.head,\n endDirty: opts.end.dirty,\n captureError,\n ...(manifest ? { manifest } : {}),\n usage: {\n inputTokens: rollup.inputTokens,\n outputTokens: rollup.outputTokens,\n cacheReadTokens: rollup.cacheReadTokens,\n cacheCreationTokens: rollup.cacheCreationTokens,\n // TPM Slice 2 (AC2.6/AC2.7): the close corrects session TOTALS \u2014\n // reasoning included, perModel deliberately NOT sent (the server\n // writes no segments at close; residuals stay disclosed).\n reasoningOutputTokens: rollup.reasoningOutputTokens,\n providerActiveDurationMs: rollup.providerActiveDurationMs,\n toolDurationMs: rollup.toolDurationMs,\n coverage: rollup.coverage,\n ...(rollup.missingRanges.length\n ? { missingRanges: rollup.missingRanges.slice(0, 200) }\n : {}),\n },\n expectedUpdatedAt: current.updatedAt,\n })) as {\n status?: string;\n captureComplete?: boolean;\n summaryArtifactId?: string | null;\n };\n // The rollup reached the server \u2014 the durable snapshot has done its job.\n try {\n unlinkSync(join(this.deps.spool.directory, \"usage.json\"));\n } catch {\n // Absent (no receipts) or unremovable \u2014 either way not worth failing.\n }\n return {\n status: result.status ?? opts.outcome,\n captureComplete: Boolean(result.captureComplete),\n summaryArtifactId: result.summaryArtifactId ?? null,\n finalResponseArtifactId,\n pendingParts: pending,\n };\n }\n}\n", "/**\n * M20.1 \u00A712.1 \u2014 the observable-event envelope (version 1). An EVIDENCE\n * serialization, not a workflow state machine: adapters map only observable\n * provider event SHAPES onto it; consumers rely on the small common envelope\n * and treat provider-native detail as opaque versioned payload.\n */\n\nexport const SESSION_EVENT_VERSION = 1 as const;\n\nexport type SessionEventKind =\n | \"session\"\n | \"user_message\"\n | \"assistant_message\"\n | \"tool_call\"\n | \"tool_result\"\n | \"command\"\n | \"file_change\"\n | \"plan\"\n | \"usage\"\n | \"error\";\n\nexport interface SessionEvent {\n version: typeof SESSION_EVENT_VERSION;\n /** Monotonic per-session sequence, assigned by the local bridge. */\n sequence: number;\n /** UTC ISO timestamp for display/audit (durations use the monotonic clock). */\n at: string;\n provider: \"claude\" | \"codex\";\n providerEventId?: string;\n kind: SessionEventKind;\n payload: unknown;\n}\n\nexport const SESSION_EVENT_KINDS: readonly SessionEventKind[] = [\n \"session\",\n \"user_message\",\n \"assistant_message\",\n \"tool_call\",\n \"tool_result\",\n \"command\",\n \"file_change\",\n \"plan\",\n \"usage\",\n \"error\",\n];\n\n/** One NDJSON line (the spool/TRACE serialization). Deterministic key order. */\nexport function serializeSessionEvent(event: SessionEvent): string {\n return `${JSON.stringify({\n version: event.version,\n sequence: event.sequence,\n at: event.at,\n provider: event.provider,\n ...(event.providerEventId ? { providerEventId: event.providerEventId } : {}),\n kind: event.kind,\n payload: event.payload,\n })}\\n`;\n}\n\n/** Parse one spool line back; null for anything that is not a v1 envelope. */\nexport function parseSessionEvent(line: string): SessionEvent | null {\n try {\n const parsed = JSON.parse(line) as SessionEvent;\n if (\n parsed?.version !== SESSION_EVENT_VERSION ||\n typeof parsed.sequence !== \"number\" ||\n typeof parsed.at !== \"string\" ||\n (parsed.provider !== \"claude\" && parsed.provider !== \"codex\") ||\n !SESSION_EVENT_KINDS.includes(parsed.kind)\n ) {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n", "/**\n * M20.1 \u00A712.5 \u2014 the PURE session usage/timing aggregator. Provider-reported\n * receipts only; NOTHING is ever estimated from characters, bytes, price\n * tables, or another tokenizer (AC35). Durations come from paired monotonic\n * lifecycle events; wall time is the SERVER's (never computed here).\n *\n * Coverage semantics (rule 9):\n * COMPLETE \u2014 every observable provider turn carried a usable receipt and\n * every measured interval closed;\n * PARTIAL \u2014 something is missing, and every gap is NAMED;\n * UNAVAILABLE \u2014 the runtime exposed no usable receipts at all.\n */\n\nexport interface UsageReceipt {\n /** Provider event/turn identity \u2014 the dedupe key (rule 2/5, AC38). */\n eventId: string;\n /** The provider turn this receipt belongs to, when known. */\n turnId?: string | null;\n /**\n * \"delta\" \u2014 tokens for one turn; \"cumulative\" \u2014 the provider reports thread\n * totals, and only a continuous-capture delta between two acknowledged\n * cumulative receipts may contribute (rule 3, AC37/AC46).\n */\n kind: \"delta\" | \"cumulative\";\n inputTokens: number;\n outputTokens: number;\n /**\n * Disjoint subsets of inputTokens (AGE-938). Absent = this receipt did not\n * report the field (an old transcript format, or a provider without the\n * concept) \u2014 distinct from a reported 0.\n */\n cacheReadTokens?: number | null;\n cacheCreationTokens?: number | null;\n /**\n * TPM Slice 2 (AC2.7): reasoning tokens as a SUBSET of outputTokens.\n * Absent = the provider does not split this out (Claude transcripts).\n */\n reasoningOutputTokens?: number | null;\n /**\n * TPM Slice 2 (AC2.4): the model that produced this receipt, as the\n * provider named it (Claude: message.model on the same transcript entry;\n * Codex: turn_context.model when the stream reports one). Absent = never\n * observed for this receipt \u2014 grouped under the null-model bucket.\n */\n modelId?: string | null;\n /** Monotonic ms when the receipt was observed. */\n at: number;\n}\n\nexport interface LifecycleInterval {\n id: string;\n startedAt: number;\n /** Missing = the terminal event was never observed (rule 7). */\n endedAt?: number | null;\n}\n\n/** A continuous-capture window on the monotonic clock (rule 3). */\nexport interface ObservedRange {\n from: number;\n to: number;\n}\n\n/** TPM Slice 2 (AC2.4): the cumulative rollup for ONE model bucket. */\nexport interface PerModelUsage {\n /** Null = receipts whose model was never observed. */\n modelId: string | null;\n inputTokens: number | null;\n outputTokens: number | null;\n cacheReadTokens: number | null;\n cacheCreationTokens: number | null;\n reasoningOutputTokens: number | null;\n}\n\nexport interface SessionUsageRollup {\n inputTokens: number | null;\n outputTokens: number | null;\n /** Null when NO receipt reported the field \u2014 never a fabricated 0. */\n cacheReadTokens: number | null;\n cacheCreationTokens: number | null;\n /** TPM Slice 2 (AC2.7): subset of outputTokens; null = never reported. */\n reasoningOutputTokens: number | null;\n providerActiveDurationMs: number | null;\n toolDurationMs: number | null;\n coverage: \"COMPLETE\" | \"PARTIAL\" | \"UNAVAILABLE\";\n missingRanges: string[];\n /**\n * TPM Slice 2 (AC2.4): the same receipts GROUPED by the model that\n * produced them \u2014 the fact the pipeline used to throw away. Empty when no\n * receipt was usable. Sums here always equal the totals above: every\n * usable receipt lands in exactly one bucket (null model included).\n */\n perModel: PerModelUsage[];\n}\n\nfunction insideOneRange(\n ranges: ObservedRange[],\n from: number,\n to: number,\n): boolean {\n return ranges.some((r) => r.from <= from && to <= r.to);\n}\n\nexport function aggregateSessionUsage(input: {\n receipts: UsageReceipt[];\n /** Continuous capture windows; a cumulative delta must sit inside ONE. */\n observedRanges: ObservedRange[];\n providerTurns: LifecycleInterval[];\n toolIntervals: LifecycleInterval[];\n}): SessionUsageRollup {\n const missing: string[] = [];\n\n // Rule 2/5 (AC38): one receipt contributes at most once \u2014 dedupe by identity.\n const seen = new Set<string>();\n const receipts = input.receipts\n .filter((r) => {\n if (seen.has(r.eventId)) return false;\n seen.add(r.eventId);\n return true;\n })\n .sort((a, b) => a.at - b.at);\n\n let inputTokens = 0;\n let outputTokens = 0;\n let usable = 0;\n const receiptTurnIds = new Set<string>();\n\n // AGE-938: field-level reporting \u2014 a cache sum surfaces only when at least\n // one receipt actually carried the field, else it stays null.\n let cacheReadTokens = 0;\n let cacheReadReported = false;\n let cacheCreationTokens = 0;\n let cacheCreationReported = false;\n // TPM Slice 2 (AC2.7): reasoning rides the same field-level honesty.\n let reasoningOutputTokens = 0;\n let reasoningReported = false;\n\n // TPM Slice 2 (AC2.4): the same contributions, grouped by producing model.\n // Every usable contribution lands in exactly one bucket (null = the model\n // was never observed for the receipt), so \u03A3 buckets \u2261 the totals above.\n interface Bucket {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheReadReported: boolean;\n cacheCreationTokens: number;\n cacheCreationReported: boolean;\n reasoningOutputTokens: number;\n reasoningReported: boolean;\n }\n const buckets = new Map<string | null, Bucket>();\n interface Contribution {\n modelId: string | null;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n reasoningOutputTokens?: number;\n }\n const contribute = (c: Contribution): void => {\n inputTokens += c.inputTokens;\n outputTokens += c.outputTokens;\n const bucket =\n buckets.get(c.modelId) ??\n ({\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheReadReported: false,\n cacheCreationTokens: 0,\n cacheCreationReported: false,\n reasoningOutputTokens: 0,\n reasoningReported: false,\n } satisfies Bucket);\n bucket.inputTokens += c.inputTokens;\n bucket.outputTokens += c.outputTokens;\n if (typeof c.cacheReadTokens === \"number\") {\n cacheReadTokens += c.cacheReadTokens;\n cacheReadReported = true;\n bucket.cacheReadTokens += c.cacheReadTokens;\n bucket.cacheReadReported = true;\n }\n if (typeof c.cacheCreationTokens === \"number\") {\n cacheCreationTokens += c.cacheCreationTokens;\n cacheCreationReported = true;\n bucket.cacheCreationTokens += c.cacheCreationTokens;\n bucket.cacheCreationReported = true;\n }\n if (typeof c.reasoningOutputTokens === \"number\") {\n reasoningOutputTokens += c.reasoningOutputTokens;\n reasoningReported = true;\n bucket.reasoningOutputTokens += c.reasoningOutputTokens;\n bucket.reasoningReported = true;\n }\n buckets.set(c.modelId, bucket);\n usable += 1;\n };\n const modelOf = (receipt: UsageReceipt): string | null =>\n receipt.modelId?.trim() || null;\n\n let cumulativeBaseline: UsageReceipt | null = null;\n for (const receipt of receipts) {\n if (receipt.turnId) receiptTurnIds.add(receipt.turnId);\n if (receipt.kind === \"delta\") {\n contribute({\n modelId: modelOf(receipt),\n inputTokens: receipt.inputTokens,\n outputTokens: receipt.outputTokens,\n ...(typeof receipt.cacheReadTokens === \"number\"\n ? { cacheReadTokens: receipt.cacheReadTokens }\n : {}),\n ...(typeof receipt.cacheCreationTokens === \"number\"\n ? { cacheCreationTokens: receipt.cacheCreationTokens }\n : {}),\n ...(typeof receipt.reasoningOutputTokens === \"number\"\n ? { reasoningOutputTokens: receipt.reasoningOutputTokens }\n : {}),\n });\n continue;\n }\n // Cumulative: a delta needs an acknowledged baseline AND continuous\n // capture across the whole interval between the two receipts (rule 3).\n if (cumulativeBaseline === null) {\n cumulativeBaseline = receipt;\n missing.push(\n `cumulative receipt ${receipt.eventId} established a baseline only \u2014 the thread total before it is not attributable to this session`,\n );\n continue;\n }\n if (!insideOneRange(input.observedRanges, cumulativeBaseline.at, receipt.at)) {\n missing.push(\n `cumulative interval ${cumulativeBaseline.eventId}\u2192${receipt.eventId} crossed an unobserved range and was not counted`,\n );\n cumulativeBaseline = receipt; // becomes the next baseline\n continue;\n }\n const dIn = receipt.inputTokens - cumulativeBaseline.inputTokens;\n const dOut = receipt.outputTokens - cumulativeBaseline.outputTokens;\n if (dIn < 0 || dOut < 0) {\n missing.push(\n `cumulative receipt ${receipt.eventId} regressed below its baseline and was not counted`,\n );\n cumulativeBaseline = receipt;\n continue;\n }\n // Cache/reasoning deltas count only when BOTH endpoints reported the\n // field and the delta is non-negative \u2014 a regressing counter on an\n // otherwise valid interval reads as unreported for that interval, never\n // as negative usage. The interval's spend belongs to the LATER receipt's\n // model \u2014 the model that was running when the total grew.\n contribute({\n modelId: modelOf(receipt),\n inputTokens: dIn,\n outputTokens: dOut,\n ...(typeof receipt.cacheReadTokens === \"number\" &&\n typeof cumulativeBaseline.cacheReadTokens === \"number\" &&\n receipt.cacheReadTokens >= cumulativeBaseline.cacheReadTokens\n ? {\n cacheReadTokens:\n receipt.cacheReadTokens - cumulativeBaseline.cacheReadTokens,\n }\n : {}),\n ...(typeof receipt.cacheCreationTokens === \"number\" &&\n typeof cumulativeBaseline.cacheCreationTokens === \"number\" &&\n receipt.cacheCreationTokens >= cumulativeBaseline.cacheCreationTokens\n ? {\n cacheCreationTokens:\n receipt.cacheCreationTokens -\n cumulativeBaseline.cacheCreationTokens,\n }\n : {}),\n ...(typeof receipt.reasoningOutputTokens === \"number\" &&\n typeof cumulativeBaseline.reasoningOutputTokens === \"number\" &&\n receipt.reasoningOutputTokens >= cumulativeBaseline.reasoningOutputTokens\n ? {\n reasoningOutputTokens:\n receipt.reasoningOutputTokens -\n cumulativeBaseline.reasoningOutputTokens,\n }\n : {}),\n });\n cumulativeBaseline = receipt;\n }\n\n const perModel: PerModelUsage[] = [...buckets.entries()].map(\n ([modelId, bucket]) => ({\n modelId,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n cacheReadTokens: bucket.cacheReadReported ? bucket.cacheReadTokens : null,\n cacheCreationTokens: bucket.cacheCreationReported\n ? bucket.cacheCreationTokens\n : null,\n reasoningOutputTokens: bucket.reasoningReported\n ? bucket.reasoningOutputTokens\n : null,\n }),\n );\n\n // Rule 7: paired monotonic intervals; unmatched terminals are NAMED.\n function sumIntervals(\n intervals: LifecycleInterval[],\n label: string,\n ): { total: number | null; complete: boolean } {\n let total = 0;\n let closed = 0;\n for (const interval of intervals) {\n if (interval.endedAt == null) {\n missing.push(`${label} interval ${interval.id} never observed its terminal event`);\n continue;\n }\n total += Math.max(0, interval.endedAt - interval.startedAt);\n closed += 1;\n }\n if (intervals.length === 0) return { total: null, complete: true };\n return { total, complete: closed === intervals.length };\n }\n const provider = sumIntervals(input.providerTurns, \"provider turn\");\n const tool = sumIntervals(input.toolIntervals, \"tool\");\n\n // Rule 9: COMPLETE needs a usable receipt for every observable provider turn.\n const turnsWithoutReceipts = input.providerTurns.filter(\n (t) => !receiptTurnIds.has(t.id),\n );\n for (const turn of turnsWithoutReceipts) {\n missing.push(`provider turn ${turn.id} carried no usable usage receipt`);\n }\n\n if (usable === 0) {\n return {\n inputTokens: null,\n outputTokens: null,\n cacheReadTokens: null,\n cacheCreationTokens: null,\n reasoningOutputTokens: null,\n providerActiveDurationMs: provider.total,\n toolDurationMs: tool.total,\n coverage: \"UNAVAILABLE\",\n missingRanges: missing,\n perModel: [],\n };\n }\n const complete =\n missing.length === 0 && provider.complete && tool.complete;\n return {\n inputTokens,\n outputTokens,\n cacheReadTokens: cacheReadReported ? cacheReadTokens : null,\n cacheCreationTokens: cacheCreationReported ? cacheCreationTokens : null,\n reasoningOutputTokens: reasoningReported ? reasoningOutputTokens : null,\n providerActiveDurationMs: provider.total,\n toolDurationMs: tool.total,\n coverage: complete ? \"COMPLETE\" : \"PARTIAL\",\n missingRanges: missing,\n perModel,\n };\n}\n", "/**\n * M20.1 \u00A715.1 \u2014 Claude Code capture: a PURE, DETERMINISTIC mapper from the\n * transcript entries the SUPPORTED hook surface names (`transcript_path` is a\n * documented lifecycle-hook payload) onto the v1 SessionEvent envelope.\n *\n * Only OBSERVABLE shapes are mapped \u2014 visible user/assistant messages, tool\n * calls/results, and usage receipts. Anything unrecognized maps to null and\n * is counted by the capability snapshot rather than guessed at (\u00A715.3). No\n * semantic classification happens here (frozen decision 19).\n */\n\nimport type { TimingLine } from \"./session-claude-timing.js\";\nimport type { SessionEvent } from \"./session-events.js\";\nimport { SESSION_EVENT_VERSION } from \"./session-events.js\";\n\ninterface ClaudeContentBlock {\n type?: string;\n text?: string;\n id?: string;\n name?: string;\n input?: unknown;\n tool_use_id?: string;\n content?: unknown;\n is_error?: boolean;\n}\n\ninterface ClaudeTranscriptEntry {\n type?: string;\n uuid?: string;\n timestamp?: string;\n /** True on subagent (sidechain) entries \u2014 not the operator's own turn. */\n isSidechain?: boolean;\n /** True on host-synthesized user entries (command wrappers, caveats). */\n isMeta?: boolean;\n /** True on the post-compaction continuation entry \u2014 synthetic, not typed. */\n isCompactSummary?: boolean;\n message?: {\n role?: string;\n /**\n * control-room AC2.1 \u2014 the model the provider ACTUALLY ran, as Claude Code\n * stamps it on every assistant entry. Free: the host already tails this\n * file, and nothing else in the record knows which model produced the work.\n */\n model?: string;\n content?: ClaudeContentBlock[] | string;\n usage?: {\n input_tokens?: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n output_tokens?: number;\n };\n };\n}\n\nexport interface MappedTranscriptLine {\n events: Array<Omit<SessionEvent, \"sequence\">>;\n /** True when the line held a shape this adapter does not observe. */\n unrecognized: boolean;\n /**\n * The model this line names, when it named one (assistant entries only).\n * Reported, never accumulated \u2014 this mapper stays pure and per-line; the\n * bridge decides what \"the session's model\" is.\n */\n modelId?: string;\n /**\n * control-room AC3.7 \u2014 what this line contributes to interval timing.\n * Reported per line for the same reason as `modelId`: pairing is cross-line\n * state, and it lives in ClaudeTimingTracker, not in this mapper.\n */\n timing?: TimingLine;\n}\n\nfunction baseEvent(\n entry: ClaudeTranscriptEntry,\n kind: SessionEvent[\"kind\"],\n payload: unknown,\n idSuffix = \"\",\n): Omit<SessionEvent, \"sequence\"> {\n return {\n version: SESSION_EVENT_VERSION,\n at: entry.timestamp ?? new Date(0).toISOString(),\n provider: \"claude\",\n ...(entry.uuid ? { providerEventId: `${entry.uuid}${idSuffix}` } : {}),\n kind,\n payload,\n };\n}\n\nfunction textOf(content: ClaudeContentBlock[] | string | undefined): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .filter((block) => block.type === \"text\" && typeof block.text === \"string\")\n .map((block) => block.text)\n .join(\"\\n\");\n}\n\n/** Map ONE transcript JSONL line. Deterministic; never throws. */\nexport function mapClaudeTranscriptLine(line: string): MappedTranscriptLine {\n let entry: ClaudeTranscriptEntry;\n try {\n entry = JSON.parse(line) as ClaudeTranscriptEntry;\n } catch {\n return { events: [], unrecognized: true };\n }\n if (entry?.type !== \"user\" && entry?.type !== \"assistant\") {\n // summary/meta/system lines are not observable conversation events.\n return { events: [], unrecognized: false };\n }\n const events: Array<Omit<SessionEvent, \"sequence\">> = [];\n const content = entry.message?.content;\n\n if (entry.type === \"user\") {\n const blocks = Array.isArray(content) ? content : [];\n const toolResults = blocks.filter((b) => b.type === \"tool_result\");\n for (const block of toolResults) {\n events.push(\n baseEvent(\n entry,\n \"tool_result\",\n {\n toolUseId: block.tool_use_id ?? null,\n isError: Boolean(block.is_error),\n content: block.content ?? null,\n },\n `:result:${block.tool_use_id ?? \"\"}`,\n ),\n );\n }\n const text = textOf(content);\n if (text) {\n events.push(baseEvent(entry, \"user_message\", { text }));\n }\n return {\n events,\n unrecognized: false,\n ...timingOf(entry, {\n toolEnds: toolResults\n .map((block) => block.tool_use_id)\n .filter((id): id is string => typeof id === \"string\"),\n }),\n };\n }\n\n // assistant\n const modelId =\n typeof entry.message?.model === \"string\" && entry.message.model.trim()\n ? entry.message.model.trim()\n : undefined;\n const blocks = Array.isArray(content) ? content : [];\n const text = textOf(content);\n if (text) {\n events.push(baseEvent(entry, \"assistant_message\", { text }));\n }\n for (const block of blocks) {\n if (block.type === \"tool_use\") {\n events.push(\n baseEvent(\n entry,\n \"tool_call\",\n { toolUseId: block.id ?? null, name: block.name ?? null, input: block.input ?? null },\n `:tool:${block.id ?? \"\"}`,\n ),\n );\n }\n }\n const usage = entry.message?.usage;\n if (\n usage &&\n (typeof usage.input_tokens === \"number\" ||\n typeof usage.cache_creation_input_tokens === \"number\" ||\n typeof usage.cache_read_input_tokens === \"number\" ||\n typeof usage.output_tokens === \"number\")\n ) {\n // Claude reports PER-TURN usage \u2014 a delta receipt keyed by the entry uuid.\n // Anthropic's input_tokens EXCLUDES cache tokens (siblings, not a subset \u2014\n // unlike OpenAI's cached_input_tokens), so total input is the three summed.\n // The cache split rides along (AGE-938) \u2014 but only when the entry actually\n // carried a cache field, so an old transcript format stays \"unreported\"\n // rather than claiming a measured zero.\n const hasCacheFields =\n typeof usage.cache_read_input_tokens === \"number\" ||\n typeof usage.cache_creation_input_tokens === \"number\";\n events.push(\n baseEvent(\n entry,\n \"usage\",\n {\n kind: \"delta\",\n inputTokens:\n (usage.input_tokens ?? 0) +\n (usage.cache_creation_input_tokens ?? 0) +\n (usage.cache_read_input_tokens ?? 0),\n outputTokens: usage.output_tokens ?? 0,\n ...(hasCacheFields\n ? {\n cacheReadTokens: usage.cache_read_input_tokens ?? 0,\n cacheCreationTokens: usage.cache_creation_input_tokens ?? 0,\n }\n : {}),\n // TPM Slice 2 (AC2.4): the model that produced THIS receipt \u2014 the\n // same entry stamps both, which is what makes per-model grouping a\n // grouped receipt rather than an estimate. Anthropic does not split\n // reasoning tokens out, so no reasoningOutputTokens here (absent,\n // never 0).\n ...(modelId ? { modelId } : {}),\n },\n \":usage\",\n ),\n );\n }\n return {\n events,\n unrecognized: false,\n ...(modelId ? { modelId } : {}),\n ...timingOf(entry, {\n toolStarts: blocks\n .filter((block) => block.type === \"tool_use\")\n .map((block) => block.id)\n .filter((id): id is string => typeof id === \"string\"),\n }),\n };\n}\n\n/**\n * The timing contribution of one entry, or nothing when the entry carries no\n * parseable timestamp. An unparseable timestamp yields NO interval rather than\n * an epoch-zero one \u2014 a fabricated 56-year duration is worse than a named gap.\n */\nfunction timingOf(\n entry: ClaudeTranscriptEntry,\n parts: { toolStarts?: string[]; toolEnds?: string[] },\n): { timing: TimingLine } | Record<string, never> {\n const at = entry.timestamp ? Date.parse(entry.timestamp) : NaN;\n if (!Number.isFinite(at)) return {};\n return {\n timing: {\n at,\n id: entry.uuid ?? String(at),\n role: entry.type === \"assistant\" ? \"assistant\" : \"user\",\n ...(parts.toolStarts?.length ? { toolStarts: parts.toolStarts } : {}),\n ...(parts.toolEnds?.length ? { toolEnds: parts.toolEnds } : {}),\n },\n };\n}\n\n/**\n * Taxonomy AC5.1 (D9) \u2014 the session's OPENING user prompt: the first\n * HUMAN-AUTHORED user entry with visible text, read from the transcript's own\n * head (the transcript begins at session start even when capture attached\n * later). Host-synthesized user entries are skipped \u2014 `isMeta`, the\n * post-compaction continuation (`isCompactSummary`), and slash-command\n * wrappers (`<command-\u2026>` / `<local-command-\u2026>` markup, which sometimes\n * carries no flag) \u2014 because a session opened with `/jentrix-align` would\n * otherwise file the align boilerplate as its input and satisfy readiness\n * check 1 with it. Null when no such entry exists yet \u2014 the caller retries\n * while the transcript grows and files nothing on a session whose transcript\n * never appears. Pure and deterministic; never throws.\n */\nexport function openingPromptOf(transcript: string): string | null {\n for (const line of transcript.split(\"\\n\")) {\n if (!line.trim()) continue;\n let entry: ClaudeTranscriptEntry;\n try {\n entry = JSON.parse(line) as ClaudeTranscriptEntry;\n } catch {\n continue;\n }\n if (entry?.type !== \"user\" || entry.isSidechain) continue;\n if (entry.isMeta || entry.isCompactSummary) continue;\n const text = textOf(entry.message?.content);\n const trimmed = text.trim();\n if (!trimmed) continue;\n if (\n trimmed.startsWith(\"<command-\") ||\n trimmed.startsWith(\"<local-command-\")\n )\n continue;\n return text;\n }\n return null;\n}\n", "/**\n * Jentrix MVP Control Room \u2014 04-2 timing (control-room PRD AC3.6/AC3.7).\n *\n * `providerActiveDurationMs` and `toolDurationMs` are null on every session\n * row ever written, and the reason is locatable rather than mysterious:\n * `aggregateSessionUsage` returns null for an EMPTY interval list\n * (session-usage.ts), and the only caller of the bridge's interval marks is\n * the CODEX interactive host. The Claude transcript-tailing path \u2014 the only\n * one the MVP actually uses \u2014 never marked an interval, so both columns were\n * structurally null.\n *\n * The gap report offered \"populate or drop the columns\". Dropping was refused\n * on evidence (17 files read them, and the schema is shared with the parent\n * deployment), so this module populates them. It is the pairing half only: the\n * aggregator already knew how to sum intervals.\n *\n * Both figures are MEASURED from timestamps the transcript already carries,\n * never derived by subtraction:\n *\n * \u2022 toolDurationMs \u2014 each `tool_use` block paired with the\n * `tool_result` that answers it.\n * \u2022 providerActiveDurationMs \u2014 each assistant entry paired with whatever\n * handed it control: the user message that prompted\n * it, or the tool result that unblocked it.\n *\n * \"Turn duration minus tool time\" would have been the easy definition and a\n * dishonest one \u2014 it goes negative under parallel tools and reports queueing\n * as generation. Measuring each generation segment where it actually begins\n * costs one more piece of state and answers the question that was asked.\n *\n * PURE and DETERMINISTIC: no I/O, no clock. The wall-clock timestamps in the\n * transcript ARE the right clock here \u2014 this is a replay of recorded events,\n * not a live measurement, and the aggregator clamps each pair at zero.\n */\n\nexport type ObservedIntervalKind = \"turn\" | \"tool\";\n\nexport interface ObservedInterval {\n kind: ObservedIntervalKind;\n /** Stable per-interval id \u2014 the aggregator dedupes and names gaps by it. */\n id: string;\n startedAt: number;\n endedAt: number;\n}\n\n/** What one mapped transcript line contributes to timing. */\nexport interface TimingLine {\n /** Epoch ms parsed from the entry's own timestamp. */\n at: number;\n role: \"user\" | \"assistant\";\n /** `tool_use` block ids this assistant entry opened. */\n toolStarts?: readonly string[];\n /** `tool_use_id`s this user entry answered. */\n toolEnds?: readonly string[];\n /** The entry's uuid \u2014 used to name the generation segment. */\n id: string;\n}\n\n/**\n * Pairs transcript lines into closed intervals as they stream past.\n *\n * Stateful by necessity (pairing is cross-line) but I/O-free and clock-free,\n * so the whole rule is unit-testable from a list of lines.\n */\nexport class ClaudeTimingTracker {\n /**\n * When the provider was last handed control: the newest user message or\n * tool result. Null before the first one \u2014 an assistant entry with no\n * preceding boundary (a resumed transcript whose head we never saw) yields\n * NO interval rather than an invented one starting at zero.\n */\n private boundaryAt: number | null = null;\n private readonly openTools = new Map<string, number>();\n\n /** Feed one line; returns every interval this line CLOSED. */\n observe(line: TimingLine): ObservedInterval[] {\n const closed: ObservedInterval[] = [];\n\n for (const toolUseId of line.toolEnds ?? []) {\n const startedAt = this.openTools.get(toolUseId);\n if (startedAt === undefined) continue; // opened before we were watching\n this.openTools.delete(toolUseId);\n closed.push({\n kind: \"tool\",\n id: `tool:${toolUseId}`,\n startedAt,\n endedAt: line.at,\n });\n }\n\n if (line.role === \"assistant\") {\n if (this.boundaryAt !== null) {\n closed.push({\n kind: \"turn\",\n id: `turn:${line.id}`,\n startedAt: this.boundaryAt,\n endedAt: line.at,\n });\n }\n for (const toolUseId of line.toolStarts ?? []) {\n this.openTools.set(toolUseId, line.at);\n }\n // An assistant entry that called tools does NOT hand control back to the\n // provider \u2014 the tools run next, and their results are the boundary that\n // does. Without this, the wait for a tool would be billed as generation.\n this.boundaryAt = (line.toolStarts?.length ?? 0) > 0 ? null : line.at;\n return closed;\n }\n\n // A user entry always hands control to the provider: a typed message, or\n // a tool result that unblocks the turn already in flight.\n this.boundaryAt = line.at;\n return closed;\n }\n\n /**\n * Tool calls still open at close \u2014 a killed host, a tool that never\n * returned. Reported so the aggregator can NAME the gap and degrade\n * coverage to PARTIAL rather than quietly summing a shorter total.\n */\n unclosedToolIds(): string[] {\n return [...this.openTools.keys()].map((id) => `tool:${id}`);\n }\n}\n", "/**\n * M20.1 \u00A715.2 \u2014 Codex capture: a PURE, DETERMINISTIC mapper from the\n * SUPPORTED SDK/app-server thread event stream (the same `runStreamed` events\n * the runner's provider adapter consumes) onto the v1 SessionEvent envelope.\n * Only observable shapes are mapped; unrecognized events surface through the\n * capability snapshot, never through guessing (\u00A715.3). No private session\n * files are ever parsed (PRD \u00A78.3).\n */\n\nimport type { SessionEvent } from \"./session-events.js\";\nimport { SESSION_EVENT_VERSION } from \"./session-events.js\";\n\ninterface CodexThreadEvent {\n type?: string;\n thread_id?: string;\n item?: {\n id?: string;\n type?: string;\n text?: string;\n command?: string;\n aggregated_output?: string;\n exit_code?: number;\n changes?: unknown;\n name?: string;\n arguments?: unknown;\n result?: unknown;\n status?: string;\n };\n usage?: {\n input_tokens?: number;\n cached_input_tokens?: number;\n output_tokens?: number;\n /** TPM Slice 2 (AC2.7): subset of output_tokens, when reported. */\n reasoning_output_tokens?: number;\n };\n /** TPM Slice 2 (AC2.4): app-server turn context \u2014 names the model PER TURN. */\n model?: string;\n turn_context?: { model?: string };\n error?: { message?: string };\n}\n\nexport interface MappedCodexEvent {\n event: Omit<SessionEvent, \"sequence\"> | null;\n /** The provider thread id when this event carries it (thread.started). */\n threadId?: string;\n /**\n * TPM Slice 2 (AC2.4): the model this event names, when it names one (a\n * turn_context event). Reported, never accumulated \u2014 the host decides what\n * \"the current model\" is, exactly like the Claude mapper's per-line report.\n */\n modelId?: string;\n unrecognized: boolean;\n}\n\nfunction make(\n kind: SessionEvent[\"kind\"],\n payload: unknown,\n providerEventId?: string,\n): Omit<SessionEvent, \"sequence\"> {\n return {\n version: SESSION_EVENT_VERSION,\n at: new Date(0).toISOString(), // stamped by the bridge at observation time\n provider: \"codex\",\n ...(providerEventId ? { providerEventId } : {}),\n kind,\n payload,\n };\n}\n\n/** Map one Codex thread event. Deterministic; never throws. */\nexport function mapCodexThreadEvent(raw: unknown): MappedCodexEvent {\n const event = (raw ?? {}) as CodexThreadEvent;\n switch (event.type) {\n case \"thread.started\":\n return {\n event: make(\"session\", { threadId: event.thread_id ?? null }),\n ...(event.thread_id ? { threadId: event.thread_id } : {}),\n unrecognized: false,\n };\n case \"turn.started\":\n return { event: null, unrecognized: false };\n case \"turn_context\": {\n // TPM Slice 2 (AC2.4): the model can change mid-session and this event\n // is where the runtime says so. Observable-shape mapping only \u2014 when\n // the SDK stream never emits it, nothing here fires and Codex receipts\n // stay in the null-model bucket, disclosed rather than guessed.\n const model = (event.turn_context?.model ?? event.model)?.trim();\n return {\n event: null,\n ...(model ? { modelId: model } : {}),\n unrecognized: false,\n };\n }\n case \"turn.completed\":\n // OpenAI's input_tokens INCLUDES cached (cached_input_tokens is a\n // subset \u2192 cacheReadTokens). Codex has no cache-creation concept, so\n // that field is never emitted here (unreported, not zero) \u2014 AGE-938.\n return {\n event: event.usage\n ? make(\"usage\", {\n kind: \"delta\",\n inputTokens: event.usage.input_tokens ?? 0,\n outputTokens: event.usage.output_tokens ?? 0,\n ...(typeof event.usage.cached_input_tokens === \"number\"\n ? { cacheReadTokens: event.usage.cached_input_tokens }\n : {}),\n // TPM Slice 2 (AC2.7): real spend visibility OpenAI reports\n // and Anthropic does not split out \u2014 mapped only when present.\n ...(typeof event.usage.reasoning_output_tokens === \"number\"\n ? {\n reasoningOutputTokens:\n event.usage.reasoning_output_tokens,\n }\n : {}),\n })\n : null,\n unrecognized: false,\n };\n case \"turn.failed\":\n return {\n event: make(\"error\", {\n message: event.error?.message ?? \"turn failed\",\n }),\n unrecognized: false,\n };\n case \"item.completed\": {\n const item = event.item ?? {};\n const id = item.id;\n switch (item.type) {\n case \"agent_message\":\n return {\n event: make(\"assistant_message\", { text: item.text ?? \"\" }, id),\n unrecognized: false,\n };\n case \"command_execution\":\n return {\n event: make(\n \"command\",\n {\n command: item.command ?? null,\n exitCode: item.exit_code ?? null,\n output: item.aggregated_output ?? null,\n },\n id,\n ),\n unrecognized: false,\n };\n case \"file_change\":\n return {\n event: make(\"file_change\", { changes: item.changes ?? null }, id),\n unrecognized: false,\n };\n case \"mcp_tool_call\":\n return {\n event: make(\n \"tool_call\",\n {\n name: item.name ?? null,\n input: item.arguments ?? null,\n status: item.status ?? null,\n },\n id,\n ),\n unrecognized: false,\n };\n case \"reasoning\":\n // Hidden reasoning is deliberately NOT captured (PRD \u00A75 non-goal).\n return { event: null, unrecognized: false };\n default:\n return { event: null, unrecognized: true };\n }\n }\n default:\n return { event: null, unrecognized: true };\n }\n}\n", "/** Pure mapping from supported Codex lifecycle hook payloads to session events. */\n\nimport type { SessionEventKind } from \"./session-events.js\";\n\nexport interface MappedCodexHook {\n events: Array<{ kind: SessionEventKind; payload: unknown }>;\n modelId: string | null;\n}\n\nfunction text(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value : null;\n}\n\nexport function mapCodexHook(\n event: string,\n payload: Record<string, unknown>,\n): MappedCodexHook {\n const modelId = text(payload.model);\n switch (event) {\n case \"SessionStart\":\n case \"SessionEnd\":\n case \"PreCompact\":\n case \"PostCompact\":\n return {\n events: [\n {\n kind: \"session\",\n payload: {\n lifecycle: event,\n sessionId: payload.session_id ?? null,\n },\n },\n ],\n modelId,\n };\n case \"UserPromptSubmit\": {\n const prompt = text(payload.prompt);\n return {\n events: prompt\n ? [{ kind: \"user_message\", payload: { text: prompt } }]\n : [],\n modelId,\n };\n }\n case \"PostToolUse\": {\n const name = text(payload.tool_name) ?? \"unknown\";\n const events: MappedCodexHook[\"events\"] = [\n {\n kind: \"tool_call\",\n payload: { name, input: payload.tool_input ?? null },\n },\n ];\n if (\"tool_response\" in payload) {\n events.push({\n kind: \"tool_result\",\n payload: { name, result: payload.tool_response },\n });\n }\n return { events, modelId };\n }\n case \"Stop\": {\n const message = text(payload.last_assistant_message);\n return {\n events: message\n ? [{ kind: \"assistant_message\", payload: { text: message } }]\n : [],\n modelId,\n };\n }\n default:\n return { events: [], modelId };\n }\n}\n", "/**\n * M20.1 \u00A712.2 \u2014 LOCAL redaction, applied BEFORE any content reaches the\n * durable spool, upload, checksum input, or diagnostics. The server re-redacts\n * at ingestion (defense in depth) \u2014 this pass is the one that keeps a secret\n * from ever being durably written on the operator's machine.\n *\n * MIRROR of `src/server/credentials/redact.ts` (the runner sits outside the\n * app's dependency firewall; contracts are mirrored, not imported \u2014 keep the\n * pattern lists in lockstep). Adds the two client-only concerns the server\n * cannot know: configured secret ENV VALUES and home-directory prefixes.\n */\n\nexport const REDACTED = \"\u2039redacted\u203A\";\n\n// Mirrored from src/server/credentials/redact.ts \u2014 keep in lockstep.\nconst SECRET_PATTERNS: RegExp[] = [\n /\\btm[or]?_[A-Za-z0-9_-]{16,}\\b/g,\n /\\bgh[posru]_[A-Za-z0-9]{20,}\\b/g,\n /\\bgithub_pat_[A-Za-z0-9_]{20,}\\b/g,\n /\\bwhsec_[A-Za-z0-9]{16,}\\b/g,\n /\\b(?:AKIA|ASIA)[A-Z0-9]{16}\\b/g,\n /\\bxox[abpsr]-[A-Za-z0-9-]{10,}\\b/g,\n /\\bAIza[A-Za-z0-9_-]{30,}\\b/g,\n /\\bsk-ant-[A-Za-z0-9_-]{20,}\\b/g,\n /\\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\\b/g,\n /\\b[rs]k_(?:live|test)_[A-Za-z0-9]{16,}\\b/g,\n /-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/g,\n /\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/g,\n /\\b(Authorization\\s*[:=]\\s*Bearer\\s+)[A-Za-z0-9._~+/=-]{12,}/gi,\n];\n\n/** Env names whose VALUES are scrubbed wherever they appear (PRD \u00A712.2). */\nconst SECRET_ENV_NAMES = [\n \"STACKS_TOKEN\",\n \"STACKS_BOOTSTRAP_TOKEN\",\n \"STACKS_WEBHOOK_SECRET\",\n \"STACKS_WORKLOAD_SVID\",\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n \"GITHUB_TOKEN\",\n \"AWS_SECRET_ACCESS_KEY\",\n \"R2_SECRET_ACCESS_KEY\",\n];\n\nexport interface SessionRedactor {\n text(input: string): string;\n value(input: unknown): unknown;\n}\n\n/**\n * Build a redactor bound to the current process env + home directory. The\n * literal set is resolved ONCE so every spool write pays only string work.\n * Home-directory prefixes are scrubbed to `~` where the absolute path is not\n * evidence (PRD \u00A712.2) \u2014 repository identity is the normalized owner/name.\n */\nexport function createSessionRedactor(opts: {\n env?: Record<string, string | undefined>;\n homedir?: string | null;\n literals?: string[];\n} = {}): SessionRedactor {\n const env = opts.env ?? process.env;\n const literals = [\n ...(opts.literals ?? []),\n ...SECRET_ENV_NAMES.map((name) => env[name]).filter(\n (v): v is string => typeof v === \"string\" && v.length >= 6,\n ),\n ];\n const home = opts.homedir?.replace(/\\/$/, \"\");\n\n function text(input: string): string {\n let out = input;\n for (const literal of literals) {\n out = out.split(literal).join(REDACTED);\n }\n for (const pattern of SECRET_PATTERNS) {\n out = out.replace(pattern, REDACTED);\n }\n if (home && home.length > 1) {\n out = out.split(home).join(\"~\");\n }\n return out;\n }\n\n function value(input: unknown): unknown {\n if (typeof input === \"string\") return text(input);\n if (Array.isArray(input)) return input.map(value);\n if (input && typeof input === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(input as Record<string, unknown>)) {\n out[k] = value(v);\n }\n return out;\n }\n return input;\n }\n\n return { text, value };\n}\n", "/**\n * M20.1 \u00A712.3 \u2014 the crash-safe local spool. Every event line is REDACTED\n * before it is appended (the caller passes lines through the session\n * redactor first); files are mode-0600 under a mode-0700 session directory.\n *\n * Deletion contract (AC22/AC23 + the amended \u00A712.3): a part file is deleted\n * ONLY when the server acknowledged that exact content \u2014 the acknowledgement\n * carries the STORED checksum, and a redacted-slot refusal or CONFLICT keeps\n * the file. Losing the network never loses evidence; the CLI reports pending\n * parts and retries with the same part numbers.\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n appendFileSync,\n closeSync,\n mkdirSync,\n openSync,\n readdirSync,\n readFileSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n writeSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * M20.1 follow-up (AGE-929): the LOCAL liveness marker `jentrix session status`\n * reads. The server cannot see the local capture leg \u2014 a bound session whose\n * host died reads healthy until the abandonment sweep \u2014 so the host marks its\n * own lifecycle in the spool directory: `host.json` written at start, stamped\n * with the exit at clean shutdown. A crash leaves the start marker with no\n * exit; the CLI detects that shape by probing the recorded pid.\n * The CLI mirrors this file's shape rather than importing it (dependency\n * firewall \u2014 the CLI never imports the runner package).\n */\nexport interface SessionHostMarker {\n pid: number;\n startedAt: string;\n provider: string;\n mode: string;\n /**\n * Whether THIS host runs TRACE capture (AGE-956): `mode` describes how the\n * host attaches (watch/launch), never what it collects, and the CLI's\n * align must report capture truthfully from the live host's actual state \u2014\n * marker existence alone reads capture-blind.\n */\n captureTrace?: boolean;\n /**\n * AGE-957: whether the host has EVER successfully stat'ed its transcript\n * path. False after the grace window means the host is observing nothing\n * (no events, no usage receipts) \u2014 `session status` surfaces it instead of\n * letting a dead tail read as healthy silence.\n */\n transcriptSeen?: boolean;\n /**\n * WHICH transcript this host watches (2026-08-11 gap report F1/P3). Two\n * things need it. `transcriptSeen: true` only reports that the host found A\n * transcript, so proving it found THIS session's needs the path recorded.\n * And a compaction hook, whose cwd is the SESSION's directory and not\n * necessarily the aligned checkout, resolves its Jentrix session by matching\n * the hook payload's transcript_path against this field \u2014 a provable link\n * where a cwd match is a guess.\n */\n transcriptPath?: string;\n /**\n * Cumulative server-acknowledged part count + when the last flush ran \u2014\n * an empty spool is ambiguous (nothing captured vs everything flushed);\n * this stamp is how `session status` tells the two apart.\n */\n ackedParts?: number;\n lastFlushAt?: string;\n exitedAt?: string;\n exitCode?: number;\n}\n\nexport function writeHostMarker(\n sessionDir: string,\n marker: Pick<\n SessionHostMarker,\n \"pid\" | \"provider\" | \"mode\" | \"captureTrace\" | \"transcriptPath\"\n >,\n): void {\n mkdirSync(sessionDir, { recursive: true, mode: 0o700 });\n const body: SessionHostMarker = {\n ...marker,\n startedAt: new Date().toISOString(),\n };\n writeFileSync(join(sessionDir, \"host.json\"), JSON.stringify(body), {\n mode: 0o600,\n });\n}\n\n/** Stamp whether the transcript path has ever been seen (AGE-957). */\nexport function markHostTranscript(sessionDir: string, seen: boolean): void {\n const path = join(sessionDir, \"host.json\");\n let marker: SessionHostMarker;\n try {\n marker = JSON.parse(readFileSync(path, \"utf8\")) as SessionHostMarker;\n } catch {\n return; // no start marker to stamp \u2014 best-effort\n }\n marker.transcriptSeen = seen;\n writeFileSync(path, JSON.stringify(marker), { mode: 0o600 });\n}\n\nexport function markHostFlushed(sessionDir: string, ackedParts: number): void {\n const path = join(sessionDir, \"host.json\");\n let marker: SessionHostMarker;\n try {\n marker = JSON.parse(readFileSync(path, \"utf8\")) as SessionHostMarker;\n } catch {\n return; // no start marker to stamp \u2014 best-effort\n }\n marker.ackedParts = ackedParts;\n marker.lastFlushAt = new Date().toISOString();\n writeFileSync(path, JSON.stringify(marker), { mode: 0o600 });\n}\n\nexport function markHostExited(sessionDir: string, exitCode: number): void {\n const path = join(sessionDir, \"host.json\");\n let marker: SessionHostMarker;\n try {\n marker = JSON.parse(readFileSync(path, \"utf8\")) as SessionHostMarker;\n } catch {\n return; // no start marker to stamp \u2014 best-effort\n }\n marker.exitedAt = new Date().toISOString();\n marker.exitCode = exitCode;\n writeFileSync(path, JSON.stringify(marker), { mode: 0o600 });\n}\n\n/** Rotate a part before it crosses the server's inline ingestion cap. */\nexport const SPOOL_PART_ROTATE_BYTES = 6 * 1024 * 1024;\n\nconst PART_FILE = /^part-(\\d{6})\\.ndjson$/;\n\nexport interface SpoolPart {\n part: number;\n path: string;\n byteSize: number;\n /** sha256 over the part's redacted NDJSON text \u2014 the convergence identity. */\n checksum: string;\n}\n\nexport class SessionSpool {\n private readonly dir: string;\n private currentPart: number;\n\n constructor(root: string, sessionId: string) {\n this.dir = join(root, sessionId);\n mkdirSync(this.dir, { recursive: true, mode: 0o700 });\n const existing = this.listPartNumbers();\n this.currentPart = existing.length ? Math.max(...existing) : 0;\n }\n\n get directory(): string {\n return this.dir;\n }\n\n private partPath(part: number): string {\n return join(this.dir, `part-${String(part).padStart(6, \"0\")}.ndjson`);\n }\n\n private listPartNumbers(): number[] {\n return readdirSync(this.dir)\n .map((name) => PART_FILE.exec(name))\n .filter((m): m is RegExpExecArray => m !== null)\n .map((m) => Number(m[1]));\n }\n\n /**\n * Append one ALREADY-REDACTED NDJSON line durably (0600, fsync'd). Rotates\n * to the next part when the current one would cross the ingestion cap.\n */\n append(redactedLine: string): void {\n const path = this.partPath(this.currentPart);\n let size = 0;\n try {\n size = statSync(path).size;\n } catch {\n // first line of a new part\n }\n if (\n size > 0 &&\n size + Buffer.byteLength(redactedLine) > SPOOL_PART_ROTATE_BYTES\n ) {\n this.currentPart += 1;\n }\n const target = this.partPath(this.currentPart);\n const fd = openSync(target, \"a\", 0o600);\n try {\n writeSync(fd, redactedLine);\n } finally {\n closeSync(fd);\n }\n }\n\n /**\n * Advance past a flushed (acked + deleted) part. Ingestion slots are\n * append-only \u2014 same part + different checksum is a permanent CONFLICT \u2014\n * so a slot the server acknowledged must never be reused for new events.\n */\n advancePast(part: number): void {\n if (part >= this.currentPart) this.currentPart = part + 1;\n }\n\n /** Cheap append without rotation checks (tests / recovery merges). */\n appendRaw(part: number, redactedLine: string): void {\n appendFileSync(this.partPath(part), redactedLine, { mode: 0o600 });\n if (part > this.currentPart) this.currentPart = part;\n }\n\n /** Every pending part with its convergence checksum, ordered by number. */\n pendingParts(): SpoolPart[] {\n return this.listPartNumbers()\n .sort((a, b) => a - b)\n .map((part) => {\n const path = this.partPath(part);\n const body = readFileSync(path, \"utf8\");\n return {\n part,\n path,\n byteSize: Buffer.byteLength(body),\n checksum: createHash(\"sha256\").update(body, \"utf8\").digest(\"hex\"),\n };\n });\n }\n\n /** Read one part's redacted text for upload. */\n readPart(part: number): string {\n return readFileSync(this.partPath(part), \"utf8\");\n }\n\n /**\n * Delete a part ONLY on a server acknowledgement of this exact content.\n * `acknowledgedChecksum` is the STORED checksum from the server's ack; when\n * the server's re-redaction changed the bytes, the caller records the acked\n * checksum into its manifest first, then confirms deletion explicitly with\n * `force`. An audit stub can never satisfy this \u2014 a refusal keeps the file.\n */\n deleteAcknowledged(\n part: number,\n acknowledgedChecksum: string,\n opts: { force?: boolean } = {},\n ): boolean {\n const path = this.partPath(part);\n let body: string;\n try {\n body = readFileSync(path, \"utf8\");\n } catch {\n return false; // already gone\n }\n const localChecksum = createHash(\"sha256\")\n .update(body, \"utf8\")\n .digest(\"hex\");\n if (localChecksum !== acknowledgedChecksum && !opts.force) {\n return false;\n }\n // Atomic-ish removal: rename first so a crash mid-delete never leaves a\n // half-truncated live part.\n const tomb = `${path}.acked`;\n renameSync(path, tomb);\n unlinkSync(tomb);\n return true;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["readFileSync", "statSync", "unlinkSync", "writeFileSync", "join", "writeFileSync", "text", "writeFileSync", "blocks", "text", "text", "mkdirSync", "readFileSync", "renameSync", "unlinkSync", "writeFileSync", "join", "join", "text", "writeFileSync", "readFileSync", "statSync", "unlinkSync"]
|
|
7
7
|
}
|