@ai-matrx/coding-sessions 0.2.0 → 0.3.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/engine/index.cjs +54 -10
  3. package/dist/engine/index.cjs.map +1 -1
  4. package/dist/engine/index.d.cts +1 -1
  5. package/dist/engine/index.d.ts +1 -1
  6. package/dist/engine/index.js +54 -10
  7. package/dist/engine/index.js.map +1 -1
  8. package/dist/{index-29t7n472.d.cts → index-Bbe11HoB.d.cts} +30 -3
  9. package/dist/{index-29t7n472.d.ts → index-Bbe11HoB.d.ts} +30 -3
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +12 -3
  12. package/dist/index.d.ts +12 -3
  13. package/dist/index.js.map +1 -1
  14. package/dist/react/index.cjs +34 -5
  15. package/dist/react/index.cjs.map +1 -1
  16. package/dist/react/index.d.cts +15 -1
  17. package/dist/react/index.d.ts +15 -1
  18. package/dist/react/index.js +34 -5
  19. package/dist/react/index.js.map +1 -1
  20. package/dist/server/index.cjs +44 -9
  21. package/dist/server/index.cjs.map +1 -1
  22. package/dist/server/index.d.cts +2 -2
  23. package/dist/server/index.d.ts +2 -2
  24. package/dist/server/index.js +44 -9
  25. package/dist/server/index.js.map +1 -1
  26. package/dist/sessions/index.cjs +26 -1
  27. package/dist/sessions/index.cjs.map +1 -1
  28. package/dist/sessions/index.d.cts +13 -5
  29. package/dist/sessions/index.d.ts +13 -5
  30. package/dist/sessions/index.js +26 -1
  31. package/dist/sessions/index.js.map +1 -1
  32. package/dist/{titles-eCnA5sY7.d.cts → titles-DjxUb0ji.d.cts} +8 -1
  33. package/dist/{titles-eCnA5sY7.d.ts → titles-DjxUb0ji.d.ts} +8 -1
  34. package/dist/ui/assets/index-BqzTnRFe.css +2 -0
  35. package/dist/ui/assets/{index-SuRr0-D2.js → index-U98AY8r-.js} +17 -17
  36. package/dist/ui/index.html +2 -2
  37. package/package.json +3 -3
  38. package/dist/ui/assets/index-BqpVx_My.css +0 -2
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/normalize/agent-block.ts","../src/normalize/claude.ts","../src/normalize/codex.ts","../src/normalize/lines.ts","../src/transcript.ts","../src/provider-health.ts","../src/tool-labels.ts","../src/client/websocket.ts"],"sourcesContent":["/**\n * The public contract of `@ai-matrx/coding-sessions`, shared by the engine\n * (Node), the local host (Node) and the UI (browser). Pure types — nothing here\n * touches Node or the DOM, and every value is JSON-serializable because it\n * crosses a transport (WebSocket today, desktop IPC later).\n */\n\nimport type { JsonValue } from \"@ai-matrx/agents/portable\";\n\nimport type { TitleSource } from \"./sessions/titles\";\n\n/** The coding agents this package drives. \"coding session\" is the canonical\n * platform term (chat.coding_session, the Coding Session Bridge). */\nexport type CodingProvider = \"claude\" | \"codex\";\n\nexport const CODING_PROVIDERS: readonly CodingProvider[] = [\"claude\", \"codex\"];\n\nexport const PROVIDER_LABEL: Record<CodingProvider, string> = {\n claude: \"Claude Code\",\n codex: \"Codex\",\n};\n\nexport type Billing = \"subscription\" | \"api\" | \"unknown\";\n\n/** Where the CLI a provider runs came from. */\nexport type BinarySource = \"desktop-app\" | \"path\" | \"npm-global\" | \"configured\";\n\n/** The exact CLI runs use: the newest copy on this computer (or the host's pick). */\nexport interface ProviderBinary {\n path: string;\n version: string | null;\n source: BinarySource;\n /** \"from ChatGPT app\", \"from PATH\", … */\n sourceLabel: string;\n /** A newer copy than the one in use, when one exists. */\n newer: { path: string; version: string; sourceLabel: string } | null;\n}\n\n/** What `providers()` answers for one provider, in plain terms. */\nexport interface ProviderStatus {\n provider: CodingProvider;\n label: string;\n installed: boolean;\n version: string | null;\n loggedIn: boolean;\n billing: Billing;\n /** \"Max\", \"Pro\", \"Plus\", … when the provider reports a plan. */\n plan: string | null;\n /** The signed-in account label, when the provider reports one. */\n account: string | null;\n /** A plain-English sentence for the screen when it is not ready. */\n problem: string | null;\n /** A plain-English fix for `problem`. */\n fix: string | null;\n /** Installed, signed in, and no known usage limit or expired sign-in. */\n ready: boolean;\n /** The last usage-limit or sign-in failure a run reported, until a run succeeds. */\n lastProblem: ProviderProblem | null;\n /** Usage windows, when the provider exposes them (Codex does; see FEATURE.md). */\n quota: QuotaWindow[];\n /** Models the driver knows for this provider (the person may type any other). */\n models?: ModelOption[] | undefined;\n /** Reasoning-effort levels this provider accepts, lowest first. */\n efforts?: string[] | undefined;\n /**\n * The model a run uses when none is picked, and where that comes from: the\n * person's own settings (`~/.claude/settings.json`, `~/.codex/config.toml`)\n * or the driver's built-in default.\n */\n defaultModel?: { id: string; source: \"settings\" | \"driver\" } | null | undefined;\n /** The effort a run uses when none is picked (the person's own settings). */\n defaultEffort?: string | null | undefined;\n /** Which CLI runs use, and its version. */\n binary?: ProviderBinary | null | undefined;\n}\n\nexport interface ModelOption {\n id: string;\n label: string;\n}\n\n/**\n * The person's own organisation of their chats — a rename, a pin, a hide. Kept\n * in this package's data dir, keyed by `chatKey()`; the providers' own files\n * are NEVER touched (a rename here does not rename the chat in Claude Code).\n */\nexport interface ChatPreference {\n /** Shown instead of the chat's own title. */\n title?: string | null | undefined;\n pinned?: boolean | undefined;\n /** Hidden from the lists (still found by search, restorable). */\n hidden?: boolean | undefined;\n updatedAt?: string | undefined;\n}\n\n/** The one key a chat's preference lives under, for ours and discovered alike. */\nexport function chatKey(provider: CodingProvider, providerSessionId: string | null, sessionId?: string | null): string {\n return providerSessionId ? `${provider}:${providerSessionId}` : `session:${sessionId ?? \"\"}`;\n}\n\n/** One chat that matched a search. */\nexport interface ChatSearchHit {\n provider: CodingProvider;\n providerSessionId: string;\n title: string;\n cwd: string | null;\n updatedAt: string;\n /** Where the words were found. */\n where: \"title\" | \"content\";\n /** A short excerpt around the first match in the conversation. */\n snippet: string | null;\n}\n\nexport interface ChatSearchResult {\n query: string;\n hits: ChatSearchHit[];\n /** How many chats were read, newest first, starting from the cursor. */\n scanned: number;\n /** How many chats exist on this computer. */\n total: number;\n /** Pass back to keep searching older chats; null when every chat was read. */\n nextCursor: number | null;\n}\n\n/** Where \"Open folder\" can open a session's folder. */\nexport type OpenTarget = \"finder\" | \"vscode\" | \"cursor\" | \"terminal\";\n\nexport interface ProviderProblem {\n kind: \"usage-limit\" | \"signed-out\";\n /** The provider's own words, verbatim. */\n message: string;\n /** When a usage limit lifts: ISO when parseable, else the provider's phrase. */\n until: string | null;\n at: string;\n}\n\nexport interface QuotaWindow {\n label: string;\n usedPercent: number | null;\n resetsAt: string | null;\n valueLabel: string | null;\n}\n\n/** An existing local Claude Code or Codex chat, found on disk (metadata only). */\nexport interface DiscoveredSession {\n provider: CodingProvider;\n providerSessionId: string;\n cwd: string | null;\n /**\n * The chat's own title by the one rule (`./sessions`): the coding app's title when the owner of\n * the apps' index supplied it (title hints), else the transcript's. Never the person's rename —\n * that is applied once, by the screen, from the preferences.\n */\n title: string;\n /** Where `title` came from (`TITLE_PRECEDENCE`). */\n titleSource?: TitleSource | undefined;\n /** The app's title is still on its way (hints not loaded yet); `title` is the transcript's for now. */\n titlePending?: boolean | undefined;\n /** Archived in the app (hidden by default, like Code › Chats). */\n archived?: boolean | undefined;\n /** A scheduled or automated run (hidden by default). */\n scheduled?: boolean | undefined;\n /** The app lists it but its conversation file is gone: why. Shown, cannot be taken over. */\n unavailable?: string | null | undefined;\n updatedAt: string;\n /** Where it was started, when the provider records it (\"cli\", \"vscode\", \"exec\", …). */\n source: string | null;\n /** Set when the chat looks live somewhere else right now (see `ActiveElsewhere`). */\n activeElsewhere: ActiveElsewhere | null;\n}\n\n/**\n * Evidence that a chat is being driven somewhere else RIGHT NOW. Taking it\n * over then puts two agents on one conversation, so the screen warns and asks —\n * it never blocks (validation offers, never blocks).\n */\nexport interface ActiveElsewhere {\n /** How we know, strongest first. */\n reason: \"process\" | \"recent-write\" | \"open-tool-call\";\n /** One plain sentence for the screen. */\n message: string;\n}\n\nexport type RunStatus = \"starting\" | \"running\" | \"completed\" | \"stopped\" | \"failed\";\n\nexport const TERMINAL_RUN_STATUSES: readonly RunStatus[] = [\"completed\", \"stopped\", \"failed\"];\n\nexport function isTerminalRunStatus(status: RunStatus): boolean {\n return TERMINAL_RUN_STATUSES.includes(status);\n}\n\nexport interface RunUsage {\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens: number;\n}\n\n/** One turn: one prompt sent to one provider process. */\nexport interface RunRecord {\n runId: string;\n /** Our session id (`CodingSession.id`). */\n sessionId: string;\n provider: CodingProvider;\n cwd: string;\n prompt: string;\n model: string | null;\n status: RunStatus;\n startedAt: string;\n endedAt: string | null;\n /** The real error, verbatim from the provider or the driver, when failed. */\n error: string | null;\n usage: RunUsage | null;\n costUsd: number | null;\n billing: Billing | null;\n}\n\n/** How a session came to be listed here. */\nexport type SessionOrigin = \"started\" | \"takeover\";\n\n/** A conversation driven from here. Its transcript lives in the provider's own\n * files; this is only the index row. */\nexport interface CodingSession {\n /** Our stable id. */\n id: string;\n provider: CodingProvider;\n /** The provider's own session/thread id — null until the first run reports it. */\n providerSessionId: string | null;\n cwd: string;\n title: string;\n model: string | null;\n /** Reasoning effort for the next run; null = the provider's own default. */\n effort?: string | null | undefined;\n origin: SessionOrigin;\n createdAt: string;\n updatedAt: string;\n /** The live or most recent run. */\n lastRunId: string | null;\n lastRunStatus: RunStatus | null;\n /** Prompts waiting for the active run to finish, oldest first. */\n queued: string[];\n /** The AI Matrx agent loaded into every run of this session, when one was picked. */\n agent?: SessionAgent | null | undefined;\n /** Codex must be told, in the next prompt, that an earlier agent no longer applies. */\n agentRemovedDue?: boolean | undefined;\n}\n\n/**\n * One normalized transcript item — the same shape from Claude and Codex, from\n * a live stream and from a provider's saved session file.\n */\nexport type TranscriptItem =\n | { kind: \"user\"; id: string; text: string; at: string | null }\n | { kind: \"text\"; id: string; text: string }\n | { kind: \"text-delta\"; id: string; text: string }\n | { kind: \"reasoning\"; id: string; text: string }\n | { kind: \"tool-call\"; id: string; name: string; input: unknown }\n | { kind: \"tool-result\"; id: string; output: string; isError: boolean }\n | { kind: \"usage\"; usage: RunUsage; costUsd: number | null }\n | { kind: \"notice\"; id: string; level: \"info\" | \"warning\"; text: string }\n | { kind: \"error\"; id: string; text: string };\n\n/** Everything the engine pushes to a listener. */\nexport type CodingEvent =\n | { type: \"session\"; session: CodingSession }\n | { type: \"run\"; run: RunRecord }\n | { type: \"preferences\"; preferences: Record<string, ChatPreference> }\n /** The apps' titles changed (or finished loading): re-read the discovered chats. */\n | { type: \"titles\" }\n | {\n type: \"item\";\n sessionId: string;\n runId: string;\n /** Monotonic per session; a history read reports the last `seq` it includes. */\n seq: number;\n item: TranscriptItem;\n };\n\n/** A transcript read back from the provider's own file. */\nexport interface SessionHistory {\n items: TranscriptItem[];\n /** True when the file was larger than the read budget and only its end was read. */\n truncated: boolean;\n /** Plain-English reason when history could not be read (never thrown at the UI). */\n unavailable: string | null;\n /** The last live item `seq` this read already contains; apply only newer ones. */\n seq: number;\n}\n\nexport interface StartInput {\n provider: CodingProvider;\n cwd: string;\n prompt: string;\n model?: string | null | undefined;\n effort?: string | null | undefined;\n /** An AI Matrx agent to load into the CLI. Needs the host's `agents` credentials. */\n agent?: AgentSelection | null | undefined;\n}\n\n/** Which AI Matrx agent a new session loads, and the person's variable values. */\nexport interface AgentSelection {\n agentId: string;\n /** Pin one saved version; omitted = the latest, pinned at start. */\n versionId?: string | null | undefined;\n variables?: Record<string, JsonValue> | undefined;\n}\n\n/** One part of an agent and whether this session's CLI carries it. */\nexport interface SessionAgentPart {\n part: \"instructions\" | \"skills\" | \"tools\";\n loaded: number;\n total: number;\n}\n\n/**\n * The agent a session runs with. Recorded at start and never drifts: every\n * later turn reloads the SAME bundle (same version, same hash).\n */\nexport interface SessionAgent {\n agentId: string;\n versionId: string | null;\n versionNumber: number | null;\n name: string;\n definitionHash: string;\n loaded: SessionAgentPart[];\n /** What could not be carried, with the reason. */\n unavailable: { kind: string; name: string; reason: string }[];\n /** The skills it carries (labels) and the tools it serves (names) — the agent's own set. */\n skills?: string[] | undefined;\n tools?: string[] | undefined;\n /** The person's variable values, kept so \"Update to vN\" can reuse them. */\n variables?: Record<string, JsonValue> | undefined;\n /**\n * The CLI must be TOLD in the next prompt (a delimited block): a Codex\n * takeover or agent switch (Codex ignores developer_instructions on resume),\n * or a Codex compaction that dropped the block. Cleared once delivered.\n */\n blockDue?: boolean | undefined;\n /** When the block (or native instructions) last reached the CLI. */\n deliveredAt?: string | null | undefined;\n /** The agent this one replaced mid-chat (\"Code Reviewer v1\"), named in the block. */\n replaces?: string | null | undefined;\n}\n\n/** Whether this host can reach AI Matrx as a signed-in person. */\nexport interface AgentAccess {\n signedIn: boolean;\n userId: string | null;\n organizationId: string | null;\n /** True when the host was started with no AI Matrx connection at all. */\n configured: boolean;\n}\n\n/** A catalogue read the picker asks the host to make (PostgREST RPC shape). */\nexport interface AgentCatalogRpcRequest {\n fn: string;\n args?: Record<string, unknown> | undefined;\n count?: \"exact\" | \"planned\" | \"estimated\" | undefined;\n range?: [number, number] | undefined;\n order?: { column: string; ascending?: boolean | undefined } | undefined;\n}\n\nexport interface AgentCatalogRpcResult {\n data: unknown;\n error: {\n message: string;\n code?: string | undefined;\n details?: string | null | undefined;\n hint?: string | null | undefined;\n } | null;\n count?: number | null;\n}\n\n/** What a picker needs about one agent — the LIGHT read (no skills, no tools). */\nexport interface AgentDetails {\n agentId: string;\n name: string;\n /** Variable declarations as authored (camelCase). */\n variables: Record<string, JsonValue>[];\n /** Newest first. */\n versions: { id: string; versionNumber: number; changedAt: string | null }[];\n /** The version \"Latest\" resolves to right now. */\n latestVersionNumber: number | null;\n latestVersionId: string | null;\n}\n\nexport interface TakeoverInput {\n provider: CodingProvider;\n providerSessionId: string;\n cwd: string;\n title?: string | undefined;\n /** Continue the chat WITH an AI Matrx agent (\"Continue with agent\"). */\n agent?: AgentSelection | null | undefined;\n}\n\nexport interface SendResult {\n session: CodingSession;\n /** The run that started, or null when the prompt was queued behind a live run. */\n run: RunRecord | null;\n queued: boolean;\n}\n\nexport interface FolderCheck {\n /** The absolute path the check resolved. */\n path: string;\n exists: boolean;\n /** False when something that is NOT a folder sits at the path. */\n isDirectory: boolean;\n}\n\n/** A folder the New session flow offers (from discovered and driven sessions). */\nexport interface RecentFolder {\n path: string;\n lastUsedAt: string;\n exists: boolean;\n}\n\n/**\n * THE ENGINE CONTRACT — what the UI can ask for, independent of transport.\n * The WebSocket host implements it over the wire; a desktop app implements it\n * over IPC; the UI never knows which.\n */\nexport interface CodingSessionsApi {\n providers(): Promise<ProviderStatus[]>;\n discoverSessions(options?: { limit?: number }): Promise<DiscoveredSession[]>;\n recentFolders(): Promise<RecentFolder[]>;\n listSessions(): Promise<CodingSession[]>;\n listRuns(sessionId: string): Promise<RunRecord[]>;\n /** `maxBytes` reads more of a long chat's file (\"Show earlier\"). */\n history(sessionId: string, options?: HistoryOptions): Promise<SessionHistory>;\n /** Read-only transcript of a chat found on disk, before taking it over. */\n readTranscript(provider: CodingProvider, providerSessionId: string, options?: HistoryOptions): Promise<SessionHistory>;\n /**\n * FULL DOWNLOAD: the provider's own complete transcript file for this chat,\n * byte for byte (every tool input and output). AI Matrx's cloud keeps only\n * text and tool names, so this computer is the first place the full file\n * lives. `available: false` carries the sentence saying why.\n */\n readRawTranscript(provider: CodingProvider, providerSessionId: string): Promise<RawTranscript>;\n /** Does this folder exist here? `~` is the person's home. */\n checkFolder(path: string): Promise<FolderCheck>;\n /** Create a folder (and any missing parents), then report on it. */\n createFolder(path: string): Promise<FolderCheck>;\n /** Fresh check: is this chat live somewhere else right now? null when not. */\n sessionActivity(provider: CodingProvider, providerSessionId: string): Promise<ActiveElsewhere | null>;\n start(input: StartInput): Promise<SendResult>;\n takeover(input: TakeoverInput): Promise<CodingSession>;\n send(sessionId: string, prompt: string): Promise<SendResult>;\n stop(runId: string): Promise<RunRecord | null>;\n /** The person's renames, pins and hides, by `chatKey()`. */\n chatPreferences(): Promise<Record<string, ChatPreference>>;\n /** Merge a change into one chat's preference; `null` fields clear. Returns them all. */\n setChatPreference(key: string, patch: ChatPreference): Promise<Record<string, ChatPreference>>;\n /** Find chats by title and by what was said in them, newest first, within a time budget. */\n searchChats(query: string, options?: { cursor?: number; limit?: number }): Promise<ChatSearchResult>;\n /** Open a folder in Finder, VS Code, Cursor or Terminal. */\n openFolder(path: string, target: OpenTarget): Promise<void>;\n /** Change the model or effort the NEXT run of a session uses. */\n setSessionOptions(sessionId: string, options: { model?: string | null; effort?: string | null }): Promise<CodingSession>;\n /** Is this host signed in to AI Matrx (so agents can load)? */\n agentAccess(): Promise<AgentAccess>;\n /** One allowlisted agent-catalogue read, made by the host as the signed-in person. */\n agentCatalogRpc(request: AgentCatalogRpcRequest): Promise<AgentCatalogRpcResult>;\n /** An agent's variables and saved versions, for the New session form. */\n agentDetails(agentId: string): Promise<AgentDetails>;\n /**\n * Load a different agent into a session from its next message on (or\n * remove it, with `null`). Claude reads it every turn; Codex is told in the\n * next prompt.\n */\n setAgent(sessionId: string, agent: AgentSelection | null): Promise<CodingSession>;\n}\n\nexport type RawTranscript =\n | { available: true; fileName: string; bytes: number; content: string }\n | { available: false; reason: string };\n\nexport interface HistoryOptions {\n /** Read up to this many bytes from the end of the file (default 24 MB). */\n maxBytes?: number | undefined;\n}\n\nexport type CodingSessionsMethod = keyof CodingSessionsApi;\n\n/** The transport the UI talks through (WebSocket, IPC, in-process). */\nexport interface CodingSessionsTransport {\n call<M extends CodingSessionsMethod>(\n method: M,\n ...args: Parameters<CodingSessionsApi[M]>\n ): ReturnType<CodingSessionsApi[M]>;\n subscribe(listener: (event: CodingEvent) => void): () => void;\n /** Connection state, for an honest banner. */\n status(): TransportStatus;\n onStatus(listener: (status: TransportStatus) => void): () => void;\n}\n\nexport type TransportStatus =\n | { state: \"connecting\" }\n | { state: \"open\" }\n | { state: \"closed\"; reason: string };\n","/**\n * The delimited AI Matrx agent block a coding session puts in front of a\n * person's message when a CLI must be TOLD about the agent (a Codex takeover,\n * an agent switch, after a compaction). Pure: the transcript strips it so the\n * screen shows what the person wrote, not how the CLI was told.\n */\n\n/** The marker every agent text we hand a CLI starts with. */\nexport const AGENT_BLOCK_MARKER = \"<ai_matrx_agent \";\n\n/**\n * Remove a leading agent block from a user message, so the transcript shows\n * what the PERSON wrote (the block is how the CLI was told, not their words).\n */\nexport function stripAgentBlock(text: string): string {\n const removed = text.match(/^<ai_matrx_agent_removed>[\\s\\S]*?<\\/ai_matrx_agent_removed>\\s*/);\n if (removed) return text.slice(removed[0].length);\n if (!text.startsWith(AGENT_BLOCK_MARKER)) return text;\n const end = text.indexOf(\"</ai_matrx_agent>\");\n if (end < 0) return text;\n let rest = text.slice(end + \"</ai_matrx_agent>\".length);\n // The Codex skills list rides after the block.\n const skills = rest.match(/^\\s*<skills_instructions>[\\s\\S]*?<\\/skills_instructions>/);\n if (skills) rest = rest.slice(skills[0].length);\n return rest.replace(/^\\s+/, \"\");\n}\n","/**\n * Claude Code → `TranscriptItem`.\n *\n * ONE normalizer reads both of Claude's shapes, because they are the same\n * shape: `claude --print --output-format stream-json` lines (live) and the\n * entries of the user's own session file `~/.claude/projects/<cwd>/<id>.jsonl`\n * (history) both carry `{ type: \"assistant\" | \"user\", message: { content } }`.\n * The live stream adds `system`/`stream_event`/`result`; the file adds its own\n * bookkeeping entries (titles, attachments, snapshots), which are skipped.\n *\n * Block identity: an assistant message arrives as several lines sharing one\n * `message.id`, one content block per line, in block order — the same order\n * the partial-message `content_block_start.index` counts. So a text block's id\n * is `<message id>:<index>` on both paths, and a streamed draft is replaced by\n * its final text rather than duplicated.\n */\n\nimport type { RunUsage, TranscriptItem } from \"../types\";\nimport { stripAgentBlock } from \"./agent-block\";\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\n/** User-role text Claude Code writes that the person never typed. */\nconst SYNTHETIC_USER_PREFIXES = [\n \"<command-name>\",\n \"<command-message>\",\n \"<command-args>\",\n \"<local-command-stdout>\",\n \"<local-command-stderr>\",\n \"<local-command-caveat>\",\n \"<system-reminder>\",\n \"<bash-input>\",\n \"<bash-stdout>\",\n \"<bash-stderr>\",\n \"<user-memory-input>\",\n \"<task-notification>\",\n \"Caveat: The messages below were generated by the user while running local commands\",\n \"[Request interrupted by user\",\n];\n\nexport function isSyntheticClaudeUserText(text: string): boolean {\n const trimmed = text.trimStart();\n return SYNTHETIC_USER_PREFIXES.some((prefix) => trimmed.startsWith(prefix));\n}\n\nfunction toolResultText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .map((block) => {\n if (!isObject(block)) return \"\";\n if (block.type === \"text\") return str(block.text) ?? \"\";\n if (block.type === \"image\") return \"[image]\";\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n return content === undefined || content === null ? \"\" : JSON.stringify(content);\n}\n\nexport interface ClaudeNormalizer {\n /** Feed one parsed JSON line; returns the items it produced (often none). */\n push(entry: unknown): TranscriptItem[];\n /** The Claude session id, once a line has carried it. */\n readonly sessionId: string | null;\n}\n\nexport function createClaudeNormalizer(): ClaudeNormalizer {\n let sessionId: string | null = null;\n let streamingMessageId: string | null = null;\n const blockCounters = new Map<string, number>();\n let userCounter = 0;\n let noticeCounter = 0;\n\n function nextBlockIndex(messageId: string): number {\n const index = blockCounters.get(messageId) ?? 0;\n blockCounters.set(messageId, index + 1);\n return index;\n }\n\n function pushAssistant(entry: Json): TranscriptItem[] {\n const message = isObject(entry.message) ? entry.message : null;\n if (!message) return [];\n const messageId = str(message.id) ?? str(entry.uuid) ?? `assistant-${blockCounters.size}`;\n const content = Array.isArray(message.content) ? message.content : [];\n const items: TranscriptItem[] = [];\n for (const block of content) {\n if (!isObject(block)) continue;\n const index = nextBlockIndex(messageId);\n const id = `${messageId}:${index}`;\n if (block.type === \"text\") {\n const text = str(block.text) ?? \"\";\n if (text.length > 0) items.push({ kind: \"text\", id, text });\n } else if (block.type === \"thinking\") {\n // Claude Code writes thinking blocks with an EMPTY text and only a\n // signature unless thinking display is on; an empty aside is noise.\n const text = str(block.thinking) ?? \"\";\n if (text.trim().length > 0) items.push({ kind: \"reasoning\", id, text });\n } else if (block.type === \"tool_use\" || block.type === \"server_tool_use\") {\n items.push({\n kind: \"tool-call\",\n id: str(block.id) ?? id,\n name: str(block.name) ?? \"tool\",\n input: block.input ?? null,\n });\n }\n }\n return items;\n }\n\n function pushUser(entry: Json): TranscriptItem[] {\n if (entry.isMeta === true || entry.isCompactSummary === true) return [];\n const message = isObject(entry.message) ? entry.message : null;\n if (!message) return [];\n const at = str(entry.timestamp);\n const content = message.content;\n if (typeof content === \"string\") {\n if (isSyntheticClaudeUserText(content) || content.trim().length === 0) return [];\n userCounter += 1;\n // The agent block is how the CLI was told, not the person's words.\n return [{ kind: \"user\", id: str(entry.uuid) ?? `user-${userCounter}`, text: stripAgentBlock(content), at }];\n }\n if (!Array.isArray(content)) return [];\n const items: TranscriptItem[] = [];\n const typed: string[] = [];\n for (const block of content) {\n if (!isObject(block)) continue;\n if (block.type === \"tool_result\") {\n items.push({\n kind: \"tool-result\",\n id: str(block.tool_use_id) ?? \"unknown\",\n output: toolResultText(block.content),\n isError: block.is_error === true,\n });\n } else if (block.type === \"text\") {\n const text = str(block.text) ?? \"\";\n if (text.trim().length > 0 && !isSyntheticClaudeUserText(text)) typed.push(text);\n }\n }\n if (typed.length > 0) {\n userCounter += 1;\n items.unshift({\n kind: \"user\",\n id: str(entry.uuid) ?? `user-${userCounter}`,\n text: stripAgentBlock(typed.join(\"\\n\\n\")),\n at,\n });\n }\n return items;\n }\n\n function pushStreamEvent(entry: Json): TranscriptItem[] {\n const event = isObject(entry.event) ? entry.event : null;\n if (!event) return [];\n if (event.type === \"message_start\" && isObject(event.message)) {\n streamingMessageId = str(event.message.id);\n return [];\n }\n if (event.type === \"content_block_delta\" && streamingMessageId !== null) {\n const delta = isObject(event.delta) ? event.delta : null;\n if (delta?.type === \"text_delta\") {\n const text = str(delta.text) ?? \"\";\n if (text.length === 0) return [];\n return [{ kind: \"text-delta\", id: `${streamingMessageId}:${num(event.index)}`, text }];\n }\n }\n return [];\n }\n\n function pushResult(entry: Json): TranscriptItem[] {\n const items: TranscriptItem[] = [];\n const usage = isObject(entry.usage) ? entry.usage : null;\n if (usage) {\n const runUsage: RunUsage = {\n inputTokens: num(usage.input_tokens) + num(usage.cache_creation_input_tokens),\n outputTokens: num(usage.output_tokens),\n cachedInputTokens: num(usage.cache_read_input_tokens),\n };\n const cost = typeof entry.total_cost_usd === \"number\" ? entry.total_cost_usd : null;\n items.push({ kind: \"usage\", usage: runUsage, costUsd: cost });\n }\n if (entry.is_error === true || (typeof entry.subtype === \"string\" && entry.subtype !== \"success\")) {\n const text =\n str(entry.result) ??\n (Array.isArray(entry.errors) ? entry.errors.map(String).join(\"\\n\") : null) ??\n `Claude Code stopped with \"${String(entry.subtype)}\".`;\n noticeCounter += 1;\n items.push({ kind: \"error\", id: `claude-result-${noticeCounter}`, text });\n }\n return items;\n }\n\n return {\n get sessionId() {\n return sessionId;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n const lineSession = str(raw.session_id) ?? str(raw.sessionId);\n if (lineSession && sessionId === null) sessionId = lineSession;\n if (raw.isSidechain === true) return [];\n switch (raw.type) {\n case \"assistant\":\n return pushAssistant(raw);\n case \"user\":\n return pushUser(raw);\n case \"stream_event\":\n return pushStreamEvent(raw);\n case \"result\":\n return pushResult(raw);\n case \"system\":\n if (raw.subtype === \"compact_boundary\") {\n noticeCounter += 1;\n return [\n {\n kind: \"notice\",\n id: `claude-compact-${noticeCounter}`,\n level: \"info\",\n text: \"Claude Code summarized the earlier part of this conversation to make room.\",\n },\n ];\n }\n return [];\n default:\n return [];\n }\n },\n };\n}\n","/**\n * Codex → `TranscriptItem`, from its two different shapes:\n *\n * - the LIVE stream (`codex exec --json`): `thread.started`, `item.started` /\n * `item.completed` for agent messages, commands, file changes, MCP calls,\n * web searches and plans, then `turn.completed` with usage;\n * - the user's own saved rollout file (`~/.codex/sessions/**\\/rollout-*.jsonl`):\n * `session_meta`, `event_msg` (the person's words, verbatim) and\n * `response_item` (assistant messages, tool calls and their outputs).\n *\n * Codex numbers stream items `item_0, item_1, …` again on every run, so live\n * ids carry a per-run prefix; rollout items carry globally unique call ids.\n */\n\nimport type { RunUsage, TranscriptItem } from \"../types\";\nimport { stripAgentBlock } from \"./agent-block\";\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\nfunction codexUsage(usage: Json): RunUsage {\n return {\n inputTokens: num(usage.input_tokens),\n outputTokens: num(usage.output_tokens),\n cachedInputTokens: num(usage.cached_input_tokens),\n };\n}\n\n/** Human names for Codex's item kinds, so a tool card reads like a sentence. */\nfunction toolCall(id: string, item: Json): TranscriptItem | null {\n switch (item.type) {\n case \"command_execution\":\n return { kind: \"tool-call\", id, name: \"Shell\", input: { command: str(item.command) ?? \"\" } };\n case \"file_change\":\n return { kind: \"tool-call\", id, name: \"Edit files\", input: { changes: item.changes ?? [] } };\n case \"mcp_tool_call\": {\n const server = str(item.server) ?? \"mcp\";\n const tool = str(item.tool) ?? \"tool\";\n return { kind: \"tool-call\", id, name: `${server}.${tool}`, input: item.arguments ?? null };\n }\n case \"web_search\":\n return { kind: \"tool-call\", id, name: \"Web search\", input: { query: str(item.query) ?? \"\" } };\n case \"todo_list\":\n return { kind: \"tool-call\", id, name: \"Plan\", input: { items: item.items ?? [] } };\n default:\n return null;\n }\n}\n\nfunction toolResult(id: string, item: Json): TranscriptItem | null {\n switch (item.type) {\n case \"command_execution\": {\n const exit = typeof item.exit_code === \"number\" ? item.exit_code : null;\n const output = str(item.aggregated_output) ?? \"\";\n return {\n kind: \"tool-result\",\n id,\n output: exit !== null && exit !== 0 ? `${output}\\n(exit code ${exit})`.trim() : output,\n isError: (exit !== null && exit !== 0) || item.status === \"failed\",\n };\n }\n case \"file_change\":\n return {\n kind: \"tool-result\",\n id,\n output: item.status === \"failed\" ? \"The file change failed.\" : \"Applied.\",\n isError: item.status === \"failed\",\n };\n case \"mcp_tool_call\": {\n const error = isObject(item.error) ? str(item.error.message) : str(item.error);\n return {\n kind: \"tool-result\",\n id,\n output: error ?? (item.result === undefined ? \"\" : JSON.stringify(item.result)),\n isError: error !== null || item.status === \"failed\",\n };\n }\n case \"web_search\":\n case \"todo_list\":\n return { kind: \"tool-result\", id, output: \"\", isError: false };\n default:\n return null;\n }\n}\n\nexport interface CodexStreamNormalizer {\n push(entry: unknown): TranscriptItem[];\n readonly sessionId: string | null;\n}\n\n/** The live `codex exec --json` stream. `runPrefix` keeps ids unique per run. */\nexport function createCodexStreamNormalizer(runPrefix: string): CodexStreamNormalizer {\n let sessionId: string | null = null;\n const started = new Set<string>();\n let counter = 0;\n\n return {\n get sessionId() {\n return sessionId;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n switch (raw.type) {\n case \"thread.started\":\n sessionId = str(raw.thread_id) ?? sessionId;\n return [];\n case \"item.started\":\n case \"item.updated\":\n case \"item.completed\": {\n const item = isObject(raw.item) ? raw.item : null;\n if (!item) return [];\n const id = `${runPrefix}:${str(item.id) ?? `item-${counter++}`}`;\n const completed = raw.type === \"item.completed\";\n if (item.type === \"agent_message\") {\n if (!completed) return [];\n const text = str(item.text) ?? \"\";\n return text ? [{ kind: \"text\", id, text }] : [];\n }\n if (item.type === \"reasoning\") {\n if (!completed) return [];\n const text = str(item.text) ?? \"\";\n return text.trim() ? [{ kind: \"reasoning\", id, text }] : [];\n }\n if (item.type === \"error\") {\n if (!completed) return [];\n // An `error` ITEM is a non-fatal warning (the run continues); a\n // fatal failure arrives as `turn.failed` or a top-level `error`.\n return [{ kind: \"notice\", id, level: \"warning\", text: str(item.message) ?? \"Codex warning.\" }];\n }\n const items: TranscriptItem[] = [];\n if (!started.has(id)) {\n const call = toolCall(id, item);\n if (call) {\n started.add(id);\n items.push(call);\n }\n }\n if (completed) {\n const result = toolResult(id, item);\n if (result) items.push(result);\n }\n return items;\n }\n case \"turn.completed\":\n return isObject(raw.usage)\n ? [{ kind: \"usage\", usage: codexUsage(raw.usage), costUsd: null }]\n : [];\n case \"turn.failed\": {\n const error = isObject(raw.error) ? str(raw.error.message) : null;\n counter += 1;\n return [{ kind: \"error\", id: `${runPrefix}:failed-${counter}`, text: error ?? \"Codex reported that the turn failed.\" }];\n }\n case \"error\":\n counter += 1;\n return [{ kind: \"error\", id: `${runPrefix}:error-${counter}`, text: str(raw.message) ?? \"Codex reported an error.\" }];\n default:\n return [];\n }\n },\n };\n}\n\nfunction contentText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .map((block) => (isObject(block) ? (str(block.text) ?? \"\") : \"\"))\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction parseArguments(raw: unknown): unknown {\n if (typeof raw !== \"string\") return raw ?? null;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n}\n\nfunction shellName(name: string): string {\n return name === \"shell\" || name === \"exec_command\" || name === \"local_shell\" ? \"Shell\" : name;\n}\n\n/**\n * The Codex app prepends ambient context to what the person typed\n * (`<in-app-browser-context …>…</in-app-browser-context>\\n## My request:\\n…`).\n * It is not their words; a title or a transcript bubble shows only theirs.\n */\nexport function stripCodexInjectedContext(text: string): string {\n let out = text;\n const leading = /^\\s*<([a-z][\\w-]*)(?:\\s[^>]*)?>[\\s\\S]*?<\\/\\1>/i;\n for (let i = 0; i < 8 && leading.test(out); i += 1) out = out.replace(leading, \"\");\n return out.replace(/^\\s*#{1,6}\\s*My request:\\s*/i, \"\").trim() || text.trim();\n}\n\n/** Text of a rollout `item_completed` item's `content` blocks. */\nfunction itemText(content: unknown): string {\n if (!Array.isArray(content)) return \"\";\n return content\n .map((block) => (isObject(block) ? (str(block.text) ?? \"\") : \"\"))\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction commandLine(command: unknown): string {\n if (Array.isArray(command)) {\n // [\"/bin/zsh\", \"-lc\", \"ls -la\"] → \"ls -la\": the shell wrapper is noise.\n const last = command[command.length - 1];\n if (command.length >= 3 && typeof last === \"string\") return last;\n return command.map(String).join(\" \");\n }\n return typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Current Codex (0.15x) records each turn TWICE in a rollout: the model-level\n * `response_item`s (where a shell command is a JavaScript `exec` snippet) and\n * the app-level `event_msg: item_completed` items the Codex app itself renders\n * (UserMessage, AgentMessage, CommandExecution, FileChange, …). The app-level\n * items read the way a person thinks about the work, so once a file shows it\n * has them, they are the transcript and the response_items are skipped.\n * Older rollouts have only response_items plus `event_msg: user_message`.\n */\nfunction rolloutItem(item: Json, fallbackId: string, at: string | null): TranscriptItem[] {\n const id = str(item.id) ?? fallbackId;\n switch (item.type) {\n case \"UserMessage\": {\n const text = stripCodexInjectedContext(stripAgentBlock(itemText(item.content)));\n return text.trim() ? [{ kind: \"user\", id, text, at }] : [];\n }\n case \"AgentMessage\": {\n const text = itemText(item.content);\n return text ? [{ kind: \"text\", id, text }] : [];\n }\n case \"Reasoning\": {\n const text = Array.isArray(item.summary_text) ? item.summary_text.map(String).join(\"\\n\") : \"\";\n return text.trim() ? [{ kind: \"reasoning\", id, text }] : [];\n }\n case \"CommandExecution\": {\n const exit = typeof item.exit_code === \"number\" ? item.exit_code : null;\n const output = str(item.aggregated_output) ?? str(item.formatted_output) ?? str(item.stdout) ?? \"\";\n const failed = (exit !== null && exit !== 0) || item.status === \"failed\";\n return [\n { kind: \"tool-call\", id, name: \"Shell\", input: { command: commandLine(item.command) } },\n {\n kind: \"tool-result\",\n id,\n output: failed && exit !== null ? `${output}\\n(exit code ${exit})`.trim() : output,\n isError: failed,\n },\n ];\n }\n case \"FileChange\":\n return [\n { kind: \"tool-call\", id, name: \"Edit files\", input: { changes: item.changes ?? null } },\n { kind: \"tool-result\", id, output: item.status === \"failed\" ? \"The file change failed.\" : \"Applied.\", isError: item.status === \"failed\" },\n ];\n case \"McpToolCall\": {\n const name = `${str(item.server) ?? \"mcp\"}.${str(item.tool) ?? \"tool\"}`;\n const error = isObject(item.error) ? str(item.error.message) : str(item.error);\n return [\n { kind: \"tool-call\", id, name, input: item.arguments ?? null },\n {\n kind: \"tool-result\",\n id,\n output: error ?? (item.result === undefined ? \"\" : JSON.stringify(item.result)),\n isError: error !== null || item.status === \"failed\",\n },\n ];\n }\n case \"WebSearch\":\n return [\n { kind: \"tool-call\", id, name: \"Web search\", input: { query: str(item.query) ?? \"\" } },\n { kind: \"tool-result\", id, output: \"\", isError: false },\n ];\n default:\n return [];\n }\n}\n\nexport interface CodexRolloutNormalizer {\n push(entry: unknown): TranscriptItem[];\n readonly sessionId: string | null;\n readonly cwd: string | null;\n}\n\n/** The user's saved rollout file. */\nexport function createCodexRolloutNormalizer(): CodexRolloutNormalizer {\n let sessionId: string | null = null;\n let cwd: string | null = null;\n let counter = 0;\n let appItems = false;\n\n return {\n get sessionId() {\n return sessionId;\n },\n get cwd() {\n return cwd;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n const payload = isObject(raw.payload) ? raw.payload : null;\n if (!payload) return [];\n const at = str(raw.timestamp);\n counter += 1;\n const fallbackId = `rollout-${typeof raw.ordinal === \"number\" ? raw.ordinal : counter}`;\n if (raw.type === \"session_meta\") {\n sessionId = str(payload.id) ?? sessionId;\n cwd = str(payload.cwd) ?? cwd;\n return [];\n }\n if (raw.type === \"event_msg\") {\n if (payload.type === \"item_completed\" && isObject(payload.item)) {\n appItems = true;\n return rolloutItem(payload.item, fallbackId, at);\n }\n if (payload.type === \"user_message\" && !appItems) {\n const text = stripCodexInjectedContext(stripAgentBlock(str(payload.message) ?? \"\"));\n return text.trim() ? [{ kind: \"user\", id: fallbackId, text, at }] : [];\n }\n return [];\n }\n if (raw.type === \"compacted\") {\n return [\n {\n kind: \"notice\",\n id: fallbackId,\n level: \"info\",\n text: \"Codex summarized the earlier part of this conversation to make room.\",\n },\n ];\n }\n if (raw.type !== \"response_item\" || appItems) return [];\n switch (payload.type) {\n case \"message\": {\n if (payload.role !== \"assistant\") return [];\n const text = contentText(payload.content);\n return text ? [{ kind: \"text\", id: str(payload.id) ?? fallbackId, text }] : [];\n }\n case \"reasoning\": {\n const summary = Array.isArray(payload.summary)\n ? payload.summary.map((part) => (isObject(part) ? (str(part.text) ?? \"\") : \"\")).join(\"\\n\")\n : \"\";\n return summary.trim()\n ? [{ kind: \"reasoning\", id: str(payload.id) ?? fallbackId, text: summary }]\n : [];\n }\n case \"function_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: shellName(str(payload.name) ?? \"tool\"),\n input: parseArguments(payload.arguments),\n },\n ];\n case \"custom_tool_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: shellName(str(payload.name) ?? \"tool\"),\n input: payload.input ?? null,\n },\n ];\n case \"local_shell_call\": {\n const action = isObject(payload.action) ? payload.action : {};\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: \"Shell\",\n input: { command: action.command ?? null },\n },\n ];\n }\n case \"web_search_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.id) ?? fallbackId,\n name: \"Web search\",\n input: payload.action ?? null,\n },\n { kind: \"tool-result\", id: str(payload.id) ?? fallbackId, output: \"\", isError: false },\n ];\n case \"function_call_output\":\n case \"custom_tool_call_output\":\n case \"local_shell_call_output\": {\n const output = payload.output;\n const text =\n typeof output === \"string\"\n ? output\n : isObject(output)\n ? (str(output.content) ?? JSON.stringify(output))\n : contentText(output);\n return [\n {\n kind: \"tool-result\",\n id: str(payload.call_id) ?? fallbackId,\n output: text,\n isError: isObject(output) && output.success === false,\n },\n ];\n }\n default:\n return [];\n }\n },\n };\n}\n","/**\n * Stdout arrives in arbitrary chunks; the providers write one JSON object per\n * line. This turns chunks into parsed lines, keeping a partial tail between\n * chunks, and reports (never throws on) a line that is not JSON — the CLIs do\n * print plain-text warnings on stdout now and then.\n */\n\nexport interface LineSplitter {\n push(chunk: string): { values: unknown[]; nonJson: string[] };\n /** Whatever is left when the stream ends. */\n flush(): { values: unknown[]; nonJson: string[] };\n}\n\nfunction parseLines(lines: string[]): { values: unknown[]; nonJson: string[] } {\n const values: unknown[] = [];\n const nonJson: string[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (!trimmed.startsWith(\"{\")) {\n nonJson.push(trimmed);\n continue;\n }\n try {\n values.push(JSON.parse(trimmed) as unknown);\n } catch {\n nonJson.push(trimmed);\n }\n }\n return { values, nonJson };\n}\n\nexport function createLineSplitter(): LineSplitter {\n let buffer = \"\";\n return {\n push(chunk) {\n buffer += chunk;\n const parts = buffer.split(\"\\n\");\n buffer = parts.pop() ?? \"\";\n return parseLines(parts);\n },\n flush() {\n const rest = buffer;\n buffer = \"\";\n return parseLines([rest]);\n },\n };\n}\n\n/** Parse a whole JSONL text (a fixture, or a provider file read in one go). */\nexport function parseJsonl(text: string): unknown[] {\n return parseLines(text.split(\"\\n\")).values;\n}\n","/**\n * `TranscriptItem`s → `@ai-matrx/chat` messages.\n *\n * The transcript is rendered by THE one person ↔ agent chat interface\n * (`@ai-matrx/chat`), not by a second message list: its message/part model\n * already has text, reasoning, tool parts on the industry tool-call state\n * machine, notices and errors, and its React transcript already renders them\n * (markdown, collapsible tool cards, streaming). This module is the only\n * adapter: one assistant message per turn, parts in arrival order.\n *\n * Identity is preserved on purpose: a change rebuilds ONLY the message it\n * touched, so the chat store's per-message subscriptions wake one bubble per\n * token instead of the whole list.\n */\n\nimport {\n createChatMessage,\n type ChatMessage,\n type ChatPart,\n type ChatToolPart,\n} from \"@ai-matrx/chat\";\n\nimport { runErrorLabel } from \"./provider-health\";\nimport { toolSubtitle } from \"./tool-labels\";\nimport type { RunStatus, RunUsage, TranscriptItem } from \"./types\";\n\nexport interface TranscriptBuilder {\n apply(item: TranscriptItem): void;\n applyAll(items: readonly TranscriptItem[]): void;\n /** Close the turn in progress with the run's final status. */\n endTurn(status: RunStatus, error?: string | null): void;\n /** Mark a turn as in progress (the assistant bubble shows it is working). */\n beginTurn(): void;\n messages(): readonly ChatMessage[];\n lastUsage(): { usage: RunUsage; costUsd: number | null } | null;\n}\n\ninterface Working {\n message: ChatMessage;\n /** item id → index in `message.parts`. */\n index: Map<string, number>;\n}\n\nexport function createTranscriptBuilder(): TranscriptBuilder {\n const list: ChatMessage[] = [];\n let current: Working | null = null;\n let turn = 0;\n let usage: { usage: RunUsage; costUsd: number | null } | null = null;\n /** tool call id → [message index, part index] for results that arrive late. */\n const toolHome = new Map<string, { messageIndex: number; partIndex: number }>();\n\n function commit(working: Working, parts: ChatPart[], status?: ChatMessage[\"status\"]): void {\n const next: ChatMessage = {\n ...working.message,\n parts,\n status: status ?? working.message.status,\n };\n working.message = next;\n const at = list.findIndex((m) => m.id === next.id);\n if (at >= 0) list[at] = next;\n }\n\n function ensureAssistant(): Working {\n if (current) return current;\n turn += 1;\n const message = createChatMessage({\n id: `turn-${turn}-${list.length}`,\n role: \"assistant\",\n status: \"streaming\",\n });\n list.push(message);\n current = { message, index: new Map() };\n return current;\n }\n\n function upsertPart(id: string, build: (existing: ChatPart | null) => ChatPart): void {\n const working = ensureAssistant();\n const parts = [...working.message.parts];\n const at = working.index.get(id);\n if (at === undefined) {\n working.index.set(id, parts.length);\n parts.push(build(null));\n } else {\n parts[at] = build(parts[at] ?? null);\n }\n commit(working, parts);\n }\n\n function closeCurrent(status: ChatMessage[\"status\"]): void {\n if (!current) return;\n const working = current;\n const parts = working.message.parts.map((part): ChatPart => {\n if (part.type === \"reasoning\" && part.state === \"streaming\") return { ...part, state: \"done\" };\n if (part.type === \"tool\" && part.state === \"input-available\" && status !== \"streaming\") {\n if (status === \"cancelled\") {\n return { ...part, state: \"output-error\", errorText: \"Stopped before this finished.\" };\n }\n if (status === \"error\") {\n return { ...part, state: \"output-error\", errorText: \"The run ended before this finished.\" };\n }\n }\n return part;\n });\n commit(working, parts, status);\n current = null;\n }\n\n const builder: TranscriptBuilder = {\n apply(item) {\n switch (item.kind) {\n case \"user\": {\n closeCurrent(\"complete\");\n list.push(\n createChatMessage({\n id: `user-${item.id}`,\n role: \"user\",\n parts: [{ type: \"text\", text: item.text }],\n status: \"complete\",\n metadata: item.at ? { createdAt: item.at } : undefined,\n }),\n );\n return;\n }\n case \"text-delta\":\n upsertPart(item.id, (existing) =>\n existing && existing.type === \"text\"\n ? { type: \"text\", text: existing.text + item.text }\n : { type: \"text\", text: item.text },\n );\n return;\n case \"text\":\n upsertPart(item.id, () => ({ type: \"text\", text: item.text }));\n return;\n case \"reasoning\":\n upsertPart(item.id, () => ({ type: \"reasoning\", text: item.text, state: \"done\" }));\n return;\n case \"tool-call\": {\n // The key argument (the command, the file) rides as the card's one\n // progress beat, which the chat card shows beside the tool's name.\n const subtitle = toolSubtitle(item.name, item.input);\n const progress = subtitle ? [{ toolName: item.name, message: subtitle, percent: null, at: null }] : [];\n upsertPart(item.id, (existing) =>\n existing && existing.type === \"tool\"\n ? { ...existing, input: item.input, progress }\n : {\n type: \"tool\",\n toolCallId: item.id,\n toolName: item.name,\n state: \"input-available\",\n input: item.input,\n output: null,\n errorText: null,\n progress,\n delegated: false,\n },\n );\n const working = current;\n if (working) {\n const partIndex = working.index.get(item.id);\n const messageIndex = list.findIndex((m) => m.id === working.message.id);\n if (partIndex !== undefined && messageIndex >= 0) {\n toolHome.set(item.id, { messageIndex, partIndex });\n }\n }\n return;\n }\n case \"tool-result\": {\n const home = toolHome.get(item.id);\n if (!home) {\n // A result whose call we never saw (a history read that started\n // mid-conversation). Show it as its own finished card.\n upsertPart(item.id, () => ({\n type: \"tool\",\n toolCallId: item.id,\n toolName: \"Tool\",\n state: item.isError ? \"output-error\" : \"output-available\",\n input: null,\n output: item.isError ? null : item.output,\n errorText: item.isError ? item.output || \"The tool reported an error.\" : null,\n progress: [],\n delegated: false,\n }));\n return;\n }\n const message = list[home.messageIndex];\n const part = message?.parts[home.partIndex];\n if (!message || !part || part.type !== \"tool\") return;\n const nextPart: ChatToolPart = item.isError\n ? { ...part, state: \"output-error\", errorText: item.output || \"The tool reported an error.\", output: null }\n : { ...part, state: \"output-available\", output: item.output };\n const parts = [...message.parts];\n parts[home.partIndex] = nextPart;\n const next: ChatMessage = { ...message, parts };\n list[home.messageIndex] = next;\n if (current && current.message.id === next.id) current.message = next;\n return;\n }\n case \"usage\":\n usage = { usage: item.usage, costUsd: item.costUsd };\n return;\n case \"notice\":\n upsertPart(item.id, () => ({\n type: \"notice\",\n level: item.level === \"warning\" ? \"medium\" : \"info\",\n code: null,\n userMessage: item.text,\n remedy: null,\n }));\n return;\n case \"error\": {\n // Codex reports one failure up to three ways (a top-level `error`,\n // `turn.failed`, and the run's final error): say it once.\n // A known class (a refused model) shows its short label, never the\n // provider's raw JSON.\n const text = runErrorLabel(item.text);\n const said = current?.message.parts.some((p) => p.type === \"error\" && p.message.trim() === text.trim());\n if (said) return;\n upsertPart(item.id, () => ({\n type: \"error\",\n errorType: \"provider\",\n code: null,\n message: text,\n userMessage: text,\n recoverable: true,\n remedy: null,\n }));\n return;\n }\n }\n },\n applyAll(items) {\n for (const item of items) builder.apply(item);\n },\n beginTurn() {\n ensureAssistant();\n },\n endTurn(status, error) {\n if (status === \"failed\" && error) {\n builder.apply({ kind: \"error\", id: `run-error-${list.length}`, text: error });\n }\n if (status === \"stopped\" && current) {\n builder.apply({\n kind: \"notice\",\n id: `run-stopped-${list.length}`,\n level: \"info\",\n text: \"You stopped this run.\",\n });\n }\n closeCurrent(status === \"stopped\" ? \"cancelled\" : status === \"failed\" ? \"error\" : \"complete\");\n },\n messages() {\n // A fresh array per read: the chat store compares the list by identity\n // to notice appends, and the message objects inside keep theirs.\n return list.slice();\n },\n lastUsage() {\n return usage;\n },\n };\n return builder;\n}\n","/**\n * USAGE LIMITS AND EXPIRED SIGN-INS, in plain English.\n *\n * A provider can be installed and signed in and still unable to run: the\n * ChatGPT or Claude plan hit its usage limit, or the saved login expired.\n * Runs report that in the provider's own words; this turns those words into\n * a remembered, honest status. Built from the real texts captured on\n * 2026-09-27 (Codex usage limit, Codex refresh failure).\n */\n\nimport { PROVIDER_LABEL, type CodingProvider, type ProviderProblem, type QuotaWindow } from \"./types\";\n\nconst USAGE_LIMIT = [\n /hit your usage limit/i,\n /usage limit (?:reached|exceeded)/i,\n /\\blimit reached\\b/i,\n /you'?ve hit your limit/i,\n /rate limit/i,\n /quota (?:exceeded|exhausted)/i,\n /purchase more credits/i,\n];\n\nconst SIGNED_OUT = [\n /access token could not be refreshed/i,\n /please sign in again/i,\n /(?:not|no longer) (?:logged|signed) in/i,\n /please run \\/login/i,\n /invalid api key/i,\n /oauth token (?:has )?expired/i,\n /authentication_error/i,\n /401 unauthorized/i,\n];\n\n/** \"Oct 4th, 2026 8:34 AM\" → ISO. null when the phrase is not a date. */\nexport function parseLimitDate(phrase: string): string | null {\n const cleaned = phrase.replace(/(\\d{1,2})(st|nd|rd|th)\\b/gi, \"$1\").replace(/[.,]\\s*$/, \"\").trim();\n const ms = Date.parse(cleaned);\n return Number.isNaN(ms) ? null : new Date(ms).toISOString();\n}\n\nfunction limitPhrase(text: string): string | null {\n const match =\n /try again (?:at|after|on) ([^\\n]+?)(?:\\.\\s|\\.$|$)/i.exec(text) ??\n /resets? (?:at |on )?([^\\n∙·|]+?)(?:\\.\\s|\\.$|$|\\s*[∙·|])/i.exec(text);\n return match?.[1]?.trim() ?? null;\n}\n\nexport function classifyProviderError(text: string, at = new Date().toISOString()): ProviderProblem | null {\n const trimmed = text.trim();\n if (!trimmed) return null;\n if (SIGNED_OUT.some((re) => re.test(trimmed))) {\n return { kind: \"signed-out\", message: trimmed, until: null, at };\n }\n if (USAGE_LIMIT.some((re) => re.test(trimmed))) {\n const phrase = limitPhrase(trimmed);\n return { kind: \"usage-limit\", message: trimmed, until: phrase ? (parseLimitDate(phrase) ?? phrase) : null, at };\n }\n return null;\n}\n\n/** A usage limit whose reset time has passed no longer applies. */\nexport function problemStillApplies(problem: ProviderProblem, now = Date.now()): boolean {\n if (problem.kind !== \"usage-limit\" || !problem.until) return true;\n const ms = Date.parse(problem.until);\n return Number.isNaN(ms) || ms > now;\n}\n\nexport function formatUntil(until: string | null): string | null {\n if (!until) return null;\n const ms = Date.parse(until);\n if (Number.isNaN(ms)) return until;\n return new Date(ms).toLocaleString(undefined, { month: \"short\", day: \"numeric\", hour: \"numeric\", minute: \"2-digit\" });\n}\n\n/** A full quota window (100% used) is a usage limit even before a run hits it. */\nexport function problemFromQuota(windows: readonly QuotaWindow[], at = new Date().toISOString()): ProviderProblem | null {\n const full = windows.find((w) => typeof w.usedPercent === \"number\" && w.usedPercent >= 100);\n if (!full) return null;\n return {\n kind: \"usage-limit\",\n message: `${full.label} is used up.`,\n until: full.resetsAt,\n at,\n };\n}\n\nexport function describeProblem(provider: CodingProvider, problem: ProviderProblem): { problem: string; fix: string } {\n const label = PROVIDER_LABEL[provider];\n if (problem.kind === \"signed-out\") {\n return {\n problem: `${label} — sign-in expired.`,\n fix: `Open ${label} and sign in again, then check again.`,\n };\n }\n const until = formatUntil(problem.until);\n return {\n problem: until ? `${label} — usage limit reached until ${until}.` : `${label} — usage limit reached.`,\n fix: until\n ? `It lifts on its own then, or add more usage in your ${provider === \"codex\" ? \"ChatGPT\" : \"Claude\"} account.`\n : `Wait for it to reset, or add more usage in your ${provider === \"codex\" ? \"ChatGPT\" : \"Claude\"} account.`,\n };\n}\n\n/**\n * A run refused because the CHOSEN MODEL is not available — to this account,\n * or to this version of the CLI. It is about the model, not the provider, so\n * the screen offers the model picker rather than a provider-wide warning.\n * Built from the real Codex text captured 2026-10-01\n * (fixtures/codex-model-unsupported.error.txt) and Claude Code's wording.\n */\nconst MODEL_UNAVAILABLE = [\n /model is not supported when using codex/i,\n /\\bmodel[\\s:'\"`][^.\\n]{0,80}\\b(?:not supported|does not exist|not available|not found)\\b/i,\n /\\bmodel_not_found\\b/i,\n /issue with the selected model/i,\n /may not exist or you may not have access to it/i,\n];\n\nexport const MODEL_UNAVAILABLE_LABEL = \"Model not available on this account\";\n\nexport function isModelUnavailable(text: string | null | undefined): boolean {\n const trimmed = (text ?? \"\").trim();\n return trimmed !== \"\" && MODEL_UNAVAILABLE.some((re) => re.test(trimmed));\n}\n\n/** What the screen says for a failed run: a short label for a known class, else the text itself. */\nexport function runErrorLabel(text: string): string {\n return isModelUnavailable(text) ? MODEL_UNAVAILABLE_LABEL : text;\n}\n","/**\n * What a tool call is CALLED on screen, and the one argument that says what\n * it is doing. `mcp__claude-in-chrome__browser_batch` reads \"Browser batch ·\n * Claude in chrome\"; `Bash {command: \"ls -la\"}` reads \"Run command\" with\n * \"ls -la\" beside it. The machine name stays on the card as `data-tool`.\n */\n\nconst BUILTIN: Record<string, string> = {\n Bash: \"Run command\",\n Shell: \"Run command\",\n BashOutput: \"Read command output\",\n KillShell: \"Stop command\",\n Read: \"Read file\",\n Write: \"Write file\",\n Edit: \"Edit file\",\n MultiEdit: \"Edit file\",\n NotebookEdit: \"Edit notebook\",\n Glob: \"Find files\",\n Grep: \"Search code\",\n LS: \"List folder\",\n WebFetch: \"Fetch page\",\n WebSearch: \"Web search\",\n \"Web search\": \"Web search\",\n Task: \"Sub-agent\",\n Agent: \"Sub-agent\",\n TodoWrite: \"Update plan\",\n Plan: \"Update plan\",\n \"Edit files\": \"Edit files\",\n ExitPlanMode: \"Finish planning\",\n Skill: \"Use skill\",\n ToolSearch: \"Load tools\",\n};\n\nfunction words(identifier: string): string {\n const spaced = identifier\n .replace(/[._-]+/g, \" \")\n .replace(/([a-z\\d])([A-Z])/g, \"$1 $2\")\n .replace(/\\s+/g, \" \")\n .trim()\n .toLowerCase();\n return spaced ? spaced.charAt(0).toUpperCase() + spaced.slice(1) : \"\";\n}\n\n/** `mcp__<server>__<tool>` → { server, tool }, or null. */\nexport function parseMcpToolName(name: string): { server: string; tool: string } | null {\n const match = /^mcp__(.+?)__(.+)$/.exec(name);\n return match?.[1] && match[2] ? { server: match[1], tool: match[2] } : null;\n}\n\nexport function friendlyToolName(name: string): string {\n const builtin = BUILTIN[name];\n if (builtin) return builtin;\n const mcp = parseMcpToolName(name);\n if (mcp) {\n // A server name often repeats in its tool (\"claude_browser\" + \"browser_batch\").\n return `${words(mcp.tool) || \"Tool\"} · ${words(mcp.server)}`;\n }\n // Codex MCP calls arrive as \"<server>.<tool>\".\n const dotted = /^([\\w-]+)\\.([\\w-]+)$/.exec(name);\n if (dotted?.[1] && dotted[2]) return `${words(dotted[2])} · ${words(dotted[1])}`;\n return words(name) || \"Working…\";\n}\n\nfunction prettyPath(value: string): string {\n const home = value.match(/^\\/(?:Users|home)\\/[^/]+/)?.[0];\n return home ? `~${value.slice(home.length)}` : value;\n}\n\nfunction clip(value: string, max = 90): string {\n const flat = value.replace(/\\s+/g, \" \").trim();\n return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;\n}\n\n/** The key argument, for the card's subtitle. null when there is none worth showing. */\nexport function toolSubtitle(name: string, input: unknown): string | null {\n if (typeof input !== \"object\" || input === null) return typeof input === \"string\" && input ? clip(input) : null;\n const args = input as Record<string, unknown>;\n const pick = (...keys: string[]): string | null => {\n for (const key of keys) {\n const value = args[key];\n if (typeof value === \"string\" && value.trim()) return value;\n }\n return null;\n };\n switch (name) {\n case \"Bash\":\n case \"Shell\": {\n const command = pick(\"command\", \"description\");\n return command ? clip(command) : null;\n }\n case \"Read\":\n case \"Write\":\n case \"Edit\":\n case \"MultiEdit\":\n case \"NotebookEdit\": {\n const file = pick(\"file_path\", \"notebook_path\", \"path\");\n return file ? clip(prettyPath(file)) : null;\n }\n case \"Glob\":\n case \"Grep\":\n return pick(\"pattern\") ? clip(pick(\"pattern\") as string) : null;\n case \"WebFetch\":\n return pick(\"url\") ? clip(pick(\"url\") as string) : null;\n case \"WebSearch\":\n case \"Web search\":\n return pick(\"query\") ? clip(pick(\"query\") as string) : null;\n case \"Task\":\n case \"Agent\":\n return pick(\"description\", \"prompt\") ? clip(pick(\"description\", \"prompt\") as string) : null;\n case \"Edit files\": {\n // The live stream lists `{ path, kind }`; a saved rollout maps path → change.\n const raw = args.changes;\n const paths = Array.isArray(raw)\n ? raw\n .map((c) => (typeof c === \"object\" && c !== null ? (c as { path?: unknown }).path : null))\n .filter((p): p is string => typeof p === \"string\")\n : typeof raw === \"object\" && raw !== null\n ? Object.keys(raw)\n : [];\n return paths.length ? clip(paths.map(prettyPath).join(\", \")) : null;\n }\n default: {\n const first = pick(\"url\", \"query\", \"command\", \"path\", \"file_path\", \"name\", \"description\");\n return first ? clip(first) : null;\n }\n }\n}\n","/**\n * The UI side of the local host: a `CodingSessionsTransport` over one\n * WebSocket. Requests are correlated by id; events stream on the same socket;\n * it reconnects on its own and says so through `status()` rather than letting\n * a screen sit on a dead connection.\n */\n\nimport type {\n CodingEvent,\n CodingSessionsApi,\n CodingSessionsMethod,\n CodingSessionsTransport,\n TransportStatus,\n} from \"../types\";\n\nexport interface WebSocketTransportOptions {\n /** `ws://127.0.0.1:<port>/ws` — defaults to the page's own host. */\n url?: string | undefined;\n token: string;\n /** Reconnect delay ceiling in ms. */\n maxBackoffMs?: number | undefined;\n}\n\ninterface Pending {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n}\n\nexport function createWebSocketTransport(options: WebSocketTransportOptions): CodingSessionsTransport {\n const base =\n options.url ??\n (typeof location !== \"undefined\" ? `ws://${location.host}/ws` : \"ws://127.0.0.1:4789/ws\");\n const url = `${base}?token=${encodeURIComponent(options.token)}`;\n const listeners = new Set<(event: CodingEvent) => void>();\n const statusListeners = new Set<(status: TransportStatus) => void>();\n const pending = new Map<number, Pending>();\n const outbox: string[] = [];\n let socket: WebSocket | null = null;\n let status: TransportStatus = { state: \"connecting\" };\n let nextId = 1;\n let backoff = 500;\n let everOpened = false;\n\n function setStatus(next: TransportStatus): void {\n status = next;\n for (const listener of statusListeners) listener(next);\n }\n\n function connect(): void {\n setStatus({ state: \"connecting\" });\n const ws = new WebSocket(url);\n socket = ws;\n ws.onopen = () => {\n everOpened = true;\n backoff = 500;\n setStatus({ state: \"open\" });\n while (outbox.length > 0) ws.send(outbox.shift() as string);\n };\n ws.onmessage = (message) => {\n let data: { id?: number; ok?: boolean; result?: unknown; error?: string; event?: CodingEvent };\n try {\n data = JSON.parse(String(message.data)) as typeof data;\n } catch {\n return;\n }\n if (data.event) {\n for (const listener of listeners) listener(data.event);\n return;\n }\n if (typeof data.id === \"number\") {\n const entry = pending.get(data.id);\n if (!entry) return;\n pending.delete(data.id);\n if (data.ok) entry.resolve(data.result);\n else entry.reject(new Error(data.error ?? \"The request failed.\"));\n }\n };\n ws.onclose = () => {\n socket = null;\n for (const [, entry] of pending) {\n entry.reject(new Error(\"Lost the connection to the coding sessions host.\"));\n }\n pending.clear();\n setStatus({\n state: \"closed\",\n reason: everOpened\n ? \"Lost the connection to the coding sessions host. Reconnecting…\"\n : \"Can't reach the coding sessions host. It may have stopped, or this link's access token is out of date.\",\n });\n const max = options.maxBackoffMs ?? 8000;\n setTimeout(connect, backoff);\n backoff = Math.min(max, backoff * 2);\n };\n }\n\n connect();\n\n return {\n call<M extends CodingSessionsMethod>(method: M, ...args: Parameters<CodingSessionsApi[M]>) {\n const id = nextId++;\n const frame = JSON.stringify({ id, method, args });\n const promise = new Promise<unknown>((resolve, reject) => {\n pending.set(id, { resolve, reject });\n });\n if (socket && socket.readyState === WebSocket.OPEN) socket.send(frame);\n else outbox.push(frame);\n return promise as ReturnType<CodingSessionsApi[M]>;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n status() {\n return status;\n },\n onStatus(listener) {\n statusListeners.add(listener);\n return () => {\n statusListeners.delete(listener);\n };\n },\n };\n}\n"],"mappings":"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","names":["isObject","str","num"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/normalize/agent-block.ts","../src/normalize/claude.ts","../src/normalize/codex.ts","../src/normalize/lines.ts","../src/transcript.ts","../src/provider-health.ts","../src/tool-labels.ts","../src/client/websocket.ts"],"sourcesContent":["/**\n * The public contract of `@ai-matrx/coding-sessions`, shared by the engine\n * (Node), the local host (Node) and the UI (browser). Pure types — nothing here\n * touches Node or the DOM, and every value is JSON-serializable because it\n * crosses a transport (WebSocket today, desktop IPC later).\n */\n\nimport type { JsonValue } from \"@ai-matrx/agents/portable\";\n\nimport type { TitleSource } from \"./sessions/titles\";\n\n/** The coding agents this package drives. \"coding session\" is the canonical\n * platform term (chat.coding_session, the Coding Session Bridge). */\nexport type CodingProvider = \"claude\" | \"codex\";\n\nexport const CODING_PROVIDERS: readonly CodingProvider[] = [\"claude\", \"codex\"];\n\nexport const PROVIDER_LABEL: Record<CodingProvider, string> = {\n claude: \"Claude Code\",\n codex: \"Codex\",\n};\n\nexport type Billing = \"subscription\" | \"api\" | \"unknown\";\n\n/** Where the CLI a provider runs came from. */\nexport type BinarySource = \"desktop-app\" | \"path\" | \"npm-global\" | \"configured\";\n\n/** The exact CLI runs use: the newest copy on this computer (or the host's pick). */\nexport interface ProviderBinary {\n path: string;\n version: string | null;\n source: BinarySource;\n /** \"from ChatGPT app\", \"from PATH\", … */\n sourceLabel: string;\n /** A newer copy than the one in use, when one exists. */\n newer: { path: string; version: string; sourceLabel: string } | null;\n}\n\n/** What `providers()` answers for one provider, in plain terms. */\nexport interface ProviderStatus {\n provider: CodingProvider;\n label: string;\n installed: boolean;\n version: string | null;\n loggedIn: boolean;\n billing: Billing;\n /** \"Max\", \"Pro\", \"Plus\", … when the provider reports a plan. */\n plan: string | null;\n /** The signed-in account label, when the provider reports one. */\n account: string | null;\n /** A plain-English sentence for the screen when it is not ready. */\n problem: string | null;\n /** A plain-English fix for `problem`. */\n fix: string | null;\n /** Installed, signed in, and no known usage limit or expired sign-in. */\n ready: boolean;\n /** The last usage-limit or sign-in failure a run reported, until a run succeeds. */\n lastProblem: ProviderProblem | null;\n /** Usage windows, when the provider exposes them (Codex does; see FEATURE.md). */\n quota: QuotaWindow[];\n /** Models the driver knows for this provider (the person may type any other). */\n models?: ModelOption[] | undefined;\n /** Reasoning-effort levels this provider accepts, lowest first. */\n efforts?: string[] | undefined;\n /**\n * The model a run uses when none is picked, and where that comes from: the\n * person's own settings (`~/.claude/settings.json`, `~/.codex/config.toml`)\n * or the driver's built-in default.\n */\n defaultModel?: { id: string; source: \"settings\" | \"driver\" } | null | undefined;\n /** The effort a run uses when none is picked (the person's own settings). */\n defaultEffort?: string | null | undefined;\n /** Which CLI runs use, and its version. */\n binary?: ProviderBinary | null | undefined;\n}\n\nexport interface ModelOption {\n id: string;\n label: string;\n}\n\n/**\n * The person's own organisation of their chats — a rename, a pin, a hide. Kept\n * in this package's data dir, keyed by `chatKey()`; the providers' own files\n * are NEVER touched (a rename here does not rename the chat in Claude Code).\n */\nexport interface ChatPreference {\n /** Shown instead of the chat's own title. */\n title?: string | null | undefined;\n pinned?: boolean | undefined;\n /** Hidden from the lists (still found by search, restorable). */\n hidden?: boolean | undefined;\n updatedAt?: string | undefined;\n}\n\n/** The one key a chat's preference lives under, for ours and discovered alike. */\nexport function chatKey(provider: CodingProvider, providerSessionId: string | null, sessionId?: string | null): string {\n return providerSessionId ? `${provider}:${providerSessionId}` : `session:${sessionId ?? \"\"}`;\n}\n\n/** One chat that matched a search. */\nexport interface ChatSearchHit {\n provider: CodingProvider;\n providerSessionId: string;\n title: string;\n cwd: string | null;\n updatedAt: string;\n /** Where the words were found. */\n where: \"title\" | \"content\";\n /** A short excerpt around the first match in the conversation. */\n snippet: string | null;\n}\n\nexport interface ChatSearchResult {\n query: string;\n hits: ChatSearchHit[];\n /** How many chats were read, newest first, starting from the cursor. */\n scanned: number;\n /** How many chats exist on this computer. */\n total: number;\n /** Pass back to keep searching older chats; null when every chat was read. */\n nextCursor: number | null;\n}\n\n/** Where \"Open folder\" can open a session's folder. */\nexport type OpenTarget = \"finder\" | \"vscode\" | \"cursor\" | \"terminal\";\n\nexport interface ProviderProblem {\n kind: \"usage-limit\" | \"signed-out\";\n /** The provider's own words, verbatim. */\n message: string;\n /** When a usage limit lifts: ISO when parseable, else the provider's phrase. */\n until: string | null;\n at: string;\n}\n\nexport interface QuotaWindow {\n label: string;\n usedPercent: number | null;\n resetsAt: string | null;\n valueLabel: string | null;\n}\n\n/** An existing local Claude Code or Codex chat, found on disk (metadata only). */\nexport interface DiscoveredSession {\n provider: CodingProvider;\n providerSessionId: string;\n cwd: string | null;\n /**\n * The chat's own title by the one rule (`./sessions`): the coding app's title when the owner of\n * the apps' index supplied it (title hints), else the transcript's. Never the person's rename —\n * that is applied once, by the screen, from the preferences.\n */\n title: string;\n /** Where `title` came from (`TITLE_PRECEDENCE`). */\n titleSource?: TitleSource | \"unknown\" | undefined;\n /** The app's title is still on its way (hints not loaded yet); `title` is the transcript's for now. */\n titlePending?: boolean | undefined;\n /** Archived in the app (hidden by default, like Code › Chats). */\n archived?: boolean | undefined;\n /** A scheduled or automated run (hidden by default). */\n scheduled?: boolean | undefined;\n /** The app lists it but its conversation file is gone: why. Shown, cannot be taken over. */\n unavailable?: string | null | undefined;\n updatedAt: string;\n /** Where it was started, when the provider records it (\"cli\", \"vscode\", \"exec\", …). */\n source: string | null;\n /** Set when the chat looks live somewhere else right now (see `ActiveElsewhere`). */\n activeElsewhere: ActiveElsewhere | null;\n}\n\n/**\n * Evidence that a chat is being driven somewhere else RIGHT NOW. Taking it\n * over then puts two agents on one conversation, so the screen warns and asks —\n * it never blocks (validation offers, never blocks).\n */\nexport interface ActiveElsewhere {\n /** How we know, strongest first. */\n reason: \"process\" | \"recent-write\" | \"open-tool-call\";\n /** One plain sentence for the screen. */\n message: string;\n}\n\nexport type RunStatus = \"starting\" | \"running\" | \"completed\" | \"stopped\" | \"failed\";\n\nexport const TERMINAL_RUN_STATUSES: readonly RunStatus[] = [\"completed\", \"stopped\", \"failed\"];\n\nexport function isTerminalRunStatus(status: RunStatus): boolean {\n return TERMINAL_RUN_STATUSES.includes(status);\n}\n\nexport interface RunUsage {\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens: number;\n}\n\n/** One turn: one prompt sent to one provider process. */\nexport interface RunRecord {\n runId: string;\n /** Our session id (`CodingSession.id`). */\n sessionId: string;\n provider: CodingProvider;\n cwd: string;\n prompt: string;\n model: string | null;\n status: RunStatus;\n startedAt: string;\n endedAt: string | null;\n /** The real error, verbatim from the provider or the driver, when failed. */\n error: string | null;\n usage: RunUsage | null;\n costUsd: number | null;\n billing: Billing | null;\n}\n\n/** How a session came to be listed here. */\nexport type SessionOrigin = \"started\" | \"takeover\";\n\n/** A conversation driven from here. Its transcript lives in the provider's own\n * files; this is only the index row. */\nexport interface CodingSession {\n /** Our stable id. */\n id: string;\n provider: CodingProvider;\n /** The provider's own session/thread id — null until the first run reports it. */\n providerSessionId: string | null;\n cwd: string;\n title: string;\n model: string | null;\n /** Reasoning effort for the next run; null = the provider's own default. */\n effort?: string | null | undefined;\n origin: SessionOrigin;\n createdAt: string;\n updatedAt: string;\n /** The live or most recent run. */\n lastRunId: string | null;\n lastRunStatus: RunStatus | null;\n /** Prompts waiting for the active run to finish, oldest first. */\n queued: string[];\n /** The AI Matrx agent loaded into every run of this session, when one was picked. */\n agent?: SessionAgent | null | undefined;\n /** Codex must be told, in the next prompt, that an earlier agent no longer applies. */\n agentRemovedDue?: boolean | undefined;\n}\n\n/**\n * One normalized transcript item — the same shape from Claude and Codex, from\n * a live stream and from a provider's saved session file.\n */\nexport type TranscriptItem =\n | { kind: \"user\"; id: string; text: string; at: string | null }\n | { kind: \"text\"; id: string; text: string }\n | { kind: \"text-delta\"; id: string; text: string }\n | { kind: \"reasoning\"; id: string; text: string }\n | { kind: \"tool-call\"; id: string; name: string; input: unknown }\n | { kind: \"tool-result\"; id: string; output: string; isError: boolean }\n | { kind: \"usage\"; usage: RunUsage; costUsd: number | null }\n | { kind: \"notice\"; id: string; level: \"info\" | \"warning\"; text: string }\n | { kind: \"error\"; id: string; text: string };\n\nexport interface TitleStatus {\n owner: boolean;\n pending: boolean;\n problem: string | null;\n}\n\n/** Everything the engine pushes to a listener. */\nexport type CodingEvent =\n | { type: \"session\"; session: CodingSession }\n | { type: \"run\"; run: RunRecord }\n | { type: \"preferences\"; preferences: Record<string, ChatPreference> }\n /** The apps' titles changed (or finished loading): re-read the discovered chats. */\n | { type: \"titles\" }\n | {\n type: \"item\";\n sessionId: string;\n runId: string;\n /** Monotonic per session; a history read reports the last `seq` it includes. */\n seq: number;\n item: TranscriptItem;\n };\n\n/** A transcript read back from the provider's own file. */\nexport interface SessionHistory {\n items: TranscriptItem[];\n /** True when the file was larger than the read budget and only its end was read. */\n truncated: boolean;\n /** Plain-English reason when history could not be read (never thrown at the UI). */\n unavailable: string | null;\n /** The last live item `seq` this read already contains; apply only newer ones. */\n seq: number;\n}\n\nexport interface StartInput {\n provider: CodingProvider;\n cwd: string;\n prompt: string;\n model?: string | null | undefined;\n effort?: string | null | undefined;\n /** An AI Matrx agent to load into the CLI. Needs the host's `agents` credentials. */\n agent?: AgentSelection | null | undefined;\n}\n\n/** Which AI Matrx agent a new session loads, and the person's variable values. */\nexport interface AgentSelection {\n agentId: string;\n /** Pin one saved version; omitted = the latest, pinned at start. */\n versionId?: string | null | undefined;\n variables?: Record<string, JsonValue> | undefined;\n}\n\n/** One part of an agent and whether this session's CLI carries it. */\nexport interface SessionAgentPart {\n part: \"instructions\" | \"skills\" | \"tools\";\n loaded: number;\n total: number;\n}\n\n/**\n * The agent a session runs with. Recorded at start and never drifts: every\n * later turn reloads the SAME bundle (same version, same hash).\n */\nexport interface SessionAgent {\n agentId: string;\n versionId: string | null;\n versionNumber: number | null;\n name: string;\n definitionHash: string;\n loaded: SessionAgentPart[];\n /** What could not be carried, with the reason. */\n unavailable: { kind: string; name: string; reason: string }[];\n /** The skills it carries (labels) and the tools it serves (names) — the agent's own set. */\n skills?: string[] | undefined;\n tools?: string[] | undefined;\n /** The person's variable values, kept so \"Update to vN\" can reuse them. */\n variables?: Record<string, JsonValue> | undefined;\n /**\n * The CLI must be TOLD in the next prompt (a delimited block): a Codex\n * takeover or agent switch (Codex ignores developer_instructions on resume),\n * or a Codex compaction that dropped the block. Cleared once delivered.\n */\n blockDue?: boolean | undefined;\n /** When the block (or native instructions) last reached the CLI. */\n deliveredAt?: string | null | undefined;\n /** The agent this one replaced mid-chat (\"Code Reviewer v1\"), named in the block. */\n replaces?: string | null | undefined;\n}\n\n/** Whether this host can reach AI Matrx as a signed-in person. */\nexport interface AgentAccess {\n signedIn: boolean;\n userId: string | null;\n organizationId: string | null;\n /** True when the host was started with no AI Matrx connection at all. */\n configured: boolean;\n}\n\n/** A catalogue read the picker asks the host to make (PostgREST RPC shape). */\nexport interface AgentCatalogRpcRequest {\n fn: string;\n args?: Record<string, unknown> | undefined;\n count?: \"exact\" | \"planned\" | \"estimated\" | undefined;\n range?: [number, number] | undefined;\n order?: { column: string; ascending?: boolean | undefined } | undefined;\n}\n\nexport interface AgentCatalogRpcResult {\n data: unknown;\n error: {\n message: string;\n code?: string | undefined;\n details?: string | null | undefined;\n hint?: string | null | undefined;\n } | null;\n count?: number | null;\n}\n\n/** What a picker needs about one agent — the LIGHT read (no skills, no tools). */\nexport interface AgentDetails {\n agentId: string;\n name: string;\n /** Variable declarations as authored (camelCase). */\n variables: Record<string, JsonValue>[];\n /** Newest first. */\n versions: { id: string; versionNumber: number; changedAt: string | null }[];\n /** The version \"Latest\" resolves to right now. */\n latestVersionNumber: number | null;\n latestVersionId: string | null;\n}\n\nexport interface TakeoverInput {\n provider: CodingProvider;\n providerSessionId: string;\n cwd: string;\n title?: string | undefined;\n /** Continue the chat WITH an AI Matrx agent (\"Continue with agent\"). */\n agent?: AgentSelection | null | undefined;\n}\n\nexport interface SendResult {\n session: CodingSession;\n /** The run that started, or null when the prompt was queued behind a live run. */\n run: RunRecord | null;\n queued: boolean;\n}\n\nexport interface FolderCheck {\n /** The absolute path the check resolved. */\n path: string;\n exists: boolean;\n /** False when something that is NOT a folder sits at the path. */\n isDirectory: boolean;\n}\n\n/** A folder the New session flow offers (from discovered and driven sessions). */\nexport interface RecentFolder {\n path: string;\n lastUsedAt: string;\n exists: boolean;\n}\n\n/**\n * THE ENGINE CONTRACT — what the UI can ask for, independent of transport.\n * The WebSocket host implements it over the wire; a desktop app implements it\n * over IPC; the UI never knows which.\n */\nexport interface CodingSessionsApi {\n providers(): Promise<ProviderStatus[]>;\n discoverSessions(options?: { limit?: number }): Promise<DiscoveredSession[]>;\n /** Where the apps' own titles stand: an owner supplies them (`owner`), still loading, or failing (`problem`, shown with Retry). */\n titleStatus(): Promise<TitleStatus>;\n /** Ask the owner of the apps' titles again (the Retry). */\n retryTitles(): Promise<void>;\n recentFolders(): Promise<RecentFolder[]>;\n listSessions(): Promise<CodingSession[]>;\n listRuns(sessionId: string): Promise<RunRecord[]>;\n /** `maxBytes` reads more of a long chat's file (\"Show earlier\"). */\n history(sessionId: string, options?: HistoryOptions): Promise<SessionHistory>;\n /** Read-only transcript of a chat found on disk, before taking it over. */\n readTranscript(provider: CodingProvider, providerSessionId: string, options?: HistoryOptions): Promise<SessionHistory>;\n /**\n * FULL DOWNLOAD: the provider's own complete transcript file for this chat,\n * byte for byte (every tool input and output). AI Matrx's cloud keeps only\n * text and tool names, so this computer is the first place the full file\n * lives. `available: false` carries the sentence saying why.\n */\n readRawTranscript(provider: CodingProvider, providerSessionId: string): Promise<RawTranscript>;\n /** Does this folder exist here? `~` is the person's home. */\n checkFolder(path: string): Promise<FolderCheck>;\n /** Create a folder (and any missing parents), then report on it. */\n createFolder(path: string): Promise<FolderCheck>;\n /** Fresh check: is this chat live somewhere else right now? null when not. */\n sessionActivity(provider: CodingProvider, providerSessionId: string): Promise<ActiveElsewhere | null>;\n start(input: StartInput): Promise<SendResult>;\n takeover(input: TakeoverInput): Promise<CodingSession>;\n send(sessionId: string, prompt: string): Promise<SendResult>;\n stop(runId: string): Promise<RunRecord | null>;\n /** The person's renames, pins and hides, by `chatKey()`. */\n chatPreferences(): Promise<Record<string, ChatPreference>>;\n /** Merge a change into one chat's preference; `null` fields clear. Returns them all. */\n setChatPreference(key: string, patch: ChatPreference): Promise<Record<string, ChatPreference>>;\n /** Find chats by title and by what was said in them, newest first, within a time budget. */\n searchChats(query: string, options?: { cursor?: number; limit?: number }): Promise<ChatSearchResult>;\n /** Open a folder in Finder, VS Code, Cursor or Terminal. */\n openFolder(path: string, target: OpenTarget): Promise<void>;\n /** Change the model or effort the NEXT run of a session uses. */\n setSessionOptions(sessionId: string, options: { model?: string | null; effort?: string | null }): Promise<CodingSession>;\n /** Is this host signed in to AI Matrx (so agents can load)? */\n agentAccess(): Promise<AgentAccess>;\n /** One allowlisted agent-catalogue read, made by the host as the signed-in person. */\n agentCatalogRpc(request: AgentCatalogRpcRequest): Promise<AgentCatalogRpcResult>;\n /** An agent's variables and saved versions, for the New session form. */\n agentDetails(agentId: string): Promise<AgentDetails>;\n /**\n * Load a different agent into a session from its next message on (or\n * remove it, with `null`). Claude reads it every turn; Codex is told in the\n * next prompt.\n */\n setAgent(sessionId: string, agent: AgentSelection | null): Promise<CodingSession>;\n}\n\nexport type RawTranscript =\n | { available: true; fileName: string; bytes: number; content: string }\n | { available: false; reason: string };\n\nexport interface HistoryOptions {\n /** Read up to this many bytes from the end of the file (default 24 MB). */\n maxBytes?: number | undefined;\n}\n\nexport type CodingSessionsMethod = keyof CodingSessionsApi;\n\n/** The transport the UI talks through (WebSocket, IPC, in-process). */\nexport interface CodingSessionsTransport {\n call<M extends CodingSessionsMethod>(\n method: M,\n ...args: Parameters<CodingSessionsApi[M]>\n ): ReturnType<CodingSessionsApi[M]>;\n subscribe(listener: (event: CodingEvent) => void): () => void;\n /** Connection state, for an honest banner. */\n status(): TransportStatus;\n onStatus(listener: (status: TransportStatus) => void): () => void;\n}\n\nexport type TransportStatus =\n | { state: \"connecting\" }\n | { state: \"open\" }\n | { state: \"closed\"; reason: string };\n","/**\n * The delimited AI Matrx agent block a coding session puts in front of a\n * person's message when a CLI must be TOLD about the agent (a Codex takeover,\n * an agent switch, after a compaction). Pure: the transcript strips it so the\n * screen shows what the person wrote, not how the CLI was told.\n */\n\n/** The marker every agent text we hand a CLI starts with. */\nexport const AGENT_BLOCK_MARKER = \"<ai_matrx_agent \";\n\n/**\n * Remove a leading agent block from a user message, so the transcript shows\n * what the PERSON wrote (the block is how the CLI was told, not their words).\n */\nexport function stripAgentBlock(text: string): string {\n const removed = text.match(/^<ai_matrx_agent_removed>[\\s\\S]*?<\\/ai_matrx_agent_removed>\\s*/);\n if (removed) return text.slice(removed[0].length);\n if (!text.startsWith(AGENT_BLOCK_MARKER)) return text;\n const end = text.indexOf(\"</ai_matrx_agent>\");\n if (end < 0) return text;\n let rest = text.slice(end + \"</ai_matrx_agent>\".length);\n // The Codex skills list rides after the block.\n const skills = rest.match(/^\\s*<skills_instructions>[\\s\\S]*?<\\/skills_instructions>/);\n if (skills) rest = rest.slice(skills[0].length);\n return rest.replace(/^\\s+/, \"\");\n}\n","/**\n * Claude Code → `TranscriptItem`.\n *\n * ONE normalizer reads both of Claude's shapes, because they are the same\n * shape: `claude --print --output-format stream-json` lines (live) and the\n * entries of the user's own session file `~/.claude/projects/<cwd>/<id>.jsonl`\n * (history) both carry `{ type: \"assistant\" | \"user\", message: { content } }`.\n * The live stream adds `system`/`stream_event`/`result`; the file adds its own\n * bookkeeping entries (titles, attachments, snapshots), which are skipped.\n *\n * Block identity: an assistant message arrives as several lines sharing one\n * `message.id`, one content block per line, in block order — the same order\n * the partial-message `content_block_start.index` counts. So a text block's id\n * is `<message id>:<index>` on both paths, and a streamed draft is replaced by\n * its final text rather than duplicated.\n */\n\nimport type { RunUsage, TranscriptItem } from \"../types\";\nimport { stripAgentBlock } from \"./agent-block\";\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\n/** User-role text Claude Code writes that the person never typed. */\nconst SYNTHETIC_USER_PREFIXES = [\n \"<command-name>\",\n \"<command-message>\",\n \"<command-args>\",\n \"<local-command-stdout>\",\n \"<local-command-stderr>\",\n \"<local-command-caveat>\",\n \"<system-reminder>\",\n \"<bash-input>\",\n \"<bash-stdout>\",\n \"<bash-stderr>\",\n \"<user-memory-input>\",\n \"<task-notification>\",\n \"Caveat: The messages below were generated by the user while running local commands\",\n \"[Request interrupted by user\",\n];\n\nexport function isSyntheticClaudeUserText(text: string): boolean {\n const trimmed = text.trimStart();\n return SYNTHETIC_USER_PREFIXES.some((prefix) => trimmed.startsWith(prefix));\n}\n\nfunction toolResultText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n return content\n .map((block) => {\n if (!isObject(block)) return \"\";\n if (block.type === \"text\") return str(block.text) ?? \"\";\n if (block.type === \"image\") return \"[image]\";\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n return content === undefined || content === null ? \"\" : JSON.stringify(content);\n}\n\nexport interface ClaudeNormalizer {\n /** Feed one parsed JSON line; returns the items it produced (often none). */\n push(entry: unknown): TranscriptItem[];\n /** The Claude session id, once a line has carried it. */\n readonly sessionId: string | null;\n}\n\nexport function createClaudeNormalizer(): ClaudeNormalizer {\n let sessionId: string | null = null;\n let streamingMessageId: string | null = null;\n const blockCounters = new Map<string, number>();\n let userCounter = 0;\n let noticeCounter = 0;\n\n function nextBlockIndex(messageId: string): number {\n const index = blockCounters.get(messageId) ?? 0;\n blockCounters.set(messageId, index + 1);\n return index;\n }\n\n function pushAssistant(entry: Json): TranscriptItem[] {\n const message = isObject(entry.message) ? entry.message : null;\n if (!message) return [];\n const messageId = str(message.id) ?? str(entry.uuid) ?? `assistant-${blockCounters.size}`;\n const content = Array.isArray(message.content) ? message.content : [];\n const items: TranscriptItem[] = [];\n for (const block of content) {\n if (!isObject(block)) continue;\n const index = nextBlockIndex(messageId);\n const id = `${messageId}:${index}`;\n if (block.type === \"text\") {\n const text = str(block.text) ?? \"\";\n if (text.length > 0) items.push({ kind: \"text\", id, text });\n } else if (block.type === \"thinking\") {\n // Claude Code writes thinking blocks with an EMPTY text and only a\n // signature unless thinking display is on; an empty aside is noise.\n const text = str(block.thinking) ?? \"\";\n if (text.trim().length > 0) items.push({ kind: \"reasoning\", id, text });\n } else if (block.type === \"tool_use\" || block.type === \"server_tool_use\") {\n items.push({\n kind: \"tool-call\",\n id: str(block.id) ?? id,\n name: str(block.name) ?? \"tool\",\n input: block.input ?? null,\n });\n }\n }\n return items;\n }\n\n function pushUser(entry: Json): TranscriptItem[] {\n if (entry.isMeta === true || entry.isCompactSummary === true) return [];\n const message = isObject(entry.message) ? entry.message : null;\n if (!message) return [];\n const at = str(entry.timestamp);\n const content = message.content;\n if (typeof content === \"string\") {\n if (isSyntheticClaudeUserText(content) || content.trim().length === 0) return [];\n userCounter += 1;\n // The agent block is how the CLI was told, not the person's words.\n return [{ kind: \"user\", id: str(entry.uuid) ?? `user-${userCounter}`, text: stripAgentBlock(content), at }];\n }\n if (!Array.isArray(content)) return [];\n const items: TranscriptItem[] = [];\n const typed: string[] = [];\n for (const block of content) {\n if (!isObject(block)) continue;\n if (block.type === \"tool_result\") {\n items.push({\n kind: \"tool-result\",\n id: str(block.tool_use_id) ?? \"unknown\",\n output: toolResultText(block.content),\n isError: block.is_error === true,\n });\n } else if (block.type === \"text\") {\n const text = str(block.text) ?? \"\";\n if (text.trim().length > 0 && !isSyntheticClaudeUserText(text)) typed.push(text);\n }\n }\n if (typed.length > 0) {\n userCounter += 1;\n items.unshift({\n kind: \"user\",\n id: str(entry.uuid) ?? `user-${userCounter}`,\n text: stripAgentBlock(typed.join(\"\\n\\n\")),\n at,\n });\n }\n return items;\n }\n\n function pushStreamEvent(entry: Json): TranscriptItem[] {\n const event = isObject(entry.event) ? entry.event : null;\n if (!event) return [];\n if (event.type === \"message_start\" && isObject(event.message)) {\n streamingMessageId = str(event.message.id);\n return [];\n }\n if (event.type === \"content_block_delta\" && streamingMessageId !== null) {\n const delta = isObject(event.delta) ? event.delta : null;\n if (delta?.type === \"text_delta\") {\n const text = str(delta.text) ?? \"\";\n if (text.length === 0) return [];\n return [{ kind: \"text-delta\", id: `${streamingMessageId}:${num(event.index)}`, text }];\n }\n }\n return [];\n }\n\n function pushResult(entry: Json): TranscriptItem[] {\n const items: TranscriptItem[] = [];\n const usage = isObject(entry.usage) ? entry.usage : null;\n if (usage) {\n const runUsage: RunUsage = {\n inputTokens: num(usage.input_tokens) + num(usage.cache_creation_input_tokens),\n outputTokens: num(usage.output_tokens),\n cachedInputTokens: num(usage.cache_read_input_tokens),\n };\n const cost = typeof entry.total_cost_usd === \"number\" ? entry.total_cost_usd : null;\n items.push({ kind: \"usage\", usage: runUsage, costUsd: cost });\n }\n if (entry.is_error === true || (typeof entry.subtype === \"string\" && entry.subtype !== \"success\")) {\n const text =\n str(entry.result) ??\n (Array.isArray(entry.errors) ? entry.errors.map(String).join(\"\\n\") : null) ??\n `Claude Code stopped with \"${String(entry.subtype)}\".`;\n noticeCounter += 1;\n items.push({ kind: \"error\", id: `claude-result-${noticeCounter}`, text });\n }\n return items;\n }\n\n return {\n get sessionId() {\n return sessionId;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n const lineSession = str(raw.session_id) ?? str(raw.sessionId);\n if (lineSession && sessionId === null) sessionId = lineSession;\n if (raw.isSidechain === true) return [];\n switch (raw.type) {\n case \"assistant\":\n return pushAssistant(raw);\n case \"user\":\n return pushUser(raw);\n case \"stream_event\":\n return pushStreamEvent(raw);\n case \"result\":\n return pushResult(raw);\n case \"system\":\n if (raw.subtype === \"compact_boundary\") {\n noticeCounter += 1;\n return [\n {\n kind: \"notice\",\n id: `claude-compact-${noticeCounter}`,\n level: \"info\",\n text: \"Claude Code summarized the earlier part of this conversation to make room.\",\n },\n ];\n }\n return [];\n default:\n return [];\n }\n },\n };\n}\n","/**\n * Codex → `TranscriptItem`, from its two different shapes:\n *\n * - the LIVE stream (`codex exec --json`): `thread.started`, `item.started` /\n * `item.completed` for agent messages, commands, file changes, MCP calls,\n * web searches and plans, then `turn.completed` with usage;\n * - the user's own saved rollout file (`~/.codex/sessions/**\\/rollout-*.jsonl`):\n * `session_meta`, `event_msg` (the person's words, verbatim) and\n * `response_item` (assistant messages, tool calls and their outputs).\n *\n * Codex numbers stream items `item_0, item_1, …` again on every run, so live\n * ids carry a per-run prefix; rollout items carry globally unique call ids.\n */\n\nimport type { RunUsage, TranscriptItem } from \"../types\";\nimport { stripAgentBlock } from \"./agent-block\";\n\ntype Json = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction str(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction num(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\nfunction codexUsage(usage: Json): RunUsage {\n return {\n inputTokens: num(usage.input_tokens),\n outputTokens: num(usage.output_tokens),\n cachedInputTokens: num(usage.cached_input_tokens),\n };\n}\n\n/** Human names for Codex's item kinds, so a tool card reads like a sentence. */\nfunction toolCall(id: string, item: Json): TranscriptItem | null {\n switch (item.type) {\n case \"command_execution\":\n return { kind: \"tool-call\", id, name: \"Shell\", input: { command: str(item.command) ?? \"\" } };\n case \"file_change\":\n return { kind: \"tool-call\", id, name: \"Edit files\", input: { changes: item.changes ?? [] } };\n case \"mcp_tool_call\": {\n const server = str(item.server) ?? \"mcp\";\n const tool = str(item.tool) ?? \"tool\";\n return { kind: \"tool-call\", id, name: `${server}.${tool}`, input: item.arguments ?? null };\n }\n case \"web_search\":\n return { kind: \"tool-call\", id, name: \"Web search\", input: { query: str(item.query) ?? \"\" } };\n case \"todo_list\":\n return { kind: \"tool-call\", id, name: \"Plan\", input: { items: item.items ?? [] } };\n default:\n return null;\n }\n}\n\nfunction toolResult(id: string, item: Json): TranscriptItem | null {\n switch (item.type) {\n case \"command_execution\": {\n const exit = typeof item.exit_code === \"number\" ? item.exit_code : null;\n const output = str(item.aggregated_output) ?? \"\";\n return {\n kind: \"tool-result\",\n id,\n output: exit !== null && exit !== 0 ? `${output}\\n(exit code ${exit})`.trim() : output,\n isError: (exit !== null && exit !== 0) || item.status === \"failed\",\n };\n }\n case \"file_change\":\n return {\n kind: \"tool-result\",\n id,\n output: item.status === \"failed\" ? \"The file change failed.\" : \"Applied.\",\n isError: item.status === \"failed\",\n };\n case \"mcp_tool_call\": {\n const error = isObject(item.error) ? str(item.error.message) : str(item.error);\n return {\n kind: \"tool-result\",\n id,\n output: error ?? (item.result === undefined ? \"\" : JSON.stringify(item.result)),\n isError: error !== null || item.status === \"failed\",\n };\n }\n case \"web_search\":\n case \"todo_list\":\n return { kind: \"tool-result\", id, output: \"\", isError: false };\n default:\n return null;\n }\n}\n\nexport interface CodexStreamNormalizer {\n push(entry: unknown): TranscriptItem[];\n readonly sessionId: string | null;\n}\n\n/** The live `codex exec --json` stream. `runPrefix` keeps ids unique per run. */\nexport function createCodexStreamNormalizer(runPrefix: string): CodexStreamNormalizer {\n let sessionId: string | null = null;\n const started = new Set<string>();\n let counter = 0;\n\n return {\n get sessionId() {\n return sessionId;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n switch (raw.type) {\n case \"thread.started\":\n sessionId = str(raw.thread_id) ?? sessionId;\n return [];\n case \"item.started\":\n case \"item.updated\":\n case \"item.completed\": {\n const item = isObject(raw.item) ? raw.item : null;\n if (!item) return [];\n const id = `${runPrefix}:${str(item.id) ?? `item-${counter++}`}`;\n const completed = raw.type === \"item.completed\";\n if (item.type === \"agent_message\") {\n if (!completed) return [];\n const text = str(item.text) ?? \"\";\n return text ? [{ kind: \"text\", id, text }] : [];\n }\n if (item.type === \"reasoning\") {\n if (!completed) return [];\n const text = str(item.text) ?? \"\";\n return text.trim() ? [{ kind: \"reasoning\", id, text }] : [];\n }\n if (item.type === \"error\") {\n if (!completed) return [];\n // An `error` ITEM is a non-fatal warning (the run continues); a\n // fatal failure arrives as `turn.failed` or a top-level `error`.\n return [{ kind: \"notice\", id, level: \"warning\", text: str(item.message) ?? \"Codex warning.\" }];\n }\n const items: TranscriptItem[] = [];\n if (!started.has(id)) {\n const call = toolCall(id, item);\n if (call) {\n started.add(id);\n items.push(call);\n }\n }\n if (completed) {\n const result = toolResult(id, item);\n if (result) items.push(result);\n }\n return items;\n }\n case \"turn.completed\":\n return isObject(raw.usage)\n ? [{ kind: \"usage\", usage: codexUsage(raw.usage), costUsd: null }]\n : [];\n case \"turn.failed\": {\n const error = isObject(raw.error) ? str(raw.error.message) : null;\n counter += 1;\n return [{ kind: \"error\", id: `${runPrefix}:failed-${counter}`, text: error ?? \"Codex reported that the turn failed.\" }];\n }\n case \"error\":\n counter += 1;\n return [{ kind: \"error\", id: `${runPrefix}:error-${counter}`, text: str(raw.message) ?? \"Codex reported an error.\" }];\n default:\n return [];\n }\n },\n };\n}\n\nfunction contentText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .map((block) => (isObject(block) ? (str(block.text) ?? \"\") : \"\"))\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction parseArguments(raw: unknown): unknown {\n if (typeof raw !== \"string\") return raw ?? null;\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return raw;\n }\n}\n\nfunction shellName(name: string): string {\n return name === \"shell\" || name === \"exec_command\" || name === \"local_shell\" ? \"Shell\" : name;\n}\n\n/**\n * The Codex app prepends ambient context to what the person typed\n * (`<in-app-browser-context …>…</in-app-browser-context>\\n## My request:\\n…`).\n * It is not their words; a title or a transcript bubble shows only theirs.\n */\nexport function stripCodexInjectedContext(text: string): string {\n let out = text;\n const leading = /^\\s*<([a-z][\\w-]*)(?:\\s[^>]*)?>[\\s\\S]*?<\\/\\1>/i;\n for (let i = 0; i < 8 && leading.test(out); i += 1) out = out.replace(leading, \"\");\n return out.replace(/^\\s*#{1,6}\\s*My request:\\s*/i, \"\").trim() || text.trim();\n}\n\n/** Text of a rollout `item_completed` item's `content` blocks. */\nfunction itemText(content: unknown): string {\n if (!Array.isArray(content)) return \"\";\n return content\n .map((block) => (isObject(block) ? (str(block.text) ?? \"\") : \"\"))\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction commandLine(command: unknown): string {\n if (Array.isArray(command)) {\n // [\"/bin/zsh\", \"-lc\", \"ls -la\"] → \"ls -la\": the shell wrapper is noise.\n const last = command[command.length - 1];\n if (command.length >= 3 && typeof last === \"string\") return last;\n return command.map(String).join(\" \");\n }\n return typeof command === \"string\" ? command : \"\";\n}\n\n/**\n * Current Codex (0.15x) records each turn TWICE in a rollout: the model-level\n * `response_item`s (where a shell command is a JavaScript `exec` snippet) and\n * the app-level `event_msg: item_completed` items the Codex app itself renders\n * (UserMessage, AgentMessage, CommandExecution, FileChange, …). The app-level\n * items read the way a person thinks about the work, so once a file shows it\n * has them, they are the transcript and the response_items are skipped.\n * Older rollouts have only response_items plus `event_msg: user_message`.\n */\nfunction rolloutItem(item: Json, fallbackId: string, at: string | null): TranscriptItem[] {\n const id = str(item.id) ?? fallbackId;\n switch (item.type) {\n case \"UserMessage\": {\n const text = stripCodexInjectedContext(stripAgentBlock(itemText(item.content)));\n return text.trim() ? [{ kind: \"user\", id, text, at }] : [];\n }\n case \"AgentMessage\": {\n const text = itemText(item.content);\n return text ? [{ kind: \"text\", id, text }] : [];\n }\n case \"Reasoning\": {\n const text = Array.isArray(item.summary_text) ? item.summary_text.map(String).join(\"\\n\") : \"\";\n return text.trim() ? [{ kind: \"reasoning\", id, text }] : [];\n }\n case \"CommandExecution\": {\n const exit = typeof item.exit_code === \"number\" ? item.exit_code : null;\n const output = str(item.aggregated_output) ?? str(item.formatted_output) ?? str(item.stdout) ?? \"\";\n const failed = (exit !== null && exit !== 0) || item.status === \"failed\";\n return [\n { kind: \"tool-call\", id, name: \"Shell\", input: { command: commandLine(item.command) } },\n {\n kind: \"tool-result\",\n id,\n output: failed && exit !== null ? `${output}\\n(exit code ${exit})`.trim() : output,\n isError: failed,\n },\n ];\n }\n case \"FileChange\":\n return [\n { kind: \"tool-call\", id, name: \"Edit files\", input: { changes: item.changes ?? null } },\n { kind: \"tool-result\", id, output: item.status === \"failed\" ? \"The file change failed.\" : \"Applied.\", isError: item.status === \"failed\" },\n ];\n case \"McpToolCall\": {\n const name = `${str(item.server) ?? \"mcp\"}.${str(item.tool) ?? \"tool\"}`;\n const error = isObject(item.error) ? str(item.error.message) : str(item.error);\n return [\n { kind: \"tool-call\", id, name, input: item.arguments ?? null },\n {\n kind: \"tool-result\",\n id,\n output: error ?? (item.result === undefined ? \"\" : JSON.stringify(item.result)),\n isError: error !== null || item.status === \"failed\",\n },\n ];\n }\n case \"WebSearch\":\n return [\n { kind: \"tool-call\", id, name: \"Web search\", input: { query: str(item.query) ?? \"\" } },\n { kind: \"tool-result\", id, output: \"\", isError: false },\n ];\n default:\n return [];\n }\n}\n\nexport interface CodexRolloutNormalizer {\n push(entry: unknown): TranscriptItem[];\n readonly sessionId: string | null;\n readonly cwd: string | null;\n}\n\n/** The user's saved rollout file. */\nexport function createCodexRolloutNormalizer(): CodexRolloutNormalizer {\n let sessionId: string | null = null;\n let cwd: string | null = null;\n let counter = 0;\n let appItems = false;\n\n return {\n get sessionId() {\n return sessionId;\n },\n get cwd() {\n return cwd;\n },\n push(raw: unknown): TranscriptItem[] {\n if (!isObject(raw)) return [];\n const payload = isObject(raw.payload) ? raw.payload : null;\n if (!payload) return [];\n const at = str(raw.timestamp);\n counter += 1;\n const fallbackId = `rollout-${typeof raw.ordinal === \"number\" ? raw.ordinal : counter}`;\n if (raw.type === \"session_meta\") {\n sessionId = str(payload.id) ?? sessionId;\n cwd = str(payload.cwd) ?? cwd;\n return [];\n }\n if (raw.type === \"event_msg\") {\n if (payload.type === \"item_completed\" && isObject(payload.item)) {\n appItems = true;\n return rolloutItem(payload.item, fallbackId, at);\n }\n if (payload.type === \"user_message\" && !appItems) {\n const text = stripCodexInjectedContext(stripAgentBlock(str(payload.message) ?? \"\"));\n return text.trim() ? [{ kind: \"user\", id: fallbackId, text, at }] : [];\n }\n return [];\n }\n if (raw.type === \"compacted\") {\n return [\n {\n kind: \"notice\",\n id: fallbackId,\n level: \"info\",\n text: \"Codex summarized the earlier part of this conversation to make room.\",\n },\n ];\n }\n if (raw.type !== \"response_item\" || appItems) return [];\n switch (payload.type) {\n case \"message\": {\n if (payload.role !== \"assistant\") return [];\n const text = contentText(payload.content);\n return text ? [{ kind: \"text\", id: str(payload.id) ?? fallbackId, text }] : [];\n }\n case \"reasoning\": {\n const summary = Array.isArray(payload.summary)\n ? payload.summary.map((part) => (isObject(part) ? (str(part.text) ?? \"\") : \"\")).join(\"\\n\")\n : \"\";\n return summary.trim()\n ? [{ kind: \"reasoning\", id: str(payload.id) ?? fallbackId, text: summary }]\n : [];\n }\n case \"function_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: shellName(str(payload.name) ?? \"tool\"),\n input: parseArguments(payload.arguments),\n },\n ];\n case \"custom_tool_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: shellName(str(payload.name) ?? \"tool\"),\n input: payload.input ?? null,\n },\n ];\n case \"local_shell_call\": {\n const action = isObject(payload.action) ? payload.action : {};\n return [\n {\n kind: \"tool-call\",\n id: str(payload.call_id) ?? fallbackId,\n name: \"Shell\",\n input: { command: action.command ?? null },\n },\n ];\n }\n case \"web_search_call\":\n return [\n {\n kind: \"tool-call\",\n id: str(payload.id) ?? fallbackId,\n name: \"Web search\",\n input: payload.action ?? null,\n },\n { kind: \"tool-result\", id: str(payload.id) ?? fallbackId, output: \"\", isError: false },\n ];\n case \"function_call_output\":\n case \"custom_tool_call_output\":\n case \"local_shell_call_output\": {\n const output = payload.output;\n const text =\n typeof output === \"string\"\n ? output\n : isObject(output)\n ? (str(output.content) ?? JSON.stringify(output))\n : contentText(output);\n return [\n {\n kind: \"tool-result\",\n id: str(payload.call_id) ?? fallbackId,\n output: text,\n isError: isObject(output) && output.success === false,\n },\n ];\n }\n default:\n return [];\n }\n },\n };\n}\n","/**\n * Stdout arrives in arbitrary chunks; the providers write one JSON object per\n * line. This turns chunks into parsed lines, keeping a partial tail between\n * chunks, and reports (never throws on) a line that is not JSON — the CLIs do\n * print plain-text warnings on stdout now and then.\n */\n\nexport interface LineSplitter {\n push(chunk: string): { values: unknown[]; nonJson: string[] };\n /** Whatever is left when the stream ends. */\n flush(): { values: unknown[]; nonJson: string[] };\n}\n\nfunction parseLines(lines: string[]): { values: unknown[]; nonJson: string[] } {\n const values: unknown[] = [];\n const nonJson: string[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (!trimmed.startsWith(\"{\")) {\n nonJson.push(trimmed);\n continue;\n }\n try {\n values.push(JSON.parse(trimmed) as unknown);\n } catch {\n nonJson.push(trimmed);\n }\n }\n return { values, nonJson };\n}\n\nexport function createLineSplitter(): LineSplitter {\n let buffer = \"\";\n return {\n push(chunk) {\n buffer += chunk;\n const parts = buffer.split(\"\\n\");\n buffer = parts.pop() ?? \"\";\n return parseLines(parts);\n },\n flush() {\n const rest = buffer;\n buffer = \"\";\n return parseLines([rest]);\n },\n };\n}\n\n/** Parse a whole JSONL text (a fixture, or a provider file read in one go). */\nexport function parseJsonl(text: string): unknown[] {\n return parseLines(text.split(\"\\n\")).values;\n}\n","/**\n * `TranscriptItem`s → `@ai-matrx/chat` messages.\n *\n * The transcript is rendered by THE one person ↔ agent chat interface\n * (`@ai-matrx/chat`), not by a second message list: its message/part model\n * already has text, reasoning, tool parts on the industry tool-call state\n * machine, notices and errors, and its React transcript already renders them\n * (markdown, collapsible tool cards, streaming). This module is the only\n * adapter: one assistant message per turn, parts in arrival order.\n *\n * Identity is preserved on purpose: a change rebuilds ONLY the message it\n * touched, so the chat store's per-message subscriptions wake one bubble per\n * token instead of the whole list.\n */\n\nimport {\n createChatMessage,\n type ChatMessage,\n type ChatPart,\n type ChatToolPart,\n} from \"@ai-matrx/chat\";\n\nimport { runErrorLabel } from \"./provider-health\";\nimport { toolSubtitle } from \"./tool-labels\";\nimport type { RunStatus, RunUsage, TranscriptItem } from \"./types\";\n\nexport interface TranscriptBuilder {\n apply(item: TranscriptItem): void;\n applyAll(items: readonly TranscriptItem[]): void;\n /** Close the turn in progress with the run's final status. */\n endTurn(status: RunStatus, error?: string | null): void;\n /** Mark a turn as in progress (the assistant bubble shows it is working). */\n beginTurn(): void;\n messages(): readonly ChatMessage[];\n lastUsage(): { usage: RunUsage; costUsd: number | null } | null;\n}\n\ninterface Working {\n message: ChatMessage;\n /** item id → index in `message.parts`. */\n index: Map<string, number>;\n}\n\nexport function createTranscriptBuilder(): TranscriptBuilder {\n const list: ChatMessage[] = [];\n let current: Working | null = null;\n let turn = 0;\n let usage: { usage: RunUsage; costUsd: number | null } | null = null;\n /** tool call id → [message index, part index] for results that arrive late. */\n const toolHome = new Map<string, { messageIndex: number; partIndex: number }>();\n\n function commit(working: Working, parts: ChatPart[], status?: ChatMessage[\"status\"]): void {\n const next: ChatMessage = {\n ...working.message,\n parts,\n status: status ?? working.message.status,\n };\n working.message = next;\n const at = list.findIndex((m) => m.id === next.id);\n if (at >= 0) list[at] = next;\n }\n\n function ensureAssistant(): Working {\n if (current) return current;\n turn += 1;\n const message = createChatMessage({\n id: `turn-${turn}-${list.length}`,\n role: \"assistant\",\n status: \"streaming\",\n });\n list.push(message);\n current = { message, index: new Map() };\n return current;\n }\n\n function upsertPart(id: string, build: (existing: ChatPart | null) => ChatPart): void {\n const working = ensureAssistant();\n const parts = [...working.message.parts];\n const at = working.index.get(id);\n if (at === undefined) {\n working.index.set(id, parts.length);\n parts.push(build(null));\n } else {\n parts[at] = build(parts[at] ?? null);\n }\n commit(working, parts);\n }\n\n function closeCurrent(status: ChatMessage[\"status\"]): void {\n if (!current) return;\n const working = current;\n const parts = working.message.parts.map((part): ChatPart => {\n if (part.type === \"reasoning\" && part.state === \"streaming\") return { ...part, state: \"done\" };\n if (part.type === \"tool\" && part.state === \"input-available\" && status !== \"streaming\") {\n if (status === \"cancelled\") {\n return { ...part, state: \"output-error\", errorText: \"Stopped before this finished.\" };\n }\n if (status === \"error\") {\n return { ...part, state: \"output-error\", errorText: \"The run ended before this finished.\" };\n }\n }\n return part;\n });\n commit(working, parts, status);\n current = null;\n }\n\n const builder: TranscriptBuilder = {\n apply(item) {\n switch (item.kind) {\n case \"user\": {\n closeCurrent(\"complete\");\n list.push(\n createChatMessage({\n id: `user-${item.id}`,\n role: \"user\",\n parts: [{ type: \"text\", text: item.text }],\n status: \"complete\",\n metadata: item.at ? { createdAt: item.at } : undefined,\n }),\n );\n return;\n }\n case \"text-delta\":\n upsertPart(item.id, (existing) =>\n existing && existing.type === \"text\"\n ? { type: \"text\", text: existing.text + item.text }\n : { type: \"text\", text: item.text },\n );\n return;\n case \"text\":\n upsertPart(item.id, () => ({ type: \"text\", text: item.text }));\n return;\n case \"reasoning\":\n upsertPart(item.id, () => ({ type: \"reasoning\", text: item.text, state: \"done\" }));\n return;\n case \"tool-call\": {\n // The key argument (the command, the file) rides as the card's one\n // progress beat, which the chat card shows beside the tool's name.\n const subtitle = toolSubtitle(item.name, item.input);\n const progress = subtitle ? [{ toolName: item.name, message: subtitle, percent: null, at: null }] : [];\n upsertPart(item.id, (existing) =>\n existing && existing.type === \"tool\"\n ? { ...existing, input: item.input, progress }\n : {\n type: \"tool\",\n toolCallId: item.id,\n toolName: item.name,\n state: \"input-available\",\n input: item.input,\n output: null,\n errorText: null,\n progress,\n delegated: false,\n },\n );\n const working = current;\n if (working) {\n const partIndex = working.index.get(item.id);\n const messageIndex = list.findIndex((m) => m.id === working.message.id);\n if (partIndex !== undefined && messageIndex >= 0) {\n toolHome.set(item.id, { messageIndex, partIndex });\n }\n }\n return;\n }\n case \"tool-result\": {\n const home = toolHome.get(item.id);\n if (!home) {\n // A result whose call we never saw (a history read that started\n // mid-conversation). Show it as its own finished card.\n upsertPart(item.id, () => ({\n type: \"tool\",\n toolCallId: item.id,\n toolName: \"Tool\",\n state: item.isError ? \"output-error\" : \"output-available\",\n input: null,\n output: item.isError ? null : item.output,\n errorText: item.isError ? item.output || \"The tool reported an error.\" : null,\n progress: [],\n delegated: false,\n }));\n return;\n }\n const message = list[home.messageIndex];\n const part = message?.parts[home.partIndex];\n if (!message || !part || part.type !== \"tool\") return;\n const nextPart: ChatToolPart = item.isError\n ? { ...part, state: \"output-error\", errorText: item.output || \"The tool reported an error.\", output: null }\n : { ...part, state: \"output-available\", output: item.output };\n const parts = [...message.parts];\n parts[home.partIndex] = nextPart;\n const next: ChatMessage = { ...message, parts };\n list[home.messageIndex] = next;\n if (current && current.message.id === next.id) current.message = next;\n return;\n }\n case \"usage\":\n usage = { usage: item.usage, costUsd: item.costUsd };\n return;\n case \"notice\":\n upsertPart(item.id, () => ({\n type: \"notice\",\n level: item.level === \"warning\" ? \"medium\" : \"info\",\n code: null,\n userMessage: item.text,\n remedy: null,\n }));\n return;\n case \"error\": {\n // Codex reports one failure up to three ways (a top-level `error`,\n // `turn.failed`, and the run's final error): say it once.\n // A known class (a refused model) shows its short label, never the\n // provider's raw JSON.\n const text = runErrorLabel(item.text);\n const said = current?.message.parts.some((p) => p.type === \"error\" && p.message.trim() === text.trim());\n if (said) return;\n upsertPart(item.id, () => ({\n type: \"error\",\n errorType: \"provider\",\n code: null,\n message: text,\n userMessage: text,\n recoverable: true,\n remedy: null,\n }));\n return;\n }\n }\n },\n applyAll(items) {\n for (const item of items) builder.apply(item);\n },\n beginTurn() {\n ensureAssistant();\n },\n endTurn(status, error) {\n if (status === \"failed\" && error) {\n builder.apply({ kind: \"error\", id: `run-error-${list.length}`, text: error });\n }\n if (status === \"stopped\" && current) {\n builder.apply({\n kind: \"notice\",\n id: `run-stopped-${list.length}`,\n level: \"info\",\n text: \"You stopped this run.\",\n });\n }\n closeCurrent(status === \"stopped\" ? \"cancelled\" : status === \"failed\" ? \"error\" : \"complete\");\n },\n messages() {\n // A fresh array per read: the chat store compares the list by identity\n // to notice appends, and the message objects inside keep theirs.\n return list.slice();\n },\n lastUsage() {\n return usage;\n },\n };\n return builder;\n}\n","/**\n * USAGE LIMITS AND EXPIRED SIGN-INS, in plain English.\n *\n * A provider can be installed and signed in and still unable to run: the\n * ChatGPT or Claude plan hit its usage limit, or the saved login expired.\n * Runs report that in the provider's own words; this turns those words into\n * a remembered, honest status. Built from the real texts captured on\n * 2026-09-27 (Codex usage limit, Codex refresh failure).\n */\n\nimport { PROVIDER_LABEL, type CodingProvider, type ProviderProblem, type QuotaWindow } from \"./types\";\n\nconst USAGE_LIMIT = [\n /hit your usage limit/i,\n /usage limit (?:reached|exceeded)/i,\n /\\blimit reached\\b/i,\n /you'?ve hit your limit/i,\n /rate limit/i,\n /quota (?:exceeded|exhausted)/i,\n /purchase more credits/i,\n];\n\nconst SIGNED_OUT = [\n /access token could not be refreshed/i,\n /please sign in again/i,\n /(?:not|no longer) (?:logged|signed) in/i,\n /please run \\/login/i,\n /invalid api key/i,\n /oauth token (?:has )?expired/i,\n /authentication_error/i,\n /401 unauthorized/i,\n];\n\n/** \"Oct 4th, 2026 8:34 AM\" → ISO. null when the phrase is not a date. */\nexport function parseLimitDate(phrase: string): string | null {\n const cleaned = phrase.replace(/(\\d{1,2})(st|nd|rd|th)\\b/gi, \"$1\").replace(/[.,]\\s*$/, \"\").trim();\n const ms = Date.parse(cleaned);\n return Number.isNaN(ms) ? null : new Date(ms).toISOString();\n}\n\nfunction limitPhrase(text: string): string | null {\n const match =\n /try again (?:at|after|on) ([^\\n]+?)(?:\\.\\s|\\.$|$)/i.exec(text) ??\n /resets? (?:at |on )?([^\\n∙·|]+?)(?:\\.\\s|\\.$|$|\\s*[∙·|])/i.exec(text);\n return match?.[1]?.trim() ?? null;\n}\n\nexport function classifyProviderError(text: string, at = new Date().toISOString()): ProviderProblem | null {\n const trimmed = text.trim();\n if (!trimmed) return null;\n if (SIGNED_OUT.some((re) => re.test(trimmed))) {\n return { kind: \"signed-out\", message: trimmed, until: null, at };\n }\n if (USAGE_LIMIT.some((re) => re.test(trimmed))) {\n const phrase = limitPhrase(trimmed);\n return { kind: \"usage-limit\", message: trimmed, until: phrase ? (parseLimitDate(phrase) ?? phrase) : null, at };\n }\n return null;\n}\n\n/** A usage limit whose reset time has passed no longer applies. */\nexport function problemStillApplies(problem: ProviderProblem, now = Date.now()): boolean {\n if (problem.kind !== \"usage-limit\" || !problem.until) return true;\n const ms = Date.parse(problem.until);\n return Number.isNaN(ms) || ms > now;\n}\n\nexport function formatUntil(until: string | null): string | null {\n if (!until) return null;\n const ms = Date.parse(until);\n if (Number.isNaN(ms)) return until;\n return new Date(ms).toLocaleString(undefined, { month: \"short\", day: \"numeric\", hour: \"numeric\", minute: \"2-digit\" });\n}\n\n/** A full quota window (100% used) is a usage limit even before a run hits it. */\nexport function problemFromQuota(windows: readonly QuotaWindow[], at = new Date().toISOString()): ProviderProblem | null {\n const full = windows.find((w) => typeof w.usedPercent === \"number\" && w.usedPercent >= 100);\n if (!full) return null;\n return {\n kind: \"usage-limit\",\n message: `${full.label} is used up.`,\n until: full.resetsAt,\n at,\n };\n}\n\nexport function describeProblem(provider: CodingProvider, problem: ProviderProblem): { problem: string; fix: string } {\n const label = PROVIDER_LABEL[provider];\n if (problem.kind === \"signed-out\") {\n return {\n problem: `${label} — sign-in expired.`,\n fix: `Open ${label} and sign in again, then check again.`,\n };\n }\n const until = formatUntil(problem.until);\n return {\n problem: until ? `${label} — usage limit reached until ${until}.` : `${label} — usage limit reached.`,\n fix: until\n ? `It lifts on its own then, or add more usage in your ${provider === \"codex\" ? \"ChatGPT\" : \"Claude\"} account.`\n : `Wait for it to reset, or add more usage in your ${provider === \"codex\" ? \"ChatGPT\" : \"Claude\"} account.`,\n };\n}\n\n/**\n * A run refused because the CHOSEN MODEL is not available — to this account,\n * or to this version of the CLI. It is about the model, not the provider, so\n * the screen offers the model picker rather than a provider-wide warning.\n * Built from the real Codex text captured 2026-10-01\n * (fixtures/codex-model-unsupported.error.txt) and Claude Code's wording.\n */\nconst MODEL_UNAVAILABLE = [\n /model is not supported when using codex/i,\n /\\bmodel[\\s:'\"`][^.\\n]{0,80}\\b(?:not supported|does not exist|not available|not found)\\b/i,\n /\\bmodel_not_found\\b/i,\n /issue with the selected model/i,\n /may not exist or you may not have access to it/i,\n];\n\nexport const MODEL_UNAVAILABLE_LABEL = \"Model not available on this account\";\n\nexport function isModelUnavailable(text: string | null | undefined): boolean {\n const trimmed = (text ?? \"\").trim();\n return trimmed !== \"\" && MODEL_UNAVAILABLE.some((re) => re.test(trimmed));\n}\n\n/** What the screen says for a failed run: a short label for a known class, else the text itself. */\nexport function runErrorLabel(text: string): string {\n return isModelUnavailable(text) ? MODEL_UNAVAILABLE_LABEL : text;\n}\n","/**\n * What a tool call is CALLED on screen, and the one argument that says what\n * it is doing. `mcp__claude-in-chrome__browser_batch` reads \"Browser batch ·\n * Claude in chrome\"; `Bash {command: \"ls -la\"}` reads \"Run command\" with\n * \"ls -la\" beside it. The machine name stays on the card as `data-tool`.\n */\n\nconst BUILTIN: Record<string, string> = {\n Bash: \"Run command\",\n Shell: \"Run command\",\n BashOutput: \"Read command output\",\n KillShell: \"Stop command\",\n Read: \"Read file\",\n Write: \"Write file\",\n Edit: \"Edit file\",\n MultiEdit: \"Edit file\",\n NotebookEdit: \"Edit notebook\",\n Glob: \"Find files\",\n Grep: \"Search code\",\n LS: \"List folder\",\n WebFetch: \"Fetch page\",\n WebSearch: \"Web search\",\n \"Web search\": \"Web search\",\n Task: \"Sub-agent\",\n Agent: \"Sub-agent\",\n TodoWrite: \"Update plan\",\n Plan: \"Update plan\",\n \"Edit files\": \"Edit files\",\n ExitPlanMode: \"Finish planning\",\n Skill: \"Use skill\",\n ToolSearch: \"Load tools\",\n};\n\nfunction words(identifier: string): string {\n const spaced = identifier\n .replace(/[._-]+/g, \" \")\n .replace(/([a-z\\d])([A-Z])/g, \"$1 $2\")\n .replace(/\\s+/g, \" \")\n .trim()\n .toLowerCase();\n return spaced ? spaced.charAt(0).toUpperCase() + spaced.slice(1) : \"\";\n}\n\n/** `mcp__<server>__<tool>` → { server, tool }, or null. */\nexport function parseMcpToolName(name: string): { server: string; tool: string } | null {\n const match = /^mcp__(.+?)__(.+)$/.exec(name);\n return match?.[1] && match[2] ? { server: match[1], tool: match[2] } : null;\n}\n\nexport function friendlyToolName(name: string): string {\n const builtin = BUILTIN[name];\n if (builtin) return builtin;\n const mcp = parseMcpToolName(name);\n if (mcp) {\n // A server name often repeats in its tool (\"claude_browser\" + \"browser_batch\").\n return `${words(mcp.tool) || \"Tool\"} · ${words(mcp.server)}`;\n }\n // Codex MCP calls arrive as \"<server>.<tool>\".\n const dotted = /^([\\w-]+)\\.([\\w-]+)$/.exec(name);\n if (dotted?.[1] && dotted[2]) return `${words(dotted[2])} · ${words(dotted[1])}`;\n return words(name) || \"Working…\";\n}\n\nfunction prettyPath(value: string): string {\n const home = value.match(/^\\/(?:Users|home)\\/[^/]+/)?.[0];\n return home ? `~${value.slice(home.length)}` : value;\n}\n\nfunction clip(value: string, max = 90): string {\n const flat = value.replace(/\\s+/g, \" \").trim();\n return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;\n}\n\n/** The key argument, for the card's subtitle. null when there is none worth showing. */\nexport function toolSubtitle(name: string, input: unknown): string | null {\n if (typeof input !== \"object\" || input === null) return typeof input === \"string\" && input ? clip(input) : null;\n const args = input as Record<string, unknown>;\n const pick = (...keys: string[]): string | null => {\n for (const key of keys) {\n const value = args[key];\n if (typeof value === \"string\" && value.trim()) return value;\n }\n return null;\n };\n switch (name) {\n case \"Bash\":\n case \"Shell\": {\n const command = pick(\"command\", \"description\");\n return command ? clip(command) : null;\n }\n case \"Read\":\n case \"Write\":\n case \"Edit\":\n case \"MultiEdit\":\n case \"NotebookEdit\": {\n const file = pick(\"file_path\", \"notebook_path\", \"path\");\n return file ? clip(prettyPath(file)) : null;\n }\n case \"Glob\":\n case \"Grep\":\n return pick(\"pattern\") ? clip(pick(\"pattern\") as string) : null;\n case \"WebFetch\":\n return pick(\"url\") ? clip(pick(\"url\") as string) : null;\n case \"WebSearch\":\n case \"Web search\":\n return pick(\"query\") ? clip(pick(\"query\") as string) : null;\n case \"Task\":\n case \"Agent\":\n return pick(\"description\", \"prompt\") ? clip(pick(\"description\", \"prompt\") as string) : null;\n case \"Edit files\": {\n // The live stream lists `{ path, kind }`; a saved rollout maps path → change.\n const raw = args.changes;\n const paths = Array.isArray(raw)\n ? raw\n .map((c) => (typeof c === \"object\" && c !== null ? (c as { path?: unknown }).path : null))\n .filter((p): p is string => typeof p === \"string\")\n : typeof raw === \"object\" && raw !== null\n ? Object.keys(raw)\n : [];\n return paths.length ? clip(paths.map(prettyPath).join(\", \")) : null;\n }\n default: {\n const first = pick(\"url\", \"query\", \"command\", \"path\", \"file_path\", \"name\", \"description\");\n return first ? clip(first) : null;\n }\n }\n}\n","/**\n * The UI side of the local host: a `CodingSessionsTransport` over one\n * WebSocket. Requests are correlated by id; events stream on the same socket;\n * it reconnects on its own and says so through `status()` rather than letting\n * a screen sit on a dead connection.\n */\n\nimport type {\n CodingEvent,\n CodingSessionsApi,\n CodingSessionsMethod,\n CodingSessionsTransport,\n TransportStatus,\n} from \"../types\";\n\nexport interface WebSocketTransportOptions {\n /** `ws://127.0.0.1:<port>/ws` — defaults to the page's own host. */\n url?: string | undefined;\n token: string;\n /** Reconnect delay ceiling in ms. */\n maxBackoffMs?: number | undefined;\n}\n\ninterface Pending {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n}\n\nexport function createWebSocketTransport(options: WebSocketTransportOptions): CodingSessionsTransport {\n const base =\n options.url ??\n (typeof location !== \"undefined\" ? `ws://${location.host}/ws` : \"ws://127.0.0.1:4789/ws\");\n const url = `${base}?token=${encodeURIComponent(options.token)}`;\n const listeners = new Set<(event: CodingEvent) => void>();\n const statusListeners = new Set<(status: TransportStatus) => void>();\n const pending = new Map<number, Pending>();\n const outbox: string[] = [];\n let socket: WebSocket | null = null;\n let status: TransportStatus = { state: \"connecting\" };\n let nextId = 1;\n let backoff = 500;\n let everOpened = false;\n\n function setStatus(next: TransportStatus): void {\n status = next;\n for (const listener of statusListeners) listener(next);\n }\n\n function connect(): void {\n setStatus({ state: \"connecting\" });\n const ws = new WebSocket(url);\n socket = ws;\n ws.onopen = () => {\n everOpened = true;\n backoff = 500;\n setStatus({ state: \"open\" });\n while (outbox.length > 0) ws.send(outbox.shift() as string);\n };\n ws.onmessage = (message) => {\n let data: { id?: number; ok?: boolean; result?: unknown; error?: string; event?: CodingEvent };\n try {\n data = JSON.parse(String(message.data)) as typeof data;\n } catch {\n return;\n }\n if (data.event) {\n for (const listener of listeners) listener(data.event);\n return;\n }\n if (typeof data.id === \"number\") {\n const entry = pending.get(data.id);\n if (!entry) return;\n pending.delete(data.id);\n if (data.ok) entry.resolve(data.result);\n else entry.reject(new Error(data.error ?? \"The request failed.\"));\n }\n };\n ws.onclose = () => {\n socket = null;\n for (const [, entry] of pending) {\n entry.reject(new Error(\"Lost the connection to the coding sessions host.\"));\n }\n pending.clear();\n setStatus({\n state: \"closed\",\n reason: everOpened\n ? \"Lost the connection to the coding sessions host. Reconnecting…\"\n : \"Can't reach the coding sessions host. It may have stopped, or this link's access token is out of date.\",\n });\n const max = options.maxBackoffMs ?? 8000;\n setTimeout(connect, backoff);\n backoff = Math.min(max, backoff * 2);\n };\n }\n\n connect();\n\n return {\n call<M extends CodingSessionsMethod>(method: M, ...args: Parameters<CodingSessionsApi[M]>) {\n const id = nextId++;\n const frame = JSON.stringify({ id, method, args });\n const promise = new Promise<unknown>((resolve, reject) => {\n pending.set(id, { resolve, reject });\n });\n if (socket && socket.readyState === WebSocket.OPEN) socket.send(frame);\n else outbox.push(frame);\n return promise as ReturnType<CodingSessionsApi[M]>;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n status() {\n return status;\n },\n onStatus(listener) {\n statusListeners.add(listener);\n return () => {\n statusListeners.delete(listener);\n };\n },\n };\n}\n"],"mappings":"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","names":["isObject","str","num"]}
@@ -1242,6 +1242,14 @@ function ChooseAgentDialog(props) {
1242
1242
  ] }) });
