@agentproto/runtime 2.7.0 → 2.10.0
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/README.md +87 -1
- package/dist/catalog-models.d.ts +62 -2
- package/dist/catalog-models.mjs +53 -5
- package/dist/catalog-models.mjs.map +1 -1
- package/dist/config.d.ts +47 -2
- package/dist/config.mjs.map +1 -1
- package/dist/index.d.ts +438 -19
- package/dist/index.mjs +2956 -961
- package/dist/index.mjs.map +1 -1
- package/dist/pr-provenance.d.ts +29 -1
- package/dist/pr-provenance.mjs +18 -3
- package/dist/pr-provenance.mjs.map +1 -1
- package/dist/release-check.d.ts +144 -0
- package/dist/release-check.mjs +149 -0
- package/dist/release-check.mjs.map +1 -0
- package/dist/resume-strategies.d.ts +48 -8
- package/dist/resume-strategies.mjs +37 -18
- package/dist/resume-strategies.mjs.map +1 -1
- package/dist/session-presence.d.ts +115 -0
- package/dist/session-presence.mjs +103 -0
- package/dist/session-presence.mjs.map +1 -0
- package/dist/session-story.mjs.map +1 -1
- package/dist/{spawn-defaults-DVgmfxWo.d.ts → spawn-defaults-DUnTfwVK.d.ts} +29 -10
- package/package.json +37 -25
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tool-presenter.ts","../src/tool-call-record.ts","../src/transcript-writer.ts","../src/transcript-export.ts","../src/conversation-store.ts","../src/resume-strategies.ts"],"names":["join","homedir","resolve","fs","text","createReadStream","createInterface","exportClaudeCodeSession","discoverHermesSessions","exportHermesSession","discoverCodexSessions","exportCodexSession","discoverOpenCodeSessions","exportOpenCodeSession","discoverMastracodeInprocessSessions","exportMastracodeInprocessSession","discoverPiSessions","exportPiSession"],"mappings":"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","file":"resume-strategies.mjs","sourcesContent":["/**\n * Turns a raw tool-call name + args (and its eventual result) into a short,\n * human-readable line for ring-buffer / CLI / transcript rendering. Without\n * this, every tool call renders as a bare `[tool] view` with no args and no\n * outcome — this module is the one place that knows how to summarize both.\n */\n\nconst SALIENT_ARG_KEYS = [\n \"file_path\",\n \"path\",\n \"filePath\",\n \"file\",\n \"command\",\n \"pattern\",\n \"query\",\n \"q\",\n \"url\",\n \"todos\",\n \"description\",\n \"prompt\",\n] as const\n\nconst MAX_CALL_LENGTH = 120\nconst MAX_RESULT_LENGTH = 160\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction truncate(value: string, max: number): string {\n const oneLine = value.replace(/\\s+/g, \" \").trim()\n return oneLine.length > max ? `${oneLine.slice(0, max - 1)}…` : oneLine\n}\n\nfunction formatArgValue(value: unknown): string {\n if (typeof value === \"string\") return value\n if (Array.isArray(value)) return `${value.length} item${value.length === 1 ? \"\" : \"s\"}`\n if (isRecord(value)) return JSON.stringify(value)\n return String(value)\n}\n\nfunction pickSalientArg(args: Record<string, unknown>): string | null {\n for (const key of SALIENT_ARG_KEYS) {\n const value = args[key]\n if (value !== undefined && value !== null && value !== \"\") {\n return formatArgValue(value)\n }\n }\n return null\n}\n\ntype BespokeFormatter = (args: Record<string, unknown>) => string\n\nfunction subagentSummary(args: Record<string, unknown>): string {\n const description =\n typeof args.description === \"string\"\n ? args.description\n : typeof args.prompt === \"string\"\n ? args.prompt\n : \"subagent\"\n return `↳ subagent: ${truncate(description, MAX_CALL_LENGTH)}`\n}\n\n// Bespoke one-liners for control tools where the generic arg-sniffing\n// below would either miss the point (ScheduleWakeup's payload isn't a\n// file/command/pattern) or just repeat the tool name pointlessly\n// (TodoWrite, ExitPlanMode carry no salient single-value arg).\nconst BESPOKE_TOOLS: Record<string, BespokeFormatter> = {\n schedulewakeup: (args) => {\n const delay = args.delaySeconds ?? args.delay ?? \"?\"\n const reason = typeof args.reason === \"string\" ? args.reason : \"\"\n return reason ? `⏰ wake in ${delay}s — ${reason}` : `⏰ wake in ${delay}s`\n },\n task: subagentSummary,\n agent: subagentSummary,\n todowrite: (args) => {\n const todos = Array.isArray(args.todos) ? args.todos : []\n return `☑ todos (${todos.length})`\n },\n exitplanmode: () => \"📋 plan ready\",\n}\n\n/** A one-line human summary of a tool call, e.g. `read src/foo.ts` or `⏰ wake in 30s — checking CI`. */\nexport function formatToolCall(toolName: string, args: unknown): string {\n const name = toolName || \"tool\"\n const argsRecord = isRecord(args) ? args : {}\n\n const bespoke = BESPOKE_TOOLS[name.toLowerCase()]\n if (bespoke) return bespoke(argsRecord)\n\n const salient = pickSalientArg(argsRecord)\n if (salient !== null) {\n // Some ACP agents (e.g. claude-agent-acp) already bake the salient\n // value into a curated title — \"Read src/foo.ts\" alongside\n // arguments.path === \"src/foo.ts\". Appending it again would render\n // \"Read src/foo.ts src/foo.ts\". Only append when it adds new info.\n if (name.toLowerCase().includes(salient.toLowerCase())) {\n return truncate(name, MAX_CALL_LENGTH)\n }\n return truncate(`${name} ${salient}`, MAX_CALL_LENGTH)\n }\n\n if (Object.keys(argsRecord).length === 0) return name\n\n return truncate(`${name} ${JSON.stringify(args)}`, MAX_CALL_LENGTH)\n}\n\nfunction extractText(value: unknown): string | null {\n if (value == null) return null\n if (typeof value === \"string\") return value\n if (Array.isArray(value)) {\n const parts = value.map(extractText).filter((v): v is string => v != null)\n return parts.length ? parts.join(\"\\n\") : null\n }\n if (isRecord(value)) {\n if (typeof value.text === \"string\") return value.text\n if (typeof value.message === \"string\") return value.message\n if (Array.isArray(value.content)) return extractText(value.content)\n if (typeof value.error === \"string\") return value.error\n if (isRecord(value.error) && typeof value.error.message === \"string\") {\n return value.error.message\n }\n return null\n }\n return null\n}\n\n/**\n * A short outcome line for a completed tool call, or `null` when there's\n * nothing useful to show (e.g. an empty/void result). `toolName` is\n * accepted for parity with `formatToolCall` and future bespoke result\n * formatting, but generic text extraction covers today's cases.\n */\nexport function formatToolResult(\n toolName: string | undefined,\n result: unknown,\n isError: boolean,\n): string | null {\n void toolName\n const text = extractText(result)\n\n if (isError) {\n const message = text ?? (result != null ? JSON.stringify(result) : \"failed\")\n const firstLine = message.split(/\\r?\\n/)[0] ?? message\n return truncate(firstLine, MAX_RESULT_LENGTH)\n }\n\n if (text == null) return null\n const trimmed = text.trim()\n if (!trimmed) return null\n\n const lines = trimmed.split(/\\r?\\n/)\n if (lines.length > 1) {\n const bytes = Buffer.byteLength(trimmed, \"utf8\")\n return `${lines.length} lines, ${bytes}B`\n }\n return truncate(lines[0]!, MAX_RESULT_LENGTH)\n}\n","/**\n * ONE normalized shape for a finished tool/command call — the unification\n * target for the two disjoint logs this repo has today: `recordCommand`'s\n * `CommandLogEntry` (command-log.ts, the `command_execute` proxy path) and\n * `transcript-writer.ts`'s per-kind `tool-call`/`tool-result` records (an\n * agent's own in-process Bash/Edit/…). Both writers append a\n * `ToolCallRecord` line (tagged `kind: \"tool-call-record\"` on disk — see\n * tool-call-log.ts) to the SAME per-session `events.jsonl` they already\n * own, so `tool_calls_list` can read either without a new store.\n *\n * Deliberately excludes session-level provenance (`harness`, `origin`,\n * `callerSessionId`): that already lives once on the owning\n * `SessionDescriptor` (see sessions.ts), and duplicating it onto every\n * call-level line would just be a snapshot that can drift. `tool_calls_list`\n * joins it in at read time from the descriptor instead.\n */\n\nexport interface ToolCallRecord {\n /** The session (command or agent-cli) whose events.jsonl this call was\n * written into. */\n sessionId: string\n /** Tool/command name — an MCP tool name for the proxy path\n * (\"command_execute\"), or an ACP tool name for the in-agent path\n * (\"Bash\", \"Read\", \"Edit\", …). */\n tool: string\n /** Shell command string, when this call is shell-shaped. Present for\n * every proxy call; only present in-agent when `extractCommandArgs`\n * recognizes the tool's `arguments` as `{command, args?}` (a Bash-style\n * tool) — every other in-agent tool (Read, Edit, …) legitimately has no\n * shell command, so this stays absent rather than guessing. */\n command?: string\n args?: string[]\n /** Process exit code — only meaningful for the proxy path, which runs a\n * real subprocess. Absent for in-agent calls (ACP has no exit-code\n * concept, only `isError`). */\n exitCode?: number\n isError?: boolean\n durationMs?: number\n ts: string\n}\n\n/**\n * Best-effort extraction of a shell-shaped `{command, args}` out of an\n * arbitrary, harness-shaped tool-call `arguments` blob (typed `unknown` at\n * the ACP boundary — see `AgentStreamEvent.arguments` in sessions.ts).\n * Only recognizes the `{command: string, args?: string[]}` shape a\n * Bash-style tool sends; every other tool shape returns `{}` rather than\n * guessing, per AGENTS.md's \"no silent caps\" ethic applied to normalization\n * (don't claim a `command` this didn't actually see).\n */\nexport function extractCommandArgs(input: unknown): { command?: string; args?: string[] } {\n if (!input || typeof input !== \"object\") return {}\n const obj = input as Record<string, unknown>\n const command = typeof obj.command === \"string\" ? obj.command : undefined\n if (command === undefined) return {}\n const argv =\n Array.isArray(obj.args) && obj.args.every(a => typeof a === \"string\")\n ? (obj.args as string[])\n : undefined\n return argv ? { command, args: argv } : { command }\n}\n","/**\n * Per-session structured event capture — one append-only JSONL file per\n * agent-cli session, written at the same tap point where `projectEvent`\n * (sessions.ts) flattens `StreamEvent`s into the ANSI ring buffer, but\n * BEFORE that flattening happens. Gives agentproto the Claude-Code\n * property: a daemon-owned structured transcript that survives a daemon\n * restart (the ring buffer doesn't) and that any frontend can render,\n * not just the two adapters `transcript-export.ts` knows how to re-read\n * from their own native stores.\n *\n * File layout: `~/.agentproto/sessions/<sessionId>/events.jsonl`, one\n * JSON object per line: `{seq, ts, kind, ...fields}`.\n *\n * PTY (`terminal`) and `command` sessions never call into this writer —\n * they have no structured event source (see report-transcript-\n * architecture.md finding C.17), so this module is only ever driven from\n * `agent-cli` sessions' `runAgentTurn`.\n */\n\nimport { createWriteStream, mkdirSync, readFileSync, type WriteStream } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { join } from \"node:path\"\nimport type { SessionObserver } from \"./session-observer.js\"\nimport type { AgentStreamEvent } from \"./sessions.js\"\nimport { extractCommandArgs } from \"./tool-call-record.js\"\nimport type { SessionUsage } from \"./usage.js\"\n\n/** Debounce window for flushing a buffered text-delta/thought fragment\n * that hasn't hit a newline yet. Keeps a long no-newline stream from\n * sitting in memory indefinitely without also spamming one record per\n * token — mirrors the \"coalesce, don't spam\" rule `projectEvent`\n * already applies to the ring buffer, just with a disk-durability\n * angle added. */\nconst DEBOUNCE_MS = 250\n\n/** `baseDir` defaults to `~/.agentproto/sessions` — overridable so tests\n * (and a future `--home` style daemon flag) can redirect writes away from\n * the real home directory instead of mocking `node:os`. */\nexport function sessionTranscriptDir(sessionId: string, baseDir?: string): string {\n return join(baseDir ?? join(homedir(), \".agentproto\", \"sessions\"), sessionId)\n}\n\nexport function sessionEventsPath(sessionId: string, baseDir?: string): string {\n return join(sessionTranscriptDir(sessionId, baseDir), \"events.jsonl\")\n}\n\n/** Highest `seq` already durably on disk for a session, or 0 when the file\n * is absent/empty. A fresh writer instance (e.g. after a daemon restart)\n * opens the existing events.jsonl in append mode, so its first record must\n * continue from this cursor rather than restarting at 1 — otherwise a\n * restart mid-session emits duplicate seq numbers and any `since`-based\n * reader (GET /sessions/:id/events) silently drops the post-restart tail.\n * Records are written in ascending `seq`, so the max is on the last valid\n * line, but a truncated/partial final line is tolerated by scanning every\n * parseable line rather than trusting the tail. */\nfunction highestSeqOnDisk(path: string): number {\n let raw: string\n try {\n raw = readFileSync(path, \"utf8\")\n } catch {\n // ENOENT (fresh session) or any read error — start from 0.\n return 0\n }\n let max = 0\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim()\n if (!trimmed) continue\n try {\n const rec = JSON.parse(trimmed) as { seq?: unknown }\n if (typeof rec.seq === \"number\" && rec.seq > max) max = rec.seq\n } catch {\n // Ignore a malformed/partial line (e.g. a torn final write).\n }\n }\n return max\n}\n\nexport interface TranscriptWriter extends SessionObserver {\n /** Record the outgoing message for a new turn. Not an ACP `StreamEvent`\n * kind (ACP's own \"agent-prompt\" means the agent asking the human a\n * question, the opposite direction) — recorded under its own\n * \"user-prompt\" kind so turns stay reconstructable without overloading\n * that name. `opts.source` (provenance, e.g. `agent:<sessionId>` for a\n * supervisor-injected prompt) rides onto the record's `source` field. */\n recordPrompt(sessionId: string, message: unknown, opts?: { source?: string }): void\n /** Record one structured stream event, ahead of `projectEvent`'s\n * flattening. Coalesces consecutive text-delta/thought chunks the same\n * way the ring buffer does. */\n recordEvent(sessionId: string, evt: AgentStreamEvent): void\n /** Record a durable `usage_snapshot` recap at a turn boundary or on\n * session exit — the cumulative cost/token/context view resolved by\n * `deriveSessionUsage`. Distinct from the high-frequency `usage_update`\n * stream: this is the aggregable turn-boundary durable record, so a\n * daemon restart doesn't lose the session's accumulated usage. */\n recordUsageSnapshot(sessionId: string, usage: SessionUsage): void\n /** Flush buffers and close the session's append stream. Safe to call\n * more than once (subsequent calls are no-ops) and safe to call for a\n * session that never wrote anything (also a no-op). Production call\n * sites treat this as fire-and-forget (same as `agentSession.close()`);\n * the returned promise exists so tests can await the on-disk flush. */\n close(sessionId: string): Promise<void>\n /** Close every open session stream — called from the registry's\n * synchronous shutdown path (fire-and-forget there too). */\n closeAll(): Promise<void>\n /** Subscribe to every record as it's written for one session — the\n * live-push half of `GET /sessions/:id/events/stream`'s replay-then-\n * subscribe handoff (http-server.ts). Delivers the exact object shape\n * written to disk (`{seq, ts, kind, ...}`, pre-JSON.stringify), so a\n * consumer already reducing the poll route's `events` array can reduce\n * this stream with identical logic. No backfill here — history is a\n * file read the caller does itself; this only wires the live tap.\n * Notification happens synchronously, in the same call that appends the\n * record, so a caller that subscribes before doing its own disk read is\n * guaranteed to observe (via this callback) every record from that\n * point on, even ones the read might otherwise race. Returns an\n * unsubscribe fn; safe to call more than once. */\n subscribe(sessionId: string, onRecord: (record: Record<string, unknown>) => void): () => void\n}\n\ninterface WriterState {\n stream: WriteStream\n seq: number\n textBuf: string\n thoughtBuf: string\n textDebounce: ReturnType<typeof setTimeout> | null\n thoughtDebounce: ReturnType<typeof setTimeout> | null\n /**\n * Latest un-written tool-call ENRICHMENT per toolCallId — the same\n * coalescing textBuf/thoughtBuf do, for the same reason.\n *\n * An ACP agent streams a tool's `rawInput` as the model types it, so one\n * call arrives as a run of growing updates:\n * {} → {adapter} → {adapter,cwd} → {adapter,cwd,role} → {…,prompt} → …\n * Writing each would put six records on disk for one `agent_start`, and\n * only the last is true. They're superseding snapshots, not increments:\n * keep the newest and write it once, when something else needs ordering\n * around it (see flushBuffers).\n */\n toolUpdates: Map<string, Record<string, unknown>>\n /**\n * Latest known {toolName, arguments} + announce time per in-flight\n * toolCallId, kept across BOTH the announcement and any enrichment\n * updates (not just the held/coalesced ones above) — the \"tool-result\"\n * handler consumes this to emit ONE normalized `tool-call-record` line\n * (see tool-call-record.ts) per finished call, since a bare \"tool-result\"\n * event carries neither the tool's name nor its input.\n */\n toolCallMeta: Map<string, { toolName: string; arguments: unknown; startedAt: number }>\n}\n\nexport function createTranscriptWriter(opts?: { baseDir?: string }): TranscriptWriter {\n const baseDir = opts?.baseDir\n const states = new Map<string, WriterState>()\n const listeners = new Map<string, Set<(record: Record<string, unknown>) => void>>()\n\n const getState = (sessionId: string): WriterState => {\n const existing = states.get(sessionId)\n if (existing) return existing\n mkdirSync(sessionTranscriptDir(sessionId, baseDir), { recursive: true })\n const eventsPath = sessionEventsPath(sessionId, baseDir)\n // Resume the seq counter from what's already durable so a restart\n // mid-session keeps events.jsonl monotonic in append mode.\n const resumeSeq = highestSeqOnDisk(eventsPath)\n const stream = createWriteStream(eventsPath, { flags: \"a\" })\n stream.on(\"error\", err => {\n console.warn(`[transcript-writer] session ${sessionId}: ${err.message}`)\n })\n const state: WriterState = {\n stream,\n seq: resumeSeq,\n textBuf: \"\",\n thoughtBuf: \"\",\n textDebounce: null,\n thoughtDebounce: null,\n toolUpdates: new Map(),\n toolCallMeta: new Map(),\n }\n states.set(sessionId, state)\n return state\n }\n\n const writeRecord = (\n sessionId: string,\n state: WriterState,\n record: Record<string, unknown>\n ): void => {\n state.seq += 1\n const full = { seq: state.seq, ts: new Date().toISOString(), ...record }\n state.stream.write(JSON.stringify(full) + \"\\n\")\n const subs = listeners.get(sessionId)\n if (subs) {\n for (const onRecord of subs) onRecord(full)\n }\n }\n\n const flushTextBuf = (sessionId: string, state: WriterState): void => {\n if (state.textDebounce) {\n clearTimeout(state.textDebounce)\n state.textDebounce = null\n }\n if (!state.textBuf) return\n const text = state.textBuf\n state.textBuf = \"\"\n writeRecord(sessionId, state, { kind: \"text-delta\", sessionId, text })\n }\n\n const flushThoughtBuf = (sessionId: string, state: WriterState): void => {\n if (state.thoughtDebounce) {\n clearTimeout(state.thoughtDebounce)\n state.thoughtDebounce = null\n }\n if (!state.thoughtBuf) return\n const text = state.thoughtBuf\n state.thoughtBuf = \"\"\n writeRecord(sessionId, state, { kind: \"thought\", sessionId, text })\n }\n\n /** Write the newest held enrichment for each in-flight tool call. */\n const flushToolUpdates = (sessionId: string, state: WriterState): void => {\n if (state.toolUpdates.size === 0) return\n const held = [...state.toolUpdates.values()]\n state.toolUpdates.clear()\n for (const record of held) writeRecord(sessionId, state, record)\n }\n\n /** Flush every coalescing buffer as FINAL (non-partial) records — called\n * before any other event so on-disk order matches wall-clock order even\n * when a partial line, or a still-growing tool input, was still held. */\n const flushBuffers = (sessionId: string, state: WriterState): void => {\n flushThoughtBuf(sessionId, state)\n flushTextBuf(sessionId, state)\n flushToolUpdates(sessionId, state)\n }\n\n const scheduleTextDebounce = (sessionId: string, state: WriterState): void => {\n if (state.textDebounce) clearTimeout(state.textDebounce)\n state.textDebounce = setTimeout(() => {\n state.textDebounce = null\n if (!state.textBuf) return\n const text = state.textBuf\n state.textBuf = \"\"\n writeRecord(sessionId, state, { kind: \"text-delta\", sessionId, text, partial: true })\n }, DEBOUNCE_MS)\n }\n\n const scheduleThoughtDebounce = (sessionId: string, state: WriterState): void => {\n if (state.thoughtDebounce) clearTimeout(state.thoughtDebounce)\n state.thoughtDebounce = setTimeout(() => {\n state.thoughtDebounce = null\n if (!state.thoughtBuf) return\n const text = state.thoughtBuf\n state.thoughtBuf = \"\"\n writeRecord(sessionId, state, { kind: \"thought\", sessionId, text, partial: true })\n }, DEBOUNCE_MS)\n }\n\n return {\n recordPrompt(sessionId, message, opts) {\n const state = getState(sessionId)\n flushBuffers(sessionId, state)\n const text = typeof message === \"string\" ? message : JSON.stringify(message)\n writeRecord(sessionId, state, {\n kind: \"user-prompt\",\n sessionId,\n text,\n ...(opts?.source ? { source: opts.source } : {}),\n })\n },\n recordEvent(sessionId, evt) {\n const state = getState(sessionId)\n switch (evt.kind) {\n case \"text-delta\": {\n if (!evt.text) break\n const combined = state.textBuf + evt.text\n const lines = combined.split(/\\r?\\n/)\n state.textBuf = lines.pop() ?? \"\"\n // `split` consumes each line's terminator — reappend it so the\n // on-disk record stays byte-for-byte reconstructable (a blank\n // line becomes \"\\n\" rather than a lossy \"\").\n for (const line of lines) {\n writeRecord(sessionId, state, { kind: \"text-delta\", sessionId, text: `${line}\\n` })\n }\n if (state.textBuf) scheduleTextDebounce(sessionId, state)\n break\n }\n case \"thought\": {\n if (!evt.text) break\n const combined = state.thoughtBuf + evt.text\n const lines = combined.split(/\\r?\\n/)\n state.thoughtBuf = lines.pop() ?? \"\"\n for (const line of lines) {\n writeRecord(sessionId, state, { kind: \"thought\", sessionId, text: `${line}\\n` })\n }\n if (state.thoughtBuf) scheduleThoughtDebounce(sessionId, state)\n break\n }\n case \"tool-call\": {\n // Remember the latest name/input for this call regardless of\n // whether this frame is an announcement or an enrichment — the\n // eventual \"tool-result\" needs both and carries neither itself.\n // An enrichment's `toolName` is `\"\"` when the update carried no\n // title (see toolCallEnrichment in @agentproto/acp); keep the\n // prior name in that case rather than overwriting it with blank.\n if (evt.toolCallId) {\n const existing = state.toolCallMeta.get(evt.toolCallId)\n state.toolCallMeta.set(evt.toolCallId, {\n toolName: evt.toolName || existing?.toolName || \"\",\n arguments: evt.arguments !== undefined ? evt.arguments : existing?.arguments,\n startedAt: existing?.startedAt ?? Date.now(),\n })\n }\n const record = {\n kind: \"tool-call\",\n sessionId,\n toolCallId: evt.toolCallId,\n toolName: evt.toolName,\n arguments: evt.arguments,\n // Carried through so a replay can tell an ENRICHMENT of an\n // announced call from a genuine second call. Readers merge by\n // toolCallId either way, but a record that silently drops the\n // distinction can't be reasoned about after the fact.\n ...(evt.isUpdate ? { isUpdate: true } : {}),\n }\n // An enrichment is a superseding SNAPSHOT of the call's input, and\n // the agent emits one per token as the model types it. Hold the\n // newest instead of writing all of them — flushBuffers puts it on\n // disk the moment anything else needs ordering around it (the\n // tool-result, the next call, a text delta, turn-end). Deliberately\n // no flushBuffers here: that's what lets consecutive updates for the\n // same call collapse into one record.\n if (evt.isUpdate && evt.toolCallId) {\n state.toolUpdates.set(evt.toolCallId, record)\n break\n }\n // The announcement is written at once — it's what makes the step\n // appear, and a pending row the user can see is the whole point.\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, record)\n break\n }\n case \"tool-result\": {\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"tool-result\",\n sessionId,\n toolCallId: evt.toolCallId,\n result: evt.result,\n isError: evt.isError ?? false,\n })\n // Normalized ToolCallRecord (see tool-call-record.ts) — the same\n // shape the command_execute proxy path writes via\n // `writeToolCallRecord`, so `tool_calls_list` reads one unified\n // log regardless of which path produced the call.\n const meta = evt.toolCallId ? state.toolCallMeta.get(evt.toolCallId) : undefined\n if (evt.toolCallId) state.toolCallMeta.delete(evt.toolCallId)\n const { command, args } = extractCommandArgs(meta?.arguments)\n writeRecord(sessionId, state, {\n kind: \"tool-call-record\",\n sessionId,\n tool: meta?.toolName || \"unknown\",\n ...(command !== undefined ? { command } : {}),\n ...(args !== undefined ? { args } : {}),\n isError: evt.isError ?? false,\n ...(meta ? { durationMs: Date.now() - meta.startedAt } : {}),\n })\n break\n }\n case \"agent-prompt\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"agent-prompt\",\n sessionId,\n toolCallId: evt.toolCallId,\n options: evt.options,\n })\n break\n // Durable counterpart to \"agent-prompt\" — recorded when\n // `respondPermission` (or a dying session's cancel-in-flight sweep)\n // resolves the ask, keyed by the same `toolCallId` so a reader can\n // tell an answered request from a still-pending one without relying\n // on the in-memory pending-permissions map (see sessions.ts's\n // `resolvePendingPermission` / `cancelPendingPermissionsForSession`).\n case \"permission-resolved\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"permission-resolved\",\n sessionId,\n toolCallId: evt.toolCallId,\n decision: evt.decision,\n ...(evt.optionId ? { optionId: evt.optionId } : {}),\n })\n break\n case \"turn-end\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, { kind: \"turn-end\", sessionId, reason: evt.reason })\n break\n case \"notice\":\n // A daemon-side system notice (not agent output) — e.g. the\n // interrupted-turn banner written on resume of a session that died\n // mid-turn under a daemon restart. Durable in events.jsonl so the\n // warning survives beyond the in-memory ring buffer; readers render\n // it as a system message (see transcript-export's \"notice\" case).\n if (!evt.text) break\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, { kind: \"notice\", sessionId, text: evt.text })\n break\n case \"error\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, { kind: \"error\", sessionId, error: evt.error })\n break\n case \"plan\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"plan\",\n sessionId,\n ...(evt.title ? { title: evt.title } : {}),\n entries: evt.entries ?? [],\n })\n break\n case \"usage_update\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"usage_update\",\n sessionId,\n size: evt.size,\n used: evt.used,\n ...(evt.cost ? { cost: evt.cost } : {}),\n // Persist cumulative token counts when the adapter reports them\n // (claude-code over ACP, hermes via its state.db reader,\n // mastracode via its native usage_update) so the transcript can\n // price/aggregate a session even without a `cost` block.\n ...(evt.tokensIn !== undefined ? { tokensIn: evt.tokensIn } : {}),\n ...(evt.tokensOut !== undefined ? { tokensOut: evt.tokensOut } : {}),\n })\n break\n default:\n // Unknown kind — drop, same as `projectEvent`'s implicit\n // no-op for anything it doesn't switch on.\n break\n }\n },\n recordUsageSnapshot(sessionId, usage) {\n const state = getState(sessionId)\n // Order after any buffered text/thought so on-disk order matches\n // wall-clock order.\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"usage_snapshot\",\n sessionId,\n // Omit absent fields so a missing value never reads as a measured 0.\n ...(usage.model !== undefined ? { model: usage.model } : {}),\n ...(usage.costUsd !== undefined ? { costUsd: usage.costUsd } : {}),\n ...(usage.tokensIn !== undefined ? { tokensIn: usage.tokensIn } : {}),\n ...(usage.tokensOut !== undefined ? { tokensOut: usage.tokensOut } : {}),\n ...(usage.contextSize !== undefined ? { contextSize: usage.contextSize } : {}),\n ...(usage.contextUsed !== undefined ? { contextUsed: usage.contextUsed } : {}),\n source: usage.source,\n })\n },\n close(sessionId) {\n const state = states.get(sessionId)\n if (!state) return Promise.resolve()\n flushBuffers(sessionId, state)\n states.delete(sessionId)\n return new Promise<void>(resolve => {\n state.stream.end(() => resolve())\n })\n },\n closeAll() {\n const closings: Promise<void>[] = []\n for (const sessionId of Array.from(states.keys())) {\n const state = states.get(sessionId)\n if (!state) continue\n flushBuffers(sessionId, state)\n closings.push(new Promise<void>(resolve => state.stream.end(() => resolve())))\n }\n states.clear()\n return Promise.all(closings).then(() => undefined)\n },\n subscribe(sessionId, onRecord) {\n let subs = listeners.get(sessionId)\n if (!subs) {\n subs = new Set()\n listeners.set(sessionId, subs)\n }\n subs.add(onRecord)\n return () => {\n const current = listeners.get(sessionId)\n if (!current) return\n current.delete(onRecord)\n if (current.size === 0) listeners.delete(sessionId)\n }\n },\n }\n}\n","/**\n * Export a clean, readable transcript, dispatched between two kinds of\n * source:\n *\n * native — the adapter's OWN persistence, re-read after the fact:\n * claude-code — ~/.claude/projects/<cwd-encoded>/<sessionId>.jsonl\n * hermes — ~/.hermes/state.db via node:sqlite (read-only)\n * codex — $CODEX_HOME/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl\n * opencode — ~/.local/share/opencode/opencode.db via node:sqlite\n * mastracode-inprocess — ~/.agentproto/mastracode-inprocess/storage.db (Mastra libsql)\n * pi — ~/.pi/agent/sessions/<cwd-slug>/<ts>_<uuid>.jsonl\n * daemon — agentproto's own capture, `~/.agentproto/sessions/<id>/events.jsonl`\n * (written by transcript-writer.ts at the same point `projectEvent`\n * flattens events into the ANSI ring buffer, ahead of that flattening).\n * Available for ANY agent-cli session (acp or print protocol), not just\n * the two adapters with a native store.\n *\n * `source: \"auto\"` (the default) tries native first and falls back to\n * daemon events when there's no native strategy or its store can't be\n * read; `\"native\"` / `\"daemon\"` force one and surface its own error.\n *\n * Output: Markdown (default) or JSON, built from a shared ExportedSession\n * model so every source produces identical rendering logic.\n */\n\nimport { createReadStream, promises as fs, type Dirent } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { join } from \"node:path\"\nimport { createInterface } from \"node:readline\"\nimport type { SessionDescriptor, SessionsRegistry } from \"./sessions.js\"\nimport { formatToolCall } from \"./tool-presenter.js\"\nimport { sessionEventsPath } from \"./transcript-writer.js\"\nimport { claudeProjectSlug } from \"./conversation-store.js\"\nimport type { ConversationCandidate } from \"./conversation-store.js\"\n\n// ── Common model ──────────────────────────────────────────────────────\n\nexport interface ExportedMessage {\n role: \"user\" | \"assistant\" | \"tool\" | \"system\"\n text?: string\n reasoning?: string\n toolName?: string\n toolCalls?: { name: string; args: string }[]\n ts?: number\n}\n\nexport interface ExportedSessionMeta {\n title?: string\n model?: string\n startedAt?: string\n endedAt?: string\n messageCount?: number\n toolCallCount?: number\n tokens?: {\n input?: number\n output?: number\n cacheRead?: number\n cacheWrite?: number\n reasoning?: number\n contextSize?: number\n contextUsed?: number\n }\n costUsd?: number\n source?: string\n /** Provenance carried over from the session descriptor's own\n * `origin`/`callerSessionId` (see sessions.ts) — distinct from `source`,\n * which names the EXPORTER that produced this payload (e.g.\n * \"daemon-events\", \"codex\"), not who invoked the underlying session. */\n origin?: string\n callerSessionId?: string\n}\n\nexport interface ExportedSession {\n meta: ExportedSessionMeta\n messages: ExportedMessage[]\n}\n\n// ── Render ────────────────────────────────────────────────────────────\n\nconst ROLE_ICON: Record<string, string> = {\n user: \"🧑 User\",\n assistant: \"🤖 Assistant\",\n tool: \"🔧 Tool\",\n system: \"⚙️ System\",\n}\n\nfunction trunc(text: string, n: number): string {\n if (text.length <= n) return text\n return text.slice(0, n) + `\\n… [${text.length - n} chars truncated]`\n}\n\nexport function renderMarkdown(\n session: ExportedSession,\n opts: { maxToolChars?: number } = {},\n): string {\n const { meta, messages } = session\n const maxToolChars = opts.maxToolChars ?? 1200\n const out: string[] = []\n\n out.push(`# ${meta.title ?? \"(untitled)\"}`)\n out.push(\"\")\n\n const sourceNote = meta.source ? ` · source \\`${meta.source}\\`` : \"\"\n const originNote = meta.origin ? ` · origin \\`${meta.origin}\\`` : \"\"\n const callerNote = meta.callerSessionId ? ` · caller \\`${meta.callerSessionId}\\`` : \"\"\n out.push(`> Session${sourceNote}${originNote}${callerNote}`)\n out.push(\"\")\n out.push(\"| | |\")\n out.push(\"|---|---|\")\n if (meta.model) out.push(`| Model | \\`${meta.model}\\` |`)\n if (meta.startedAt || meta.endedAt) {\n out.push(`| Start → end | ${meta.startedAt ?? \"?\"} → ${meta.endedAt ?? \"?\"} |`)\n }\n if (meta.messageCount !== undefined || meta.toolCallCount !== undefined) {\n const parts: string[] = []\n if (meta.messageCount !== undefined) parts.push(`${meta.messageCount} messages`)\n if (meta.toolCallCount !== undefined) parts.push(`${meta.toolCallCount} tool calls`)\n out.push(`| Count | ${parts.join(\" · \")} |`)\n }\n if (meta.tokens && Object.keys(meta.tokens).length) {\n const t = meta.tokens\n const parts: string[] = []\n if (t.input !== undefined) parts.push(`in ${t.input.toLocaleString(\"en-US\")}`)\n if (t.output !== undefined) parts.push(`out ${t.output.toLocaleString(\"en-US\")}`)\n if (t.cacheRead !== undefined || t.cacheWrite !== undefined) {\n parts.push(\n `cache r/w ${(t.cacheRead ?? 0).toLocaleString(\"en-US\")}/${(t.cacheWrite ?? 0).toLocaleString(\"en-US\")}`,\n )\n }\n if (t.reasoning !== undefined) parts.push(`reason. ${t.reasoning.toLocaleString(\"en-US\")}`)\n if (parts.length) out.push(`| Tokens | ${parts.join(\" · \")} |`)\n }\n if (meta.costUsd !== undefined) {\n out.push(`| Cost | $${meta.costUsd.toFixed(4)} |`)\n }\n out.push(\"\")\n out.push(\"---\")\n out.push(\"\")\n\n for (const m of messages) {\n const icon = ROLE_ICON[m.role] ?? m.role\n const nameSuffix = m.toolName ? ` · \\`${m.toolName}\\`` : \"\"\n out.push(`### ${icon}${nameSuffix}`)\n\n if (m.reasoning?.trim()) {\n out.push(\"\")\n out.push(\"<details><summary>💭 reasoning</summary>\")\n out.push(\"\")\n out.push(trunc(m.reasoning, 4000))\n out.push(\"\")\n out.push(\"</details>\")\n }\n\n if (m.text?.trim()) {\n out.push(\"\")\n if (m.role === \"tool\") {\n out.push(\"```\")\n out.push(trunc(m.text, maxToolChars))\n out.push(\"```\")\n } else {\n out.push(m.text.trim())\n }\n }\n\n if (m.toolCalls?.length) {\n out.push(\"\")\n for (const tc of m.toolCalls) {\n let parsedArgs: unknown\n try {\n parsedArgs = JSON.parse(tc.args)\n } catch {\n parsedArgs = tc.args\n }\n out.push(`> 📞 ${formatToolCall(tc.name, parsedArgs)}`)\n }\n }\n\n out.push(\"\")\n }\n\n return out.join(\"\\n\")\n}\n\nexport function renderJson(session: ExportedSession): string {\n return JSON.stringify(session, null, 2)\n}\n\n// ── Exporter interface ────────────────────────────────────────────────\n\ninterface ExportStrategy {\n exportSession(adapterSessionId: string, cwd?: string): Promise<ExportedSession>\n}\n\n// ── claude-code exporter (JSONL) ──────────────────────────────────────\n\ninterface ClaudeTextBlock {\n type: \"text\"\n text: string\n}\ninterface ClaudeThinkingBlock {\n type: \"thinking\"\n thinking: string\n}\ninterface ClaudeToolUseBlock {\n type: \"tool_use\"\n name: string\n input?: unknown\n}\ninterface ClaudeToolResultBlock {\n type: \"tool_result\"\n tool_use_id?: string\n content?: unknown\n}\ntype ClaudeContentBlock =\n | ClaudeTextBlock\n | ClaudeThinkingBlock\n | ClaudeToolUseBlock\n | ClaudeToolResultBlock\n | { type: string }\n\ninterface ClaudeCodeJsonlLine {\n type: string\n message?: {\n role?: string\n content?: string | ClaudeContentBlock[]\n }\n}\n\nconst IGNORED_CLAUDE_TYPES = new Set([\n \"queue-operation\",\n \"attachment\",\n \"file-history-snapshot\",\n \"ai-title\",\n \"last-prompt\",\n])\n\nexport async function exportClaudeCodeSession(\n adapterSessionId: string,\n cwd?: string,\n): Promise<ExportedSession> {\n if (!cwd) {\n throw new Error(\n \"claude-code exporter: cwd is required to locate the JSONL file.\\n\" +\n \"Pass cwd explicitly or use a session id that is in the registry.\",\n )\n }\n const encoded = claudeProjectSlug(cwd)\n const filePath = join(homedir(), \".claude\", \"projects\", encoded, `${adapterSessionId}.jsonl`)\n\n let stream: ReturnType<typeof createReadStream>\n try {\n stream = createReadStream(filePath, { encoding: \"utf8\" })\n // Trigger ENOENT eagerly before readline wraps it.\n await new Promise<void>((resolve, reject) => {\n stream.once(\"error\", reject)\n stream.once(\"open\", resolve)\n })\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === \"ENOENT\") {\n throw new Error(\n `claude-code: JSONL file not found: ${filePath}\\n` +\n `Verify cwd=\"${cwd}\" and adapterSessionId=\"${adapterSessionId}\".`,\n )\n }\n throw err\n }\n\n const messages: ExportedMessage[] = []\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let entry: ClaudeCodeJsonlLine\n try {\n entry = JSON.parse(trimmed) as ClaudeCodeJsonlLine\n } catch {\n continue\n }\n if (IGNORED_CLAUDE_TYPES.has(entry.type)) continue\n if (entry.type !== \"user\" && entry.type !== \"assistant\") continue\n const msg = entry.message\n if (!msg) continue\n\n const role: ExportedMessage[\"role\"] =\n msg.role === \"assistant\" ? \"assistant\" : \"user\"\n const content = msg.content\n\n if (typeof content === \"string\") {\n if (content.trim()) messages.push({ role, text: content.trim() })\n continue\n }\n if (!Array.isArray(content)) continue\n\n // Collect all block types from this message event\n let textAcc = \"\"\n let reasoningAcc = \"\"\n const toolCalls: { name: string; args: string }[] = []\n const toolResults: { text: string }[] = []\n\n for (const block of content) {\n switch (block.type) {\n case \"text\": {\n textAcc += (block as ClaudeTextBlock).text\n break\n }\n case \"thinking\": {\n reasoningAcc += (block as ClaudeThinkingBlock).thinking\n break\n }\n case \"tool_use\": {\n const tb = block as ClaudeToolUseBlock\n const args =\n typeof tb.input === \"string\"\n ? tb.input\n : JSON.stringify(tb.input ?? {})\n toolCalls.push({ name: tb.name, args })\n break\n }\n case \"tool_result\": {\n const tb = block as ClaudeToolResultBlock\n let resultText = \"\"\n if (typeof tb.content === \"string\") {\n resultText = tb.content\n } else if (Array.isArray(tb.content)) {\n for (const c of tb.content as ClaudeContentBlock[]) {\n if (c.type === \"text\") resultText += (c as ClaudeTextBlock).text\n }\n }\n toolResults.push({ text: resultText })\n break\n }\n }\n }\n\n // Emit the main message (user text or assistant with optional tool calls)\n if (textAcc.trim() || toolCalls.length || reasoningAcc) {\n const m: ExportedMessage = { role }\n if (textAcc.trim()) m.text = textAcc.trim()\n if (reasoningAcc) m.reasoning = reasoningAcc\n if (toolCalls.length) m.toolCalls = toolCalls\n messages.push(m)\n }\n\n // Emit each tool result as its own role=tool message\n for (const tr of toolResults) {\n messages.push({ role: \"tool\", text: tr.text })\n }\n }\n\n return { meta: { source: \"claude-code\" }, messages }\n}\n\n// ── hermes exporter (SQLite) ──────────────────────────────────────────\n// node:sqlite is experimental in Node 22.x but functional.\n// Isolated here so a future stable import replaces only this function.\n\n// esbuild (via tsup) strips the `node:` prefix from builtin imports. Most\n// builtins work without it, but `node:sqlite` has NO unprefixed name —\n// `import('sqlite')` fails at runtime. A computed specifier dodges the\n// static analysis so the prefix survives bundling.\nconst NODE_SQLITE = \"node:\" + \"sqlite\"\nasync function importNodeSqlite(): Promise<typeof import(\"node:sqlite\")> {\n return import(/* @vite-ignore */ NODE_SQLITE)\n}\n\ninterface HermesSessionRow {\n id: string\n title?: string\n model?: string\n started_at?: number\n ended_at?: number\n message_count?: number\n tool_call_count?: number\n api_call_count?: number\n input_tokens?: number\n output_tokens?: number\n cache_read_tokens?: number\n cache_write_tokens?: number\n reasoning_tokens?: number\n actual_cost_usd?: number\n estimated_cost_usd?: number\n source?: string\n end_reason?: string\n}\n\ninterface HermesMessageRow {\n id: number\n session_id: string\n role: string\n content?: string\n tool_calls?: string\n tool_name?: string\n reasoning?: string\n reasoning_content?: string\n timestamp?: number\n}\n\n// Shared by exportHermesSession AND discoverHermesSessions (below) — the\n// open + SQLITE_BUSY-retry handling lives in exactly one place so the two\n// callers can never drift.\ntype HermesDb = InstanceType<(typeof import(\"node:sqlite\"))[\"DatabaseSync\"]>\n\nasync function openHermesDb(dbPath: string): Promise<HermesDb> {\n let DatabaseSync: (typeof import(\"node:sqlite\"))[\"DatabaseSync\"]\n try {\n const sqlite = await importNodeSqlite()\n DatabaseSync = sqlite.DatabaseSync\n } catch {\n throw new Error(\"hermes: node:sqlite unavailable. Requires Node.js ≥22.5.0.\")\n }\n\n try {\n return new DatabaseSync(dbPath, { readOnly: true })\n } catch (err) {\n const msg = String(err)\n if (\n (err as NodeJS.ErrnoException).code === \"ENOENT\" ||\n msg.includes(\"unable to open database file\")\n ) {\n throw new Error(\n `hermes: state.db not found at ${dbPath}. ` +\n `Has hermes been run at least once?`,\n )\n }\n if (msg.includes(\"SQLITE_BUSY\") || msg.includes(\"database is locked\")) {\n throw new Error(\n `hermes: database is locked (SQLITE_BUSY). ` +\n `Hermes may be writing. Try again in a moment.`,\n )\n }\n throw err\n }\n}\n\nfunction withRetryOnBusy<T>(fn: () => T): T {\n try {\n return fn()\n } catch (err) {\n const msg = String(err)\n if (msg.includes(\"SQLITE_BUSY\") || msg.includes(\"database is locked\")) {\n // One brief retry — the lock is usually transient\n try {\n return fn()\n } catch {\n throw new Error(\n `hermes: database is locked. Hermes may be actively writing. Try again.`,\n )\n }\n }\n throw err\n }\n}\n\n/** Generic read-only sqlite open, sharing hermes's node:sqlite plumbing so\n * the opencode + mastracode-inprocess stores don't each reinvent the\n * experimental-module guard and the ENOENT/BUSY error mapping. `label` is\n * the provider name used in the error strings. Returns the same handle\n * type `withRetryOnBusy` operates on. */\nasync function openReadonlySqlite(dbPath: string, label: string): Promise<HermesDb> {\n let DatabaseSync: (typeof import(\"node:sqlite\"))[\"DatabaseSync\"]\n try {\n const sqlite = await importNodeSqlite()\n DatabaseSync = sqlite.DatabaseSync\n } catch {\n throw new Error(`${label}: node:sqlite unavailable. Requires Node.js ≥22.5.0.`)\n }\n try {\n return new DatabaseSync(dbPath, { readOnly: true })\n } catch (err) {\n const msg = String(err)\n if (\n (err as NodeJS.ErrnoException).code === \"ENOENT\" ||\n msg.includes(\"unable to open database file\")\n ) {\n throw new Error(`${label}: database not found at ${dbPath}. Has ${label} been run at least once?`)\n }\n if (msg.includes(\"SQLITE_BUSY\") || msg.includes(\"database is locked\")) {\n throw new Error(`${label}: database is locked (SQLITE_BUSY). It may be writing. Try again in a moment.`)\n }\n throw err\n }\n}\n\nexport async function exportHermesSession(adapterSessionId: string): Promise<ExportedSession> {\n const dbPath = join(homedir(), \".hermes\", \"state.db\")\n const db = await openHermesDb(dbPath)\n\n const session = withRetryOnBusy(\n () =>\n db\n .prepare(\"SELECT * FROM sessions WHERE id = ?\")\n .get(adapterSessionId) as unknown as HermesSessionRow | undefined,\n )\n\n if (!session) {\n db.close()\n throw new Error(\n `hermes: session \"${adapterSessionId}\" not found in ${dbPath}. ` +\n `ACP sessions are indexed by the agentproto UUID passed as resumeSessionId.`,\n )\n }\n\n const rows = withRetryOnBusy(\n () =>\n db\n .prepare(\n \"SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC\",\n )\n .all(adapterSessionId) as unknown as HermesMessageRow[],\n )\n\n db.close()\n\n const cost =\n session.actual_cost_usd != null\n ? session.actual_cost_usd\n : session.estimated_cost_usd\n\n const startedAt = session.started_at\n ? new Date(session.started_at * 1000).toISOString().replace(\"T\", \" \").slice(0, 19)\n : undefined\n const endedAt = session.ended_at\n ? new Date(session.ended_at * 1000).toISOString().replace(\"T\", \" \").slice(0, 19)\n : undefined\n\n const meta: ExportedSessionMeta = {\n ...(session.title ? { title: session.title } : {}),\n ...(session.model ? { model: session.model } : {}),\n ...(startedAt ? { startedAt } : {}),\n ...(endedAt ? { endedAt } : {}),\n ...(session.message_count !== undefined ? { messageCount: session.message_count } : {}),\n ...(session.tool_call_count !== undefined\n ? { toolCallCount: session.tool_call_count }\n : {}),\n ...(cost != null ? { costUsd: Number(cost) } : {}),\n ...(session.source ? { source: session.source } : {}),\n }\n\n // Only include tokens sub-object when at least one field is present\n const tokensInput = session.input_tokens\n const tokensOutput = session.output_tokens\n const tokensCacheRead = session.cache_read_tokens\n const tokensCacheWrite = session.cache_write_tokens\n const tokensReasoning = session.reasoning_tokens\n if (\n tokensInput !== undefined ||\n tokensOutput !== undefined ||\n tokensCacheRead !== undefined ||\n tokensCacheWrite !== undefined ||\n tokensReasoning !== undefined\n ) {\n meta.tokens = {\n ...(tokensInput !== undefined ? { input: tokensInput } : {}),\n ...(tokensOutput !== undefined ? { output: tokensOutput } : {}),\n ...(tokensCacheRead !== undefined ? { cacheRead: tokensCacheRead } : {}),\n ...(tokensCacheWrite !== undefined ? { cacheWrite: tokensCacheWrite } : {}),\n ...(tokensReasoning !== undefined ? { reasoning: tokensReasoning } : {}),\n }\n }\n\n const messages: ExportedMessage[] = rows.map(row => {\n const validRoles = new Set([\"user\", \"assistant\", \"tool\", \"system\"])\n const role = (\n validRoles.has(row.role) ? row.role : \"user\"\n ) as ExportedMessage[\"role\"]\n\n const reasoning = row.reasoning ?? row.reasoning_content\n\n let toolCalls: { name: string; args: string }[] | undefined\n if (row.tool_calls) {\n try {\n const tc = JSON.parse(row.tool_calls) as unknown[]\n if (Array.isArray(tc) && tc.length) {\n toolCalls = tc.map(c => {\n const entry = c as Record<string, unknown>\n const fn =\n entry.function != null\n ? (entry.function as Record<string, unknown>)\n : entry\n const name = String(fn.name ?? entry.name ?? \"tool\")\n const args =\n typeof fn.arguments === \"string\"\n ? fn.arguments\n : JSON.stringify(fn.arguments ?? {})\n return { name, args }\n })\n }\n } catch {\n // malformed tool_calls — skip\n }\n }\n\n const m: ExportedMessage = { role }\n if (row.content?.trim()) m.text = row.content.trim()\n if (reasoning && String(reasoning).trim()) m.reasoning = String(reasoning)\n if (row.tool_name) m.toolName = row.tool_name\n if (toolCalls) m.toolCalls = toolCalls\n if (row.timestamp) m.ts = row.timestamp\n return m\n })\n\n // Fire-and-forget: cross-check our row count against the binary's export.\n // Non-blocking — a mismatch only logs a warning, it never fails the call.\n void crossValidateHermesExport(adapterSessionId, messages.length).catch(() => {})\n\n return { meta, messages }\n}\n\n// ── hermes discovery (SQLite, cwd-scoped) ─────────────────────────────\n//\n// Reuses openHermesDb/withRetryOnBusy above — the SAME open + BUSY-retry\n// path exportHermesSession uses — so there is one sqlite plumbing to\n// maintain, not two. Called from conversation-store.ts's hermes `discover`\n// via a dynamic import (see that file for why it's dynamic, not static).\n\nfunction hermesRowToCandidate(row: HermesSessionRow): ConversationCandidate {\n const startedAtIso =\n row.started_at !== undefined ? new Date(row.started_at * 1000).toISOString() : undefined\n // \"Last activity\" is when the conversation was last written to — ended_at\n // if it has one, else fall back to started_at (a still-open session).\n const lastActivitySec = row.ended_at ?? row.started_at\n const lastActivityIso =\n lastActivitySec !== undefined ? new Date(lastActivitySec * 1000).toISOString() : undefined\n return {\n conversationId: row.id,\n ...(startedAtIso ? { startedAt: startedAtIso } : {}),\n ...(lastActivityIso ? { lastActivityAt: lastActivityIso } : {}),\n ...(row.message_count !== undefined ? { messageCount: row.message_count } : {}),\n ...(row.title ? { preview: row.title } : {}),\n ...(row.source ? { lastWriter: row.source } : {}),\n }\n}\n\nexport async function discoverHermesSessions(\n cwd: string,\n since?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const dbPath = join(homedir(), \".hermes\", \"state.db\")\n\n let db: HermesDb\n try {\n db = await openHermesDb(dbPath)\n } catch (err) {\n // \"state.db not found\" == hermes has never run on this box — a normal,\n // empty store, not a discovery error. Anything else (locked, node:sqlite\n // missing) is a genuinely unreadable store and propagates — see the\n // ConversationStore.discover contract in conversation-store.ts.\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes(\"state.db not found\")) return []\n throw err\n }\n\n try {\n // Ground truth beats heuristic: bind to exactly the conversation we\n // were asked about. Binding is by `id`, which is cwd-independent, so\n // this never even looks at `cwd` — never falls through to the cwd-scan\n // below. See the exact-bind invariant in conversation-store.ts.\n if (expectedId) {\n const row = withRetryOnBusy(\n () =>\n db.prepare(\"SELECT * FROM sessions WHERE id = ?\").get(expectedId) as unknown as\n | HermesSessionRow\n | undefined,\n )\n return row ? [hermesRowToCandidate(row)] : []\n }\n\n const rows = withRetryOnBusy(\n () =>\n db\n .prepare(\"SELECT * FROM sessions WHERE cwd = ?\")\n .all(cwd) as unknown as HermesSessionRow[],\n )\n const sinceMs = since ? Date.parse(since) : NaN\n return rows\n .filter(row => {\n if (!Number.isFinite(sinceMs)) return true\n const lastActivitySec = row.ended_at ?? row.started_at\n if (lastActivitySec === undefined) return true\n return lastActivitySec * 1000 >= sinceMs - 1000\n })\n .map(hermesRowToCandidate)\n } finally {\n db.close()\n }\n}\n\n// ── Hermes cross-validation via native CLI ────────────────────────────\n//\n// `hermes sessions export --session-id <id> -` emits a stable JSONL\n// transcript on stdout. We use it as a non-blocking sanity-check:\n// if the message count from state.db differs from the binary's output,\n// something in the SQLite schema likely changed and the reader needs\n// updating. The check is fire-and-forget — a mismatch logs a warning but\n// does NOT affect the returned ExportedSession (SQLite stays primary).\n//\n// The export JSONL has one JSON object per message line; lines with a\n// `role` key are treated as messages (other metadata lines are ignored).\n\nexport interface HermesCrossValidationResult {\n sqliteCount: number\n binaryCount: number\n matched: boolean\n /** True when the hermes binary was not found on PATH */\n binaryUnavailable?: boolean\n}\n\n/** Default subprocess runner: spawns `hermes sessions export --session-id <id> -`\n * and returns stdout. Throws with `.code=\"ENOENT\"` when the binary isn't on PATH. */\nasync function defaultHermesRunner(adapterSessionId: string): Promise<string> {\n const { spawn } = await import(\"node:child_process\")\n return new Promise<string>((resolve, reject) => {\n const chunks: Buffer[] = []\n const errChunks: Buffer[] = []\n const proc = spawn(\n \"hermes\",\n [\"sessions\", \"export\", \"--session-id\", adapterSessionId, \"-\"],\n { stdio: [\"ignore\", \"pipe\", \"pipe\"] },\n )\n proc.stdout.on(\"data\", (chunk: Buffer) => chunks.push(chunk))\n proc.stderr.on(\"data\", (chunk: Buffer) => errChunks.push(chunk))\n proc.on(\"error\", reject)\n proc.on(\"close\", code => {\n if (code !== 0) {\n reject(\n new Error(\n `hermes exited with code ${code}: ${Buffer.concat(errChunks).toString()}`,\n ),\n )\n } else {\n resolve(Buffer.concat(chunks).toString(\"utf8\"))\n }\n })\n })\n}\n\n/** Run `hermes sessions export` and compare its message count with\n * what our SQLite reader produced. Returns null on any subprocess\n * error (binary missing, timeout, parse failure).\n *\n * The optional `_runner` parameter lets tests inject a mock that returns stdout\n * directly, avoiding subprocess mocking complexity (promisify + child_process). */\nexport async function crossValidateHermesExport(\n adapterSessionId: string,\n sqliteCount: number,\n _runner: (id: string) => Promise<string> = defaultHermesRunner,\n): Promise<HermesCrossValidationResult | null> {\n let stdout: string\n try {\n stdout = await _runner(adapterSessionId)\n } catch (err) {\n const msg = String(err)\n // ENOENT = binary not on PATH — expected when hermes isn't installed\n if (\n (err as NodeJS.ErrnoException).code === \"ENOENT\" ||\n msg.includes(\"ENOENT\") ||\n msg.includes(\"not found\")\n ) {\n return { sqliteCount, binaryCount: -1, matched: true, binaryUnavailable: true }\n }\n // Any other error (timeout, non-zero exit, etc.) — skip validation\n return null\n }\n\n // Count lines that look like message objects (have a `role` field)\n const binaryCount = stdout\n .split(\"\\n\")\n .filter(l => l.trim())\n .filter(l => {\n try {\n const obj = JSON.parse(l) as Record<string, unknown>\n return typeof obj.role === \"string\"\n } catch {\n return false\n }\n }).length\n\n const matched = binaryCount === sqliteCount\n if (!matched) {\n console.warn(\n `[hermes export] cross-validation mismatch for session ${adapterSessionId}: ` +\n `SQLite=${sqliteCount} messages, binary=${binaryCount} messages. ` +\n `The state.db schema may have changed — check the SQLite reader in transcript-export.ts.`,\n )\n }\n return { sqliteCount, binaryCount, matched }\n}\n\n// ── daemon-events exporter (agentproto's own JSONL capture) ────────────\n\n/** Structural shape of one events.jsonl line — a superset of every\n * `AgentStreamEvent` kind (see sessions.ts) plus the writer's own\n * \"user-prompt\" record. Untyped fields default to undefined rather than\n * erroring, so a future field this reader doesn't know about is just\n * ignored instead of breaking the export. */\ninterface TranscriptRecord {\n seq: number\n ts: string\n kind: string\n text?: string\n partial?: boolean\n toolCallId?: string\n toolName?: string\n arguments?: unknown\n result?: unknown\n isError?: boolean\n reason?: string\n error?: { message: string; code?: number }\n entries?: Array<{ content: string; priority: string; status: string }>\n size?: number\n used?: number\n cost?: { amount: number; currency: string }\n}\n\nexport async function exportDaemonEventsSession(\n sessionId: string,\n desc?: SessionDescriptor,\n): Promise<ExportedSession> {\n const filePath = sessionEventsPath(sessionId)\n\n let stream: ReturnType<typeof createReadStream>\n try {\n stream = createReadStream(filePath, { encoding: \"utf8\" })\n await new Promise<void>((resolve, reject) => {\n stream.once(\"error\", reject)\n stream.once(\"open\", resolve)\n })\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === \"ENOENT\") {\n throw new Error(\n `daemon-events: no events.jsonl for session \"${sessionId}\" (${filePath}).\\n` +\n `Either the session never drove an agent-cli turn, or it predates this feature.`,\n )\n }\n throw err\n }\n\n const messages: ExportedMessage[] = []\n const toolNameById = new Map<string, string>()\n let toolCallCount = 0\n let lastUsage: { size?: number; used?: number; cost?: { amount: number; currency: string } } | undefined\n\n // One assistant \"turn batch\" accumulator — text/thought/tool-calls that\n // arrive between two boundary events (a tool-result, a new prompt, a\n // turn-end, ...) collapse into ONE assistant message, mirroring how the\n // claude-code exporter batches a single API-level assistant entry.\n let asmText = \"\"\n let asmReasoning = \"\"\n let asmToolCalls: { name: string; args: string }[] = []\n let asmTs: number | undefined\n\n const flushAssistant = (): void => {\n if (!asmText.trim() && !asmReasoning.trim() && asmToolCalls.length === 0) return\n const m: ExportedMessage = { role: \"assistant\" }\n if (asmText.trim()) m.text = asmText.trim()\n if (asmReasoning.trim()) m.reasoning = asmReasoning.trim()\n if (asmToolCalls.length) m.toolCalls = asmToolCalls\n if (asmTs !== undefined) m.ts = asmTs\n messages.push(m)\n asmText = \"\"\n asmReasoning = \"\"\n asmToolCalls = []\n asmTs = undefined\n }\n\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let rec: TranscriptRecord\n try {\n rec = JSON.parse(trimmed) as TranscriptRecord\n } catch {\n continue\n }\n const ts = Date.parse(rec.ts)\n const tsOrUndefined = Number.isNaN(ts) ? undefined : ts\n\n switch (rec.kind) {\n case \"user-prompt\":\n flushAssistant()\n messages.push({ role: \"user\", text: rec.text ?? \"\", ...(tsOrUndefined !== undefined ? { ts: tsOrUndefined } : {}) })\n break\n case \"text-delta\":\n // Terminated lines already carry their own trailing \"\\n\" (see\n // transcript-writer.ts) — only an unterminated tail fragment\n // (still `partial`, or flushed bare at a turn boundary) lacks one,\n // and that's exactly the byte-for-byte original content.\n if (asmTs === undefined) asmTs = tsOrUndefined\n asmText += rec.text ?? \"\"\n break\n case \"thought\":\n if (asmTs === undefined) asmTs = tsOrUndefined\n asmReasoning += rec.text ?? \"\"\n break\n case \"tool-call\": {\n if (asmTs === undefined) asmTs = tsOrUndefined\n const name = rec.toolName ?? \"tool\"\n if (rec.toolCallId) toolNameById.set(rec.toolCallId, name)\n const args =\n typeof rec.arguments === \"string\" ? rec.arguments : JSON.stringify(rec.arguments ?? {})\n asmToolCalls.push({ name, args })\n toolCallCount += 1\n break\n }\n case \"tool-result\": {\n flushAssistant()\n const name = rec.toolCallId ? toolNameById.get(rec.toolCallId) : undefined\n const text = typeof rec.result === \"string\" ? rec.result : JSON.stringify(rec.result ?? \"\")\n messages.push({\n role: \"tool\",\n text: rec.isError ? `[error] ${text}` : text,\n ...(name ? { toolName: name } : {}),\n ...(tsOrUndefined !== undefined ? { ts: tsOrUndefined } : {}),\n })\n break\n }\n case \"agent-prompt\":\n flushAssistant()\n messages.push({ role: \"system\", text: \"[awaiting input] agent requested a decision\" })\n break\n case \"plan\": {\n flushAssistant()\n const entries = rec.entries ?? []\n const done = entries.filter(e => e.status === \"completed\").length\n const list = entries.map(e => e.content).join(\"; \")\n messages.push({ role: \"system\", text: `[plan] ${done}/${entries.length} ${list}`.trim() })\n break\n }\n case \"usage_update\":\n lastUsage = { size: rec.size, used: rec.used, cost: rec.cost }\n break\n case \"error\":\n flushAssistant()\n messages.push({ role: \"system\", text: `[error] ${rec.error?.message ?? \"unknown\"}` })\n break\n case \"turn-end\":\n flushAssistant()\n break\n case \"notice\":\n // Daemon-side system notice (e.g. the interrupted-turn resume banner)\n // — surfaced as a system message, same as plan/error notices above.\n flushAssistant()\n messages.push({ role: \"system\", text: rec.text ?? \"\" })\n break\n default:\n break\n }\n }\n flushAssistant()\n\n const meta: ExportedSessionMeta = { source: \"daemon-events\" }\n if (desc?.label) meta.title = desc.label\n if (desc?.model) meta.model = desc.model\n if (desc?.startedAt) meta.startedAt = desc.startedAt\n if (desc?.endedAt) meta.endedAt = desc.endedAt\n if (desc?.origin) meta.origin = desc.origin\n if (desc?.callerSessionId) meta.callerSessionId = desc.callerSessionId\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n if (desc?.costUsd !== undefined) meta.costUsd = desc.costUsd\n else if (lastUsage?.cost) meta.costUsd = lastUsage.cost.amount\n if (desc?.tokensIn !== undefined || desc?.tokensOut !== undefined) {\n meta.tokens = {\n ...(desc?.tokensIn !== undefined ? { input: desc.tokensIn } : {}),\n ...(desc?.tokensOut !== undefined ? { output: desc.tokensOut } : {}),\n }\n }\n\n return { meta, messages }\n}\n\n// ── shared jsonl helper ───────────────────────────────────────────────\n\n/** Read only the first non-empty line of a jsonl file — used by the codex\n * and pi discovery scans, which only need each file's leading metadata\n * record (session_meta / session) to answer cwd/id questions without\n * parsing a possibly-multi-MB transcript. */\nasync function readFirstJsonLine(path: string): Promise<string | undefined> {\n const stream = createReadStream(path, { encoding: \"utf8\" })\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n try {\n for await (const line of rl) {\n const t = line.trim()\n if (t) return t\n }\n return undefined\n } finally {\n rl.close()\n stream.destroy()\n }\n}\n\n// ── codex exporter (rollout JSONL) ────────────────────────────────────\n//\n// Native store: $CODEX_HOME/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl\n// (CODEX_HOME defaults to ~/.codex). One append-only JSONL file per\n// conversation, written by the Codex core that @agentclientprotocol/codex-acp\n// bundles. The first line is a `session_meta` record carrying the\n// conversation's `id` (== the trailing uuid in the filename == the ACP\n// session id agentproto records as `adapterSessionId` — verified\n// empirically against live rollouts) and its `cwd`. Subsequent\n// `response_item` lines carry the turns; `event_msg` / `turn_context`\n// lines are transport bookkeeping we skip.\n\nfunction codexHome(): string {\n return process.env.CODEX_HOME ?? join(homedir(), \".codex\")\n}\nfunction codexSessionsDir(): string {\n return join(codexHome(), \"sessions\")\n}\n\ninterface CodexRolloutLine {\n type?: string\n timestamp?: string\n payload?: {\n type?: string\n id?: string\n session_id?: string\n timestamp?: string\n cwd?: string\n model?: string\n model_provider?: string\n role?: string\n content?: Array<{ type?: string; text?: string }>\n summary?: Array<{ type?: string; text?: string }>\n name?: string\n input?: unknown\n arguments?: unknown\n call_id?: string\n output?: unknown\n }\n}\n\n/** Recursively collect `rollout-*.jsonl` paths under the YYYY/MM/DD tree. */\nasync function walkCodexRollouts(dir: string): Promise<string[]> {\n let entries: Dirent[]\n try {\n entries = await fs.readdir(dir, { withFileTypes: true })\n } catch {\n return []\n }\n const out: string[] = []\n for (const e of entries) {\n const p = join(dir, e.name)\n if (e.isDirectory()) {\n out.push(...(await walkCodexRollouts(p)))\n } else if (e.isFile() && e.name.startsWith(\"rollout-\") && e.name.endsWith(\".jsonl\")) {\n out.push(p)\n }\n }\n return out\n}\n\n/** Join codex output blocks (input_text / output_text) into one string. */\nfunction codexBlocksText(content: unknown): string {\n if (typeof content === \"string\") return content\n if (!Array.isArray(content)) return \"\"\n let acc = \"\"\n for (const c of content) {\n if (c && typeof c === \"object\") {\n const b = c as { type?: string; text?: string }\n if (typeof b.text === \"string\" && (b.type === \"input_text\" || b.type === \"output_text\" || b.type === \"text\")) {\n acc += b.text\n }\n }\n }\n return acc\n}\n\nasync function findCodexRolloutFile(conversationId: string): Promise<string | undefined> {\n const files = await walkCodexRollouts(codexSessionsDir())\n // Fast path: the uuid is the filename suffix.\n const byName = files.find(f => f.endsWith(`-${conversationId}.jsonl`))\n if (byName) return byName\n // Fallback: match on the session_meta id/session_id (covers a future\n // codex build whose filename uuid diverges from the meta id).\n for (const f of files) {\n const first = await readFirstJsonLine(f)\n if (!first) continue\n let meta: CodexRolloutLine\n try {\n meta = JSON.parse(first) as CodexRolloutLine\n } catch {\n continue\n }\n const p = meta.payload\n if (p && (p.id === conversationId || p.session_id === conversationId)) return f\n }\n return undefined\n}\n\nexport async function exportCodexSession(conversationId: string): Promise<ExportedSession> {\n const file = await findCodexRolloutFile(conversationId)\n if (!file) {\n throw new Error(\n `codex: no rollout file for conversation \"${conversationId}\" under ${codexSessionsDir()}.\\n` +\n `The session may predate persistence, or CODEX_HOME points elsewhere.`,\n )\n }\n\n const stream = createReadStream(file, { encoding: \"utf8\" })\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n const messages: ExportedMessage[] = []\n const toolNameByCall = new Map<string, string>()\n let toolCallCount = 0\n let startedAt: string | undefined\n let model: string | undefined\n\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let entry: CodexRolloutLine\n try {\n entry = JSON.parse(trimmed) as CodexRolloutLine\n } catch {\n continue\n }\n const p = entry.payload ?? {}\n\n if (entry.type === \"session_meta\") {\n startedAt = p.timestamp ?? entry.timestamp\n if (typeof p.model === \"string\") model = p.model\n continue\n }\n if (entry.type === \"turn_context\") {\n if (!model && typeof p.model === \"string\") model = p.model\n continue\n }\n if (entry.type !== \"response_item\") continue\n\n switch (p.type) {\n case \"message\": {\n const text = codexBlocksText(p.content).trim()\n if (!text) break\n const role: ExportedMessage[\"role\"] =\n p.role === \"assistant\" ? \"assistant\" : p.role === \"user\" ? \"user\" : \"system\"\n messages.push({ role, text })\n break\n }\n case \"reasoning\": {\n // Codex reasoning is usually an opaque `encrypted_content` blob; only\n // an unencrypted `summary` (rare) is human-readable. Emit only when\n // there's real text — never the ciphertext.\n const r = (p.summary ?? []).map(s => s.text ?? \"\").join(\"\\n\").trim()\n if (r) messages.push({ role: \"assistant\", reasoning: r })\n break\n }\n case \"function_call\":\n case \"custom_tool_call\": {\n const name = p.name ?? \"tool\"\n if (typeof p.call_id === \"string\") toolNameByCall.set(p.call_id, name)\n const raw = p.type === \"custom_tool_call\" ? p.input : p.arguments\n const args = typeof raw === \"string\" ? raw : JSON.stringify(raw ?? {})\n messages.push({ role: \"assistant\", toolCalls: [{ name, args }] })\n toolCallCount += 1\n break\n }\n case \"function_call_output\":\n case \"custom_tool_call_output\": {\n const name = typeof p.call_id === \"string\" ? toolNameByCall.get(p.call_id) : undefined\n const out = codexBlocksText(p.output) || (typeof p.output === \"string\" ? p.output : \"\")\n messages.push({ role: \"tool\", text: out, ...(name ? { toolName: name } : {}) })\n break\n }\n }\n }\n\n const meta: ExportedSessionMeta = { source: \"codex\" }\n if (startedAt) meta.startedAt = startedAt\n if (model) meta.model = model\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n return { meta, messages }\n}\n\nexport async function discoverCodexSessions(\n cwd: string,\n since?: string,\n until?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const files = await walkCodexRollouts(codexSessionsDir())\n const sinceMs = since ? Date.parse(since) : NaN\n const untilMs = until ? Date.parse(until) : NaN\n const scored: { candidate: ConversationCandidate; mtimeMs: number }[] = []\n\n for (const f of files) {\n let mtimeMs: number\n try {\n mtimeMs = (await fs.stat(f)).mtimeMs\n } catch {\n continue\n }\n if (Number.isFinite(sinceMs) && mtimeMs < sinceMs - 1000) continue\n const first = await readFirstJsonLine(f)\n if (!first) continue\n let meta: CodexRolloutLine\n try {\n meta = JSON.parse(first) as CodexRolloutLine\n } catch {\n continue\n }\n if (meta.type !== \"session_meta\") continue\n const p = meta.payload ?? {}\n const id = p.id ?? p.session_id\n if (!id) continue\n // Ground truth beats heuristic: bind to exactly the requested id and\n // ignore cwd (the id is globally unique). See the exact-bind invariant.\n if (expectedId) {\n if (id !== expectedId) continue\n } else if (p.cwd !== cwd) {\n continue\n }\n const startedAt = p.timestamp\n if (Number.isFinite(untilMs) && startedAt) {\n const startedMs = Date.parse(startedAt)\n if (Number.isFinite(startedMs) && startedMs > untilMs) continue\n }\n scored.push({\n candidate: {\n conversationId: id,\n ...(startedAt ? { startedAt } : {}),\n lastActivityAt: new Date(mtimeMs).toISOString(),\n },\n mtimeMs,\n })\n }\n\n scored.sort((a, b) => b.mtimeMs - a.mtimeMs)\n return scored.map(s => s.candidate)\n}\n\n// ── opencode exporter (opencode.db SQLite) ────────────────────────────\n//\n// Native store: ${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db — a\n// drizzle-managed sqlite with `session` (keyed by the `ses_…` id opencode\n// returns over ACP, which agentproto records verbatim as adapterSessionId\n// — verified empirically), `message` (JSON `data` per row), and `part`\n// (JSON `data`, one row per text/reasoning/tool block). The `session`\n// table's `directory` column is the conversation's cwd, enabling\n// cwd-scoped discovery.\n\ninterface OpenCodeSessionRow {\n id: string\n directory?: string\n title?: string\n model?: string\n cost?: number\n tokens_input?: number\n tokens_output?: number\n tokens_reasoning?: number\n tokens_cache_read?: number\n tokens_cache_write?: number\n time_created?: number\n time_updated?: number\n}\ninterface OpenCodeMessageRow {\n id: string\n data: string\n time_created: number\n}\ninterface OpenCodePartRow {\n message_id: string\n data: string\n time_created: number\n}\n\nfunction openCodeDbPath(): string {\n const dataHome = process.env.XDG_DATA_HOME ?? join(homedir(), \".local\", \"share\")\n return join(dataHome, \"opencode\", \"opencode.db\")\n}\n\n/** `{\"id\":\"gpt-5-mini\",\"providerID\":\"openai\",…}` → `openai/gpt-5-mini`. */\nfunction openCodeModelLabel(raw: string | undefined): string | undefined {\n if (!raw) return undefined\n try {\n const m = JSON.parse(raw) as { id?: string; modelID?: string; providerID?: string }\n const id = m.modelID ?? m.id\n if (!id) return undefined\n return m.providerID ? `${m.providerID}/${id}` : id\n } catch {\n return undefined\n }\n}\n\nexport async function exportOpenCodeSession(conversationId: string): Promise<ExportedSession> {\n const dbPath = openCodeDbPath()\n const db = await openReadonlySqlite(dbPath, \"opencode\")\n try {\n const session = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM session WHERE id = ?\").get(conversationId) as unknown as\n | OpenCodeSessionRow\n | undefined,\n )\n if (!session) {\n throw new Error(\n `opencode: session \"${conversationId}\" not found in ${dbPath}. ` +\n `Sessions are keyed by the ACP session id (ses_…) recorded as adapterSessionId.`,\n )\n }\n const msgRows = withRetryOnBusy(\n () =>\n db\n .prepare(\"SELECT id, data, time_created FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC\")\n .all(conversationId) as unknown as OpenCodeMessageRow[],\n )\n const partRows = withRetryOnBusy(\n () =>\n db\n .prepare(\"SELECT message_id, data, time_created FROM part WHERE session_id = ? ORDER BY time_created ASC, id ASC\")\n .all(conversationId) as unknown as OpenCodePartRow[],\n )\n\n const partsByMsg = new Map<string, OpenCodePartRow[]>()\n for (const r of partRows) {\n const list = partsByMsg.get(r.message_id) ?? []\n list.push(r)\n partsByMsg.set(r.message_id, list)\n }\n\n const messages: ExportedMessage[] = []\n let toolCallCount = 0\n for (const m of msgRows) {\n let mdata: { role?: string }\n try {\n mdata = JSON.parse(m.data) as { role?: string }\n } catch {\n continue\n }\n const role: ExportedMessage[\"role\"] = mdata.role === \"assistant\" ? \"assistant\" : \"user\"\n let text = \"\"\n let reasoning = \"\"\n const toolCalls: { name: string; args: string }[] = []\n const toolResults: { name?: string; text: string }[] = []\n for (const pr of partsByMsg.get(m.id) ?? []) {\n let part: {\n type?: string\n text?: string\n tool?: string\n state?: { input?: unknown; output?: unknown }\n }\n try {\n part = JSON.parse(pr.data) as typeof part\n } catch {\n continue\n }\n switch (part.type) {\n case \"text\":\n if (part.text) text += part.text\n break\n case \"reasoning\":\n if (part.text) reasoning += part.text\n break\n case \"tool\": {\n const name = part.tool ?? \"tool\"\n toolCalls.push({ name, args: JSON.stringify(part.state?.input ?? {}) })\n toolCallCount += 1\n const output = part.state?.output\n if (output !== undefined && output !== null && output !== \"\") {\n toolResults.push({ name, text: typeof output === \"string\" ? output : JSON.stringify(output) })\n }\n break\n }\n // step-start / step-finish / patch / snapshot / file — skip.\n }\n }\n if (text.trim() || reasoning.trim() || toolCalls.length) {\n const em: ExportedMessage = { role }\n if (text.trim()) em.text = text.trim()\n if (reasoning.trim()) em.reasoning = reasoning.trim()\n if (toolCalls.length) em.toolCalls = toolCalls\n em.ts = m.time_created\n messages.push(em)\n }\n for (const tr of toolResults) {\n messages.push({ role: \"tool\", text: tr.text, ...(tr.name ? { toolName: tr.name } : {}) })\n }\n }\n\n const meta: ExportedSessionMeta = { source: \"opencode\" }\n if (session.title) meta.title = session.title\n const model = openCodeModelLabel(session.model)\n if (model) meta.model = model\n if (session.time_created) meta.startedAt = new Date(session.time_created).toISOString()\n if (session.time_updated) meta.endedAt = new Date(session.time_updated).toISOString()\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n if (session.cost != null) meta.costUsd = Number(session.cost)\n const tk = {\n ...(session.tokens_input != null ? { input: session.tokens_input } : {}),\n ...(session.tokens_output != null ? { output: session.tokens_output } : {}),\n ...(session.tokens_cache_read != null ? { cacheRead: session.tokens_cache_read } : {}),\n ...(session.tokens_cache_write != null ? { cacheWrite: session.tokens_cache_write } : {}),\n ...(session.tokens_reasoning != null ? { reasoning: session.tokens_reasoning } : {}),\n }\n if (Object.keys(tk).length) meta.tokens = tk\n return { meta, messages }\n } finally {\n db.close()\n }\n}\n\nexport async function discoverOpenCodeSessions(\n cwd: string,\n since?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const dbPath = openCodeDbPath()\n let db: HermesDb\n try {\n db = await openReadonlySqlite(dbPath, \"opencode\")\n } catch (err) {\n // A missing db == opencode never ran here — a normal empty store, not a\n // discovery error (mirrors discoverHermesSessions).\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes(\"database not found\")) return []\n throw err\n }\n try {\n if (expectedId) {\n const row = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM session WHERE id = ?\").get(expectedId) as unknown as\n | OpenCodeSessionRow\n | undefined,\n )\n return row ? [openCodeRowToCandidate(row)] : []\n }\n const rows = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM session WHERE directory = ?\").all(cwd) as unknown as OpenCodeSessionRow[],\n )\n const sinceMs = since ? Date.parse(since) : NaN\n return rows\n .filter(r => {\n if (!Number.isFinite(sinceMs)) return true\n const last = r.time_updated ?? r.time_created\n return last === undefined || last >= sinceMs - 1000\n })\n .map(openCodeRowToCandidate)\n } finally {\n db.close()\n }\n}\n\nfunction openCodeRowToCandidate(row: OpenCodeSessionRow): ConversationCandidate {\n return {\n conversationId: row.id,\n ...(row.time_created ? { startedAt: new Date(row.time_created).toISOString() } : {}),\n ...(row.time_updated ? { lastActivityAt: new Date(row.time_updated).toISOString() } : {}),\n ...(row.title ? { preview: row.title } : {}),\n }\n}\n\n// ── mastracode-inprocess exporter (Mastra libsql) ─────────────────────\n//\n// Native store: ${AGENTPROTO_HOME:-~/.agentproto}/mastracode-inprocess/\n// storage.db — the dedicated Mastra libsql db the in-process arm writes\n// (adapters/mastracode-inprocess/src/client.ts). The arm's public\n// sessionId is the composite \"<resourceId>:<threadId>\"; agentproto records\n// it verbatim as adapterSessionId. Threads live in `mastra_threads` (keyed\n// by threadId) and messages in `mastra_messages` (keyed by `thread_id`,\n// each `content` a Mastra v2 `{format,parts}` JSON). The store has no cwd\n// column, so cwd-scoped discovery is not possible — but this in-process arm\n// always yields an adapterSessionId, so the exact-bind path is the only one\n// that ever runs in practice.\n\ninterface MastraThreadRow {\n id: string\n resourceId?: string\n title?: string\n createdAt?: string\n updatedAt?: string\n}\ninterface MastraMessageRow {\n role: string\n content: string\n createdAt: string\n}\n\nfunction mastracodeInprocessDbPath(): string {\n const home = process.env.AGENTPROTO_HOME ?? join(homedir(), \".agentproto\")\n return join(home, \"mastracode-inprocess\", \"storage.db\")\n}\n\n/** Split \"<resourceId>:<threadId>\"; tolerate a bare threadId (no colon). */\nfunction mastraThreadId(conversationId: string): string {\n const idx = conversationId.indexOf(\":\")\n return idx > 0 ? conversationId.slice(idx + 1) : conversationId\n}\n\n/** Pull user/assistant text, reasoning, and tool calls/results out of one\n * Mastra v2 `{format,parts}` content blob. */\nfunction mastraContentToMessage(\n role: ExportedMessage[\"role\"],\n content: string,\n): { message?: ExportedMessage; toolResults: { name?: string; text: string }[]; toolCalls: number } {\n const toolResults: { name?: string; text: string }[] = []\n let parsed: { parts?: unknown[] }\n try {\n parsed = JSON.parse(content) as { parts?: unknown[] }\n } catch {\n return { message: undefined, toolResults, toolCalls: 0 }\n }\n let text = \"\"\n let reasoning = \"\"\n const toolCalls: { name: string; args: string }[] = []\n for (const raw of parsed.parts ?? []) {\n if (!raw || typeof raw !== \"object\") continue\n const part = raw as {\n type?: string\n text?: string\n reasoning?: string\n toolInvocation?: { toolName?: string; args?: unknown; result?: unknown }\n }\n if (part.type === \"text\" && part.text) text += part.text\n else if (part.type === \"reasoning\" && part.reasoning) reasoning += part.reasoning\n else if (part.type === \"tool-invocation\" && part.toolInvocation) {\n const inv = part.toolInvocation\n const name = inv.toolName ?? \"tool\"\n toolCalls.push({ name, args: JSON.stringify(inv.args ?? {}) })\n if (inv.result !== undefined) {\n const r = inv.result as { content?: Array<{ type?: string; text?: string }> }\n const rtext = Array.isArray(r?.content)\n ? r.content.filter(c => c?.type === \"text\").map(c => c.text ?? \"\").join(\"\")\n : typeof inv.result === \"string\"\n ? inv.result\n : JSON.stringify(inv.result)\n toolResults.push({ name, text: rtext })\n }\n }\n // data-* and step-start parts are internal bookkeeping — skip.\n }\n let message: ExportedMessage | undefined\n if (text.trim() || reasoning.trim() || toolCalls.length) {\n message = { role }\n if (text.trim()) message.text = text.trim()\n if (reasoning.trim()) message.reasoning = reasoning.trim()\n if (toolCalls.length) message.toolCalls = toolCalls\n }\n return { message, toolResults, toolCalls: toolCalls.length }\n}\n\nexport async function exportMastracodeInprocessSession(conversationId: string): Promise<ExportedSession> {\n const threadId = mastraThreadId(conversationId)\n const dbPath = mastracodeInprocessDbPath()\n const db = await openReadonlySqlite(dbPath, \"mastracode-inprocess\")\n try {\n const thread = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM mastra_threads WHERE id = ?\").get(threadId) as unknown as\n | MastraThreadRow\n | undefined,\n )\n if (!thread) {\n throw new Error(\n `mastracode-inprocess: thread \"${threadId}\" not found in ${dbPath}. ` +\n `The sessionId is \"<resourceId>:<threadId>\"; only the threadId is looked up.`,\n )\n }\n const rows = withRetryOnBusy(\n () =>\n db\n .prepare('SELECT role, content, createdAt FROM mastra_messages WHERE thread_id = ? ORDER BY \"createdAt\" ASC')\n .all(threadId) as unknown as MastraMessageRow[],\n )\n const messages: ExportedMessage[] = []\n let toolCallCount = 0\n for (const r of rows) {\n // Mastra tags user turns with role \"signal\"; assistant with \"assistant\".\n const role: ExportedMessage[\"role\"] = r.role === \"assistant\" ? \"assistant\" : \"user\"\n const { message, toolResults, toolCalls } = mastraContentToMessage(role, r.content)\n if (message) messages.push(message)\n toolCallCount += toolCalls\n for (const tr of toolResults) {\n messages.push({ role: \"tool\", text: tr.text, ...(tr.name ? { toolName: tr.name } : {}) })\n }\n }\n const meta: ExportedSessionMeta = { source: \"mastracode-inprocess\" }\n if (thread.title) meta.title = thread.title\n if (thread.createdAt) meta.startedAt = thread.createdAt\n if (thread.updatedAt) meta.endedAt = thread.updatedAt\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n return { meta, messages }\n } finally {\n db.close()\n }\n}\n\nexport async function discoverMastracodeInprocessSessions(\n _cwd: string,\n since?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const dbPath = mastracodeInprocessDbPath()\n let db: HermesDb\n try {\n db = await openReadonlySqlite(dbPath, \"mastracode-inprocess\")\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes(\"database not found\")) return []\n throw err\n }\n try {\n // Exact-bind only: `mastra_threads` has no cwd column, so a cwd-scoped\n // scan is impossible. Absent an expectedId there is nothing to safely\n // scope to, so return none (this in-process arm always supplies an\n // adapterSessionId, so the exact-bind path is the real one).\n if (!expectedId) return []\n const threadId = mastraThreadId(expectedId)\n const thread = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM mastra_threads WHERE id = ?\").get(threadId) as unknown as\n | MastraThreadRow\n | undefined,\n )\n if (!thread) return []\n const sinceMs = since ? Date.parse(since) : NaN\n if (Number.isFinite(sinceMs) && thread.updatedAt) {\n const upd = Date.parse(thread.updatedAt)\n if (Number.isFinite(upd) && upd < sinceMs - 1000) return []\n }\n return [\n {\n // Echo back the full composite id so callers/read() round-trip it.\n conversationId: expectedId,\n ...(thread.createdAt ? { startedAt: thread.createdAt } : {}),\n ...(thread.updatedAt ? { lastActivityAt: thread.updatedAt } : {}),\n ...(thread.title ? { preview: thread.title } : {}),\n },\n ]\n } finally {\n db.close()\n }\n}\n\n// ── pi exporter (JSON-over-stdio session log) ─────────────────────────\n//\n// Native store: ~/.pi/agent/sessions/<cwd-slug>/<ts>_<uuid>.jsonl — pi\n// writes one append-only JSONL per conversation. The first line is a\n// `session` record carrying the uuid `id` (== pi's RPC `sessionId`, which\n// agentproto records as adapterSessionId — pi's client captures it from\n// get_state) and the `cwd`. `message` lines carry the turns; the\n// cwd-slug directory encoding is version-dependent, so discovery scans and\n// keys off each file's authoritative `session.cwd` rather than the slug.\n\nfunction piSessionsDir(): string {\n return join(homedir(), \".pi\", \"agent\", \"sessions\")\n}\n\ninterface PiLine {\n type?: string\n id?: string\n cwd?: string\n timestamp?: string\n provider?: string\n modelId?: string\n message?: {\n role?: string\n toolName?: string\n isError?: boolean\n content?: unknown\n }\n}\n\n/** Text of pi content blocks (`{type:\"text\",text}`), string-tolerant. */\nfunction piBlocksText(content: unknown): string {\n if (typeof content === \"string\") return content\n if (!Array.isArray(content)) return \"\"\n let acc = \"\"\n for (const c of content) {\n if (c && typeof c === \"object\") {\n const b = c as { type?: string; text?: string }\n if (b.type === \"text\" && typeof b.text === \"string\") acc += b.text\n }\n }\n return acc\n}\n\nasync function walkPiSessionFiles(dir: string): Promise<string[]> {\n let entries: Dirent[]\n try {\n entries = await fs.readdir(dir, { withFileTypes: true })\n } catch {\n return []\n }\n const out: string[] = []\n for (const e of entries) {\n const p = join(dir, e.name)\n if (e.isDirectory()) out.push(...(await walkPiSessionFiles(p)))\n else if (e.isFile() && e.name.endsWith(\".jsonl\")) out.push(p)\n }\n return out\n}\n\nasync function findPiSessionFile(conversationId: string): Promise<string | undefined> {\n const files = await walkPiSessionFiles(piSessionsDir())\n const byName = files.find(f => f.endsWith(`_${conversationId}.jsonl`))\n if (byName) return byName\n for (const f of files) {\n const first = await readFirstJsonLine(f)\n if (!first) continue\n try {\n const meta = JSON.parse(first) as PiLine\n if (meta.type === \"session\" && meta.id === conversationId) return f\n } catch {\n // skip\n }\n }\n return undefined\n}\n\nexport async function exportPiSession(conversationId: string): Promise<ExportedSession> {\n const file = await findPiSessionFile(conversationId)\n if (!file) {\n throw new Error(\n `pi: no session file for conversation \"${conversationId}\" under ${piSessionsDir()}.`,\n )\n }\n const stream = createReadStream(file, { encoding: \"utf8\" })\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n const messages: ExportedMessage[] = []\n let toolCallCount = 0\n let startedAt: string | undefined\n let model: string | undefined\n\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let entry: PiLine\n try {\n entry = JSON.parse(trimmed) as PiLine\n } catch {\n continue\n }\n if (entry.type === \"session\") {\n startedAt = entry.timestamp\n continue\n }\n if (entry.type === \"model_change\") {\n model = entry.provider ? `${entry.provider}/${entry.modelId ?? \"\"}` : entry.modelId\n continue\n }\n if (entry.type !== \"message\" || !entry.message) continue\n const m = entry.message\n const content = m.content\n\n if (m.role === \"toolResult\") {\n const text = piBlocksText(content)\n messages.push({\n role: \"tool\",\n text: m.isError ? `[error] ${text}` : text,\n ...(m.toolName ? { toolName: m.toolName } : {}),\n })\n continue\n }\n\n const role: ExportedMessage[\"role\"] = m.role === \"assistant\" ? \"assistant\" : \"user\"\n let text = \"\"\n let reasoning = \"\"\n const toolCalls: { name: string; args: string }[] = []\n if (typeof content === \"string\") {\n text = content\n } else if (Array.isArray(content)) {\n for (const raw of content) {\n if (!raw || typeof raw !== \"object\") continue\n const part = raw as {\n type?: string\n text?: string\n thinking?: string\n name?: string\n arguments?: unknown\n }\n if (part.type === \"text\" && part.text) text += part.text\n else if (part.type === \"thinking\" && part.thinking) reasoning += part.thinking\n else if (part.type === \"toolCall\") {\n toolCalls.push({ name: part.name ?? \"tool\", args: JSON.stringify(part.arguments ?? {}) })\n toolCallCount += 1\n }\n }\n }\n if (text.trim() || reasoning.trim() || toolCalls.length) {\n const em: ExportedMessage = { role }\n if (text.trim()) em.text = text.trim()\n if (reasoning.trim()) em.reasoning = reasoning.trim()\n if (toolCalls.length) em.toolCalls = toolCalls\n messages.push(em)\n }\n }\n\n const meta: ExportedSessionMeta = { source: \"pi\" }\n if (startedAt) meta.startedAt = startedAt\n if (model) meta.model = model\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n return { meta, messages }\n}\n\nexport async function discoverPiSessions(\n cwd: string,\n since?: string,\n until?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const files = await walkPiSessionFiles(piSessionsDir())\n const sinceMs = since ? Date.parse(since) : NaN\n const untilMs = until ? Date.parse(until) : NaN\n const scored: { candidate: ConversationCandidate; mtimeMs: number }[] = []\n\n for (const f of files) {\n let mtimeMs: number\n try {\n mtimeMs = (await fs.stat(f)).mtimeMs\n } catch {\n continue\n }\n if (Number.isFinite(sinceMs) && mtimeMs < sinceMs - 1000) continue\n const first = await readFirstJsonLine(f)\n if (!first) continue\n let meta: PiLine\n try {\n meta = JSON.parse(first) as PiLine\n } catch {\n continue\n }\n if (meta.type !== \"session\" || !meta.id) continue\n if (expectedId) {\n if (meta.id !== expectedId) continue\n } else if (meta.cwd !== cwd) {\n continue\n }\n const startedAt = meta.timestamp\n if (Number.isFinite(untilMs) && startedAt) {\n const s = Date.parse(startedAt)\n if (Number.isFinite(s) && s > untilMs) continue\n }\n scored.push({\n candidate: {\n conversationId: meta.id,\n ...(startedAt ? { startedAt } : {}),\n lastActivityAt: new Date(mtimeMs).toISOString(),\n },\n mtimeMs,\n })\n }\n\n scored.sort((a, b) => b.mtimeMs - a.mtimeMs)\n return scored.map(s => s.candidate)\n}\n\n// ── Strategy registry ─────────────────────────────────────────────────\n\nconst EXPORT_STRATEGIES: Record<string, ExportStrategy> = {\n \"claude-code\": {\n exportSession: exportClaudeCodeSession,\n },\n hermes: {\n exportSession: (id: string) => exportHermesSession(id),\n },\n codex: {\n exportSession: (id: string) => exportCodexSession(id),\n },\n opencode: {\n exportSession: (id: string) => exportOpenCodeSession(id),\n },\n \"mastracode-inprocess\": {\n exportSession: (id: string) => exportMastracodeInprocessSession(id),\n },\n pi: {\n exportSession: (id: string) => exportPiSession(id),\n },\n}\n\n// ── Public API ────────────────────────────────────────────────────────\n\nexport type ExportSource = \"auto\" | \"native\" | \"daemon\"\n\nexport interface ExportAgentSessionInput {\n /** agentproto session id (sess_xxx) or an adapter-native id */\n sessionId: string\n registry: SessionsRegistry\n format?: \"markdown\" | \"json\"\n maxToolChars?: number\n /** Override adapter slug when sessionId is an adapter-native id */\n adapter?: string\n /** Override cwd when sessionId is an adapter-native id (claude-code only) */\n cwd?: string\n /** Which backend to read from. \"auto\" (default) prefers the adapter's\n * own native store and falls back to agentproto's own events.jsonl\n * capture when there isn't one (or it can't be read); \"native\" / \"daemon\"\n * force one and surface its own error instead of falling back. */\n source?: ExportSource\n}\n\nexport interface ExportAgentSessionResult {\n sessionId: string\n adapter: string\n format: string\n meta: ExportedSessionMeta\n content: string\n}\n\nexport async function exportAgentSession(\n input: ExportAgentSessionInput,\n): Promise<ExportAgentSessionResult> {\n const { sessionId, registry, format = \"markdown\", maxToolChars = 1200 } = input\n const source = input.source ?? \"auto\"\n\n // Resolve via registry first. `err` closes over `adapterSlug` so it\n // returns the resolved slug (not the raw input) after registry lookup.\n let adapterSlug = input.adapter\n let cwd = input.cwd\n let adapterSessionId = sessionId\n\n const err = (msg: string): ExportAgentSessionResult => ({\n sessionId,\n adapter: adapterSlug ?? \"unknown\",\n format,\n meta: {},\n content: `Error: ${msg}`,\n })\n\n const desc = registry.findByIdOrName(sessionId)\n // events.jsonl is always keyed by the agentproto session id — never the\n // adapter-native id substituted below for the native strategies.\n const daemonSessionId = desc?.id ?? sessionId\n if (desc) {\n adapterSlug = adapterSlug ?? desc.adapterSlug\n cwd = cwd ?? desc.cwd\n // prefer the adapter-native id over the agentproto id\n if (desc.adapterSessionId) adapterSessionId = desc.adapterSessionId\n }\n\n const tryNative = async (): Promise<ExportedSession> => {\n if (!adapterSlug) {\n throw new Error(\n `session \"${sessionId}\" not found in registry and no adapter override supplied.\\n` +\n `Pass adapter explicitly or use a known session id (sess_xxx or name).`,\n )\n }\n const exporter = EXPORT_STRATEGIES[adapterSlug]\n if (!exporter) {\n const supported = Object.keys(EXPORT_STRATEGIES).join(\", \")\n throw new Error(\n `no exporter for adapter \"${adapterSlug}\". Supported: ${supported}.\\n` +\n `Only sessions spawned via claude-code or hermes can be exported.`,\n )\n }\n return exporter.exportSession(adapterSessionId, cwd)\n }\n\n const tryDaemon = (): Promise<ExportedSession> => exportDaemonEventsSession(daemonSessionId, desc)\n\n let session: ExportedSession\n try {\n if (source === \"native\") {\n session = await tryNative()\n } else if (source === \"daemon\") {\n session = await tryDaemon()\n } else {\n try {\n session = await tryNative()\n } catch (nativeErr) {\n try {\n session = await tryDaemon()\n } catch (daemonErr) {\n const nativeMsg = nativeErr instanceof Error ? nativeErr.message : String(nativeErr)\n const daemonMsg = daemonErr instanceof Error ? daemonErr.message : String(daemonErr)\n return err(`${nativeMsg}\\n(daemon-events fallback also failed: ${daemonMsg})`)\n }\n }\n }\n } catch (e) {\n return err(e instanceof Error ? e.message : String(e))\n }\n\n const content =\n format === \"json\"\n ? renderJson(session)\n : renderMarkdown(session, { maxToolChars })\n\n return {\n sessionId,\n adapter: adapterSlug ?? (session.meta.source === \"daemon-events\" ? \"daemon\" : \"unknown\"),\n format,\n meta: session.meta,\n content,\n }\n}\n","/**\n * Conversation as pivot: one store abstraction per provider, read on any\n * session. A \"conversation\" is the provider's own persisted session — the\n * durable object. An agentproto session (ACP or PTY) is just an attachment\n * to it. `CONVERSATION_STORES` is the single source of truth for \"where does\n * this provider keep its conversations, and how do I read/attach to one\" —\n * `RESUME_STRATEGIES` (resume-strategies.ts) and `EXPORT_STRATEGIES`\n * (transcript-export.ts) are thin adapters over it so the two historically\n * drifted tables can never diverge again.\n */\n\nimport { promises as fs, createReadStream } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { createInterface } from \"node:readline\"\nimport { join, resolve } from \"node:path\"\nimport type { ExportedSession, ExportedMessage } from \"./transcript-export.js\"\n\n/** Where a captured conversation id is recorded on the descriptor.\n * Same union as resume-strategies.ts's ResumeMetadataKey — re-exported\n * from there, NOT redefined, so the two can never drift. */\nexport type { ResumeMetadataKey } from \"./resume-strategies.js\"\nimport type { ResumeMetadataKey } from \"./resume-strategies.js\"\n\n/** One conversation found in a provider's native store, plus enough\n * evidence for a caller (or a human) to pick between several. */\nexport interface ConversationCandidate {\n /** The provider-native conversation id (claude: the jsonl uuid). */\n conversationId: string\n startedAt?: string\n lastActivityAt?: string\n messageCount?: number\n /** First user message, truncated to ~120 chars. Disambiguation aid. */\n preview?: string\n /** Which attachment wrote the tail, provider-native vocabulary\n * (claude-code: \"sdk-ts\" = ACP arm, \"cli\" = native TUI). */\n lastWriter?: string\n}\n\nexport interface DiscoverInput {\n cwd: string\n /** Only consider conversations active at-or-after this ISO ts. */\n since?: string\n /** Only consider conversations that STARTED at-or-before this ISO ts —\n * an upper bound, typically a dead session's `endedAt`. A conversation\n * whose own first message postdates it provably belongs to some other,\n * later session. Omit for a live/ongoing session (no `endedAt` yet) —\n * it must keep matching conversations that started after `since` with\n * no upper bound. Conservative: a candidate with no discoverable\n * `startedAt` is never dropped by this filter. */\n until?: string\n /** The requesting session's attachment mode, in ABSTRACT (provider-\n * agnostic) vocabulary — `\"native\"` for a real PTY/TUI attach,\n * `\"acp\"` for the agent-cli/ACP arm. When set, drops candidates whose\n * `lastWriter` is present and maps to the OPPOSITE mode (a native PTY's\n * conversation is never written by the ACP arm, and vice versa).\n * Conservative: a candidate with no `lastWriter` is never dropped, and\n * omitting this field applies no mode filtering at all. */\n attachmentMode?: \"native\" | \"acp\"\n /** When set, bind to EXACTLY this conversation or return [].\n * MUST NOT fall back to a recency guess — see invariants. */\n expectedId?: string\n}\n\nexport interface ConversationStore {\n storeAs: ResumeMetadataKey\n /** Capture the conversation id from a live output line; group 1 = the id. */\n outputHint?: RegExp\n /** argv that attaches a NATIVE PTY to an existing conversation.\n * Omitted ⇒ this provider has no native attach path. */\n attachArgv?(conversationId: string): string[]\n /** Find conversations in the provider's native store. `[]` = none —\n * a normal answer (e.g. the PTY is a bash shell). Never throws for\n * \"nothing found\"; throws only on a genuinely unreadable store. */\n discover(input: DiscoverInput): Promise<ConversationCandidate[]>\n /** Read a full conversation into the shared export model. */\n read(conversationId: string, cwd?: string): Promise<ExportedSession>\n /** Follow a conversation live. Resolves to an unsubscribe fn.\n * Omitted ⇒ no live tail for this provider (caller polls `read`). */\n follow?(input: {\n conversationId: string\n cwd?: string\n onMessage: (m: ExportedMessage) => void\n }): Promise<() => void>\n}\n\n// ── claude-code store ──────────────────────────────────────────────────\n//\n// Native store: ~/.claude/projects/<cwd-encoded>/<uuid>.jsonl, one file per\n// conversation. `<cwd-encoded>` is the absolute cwd run through\n// `claudeProjectSlug` (claude's own convention — see that function's\n// docblock for the empirically-verified rule).\n\ninterface ClaudeJsonlMeta {\n type?: string\n timestamp?: string\n entrypoint?: string\n message?: { role?: string; content?: unknown }\n}\n\n/**\n * Claude Code's own `cwd` → project-dir-name encoder.\n *\n * The real rule (verified empirically against `~/.claude/projects/`\n * directory names for dozens of known cwds, including dotted worktree\n * paths and macOS temp dirs): every character that is NOT `[a-zA-Z0-9]`\n * is replaced 1:1 with `-`. Crucially, runs of consecutive non-alnum\n * characters are NOT collapsed — each input character produces exactly\n * one output character.\n *\n * This used to be `cwd.replace(/\\//g, \"-\")` — slashes only. That's wrong\n * for any cwd containing a dot (every `.agentproto` worktree, any\n * dotdir), an underscore-prefixed segment, a space, etc., because those\n * characters are left untouched instead of becoming `-`, so the computed\n * directory never matches the one claude actually created.\n *\n * Reconstruction proof (both real, both `ls ~/.claude/projects/`-verified):\n * cwd /Users/jeremy/.agentproto/worktrees/ts/gc-fresh-hold\n * → -Users-jeremy--agentproto-worktrees-ts-gc-fresh-hold\n * (note the \"--\" from \"/.\" — one dash for \"/\", one for \".\", not collapsed)\n *\n * cwd /Volumes/SSDExternalMacStudio/Code/_agentproto-worktrees/adapter-claude-sdk\n * → -Volumes-SSDExternalMacStudio-Code--agentproto-worktrees-adapter-claude-sdk\n * (same double-dash shape, this time from \"/_\")\n */\nexport function claudeProjectSlug(cwd: string): string {\n return cwd.replace(/[^a-zA-Z0-9]/g, \"-\")\n}\n\n/** Exported so `conversation-index.ts` can resolve the same directory\n * without re-deriving the slug rule itself. */\nexport function claudeCodeProjectDir(cwd: string): string {\n return resolve(homedir(), \".claude\", \"projects\", claudeProjectSlug(cwd))\n}\n\nfunction extractFirstText(content: unknown): string | undefined {\n if (typeof content === \"string\") {\n const t = content.trim()\n return t || undefined\n }\n if (Array.isArray(content)) {\n for (const block of content) {\n if (\n block &&\n typeof block === \"object\" &&\n (block as { type?: string }).type === \"text\" &&\n typeof (block as { text?: unknown }).text === \"string\"\n ) {\n const t = ((block as { text: string }).text).trim()\n if (t) return t\n }\n }\n }\n return undefined\n}\n\n/** Light line-scan for candidate metadata — NOT the full transcript parser\n * (that's exportClaudeCodeSession). Streams the file so large jsonl files\n * don't get pulled fully into memory. */\nasync function scanClaudeJsonl(filePath: string): Promise<{\n startedAt?: string\n lastActivityAt?: string\n messageCount: number\n preview?: string\n lastWriter?: string\n}> {\n const stream = createReadStream(filePath, { encoding: \"utf8\" })\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n\n let startedAt: string | undefined\n let lastActivityAt: string | undefined\n let messageCount = 0\n let preview: string | undefined\n let lastWriter: string | undefined\n\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let entry: ClaudeJsonlMeta\n try {\n entry = JSON.parse(trimmed) as ClaudeJsonlMeta\n } catch {\n continue\n }\n\n if (typeof entry.timestamp === \"string\") {\n if (!startedAt) startedAt = entry.timestamp\n lastActivityAt = entry.timestamp\n }\n if (typeof entry.entrypoint === \"string\") {\n lastWriter = entry.entrypoint\n }\n if (entry.type === \"user\" || entry.type === \"assistant\") {\n messageCount += 1\n if (preview === undefined && entry.type === \"user\") {\n const text = extractFirstText(entry.message?.content)\n if (text !== undefined) {\n preview = text.length > 120 ? text.slice(0, 120) : text\n }\n }\n }\n }\n\n return { startedAt, lastActivityAt, messageCount, preview, lastWriter }\n}\n\nasync function buildClaudeCandidate(\n filePath: string,\n conversationId: string,\n): Promise<ConversationCandidate> {\n const scanned = await scanClaudeJsonl(filePath)\n return { conversationId, ...scanned }\n}\n\n/** Maps an abstract `attachmentMode` to claude's own jsonl `entrypoint`\n * vocabulary. Kept local to this store — callers deal only in\n * `\"native\" | \"acp\"`, never `\"cli\" | \"sdk-ts\"`. */\nfunction claudeEntrypointFor(mode: \"native\" | \"acp\"): string {\n return mode === \"native\" ? \"cli\" : \"sdk-ts\"\n}\n\nasync function discoverClaudeCode(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { cwd, since, until, attachmentMode, expectedId } = input\n const dir = claudeCodeProjectDir(cwd)\n\n // Ground truth beats heuristic: bind to exactly the conversation we were\n // asked about, never whichever transcript happens to be newest. Never\n // falls through to the mtime path below — see invariants.\n if (expectedId) {\n const filePath = join(dir, `${expectedId}.jsonl`)\n try {\n await fs.stat(filePath)\n } catch {\n return []\n }\n return [await buildClaudeCandidate(filePath, expectedId)]\n }\n\n let entries: string[]\n try {\n entries = await fs.readdir(dir)\n } catch {\n return []\n }\n const jsonlFiles = entries.filter(e => e.endsWith(\".jsonl\"))\n if (jsonlFiles.length === 0) return []\n\n const sinceMs = since ? Date.parse(since) : NaN\n const untilMs = until ? Date.parse(until) : NaN\n const wantEntrypoint = attachmentMode ? claudeEntrypointFor(attachmentMode) : undefined\n const scored: { candidate: ConversationCandidate; mtimeMs: number }[] = []\n for (const f of jsonlFiles) {\n const filePath = join(dir, f)\n let mtimeMs: number\n try {\n mtimeMs = (await fs.stat(filePath)).mtimeMs\n } catch {\n continue\n }\n if (Number.isFinite(sinceMs) && mtimeMs < sinceMs - 1000) continue\n const conversationId = f.replace(/\\.jsonl$/, \"\")\n const candidate = await buildClaudeCandidate(filePath, conversationId)\n // `until` is an upper bound on the conversation's own first message —\n // provably not this session's if it started after the session ended.\n // Conservative: no discoverable startedAt ⇒ never dropped.\n if (Number.isFinite(untilMs) && candidate.startedAt !== undefined) {\n const startedMs = Date.parse(candidate.startedAt)\n if (Number.isFinite(startedMs) && startedMs > untilMs) continue\n }\n // Attachment-mode match: a native PTY's conversation is never written\n // by the ACP arm and vice versa. Conservative: no lastWriter ⇒ never\n // dropped, and an unset attachmentMode applies no filtering at all.\n if (wantEntrypoint !== undefined && candidate.lastWriter !== undefined && candidate.lastWriter !== wantEntrypoint) {\n continue\n }\n scored.push({ candidate, mtimeMs })\n }\n\n // Newest first — mirrors the old fsProbe's mtime-desc pick, and gives\n // callers of `discover` (which may just want \"the likely one\") a sane\n // default ordering without silently collapsing the list.\n scored.sort((a, b) => b.mtimeMs - a.mtimeMs)\n return scored.map(s => s.candidate)\n}\n\nasync function readClaudeCode(conversationId: string, cwd?: string): Promise<ExportedSession> {\n // Dynamic import, not a top-level one: resume-strategies.ts is its own\n // lean tsup entry (splitting:false) and pulls this module in as a value\n // import via CONVERSATION_STORES. esbuild still bundles transcript-\n // export.ts's bytes into that entry either way (no code-splitting means\n // no separate chunk to defer to) — what the dynamic import buys is\n // deferred MODULE INIT: transcript-export.ts's top-level code only runs\n // the first time `read()` is actually called, not merely by importing\n // resume-strategies.ts. See resume-strategies.ts's splitting:false note.\n const { exportClaudeCodeSession } = await import(\"./transcript-export.js\")\n return exportClaudeCodeSession(conversationId, cwd)\n}\n\n// ── hermes store ────────────────────────────────────────────────────\n//\n// Native store: ~/.hermes/state.db, a sqlite `sessions` table keyed by\n// `id` (the agentproto UUID passed as resumeSessionId — the same id\n// agentproto records as `adapterSessionId`, unlike claude-code's on-disk\n// jsonl uuid). It has a `cwd` column (live-verified 2026-07-17), so\n// cwd-scoped discovery is possible, unlike a plain folder-of-files store.\n\nasync function discoverHermes(input: DiscoverInput): Promise<ConversationCandidate[]> {\n // Dynamic import, not a top-level one — same reasoning as readClaudeCode\n // above: keeps transcript-export.ts's sqlite plumbing out of\n // resume-strategies.ts's lean tsup entry until a hermes store method\n // actually runs.\n const { discoverHermesSessions } = await import(\"./transcript-export.js\")\n return discoverHermesSessions(input.cwd, input.since, input.expectedId)\n}\n\nasync function readHermes(conversationId: string): Promise<ExportedSession> {\n const { exportHermesSession } = await import(\"./transcript-export.js\")\n return exportHermesSession(conversationId)\n}\n\n// ── codex store ───────────────────────────────────────────────────────\n//\n// Native store: $CODEX_HOME/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl.\n// The rollout uuid == the ACP session id agentproto records as\n// `adapterSessionId` (verified empirically), so a codex session's export\n// binds by that id directly (step 1 of the conversation-read ladder), and\n// `discover` scopes a PTY-only codex by the session_meta `cwd`. Reader in\n// transcript-export.ts, dynamically imported for the same reason as\n// readClaudeCode above (keep it out of resume-strategies.ts's lean entry).\n\nasync function discoverCodex(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { discoverCodexSessions } = await import(\"./transcript-export.js\")\n return discoverCodexSessions(input.cwd, input.since, input.until, input.expectedId)\n}\n\nasync function readCodex(conversationId: string): Promise<ExportedSession> {\n const { exportCodexSession } = await import(\"./transcript-export.js\")\n return exportCodexSession(conversationId)\n}\n\n// ── opencode store ────────────────────────────────────────────────────\n//\n// Native store: ${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db. The\n// `session` table's id is the `ses_…` id agentproto records as\n// `adapterSessionId` (verified), and its `directory` column is the cwd — so\n// discovery is cwd-scoped like hermes.\n\nasync function discoverOpenCode(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { discoverOpenCodeSessions } = await import(\"./transcript-export.js\")\n return discoverOpenCodeSessions(input.cwd, input.since, input.expectedId)\n}\n\nasync function readOpenCode(conversationId: string): Promise<ExportedSession> {\n const { exportOpenCodeSession } = await import(\"./transcript-export.js\")\n return exportOpenCodeSession(conversationId)\n}\n\n// ── mastracode-inprocess store ────────────────────────────────────────\n//\n// Native store: ${AGENTPROTO_HOME:-~/.agentproto}/mastracode-inprocess/\n// storage.db (Mastra libsql). sessionId is \"<resourceId>:<threadId>\";\n// `read` splits out the threadId. No cwd column, so `discover` is\n// exact-bind only (this in-process arm always supplies an adapterSessionId).\n\nasync function discoverMastracodeInprocess(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { discoverMastracodeInprocessSessions } = await import(\"./transcript-export.js\")\n return discoverMastracodeInprocessSessions(input.cwd, input.since, input.expectedId)\n}\n\nasync function readMastracodeInprocess(conversationId: string): Promise<ExportedSession> {\n const { exportMastracodeInprocessSession } = await import(\"./transcript-export.js\")\n return exportMastracodeInprocessSession(conversationId)\n}\n\n// ── pi store ──────────────────────────────────────────────────────────\n//\n// Native store: ~/.pi/agent/sessions/<cwd-slug>/<ts>_<uuid>.jsonl. The uuid\n// == pi's RPC sessionId recorded as `adapterSessionId`; discovery keys off\n// each file's authoritative `session.cwd` (the slug encoding is\n// version-dependent, so it is never trusted for scoping).\n\nasync function discoverPi(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { discoverPiSessions } = await import(\"./transcript-export.js\")\n return discoverPiSessions(input.cwd, input.since, input.until, input.expectedId)\n}\n\nasync function readPi(conversationId: string): Promise<ExportedSession> {\n const { exportPiSession } = await import(\"./transcript-export.js\")\n return exportPiSession(conversationId)\n}\n\nexport const CONVERSATION_STORES: Record<string, ConversationStore> = {\n \"claude-code\": {\n storeAs: \"claudeResumeId\",\n // Printed by claude on graceful exit when session persistence is on\n // (default). Example: `claude --resume 0e483f81-1a44-4bec-9667-b37158450296`\n outputHint: /claude\\s+--resume\\s+([0-9a-f-]{8,})/i,\n attachArgv: (conversationId: string) => [\"claude\", \"--resume\", conversationId],\n discover: discoverClaudeCode,\n read: readClaudeCode,\n },\n hermes: {\n storeAs: \"hermesResumeId\",\n // `hermes acp` is the ACP arm (bin_args in adapters/hermes/src/index.ts);\n // `--resume SESSION --tui` is the native TUI resume path — same binary,\n // different flags, unlike claude-code where the two arms are different\n // binaries. Verified via `hermes --help`: `--resume SESSION, -r` =\n // \"Resume a previous session by ID or title\", `--tui` = the real TUI.\n attachArgv: (conversationId: string) => [\"hermes\", \"--resume\", conversationId, \"--tui\"],\n discover: discoverHermes,\n read: readHermes,\n },\n // codex-acp writes no resume flag we sniff, and there's no native PTY\n // reattach argv to declare — export/read only, so no outputHint/attachArgv.\n codex: {\n storeAs: \"codexResumeId\",\n discover: discoverCodex,\n read: readCodex,\n },\n opencode: {\n storeAs: \"openCodeResumeId\",\n discover: discoverOpenCode,\n read: readOpenCode,\n },\n \"mastracode-inprocess\": {\n storeAs: \"mastracodeInprocessResumeId\",\n discover: discoverMastracodeInprocess,\n read: readMastracodeInprocess,\n },\n pi: {\n storeAs: \"piResumeId\",\n discover: discoverPi,\n read: readPi,\n },\n}\n\n/**\n * Bare (non-resume) launch argv for a provider's native terminal/TUI — the\n * \"start fresh\" counterpart to `attachArgv`, used to open a NEW native\n * session (e.g. a harness card's \"Terminal\" button) rather than reattach an\n * existing conversation.\n *\n * Coverage is deliberately BROADER than `attachArgv`'s: reattach needs a\n * documented resume flag, but a fresh launch only needs the CLI's\n * interactive arm. npx-spawned adapters use the same npx form here so the\n * terminal works wherever the adapter itself works, PATH binary or not.\n *\n * Absent on purpose (no interactive arm to launch):\n * - `mastracode-inprocess` — in-process SDK, nothing to exec\n * - `mastra-agent`, `claude-sdk` — first-party ACP servers, no TUI\n * - `antigravity` — `agy` is headless-only (`-p`/stream-json), no TUI\n */\nexport const NATIVE_LAUNCH_ARGV: Record<string, string[]> = {\n \"claude-code\": [\"claude\"],\n hermes: [\"hermes\", \"--tui\"],\n // Bare arm of the same npx package the adapter spawns IS the TUI.\n opencode: [\"npx\", \"-y\", \"opencode-ai\"],\n mastracode: [\"npx\", \"-y\", \"mastracode\"],\n // The adapter bundles the codex-acp wrapper (ACP-only); the interactive\n // Codex TUI lives in @openai/codex, fetched by npx on first use.\n codex: [\"npx\", \"-y\", \"@openai/codex\"],\n // ACP arms add flags/subcommands to these binaries; bare is interactive.\n gemini: [\"gemini\"],\n \"grok-cli\": [\"grok\"],\n pi: [\"pi\"],\n jcode: [\"jcode\"],\n // `openclaw chat` = \"Open a local terminal UI (alias for tui --local)\".\n openclaw: [\"openclaw\", \"chat\"],\n // Generic ACP catalog CLIs whose ACP arm is a separate binary/subcommand;\n // the bare bin is the interactive TUI.\n \"gemini-cli\": [\"gemini\"],\n \"qwen-code\": [\"qwen\"],\n \"mistral-vibe\": [\"vibe\"],\n \"kimi-cli\": [\"kimi\"],\n}\n","/**\n * Per-adapter resume strategies — the daemon's view of \"how do I\n * continue a previous session for THIS adapter?\".\n *\n * The driver already has an `AgentCliContinuation` declaration in\n * the adapter manifest (AIP-45). That covers strategy NAMES\n * (`native-resume`, `pinned-session`, `transcript`, `none`) but is\n * silent on the mechanics that live OUTSIDE the runtime — like\n * \"where on disk does this adapter store its conversations?\" or\n * \"what argv do I pass to resume into PTY mode?\".\n *\n * This table is that practical bridge. Each entry declares three\n * optional hooks:\n *\n * outputHint regex matched against each output line; group 1 is\n * the resume id. Stored as `desc.resumeMetadata[storeAs]`.\n * fsProbe async function that probes a per-adapter directory\n * for a stored session id, scoped to a workspace cwd.\n * Used when `outputHint` never matched.\n * spawnArgs given a captured id, returns the argv to spawn a\n * PTY that resumes the session. agentproto then\n * bypasses ACP/agent-cli and runs the provider\n * directly — the most reliable resume path because\n * it leans on the provider's native UX.\n *\n * Adapters that don't declare anything here fall back to:\n * 1. ACP-level resume via `resumeSessionId` on POST /sessions/agent\n * 2. Fresh spawn (same shape, no continuity)\n *\n * Eventually each adapter should ship its own strategy on\n * `AgentCliHandle.resumeStrategy` (driver-side). This central table\n * is the bootstrap: it lets a new adapter become resume-capable\n * without bumping its npm package; once that lands, entries\n * graduate into the adapter packages.\n */\n\nimport { CONVERSATION_STORES } from \"./conversation-store.js\"\nimport type { ConversationStore } from \"./conversation-store.js\"\n\n/** Where on disk the resume id ends up on the session descriptor. */\nexport type ResumeMetadataKey =\n | \"claudeResumeId\"\n | \"hermesResumeId\"\n | \"codexResumeId\"\n | \"openClawResumeId\"\n | \"openCodeResumeId\"\n // Export/read-only stores (no native resume wired): the key labels the\n // conversation store entry in CONVERSATION_STORES but is never written to\n // a descriptor's resumeMetadata, since these have no attachArgv/outputHint.\n | \"mastracodeInprocessResumeId\"\n | \"piResumeId\"\n\nexport interface ResumeStrategy {\n /** When set, run on every output line for this adapter. Group 1\n * captures the resume id. The match is saved on the descriptor\n * as `resumeMetadata[storeAs]`. */\n outputHint?: RegExp\n /** Where the matched id is recorded on the descriptor. */\n storeAs: ResumeMetadataKey\n /** Probe the adapter's on-disk session store for the resume id of a\n * session in the given workspace. Returns the id or null when nothing\n * eligible.\n *\n * When `expectedId` is set the session's own conversation id is known\n * (agent-cli descriptors carry it as `adapterSessionId`; for\n * claude-code it IS the on-disk `.jsonl` uuid — see acp-host.ts) and\n * the probe MUST bind to exactly that transcript: it confirms\n * `<expectedId>` exists and returns it, else null. It never falls\n * through to a mtime guess in that case — resuming *some other*\n * session that merely shares the cwd is a silent cross-session\n * correctness bug, strictly worse than not resuming at all.\n *\n * Only when `expectedId` is absent (e.g. a raw PTY claude session that\n * never had an ACP session id) does the probe fall back to\n * most-recently-modified, filtered to files at-or-after `prevStartedAt`\n * (avoids resuming an unrelated prior conversation).\n *\n * Skip when the adapter doesn't persist sessions externally. */\n fsProbe?(\n cwd: string,\n prevStartedAt: string,\n expectedId?: string,\n ): Promise<string | null>\n /** Return the argv to spawn a PTY that resumes into the given id.\n * When omitted, the daemon falls back to ACP-level resume via\n * the agent-cli protocol instead of the provider's native CLI. */\n spawnArgs?(id: string): string[]\n}\n\n// Project every conversation store that declares a native PTY attach argv\n// into the resume-strategy table, so the table and the store can never drift\n// apart again. Only stores with `attachArgv` offer a provider-native TUI\n// resume; the rest are read/export-only. The actual decision to USE a\n// `pty-native` restart is still gated on `RestartCandidate.nativeTerminalResume`\n// below — a store entry alone does not license terminal mode.\nexport const RESUME_STRATEGIES: Record<string, ResumeStrategy> = Object.fromEntries(\n Object.entries(CONVERSATION_STORES)\n .filter(([, store]) => typeof store.attachArgv === \"function\")\n .map(([slug, store]) => {\n const s = store as Required<Pick<ConversationStore, \"attachArgv\" | \"discover\">> & ConversationStore\n return [\n slug,\n {\n outputHint: store.outputHint,\n storeAs: store.storeAs,\n fsProbe: async (cwd, prevStartedAt, expectedId) => {\n const candidates = await s.discover({\n cwd,\n since: prevStartedAt,\n expectedId,\n })\n return candidates[0]?.conversationId ?? null\n },\n spawnArgs: s.attachArgv,\n } satisfies ResumeStrategy,\n ]\n }),\n)\n\n/**\n * Helper: which adapters declare any resume capability? Used by\n * `agentproto sessions restart` to print a helpful \"this adapter\n * doesn't support resume; falling back to fresh spawn\" hint when\n * applicable.\n */\nexport function hasResumeStrategy(adapterSlug: string | undefined): boolean {\n if (!adapterSlug) return false\n const s = RESUME_STRATEGIES[adapterSlug]\n return !!(s && (s.outputHint || s.fsProbe || s.spawnArgs))\n}\n\n// ── Restart decision tree ────────────────────────────────────────\n//\n// Shared between the CLI (`agentproto sessions restart`, sessions.ts)\n// and the daemon's `session_restart` MCP tool (session-tools.ts) —\n// both need to answer \"given this dead/alive session, how do I bring\n// it back with the most continuity?\" the exact same way. Duck-typed\n// on a minimal shape rather than importing `SessionDescriptor` from\n// sessions.ts: this file is its own tsup entry (`splitting: false`),\n// so a value-level cross-entry import would inline the whole sessions\n// module here. A full `SessionDescriptor` satisfies these structurally.\n\nexport interface RestartCandidate {\n adapterSlug?: string\n resumeMetadata?: Record<string, string>\n pty?: boolean\n adapterSessionId?: string\n /** Manifest-declared `capabilities.resumable` for `adapterSlug` (see\n * `SessionDescriptor.resumable`'s doc) — the honesty gate for the whole\n * decision tree below. `false` means an `adapterSessionId` here is a\n * dead end: the adapter cannot rehydrate a prior conversation from it, no\n * matter how it's presented. Omitted/`true` preserves today's behaviour\n * (assumed resumable) for every adapter/row that doesn't set this. */\n resumable?: boolean\n /**\n * Manifest-declared `capabilities.nativeTerminalResume` for `adapterSlug`.\n * The `pty-native` restart strategy is only chosen when this flag is true\n * AND a native resume id is available. ACP resumability (`resumable`)\n * alone does NOT imply a native TUI resume is safe or available.\n */\n nativeTerminalResume?: boolean\n}\n\nexport interface FsProbeCandidate extends RestartCandidate {\n cwd?: string\n startedAt: string\n}\n\n/**\n * Where a restart should land. Computed once so callers never diverge:\n *\n * 1. pty-native — the adapter has a captured resume id AND declares\n * `spawnArgs` (e.g. claude-code): respawn a PTY running the\n * provider's own resume command. Most reliable — works whenever\n * the provider persisted the session, regardless of whether the\n * ACP wrapper did.\n * 2. pty-plain — the previous session was a real PTY with no\n * native strategy match: re-run the same argv, no continuity.\n * 3. agent — an agent-cli session with no native strategy:\n * resume at the ACP level via the adapter's own session id (may\n * still 404 if the adapter never persisted a turn — callers\n * should retry without `resumeSessionId` on a \"not found\" error).\n * 4. unsupported — a generic command session; no history to resume\n * and no shape to clone reliably.\n */\nexport type RestartStrategy =\n | { kind: \"pty-native\"; argv: string[] }\n | { kind: \"pty-plain\" }\n | { kind: \"agent\"; resumeSessionId?: string; resumeFallback?: boolean }\n | { kind: \"unsupported\"; reason: string }\n\nexport function decideRestartStrategy(prev: RestartCandidate): RestartStrategy {\n // Provider-native terminal resume takes precedence over ACP-level resume —\n // but ONLY when the adapter manifest explicitly declares a verified native\n // TUI resume capability (`nativeTerminalResume`). ACP resumability alone\n // (`resumable`) does not imply it is safe or correct to reattach as a raw\n // PTY; without the flag we fall back to ACP-level or fresh-spawn restart.\n if (prev.adapterSlug && prev.nativeTerminalResume === true) {\n const strategy = RESUME_STRATEGIES[prev.adapterSlug]\n const id = strategy?.storeAs\n ? prev.resumeMetadata?.[strategy.storeAs]\n : undefined\n if (strategy?.spawnArgs && id) {\n return { kind: \"pty-native\", argv: strategy.spawnArgs(id) }\n }\n }\n if (prev.pty === true) {\n return { kind: \"pty-plain\" }\n }\n if (prev.adapterSlug) {\n // Honesty gate (resume-honesty fix): an adapter that declares\n // `resumable: false` (hermes, mastra-agent, …) cannot rehydrate a prior\n // conversation from `adapterSessionId` at all — passing it as\n // `resumeSessionId` either silently comes back blank or gets rejected by\n // the wrapper, and either way the caller must never present it as\n // continuity. Route straight to a flagged fresh spawn instead of\n // emitting a phantom id. `resumable === undefined` (unknown/legacy row,\n // or an adapter this fix hasn't reached) keeps today's behaviour.\n const canResumeAtAcpLevel = prev.resumable !== false\n return {\n kind: \"agent\",\n ...(prev.adapterSessionId && canResumeAtAcpLevel\n ? { resumeSessionId: prev.adapterSessionId }\n : {}),\n ...(prev.adapterSessionId && !canResumeAtAcpLevel\n ? { resumeFallback: true }\n : {}),\n }\n }\n return {\n kind: \"unsupported\",\n reason: \"generic command session — restart only supports pty + agent-cli\",\n }\n}\n\n/**\n * Matches an adapter's rejection of a `resumeSessionId` it can't honour —\n * the trigger for the \"retry as a fresh spawn\" fallback in\n * `session-restart-core.ts` and the CLI's `sessions restart`. Beyond a\n * literal \"not found\" (an unknown/never-persisted id), this also covers the\n * ACP wrapper-level rejection an adapter with `loadSession: false` throws\n * when a generic `resumeSessionId` reaches it despite `capabilities.\n * resumable: true` at the manifest level (e.g. claude-sdk — resumable via\n * its own SDK session store, but no ACP `session/load` surface): the\n * `@agentclientprotocol/sdk` server-side dispatcher throws a JSON-RPC\n * \"Method not found\" for an unimplemented `session/load`, and an agent may\n * instead reject with its own \"does not support\" / \"not supported\" wording.\n * Shared by every fallback call site so they can't drift out of sync (see\n * this module's own header comment on why that matters).\n */\nexport const RESUME_ID_REJECTED_RE =\n /not found|does not support|not supported|unsupported/i\n\n/**\n * Generic filesystem-fallback: for each known adapter strategy that\n * defines an `fsProbe`, run it against this session's cwd. If a\n * resume id is found, attach it to the descriptor's resumeMetadata.\n *\n * Lets `restart` recover continuity even when our own output sniffer\n * missed the resume hint (session killed too quickly, output buffered\n * past the kill, …). Eligible only when the file is at-or-after the\n * session's `startedAt` (avoid resuming an unrelated prior session\n * in the same cwd — see ResumeStrategy.fsProbe comment).\n *\n * Fix: when NO `adapterSessionId` was ever captured (session killed\n * before the ACP handshake), run a recency-window probe. When an\n * `adapterSessionId` exists but points to a missing JSONL, the probe\n * tries exact-bind and returns nothing — that's correct, we NEVER\n * silently resume a sibling conversation (safety: prevents cross-\n * session contamination). The adapter-level resume will fail with\n * \"not found\", triggering the fresh-spawn fallback + digest injection.\n */\nexport async function augmentWithFsResume<T extends FsProbeCandidate>(\n prev: T,\n): Promise<T> {\n const slug = prev.adapterSlug\n if (!slug) return prev\n const strategy = RESUME_STRATEGIES[slug]\n if (!strategy?.fsProbe) return prev\n // If we already have a captured id for this strategy's storage key,\n // skip the FS probe — the sniffer found it during the session.\n if (prev.resumeMetadata?.[strategy.storeAs]) return prev\n if (!prev.cwd) return prev\n // Pass the session's own conversation id (agent-cli sets it as\n // `adapterSessionId`; for claude-code it equals the on-disk `.jsonl`\n // uuid — acp-host.ts pins them equal) so the probe binds to THIS\n // session's transcript instead of the newest one in the cwd. Without\n // it, a restart of a session that shares a cwd with a concurrent one\n // could silently resume the wrong conversation. When the exact-bind\n // finds nothing (the JSONL is gone), we deliberately do NOT fall\n // through to a sibling — better to fail-fast and inject a digest.\n const id = await strategy.fsProbe(\n prev.cwd,\n prev.startedAt,\n prev.adapterSessionId,\n )\n if (!id) return prev\n return {\n ...prev,\n // When `adapterSessionId` was never captured (session killed before\n // the ACP handshake completed), backfill it from the fsProbe result\n // so the agent restart path can attempt ACP-level resume too — not\n // just the PTY-native path. For claude-code (and most adapters) the\n // on-disk conversation id IS the ACP session id, so the values are\n // interchangeable. Only backfills; never overwrites an existing id.\n ...(!prev.adapterSessionId ? { adapterSessionId: id } : {}),\n resumeMetadata: {\n ...(prev.resumeMetadata ?? {}),\n [strategy.storeAs]: id,\n },\n }\n}\n\n/**\n * Describe which resume path a restart used, for CLI banners / MCP\n * responses. Returns a short phrase like \"resumed via claude --resume\",\n * or \"resumed via ACP\", or \"\" when no resume was attempted.\n *\n * Honesty gate (resume-honesty fix): \"resumed via ACP\" is a claim of actual\n * conversation continuity, so it's only returned when the adapter's\n * declared capability backs that claim (`resumable !== false`). An adapter\n * that declared `resumable: false` but still carries an `adapterSessionId`\n * gets an honest degraded label instead of the lie — never silently \"\".\n */\nexport function describeResumePath(prev: RestartCandidate): string {\n if (prev.adapterSlug) {\n const s = RESUME_STRATEGIES[prev.adapterSlug]\n if (s?.spawnArgs && s.storeAs && prev.resumeMetadata?.[s.storeAs]) {\n const sample = s.spawnArgs(\"…\")[0] ?? prev.adapterSlug\n return `resumed via ${sample} --resume`\n }\n }\n if (prev.adapterSlug && prev.adapterSessionId) {\n if (prev.resumable === false) {\n return `fresh — resume not supported by ${prev.adapterSlug}`\n }\n return \"resumed via ACP\"\n }\n return \"\"\n}\n\n/**\n * Shell-style argv tokenizer for descriptors that don't carry `argv`\n * separately (legacy persisted rows predating that field). Same rules\n * as the spawn-dialog tokenizer in the web app: whitespace splits,\n * single + double quotes group.\n */\nexport function tokenizeCommand(s: string): string[] {\n const out: string[] = []\n let buf = \"\"\n let inSingle = false\n let inDouble = false\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]\n if (ch === \"'\" && !inDouble) {\n inSingle = !inSingle\n continue\n }\n if (ch === '\"' && !inSingle) {\n inDouble = !inDouble\n continue\n }\n if (!inSingle && !inDouble && /\\s/.test(ch ?? \"\")) {\n if (buf) {\n out.push(buf)\n buf = \"\"\n }\n continue\n }\n buf += ch\n }\n if (buf) out.push(buf)\n return out\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/tool-presenter.ts","../src/tool-call-record.ts","../src/pr-provenance.ts","../src/transcript-writer.ts","../src/transcript-export.ts","../src/conversation-store.ts","../src/resume-strategies.ts"],"names":["join","resolve","homedir","fs","text","createReadStream","createInterface","exportClaudeCodeSession","discoverHermesSessions","exportHermesSession","discoverCodexSessions","exportCodexSession","discoverOpenCodeSessions","exportOpenCodeSession","discoverMastracodeInprocessSessions","exportMastracodeInprocessSession","discoverPiSessions","exportPiSession"],"mappings":"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","file":"resume-strategies.mjs","sourcesContent":["/**\n * Turns a raw tool-call name + args (and its eventual result) into a short,\n * human-readable line for ring-buffer / CLI / transcript rendering. Without\n * this, every tool call renders as a bare `[tool] view` with no args and no\n * outcome — this module is the one place that knows how to summarize both.\n */\n\nconst SALIENT_ARG_KEYS = [\n \"file_path\",\n \"path\",\n \"filePath\",\n \"file\",\n \"command\",\n \"pattern\",\n \"query\",\n \"q\",\n \"url\",\n \"todos\",\n \"description\",\n \"prompt\",\n] as const\n\nconst MAX_CALL_LENGTH = 120\nconst MAX_RESULT_LENGTH = 160\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction truncate(value: string, max: number): string {\n const oneLine = value.replace(/\\s+/g, \" \").trim()\n return oneLine.length > max ? `${oneLine.slice(0, max - 1)}…` : oneLine\n}\n\nfunction formatArgValue(value: unknown): string {\n if (typeof value === \"string\") return value\n if (Array.isArray(value)) return `${value.length} item${value.length === 1 ? \"\" : \"s\"}`\n if (isRecord(value)) return JSON.stringify(value)\n return String(value)\n}\n\nfunction pickSalientArg(args: Record<string, unknown>): string | null {\n for (const key of SALIENT_ARG_KEYS) {\n const value = args[key]\n if (value !== undefined && value !== null && value !== \"\") {\n return formatArgValue(value)\n }\n }\n return null\n}\n\ntype BespokeFormatter = (args: Record<string, unknown>) => string\n\nfunction subagentSummary(args: Record<string, unknown>): string {\n const description =\n typeof args.description === \"string\"\n ? args.description\n : typeof args.prompt === \"string\"\n ? args.prompt\n : \"subagent\"\n return `↳ subagent: ${truncate(description, MAX_CALL_LENGTH)}`\n}\n\n// Bespoke one-liners for control tools where the generic arg-sniffing\n// below would either miss the point (ScheduleWakeup's payload isn't a\n// file/command/pattern) or just repeat the tool name pointlessly\n// (TodoWrite, ExitPlanMode carry no salient single-value arg).\nconst BESPOKE_TOOLS: Record<string, BespokeFormatter> = {\n schedulewakeup: (args) => {\n const delay = args.delaySeconds ?? args.delay ?? \"?\"\n const reason = typeof args.reason === \"string\" ? args.reason : \"\"\n return reason ? `⏰ wake in ${delay}s — ${reason}` : `⏰ wake in ${delay}s`\n },\n task: subagentSummary,\n agent: subagentSummary,\n todowrite: (args) => {\n const todos = Array.isArray(args.todos) ? args.todos : []\n return `☑ todos (${todos.length})`\n },\n exitplanmode: () => \"📋 plan ready\",\n}\n\n/** A one-line human summary of a tool call, e.g. `read src/foo.ts` or `⏰ wake in 30s — checking CI`. */\nexport function formatToolCall(toolName: string, args: unknown): string {\n const name = toolName || \"tool\"\n const argsRecord = isRecord(args) ? args : {}\n\n const bespoke = BESPOKE_TOOLS[name.toLowerCase()]\n if (bespoke) return bespoke(argsRecord)\n\n const salient = pickSalientArg(argsRecord)\n if (salient !== null) {\n // Some ACP agents (e.g. claude-agent-acp) already bake the salient\n // value into a curated title — \"Read src/foo.ts\" alongside\n // arguments.path === \"src/foo.ts\". Appending it again would render\n // \"Read src/foo.ts src/foo.ts\". Only append when it adds new info.\n if (name.toLowerCase().includes(salient.toLowerCase())) {\n return truncate(name, MAX_CALL_LENGTH)\n }\n return truncate(`${name} ${salient}`, MAX_CALL_LENGTH)\n }\n\n if (Object.keys(argsRecord).length === 0) return name\n\n return truncate(`${name} ${JSON.stringify(args)}`, MAX_CALL_LENGTH)\n}\n\nfunction extractText(value: unknown): string | null {\n if (value == null) return null\n if (typeof value === \"string\") return value\n if (Array.isArray(value)) {\n const parts = value.map(extractText).filter((v): v is string => v != null)\n return parts.length ? parts.join(\"\\n\") : null\n }\n if (isRecord(value)) {\n if (typeof value.text === \"string\") return value.text\n if (typeof value.message === \"string\") return value.message\n if (Array.isArray(value.content)) return extractText(value.content)\n if (typeof value.error === \"string\") return value.error\n if (isRecord(value.error) && typeof value.error.message === \"string\") {\n return value.error.message\n }\n return null\n }\n return null\n}\n\n/**\n * A short outcome line for a completed tool call, or `null` when there's\n * nothing useful to show (e.g. an empty/void result). `toolName` is\n * accepted for parity with `formatToolCall` and future bespoke result\n * formatting, but generic text extraction covers today's cases.\n */\nexport function formatToolResult(\n toolName: string | undefined,\n result: unknown,\n isError: boolean,\n): string | null {\n void toolName\n const text = extractText(result)\n\n if (isError) {\n const message = text ?? (result != null ? JSON.stringify(result) : \"failed\")\n const firstLine = message.split(/\\r?\\n/)[0] ?? message\n return truncate(firstLine, MAX_RESULT_LENGTH)\n }\n\n if (text == null) return null\n const trimmed = text.trim()\n if (!trimmed) return null\n\n const lines = trimmed.split(/\\r?\\n/)\n if (lines.length > 1) {\n const bytes = Buffer.byteLength(trimmed, \"utf8\")\n return `${lines.length} lines, ${bytes}B`\n }\n return truncate(lines[0]!, MAX_RESULT_LENGTH)\n}\n\n/** The stdout sentinel the CI artifact-ledger delivery helper prints when it\n * creates a PR / review / comment — MUST byte-match `ARTIFACT_MARKER` in\n * `scripts/lib/artifact-ledger.mjs` (the runner-side harvester). */\nexport const ARTIFACT_MARKER = \"::agentproto-artifact::\"\n\n/** Ring lines per tool result the marker passthrough will re-emit at most —\n * a delivery tool call creates one artifact, so >1 is already unusual; the\n * cap only bounds a pathological result that echoes markers in a loop. */\nconst MAX_ARTIFACT_MARKER_LINES = 8\n\n/**\n * The `::agentproto-artifact::` marker lines buried in a tool result, if any.\n *\n * The one-line summary {@link formatToolResult} produces is deliberately\n * lossy (\"N lines, XB\") — correct for humans, fatal for the CI artifact\n * ledger: the agentflow delivery helper (`deliver-artifact.mjs`) prints its\n * marker to a tool's stdout precisely so the `agentproto-run` driver can\n * harvest created PR/review/comment ids back out of `agent_output`. This\n * extracts those lines so the ring can carry them verbatim alongside the\n * summary. Returned WITHOUT ANSI styling on purpose: the harvester\n * (`parseArtifactMarkers`) does `indexOf(marker)` then `JSON.parse` of the\n * line's remainder, so a trailing reset code would corrupt the JSON.\n */\nexport function artifactMarkerLines(result: unknown): string[] {\n const text = extractText(result)\n if (text == null || !text.includes(ARTIFACT_MARKER)) return []\n return text\n .split(/\\r?\\n/)\n .filter(line => line.includes(ARTIFACT_MARKER))\n .slice(0, MAX_ARTIFACT_MARKER_LINES)\n .map(line => line.trim())\n}\n","/**\n * ONE normalized shape for a finished tool/command call — the unification\n * target for the two disjoint logs this repo has today: `recordCommand`'s\n * `CommandLogEntry` (command-log.ts, the `command_execute` proxy path) and\n * `transcript-writer.ts`'s per-kind `tool-call`/`tool-result` records (an\n * agent's own in-process Bash/Edit/…). Both writers append a\n * `ToolCallRecord` line (tagged `kind: \"tool-call-record\"` on disk — see\n * tool-call-log.ts) to the SAME per-session `events.jsonl` they already\n * own, so `tool_calls_list` can read either without a new store.\n *\n * Deliberately excludes session-level provenance (`harness`, `origin`,\n * `callerSessionId`): that already lives once on the owning\n * `SessionDescriptor` (see sessions.ts), and duplicating it onto every\n * call-level line would just be a snapshot that can drift. `tool_calls_list`\n * joins it in at read time from the descriptor instead.\n */\n\nexport interface ToolCallRecord {\n /** The session (command or agent-cli) whose events.jsonl this call was\n * written into. */\n sessionId: string\n /** Tool/command name — an MCP tool name for the proxy path\n * (\"command_execute\"), or an ACP tool name for the in-agent path\n * (\"Bash\", \"Read\", \"Edit\", …). */\n tool: string\n /** Shell command string, when this call is shell-shaped. Present for\n * every proxy call; only present in-agent when `extractCommandArgs`\n * recognizes the tool's `arguments` as `{command, args?}` (a Bash-style\n * tool) — every other in-agent tool (Read, Edit, …) legitimately has no\n * shell command, so this stays absent rather than guessing. */\n command?: string\n args?: string[]\n /** Process exit code — only meaningful for the proxy path, which runs a\n * real subprocess. Absent for in-agent calls (ACP has no exit-code\n * concept, only `isError`). */\n exitCode?: number\n isError?: boolean\n durationMs?: number\n /** The PR this call CREATED, when the call was a successful shell-shaped\n * `gh pr create` (detected at write time via `detectShellPrCreate` in\n * pr-provenance.ts, from the command string + the call's result text).\n * This is the exact-attribution source the PR-provenance reconciler\n * prefers over branch→PR guessing: the session whose events.jsonl holds\n * this record IS the session that opened the PR, no matter what branch\n * its cwd sits on by the time the turn ends. Absent for every other\n * call. */\n createdPrUrl?: string\n createdPrNumber?: number\n ts: string\n}\n\n/**\n * Best-effort extraction of a shell-shaped `{command, args}` out of an\n * arbitrary, harness-shaped tool-call `arguments` blob (typed `unknown` at\n * the ACP boundary — see `AgentStreamEvent.arguments` in sessions.ts).\n * Only recognizes the `{command: string, args?: string[]}` shape a\n * Bash-style tool sends; every other tool shape returns `{}` rather than\n * guessing, per AGENTS.md's \"no silent caps\" ethic applied to normalization\n * (don't claim a `command` this didn't actually see).\n */\nexport function extractCommandArgs(input: unknown): { command?: string; args?: string[] } {\n if (!input || typeof input !== \"object\") return {}\n const obj = input as Record<string, unknown>\n const command = typeof obj.command === \"string\" ? obj.command : undefined\n if (command === undefined) return {}\n const argv =\n Array.isArray(obj.args) && obj.args.every(a => typeof a === \"string\")\n ? (obj.args as string[])\n : undefined\n return argv ? { command, args: argv } : { command }\n}\n","/**\n * PR provenance footer — daemon/MCP lane.\n *\n * This is the SAME footer the runner-side agentflow scripts stamp on the\n * CI-PR, review, and local-`gh_open_pr` lanes; `scripts/lib/provenance-\n * footer.mjs` re-exports {@link buildFooter}/{@link MARKER}/{@link fmtTokens}\n * from HERE so there is exactly one format, one marker, one renderer. The\n * only reason this canonical copy lives in `@agentproto/runtime` rather than\n * in `scripts/` is direction of dependency: the daemon is a package and\n * cannot import a loose script, but a script can import a package's built\n * `dist/` (it already does for `computeProvenance`).\n *\n * What the DAEMON lane adds over the runner lanes: the footer is built from\n * a live {@link SessionDescriptor} (the executor agent-cli session that ran\n * `gh pr create`) plus its supervisor/parent session, rather than from a\n * `computeProvenance` join over the worktree. So this file also owns the\n * mapping from a session descriptor to the footer's provenance shape\n * ({@link sessionFooterProvenance}) and the small pure helpers the\n * command_execute stamp path needs ({@link parseGhPrCreate},\n * {@link pickExecutorSession}, {@link appendFooterOnce}).\n *\n * Pure by construction — only `node:path`, no daemon imports, no I/O — so it\n * bundles to a standalone `dist/pr-provenance.mjs` the scripts can import\n * without pulling the rest of the runtime in. Keep it that way. The\n * side-effecting orchestration (spawning `gh`, editing the PR body, recording\n * the opened PR) lives in `pr-provenance-stamp.ts`.\n */\n\nimport { basename } from \"node:path\"\n\n/** Deterministic marker the runner owns — a reliable native-vs-legacy\n * discriminator across every lane (CI-PR, review, local, daemon). */\nexport const MARKER = \"@agentproto-bot\"\n\nexport const fmtTokens = (n: unknown): string | null => {\n if (typeof n !== \"number\" || !Number.isFinite(n)) return null\n return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n)\n}\n\n/** The footer's provenance shape — field names are the renderer's, not the\n * session registry's (see {@link sessionFooterProvenance} for the mapping). */\nexport interface FooterProvenance {\n sessionId?: string\n label?: string\n /** Adapter / harness slug that ran (\"claude-code\", \"codex\", …). */\n adapter?: string\n model?: string\n /** Bound auth-profile IDENTITY — a label or ref, NEVER the credential. */\n authProfile?: string\n sandboxId?: string\n /** Supervisor / parent session that spawned the executor. */\n parentSessionId?: string\n tokensIn?: number\n tokensOut?: number\n costUsd?: number\n /** \"adapter\" | \"local\" | \"daemon\" — drives host/cwd vs run-link rendering. */\n source?: string\n host?: string\n cwd?: string\n /** The session's registered workspace slug (`SessionDescriptor.workspaceSlug`,\n * e.g. \"ts\", \"default\"). Rendered alongside `cwd`'s leaf directory name so\n * the footer identifies WHICH workspace ran the command, not just an\n * arbitrary trailing path segment — a bare `basename(cwd)` reads as\n * meaningless (or actively misleading) when the session's cwd is a\n * workspace root rather than a per-branch worktree. */\n workspaceSlug?: string\n}\n\n/**\n * Render the footer's `cwd` value. A bare `basename(cwd)` collapses to a\n * meaningless (or actively misleading) fragment whenever the session's cwd IS\n * the workspace root rather than a per-branch worktree dir — e.g. a checkout\n * literally named `ts` renders as the opaque `cwd \\`ts\\`` with no indication\n * that's a workspace name, not a worktree/branch leaf. Prefixing the\n * registered workspace slug disambiguates it, and is dropped when it's\n * identical to the leaf (the common per-worktree case) so the common case\n * stays exactly as compact as before.\n */\nfunction cwdLabel(cwd: string, workspaceSlug?: string): string {\n const leaf = basename(cwd)\n if (!workspaceSlug || workspaceSlug === leaf) return workspaceSlug ?? leaf\n return `${workspaceSlug}/${leaf}`\n}\n\nexport interface BuildFooterInput {\n prov?: FooterProvenance\n authMode?: string\n runId?: string\n runUrl?: string\n sha?: string\n kind?: string\n}\n\nexport const buildFooter = ({\n prov,\n authMode,\n runId,\n runUrl,\n sha,\n kind = \"review\",\n}: BuildFooterInput): string => {\n const parts = [`🤖 **${MARKER}** — ${kind}`]\n if (prov?.sessionId) {\n parts.push(`session \\`${prov.sessionId}\\`${prov.label ? ` (\\`${prov.label}\\`)` : \"\"}`)\n }\n // Engine label: \"adapter / authMode\" when an adapter ran; \"legacy fallback\n // (authMode)\" when no agent session exists at all (the API-key fallback path);\n // bare authMode only if a session ran without a resolved adapter slug.\n if (prov?.adapter) parts.push([prov.adapter, authMode].filter(Boolean).join(\" / \"))\n else if (!prov?.sessionId) parts.push(`legacy fallback${authMode ? ` (${authMode})` : \"\"}`)\n else if (authMode) parts.push(authMode)\n // Bound auth profile identity (the \"wallet\") — daemon lane; NEVER the secret.\n if (prov?.authProfile) parts.push(`auth-profile \\`${prov.authProfile}\\``)\n if (prov?.model) parts.push(`model \\`${prov.model}\\``)\n if (prov?.sandboxId) parts.push(`e2b \\`${prov.sandboxId}\\``)\n if (prov?.parentSessionId) parts.push(`supervisor \\`${prov.parentSessionId}\\``)\n const tin = fmtTokens(prov?.tokensIn)\n const tout = fmtTokens(prov?.tokensOut)\n if (tin || tout) parts.push(`${tin ?? \"?\"} in / ${tout ?? \"?\"} out`)\n if (typeof prov?.costUsd === \"number\") {\n parts.push(`$${prov.costUsd.toFixed(4)}${prov.source && prov.source !== \"adapter\" ? ` (${prov.source})` : \"\"}`)\n }\n const showLocalHostCwd = prov?.source === \"local\" || prov?.source === \"daemon\" || !runId\n if (runId && !showLocalHostCwd) parts.push(`run [${runId}](${runUrl})`)\n if (showLocalHostCwd) {\n if (prov?.host) parts.push(`host \\`${prov.host}\\``)\n if (prov?.cwd) parts.push(`cwd \\`${cwdLabel(prov.cwd, prov.workspaceSlug)}\\``)\n }\n if (sha) parts.push(`sha \\`${sha}\\``)\n return `\\n\\n---\\n<sub>${parts.join(\" · \")}</sub>`\n}\n\n/** Structural subset of `SessionDescriptor` the footer needs. The runtime's\n * full descriptor satisfies this; keeping it structural is what lets this\n * module stay free of a `./sessions.js` import (and thus standalone). */\nexport interface FooterSession {\n id: string\n kind?: string\n status?: string\n startedAt?: string\n label?: string\n cwd?: string\n workspaceSlug?: string\n adapterSlug?: string\n harness?: string\n model?: string\n parentSessionId?: string\n costUsd?: number\n tokensIn?: number\n tokensOut?: number\n auth?: { mode?: string }\n accessProfile?: { profileRef: string; label?: string }\n}\n\nexport interface SessionFooterOptions {\n /** The supervisor/parent session descriptor, when resolvable. */\n supervisor?: { id: string } | null\n host?: string\n /** Provenance source tag; defaults to \"daemon\". */\n source?: string\n}\n\n/**\n * Map a live executor session (+ its supervisor) onto the footer's provenance\n * shape and the `authMode` the renderer takes separately. The adapter is the\n * canonical harness slug, falling back to `adapterSlug`. The bound auth\n * profile is the profile's human label (or its ref), never the credential.\n */\nexport function sessionFooterProvenance(\n session: FooterSession,\n options: SessionFooterOptions = {},\n): { prov: FooterProvenance; authMode: string | undefined } {\n const prov: FooterProvenance = {\n sessionId: session.id,\n label: session.label,\n adapter: session.harness ?? session.adapterSlug,\n model: session.model,\n authProfile: session.accessProfile?.label ?? session.accessProfile?.profileRef,\n parentSessionId: options.supervisor?.id,\n costUsd: session.costUsd,\n tokensIn: session.tokensIn,\n tokensOut: session.tokensOut,\n source: options.source ?? \"daemon\",\n host: options.host,\n cwd: session.cwd,\n workspaceSlug: session.workspaceSlug,\n }\n return { prov, authMode: session.auth?.mode }\n}\n\n/** Build the daemon-lane PR footer for one executor session directly. */\nexport function buildSessionPrFooter(\n session: FooterSession,\n options: SessionFooterOptions & { sha?: string } = {},\n): string {\n const { prov, authMode } = sessionFooterProvenance(session, options)\n return buildFooter({ prov, authMode, sha: options.sha, kind: \"PR\" })\n}\n\n/**\n * Append the footer to a PR body exactly once. Idempotent by the marker: a\n * body that already carries a `@agentproto-bot` footer is returned unchanged,\n * so a retried stamp (network reply lost after the edit landed) never stacks\n * a second footer.\n */\nexport function appendFooterOnce(body: string, footer: string): string {\n if (hasProvenanceFooter(body)) return body\n return `${body}${footer}`\n}\n\n/**\n * Whether a PR/review body already carries a RENDERED provenance footer — the\n * `<sub>…@agentproto-bot…</sub>` line {@link buildFooter} emits — as opposed\n * to merely MENTIONING the marker in prose. The distinction matters: a PR\n * whose description discusses the provenance machinery itself (they exist —\n * #999 explains a footer bug and quotes the marker) would otherwise read as\n * \"already stamped\" forever and never receive its real footer.\n */\nexport function hasProvenanceFooter(body: string): boolean {\n return new RegExp(`<sub>[^\\\\n]*${MARKER}`).test(body)\n}\n\n/**\n * Recognise a successful `gh pr create` from its argv + stdout and pull the\n * created PR's URL + number out. Returns null for anything that isn't a\n * PR-creating `gh` invocation, or a create whose stdout carried no PR URL.\n *\n * `gh pr create` prints the PR URL on its own line (often the last line,\n * after any advisory notices) — we take the LAST `…/pull/<n>` match so a\n * \"Warning: …/pull/…\" style notice can't shadow the real one.\n */\nexport function parseGhPrCreate(\n command: string,\n args: readonly string[],\n stdout: string,\n): { url: string; number: number } | null {\n if (basename(command) !== \"gh\") return null\n // Skip global flags; the first two non-flag tokens must be `pr` then `create`.\n const positionals = args.filter(a => !a.startsWith(\"-\"))\n if (positionals[0] !== \"pr\" || positionals[1] !== \"create\") return null\n const re = /https?:\\/\\/\\S+?\\/pull\\/(\\d+)/g\n let match: RegExpExecArray | null\n let last: { url: string; number: number } | null = null\n while ((match = re.exec(stdout)) !== null) {\n last = { url: match[0], number: Number(match[1]) }\n }\n return last\n}\n\n/**\n * String-form counterpart of {@link parseGhPrCreate} for the in-agent tool\n * lane: an ACP harness's Bash-style tool reports ONE shell string (possibly\n * compound — `git push && gh pr create … | tail -1`), not an argv, so the\n * argv parser above can't see it. Detects \"this call created a PR\" from the\n * command string plus the call's recorded result text, and returns the\n * created PR (LAST `…/pull/<n>` match in the result, same shadowing rule as\n * {@link parseGhPrCreate} — `gh pr create` prints its URL after any notices).\n *\n * Quoted spans are stripped before matching so a command that merely\n * MENTIONS the phrase — `grep \"gh pr create\" src/` over a result that quotes\n * a PR url — can never read as a create. Best-effort by design: the caller\n * additionally gates on the call's own `isError` (a failed create whose\n * stderr cites an existing PR must not attribute that PR here).\n */\nexport function detectShellPrCreate(\n command: string | undefined,\n resultText: string | undefined,\n): { url: string; number: number } | null {\n if (!command || !resultText) return null\n const unquoted = command.replace(/'[^']*'/g, \" \").replace(/\"(?:[^\"\\\\]|\\\\.)*\"/g, \" \")\n if (!/(^|[\\s;&|({])gh\\s+pr\\s+create(\\s|$)/.test(unquoted)) return null\n const re = /https?:\\/\\/\\S+?\\/pull\\/(\\d+)/g\n let match: RegExpExecArray | null\n let last: { url: string; number: number } | null = null\n while ((match = re.exec(resultText)) !== null) {\n last = { url: match[0], number: Number(match[1]) }\n }\n return last\n}\n\n/** `session.cwd == cwd || one contains the other` — the executor's cwd is\n * usually the worktree root while the command may run in a subdir (or vice\n * versa), so containment is checked in both directions. */\nfunction cwdRelated(sessionCwd: string, cwd: string): boolean {\n if (sessionCwd === cwd) return true\n const sep = \"/\"\n return cwd.startsWith(sessionCwd + sep) || sessionCwd.startsWith(cwd + sep)\n}\n\n/**\n * Best-effort attribution of a `command_execute` run to the executor agent\n * session that most likely issued it: the newest agent-cli session whose cwd\n * is related to the command's cwd, preferring a still-alive one. Returns\n * undefined when no agent-cli session matches (e.g. a bare shell opened the\n * PR) — the caller then skips stamping rather than emit a misleading \"legacy\n * fallback\" footer.\n */\nexport function pickExecutorSession<T extends FooterSession>(\n sessions: readonly T[],\n cwd: string,\n): T | undefined {\n const candidates = sessions.filter(\n s => s.kind === \"agent-cli\" && typeof s.cwd === \"string\" && cwdRelated(s.cwd, cwd),\n )\n if (candidates.length === 0) return undefined\n const alive = (s: T) => s.status === \"running\" || s.status === \"starting\"\n const byRecency = (a: T, b: T) => (b.startedAt ?? \"\").localeCompare(a.startedAt ?? \"\")\n const live = candidates.filter(alive).sort(byRecency)\n if (live.length > 0) return live[0]\n return [...candidates].sort(byRecency)[0]\n}\n","/**\n * Per-session structured event capture — one append-only JSONL file per\n * agent-cli session, written at the same tap point where `projectEvent`\n * (sessions.ts) flattens `StreamEvent`s into the ANSI ring buffer, but\n * BEFORE that flattening happens. Gives agentproto the Claude-Code\n * property: a daemon-owned structured transcript that survives a daemon\n * restart (the ring buffer doesn't) and that any frontend can render,\n * not just the two adapters `transcript-export.ts` knows how to re-read\n * from their own native stores.\n *\n * File layout: `~/.agentproto/sessions/<sessionId>/events.jsonl`, one\n * JSON object per line: `{seq, ts, kind, ...fields}`.\n *\n * PTY (`terminal`) and `command` sessions never call into this writer —\n * they have no structured event source (see report-transcript-\n * architecture.md finding C.17), so this module is only ever driven from\n * `agent-cli` sessions' `runAgentTurn`.\n */\n\nimport { createWriteStream, mkdirSync, readFileSync, type WriteStream } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { join } from \"node:path\"\nimport type { SessionObserver } from \"./session-observer.js\"\nimport type { AgentStreamEvent } from \"./sessions.js\"\nimport { extractCommandArgs } from \"./tool-call-record.js\"\nimport { detectShellPrCreate } from \"./pr-provenance.js\"\nimport type { SessionUsage } from \"./usage.js\"\n\n/** Debounce window for flushing a buffered text-delta/thought fragment\n * that hasn't hit a newline yet. Keeps a long no-newline stream from\n * sitting in memory indefinitely without also spamming one record per\n * token — mirrors the \"coalesce, don't spam\" rule `projectEvent`\n * already applies to the ring buffer, just with a disk-durability\n * angle added. */\nconst DEBOUNCE_MS = 250\n\n/** `baseDir` defaults to `~/.agentproto/sessions` — overridable so tests\n * (and a future `--home` style daemon flag) can redirect writes away from\n * the real home directory instead of mocking `node:os`. */\nexport function sessionTranscriptDir(sessionId: string, baseDir?: string): string {\n return join(baseDir ?? join(homedir(), \".agentproto\", \"sessions\"), sessionId)\n}\n\nexport function sessionEventsPath(sessionId: string, baseDir?: string): string {\n return join(sessionTranscriptDir(sessionId, baseDir), \"events.jsonl\")\n}\n\n/** Highest `seq` already durably on disk for a session, or 0 when the file\n * is absent/empty. A fresh writer instance (e.g. after a daemon restart)\n * opens the existing events.jsonl in append mode, so its first record must\n * continue from this cursor rather than restarting at 1 — otherwise a\n * restart mid-session emits duplicate seq numbers and any `since`-based\n * reader (GET /sessions/:id/events) silently drops the post-restart tail.\n * Records are written in ascending `seq`, so the max is on the last valid\n * line, but a truncated/partial final line is tolerated by scanning every\n * parseable line rather than trusting the tail. */\nfunction highestSeqOnDisk(path: string): number {\n let raw: string\n try {\n raw = readFileSync(path, \"utf8\")\n } catch {\n // ENOENT (fresh session) or any read error — start from 0.\n return 0\n }\n let max = 0\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim()\n if (!trimmed) continue\n try {\n const rec = JSON.parse(trimmed) as { seq?: unknown }\n if (typeof rec.seq === \"number\" && rec.seq > max) max = rec.seq\n } catch {\n // Ignore a malformed/partial line (e.g. a torn final write).\n }\n }\n return max\n}\n\nexport interface TranscriptWriter extends SessionObserver {\n /** Record the outgoing message for a new turn. Not an ACP `StreamEvent`\n * kind (ACP's own \"agent-prompt\" means the agent asking the human a\n * question, the opposite direction) — recorded under its own\n * \"user-prompt\" kind so turns stay reconstructable without overloading\n * that name. `opts.source` (provenance, e.g. `agent:<sessionId>` for a\n * supervisor-injected prompt) rides onto the record's `source` field.\n *\n * `opts.system`, when present, is the daemon-composed SYSTEM slice of\n * `message` (role disposition + AGENTS.md + lineage — the preamble the\n * daemon prepended to a spawned child's prompt, which the ADAPTER still\n * receives as one string). It is recorded as its own `system-prompt`\n * record AHEAD of the `user-prompt`, and that user-prompt carries only\n * the CALLER's own ask (the preamble stripped) — so viewers can fold\n * the synthesized text instead of showing it as a user bubble. Recording-\n * only; never alters what the adapter receives or how the turn runs. */\n recordPrompt(\n sessionId: string,\n message: unknown,\n opts?: { source?: string; system?: string }\n ): void\n /** Record one structured stream event, ahead of `projectEvent`'s\n * flattening. Coalesces consecutive text-delta/thought chunks the same\n * way the ring buffer does. */\n recordEvent(sessionId: string, evt: AgentStreamEvent): void\n /** Record a durable `usage_snapshot` recap at a turn boundary or on\n * session exit — the cumulative cost/token/context view resolved by\n * `deriveSessionUsage`. Distinct from the high-frequency `usage_update`\n * stream: this is the aggregable turn-boundary durable record, so a\n * daemon restart doesn't lose the session's accumulated usage. */\n recordUsageSnapshot(sessionId: string, usage: SessionUsage): void\n /** Flush buffers and close the session's append stream. Safe to call\n * more than once (subsequent calls are no-ops) and safe to call for a\n * session that never wrote anything (also a no-op). Production call\n * sites treat this as fire-and-forget (same as `agentSession.close()`);\n * the returned promise exists so tests can await the on-disk flush. */\n close(sessionId: string): Promise<void>\n /** Close every open session stream — called from the registry's\n * synchronous shutdown path (fire-and-forget there too). */\n closeAll(): Promise<void>\n /** Subscribe to every record as it's written for one session — the\n * live-push half of `GET /sessions/:id/events/stream`'s replay-then-\n * subscribe handoff (http-server.ts). Delivers the exact object shape\n * written to disk (`{seq, ts, kind, ...}`, pre-JSON.stringify), so a\n * consumer already reducing the poll route's `events` array can reduce\n * this stream with identical logic. No backfill here — history is a\n * file read the caller does itself; this only wires the live tap.\n * Notification happens synchronously, in the same call that appends the\n * record, so a caller that subscribes before doing its own disk read is\n * guaranteed to observe (via this callback) every record from that\n * point on, even ones the read might otherwise race. Returns an\n * unsubscribe fn; safe to call more than once. */\n subscribe(sessionId: string, onRecord: (record: Record<string, unknown>) => void): () => void\n}\n\ninterface WriterState {\n stream: WriteStream\n seq: number\n textBuf: string\n thoughtBuf: string\n textDebounce: ReturnType<typeof setTimeout> | null\n thoughtDebounce: ReturnType<typeof setTimeout> | null\n /**\n * Latest un-written tool-call ENRICHMENT per toolCallId — the same\n * coalescing textBuf/thoughtBuf do, for the same reason.\n *\n * An ACP agent streams a tool's `rawInput` as the model types it, so one\n * call arrives as a run of growing updates:\n * {} → {adapter} → {adapter,cwd} → {adapter,cwd,role} → {…,prompt} → …\n * Writing each would put six records on disk for one `agent_start`, and\n * only the last is true. They're superseding snapshots, not increments:\n * keep the newest and write it once, when something else needs ordering\n * around it (see flushBuffers).\n */\n toolUpdates: Map<string, Record<string, unknown>>\n /**\n * Latest known {toolName, arguments} + announce time per in-flight\n * toolCallId, kept across BOTH the announcement and any enrichment\n * updates (not just the held/coalesced ones above) — the \"tool-result\"\n * handler consumes this to emit ONE normalized `tool-call-record` line\n * (see tool-call-record.ts) per finished call, since a bare \"tool-result\"\n * event carries neither the tool's name nor its input.\n */\n toolCallMeta: Map<string, { toolName: string; arguments: unknown; startedAt: number }>\n}\n\nexport function createTranscriptWriter(opts?: { baseDir?: string }): TranscriptWriter {\n const baseDir = opts?.baseDir\n const states = new Map<string, WriterState>()\n const listeners = new Map<string, Set<(record: Record<string, unknown>) => void>>()\n\n const getState = (sessionId: string): WriterState => {\n const existing = states.get(sessionId)\n if (existing) return existing\n mkdirSync(sessionTranscriptDir(sessionId, baseDir), { recursive: true })\n const eventsPath = sessionEventsPath(sessionId, baseDir)\n // Resume the seq counter from what's already durable so a restart\n // mid-session keeps events.jsonl monotonic in append mode.\n const resumeSeq = highestSeqOnDisk(eventsPath)\n const stream = createWriteStream(eventsPath, { flags: \"a\" })\n stream.on(\"error\", err => {\n console.warn(`[transcript-writer] session ${sessionId}: ${err.message}`)\n })\n const state: WriterState = {\n stream,\n seq: resumeSeq,\n textBuf: \"\",\n thoughtBuf: \"\",\n textDebounce: null,\n thoughtDebounce: null,\n toolUpdates: new Map(),\n toolCallMeta: new Map(),\n }\n states.set(sessionId, state)\n return state\n }\n\n const writeRecord = (\n sessionId: string,\n state: WriterState,\n record: Record<string, unknown>\n ): void => {\n state.seq += 1\n const full = { seq: state.seq, ts: new Date().toISOString(), ...record }\n state.stream.write(JSON.stringify(full) + \"\\n\")\n const subs = listeners.get(sessionId)\n if (subs) {\n for (const onRecord of subs) onRecord(full)\n }\n }\n\n const flushTextBuf = (sessionId: string, state: WriterState): void => {\n if (state.textDebounce) {\n clearTimeout(state.textDebounce)\n state.textDebounce = null\n }\n if (!state.textBuf) return\n const text = state.textBuf\n state.textBuf = \"\"\n writeRecord(sessionId, state, { kind: \"text-delta\", sessionId, text })\n }\n\n const flushThoughtBuf = (sessionId: string, state: WriterState): void => {\n if (state.thoughtDebounce) {\n clearTimeout(state.thoughtDebounce)\n state.thoughtDebounce = null\n }\n if (!state.thoughtBuf) return\n const text = state.thoughtBuf\n state.thoughtBuf = \"\"\n writeRecord(sessionId, state, { kind: \"thought\", sessionId, text })\n }\n\n /** Write the newest held enrichment for each in-flight tool call. */\n const flushToolUpdates = (sessionId: string, state: WriterState): void => {\n if (state.toolUpdates.size === 0) return\n const held = [...state.toolUpdates.values()]\n state.toolUpdates.clear()\n for (const record of held) writeRecord(sessionId, state, record)\n }\n\n /** Flush every coalescing buffer as FINAL (non-partial) records — called\n * before any other event so on-disk order matches wall-clock order even\n * when a partial line, or a still-growing tool input, was still held. */\n const flushBuffers = (sessionId: string, state: WriterState): void => {\n flushThoughtBuf(sessionId, state)\n flushTextBuf(sessionId, state)\n flushToolUpdates(sessionId, state)\n }\n\n const scheduleTextDebounce = (sessionId: string, state: WriterState): void => {\n if (state.textDebounce) clearTimeout(state.textDebounce)\n state.textDebounce = setTimeout(() => {\n state.textDebounce = null\n if (!state.textBuf) return\n const text = state.textBuf\n state.textBuf = \"\"\n writeRecord(sessionId, state, { kind: \"text-delta\", sessionId, text, partial: true })\n }, DEBOUNCE_MS)\n }\n\n const scheduleThoughtDebounce = (sessionId: string, state: WriterState): void => {\n if (state.thoughtDebounce) clearTimeout(state.thoughtDebounce)\n state.thoughtDebounce = setTimeout(() => {\n state.thoughtDebounce = null\n if (!state.thoughtBuf) return\n const text = state.thoughtBuf\n state.thoughtBuf = \"\"\n writeRecord(sessionId, state, { kind: \"thought\", sessionId, text, partial: true })\n }, DEBOUNCE_MS)\n }\n\n return {\n recordPrompt(sessionId, message, opts) {\n const state = getState(sessionId)\n flushBuffers(sessionId, state)\n const text = typeof message === \"string\" ? message : JSON.stringify(message)\n // The daemon-composed SYSTEM slice of a spawned child's initial\n // prompt is recorded apart from the caller's ask. The user-prompt\n // text is the composed string with that preamble stripped (the\n // preamble was prepended verbatim at composition, joined by \"\\n\\n\").\n if (opts?.system) {\n writeRecord(sessionId, state, { kind: \"system-prompt\", sessionId, text: opts.system })\n }\n // Strip the system preamble off the front of `text` to get the\n // caller's own ask. Guarded by an explicit prefix check (not just a\n // length comparison) so a future change to the composition format\n // (session-spawn.ts's `composedPreamble`/`effectivePrompt` join) can't\n // silently slice the wrong bytes here — if the invariant doesn't\n // hold, fall back to recording the FULL text rather than producing\n // corrupted output.\n let userText = text\n if (opts?.system) {\n if (text.startsWith(opts.system)) {\n userText = text.slice(opts.system.length).replace(/^\\n\\n/, \"\")\n } else {\n console.warn(\n `[transcript-writer] recordPrompt: system preamble is not a prefix of the composed ` +\n `prompt for session ${sessionId} — composition invariant violated (see ` +\n `session-spawn.ts's composedPreamble), recording the full text as user-prompt ` +\n `instead of risking a bad slice.`,\n )\n }\n }\n writeRecord(sessionId, state, {\n kind: \"user-prompt\",\n sessionId,\n text: userText,\n ...(opts?.source ? { source: opts.source } : {}),\n })\n },\n recordEvent(sessionId, evt) {\n const state = getState(sessionId)\n switch (evt.kind) {\n case \"text-delta\": {\n if (!evt.text) break\n const combined = state.textBuf + evt.text\n const lines = combined.split(/\\r?\\n/)\n state.textBuf = lines.pop() ?? \"\"\n // `split` consumes each line's terminator — reappend it so the\n // on-disk record stays byte-for-byte reconstructable (a blank\n // line becomes \"\\n\" rather than a lossy \"\").\n for (const line of lines) {\n writeRecord(sessionId, state, { kind: \"text-delta\", sessionId, text: `${line}\\n` })\n }\n if (state.textBuf) scheduleTextDebounce(sessionId, state)\n break\n }\n case \"thought\": {\n if (!evt.text) break\n const combined = state.thoughtBuf + evt.text\n const lines = combined.split(/\\r?\\n/)\n state.thoughtBuf = lines.pop() ?? \"\"\n for (const line of lines) {\n writeRecord(sessionId, state, { kind: \"thought\", sessionId, text: `${line}\\n` })\n }\n if (state.thoughtBuf) scheduleThoughtDebounce(sessionId, state)\n break\n }\n case \"tool-call\": {\n // Remember the latest name/input for this call regardless of\n // whether this frame is an announcement or an enrichment — the\n // eventual \"tool-result\" needs both and carries neither itself.\n // An enrichment's `toolName` is `\"\"` when the update carried no\n // title (see toolCallEnrichment in @agentproto/acp); keep the\n // prior name in that case rather than overwriting it with blank.\n if (evt.toolCallId) {\n const existing = state.toolCallMeta.get(evt.toolCallId)\n state.toolCallMeta.set(evt.toolCallId, {\n toolName: evt.toolName || existing?.toolName || \"\",\n arguments: evt.arguments !== undefined ? evt.arguments : existing?.arguments,\n startedAt: existing?.startedAt ?? Date.now(),\n })\n }\n const record = {\n kind: \"tool-call\",\n sessionId,\n toolCallId: evt.toolCallId,\n toolName: evt.toolName,\n arguments: evt.arguments,\n // Carried through so a replay can tell an ENRICHMENT of an\n // announced call from a genuine second call. Readers merge by\n // toolCallId either way, but a record that silently drops the\n // distinction can't be reasoned about after the fact.\n ...(evt.isUpdate ? { isUpdate: true } : {}),\n }\n // An enrichment is a superseding SNAPSHOT of the call's input, and\n // the agent emits one per token as the model types it. Hold the\n // newest instead of writing all of them — flushBuffers puts it on\n // disk the moment anything else needs ordering around it (the\n // tool-result, the next call, a text delta, turn-end). Deliberately\n // no flushBuffers here: that's what lets consecutive updates for the\n // same call collapse into one record.\n if (evt.isUpdate && evt.toolCallId) {\n state.toolUpdates.set(evt.toolCallId, record)\n break\n }\n // The announcement is written at once — it's what makes the step\n // appear, and a pending row the user can see is the whole point.\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, record)\n break\n }\n case \"tool-result\": {\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"tool-result\",\n sessionId,\n toolCallId: evt.toolCallId,\n result: evt.result,\n isError: evt.isError ?? false,\n })\n // Normalized ToolCallRecord (see tool-call-record.ts) — the same\n // shape the command_execute proxy path writes via\n // `writeToolCallRecord`, so `tool_calls_list` reads one unified\n // log regardless of which path produced the call.\n const meta = evt.toolCallId ? state.toolCallMeta.get(evt.toolCallId) : undefined\n if (evt.toolCallId) state.toolCallMeta.delete(evt.toolCallId)\n const { command, args } = extractCommandArgs(meta?.arguments)\n // Exact PR-creation provenance, captured at the only moment both\n // halves exist together (command + result text) — see the\n // `createdPrUrl` field's doc in tool-call-record.ts. Some harnesses\n // surface the shell string as the tool NAME rather than in\n // arguments, so fall back to that.\n const createdPr =\n (evt.isError ?? false)\n ? null\n : detectShellPrCreate(\n command ?? meta?.toolName,\n typeof evt.result === \"string\" ? evt.result : undefined,\n )\n writeRecord(sessionId, state, {\n kind: \"tool-call-record\",\n sessionId,\n tool: meta?.toolName || \"unknown\",\n ...(command !== undefined ? { command } : {}),\n ...(args !== undefined ? { args } : {}),\n isError: evt.isError ?? false,\n ...(meta ? { durationMs: Date.now() - meta.startedAt } : {}),\n ...(createdPr ? { createdPrUrl: createdPr.url, createdPrNumber: createdPr.number } : {}),\n })\n break\n }\n case \"agent-prompt\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"agent-prompt\",\n sessionId,\n toolCallId: evt.toolCallId,\n options: evt.options,\n })\n break\n // Durable counterpart to \"agent-prompt\" — recorded when\n // `respondPermission` (or a dying session's cancel-in-flight sweep)\n // resolves the ask, keyed by the same `toolCallId` so a reader can\n // tell an answered request from a still-pending one without relying\n // on the in-memory pending-permissions map (see sessions.ts's\n // `resolvePendingPermission` / `cancelPendingPermissionsForSession`).\n case \"permission-resolved\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"permission-resolved\",\n sessionId,\n toolCallId: evt.toolCallId,\n decision: evt.decision,\n ...(evt.optionId ? { optionId: evt.optionId } : {}),\n })\n break\n case \"turn-end\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, { kind: \"turn-end\", sessionId, reason: evt.reason })\n break\n case \"notice\":\n // A daemon-side system notice (not agent output) — e.g. the\n // interrupted-turn banner written on resume of a session that died\n // mid-turn under a daemon restart. Durable in events.jsonl so the\n // warning survives beyond the in-memory ring buffer; readers render\n // it as a system message (see transcript-export's \"notice\" case).\n if (!evt.text) break\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, { kind: \"notice\", sessionId, text: evt.text })\n break\n case \"error\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, { kind: \"error\", sessionId, error: evt.error })\n break\n case \"plan\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"plan\",\n sessionId,\n ...(evt.title ? { title: evt.title } : {}),\n entries: evt.entries ?? [],\n })\n break\n case \"usage_update\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"usage_update\",\n sessionId,\n size: evt.size,\n used: evt.used,\n ...(evt.cost ? { cost: evt.cost } : {}),\n // Persist cumulative token counts when the adapter reports them\n // (claude-code over ACP, hermes via its state.db reader,\n // mastracode via its native usage_update) so the transcript can\n // price/aggregate a session even without a `cost` block.\n ...(evt.tokensIn !== undefined ? { tokensIn: evt.tokensIn } : {}),\n ...(evt.tokensOut !== undefined ? { tokensOut: evt.tokensOut } : {}),\n })\n break\n case \"available-commands\":\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"available-commands\",\n sessionId,\n commands: evt.commands ?? [],\n })\n break\n default:\n // Unknown kind — drop, same as `projectEvent`'s implicit\n // no-op for anything it doesn't switch on.\n break\n }\n },\n recordUsageSnapshot(sessionId, usage) {\n const state = getState(sessionId)\n // Order after any buffered text/thought so on-disk order matches\n // wall-clock order.\n flushBuffers(sessionId, state)\n writeRecord(sessionId, state, {\n kind: \"usage_snapshot\",\n sessionId,\n // Omit absent fields so a missing value never reads as a measured 0.\n ...(usage.model !== undefined ? { model: usage.model } : {}),\n ...(usage.costUsd !== undefined ? { costUsd: usage.costUsd } : {}),\n ...(usage.tokensIn !== undefined ? { tokensIn: usage.tokensIn } : {}),\n ...(usage.tokensOut !== undefined ? { tokensOut: usage.tokensOut } : {}),\n ...(usage.contextSize !== undefined ? { contextSize: usage.contextSize } : {}),\n ...(usage.contextUsed !== undefined ? { contextUsed: usage.contextUsed } : {}),\n source: usage.source,\n })\n },\n close(sessionId) {\n const state = states.get(sessionId)\n if (!state) return Promise.resolve()\n flushBuffers(sessionId, state)\n states.delete(sessionId)\n return new Promise<void>(resolve => {\n state.stream.end(() => resolve())\n })\n },\n closeAll() {\n const closings: Promise<void>[] = []\n for (const sessionId of Array.from(states.keys())) {\n const state = states.get(sessionId)\n if (!state) continue\n flushBuffers(sessionId, state)\n closings.push(new Promise<void>(resolve => state.stream.end(() => resolve())))\n }\n states.clear()\n return Promise.all(closings).then(() => undefined)\n },\n subscribe(sessionId, onRecord) {\n let subs = listeners.get(sessionId)\n if (!subs) {\n subs = new Set()\n listeners.set(sessionId, subs)\n }\n subs.add(onRecord)\n return () => {\n const current = listeners.get(sessionId)\n if (!current) return\n current.delete(onRecord)\n if (current.size === 0) listeners.delete(sessionId)\n }\n },\n }\n}\n","/**\n * Export a clean, readable transcript, dispatched between two kinds of\n * source:\n *\n * native — the adapter's OWN persistence, re-read after the fact:\n * claude-code — ~/.claude/projects/<cwd-encoded>/<sessionId>.jsonl\n * hermes — ~/.hermes/state.db via node:sqlite (read-only)\n * codex — $CODEX_HOME/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl\n * opencode — ~/.local/share/opencode/opencode.db via node:sqlite\n * mastracode-inprocess — ~/.agentproto/mastracode-inprocess/storage.db (Mastra libsql)\n * pi — ~/.pi/agent/sessions/<cwd-slug>/<ts>_<uuid>.jsonl\n * daemon — agentproto's own capture, `~/.agentproto/sessions/<id>/events.jsonl`\n * (written by transcript-writer.ts at the same point `projectEvent`\n * flattens events into the ANSI ring buffer, ahead of that flattening).\n * Available for ANY agent-cli session (acp or print protocol), not just\n * the two adapters with a native store.\n *\n * `source: \"auto\"` (the default) tries native first and falls back to\n * daemon events when there's no native strategy or its store can't be\n * read; `\"native\"` / `\"daemon\"` force one and surface its own error.\n *\n * Output: Markdown (default) or JSON, built from a shared ExportedSession\n * model so every source produces identical rendering logic.\n */\n\nimport { createReadStream, promises as fs, type Dirent } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { join } from \"node:path\"\nimport { createInterface } from \"node:readline\"\nimport type { SessionDescriptor, SessionsRegistry } from \"./sessions.js\"\nimport { formatToolCall } from \"./tool-presenter.js\"\nimport { sessionEventsPath } from \"./transcript-writer.js\"\nimport { claudeCodeProjectDir } from \"./conversation-store.js\"\nimport type { ConversationCandidate } from \"./conversation-store.js\"\n\n// ── Common model ──────────────────────────────────────────────────────\n\nexport interface ExportedMessage {\n role: \"user\" | \"assistant\" | \"tool\" | \"system\"\n text?: string\n reasoning?: string\n toolName?: string\n toolCalls?: { name: string; args: string }[]\n ts?: number\n}\n\nexport interface ExportedSessionMeta {\n title?: string\n model?: string\n startedAt?: string\n endedAt?: string\n messageCount?: number\n toolCallCount?: number\n tokens?: {\n input?: number\n output?: number\n cacheRead?: number\n cacheWrite?: number\n reasoning?: number\n contextSize?: number\n contextUsed?: number\n }\n costUsd?: number\n source?: string\n /** Provenance carried over from the session descriptor's own\n * `origin`/`callerSessionId` (see sessions.ts) — distinct from `source`,\n * which names the EXPORTER that produced this payload (e.g.\n * \"daemon-events\", \"codex\"), not who invoked the underlying session. */\n origin?: string\n callerSessionId?: string\n}\n\nexport interface ExportedSession {\n meta: ExportedSessionMeta\n messages: ExportedMessage[]\n}\n\n// ── Render ────────────────────────────────────────────────────────────\n\nconst ROLE_ICON: Record<string, string> = {\n user: \"🧑 User\",\n assistant: \"🤖 Assistant\",\n tool: \"🔧 Tool\",\n system: \"⚙️ System\",\n}\n\nfunction trunc(text: string, n: number): string {\n if (text.length <= n) return text\n return text.slice(0, n) + `\\n… [${text.length - n} chars truncated]`\n}\n\nexport function renderMarkdown(\n session: ExportedSession,\n opts: { maxToolChars?: number } = {},\n): string {\n const { meta, messages } = session\n const maxToolChars = opts.maxToolChars ?? 1200\n const out: string[] = []\n\n out.push(`# ${meta.title ?? \"(untitled)\"}`)\n out.push(\"\")\n\n const sourceNote = meta.source ? ` · source \\`${meta.source}\\`` : \"\"\n const originNote = meta.origin ? ` · origin \\`${meta.origin}\\`` : \"\"\n const callerNote = meta.callerSessionId ? ` · caller \\`${meta.callerSessionId}\\`` : \"\"\n out.push(`> Session${sourceNote}${originNote}${callerNote}`)\n out.push(\"\")\n out.push(\"| | |\")\n out.push(\"|---|---|\")\n if (meta.model) out.push(`| Model | \\`${meta.model}\\` |`)\n if (meta.startedAt || meta.endedAt) {\n out.push(`| Start → end | ${meta.startedAt ?? \"?\"} → ${meta.endedAt ?? \"?\"} |`)\n }\n if (meta.messageCount !== undefined || meta.toolCallCount !== undefined) {\n const parts: string[] = []\n if (meta.messageCount !== undefined) parts.push(`${meta.messageCount} messages`)\n if (meta.toolCallCount !== undefined) parts.push(`${meta.toolCallCount} tool calls`)\n out.push(`| Count | ${parts.join(\" · \")} |`)\n }\n if (meta.tokens && Object.keys(meta.tokens).length) {\n const t = meta.tokens\n const parts: string[] = []\n if (t.input !== undefined) parts.push(`in ${t.input.toLocaleString(\"en-US\")}`)\n if (t.output !== undefined) parts.push(`out ${t.output.toLocaleString(\"en-US\")}`)\n if (t.cacheRead !== undefined || t.cacheWrite !== undefined) {\n parts.push(\n `cache r/w ${(t.cacheRead ?? 0).toLocaleString(\"en-US\")}/${(t.cacheWrite ?? 0).toLocaleString(\"en-US\")}`,\n )\n }\n if (t.reasoning !== undefined) parts.push(`reason. ${t.reasoning.toLocaleString(\"en-US\")}`)\n if (parts.length) out.push(`| Tokens | ${parts.join(\" · \")} |`)\n }\n if (meta.costUsd !== undefined) {\n out.push(`| Cost | $${meta.costUsd.toFixed(4)} |`)\n }\n out.push(\"\")\n out.push(\"---\")\n out.push(\"\")\n\n for (const m of messages) {\n const icon = ROLE_ICON[m.role] ?? m.role\n const nameSuffix = m.toolName ? ` · \\`${m.toolName}\\`` : \"\"\n out.push(`### ${icon}${nameSuffix}`)\n\n if (m.reasoning?.trim()) {\n out.push(\"\")\n out.push(\"<details><summary>💭 reasoning</summary>\")\n out.push(\"\")\n out.push(trunc(m.reasoning, 4000))\n out.push(\"\")\n out.push(\"</details>\")\n }\n\n if (m.text?.trim()) {\n out.push(\"\")\n if (m.role === \"tool\") {\n out.push(\"```\")\n out.push(trunc(m.text, maxToolChars))\n out.push(\"```\")\n } else {\n out.push(m.text.trim())\n }\n }\n\n if (m.toolCalls?.length) {\n out.push(\"\")\n for (const tc of m.toolCalls) {\n let parsedArgs: unknown\n try {\n parsedArgs = JSON.parse(tc.args)\n } catch {\n parsedArgs = tc.args\n }\n out.push(`> 📞 ${formatToolCall(tc.name, parsedArgs)}`)\n }\n }\n\n out.push(\"\")\n }\n\n return out.join(\"\\n\")\n}\n\nexport function renderJson(session: ExportedSession): string {\n return JSON.stringify(session, null, 2)\n}\n\n// ── Exporter interface ────────────────────────────────────────────────\n\ninterface ExportStrategy {\n /** `configDir` = the session's isolated provider config dir\n * (`SessionDescriptor.adapterConfigDir`) — only claude-code keys its\n * store off it; the other strategies ignore it. */\n exportSession(adapterSessionId: string, cwd?: string, configDir?: string): Promise<ExportedSession>\n}\n\n// ── claude-code exporter (JSONL) ──────────────────────────────────────\n\ninterface ClaudeTextBlock {\n type: \"text\"\n text: string\n}\ninterface ClaudeThinkingBlock {\n type: \"thinking\"\n thinking: string\n}\ninterface ClaudeToolUseBlock {\n type: \"tool_use\"\n name: string\n input?: unknown\n}\ninterface ClaudeToolResultBlock {\n type: \"tool_result\"\n tool_use_id?: string\n content?: unknown\n}\ntype ClaudeContentBlock =\n | ClaudeTextBlock\n | ClaudeThinkingBlock\n | ClaudeToolUseBlock\n | ClaudeToolResultBlock\n | { type: string }\n\ninterface ClaudeCodeJsonlLine {\n type: string\n message?: {\n role?: string\n content?: string | ClaudeContentBlock[]\n }\n}\n\nconst IGNORED_CLAUDE_TYPES = new Set([\n \"queue-operation\",\n \"attachment\",\n \"file-history-snapshot\",\n \"ai-title\",\n \"last-prompt\",\n])\n\nexport async function exportClaudeCodeSession(\n adapterSessionId: string,\n cwd?: string,\n configDir?: string,\n): Promise<ExportedSession> {\n if (!cwd) {\n throw new Error(\n \"claude-code exporter: cwd is required to locate the JSONL file.\\n\" +\n \"Pass cwd explicitly or use a session id that is in the registry.\",\n )\n }\n // A config-dir-isolated session (#824) writes its transcripts under its\n // own CLAUDE_CONFIG_DIR, same projects/<slug> layout as ~/.claude.\n const filePath = join(claudeCodeProjectDir(cwd, configDir), `${adapterSessionId}.jsonl`)\n\n let stream: ReturnType<typeof createReadStream>\n try {\n stream = createReadStream(filePath, { encoding: \"utf8\" })\n // Trigger ENOENT eagerly before readline wraps it.\n await new Promise<void>((resolve, reject) => {\n stream.once(\"error\", reject)\n stream.once(\"open\", resolve)\n })\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === \"ENOENT\") {\n throw new Error(\n `claude-code: JSONL file not found: ${filePath}\\n` +\n `Verify cwd=\"${cwd}\" and adapterSessionId=\"${adapterSessionId}\".`,\n )\n }\n throw err\n }\n\n const messages: ExportedMessage[] = []\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let entry: ClaudeCodeJsonlLine\n try {\n entry = JSON.parse(trimmed) as ClaudeCodeJsonlLine\n } catch {\n continue\n }\n if (IGNORED_CLAUDE_TYPES.has(entry.type)) continue\n if (entry.type !== \"user\" && entry.type !== \"assistant\") continue\n const msg = entry.message\n if (!msg) continue\n\n const role: ExportedMessage[\"role\"] =\n msg.role === \"assistant\" ? \"assistant\" : \"user\"\n const content = msg.content\n\n if (typeof content === \"string\") {\n if (content.trim()) messages.push({ role, text: content.trim() })\n continue\n }\n if (!Array.isArray(content)) continue\n\n // Collect all block types from this message event\n let textAcc = \"\"\n let reasoningAcc = \"\"\n const toolCalls: { name: string; args: string }[] = []\n const toolResults: { text: string }[] = []\n\n for (const block of content) {\n switch (block.type) {\n case \"text\": {\n textAcc += (block as ClaudeTextBlock).text\n break\n }\n case \"thinking\": {\n reasoningAcc += (block as ClaudeThinkingBlock).thinking\n break\n }\n case \"tool_use\": {\n const tb = block as ClaudeToolUseBlock\n const args =\n typeof tb.input === \"string\"\n ? tb.input\n : JSON.stringify(tb.input ?? {})\n toolCalls.push({ name: tb.name, args })\n break\n }\n case \"tool_result\": {\n const tb = block as ClaudeToolResultBlock\n let resultText = \"\"\n if (typeof tb.content === \"string\") {\n resultText = tb.content\n } else if (Array.isArray(tb.content)) {\n for (const c of tb.content as ClaudeContentBlock[]) {\n if (c.type === \"text\") resultText += (c as ClaudeTextBlock).text\n }\n }\n toolResults.push({ text: resultText })\n break\n }\n }\n }\n\n // Emit the main message (user text or assistant with optional tool calls)\n if (textAcc.trim() || toolCalls.length || reasoningAcc) {\n const m: ExportedMessage = { role }\n if (textAcc.trim()) m.text = textAcc.trim()\n if (reasoningAcc) m.reasoning = reasoningAcc\n if (toolCalls.length) m.toolCalls = toolCalls\n messages.push(m)\n }\n\n // Emit each tool result as its own role=tool message\n for (const tr of toolResults) {\n messages.push({ role: \"tool\", text: tr.text })\n }\n }\n\n return { meta: { source: \"claude-code\" }, messages }\n}\n\n// ── hermes exporter (SQLite) ──────────────────────────────────────────\n// node:sqlite is experimental in Node 22.x but functional.\n// Isolated here so a future stable import replaces only this function.\n\n// esbuild (via tsup) strips the `node:` prefix from builtin imports. Most\n// builtins work without it, but `node:sqlite` has NO unprefixed name —\n// `import('sqlite')` fails at runtime. A computed specifier dodges the\n// static analysis so the prefix survives bundling.\nconst NODE_SQLITE = \"node:\" + \"sqlite\"\nasync function importNodeSqlite(): Promise<typeof import(\"node:sqlite\")> {\n return import(/* @vite-ignore */ NODE_SQLITE)\n}\n\ninterface HermesSessionRow {\n id: string\n title?: string\n model?: string\n started_at?: number\n ended_at?: number\n message_count?: number\n tool_call_count?: number\n api_call_count?: number\n input_tokens?: number\n output_tokens?: number\n cache_read_tokens?: number\n cache_write_tokens?: number\n reasoning_tokens?: number\n actual_cost_usd?: number\n estimated_cost_usd?: number\n source?: string\n end_reason?: string\n}\n\ninterface HermesMessageRow {\n id: number\n session_id: string\n role: string\n content?: string\n tool_calls?: string\n tool_name?: string\n reasoning?: string\n reasoning_content?: string\n timestamp?: number\n}\n\n// Shared by exportHermesSession AND discoverHermesSessions (below) — the\n// open + SQLITE_BUSY-retry handling lives in exactly one place so the two\n// callers can never drift.\ntype HermesDb = InstanceType<(typeof import(\"node:sqlite\"))[\"DatabaseSync\"]>\n\nasync function openHermesDb(dbPath: string): Promise<HermesDb> {\n let DatabaseSync: (typeof import(\"node:sqlite\"))[\"DatabaseSync\"]\n try {\n const sqlite = await importNodeSqlite()\n DatabaseSync = sqlite.DatabaseSync\n } catch {\n throw new Error(\"hermes: node:sqlite unavailable. Requires Node.js ≥22.5.0.\")\n }\n\n try {\n return new DatabaseSync(dbPath, { readOnly: true })\n } catch (err) {\n const msg = String(err)\n if (\n (err as NodeJS.ErrnoException).code === \"ENOENT\" ||\n msg.includes(\"unable to open database file\")\n ) {\n throw new Error(\n `hermes: state.db not found at ${dbPath}. ` +\n `Has hermes been run at least once?`,\n )\n }\n if (msg.includes(\"SQLITE_BUSY\") || msg.includes(\"database is locked\")) {\n throw new Error(\n `hermes: database is locked (SQLITE_BUSY). ` +\n `Hermes may be writing. Try again in a moment.`,\n )\n }\n throw err\n }\n}\n\nfunction withRetryOnBusy<T>(fn: () => T): T {\n try {\n return fn()\n } catch (err) {\n const msg = String(err)\n if (msg.includes(\"SQLITE_BUSY\") || msg.includes(\"database is locked\")) {\n // One brief retry — the lock is usually transient\n try {\n return fn()\n } catch {\n throw new Error(\n `hermes: database is locked. Hermes may be actively writing. Try again.`,\n )\n }\n }\n throw err\n }\n}\n\n/** Generic read-only sqlite open, sharing hermes's node:sqlite plumbing so\n * the opencode + mastracode-inprocess stores don't each reinvent the\n * experimental-module guard and the ENOENT/BUSY error mapping. `label` is\n * the provider name used in the error strings. Returns the same handle\n * type `withRetryOnBusy` operates on. */\nasync function openReadonlySqlite(dbPath: string, label: string): Promise<HermesDb> {\n let DatabaseSync: (typeof import(\"node:sqlite\"))[\"DatabaseSync\"]\n try {\n const sqlite = await importNodeSqlite()\n DatabaseSync = sqlite.DatabaseSync\n } catch {\n throw new Error(`${label}: node:sqlite unavailable. Requires Node.js ≥22.5.0.`)\n }\n try {\n return new DatabaseSync(dbPath, { readOnly: true })\n } catch (err) {\n const msg = String(err)\n if (\n (err as NodeJS.ErrnoException).code === \"ENOENT\" ||\n msg.includes(\"unable to open database file\")\n ) {\n throw new Error(`${label}: database not found at ${dbPath}. Has ${label} been run at least once?`)\n }\n if (msg.includes(\"SQLITE_BUSY\") || msg.includes(\"database is locked\")) {\n throw new Error(`${label}: database is locked (SQLITE_BUSY). It may be writing. Try again in a moment.`)\n }\n throw err\n }\n}\n\nexport async function exportHermesSession(adapterSessionId: string): Promise<ExportedSession> {\n const dbPath = join(homedir(), \".hermes\", \"state.db\")\n const db = await openHermesDb(dbPath)\n\n const session = withRetryOnBusy(\n () =>\n db\n .prepare(\"SELECT * FROM sessions WHERE id = ?\")\n .get(adapterSessionId) as unknown as HermesSessionRow | undefined,\n )\n\n if (!session) {\n db.close()\n throw new Error(\n `hermes: session \"${adapterSessionId}\" not found in ${dbPath}. ` +\n `ACP sessions are indexed by the agentproto UUID passed as resumeSessionId.`,\n )\n }\n\n const rows = withRetryOnBusy(\n () =>\n db\n .prepare(\n \"SELECT * FROM messages WHERE session_id = ? ORDER BY id ASC\",\n )\n .all(adapterSessionId) as unknown as HermesMessageRow[],\n )\n\n db.close()\n\n const cost =\n session.actual_cost_usd != null\n ? session.actual_cost_usd\n : session.estimated_cost_usd\n\n const startedAt = session.started_at\n ? new Date(session.started_at * 1000).toISOString().replace(\"T\", \" \").slice(0, 19)\n : undefined\n const endedAt = session.ended_at\n ? new Date(session.ended_at * 1000).toISOString().replace(\"T\", \" \").slice(0, 19)\n : undefined\n\n const meta: ExportedSessionMeta = {\n ...(session.title ? { title: session.title } : {}),\n ...(session.model ? { model: session.model } : {}),\n ...(startedAt ? { startedAt } : {}),\n ...(endedAt ? { endedAt } : {}),\n ...(session.message_count !== undefined ? { messageCount: session.message_count } : {}),\n ...(session.tool_call_count !== undefined\n ? { toolCallCount: session.tool_call_count }\n : {}),\n ...(cost != null ? { costUsd: Number(cost) } : {}),\n ...(session.source ? { source: session.source } : {}),\n }\n\n // Only include tokens sub-object when at least one field is present\n const tokensInput = session.input_tokens\n const tokensOutput = session.output_tokens\n const tokensCacheRead = session.cache_read_tokens\n const tokensCacheWrite = session.cache_write_tokens\n const tokensReasoning = session.reasoning_tokens\n if (\n tokensInput !== undefined ||\n tokensOutput !== undefined ||\n tokensCacheRead !== undefined ||\n tokensCacheWrite !== undefined ||\n tokensReasoning !== undefined\n ) {\n meta.tokens = {\n ...(tokensInput !== undefined ? { input: tokensInput } : {}),\n ...(tokensOutput !== undefined ? { output: tokensOutput } : {}),\n ...(tokensCacheRead !== undefined ? { cacheRead: tokensCacheRead } : {}),\n ...(tokensCacheWrite !== undefined ? { cacheWrite: tokensCacheWrite } : {}),\n ...(tokensReasoning !== undefined ? { reasoning: tokensReasoning } : {}),\n }\n }\n\n const messages: ExportedMessage[] = rows.map(row => {\n const validRoles = new Set([\"user\", \"assistant\", \"tool\", \"system\"])\n const role = (\n validRoles.has(row.role) ? row.role : \"user\"\n ) as ExportedMessage[\"role\"]\n\n const reasoning = row.reasoning ?? row.reasoning_content\n\n let toolCalls: { name: string; args: string }[] | undefined\n if (row.tool_calls) {\n try {\n const tc = JSON.parse(row.tool_calls) as unknown[]\n if (Array.isArray(tc) && tc.length) {\n toolCalls = tc.map(c => {\n const entry = c as Record<string, unknown>\n const fn =\n entry.function != null\n ? (entry.function as Record<string, unknown>)\n : entry\n const name = String(fn.name ?? entry.name ?? \"tool\")\n const args =\n typeof fn.arguments === \"string\"\n ? fn.arguments\n : JSON.stringify(fn.arguments ?? {})\n return { name, args }\n })\n }\n } catch {\n // malformed tool_calls — skip\n }\n }\n\n const m: ExportedMessage = { role }\n if (row.content?.trim()) m.text = row.content.trim()\n if (reasoning && String(reasoning).trim()) m.reasoning = String(reasoning)\n if (row.tool_name) m.toolName = row.tool_name\n if (toolCalls) m.toolCalls = toolCalls\n if (row.timestamp) m.ts = row.timestamp\n return m\n })\n\n // Fire-and-forget: cross-check our row count against the binary's export.\n // Non-blocking — a mismatch only logs a warning, it never fails the call.\n void crossValidateHermesExport(adapterSessionId, messages.length).catch(() => {})\n\n return { meta, messages }\n}\n\n// ── hermes discovery (SQLite, cwd-scoped) ─────────────────────────────\n//\n// Reuses openHermesDb/withRetryOnBusy above — the SAME open + BUSY-retry\n// path exportHermesSession uses — so there is one sqlite plumbing to\n// maintain, not two. Called from conversation-store.ts's hermes `discover`\n// via a dynamic import (see that file for why it's dynamic, not static).\n\nfunction hermesRowToCandidate(row: HermesSessionRow): ConversationCandidate {\n const startedAtIso =\n row.started_at !== undefined ? new Date(row.started_at * 1000).toISOString() : undefined\n // \"Last activity\" is when the conversation was last written to — ended_at\n // if it has one, else fall back to started_at (a still-open session).\n const lastActivitySec = row.ended_at ?? row.started_at\n const lastActivityIso =\n lastActivitySec !== undefined ? new Date(lastActivitySec * 1000).toISOString() : undefined\n return {\n conversationId: row.id,\n ...(startedAtIso ? { startedAt: startedAtIso } : {}),\n ...(lastActivityIso ? { lastActivityAt: lastActivityIso } : {}),\n ...(row.message_count !== undefined ? { messageCount: row.message_count } : {}),\n ...(row.title ? { preview: row.title } : {}),\n ...(row.source ? { lastWriter: row.source } : {}),\n }\n}\n\nexport async function discoverHermesSessions(\n cwd: string,\n since?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const dbPath = join(homedir(), \".hermes\", \"state.db\")\n\n let db: HermesDb\n try {\n db = await openHermesDb(dbPath)\n } catch (err) {\n // \"state.db not found\" == hermes has never run on this box — a normal,\n // empty store, not a discovery error. Anything else (locked, node:sqlite\n // missing) is a genuinely unreadable store and propagates — see the\n // ConversationStore.discover contract in conversation-store.ts.\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes(\"state.db not found\")) return []\n throw err\n }\n\n try {\n // Ground truth beats heuristic: bind to exactly the conversation we\n // were asked about. Binding is by `id`, which is cwd-independent, so\n // this never even looks at `cwd` — never falls through to the cwd-scan\n // below. See the exact-bind invariant in conversation-store.ts.\n if (expectedId) {\n const row = withRetryOnBusy(\n () =>\n db.prepare(\"SELECT * FROM sessions WHERE id = ?\").get(expectedId) as unknown as\n | HermesSessionRow\n | undefined,\n )\n return row ? [hermesRowToCandidate(row)] : []\n }\n\n const rows = withRetryOnBusy(\n () =>\n db\n .prepare(\"SELECT * FROM sessions WHERE cwd = ?\")\n .all(cwd) as unknown as HermesSessionRow[],\n )\n const sinceMs = since ? Date.parse(since) : NaN\n return rows\n .filter(row => {\n if (!Number.isFinite(sinceMs)) return true\n const lastActivitySec = row.ended_at ?? row.started_at\n if (lastActivitySec === undefined) return true\n return lastActivitySec * 1000 >= sinceMs - 1000\n })\n .map(hermesRowToCandidate)\n } finally {\n db.close()\n }\n}\n\n// ── Hermes cross-validation via native CLI ────────────────────────────\n//\n// `hermes sessions export --session-id <id> -` emits a stable JSONL\n// transcript on stdout. We use it as a non-blocking sanity-check:\n// if the message count from state.db differs from the binary's output,\n// something in the SQLite schema likely changed and the reader needs\n// updating. The check is fire-and-forget — a mismatch logs a warning but\n// does NOT affect the returned ExportedSession (SQLite stays primary).\n//\n// The export JSONL has one JSON object per message line; lines with a\n// `role` key are treated as messages (other metadata lines are ignored).\n\nexport interface HermesCrossValidationResult {\n sqliteCount: number\n binaryCount: number\n matched: boolean\n /** True when the hermes binary was not found on PATH */\n binaryUnavailable?: boolean\n}\n\n/** Default subprocess runner: spawns `hermes sessions export --session-id <id> -`\n * and returns stdout. Throws with `.code=\"ENOENT\"` when the binary isn't on PATH. */\nasync function defaultHermesRunner(adapterSessionId: string): Promise<string> {\n const { spawn } = await import(\"node:child_process\")\n return new Promise<string>((resolve, reject) => {\n const chunks: Buffer[] = []\n const errChunks: Buffer[] = []\n const proc = spawn(\n \"hermes\",\n [\"sessions\", \"export\", \"--session-id\", adapterSessionId, \"-\"],\n { stdio: [\"ignore\", \"pipe\", \"pipe\"] },\n )\n proc.stdout.on(\"data\", (chunk: Buffer) => chunks.push(chunk))\n proc.stderr.on(\"data\", (chunk: Buffer) => errChunks.push(chunk))\n proc.on(\"error\", reject)\n proc.on(\"close\", code => {\n if (code !== 0) {\n reject(\n new Error(\n `hermes exited with code ${code}: ${Buffer.concat(errChunks).toString()}`,\n ),\n )\n } else {\n resolve(Buffer.concat(chunks).toString(\"utf8\"))\n }\n })\n })\n}\n\n/** Run `hermes sessions export` and compare its message count with\n * what our SQLite reader produced. Returns null on any subprocess\n * error (binary missing, timeout, parse failure).\n *\n * The optional `_runner` parameter lets tests inject a mock that returns stdout\n * directly, avoiding subprocess mocking complexity (promisify + child_process). */\nexport async function crossValidateHermesExport(\n adapterSessionId: string,\n sqliteCount: number,\n _runner: (id: string) => Promise<string> = defaultHermesRunner,\n): Promise<HermesCrossValidationResult | null> {\n let stdout: string\n try {\n stdout = await _runner(adapterSessionId)\n } catch (err) {\n const msg = String(err)\n // ENOENT = binary not on PATH — expected when hermes isn't installed\n if (\n (err as NodeJS.ErrnoException).code === \"ENOENT\" ||\n msg.includes(\"ENOENT\") ||\n msg.includes(\"not found\")\n ) {\n return { sqliteCount, binaryCount: -1, matched: true, binaryUnavailable: true }\n }\n // Any other error (timeout, non-zero exit, etc.) — skip validation\n return null\n }\n\n // Count lines that look like message objects (have a `role` field)\n const binaryCount = stdout\n .split(\"\\n\")\n .filter(l => l.trim())\n .filter(l => {\n try {\n const obj = JSON.parse(l) as Record<string, unknown>\n return typeof obj.role === \"string\"\n } catch {\n return false\n }\n }).length\n\n const matched = binaryCount === sqliteCount\n if (!matched) {\n console.warn(\n `[hermes export] cross-validation mismatch for session ${adapterSessionId}: ` +\n `SQLite=${sqliteCount} messages, binary=${binaryCount} messages. ` +\n `The state.db schema may have changed — check the SQLite reader in transcript-export.ts.`,\n )\n }\n return { sqliteCount, binaryCount, matched }\n}\n\n// ── daemon-events exporter (agentproto's own JSONL capture) ────────────\n\n/** Structural shape of one events.jsonl line — a superset of every\n * `AgentStreamEvent` kind (see sessions.ts) plus the writer's own\n * \"user-prompt\" record. Untyped fields default to undefined rather than\n * erroring, so a future field this reader doesn't know about is just\n * ignored instead of breaking the export. */\ninterface TranscriptRecord {\n seq: number\n ts: string\n kind: string\n text?: string\n partial?: boolean\n toolCallId?: string\n toolName?: string\n arguments?: unknown\n result?: unknown\n isError?: boolean\n reason?: string\n error?: { message: string; code?: number }\n entries?: Array<{ content: string; priority: string; status: string }>\n size?: number\n used?: number\n cost?: { amount: number; currency: string }\n}\n\nexport async function exportDaemonEventsSession(\n sessionId: string,\n desc?: SessionDescriptor,\n): Promise<ExportedSession> {\n const filePath = sessionEventsPath(sessionId)\n\n let stream: ReturnType<typeof createReadStream>\n try {\n stream = createReadStream(filePath, { encoding: \"utf8\" })\n await new Promise<void>((resolve, reject) => {\n stream.once(\"error\", reject)\n stream.once(\"open\", resolve)\n })\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === \"ENOENT\") {\n throw new Error(\n `daemon-events: no events.jsonl for session \"${sessionId}\" (${filePath}).\\n` +\n `Either the session never drove an agent-cli turn, or it predates this feature.`,\n )\n }\n throw err\n }\n\n const messages: ExportedMessage[] = []\n const toolNameById = new Map<string, string>()\n let toolCallCount = 0\n let lastUsage: { size?: number; used?: number; cost?: { amount: number; currency: string } } | undefined\n\n // One assistant \"turn batch\" accumulator — text/thought/tool-calls that\n // arrive between two boundary events (a tool-result, a new prompt, a\n // turn-end, ...) collapse into ONE assistant message, mirroring how the\n // claude-code exporter batches a single API-level assistant entry.\n let asmText = \"\"\n let asmReasoning = \"\"\n let asmToolCalls: { name: string; args: string }[] = []\n let asmTs: number | undefined\n\n const flushAssistant = (): void => {\n if (!asmText.trim() && !asmReasoning.trim() && asmToolCalls.length === 0) return\n const m: ExportedMessage = { role: \"assistant\" }\n if (asmText.trim()) m.text = asmText.trim()\n if (asmReasoning.trim()) m.reasoning = asmReasoning.trim()\n if (asmToolCalls.length) m.toolCalls = asmToolCalls\n if (asmTs !== undefined) m.ts = asmTs\n messages.push(m)\n asmText = \"\"\n asmReasoning = \"\"\n asmToolCalls = []\n asmTs = undefined\n }\n\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let rec: TranscriptRecord\n try {\n rec = JSON.parse(trimmed) as TranscriptRecord\n } catch {\n continue\n }\n const ts = Date.parse(rec.ts)\n const tsOrUndefined = Number.isNaN(ts) ? undefined : ts\n\n switch (rec.kind) {\n case \"user-prompt\":\n flushAssistant()\n messages.push({ role: \"user\", text: rec.text ?? \"\", ...(tsOrUndefined !== undefined ? { ts: tsOrUndefined } : {}) })\n break\n case \"system-prompt\":\n // The daemon-composed SYSTEM slice of a spawned child's initial\n // prompt (role disposition + AGENTS.md + lineage). Recorded apart\n // from the caller's ask so viewers fold it; rendered as a system\n // message (never a user bubble).\n flushAssistant()\n messages.push({ role: \"system\", text: rec.text ?? \"\", ...(tsOrUndefined !== undefined ? { ts: tsOrUndefined } : {}) })\n break\n case \"text-delta\":\n // Terminated lines already carry their own trailing \"\\n\" (see\n // transcript-writer.ts) — only an unterminated tail fragment\n // (still `partial`, or flushed bare at a turn boundary) lacks one,\n // and that's exactly the byte-for-byte original content.\n if (asmTs === undefined) asmTs = tsOrUndefined\n asmText += rec.text ?? \"\"\n break\n case \"thought\":\n if (asmTs === undefined) asmTs = tsOrUndefined\n asmReasoning += rec.text ?? \"\"\n break\n case \"tool-call\": {\n if (asmTs === undefined) asmTs = tsOrUndefined\n const name = rec.toolName ?? \"tool\"\n if (rec.toolCallId) toolNameById.set(rec.toolCallId, name)\n const args =\n typeof rec.arguments === \"string\" ? rec.arguments : JSON.stringify(rec.arguments ?? {})\n asmToolCalls.push({ name, args })\n toolCallCount += 1\n break\n }\n case \"tool-result\": {\n flushAssistant()\n const name = rec.toolCallId ? toolNameById.get(rec.toolCallId) : undefined\n const text = typeof rec.result === \"string\" ? rec.result : JSON.stringify(rec.result ?? \"\")\n messages.push({\n role: \"tool\",\n text: rec.isError ? `[error] ${text}` : text,\n ...(name ? { toolName: name } : {}),\n ...(tsOrUndefined !== undefined ? { ts: tsOrUndefined } : {}),\n })\n break\n }\n case \"agent-prompt\":\n flushAssistant()\n messages.push({ role: \"system\", text: \"[awaiting input] agent requested a decision\" })\n break\n case \"plan\": {\n flushAssistant()\n const entries = rec.entries ?? []\n const done = entries.filter(e => e.status === \"completed\").length\n const list = entries.map(e => e.content).join(\"; \")\n messages.push({ role: \"system\", text: `[plan] ${done}/${entries.length} ${list}`.trim() })\n break\n }\n case \"usage_update\":\n lastUsage = { size: rec.size, used: rec.used, cost: rec.cost }\n break\n case \"error\":\n flushAssistant()\n messages.push({ role: \"system\", text: `[error] ${rec.error?.message ?? \"unknown\"}` })\n break\n case \"turn-end\":\n flushAssistant()\n break\n case \"notice\":\n // Daemon-side system notice (e.g. the interrupted-turn resume banner)\n // — surfaced as a system message, same as plan/error notices above.\n flushAssistant()\n messages.push({ role: \"system\", text: rec.text ?? \"\" })\n break\n default:\n break\n }\n }\n flushAssistant()\n\n const meta: ExportedSessionMeta = { source: \"daemon-events\" }\n if (desc?.label) meta.title = desc.label\n if (desc?.model) meta.model = desc.model\n if (desc?.startedAt) meta.startedAt = desc.startedAt\n if (desc?.endedAt) meta.endedAt = desc.endedAt\n if (desc?.origin) meta.origin = desc.origin\n if (desc?.callerSessionId) meta.callerSessionId = desc.callerSessionId\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n if (desc?.costUsd !== undefined) meta.costUsd = desc.costUsd\n else if (lastUsage?.cost) meta.costUsd = lastUsage.cost.amount\n if (desc?.tokensIn !== undefined || desc?.tokensOut !== undefined) {\n meta.tokens = {\n ...(desc?.tokensIn !== undefined ? { input: desc.tokensIn } : {}),\n ...(desc?.tokensOut !== undefined ? { output: desc.tokensOut } : {}),\n }\n }\n\n return { meta, messages }\n}\n\n// ── shared jsonl helper ───────────────────────────────────────────────\n\n/** Read only the first non-empty line of a jsonl file — used by the codex\n * and pi discovery scans, which only need each file's leading metadata\n * record (session_meta / session) to answer cwd/id questions without\n * parsing a possibly-multi-MB transcript. */\nasync function readFirstJsonLine(path: string): Promise<string | undefined> {\n const stream = createReadStream(path, { encoding: \"utf8\" })\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n try {\n for await (const line of rl) {\n const t = line.trim()\n if (t) return t\n }\n return undefined\n } finally {\n rl.close()\n stream.destroy()\n }\n}\n\n// ── codex exporter (rollout JSONL) ────────────────────────────────────\n//\n// Native store: $CODEX_HOME/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl\n// (CODEX_HOME defaults to ~/.codex). One append-only JSONL file per\n// conversation, written by the Codex core that @agentclientprotocol/codex-acp\n// bundles. The first line is a `session_meta` record carrying the\n// conversation's `id` (== the trailing uuid in the filename == the ACP\n// session id agentproto records as `adapterSessionId` — verified\n// empirically against live rollouts) and its `cwd`. Subsequent\n// `response_item` lines carry the turns; `event_msg` / `turn_context`\n// lines are transport bookkeeping we skip.\n\nfunction codexHome(): string {\n return process.env.CODEX_HOME ?? join(homedir(), \".codex\")\n}\nfunction codexSessionsDir(): string {\n return join(codexHome(), \"sessions\")\n}\n\ninterface CodexRolloutLine {\n type?: string\n timestamp?: string\n payload?: {\n type?: string\n id?: string\n session_id?: string\n timestamp?: string\n cwd?: string\n model?: string\n model_provider?: string\n role?: string\n content?: Array<{ type?: string; text?: string }>\n summary?: Array<{ type?: string; text?: string }>\n name?: string\n input?: unknown\n arguments?: unknown\n call_id?: string\n output?: unknown\n }\n}\n\n/** Recursively collect `rollout-*.jsonl` paths under the YYYY/MM/DD tree. */\nasync function walkCodexRollouts(dir: string): Promise<string[]> {\n let entries: Dirent[]\n try {\n entries = await fs.readdir(dir, { withFileTypes: true })\n } catch {\n return []\n }\n const out: string[] = []\n for (const e of entries) {\n const p = join(dir, e.name)\n if (e.isDirectory()) {\n out.push(...(await walkCodexRollouts(p)))\n } else if (e.isFile() && e.name.startsWith(\"rollout-\") && e.name.endsWith(\".jsonl\")) {\n out.push(p)\n }\n }\n return out\n}\n\n/** Join codex output blocks (input_text / output_text) into one string. */\nfunction codexBlocksText(content: unknown): string {\n if (typeof content === \"string\") return content\n if (!Array.isArray(content)) return \"\"\n let acc = \"\"\n for (const c of content) {\n if (c && typeof c === \"object\") {\n const b = c as { type?: string; text?: string }\n if (typeof b.text === \"string\" && (b.type === \"input_text\" || b.type === \"output_text\" || b.type === \"text\")) {\n acc += b.text\n }\n }\n }\n return acc\n}\n\nasync function findCodexRolloutFile(conversationId: string): Promise<string | undefined> {\n const files = await walkCodexRollouts(codexSessionsDir())\n // Fast path: the uuid is the filename suffix.\n const byName = files.find(f => f.endsWith(`-${conversationId}.jsonl`))\n if (byName) return byName\n // Fallback: match on the session_meta id/session_id (covers a future\n // codex build whose filename uuid diverges from the meta id).\n for (const f of files) {\n const first = await readFirstJsonLine(f)\n if (!first) continue\n let meta: CodexRolloutLine\n try {\n meta = JSON.parse(first) as CodexRolloutLine\n } catch {\n continue\n }\n const p = meta.payload\n if (p && (p.id === conversationId || p.session_id === conversationId)) return f\n }\n return undefined\n}\n\nexport async function exportCodexSession(conversationId: string): Promise<ExportedSession> {\n const file = await findCodexRolloutFile(conversationId)\n if (!file) {\n throw new Error(\n `codex: no rollout file for conversation \"${conversationId}\" under ${codexSessionsDir()}.\\n` +\n `The session may predate persistence, or CODEX_HOME points elsewhere.`,\n )\n }\n\n const stream = createReadStream(file, { encoding: \"utf8\" })\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n const messages: ExportedMessage[] = []\n const toolNameByCall = new Map<string, string>()\n let toolCallCount = 0\n let startedAt: string | undefined\n let model: string | undefined\n\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let entry: CodexRolloutLine\n try {\n entry = JSON.parse(trimmed) as CodexRolloutLine\n } catch {\n continue\n }\n const p = entry.payload ?? {}\n\n if (entry.type === \"session_meta\") {\n startedAt = p.timestamp ?? entry.timestamp\n if (typeof p.model === \"string\") model = p.model\n continue\n }\n if (entry.type === \"turn_context\") {\n if (!model && typeof p.model === \"string\") model = p.model\n continue\n }\n if (entry.type !== \"response_item\") continue\n\n switch (p.type) {\n case \"message\": {\n const text = codexBlocksText(p.content).trim()\n if (!text) break\n const role: ExportedMessage[\"role\"] =\n p.role === \"assistant\" ? \"assistant\" : p.role === \"user\" ? \"user\" : \"system\"\n messages.push({ role, text })\n break\n }\n case \"reasoning\": {\n // Codex reasoning is usually an opaque `encrypted_content` blob; only\n // an unencrypted `summary` (rare) is human-readable. Emit only when\n // there's real text — never the ciphertext.\n const r = (p.summary ?? []).map(s => s.text ?? \"\").join(\"\\n\").trim()\n if (r) messages.push({ role: \"assistant\", reasoning: r })\n break\n }\n case \"function_call\":\n case \"custom_tool_call\": {\n const name = p.name ?? \"tool\"\n if (typeof p.call_id === \"string\") toolNameByCall.set(p.call_id, name)\n const raw = p.type === \"custom_tool_call\" ? p.input : p.arguments\n const args = typeof raw === \"string\" ? raw : JSON.stringify(raw ?? {})\n messages.push({ role: \"assistant\", toolCalls: [{ name, args }] })\n toolCallCount += 1\n break\n }\n case \"function_call_output\":\n case \"custom_tool_call_output\": {\n const name = typeof p.call_id === \"string\" ? toolNameByCall.get(p.call_id) : undefined\n const out = codexBlocksText(p.output) || (typeof p.output === \"string\" ? p.output : \"\")\n messages.push({ role: \"tool\", text: out, ...(name ? { toolName: name } : {}) })\n break\n }\n }\n }\n\n const meta: ExportedSessionMeta = { source: \"codex\" }\n if (startedAt) meta.startedAt = startedAt\n if (model) meta.model = model\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n return { meta, messages }\n}\n\nexport async function discoverCodexSessions(\n cwd: string,\n since?: string,\n until?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const files = await walkCodexRollouts(codexSessionsDir())\n const sinceMs = since ? Date.parse(since) : NaN\n const untilMs = until ? Date.parse(until) : NaN\n const scored: { candidate: ConversationCandidate; mtimeMs: number }[] = []\n\n for (const f of files) {\n let mtimeMs: number\n try {\n mtimeMs = (await fs.stat(f)).mtimeMs\n } catch {\n continue\n }\n if (Number.isFinite(sinceMs) && mtimeMs < sinceMs - 1000) continue\n const first = await readFirstJsonLine(f)\n if (!first) continue\n let meta: CodexRolloutLine\n try {\n meta = JSON.parse(first) as CodexRolloutLine\n } catch {\n continue\n }\n if (meta.type !== \"session_meta\") continue\n const p = meta.payload ?? {}\n const id = p.id ?? p.session_id\n if (!id) continue\n // Ground truth beats heuristic: bind to exactly the requested id and\n // ignore cwd (the id is globally unique). See the exact-bind invariant.\n if (expectedId) {\n if (id !== expectedId) continue\n } else if (p.cwd !== cwd) {\n continue\n }\n const startedAt = p.timestamp\n if (Number.isFinite(untilMs) && startedAt) {\n const startedMs = Date.parse(startedAt)\n if (Number.isFinite(startedMs) && startedMs > untilMs) continue\n }\n scored.push({\n candidate: {\n conversationId: id,\n ...(startedAt ? { startedAt } : {}),\n lastActivityAt: new Date(mtimeMs).toISOString(),\n },\n mtimeMs,\n })\n }\n\n scored.sort((a, b) => b.mtimeMs - a.mtimeMs)\n return scored.map(s => s.candidate)\n}\n\n// ── opencode exporter (opencode.db SQLite) ────────────────────────────\n//\n// Native store: ${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db — a\n// drizzle-managed sqlite with `session` (keyed by the `ses_…` id opencode\n// returns over ACP, which agentproto records verbatim as adapterSessionId\n// — verified empirically), `message` (JSON `data` per row), and `part`\n// (JSON `data`, one row per text/reasoning/tool block). The `session`\n// table's `directory` column is the conversation's cwd, enabling\n// cwd-scoped discovery.\n\ninterface OpenCodeSessionRow {\n id: string\n directory?: string\n title?: string\n model?: string\n cost?: number\n tokens_input?: number\n tokens_output?: number\n tokens_reasoning?: number\n tokens_cache_read?: number\n tokens_cache_write?: number\n time_created?: number\n time_updated?: number\n}\ninterface OpenCodeMessageRow {\n id: string\n data: string\n time_created: number\n}\ninterface OpenCodePartRow {\n message_id: string\n data: string\n time_created: number\n}\n\nfunction openCodeDbPath(): string {\n const dataHome = process.env.XDG_DATA_HOME ?? join(homedir(), \".local\", \"share\")\n return join(dataHome, \"opencode\", \"opencode.db\")\n}\n\n/** `{\"id\":\"gpt-5-mini\",\"providerID\":\"openai\",…}` → `openai/gpt-5-mini`. */\nfunction openCodeModelLabel(raw: string | undefined): string | undefined {\n if (!raw) return undefined\n try {\n const m = JSON.parse(raw) as { id?: string; modelID?: string; providerID?: string }\n const id = m.modelID ?? m.id\n if (!id) return undefined\n return m.providerID ? `${m.providerID}/${id}` : id\n } catch {\n return undefined\n }\n}\n\nexport async function exportOpenCodeSession(conversationId: string): Promise<ExportedSession> {\n const dbPath = openCodeDbPath()\n const db = await openReadonlySqlite(dbPath, \"opencode\")\n try {\n const session = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM session WHERE id = ?\").get(conversationId) as unknown as\n | OpenCodeSessionRow\n | undefined,\n )\n if (!session) {\n throw new Error(\n `opencode: session \"${conversationId}\" not found in ${dbPath}. ` +\n `Sessions are keyed by the ACP session id (ses_…) recorded as adapterSessionId.`,\n )\n }\n const msgRows = withRetryOnBusy(\n () =>\n db\n .prepare(\"SELECT id, data, time_created FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC\")\n .all(conversationId) as unknown as OpenCodeMessageRow[],\n )\n const partRows = withRetryOnBusy(\n () =>\n db\n .prepare(\"SELECT message_id, data, time_created FROM part WHERE session_id = ? ORDER BY time_created ASC, id ASC\")\n .all(conversationId) as unknown as OpenCodePartRow[],\n )\n\n const partsByMsg = new Map<string, OpenCodePartRow[]>()\n for (const r of partRows) {\n const list = partsByMsg.get(r.message_id) ?? []\n list.push(r)\n partsByMsg.set(r.message_id, list)\n }\n\n const messages: ExportedMessage[] = []\n let toolCallCount = 0\n for (const m of msgRows) {\n let mdata: { role?: string }\n try {\n mdata = JSON.parse(m.data) as { role?: string }\n } catch {\n continue\n }\n const role: ExportedMessage[\"role\"] = mdata.role === \"assistant\" ? \"assistant\" : \"user\"\n let text = \"\"\n let reasoning = \"\"\n const toolCalls: { name: string; args: string }[] = []\n const toolResults: { name?: string; text: string }[] = []\n for (const pr of partsByMsg.get(m.id) ?? []) {\n let part: {\n type?: string\n text?: string\n tool?: string\n state?: { input?: unknown; output?: unknown }\n }\n try {\n part = JSON.parse(pr.data) as typeof part\n } catch {\n continue\n }\n switch (part.type) {\n case \"text\":\n if (part.text) text += part.text\n break\n case \"reasoning\":\n if (part.text) reasoning += part.text\n break\n case \"tool\": {\n const name = part.tool ?? \"tool\"\n toolCalls.push({ name, args: JSON.stringify(part.state?.input ?? {}) })\n toolCallCount += 1\n const output = part.state?.output\n if (output !== undefined && output !== null && output !== \"\") {\n toolResults.push({ name, text: typeof output === \"string\" ? output : JSON.stringify(output) })\n }\n break\n }\n // step-start / step-finish / patch / snapshot / file — skip.\n }\n }\n if (text.trim() || reasoning.trim() || toolCalls.length) {\n const em: ExportedMessage = { role }\n if (text.trim()) em.text = text.trim()\n if (reasoning.trim()) em.reasoning = reasoning.trim()\n if (toolCalls.length) em.toolCalls = toolCalls\n em.ts = m.time_created\n messages.push(em)\n }\n for (const tr of toolResults) {\n messages.push({ role: \"tool\", text: tr.text, ...(tr.name ? { toolName: tr.name } : {}) })\n }\n }\n\n const meta: ExportedSessionMeta = { source: \"opencode\" }\n if (session.title) meta.title = session.title\n const model = openCodeModelLabel(session.model)\n if (model) meta.model = model\n if (session.time_created) meta.startedAt = new Date(session.time_created).toISOString()\n if (session.time_updated) meta.endedAt = new Date(session.time_updated).toISOString()\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n if (session.cost != null) meta.costUsd = Number(session.cost)\n const tk = {\n ...(session.tokens_input != null ? { input: session.tokens_input } : {}),\n ...(session.tokens_output != null ? { output: session.tokens_output } : {}),\n ...(session.tokens_cache_read != null ? { cacheRead: session.tokens_cache_read } : {}),\n ...(session.tokens_cache_write != null ? { cacheWrite: session.tokens_cache_write } : {}),\n ...(session.tokens_reasoning != null ? { reasoning: session.tokens_reasoning } : {}),\n }\n if (Object.keys(tk).length) meta.tokens = tk\n return { meta, messages }\n } finally {\n db.close()\n }\n}\n\nexport async function discoverOpenCodeSessions(\n cwd: string,\n since?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const dbPath = openCodeDbPath()\n let db: HermesDb\n try {\n db = await openReadonlySqlite(dbPath, \"opencode\")\n } catch (err) {\n // A missing db == opencode never ran here — a normal empty store, not a\n // discovery error (mirrors discoverHermesSessions).\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes(\"database not found\")) return []\n throw err\n }\n try {\n if (expectedId) {\n const row = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM session WHERE id = ?\").get(expectedId) as unknown as\n | OpenCodeSessionRow\n | undefined,\n )\n return row ? [openCodeRowToCandidate(row)] : []\n }\n const rows = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM session WHERE directory = ?\").all(cwd) as unknown as OpenCodeSessionRow[],\n )\n const sinceMs = since ? Date.parse(since) : NaN\n return rows\n .filter(r => {\n if (!Number.isFinite(sinceMs)) return true\n const last = r.time_updated ?? r.time_created\n return last === undefined || last >= sinceMs - 1000\n })\n .map(openCodeRowToCandidate)\n } finally {\n db.close()\n }\n}\n\nfunction openCodeRowToCandidate(row: OpenCodeSessionRow): ConversationCandidate {\n return {\n conversationId: row.id,\n ...(row.time_created ? { startedAt: new Date(row.time_created).toISOString() } : {}),\n ...(row.time_updated ? { lastActivityAt: new Date(row.time_updated).toISOString() } : {}),\n ...(row.title ? { preview: row.title } : {}),\n }\n}\n\n// ── mastracode-inprocess exporter (Mastra libsql) ─────────────────────\n//\n// Native store: ${AGENTPROTO_HOME:-~/.agentproto}/mastracode-inprocess/\n// storage.db — the dedicated Mastra libsql db the in-process arm writes\n// (adapters/mastracode-inprocess/src/client.ts). The arm's public\n// sessionId is the composite \"<resourceId>:<threadId>\"; agentproto records\n// it verbatim as adapterSessionId. Threads live in `mastra_threads` (keyed\n// by threadId) and messages in `mastra_messages` (keyed by `thread_id`,\n// each `content` a Mastra v2 `{format,parts}` JSON). The store has no cwd\n// column, so cwd-scoped discovery is not possible — but this in-process arm\n// always yields an adapterSessionId, so the exact-bind path is the only one\n// that ever runs in practice.\n\ninterface MastraThreadRow {\n id: string\n resourceId?: string\n title?: string\n createdAt?: string\n updatedAt?: string\n}\ninterface MastraMessageRow {\n role: string\n content: string\n createdAt: string\n}\n\nfunction mastracodeInprocessDbPath(): string {\n const home = process.env.AGENTPROTO_HOME ?? join(homedir(), \".agentproto\")\n return join(home, \"mastracode-inprocess\", \"storage.db\")\n}\n\n/** Split \"<resourceId>:<threadId>\"; tolerate a bare threadId (no colon). */\nfunction mastraThreadId(conversationId: string): string {\n const idx = conversationId.indexOf(\":\")\n return idx > 0 ? conversationId.slice(idx + 1) : conversationId\n}\n\n/** Pull user/assistant text, reasoning, and tool calls/results out of one\n * Mastra v2 `{format,parts}` content blob. */\nfunction mastraContentToMessage(\n role: ExportedMessage[\"role\"],\n content: string,\n): { message?: ExportedMessage; toolResults: { name?: string; text: string }[]; toolCalls: number } {\n const toolResults: { name?: string; text: string }[] = []\n let parsed: { parts?: unknown[] }\n try {\n parsed = JSON.parse(content) as { parts?: unknown[] }\n } catch {\n return { message: undefined, toolResults, toolCalls: 0 }\n }\n let text = \"\"\n let reasoning = \"\"\n const toolCalls: { name: string; args: string }[] = []\n for (const raw of parsed.parts ?? []) {\n if (!raw || typeof raw !== \"object\") continue\n const part = raw as {\n type?: string\n text?: string\n reasoning?: string\n toolInvocation?: { toolName?: string; args?: unknown; result?: unknown }\n }\n if (part.type === \"text\" && part.text) text += part.text\n else if (part.type === \"reasoning\" && part.reasoning) reasoning += part.reasoning\n else if (part.type === \"tool-invocation\" && part.toolInvocation) {\n const inv = part.toolInvocation\n const name = inv.toolName ?? \"tool\"\n toolCalls.push({ name, args: JSON.stringify(inv.args ?? {}) })\n if (inv.result !== undefined) {\n const r = inv.result as { content?: Array<{ type?: string; text?: string }> }\n const rtext = Array.isArray(r?.content)\n ? r.content.filter(c => c?.type === \"text\").map(c => c.text ?? \"\").join(\"\")\n : typeof inv.result === \"string\"\n ? inv.result\n : JSON.stringify(inv.result)\n toolResults.push({ name, text: rtext })\n }\n }\n // data-* and step-start parts are internal bookkeeping — skip.\n }\n let message: ExportedMessage | undefined\n if (text.trim() || reasoning.trim() || toolCalls.length) {\n message = { role }\n if (text.trim()) message.text = text.trim()\n if (reasoning.trim()) message.reasoning = reasoning.trim()\n if (toolCalls.length) message.toolCalls = toolCalls\n }\n return { message, toolResults, toolCalls: toolCalls.length }\n}\n\nexport async function exportMastracodeInprocessSession(conversationId: string): Promise<ExportedSession> {\n const threadId = mastraThreadId(conversationId)\n const dbPath = mastracodeInprocessDbPath()\n const db = await openReadonlySqlite(dbPath, \"mastracode-inprocess\")\n try {\n const thread = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM mastra_threads WHERE id = ?\").get(threadId) as unknown as\n | MastraThreadRow\n | undefined,\n )\n if (!thread) {\n throw new Error(\n `mastracode-inprocess: thread \"${threadId}\" not found in ${dbPath}. ` +\n `The sessionId is \"<resourceId>:<threadId>\"; only the threadId is looked up.`,\n )\n }\n const rows = withRetryOnBusy(\n () =>\n db\n .prepare('SELECT role, content, createdAt FROM mastra_messages WHERE thread_id = ? ORDER BY \"createdAt\" ASC')\n .all(threadId) as unknown as MastraMessageRow[],\n )\n const messages: ExportedMessage[] = []\n let toolCallCount = 0\n for (const r of rows) {\n // Mastra tags user turns with role \"signal\"; assistant with \"assistant\".\n const role: ExportedMessage[\"role\"] = r.role === \"assistant\" ? \"assistant\" : \"user\"\n const { message, toolResults, toolCalls } = mastraContentToMessage(role, r.content)\n if (message) messages.push(message)\n toolCallCount += toolCalls\n for (const tr of toolResults) {\n messages.push({ role: \"tool\", text: tr.text, ...(tr.name ? { toolName: tr.name } : {}) })\n }\n }\n const meta: ExportedSessionMeta = { source: \"mastracode-inprocess\" }\n if (thread.title) meta.title = thread.title\n if (thread.createdAt) meta.startedAt = thread.createdAt\n if (thread.updatedAt) meta.endedAt = thread.updatedAt\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n return { meta, messages }\n } finally {\n db.close()\n }\n}\n\nexport async function discoverMastracodeInprocessSessions(\n _cwd: string,\n since?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const dbPath = mastracodeInprocessDbPath()\n let db: HermesDb\n try {\n db = await openReadonlySqlite(dbPath, \"mastracode-inprocess\")\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n if (msg.includes(\"database not found\")) return []\n throw err\n }\n try {\n // Exact-bind only: `mastra_threads` has no cwd column, so a cwd-scoped\n // scan is impossible. Absent an expectedId there is nothing to safely\n // scope to, so return none (this in-process arm always supplies an\n // adapterSessionId, so the exact-bind path is the real one).\n if (!expectedId) return []\n const threadId = mastraThreadId(expectedId)\n const thread = withRetryOnBusy(\n () => db.prepare(\"SELECT * FROM mastra_threads WHERE id = ?\").get(threadId) as unknown as\n | MastraThreadRow\n | undefined,\n )\n if (!thread) return []\n const sinceMs = since ? Date.parse(since) : NaN\n if (Number.isFinite(sinceMs) && thread.updatedAt) {\n const upd = Date.parse(thread.updatedAt)\n if (Number.isFinite(upd) && upd < sinceMs - 1000) return []\n }\n return [\n {\n // Echo back the full composite id so callers/read() round-trip it.\n conversationId: expectedId,\n ...(thread.createdAt ? { startedAt: thread.createdAt } : {}),\n ...(thread.updatedAt ? { lastActivityAt: thread.updatedAt } : {}),\n ...(thread.title ? { preview: thread.title } : {}),\n },\n ]\n } finally {\n db.close()\n }\n}\n\n// ── pi exporter (JSON-over-stdio session log) ─────────────────────────\n//\n// Native store: ~/.pi/agent/sessions/<cwd-slug>/<ts>_<uuid>.jsonl — pi\n// writes one append-only JSONL per conversation. The first line is a\n// `session` record carrying the uuid `id` (== pi's RPC `sessionId`, which\n// agentproto records as adapterSessionId — pi's client captures it from\n// get_state) and the `cwd`. `message` lines carry the turns; the\n// cwd-slug directory encoding is version-dependent, so discovery scans and\n// keys off each file's authoritative `session.cwd` rather than the slug.\n\nfunction piSessionsDir(): string {\n return join(homedir(), \".pi\", \"agent\", \"sessions\")\n}\n\ninterface PiLine {\n type?: string\n id?: string\n cwd?: string\n timestamp?: string\n provider?: string\n modelId?: string\n message?: {\n role?: string\n toolName?: string\n isError?: boolean\n content?: unknown\n }\n}\n\n/** Text of pi content blocks (`{type:\"text\",text}`), string-tolerant. */\nfunction piBlocksText(content: unknown): string {\n if (typeof content === \"string\") return content\n if (!Array.isArray(content)) return \"\"\n let acc = \"\"\n for (const c of content) {\n if (c && typeof c === \"object\") {\n const b = c as { type?: string; text?: string }\n if (b.type === \"text\" && typeof b.text === \"string\") acc += b.text\n }\n }\n return acc\n}\n\nasync function walkPiSessionFiles(dir: string): Promise<string[]> {\n let entries: Dirent[]\n try {\n entries = await fs.readdir(dir, { withFileTypes: true })\n } catch {\n return []\n }\n const out: string[] = []\n for (const e of entries) {\n const p = join(dir, e.name)\n if (e.isDirectory()) out.push(...(await walkPiSessionFiles(p)))\n else if (e.isFile() && e.name.endsWith(\".jsonl\")) out.push(p)\n }\n return out\n}\n\nasync function findPiSessionFile(conversationId: string): Promise<string | undefined> {\n const files = await walkPiSessionFiles(piSessionsDir())\n const byName = files.find(f => f.endsWith(`_${conversationId}.jsonl`))\n if (byName) return byName\n for (const f of files) {\n const first = await readFirstJsonLine(f)\n if (!first) continue\n try {\n const meta = JSON.parse(first) as PiLine\n if (meta.type === \"session\" && meta.id === conversationId) return f\n } catch {\n // skip\n }\n }\n return undefined\n}\n\nexport async function exportPiSession(conversationId: string): Promise<ExportedSession> {\n const file = await findPiSessionFile(conversationId)\n if (!file) {\n throw new Error(\n `pi: no session file for conversation \"${conversationId}\" under ${piSessionsDir()}.`,\n )\n }\n const stream = createReadStream(file, { encoding: \"utf8\" })\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n const messages: ExportedMessage[] = []\n let toolCallCount = 0\n let startedAt: string | undefined\n let model: string | undefined\n\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let entry: PiLine\n try {\n entry = JSON.parse(trimmed) as PiLine\n } catch {\n continue\n }\n if (entry.type === \"session\") {\n startedAt = entry.timestamp\n continue\n }\n if (entry.type === \"model_change\") {\n model = entry.provider ? `${entry.provider}/${entry.modelId ?? \"\"}` : entry.modelId\n continue\n }\n if (entry.type !== \"message\" || !entry.message) continue\n const m = entry.message\n const content = m.content\n\n if (m.role === \"toolResult\") {\n const text = piBlocksText(content)\n messages.push({\n role: \"tool\",\n text: m.isError ? `[error] ${text}` : text,\n ...(m.toolName ? { toolName: m.toolName } : {}),\n })\n continue\n }\n\n const role: ExportedMessage[\"role\"] = m.role === \"assistant\" ? \"assistant\" : \"user\"\n let text = \"\"\n let reasoning = \"\"\n const toolCalls: { name: string; args: string }[] = []\n if (typeof content === \"string\") {\n text = content\n } else if (Array.isArray(content)) {\n for (const raw of content) {\n if (!raw || typeof raw !== \"object\") continue\n const part = raw as {\n type?: string\n text?: string\n thinking?: string\n name?: string\n arguments?: unknown\n }\n if (part.type === \"text\" && part.text) text += part.text\n else if (part.type === \"thinking\" && part.thinking) reasoning += part.thinking\n else if (part.type === \"toolCall\") {\n toolCalls.push({ name: part.name ?? \"tool\", args: JSON.stringify(part.arguments ?? {}) })\n toolCallCount += 1\n }\n }\n }\n if (text.trim() || reasoning.trim() || toolCalls.length) {\n const em: ExportedMessage = { role }\n if (text.trim()) em.text = text.trim()\n if (reasoning.trim()) em.reasoning = reasoning.trim()\n if (toolCalls.length) em.toolCalls = toolCalls\n messages.push(em)\n }\n }\n\n const meta: ExportedSessionMeta = { source: \"pi\" }\n if (startedAt) meta.startedAt = startedAt\n if (model) meta.model = model\n meta.messageCount = messages.length\n meta.toolCallCount = toolCallCount\n return { meta, messages }\n}\n\nexport async function discoverPiSessions(\n cwd: string,\n since?: string,\n until?: string,\n expectedId?: string,\n): Promise<ConversationCandidate[]> {\n const files = await walkPiSessionFiles(piSessionsDir())\n const sinceMs = since ? Date.parse(since) : NaN\n const untilMs = until ? Date.parse(until) : NaN\n const scored: { candidate: ConversationCandidate; mtimeMs: number }[] = []\n\n for (const f of files) {\n let mtimeMs: number\n try {\n mtimeMs = (await fs.stat(f)).mtimeMs\n } catch {\n continue\n }\n if (Number.isFinite(sinceMs) && mtimeMs < sinceMs - 1000) continue\n const first = await readFirstJsonLine(f)\n if (!first) continue\n let meta: PiLine\n try {\n meta = JSON.parse(first) as PiLine\n } catch {\n continue\n }\n if (meta.type !== \"session\" || !meta.id) continue\n if (expectedId) {\n if (meta.id !== expectedId) continue\n } else if (meta.cwd !== cwd) {\n continue\n }\n const startedAt = meta.timestamp\n if (Number.isFinite(untilMs) && startedAt) {\n const s = Date.parse(startedAt)\n if (Number.isFinite(s) && s > untilMs) continue\n }\n scored.push({\n candidate: {\n conversationId: meta.id,\n ...(startedAt ? { startedAt } : {}),\n lastActivityAt: new Date(mtimeMs).toISOString(),\n },\n mtimeMs,\n })\n }\n\n scored.sort((a, b) => b.mtimeMs - a.mtimeMs)\n return scored.map(s => s.candidate)\n}\n\n// ── Strategy registry ─────────────────────────────────────────────────\n\nconst EXPORT_STRATEGIES: Record<string, ExportStrategy> = {\n \"claude-code\": {\n exportSession: exportClaudeCodeSession,\n },\n hermes: {\n exportSession: (id: string) => exportHermesSession(id),\n },\n codex: {\n exportSession: (id: string) => exportCodexSession(id),\n },\n opencode: {\n exportSession: (id: string) => exportOpenCodeSession(id),\n },\n \"mastracode-inprocess\": {\n exportSession: (id: string) => exportMastracodeInprocessSession(id),\n },\n pi: {\n exportSession: (id: string) => exportPiSession(id),\n },\n}\n\n// ── Public API ────────────────────────────────────────────────────────\n\nexport type ExportSource = \"auto\" | \"native\" | \"daemon\"\n\nexport interface ExportAgentSessionInput {\n /** agentproto session id (sess_xxx) or an adapter-native id */\n sessionId: string\n registry: SessionsRegistry\n format?: \"markdown\" | \"json\"\n maxToolChars?: number\n /** Override adapter slug when sessionId is an adapter-native id */\n adapter?: string\n /** Override cwd when sessionId is an adapter-native id (claude-code only) */\n cwd?: string\n /** Which backend to read from. \"auto\" (default) prefers the adapter's\n * own native store and falls back to agentproto's own events.jsonl\n * capture when there isn't one (or it can't be read); \"native\" / \"daemon\"\n * force one and surface its own error instead of falling back. */\n source?: ExportSource\n}\n\nexport interface ExportAgentSessionResult {\n sessionId: string\n adapter: string\n format: string\n meta: ExportedSessionMeta\n content: string\n}\n\nexport async function exportAgentSession(\n input: ExportAgentSessionInput,\n): Promise<ExportAgentSessionResult> {\n const { sessionId, registry, format = \"markdown\", maxToolChars = 1200 } = input\n const source = input.source ?? \"auto\"\n\n // Resolve via registry first. `err` closes over `adapterSlug` so it\n // returns the resolved slug (not the raw input) after registry lookup.\n let adapterSlug = input.adapter\n let cwd = input.cwd\n let adapterSessionId = sessionId\n let configDir: string | undefined\n\n const err = (msg: string): ExportAgentSessionResult => ({\n sessionId,\n adapter: adapterSlug ?? \"unknown\",\n format,\n meta: {},\n content: `Error: ${msg}`,\n })\n\n const desc = registry.findByIdOrName(sessionId)\n // events.jsonl is always keyed by the agentproto session id — never the\n // adapter-native id substituted below for the native strategies.\n const daemonSessionId = desc?.id ?? sessionId\n if (desc) {\n adapterSlug = adapterSlug ?? desc.adapterSlug\n cwd = cwd ?? desc.cwd\n // A config-dir-isolated session's transcripts live under its own\n // CLAUDE_CONFIG_DIR, not ~/.claude (#824) — thread it to the exporter.\n configDir = desc.adapterConfigDir\n // prefer the adapter-native id over the agentproto id\n if (desc.adapterSessionId) adapterSessionId = desc.adapterSessionId\n }\n\n const tryNative = async (): Promise<ExportedSession> => {\n if (!adapterSlug) {\n throw new Error(\n `session \"${sessionId}\" not found in registry and no adapter override supplied.\\n` +\n `Pass adapter explicitly or use a known session id (sess_xxx or name).`,\n )\n }\n const exporter = EXPORT_STRATEGIES[adapterSlug]\n if (!exporter) {\n const supported = Object.keys(EXPORT_STRATEGIES).join(\", \")\n throw new Error(\n `no exporter for adapter \"${adapterSlug}\". Supported: ${supported}.\\n` +\n `Only sessions spawned via claude-code or hermes can be exported.`,\n )\n }\n return exporter.exportSession(adapterSessionId, cwd, configDir)\n }\n\n const tryDaemon = (): Promise<ExportedSession> => exportDaemonEventsSession(daemonSessionId, desc)\n\n let session: ExportedSession\n try {\n if (source === \"native\") {\n session = await tryNative()\n } else if (source === \"daemon\") {\n session = await tryDaemon()\n } else {\n try {\n session = await tryNative()\n } catch (nativeErr) {\n try {\n session = await tryDaemon()\n } catch (daemonErr) {\n const nativeMsg = nativeErr instanceof Error ? nativeErr.message : String(nativeErr)\n const daemonMsg = daemonErr instanceof Error ? daemonErr.message : String(daemonErr)\n return err(`${nativeMsg}\\n(daemon-events fallback also failed: ${daemonMsg})`)\n }\n }\n }\n } catch (e) {\n return err(e instanceof Error ? e.message : String(e))\n }\n\n const content =\n format === \"json\"\n ? renderJson(session)\n : renderMarkdown(session, { maxToolChars })\n\n return {\n sessionId,\n adapter: adapterSlug ?? (session.meta.source === \"daemon-events\" ? \"daemon\" : \"unknown\"),\n format,\n meta: session.meta,\n content,\n }\n}\n","/**\n * Conversation as pivot: one store abstraction per provider, read on any\n * session. A \"conversation\" is the provider's own persisted session — the\n * durable object. An agentproto session (ACP or PTY) is just an attachment\n * to it. `CONVERSATION_STORES` is the single source of truth for \"where does\n * this provider keep its conversations, and how do I read/attach to one\" —\n * `RESUME_STRATEGIES` (resume-strategies.ts) and `EXPORT_STRATEGIES`\n * (transcript-export.ts) are thin adapters over it so the two historically\n * drifted tables can never diverge again.\n */\n\nimport { promises as fs, createReadStream } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { createInterface } from \"node:readline\"\nimport { join, resolve } from \"node:path\"\nimport type { ExportedSession, ExportedMessage } from \"./transcript-export.js\"\n\n/** Where a captured conversation id is recorded on the descriptor.\n * Same union as resume-strategies.ts's ResumeMetadataKey — re-exported\n * from there, NOT redefined, so the two can never drift. */\nexport type { ResumeMetadataKey } from \"./resume-strategies.js\"\nimport type { ResumeMetadataKey } from \"./resume-strategies.js\"\n\n/** One conversation found in a provider's native store, plus enough\n * evidence for a caller (or a human) to pick between several. */\nexport interface ConversationCandidate {\n /** The provider-native conversation id (claude: the jsonl uuid). */\n conversationId: string\n startedAt?: string\n lastActivityAt?: string\n messageCount?: number\n /** First user message, truncated to ~120 chars. Disambiguation aid. */\n preview?: string\n /** Which attachment wrote the tail, provider-native vocabulary\n * (claude-code: \"sdk-ts\" = ACP arm, \"cli\" = native TUI). */\n lastWriter?: string\n}\n\nexport interface DiscoverInput {\n cwd: string\n /** Only consider conversations active at-or-after this ISO ts. */\n since?: string\n /** Only consider conversations that STARTED at-or-before this ISO ts —\n * an upper bound, typically a dead session's `endedAt`. A conversation\n * whose own first message postdates it provably belongs to some other,\n * later session. Omit for a live/ongoing session (no `endedAt` yet) —\n * it must keep matching conversations that started after `since` with\n * no upper bound. Conservative: a candidate with no discoverable\n * `startedAt` is never dropped by this filter. */\n until?: string\n /** The requesting session's attachment mode, in ABSTRACT (provider-\n * agnostic) vocabulary — `\"native\"` for a real PTY/TUI attach,\n * `\"acp\"` for the agent-cli/ACP arm. When set, drops candidates whose\n * `lastWriter` is present and maps to the OPPOSITE mode (a native PTY's\n * conversation is never written by the ACP arm, and vice versa).\n * Conservative: a candidate with no `lastWriter` is never dropped, and\n * omitting this field applies no mode filtering at all. */\n attachmentMode?: \"native\" | \"acp\"\n /** The session's isolated provider config dir (`SessionDescriptor.\n * adapterConfigDir` — the `CLAUDE_CONFIG_DIR` the daemon spawns\n * claude-code with since the #824 MCP-isolation fix). When set, the\n * provider wrote its transcripts under THIS dir, not its global\n * default (`~/.claude`), so discovery must look there. Omit for a\n * native PTY / pre-#824 session — the global store applies. Only\n * claude-code keys its store off a config dir; other stores ignore\n * this field. */\n configDir?: string\n /** When set, bind to EXACTLY this conversation or return [].\n * MUST NOT fall back to a recency guess — see invariants. */\n expectedId?: string\n}\n\nexport interface ConversationStore {\n storeAs: ResumeMetadataKey\n /** Capture the conversation id from a live output line; group 1 = the id. */\n outputHint?: RegExp\n /** argv that attaches a NATIVE PTY to an existing conversation.\n * Omitted ⇒ this provider has no native attach path. */\n attachArgv?(conversationId: string): string[]\n /** The env var `attachArgv`'s spawned PTY reads to find its conversation\n * store, when the store is keyed off a per-session isolated config dir\n * (`DiscoverInput.configDir`'s doc — today only claude-code's\n * `CLAUDE_CONFIG_DIR`; see #824). When set, `session_restart`'s\n * `pty-native` branch (session-tools.ts) passes\n * `{ [configDirEnvVar]: descriptor.adapterConfigDir }` to the resumed\n * PTY's env — omitting it is what leaves a `claude --resume <id>`\n * looking in the global `~/.claude` for a transcript that only exists\n * under the session's isolated dir, failing with \"No conversation\n * found\" before the resumed session's first turn. Omitted for stores\n * with no config-dir isolation (hermes: global store only). */\n configDirEnvVar?: string\n /** Find conversations in the provider's native store. `[]` = none —\n * a normal answer (e.g. the PTY is a bash shell). Never throws for\n * \"nothing found\"; throws only on a genuinely unreadable store. */\n discover(input: DiscoverInput): Promise<ConversationCandidate[]>\n /** Read a full conversation into the shared export model. `configDir`\n * has the same semantics as `DiscoverInput.configDir`. */\n read(conversationId: string, cwd?: string, configDir?: string): Promise<ExportedSession>\n /** Follow a conversation live. Resolves to an unsubscribe fn.\n * Omitted ⇒ no live tail for this provider (caller polls `read`). */\n follow?(input: {\n conversationId: string\n cwd?: string\n onMessage: (m: ExportedMessage) => void\n }): Promise<() => void>\n}\n\n// ── claude-code store ──────────────────────────────────────────────────\n//\n// Native store: ~/.claude/projects/<cwd-encoded>/<uuid>.jsonl, one file per\n// conversation. `<cwd-encoded>` is the absolute cwd run through\n// `claudeProjectSlug` (claude's own convention — see that function's\n// docblock for the empirically-verified rule). A daemon-spawned session is\n// config-dir-isolated (#824) and its store root is the session's\n// `CLAUDE_CONFIG_DIR` instead of `~/.claude` — same `projects/<slug>`\n// layout under it; see `DiscoverInput.configDir`.\n\ninterface ClaudeJsonlMeta {\n type?: string\n timestamp?: string\n entrypoint?: string\n message?: { role?: string; content?: unknown }\n}\n\n/**\n * Claude Code's own `cwd` → project-dir-name encoder.\n *\n * The real rule (verified empirically against `~/.claude/projects/`\n * directory names for dozens of known cwds, including dotted worktree\n * paths and macOS temp dirs): every character that is NOT `[a-zA-Z0-9]`\n * is replaced 1:1 with `-`. Crucially, runs of consecutive non-alnum\n * characters are NOT collapsed — each input character produces exactly\n * one output character.\n *\n * This used to be `cwd.replace(/\\//g, \"-\")` — slashes only. That's wrong\n * for any cwd containing a dot (every `.agentproto` worktree, any\n * dotdir), an underscore-prefixed segment, a space, etc., because those\n * characters are left untouched instead of becoming `-`, so the computed\n * directory never matches the one claude actually created.\n *\n * Reconstruction proof (both real, both `ls ~/.claude/projects/`-verified):\n * cwd /Users/jeremy/.agentproto/worktrees/ts/gc-fresh-hold\n * → -Users-jeremy--agentproto-worktrees-ts-gc-fresh-hold\n * (note the \"--\" from \"/.\" — one dash for \"/\", one for \".\", not collapsed)\n *\n * cwd /Volumes/SSDExternalMacStudio/Code/_agentproto-worktrees/adapter-claude-sdk\n * → -Volumes-SSDExternalMacStudio-Code--agentproto-worktrees-adapter-claude-sdk\n * (same double-dash shape, this time from \"/_\")\n */\nexport function claudeProjectSlug(cwd: string): string {\n return cwd.replace(/[^a-zA-Z0-9]/g, \"-\")\n}\n\n/** Exported so `conversation-index.ts` can resolve the same directory\n * without re-deriving the slug rule itself.\n *\n * `configDir` is the session's isolated `CLAUDE_CONFIG_DIR` (see\n * `DiscoverInput.configDir`): the SDK mirrors the global layout under it\n * (`<configDir>/projects/<slug>/<uuid>.jsonl`, empirically verified\n * against real `~/.agentproto/adapter-config/sess_<id>` trees), so the\n * only difference is the base dir. */\nexport function claudeCodeProjectDir(cwd: string, configDir?: string): string {\n const base = configDir ?? resolve(homedir(), \".claude\")\n return resolve(base, \"projects\", claudeProjectSlug(cwd))\n}\n\nfunction extractFirstText(content: unknown): string | undefined {\n if (typeof content === \"string\") {\n const t = content.trim()\n return t || undefined\n }\n if (Array.isArray(content)) {\n for (const block of content) {\n if (\n block &&\n typeof block === \"object\" &&\n (block as { type?: string }).type === \"text\" &&\n typeof (block as { text?: unknown }).text === \"string\"\n ) {\n const t = ((block as { text: string }).text).trim()\n if (t) return t\n }\n }\n }\n return undefined\n}\n\n/** Light line-scan for candidate metadata — NOT the full transcript parser\n * (that's exportClaudeCodeSession). Streams the file so large jsonl files\n * don't get pulled fully into memory. */\nasync function scanClaudeJsonl(filePath: string): Promise<{\n startedAt?: string\n lastActivityAt?: string\n messageCount: number\n preview?: string\n lastWriter?: string\n}> {\n const stream = createReadStream(filePath, { encoding: \"utf8\" })\n const rl = createInterface({ input: stream, crlfDelay: Infinity })\n\n let startedAt: string | undefined\n let lastActivityAt: string | undefined\n let messageCount = 0\n let preview: string | undefined\n let lastWriter: string | undefined\n\n for await (const line of rl) {\n const trimmed = line.trim()\n if (!trimmed) continue\n let entry: ClaudeJsonlMeta\n try {\n entry = JSON.parse(trimmed) as ClaudeJsonlMeta\n } catch {\n continue\n }\n\n if (typeof entry.timestamp === \"string\") {\n if (!startedAt) startedAt = entry.timestamp\n lastActivityAt = entry.timestamp\n }\n if (typeof entry.entrypoint === \"string\") {\n lastWriter = entry.entrypoint\n }\n if (entry.type === \"user\" || entry.type === \"assistant\") {\n messageCount += 1\n if (preview === undefined && entry.type === \"user\") {\n const text = extractFirstText(entry.message?.content)\n if (text !== undefined) {\n preview = text.length > 120 ? text.slice(0, 120) : text\n }\n }\n }\n }\n\n return { startedAt, lastActivityAt, messageCount, preview, lastWriter }\n}\n\nasync function buildClaudeCandidate(\n filePath: string,\n conversationId: string,\n): Promise<ConversationCandidate> {\n const scanned = await scanClaudeJsonl(filePath)\n return { conversationId, ...scanned }\n}\n\n/** Maps an abstract `attachmentMode` to claude's own jsonl `entrypoint`\n * vocabulary. Kept local to this store — callers deal only in\n * `\"native\" | \"acp\"`, never `\"cli\" | \"sdk-ts\"`. */\nfunction claudeEntrypointFor(mode: \"native\" | \"acp\"): string {\n return mode === \"native\" ? \"cli\" : \"sdk-ts\"\n}\n\nasync function discoverClaudeCode(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { cwd, since, until, attachmentMode, configDir, expectedId } = input\n const dir = claudeCodeProjectDir(cwd, configDir)\n\n // Ground truth beats heuristic: bind to exactly the conversation we were\n // asked about, never whichever transcript happens to be newest. Never\n // falls through to the mtime path below — see invariants.\n if (expectedId) {\n const filePath = join(dir, `${expectedId}.jsonl`)\n try {\n await fs.stat(filePath)\n } catch {\n return []\n }\n return [await buildClaudeCandidate(filePath, expectedId)]\n }\n\n let entries: string[]\n try {\n entries = await fs.readdir(dir)\n } catch {\n return []\n }\n const jsonlFiles = entries.filter(e => e.endsWith(\".jsonl\"))\n if (jsonlFiles.length === 0) return []\n\n const sinceMs = since ? Date.parse(since) : NaN\n const untilMs = until ? Date.parse(until) : NaN\n const wantEntrypoint = attachmentMode ? claudeEntrypointFor(attachmentMode) : undefined\n const scored: { candidate: ConversationCandidate; mtimeMs: number }[] = []\n for (const f of jsonlFiles) {\n const filePath = join(dir, f)\n let mtimeMs: number\n try {\n mtimeMs = (await fs.stat(filePath)).mtimeMs\n } catch {\n continue\n }\n if (Number.isFinite(sinceMs) && mtimeMs < sinceMs - 1000) continue\n const conversationId = f.replace(/\\.jsonl$/, \"\")\n const candidate = await buildClaudeCandidate(filePath, conversationId)\n // `until` is an upper bound on the conversation's own first message —\n // provably not this session's if it started after the session ended.\n // Conservative: no discoverable startedAt ⇒ never dropped.\n if (Number.isFinite(untilMs) && candidate.startedAt !== undefined) {\n const startedMs = Date.parse(candidate.startedAt)\n if (Number.isFinite(startedMs) && startedMs > untilMs) continue\n }\n // Attachment-mode match: a native PTY's conversation is never written\n // by the ACP arm and vice versa. Conservative: no lastWriter ⇒ never\n // dropped, and an unset attachmentMode applies no filtering at all.\n if (wantEntrypoint !== undefined && candidate.lastWriter !== undefined && candidate.lastWriter !== wantEntrypoint) {\n continue\n }\n scored.push({ candidate, mtimeMs })\n }\n\n // Newest first — mirrors the old fsProbe's mtime-desc pick, and gives\n // callers of `discover` (which may just want \"the likely one\") a sane\n // default ordering without silently collapsing the list.\n scored.sort((a, b) => b.mtimeMs - a.mtimeMs)\n return scored.map(s => s.candidate)\n}\n\nasync function readClaudeCode(conversationId: string, cwd?: string, configDir?: string): Promise<ExportedSession> {\n // Dynamic import, not a top-level one: resume-strategies.ts is its own\n // lean tsup entry (splitting:false) and pulls this module in as a value\n // import via CONVERSATION_STORES. esbuild still bundles transcript-\n // export.ts's bytes into that entry either way (no code-splitting means\n // no separate chunk to defer to) — what the dynamic import buys is\n // deferred MODULE INIT: transcript-export.ts's top-level code only runs\n // the first time `read()` is actually called, not merely by importing\n // resume-strategies.ts. See resume-strategies.ts's splitting:false note.\n const { exportClaudeCodeSession } = await import(\"./transcript-export.js\")\n return exportClaudeCodeSession(conversationId, cwd, configDir)\n}\n\n// ── hermes store ────────────────────────────────────────────────────\n//\n// Native store: ~/.hermes/state.db, a sqlite `sessions` table keyed by\n// `id` (the agentproto UUID passed as resumeSessionId — the same id\n// agentproto records as `adapterSessionId`, unlike claude-code's on-disk\n// jsonl uuid). It has a `cwd` column (live-verified 2026-07-17), so\n// cwd-scoped discovery is possible, unlike a plain folder-of-files store.\n\nasync function discoverHermes(input: DiscoverInput): Promise<ConversationCandidate[]> {\n // Dynamic import, not a top-level one — same reasoning as readClaudeCode\n // above: keeps transcript-export.ts's sqlite plumbing out of\n // resume-strategies.ts's lean tsup entry until a hermes store method\n // actually runs.\n const { discoverHermesSessions } = await import(\"./transcript-export.js\")\n return discoverHermesSessions(input.cwd, input.since, input.expectedId)\n}\n\nasync function readHermes(conversationId: string): Promise<ExportedSession> {\n const { exportHermesSession } = await import(\"./transcript-export.js\")\n return exportHermesSession(conversationId)\n}\n\n// ── codex store ───────────────────────────────────────────────────────\n//\n// Native store: $CODEX_HOME/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl.\n// The rollout uuid == the ACP session id agentproto records as\n// `adapterSessionId` (verified empirically), so a codex session's export\n// binds by that id directly (step 1 of the conversation-read ladder), and\n// `discover` scopes a PTY-only codex by the session_meta `cwd`. Reader in\n// transcript-export.ts, dynamically imported for the same reason as\n// readClaudeCode above (keep it out of resume-strategies.ts's lean entry).\n\nasync function discoverCodex(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { discoverCodexSessions } = await import(\"./transcript-export.js\")\n return discoverCodexSessions(input.cwd, input.since, input.until, input.expectedId)\n}\n\nasync function readCodex(conversationId: string): Promise<ExportedSession> {\n const { exportCodexSession } = await import(\"./transcript-export.js\")\n return exportCodexSession(conversationId)\n}\n\n// ── opencode store ────────────────────────────────────────────────────\n//\n// Native store: ${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db. The\n// `session` table's id is the `ses_…` id agentproto records as\n// `adapterSessionId` (verified), and its `directory` column is the cwd — so\n// discovery is cwd-scoped like hermes.\n\nasync function discoverOpenCode(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { discoverOpenCodeSessions } = await import(\"./transcript-export.js\")\n return discoverOpenCodeSessions(input.cwd, input.since, input.expectedId)\n}\n\nasync function readOpenCode(conversationId: string): Promise<ExportedSession> {\n const { exportOpenCodeSession } = await import(\"./transcript-export.js\")\n return exportOpenCodeSession(conversationId)\n}\n\n// ── mastracode-inprocess store ────────────────────────────────────────\n//\n// Native store: ${AGENTPROTO_HOME:-~/.agentproto}/mastracode-inprocess/\n// storage.db (Mastra libsql). sessionId is \"<resourceId>:<threadId>\";\n// `read` splits out the threadId. No cwd column, so `discover` is\n// exact-bind only (this in-process arm always supplies an adapterSessionId).\n\nasync function discoverMastracodeInprocess(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { discoverMastracodeInprocessSessions } = await import(\"./transcript-export.js\")\n return discoverMastracodeInprocessSessions(input.cwd, input.since, input.expectedId)\n}\n\nasync function readMastracodeInprocess(conversationId: string): Promise<ExportedSession> {\n const { exportMastracodeInprocessSession } = await import(\"./transcript-export.js\")\n return exportMastracodeInprocessSession(conversationId)\n}\n\n// ── pi store ──────────────────────────────────────────────────────────\n//\n// Native store: ~/.pi/agent/sessions/<cwd-slug>/<ts>_<uuid>.jsonl. The uuid\n// == pi's RPC sessionId recorded as `adapterSessionId`; discovery keys off\n// each file's authoritative `session.cwd` (the slug encoding is\n// version-dependent, so it is never trusted for scoping).\n\nasync function discoverPi(input: DiscoverInput): Promise<ConversationCandidate[]> {\n const { discoverPiSessions } = await import(\"./transcript-export.js\")\n return discoverPiSessions(input.cwd, input.since, input.until, input.expectedId)\n}\n\nasync function readPi(conversationId: string): Promise<ExportedSession> {\n const { exportPiSession } = await import(\"./transcript-export.js\")\n return exportPiSession(conversationId)\n}\n\nexport const CONVERSATION_STORES: Record<string, ConversationStore> = {\n \"claude-code\": {\n storeAs: \"claudeResumeId\",\n // Printed by claude on graceful exit when session persistence is on\n // (default). Example: `claude --resume 0e483f81-1a44-4bec-9667-b37158450296`\n outputHint: /claude\\s+--resume\\s+([0-9a-f-]{8,})/i,\n attachArgv: (conversationId: string) => [\"claude\", \"--resume\", conversationId],\n configDirEnvVar: \"CLAUDE_CONFIG_DIR\",\n discover: discoverClaudeCode,\n read: readClaudeCode,\n },\n hermes: {\n storeAs: \"hermesResumeId\",\n // `hermes acp` is the ACP arm (bin_args in adapters/hermes/src/index.ts);\n // `--resume SESSION --tui` is the native TUI resume path — same binary,\n // different flags, unlike claude-code where the two arms are different\n // binaries. Verified via `hermes --help`: `--resume SESSION, -r` =\n // \"Resume a previous session by ID or title\", `--tui` = the real TUI.\n attachArgv: (conversationId: string) => [\"hermes\", \"--resume\", conversationId, \"--tui\"],\n discover: discoverHermes,\n read: readHermes,\n },\n // codex-acp writes no resume flag we sniff, and there's no native PTY\n // reattach argv to declare — export/read only, so no outputHint/attachArgv.\n codex: {\n storeAs: \"codexResumeId\",\n discover: discoverCodex,\n read: readCodex,\n },\n opencode: {\n storeAs: \"openCodeResumeId\",\n discover: discoverOpenCode,\n read: readOpenCode,\n },\n \"mastracode-inprocess\": {\n storeAs: \"mastracodeInprocessResumeId\",\n discover: discoverMastracodeInprocess,\n read: readMastracodeInprocess,\n },\n pi: {\n storeAs: \"piResumeId\",\n discover: discoverPi,\n read: readPi,\n },\n}\n\n/**\n * Bare (non-resume) launch argv for a provider's native terminal/TUI — the\n * \"start fresh\" counterpart to `attachArgv`, used to open a NEW native\n * session (e.g. a harness card's \"Terminal\" button) rather than reattach an\n * existing conversation.\n *\n * Coverage is deliberately BROADER than `attachArgv`'s: reattach needs a\n * documented resume flag, but a fresh launch only needs the CLI's\n * interactive arm. npx-spawned adapters use the same npx form here so the\n * terminal works wherever the adapter itself works, PATH binary or not.\n *\n * Absent on purpose (no interactive arm to launch):\n * - `mastracode-inprocess` — in-process SDK, nothing to exec\n * - `mastra-agent`, `claude-sdk` — first-party ACP servers, no TUI\n * - `antigravity` — `agy` is headless-only (`-p`/stream-json), no TUI\n */\nexport const NATIVE_LAUNCH_ARGV: Record<string, string[]> = {\n \"claude-code\": [\"claude\"],\n hermes: [\"hermes\", \"--tui\"],\n // Bare arm of the same npx package the adapter spawns IS the TUI.\n opencode: [\"npx\", \"-y\", \"opencode-ai\"],\n mastracode: [\"npx\", \"-y\", \"mastracode\"],\n // The adapter bundles the codex-acp wrapper (ACP-only); the interactive\n // Codex TUI lives in @openai/codex, fetched by npx on first use.\n codex: [\"npx\", \"-y\", \"@openai/codex\"],\n // ACP arms add flags/subcommands to these binaries; bare is interactive.\n gemini: [\"gemini\"],\n \"grok-cli\": [\"grok\"],\n pi: [\"pi\"],\n jcode: [\"jcode\"],\n // `openclaw chat` = \"Open a local terminal UI (alias for tui --local)\".\n openclaw: [\"openclaw\", \"chat\"],\n // Generic ACP catalog CLIs whose ACP arm is a separate binary/subcommand;\n // the bare bin is the interactive TUI.\n \"gemini-cli\": [\"gemini\"],\n \"qwen-code\": [\"qwen\"],\n \"mistral-vibe\": [\"vibe\"],\n \"kimi-cli\": [\"kimi\"],\n}\n","/**\n * Per-adapter resume strategies — the daemon's view of \"how do I\n * continue a previous session for THIS adapter?\".\n *\n * The driver already has an `AgentCliContinuation` declaration in\n * the adapter manifest (AIP-45). That covers strategy NAMES\n * (`native-resume`, `pinned-session`, `transcript`, `none`) but is\n * silent on the mechanics that live OUTSIDE the runtime — like\n * \"where on disk does this adapter store its conversations?\" or\n * \"what argv do I pass to resume into PTY mode?\".\n *\n * This table is that practical bridge. Each entry declares three\n * optional hooks:\n *\n * outputHint regex matched against each output line; group 1 is\n * the resume id. Stored as `desc.resumeMetadata[storeAs]`.\n * fsProbe async function that probes a per-adapter directory\n * for a stored session id, scoped to a workspace cwd.\n * Used when `outputHint` never matched.\n * spawnArgs given a captured id, returns the argv to spawn a\n * PTY that resumes the session. agentproto then\n * bypasses ACP/agent-cli and runs the provider\n * directly — the most reliable resume path because\n * it leans on the provider's native UX.\n *\n * Adapters that don't declare anything here fall back to:\n * 1. ACP-level resume via `resumeSessionId` on POST /sessions/agent\n * 2. Fresh spawn (same shape, no continuity)\n *\n * Eventually each adapter should ship its own strategy on\n * `AgentCliHandle.resumeStrategy` (driver-side). This central table\n * is the bootstrap: it lets a new adapter become resume-capable\n * without bumping its npm package; once that lands, entries\n * graduate into the adapter packages.\n */\n\nimport { CONVERSATION_STORES } from \"./conversation-store.js\"\nimport type { ConversationStore } from \"./conversation-store.js\"\n\n/** Where on disk the resume id ends up on the session descriptor. */\nexport type ResumeMetadataKey =\n | \"claudeResumeId\"\n | \"hermesResumeId\"\n | \"codexResumeId\"\n | \"openClawResumeId\"\n | \"openCodeResumeId\"\n // Export/read-only stores (no native resume wired): the key labels the\n // conversation store entry in CONVERSATION_STORES but is never written to\n // a descriptor's resumeMetadata, since these have no attachArgv/outputHint.\n | \"mastracodeInprocessResumeId\"\n | \"piResumeId\"\n\nexport interface ResumeStrategy {\n /** When set, run on every output line for this adapter. Group 1\n * captures the resume id. The match is saved on the descriptor\n * as `resumeMetadata[storeAs]`. */\n outputHint?: RegExp\n /** Where the matched id is recorded on the descriptor. */\n storeAs: ResumeMetadataKey\n /** Probe the adapter's on-disk session store for the resume id of a\n * session in the given workspace. Returns the id or null when nothing\n * eligible.\n *\n * When `expectedId` is set the session's own conversation id is known\n * (agent-cli descriptors carry it as `adapterSessionId`; for\n * claude-code it IS the on-disk `.jsonl` uuid — see acp-host.ts) and\n * the probe MUST bind to exactly that transcript: it confirms\n * `<expectedId>` exists and returns it, else null. It never falls\n * through to a mtime guess in that case — resuming *some other*\n * session that merely shares the cwd is a silent cross-session\n * correctness bug, strictly worse than not resuming at all.\n *\n * Only when `expectedId` is absent (e.g. a raw PTY claude session that\n * never had an ACP session id) does the probe fall back to\n * most-recently-modified, filtered to files at-or-after `prevStartedAt`\n * (avoids resuming an unrelated prior conversation).\n *\n * `configDir` is the session's isolated provider config dir\n * (`SessionDescriptor.adapterConfigDir`): a daemon-spawned claude-code\n * session (#824) persists its transcripts under that dir, not the\n * provider's global store — the probe must look there. Omit for a\n * native PTY / pre-#824 session (global store applies).\n *\n * Skip when the adapter doesn't persist sessions externally. */\n fsProbe?(\n cwd: string,\n prevStartedAt: string,\n expectedId?: string,\n configDir?: string,\n ): Promise<string | null>\n /** Return the argv to spawn a PTY that resumes into the given id.\n * When omitted, the daemon falls back to ACP-level resume via\n * the agent-cli protocol instead of the provider's native CLI. */\n spawnArgs?(id: string): string[]\n /** Env var the resumed PTY needs pointed at the session's isolated\n * provider config dir to find ITS OWN conversation store — see\n * `ConversationStore.configDirEnvVar`'s doc (conversation-store.ts) for\n * why this exists and what silently omitting it breaks. Undefined for\n * a provider with no config-dir-isolated store. */\n configDirEnvVar?: string\n}\n\n// Project every conversation store that declares a native PTY attach argv\n// into the resume-strategy table, so the table and the store can never drift\n// apart again. Only stores with `attachArgv` offer a provider-native TUI\n// resume; the rest are read/export-only. The actual decision to USE a\n// `pty-native` restart is still gated on `RestartCandidate.nativeTerminalResume`\n// below — a store entry alone does not license terminal mode.\nexport const RESUME_STRATEGIES: Record<string, ResumeStrategy> = Object.fromEntries(\n Object.entries(CONVERSATION_STORES)\n .filter(([, store]) => typeof store.attachArgv === \"function\")\n .map(([slug, store]) => {\n const s = store as Required<Pick<ConversationStore, \"attachArgv\" | \"discover\">> & ConversationStore\n return [\n slug,\n {\n outputHint: store.outputHint,\n storeAs: store.storeAs,\n ...(store.configDirEnvVar ? { configDirEnvVar: store.configDirEnvVar } : {}),\n fsProbe: async (cwd, prevStartedAt, expectedId, configDir) => {\n const candidates = await s.discover({\n cwd,\n since: prevStartedAt,\n expectedId,\n configDir,\n })\n return candidates[0]?.conversationId ?? null\n },\n spawnArgs: s.attachArgv,\n } satisfies ResumeStrategy,\n ]\n }),\n)\n\n/**\n * Helper: which adapters declare any resume capability? Used by\n * `agentproto sessions restart` to print a helpful \"this adapter\n * doesn't support resume; falling back to fresh spawn\" hint when\n * applicable.\n */\nexport function hasResumeStrategy(adapterSlug: string | undefined): boolean {\n if (!adapterSlug) return false\n const s = RESUME_STRATEGIES[adapterSlug]\n return !!(s && (s.outputHint || s.fsProbe || s.spawnArgs))\n}\n\n// ── Restart decision tree ────────────────────────────────────────\n//\n// Shared between the CLI (`agentproto sessions restart`, sessions.ts)\n// and the daemon's `session_restart` MCP tool (session-tools.ts) —\n// both need to answer \"given this dead/alive session, how do I bring\n// it back with the most continuity?\" the exact same way. Duck-typed\n// on a minimal shape rather than importing `SessionDescriptor` from\n// sessions.ts: this file is its own tsup entry (`splitting: false`),\n// so a value-level cross-entry import would inline the whole sessions\n// module here. A full `SessionDescriptor` satisfies these structurally.\n\nexport interface RestartCandidate {\n adapterSlug?: string\n resumeMetadata?: Record<string, string>\n pty?: boolean\n adapterSessionId?: string\n /** Manifest-declared `capabilities.resumable` for `adapterSlug` (see\n * `SessionDescriptor.resumable`'s doc) — the honesty gate for the whole\n * decision tree below. `false` means an `adapterSessionId` here is a\n * dead end: the adapter cannot rehydrate a prior conversation from it, no\n * matter how it's presented. Omitted/`true` preserves today's behaviour\n * (assumed resumable) for every adapter/row that doesn't set this. */\n resumable?: boolean\n /**\n * Manifest-declared `capabilities.nativeTerminalResume` for `adapterSlug`.\n * The `pty-native` restart strategy is only chosen when this flag is true\n * AND a native resume id is available. ACP resumability (`resumable`)\n * alone does NOT imply a native TUI resume is safe or available.\n */\n nativeTerminalResume?: boolean\n}\n\nexport interface FsProbeCandidate extends RestartCandidate {\n cwd?: string\n startedAt: string\n /** The session's isolated provider config dir (`SessionDescriptor.\n * adapterConfigDir`) — where a daemon-spawned claude-code session's\n * transcripts actually live since #824. A full `SessionDescriptor`\n * satisfies this structurally; absent on pre-#824/PTY rows, where the\n * provider's global store is the right place to probe. */\n adapterConfigDir?: string\n}\n\n/**\n * Where a restart should land. Computed once so callers never diverge:\n *\n * 1. pty-native — the adapter has a captured resume id AND declares\n * `spawnArgs` (e.g. claude-code): respawn a PTY running the\n * provider's own resume command. Most reliable CONTINUITY mechanism\n * when it applies — but only actually reachable by default when the\n * prior session was ITSELF a real PTY (`prev.pty === true`), or the\n * caller explicitly opts in (`preferNativeTerminal`) — see the\n * `mayPreferNative` doc below for why.\n * 2. pty-plain — the previous session was a real PTY with no\n * native strategy match: re-run the same argv, no continuity.\n * 3. agent — an agent-cli session with no native strategy (or an\n * ACP-origin session where pty-native doesn't apply — see above):\n * resume at the ACP level via the adapter's own session id (may\n * still 404 if the adapter never persisted a turn — callers\n * should retry without `resumeSessionId` on a \"not found\" error).\n * 4. unsupported — a generic command session; no history to resume\n * and no shape to clone reliably.\n */\nexport type RestartStrategy =\n | { kind: \"pty-native\"; argv: string[] }\n | { kind: \"pty-plain\" }\n | { kind: \"agent\"; resumeSessionId?: string; resumeFallback?: boolean }\n | { kind: \"unsupported\"; reason: string }\n\nexport interface DecideRestartStrategyOptions {\n /**\n * Explicit opt-in to provider-native terminal resume for a session whose\n * ORIGIN was agent-cli/ACP (not itself a PTY) — a human who wants the raw\n * provider TUI instead of ACP-level resume, understanding the tradeoffs\n * (see `mayPreferNative`'s doc below). Default false/omitted: an\n * ACP-origin session always resumes via ACP.\n */\n preferNativeTerminal?: boolean\n}\n\nexport function decideRestartStrategy(\n prev: RestartCandidate,\n opts: DecideRestartStrategyOptions = {},\n): RestartStrategy {\n // Provider-native terminal resume takes precedence over ACP-level resume —\n // but ONLY when the adapter manifest explicitly declares a verified native\n // TUI resume capability (`nativeTerminalResume`) AND (origin-gate, closing\n // the \"restart starts a terminal but it doesn't work\" bug) either the prior\n // session was ITSELF a raw PTY (`prev.pty === true` — a real provider TUI a\n // human was already looking at, whose config dir went through the actual\n // interactive onboarding wizard), or the caller explicitly opted in\n // (`preferNativeTerminal`). An agent-cli/ACP session's isolated\n // `CLAUDE_CONFIG_DIR` (#824) is populated ONLY by the headless ACP\n // entrypoint, which never runs the interactive TUI wizard — so defaulting\n // an ACP-origin session's restart to pty-native silently drops it onto\n // claude-code's first-run onboarding screen (theme picker, \"detected a\n // custom API key\" prompt) with no one attached to answer it, forever.\n // `nativeTerminalResume` alone is a CAPABILITY declaration (\"this adapter\n // supports native resume for a real terminal\"), not license to mode-switch\n // a headless session into an unattended one.\n const mayPreferNative = prev.pty === true || opts.preferNativeTerminal === true\n if (prev.adapterSlug && prev.nativeTerminalResume === true && mayPreferNative) {\n const strategy = RESUME_STRATEGIES[prev.adapterSlug]\n const id = strategy?.storeAs\n ? prev.resumeMetadata?.[strategy.storeAs]\n : undefined\n if (strategy?.spawnArgs && id) {\n return { kind: \"pty-native\", argv: strategy.spawnArgs(id) }\n }\n }\n if (prev.pty === true) {\n return { kind: \"pty-plain\" }\n }\n if (prev.adapterSlug) {\n // Honesty gate (resume-honesty fix): an adapter that declares\n // `resumable: false` (hermes, mastra-agent, …) cannot rehydrate a prior\n // conversation from `adapterSessionId` at all — passing it as\n // `resumeSessionId` either silently comes back blank or gets rejected by\n // the wrapper, and either way the caller must never present it as\n // continuity. Route straight to a flagged fresh spawn instead of\n // emitting a phantom id. `resumable === undefined` (unknown/legacy row,\n // or an adapter this fix hasn't reached) keeps today's behaviour.\n const canResumeAtAcpLevel = prev.resumable !== false\n return {\n kind: \"agent\",\n ...(prev.adapterSessionId && canResumeAtAcpLevel\n ? { resumeSessionId: prev.adapterSessionId }\n : {}),\n ...(prev.adapterSessionId && !canResumeAtAcpLevel\n ? { resumeFallback: true }\n : {}),\n }\n }\n return {\n kind: \"unsupported\",\n reason: \"generic command session — restart only supports pty + agent-cli\",\n }\n}\n\n/**\n * Matches an adapter's rejection of a `resumeSessionId` it can't honour —\n * the trigger for the \"retry as a fresh spawn\" fallback in\n * `session-restart-core.ts` and the CLI's `sessions restart`. Beyond a\n * literal \"not found\" (an unknown/never-persisted id), this also covers the\n * ACP wrapper-level rejection an adapter with `loadSession: false` throws\n * when a generic `resumeSessionId` reaches it despite `capabilities.\n * resumable: true` at the manifest level (e.g. claude-sdk — resumable via\n * its own SDK session store, but no ACP `session/load` surface): the\n * `@agentclientprotocol/sdk` server-side dispatcher throws a JSON-RPC\n * \"Method not found\" for an unimplemented `session/load`, and an agent may\n * instead reject with its own \"does not support\" / \"not supported\" wording.\n * Shared by every fallback call site so they can't drift out of sync (see\n * this module's own header comment on why that matters).\n */\nexport const RESUME_ID_REJECTED_RE =\n /not found|does not support|not supported|unsupported/i\n\n/**\n * Generic filesystem-fallback: for each known adapter strategy that\n * defines an `fsProbe`, run it against this session's cwd. If a\n * resume id is found, attach it to the descriptor's resumeMetadata.\n *\n * Lets `restart` recover continuity even when our own output sniffer\n * missed the resume hint (session killed too quickly, output buffered\n * past the kill, …). Eligible only when the file is at-or-after the\n * session's `startedAt` (avoid resuming an unrelated prior session\n * in the same cwd — see ResumeStrategy.fsProbe comment).\n *\n * Fix: when NO `adapterSessionId` was ever captured (session killed\n * before the ACP handshake), run a recency-window probe. When an\n * `adapterSessionId` exists but points to a missing JSONL, the probe\n * tries exact-bind and returns nothing — that's correct, we NEVER\n * silently resume a sibling conversation (safety: prevents cross-\n * session contamination). The adapter-level resume will fail with\n * \"not found\", triggering the fresh-spawn fallback + digest injection.\n */\nexport async function augmentWithFsResume<T extends FsProbeCandidate>(\n prev: T,\n): Promise<T> {\n const slug = prev.adapterSlug\n if (!slug) return prev\n const strategy = RESUME_STRATEGIES[slug]\n if (!strategy?.fsProbe) return prev\n // If we already have a captured id for this strategy's storage key,\n // skip the FS probe — the sniffer found it during the session.\n if (prev.resumeMetadata?.[strategy.storeAs]) return prev\n if (!prev.cwd) return prev\n // Pass the session's own conversation id (agent-cli sets it as\n // `adapterSessionId`; for claude-code it equals the on-disk `.jsonl`\n // uuid — acp-host.ts pins them equal) so the probe binds to THIS\n // session's transcript instead of the newest one in the cwd. Without\n // it, a restart of a session that shares a cwd with a concurrent one\n // could silently resume the wrong conversation. When the exact-bind\n // finds nothing (the JSONL is gone), we deliberately do NOT fall\n // through to a sibling — better to fail-fast and inject a digest.\n const id = await strategy.fsProbe(\n prev.cwd,\n prev.startedAt,\n prev.adapterSessionId,\n // A config-dir-isolated session (#824) persisted its transcript under\n // its own CLAUDE_CONFIG_DIR — probe there, not the global ~/.claude.\n prev.adapterConfigDir,\n )\n if (!id) return prev\n return {\n ...prev,\n // When `adapterSessionId` was never captured (session killed before\n // the ACP handshake completed), backfill it from the fsProbe result\n // so the agent restart path can attempt ACP-level resume too — not\n // just the PTY-native path. For claude-code (and most adapters) the\n // on-disk conversation id IS the ACP session id, so the values are\n // interchangeable. Only backfills; never overwrites an existing id.\n ...(!prev.adapterSessionId ? { adapterSessionId: id } : {}),\n resumeMetadata: {\n ...(prev.resumeMetadata ?? {}),\n [strategy.storeAs]: id,\n },\n }\n}\n\n/**\n * Describe which resume path a restart used, for CLI banners / MCP\n * responses. Returns a short phrase like \"resumed via claude --resume\",\n * or \"resumed via ACP\", or \"\" when no resume was attempted.\n *\n * Honesty gate (resume-honesty fix): \"resumed via ACP\" is a claim of actual\n * conversation continuity, so it's only returned when the adapter's\n * declared capability backs that claim (`resumable !== false`). An adapter\n * that declared `resumable: false` but still carries an `adapterSessionId`\n * gets an honest degraded label instead of the lie — never silently \"\".\n *\n * Origin gate (mirrors `decideRestartStrategy`'s own — MUST stay in sync or\n * this label lies about what actually happened): the native-resume phrasing\n * is only reported when `decideRestartStrategy` itself would have picked\n * pty-native for this `prev` — i.e. `prev.pty === true` or the caller passed\n * the SAME `preferNativeTerminal` it decided the strategy with. Without this\n * gate, a captured `resumeMetadata` alone used to make this function claim\n * \"resumed via claude --resume\" even when the actual decision (now)\n * downgrades an ACP-origin session to ACP-level resume instead.\n */\nexport function describeResumePath(\n prev: RestartCandidate,\n opts: DecideRestartStrategyOptions = {},\n): string {\n const mayPreferNative = prev.pty === true || opts.preferNativeTerminal === true\n if (prev.adapterSlug && mayPreferNative) {\n const s = RESUME_STRATEGIES[prev.adapterSlug]\n if (s?.spawnArgs && s.storeAs && prev.resumeMetadata?.[s.storeAs]) {\n const sample = s.spawnArgs(\"…\")[0] ?? prev.adapterSlug\n return `resumed via ${sample} --resume`\n }\n }\n if (prev.adapterSlug && prev.adapterSessionId) {\n if (prev.resumable === false) {\n return `fresh — resume not supported by ${prev.adapterSlug}`\n }\n return \"resumed via ACP\"\n }\n return \"\"\n}\n\n/**\n * Shell-style argv tokenizer for descriptors that don't carry `argv`\n * separately (legacy persisted rows predating that field). Same rules\n * as the spawn-dialog tokenizer in the web app: whitespace splits,\n * single + double quotes group.\n */\nexport function tokenizeCommand(s: string): string[] {\n const out: string[] = []\n let buf = \"\"\n let inSingle = false\n let inDouble = false\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]\n if (ch === \"'\" && !inDouble) {\n inSingle = !inSingle\n continue\n }\n if (ch === '\"' && !inSingle) {\n inDouble = !inDouble\n continue\n }\n if (!inSingle && !inDouble && /\\s/.test(ch ?? \"\")) {\n if (buf) {\n out.push(buf)\n buf = \"\"\n }\n continue\n }\n buf += ch\n }\n if (buf) out.push(buf)\n return out\n}\n"]}
|