zidane 8.2.3 → 8.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{acp-oYRjlh71.js → acp-BIInKhVI.js} +6 -6
- package/dist/{acp-oYRjlh71.js.map → acp-BIInKhVI.js.map} +1 -1
- package/dist/acp-cli.js +4 -4
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-CBQglXtH.js → agent-CmhCOmyO.js} +10 -5
- package/dist/{agent-CBQglXtH.js.map → agent-CmhCOmyO.js.map} +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/chat/pure.d.ts +4 -4
- package/dist/chat/pure.js +7 -7
- package/dist/chat.d.ts +3 -3
- package/dist/chat.js +16 -16
- package/dist/{cli-shared-E5m_pI8A.js → cli-shared-GOehTeqk.js} +2 -2
- package/dist/{cli-shared-E5m_pI8A.js.map → cli-shared-GOehTeqk.js.map} +1 -1
- package/dist/{client-core-EEEX_u6D.d.ts → client-core-Dz8hELs4.d.ts} +15 -5
- package/dist/client-core-Dz8hELs4.d.ts.map +1 -0
- package/dist/codemode-worker.js +1 -1
- package/dist/codemode.js +1 -1
- package/dist/{connection-loop-CpgfUmuw.d.ts → connection-loop-dm_TN-QD.d.ts} +3 -3
- package/dist/{connection-loop-CpgfUmuw.d.ts.map → connection-loop-dm_TN-QD.d.ts.map} +1 -1
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/{credentials-B9DfBJP9.js → credentials-DxOQmset.js} +2 -2
- package/dist/{credentials-B9DfBJP9.js.map → credentials-DxOQmset.js.map} +1 -1
- package/dist/daemon-cli.js +2 -2
- package/dist/{dispatcher-Bv9-c6I2.js → dispatcher-Dclv6HXn.js} +22 -18
- package/dist/dispatcher-Dclv6HXn.js.map +1 -0
- package/dist/{engine-XmoPPB6U.js → engine-C_U6kDfA.js} +6 -6
- package/dist/{engine-XmoPPB6U.js.map → engine-C_U6kDfA.js.map} +1 -1
- package/dist/{eval-CfQlBR81.js → eval-CIHIF_Ns.js} +3 -3
- package/dist/{eval-CfQlBR81.js.map → eval-CIHIF_Ns.js.map} +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/{executor-BhthPE1q.js → executor-BFaR2nfc.js} +3 -3
- package/dist/{executor-BhthPE1q.js.map → executor-BFaR2nfc.js.map} +1 -1
- package/dist/{extensions-BgBwogRW.js → extensions-DIbpUj5R.js} +3 -3
- package/dist/{extensions-BgBwogRW.js.map → extensions-DIbpUj5R.js.map} +1 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/{fold-rules-DSypi36k.d.ts → fold-rules-CMpWNPqk.d.ts} +2 -2
- package/dist/{fold-rules-DSypi36k.d.ts.map → fold-rules-CMpWNPqk.d.ts.map} +1 -1
- package/dist/{headless-R4pbpTkm.js → headless-Bs9Lb4vs.js} +4 -4
- package/dist/{headless-R4pbpTkm.js.map → headless-Bs9Lb4vs.js.map} +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/history-worker.js +1 -1
- package/dist/{host-scoped-settings-C-Nmb6vr.js → host-scoped-settings-DxxI_yRo.js} +2 -2
- package/dist/{host-scoped-settings-C-Nmb6vr.js.map → host-scoped-settings-DxxI_yRo.js.map} +1 -1
- package/dist/{host-signals-BFudPyCT.js → host-signals-CQ2jZR-2.js} +5 -5
- package/dist/{host-signals-BFudPyCT.js.map → host-signals-CQ2jZR-2.js.map} +1 -1
- package/dist/{index-DyQyDLX1.d.ts → index-4mDRyTGJ.d.ts} +1722 -1691
- package/dist/index-4mDRyTGJ.d.ts.map +1 -0
- package/dist/{index-CDS7YdUC.d.ts → index-Dlmu8HnG.d.ts} +5 -5
- package/dist/{index-CDS7YdUC.d.ts.map → index-Dlmu8HnG.d.ts.map} +1 -1
- package/dist/{index-AqRZ3gEz.d.ts → index-QsAN9yjZ.d.ts} +3 -3
- package/dist/{index-AqRZ3gEz.d.ts.map → index-QsAN9yjZ.d.ts.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +8 -8
- package/dist/ipc/remote.d.ts +5 -5
- package/dist/ipc/remote.js +3 -3
- package/dist/ipc.d.ts +5 -5
- package/dist/ipc.js +9 -9
- package/dist/{links-rFaWqS2Y.js → links-D5itfH8P.js} +10 -10
- package/dist/{links-rFaWqS2Y.js.map → links-D5itfH8P.js.map} +1 -1
- package/dist/{mcp-allowlist-CLXweyxk.js → mcp-allowlist-BbnTBKNN.js} +2 -2
- package/dist/{mcp-allowlist-CLXweyxk.js.map → mcp-allowlist-BbnTBKNN.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/{oauth-7_48zR7n.js → oauth-Ck3wQX4Q.js} +66 -32
- package/dist/oauth-Ck3wQX4Q.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/{prelude-HzY_JEGq.js → prelude-qjPUkw4f.js} +26 -2
- package/dist/prelude-qjPUkw4f.js.map +1 -0
- package/dist/{presets-DXeHsd24.js → presets-C4hkykN-.js} +2 -2
- package/dist/{presets-DXeHsd24.js.map → presets-C4hkykN-.js.map} +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/{protocol-BIv1Yuvl.js → protocol-Do_i6Ras.js} +3 -1
- package/dist/protocol-Do_i6Ras.js.map +1 -0
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/neuralwatt.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/{registry-eourRLY2.js → registry-DxPP_tAt.js} +3 -3
- package/dist/{registry-eourRLY2.js.map → registry-DxPP_tAt.js.map} +1 -1
- package/dist/{remote-hosts-DY2J07ut.js → remote-hosts-BkOwRszu.js} +4 -4
- package/dist/{remote-hosts-DY2J07ut.js.map → remote-hosts-BkOwRszu.js.map} +1 -1
- package/dist/restate.d.ts +1 -1
- package/dist/{secret-shapes-BjW4l6U0.js → secret-shapes-HvaYVzwc.js} +10 -2
- package/dist/secret-shapes-HvaYVzwc.js.map +1 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-7TUHs42_.js → session-CCsKXID6.js} +6 -2
- package/dist/session-CCsKXID6.js.map +1 -0
- package/dist/{session-factory-CMwIXE-7.js → session-factory-Ct7J9CK1.js} +6 -6
- package/dist/{session-factory-CMwIXE-7.js.map → session-factory-Ct7J9CK1.js.map} +1 -1
- package/dist/session.d.ts +2 -2
- package/dist/session.js +1 -1
- package/dist/{settings-keys-CPdmkTz7.js → settings-keys-QoGJ5n3e.js} +4 -4
- package/dist/{settings-keys-CPdmkTz7.js.map → settings-keys-QoGJ5n3e.js.map} +1 -1
- package/dist/{shell-path-B8b3EOtK.js → shell-path-BXXtRmEA.js} +4 -4
- package/dist/{shell-path-B8b3EOtK.js.map → shell-path-BXXtRmEA.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/{spaces-CyjMh5Zf.js → spaces-C_x2bvEl.js} +14 -4
- package/dist/spaces-C_x2bvEl.js.map +1 -0
- package/dist/{store-L01W0gGI.js → store-BpkWIaSH.js} +10 -30
- package/dist/store-BpkWIaSH.js.map +1 -0
- package/dist/{todo-edits-BERpCRPj.js → todo-edits-DKoxu7Ss.js} +3 -3
- package/dist/{todo-edits-BERpCRPj.js.map → todo-edits-DKoxu7Ss.js.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/{tools-pZVFIJ_K.js → tools-FHEIKGkh.js} +2 -2
- package/dist/{tools-pZVFIJ_K.js.map → tools-FHEIKGkh.js.map} +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +2 -2
- package/dist/{transcript-anchors-jHrg-r-H.js → transcript-anchors-D8jWLpe5.js} +10 -10
- package/dist/{transcript-anchors-jHrg-r-H.js.map → transcript-anchors-D8jWLpe5.js.map} +1 -1
- package/dist/{transcript-cache-DXdgVuoy.js → transcript-cache-CdHKtx9y.js} +4 -4
- package/dist/{transcript-cache-DXdgVuoy.js.map → transcript-cache-CdHKtx9y.js.map} +1 -1
- package/dist/{transcript-reconcile-CPdrNbbR.js → transcript-reconcile-D_SWw6dX.js} +11 -3
- package/dist/transcript-reconcile-D_SWw6dX.js.map +1 -0
- package/dist/tui.d.ts +7 -7
- package/dist/tui.js +24 -23
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-DuGtKuc_.d.ts → turn-operations-Dbk3xPKu.d.ts} +11 -3
- package/dist/{turn-operations-DuGtKuc_.d.ts.map → turn-operations-Dbk3xPKu.d.ts.map} +1 -1
- package/dist/{types-C0PJmBaO.d.ts → types-CMXR7A0b.d.ts} +2 -2
- package/dist/{types-C0PJmBaO.d.ts.map → types-CMXR7A0b.d.ts.map} +1 -1
- package/dist/types-CzmghX7C.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/{url-D8KZ7Edw.js → url-D4vG7lzO.js} +2 -2
- package/dist/{url-D8KZ7Edw.js.map → url-D4vG7lzO.js.map} +1 -1
- package/dist/{version-bd3DQJkc.js → version-DDRBX7K6.js} +2 -2
- package/dist/{version-bd3DQJkc.js.map → version-DDRBX7K6.js.map} +1 -1
- package/dist/{workspace-exec-stream-CyfYgqAh.js → workspace-exec-stream-iHv9cooF.js} +5 -5
- package/dist/{workspace-exec-stream-CyfYgqAh.js.map → workspace-exec-stream-iHv9cooF.js.map} +1 -1
- package/dist/{write-file-QYrcDdl3.js → write-file-ChtRPdEL.js} +3 -3
- package/dist/{write-file-QYrcDdl3.js.map → write-file-ChtRPdEL.js.map} +1 -1
- package/dist/{ws-CURQ2igk.js → ws-B2HB87nz.js} +6 -6
- package/dist/{ws-CURQ2igk.js.map → ws-B2HB87nz.js.map} +1 -1
- package/dist/{ws-client-BVljYbdb.js → ws-client-DPC9ZJHr.js} +4 -4
- package/dist/{ws-client-BVljYbdb.js.map → ws-client-DPC9ZJHr.js.map} +1 -1
- package/docs/CODEMODE.md +6 -0
- package/docs/IPC.md +2 -0
- package/docs/ONBOARDING.md +1 -1
- package/package.json +1 -1
- package/dist/client-core-EEEX_u6D.d.ts.map +0 -1
- package/dist/dispatcher-Bv9-c6I2.js.map +0 -1
- package/dist/index-DyQyDLX1.d.ts.map +0 -1
- package/dist/oauth-7_48zR7n.js.map +0 -1
- package/dist/prelude-HzY_JEGq.js.map +0 -1
- package/dist/protocol-BIv1Yuvl.js.map +0 -1
- package/dist/secret-shapes-BjW4l6U0.js.map +0 -1
- package/dist/session-7TUHs42_.js.map +0 -1
- package/dist/spaces-CyjMh5Zf.js.map +0 -1
- package/dist/store-L01W0gGI.js.map +0 -1
- package/dist/transcript-reconcile-CPdrNbbR.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"todo-edits-BERpCRPj.js","names":["str"],"sources":["../src/chat/hosts/host-index.ts","../src/chat/hosts/session-key.ts","../src/chat/attachment-rules.ts","../src/chat/auth-rows.ts","../src/chat/fold-actions.ts","../src/chat/fold-rules.ts","../src/chat/instruction-rows.ts","../src/chat/machines-view.ts","../src/chat/mcp-form.ts","../src/chat/notice-format.ts","../src/chat/palette.ts","../src/chat/panels.ts","../src/chat/prompt-text.ts","../src/chat/run-stops.ts","../src/chat/stream-rate.ts","../src/chat/todo-edits.ts"],"sourcesContent":["/**\n * Which host an id lives on: a session (or a request a host handed out: an\n * approval, a question, a terminal). A client learns it from what a host\n * tells it (its lists, a create, an activation, its signals) and routes\n * every later call on that id there.\n *\n * Never guessed: an id no host told about is an error\n * ({@link UnknownHostIdError}), one several hosts list is an error unless the\n * lookup names its host ({@link AmbiguousHostIdError}), and the ids of a host\n * that was removed stay remembered as such ({@link HostRemovedError}) until\n * a host claims them again, so nothing aimed at a removed server quietly\n * lands on another host.\n * Node-free, shared by the TUI and the GUI main process.\n */\n\n/** No host told this client about the id: nothing to route it to. */\nexport class UnknownHostIdError extends Error {\n /** Machine-readable error code. */\n readonly code = 'unknown-host-id'\n /**\n * Creates the error.\n * @param id - Id that no host reported.\n * @param noun - What the id names, used in the message.\n */\n constructor(readonly id: string, noun = 'session') {\n super(`No host is known for ${noun} \"${id}\": list or open it on its host first.`)\n this.name = 'UnknownHostIdError'\n }\n}\n\n/** The id lived on a host that was removed from this window. */\nexport class HostRemovedError extends Error {\n /** Machine-readable error code. */\n readonly code = 'host-removed'\n /**\n * Creates the error.\n * @param hostKey - Key of the removed host.\n * @param hostName - Display name of the removed host.\n */\n constructor(readonly hostKey: string, readonly hostName: string) {\n super(`${hostName} was removed.`)\n this.name = 'HostRemovedError'\n }\n}\n\n/**\n * Several hosts list the id (two hosts can hold the same session id: a\n * server sharing this machine's data dir, a copied store) and the lookup\n * did not say which: refused, never guessed.\n */\nexport class AmbiguousHostIdError extends Error {\n /** Machine-readable error code. */\n readonly code = 'ambiguous-host-id'\n /**\n * Creates the error.\n * @param id - Id that several hosts list.\n * @param hostKeys - Keys of the hosts that list it.\n * @param noun - What the id names, used in the message.\n */\n constructor(readonly id: string, readonly hostKeys: readonly string[], noun = 'session') {\n super(`${noun[0]!.toUpperCase()}${noun.slice(1)} \"${id}\" exists on several hosts (${hostKeys.join(', ')}): say which one.`)\n this.name = 'AmbiguousHostIdError'\n }\n}\n\n/**\n * Keyed by (host, id): the same id may live on several hosts. A lookup that\n * names its host (`hostKey`) gets exactly that pair; one that doesn't\n * resolves only when one host has the id.\n */\nexport interface HostIndex {\n /** `id` lives on `hostKey` (clears that pair's removed-host mark). */\n note: (id: string, hostKey: string) => void\n /** The id is gone from `hostKey` (deleted there), or from every host. */\n forget: (id: string, hostKey?: string) => void\n /** With `hostKey`: it, when `id` is known live there. Without: the one live host of `id` (`undefined` when none, or several). */\n hostOf: (id: string, hostKey?: string) => string | undefined\n /** Every live host of `id`. */\n hostsOf: (id: string) => string[]\n /**\n * The live host of `id` (with `hostKey`: that pair). Throws\n * {@link HostRemovedError}, {@link UnknownHostIdError}, or without\n * `hostKey` {@link AmbiguousHostIdError} when several hosts have it.\n */\n require: (id: string, hostKey?: string) => string\n /** The removed host `id` lived on (with `hostKey`: that one), if any. */\n removedHostOf: (id: string, hostKey?: string) => { key: string, name: string } | undefined\n /** Ids noted on `hostKey`. */\n idsOf: (hostKey: string) => string[]\n /** The host was removed: its pairs are marked so (lookups say so); returns their ids. */\n dropHost: (hostKey: string, hostName: string) => string[]\n}\n\n/**\n * Creates an empty index of which host holds each id.\n *\n * @param noun - What the ids name, used in error messages.\n */\nexport function createHostIndex(noun = 'session'): HostIndex {\n /** id → live host keys, in the order they were noted. */\n const live = new Map<string, Set<string>>()\n /** id → removed host key → its name. */\n const removed = new Map<string, Map<string, string>>()\n const liveOf = (id: string): string[] => [...(live.get(id) ?? [])]\n const removedOf = (id: string, hostKey?: string): { key: string, name: string } | undefined => {\n const marks = removed.get(id)\n if (!marks)\n return undefined\n if (hostKey !== undefined) {\n const name = marks.get(hostKey)\n return name === undefined ? undefined : { key: hostKey, name }\n }\n const first = [...marks][0]\n return first ? { key: first[0], name: first[1] } : undefined\n }\n const index: HostIndex = {\n note: (id, hostKey) => {\n let hosts = live.get(id)\n if (!hosts)\n live.set(id, hosts = new Set())\n hosts.add(hostKey)\n const marks = removed.get(id)\n marks?.delete(hostKey)\n if (marks?.size === 0)\n removed.delete(id)\n },\n forget: (id, hostKey) => {\n if (hostKey === undefined) {\n live.delete(id)\n removed.delete(id)\n return\n }\n live.get(id)?.delete(hostKey)\n if (live.get(id)?.size === 0)\n live.delete(id)\n removed.get(id)?.delete(hostKey)\n if (removed.get(id)?.size === 0)\n removed.delete(id)\n },\n hostOf: (id, hostKey) => {\n const hosts = liveOf(id)\n if (hostKey !== undefined)\n return hosts.includes(hostKey) ? hostKey : undefined\n return hosts.length === 1 ? hosts[0] : undefined\n },\n hostsOf: liveOf,\n require: (id, hostKey) => {\n const hosts = liveOf(id)\n if (hostKey !== undefined) {\n if (hosts.includes(hostKey))\n return hostKey\n const gone = removedOf(id, hostKey)\n if (gone)\n throw new HostRemovedError(gone.key, gone.name)\n throw new UnknownHostIdError(id, noun)\n }\n if (hosts.length === 1)\n return hosts[0]!\n if (hosts.length > 1)\n throw new AmbiguousHostIdError(id, hosts, noun)\n const gone = removedOf(id)\n if (gone)\n throw new HostRemovedError(gone.key, gone.name)\n throw new UnknownHostIdError(id, noun)\n },\n removedHostOf: removedOf,\n idsOf: hostKey => [...live].filter(([, hosts]) => hosts.has(hostKey)).map(([id]) => id),\n dropHost: (hostKey, hostName) => {\n const ids = index.idsOf(hostKey)\n for (const id of ids) {\n index.forget(id, hostKey)\n let marks = removed.get(id)\n if (!marks)\n removed.set(id, marks = new Map())\n marks.set(hostKey, hostName)\n }\n return ids\n },\n }\n return index\n}\n","/**\n * A session's identity across hosts: the (host, session) pair, as one\n * string every client keys rows, maps and persisted state by. Two hosts may\n * hold the same session id (a server sharing this computer's data dir, a\n * copied store), so a bare id never names a session on its own once several\n * hosts are listed.\n *\n * The host is named by its HOST KEY, the key of a client's host directory:\n * {@link LOCAL_HOST_KEY} for This computer (the in-process host or the\n * daemon), a saved server's `hostId` (for a server, hostKey === hostId),\n * or a client's own key for a host it never saves (the TUI's `--host`\n * server: `'ad-hoc'`).\n *\n * The encoding, shared by the TUI and the GUI:\n *\n * - This computer: the bare id (`abc`). Local-only users see exactly the\n * ids, and state persisted before keys existed still means the same\n * session.\n * - Any other host: `<hostKey>␟<id>` (U+001F, never in a host key).\n *\n * A local id that itself contains U+001F is written `local␟<id>`, so a key\n * always parses back to the pair it was made from. Node-free.\n */\nimport { LOCAL_HOST_KEY } from './connection'\n\n/** Character that separates the host key from the session id in a session key (U+001F). */\nexport const SESSION_KEY_SEPARATOR = '\\u001F'\n\n/** The pair a session key names. */\nexport interface SessionKeyParts {\n /** Always explicit: {@link LOCAL_HOST_KEY} for This computer. */\n hostKey: string\n /** Session id on that host. */\n sessionId: string\n}\n\n/**\n * The key of `sessionId` on `hostKey` (`null` / absent / {@link LOCAL_HOST_KEY}: a local session).\n *\n * @param hostKey - Key of the host. `null`, absent or the local host key mean This computer.\n * @param sessionId - Session id on that host.\n */\nexport function sessionKey(hostKey: string | null | undefined, sessionId: string): string {\n if (!hostKey || hostKey === LOCAL_HOST_KEY)\n return sessionId.includes(SESSION_KEY_SEPARATOR) ? `${LOCAL_HOST_KEY}${SESSION_KEY_SEPARATOR}${sessionId}` : sessionId\n if (hostKey.includes(SESSION_KEY_SEPARATOR))\n throw new Error('A host key cannot contain U+001F.')\n return `${hostKey}${SESSION_KEY_SEPARATOR}${sessionId}`\n}\n\n/**\n * The pair `key` names (a bare id: This computer's).\n *\n * @param key - Key built by {@link sessionKey}.\n */\nexport function parseSessionKey(key: string): SessionKeyParts {\n const at = key.indexOf(SESSION_KEY_SEPARATOR)\n if (at < 0)\n return { hostKey: LOCAL_HOST_KEY, sessionId: key }\n return { hostKey: key.slice(0, at), sessionId: key.slice(at + 1) }\n}\n","/**\n * What a prompt can carry as an attachment, the same in every composer: the\n * image types every provider reads, PDFs, and files whose bytes read as\n * text, each under its size cap. Anything else is refused with a reason the\n * composer puts into words.\n *\n * Pure: a browser composer reads a file's first bytes and asks\n * {@link planAttachment}; the TUI shares the caps.\n */\nimport { looksBinary } from '../tools/binary-detect'\n\n/**\n * Cap on an image's bytes. Base64 inflates ~33%, so this keeps the encoded\n * payload under Anthropic's 5 MB image ceiling while covering essentially\n * every screenshot. A composer scales a bigger image down to fit.\n */\nexport const MAX_IMAGE_ATTACHMENT_BYTES = 3.5 * 1024 * 1024\n\n/** Cap on a PDF's or a text file's bytes. */\nexport const MAX_FILE_ATTACHMENT_BYTES = 20 * 1024 * 1024\n\n/** How much of a file's start {@link planAttachment} reads to tell text from binary. */\nexport const ATTACHMENT_SNIFF_BYTES = 8192\n\n/** Image types every provider takes as they are. */\nexport const SENDABLE_IMAGE_TYPES: ReadonlySet<string> = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp'])\n\n/** Image types by extension, for files handed over untyped. */\nconst IMAGE_BY_EXTENSION: Readonly<Record<string, string>> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n avif: 'image/avif',\n bmp: 'image/bmp',\n ico: 'image/x-icon',\n svg: 'image/svg+xml',\n heic: 'image/heic',\n heif: 'image/heif',\n tif: 'image/tiff',\n tiff: 'image/tiff',\n}\n\n/** Office and iWork documents: the model reads them once exported as PDF. */\nconst EXPORT_AS_PDF: ReadonlySet<string> = new Set(['doc', 'docx', 'odt', 'pages', 'ppt', 'pptx', 'odp', 'key', 'xls', 'xlsx', 'ods', 'numbers'])\n\n/** A file a composer was handed, as {@link planAttachment} needs it. */\nexport interface AttachmentCandidate {\n /** The file's name. Its extension stands in for a missing type. */\n name: string\n /** The type the browser or the OS reported. Often empty. */\n mediaType: string\n /** Size in bytes. */\n size: number\n /** The file's first {@link ATTACHMENT_SNIFF_BYTES} bytes decoded as UTF-8, invalid bytes as U+FFFD. */\n head: string\n}\n\n/** Why a file is not attached. */\nexport type AttachmentRefusal\n = | { reason: 'empty' }\n | { reason: 'too-large', size: number, limit: number }\n /** An Office or iWork document. */\n | { reason: 'export-pdf' }\n /** An image the composer could not decode to convert it (HEIC or TIFF in Chromium). */\n | { reason: 'unreadable-image' }\n | { reason: 'unsupported' }\n\n/**\n * What to do with a file: attach its bytes as they are, typed `mediaType`;\n * decode and re-encode an image first (a format providers don't take, or\n * over {@link MAX_IMAGE_ATTACHMENT_BYTES}); or refuse it.\n */\nexport type AttachmentPlan\n = | { kind: 'image' | 'pdf' | 'text', mediaType: string }\n | { kind: 'convert-image', mediaType: string }\n | ({ kind: 'refuse' } & AttachmentRefusal)\n\n/** Declared types that already say text: kept as they are. */\nfunction isTextType(mime: string): boolean {\n return mime.startsWith('text/')\n || mime === 'application/json'\n || mime === 'application/xml'\n || mime === 'application/javascript'\n || mime === 'application/typescript'\n || mime.endsWith('+json')\n || mime.endsWith('+xml')\n}\n\nfunction extensionOf(name: string): string {\n const base = name.slice(name.lastIndexOf('/') + 1).toLowerCase()\n const dot = base.lastIndexOf('.')\n return dot > 0 ? base.slice(dot + 1) : ''\n}\n\nconst tooLarge = (size: number, limit: number): AttachmentPlan => ({ kind: 'refuse', reason: 'too-large', size, limit })\n\n/**\n * Decide how a file is attached. Images go by type (or extension); PDFs by\n * type, extension or their `%PDF-` signature; anything else is text when its\n * first bytes read as text, sent as `text/plain` unless its type already\n * names text (a `.ts` file the browser types `video/mp2t` is text).\n *\n * @param file - The file's name, reported type, size and first bytes.\n */\nexport function planAttachment(file: AttachmentCandidate): AttachmentPlan {\n if (file.size === 0)\n return { kind: 'refuse', reason: 'empty' }\n const declared = file.mediaType.split(';')[0]!.trim().toLowerCase()\n const ext = extensionOf(file.name)\n const image = declared.startsWith('image/') ? declared : IMAGE_BY_EXTENSION[ext]\n if (image) {\n return SENDABLE_IMAGE_TYPES.has(image) && file.size <= MAX_IMAGE_ATTACHMENT_BYTES\n ? { kind: 'image', mediaType: image }\n : { kind: 'convert-image', mediaType: image }\n }\n if (declared === 'application/pdf' || ext === 'pdf' || file.head.startsWith('%PDF-')) {\n return file.size > MAX_FILE_ATTACHMENT_BYTES\n ? tooLarge(file.size, MAX_FILE_ATTACHMENT_BYTES)\n : { kind: 'pdf', mediaType: 'application/pdf' }\n }\n if (EXPORT_AS_PDF.has(ext))\n return { kind: 'refuse', reason: 'export-pdf' }\n if (looksBinary(file.head))\n return { kind: 'refuse', reason: 'unsupported' }\n if (file.size > MAX_FILE_ATTACHMENT_BYTES)\n return tooLarge(file.size, MAX_FILE_ATTACHMENT_BYTES)\n return { kind: 'text', mediaType: isTextType(declared) ? declared : 'text/plain' }\n}\n","/**\n * Renderer-agnostic data model for the Authentication settings list when a\n * provider holds more than one credential source.\n *\n * Mirrors `chat/mcp-rows.ts` deliberately: a flat row list plus a single\n * integer cursor that walks both provider headers AND their nested source\n * rows, so a renderer iterates once and never needs separate \"which provider\n * am I on / which source inside it\" state.\n *\n * Lives in `chat/` rather than `tui/` for the same reason as the MCP model —\n * the flattening and cursor arithmetic are pure, and pure means they can be\n * asserted directly instead of through a rendered modal.\n *\n * A provider is only expandable when it has MORE THAN ONE source. Single-source\n * providers (the overwhelming majority) are one row with no chevron and no\n * expansion state. That keeps the list quiet for anyone who has not stacked two\n * credentials.\n */\n\nimport type { AuthMethod, ProviderAuth } from './auth'\n\n/**\n * One row in the flattened Authentication list. Two kinds:\n *\n * - `'provider'` — provider header with label, configured badge, and (when\n * expandable) the chevron. Always present.\n * - `'source'` — one credential source belonging to the provider above.\n * Present only while that provider is expanded.\n */\nexport type VisibleAuthRow\n = | { kind: 'provider', provider: ProviderAuth, expandable: boolean }\n | { kind: 'source', providerKey: string, method: AuthMethod }\n\n/**\n * Stored credentials, i.e. the ones a user can actually choose between.\n *\n * `env` is excluded: it is observed rather than stored, and is usually just the\n * mirror `applyApiKeyEnv` wrote from the stored API key, so counting it would\n * advertise a choice that does not exist.\n *\n * @param provider - The provider whose auth methods are filtered.\n */\nexport function selectableSources(provider: ProviderAuth): AuthMethod[] {\n return provider.methods.filter(m => m.source !== 'env')\n}\n\n/**\n * A provider earns a chevron only when there is a real choice to reveal.\n *\n * @param provider - The provider to test.\n */\nexport function isExpandableProvider(provider: ProviderAuth): boolean {\n return selectableSources(provider).length > 1\n}\n\n/**\n * Flatten the provider list plus the expanded set into the visible-row list.\n *\n * - `providers` — filtered / ordered provider list (post-search).\n * - `expanded` — keys of providers whose sources are open. Keys for\n * providers that are no longer expandable are ignored rather\n * than cleaned up, so stale expansion state (a credential\n * removed while the modal is open) can't desync the cursor.\n *\n * @param providers - Filtered and ordered provider list.\n * @param expanded - Keys of providers whose sources are open.\n */\nexport function buildVisibleAuthRows(\n providers: readonly ProviderAuth[],\n expanded: ReadonlySet<string>,\n): VisibleAuthRow[] {\n const out: VisibleAuthRow[] = []\n for (const provider of providers) {\n const expandable = isExpandableProvider(provider)\n out.push({ kind: 'provider', provider, expandable })\n if (!expandable || !expanded.has(provider.key))\n continue\n for (const method of selectableSources(provider))\n out.push({ kind: 'source', providerKey: provider.key, method })\n // The env slot is listed for context whenever the provider declares one,\n // present or not. It disappears from `methods` the moment a stored OAuth\n // grant wins (`applyApiKeyEnv` clears the var so the refresh path reads the\n // file), and a row that vanishes on selection reads as a bug.\n if (provider.envKey) {\n const envMethod = provider.methods.find(m => m.source === 'env')\n out.push({\n kind: 'source',\n providerKey: provider.key,\n method: envMethod ?? { source: 'env', detail: provider.envKey, active: false },\n })\n }\n }\n return out\n}\n\n/**\n * Provider key a row \"belongs to\" — its own for a provider header, the parent's\n * for a source row.\n *\n * @param row - A visible row.\n */\nexport function parentProviderKey(row: VisibleAuthRow): string {\n return row.kind === 'provider' ? row.provider.key : row.providerKey\n}\n\n/**\n * Index in `rows` of the header for the given provider key, or `-1`.\n *\n * Collapse handlers snap the cursor up to the parent BEFORE the row list\n * shrinks; without that the cursor keeps its flat index and silently lands on\n * whichever sibling row slid into that slot.\n *\n * @param rows - The visible rows.\n * @param providerKey - Key of the provider to find.\n */\nexport function indexOfProviderRow(rows: readonly VisibleAuthRow[], providerKey: string): number {\n return rows.findIndex(r => r.kind === 'provider' && r.provider.key === providerKey)\n}\n","/**\n * The words for what the agent did, shared by the GUI's compact fold and\n * the TUI's: one overview line per tool call (`Ran bun test`, `Edited\n * Timeline.tsx +12 −3`, `Read select-stops.ts`), and the settled summary\n * of a batch (`Read a file, ran a command +3`).\n *\n * An overview says WHAT happened, not the payload; the payload stays one\n * click away and in `title`.\n */\nimport type { EditPayload } from './types'\nimport { readFileInputPaths } from '../tools/read-file-targets'\nimport { computeLineDiff } from './edit-diff'\nimport { descriptionLabel } from './tool-formatters'\n\n// ---------------------------------------------------------------------------\n// Shell commands → a gist\n// ---------------------------------------------------------------------------\n\n/** Programs whose first argument is the thing they do (`git status`, `bun test`). */\nconst SUBCOMMAND_PROGRAMS = new Set([\n 'git',\n 'gh',\n 'bun',\n 'npm',\n 'pnpm',\n 'yarn',\n 'npx',\n 'bunx',\n 'cargo',\n 'go',\n 'docker',\n 'kubectl',\n 'make',\n 'uv',\n 'pip',\n 'pip3',\n 'brew',\n 'deno',\n 'node',\n 'playwright',\n 'vitest',\n 'jest',\n 'tsc',\n 'eslint',\n 'prettier',\n])\n/** Wrappers that only change how the next program runs. */\nconst WRAPPERS = new Set(['sudo', 'time', 'nice', 'nohup', 'exec', 'command', 'caffeinate'])\n/** Setup steps that carry no meaning of their own. */\nconst SETUP = new Set(['cd', 'pushd', 'popd', 'export', 'set', 'source', '.', 'unset', 'true', 'mkdir'])\n\n/** Split on `&&`, `||`, `;`, `|` and newlines outside quotes. */\nfunction splitSegments(command: string): string[] {\n const out: string[] = []\n let cur = ''\n let quote: '\"' | '\\'' | null = null\n for (let i = 0; i < command.length; i++) {\n const ch = command[i]!\n if (quote) {\n if (ch === quote)\n quote = null\n cur += ch\n continue\n }\n if (ch === '\"' || ch === '\\'') {\n quote = ch\n cur += ch\n continue\n }\n const two = command.slice(i, i + 2)\n if (two === '&&' || two === '||') {\n out.push(cur)\n cur = ''\n i++\n continue\n }\n if (ch === ';' || ch === '|' || ch === '\\n') {\n out.push(cur)\n cur = ''\n continue\n }\n cur += ch\n }\n out.push(cur)\n return out.map(s => s.trim()).filter(Boolean)\n}\n\n/** Words of a segment, quotes kept as one word (unquoted). */\nfunction words(segment: string): string[] {\n const out: string[] = []\n const re = /\"([^\"]*)\"|'([^']*)'|(\\S+)/g\n for (const m of segment.matchAll(re))\n out.push(m[1] ?? m[2] ?? m[3] ?? '')\n return out\n}\n\n/** The gist of one segment (`bun run build`, `python3`), or null for setup noise. */\nfunction segmentGist(segment: string): string | null {\n let w = words(segment)\n // Leading env assignments (`FOO=1 cmd`), then wrappers (`sudo`, `env -u X`, `timeout 30`).\n for (;;) {\n if (w.length === 0)\n return null\n const head = w[0]!\n if (/^[A-Z_]\\w*=/i.test(head)) {\n w = w.slice(1)\n }\n else if (WRAPPERS.has(head)) {\n w = w.slice(1)\n }\n else if (head === 'env') {\n w = w.slice(1)\n while (w[0] && (w[0].startsWith('-') || /^[A-Z_]\\w*=/i.test(w[0]))) {\n const flag = w[0]\n w = w.slice(1)\n if (flag === '-u' && w[0])\n w = w.slice(1)\n }\n }\n else if (head === 'timeout' && w[1] && /^\\d/.test(w[1])) {\n w = w.slice(2)\n }\n else {\n break\n }\n }\n const program = w[0]!.split('/').pop()!\n if (SETUP.has(program))\n return null\n if (!SUBCOMMAND_PROGRAMS.has(program))\n return program\n const rest = w.slice(1).filter(arg => !arg.startsWith('-'))\n let sub: string | undefined = rest[0]\n // `npx tsc`, `bunx playwright test`: the tool after the runner, and its own subcommand.\n if ((program === 'npx' || program === 'bunx') && sub) {\n const tool = sub.split('/').pop()!\n const next = rest[1]\n return SUBCOMMAND_PROGRAMS.has(tool) && next && !next.includes('/') && !next.includes('.')\n ? `${tool} ${next}`\n : tool\n }\n // `bun run build`: the script name is the subcommand's point.\n if ((sub === 'run' || sub === 'exec') && rest[1] && ['bun', 'npm', 'pnpm', 'yarn'].includes(program)) {\n return `${program} ${sub} ${rest[1]}`\n }\n // A path or file is an argument, not a subcommand (`node script.js` → `node`).\n if (sub && (sub.includes('/') || /\\.[a-z]+$/i.test(sub)))\n sub = undefined\n return sub ? `${program} ${sub}` : program\n}\n\n/**\n * `Ran <gist>` for a shell command: heredoc bodies dropped, setup steps\n * (`cd`, `export`, `set -e`) skipped, env and wrappers peeled off, program\n * plus subcommand kept. Further meaningful steps read as `+N`.\n *\n * @param command - Shell command text, possibly several steps.\n */\nexport function commandGist(command: string): { gist: string, more: number } {\n // eslint-disable-next-line regexp/no-super-linear-backtracking -- bounded by one command's text\n const withoutHeredocs = command.replace(/<<-?\\s*(['\"]?)(\\w+)\\1[\\s\\S]*?(?:\\n\\2\\b|$)/g, '')\n const gists = splitSegments(withoutHeredocs)\n .map(segmentGist)\n .filter((g): g is string => g !== null)\n if (gists.length === 0)\n return { gist: 'a command', more: 0 }\n return { gist: gists[0]!, more: gists.length - 1 }\n}\n\n// ---------------------------------------------------------------------------\n// One tool call → its overview\n// ---------------------------------------------------------------------------\n\n/** What a tool call is, independent of how a surface stores it. */\nexport interface ToolOverviewInput {\n /** Tool name, such as `shell` or `read_file`. */\n name: string\n /** Name shown to the user for the tool. */\n displayName: string\n /** The call's input arguments. */\n input?: Record<string, unknown>\n /** The formatted target (`tool-formatters`), when there is one. */\n target?: string\n /** The call's result text, once it has one. */\n result?: string | null\n /** `null` while running. */\n ok?: boolean | null\n /** Edit payload, when the call changed a file. */\n edit?: EditPayload\n}\n\n/** One-line description of a tool call, built by {@link toolOverview}. */\nexport interface ToolOverview {\n /** What the call did, such as `Ran bun test`. */\n label: string\n /** Quiet context after the label: a file's directory, `+2` chained commands. */\n hint?: string\n /** Lines added, for edits. */\n added?: number\n /** Lines removed, for edits. */\n removed?: number\n /** The full payload (the whole command, the full path). */\n title?: string\n}\n\nfunction splitPath(path: string): { name: string, dir: string } {\n const clean = path.replace(/\\/+$/, '')\n const i = clean.lastIndexOf('/')\n return i < 0 ? { name: clean, dir: '' } : { name: clean.slice(i + 1), dir: clean.slice(0, i) }\n}\n\nfunction str(input: Record<string, unknown> | undefined, key: string): string | undefined {\n const v = input?.[key]\n return typeof v === 'string' && v.trim() !== '' ? v : undefined\n}\n\n/** Line counts exactly as the diff in the details shows them. */\nfunction editCounts(edit: EditPayload | undefined): { added: number, removed: number } | null {\n if (!edit)\n return null\n let added = 0\n let removed = 0\n for (const h of edit.hunks) {\n for (const d of computeLineDiff(h.oldString, h.newString)) {\n if (d.op === 'add')\n added++\n else if (d.op === 'remove')\n removed++\n }\n }\n return { added, removed }\n}\n\nfunction shortUrl(url: string): string {\n const short = url.replace(/^https?:\\/\\//, '').replace(/\\/$/, '')\n return short.length > 48 ? `${short.slice(0, 47)}…` : short\n}\n\n/**\n * The dev browser in words: where it went and what it did. Clicks and typing\n * read their result's first line (`Clicked \"Save\"`), which names the element;\n * the ref the model used (`e12`) means nothing to a person.\n */\nfunction browserOverview(tool: ToolOverviewInput): ToolOverview | null {\n const input = tool.input\n const url = str(input, 'url')\n const head = typeof tool.result === 'string' && tool.ok\n ? tool.result.split('\\n')[0]!.replace(/\\. No navigation, dialog or error\\.$|\\.$/, '')\n : ''\n switch (tool.name) {\n case 'browser_open':\n return url ? { label: `Opened ${shortUrl(url)}`, title: url } : { label: 'Opened the browser' }\n case 'browser_navigate': {\n const action = str(input, 'action')\n if (action === 'back')\n return { label: 'Went back' }\n if (action === 'forward')\n return { label: 'Went forward' }\n if (action === 'reload')\n return { label: 'Reloaded the page' }\n return url ? { label: `Went to ${shortUrl(url)}`, title: url } : { label: 'Navigated' }\n }\n case 'browser_snapshot':\n return { label: 'Read the page' }\n case 'browser_screenshot':\n return { label: 'Took a screenshot' }\n case 'browser_click':\n return { label: head.startsWith('Clicked') ? head : `Clicked ${tool.target ?? 'the page'}` }\n case 'browser_type':\n return { label: head.startsWith('Typed') ? head : 'Typed in the page' }\n case 'browser_press':\n return { label: head.startsWith('Pressed') ? head : `Pressed ${str(input, 'key') ?? 'a key'}` }\n case 'browser_scroll':\n return { label: 'Scrolled the page' }\n case 'browser_wait_for': {\n const what = str(input, 'text') ?? str(input, 'selector') ?? str(input, 'urlIncludes')\n return { label: what ? `Waited for “${what.length > 40 ? `${what.slice(0, 39)}…` : what}”` : 'Waited' }\n }\n case 'browser_evaluate': {\n const expression = str(input, 'expression') ?? ''\n return { label: 'Ran a script in the page', ...(expression ? { title: expression.slice(0, 600) } : {}) }\n }\n case 'browser_console':\n return { label: 'Read the console' }\n default:\n return null\n }\n}\n\n/**\n * The overview line for one tool call.\n *\n * @param tool - Tool call with its name, input, target, result, and edit payload.\n */\nexport function toolOverview(tool: ToolOverviewInput): ToolOverview {\n const input = tool.input\n if (tool.name.startsWith('browser_')) {\n const browser = browserOverview(tool)\n if (browser)\n return browser\n }\n switch (tool.name) {\n case 'shell':\n case 'bash': {\n const command = str(input, 'command') ?? tool.target ?? ''\n // The model's description says what the call does (\"Run the GUI\n // typecheck\"); the command is behind it (title, and the opened input).\n const description = descriptionLabel(input)\n if (description)\n return { label: description, title: command.slice(0, 600) }\n const { gist, more } = commandGist(command)\n return { label: `Ran ${gist}`, ...(more > 0 ? { hint: `+${more}` } : {}), title: command.slice(0, 600) }\n }\n case 'read_file': {\n const batch = str(input, 'path') ? [] : readFileInputPaths(input)\n if (batch.length > 1)\n return { label: `Read ${splitPath(batch[0]).name} +${batch.length - 1}`, title: batch.join('\\n') }\n const path = str(input, 'path') ?? batch[0] ?? tool.target ?? ''\n const { name, dir } = splitPath(path)\n return { label: `Read ${name || 'a file'}`, ...(dir ? { hint: dir } : {}), title: path }\n }\n case 'edit':\n case 'multi_edit':\n case 'write_file': {\n const path = str(input, 'path') ?? tool.edit?.path ?? tool.target ?? ''\n const { name, dir } = splitPath(path)\n const counts = editCounts(tool.edit)\n const verb = tool.name === 'write_file' ? 'Wrote' : 'Edited'\n return {\n label: `${verb} ${name || 'a file'}`,\n ...(dir ? { hint: dir } : {}),\n ...(counts && (counts.added > 0 || counts.removed > 0) ? counts : {}),\n title: path,\n }\n }\n case 'grep': {\n const pattern = str(input, 'pattern') ?? tool.target ?? ''\n const where = str(input, 'path')\n return {\n label: pattern ? `Searched for “${pattern.length > 48 ? `${pattern.slice(0, 47)}…` : pattern}”` : 'Searched',\n ...(where ? { hint: where } : {}),\n title: pattern,\n }\n }\n case 'glob': {\n const pattern = str(input, 'pattern') ?? tool.target ?? ''\n return { label: pattern ? `Found files ${pattern}` : 'Found files', title: pattern }\n }\n case 'spawn': {\n // The worker is named by what it was asked to do; the full task sits behind it.\n const task = str(input, 'task') ?? tool.target ?? ''\n const first = task.split('\\n').find(line => line.trim()) ?? ''\n return { label: 'Agent', ...(first ? { hint: first.length > 80 ? `${first.slice(0, 79)}…` : first } : {}), ...(task ? { title: task.slice(0, 600) } : {}) }\n }\n case 'present_plan': {\n const title = str(input, 'title')\n return { label: 'Presented a plan', ...(title ? { hint: title, title } : {}) }\n }\n case 'ask_user': {\n const n = Array.isArray(input?.questions) ? input.questions.length : 0\n return { label: n > 0 ? `Asked ${n} question${n === 1 ? '' : 's'}` : 'Asked a question' }\n }\n case 'todowrite': {\n const todos = Array.isArray(input?.todos) ? (input.todos as { status?: unknown }[]) : []\n const done = todos.filter(t => t.status === 'completed').length\n return { label: 'Updated todos', ...(todos.length > 0 ? { hint: `${done} of ${todos.length} done` } : {}) }\n }\n case 'list_files': {\n const path = str(input, 'path') ?? tool.target ?? '.'\n return { label: `Listed ${path}`, title: path }\n }\n default: {\n const target = tool.target\n const short = target && target.length > 60 ? `${target.slice(0, 59)}…` : target\n return { label: short ? `${tool.displayName} ${short}` : tool.displayName, ...(target ? { title: target } : {}) }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Many calls → one summary\n// ---------------------------------------------------------------------------\n\n/**\n * Verb phrase per canonical tool name for a batch summary. Unknown tools\n * derive one from their display name, so MCP and host tools read cleanly.\n */\nconst BATCH_VERB_PHRASE: Record<string, string> = {\n shell: 'ran a command',\n read_file: 'read a file',\n grep: 'searched',\n glob: 'searched for files',\n list_files: 'listed files',\n edit: 'edited a file',\n multi_edit: 'edited a file',\n write_file: 'created a file',\n spawn: 'spawned a subagent',\n tool_search: 'searched for tools',\n skills_use: 'activated a skill',\n skills_read: 'read a skill',\n skills_run_script: 'ran a skill script',\n ask_user: 'asked a question',\n present_plan: 'presented a plan',\n browser_open: 'opened the browser',\n browser_navigate: 'navigated',\n browser_snapshot: 'read the page',\n browser_screenshot: 'took a screenshot',\n browser_click: 'clicked',\n browser_type: 'typed',\n browser_press: 'pressed a key',\n browser_scroll: 'scrolled',\n browser_wait_for: 'waited',\n browser_evaluate: 'ran a script in the page',\n browser_console: 'read the console',\n terminal_list: 'listed terminals',\n terminal_read: 'read a terminal',\n terminal_write: 'typed in a terminal',\n}\n\n/**\n * Returns the lowercase verb phrase for a tool in a batch summary, such as `read a file`.\n *\n * @param name - Tool name.\n * @param displayName - Name shown to the user, used for tools without a known phrase.\n */\nexport function toolPhrase(name: string, displayName: string): string {\n return BATCH_VERB_PHRASE[name] ?? `used ${displayName.toLowerCase()}`\n}\n\n/**\n * Cap on phrases shown in a summary: a 40-call exchange reads \"Ran a\n * command, searched, read a file, edited a file +23\", where +N counts the\n * calls the shown phrases do not cover.\n */\nconst MAX_SUMMARY_PHRASES = 4\n\n/**\n * \"Ran a command, read a file +2\" for a run of calls. Adjacent identical\n * phrases merge, so three reads in a row say \"read a file\" once.\n * `overflow: false` leaves the +N off, for a header that counts its calls\n * another way.\n *\n * @param tools - Tool calls in run order.\n * @param options - Set `overflow` to `false` to leave the `+N` count off. Defaults to showing it.\n */\nexport function summarizeTools(tools: ReadonlyArray<{ name: string, displayName: string }>, options: { overflow?: boolean } = {}): string {\n const phrases: Array<{ phrase: string, calls: number }> = []\n for (const t of tools) {\n const phrase = toolPhrase(t.name, t.displayName)\n const last = phrases[phrases.length - 1]\n if (last && last.phrase === phrase)\n last.calls += 1\n else\n phrases.push({ phrase, calls: 1 })\n }\n if (phrases.length === 0)\n return 'Ran tools'\n const shown = phrases.slice(0, MAX_SUMMARY_PHRASES)\n const shownCalls = shown.reduce((n, p) => n + p.calls, 0)\n const rest = tools.length - shownCalls\n const joined = shown.map(p => p.phrase).join(', ')\n const capped = rest > 0 && options.overflow !== false ? `${joined} +${rest}` : joined\n return capped.charAt(0).toUpperCase() + capped.slice(1)\n}\n\n/**\n * A message as a person skims it: its words, markdown syntax and code\n * blocks dropped, whitespace folded. For the compact stacks of earlier\n * messages.\n *\n * @param text - Message text, usually markdown.\n */\nexport function messagePreview(text: string): string {\n return text\n .replace(/```[\\s\\S]*?(?:```|$)/g, ' ')\n .replace(/`([^`]*)`/g, '$1')\n .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/^\\s{0,3}(?:#{1,6}\\s+|>\\s?|[-*+]\\s+|\\d+[.)]\\s+)/gm, '')\n .replace(/(\\*\\*|__|\\*|_|~~)(\\S(?:.*?\\S)?)\\1/g, '$2')\n .replace(/\\s+/g, ' ')\n .trim()\n}\n","/**\n * Compact density's fold, one set of rules for both transcripts: what folds\n * into an exchange's one row (`foldsInCompactShape`), the steps the opened\n * fold lists and the counts its header reads (`planFold`), and the header's\n * words (`foldSummary`). The TUI maps its stream events onto these\n * (`src/tui/transcript/partition.ts`), the desktop app its rows\n * (`ui/src/chat/headless/transcript/fold.ts`, `fold-actions.ts`); each only\n * draws the steps in its own way.\n */\nimport type { StreamEvent } from './types'\nimport { summarizeTools } from './fold-actions'\nimport { describeSpawnEnd, previewLine, spawnStartParts } from './format'\nimport { spawnLaneResolver } from './spawn-tree'\n\n/** What decides whether an item folds: its kind and owner, and two facts only its surface knows. */\nexport interface FoldShape {\n /** The item's kind (`thinking`, `tool`, `info`, …). */\n kind: string\n /** Set when the item is a notice: an `info` notice stays out of the fold. */\n notice?: unknown\n /** The worker session that produced it; absent on the main session. */\n childId?: string\n /** Worker nesting depth; `0` or absent on the main session. */\n depth?: number\n /** The user's own `!` run: they ran it to see it. */\n userBash?: boolean\n /** The transcript's \"N earlier events\" marker: its top, not part of an exchange. */\n earlierMarker?: boolean\n}\n\n/**\n * Compact density: does this item fold into its exchange's one row?\n * Thinking, tool traffic, worker lifecycle, a `/` command's details and\n * everything a worker produced fold; the prompt, the assistant's prose,\n * errors, notices, the user's own `!` runs and session events stay.\n *\n * @param shape - The item's kind, owner and notice.\n */\nexport function foldsInCompactShape(shape: FoldShape): boolean {\n // Everything a worker session produced belongs to the parent's work.\n if ((shape.depth ?? 0) > 0 || shape.childId)\n return true\n switch (shape.kind) {\n case 'thinking':\n case 'thinking-batch':\n case 'spawn-start':\n case 'spawn-end':\n case 'spawn-queued':\n case 'command-detail':\n return true\n case 'tool':\n case 'tool-result':\n case 'tool-batch':\n return !shape.userBash\n case 'info':\n return shape.notice === undefined && !shape.earlierMarker\n default:\n return false\n }\n}\n\n/** A step's progress: `waiting` is a `spawn` call every worker slot is taken for. */\nexport type FoldStepState = 'waiting' | 'running' | 'ok' | 'err'\n\n/** One folded item, as the planner reads it. `item` is the surface's own object, handed back in the steps. */\nexport type FoldUnit<T> = {\n item: T\n childId?: string\n depth?: number\n /** Lifecycle metadata of a worker marker (its call, task, parent worker, structured end). */\n spawn?: StreamEvent['spawn']\n} & (\n | { kind: 'thought', live?: boolean, ms?: number }\n | {\n kind: 'call'\n name: string\n displayName: string\n callId?: string\n /** The call that made this one (a codemode script's `tools.*`). */\n parentId?: string\n state: FoldStepState\n waitingFor?: { active: number, max: number }\n /** A `spawn` call's task, to pair it with a worker whose marker names no call. */\n task?: string\n ms?: number\n }\n | { kind: 'result', callId: string, failed: boolean }\n | { kind: 'spawn-start' | 'spawn-end', text: string }\n | { kind: 'note' }\n | { kind: 'other' }\n)\n\n/** One line of an opened fold: a tool call, consecutive thoughts, a worker, or a command's note. */\nexport interface FoldStep<T> {\n /** What the line shows: a tool call, consecutive thoughts, a worker, or a command's note. */\n kind: 'tool' | 'thought' | 'worker' | 'note'\n /** Its progress; a worker's is its own end, not its call's result. */\n state: FoldStepState\n /** How many steps came before it when it started: a stable index for ids. */\n at: number\n /** Tool: the call and its results. Thought: its thinking items. Worker: every item of its lane. Note: the note. */\n items: T[]\n /** A tool step's call, or the `spawn` call that started a worker. */\n call?: T\n /** A tool step's call id. */\n callId?: string\n /** The call that made this one (a codemode script's `tools.*`). */\n parentId?: string\n /** A `waiting` spawn call: the worker slots taken and the limit. */\n waitingFor?: { active: number, max: number }\n /** A thought still streaming. */\n live?: boolean\n /** A worker's lane (its `childId`, or the worker that started it). */\n lane?: string\n /** A worker no call started: the task its marker carries. */\n task?: string\n}\n\n/** What the header reads. Worker-owned calls and thoughts count under the worker, not here. */\nexport interface FoldStats {\n /** The exchange's own calls (a script's nested calls ride their script's). */\n tools: number\n /** The exchange's own thinking items. */\n thoughts: number\n /** Distinct workers; one a worker started counts under its spawner. */\n workers: number\n /** Own calls that failed. */\n failed: number\n /** Own calls (nested ones included) with no result yet. */\n pending: number\n /** Known time of the own calls and thoughts; absent when nothing carries timing. */\n durationMs?: number\n}\n\n/** {@link planFold}'s result. */\nexport interface FoldPlan<T> {\n /** The opened fold's lines, in order. */\n steps: FoldStep<T>[]\n /** The counts the header reads. */\n stats: FoldStats\n /** The exchange's own top-level calls, in order, for {@link foldSummary}. */\n calls: Array<{ name: string, displayName: string }>\n}\n\nfunction isWorkerOwned(unit: { childId?: string, depth?: number }): boolean {\n return unit.childId !== undefined || (unit.depth ?? 0) > 0\n}\n\n/**\n * A `/` command's details line: its label, capitalised, or \"Details\".\n *\n * @param label - The command's notice label, if any.\n */\nexport function noteLabel(label: string | undefined): string {\n return label ? label.charAt(0).toUpperCase() + label.slice(1) : 'Details'\n}\n\n/**\n * A thought's line: \"Thinking\" while it streams, \"Thought\" once settled.\n *\n * @param live - Whether the thought is still streaming.\n */\nexport function thoughtLabel(live: boolean): string {\n return live ? 'Thinking' : 'Thought'\n}\n\n/**\n * The steps of one exchange in order, and its counts. Consecutive thoughts\n * are one step; each worker is one step holding its lane's items, merged\n * with the `spawn` call that started it (the call's line opens onto the\n * worker's progress). A worker's state is its own structured end: failed\n * only when it errored (core `describeSpawnEnd`), stopped reads done.\n *\n * @param units - The exchange's folded items, oldest first.\n */\nexport function planFold<T>(units: readonly FoldUnit<T>[]): FoldPlan<T> {\n const steps: FoldStep<T>[] = []\n const stats: FoldStats = { tools: 0, thoughts: 0, workers: 0, failed: 0, pending: 0 }\n const plan: FoldPlan<T> = { steps, stats, calls: [] }\n const calls = new Map<string, FoldStep<T>>()\n // An own call's outcome is its own, even once its step became the worker it started.\n const own = new Map<FoldStep<T>, FoldStepState>()\n const workers = new Map<string, FoldStep<T>>()\n const spawnCalls: Array<{ step: FoldStep<T>, task?: string }> = []\n const open = new Set<string>()\n const laneOf = spawnLaneResolver(units)\n let ms = 0\n let timed = false\n const time = (unitMs: number | undefined) => {\n if (unitMs === undefined)\n return\n ms += unitMs\n timed = true\n }\n let thought: FoldStep<T> | null = null\n\n for (const unit of units) {\n if (isWorkerOwned(unit)) {\n thought = null\n const lane = unit.childId !== undefined ? laneOf(unit.childId) : ''\n let worker = workers.get(lane)\n if (!worker) {\n worker = claimSpawnCall(spawnCalls, unit) ?? newWorker(steps, unit, lane)\n worker.kind = 'worker'\n worker.state = 'running'\n worker.lane = lane\n worker.items = []\n delete worker.waitingFor\n workers.set(lane, worker)\n }\n worker.items.push(unit.item)\n // The worker's own end only: a nested worker's ending rides along.\n if (unit.kind === 'spawn-end' && unit.childId === lane)\n worker.state = describeSpawnEnd({ text: unit.text, spawn: unit.spawn }).failed ? 'err' : 'ok'\n continue\n }\n if (unit.kind === 'thought') {\n if (!thought) {\n thought = { kind: 'thought', state: 'ok', at: steps.length, items: [] }\n steps.push(thought)\n }\n thought.items.push(unit.item)\n if (unit.live) {\n thought.live = true\n thought.state = 'running'\n }\n stats.thoughts += 1\n time(unit.ms)\n continue\n }\n thought = null\n if (unit.kind === 'call') {\n const step: FoldStep<T> = { kind: 'tool', state: unit.state, at: steps.length, items: [unit.item], call: unit.item }\n if (unit.callId !== undefined)\n step.callId = unit.callId\n if (unit.parentId !== undefined)\n step.parentId = unit.parentId\n if (unit.waitingFor)\n step.waitingFor = unit.waitingFor\n steps.push(step)\n if (unit.callId !== undefined) {\n calls.set(unit.callId, step)\n if (unit.state === 'running' || unit.state === 'waiting')\n open.add(unit.callId)\n }\n if (unit.name === 'spawn')\n spawnCalls.push({ step, ...(unit.task !== undefined ? { task: unit.task } : {}) })\n if (unit.parentId === undefined) {\n own.set(step, unit.state)\n plan.calls.push({ name: unit.name, displayName: unit.displayName })\n time(unit.ms)\n }\n continue\n }\n if (unit.kind === 'result') {\n open.delete(unit.callId)\n const step = calls.get(unit.callId)\n if (step && own.has(step))\n own.set(step, unit.failed ? 'err' : 'ok')\n // A worker's step ends with the worker, not with its call's result.\n if (step && step.kind === 'tool') {\n step.items.push(unit.item)\n step.state = unit.failed ? 'err' : 'ok'\n }\n continue\n }\n if (unit.kind === 'note')\n steps.push({ kind: 'note', state: 'ok', at: steps.length, items: [unit.item] })\n }\n\n for (const state of own.values()) {\n stats.tools += 1\n if (state === 'err')\n stats.failed += 1\n }\n const lanes = new Set<string>()\n for (const unit of units) {\n if (unit.childId !== undefined)\n lanes.add(laneOf(unit.childId))\n }\n stats.workers = lanes.size\n stats.pending = open.size\n if (timed)\n stats.durationMs = ms\n return plan\n}\n\n/**\n * The `spawn` call a worker's first item belongs to, among the calls no\n * worker claimed yet. The start marker names its call; markers recorded\n * before that pair by task text, never with a call that ran no worker.\n */\nfunction claimSpawnCall<T>(spawnCalls: Array<{ step: FoldStep<T>, task?: string }>, unit: FoldUnit<T>): FoldStep<T> | undefined {\n const open = spawnCalls.filter(({ step }) => step.kind === 'tool')\n const callId = unit.kind === 'spawn-start' ? unit.spawn?.callId : undefined\n if (callId)\n return open.find(({ step }) => step.callId === callId)?.step\n const candidates = open.filter(({ step }) => step.state !== 'err')\n const preview = unit.kind === 'spawn-start' ? spawnStartParts({ text: unit.text, spawn: unit.spawn }).task : undefined\n const byTask = preview ? candidates.find(({ task }) => previewLine(task ?? '', 80) === preview) : undefined\n return (byTask ?? candidates[0])?.step\n}\n\nfunction newWorker<T>(steps: FoldStep<T>[], unit: FoldUnit<T>, lane: string): FoldStep<T> {\n const task = unit.spawn?.task ?? (unit.kind === 'spawn-start' || unit.kind === 'spawn-end' ? unit.text : undefined)\n const step: FoldStep<T> = { kind: 'worker', state: 'running', at: steps.length, items: [], lane, ...(task ? { task } : {}) }\n steps.push(step)\n return step\n}\n\n/**\n * A settled fold's header: its own calls in the shared words (`Read a file,\n * ran a command +2`), with the workers after them when no `spawn` call\n * already says so (`, 1 worker`: a script started it). Exchanges without\n * calls say what they did: `Delegated to a worker`, `Thought`, `Worked`.\n *\n * @param plan - The fold's plan.\n * @param options - Header options.\n * @param options.overflow - `false` leaves the `+N` off (a surface that shows the counts beside it).\n */\nexport function foldSummary(plan: Pick<FoldPlan<unknown>, 'stats' | 'calls'>, options: { overflow?: boolean } = {}): string {\n const { stats, calls } = plan\n const workers = stats.workers > 0 && !calls.some(c => c.name === 'spawn') ? `${stats.workers} worker${stats.workers === 1 ? '' : 's'}` : ''\n if (calls.length > 0)\n return [summarizeTools(calls, options), workers].filter(Boolean).join(', ')\n if (stats.workers > 0)\n return stats.workers === 1 ? 'Delegated to a worker' : `Delegated to ${stats.workers} workers`\n return stats.thoughts > 0 ? 'Thought' : 'Worked'\n}\n","/**\n * Renderer-agnostic visible-row model for the Settings → Instructions tab.\n *\n * Simpler than the MCP / extension row models next door: a segment's expanded\n * TEXT is rendered inside its own row box rather than as sibling rows, so the\n * cursor walks one slot per segment no matter how long the text is. Expanding a\n * 1500-line AGENTS.md must not turn ↓ into 1500 keypresses.\n *\n * Pure (no OpenTUI / React) so the filtering + preview clamping is\n * unit-testable.\n */\n\nimport type { ContextSegment } from './context-segments'\n\n/**\n * Upper bound on preview lines rendered for one expanded segment. Same idea as\n * the Logs tab's `LOGS_RENDER_CAP`: the scrollbox can hold arbitrary height, but pasting a\n * runaway 64KB instruction file into the layout pass is a waste of a frame.\n * File-backed segments have `$EDITOR` as the escape hatch for the remainder.\n */\nexport const INSTRUCTION_PREVIEW_LINE_CAP = 400\n\n/** One selectable row: a context segment, plus its resolved open state. */\nexport interface VisibleInstructionRow {\n /** Context segment shown in the row. */\n segment: ContextSegment\n /** Whether the row is open. */\n expanded: boolean\n}\n\n/** Options for {@link buildVisibleInstructionRows}. */\nexport interface BuildVisibleInstructionRowsOptions {\n /** Segments to list, in display order. */\n segments: readonly ContextSegment[]\n /** Segment ids the user has expanded. */\n expanded: ReadonlySet<string>\n /** True when a search query is active. */\n queryActive: boolean\n /** Whether a segment matches the query. Ignored when `queryActive` is false. */\n matchSegment: (segment: ContextSegment) => boolean\n}\n\n/**\n * Filter segments by the active query and resolve each one's expanded state.\n *\n * Deliberately does NOT auto-expand matches the way the Extensions tab does:\n * the search corpus includes each segment's full text, so a query typically\n * matches deep inside a long document — auto-expanding every hit would dump\n * thousands of lines into the viewport on a keystroke. The user expands the row\n * they care about.\n *\n * @param opts - Segments, expanded ids, and the active search state.\n */\nexport function buildVisibleInstructionRows(\n opts: BuildVisibleInstructionRowsOptions,\n): VisibleInstructionRow[] {\n const { segments, expanded, queryActive, matchSegment } = opts\n const out: VisibleInstructionRow[] = []\n for (const segment of segments) {\n if (queryActive && !matchSegment(segment))\n continue\n out.push({ segment, expanded: expanded.has(segment.id) })\n }\n return out\n}\n\n/**\n * Split a segment's text into renderable preview lines, clamped to\n * {@link INSTRUCTION_PREVIEW_LINE_CAP}.\n *\n * `hidden` is how many lines were dropped off the tail, so the view can render\n * an honest \"+N more lines\" marker instead of silently truncating. Tabs are\n * expanded to two spaces because the terminal text renderable doesn't\n * interpret `\\t`, and `\\r` is stripped so CRLF files don't leave artefacts at\n * every line end.\n *\n * @param text - Segment text to preview.\n */\nexport function instructionPreviewLines(text: string): { lines: string[], hidden: number } {\n const all = text.replace(/\\r\\n?/g, '\\n').replace(/\\t/g, ' ').split('\\n')\n // Trailing blank lines carry no information in a preview and would render as\n // dead space under the last line of a file that ends with a newline.\n while (all.length > 0 && all[all.length - 1]!.trim() === '')\n all.pop()\n if (all.length <= INSTRUCTION_PREVIEW_LINE_CAP)\n return { lines: all, hidden: 0 }\n return {\n lines: all.slice(0, INSTRUCTION_PREVIEW_LINE_CAP),\n hidden: all.length - INSTRUCTION_PREVIEW_LINE_CAP,\n }\n}\n\n/**\n * Short badge for a segment's origin — the \"where does this come from\" column.\n * `'file'` is intentionally the only one that reads like a location, since it's\n * the only origin the user can act on.\n *\n * @param segment - Segment whose `origin` is labeled.\n */\nexport function instructionOriginBadge(segment: ContextSegment): string {\n switch (segment.origin) {\n case 'file':\n return 'file'\n case 'generated':\n return 'generated'\n case 'mcp':\n return 'mcp server'\n case 'built-in':\n return 'built-in'\n }\n}\n","/**\n * What clients show about machines (`docs/MACHINES.md` § Client UI), shared\n * by the TUI and the GUI renderer (node-free, re-exported by\n * `zidane/chat/pure`): the \"waiting for <machine>…\" state of a session, a\n * machine's folders as a folder-picker listing, environment kinds grouped\n * by machine, and the words for a link's state.\n */\nimport type { MachineLinkState } from './machine-protocol'\nimport { parseMachineKind } from './machine-protocol'\n\n/** The `label` of the notices a host emits about a session's machine. */\nexport const MACHINE_NOTICE_LABEL = 'machine'\n\nconst WAITING_RE = /^waiting for (\\S+?)…/\nconst BACK_RE = /^\\S+ is back\\./\nconst GAVE_UP_RE = /^\\S+ stayed offline for /\n\n/**\n * The machine a session's run is paused on, from its notices (`waiting for\n * laptop…` until `laptop is back.` or `laptop stayed offline … run stopped`),\n * `null` when none. `online`: machines known to be back since (a\n * `machine:status` the window saw), which clear the wait at once.\n *\n * @param events - A session's events, oldest first.\n * @param online - Machine names known to be back online.\n */\nexport function machineWaiting(events: readonly { text?: string, notice?: { label?: string } }[], online: ReadonlySet<string> = new Set()): string | null {\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i]!\n if (event.notice?.label !== MACHINE_NOTICE_LABEL || typeof event.text !== 'string')\n continue\n if (BACK_RE.test(event.text) || GAVE_UP_RE.test(event.text))\n return null\n const waiting = WAITING_RE.exec(event.text)?.[1]\n if (waiting)\n return online.has(waiting) ? null : waiting\n }\n return null\n}\n\n/** A folder listing a folder picker renders (the shape of `fs.listDirs`). */\nexport interface MachineDirListing {\n /** Folders the picker may start from. */\n roots: string[]\n /** The folder being listed. */\n path: string\n /** Parent folder, or `null` when `path` is a root. */\n parent: string | null\n /** Folders under `path`. `isGitRepo` is always `false` here. */\n entries: { path: string, name: string, isGitRepo: boolean }[]\n}\n\nfunction dirname(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n const at = trimmed.lastIndexOf('/')\n return at <= 0 ? '/' : trimmed.slice(0, at)\n}\n\nfunction basename(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n return trimmed.slice(trimmed.lastIndexOf('/') + 1) || trimmed\n}\n\n/**\n * `machines.listDirs` as a folder listing: the parent stops at the root the folder is in.\n *\n * @param result - Directory names, the listed path and the allowed roots from `machines.listDirs`.\n */\nexport function machineDirListing(result: { path: string, dirs: string[], roots: string[] }): MachineDirListing {\n const { path } = result\n return {\n roots: result.roots,\n path,\n parent: result.roots.includes(path) ? null : dirname(path),\n entries: result.dirs.map(dir => ({ path: dir, name: basename(dir), isGitRepo: false })),\n }\n}\n\n/**\n * Environment kinds in picker order: this host's own first, then each\n * machine's together (`local@` before `worktree@`), machines by name.\n *\n * @param descriptors - Environment kind descriptors.\n */\nexport function orderByMachine<T extends { kind: string, machine?: { name: string } }>(descriptors: readonly T[]): T[] {\n const rank = (d: T): [number, string, number] => {\n const parsed = parseMachineKind(d.kind)\n return parsed ? [1, parsed.name, parsed.base === 'local' ? 0 : 1] : [0, '', 0]\n }\n return descriptors\n .map((d, i) => ({ d, i, r: rank(d) }))\n .sort((a, b) => a.r[0] - b.r[0] || a.r[1].localeCompare(b.r[1]) || a.r[2] - b.r[2] || a.i - b.i)\n .map(entry => entry.d)\n}\n\n/**\n * Why a machine kind can't be picked now (its machine is offline), else `undefined`.\n *\n * @param descriptor - Environment kind descriptor with its machine and the machine's status.\n */\nexport function machineBlockedReason(descriptor: { machine?: { name: string, status: 'online' | 'offline' } }): string | undefined {\n return descriptor.machine?.status === 'offline' ? `${descriptor.machine.name} is offline` : undefined\n}\n\n/**\n * A session's environment as its header shows it: `local@laptop`, `worktree@laptop ⎇ feat`, `⎇ feat`, or the kind.\n *\n * @param environment - The session environment: its kind and optional branch.\n */\nexport function environmentLabel(environment: { kind: string, branch?: string }): string {\n if (parseMachineKind(environment.kind))\n return environment.branch ? `${environment.kind} ⎇ ${environment.branch}` : environment.kind\n return environment.branch ? `⎇ ${environment.branch}` : environment.kind\n}\n\n/** Display text for each {@link MachineLinkState}. */\nexport const MACHINE_LINK_STATE_TEXT: Record<MachineLinkState, string> = {\n 'connecting': 'connecting…',\n 'connected': 'connected',\n 'reconnecting': 'reconnecting…',\n 'offline': 'offline',\n 'auth-refused': 'refused',\n 'identity': 'another server answers there',\n 'version-mismatch': 'another protocol version (upgrade one side)',\n 'refused': 'refused',\n}\n\n/**\n * \"seen 5 min ago\" for a machine's `lastSeen`.\n *\n * @param lastSeen - Epoch milliseconds the machine was last seen, or `undefined` if never.\n * @param now - Epoch milliseconds to measure from.\n */\nexport function lastSeenText(lastSeen: number | undefined, now: number): string {\n if (lastSeen === undefined)\n return 'never seen'\n const minutes = Math.max(0, Math.round((now - lastSeen) / 60_000))\n if (minutes < 1)\n return 'seen just now'\n if (minutes < 60)\n return `seen ${minutes} min ago`\n const hours = Math.round(minutes / 60)\n return hours < 48 ? `seen ${hours} h ago` : `seen ${Math.round(hours / 24)} d ago`\n}\n","/**\n * Add-MCP form model — values, validation, and the two tokenizers it depends\n * on. Renderer-agnostic and node-free.\n *\n * Lives in `chat/` because BOTH clients render this form (the TUI's\n * `settings-form-dialog`, the GUI's `McpsPanel`). Validation is the one place\n * a divergence between two copies would matter, because it decides which MCP\n * configs each surface accepts. One implementation means the same `mcps.json`\n * entry is accepted or rejected identically everywhere.\n */\nimport type { McpOAuthClientConfig, McpServerConfig } from '../types'\n\n/** Where a written MCP entry lands. */\nexport type InstallScopeChoice = 'user' | 'project'\n\n/** Transport an MCP server is reached over. */\nexport type McpTransport = 'stdio' | 'streamable-http' | 'sse'\n\n/** Every {@link McpTransport} in the order a form lists them. */\nexport const MCP_TRANSPORTS: readonly McpTransport[] = ['stdio', 'streamable-http', 'sse']\n\n/** Raw field values of the add-MCP-server form. */\nexport interface McpFormValues {\n /** Server name. Letters, digits, dots, hyphens and underscores. */\n name: string\n /** Transport the server uses. */\n transport: McpTransport\n /** stdio: full command line (first token = command, rest = args). */\n commandLine: string\n /** http/sse: server URL. */\n url: string\n /** One `KEY=VALUE` per line — stdio only. Values may contain spaces. */\n env: string\n /** One `Name: value` (or `Name=value`) per line — http/sse only. */\n headers: string\n /** Whether to write the entry to the user or the project config. */\n scope: InstallScopeChoice\n /**\n * Advanced OAuth (http/sse only): a pre-registered client for auth\n * servers without dynamic client registration. Optional so forms that\n * don't render the section keep compiling.\n */\n oauthClientId?: string\n /** Secret of the pre-registered client, when it has one. */\n oauthClientSecret?: string\n /** Raw field text; validated to an unprivileged port. */\n oauthCallbackPort?: string\n /** Space- or comma-separated OAuth scopes to request. */\n oauthScope?: string\n}\n\n/** A validated form: the config entry to write and where to write it. */\nexport interface McpFormResult {\n /** Normalized server config. */\n entry: McpServerConfig\n /** Where the entry should be written. */\n scope: InstallScopeChoice\n /**\n * Client secret from the Advanced OAuth section. Deliberately NOT in\n * `entry`: hosts keep it in the MCP credential store, out of `mcps.json`.\n */\n clientSecret?: string\n}\n\n/**\n * Validate + normalize the raw field values into a config entry.\n * Returns the first problem in row order so the dialog can surface it.\n *\n * @param values - Raw form field values.\n */\nexport function validateMcpForm(values: McpFormValues): { ok: true, result: McpFormResult } | { ok: false, error: string } {\n const name = values.name.trim()\n if (name.length === 0)\n return { ok: false, error: 'name is required' }\n if (!/^[\\w.-]+$/.test(name))\n return { ok: false, error: 'name must be alphanumerics, dots, hyphens, underscores' }\n\n if (values.transport === 'stdio') {\n const tokens = splitCommandLine(values.commandLine)\n if (tokens.length === 0)\n return { ok: false, error: 'command is required for stdio servers' }\n const env = parseKeyValueLines(values.env, { label: 'env', separators: ['='] })\n if (!env.ok)\n return { ok: false, error: env.error }\n const entry: McpServerConfig = {\n name,\n transport: 'stdio',\n command: tokens[0] as string,\n ...(tokens.length > 1 ? { args: tokens.slice(1) } : {}),\n ...(Object.keys(env.pairs).length > 0 ? { env: env.pairs } : {}),\n }\n return { ok: true, result: { entry, scope: values.scope } }\n }\n\n const url = values.url.trim()\n if (url.length === 0)\n return { ok: false, error: 'url is required for http/sse servers' }\n if (!/^https?:\\/\\//.test(url))\n return { ok: false, error: 'url must start with http:// or https://' }\n const headers = parseKeyValueLines(values.headers, { label: 'headers', separators: [':', '='] })\n if (!headers.ok)\n return { ok: false, error: headers.error }\n const oauth = validateOAuthFields(values)\n if (!oauth.ok)\n return { ok: false, error: oauth.error }\n return {\n ok: true,\n result: {\n entry: {\n name,\n transport: values.transport,\n url,\n ...(Object.keys(headers.pairs).length > 0 ? { headers: headers.pairs } : {}),\n ...(oauth.config ? { auth: 'oauth' as const, oauth: oauth.config } : {}),\n },\n scope: values.scope,\n ...(oauth.clientSecret ? { clientSecret: oauth.clientSecret } : {}),\n },\n }\n}\n\nfunction validateOAuthFields(values: McpFormValues):\n | { ok: true, config?: McpOAuthClientConfig, clientSecret?: string }\n | { ok: false, error: string } {\n const clientId = values.oauthClientId?.trim() ?? ''\n const clientSecret = values.oauthClientSecret?.trim() ?? ''\n const portText = values.oauthCallbackPort?.trim() ?? ''\n const scope = values.oauthScope?.trim().split(/[\\s,]+/).filter(Boolean).join(' ') ?? ''\n if (clientId === '') {\n if (clientSecret !== '' || portText !== '' || scope !== '')\n return { ok: false, error: 'client ID is required for advanced OAuth' }\n return { ok: true }\n }\n let callbackPort: number | undefined\n if (portText !== '') {\n callbackPort = /^\\d+$/.test(portText) ? Number(portText) : Number.NaN\n if (!Number.isInteger(callbackPort) || callbackPort < 1024 || callbackPort > 65535)\n return { ok: false, error: 'callback port must be a number from 1024 to 65535' }\n }\n return {\n ok: true,\n config: {\n clientId,\n ...(callbackPort !== undefined ? { callbackPort } : {}),\n ...(scope !== '' ? { scope } : {}),\n },\n ...(clientSecret !== '' ? { clientSecret } : {}),\n }\n}\n\n/**\n * Split a command line into tokens, honoring single/double quotes so\n * `npx -y my-server --root \"/path with spaces\"` round-trips. No escape\n * processing beyond quote grouping — this is a form field, not a shell.\n *\n * @param line - Command line text.\n */\nexport function splitCommandLine(line: string): string[] {\n const out: string[] = []\n const re = /\"([^\"]*)\"|'([^']*)'|(\\S+)/g\n for (let m = re.exec(line); m !== null; m = re.exec(line))\n out.push((m[1] ?? m[2] ?? m[3]) as string)\n return out\n}\n\n/**\n * Parse one key/value pair PER LINE. Line-based (not whitespace-split)\n * because values legitimately contain spaces — `Authorization: Bearer\n * abc123` is the canonical headers case, and env values like\n * `GREETING=hello world` are equally valid. The first separator found\n * (the separator that appears first in the line) splits.\n * The rest of the line is the value, trimmed. Blank lines skipped.\n *\n * @param raw - Field text, one pair per line.\n * @param opts - A `label` for error messages and the separators to split on.\n */\nexport function parseKeyValueLines(\n raw: string,\n opts: { label: string, separators: readonly string[] },\n): { ok: true, pairs: Record<string, string> } | { ok: false, error: string } {\n const pairs: Record<string, string> = {}\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed.length === 0)\n continue\n let splitAt = -1\n for (const sep of opts.separators) {\n const idx = trimmed.indexOf(sep)\n if (idx > 0 && (splitAt === -1 || idx < splitAt))\n splitAt = idx\n }\n if (splitAt <= 0) {\n const forms = opts.separators.map(s => `KEY${s}VALUE`).join(' or ')\n return { ok: false, error: `${opts.label} entries must be ${forms}, one per line (got \"${trimmed}\")` }\n }\n const key = trimmed.slice(0, splitAt).trim()\n const value = trimmed.slice(splitAt + 1).trim()\n if (key.length === 0)\n return { ok: false, error: `${opts.label} entry has an empty key (\"${trimmed}\")` }\n pairs[key] = value\n }\n return { ok: true, pairs }\n}\n","/**\n * Presentation constants for structured transcript notices (`StreamEvent.notice`).\n *\n * Shared by the TUI transcript and the GUI timeline so a `warn` notice reads\n * with the same glyph on both, and so the label vocabulary (`model fallback`,\n * `output limit`, `repeat guard`, …) is recognisably the same row across\n * surfaces. Pure; re-exported from `zidane/chat/pure`.\n */\nimport type { StreamEvent } from './types'\n\n/** Severity of a transcript notice. */\nexport type NoticeSeverity = NonNullable<StreamEvent['notice']>['severity']\n\n/** Leading glyph per severity. `info` is deliberately quiet: a plain `i`, single-width in every terminal. */\nexport const NOTICE_GLYPH: Readonly<Record<NoticeSeverity, string>> = {\n info: 'i',\n warn: '!',\n error: '✗',\n}\n","/**\n * Command palette: the renderer-agnostic model.\n *\n * Everything the user can do from the palette is a {@link PaletteItem}:\n * built-in key actions, `/` commands, panels, sessions, settings toggles\n * and extension actions all flow through one shape, so one search covers\n * the app. Items are JSON-safe data and `run` is addressed by id, the same\n * contract side panels use: an extension's provider executes where the\n * extension lives (TUI in-process, GUI main process) and the palette\n * paints in the host with its own components.\n *\n * This module is pure (no React, no node): ranking, grouping, recents and\n * the normaliser applied before items cross IPC. The TUI and the GUI each\n * render the result; they never re-implement the ordering.\n */\nimport type { PanelIcon } from '../extensions/panels'\nimport type { JsonValue } from '../types'\n\n/** Which app renders the palette. */\nexport type PaletteHost = 'gui' | 'tui'\n\n/** `toggle` shows a checked state; `picker` opens a nested list on run. */\nexport type PaletteItemKind = 'action' | 'toggle' | 'picker'\n\n/** An entry in the command palette. */\nexport interface PaletteItem {\n /** Stable, unique across providers: `builtin:openSettings`, `slash:compact`, `<extension>/<id>`. */\n id: string\n /** Text shown in the row. */\n title: string\n /** Secondary text shown beside the title. */\n description?: string\n /** Section header. Hosts order groups by first appearance after `Recent`. */\n group: string\n /** Extra search terms not shown in the row. */\n keywords?: readonly string[]\n /** Icon for each renderer. */\n icon?: PanelIcon\n /** How the item behaves. Treated as `action` when omitted. */\n kind?: PaletteItemKind\n /** For `toggle` items. */\n checked?: boolean\n /** Resolved chord spec (`ctrl+shift+k`); the host formats it for display. */\n keybinding?: string\n /** Reason the item cannot run right now; it stays listed, muted. */\n disabled?: string\n /**\n * Only appears once the query matches it: bulk catalogs (every file in\n * the project) stay out of the empty-query listing but are one keystroke\n * away.\n */\n searchOnly?: boolean\n /** Provider that owns `run` for this item. Stamped by the aggregator. */\n source: string\n}\n\n/** JSON-safe snapshot of the host handed to providers. Never holds functions. */\nexport interface PaletteContext {\n /** Which app is asking. */\n host: PaletteHost\n /** Working directory of the active session. */\n cwd?: string\n /** Id of the active session. */\n sessionId?: string\n /** A run is in flight on the active session. */\n busy?: boolean\n}\n\n/**\n * What a provider's `run` may hand back. `items` opens a nested picker\n * (branches, environments); the host keeps a stack so Backspace on an\n * empty query goes back one level. `prompt` sends text to the chat,\n * `insert` puts it in the composer (a `/` command that takes arguments).\n */\nexport type PaletteRunResult\n = | void\n | undefined\n | { kind: 'items', title?: string, placeholder?: string, items: readonly PaletteItem[] }\n | { kind: 'prompt', text: string }\n | { kind: 'insert', text: string }\n | { kind: 'notify', text: string, tone?: 'info' | 'warn' | 'error' }\n\n/** Source of palette items and the handler that runs them. */\nexport interface PaletteProvider {\n /** Provider id, stamped on its items as `source`. */\n id: string\n /** Items for the current context. Called on open, on `subscribe` emits, and on explicit refresh. */\n items: (ctx: PaletteContext) => readonly PaletteItem[] | Promise<readonly PaletteItem[]>\n /** Runs the item with the given id. May return a follow-up result. */\n run: (itemId: string, ctx: PaletteContext) => PaletteRunResult | Promise<PaletteRunResult>\n /** Live updates while the palette is open, same contract as panels. */\n subscribe?: (emit: () => void) => () => void\n}\n\n// ---------------------------------------------------------------------------\n// Ranking\n// ---------------------------------------------------------------------------\n\n/** A palette item with its match score. */\nexport interface RankedPaletteItem {\n /** The matched item. */\n item: PaletteItem\n /** Match score. Higher ranks first. */\n score: number\n /** Indices into `item.title` to highlight. Empty when the match came from elsewhere. */\n titleMatches: readonly number[]\n}\n\n/** Group name the hosts use for the most-recently-used rows shown on an empty query. */\nexport const PALETTE_RECENT_GROUP = 'Recent'\n/** Maximum number of recent item ids kept. */\nexport const PALETTE_RECENTS_MAX = 12\n/** Ranked rows returned for a query; the host virtualises anyway, this bounds the work. */\nexport const PALETTE_RESULT_MAX = 200\n\nconst WORD_BREAKS = new Set([' ', '/', '-', '_', ':', '.'])\n\n/** What a hit at `at` is worth: the very start, a word start, a camelCase hump, or anywhere. */\nfunction startBonus(text: string, lower: string, at: number): number {\n if (at === 0)\n return 8\n if (WORD_BREAKS.has(lower[at - 1]!))\n return 6\n if (text[at] !== lower[at] && text[at - 1] === lower[at - 1])\n return 4\n return 1\n}\n\n/** Bonus per character for a term found whole: \"set\" in \"settings\" beats s, e and t spread across words. */\nconst WHOLE_TERM_BONUS = 2\n\n/**\n * Subsequence match of `query` in `text` with the usual bonuses: word\n * starts and the very beginning score higher, gaps cost, runs of adjacent\n * hits are rewarded, and the query found whole (as one run) beats the same\n * letters scattered. Returns null when not every query character appears\n * in order. Case-insensitive; `query` must already be lower-cased.\n *\n * @param text - Text to search in.\n * @param query - Lower-cased query to look for.\n */\nexport function fuzzyMatch(text: string, query: string): { score: number, indices: number[] } | null {\n return matchLowered(text, text.toLowerCase(), query)\n}\n\nconst NO_INDICES: number[] = []\n\n/** `indices` null: the score alone (a fallback field never highlights), without the allocations. */\nfunction matchLowered(\n text: string,\n lower: string,\n query: string,\n indices: number[] | null = [],\n): { score: number, indices: number[], whole: boolean } | null {\n if (query.length === 0)\n return { score: 0, indices: [], whole: true }\n // Scattered: each character at its first place after the previous one.\n let score = 0\n let from = 0\n let prev = -2\n for (let q = 0; q < query.length; q++) {\n const at = lower.indexOf(query[q]!, from)\n if (at === -1)\n return null\n score += startBonus(text, lower, at)\n if (at === prev + 1)\n score += 3\n else if (prev >= 0)\n score -= Math.min(3, at - prev - 1) * 0.5\n indices?.push(at)\n prev = at\n from = at + 1\n }\n // Whole: the best place the query appears as one run, if it does.\n let whole = -Infinity\n let wholeAt = -1\n for (let at = lower.indexOf(query); at !== -1; at = lower.indexOf(query, at + 1)) {\n const value = startBonus(text, lower, at) + (query.length - 1) * 4 + query.length * WHOLE_TERM_BONUS\n if (value > whole) {\n whole = value\n wholeAt = at\n }\n // A word start is the best a later place could do (the very start only comes first).\n if (at === 0 || WORD_BREAKS.has(lower[at - 1]!))\n break\n }\n const found = whole > score\n if (found) {\n score = whole\n if (indices) {\n for (let q = 0; q < query.length; q++) indices[q] = wholeAt + q\n }\n }\n // Shorter targets win ties: \"Open settings\" over \"Open settings: keybindings\".\n score -= text.length * 0.02\n return { score, indices: indices ?? NO_INDICES, whole: found }\n}\n\n/** An item's searchable text, lower-cased once per item instead of once per key. */\ninterface Haystack {\n title: string\n fields: readonly (readonly [text: string, lower: string])[]\n}\n\nconst haystacks = new WeakMap<PaletteItem, Haystack>()\n\nfunction haystackOf(item: PaletteItem): Haystack {\n let h = haystacks.get(item)\n if (!h) {\n const texts = [item.title, item.description, item.group, ...(item.keywords ?? [])].filter(\n (t): t is string => !!t,\n )\n h = { title: item.title.toLowerCase(), fields: texts.map(t => [t, t.toLowerCase()] as const) }\n haystacks.set(item, h)\n }\n return h\n}\n\n/**\n * Every whitespace-separated term must match (AND); scores add. `whole`:\n * each term was found as one run (the words typed, not letters picked\n * across the text). `indices` collects the merged highlight when given;\n * ranking scores without it and highlights only the rows it keeps.\n */\nfunction matchTerms(\n text: string,\n lower: string,\n terms: readonly string[],\n indices: number[] | null,\n): { score: number, whole: boolean } | null {\n let score = 0\n let whole = true\n for (const term of terms) {\n const m = matchLowered(text, lower, term, indices && [])\n if (!m)\n return null\n score += m.score\n whole &&= m.whole\n indices?.push(...m.indices)\n }\n return { score, whole }\n}\n\nfunction titleIndices(item: PaletteItem, terms: readonly string[]): number[] {\n const indices: number[] = []\n matchTerms(item.title, haystackOf(item).title, terms, indices)\n return terms.length === 1 ? indices : [...new Set(indices)].sort((a, b) => a - b)\n}\n\nconst collator = new Intl.Collator()\n\nfunction termsOf(query: string): string[] {\n return query.trim().toLowerCase().split(/\\s+/).filter(Boolean)\n}\n\n/** On an empty query: recents first (most recent on top), then the catalog in provider order. */\nfunction listUnfiltered(items: readonly PaletteItem[], recents: readonly string[]): RankedPaletteItem[] {\n const recentRank = new Map(recents.map((id, i) => [id, i]))\n const out: RankedPaletteItem[] = []\n for (const item of items) {\n const r = recentRank.get(item.id)\n // Search-only items surface on an empty query only as recents.\n if (item.searchOnly && r === undefined)\n continue\n out.push({ item, score: r === undefined ? 0 : PALETTE_RECENTS_MAX - r, titleMatches: [] })\n }\n // Stable: recents by recency, everything else keeps provider order.\n return out.sort((a, b) => b.score - a.score).slice(0, PALETTE_RESULT_MAX)\n}\n\n/** The ranked rows for `terms`, and every item that matched (the pool a longer query searches). */\nfunction rankTerms(\n items: readonly PaletteItem[],\n terms: readonly string[],\n): { ranked: RankedPaletteItem[], matched: PaletteItem[] } {\n const hits: { item: PaletteItem, score: number, inTitle: boolean }[] = []\n for (const item of items) {\n const hay = haystackOf(item)\n // The words typed, found in the title, come first; letters picked across a\n // title compete with what the description and keywords found.\n const title = matchTerms(item.title, hay.title, terms, null)\n if (title?.whole) {\n hits.push({ item, score: 100 + title.score, inTitle: true })\n continue\n }\n // Fallback: every term must land somewhere across title, description, keywords, group.\n let total = 0\n let ok = true\n for (const term of terms) {\n let best = -Infinity\n for (const [text, lower] of hay.fields) {\n const m = matchLowered(text, lower, term, null)\n if (m && m.score > best)\n best = m.score\n }\n if (best === -Infinity) {\n ok = false\n break\n }\n total += best\n }\n if (title && title.score >= total)\n hits.push({ item, score: title.score, inTitle: true })\n else if (ok)\n hits.push({ item, score: total, inTitle: false })\n }\n const matched = hits.map(h => h.item)\n hits.sort((a, b) => b.score - a.score || collator.compare(a.item.title, b.item.title))\n const ranked = hits.slice(0, PALETTE_RESULT_MAX).map(({ item, score, inTitle }) => ({\n item,\n score,\n titleMatches: inTitle ? titleIndices(item, terms) : [],\n }))\n return { ranked, matched }\n}\n\n/**\n * Rank every item against `query`. Terms are AND-ed: `tog sid` needs both\n * `tog` and `sid` somewhere in the text, each with its letters in order. A\n * title that holds every term as one run gets a large bonus;\n * description, keywords and group are fallbacks. On an empty query recents\n * come first (most recent on top), then the catalog in provider order.\n * Returns at most 200 rows.\n *\n * @param items - Items to rank.\n * @param query - Space-separated search terms.\n * @param recents - Most-recent-first item ids, shown first on an empty query.\n * @example\n * ```ts\n * import { rankPaletteItems } from 'zidane/chat/pure'\n *\n * const ranked = rankPaletteItems(\n * [{ id: 'builtin:openSettings', title: 'Open settings', group: 'App', source: 'builtin' }],\n * 'set',\n * )\n * ranked[0]?.item.id // 'builtin:openSettings'\n * ```\n */\nexport function rankPaletteItems(\n items: readonly PaletteItem[],\n query: string,\n recents: readonly string[] = [],\n): RankedPaletteItem[] {\n const terms = termsOf(query)\n return terms.length === 0 ? listUnfiltered(items, recents) : rankTerms(items, terms).ranked\n}\n\n/** `next` asks for at least what `prev` did: each earlier term grew or stayed, new ones came after. */\nfunction narrows(prev: readonly string[], next: readonly string[]): boolean {\n return next.length >= prev.length && prev.every((term, i) => next[i]!.startsWith(term))\n}\n\n/**\n * `rankPaletteItems` for a palette being typed into: it remembers the last\n * query, and when the next one only adds to it (one more character, one\n * more word) it searches just what matched before. A longer query never\n * matches an item the shorter one missed, so the result is the same.\n */\nexport function createPaletteRanker(): typeof rankPaletteItems {\n let last: { items: readonly PaletteItem[], terms: readonly string[], matched: PaletteItem[] } | null = null\n return (items, query, recents = []) => {\n const terms = termsOf(query)\n if (terms.length === 0) {\n last = null\n return listUnfiltered(items, recents)\n }\n const pool = last && last.items === items && narrows(last.terms, terms) ? last.matched : items\n const { ranked, matched } = rankTerms(pool, terms)\n last = { items, terms, matched }\n return ranked\n }\n}\n\n/** A titled section of ranked palette rows. */\nexport interface PaletteGroup {\n /** Section header. */\n title: string\n /** Rows in the section, in display order. */\n rows: readonly RankedPaletteItem[]\n}\n\n/**\n * Sections for display. With a query the ranking already interleaves\n * providers, so groups follow the order of their best row. Without a\n * query the recents (ids in `recents`, present in `ranked`) form a\n * leading `Recent` section and the rest keeps provider order.\n *\n * @param ranked - Rows from {@link rankPaletteItems}.\n * @param query - The query the rows were ranked for. A non-blank query disables the `Recent` section.\n * @param recents - Most-recent-first item ids.\n */\nexport function groupPaletteRows(\n ranked: readonly RankedPaletteItem[],\n query: string,\n recents: readonly string[] = [],\n): PaletteGroup[] {\n const groups = new Map<string, RankedPaletteItem[]>()\n const push = (title: string, row: RankedPaletteItem) => {\n const list = groups.get(title)\n if (list)\n list.push(row)\n else groups.set(title, [row])\n }\n const isRecent = new Set(query.trim() ? [] : recents)\n for (const row of ranked)\n push(isRecent.has(row.item.id) ? PALETTE_RECENT_GROUP : row.item.group, row)\n return [...groups.entries()].map(([title, rows]) => ({ title, rows }))\n}\n\n/**\n * Most-recent-first list of ids, deduplicated and capped.\n *\n * @param recents - Current most-recent-first ids.\n * @param id - Id to move to the front.\n */\nexport function pushPaletteRecent(recents: readonly string[], id: string): string[] {\n return [id, ...recents.filter(r => r !== id)].slice(0, PALETTE_RECENTS_MAX)\n}\n\n// ---------------------------------------------------------------------------\n// Normalisation (before items cross IPC or reach a renderer)\n// ---------------------------------------------------------------------------\n\n/** Caps applied by {@link normalizePaletteItems}: item count, text length and keyword count. */\nexport const PALETTE_LIMITS = {\n items: 500,\n textChars: 500,\n keywords: 16,\n} as const\n\nfunction str(v: unknown, max: number = PALETTE_LIMITS.textChars): string | undefined {\n return typeof v === 'string' && v.length > 0 ? (v.length > max ? `${v.slice(0, max - 1)}…` : v) : undefined\n}\n\n/**\n * Coerce whatever a provider returned into well-formed items: entries\n * without an id or title are dropped, strings are capped, unknown kinds\n * fall back to `action`, and `source` is stamped with the provider id.\n * Never throws.\n *\n * @param input - Value a provider returned.\n * @param source - Provider id stamped on each item.\n * @param defaultGroup - Group for items that name none.\n */\nexport function normalizePaletteItems(input: unknown, source: string, defaultGroup: string): PaletteItem[] {\n if (!Array.isArray(input))\n return []\n const out: PaletteItem[] = []\n const seen = new Set<string>()\n for (const raw of input.slice(0, PALETTE_LIMITS.items)) {\n if (!raw || typeof raw !== 'object')\n continue\n const r = raw as Record<string, unknown>\n const id = str(r.id, 200)\n const title = str(r.title, 200)\n if (!id || !title || seen.has(id))\n continue\n seen.add(id)\n const item: PaletteItem = { id, title, group: str(r.group, 80) ?? defaultGroup, source }\n const description = str(r.description)\n if (description)\n item.description = description\n if (Array.isArray(r.keywords)) {\n const kw = r.keywords.filter((k): k is string => typeof k === 'string' && k.length > 0).slice(0, PALETTE_LIMITS.keywords)\n if (kw.length > 0)\n item.keywords = kw.map(k => k.slice(0, 60))\n }\n if (r.icon && typeof r.icon === 'object') {\n const icon = r.icon as Record<string, unknown>\n const gui = str(icon.gui, 120)\n const tui = str(icon.tui, 8)\n if (gui || tui)\n item.icon = { ...(gui ? { gui } : {}), ...(tui ? { tui } : {}) }\n }\n if (r.kind === 'toggle' || r.kind === 'picker')\n item.kind = r.kind\n if (typeof r.checked === 'boolean')\n item.checked = r.checked\n const keybinding = str(r.keybinding, 60)\n if (keybinding)\n item.keybinding = keybinding\n const disabled = str(r.disabled, 200)\n if (disabled)\n item.disabled = disabled\n if (r.searchOnly === true)\n item.searchOnly = true\n out.push(item)\n }\n return out\n}\n\n/**\n * Same guard for a `run` result: anything malformed becomes `undefined` (nothing to do).\n *\n * @param input - Value a provider's `run` returned.\n * @param source - Provider id stamped on nested items.\n * @param defaultGroup - Group for nested items that name none.\n */\nexport function normalizePaletteRunResult(input: unknown, source: string, defaultGroup: string): PaletteRunResult {\n if (!input || typeof input !== 'object')\n return undefined\n const r = input as Record<string, unknown>\n switch (r.kind) {\n case 'items': {\n const out: Extract<PaletteRunResult, { kind: 'items' }> = {\n kind: 'items',\n items: normalizePaletteItems(r.items, source, defaultGroup),\n }\n const title = str(r.title, 200)\n const placeholder = str(r.placeholder, 200)\n if (title)\n out.title = title\n if (placeholder)\n out.placeholder = placeholder\n return out\n }\n case 'prompt':\n case 'insert': {\n const text = str(r.text, 20_000)\n return text ? { kind: r.kind, text } : undefined\n }\n case 'notify': {\n const text = str(r.text, 1000)\n if (!text)\n return undefined\n const tone = r.tone === 'warn' || r.tone === 'error' ? r.tone : 'info'\n return { kind: 'notify', text, tone }\n }\n default:\n return undefined\n }\n}\n\n/**\n * Type guard hosts use before forwarding a payload from an untrusted provider.\n *\n * @param v - Value to test.\n */\nexport function isPaletteContext(v: unknown): v is PaletteContext {\n if (!v || typeof v !== 'object')\n return false\n const c = v as Record<string, JsonValue | undefined>\n return (c.host === 'gui' || c.host === 'tui')\n && (c.cwd === undefined || typeof c.cwd === 'string')\n && (c.sessionId === undefined || typeof c.sessionId === 'string')\n && (c.busy === undefined || typeof c.busy === 'boolean')\n}\n","/**\n * Side-panel catalog and open state. Renderer-agnostic: the TUI rail and\n * the GUI side panel both read the same catalog (built-ins first, then\n * extension panels in load order) and drive the same state machine.\n *\n * The one behavioural rule worth spelling out: `openProactive`. Agent- or\n * extension-driven opens (a PR was created, a badge flipped) must never\n * yank the panel away from a tab the user chose. So a proactive request\n * is honoured only while the user has not picked a tab since the previous\n * proactive open; the moment they click a tab, proactive opens are ignored\n * until the next user pick resets the gate.\n */\nimport type { ExtensionPanelEntry, PanelIcon } from '../extensions/panels'\nimport { panelShowsIn } from '../extensions/panels'\n\n/** Id of the inbox panel. */\nexport const INBOX_PANEL_ID = 'inbox'\n/** Id of the todos panel. */\nexport const TODOS_PANEL_ID = 'todos'\n/** Id of the queue panel: messages sent during a run, waiting for it to end (the desktop app only). */\nexport const QUEUE_PANEL_ID = 'queue'\n/** Id of the artifacts panel. */\nexport const ARTIFACTS_PANEL_ID = 'artifacts'\n/** Id of the diffs panel. */\nexport const DIFFS_PANEL_ID = 'diffs'\n/** Id of the files panel. */\nexport const FILES_PANEL_ID = 'files'\n/** Id of the browser panel. */\nexport const BROWSER_PANEL_ID = 'browser'\n/** Id of the terminal panel. */\nexport const TERMINAL_PANEL_ID = 'terminal'\n/** A `/side` chat about the session (the desktop app only). */\nexport const SIDE_PANEL_ID = 'side'\n\n/** Built-in tabs the hosts render with their own components. */\nexport type BuiltinPanelId\n = | typeof INBOX_PANEL_ID\n | typeof TODOS_PANEL_ID\n | typeof QUEUE_PANEL_ID\n | typeof ARTIFACTS_PANEL_ID\n | typeof DIFFS_PANEL_ID\n | typeof FILES_PANEL_ID\n | typeof BROWSER_PANEL_ID\n | typeof TERMINAL_PANEL_ID\n | typeof SIDE_PANEL_ID\n\n/** A tab for a panel the host renders itself. */\nexport interface BuiltinPanelTab {\n /** Built-in panel id. */\n id: BuiltinPanelId\n /** Tab label. */\n label: string\n /** Icon for each renderer. */\n icon: PanelIcon\n /** Discriminant that marks a built-in tab. */\n builtin: true\n}\n\n/** A tab for a panel an extension registered. */\nexport interface ExtensionPanelTab {\n /** Panel id. */\n id: string\n /** Tab label. */\n label: string\n /** Icon for each renderer, when the extension set one. */\n icon?: PanelIcon\n /** Discriminant that marks an extension tab. */\n builtin: false\n /** Name of the extension that registered the panel. */\n owner: string\n}\n\n/** A built-in or extension panel tab. */\nexport type PanelTab = BuiltinPanelTab | ExtensionPanelTab\n\n/** Built-in panel tabs in display order. */\nexport const BUILTIN_PANEL_TABS: readonly BuiltinPanelTab[] = [\n // Agent-facing surfaces first: what is waiting on the user, then the plan.\n { id: INBOX_PANEL_ID, label: 'Inbox', icon: { gui: 'i-ph-tray', tui: '✉' }, builtin: true },\n { id: TODOS_PANEL_ID, label: 'Todos', icon: { gui: 'i-ph-list-checks', tui: '▣' }, builtin: true },\n { id: QUEUE_PANEL_ID, label: 'Queue', icon: { gui: 'i-ph-queue', tui: '❯' }, builtin: true },\n { id: ARTIFACTS_PANEL_ID, label: 'Artifacts', icon: { gui: 'i-ph-cube', tui: '◆' }, builtin: true },\n { id: DIFFS_PANEL_ID, label: 'Diffs', icon: { gui: 'i-ph-git-diff', tui: '±' }, builtin: true },\n { id: FILES_PANEL_ID, label: 'Files', icon: { gui: 'i-ph-tree-structure', tui: '▤' }, builtin: true },\n { id: BROWSER_PANEL_ID, label: 'Browser', icon: { gui: 'i-ph-globe-simple', tui: '◎' }, builtin: true },\n { id: TERMINAL_PANEL_ID, label: 'Terminal', icon: { gui: 'i-ph-terminal-window', tui: '❯' }, builtin: true },\n { id: SIDE_PANEL_ID, label: 'Side', icon: { gui: 'i-ph-chats-circle', tui: '◇' }, builtin: true },\n]\n\n/** Options for {@link buildPanelCatalog}. */\nexport interface PanelCatalogOptions {\n /** Hide the artifacts tab (the user's `artifacts: false` setting). */\n showArtifacts?: boolean\n /** Built-in ids the host does not render (the TUI keeps only the artifacts tab). */\n omitBuiltins?: readonly BuiltinPanelId[]\n /**\n * No session is bound (only a folder is open): keep just the extension\n * panels that opted in (`scope: 'project' | 'both'`). Bound (the\n * default), `scope: 'project'` panels are dropped. Built-ins are not\n * filtered here; hosts drop session-only ones via `omitBuiltins`.\n */\n unbound?: boolean\n}\n\n/**\n * Built-ins first, then extension panels in registry (load) order.\n *\n * @param extensionPanels - Panels registered by extensions.\n * @param options - Catalog filters.\n */\nexport function buildPanelCatalog(\n extensionPanels: readonly Pick<ExtensionPanelEntry, 'id' | 'label' | 'icon' | 'owner' | 'scope'>[],\n options: PanelCatalogOptions = {},\n): PanelTab[] {\n const tabs: PanelTab[] = []\n for (const tab of BUILTIN_PANEL_TABS) {\n if (tab.id === ARTIFACTS_PANEL_ID && options.showArtifacts === false)\n continue\n if (options.omitBuiltins?.includes(tab.id))\n continue\n tabs.push(tab)\n }\n const seen = new Set(tabs.map(t => t.id))\n for (const p of extensionPanels) {\n if (seen.has(p.id))\n continue\n if (!panelShowsIn(p.scope, options.unbound ? 'project' : 'session'))\n continue\n seen.add(p.id)\n tabs.push({ id: p.id, label: p.label, builtin: false, owner: p.owner, ...(p.icon ? { icon: p.icon } : {}) })\n }\n return tabs\n}\n\n// ---------------------------------------------------------------------------\n// State\n// ---------------------------------------------------------------------------\n\n/** Open state of the side panel. */\nexport interface PanelState {\n /** Whether the side panel is open. */\n open: boolean\n /** Active tab id; `null` when nothing has been chosen yet (hosts pick the first tab). */\n activeId: string | null\n /** Monotonic counter bumped on every user pick; gates proactive opens. */\n userPicks: number\n /** `userPicks` value at the last proactive open that was honoured. */\n proactiveAt: number\n}\n\n/** Panel state at startup: closed, no active tab, no user picks. */\nexport const INITIAL_PANEL_STATE: PanelState = { open: false, activeId: null, userPicks: 0, proactiveAt: 0 }\n\n/**\n * Add a tab to the host's pinned strip (idempotent, keeps order).\n *\n * @param pinned - The host's pinned tab ids in order.\n * @param id - Id of the tab to pin.\n */\nexport function pinTab(pinned: readonly string[], id: string): readonly string[] {\n return pinned.includes(id) ? pinned : [...pinned, id]\n}\n\n/**\n * Apply a user reorder of the VISIBLE strip to the pinned list. `pinned` can\n * hold ids the catalog no longer shows (an extension disabled for this cwd);\n * they keep their slots, and the visible ids fill the remaining slots in the\n * new order, so re-enabling the extension brings its tab back where it was.\n * Ids in `visible` that aren't pinned are ignored. Returns `pinned` itself\n * when nothing moved.\n *\n * @param pinned - The host's pinned tab ids in order.\n * @param visible - Ids of the tabs currently shown, in their new order.\n */\nexport function reorderTabs(pinned: readonly string[], visible: readonly string[]): readonly string[] {\n const shown = new Set(visible.filter(id => pinned.includes(id)))\n const order = visible.filter(id => shown.has(id))\n let next = 0\n const out = pinned.map(id => (shown.has(id) ? order[next++]! : id))\n return out.every((id, i) => id === pinned[i]) ? pinned : out\n}\n\n/**\n * Move one visible tab `delta` slots within the visible strip (keyboard\n * reorder), clamped at the ends. Hidden pinned ids keep their slots.\n *\n * @param pinned - The host's pinned tab ids in order.\n * @param visible - Ids of the tabs currently shown, in display order.\n * @param id - Id of the tab to move.\n * @param delta - Positions to move by. Negative moves earlier. Clamped to the visible range.\n */\nexport function moveTab(\n pinned: readonly string[],\n visible: readonly string[],\n id: string,\n delta: number,\n): readonly string[] {\n const from = visible.indexOf(id)\n if (from < 0)\n return pinned\n const to = Math.max(0, Math.min(visible.length - 1, from + delta))\n if (to === from)\n return pinned\n const order = [...visible]\n order.splice(from, 1)\n order.splice(to, 0, id)\n return reorderTabs(pinned, order)\n}\n\n/**\n * The user clicked a tab (or a keybinding cycled to it). Always honoured, always opens.\n *\n * @param state - The current panel state.\n * @param id - Id of the chosen tab.\n */\nexport function pickTab(state: PanelState, id: string): PanelState {\n return { ...state, open: true, activeId: id, userPicks: state.userPicks + 1 }\n}\n\n/**\n * Opens the panel when closed and closes it when open.\n *\n * @param state - The current panel state.\n */\nexport function togglePanel(state: PanelState): PanelState {\n return { ...state, open: !state.open }\n}\n\n/**\n * Closes the panel and keeps the active tab.\n *\n * @param state - The current panel state.\n */\nexport function closePanel(state: PanelState): PanelState {\n return { ...state, open: false }\n}\n\n/**\n * Agent / extension asked to show a tab. Honoured only until the user has\n * picked a tab themselves (a badge that flipped must never steal the tab);\n * otherwise the request is dropped and the state returned unchanged.\n *\n * @param state - The current panel state.\n * @param id - Id of the tab to show.\n */\nexport function openProactive(state: PanelState, id: string): PanelState {\n if (state.userPicks !== state.proactiveAt)\n return state\n return { ...state, open: true, activeId: id }\n}\n\n/**\n * The agent is blocked on the user (a plan to approve, a question to\n * answer): show the tab regardless of earlier picks. Costs at most a tab\n * switch, and nothing in that tab decides implicitly. Not a user pick, so\n * it does not lock out later proactive opens.\n *\n * @param state - The current panel state.\n * @param id - Id of the tab that needs attention.\n */\nexport function openForAttention(state: PanelState, id: string): PanelState {\n if (state.open && state.activeId === id)\n return state\n return { ...state, open: true, activeId: id }\n}\n\n/**\n * Resolve the tab to render: the active one when it still exists, else the\n * first tab, else `null` (empty catalog). Keeps state stable when an\n * extension is disabled and its tab vanishes.\n *\n * @param state - The current panel state.\n * @param catalog - Tabs in display order.\n */\nexport function resolveActiveTab(state: PanelState, catalog: readonly PanelTab[]): PanelTab | null {\n if (catalog.length === 0)\n return null\n return catalog.find(t => t.id === state.activeId) ?? catalog[0]\n}\n\n/**\n * Cycle to the next / previous tab (wraps). Counts as a user pick.\n *\n * @param state - The current panel state.\n * @param catalog - Tabs in display order.\n * @param direction - `1` for the next tab, `-1` for the previous.\n */\nexport function cycleTab(state: PanelState, catalog: readonly PanelTab[], direction: 1 | -1): PanelState {\n if (catalog.length === 0)\n return state\n const current = resolveActiveTab(state, catalog)\n const idx = current ? catalog.findIndex(t => t.id === current.id) : 0\n const next = catalog[(idx + direction + catalog.length) % catalog.length]\n return pickTab(state, next.id)\n}\n","/**\n * Display form of a stored prompt. Prompts sent before the composer kept one\n * newline per line break carry a markdown paragraph gap after every line\n * (`a\\n\\nb`, and `a\\n\\n\\n\\nb` for one blank line): shown as plain text, that\n * spread a short message over a whole screen. Runs of three or more newlines\n * collapse to one blank line; chip spans are remapped onto the result.\n */\nimport type { PromptSegmentRef } from './prompt-segments'\n\n/**\n * Collapses runs of three or more newlines to one blank line, trims trailing whitespace and remaps the chip spans.\n *\n * @param text - Stored prompt text.\n * @param refs - Chip spans over `text`.\n */\nexport function tidyPromptText(\n text: string,\n refs: readonly PromptSegmentRef[],\n): { text: string, refs: PromptSegmentRef[] } {\n const trimmed = text.trimEnd()\n if (!/\\n{3,}/.test(trimmed))\n return { text: trimmed, refs: refs.filter(r => r.end <= trimmed.length) }\n // map[i] = index in the output of input index i (and map[len] = output length).\n const map: number[] = Array.from({ length: trimmed.length + 1 })\n let out = ''\n for (let i = 0; i < trimmed.length;) {\n const run = /^\\n{3,}/.exec(trimmed.slice(i, i + 64))\n if (run && trimmed[i] === '\\n') {\n let end = i\n while (trimmed[end] === '\\n') end++\n for (let k = i; k < end; k++) map[k] = out.length + Math.min(k - i, 2)\n out += '\\n\\n'\n i = end\n continue\n }\n map[i] = out.length\n out += trimmed[i]\n i++\n }\n map[trimmed.length] = out.length\n const remapped = refs\n .filter(r => r.end <= trimmed.length)\n .map(r => ({ ...r, start: map[r.start]!, end: map[r.end]! }))\n return { text: out, refs: remapped }\n}\n","/**\n * A run that ended early (failed, or stopped by the user) reads as ONE quiet\n * line in a transcript, never as a `[✗ …]` / `[⏹ …]` reply. The loop persists\n * those markers in the assistant turn for the model; this pass splits them off\n * the reply, merges them with the run-ending error (live from `run:end`, on\n * replay from the run record) and lets one item speak for the stop.\n *\n * The one classifier both surfaces use: the TUI over stream events\n * (`src/tui/run-stops.ts` tags them), the GUI over transcript rows\n * (`ui/src/chat/headless/transcript/run-failures.ts` mints rows with a\n * `failure`). Each supplies only how to copy and mark its items.\n */\nimport { mayHaveStreamFailure, splitStreamFailure } from './stream-failure'\n\n/** How a run ended early and how to pick it back up. */\nexport interface RunStop {\n /** `aborted` when the user stopped the run, `error` when it failed. */\n cause: 'error' | 'aborted'\n /** `continue` when the run had done work, `retry` (resend `prompt`) when not. */\n resume: 'continue' | 'retry'\n /** The prompt to resend, set only with `resume: 'retry'`. */\n prompt?: string\n}\n\n/** What the classifier reads off an item: stream events and the GUI's rows both carry it. */\nexport interface RunStopItem {\n /** The item's kind (`markdown`, `error`, `user-prompt`, `tool`, …). */\n kind: string\n /** Its text: a reply's markdown, an error's message, a prompt. */\n text?: string\n /** A reply still streaming: its marker, if any, is not final yet. */\n streaming?: boolean\n /** The worker session that produced it; absent on the main session. */\n childId?: string\n /** Worker nesting depth; `0` or absent on the main session. */\n depth?: number\n /** The tool an error belongs to: not the run's own error. */\n tool?: string\n /** The call an error belongs to: not the run's own error. */\n callId?: string\n /** Set when the item is a notice; `label` names its source (`run`, `repeat guard`, …). */\n notice?: { label?: string }\n}\n\n/** How one surface copies and marks its items. */\nexport interface RunStopAdapter<T extends RunStopItem> {\n /** The item already speaks for a stop (an earlier pass's output fed back in). */\n isMarked: (item: T) => boolean\n /** The reply with its marker split off. */\n withText: (reply: T, text: string) => T\n /** The stop line a marker becomes when no run error closes the exchange. */\n mint: (reply: T, text: string, stop: RunStop) => T\n /** The run's own error, now speaking for the stop with `text`. */\n mark: (error: T, text: string, stop: RunStop) => T\n}\n\nconst WORK_KINDS = new Set(['tool', 'tool-result', 'tool-batch', 'thinking', 'thinking-batch', 'user-bash', 'spawn-start', 'spawn-end', 'command-detail'])\n\n/** The run had done something: a tool call, a thought, a worker, a command's output, or a reply with words. */\nfunction isRunWork(item: RunStopItem): boolean {\n return WORK_KINDS.has(item.kind) || (item.kind === 'markdown' && (item.text ?? '').trim() !== '')\n}\n\n/** Belongs to the main session, not to a worker. */\nfunction isTopLevel(item: RunStopItem): boolean {\n return !item.childId && (item.depth ?? 0) === 0\n}\n\n/** Receipts and turn boundaries come after a run's end: the search for it looks past them. */\nfunction isSkippable(item: RunStopItem): boolean {\n return item.kind === 'run-summary' || item.kind === 'separator'\n}\n\n/**\n * Notices that end a run: older sessions persisted the run's error as a `run`\n * notice, and the repeat guard stops a run with one. Any other notice (a `/`\n * command's error, a failed auto-compaction) is not the run failing.\n */\nconst RUN_ENDING_NOTICES = new Set(['run', 'repeat guard'])\n\n/** A run's own error: not a tool's, not a `/` command's. */\nfunction isRunError(item: RunStopItem): boolean {\n return item.kind === 'error' && isTopLevel(item) && !item.tool && !item.callId\n && (!item.notice || RUN_ENDING_NOTICES.has(item.notice.label ?? ''))\n}\n\n/**\n * The run-stop pass for one surface. It returns its input itself when no run\n * stopped early, so memoised consumers stay put.\n *\n * It runs on every stream drain tick, where only the tail changes. Items are\n * immutable, so both caches key on identity: the failure scan reads each\n * reply once, and a segment whose items are unchanged hands back its previous\n * output (without that, a session with one old failed run minted fresh stop\n * items every tick, so they re-rendered on every streamed token).\n *\n * @param adapter - How the surface copies and marks its items.\n */\nexport function createRunStopMarker<T extends RunStopItem>(adapter: RunStopAdapter<T>): (items: readonly T[]) => readonly T[] {\n const failureScans = new WeakMap<T, boolean>()\n const segments = new WeakMap<T, { input: T[], output: T[] | null }>()\n\n const mayMarkStop = (item: T): boolean => {\n if (item.kind === 'error')\n return isTopLevel(item)\n if (item.kind !== 'markdown')\n return false\n let hit = failureScans.get(item)\n if (hit === undefined) {\n hit = mayHaveStreamFailure(item.text ?? '')\n failureScans.set(item, hit)\n }\n return hit\n }\n\n /** `markSegment` over `items[start, end)`, or `null` when it left the segment as is. */\n const markSegmentCached = (items: readonly T[], start: number, end: number): T[] | null => {\n const first = items[start]\n const cached = first ? segments.get(first) : undefined\n if (cached && cached.input.length === end - start) {\n let same = true\n for (let k = 1; k < cached.input.length && same; k++)\n same = cached.input[k] === items[start + k]\n if (same)\n return cached.output\n }\n const input = items.slice(start, end)\n const marked = markSegment(input, adapter)\n const output = marked === input ? null : marked\n if (first)\n segments.set(first, { input, output })\n return output\n }\n\n return (items) => {\n if (!items.some(mayMarkStop))\n return items\n const out: T[] = []\n let changed = false\n let start = 0\n // A segment is one exchange: a top-level prompt and everything up to the next one.\n for (let i = 0; i <= items.length; i++) {\n if (i < items.length && !(items[i]!.kind === 'user-prompt' && isTopLevel(items[i]!) && i > start))\n continue\n const next = markSegmentCached(items, start, i)\n if (next) {\n changed = true\n out.push(...next)\n }\n else {\n for (let k = start; k < i; k++)\n out.push(items[k]!)\n }\n start = i\n }\n return changed ? out : items\n }\n}\n\nfunction markSegment<T extends RunStopItem>(segment: T[], adapter: RunStopAdapter<T>): T[] {\n let marker: { index: number, message: string, aborted: boolean } | null = null\n const items = segment.map((item, index) => {\n if (item.kind !== 'markdown' || item.streaming || !isTopLevel(item))\n return item\n const split = splitStreamFailure(item.text ?? '')\n if (!split.failure)\n return item\n marker = { index, message: split.failure.message, aborted: split.failure.aborted }\n return adapter.withText(item, split.text)\n })\n\n // The run's own end: a run error closing the exchange (receipts and turn boundaries aside).\n let terminal = -1\n for (let i = items.length - 1; i >= 0; i--) {\n const item = items[i]!\n if (isSkippable(item))\n continue\n if (isRunError(item) && !adapter.isMarked(item))\n terminal = i\n break\n }\n const found = marker as { index: number, message: string, aborted: boolean } | null\n const prompt = items[0]?.kind === 'user-prompt' ? items[0] : null\n // Without a marker, only an error closing a prompted run is that run's end.\n if (!found && (terminal < 0 || !prompt))\n return segment\n\n const workEnd = terminal >= 0 ? terminal : found!.index + 1\n const didWork = items.slice(prompt ? 1 : 0, workEnd).some(isRunWork)\n // Live, a stop can arrive as the run's error alone (\"This operation was aborted\").\n const aborted = found ? found.aborted : /\\babort/i.test(items[terminal]!.text ?? '')\n const cause = aborted ? 'aborted' as const : 'error' as const\n const promptText = prompt?.text ?? ''\n const stop: RunStop = didWork || !prompt || promptText.trim() === ''\n ? { cause, resume: 'continue' }\n : { cause, resume: 'retry', prompt: promptText }\n\n const result: T[] = []\n items.forEach((item, index) => {\n if (index === found?.index) {\n // Nothing left of the reply: the stop line takes its place.\n if ((item.text ?? '').trim() !== '')\n result.push(item)\n if (terminal < 0)\n result.push(adapter.mint(item, aborted ? '' : found.message, stop))\n return\n }\n if (index === terminal) {\n // A stop the user asked for needs no reason. A failure reads the run's\n // typed error (the classifier's words, e.g. a rate limit's reset) over\n // the marker, which older sessions persisted with the raw provider body.\n result.push(adapter.mark(item, aborted ? '' : item.text || found?.message || '', stop))\n return\n }\n result.push(item)\n })\n return result\n}\n","/**\n * Output throughput for the live run readout (`41 tok/s`), from the turn's\n * `stream:progress` samples.\n *\n * `tokens / elapsed since the request` was wrong in two ways that produced\n * absurd rates: the count mid-stream is an estimate from the visible text,\n * then jumps to the provider's real figure right before the stream ends\n * (for Anthropic that includes hidden reasoning, often many times the\n * estimate), so the division reported that correction as throughput; and\n * the denominator included the time to first token, so early readings\n * swung. Here the rate is tokens GAINED per second over a short trailing\n * window of samples: a correction (the estimate→provider snap, or a count\n * that goes backwards) rebases the window instead of counting, readings\n * are smoothed, and anything no model can produce is dropped.\n */\n\n/** One `stream:progress` reading of a turn, as {@link stepStreamRate} takes it. */\nexport interface RateSample {\n /** Turn the sample belongs to. */\n turnId: string\n /** ms since the turn's request; only differences are used. */\n elapsedMs: number\n /** Output tokens counted so far in the turn. */\n outputTokens: number\n /** Whether `outputTokens` is an estimate rather than a provider-reported count. */\n estimated: boolean\n}\n\n/** Sliding-window state of the output rate of a streaming turn. */\nexport interface RateState {\n /** Turn being measured, or `null` before the first sample. */\n turnId: string | null\n /** Samples inside the window, oldest first; the first is the baseline. */\n samples: readonly { t: number, n: number }[]\n /** Whether the samples are estimates, or `null` before the first sample. */\n estimated: boolean | null\n /** Smoothed tokens/second, `null` until the window has enough span. */\n rate: number | null\n}\n\n/** Initial rate state, before any sample. */\nexport const EMPTY_RATE: RateState = { turnId: null, samples: [], estimated: null, rate: null }\n\n/** Trailing window the rate is measured over. */\nconst WINDOW_MS = 3000\n/** Minimum span before a reading counts: shorter spans are one or two ticks of noise. */\nconst MIN_SPAN_MS = 1200\n/** Faster than any served model today (the fastest wafer-scale ones run ~3k): a reading above is a glitch. */\nexport const MAX_PLAUSIBLE_RATE = 6000\n/** Weight of a new reading in the smoothed rate. */\nconst SMOOTHING = 0.35\n\n/**\n * Folds one output token reading into the rate state. Returns a new state, or\n * the same one for an out-of-order or duplicate sample.\n *\n * @param state - The current rate state.\n * @param sample - The newest output token reading.\n */\nexport function stepStreamRate(state: RateState, sample: RateSample): RateState {\n const point = { t: sample.elapsedMs, n: sample.outputTokens }\n if (state.turnId !== sample.turnId) {\n return { turnId: sample.turnId, samples: [point], estimated: sample.estimated, rate: null }\n }\n const last = state.samples[state.samples.length - 1]\n // A correction, not throughput: the provider's count replaced the estimate,\n // or the count went backwards. Rebase on this sample, keep the last rate.\n const corrected\n = (state.estimated === true && !sample.estimated) || (last !== undefined && point.n < last.n) || !last\n if (corrected) {\n return { ...state, samples: [point], estimated: sample.estimated }\n }\n if (point.t <= last.t)\n return state // out-of-order or duplicate tick\n\n // Keep the window, plus the newest sample older than it as the baseline.\n const kept = [...state.samples, point]\n let start = 0\n while (start < kept.length - 2 && kept[start + 1]!.t <= point.t - WINDOW_MS)\n start++\n const samples = kept.slice(start)\n\n const base = samples[0]!\n const span = point.t - base.t\n let rate = state.rate\n if (span >= MIN_SPAN_MS) {\n const reading = ((point.n - base.n) / span) * 1000\n if (reading >= 0 && reading <= MAX_PLAUSIBLE_RATE) {\n rate = rate === null ? reading : rate + SMOOTHING * (reading - rate)\n }\n }\n return { turnId: state.turnId, samples, estimated: sample.estimated, rate }\n}\n\n/**\n * Whole tokens per second for display, or `null` when there is no honest reading.\n *\n * @param state - The current rate state.\n */\nexport function streamRateValue(state: RateState): number | null {\n if (state.rate === null)\n return null\n const rounded = Math.round(state.rate)\n return rounded > 0 ? rounded : null\n}\n","/**\n * User-initiated todo-list edits — pure transforms over `TodoItem[]`.\n *\n * The todo list is normally MODEL-owned: `todowrite` passes the full array on\n * every call, so a checkpoint replaces whatever was there. These transforms let\n * the TUI's `ctrl+t` panel and the GUI todos tab edit the same list, with one consequence the UI must\n * surface rather than hide: **a user edit made during a live run is overwritten\n * by the agent's next checkpoint**. Nothing here can prevent that — it is the\n * tool's contract — so the modal warns while a run is in flight instead of\n * pretending the edit is durable.\n *\n * Kept pure and renderer-agnostic (no React, no node) so the reducers are\n * unit-testable and both the TUI and the GUI drive the same edits.\n */\n\nimport type { TodoItem, TodoStatus } from './todos'\n\n/**\n * Prefix for ids minted here, distinguishing user-authored rows from the\n * model's own ids in a session file. Purely diagnostic — nothing branches on\n * it — but it makes \"who added this\" answerable after the fact.\n */\nconst USER_TODO_ID_PREFIX = 'user-'\n\n/**\n * Mint an id that cannot collide with an existing row.\n *\n * Counter-based rather than random: a stable, readable id keeps session diffs\n * legible, and the collision check makes it safe against ids the model already\n * used (including previous `user-*` ones after a reload).\n *\n * @param items - The current todo list.\n */\nexport function nextTodoId(items: readonly TodoItem[]): string {\n const taken = new Set(items.map(i => i.id))\n for (let n = 1; ; n++) {\n const id = `${USER_TODO_ID_PREFIX}${n}`\n if (!taken.has(id))\n return id\n }\n}\n\n/**\n * Append a todo. Returns the list unchanged when `content` is blank — an empty\n * row is never what the user meant, and rejecting it here means every caller\n * (keyboard, click, GUI) gets the same guard.\n *\n * @param items - The current todo list.\n * @param content - Text of the new todo. Blank text adds nothing.\n */\nexport function addTodo(items: readonly TodoItem[], content: string): TodoItem[] {\n const trimmed = content.trim()\n if (!trimmed)\n return [...items]\n return [...items, { id: nextTodoId(items), content: trimmed, status: 'pending' }]\n}\n\n/**\n * Replace one todo's text. Blank content is rejected (see {@link addTodo}); an\n * unknown id is a no-op rather than an error, because the list can be replaced\n * by a `todowrite` between render and keypress.\n *\n * @param items - The current todo list.\n * @param id - Id of the todo to change.\n * @param content - New text. Blank text changes nothing.\n */\nexport function editTodo(items: readonly TodoItem[], id: string, content: string): TodoItem[] {\n const trimmed = content.trim()\n if (!trimmed)\n return [...items]\n return items.map(item => item.id === id ? { ...item, content: trimmed } : item)\n}\n\n/**\n * Drop one todo. Unknown id is a no-op, same rationale as {@link editTodo}.\n *\n * @param items - The current todo list.\n * @param id - Id of the todo to remove.\n */\nexport function removeTodo(items: readonly TodoItem[], id: string): TodoItem[] {\n return items.filter(item => item.id !== id)\n}\n\n/** Drop everything. Separate from `removeTodo` so the caller's intent is explicit at the call site. */\nexport function clearTodos(): TodoItem[] {\n return []\n}\n\n/**\n * Advance a todo's status one step: pending → in_progress → completed →\n * pending. `cancelled` also lands on `pending`, so a dropped item can be\n * revived without a dedicated key.\n *\n * Cycling INTO `in_progress` demotes any other in-progress row to `pending`:\n * the list's whole purpose is \"what is being worked on right now\", and two\n * live rows make that unanswerable — `todoProgressLabel`\n * reads the first one and would silently ignore the rest.\n *\n * @param items - The current todo list.\n * @param id - Id of the todo to advance. An unknown id changes nothing.\n */\nexport function cycleTodoStatus(items: readonly TodoItem[], id: string): TodoItem[] {\n const target = items.find(item => item.id === id)\n if (!target)\n return [...items]\n const next = nextStatus(target.status)\n return items.map((item) => {\n if (item.id === id)\n return { ...item, status: next }\n if (next === 'in_progress' && item.status === 'in_progress')\n return { ...item, status: 'pending' as TodoStatus }\n return item\n })\n}\n\nfunction nextStatus(status: TodoStatus): TodoStatus {\n switch (status) {\n case 'pending':\n return 'in_progress'\n case 'in_progress':\n return 'completed'\n case 'completed':\n case 'cancelled':\n default:\n return 'pending'\n }\n}\n\n/**\n * Steering text for a \"retry this todo\" request.\n *\n * Quotes the content so a model reading it can match the row verbatim against\n * its own list, and names the status because \"retry\" means different things\n * for a row it believes is `completed` versus one it abandoned as `cancelled`.\n * Shared by the TUI and GUI modals so both surfaces steer with byte-identical\n * text; pinned by a test rather than living inside a JSX callback.\n *\n * @param item - The todo to retry.\n */\nexport function buildTodoRetryMessage(item: TodoItem): string {\n return `Retry this todo (currently ${item.status}): \"${item.content}\"`\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"todo-edits-DKoxu7Ss.js","names":["str"],"sources":["../src/chat/hosts/host-index.ts","../src/chat/hosts/session-key.ts","../src/chat/attachment-rules.ts","../src/chat/auth-rows.ts","../src/chat/fold-actions.ts","../src/chat/fold-rules.ts","../src/chat/instruction-rows.ts","../src/chat/machines-view.ts","../src/chat/mcp-form.ts","../src/chat/notice-format.ts","../src/chat/palette.ts","../src/chat/panels.ts","../src/chat/prompt-text.ts","../src/chat/run-stops.ts","../src/chat/stream-rate.ts","../src/chat/todo-edits.ts"],"sourcesContent":["/**\n * Which host an id lives on: a session (or a request a host handed out: an\n * approval, a question, a terminal). A client learns it from what a host\n * tells it (its lists, a create, an activation, its signals) and routes\n * every later call on that id there.\n *\n * Never guessed: an id no host told about is an error\n * ({@link UnknownHostIdError}), one several hosts list is an error unless the\n * lookup names its host ({@link AmbiguousHostIdError}), and the ids of a host\n * that was removed stay remembered as such ({@link HostRemovedError}) until\n * a host claims them again, so nothing aimed at a removed server quietly\n * lands on another host.\n * Node-free, shared by the TUI and the GUI main process.\n */\n\n/** No host told this client about the id: nothing to route it to. */\nexport class UnknownHostIdError extends Error {\n /** Machine-readable error code. */\n readonly code = 'unknown-host-id'\n /**\n * Creates the error.\n * @param id - Id that no host reported.\n * @param noun - What the id names, used in the message.\n */\n constructor(readonly id: string, noun = 'session') {\n super(`No host is known for ${noun} \"${id}\": list or open it on its host first.`)\n this.name = 'UnknownHostIdError'\n }\n}\n\n/** The id lived on a host that was removed from this window. */\nexport class HostRemovedError extends Error {\n /** Machine-readable error code. */\n readonly code = 'host-removed'\n /**\n * Creates the error.\n * @param hostKey - Key of the removed host.\n * @param hostName - Display name of the removed host.\n */\n constructor(readonly hostKey: string, readonly hostName: string) {\n super(`${hostName} was removed.`)\n this.name = 'HostRemovedError'\n }\n}\n\n/**\n * Several hosts list the id (two hosts can hold the same session id: a\n * server sharing this machine's data dir, a copied store) and the lookup\n * did not say which: refused, never guessed.\n */\nexport class AmbiguousHostIdError extends Error {\n /** Machine-readable error code. */\n readonly code = 'ambiguous-host-id'\n /**\n * Creates the error.\n * @param id - Id that several hosts list.\n * @param hostKeys - Keys of the hosts that list it.\n * @param noun - What the id names, used in the message.\n */\n constructor(readonly id: string, readonly hostKeys: readonly string[], noun = 'session') {\n super(`${noun[0]!.toUpperCase()}${noun.slice(1)} \"${id}\" exists on several hosts (${hostKeys.join(', ')}): say which one.`)\n this.name = 'AmbiguousHostIdError'\n }\n}\n\n/**\n * Keyed by (host, id): the same id may live on several hosts. A lookup that\n * names its host (`hostKey`) gets exactly that pair; one that doesn't\n * resolves only when one host has the id.\n */\nexport interface HostIndex {\n /** `id` lives on `hostKey` (clears that pair's removed-host mark). */\n note: (id: string, hostKey: string) => void\n /** The id is gone from `hostKey` (deleted there), or from every host. */\n forget: (id: string, hostKey?: string) => void\n /** With `hostKey`: it, when `id` is known live there. Without: the one live host of `id` (`undefined` when none, or several). */\n hostOf: (id: string, hostKey?: string) => string | undefined\n /** Every live host of `id`. */\n hostsOf: (id: string) => string[]\n /**\n * The live host of `id` (with `hostKey`: that pair). Throws\n * {@link HostRemovedError}, {@link UnknownHostIdError}, or without\n * `hostKey` {@link AmbiguousHostIdError} when several hosts have it.\n */\n require: (id: string, hostKey?: string) => string\n /** The removed host `id` lived on (with `hostKey`: that one), if any. */\n removedHostOf: (id: string, hostKey?: string) => { key: string, name: string } | undefined\n /** Ids noted on `hostKey`. */\n idsOf: (hostKey: string) => string[]\n /** The host was removed: its pairs are marked so (lookups say so); returns their ids. */\n dropHost: (hostKey: string, hostName: string) => string[]\n}\n\n/**\n * Creates an empty index of which host holds each id.\n *\n * @param noun - What the ids name, used in error messages.\n */\nexport function createHostIndex(noun = 'session'): HostIndex {\n /** id → live host keys, in the order they were noted. */\n const live = new Map<string, Set<string>>()\n /** id → removed host key → its name. */\n const removed = new Map<string, Map<string, string>>()\n const liveOf = (id: string): string[] => [...(live.get(id) ?? [])]\n const removedOf = (id: string, hostKey?: string): { key: string, name: string } | undefined => {\n const marks = removed.get(id)\n if (!marks)\n return undefined\n if (hostKey !== undefined) {\n const name = marks.get(hostKey)\n return name === undefined ? undefined : { key: hostKey, name }\n }\n const first = [...marks][0]\n return first ? { key: first[0], name: first[1] } : undefined\n }\n const index: HostIndex = {\n note: (id, hostKey) => {\n let hosts = live.get(id)\n if (!hosts)\n live.set(id, hosts = new Set())\n hosts.add(hostKey)\n const marks = removed.get(id)\n marks?.delete(hostKey)\n if (marks?.size === 0)\n removed.delete(id)\n },\n forget: (id, hostKey) => {\n if (hostKey === undefined) {\n live.delete(id)\n removed.delete(id)\n return\n }\n live.get(id)?.delete(hostKey)\n if (live.get(id)?.size === 0)\n live.delete(id)\n removed.get(id)?.delete(hostKey)\n if (removed.get(id)?.size === 0)\n removed.delete(id)\n },\n hostOf: (id, hostKey) => {\n const hosts = liveOf(id)\n if (hostKey !== undefined)\n return hosts.includes(hostKey) ? hostKey : undefined\n return hosts.length === 1 ? hosts[0] : undefined\n },\n hostsOf: liveOf,\n require: (id, hostKey) => {\n const hosts = liveOf(id)\n if (hostKey !== undefined) {\n if (hosts.includes(hostKey))\n return hostKey\n const gone = removedOf(id, hostKey)\n if (gone)\n throw new HostRemovedError(gone.key, gone.name)\n throw new UnknownHostIdError(id, noun)\n }\n if (hosts.length === 1)\n return hosts[0]!\n if (hosts.length > 1)\n throw new AmbiguousHostIdError(id, hosts, noun)\n const gone = removedOf(id)\n if (gone)\n throw new HostRemovedError(gone.key, gone.name)\n throw new UnknownHostIdError(id, noun)\n },\n removedHostOf: removedOf,\n idsOf: hostKey => [...live].filter(([, hosts]) => hosts.has(hostKey)).map(([id]) => id),\n dropHost: (hostKey, hostName) => {\n const ids = index.idsOf(hostKey)\n for (const id of ids) {\n index.forget(id, hostKey)\n let marks = removed.get(id)\n if (!marks)\n removed.set(id, marks = new Map())\n marks.set(hostKey, hostName)\n }\n return ids\n },\n }\n return index\n}\n","/**\n * A session's identity across hosts: the (host, session) pair, as one\n * string every client keys rows, maps and persisted state by. Two hosts may\n * hold the same session id (a server sharing this computer's data dir, a\n * copied store), so a bare id never names a session on its own once several\n * hosts are listed.\n *\n * The host is named by its HOST KEY, the key of a client's host directory:\n * {@link LOCAL_HOST_KEY} for This computer (the in-process host or the\n * daemon), a saved server's `hostId` (for a server, hostKey === hostId),\n * or a client's own key for a host it never saves (the TUI's `--host`\n * server: `'ad-hoc'`).\n *\n * The encoding, shared by the TUI and the GUI:\n *\n * - This computer: the bare id (`abc`). Local-only users see exactly the\n * ids, and state persisted before keys existed still means the same\n * session.\n * - Any other host: `<hostKey>␟<id>` (U+001F, never in a host key).\n *\n * A local id that itself contains U+001F is written `local␟<id>`, so a key\n * always parses back to the pair it was made from. Node-free.\n */\nimport { LOCAL_HOST_KEY } from './connection'\n\n/** Character that separates the host key from the session id in a session key (U+001F). */\nexport const SESSION_KEY_SEPARATOR = '\\u001F'\n\n/** The pair a session key names. */\nexport interface SessionKeyParts {\n /** Always explicit: {@link LOCAL_HOST_KEY} for This computer. */\n hostKey: string\n /** Session id on that host. */\n sessionId: string\n}\n\n/**\n * The key of `sessionId` on `hostKey` (`null` / absent / {@link LOCAL_HOST_KEY}: a local session).\n *\n * @param hostKey - Key of the host. `null`, absent or the local host key mean This computer.\n * @param sessionId - Session id on that host.\n */\nexport function sessionKey(hostKey: string | null | undefined, sessionId: string): string {\n if (!hostKey || hostKey === LOCAL_HOST_KEY)\n return sessionId.includes(SESSION_KEY_SEPARATOR) ? `${LOCAL_HOST_KEY}${SESSION_KEY_SEPARATOR}${sessionId}` : sessionId\n if (hostKey.includes(SESSION_KEY_SEPARATOR))\n throw new Error('A host key cannot contain U+001F.')\n return `${hostKey}${SESSION_KEY_SEPARATOR}${sessionId}`\n}\n\n/**\n * The pair `key` names (a bare id: This computer's).\n *\n * @param key - Key built by {@link sessionKey}.\n */\nexport function parseSessionKey(key: string): SessionKeyParts {\n const at = key.indexOf(SESSION_KEY_SEPARATOR)\n if (at < 0)\n return { hostKey: LOCAL_HOST_KEY, sessionId: key }\n return { hostKey: key.slice(0, at), sessionId: key.slice(at + 1) }\n}\n","/**\n * What a prompt can carry as an attachment, the same in every composer: the\n * image types every provider reads, PDFs, and files whose bytes read as\n * text, each under its size cap. Anything else is refused with a reason the\n * composer puts into words.\n *\n * Pure: a browser composer reads a file's first bytes and asks\n * {@link planAttachment}; the TUI shares the caps.\n */\nimport { looksBinary } from '../tools/binary-detect'\n\n/**\n * Cap on an image's bytes. Base64 inflates ~33%, so this keeps the encoded\n * payload under Anthropic's 5 MB image ceiling while covering essentially\n * every screenshot. A composer scales a bigger image down to fit.\n */\nexport const MAX_IMAGE_ATTACHMENT_BYTES = 3.5 * 1024 * 1024\n\n/** Cap on a PDF's or a text file's bytes. */\nexport const MAX_FILE_ATTACHMENT_BYTES = 20 * 1024 * 1024\n\n/** How much of a file's start {@link planAttachment} reads to tell text from binary. */\nexport const ATTACHMENT_SNIFF_BYTES = 8192\n\n/** Image types every provider takes as they are. */\nexport const SENDABLE_IMAGE_TYPES: ReadonlySet<string> = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp'])\n\n/** Image types by extension, for files handed over untyped. */\nconst IMAGE_BY_EXTENSION: Readonly<Record<string, string>> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n avif: 'image/avif',\n bmp: 'image/bmp',\n ico: 'image/x-icon',\n svg: 'image/svg+xml',\n heic: 'image/heic',\n heif: 'image/heif',\n tif: 'image/tiff',\n tiff: 'image/tiff',\n}\n\n/** Office and iWork documents: the model reads them once exported as PDF. */\nconst EXPORT_AS_PDF: ReadonlySet<string> = new Set(['doc', 'docx', 'odt', 'pages', 'ppt', 'pptx', 'odp', 'key', 'xls', 'xlsx', 'ods', 'numbers'])\n\n/** A file a composer was handed, as {@link planAttachment} needs it. */\nexport interface AttachmentCandidate {\n /** The file's name. Its extension stands in for a missing type. */\n name: string\n /** The type the browser or the OS reported. Often empty. */\n mediaType: string\n /** Size in bytes. */\n size: number\n /** The file's first {@link ATTACHMENT_SNIFF_BYTES} bytes decoded as UTF-8, invalid bytes as U+FFFD. */\n head: string\n}\n\n/** Why a file is not attached. */\nexport type AttachmentRefusal\n = | { reason: 'empty' }\n | { reason: 'too-large', size: number, limit: number }\n /** An Office or iWork document. */\n | { reason: 'export-pdf' }\n /** An image the composer could not decode to convert it (HEIC or TIFF in Chromium). */\n | { reason: 'unreadable-image' }\n | { reason: 'unsupported' }\n\n/**\n * What to do with a file: attach its bytes as they are, typed `mediaType`;\n * decode and re-encode an image first (a format providers don't take, or\n * over {@link MAX_IMAGE_ATTACHMENT_BYTES}); or refuse it.\n */\nexport type AttachmentPlan\n = | { kind: 'image' | 'pdf' | 'text', mediaType: string }\n | { kind: 'convert-image', mediaType: string }\n | ({ kind: 'refuse' } & AttachmentRefusal)\n\n/** Declared types that already say text: kept as they are. */\nfunction isTextType(mime: string): boolean {\n return mime.startsWith('text/')\n || mime === 'application/json'\n || mime === 'application/xml'\n || mime === 'application/javascript'\n || mime === 'application/typescript'\n || mime.endsWith('+json')\n || mime.endsWith('+xml')\n}\n\nfunction extensionOf(name: string): string {\n const base = name.slice(name.lastIndexOf('/') + 1).toLowerCase()\n const dot = base.lastIndexOf('.')\n return dot > 0 ? base.slice(dot + 1) : ''\n}\n\nconst tooLarge = (size: number, limit: number): AttachmentPlan => ({ kind: 'refuse', reason: 'too-large', size, limit })\n\n/**\n * Decide how a file is attached. Images go by type (or extension); PDFs by\n * type, extension or their `%PDF-` signature; anything else is text when its\n * first bytes read as text, sent as `text/plain` unless its type already\n * names text (a `.ts` file the browser types `video/mp2t` is text).\n *\n * @param file - The file's name, reported type, size and first bytes.\n */\nexport function planAttachment(file: AttachmentCandidate): AttachmentPlan {\n if (file.size === 0)\n return { kind: 'refuse', reason: 'empty' }\n const declared = file.mediaType.split(';')[0]!.trim().toLowerCase()\n const ext = extensionOf(file.name)\n const image = declared.startsWith('image/') ? declared : IMAGE_BY_EXTENSION[ext]\n if (image) {\n return SENDABLE_IMAGE_TYPES.has(image) && file.size <= MAX_IMAGE_ATTACHMENT_BYTES\n ? { kind: 'image', mediaType: image }\n : { kind: 'convert-image', mediaType: image }\n }\n if (declared === 'application/pdf' || ext === 'pdf' || file.head.startsWith('%PDF-')) {\n return file.size > MAX_FILE_ATTACHMENT_BYTES\n ? tooLarge(file.size, MAX_FILE_ATTACHMENT_BYTES)\n : { kind: 'pdf', mediaType: 'application/pdf' }\n }\n if (EXPORT_AS_PDF.has(ext))\n return { kind: 'refuse', reason: 'export-pdf' }\n if (looksBinary(file.head))\n return { kind: 'refuse', reason: 'unsupported' }\n if (file.size > MAX_FILE_ATTACHMENT_BYTES)\n return tooLarge(file.size, MAX_FILE_ATTACHMENT_BYTES)\n return { kind: 'text', mediaType: isTextType(declared) ? declared : 'text/plain' }\n}\n","/**\n * Renderer-agnostic data model for the Authentication settings list when a\n * provider holds more than one credential source.\n *\n * Mirrors `chat/mcp-rows.ts` deliberately: a flat row list plus a single\n * integer cursor that walks both provider headers AND their nested source\n * rows, so a renderer iterates once and never needs separate \"which provider\n * am I on / which source inside it\" state.\n *\n * Lives in `chat/` rather than `tui/` for the same reason as the MCP model —\n * the flattening and cursor arithmetic are pure, and pure means they can be\n * asserted directly instead of through a rendered modal.\n *\n * A provider is only expandable when it has MORE THAN ONE source. Single-source\n * providers (the overwhelming majority) are one row with no chevron and no\n * expansion state. That keeps the list quiet for anyone who has not stacked two\n * credentials.\n */\n\nimport type { AuthMethod, ProviderAuth } from './auth'\n\n/**\n * One row in the flattened Authentication list. Two kinds:\n *\n * - `'provider'` — provider header with label, configured badge, and (when\n * expandable) the chevron. Always present.\n * - `'source'` — one credential source belonging to the provider above.\n * Present only while that provider is expanded.\n */\nexport type VisibleAuthRow\n = | { kind: 'provider', provider: ProviderAuth, expandable: boolean }\n | { kind: 'source', providerKey: string, method: AuthMethod }\n\n/**\n * Stored credentials, i.e. the ones a user can actually choose between.\n *\n * `env` is excluded: it is observed rather than stored, and is usually just the\n * mirror `applyApiKeyEnv` wrote from the stored API key, so counting it would\n * advertise a choice that does not exist.\n *\n * @param provider - The provider whose auth methods are filtered.\n */\nexport function selectableSources(provider: ProviderAuth): AuthMethod[] {\n return provider.methods.filter(m => m.source !== 'env')\n}\n\n/**\n * A provider earns a chevron only when there is a real choice to reveal.\n *\n * @param provider - The provider to test.\n */\nexport function isExpandableProvider(provider: ProviderAuth): boolean {\n return selectableSources(provider).length > 1\n}\n\n/**\n * Flatten the provider list plus the expanded set into the visible-row list.\n *\n * - `providers` — filtered / ordered provider list (post-search).\n * - `expanded` — keys of providers whose sources are open. Keys for\n * providers that are no longer expandable are ignored rather\n * than cleaned up, so stale expansion state (a credential\n * removed while the modal is open) can't desync the cursor.\n *\n * @param providers - Filtered and ordered provider list.\n * @param expanded - Keys of providers whose sources are open.\n */\nexport function buildVisibleAuthRows(\n providers: readonly ProviderAuth[],\n expanded: ReadonlySet<string>,\n): VisibleAuthRow[] {\n const out: VisibleAuthRow[] = []\n for (const provider of providers) {\n const expandable = isExpandableProvider(provider)\n out.push({ kind: 'provider', provider, expandable })\n if (!expandable || !expanded.has(provider.key))\n continue\n for (const method of selectableSources(provider))\n out.push({ kind: 'source', providerKey: provider.key, method })\n // The env slot is listed for context whenever the provider declares one,\n // present or not. It disappears from `methods` the moment a stored OAuth\n // grant wins (`applyApiKeyEnv` clears the var so the refresh path reads the\n // file), and a row that vanishes on selection reads as a bug.\n if (provider.envKey) {\n const envMethod = provider.methods.find(m => m.source === 'env')\n out.push({\n kind: 'source',\n providerKey: provider.key,\n method: envMethod ?? { source: 'env', detail: provider.envKey, active: false },\n })\n }\n }\n return out\n}\n\n/**\n * Provider key a row \"belongs to\" — its own for a provider header, the parent's\n * for a source row.\n *\n * @param row - A visible row.\n */\nexport function parentProviderKey(row: VisibleAuthRow): string {\n return row.kind === 'provider' ? row.provider.key : row.providerKey\n}\n\n/**\n * Index in `rows` of the header for the given provider key, or `-1`.\n *\n * Collapse handlers snap the cursor up to the parent BEFORE the row list\n * shrinks; without that the cursor keeps its flat index and silently lands on\n * whichever sibling row slid into that slot.\n *\n * @param rows - The visible rows.\n * @param providerKey - Key of the provider to find.\n */\nexport function indexOfProviderRow(rows: readonly VisibleAuthRow[], providerKey: string): number {\n return rows.findIndex(r => r.kind === 'provider' && r.provider.key === providerKey)\n}\n","/**\n * The words for what the agent did, shared by the GUI's compact fold and\n * the TUI's: one overview line per tool call (`Ran bun test`, `Edited\n * Timeline.tsx +12 −3`, `Read select-stops.ts`), and the settled summary\n * of a batch (`Read a file, ran a command +3`).\n *\n * An overview says WHAT happened, not the payload; the payload stays one\n * click away and in `title`.\n */\nimport type { EditPayload } from './types'\nimport { readFileInputPaths } from '../tools/read-file-targets'\nimport { computeLineDiff } from './edit-diff'\nimport { descriptionLabel } from './tool-formatters'\n\n// ---------------------------------------------------------------------------\n// Shell commands → a gist\n// ---------------------------------------------------------------------------\n\n/** Programs whose first argument is the thing they do (`git status`, `bun test`). */\nconst SUBCOMMAND_PROGRAMS = new Set([\n 'git',\n 'gh',\n 'bun',\n 'npm',\n 'pnpm',\n 'yarn',\n 'npx',\n 'bunx',\n 'cargo',\n 'go',\n 'docker',\n 'kubectl',\n 'make',\n 'uv',\n 'pip',\n 'pip3',\n 'brew',\n 'deno',\n 'node',\n 'playwright',\n 'vitest',\n 'jest',\n 'tsc',\n 'eslint',\n 'prettier',\n])\n/** Wrappers that only change how the next program runs. */\nconst WRAPPERS = new Set(['sudo', 'time', 'nice', 'nohup', 'exec', 'command', 'caffeinate'])\n/** Setup steps that carry no meaning of their own. */\nconst SETUP = new Set(['cd', 'pushd', 'popd', 'export', 'set', 'source', '.', 'unset', 'true', 'mkdir'])\n\n/** Split on `&&`, `||`, `;`, `|` and newlines outside quotes. */\nfunction splitSegments(command: string): string[] {\n const out: string[] = []\n let cur = ''\n let quote: '\"' | '\\'' | null = null\n for (let i = 0; i < command.length; i++) {\n const ch = command[i]!\n if (quote) {\n if (ch === quote)\n quote = null\n cur += ch\n continue\n }\n if (ch === '\"' || ch === '\\'') {\n quote = ch\n cur += ch\n continue\n }\n const two = command.slice(i, i + 2)\n if (two === '&&' || two === '||') {\n out.push(cur)\n cur = ''\n i++\n continue\n }\n if (ch === ';' || ch === '|' || ch === '\\n') {\n out.push(cur)\n cur = ''\n continue\n }\n cur += ch\n }\n out.push(cur)\n return out.map(s => s.trim()).filter(Boolean)\n}\n\n/** Words of a segment, quotes kept as one word (unquoted). */\nfunction words(segment: string): string[] {\n const out: string[] = []\n const re = /\"([^\"]*)\"|'([^']*)'|(\\S+)/g\n for (const m of segment.matchAll(re))\n out.push(m[1] ?? m[2] ?? m[3] ?? '')\n return out\n}\n\n/** The gist of one segment (`bun run build`, `python3`), or null for setup noise. */\nfunction segmentGist(segment: string): string | null {\n let w = words(segment)\n // Leading env assignments (`FOO=1 cmd`), then wrappers (`sudo`, `env -u X`, `timeout 30`).\n for (;;) {\n if (w.length === 0)\n return null\n const head = w[0]!\n if (/^[A-Z_]\\w*=/i.test(head)) {\n w = w.slice(1)\n }\n else if (WRAPPERS.has(head)) {\n w = w.slice(1)\n }\n else if (head === 'env') {\n w = w.slice(1)\n while (w[0] && (w[0].startsWith('-') || /^[A-Z_]\\w*=/i.test(w[0]))) {\n const flag = w[0]\n w = w.slice(1)\n if (flag === '-u' && w[0])\n w = w.slice(1)\n }\n }\n else if (head === 'timeout' && w[1] && /^\\d/.test(w[1])) {\n w = w.slice(2)\n }\n else {\n break\n }\n }\n const program = w[0]!.split('/').pop()!\n if (SETUP.has(program))\n return null\n if (!SUBCOMMAND_PROGRAMS.has(program))\n return program\n const rest = w.slice(1).filter(arg => !arg.startsWith('-'))\n let sub: string | undefined = rest[0]\n // `npx tsc`, `bunx playwright test`: the tool after the runner, and its own subcommand.\n if ((program === 'npx' || program === 'bunx') && sub) {\n const tool = sub.split('/').pop()!\n const next = rest[1]\n return SUBCOMMAND_PROGRAMS.has(tool) && next && !next.includes('/') && !next.includes('.')\n ? `${tool} ${next}`\n : tool\n }\n // `bun run build`: the script name is the subcommand's point.\n if ((sub === 'run' || sub === 'exec') && rest[1] && ['bun', 'npm', 'pnpm', 'yarn'].includes(program)) {\n return `${program} ${sub} ${rest[1]}`\n }\n // A path or file is an argument, not a subcommand (`node script.js` → `node`).\n if (sub && (sub.includes('/') || /\\.[a-z]+$/i.test(sub)))\n sub = undefined\n return sub ? `${program} ${sub}` : program\n}\n\n/**\n * `Ran <gist>` for a shell command: heredoc bodies dropped, setup steps\n * (`cd`, `export`, `set -e`) skipped, env and wrappers peeled off, program\n * plus subcommand kept. Further meaningful steps read as `+N`.\n *\n * @param command - Shell command text, possibly several steps.\n */\nexport function commandGist(command: string): { gist: string, more: number } {\n // eslint-disable-next-line regexp/no-super-linear-backtracking -- bounded by one command's text\n const withoutHeredocs = command.replace(/<<-?\\s*(['\"]?)(\\w+)\\1[\\s\\S]*?(?:\\n\\2\\b|$)/g, '')\n const gists = splitSegments(withoutHeredocs)\n .map(segmentGist)\n .filter((g): g is string => g !== null)\n if (gists.length === 0)\n return { gist: 'a command', more: 0 }\n return { gist: gists[0]!, more: gists.length - 1 }\n}\n\n// ---------------------------------------------------------------------------\n// One tool call → its overview\n// ---------------------------------------------------------------------------\n\n/** What a tool call is, independent of how a surface stores it. */\nexport interface ToolOverviewInput {\n /** Tool name, such as `shell` or `read_file`. */\n name: string\n /** Name shown to the user for the tool. */\n displayName: string\n /** The call's input arguments. */\n input?: Record<string, unknown>\n /** The formatted target (`tool-formatters`), when there is one. */\n target?: string\n /** The call's result text, once it has one. */\n result?: string | null\n /** `null` while running. */\n ok?: boolean | null\n /** Edit payload, when the call changed a file. */\n edit?: EditPayload\n}\n\n/** One-line description of a tool call, built by {@link toolOverview}. */\nexport interface ToolOverview {\n /** What the call did, such as `Ran bun test`. */\n label: string\n /** Quiet context after the label: a file's directory, `+2` chained commands. */\n hint?: string\n /** Lines added, for edits. */\n added?: number\n /** Lines removed, for edits. */\n removed?: number\n /** The full payload (the whole command, the full path). */\n title?: string\n}\n\nfunction splitPath(path: string): { name: string, dir: string } {\n const clean = path.replace(/\\/+$/, '')\n const i = clean.lastIndexOf('/')\n return i < 0 ? { name: clean, dir: '' } : { name: clean.slice(i + 1), dir: clean.slice(0, i) }\n}\n\nfunction str(input: Record<string, unknown> | undefined, key: string): string | undefined {\n const v = input?.[key]\n return typeof v === 'string' && v.trim() !== '' ? v : undefined\n}\n\n/** Line counts exactly as the diff in the details shows them. */\nfunction editCounts(edit: EditPayload | undefined): { added: number, removed: number } | null {\n if (!edit)\n return null\n let added = 0\n let removed = 0\n for (const h of edit.hunks) {\n for (const d of computeLineDiff(h.oldString, h.newString)) {\n if (d.op === 'add')\n added++\n else if (d.op === 'remove')\n removed++\n }\n }\n return { added, removed }\n}\n\nfunction shortUrl(url: string): string {\n const short = url.replace(/^https?:\\/\\//, '').replace(/\\/$/, '')\n return short.length > 48 ? `${short.slice(0, 47)}…` : short\n}\n\n/**\n * The dev browser in words: where it went and what it did. Clicks and typing\n * read their result's first line (`Clicked \"Save\"`), which names the element;\n * the ref the model used (`e12`) means nothing to a person.\n */\nfunction browserOverview(tool: ToolOverviewInput): ToolOverview | null {\n const input = tool.input\n const url = str(input, 'url')\n const head = typeof tool.result === 'string' && tool.ok\n ? tool.result.split('\\n')[0]!.replace(/\\. No navigation, dialog or error\\.$|\\.$/, '')\n : ''\n switch (tool.name) {\n case 'browser_open':\n return url ? { label: `Opened ${shortUrl(url)}`, title: url } : { label: 'Opened the browser' }\n case 'browser_navigate': {\n const action = str(input, 'action')\n if (action === 'back')\n return { label: 'Went back' }\n if (action === 'forward')\n return { label: 'Went forward' }\n if (action === 'reload')\n return { label: 'Reloaded the page' }\n return url ? { label: `Went to ${shortUrl(url)}`, title: url } : { label: 'Navigated' }\n }\n case 'browser_snapshot':\n return { label: 'Read the page' }\n case 'browser_screenshot':\n return { label: 'Took a screenshot' }\n case 'browser_click':\n return { label: head.startsWith('Clicked') ? head : `Clicked ${tool.target ?? 'the page'}` }\n case 'browser_type':\n return { label: head.startsWith('Typed') ? head : 'Typed in the page' }\n case 'browser_press':\n return { label: head.startsWith('Pressed') ? head : `Pressed ${str(input, 'key') ?? 'a key'}` }\n case 'browser_scroll':\n return { label: 'Scrolled the page' }\n case 'browser_wait_for': {\n const what = str(input, 'text') ?? str(input, 'selector') ?? str(input, 'urlIncludes')\n return { label: what ? `Waited for “${what.length > 40 ? `${what.slice(0, 39)}…` : what}”` : 'Waited' }\n }\n case 'browser_evaluate': {\n const expression = str(input, 'expression') ?? ''\n return { label: 'Ran a script in the page', ...(expression ? { title: expression.slice(0, 600) } : {}) }\n }\n case 'browser_console':\n return { label: 'Read the console' }\n default:\n return null\n }\n}\n\n/**\n * The overview line for one tool call.\n *\n * @param tool - Tool call with its name, input, target, result, and edit payload.\n */\nexport function toolOverview(tool: ToolOverviewInput): ToolOverview {\n const input = tool.input\n if (tool.name.startsWith('browser_')) {\n const browser = browserOverview(tool)\n if (browser)\n return browser\n }\n switch (tool.name) {\n case 'shell':\n case 'bash': {\n const command = str(input, 'command') ?? tool.target ?? ''\n // The model's description says what the call does (\"Run the GUI\n // typecheck\"); the command is behind it (title, and the opened input).\n const description = descriptionLabel(input)\n if (description)\n return { label: description, title: command.slice(0, 600) }\n const { gist, more } = commandGist(command)\n return { label: `Ran ${gist}`, ...(more > 0 ? { hint: `+${more}` } : {}), title: command.slice(0, 600) }\n }\n case 'read_file': {\n const batch = str(input, 'path') ? [] : readFileInputPaths(input)\n if (batch.length > 1)\n return { label: `Read ${splitPath(batch[0]).name} +${batch.length - 1}`, title: batch.join('\\n') }\n const path = str(input, 'path') ?? batch[0] ?? tool.target ?? ''\n const { name, dir } = splitPath(path)\n return { label: `Read ${name || 'a file'}`, ...(dir ? { hint: dir } : {}), title: path }\n }\n case 'edit':\n case 'multi_edit':\n case 'write_file': {\n const path = str(input, 'path') ?? tool.edit?.path ?? tool.target ?? ''\n const { name, dir } = splitPath(path)\n const counts = editCounts(tool.edit)\n const verb = tool.name === 'write_file' ? 'Wrote' : 'Edited'\n return {\n label: `${verb} ${name || 'a file'}`,\n ...(dir ? { hint: dir } : {}),\n ...(counts && (counts.added > 0 || counts.removed > 0) ? counts : {}),\n title: path,\n }\n }\n case 'grep': {\n const pattern = str(input, 'pattern') ?? tool.target ?? ''\n const where = str(input, 'path')\n return {\n label: pattern ? `Searched for “${pattern.length > 48 ? `${pattern.slice(0, 47)}…` : pattern}”` : 'Searched',\n ...(where ? { hint: where } : {}),\n title: pattern,\n }\n }\n case 'glob': {\n const pattern = str(input, 'pattern') ?? tool.target ?? ''\n return { label: pattern ? `Found files ${pattern}` : 'Found files', title: pattern }\n }\n case 'spawn': {\n // The worker is named by what it was asked to do; the full task sits behind it.\n const task = str(input, 'task') ?? tool.target ?? ''\n const first = task.split('\\n').find(line => line.trim()) ?? ''\n return { label: 'Agent', ...(first ? { hint: first.length > 80 ? `${first.slice(0, 79)}…` : first } : {}), ...(task ? { title: task.slice(0, 600) } : {}) }\n }\n case 'present_plan': {\n const title = str(input, 'title')\n return { label: 'Presented a plan', ...(title ? { hint: title, title } : {}) }\n }\n case 'ask_user': {\n const n = Array.isArray(input?.questions) ? input.questions.length : 0\n return { label: n > 0 ? `Asked ${n} question${n === 1 ? '' : 's'}` : 'Asked a question' }\n }\n case 'todowrite': {\n const todos = Array.isArray(input?.todos) ? (input.todos as { status?: unknown }[]) : []\n const done = todos.filter(t => t.status === 'completed').length\n return { label: 'Updated todos', ...(todos.length > 0 ? { hint: `${done} of ${todos.length} done` } : {}) }\n }\n case 'list_files': {\n const path = str(input, 'path') ?? tool.target ?? '.'\n return { label: `Listed ${path}`, title: path }\n }\n default: {\n const target = tool.target\n const short = target && target.length > 60 ? `${target.slice(0, 59)}…` : target\n return { label: short ? `${tool.displayName} ${short}` : tool.displayName, ...(target ? { title: target } : {}) }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Many calls → one summary\n// ---------------------------------------------------------------------------\n\n/**\n * Verb phrase per canonical tool name for a batch summary. Unknown tools\n * derive one from their display name, so MCP and host tools read cleanly.\n */\nconst BATCH_VERB_PHRASE: Record<string, string> = {\n shell: 'ran a command',\n read_file: 'read a file',\n grep: 'searched',\n glob: 'searched for files',\n list_files: 'listed files',\n edit: 'edited a file',\n multi_edit: 'edited a file',\n write_file: 'created a file',\n spawn: 'spawned a subagent',\n tool_search: 'searched for tools',\n skills_use: 'activated a skill',\n skills_read: 'read a skill',\n skills_run_script: 'ran a skill script',\n ask_user: 'asked a question',\n present_plan: 'presented a plan',\n browser_open: 'opened the browser',\n browser_navigate: 'navigated',\n browser_snapshot: 'read the page',\n browser_screenshot: 'took a screenshot',\n browser_click: 'clicked',\n browser_type: 'typed',\n browser_press: 'pressed a key',\n browser_scroll: 'scrolled',\n browser_wait_for: 'waited',\n browser_evaluate: 'ran a script in the page',\n browser_console: 'read the console',\n terminal_list: 'listed terminals',\n terminal_read: 'read a terminal',\n terminal_write: 'typed in a terminal',\n}\n\n/**\n * Returns the lowercase verb phrase for a tool in a batch summary, such as `read a file`.\n *\n * @param name - Tool name.\n * @param displayName - Name shown to the user, used for tools without a known phrase.\n */\nexport function toolPhrase(name: string, displayName: string): string {\n return BATCH_VERB_PHRASE[name] ?? `used ${displayName.toLowerCase()}`\n}\n\n/**\n * Cap on phrases shown in a summary: a 40-call exchange reads \"Ran a\n * command, searched, read a file, edited a file +23\", where +N counts the\n * calls the shown phrases do not cover.\n */\nconst MAX_SUMMARY_PHRASES = 4\n\n/**\n * \"Ran a command, read a file +2\" for a run of calls. Adjacent identical\n * phrases merge, so three reads in a row say \"read a file\" once.\n * `overflow: false` leaves the +N off, for a header that counts its calls\n * another way.\n *\n * @param tools - Tool calls in run order.\n * @param options - Set `overflow` to `false` to leave the `+N` count off. Defaults to showing it.\n */\nexport function summarizeTools(tools: ReadonlyArray<{ name: string, displayName: string }>, options: { overflow?: boolean } = {}): string {\n const phrases: Array<{ phrase: string, calls: number }> = []\n for (const t of tools) {\n const phrase = toolPhrase(t.name, t.displayName)\n const last = phrases[phrases.length - 1]\n if (last && last.phrase === phrase)\n last.calls += 1\n else\n phrases.push({ phrase, calls: 1 })\n }\n if (phrases.length === 0)\n return 'Ran tools'\n const shown = phrases.slice(0, MAX_SUMMARY_PHRASES)\n const shownCalls = shown.reduce((n, p) => n + p.calls, 0)\n const rest = tools.length - shownCalls\n const joined = shown.map(p => p.phrase).join(', ')\n const capped = rest > 0 && options.overflow !== false ? `${joined} +${rest}` : joined\n return capped.charAt(0).toUpperCase() + capped.slice(1)\n}\n\n/**\n * A message as a person skims it: its words, markdown syntax and code\n * blocks dropped, whitespace folded. For the compact stacks of earlier\n * messages.\n *\n * @param text - Message text, usually markdown.\n */\nexport function messagePreview(text: string): string {\n return text\n .replace(/```[\\s\\S]*?(?:```|$)/g, ' ')\n .replace(/`([^`]*)`/g, '$1')\n .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/^\\s{0,3}(?:#{1,6}\\s+|>\\s?|[-*+]\\s+|\\d+[.)]\\s+)/gm, '')\n .replace(/(\\*\\*|__|\\*|_|~~)(\\S(?:.*?\\S)?)\\1/g, '$2')\n .replace(/\\s+/g, ' ')\n .trim()\n}\n","/**\n * Compact density's fold, one set of rules for both transcripts: what folds\n * into an exchange's one row (`foldsInCompactShape`), the steps the opened\n * fold lists and the counts its header reads (`planFold`), and the header's\n * words (`foldSummary`). The TUI maps its stream events onto these\n * (`src/tui/transcript/partition.ts`), the desktop app its rows\n * (`ui/src/chat/headless/transcript/fold.ts`, `fold-actions.ts`); each only\n * draws the steps in its own way.\n */\nimport type { StreamEvent } from './types'\nimport { summarizeTools } from './fold-actions'\nimport { describeSpawnEnd, previewLine, spawnStartParts } from './format'\nimport { spawnLaneResolver } from './spawn-tree'\n\n/** What decides whether an item folds: its kind and owner, and two facts only its surface knows. */\nexport interface FoldShape {\n /** The item's kind (`thinking`, `tool`, `info`, …). */\n kind: string\n /** Set when the item is a notice: an `info` notice stays out of the fold. */\n notice?: unknown\n /** The worker session that produced it; absent on the main session. */\n childId?: string\n /** Worker nesting depth; `0` or absent on the main session. */\n depth?: number\n /** The user's own `!` run: they ran it to see it. */\n userBash?: boolean\n /** The transcript's \"N earlier events\" marker: its top, not part of an exchange. */\n earlierMarker?: boolean\n}\n\n/**\n * Compact density: does this item fold into its exchange's one row?\n * Thinking, tool traffic, worker lifecycle, a `/` command's details and\n * everything a worker produced fold; the prompt, the assistant's prose,\n * errors, notices, the user's own `!` runs and session events stay.\n *\n * @param shape - The item's kind, owner and notice.\n */\nexport function foldsInCompactShape(shape: FoldShape): boolean {\n // Everything a worker session produced belongs to the parent's work.\n if ((shape.depth ?? 0) > 0 || shape.childId)\n return true\n switch (shape.kind) {\n case 'thinking':\n case 'thinking-batch':\n case 'spawn-start':\n case 'spawn-end':\n case 'spawn-queued':\n case 'command-detail':\n return true\n case 'tool':\n case 'tool-result':\n case 'tool-batch':\n return !shape.userBash\n case 'info':\n return shape.notice === undefined && !shape.earlierMarker\n default:\n return false\n }\n}\n\n/** A step's progress: `waiting` is a `spawn` call every worker slot is taken for. */\nexport type FoldStepState = 'waiting' | 'running' | 'ok' | 'err'\n\n/** One folded item, as the planner reads it. `item` is the surface's own object, handed back in the steps. */\nexport type FoldUnit<T> = {\n item: T\n childId?: string\n depth?: number\n /** Lifecycle metadata of a worker marker (its call, task, parent worker, structured end). */\n spawn?: StreamEvent['spawn']\n} & (\n | { kind: 'thought', live?: boolean, ms?: number }\n | {\n kind: 'call'\n name: string\n displayName: string\n callId?: string\n /** The call that made this one (a codemode script's `tools.*`). */\n parentId?: string\n state: FoldStepState\n waitingFor?: { active: number, max: number }\n /** A `spawn` call's task, to pair it with a worker whose marker names no call. */\n task?: string\n ms?: number\n }\n | { kind: 'result', callId: string, failed: boolean }\n | { kind: 'spawn-start' | 'spawn-end', text: string }\n | { kind: 'note' }\n | { kind: 'other' }\n)\n\n/** One line of an opened fold: a tool call, consecutive thoughts, a worker, or a command's note. */\nexport interface FoldStep<T> {\n /** What the line shows: a tool call, consecutive thoughts, a worker, or a command's note. */\n kind: 'tool' | 'thought' | 'worker' | 'note'\n /** Its progress; a worker's is its own end, not its call's result. */\n state: FoldStepState\n /** How many steps came before it when it started: a stable index for ids. */\n at: number\n /** Tool: the call and its results. Thought: its thinking items. Worker: every item of its lane. Note: the note. */\n items: T[]\n /** A tool step's call, or the `spawn` call that started a worker. */\n call?: T\n /** A tool step's call id. */\n callId?: string\n /** The call that made this one (a codemode script's `tools.*`). */\n parentId?: string\n /** A `waiting` spawn call: the worker slots taken and the limit. */\n waitingFor?: { active: number, max: number }\n /** A thought still streaming. */\n live?: boolean\n /** A worker's lane (its `childId`, or the worker that started it). */\n lane?: string\n /** A worker no call started: the task its marker carries. */\n task?: string\n}\n\n/** What the header reads. Worker-owned calls and thoughts count under the worker, not here. */\nexport interface FoldStats {\n /** The exchange's own calls (a script's nested calls ride their script's). */\n tools: number\n /** The exchange's own thinking items. */\n thoughts: number\n /** Distinct workers; one a worker started counts under its spawner. */\n workers: number\n /** Own calls that failed. */\n failed: number\n /** Own calls (nested ones included) with no result yet. */\n pending: number\n /** Known time of the own calls and thoughts; absent when nothing carries timing. */\n durationMs?: number\n}\n\n/** {@link planFold}'s result. */\nexport interface FoldPlan<T> {\n /** The opened fold's lines, in order. */\n steps: FoldStep<T>[]\n /** The counts the header reads. */\n stats: FoldStats\n /** The exchange's own top-level calls, in order, for {@link foldSummary}. */\n calls: Array<{ name: string, displayName: string }>\n}\n\nfunction isWorkerOwned(unit: { childId?: string, depth?: number }): boolean {\n return unit.childId !== undefined || (unit.depth ?? 0) > 0\n}\n\n/**\n * A `/` command's details line: its label, capitalised, or \"Details\".\n *\n * @param label - The command's notice label, if any.\n */\nexport function noteLabel(label: string | undefined): string {\n return label ? label.charAt(0).toUpperCase() + label.slice(1) : 'Details'\n}\n\n/**\n * A thought's line: \"Thinking\" while it streams, \"Thought\" once settled.\n *\n * @param live - Whether the thought is still streaming.\n */\nexport function thoughtLabel(live: boolean): string {\n return live ? 'Thinking' : 'Thought'\n}\n\n/**\n * The steps of one exchange in order, and its counts. Consecutive thoughts\n * are one step; each worker is one step holding its lane's items, merged\n * with the `spawn` call that started it (the call's line opens onto the\n * worker's progress). A worker's state is its own structured end: failed\n * only when it errored (core `describeSpawnEnd`), stopped reads done.\n *\n * @param units - The exchange's folded items, oldest first.\n */\nexport function planFold<T>(units: readonly FoldUnit<T>[]): FoldPlan<T> {\n const steps: FoldStep<T>[] = []\n const stats: FoldStats = { tools: 0, thoughts: 0, workers: 0, failed: 0, pending: 0 }\n const plan: FoldPlan<T> = { steps, stats, calls: [] }\n const calls = new Map<string, FoldStep<T>>()\n // An own call's outcome is its own, even once its step became the worker it started.\n const own = new Map<FoldStep<T>, FoldStepState>()\n const workers = new Map<string, FoldStep<T>>()\n const spawnCalls: Array<{ step: FoldStep<T>, task?: string }> = []\n const open = new Set<string>()\n const laneOf = spawnLaneResolver(units)\n let ms = 0\n let timed = false\n const time = (unitMs: number | undefined) => {\n if (unitMs === undefined)\n return\n ms += unitMs\n timed = true\n }\n let thought: FoldStep<T> | null = null\n\n for (const unit of units) {\n if (isWorkerOwned(unit)) {\n thought = null\n const lane = unit.childId !== undefined ? laneOf(unit.childId) : ''\n let worker = workers.get(lane)\n if (!worker) {\n worker = claimSpawnCall(spawnCalls, unit) ?? newWorker(steps, unit, lane)\n worker.kind = 'worker'\n worker.state = 'running'\n worker.lane = lane\n worker.items = []\n delete worker.waitingFor\n workers.set(lane, worker)\n }\n worker.items.push(unit.item)\n // The worker's own end only: a nested worker's ending rides along.\n if (unit.kind === 'spawn-end' && unit.childId === lane)\n worker.state = describeSpawnEnd({ text: unit.text, spawn: unit.spawn }).failed ? 'err' : 'ok'\n continue\n }\n if (unit.kind === 'thought') {\n if (!thought) {\n thought = { kind: 'thought', state: 'ok', at: steps.length, items: [] }\n steps.push(thought)\n }\n thought.items.push(unit.item)\n if (unit.live) {\n thought.live = true\n thought.state = 'running'\n }\n stats.thoughts += 1\n time(unit.ms)\n continue\n }\n thought = null\n if (unit.kind === 'call') {\n const step: FoldStep<T> = { kind: 'tool', state: unit.state, at: steps.length, items: [unit.item], call: unit.item }\n if (unit.callId !== undefined)\n step.callId = unit.callId\n if (unit.parentId !== undefined)\n step.parentId = unit.parentId\n if (unit.waitingFor)\n step.waitingFor = unit.waitingFor\n steps.push(step)\n if (unit.callId !== undefined) {\n calls.set(unit.callId, step)\n if (unit.state === 'running' || unit.state === 'waiting')\n open.add(unit.callId)\n }\n if (unit.name === 'spawn')\n spawnCalls.push({ step, ...(unit.task !== undefined ? { task: unit.task } : {}) })\n if (unit.parentId === undefined) {\n own.set(step, unit.state)\n plan.calls.push({ name: unit.name, displayName: unit.displayName })\n time(unit.ms)\n }\n continue\n }\n if (unit.kind === 'result') {\n open.delete(unit.callId)\n const step = calls.get(unit.callId)\n if (step && own.has(step))\n own.set(step, unit.failed ? 'err' : 'ok')\n // A worker's step ends with the worker, not with its call's result.\n if (step && step.kind === 'tool') {\n step.items.push(unit.item)\n step.state = unit.failed ? 'err' : 'ok'\n }\n continue\n }\n if (unit.kind === 'note')\n steps.push({ kind: 'note', state: 'ok', at: steps.length, items: [unit.item] })\n }\n\n for (const state of own.values()) {\n stats.tools += 1\n if (state === 'err')\n stats.failed += 1\n }\n const lanes = new Set<string>()\n for (const unit of units) {\n if (unit.childId !== undefined)\n lanes.add(laneOf(unit.childId))\n }\n stats.workers = lanes.size\n stats.pending = open.size\n if (timed)\n stats.durationMs = ms\n return plan\n}\n\n/**\n * The `spawn` call a worker's first item belongs to, among the calls no\n * worker claimed yet. The start marker names its call; markers recorded\n * before that pair by task text, never with a call that ran no worker.\n */\nfunction claimSpawnCall<T>(spawnCalls: Array<{ step: FoldStep<T>, task?: string }>, unit: FoldUnit<T>): FoldStep<T> | undefined {\n const open = spawnCalls.filter(({ step }) => step.kind === 'tool')\n const callId = unit.kind === 'spawn-start' ? unit.spawn?.callId : undefined\n if (callId)\n return open.find(({ step }) => step.callId === callId)?.step\n const candidates = open.filter(({ step }) => step.state !== 'err')\n const preview = unit.kind === 'spawn-start' ? spawnStartParts({ text: unit.text, spawn: unit.spawn }).task : undefined\n const byTask = preview ? candidates.find(({ task }) => previewLine(task ?? '', 80) === preview) : undefined\n return (byTask ?? candidates[0])?.step\n}\n\nfunction newWorker<T>(steps: FoldStep<T>[], unit: FoldUnit<T>, lane: string): FoldStep<T> {\n const task = unit.spawn?.task ?? (unit.kind === 'spawn-start' || unit.kind === 'spawn-end' ? unit.text : undefined)\n const step: FoldStep<T> = { kind: 'worker', state: 'running', at: steps.length, items: [], lane, ...(task ? { task } : {}) }\n steps.push(step)\n return step\n}\n\n/**\n * A settled fold's header: its own calls in the shared words (`Read a file,\n * ran a command +2`), with the workers after them when no `spawn` call\n * already says so (`, 1 worker`: a script started it). Exchanges without\n * calls say what they did: `Delegated to a worker`, `Thought`, `Worked`.\n *\n * @param plan - The fold's plan.\n * @param options - Header options.\n * @param options.overflow - `false` leaves the `+N` off (a surface that shows the counts beside it).\n */\nexport function foldSummary(plan: Pick<FoldPlan<unknown>, 'stats' | 'calls'>, options: { overflow?: boolean } = {}): string {\n const { stats, calls } = plan\n const workers = stats.workers > 0 && !calls.some(c => c.name === 'spawn') ? `${stats.workers} worker${stats.workers === 1 ? '' : 's'}` : ''\n if (calls.length > 0)\n return [summarizeTools(calls, options), workers].filter(Boolean).join(', ')\n if (stats.workers > 0)\n return stats.workers === 1 ? 'Delegated to a worker' : `Delegated to ${stats.workers} workers`\n return stats.thoughts > 0 ? 'Thought' : 'Worked'\n}\n","/**\n * Renderer-agnostic visible-row model for the Settings → Instructions tab.\n *\n * Simpler than the MCP / extension row models next door: a segment's expanded\n * TEXT is rendered inside its own row box rather than as sibling rows, so the\n * cursor walks one slot per segment no matter how long the text is. Expanding a\n * 1500-line AGENTS.md must not turn ↓ into 1500 keypresses.\n *\n * Pure (no OpenTUI / React) so the filtering + preview clamping is\n * unit-testable.\n */\n\nimport type { ContextSegment } from './context-segments'\n\n/**\n * Upper bound on preview lines rendered for one expanded segment. Same idea as\n * the Logs tab's `LOGS_RENDER_CAP`: the scrollbox can hold arbitrary height, but pasting a\n * runaway 64KB instruction file into the layout pass is a waste of a frame.\n * File-backed segments have `$EDITOR` as the escape hatch for the remainder.\n */\nexport const INSTRUCTION_PREVIEW_LINE_CAP = 400\n\n/** One selectable row: a context segment, plus its resolved open state. */\nexport interface VisibleInstructionRow {\n /** Context segment shown in the row. */\n segment: ContextSegment\n /** Whether the row is open. */\n expanded: boolean\n}\n\n/** Options for {@link buildVisibleInstructionRows}. */\nexport interface BuildVisibleInstructionRowsOptions {\n /** Segments to list, in display order. */\n segments: readonly ContextSegment[]\n /** Segment ids the user has expanded. */\n expanded: ReadonlySet<string>\n /** True when a search query is active. */\n queryActive: boolean\n /** Whether a segment matches the query. Ignored when `queryActive` is false. */\n matchSegment: (segment: ContextSegment) => boolean\n}\n\n/**\n * Filter segments by the active query and resolve each one's expanded state.\n *\n * Deliberately does NOT auto-expand matches the way the Extensions tab does:\n * the search corpus includes each segment's full text, so a query typically\n * matches deep inside a long document — auto-expanding every hit would dump\n * thousands of lines into the viewport on a keystroke. The user expands the row\n * they care about.\n *\n * @param opts - Segments, expanded ids, and the active search state.\n */\nexport function buildVisibleInstructionRows(\n opts: BuildVisibleInstructionRowsOptions,\n): VisibleInstructionRow[] {\n const { segments, expanded, queryActive, matchSegment } = opts\n const out: VisibleInstructionRow[] = []\n for (const segment of segments) {\n if (queryActive && !matchSegment(segment))\n continue\n out.push({ segment, expanded: expanded.has(segment.id) })\n }\n return out\n}\n\n/**\n * Split a segment's text into renderable preview lines, clamped to\n * {@link INSTRUCTION_PREVIEW_LINE_CAP}.\n *\n * `hidden` is how many lines were dropped off the tail, so the view can render\n * an honest \"+N more lines\" marker instead of silently truncating. Tabs are\n * expanded to two spaces because the terminal text renderable doesn't\n * interpret `\\t`, and `\\r` is stripped so CRLF files don't leave artefacts at\n * every line end.\n *\n * @param text - Segment text to preview.\n */\nexport function instructionPreviewLines(text: string): { lines: string[], hidden: number } {\n const all = text.replace(/\\r\\n?/g, '\\n').replace(/\\t/g, ' ').split('\\n')\n // Trailing blank lines carry no information in a preview and would render as\n // dead space under the last line of a file that ends with a newline.\n while (all.length > 0 && all[all.length - 1]!.trim() === '')\n all.pop()\n if (all.length <= INSTRUCTION_PREVIEW_LINE_CAP)\n return { lines: all, hidden: 0 }\n return {\n lines: all.slice(0, INSTRUCTION_PREVIEW_LINE_CAP),\n hidden: all.length - INSTRUCTION_PREVIEW_LINE_CAP,\n }\n}\n\n/**\n * Short badge for a segment's origin — the \"where does this come from\" column.\n * `'file'` is intentionally the only one that reads like a location, since it's\n * the only origin the user can act on.\n *\n * @param segment - Segment whose `origin` is labeled.\n */\nexport function instructionOriginBadge(segment: ContextSegment): string {\n switch (segment.origin) {\n case 'file':\n return 'file'\n case 'generated':\n return 'generated'\n case 'mcp':\n return 'mcp server'\n case 'built-in':\n return 'built-in'\n }\n}\n","/**\n * What clients show about machines (`docs/MACHINES.md` § Client UI), shared\n * by the TUI and the GUI renderer (node-free, re-exported by\n * `zidane/chat/pure`): the \"waiting for <machine>…\" state of a session, a\n * machine's folders as a folder-picker listing, environment kinds grouped\n * by machine, and the words for a link's state.\n */\nimport type { MachineLinkState } from './machine-protocol'\nimport { parseMachineKind } from './machine-protocol'\n\n/** The `label` of the notices a host emits about a session's machine. */\nexport const MACHINE_NOTICE_LABEL = 'machine'\n\nconst WAITING_RE = /^waiting for (\\S+?)…/\nconst BACK_RE = /^\\S+ is back\\./\nconst GAVE_UP_RE = /^\\S+ stayed offline for /\n\n/**\n * The machine a session's run is paused on, from its notices (`waiting for\n * laptop…` until `laptop is back.` or `laptop stayed offline … run stopped`),\n * `null` when none. `online`: machines known to be back since (a\n * `machine:status` the window saw), which clear the wait at once.\n *\n * @param events - A session's events, oldest first.\n * @param online - Machine names known to be back online.\n */\nexport function machineWaiting(events: readonly { text?: string, notice?: { label?: string } }[], online: ReadonlySet<string> = new Set()): string | null {\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i]!\n if (event.notice?.label !== MACHINE_NOTICE_LABEL || typeof event.text !== 'string')\n continue\n if (BACK_RE.test(event.text) || GAVE_UP_RE.test(event.text))\n return null\n const waiting = WAITING_RE.exec(event.text)?.[1]\n if (waiting)\n return online.has(waiting) ? null : waiting\n }\n return null\n}\n\n/** A folder listing a folder picker renders (the shape of `fs.listDirs`). */\nexport interface MachineDirListing {\n /** Folders the picker may start from. */\n roots: string[]\n /** The folder being listed. */\n path: string\n /** Parent folder, or `null` when `path` is a root. */\n parent: string | null\n /** Folders under `path`. `isGitRepo` is always `false` here. */\n entries: { path: string, name: string, isGitRepo: boolean }[]\n}\n\nfunction dirname(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n const at = trimmed.lastIndexOf('/')\n return at <= 0 ? '/' : trimmed.slice(0, at)\n}\n\nfunction basename(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n return trimmed.slice(trimmed.lastIndexOf('/') + 1) || trimmed\n}\n\n/**\n * `machines.listDirs` as a folder listing: the parent stops at the root the folder is in.\n *\n * @param result - Directory names, the listed path and the allowed roots from `machines.listDirs`.\n */\nexport function machineDirListing(result: { path: string, dirs: string[], roots: string[] }): MachineDirListing {\n const { path } = result\n return {\n roots: result.roots,\n path,\n parent: result.roots.includes(path) ? null : dirname(path),\n entries: result.dirs.map(dir => ({ path: dir, name: basename(dir), isGitRepo: false })),\n }\n}\n\n/**\n * Environment kinds in picker order: this host's own first, then each\n * machine's together (`local@` before `worktree@`), machines by name.\n *\n * @param descriptors - Environment kind descriptors.\n */\nexport function orderByMachine<T extends { kind: string, machine?: { name: string } }>(descriptors: readonly T[]): T[] {\n const rank = (d: T): [number, string, number] => {\n const parsed = parseMachineKind(d.kind)\n return parsed ? [1, parsed.name, parsed.base === 'local' ? 0 : 1] : [0, '', 0]\n }\n return descriptors\n .map((d, i) => ({ d, i, r: rank(d) }))\n .sort((a, b) => a.r[0] - b.r[0] || a.r[1].localeCompare(b.r[1]) || a.r[2] - b.r[2] || a.i - b.i)\n .map(entry => entry.d)\n}\n\n/**\n * Why a machine kind can't be picked now (its machine is offline), else `undefined`.\n *\n * @param descriptor - Environment kind descriptor with its machine and the machine's status.\n */\nexport function machineBlockedReason(descriptor: { machine?: { name: string, status: 'online' | 'offline' } }): string | undefined {\n return descriptor.machine?.status === 'offline' ? `${descriptor.machine.name} is offline` : undefined\n}\n\n/**\n * A session's environment as its header shows it: `local@laptop`, `worktree@laptop ⎇ feat`, `⎇ feat`, or the kind.\n *\n * @param environment - The session environment: its kind and optional branch.\n */\nexport function environmentLabel(environment: { kind: string, branch?: string }): string {\n if (parseMachineKind(environment.kind))\n return environment.branch ? `${environment.kind} ⎇ ${environment.branch}` : environment.kind\n return environment.branch ? `⎇ ${environment.branch}` : environment.kind\n}\n\n/** Display text for each {@link MachineLinkState}. */\nexport const MACHINE_LINK_STATE_TEXT: Record<MachineLinkState, string> = {\n 'connecting': 'connecting…',\n 'connected': 'connected',\n 'reconnecting': 'reconnecting…',\n 'offline': 'offline',\n 'auth-refused': 'refused',\n 'identity': 'another server answers there',\n 'version-mismatch': 'another protocol version (upgrade one side)',\n 'refused': 'refused',\n}\n\n/**\n * \"seen 5 min ago\" for a machine's `lastSeen`.\n *\n * @param lastSeen - Epoch milliseconds the machine was last seen, or `undefined` if never.\n * @param now - Epoch milliseconds to measure from.\n */\nexport function lastSeenText(lastSeen: number | undefined, now: number): string {\n if (lastSeen === undefined)\n return 'never seen'\n const minutes = Math.max(0, Math.round((now - lastSeen) / 60_000))\n if (minutes < 1)\n return 'seen just now'\n if (minutes < 60)\n return `seen ${minutes} min ago`\n const hours = Math.round(minutes / 60)\n return hours < 48 ? `seen ${hours} h ago` : `seen ${Math.round(hours / 24)} d ago`\n}\n","/**\n * Add-MCP form model — values, validation, and the two tokenizers it depends\n * on. Renderer-agnostic and node-free.\n *\n * Lives in `chat/` because BOTH clients render this form (the TUI's\n * `settings-form-dialog`, the GUI's `McpsPanel`). Validation is the one place\n * a divergence between two copies would matter, because it decides which MCP\n * configs each surface accepts. One implementation means the same `mcps.json`\n * entry is accepted or rejected identically everywhere.\n */\nimport type { McpOAuthClientConfig, McpServerConfig } from '../types'\n\n/** Where a written MCP entry lands. */\nexport type InstallScopeChoice = 'user' | 'project'\n\n/** Transport an MCP server is reached over. */\nexport type McpTransport = 'stdio' | 'streamable-http' | 'sse'\n\n/** Every {@link McpTransport} in the order a form lists them. */\nexport const MCP_TRANSPORTS: readonly McpTransport[] = ['stdio', 'streamable-http', 'sse']\n\n/** Raw field values of the add-MCP-server form. */\nexport interface McpFormValues {\n /** Server name. Letters, digits, dots, hyphens and underscores. */\n name: string\n /** Transport the server uses. */\n transport: McpTransport\n /** stdio: full command line (first token = command, rest = args). */\n commandLine: string\n /** http/sse: server URL. */\n url: string\n /** One `KEY=VALUE` per line — stdio only. Values may contain spaces. */\n env: string\n /** One `Name: value` (or `Name=value`) per line — http/sse only. */\n headers: string\n /** Whether to write the entry to the user or the project config. */\n scope: InstallScopeChoice\n /**\n * Advanced OAuth (http/sse only): a pre-registered client for auth\n * servers without dynamic client registration. Optional so forms that\n * don't render the section keep compiling.\n */\n oauthClientId?: string\n /** Secret of the pre-registered client, when it has one. */\n oauthClientSecret?: string\n /** Raw field text; validated to an unprivileged port. */\n oauthCallbackPort?: string\n /** Space- or comma-separated OAuth scopes to request. */\n oauthScope?: string\n}\n\n/** A validated form: the config entry to write and where to write it. */\nexport interface McpFormResult {\n /** Normalized server config. */\n entry: McpServerConfig\n /** Where the entry should be written. */\n scope: InstallScopeChoice\n /**\n * Client secret from the Advanced OAuth section. Deliberately NOT in\n * `entry`: hosts keep it in the MCP credential store, out of `mcps.json`.\n */\n clientSecret?: string\n}\n\n/**\n * Validate + normalize the raw field values into a config entry.\n * Returns the first problem in row order so the dialog can surface it.\n *\n * @param values - Raw form field values.\n */\nexport function validateMcpForm(values: McpFormValues): { ok: true, result: McpFormResult } | { ok: false, error: string } {\n const name = values.name.trim()\n if (name.length === 0)\n return { ok: false, error: 'name is required' }\n if (!/^[\\w.-]+$/.test(name))\n return { ok: false, error: 'name must be alphanumerics, dots, hyphens, underscores' }\n\n if (values.transport === 'stdio') {\n const tokens = splitCommandLine(values.commandLine)\n if (tokens.length === 0)\n return { ok: false, error: 'command is required for stdio servers' }\n const env = parseKeyValueLines(values.env, { label: 'env', separators: ['='] })\n if (!env.ok)\n return { ok: false, error: env.error }\n const entry: McpServerConfig = {\n name,\n transport: 'stdio',\n command: tokens[0] as string,\n ...(tokens.length > 1 ? { args: tokens.slice(1) } : {}),\n ...(Object.keys(env.pairs).length > 0 ? { env: env.pairs } : {}),\n }\n return { ok: true, result: { entry, scope: values.scope } }\n }\n\n const url = values.url.trim()\n if (url.length === 0)\n return { ok: false, error: 'url is required for http/sse servers' }\n if (!/^https?:\\/\\//.test(url))\n return { ok: false, error: 'url must start with http:// or https://' }\n const headers = parseKeyValueLines(values.headers, { label: 'headers', separators: [':', '='] })\n if (!headers.ok)\n return { ok: false, error: headers.error }\n const oauth = validateOAuthFields(values)\n if (!oauth.ok)\n return { ok: false, error: oauth.error }\n return {\n ok: true,\n result: {\n entry: {\n name,\n transport: values.transport,\n url,\n ...(Object.keys(headers.pairs).length > 0 ? { headers: headers.pairs } : {}),\n ...(oauth.config ? { auth: 'oauth' as const, oauth: oauth.config } : {}),\n },\n scope: values.scope,\n ...(oauth.clientSecret ? { clientSecret: oauth.clientSecret } : {}),\n },\n }\n}\n\nfunction validateOAuthFields(values: McpFormValues):\n | { ok: true, config?: McpOAuthClientConfig, clientSecret?: string }\n | { ok: false, error: string } {\n const clientId = values.oauthClientId?.trim() ?? ''\n const clientSecret = values.oauthClientSecret?.trim() ?? ''\n const portText = values.oauthCallbackPort?.trim() ?? ''\n const scope = values.oauthScope?.trim().split(/[\\s,]+/).filter(Boolean).join(' ') ?? ''\n if (clientId === '') {\n if (clientSecret !== '' || portText !== '' || scope !== '')\n return { ok: false, error: 'client ID is required for advanced OAuth' }\n return { ok: true }\n }\n let callbackPort: number | undefined\n if (portText !== '') {\n callbackPort = /^\\d+$/.test(portText) ? Number(portText) : Number.NaN\n if (!Number.isInteger(callbackPort) || callbackPort < 1024 || callbackPort > 65535)\n return { ok: false, error: 'callback port must be a number from 1024 to 65535' }\n }\n return {\n ok: true,\n config: {\n clientId,\n ...(callbackPort !== undefined ? { callbackPort } : {}),\n ...(scope !== '' ? { scope } : {}),\n },\n ...(clientSecret !== '' ? { clientSecret } : {}),\n }\n}\n\n/**\n * Split a command line into tokens, honoring single/double quotes so\n * `npx -y my-server --root \"/path with spaces\"` round-trips. No escape\n * processing beyond quote grouping — this is a form field, not a shell.\n *\n * @param line - Command line text.\n */\nexport function splitCommandLine(line: string): string[] {\n const out: string[] = []\n const re = /\"([^\"]*)\"|'([^']*)'|(\\S+)/g\n for (let m = re.exec(line); m !== null; m = re.exec(line))\n out.push((m[1] ?? m[2] ?? m[3]) as string)\n return out\n}\n\n/**\n * Parse one key/value pair PER LINE. Line-based (not whitespace-split)\n * because values legitimately contain spaces — `Authorization: Bearer\n * abc123` is the canonical headers case, and env values like\n * `GREETING=hello world` are equally valid. The first separator found\n * (the separator that appears first in the line) splits.\n * The rest of the line is the value, trimmed. Blank lines skipped.\n *\n * @param raw - Field text, one pair per line.\n * @param opts - A `label` for error messages and the separators to split on.\n */\nexport function parseKeyValueLines(\n raw: string,\n opts: { label: string, separators: readonly string[] },\n): { ok: true, pairs: Record<string, string> } | { ok: false, error: string } {\n const pairs: Record<string, string> = {}\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed.length === 0)\n continue\n let splitAt = -1\n for (const sep of opts.separators) {\n const idx = trimmed.indexOf(sep)\n if (idx > 0 && (splitAt === -1 || idx < splitAt))\n splitAt = idx\n }\n if (splitAt <= 0) {\n const forms = opts.separators.map(s => `KEY${s}VALUE`).join(' or ')\n return { ok: false, error: `${opts.label} entries must be ${forms}, one per line (got \"${trimmed}\")` }\n }\n const key = trimmed.slice(0, splitAt).trim()\n const value = trimmed.slice(splitAt + 1).trim()\n if (key.length === 0)\n return { ok: false, error: `${opts.label} entry has an empty key (\"${trimmed}\")` }\n pairs[key] = value\n }\n return { ok: true, pairs }\n}\n","/**\n * Presentation constants for structured transcript notices (`StreamEvent.notice`).\n *\n * Shared by the TUI transcript and the GUI timeline so a `warn` notice reads\n * with the same glyph on both, and so the label vocabulary (`model fallback`,\n * `output limit`, `repeat guard`, …) is recognisably the same row across\n * surfaces. Pure; re-exported from `zidane/chat/pure`.\n */\nimport type { StreamEvent } from './types'\n\n/** Severity of a transcript notice. */\nexport type NoticeSeverity = NonNullable<StreamEvent['notice']>['severity']\n\n/** Leading glyph per severity. `info` is deliberately quiet: a plain `i`, single-width in every terminal. */\nexport const NOTICE_GLYPH: Readonly<Record<NoticeSeverity, string>> = {\n info: 'i',\n warn: '!',\n error: '✗',\n}\n","/**\n * Command palette: the renderer-agnostic model.\n *\n * Everything the user can do from the palette is a {@link PaletteItem}:\n * built-in key actions, `/` commands, panels, sessions, settings toggles\n * and extension actions all flow through one shape, so one search covers\n * the app. Items are JSON-safe data and `run` is addressed by id, the same\n * contract side panels use: an extension's provider executes where the\n * extension lives (TUI in-process, GUI main process) and the palette\n * paints in the host with its own components.\n *\n * This module is pure (no React, no node): ranking, grouping, recents and\n * the normaliser applied before items cross IPC. The TUI and the GUI each\n * render the result; they never re-implement the ordering.\n */\nimport type { PanelIcon } from '../extensions/panels'\nimport type { JsonValue } from '../types'\n\n/** Which app renders the palette. */\nexport type PaletteHost = 'gui' | 'tui'\n\n/** `toggle` shows a checked state; `picker` opens a nested list on run. */\nexport type PaletteItemKind = 'action' | 'toggle' | 'picker'\n\n/** An entry in the command palette. */\nexport interface PaletteItem {\n /** Stable, unique across providers: `builtin:openSettings`, `slash:compact`, `<extension>/<id>`. */\n id: string\n /** Text shown in the row. */\n title: string\n /** Secondary text shown beside the title. */\n description?: string\n /** Section header. Hosts order groups by first appearance after `Recent`. */\n group: string\n /** Extra search terms not shown in the row. */\n keywords?: readonly string[]\n /** Icon for each renderer. */\n icon?: PanelIcon\n /** How the item behaves. Treated as `action` when omitted. */\n kind?: PaletteItemKind\n /** For `toggle` items. */\n checked?: boolean\n /** Resolved chord spec (`ctrl+shift+k`); the host formats it for display. */\n keybinding?: string\n /** Reason the item cannot run right now; it stays listed, muted. */\n disabled?: string\n /**\n * Only appears once the query matches it: bulk catalogs (every file in\n * the project) stay out of the empty-query listing but are one keystroke\n * away.\n */\n searchOnly?: boolean\n /** Provider that owns `run` for this item. Stamped by the aggregator. */\n source: string\n}\n\n/** JSON-safe snapshot of the host handed to providers. Never holds functions. */\nexport interface PaletteContext {\n /** Which app is asking. */\n host: PaletteHost\n /** Working directory of the active session. */\n cwd?: string\n /** Id of the active session. */\n sessionId?: string\n /** A run is in flight on the active session. */\n busy?: boolean\n}\n\n/**\n * What a provider's `run` may hand back. `items` opens a nested picker\n * (branches, environments); the host keeps a stack so Backspace on an\n * empty query goes back one level. `prompt` sends text to the chat,\n * `insert` puts it in the composer (a `/` command that takes arguments).\n */\nexport type PaletteRunResult\n = | void\n | undefined\n | { kind: 'items', title?: string, placeholder?: string, items: readonly PaletteItem[] }\n | { kind: 'prompt', text: string }\n | { kind: 'insert', text: string }\n | { kind: 'notify', text: string, tone?: 'info' | 'warn' | 'error' }\n\n/** Source of palette items and the handler that runs them. */\nexport interface PaletteProvider {\n /** Provider id, stamped on its items as `source`. */\n id: string\n /** Items for the current context. Called on open, on `subscribe` emits, and on explicit refresh. */\n items: (ctx: PaletteContext) => readonly PaletteItem[] | Promise<readonly PaletteItem[]>\n /** Runs the item with the given id. May return a follow-up result. */\n run: (itemId: string, ctx: PaletteContext) => PaletteRunResult | Promise<PaletteRunResult>\n /** Live updates while the palette is open, same contract as panels. */\n subscribe?: (emit: () => void) => () => void\n}\n\n// ---------------------------------------------------------------------------\n// Ranking\n// ---------------------------------------------------------------------------\n\n/** A palette item with its match score. */\nexport interface RankedPaletteItem {\n /** The matched item. */\n item: PaletteItem\n /** Match score. Higher ranks first. */\n score: number\n /** Indices into `item.title` to highlight. Empty when the match came from elsewhere. */\n titleMatches: readonly number[]\n}\n\n/** Group name the hosts use for the most-recently-used rows shown on an empty query. */\nexport const PALETTE_RECENT_GROUP = 'Recent'\n/** Maximum number of recent item ids kept. */\nexport const PALETTE_RECENTS_MAX = 12\n/** Ranked rows returned for a query; the host virtualises anyway, this bounds the work. */\nexport const PALETTE_RESULT_MAX = 200\n\nconst WORD_BREAKS = new Set([' ', '/', '-', '_', ':', '.'])\n\n/** What a hit at `at` is worth: the very start, a word start, a camelCase hump, or anywhere. */\nfunction startBonus(text: string, lower: string, at: number): number {\n if (at === 0)\n return 8\n if (WORD_BREAKS.has(lower[at - 1]!))\n return 6\n if (text[at] !== lower[at] && text[at - 1] === lower[at - 1])\n return 4\n return 1\n}\n\n/** Bonus per character for a term found whole: \"set\" in \"settings\" beats s, e and t spread across words. */\nconst WHOLE_TERM_BONUS = 2\n\n/**\n * Subsequence match of `query` in `text` with the usual bonuses: word\n * starts and the very beginning score higher, gaps cost, runs of adjacent\n * hits are rewarded, and the query found whole (as one run) beats the same\n * letters scattered. Returns null when not every query character appears\n * in order. Case-insensitive; `query` must already be lower-cased.\n *\n * @param text - Text to search in.\n * @param query - Lower-cased query to look for.\n */\nexport function fuzzyMatch(text: string, query: string): { score: number, indices: number[] } | null {\n return matchLowered(text, text.toLowerCase(), query)\n}\n\nconst NO_INDICES: number[] = []\n\n/** `indices` null: the score alone (a fallback field never highlights), without the allocations. */\nfunction matchLowered(\n text: string,\n lower: string,\n query: string,\n indices: number[] | null = [],\n): { score: number, indices: number[], whole: boolean } | null {\n if (query.length === 0)\n return { score: 0, indices: [], whole: true }\n // Scattered: each character at its first place after the previous one.\n let score = 0\n let from = 0\n let prev = -2\n for (let q = 0; q < query.length; q++) {\n const at = lower.indexOf(query[q]!, from)\n if (at === -1)\n return null\n score += startBonus(text, lower, at)\n if (at === prev + 1)\n score += 3\n else if (prev >= 0)\n score -= Math.min(3, at - prev - 1) * 0.5\n indices?.push(at)\n prev = at\n from = at + 1\n }\n // Whole: the best place the query appears as one run, if it does.\n let whole = -Infinity\n let wholeAt = -1\n for (let at = lower.indexOf(query); at !== -1; at = lower.indexOf(query, at + 1)) {\n const value = startBonus(text, lower, at) + (query.length - 1) * 4 + query.length * WHOLE_TERM_BONUS\n if (value > whole) {\n whole = value\n wholeAt = at\n }\n // A word start is the best a later place could do (the very start only comes first).\n if (at === 0 || WORD_BREAKS.has(lower[at - 1]!))\n break\n }\n const found = whole > score\n if (found) {\n score = whole\n if (indices) {\n for (let q = 0; q < query.length; q++) indices[q] = wholeAt + q\n }\n }\n // Shorter targets win ties: \"Open settings\" over \"Open settings: keybindings\".\n score -= text.length * 0.02\n return { score, indices: indices ?? NO_INDICES, whole: found }\n}\n\n/** An item's searchable text, lower-cased once per item instead of once per key. */\ninterface Haystack {\n title: string\n fields: readonly (readonly [text: string, lower: string])[]\n}\n\nconst haystacks = new WeakMap<PaletteItem, Haystack>()\n\nfunction haystackOf(item: PaletteItem): Haystack {\n let h = haystacks.get(item)\n if (!h) {\n const texts = [item.title, item.description, item.group, ...(item.keywords ?? [])].filter(\n (t): t is string => !!t,\n )\n h = { title: item.title.toLowerCase(), fields: texts.map(t => [t, t.toLowerCase()] as const) }\n haystacks.set(item, h)\n }\n return h\n}\n\n/**\n * Every whitespace-separated term must match (AND); scores add. `whole`:\n * each term was found as one run (the words typed, not letters picked\n * across the text). `indices` collects the merged highlight when given;\n * ranking scores without it and highlights only the rows it keeps.\n */\nfunction matchTerms(\n text: string,\n lower: string,\n terms: readonly string[],\n indices: number[] | null,\n): { score: number, whole: boolean } | null {\n let score = 0\n let whole = true\n for (const term of terms) {\n const m = matchLowered(text, lower, term, indices && [])\n if (!m)\n return null\n score += m.score\n whole &&= m.whole\n indices?.push(...m.indices)\n }\n return { score, whole }\n}\n\nfunction titleIndices(item: PaletteItem, terms: readonly string[]): number[] {\n const indices: number[] = []\n matchTerms(item.title, haystackOf(item).title, terms, indices)\n return terms.length === 1 ? indices : [...new Set(indices)].sort((a, b) => a - b)\n}\n\nconst collator = new Intl.Collator()\n\nfunction termsOf(query: string): string[] {\n return query.trim().toLowerCase().split(/\\s+/).filter(Boolean)\n}\n\n/** On an empty query: recents first (most recent on top), then the catalog in provider order. */\nfunction listUnfiltered(items: readonly PaletteItem[], recents: readonly string[]): RankedPaletteItem[] {\n const recentRank = new Map(recents.map((id, i) => [id, i]))\n const out: RankedPaletteItem[] = []\n for (const item of items) {\n const r = recentRank.get(item.id)\n // Search-only items surface on an empty query only as recents.\n if (item.searchOnly && r === undefined)\n continue\n out.push({ item, score: r === undefined ? 0 : PALETTE_RECENTS_MAX - r, titleMatches: [] })\n }\n // Stable: recents by recency, everything else keeps provider order.\n return out.sort((a, b) => b.score - a.score).slice(0, PALETTE_RESULT_MAX)\n}\n\n/** The ranked rows for `terms`, and every item that matched (the pool a longer query searches). */\nfunction rankTerms(\n items: readonly PaletteItem[],\n terms: readonly string[],\n): { ranked: RankedPaletteItem[], matched: PaletteItem[] } {\n const hits: { item: PaletteItem, score: number, inTitle: boolean }[] = []\n for (const item of items) {\n const hay = haystackOf(item)\n // The words typed, found in the title, come first; letters picked across a\n // title compete with what the description and keywords found.\n const title = matchTerms(item.title, hay.title, terms, null)\n if (title?.whole) {\n hits.push({ item, score: 100 + title.score, inTitle: true })\n continue\n }\n // Fallback: every term must land somewhere across title, description, keywords, group.\n let total = 0\n let ok = true\n for (const term of terms) {\n let best = -Infinity\n for (const [text, lower] of hay.fields) {\n const m = matchLowered(text, lower, term, null)\n if (m && m.score > best)\n best = m.score\n }\n if (best === -Infinity) {\n ok = false\n break\n }\n total += best\n }\n if (title && title.score >= total)\n hits.push({ item, score: title.score, inTitle: true })\n else if (ok)\n hits.push({ item, score: total, inTitle: false })\n }\n const matched = hits.map(h => h.item)\n hits.sort((a, b) => b.score - a.score || collator.compare(a.item.title, b.item.title))\n const ranked = hits.slice(0, PALETTE_RESULT_MAX).map(({ item, score, inTitle }) => ({\n item,\n score,\n titleMatches: inTitle ? titleIndices(item, terms) : [],\n }))\n return { ranked, matched }\n}\n\n/**\n * Rank every item against `query`. Terms are AND-ed: `tog sid` needs both\n * `tog` and `sid` somewhere in the text, each with its letters in order. A\n * title that holds every term as one run gets a large bonus;\n * description, keywords and group are fallbacks. On an empty query recents\n * come first (most recent on top), then the catalog in provider order.\n * Returns at most 200 rows.\n *\n * @param items - Items to rank.\n * @param query - Space-separated search terms.\n * @param recents - Most-recent-first item ids, shown first on an empty query.\n * @example\n * ```ts\n * import { rankPaletteItems } from 'zidane/chat/pure'\n *\n * const ranked = rankPaletteItems(\n * [{ id: 'builtin:openSettings', title: 'Open settings', group: 'App', source: 'builtin' }],\n * 'set',\n * )\n * ranked[0]?.item.id // 'builtin:openSettings'\n * ```\n */\nexport function rankPaletteItems(\n items: readonly PaletteItem[],\n query: string,\n recents: readonly string[] = [],\n): RankedPaletteItem[] {\n const terms = termsOf(query)\n return terms.length === 0 ? listUnfiltered(items, recents) : rankTerms(items, terms).ranked\n}\n\n/** `next` asks for at least what `prev` did: each earlier term grew or stayed, new ones came after. */\nfunction narrows(prev: readonly string[], next: readonly string[]): boolean {\n return next.length >= prev.length && prev.every((term, i) => next[i]!.startsWith(term))\n}\n\n/**\n * `rankPaletteItems` for a palette being typed into: it remembers the last\n * query, and when the next one only adds to it (one more character, one\n * more word) it searches just what matched before. A longer query never\n * matches an item the shorter one missed, so the result is the same.\n */\nexport function createPaletteRanker(): typeof rankPaletteItems {\n let last: { items: readonly PaletteItem[], terms: readonly string[], matched: PaletteItem[] } | null = null\n return (items, query, recents = []) => {\n const terms = termsOf(query)\n if (terms.length === 0) {\n last = null\n return listUnfiltered(items, recents)\n }\n const pool = last && last.items === items && narrows(last.terms, terms) ? last.matched : items\n const { ranked, matched } = rankTerms(pool, terms)\n last = { items, terms, matched }\n return ranked\n }\n}\n\n/** A titled section of ranked palette rows. */\nexport interface PaletteGroup {\n /** Section header. */\n title: string\n /** Rows in the section, in display order. */\n rows: readonly RankedPaletteItem[]\n}\n\n/**\n * Sections for display. With a query the ranking already interleaves\n * providers, so groups follow the order of their best row. Without a\n * query the recents (ids in `recents`, present in `ranked`) form a\n * leading `Recent` section and the rest keeps provider order.\n *\n * @param ranked - Rows from {@link rankPaletteItems}.\n * @param query - The query the rows were ranked for. A non-blank query disables the `Recent` section.\n * @param recents - Most-recent-first item ids.\n */\nexport function groupPaletteRows(\n ranked: readonly RankedPaletteItem[],\n query: string,\n recents: readonly string[] = [],\n): PaletteGroup[] {\n const groups = new Map<string, RankedPaletteItem[]>()\n const push = (title: string, row: RankedPaletteItem) => {\n const list = groups.get(title)\n if (list)\n list.push(row)\n else groups.set(title, [row])\n }\n const isRecent = new Set(query.trim() ? [] : recents)\n for (const row of ranked)\n push(isRecent.has(row.item.id) ? PALETTE_RECENT_GROUP : row.item.group, row)\n return [...groups.entries()].map(([title, rows]) => ({ title, rows }))\n}\n\n/**\n * Most-recent-first list of ids, deduplicated and capped.\n *\n * @param recents - Current most-recent-first ids.\n * @param id - Id to move to the front.\n */\nexport function pushPaletteRecent(recents: readonly string[], id: string): string[] {\n return [id, ...recents.filter(r => r !== id)].slice(0, PALETTE_RECENTS_MAX)\n}\n\n// ---------------------------------------------------------------------------\n// Normalisation (before items cross IPC or reach a renderer)\n// ---------------------------------------------------------------------------\n\n/** Caps applied by {@link normalizePaletteItems}: item count, text length and keyword count. */\nexport const PALETTE_LIMITS = {\n items: 500,\n textChars: 500,\n keywords: 16,\n} as const\n\nfunction str(v: unknown, max: number = PALETTE_LIMITS.textChars): string | undefined {\n return typeof v === 'string' && v.length > 0 ? (v.length > max ? `${v.slice(0, max - 1)}…` : v) : undefined\n}\n\n/**\n * Coerce whatever a provider returned into well-formed items: entries\n * without an id or title are dropped, strings are capped, unknown kinds\n * fall back to `action`, and `source` is stamped with the provider id.\n * Never throws.\n *\n * @param input - Value a provider returned.\n * @param source - Provider id stamped on each item.\n * @param defaultGroup - Group for items that name none.\n */\nexport function normalizePaletteItems(input: unknown, source: string, defaultGroup: string): PaletteItem[] {\n if (!Array.isArray(input))\n return []\n const out: PaletteItem[] = []\n const seen = new Set<string>()\n for (const raw of input.slice(0, PALETTE_LIMITS.items)) {\n if (!raw || typeof raw !== 'object')\n continue\n const r = raw as Record<string, unknown>\n const id = str(r.id, 200)\n const title = str(r.title, 200)\n if (!id || !title || seen.has(id))\n continue\n seen.add(id)\n const item: PaletteItem = { id, title, group: str(r.group, 80) ?? defaultGroup, source }\n const description = str(r.description)\n if (description)\n item.description = description\n if (Array.isArray(r.keywords)) {\n const kw = r.keywords.filter((k): k is string => typeof k === 'string' && k.length > 0).slice(0, PALETTE_LIMITS.keywords)\n if (kw.length > 0)\n item.keywords = kw.map(k => k.slice(0, 60))\n }\n if (r.icon && typeof r.icon === 'object') {\n const icon = r.icon as Record<string, unknown>\n const gui = str(icon.gui, 120)\n const tui = str(icon.tui, 8)\n if (gui || tui)\n item.icon = { ...(gui ? { gui } : {}), ...(tui ? { tui } : {}) }\n }\n if (r.kind === 'toggle' || r.kind === 'picker')\n item.kind = r.kind\n if (typeof r.checked === 'boolean')\n item.checked = r.checked\n const keybinding = str(r.keybinding, 60)\n if (keybinding)\n item.keybinding = keybinding\n const disabled = str(r.disabled, 200)\n if (disabled)\n item.disabled = disabled\n if (r.searchOnly === true)\n item.searchOnly = true\n out.push(item)\n }\n return out\n}\n\n/**\n * Same guard for a `run` result: anything malformed becomes `undefined` (nothing to do).\n *\n * @param input - Value a provider's `run` returned.\n * @param source - Provider id stamped on nested items.\n * @param defaultGroup - Group for nested items that name none.\n */\nexport function normalizePaletteRunResult(input: unknown, source: string, defaultGroup: string): PaletteRunResult {\n if (!input || typeof input !== 'object')\n return undefined\n const r = input as Record<string, unknown>\n switch (r.kind) {\n case 'items': {\n const out: Extract<PaletteRunResult, { kind: 'items' }> = {\n kind: 'items',\n items: normalizePaletteItems(r.items, source, defaultGroup),\n }\n const title = str(r.title, 200)\n const placeholder = str(r.placeholder, 200)\n if (title)\n out.title = title\n if (placeholder)\n out.placeholder = placeholder\n return out\n }\n case 'prompt':\n case 'insert': {\n const text = str(r.text, 20_000)\n return text ? { kind: r.kind, text } : undefined\n }\n case 'notify': {\n const text = str(r.text, 1000)\n if (!text)\n return undefined\n const tone = r.tone === 'warn' || r.tone === 'error' ? r.tone : 'info'\n return { kind: 'notify', text, tone }\n }\n default:\n return undefined\n }\n}\n\n/**\n * Type guard hosts use before forwarding a payload from an untrusted provider.\n *\n * @param v - Value to test.\n */\nexport function isPaletteContext(v: unknown): v is PaletteContext {\n if (!v || typeof v !== 'object')\n return false\n const c = v as Record<string, JsonValue | undefined>\n return (c.host === 'gui' || c.host === 'tui')\n && (c.cwd === undefined || typeof c.cwd === 'string')\n && (c.sessionId === undefined || typeof c.sessionId === 'string')\n && (c.busy === undefined || typeof c.busy === 'boolean')\n}\n","/**\n * Side-panel catalog and open state. Renderer-agnostic: the TUI rail and\n * the GUI side panel both read the same catalog (built-ins first, then\n * extension panels in load order) and drive the same state machine.\n *\n * The one behavioural rule worth spelling out: `openProactive`. Agent- or\n * extension-driven opens (a PR was created, a badge flipped) must never\n * yank the panel away from a tab the user chose. So a proactive request\n * is honoured only while the user has not picked a tab since the previous\n * proactive open; the moment they click a tab, proactive opens are ignored\n * until the next user pick resets the gate.\n */\nimport type { ExtensionPanelEntry, PanelIcon } from '../extensions/panels'\nimport { panelShowsIn } from '../extensions/panels'\n\n/** Id of the inbox panel. */\nexport const INBOX_PANEL_ID = 'inbox'\n/** Id of the todos panel. */\nexport const TODOS_PANEL_ID = 'todos'\n/** Id of the queue panel: messages sent during a run, waiting for it to end (the desktop app only). */\nexport const QUEUE_PANEL_ID = 'queue'\n/** Id of the artifacts panel. */\nexport const ARTIFACTS_PANEL_ID = 'artifacts'\n/** Id of the diffs panel. */\nexport const DIFFS_PANEL_ID = 'diffs'\n/** Id of the files panel. */\nexport const FILES_PANEL_ID = 'files'\n/** Id of the browser panel. */\nexport const BROWSER_PANEL_ID = 'browser'\n/** Id of the terminal panel. */\nexport const TERMINAL_PANEL_ID = 'terminal'\n/** A `/side` chat about the session (the desktop app only). */\nexport const SIDE_PANEL_ID = 'side'\n\n/** Built-in tabs the hosts render with their own components. */\nexport type BuiltinPanelId\n = | typeof INBOX_PANEL_ID\n | typeof TODOS_PANEL_ID\n | typeof QUEUE_PANEL_ID\n | typeof ARTIFACTS_PANEL_ID\n | typeof DIFFS_PANEL_ID\n | typeof FILES_PANEL_ID\n | typeof BROWSER_PANEL_ID\n | typeof TERMINAL_PANEL_ID\n | typeof SIDE_PANEL_ID\n\n/** A tab for a panel the host renders itself. */\nexport interface BuiltinPanelTab {\n /** Built-in panel id. */\n id: BuiltinPanelId\n /** Tab label. */\n label: string\n /** Icon for each renderer. */\n icon: PanelIcon\n /** Discriminant that marks a built-in tab. */\n builtin: true\n}\n\n/** A tab for a panel an extension registered. */\nexport interface ExtensionPanelTab {\n /** Panel id. */\n id: string\n /** Tab label. */\n label: string\n /** Icon for each renderer, when the extension set one. */\n icon?: PanelIcon\n /** Discriminant that marks an extension tab. */\n builtin: false\n /** Name of the extension that registered the panel. */\n owner: string\n}\n\n/** A built-in or extension panel tab. */\nexport type PanelTab = BuiltinPanelTab | ExtensionPanelTab\n\n/** Built-in panel tabs in display order. */\nexport const BUILTIN_PANEL_TABS: readonly BuiltinPanelTab[] = [\n // Agent-facing surfaces first: what is waiting on the user, then the plan.\n { id: INBOX_PANEL_ID, label: 'Inbox', icon: { gui: 'i-ph-tray', tui: '✉' }, builtin: true },\n { id: TODOS_PANEL_ID, label: 'Todos', icon: { gui: 'i-ph-list-checks', tui: '▣' }, builtin: true },\n { id: QUEUE_PANEL_ID, label: 'Queue', icon: { gui: 'i-ph-queue', tui: '❯' }, builtin: true },\n { id: ARTIFACTS_PANEL_ID, label: 'Artifacts', icon: { gui: 'i-ph-cube', tui: '◆' }, builtin: true },\n { id: DIFFS_PANEL_ID, label: 'Diffs', icon: { gui: 'i-ph-git-diff', tui: '±' }, builtin: true },\n { id: FILES_PANEL_ID, label: 'Files', icon: { gui: 'i-ph-tree-structure', tui: '▤' }, builtin: true },\n { id: BROWSER_PANEL_ID, label: 'Browser', icon: { gui: 'i-ph-globe-simple', tui: '◎' }, builtin: true },\n { id: TERMINAL_PANEL_ID, label: 'Terminal', icon: { gui: 'i-ph-terminal-window', tui: '❯' }, builtin: true },\n { id: SIDE_PANEL_ID, label: 'Side', icon: { gui: 'i-ph-chats-circle', tui: '◇' }, builtin: true },\n]\n\n/** Options for {@link buildPanelCatalog}. */\nexport interface PanelCatalogOptions {\n /** Hide the artifacts tab (the user's `artifacts: false` setting). */\n showArtifacts?: boolean\n /** Built-in ids the host does not render (the TUI keeps only the artifacts tab). */\n omitBuiltins?: readonly BuiltinPanelId[]\n /**\n * No session is bound (only a folder is open): keep just the extension\n * panels that opted in (`scope: 'project' | 'both'`). Bound (the\n * default), `scope: 'project'` panels are dropped. Built-ins are not\n * filtered here; hosts drop session-only ones via `omitBuiltins`.\n */\n unbound?: boolean\n}\n\n/**\n * Built-ins first, then extension panels in registry (load) order.\n *\n * @param extensionPanels - Panels registered by extensions.\n * @param options - Catalog filters.\n */\nexport function buildPanelCatalog(\n extensionPanels: readonly Pick<ExtensionPanelEntry, 'id' | 'label' | 'icon' | 'owner' | 'scope'>[],\n options: PanelCatalogOptions = {},\n): PanelTab[] {\n const tabs: PanelTab[] = []\n for (const tab of BUILTIN_PANEL_TABS) {\n if (tab.id === ARTIFACTS_PANEL_ID && options.showArtifacts === false)\n continue\n if (options.omitBuiltins?.includes(tab.id))\n continue\n tabs.push(tab)\n }\n const seen = new Set(tabs.map(t => t.id))\n for (const p of extensionPanels) {\n if (seen.has(p.id))\n continue\n if (!panelShowsIn(p.scope, options.unbound ? 'project' : 'session'))\n continue\n seen.add(p.id)\n tabs.push({ id: p.id, label: p.label, builtin: false, owner: p.owner, ...(p.icon ? { icon: p.icon } : {}) })\n }\n return tabs\n}\n\n// ---------------------------------------------------------------------------\n// State\n// ---------------------------------------------------------------------------\n\n/** Open state of the side panel. */\nexport interface PanelState {\n /** Whether the side panel is open. */\n open: boolean\n /** Active tab id; `null` when nothing has been chosen yet (hosts pick the first tab). */\n activeId: string | null\n /** Monotonic counter bumped on every user pick; gates proactive opens. */\n userPicks: number\n /** `userPicks` value at the last proactive open that was honoured. */\n proactiveAt: number\n}\n\n/** Panel state at startup: closed, no active tab, no user picks. */\nexport const INITIAL_PANEL_STATE: PanelState = { open: false, activeId: null, userPicks: 0, proactiveAt: 0 }\n\n/**\n * Add a tab to the host's pinned strip (idempotent, keeps order).\n *\n * @param pinned - The host's pinned tab ids in order.\n * @param id - Id of the tab to pin.\n */\nexport function pinTab(pinned: readonly string[], id: string): readonly string[] {\n return pinned.includes(id) ? pinned : [...pinned, id]\n}\n\n/**\n * Apply a user reorder of the VISIBLE strip to the pinned list. `pinned` can\n * hold ids the catalog no longer shows (an extension disabled for this cwd);\n * they keep their slots, and the visible ids fill the remaining slots in the\n * new order, so re-enabling the extension brings its tab back where it was.\n * Ids in `visible` that aren't pinned are ignored. Returns `pinned` itself\n * when nothing moved.\n *\n * @param pinned - The host's pinned tab ids in order.\n * @param visible - Ids of the tabs currently shown, in their new order.\n */\nexport function reorderTabs(pinned: readonly string[], visible: readonly string[]): readonly string[] {\n const shown = new Set(visible.filter(id => pinned.includes(id)))\n const order = visible.filter(id => shown.has(id))\n let next = 0\n const out = pinned.map(id => (shown.has(id) ? order[next++]! : id))\n return out.every((id, i) => id === pinned[i]) ? pinned : out\n}\n\n/**\n * Move one visible tab `delta` slots within the visible strip (keyboard\n * reorder), clamped at the ends. Hidden pinned ids keep their slots.\n *\n * @param pinned - The host's pinned tab ids in order.\n * @param visible - Ids of the tabs currently shown, in display order.\n * @param id - Id of the tab to move.\n * @param delta - Positions to move by. Negative moves earlier. Clamped to the visible range.\n */\nexport function moveTab(\n pinned: readonly string[],\n visible: readonly string[],\n id: string,\n delta: number,\n): readonly string[] {\n const from = visible.indexOf(id)\n if (from < 0)\n return pinned\n const to = Math.max(0, Math.min(visible.length - 1, from + delta))\n if (to === from)\n return pinned\n const order = [...visible]\n order.splice(from, 1)\n order.splice(to, 0, id)\n return reorderTabs(pinned, order)\n}\n\n/**\n * The user clicked a tab (or a keybinding cycled to it). Always honoured, always opens.\n *\n * @param state - The current panel state.\n * @param id - Id of the chosen tab.\n */\nexport function pickTab(state: PanelState, id: string): PanelState {\n return { ...state, open: true, activeId: id, userPicks: state.userPicks + 1 }\n}\n\n/**\n * Opens the panel when closed and closes it when open.\n *\n * @param state - The current panel state.\n */\nexport function togglePanel(state: PanelState): PanelState {\n return { ...state, open: !state.open }\n}\n\n/**\n * Closes the panel and keeps the active tab.\n *\n * @param state - The current panel state.\n */\nexport function closePanel(state: PanelState): PanelState {\n return { ...state, open: false }\n}\n\n/**\n * Agent / extension asked to show a tab. Honoured only until the user has\n * picked a tab themselves (a badge that flipped must never steal the tab);\n * otherwise the request is dropped and the state returned unchanged.\n *\n * @param state - The current panel state.\n * @param id - Id of the tab to show.\n */\nexport function openProactive(state: PanelState, id: string): PanelState {\n if (state.userPicks !== state.proactiveAt)\n return state\n return { ...state, open: true, activeId: id }\n}\n\n/**\n * The agent is blocked on the user (a plan to approve, a question to\n * answer): show the tab regardless of earlier picks. Costs at most a tab\n * switch, and nothing in that tab decides implicitly. Not a user pick, so\n * it does not lock out later proactive opens.\n *\n * @param state - The current panel state.\n * @param id - Id of the tab that needs attention.\n */\nexport function openForAttention(state: PanelState, id: string): PanelState {\n if (state.open && state.activeId === id)\n return state\n return { ...state, open: true, activeId: id }\n}\n\n/**\n * Resolve the tab to render: the active one when it still exists, else the\n * first tab, else `null` (empty catalog). Keeps state stable when an\n * extension is disabled and its tab vanishes.\n *\n * @param state - The current panel state.\n * @param catalog - Tabs in display order.\n */\nexport function resolveActiveTab(state: PanelState, catalog: readonly PanelTab[]): PanelTab | null {\n if (catalog.length === 0)\n return null\n return catalog.find(t => t.id === state.activeId) ?? catalog[0]\n}\n\n/**\n * Cycle to the next / previous tab (wraps). Counts as a user pick.\n *\n * @param state - The current panel state.\n * @param catalog - Tabs in display order.\n * @param direction - `1` for the next tab, `-1` for the previous.\n */\nexport function cycleTab(state: PanelState, catalog: readonly PanelTab[], direction: 1 | -1): PanelState {\n if (catalog.length === 0)\n return state\n const current = resolveActiveTab(state, catalog)\n const idx = current ? catalog.findIndex(t => t.id === current.id) : 0\n const next = catalog[(idx + direction + catalog.length) % catalog.length]\n return pickTab(state, next.id)\n}\n","/**\n * Display form of a stored prompt. Prompts sent before the composer kept one\n * newline per line break carry a markdown paragraph gap after every line\n * (`a\\n\\nb`, and `a\\n\\n\\n\\nb` for one blank line): shown as plain text, that\n * spread a short message over a whole screen. Runs of three or more newlines\n * collapse to one blank line; chip spans are remapped onto the result.\n */\nimport type { PromptSegmentRef } from './prompt-segments'\n\n/**\n * Collapses runs of three or more newlines to one blank line, trims trailing whitespace and remaps the chip spans.\n *\n * @param text - Stored prompt text.\n * @param refs - Chip spans over `text`.\n */\nexport function tidyPromptText(\n text: string,\n refs: readonly PromptSegmentRef[],\n): { text: string, refs: PromptSegmentRef[] } {\n const trimmed = text.trimEnd()\n if (!/\\n{3,}/.test(trimmed))\n return { text: trimmed, refs: refs.filter(r => r.end <= trimmed.length) }\n // map[i] = index in the output of input index i (and map[len] = output length).\n const map: number[] = Array.from({ length: trimmed.length + 1 })\n let out = ''\n for (let i = 0; i < trimmed.length;) {\n const run = /^\\n{3,}/.exec(trimmed.slice(i, i + 64))\n if (run && trimmed[i] === '\\n') {\n let end = i\n while (trimmed[end] === '\\n') end++\n for (let k = i; k < end; k++) map[k] = out.length + Math.min(k - i, 2)\n out += '\\n\\n'\n i = end\n continue\n }\n map[i] = out.length\n out += trimmed[i]\n i++\n }\n map[trimmed.length] = out.length\n const remapped = refs\n .filter(r => r.end <= trimmed.length)\n .map(r => ({ ...r, start: map[r.start]!, end: map[r.end]! }))\n return { text: out, refs: remapped }\n}\n","/**\n * A run that ended early (failed, or stopped by the user) reads as ONE quiet\n * line in a transcript, never as a `[✗ …]` / `[⏹ …]` reply. The loop persists\n * those markers in the assistant turn for the model; this pass splits them off\n * the reply, merges them with the run-ending error (live from `run:end`, on\n * replay from the run record) and lets one item speak for the stop.\n *\n * The one classifier both surfaces use: the TUI over stream events\n * (`src/tui/run-stops.ts` tags them), the GUI over transcript rows\n * (`ui/src/chat/headless/transcript/run-failures.ts` mints rows with a\n * `failure`). Each supplies only how to copy and mark its items.\n */\nimport { mayHaveStreamFailure, splitStreamFailure } from './stream-failure'\n\n/** How a run ended early and how to pick it back up. */\nexport interface RunStop {\n /** `aborted` when the user stopped the run, `error` when it failed. */\n cause: 'error' | 'aborted'\n /** `continue` when the run had done work, `retry` (resend `prompt`) when not. */\n resume: 'continue' | 'retry'\n /** The prompt to resend, set only with `resume: 'retry'`. */\n prompt?: string\n}\n\n/** What the classifier reads off an item: stream events and the GUI's rows both carry it. */\nexport interface RunStopItem {\n /** The item's kind (`markdown`, `error`, `user-prompt`, `tool`, …). */\n kind: string\n /** Its text: a reply's markdown, an error's message, a prompt. */\n text?: string\n /** A reply still streaming: its marker, if any, is not final yet. */\n streaming?: boolean\n /** The worker session that produced it; absent on the main session. */\n childId?: string\n /** Worker nesting depth; `0` or absent on the main session. */\n depth?: number\n /** The tool an error belongs to: not the run's own error. */\n tool?: string\n /** The call an error belongs to: not the run's own error. */\n callId?: string\n /** Set when the item is a notice; `label` names its source (`run`, `repeat guard`, …). */\n notice?: { label?: string }\n}\n\n/** How one surface copies and marks its items. */\nexport interface RunStopAdapter<T extends RunStopItem> {\n /** The item already speaks for a stop (an earlier pass's output fed back in). */\n isMarked: (item: T) => boolean\n /** The reply with its marker split off. */\n withText: (reply: T, text: string) => T\n /** The stop line a marker becomes when no run error closes the exchange. */\n mint: (reply: T, text: string, stop: RunStop) => T\n /** The run's own error, now speaking for the stop with `text`. */\n mark: (error: T, text: string, stop: RunStop) => T\n}\n\nconst WORK_KINDS = new Set(['tool', 'tool-result', 'tool-batch', 'thinking', 'thinking-batch', 'user-bash', 'spawn-start', 'spawn-end', 'command-detail'])\n\n/** The run had done something: a tool call, a thought, a worker, a command's output, or a reply with words. */\nfunction isRunWork(item: RunStopItem): boolean {\n return WORK_KINDS.has(item.kind) || (item.kind === 'markdown' && (item.text ?? '').trim() !== '')\n}\n\n/** Belongs to the main session, not to a worker. */\nfunction isTopLevel(item: RunStopItem): boolean {\n return !item.childId && (item.depth ?? 0) === 0\n}\n\n/** Receipts and turn boundaries come after a run's end: the search for it looks past them. */\nfunction isSkippable(item: RunStopItem): boolean {\n return item.kind === 'run-summary' || item.kind === 'separator'\n}\n\n/**\n * Notices that end a run: older sessions persisted the run's error as a `run`\n * notice, and the repeat guard stops a run with one. Any other notice (a `/`\n * command's error, a failed auto-compaction) is not the run failing.\n */\nconst RUN_ENDING_NOTICES = new Set(['run', 'repeat guard'])\n\n/** A run's own error: not a tool's, not a `/` command's. */\nfunction isRunError(item: RunStopItem): boolean {\n return item.kind === 'error' && isTopLevel(item) && !item.tool && !item.callId\n && (!item.notice || RUN_ENDING_NOTICES.has(item.notice.label ?? ''))\n}\n\n/**\n * The run-stop pass for one surface. It returns its input itself when no run\n * stopped early, so memoised consumers stay put.\n *\n * It runs on every stream drain tick, where only the tail changes. Items are\n * immutable, so both caches key on identity: the failure scan reads each\n * reply once, and a segment whose items are unchanged hands back its previous\n * output (without that, a session with one old failed run minted fresh stop\n * items every tick, so they re-rendered on every streamed token).\n *\n * @param adapter - How the surface copies and marks its items.\n */\nexport function createRunStopMarker<T extends RunStopItem>(adapter: RunStopAdapter<T>): (items: readonly T[]) => readonly T[] {\n const failureScans = new WeakMap<T, boolean>()\n const segments = new WeakMap<T, { input: T[], output: T[] | null }>()\n\n const mayMarkStop = (item: T): boolean => {\n if (item.kind === 'error')\n return isTopLevel(item)\n if (item.kind !== 'markdown')\n return false\n let hit = failureScans.get(item)\n if (hit === undefined) {\n hit = mayHaveStreamFailure(item.text ?? '')\n failureScans.set(item, hit)\n }\n return hit\n }\n\n /** `markSegment` over `items[start, end)`, or `null` when it left the segment as is. */\n const markSegmentCached = (items: readonly T[], start: number, end: number): T[] | null => {\n const first = items[start]\n const cached = first ? segments.get(first) : undefined\n if (cached && cached.input.length === end - start) {\n let same = true\n for (let k = 1; k < cached.input.length && same; k++)\n same = cached.input[k] === items[start + k]\n if (same)\n return cached.output\n }\n const input = items.slice(start, end)\n const marked = markSegment(input, adapter)\n const output = marked === input ? null : marked\n if (first)\n segments.set(first, { input, output })\n return output\n }\n\n return (items) => {\n if (!items.some(mayMarkStop))\n return items\n const out: T[] = []\n let changed = false\n let start = 0\n // A segment is one exchange: a top-level prompt and everything up to the next one.\n for (let i = 0; i <= items.length; i++) {\n if (i < items.length && !(items[i]!.kind === 'user-prompt' && isTopLevel(items[i]!) && i > start))\n continue\n const next = markSegmentCached(items, start, i)\n if (next) {\n changed = true\n out.push(...next)\n }\n else {\n for (let k = start; k < i; k++)\n out.push(items[k]!)\n }\n start = i\n }\n return changed ? out : items\n }\n}\n\nfunction markSegment<T extends RunStopItem>(segment: T[], adapter: RunStopAdapter<T>): T[] {\n let marker: { index: number, message: string, aborted: boolean } | null = null\n const items = segment.map((item, index) => {\n if (item.kind !== 'markdown' || item.streaming || !isTopLevel(item))\n return item\n const split = splitStreamFailure(item.text ?? '')\n if (!split.failure)\n return item\n marker = { index, message: split.failure.message, aborted: split.failure.aborted }\n return adapter.withText(item, split.text)\n })\n\n // The run's own end: a run error closing the exchange (receipts and turn boundaries aside).\n let terminal = -1\n for (let i = items.length - 1; i >= 0; i--) {\n const item = items[i]!\n if (isSkippable(item))\n continue\n if (isRunError(item) && !adapter.isMarked(item))\n terminal = i\n break\n }\n const found = marker as { index: number, message: string, aborted: boolean } | null\n const prompt = items[0]?.kind === 'user-prompt' ? items[0] : null\n // Without a marker, only an error closing a prompted run is that run's end.\n if (!found && (terminal < 0 || !prompt))\n return segment\n\n const workEnd = terminal >= 0 ? terminal : found!.index + 1\n const didWork = items.slice(prompt ? 1 : 0, workEnd).some(isRunWork)\n // Live, a stop can arrive as the run's error alone (\"This operation was aborted\").\n const aborted = found ? found.aborted : /\\babort/i.test(items[terminal]!.text ?? '')\n const cause = aborted ? 'aborted' as const : 'error' as const\n const promptText = prompt?.text ?? ''\n const stop: RunStop = didWork || !prompt || promptText.trim() === ''\n ? { cause, resume: 'continue' }\n : { cause, resume: 'retry', prompt: promptText }\n\n const result: T[] = []\n items.forEach((item, index) => {\n if (index === found?.index) {\n // Nothing left of the reply: the stop line takes its place.\n if ((item.text ?? '').trim() !== '')\n result.push(item)\n if (terminal < 0)\n result.push(adapter.mint(item, aborted ? '' : found.message, stop))\n return\n }\n if (index === terminal) {\n // A stop the user asked for needs no reason. A failure reads the run's\n // typed error (the classifier's words, e.g. a rate limit's reset) over\n // the marker, which older sessions persisted with the raw provider body.\n result.push(adapter.mark(item, aborted ? '' : item.text || found?.message || '', stop))\n return\n }\n result.push(item)\n })\n return result\n}\n","/**\n * Output throughput for the live run readout (`41 tok/s`), from the turn's\n * `stream:progress` samples.\n *\n * `tokens / elapsed since the request` was wrong in two ways that produced\n * absurd rates: the count mid-stream is an estimate from the visible text,\n * then jumps to the provider's real figure right before the stream ends\n * (for Anthropic that includes hidden reasoning, often many times the\n * estimate), so the division reported that correction as throughput; and\n * the denominator included the time to first token, so early readings\n * swung. Here the rate is tokens GAINED per second over a short trailing\n * window of samples: a correction (the estimate→provider snap, or a count\n * that goes backwards) rebases the window instead of counting, readings\n * are smoothed, and anything no model can produce is dropped.\n */\n\n/** One `stream:progress` reading of a turn, as {@link stepStreamRate} takes it. */\nexport interface RateSample {\n /** Turn the sample belongs to. */\n turnId: string\n /** ms since the turn's request; only differences are used. */\n elapsedMs: number\n /** Output tokens counted so far in the turn. */\n outputTokens: number\n /** Whether `outputTokens` is an estimate rather than a provider-reported count. */\n estimated: boolean\n}\n\n/** Sliding-window state of the output rate of a streaming turn. */\nexport interface RateState {\n /** Turn being measured, or `null` before the first sample. */\n turnId: string | null\n /** Samples inside the window, oldest first; the first is the baseline. */\n samples: readonly { t: number, n: number }[]\n /** Whether the samples are estimates, or `null` before the first sample. */\n estimated: boolean | null\n /** Smoothed tokens/second, `null` until the window has enough span. */\n rate: number | null\n}\n\n/** Initial rate state, before any sample. */\nexport const EMPTY_RATE: RateState = { turnId: null, samples: [], estimated: null, rate: null }\n\n/** Trailing window the rate is measured over. */\nconst WINDOW_MS = 3000\n/** Minimum span before a reading counts: shorter spans are one or two ticks of noise. */\nconst MIN_SPAN_MS = 1200\n/** Faster than any served model today (the fastest wafer-scale ones run ~3k): a reading above is a glitch. */\nexport const MAX_PLAUSIBLE_RATE = 6000\n/** Weight of a new reading in the smoothed rate. */\nconst SMOOTHING = 0.35\n\n/**\n * Folds one output token reading into the rate state. Returns a new state, or\n * the same one for an out-of-order or duplicate sample.\n *\n * @param state - The current rate state.\n * @param sample - The newest output token reading.\n */\nexport function stepStreamRate(state: RateState, sample: RateSample): RateState {\n const point = { t: sample.elapsedMs, n: sample.outputTokens }\n if (state.turnId !== sample.turnId) {\n return { turnId: sample.turnId, samples: [point], estimated: sample.estimated, rate: null }\n }\n const last = state.samples[state.samples.length - 1]\n // A correction, not throughput: the provider's count replaced the estimate,\n // or the count went backwards. Rebase on this sample, keep the last rate.\n const corrected\n = (state.estimated === true && !sample.estimated) || (last !== undefined && point.n < last.n) || !last\n if (corrected) {\n return { ...state, samples: [point], estimated: sample.estimated }\n }\n if (point.t <= last.t)\n return state // out-of-order or duplicate tick\n\n // Keep the window, plus the newest sample older than it as the baseline.\n const kept = [...state.samples, point]\n let start = 0\n while (start < kept.length - 2 && kept[start + 1]!.t <= point.t - WINDOW_MS)\n start++\n const samples = kept.slice(start)\n\n const base = samples[0]!\n const span = point.t - base.t\n let rate = state.rate\n if (span >= MIN_SPAN_MS) {\n const reading = ((point.n - base.n) / span) * 1000\n if (reading >= 0 && reading <= MAX_PLAUSIBLE_RATE) {\n rate = rate === null ? reading : rate + SMOOTHING * (reading - rate)\n }\n }\n return { turnId: state.turnId, samples, estimated: sample.estimated, rate }\n}\n\n/**\n * Whole tokens per second for display, or `null` when there is no honest reading.\n *\n * @param state - The current rate state.\n */\nexport function streamRateValue(state: RateState): number | null {\n if (state.rate === null)\n return null\n const rounded = Math.round(state.rate)\n return rounded > 0 ? rounded : null\n}\n","/**\n * User-initiated todo-list edits — pure transforms over `TodoItem[]`.\n *\n * The todo list is normally MODEL-owned: `todowrite` passes the full array on\n * every call, so a checkpoint replaces whatever was there. These transforms let\n * the TUI's `ctrl+t` panel and the GUI todos tab edit the same list, with one consequence the UI must\n * surface rather than hide: **a user edit made during a live run is overwritten\n * by the agent's next checkpoint**. Nothing here can prevent that — it is the\n * tool's contract — so the modal warns while a run is in flight instead of\n * pretending the edit is durable.\n *\n * Kept pure and renderer-agnostic (no React, no node) so the reducers are\n * unit-testable and both the TUI and the GUI drive the same edits.\n */\n\nimport type { TodoItem, TodoStatus } from './todos'\n\n/**\n * Prefix for ids minted here, distinguishing user-authored rows from the\n * model's own ids in a session file. Purely diagnostic — nothing branches on\n * it — but it makes \"who added this\" answerable after the fact.\n */\nconst USER_TODO_ID_PREFIX = 'user-'\n\n/**\n * Mint an id that cannot collide with an existing row.\n *\n * Counter-based rather than random: a stable, readable id keeps session diffs\n * legible, and the collision check makes it safe against ids the model already\n * used (including previous `user-*` ones after a reload).\n *\n * @param items - The current todo list.\n */\nexport function nextTodoId(items: readonly TodoItem[]): string {\n const taken = new Set(items.map(i => i.id))\n for (let n = 1; ; n++) {\n const id = `${USER_TODO_ID_PREFIX}${n}`\n if (!taken.has(id))\n return id\n }\n}\n\n/**\n * Append a todo. Returns the list unchanged when `content` is blank — an empty\n * row is never what the user meant, and rejecting it here means every caller\n * (keyboard, click, GUI) gets the same guard.\n *\n * @param items - The current todo list.\n * @param content - Text of the new todo. Blank text adds nothing.\n */\nexport function addTodo(items: readonly TodoItem[], content: string): TodoItem[] {\n const trimmed = content.trim()\n if (!trimmed)\n return [...items]\n return [...items, { id: nextTodoId(items), content: trimmed, status: 'pending' }]\n}\n\n/**\n * Replace one todo's text. Blank content is rejected (see {@link addTodo}); an\n * unknown id is a no-op rather than an error, because the list can be replaced\n * by a `todowrite` between render and keypress.\n *\n * @param items - The current todo list.\n * @param id - Id of the todo to change.\n * @param content - New text. Blank text changes nothing.\n */\nexport function editTodo(items: readonly TodoItem[], id: string, content: string): TodoItem[] {\n const trimmed = content.trim()\n if (!trimmed)\n return [...items]\n return items.map(item => item.id === id ? { ...item, content: trimmed } : item)\n}\n\n/**\n * Drop one todo. Unknown id is a no-op, same rationale as {@link editTodo}.\n *\n * @param items - The current todo list.\n * @param id - Id of the todo to remove.\n */\nexport function removeTodo(items: readonly TodoItem[], id: string): TodoItem[] {\n return items.filter(item => item.id !== id)\n}\n\n/** Drop everything. Separate from `removeTodo` so the caller's intent is explicit at the call site. */\nexport function clearTodos(): TodoItem[] {\n return []\n}\n\n/**\n * Advance a todo's status one step: pending → in_progress → completed →\n * pending. `cancelled` also lands on `pending`, so a dropped item can be\n * revived without a dedicated key.\n *\n * Cycling INTO `in_progress` demotes any other in-progress row to `pending`:\n * the list's whole purpose is \"what is being worked on right now\", and two\n * live rows make that unanswerable — `todoProgressLabel`\n * reads the first one and would silently ignore the rest.\n *\n * @param items - The current todo list.\n * @param id - Id of the todo to advance. An unknown id changes nothing.\n */\nexport function cycleTodoStatus(items: readonly TodoItem[], id: string): TodoItem[] {\n const target = items.find(item => item.id === id)\n if (!target)\n return [...items]\n const next = nextStatus(target.status)\n return items.map((item) => {\n if (item.id === id)\n return { ...item, status: next }\n if (next === 'in_progress' && item.status === 'in_progress')\n return { ...item, status: 'pending' as TodoStatus }\n return item\n })\n}\n\nfunction nextStatus(status: TodoStatus): TodoStatus {\n switch (status) {\n case 'pending':\n return 'in_progress'\n case 'in_progress':\n return 'completed'\n case 'completed':\n case 'cancelled':\n default:\n return 'pending'\n }\n}\n\n/**\n * Steering text for a \"retry this todo\" request.\n *\n * Quotes the content so a model reading it can match the row verbatim against\n * its own list, and names the status because \"retry\" means different things\n * for a row it believes is `completed` versus one it abandoned as `cancelled`.\n * Shared by the TUI and GUI modals so both surfaces steer with byte-identical\n * text; pinned by a test rather than living inside a JSX callback.\n *\n * @param item - The todo to retry.\n */\nexport function buildTodoRetryMessage(item: TodoItem): string {\n return `Retry this todo (currently ${item.status}): \"${item.content}\"`\n}\n"],"mappings":"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"}
|