1243
1243
  }
1244
1244
 
1245
+ // src/sessions/titles.ts
1246
+ var DISPLAY_MAX = 100;
1247
+ var LEADING_NOISE = /^(?:\s*(?:\d{1,3}[.)]|[-*•]|#{1,6}|>)\s+|\s*["“'‘`]+)+/;
1248
+ function displayTitle(title, max = DISPLAY_MAX) {
1249
+ const stripped = title.replace(LEADING_NOISE, "").replace(/["”'’`]+$/, "").trim() || title.trim();
1250
+ return stripped.length > max ? `${stripped.slice(0, max - 1).trimEnd()}\u2026` : stripped;
1251
+ }
1252
+
1245
1253
  // src/react/sidebar.tsx
1246
1254
  var import_react7 = require("react");
1247
1255
  var import_design_system5 = require("@ai-matrx/design-system");
@@ -1341,7 +1349,7 @@ function Row(props) {
1341
1349
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "pointer-events-none mt-0.5 shrink-0", children: props.live ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SpinnerIcon, { size: 16, className: "text-primary" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProviderMark, { provider: entry.provider, size: 16 }) }),
1342
1350
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "cs-row__body", children: [
1343
1351
  renaming ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "pointer-events-auto relative z-10 block", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RenameInput, { initial: entry.title, onDone: rename }) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "flex items-center gap-1", children: [
1344
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "min-w-0 truncate text-[13px] font-medium leading-5", children: entry.title }),
1352
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "min-w-0 truncate text-[13px] font-medium leading-5", children: displayTitle(entry.title) }),
1345
1353
  entry.pinned ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PinIcon, { size: 11, className: "shrink-0 text-muted-foreground", "aria-label": "Pinned" }) : null
1346
1354
  ] }),
1347
1355
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "block truncate text-[11.5px] leading-4 text-muted-foreground", children: props.meta }),
@@ -1443,7 +1451,8 @@ function Sidebar(props) {
1443
1451
  const [search, searchMore] = useContentSearch(query);
1444
1452
  const [groupMode, setGroupMode] = (0, import_react7.useState)(() => readLocal("coding-sessions.group", ["date", "folder"], "date"));
1445
1453
  const [showHidden, setShowHidden] = (0, import_react7.useState)(false);
1446
- const titlesUpdating = state.discovered.data.some((d) => d.titlePending === true);
1454
+ const titlesProblem = state.titles?.problem ?? null;
1455
+ const titlesUpdating = !titlesProblem && state.discovered.data.some((d) => d.titlePending === true);
1447
1456
  const [takingOver, setTakingOver] = (0, import_react7.useState)(null);
1448
1457
  const [takeoverError, setTakeoverError] = (0, import_react7.useState)(null);
1449
1458
  const prefs = state.preferences;
@@ -1617,7 +1626,12 @@ function Sidebar(props) {
1617
1626
  ] }),
1618
1627
  children: [
1619
1628
  "Your other chats",
1620
- titlesUpdating ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ml-1 font-normal normal-case text-muted-foreground", "data-cs-titles": "updating", children: "\xB7 titles updating" }) : null
1629
+ titlesUpdating ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ml-1 font-normal normal-case text-muted-foreground", "data-cs-titles": "updating", children: "\xB7 titles updating" }) : null,
1630
+ titlesProblem ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ml-1 font-normal normal-case text-destructive", "data-cs-titles": "unavailable", title: titlesProblem, children: [
1631
+ "\xB7 app titles unavailable \u2014",
1632
+ " ",
1633
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "cs-link", onClick: () => void client.retryTitles(), children: "Retry" })
1634
+ ] }) : null
1621
1635
  ]
1622
1636
  }
1623
1637
  ),
@@ -2085,7 +2099,8 @@ var CodingSessionsClient = class {
2085
2099
  folders: loadable([]),
2086
2100
  runs: {},
2087
2101
  preferences: {},
2088
- discoveredLimit: DISCOVERED_PAGE
2102
+ discoveredLimit: DISCOVERED_PAGE,
2103
+ titles: null
2089
2104
  };
2090
2105
  transport.onStatus((connection) => {
2091
2106
  const wasOpen = this.state.connection.state === "open";
@@ -2154,7 +2169,21 @@ var CodingSessionsClient = class {
2154
2169
  }
2155
2170
  }
2156
2171
  refreshProviders = () => this.load("providers", () => this.transport.call("providers"));
2157
- refreshDiscovered = () => this.load("discovered", () => this.transport.call("discoverSessions", { limit: this.state.discoveredLimit }));
2172
+ refreshDiscovered = async () => {
2173
+ void this.refreshTitleStatus();
2174
+ await this.load("discovered", () => this.transport.call("discoverSessions", { limit: this.state.discoveredLimit }));
2175
+ };
2176
+ refreshTitleStatus = async () => {
2177
+ try {
2178
+ this.set({ titles: await this.transport.call("titleStatus") });
2179
+ } catch {
2180
+ }
2181
+ };
2182
+ /** The Retry beside "app titles unavailable". */
2183
+ retryTitles = async () => {
2184
+ await this.transport.call("retryTitles").catch(() => void 0);
2185
+ await this.refreshTitleStatus();
2186
+ };
2158
2187
  /** List more of "Your other chats". */
2159
2188
  showMoreDiscovered = async () => {
2160
2189
  this.set({ discoveredLimit: this.state.discoveredLimit + DISCOVERED_PAGE });