zidane 7.2.5 → 8.0.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/LICENSE +21 -0
- package/README.md +34 -6
- package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
- package/dist/acp-DQDhi2dj.js.map +1 -0
- package/dist/acp-cli.d.ts +1 -1
- package/dist/acp-cli.js +9 -66
- package/dist/acp-cli.js.map +1 -1
- package/dist/acp.d.ts +10 -590
- package/dist/acp.d.ts.map +1 -1
- package/dist/acp.js +3 -3
- package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
- package/dist/agent-DSLNmBp0.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -2
- package/dist/aliasing-lVFbm81n.js +217 -0
- package/dist/aliasing-lVFbm81n.js.map +1 -0
- package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
- package/dist/anthropic-CD00LhUP.js.map +1 -0
- package/dist/artifacts-CV2hUKnL.js.map +1 -1
- package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
- package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
- package/dist/call-tool-dHlbGOIY.js +70 -0
- package/dist/call-tool-dHlbGOIY.js.map +1 -0
- package/dist/chat/pure.d.ts +372 -6
- package/dist/chat/pure.d.ts.map +1 -1
- package/dist/chat/pure.js +35 -244
- package/dist/chat/pure.js.map +1 -1
- package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
- package/dist/chat-JPJJ8uu5.js.map +1 -0
- package/dist/chat.d.ts +4 -6
- package/dist/chat.js +23 -12
- package/dist/cli-shared-C-YCaglL.js +159 -0
- package/dist/cli-shared-C-YCaglL.js.map +1 -0
- package/dist/client-core-BQSyDALT.d.ts +2115 -0
- package/dist/client-core-BQSyDALT.d.ts.map +1 -0
- package/dist/codemode-worker.d.ts +1 -0
- package/dist/codemode-worker.js +155 -0
- package/dist/codemode-worker.js.map +1 -0
- package/dist/codemode.d.ts +352 -0
- package/dist/codemode.d.ts.map +1 -0
- package/dist/codemode.js +5 -0
- package/dist/connection-Dr-Js4yZ.d.ts +28 -0
- package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
- package/dist/connection-loop-gdh22LTI.js +112 -0
- package/dist/connection-loop-gdh22LTI.js.map +1 -0
- package/dist/context-segments-BHKlagL6.js +1016 -0
- package/dist/context-segments-BHKlagL6.js.map +1 -0
- package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
- package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
- package/dist/contexts/daytona.d.ts +19 -8
- package/dist/contexts/daytona.d.ts.map +1 -1
- package/dist/contexts/daytona.js +1 -440
- package/dist/contexts/docker.d.ts +36 -7
- package/dist/contexts/docker.d.ts.map +1 -1
- package/dist/contexts/docker.js +1 -456
- package/dist/contexts/e2b.d.ts +68 -13
- package/dist/contexts/e2b.d.ts.map +1 -1
- package/dist/contexts/e2b.js +1 -382
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/contexts/sandbox.js +5 -0
- package/dist/contexts/sandbox.js.map +1 -1
- package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
- package/dist/contexts-d7UolYot.js.map +1 -0
- package/dist/contexts.d.ts +3 -3
- package/dist/contexts.js +1 -1
- package/dist/cred-keys-GpBg71cP.js +105 -0
- package/dist/cred-keys-GpBg71cP.js.map +1 -0
- package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
- package/dist/credentials-JttEuRON.js.map +1 -0
- package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
- package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
- package/dist/daemon-cli.d.ts +1 -1
- package/dist/daemon-cli.js +3 -2
- package/dist/daemon-cli.js.map +1 -1
- package/dist/daytona-DG3omipZ.js +513 -0
- package/dist/daytona-DG3omipZ.js.map +1 -0
- package/dist/defaults-Cx3zvDOV.js +23 -0
- package/dist/defaults-Cx3zvDOV.js.map +1 -0
- package/dist/dispatcher-BMlu2BmZ.js +4941 -0
- package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
- package/dist/docker-BZhMMJUp.js +727 -0
- package/dist/docker-BZhMMJUp.js.map +1 -0
- package/dist/e2b-CEVOdRib.js +480 -0
- package/dist/e2b-CEVOdRib.js.map +1 -0
- package/dist/edit-utils-EGosADZq.js +234 -0
- package/dist/edit-utils-EGosADZq.js.map +1 -0
- package/dist/environment-8wsKE2Ln.js +214 -0
- package/dist/environment-8wsKE2Ln.js.map +1 -0
- package/dist/eval-BNcvle_J.js +1595 -0
- package/dist/eval-BNcvle_J.js.map +1 -0
- package/dist/eval.d.ts +2 -2
- package/dist/eval.js +1 -1489
- package/dist/executor-Cx5-8yqi.js +621 -0
- package/dist/executor-Cx5-8yqi.js.map +1 -0
- package/dist/extension-authoring-DyGGmq9V.js +385 -0
- package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
- package/dist/extensions.d.ts +2 -2
- package/dist/extensions.js +3 -3
- package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
- package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
- package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
- package/dist/format-C2NQEVUH.js.map +1 -0
- package/dist/format-bytes-C7tfc3Zm.js +55 -0
- package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
- package/dist/headless-C_rNUuYC.js +960 -0
- package/dist/headless-C_rNUuYC.js.map +1 -0
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -413
- package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
- package/dist/history-search-CcYzF8-0.js.map +1 -0
- package/dist/history-search-worker.d.ts +1 -1
- package/dist/history-search-worker.js +1 -1
- package/dist/host-D7NrI03V.js +378 -0
- package/dist/host-D7NrI03V.js.map +1 -0
- package/dist/host-signals-BcP5QKUD.js +118 -0
- package/dist/host-signals-BcP5QKUD.js.map +1 -0
- package/dist/identity-CwfO8K-t.js +26 -0
- package/dist/identity-CwfO8K-t.js.map +1 -0
- package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
- package/dist/index-BGe1fQT7.d.ts.map +1 -0
- package/dist/index-BVQsIKGn.d.ts +448 -0
- package/dist/index-BVQsIKGn.d.ts.map +1 -0
- package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
- package/dist/index-CHABJd-L.d.ts.map +1 -0
- package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
- package/dist/index-D6a7qXpg.d.ts.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +27 -23
- package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
- package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
- package/dist/ipc/remote.d.ts +313 -0
- package/dist/ipc/remote.d.ts.map +1 -0
- package/dist/ipc/remote.js +4 -0
- package/dist/ipc.d.ts +6 -964
- package/dist/ipc.js +403 -4
- package/dist/ipc.js.map +1 -0
- package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
- package/dist/isolation-D9L650W5.d.ts.map +1 -0
- package/dist/json-rpc--HXQti1E.js +350 -0
- package/dist/json-rpc--HXQti1E.js.map +1 -0
- package/dist/links-j8rED1sR.js +603 -0
- package/dist/links-j8rED1sR.js.map +1 -0
- package/dist/local-terminal-D8QThwo_.js +252 -0
- package/dist/local-terminal-D8QThwo_.js.map +1 -0
- package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
- package/dist/logger-Gtqlayx8.js.map +1 -0
- package/dist/logs-view-CWG8aUAG.js.map +1 -1
- package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
- package/dist/mcp-_wecH9Qe.js.map +1 -0
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +2 -2
- package/dist/media-sniff-UKijEaiQ.js.map +1 -1
- package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
- package/dist/messages-BqiwcD2Q.js.map +1 -0
- package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
- package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
- package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
- package/dist/openai-compat-CFrpH7uq.js.map +1 -0
- package/dist/orchestration-BCGmB8Ps.js +511 -0
- package/dist/orchestration-BCGmB8Ps.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -2
- package/dist/output/stream-json.d.ts.map +1 -1
- package/dist/output/stream-json.js +1 -1
- package/dist/output/terminal.d.ts +1 -2
- package/dist/output/terminal.d.ts.map +1 -1
- package/dist/output/terminal.js +13 -7
- package/dist/output/terminal.js.map +1 -1
- package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
- package/dist/plugins-DS7mahzZ.js.map +1 -0
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +1 -2
- package/dist/prelude-Cxo4t74B.js +517 -0
- package/dist/prelude-Cxo4t74B.js.map +1 -0
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -2
- package/dist/project-root-B8zADr4o.js +167 -0
- package/dist/project-root-B8zADr4o.js.map +1 -0
- package/dist/project-user-paths-BSgtrRxl.js +58 -0
- package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
- package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
- package/dist/prompts-DYcvqShf.d.ts.map +1 -0
- package/dist/protocol-DnhqqSmE.js +13 -0
- package/dist/protocol-DnhqqSmE.js.map +1 -0
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +1 -2
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/arcee.js +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/baseten.js +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/cerebras.js +3 -2
- package/dist/providers/cerebras.js.map +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/local.js +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai-compat.js +1 -2
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +15 -12
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +3 -2
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +3 -3
- package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
- package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +4 -4
- package/dist/registry-D6ShBWJU.js +5234 -0
- package/dist/registry-D6ShBWJU.js.map +1 -0
- package/dist/remote-hosts-BtA_9ZGp.js +97 -0
- package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
- package/dist/restate.d.ts +2 -3
- package/dist/restate.d.ts.map +1 -1
- package/dist/restate.js +631 -572
- package/dist/restate.js.map +1 -1
- package/dist/run-summary-CklLiZ4y.js +288 -0
- package/dist/run-summary-CklLiZ4y.js.map +1 -0
- package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
- package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
- package/dist/session/sqlite.d.ts +1 -2
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +1 -616
- package/dist/session-factory-BUGY5P40.js +1576 -0
- package/dist/session-factory-BUGY5P40.js.map +1 -0
- package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
- package/dist/session-xh9JXu6i.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/settings-keys-Ckf29NeM.js +677 -0
- package/dist/settings-keys-Ckf29NeM.js.map +1 -0
- package/dist/shell-path-Dqaoow2J.js +412 -0
- package/dist/shell-path-Dqaoow2J.js.map +1 -0
- package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
- package/dist/skills-DKqZJm4X.js.map +1 -0
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -2
- package/dist/source-mPExaUm8.js +381 -0
- package/dist/source-mPExaUm8.js.map +1 -0
- package/dist/sqlite-DV1DQzN2.js +698 -0
- package/dist/sqlite-DV1DQzN2.js.map +1 -0
- package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
- package/dist/src-BRMYRJib.js.map +1 -0
- package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
- package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
- package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
- package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
- package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
- package/dist/timeout-DEaqslLO.d.ts.map +1 -1
- package/dist/todo-edits-Dn251YUP.js +1790 -0
- package/dist/todo-edits-Dn251YUP.js.map +1 -0
- package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
- package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
- package/dist/tool-state-Dku6YqAB.js +989 -0
- package/dist/tool-state-Dku6YqAB.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -2
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +1 -2
- package/dist/tools/prompts.d.ts +1 -1
- package/dist/tools/prompts.js +7 -7
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/web-search.d.ts +1 -2
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +2 -2
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools-_DnT3AGM.js +578 -0
- package/dist/tools-_DnT3AGM.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +4 -2
- package/dist/tui.d.ts +534 -517
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +34933 -27243
- package/dist/tui.js.map +1 -1
- package/dist/turn-operations-B8sokwi5.js +333 -0
- package/dist/turn-operations-B8sokwi5.js.map +1 -0
- package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
- package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
- package/dist/types-C7ZFOztE.d.ts +132 -0
- package/dist/types-C7ZFOztE.d.ts.map +1 -0
- package/dist/types-CH5XpIHw.js +114 -0
- package/dist/types-CH5XpIHw.js.map +1 -0
- package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
- package/dist/types-Cu0ZGDu9.js.map +1 -0
- package/dist/types-IqegbJEE.d.ts +624 -0
- package/dist/types-IqegbJEE.d.ts.map +1 -0
- package/dist/types.d.ts +4 -4
- package/dist/types.js +1 -1
- package/dist/url-D8HCl65b.js +1259 -0
- package/dist/url-D8HCl65b.js.map +1 -0
- package/dist/wasm-BVT-j5cl.js +33 -0
- package/dist/wasm-BVT-j5cl.js.map +1 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
- package/dist/ws-CIHMvlSh.js +952 -0
- package/dist/ws-CIHMvlSh.js.map +1 -0
- package/dist/ws-client-N7NxzvQp.js +230 -0
- package/dist/ws-client-N7NxzvQp.js.map +1 -0
- package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
- package/dist/xai-CvJTeLrI.js.map +1 -0
- package/dist/xdg-zweed0-t.js +117 -0
- package/dist/xdg-zweed0-t.js.map +1 -0
- package/docs/ACP.md +52 -0
- package/docs/ARCHITECTURE.md +103 -6
- package/docs/ARTIFACTS.md +8 -4
- package/docs/CHAT.md +165 -14
- package/docs/EXECUTION_CONTEXT.md +8 -0
- package/docs/EXTENSIONS.md +123 -2
- package/docs/HEADLESS.md +2 -0
- package/docs/IPC.md +775 -64
- package/docs/MACHINES.md +456 -0
- package/docs/PANELS.md +3 -0
- package/docs/README.md +4 -0
- package/docs/RESTATE.md +3 -2
- package/docs/RUN_IN_BACKGROUND.md +10 -2
- package/docs/SERVER.md +1085 -0
- package/docs/SKILL.md +6 -1
- package/docs/TERMINAL.md +75 -0
- package/docs/TUI.md +65 -14
- package/package.json +58 -26
- package/scripts/eval.ts +4 -0
- package/dist/acp-D-tVyUjw.js.map +0 -1
- package/dist/agent-D0zZnGbt.js.map +0 -1
- package/dist/anthropic-C2aole0G.js.map +0 -1
- package/dist/approvals-DKaJZYlm.js.map +0 -1
- package/dist/atomic-write-B7zr1ddF.js.map +0 -1
- package/dist/auth-BG2rVKSt.js.map +0 -1
- package/dist/completion-core-BRo86R_L.js.map +0 -1
- package/dist/contexts/daytona.js.map +0 -1
- package/dist/contexts/docker.js.map +0 -1
- package/dist/contexts/e2b.js.map +0 -1
- package/dist/contexts-CRE9pw07.js.map +0 -1
- package/dist/eval.js.map +0 -1
- package/dist/format-BF745pLL.js.map +0 -1
- package/dist/glob-DluQFSw1.js +0 -270
- package/dist/glob-DluQFSw1.js.map +0 -1
- package/dist/headless.js.map +0 -1
- package/dist/history-search-C4bk1Wz_.js.map +0 -1
- package/dist/index-BgN1T3lk.d.ts.map +0 -1
- package/dist/index-C37_ppWv.d.ts.map +0 -1
- package/dist/index-C6NEd5y_.d.ts.map +0 -1
- package/dist/ipc-BKVIIOqH.js +0 -331
- package/dist/ipc-BKVIIOqH.js.map +0 -1
- package/dist/ipc.d.ts.map +0 -1
- package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
- package/dist/json-rpc-rSWMUh9b.js +0 -192
- package/dist/json-rpc-rSWMUh9b.js.map +0 -1
- package/dist/logger--C1VQjwJ.js.map +0 -1
- package/dist/mcp-CgNd-f3F.js.map +0 -1
- package/dist/messages-2jcOA_5R.js.map +0 -1
- package/dist/openai-compat-Dy56weK8.js.map +0 -1
- package/dist/output-cap-C9zukcCj.js +0 -100
- package/dist/output-cap-C9zukcCj.js.map +0 -1
- package/dist/panels-B6gRk4bf.js +0 -789
- package/dist/panels-B6gRk4bf.js.map +0 -1
- package/dist/plugins-gbI7SBA6.js.map +0 -1
- package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
- package/dist/run-summary-BU_NgwUT.js +0 -269
- package/dist/run-summary-BU_NgwUT.js.map +0 -1
- package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
- package/dist/session/sqlite.js.map +0 -1
- package/dist/session-BqRP1hS7.js.map +0 -1
- package/dist/shell-path-DfdXrGg9.js +0 -1549
- package/dist/shell-path-DfdXrGg9.js.map +0 -1
- package/dist/skills-BC3dodWp.js.map +0 -1
- package/dist/src-CkNQKFKr.js.map +0 -1
- package/dist/todo-edits-UOwgxGKu.js +0 -528
- package/dist/todo-edits-UOwgxGKu.js.map +0 -1
- package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
- package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
- package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
- package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
- package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
- package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
- package/dist/turn-operations-DrbJlpq9.js.map +0 -1
- package/dist/types-CWgENVLY.js.map +0 -1
- package/dist/xai-CazjStOK.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-formatters-IQFDrdrs.js","names":["DEFAULT_RESULT_LIMIT","fzfByCatalog","fzfFor","fzfByCatalog"],"sources":["../src/chat/todo-glyphs.ts","../src/chat/agent-accent.ts","../src/chat/turn-selection.ts","../src/chat/machine-protocol.ts","../src/chat/feature-gate.ts","../src/chat/footer-chips.ts","../src/chat/completion-chats.ts","../src/chat/browser/protocol.ts","../src/chat/terminal/protocol.ts","../src/chat/color-gradient.ts","../src/chat/completion-commands.ts","../src/chat/completion-files.ts","../src/chat/completion-skills.ts","../src/chat/daemon-health.ts","../src/chat/markdown-segments.ts","../src/chat/mcp-allowlist.ts","../src/chat/mcp-auth-state.ts","../src/chat/mcp-test-outcome.ts","../src/chat/model-catalog.ts","../src/chat/model-lineup.ts","../src/chat/provider-usage-format.ts","../src/chat/spawn-tree.ts","../src/chat/streaming-pure.ts","../src/chat/tool-formatters.ts"],"sourcesContent":["import type { TodoStatus } from './todos'\n\n// Status glyphs — single source of truth for every UI surface that\n// renders a todo. Both the modal and the inline indicator import these\n// so the two read as the same visual language. Glyphs are intentionally\n// monochrome / single-cell so they line up cleanly in a column.\n//\n// pending ☐ empty box — \"queued\"\n// in_progress ◐ half-filled circle — \"currently working\"\n// completed ☑ checked box — \"done\"\n// cancelled ☒ crossed box — \"no longer relevant\"\n//\n// The inline indicator uses the `in_progress` glyph as its prefix so a\n// quick glance at the bar matches the modal's row marker. Renderer-\n// agnostic by design — a GUI shell can reuse the same map verbatim.\nexport const TODO_STATUS_GLYPHS: Readonly<Record<TodoStatus, string>> = {\n pending: '☐',\n in_progress: '◐',\n completed: '☑',\n cancelled: '☒',\n}\n","/**\n * Agent profile accent tokens, split from `./agents` (which pulls the tool\n * runtime) so the GUI renderer resolves them through `zidane/chat/pure`.\n */\n\n/**\n * Theme color token used to accent the active profile in the UI (footer\n * badge, picker highlight). Resolved against `ThemeColors` via\n * `useColors()`; falls back to `accent` when omitted.\n */\nexport type AgentAccent = 'brand' | 'accent' | 'warn' | 'model'\n\n/**\n * Resolve a profile's `accent` token to a concrete hex color via the\n * caller's color palette. Renderer-agnostic — accepts the four-role\n * subset of `ThemeColors` that's relevant to accent surfaces, so this\n * helper composes against either `useColors()` (TUI) or a CSS-variable\n * lookup (GUI). Omitted / unknown tokens fall back to `accent`.\n */\nexport function accentColor(\n accent: AgentAccent | (string & {}) | undefined,\n COLOR: { brand: string, accent: string, warn: string, model: string },\n): string {\n switch (accent) {\n case 'brand': return COLOR.brand\n case 'warn': return COLOR.warn\n case 'model': return COLOR.model\n case 'accent':\n default:\n return COLOR.accent\n }\n}\n","// ---------------------------------------------------------------------------\n// Transcript visibility + select-turn navigation — pure data rules consumed\n// by any renderer that walks a `StreamEvent[]`. They encode the user-facing\n// semantics (settings + edit-tool error prefixes) rather than any\n// presentation primitive, and import nothing node-bound — so they live in\n// their own leaf module that a browser-context renderer can import via\n// `zidane/chat/pure`. `store.ts` re-exports them for back-compat; the TUI\n// re-exports them via `zidane/tui`.\n// ---------------------------------------------------------------------------\n\nimport type { SessionTurn } from '../types'\nimport type { Settings, StreamEvent } from './types'\nimport { searchHighlightRanges } from './history-search'\n\n/** Tools whose `tool-result` event is suppressed when `showEditDiffs` is on. */\nexport const EDIT_TOOL_NAMES: ReadonlySet<string> = new Set(['edit', 'multi_edit', 'write_file'])\n\n/**\n * Keep turn-selection mode alive after deleting its active row. Prefer the\n * row that slides into the deleted index; at the tail, select the new last\n * row. Returns null only when no selectable rows survive.\n */\nexport function selectionAfterTurnRemoval(\n before: readonly string[],\n removedId: string,\n after: readonly string[],\n): string | null {\n if (after.includes(removedId))\n return removedId\n if (after.length === 0)\n return null\n const index = before.indexOf(removedId)\n return after[Math.min(Math.max(0, index), after.length - 1)] ?? null\n}\n\n/**\n * Recognize a tool-result body as carrying NON-success information so the\n * renderer doesn't suppress it under `showEditDiffs`. Three categories:\n *\n * - `edit` → \"Edit error: …\"\n * - `write_file` permission errors wrapped by the loop → \"Tool failed: …\"\n * - `multi_edit` → legacy single-line error `multi_edit error: …`, OR\n * a result carrying an `<edit-outcomes>…</edit-outcomes>` annotation\n * block. The TUI only appends the annotation when at least one hunk\n * was NOT applied, so its mere presence is the signal — the result\n * body needs to stay visible next to the diff so the user can read\n * denial / skip / failure reasons longer than the per-hunk badge.\n * - Fully-denied gate emit (`[fully denied] <edit-outcomes>…`) likewise\n * stays visible.\n *\n * Exported for unit-testability of the visibility matrix.\n */\nexport function isEditErrorResult(text: string): boolean {\n if (text.startsWith('Edit error:'))\n return true\n if (text.startsWith('Tool failed:'))\n return true\n if (text.startsWith('multi_edit error:'))\n return true\n if (text.startsWith('[fully denied]'))\n return true\n // The annotation block only appears when at least one hunk was NOT\n // applied (see `src/chat/host/edits/index.ts` `annotateEditResult`), so a present\n // sentinel pair signals \"denial / skip / failure attached — surface\n // the result body so reasons are readable next to the diff badges\".\n if (text.includes('\\n<edit-outcomes>\\n') || text.startsWith('<edit-outcomes>\\n'))\n return true\n return false\n}\n\n/**\n * `callId` prefix minted by the TUI's `!` bash mode (see `runBashMode`\n * in `src/tui/commands/run-bash-mode.ts`). The prefix is the durable signal — it survives\n * persistence and replay — that a `shell` tool exchange was USER-initiated,\n * so renderers can keep it visible even when the tool-display settings\n * hide model-driven plumbing: the user typed the command and expects to\n * see it and what it printed.\n */\nexport const BASH_CALL_ID_PREFIX = 'bash_'\n\n/** Is this event a user-initiated `!` bash exchange (vs. a model-driven shell call)? */\nexport function isUserBashEvent(event: Pick<StreamEvent, 'tool' | 'callId'>): boolean {\n return event.tool === 'shell' && event.callId?.startsWith(BASH_CALL_ID_PREFIX) === true\n}\n\n/**\n * Prompt-history entries (↑/↓ cycling) from a transcript, in submit order:\n * every submitted prompt (`user-prompt` events, raw text) AND every `!` bash\n * command (its `tool` event, reconstructed as `!command` so a recalled entry\n * re-submits through the same bash path). Model-driven tool calls are\n * excluded — only what the user actually typed belongs in their history.\n * Works identically on live events and on `eventsFromTurns` replay, so bash\n * commands persist in the history across session reloads for free.\n */\nexport function promptHistoryFromEvents(events: readonly StreamEvent[]): string[] {\n const history: string[] = []\n for (const event of events) {\n // Skip synthetic echoes (command injected-prompt markers, context-note\n // `display` lines) — the user never typed them, so they must not\n // resurface via up-arrow recall.\n if (event.kind === 'user-prompt' && !event.synthetic)\n history.push(event.text)\n else if (event.kind === 'tool' && isUserBashEvent(event) && typeof event.input?.command === 'string')\n history.push(`!${event.input.command}`)\n }\n return history\n}\n\n/**\n * Retro-tag live `user-prompt` events with the id of their persisted turn.\n *\n * Live prompt echoes are appended to the stream BEFORE `agent.run()` mints\n * and persists the user turn, so they carry no `turnId` — which makes them\n * invisible to select-turn navigation, hover, and click (all keyed on\n * `turnId`), while the SAME prompt becomes selectable after a session reload\n * (replay tags every event). Hosts call this when the seeded turns land\n * (e.g. the `session:turns` hook, which fires right after the prompt turn\n * persists, before the first model turn).\n *\n * Matching rule, per prompt-bearing turn: the NEWEST `user-prompt` event\n * that has no `turnId` yet and whose text equals one of the turn's text\n * blocks — or the turn's `display` echo when the caller supplies one\n * (run-minted prompt turns never carry `display` themselves; the TUI's\n * command `runAgent` path injects the origin display onto a copy after the\n * sub-run resolves, since the echo event's text is the short display line,\n * not the full prompt). A prompt turn qualifies with at least one non-blank\n * text block, OR — the attachment-only submit — with media blocks\n * (document/image/audio/video) and no tool plumbing; the latter matches the\n * newest untagged blank-text event that carries attachment chips. Tool-\n * result-only user turns contribute nothing and synthetic loop-continue\n * turns match no untagged event, so both fall through harmlessly.\n *\n * Pure — returns the SAME array instance when nothing matched, so hosts\n * can cheaply skip a re-render.\n */\nexport function retagUserPromptEvents(\n events: readonly StreamEvent[],\n appendedTurns: readonly SessionTurn[],\n): readonly StreamEvent[] {\n return retagUserPromptEventsFromRefs(events, promptTurnRefs(appendedTurns))\n}\n\n/**\n * Reduce persisted turns to the prompt refs the retag needs, dropping\n * non-prompt turns (assistant, tool results) entirely.\n *\n * Shared by the in-process path and the daemon broadcast so both select the\n * same turns as \"prompts\" — a divergence here would make a prompt selectable\n * on one surface and not the other.\n */\nexport function promptTurnRefs(turns: readonly SessionTurn[]): PromptTurnRef[] {\n const isMediaBlock = (b: SessionTurn['content'][number]): boolean =>\n b.type === 'document' || b.type === 'image' || b.type === 'audio' || b.type === 'video'\n const hasPromptText = (t: SessionTurn): boolean =>\n t.content.some(b => b.type === 'text' && b.text.trim().length > 0)\n const isAttachmentOnly = (t: SessionTurn): boolean =>\n t.content.some(isMediaBlock) && !t.content.some(b => b.type === 'tool_result')\n\n return turns\n .filter(t => t.role === 'user' && (hasPromptText(t) || isAttachmentOnly(t)))\n .map(turn => ({\n id: turn.id,\n texts: [\n ...turn.content.filter(b => b.type === 'text').map(b => b.text),\n ...(turn.display ? [turn.display] : []),\n ],\n // Attachment-only prompts have no (non-blank) text to match on — their\n // live echo is a blank-text event whose identity is the attachment chips.\n attachmentOnly: !hasPromptText(turn) && isAttachmentOnly(turn),\n }))\n}\n\n/**\n * The minimum a prompt turn must carry to be matched against its live echo.\n *\n * Exists because the daemon has to send this over a wire: a full `SessionTurn`\n * carries every content block, including base64 image and document payloads,\n * which would be megabytes per prompt to ship for the sake of attaching an id.\n */\nexport interface PromptTurnRef {\n id: string\n /** Text blocks plus the `display` override, if any. */\n texts: readonly string[]\n attachmentOnly: boolean\n}\n\n/**\n * Attach persisted turn ids to the live `user-prompt` events they correspond\n * to, so a just-sent prompt becomes selectable (hover, click, edit, delete)\n * without waiting for a session reload.\n *\n * Matching is newest-first and one-to-one: identical prompt text sent twice\n * must bind to two different turns, so each ref consumes exactly one untagged\n * event.\n */\nexport function retagUserPromptEventsFromRefs(\n events: readonly StreamEvent[],\n refs: readonly PromptTurnRef[],\n): readonly StreamEvent[] {\n if (refs.length === 0)\n return events\n let changed = false\n const next = [...events]\n for (const ref of refs) {\n const texts = new Set(ref.texts)\n for (let i = next.length - 1; i >= 0; i--) {\n const e = next[i]!\n if (e.kind !== 'user-prompt' || e.turnId)\n continue\n const matched = texts.has(e.text)\n || (ref.attachmentOnly && e.text.trim().length === 0 && (e.attachments?.length ?? 0) > 0)\n if (matched) {\n next[i] = { ...e, turnId: ref.id }\n changed = true\n break\n }\n }\n }\n return changed ? next : events\n}\n\n/** Searchable text of one stream event — tool name, label, and body text. */\nexport function streamEventSearchText(event: StreamEvent): string {\n return [event.tool, event.label, event.text].filter(Boolean).join('\\n')\n}\n\nexport function isVisibleDuringSearch(event: StreamEvent, settings: Settings, query: string): boolean {\n if (isVisible(event, settings))\n return true\n // Search may reveal a matching top-level row that its normal preference\n // hides (thinking, tool results — including a subagent's final report).\n // Nested child output stays collapsed and signals through the visible\n // lifecycle parent instead.\n return (event.depth ?? 0) === 0\n && searchHighlightRanges(streamEventSearchText(event), query).length > 0\n}\n\n/**\n * Per-event visibility — filters honor user toggles and the\n * `hideSubagentOutput` setting. When subagent output is hidden:\n * - Child-agent events are filtered down to the `spawn-start` /\n * `spawn-end` markers so the user still sees \"🌱 working… 🌳 done\".\n * - The parent's `tool-result` for `spawn` is hidden too. Its body\n * duplicates `spawn-end`'s stats line *and* the parent's next\n * markdown turn; showing it again produces an extra\n * `┃ [sub-agent child-1] Completed …` block users just want gone.\n *\n * Renderer-agnostic — returns plain `boolean` so TUI / GUI consumers\n * can filter events identically.\n */\n/** `notice.label` the host stamps on prompt-cache break/expiry rows (`host/notices/index.ts`). */\nexport const CACHE_NOTICE_LABEL = 'cache'\n\nexport function isVisible(event: StreamEvent, settings: Settings): boolean {\n if (settings.hideSubagentOutput) {\n if ((event.depth ?? 0) > 0)\n return event.kind === 'spawn-start' || event.kind === 'spawn-end'\n if (event.kind === 'tool-result' && event.tool === 'spawn')\n return false\n }\n // Suppress successful `tool-result`s for edit/multi_edit/write_file when\n // the diff renderer is on — the diff itself is the success indicator;\n // the `Edited path: N replacements.` line just adds noise. Error\n // results bypass the suppression so failures stay visible.\n if (\n settings.showEditDiffs\n && event.kind === 'tool-result'\n && event.tool\n && EDIT_TOOL_NAMES.has(event.tool)\n && !isEditErrorResult(event.text)\n ) {\n return false\n }\n switch (event.kind) {\n case 'thinking': return settings.showThinking\n // User-initiated `!` bash rows are never hidden — the user ran the\n // command to SEE it and its output; `toolCallDisplay` / `showToolResults`\n // gate model plumbing only. Without the `tool` exemption, hiding tool\n // calls would leave bash output floating with no sign of what ran.\n case 'tool': return settings.toolCallDisplay !== 'hidden' || isUserBashEvent(event)\n case 'tool-result': return settings.showToolResults || isUserBashEvent(event)\n case 'run-summary': return settings.showRunReceipt\n case 'info': return settings.showCacheNotices || event.notice?.label !== CACHE_NOTICE_LABEL\n // State for its spawn call's line, never a row of its own: it reaches\n // the compact fold (which shows the call as waiting) and nothing else.\n case 'spawn-queued': return settings.transcriptDensity === 'compact'\n default: return true\n }\n}\n\n/**\n * Build the `resultTurnId → owningAssistantTurnId` map used by the select-\n * turn mode to coalesce a tool-call's surrounding turns into ONE navigation\n * stop.\n *\n * Protocol shape: every `tool_call` block in an assistant turn is closed by\n * a matching `tool_result` block in the *next* user turn (the agent loop's\n * history validator depends on this). When the next user turn's only events\n * are `tool-result`s — i.e. it's pure plumbing for the prior assistant\n * turn — we map it back to that assistant turn here. The select-turn nav\n * index ({@link selectableTurnIds}) skips owned turns, and the renderer's\n * highlight gate ({@link isTurnHighlighted}) extends the selection accent\n * from the assistant turn to the events of any turn it owns. Net effect:\n *\n * - Navigation never lands the cursor on a result-only turn whose own\n * events may be hidden by `showToolResults: false` — the cursor\n * wouldn't be visible.\n * - Selecting an assistant turn highlights the call AND its result as\n * one unit, matching the user's mental model of \"one message\".\n *\n * Owner-lookup is conservative: result-only turns with no matching prior\n * assistant turn (orphaned — usually because the parent was deleted)\n * stay selectable so the user can act on them via the turn-details modal.\n *\n * Subagent (`childId` set) events are ignored — they live in a separate\n * conversation tree.\n */\nexport function turnSelectionOwnership(events: readonly StreamEvent[]): Map<string, string> {\n // Build per-turn event-kind summary in render order. We need:\n // - Whether a turn is \"result-only\" (every event is `tool-result`).\n // - The most recent previous turn that emitted a `tool` event (= the\n // candidate owner for the next result-only turn).\n const orderedTurnIds: string[] = []\n const summaryByTurn = new Map<string, { kinds: StreamEvent['kind'][], resultCallIds: string[] }>()\n const callOwner = new Map<string, string>()\n for (const e of events) {\n if (!e.turnId)\n continue\n if (e.childId)\n continue\n let summary = summaryByTurn.get(e.turnId)\n if (!summary) {\n orderedTurnIds.push(e.turnId)\n summary = { kinds: [], resultCallIds: [] }\n summaryByTurn.set(e.turnId, summary)\n }\n summary.kinds.push(e.kind)\n if (e.callId) {\n if (e.kind === 'tool')\n callOwner.set(e.callId, e.turnId)\n else if (e.kind === 'tool-result')\n summary.resultCallIds.push(e.callId)\n }\n }\n\n const ownership = new Map<string, string>()\n let lastToolEmitterTurnId: string | null = null\n for (const tid of orderedTurnIds) {\n const { kinds, resultCallIds } = summaryByTurn.get(tid)!\n const isResultOnly = kinds.length > 0 && kinds.every(k => k === 'tool-result')\n if (isResultOnly) {\n // Prefer the exact callId owner: in a FILTERED transcript (search) an\n // unrelated tool-emitting turn can sit between a result and its true\n // owner, so adjacency alone would coalesce onto the interloper.\n const exactOwner = resultCallIds\n .map(callId => callOwner.get(callId))\n .find(owner => owner !== undefined && owner !== tid)\n if (exactOwner)\n ownership.set(tid, exactOwner)\n else if (lastToolEmitterTurnId)\n ownership.set(tid, lastToolEmitterTurnId)\n // No owner found — leave the orphan selectable. Don't update\n // `lastToolEmitterTurnId` either (a result-only turn never emits\n // a `tool` event itself).\n continue\n }\n if (kinds.includes('tool'))\n lastToolEmitterTurnId = tid\n }\n return ownership\n}\n\n/**\n * Render-time check: should `event` paint with the selection accent?\n *\n * `true` when the event's own turn is selected, OR when the selected turn\n * `owns` the event's turn via {@link turnSelectionOwnership} (the call and\n * its tool-result rows highlight together). `false` when nothing is\n * selected or the relationship doesn't apply.\n *\n * Pure. Renderer-agnostic — the TUI's `<Transcript>` uses it; a GUI's\n * equivalent walks the same rule.\n */\nexport function isTurnHighlighted(\n event: Pick<StreamEvent, 'turnId'>,\n selectedTurnId: string | null,\n ownership: ReadonlyMap<string, string>,\n): boolean {\n if (selectedTurnId === null || !event.turnId)\n return false\n if (event.turnId === selectedTurnId)\n return true\n return ownership.get(event.turnId) === selectedTurnId\n || ownership.get(selectedTurnId) === event.turnId\n}\n\n/**\n * Ownership for \"one selection stop per message\": result-only turns fold\n * into their assistant turn (`turnSelectionOwnership`), and turns that only\n * did work (thinking, tool calls, worker markers) fold into the answer that\n * follows them in the same exchange. \"Read three files, then answered\" is\n * one stop, so ↑ moves one visible message at a time. An exchange that ends\n * in work alone stops on its first work turn. Same rule as the GUI's\n * `computeSelectStops`.\n */\nexport function messageSelectionOwnership(events: readonly StreamEvent[]): Map<string, string> {\n const base = turnSelectionOwnership(events)\n const resolve = (id: string): string => base.get(id) ?? id\n const stops = new Set<string>()\n const merged = new Map<string, string>()\n let pending: string[] = []\n const settle = (into: string | null) => {\n const target = into ?? pending[0]\n for (const id of pending) {\n if (target !== undefined && id !== target)\n merged.set(id, target)\n }\n if (target !== undefined)\n stops.add(target)\n pending = []\n }\n for (const event of events) {\n if (event.childId !== undefined || (event.depth ?? 0) > 0)\n continue\n if (event.kind === 'separator' || event.kind === 'user-prompt' || event.kind === 'compact-summary')\n settle(null)\n if (!event.turnId)\n continue\n const owner = resolve(event.turnId)\n const work = event.kind === 'tool' || event.kind === 'tool-result' || event.kind === 'thinking'\n || event.kind === 'spawn-start' || event.kind === 'spawn-end' || event.kind === 'command-detail'\n || (event.kind === 'info' && event.notice === undefined)\n if (event.kind === 'markdown' && event.text.trim()) {\n stops.add(owner)\n settle(owner)\n }\n else if (work) {\n if (!stops.has(owner) && !pending.includes(owner))\n pending.push(owner)\n }\n else if (event.kind !== 'user-prompt' && event.kind !== 'compact-summary') {\n settle(null)\n stops.add(owner)\n }\n else {\n stops.add(owner)\n }\n }\n settle(null)\n const out = new Map<string, string>()\n const final = (id: string): string => merged.get(id) ?? id\n for (const [raw, owner] of base) {\n const stop = final(owner)\n if (stop !== raw)\n out.set(raw, stop)\n }\n for (const [id, stop] of merged)\n out.set(id, stop)\n return out\n}\n\n/**\n * Deduplicated, in-order list of **parent-conversation** turn ids that appear\n * in a rendered transcript — the navigation index for the TUI's select-turn\n * mode. Three classes of turns are deliberately skipped:\n *\n * - **Subagent turns** (`childId` set). Nested execution detail; the\n * user's mental model of a \"message\" is the conversational exchange,\n * not each spawn turn. Also filtered out by `isVisible` under\n * `hideSubagentOutput: true` — selecting them would highlight nothing.\n * - **Result-only turns** — see {@link turnSelectionOwnership}. These get\n * coalesced into the assistant turn that emitted their tool_calls.\n * - **Settings-hidden turns** (when `settings` is supplied). A turn whose\n * every event fails {@link isVisible} would render no rows — landing\n * the cursor there hides it from the user entirely. The check is opt-\n * in so SDK callers without a Settings object keep the legacy\n * \"everything visible\" behavior.\n *\n * Synthetic events (separator, spawn-start, spawn-end) have no `turnId` and\n * are skipped naturally.\n */\nexport function selectableTurnIds(\n events: readonly StreamEvent[],\n settings?: Settings,\n visible?: (event: StreamEvent) => boolean,\n opts?: { byMessage?: boolean },\n): string[] {\n // `byMessage`: one stop per visible message (`messageSelectionOwnership`).\n const ownership = opts?.byMessage ? messageSelectionOwnership(events) : turnSelectionOwnership(events)\n\n // Per-turn visible event count (only computed when settings is supplied).\n // We need this to drop turns whose every event is filtered out by user\n // toggles — otherwise `↑/↓` could land the cursor on a row that paints\n // nothing visible.\n const visibleCount = settings ? new Map<string, number>() : null\n if (settings && visibleCount) {\n for (const e of events) {\n if (!e.turnId || e.childId)\n continue\n if (!(visible ? visible(e) : isVisible(e, settings)))\n continue\n visibleCount.set(e.turnId, (visibleCount.get(e.turnId) ?? 0) + 1)\n }\n }\n\n const seen = new Set<string>()\n const ordered: string[] = []\n for (const e of events) {\n if (!e.turnId)\n continue\n if (e.childId)\n continue\n if (seen.has(e.turnId))\n continue\n if (ownership.has(e.turnId))\n continue // result-only — owned by an earlier assistant turn\n if (visibleCount && (visibleCount.get(e.turnId) ?? 0) === 0)\n continue // every event of this turn is hidden by user settings\n seen.add(e.turnId)\n ordered.push(e.turnId)\n }\n return ordered\n}\n","import type { JsonValue } from '../types'\n/**\n * The machine protocol (`docs/MACHINES.md`): what a machine and its host say\n * over the machine's own WebSocket. Leaf module, shared by the host engine\n * (`chat/host/machines`), the machine agent (`ipc/machine`) and the IPC\n * protocol (re-exported by `ipc/protocol.ts`).\n */\nimport type { EnvironmentConfig } from './environment'\n\n/** Bumped on an incompatible change; a host refuses another major. */\nexport const MACHINE_PROTOCOL_VERSION = 1\n\nexport interface MachineRoot {\n path: string\n label?: string\n}\n\nexport interface MachineCapabilities {\n shell: boolean\n terminals: boolean\n background: boolean\n worktrees: boolean\n /** `exec.stream*` (live stdin/stdout: context-scoped MCP servers). Absent on older machines. */\n stream?: boolean\n /** The machine runs every command under its own OS sandbox (its user's `sandbox*` settings). */\n sandboxed?: boolean\n}\n\n/** At most this many live `exec.stream` processes per machine. */\nexport const MACHINE_MAX_STREAMS = 16\n/** Largest `data` chunk (decoded bytes) of one `exec.stream.data` notification or `exec.stream.write`. */\nexport const MACHINE_STREAM_CHUNK_BYTES = 256 * 1024\n\nexport interface MachineRegisterParams {\n machineId: string\n name: string\n roots: MachineRoot[]\n capabilities: MachineCapabilities\n version: string\n protocolVersion: number\n}\n\nexport interface MachineRegisterResult {\n machineId: string\n hostId?: string\n}\n\n/** A handle as the host names it: the machine rebuilds an unknown one (it restarted). */\nexport interface MachineHandleRef {\n id: string\n cwd: string\n}\n\nexport interface MachineListOptions {\n glob?: boolean\n limit?: number\n metadata?: boolean\n gitignore?: boolean\n}\n\nexport interface MachineTaskHandle {\n taskId: string\n pid: number\n outputPath: string\n}\n\n/** A machine's worktree, on its filesystem. */\nexport interface MachineWorktreeRef {\n path: string\n repoRoot: string\n}\n\n/** Requests the host sends to a machine: params → result. */\nexport interface MachineMethods {\n 'machine.ping': { params: Record<string, never>, result: { ok: true } }\n 'exec.spawn': { params: { handle: MachineHandleRef }, result: { id: string, cwd: string } }\n 'exec.run': { params: { handle: MachineHandleRef, callId: string, command: string, cwd?: string, env?: Record<string, string>, timeout?: number }, result: { stdout: string, stderr: string, exitCode: number } }\n 'exec.cancel': { params: { callId: string }, result: { cancelled: boolean } }\n 'exec.destroy': { params: { handle: MachineHandleRef }, result: { ok: true } }\n /** Start a live process; its output comes as `exec.stream.data` / `exec.stream.exit`, `exec.cancel` kills it. */\n 'exec.stream': { params: { handle: MachineHandleRef, callId: string, command: string, cwd?: string, env?: Record<string, string> }, result: { pid: number } }\n 'exec.stream.write': { params: { callId: string, data: string }, result: { ok: true } }\n 'fs.read': { params: { handle: MachineHandleRef, path: string, binary?: boolean }, result: { content: string } }\n 'fs.write': { params: { handle: MachineHandleRef, path: string, content: string }, result: { ok: true } }\n 'fs.list': { params: { handle: MachineHandleRef, path: string, options?: MachineListOptions }, result: { entries: Array<string | { path: string, size?: number, mtimeMs?: number }> } }\n 'fs.size': { params: { handle: MachineHandleRef, path: string }, result: { size: number | null } }\n 'bg.start': { params: { handle: MachineHandleRef, command: string, cwd?: string, env?: Record<string, string>, maxOutputBytes?: number }, result: MachineTaskHandle }\n 'bg.list': { params: { handle: MachineHandleRef }, result: { tasks: JsonValue[] } }\n 'bg.kill': { params: { handle: MachineHandleRef, taskId: string }, result: { exit: JsonValue | null } }\n 'bg.wait': { params: { handle: MachineHandleRef, taskId: string, timeoutMs?: number }, result: { exit: JsonValue | null } }\n 'terminal.open': { params: { handle: MachineHandleRef, cols: number, rows: number, cwd?: string }, result: { terminalId: string } }\n 'terminal.attach': { params: { terminalId: string }, result: { attached: boolean, backlog: string, total: number } }\n 'terminal.write': { params: { terminalId: string, data: string }, result: { ok: true } }\n 'terminal.resize': { params: { terminalId: string, cols: number, rows: number }, result: { ok: true } }\n 'terminal.kill': { params: { terminalId: string }, result: { ok: true } }\n 'terminal.detach': { params: { terminalId: string }, result: { ok: true } }\n 'env.checkFolder': { params: { cwd: string }, result: { cwd: string } }\n 'env.prepareWorktree': { params: { cwd: string, branch: string, base?: string, config: EnvironmentConfig }, result: { cwd: string, branch: string, base: string, ref: MachineWorktreeRef } }\n 'env.teardownWorktree': { params: { ref: MachineWorktreeRef, branch?: string, config: EnvironmentConfig }, result: { removed: boolean, reason?: string } }\n}\n\nexport type MachineMethodName = keyof MachineMethods\nexport type MachineParams<M extends MachineMethodName> = MachineMethods[M]['params']\nexport type MachineResult<M extends MachineMethodName> = MachineMethods[M]['result']\n\n/** Notifications a machine sends its host (base64 `data`). */\nexport interface MachineNotifications {\n 'terminal.data': { terminalId: string, data: string }\n 'terminal.exit': { terminalId: string, code: number }\n 'task.exit': { taskId: string, exit: JsonValue }\n 'exec.stream.data': { callId: string, stream: 'stdout' | 'stderr', data: string }\n 'exec.stream.exit': { callId: string, code: number }\n}\n\n/**\n * Calls whose re-send after a lost reply cannot change anything (reads, and\n * the idempotent handle calls: the machine keys handles by the host's id).\n * Everything else that was sent is reported as a lost result, never re-sent.\n */\nexport const MACHINE_IDEMPOTENT_METHODS: ReadonlySet<MachineMethodName> = new Set<MachineMethodName>([\n 'machine.ping',\n 'exec.spawn',\n 'exec.cancel',\n 'exec.destroy',\n 'fs.read',\n 'fs.list',\n 'fs.size',\n 'bg.list',\n 'bg.wait',\n 'env.checkFolder',\n 'terminal.attach',\n])\n\n/** Methods a machine connection may call on its host. */\nexport const MACHINE_HOST_METHODS = ['machine.register'] as const\n\n/** Error codes of the machine protocol (JSON-RPC server-error range, apart from `IpcErrorCode`). */\nexport const MachineErrorCode = {\n /** A machine connection called a client method, or a client a machine one. */\n MethodNotAllowed: -32040,\n /** `machine.register` from another major `MACHINE_PROTOCOL_VERSION`. */\n VersionSkew: -32041,\n /** The name is held by another machine on this host. */\n NameTaken: -32042,\n /** A path or cwd outside the machine's roots, or in its data dir. */\n OutsideRoots: -32043,\n /** The machine id is bound to another (live) token, or this token was used by the machine before the host forgot it. */\n IdBound: -32044,\n /** No room now (a capacity limit): try again later, unlike a refusal. */\n Busy: -32045,\n} as const\n\n/** A machine as clients see it (`machines.list`, `environments.list`). */\nexport interface MachineInfo {\n id: string\n name: string\n roots: MachineRoot[]\n status: 'online' | 'offline'\n lastSeen?: number\n version?: string\n /** What it registered with (absent: never connected since this host recorded it). */\n capabilities?: Partial<MachineCapabilities>\n}\n\n/** `machine:status` payload. */\nexport interface MachineStatusChange {\n machineId: string\n name: string\n status: 'online' | 'offline'\n}\n\n/**\n * What a local host's machine links are doing (`machines.links.status`,\n * `machine:links`): this computer shared with a saved server (it is the\n * machine), and saved servers used as machines (`local@<server>`, the\n * reverse direction over this host's own client connection).\n */\nexport type MachineLinkState = 'connecting' | 'connected' | 'reconnecting' | 'offline' | 'auth-refused' | 'identity' | 'refused'\n\nexport interface MachineShareStatus {\n /** The saved server's host id. */\n hostId: string\n /** This computer's name there (`local@<name>`). */\n name: string\n roots: string[]\n state: MachineLinkState\n /** Why it is not connected. Never a token. */\n detail?: string\n}\n\nexport interface MachineUseStatus {\n hostId: string\n state: MachineLinkState\n detail?: string\n /** The server's machine name on this host, once attached. */\n machineName?: string\n}\n\nexport interface MachineLinksStatus {\n shares: MachineShareStatus[]\n uses: MachineUseStatus[]\n}\n\n/** Where a local host keeps the machine token a saved server gave it (credentials store). */\nexport function machineCredentialKey(hostId: string): string {\n return `machine:${hostId}`\n}\n\n/** A machine name from a free-form one (a server's display name): the valid characters kept, the rest dashed. */\nexport function toMachineName(raw: string): string {\n const cleaned = raw.trim().replace(/[^\\w.-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 64)\n return cleaned || 'machine'\n}\n\n/** A machine-qualified environment kind: `<base>@<machine name>`. */\nexport function machineKind(base: 'local' | 'worktree', name: string): string {\n return `${base}@${name}`\n}\n\n/** `{ base, name }` of a machine-qualified kind, `null` for any other. */\nexport function parseMachineKind(kind: string): { base: 'local' | 'worktree', name: string } | null {\n const match = /^(local|worktree)@(.+)$/.exec(kind)\n return match ? { base: match[1] as 'local' | 'worktree', name: match[2]! } : null\n}\n\n/** A machine name: one path-safe segment, so `local@<name>` is unambiguous. */\nexport function isValidMachineName(name: string): boolean {\n return /^[\\w.-]{1,64}$/.test(name)\n}\n","/**\n * Opt-in feature gates: an experimental feature is one boolean setting\n * (default off) plus a kill-switch env var that wins over it.\n *\n * The kill switch exists so a bug in the gated path can never lock the user\n * out: the ungated path is always one flag away, even when the settings UI\n * itself is unreachable. Each gate names its flag (`--no-daemon`,\n * `--no-remote`); the CLI's {@link applyKillSwitchFlags} exports the env var\n * for the process, so child processes inherit the switch too.\n *\n * Node-free on purpose (re-exported from `zidane/chat/pure`): the TUI and the\n * GUI main process share one definition per gate, so both read the same\n * setting and honor the same kill switch.\n */\n\ntype Env = Record<string, string | undefined>\n\nexport interface FeatureGateOptions<K extends string> {\n /** Settings key holding the opt-in. Only a literal `true` enables. */\n setting: K\n /** Env var that disables the feature when set to `'1'`, whatever the setting says. */\n killSwitchEnv: string\n /** The `zidane` flag that sets {@link killSwitchEnv} for the launch (`--no-…`). */\n flag: string\n}\n\nexport interface FeatureGate<K extends string> {\n readonly setting: K\n readonly killSwitchEnv: string\n readonly flag: string\n /** The kill-switch env var is set to `'1'`. */\n isKilled: (env?: Env) => boolean\n /** Setting is `true` and the kill switch is not engaged. */\n isEnabled: (settings: Partial<Record<K, unknown>>, env?: Env) => boolean\n}\n\n/** `process.env` when there is one; a renderer has no `process`. */\nfunction ambientEnv(): Env {\n return (globalThis as { process?: { env?: Env } }).process?.env ?? {}\n}\n\nexport function defineFeatureGate<K extends string>({ setting, killSwitchEnv, flag }: FeatureGateOptions<K>): FeatureGate<K> {\n const isKilled = (env: Env = ambientEnv()): boolean => env[killSwitchEnv] === '1'\n return {\n setting,\n killSwitchEnv,\n flag,\n isKilled,\n isEnabled: (settings, env) => settings[setting] === true && !isKilled(env),\n }\n}\n\n/**\n * The shared daemon runtime. `ZIDANE_NO_DAEMON=1` is set by\n * `zidane --no-daemon`.\n */\nexport const daemonGate = defineFeatureGate({ setting: 'useDaemon', killSwitchEnv: 'ZIDANE_NO_DAEMON', flag: '--no-daemon' })\n\n/**\n * Remote hosts (zidane-server). The setting (\"Remote hosts\")\n * gates the saved servers: the Hosts settings, the per-host session groups\n * and picking a host for a new session. Connecting through an explicit `--host` /\n * `ZIDANE_HOST_URL` is its own opt-in, but `ZIDANE_NO_REMOTE=1` still wins\n * over it (`src/tui/host-target.ts`). `ZIDANE_NO_REMOTE=1` is set by\n * `zidane --no-remote`.\n */\nexport const remoteHostsGate = defineFeatureGate({ setting: 'remoteHosts', killSwitchEnv: 'ZIDANE_NO_REMOTE', flag: '--no-remote' })\n\n/** Every gate, so a client can report which kill switches are engaged. */\nexport const FEATURE_GATES: readonly FeatureGate<string>[] = [daemonGate, remoteHostsGate]\n\n/**\n * The kill-switch env vars engaged in `env`, sorted. The GUI main process\n * hands this to its renderer (which has no `process.env`) so settings rows\n * can say why they are inert.\n */\nexport function engagedKillSwitches(env: Env = ambientEnv()): string[] {\n return FEATURE_GATES.filter(g => g.isKilled(env)).map(g => g.killSwitchEnv).sort()\n}\n\n/**\n * Engages the kill switch of every gate whose flag is in `args` (sets its env\n * var to `'1'` in `env`, so child processes inherit it) and returns `args`\n * without those flags.\n */\nexport function applyKillSwitchFlags(args: readonly string[], env: Env): string[] {\n const rest: string[] = []\n for (const arg of args) {\n const gate = FEATURE_GATES.find(g => g.flag === arg)\n if (gate)\n env[gate.killSwitchEnv] = '1'\n else\n rest.push(arg)\n }\n return rest\n}\n\n/** `name` is set to `'1'` in `env`: the kill-switch test, for a row that only knows the variable. */\nexport function isKillSwitchEngaged(name: string, env: Env = ambientEnv()): boolean {\n return env[name] === '1'\n}\n","/**\n * Presentation logic for the transient footer status chips, shared by every\n * surface: currently the prompt-cache chip and the provider-retry indicator.\n *\n * Both report an invisible condition with no error attached — a turn re-billing\n * a prefix the provider should have served from cache, or a stalled stream being\n * retried — and both carry real judgment in their wording: which dimensions\n * changed, when a figure is an estimate, when there is no figure to show at\n * all, whose stream is stuck. That is why they live here instead of being\n * re-derived per surface. A GUI chip that rounded differently, or printed\n * `$0.00` where the TUI printed nothing, would be reporting different facts\n * about the same event.\n *\n * Node-free, so it is re-exported from `zidane/chat/pure` for the Electron\n * renderer.\n */\nimport type { CacheBreakInfo } from '../cache-telemetry'\nimport { fmtTokens, formatDuration, formatElapsed } from './format'\n\n/**\n * `warn` = a real cache break (a named dimension changed, so it was\n * avoidable); `dim` = ordinary TTL expiry, which is not anyone's fault and\n * should not shout.\n */\nexport type CacheChipTone = 'warn' | 'dim'\n\nexport interface CacheChipContent {\n tone: CacheChipTone\n /** Leading glyph. Kept out of `label` so a surface can style it separately. */\n glyph: string\n label: string\n}\n\n/**\n * Abbreviate a re-billed token count: `1200` → `1.2k`, `800` → `800`.\n * Thousands only — a cache prefix large enough to need `M` would be past any\n * provider's window.\n */\nfunction formatTokens(tokens: number): string {\n return tokens >= 1000 ? `${(tokens / 1000).toFixed(1)}k` : String(tokens)\n}\n\n/**\n * Build the chip for a cache break.\n *\n * `costUsd` is OPTIONAL and omitted entirely on a rate miss — never rendered\n * as `$0.00`. A fabricated zero would read as \"this was free\", which is the\n * opposite of what the chip exists to say. When present it is prefixed `~`\n * because it is an estimate (registry rates × re-billed prefix), and clamped\n * to `<0.01` rather than rounding a real charge down to nothing.\n */\nexport function cacheBreakChip(info: CacheBreakInfo & { costUsd?: number }): CacheChipContent {\n const rebilled = formatTokens(info.rebilledTokens)\n const cost = info.costUsd !== undefined\n ? ` · ~$${info.costUsd < 0.01 ? '<0.01' : info.costUsd.toFixed(2)}`\n : ''\n\n // No named dimension changed → the prefix simply aged out of the provider's\n // cache window. Reported quietly: nothing was done wrong.\n if (info.changed.length === 0) {\n return { tone: 'dim', glyph: '⚡', label: `cache expired · +${rebilled} tok${cost}` }\n }\n\n return {\n tone: 'warn',\n glyph: '⚡',\n label: `cache break · ${info.changed.join(',')} · +${rebilled} tok${cost}`,\n }\n}\n\n/**\n * Transcript-row text for a persisted cache-break notice. Multi-line, one\n * fact per line, so both hosts can show a short headline and fold or list\n * the rest:\n *\n * cache break ↑116.9k tokens ~$0.48\n * messagePrefix: message 16 of 41→43 rewritten\n * likely compaction or history trimming\n *\n * The footer chip stays terse; the row carries the culprit so a break is\n * diagnosable from the transcript. Only the headline on a TTL / eviction\n * break (nothing was done wrong).\n */\nexport function cacheBreakNoticeText(info: CacheBreakInfo & { costUsd?: number }): string {\n const rebilled = formatTokens(info.rebilledTokens)\n const cost = info.costUsd !== undefined\n ? ` ~$${info.costUsd < 0.01 ? '<0.01' : info.costUsd.toFixed(2)}`\n : ''\n const headline = `${info.changed.length === 0 ? 'cache expired' : 'cache break'} ↑${rebilled} tokens${cost}`\n // One line per changed dimension, `name: detail`; a detail may itself span\n // lines (fact, then likely cause) and only its first line takes the prefix.\n const culprits = info.changed.flatMap((dim) => {\n const detail = info.details[dim]\n if (typeof detail !== 'string' || detail.length === 0)\n return [`${dim} changed`]\n const [first, ...rest] = detail.split('\\n')\n return [`${dim}: ${first}`, ...rest]\n })\n return [headline, ...culprits].join('\\n')\n}\n\n/**\n * Provider-retry label — `retrying 2/5`, or `retrying 2/5 · child-3` when the\n * stalled stream belongs to a subagent rather than the parent.\n *\n * Naming the source matters: with subagents in flight, an unattributed\n * \"retrying\" leaves the user unable to tell whether their own turn is stuck or\n * a delegated worker is.\n */\nexport function retryLabel(info: { attempt: number, max: number, source: string }): string {\n const suffix = info.source === 'parent' ? '' : ` · ${info.source}`\n return `retrying ${info.attempt}/${info.max}${suffix}`\n}\n\n/**\n * Footer label while a compaction summary is being generated:\n * `Compacting...`, then `~12k` once the loop reports a token estimate, then\n * ` · 8s` once a second has passed. Same rule on every surface so a\n * minutes-long compaction of a large transcript reads as progress — not a\n * hang — identically in the TUI and the GUI.\n *\n * `now` is injectable so callers driving a 1 Hz tick don't have to re-read\n * the clock, and so tests are deterministic.\n */\n/**\n * The live run readout: `1m 15s · ↓1.2k · 41 tok/s`. Time runs from the\n * run's start, the count covers the whole run (settled turns plus the one\n * streaming), and the rate is the honest windowed figure from\n * `stepStreamRate` (`null` until it has one). `↓~` marks a count that is\n * still the character heuristic. A tool-only stretch shows just the time.\n *\n * `detail` drops the least useful part first when space runs out:\n * `'full'` → `'count'` (no rate) → `'time'`.\n */\nexport function runStatusLabel(\n run: { elapsedSec: number, outputTokens: number, estimated: boolean, rate: number | null },\n detail: 'full' | 'count' | 'time' = 'full',\n): string {\n const parts = [formatElapsed(Math.max(0, Math.floor(run.elapsedSec)))]\n if (detail !== 'time' && run.outputTokens > 0)\n parts.push(`↓${run.estimated ? '~' : ''}${fmtTokens(run.outputTokens)}`)\n if (detail === 'full' && run.outputTokens > 0 && run.rate !== null && run.rate > 0)\n parts.push(`${run.rate} tok/s`)\n return parts.join(' · ')\n}\n\n/**\n * Live counter for one streaming turn: `↓1.2k`, `↓~1.2k` for the character\n * heuristic, `↓1.2k · 41 tok/s` when an honest rate is passed in (see\n * `stepStreamRate`; dividing tokens by time since the request counted the\n * wait for the first token and the estimate correction). Empty until the\n * first token.\n */\nexport function streamingLabel(\n progress: { outputTokens: number, estimated: boolean } | null | undefined,\n opts: { rate?: number | null } = {},\n): string {\n if (!progress || progress.outputTokens <= 0)\n return ''\n const count = `↓${progress.estimated ? '~' : ''}${fmtTokens(progress.outputTokens)}`\n return opts.rate ? `${count} · ${opts.rate} tok/s` : count\n}\n\n/**\n * Session cost while a turn streams: settled figure plus the running estimate\n * for the in-flight turn. `estimated` tells the surface to render it dimmed\n * (the number will move, then snap to the settled value at turn end). `null`\n * when there is nothing to show — never `$0.00`.\n */\nexport function liveSessionCost(\n settledUsd: number,\n progress: { estCostUsd?: number } | null | undefined,\n): { usd: number, estimated: boolean } | null {\n const live = progress?.estCostUsd ?? 0\n const total = settledUsd + live\n if (total <= 0)\n return null\n return { usd: total, estimated: live > 0 }\n}\n\nexport function compactingLabel(\n estTokens: number | null | undefined,\n startedAt: number | null | undefined,\n now: number = Date.now(),\n): string {\n const base = 'Compacting...'\n const elapsedMs = typeof startedAt === 'number' ? now - startedAt : 0\n const elapsed = elapsedMs >= 1000 ? ` · ${formatDuration(elapsedMs)}` : ''\n return typeof estTokens === 'number' && estTokens > 0\n ? `${base} ~${fmtTokens(estTokens)}${elapsed}`\n : `${base}${elapsed}`\n}\n","/**\n * Completion provider for cross-chat references. Trigger: `#`.\n *\n * The visible row is human-friendly (session title, age, project), but the\n * inserted token is id-based (`#abc123`) so titles with spaces never enter the\n * prompt grammar. The token is the shortest normalized id prefix that is unique\n * within the reference catalog, with a six-character floor for readability.\n */\n\nimport type {\n CompletionContext,\n CompletionItem,\n CompletionProvider,\n CompletionReference,\n} from './completion-core'\nimport { Fzf } from 'fzf'\nimport { ageString, shortId } from './format'\n\nexport const CHATS_TRIGGER = '#'\n\nconst DEFAULT_RESULT_LIMIT = 50\nconst MIN_TOKEN_LENGTH = 6\n\nexport type ChatReferenceScope = 'project' | 'all'\n\nexport interface ChatReferenceEntry {\n id: string\n title: string\n turnCount: number\n userMessageCount: number\n runCount: number\n projectRoot?: string\n updatedAt: number\n /** Optional (store-dependent); shown as a hint when > 0. */\n artifactCount?: number\n}\n\nexport interface ChatReferenceData {\n entry: ChatReferenceEntry\n token: string\n}\n\nfunction normalizeId(id: string): string {\n return id.replace(/-/g, '').toLowerCase()\n}\n\nfunction projectLabel(projectRoot: string | undefined): string {\n if (!projectRoot)\n return ''\n const parts = projectRoot.split(/[\\\\/]/).filter(Boolean)\n return parts[parts.length - 1] ?? projectRoot\n}\n\n/**\n * Per-catalog memo for `tokenFor`, keyed on catalog reference identity.\n * Token derivation is O(catalog) per id, and both `suggest()` (every\n * keystroke) and `parseReferences()` (every submit/highlight pass) need\n * a token for EVERY entry — quadratic over catalogs that can reach\n * thousands of sessions. The catalog getters return a stable array until\n * a refresh swaps it, so a WeakMap invalidates exactly when it should.\n */\nconst tokensByCatalog = new WeakMap<readonly ChatReferenceEntry[], { normalizedIds: string[], tokens: Map<string, string> }>()\n\nfunction catalogTokens(catalog: readonly ChatReferenceEntry[]): { normalizedIds: string[], tokens: Map<string, string> } {\n let cached = tokensByCatalog.get(catalog)\n if (!cached) {\n cached = { normalizedIds: catalog.map(entry => normalizeId(entry.id)), tokens: new Map() }\n tokensByCatalog.set(catalog, cached)\n }\n return cached\n}\n\nfunction tokenFor(id: string, catalog: readonly ChatReferenceEntry[]): string {\n const { normalizedIds, tokens } = catalogTokens(catalog)\n const known = tokens.get(id)\n if (known !== undefined)\n return known\n const normalized = normalizeId(id)\n let result: string | undefined\n for (let len = Math.min(MIN_TOKEN_LENGTH, normalized.length); len <= normalized.length; len++) {\n const token = normalized.slice(0, len)\n const matches = normalizedIds.filter(candidate => candidate.startsWith(token))\n if (matches.length === 1) {\n result = token\n break\n }\n }\n result ??= normalized || shortId(id)\n tokens.set(id, result)\n return result\n}\n\nfunction stripTrailingPunctuation(candidate: string): string {\n return candidate.replace(/[.,;:)\\]}!?]+$/, '')\n}\n\nfunction descriptionFor(entry: ChatReferenceEntry, token: string, scope: ChatReferenceScope): string {\n const bits = [\n `#${token}`,\n ageString(entry.updatedAt),\n `${entry.userMessageCount} msg${entry.userMessageCount === 1 ? '' : 's'}`,\n ]\n if ((entry.artifactCount ?? 0) > 0)\n bits.push(`${entry.artifactCount} artifact${entry.artifactCount === 1 ? '' : 's'}`)\n const project = projectLabel(entry.projectRoot)\n if (scope === 'all' && project)\n bits.push(project)\n return bits.join(' · ')\n}\n\nfunction scoreChats(\n catalog: readonly ChatReferenceEntry[],\n tokenCatalog: readonly ChatReferenceEntry[],\n query: string,\n limit: number,\n scope: ChatReferenceScope,\n): CompletionItem<ChatReferenceData>[] {\n const q = query.trim().toLowerCase()\n const rows = catalog.map(entry => ({\n entry,\n token: tokenFor(entry.id, tokenCatalog),\n project: projectLabel(entry.projectRoot),\n }))\n const fuzzyHits = q.length > 0\n ? new Set(new Fzf(rows, {\n selector: r => `${r.entry.title} ${r.token} ${r.project}`,\n casing: 'case-insensitive',\n }).find(q).map(r => r.item))\n : null\n const scored: { entry: ChatReferenceEntry, token: string, rank: number }[] = []\n for (const row of rows) {\n const title = row.entry.title.toLowerCase()\n const token = row.token.toLowerCase()\n const project = row.project.toLowerCase()\n if (q.length === 0) {\n scored.push({ entry: row.entry, token: row.token, rank: 5 })\n continue\n }\n if (token.startsWith(q)) {\n scored.push({ entry: row.entry, token: row.token, rank: 0 })\n continue\n }\n if (title.startsWith(q)) {\n scored.push({ entry: row.entry, token: row.token, rank: 1 })\n continue\n }\n if (title.includes(q)) {\n scored.push({ entry: row.entry, token: row.token, rank: 2 })\n continue\n }\n if (project.includes(q)) {\n scored.push({ entry: row.entry, token: row.token, rank: 3 })\n continue\n }\n if (fuzzyHits?.has(row)) {\n scored.push({ entry: row.entry, token: row.token, rank: 4 })\n }\n }\n scored.sort((a, b) => {\n if (a.rank !== b.rank)\n return a.rank - b.rank\n return b.entry.updatedAt - a.entry.updatedAt\n })\n return scored.slice(0, limit).map<CompletionItem<ChatReferenceData>>(({ entry, token }) => ({\n id: token,\n label: entry.title,\n description: descriptionFor(entry, token, scope),\n insertText: `${CHATS_TRIGGER}${token} `,\n data: { entry, token },\n }))\n}\n\nexport function createChatsCompletionProvider(opts: {\n getCatalog: () => readonly ChatReferenceEntry[]\n getReferenceCatalog?: () => readonly ChatReferenceEntry[]\n getScope?: () => ChatReferenceScope\n ensureCatalog?: () => Promise<readonly ChatReferenceEntry[]>\n limit?: number\n}): CompletionProvider<ChatReferenceData> {\n const limit = opts.limit ?? DEFAULT_RESULT_LIMIT\n const scope = () => opts.getScope?.() ?? 'project'\n return {\n id: 'chats',\n trigger: CHATS_TRIGGER,\n label: 'Chats',\n suggest(query) {\n const current = opts.getCatalog()\n const tokenCatalog = opts.getReferenceCatalog?.() ?? current\n const effectiveTokenCatalog = tokenCatalog.length > 0 ? tokenCatalog : current\n if (current.length > 0)\n return scoreChats(current, effectiveTokenCatalog, query, limit, scope())\n if (opts.ensureCatalog) {\n return opts.ensureCatalog().then((loaded) => {\n const refreshed = opts.getReferenceCatalog?.() ?? loaded\n const refreshedTokenCatalog = refreshed.length > 0 ? refreshed : loaded\n return scoreChats(loaded, refreshedTokenCatalog, query, limit, scope())\n })\n }\n return []\n },\n parseReferences(text, _ctx: CompletionContext) {\n const catalog = opts.getReferenceCatalog?.() ?? opts.getCatalog()\n if (catalog.length === 0)\n return []\n const byToken = new Map<string, ChatReferenceData>()\n for (const entry of catalog) {\n const token = tokenFor(entry.id, catalog)\n byToken.set(token, { entry, token })\n }\n const refs: CompletionReference<ChatReferenceData>[] = []\n const rx = /(^|\\s)#(\\S+)/g\n for (const m of text.matchAll(rx)) {\n const candidate = stripTrailingPunctuation(m[2])\n const data = byToken.get(candidate.toLowerCase())\n if (!data)\n continue\n const start = m.index + m[1].length\n refs.push({\n providerId: 'chats',\n start,\n end: start + 1 + candidate.length,\n itemId: data.entry.id,\n data,\n })\n }\n return refs\n },\n }\n}\n\nexport function uniqueChatIdsFromReferences(\n references: readonly CompletionReference<unknown>[],\n): string[] {\n const out: string[] = []\n const seen = new Set<string>()\n for (const ref of references) {\n if (ref.providerId !== 'chats')\n continue\n if (seen.has(ref.itemId))\n continue\n seen.add(ref.itemId)\n out.push(ref.itemId)\n }\n return out\n}\n\nexport function chatReferenceTokensFromText(text: string): string[] {\n const out: string[] = []\n const seen = new Set<string>()\n const rx = /(^|\\s)#(\\S+)/g\n for (const m of text.matchAll(rx)) {\n const token = stripTrailingPunctuation(m[2]).toLowerCase()\n if (!token || seen.has(token))\n continue\n seen.add(token)\n out.push(token)\n }\n return out\n}\n","/**\n * The dev browser's automation contract: what the agent's `browser_*` tools\n * send, what the GUI (the process that owns the page) answers. Plain data\n * both ways, so it crosses the daemon socket and IPC unchanged.\n */\n\n/** A target on the page: a snapshot ref (preferred), a CSS selector / `text=` / `role=` locator, or a point. */\nexport interface BrowserTarget {\n ref?: string\n selector?: string\n x?: number\n y?: number\n}\n\nexport type BrowserWaitUntil = 'load' | 'domcontentloaded' | 'none'\n\nexport interface BrowserOpInputs {\n open: { url?: string, show?: boolean }\n navigate: { url?: string, action?: 'back' | 'forward' | 'reload', waitUntil?: BrowserWaitUntil, timeoutMs?: number }\n snapshot: Record<string, never>\n screenshot: { ref?: string }\n click: BrowserTarget & { timeoutMs?: number }\n type: BrowserTarget & { text: string, clear?: boolean, submit?: boolean, timeoutMs?: number }\n press: { key: string, modifiers?: ('Alt' | 'Control' | 'Meta' | 'Shift')[] }\n scroll: BrowserTarget & { dx?: number, dy?: number }\n wait_for: { text?: string, selector?: string, urlIncludes?: string, timeoutMs?: number }\n evaluate: { expression: string }\n console: { since?: number, level?: 'error' | 'warning' | 'all' }\n}\n\nexport type BrowserOp = keyof BrowserOpInputs\n\nexport const BROWSER_OPS = [\n 'open',\n 'navigate',\n 'snapshot',\n 'screenshot',\n 'click',\n 'type',\n 'press',\n 'scroll',\n 'wait_for',\n 'evaluate',\n 'console',\n] as const satisfies readonly BrowserOp[]\n\nexport interface BrowserStatus {\n url: string\n title: string\n loading: boolean\n viewport?: { width: number, height: number }\n}\n\n/** What changed on the page because of an action; the agent reads this instead of re-snapshotting every step. */\nexport interface BrowserChange {\n /** The element acted on, by its accessible name (or tag when it has none). */\n target?: string\n url?: string\n title?: string\n /** A JavaScript dialog the page opened, and what was done with it. */\n dialog?: { type: string, message: string, handled: 'accepted' | 'dismissed' }\n /** Console errors and failed requests since the action started. */\n errors?: string[]\n /** The page navigated or changed a lot: refs from the last snapshot may be gone. */\n refsStale?: boolean\n}\n\nexport interface BrowserConsoleEntry {\n seq: number\n level: 'error' | 'warning' | 'info' | 'log' | 'debug'\n text: string\n /** Set for failed network requests. */\n url?: string\n}\n\nexport interface BrowserSnapshot {\n status: BrowserStatus\n /** One line per interactive or landmark element, `[ref=eN]` on the ones you can act on. */\n outline: string\n /** Elements left out because of the cap. */\n truncated: number\n text: string\n errors: string[]\n}\n\nexport interface BrowserScreenshot {\n /** Base64 JPEG. */\n data: string\n mediaType: 'image/jpeg'\n width: number\n height: number\n /** Image pixels per CSS pixel: divide image coordinates by this to click. */\n scale: number\n}\n\nexport interface BrowserOpResults {\n open: BrowserStatus\n navigate: BrowserStatus\n snapshot: BrowserSnapshot\n screenshot: BrowserScreenshot\n click: BrowserChange\n type: BrowserChange\n press: BrowserChange\n scroll: BrowserChange & { scrollX?: number, scrollY?: number }\n wait_for: BrowserStatus\n evaluate: { value: unknown }\n console: { entries: BrowserConsoleEntry[], next: number }\n}\n\nexport type BrowserErrorCode\n = | 'no_browser'\n | 'no_page'\n | 'stale_ref'\n | 'not_found'\n | 'not_actionable'\n | 'invalid_url'\n | 'invalid_input'\n | 'timeout'\n | 'interrupted'\n | 'cancelled'\n | 'too_large'\n | 'failed'\n\nexport interface BrowserRequest<O extends BrowserOp = BrowserOp> {\n requestId: string\n sessionId: string\n op: O\n input: BrowserOpInputs[O]\n timeoutMs: number\n}\n\nexport type BrowserResponse<O extends BrowserOp = BrowserOp>\n = | { ok: true, result: BrowserOpResults[O] }\n | { ok: false, error: { code: BrowserErrorCode, message: string } }\n\nexport class BrowserOpError extends Error {\n constructor(readonly code: BrowserErrorCode, message: string) {\n super(message)\n this.name = 'BrowserOpError'\n }\n}\n\n/** Default and ceiling for an action's own wait (element to become actionable, text to appear). */\nexport const BROWSER_ACTION_TIMEOUT_MS = 5_000\nexport const BROWSER_WAIT_TIMEOUT_MS = 10_000\nexport const BROWSER_MAX_WAIT_MS = 30_000\n/** How long the host waits for a page to mount and register before `open` gives up. */\nexport const BROWSER_OPEN_MOUNT_MS = 15_000\n/** Transport budget on top of the action's own wait. */\nexport const BROWSER_REQUEST_SLACK_MS = 5_000\nexport const BROWSER_EVALUATE_MAX_BYTES = 64 * 1024\nexport const BROWSER_OUTLINE_MAX_ELEMENTS = 250\nexport const BROWSER_TEXT_MAX_CHARS = 8_000\n","/**\n * Terminals: the contract between the host that runs them (the daemon) and\n * the clients that show them (the GUI's drawer and panel tab). Pure types\n * and limits, safe for a renderer bundle.\n *\n * Output travels as text with a running character offset: a client knows\n * where each chunk starts, drops what it already has, and acknowledges what\n * it wrote. The host stops sending to clients that fall a window behind and\n * later resets them from history instead of queueing without end.\n */\n\n/** Who started it: the user, or the agent (a background `shell` task). */\nexport type TerminalOwner = 'user' | 'agent'\n\n/** Where it runs: the session's environment, or this machine in the project. */\nexport type TerminalTarget = 'session' | 'local'\n\n/**\n * `paused`: not connected right now (the sandbox paused, or the host\n * restarted) but it can be found again; opening it reconnects.\n */\nexport type TerminalStatus = 'starting' | 'running' | 'paused' | 'exited' | 'error'\n\nexport interface TerminalInfo {\n id: string\n sessionId: string\n /** Stable name (\"Terminal 2\", or the agent's command). */\n label: string\n /** Title the program set (OSC 0/2), if any. */\n title?: string\n /** The program in the foreground, for terminals on this machine. */\n program?: string\n owner: TerminalOwner\n target: TerminalTarget\n /** Environment kind it runs in (`local`, `worktree`, `docker`, `e2b`, …). */\n environment: string\n cwd: string\n status: TerminalStatus\n exitCode?: number\n error?: string\n cols: number\n rows: number\n /**\n * Bumped on every size change: signals and attach replies reach a view by\n * different routes, so it keeps the newest size, not the last to arrive.\n */\n sizeSeq: number\n /** The agent's terminal tools skip it. */\n hiddenFromAgent: boolean\n /** The background task it runs (agent terminals). */\n taskId?: string\n createdAt: number\n lastActivityAt: number\n}\n\nexport interface TerminalSessionState {\n /** False when this host can't run terminals (the GUI without the daemon). */\n available: boolean\n /** Why not, when `available` is false. */\n reason?: string\n /** Kind of the session's environment, and whether it runs somewhere else. */\n environment: { kind: string, remote: boolean }\n terminals: TerminalInfo[]\n}\n\nexport interface TerminalOpenInput {\n sessionId: string\n target?: TerminalTarget\n cols: number\n rows: number\n}\n\n/** What a client needs to start showing a terminal: its history, and where live output resumes. */\nexport interface TerminalAttachResult {\n terminal: TerminalInfo\n data: string\n offset: number\n}\n\n/** The agent's view: plain text lines, with a cursor for the next read. */\nexport interface TerminalReadResult {\n terminal: TerminalInfo\n text: string\n /** Pass as `since` to get only newer lines. */\n next: number\n /** Lines dropped from the front because of the size cap. */\n truncated: number\n}\n\n/** Characters a client may be behind before the host stops sending to it. */\nexport const TERMINAL_OUTPUT_WINDOW = 256 * 1024\n/** History kept per terminal for new views (characters). */\nexport const TERMINAL_HISTORY_MAX_CHARS = 4 * 1024 * 1024\n/** Plain-text lines kept per terminal for the agent. */\nexport const TERMINAL_TEXT_MAX_LINES = 5000\n/** Most the agent gets from one read (characters). */\nexport const TERMINAL_READ_MAX_CHARS = 16 * 1024\n/** Terminals a session may have open at once. */\nexport const TERMINAL_MAX_PER_SESSION = 12\n\nexport class TerminalError extends Error {\n constructor(readonly code: 'unavailable' | 'not_found' | 'limit' | 'not_running' | 'failed', message: string) {\n super(message)\n this.name = 'TerminalError'\n }\n}\n","// ---------------------------------------------------------------------------\n// HSL color gradient helpers — shared between the Crush throbber (cycling\n// per-frame paint) and the title overlay (static per-character paint).\n//\n// Renderer-agnostic on purpose: a future GUI shell wants the same ramp\n// math against the same hex strings the theme palette already stores, so\n// this lives in `zidane/chat` next to the theme definition rather than\n// inside the TUI's OpenTUI layer.\n//\n// We blend in HSL with shortest-path hue interpolation rather than\n// straight sRGB lerp because saturated palette pairs (e.g. Charple →\n// Dolly = purple → magenta) would muddy through grey when interpolated\n// componentwise in RGB. HSL keeps the path along the hue ring, so the\n// gradient stays vivid.\n// ---------------------------------------------------------------------------\n\n/** Parse `#rrggbb` (case-insensitive) into `[r, g, b]` 0–255 integers. */\nfunction parseHex(hex: string): [number, number, number] {\n const h = hex.replace('#', '')\n return [\n Number.parseInt(h.slice(0, 2), 16),\n Number.parseInt(h.slice(2, 4), 16),\n Number.parseInt(h.slice(4, 6), 16),\n ]\n}\n\n/** Convert sRGB 0–255 → HSL 0–1. */\nfunction rgbToHsl(r: number, g: number, b: number): [number, number, number] {\n r /= 255\n g /= 255\n b /= 255\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n const l = (max + min) / 2\n if (max === min)\n return [0, 0, l]\n const d = max - min\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)\n let h: number\n if (max === r)\n h = (g - b) / d + (g < b ? 6 : 0)\n else if (max === g)\n h = (b - r) / d + 2\n else\n h = (r - g) / d + 4\n return [h / 6, s, l]\n}\n\n/** Convert HSL 0–1 → sRGB 0–255. Standard piecewise formula. */\nfunction hslToRgb(h: number, s: number, l: number): [number, number, number] {\n if (s === 0)\n return [l * 255, l * 255, l * 255]\n const hue2rgb = (p: number, q: number, t: number) => {\n if (t < 0)\n t += 1\n if (t > 1)\n t -= 1\n if (t < 1 / 6)\n return p + (q - p) * 6 * t\n if (t < 1 / 2)\n return q\n if (t < 2 / 3)\n return p + (q - p) * (2 / 3 - t) * 6\n return p\n }\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s\n const p = 2 * l - q\n return [\n hue2rgb(p, q, h + 1 / 3) * 255,\n hue2rgb(p, q, h) * 255,\n hue2rgb(p, q, h - 1 / 3) * 255,\n ]\n}\n\nfunction toHex(rgb: readonly [number, number, number]): string {\n const pad = (v: number) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, '0')\n return `#${pad(rgb[0])}${pad(rgb[1])}${pad(rgb[2])}`\n}\n\n/**\n * Blend two hex colors in HSL space with shortest-path hue interpolation.\n * `t` ∈ [0, 1]; `t=0` returns `from`, `t=1` returns `to`.\n */\nexport function blendHsl(from: string, to: string, t: number): string {\n const [r1, g1, b1] = parseHex(from)\n const [r2, g2, b2] = parseHex(to)\n const [h1, s1, l1] = rgbToHsl(r1, g1, b1)\n const [h2, s2, l2] = rgbToHsl(r2, g2, b2)\n // Shortest path around the hue wheel — purple→pink shouldn't detour\n // through cyan just because the raw subtraction is positive.\n let dh = h2 - h1\n if (dh > 0.5)\n dh -= 1\n else if (dh < -0.5)\n dh += 1\n const h = (h1 + dh * t + 1) % 1\n const s = s1 + (s2 - s1) * t\n const l = l1 + (l2 - l1) * t\n return toHex(hslToRgb(h, s, l))\n}\n\n/**\n * Static gradient ramp of length `n` going from `from` (index 0) to\n * `to` (index n-1) in HSL space. For the cycling A→B→A→B ramp the\n * throbber uses, see `buildCycleRamp` in `src/tui/crush-throbber.tsx`.\n */\nexport function buildLinearRamp(from: string, to: string, n: number): string[] {\n if (n <= 0)\n return []\n if (n === 1)\n return [blendHsl(from, to, 0.5)]\n const ramp: string[] = []\n for (let i = 0; i < n; i++)\n ramp.push(blendHsl(from, to, i / (n - 1)))\n return ramp\n}\n","/**\n * Completion provider exposing `/` commands in the popover, as a peer to the\n * skills provider on the same trigger (the engine merges both via\n * {@link mergeSuggestions}, tagging each with its `label` section).\n *\n * Suggest-only: commands are invoked as the WHOLE prompt (`/name …`), so\n * they're not inline \"references\". `parseReferences` returns none; the host's\n * submit path detects command invocations via `parseCommandInvocation`.\n */\n\nimport type { Command } from './commands'\nimport type { CompletionItem, CompletionProvider } from './completion-core'\nimport { Fzf } from 'fzf'\n\n/** Trigger character — shared with skills. */\nexport const COMMANDS_TRIGGER = '/'\n\n/**\n * Per-catalog fzf instance, keyed on catalog reference identity —\n * `suggest()` runs per keystroke and `new Fzf(...)` walks the whole\n * command list to build its match structures. The getter returns a\n * stable array until a registry rebuild swaps it.\n */\nconst fzfByCatalog = new WeakMap<readonly Command[], Fzf<readonly Command[]>>()\n\nfunction fzfFor(catalog: readonly Command[]): Fzf<readonly Command[]> {\n let fzf = fzfByCatalog.get(catalog)\n if (!fzf) {\n fzf = new Fzf(catalog, { selector: c => c.name, casing: 'case-insensitive' })\n fzfByCatalog.set(catalog, fzf)\n }\n return fzf\n}\n\n/** Filter + rank commands against a query (name-priority, then description, then fuzzy on name). */\nfunction scoreCommands(catalog: readonly Command[], query: string): CompletionItem<Command>[] {\n const q = query.trim().toLowerCase()\n const fuzzyHits = q.length > 0\n ? new Set(fzfFor(catalog).find(q).map(r => r.item))\n : null\n const scored: { command: Command, rank: number }[] = []\n for (const command of catalog) {\n const name = command.name.toLowerCase()\n const aliases = (command.aliases ?? []).map(a => a.toLowerCase())\n const group = command.group?.toLowerCase()\n const desc = command.description.toLowerCase()\n if (q.length === 0)\n scored.push({ command, rank: 4 })\n else if (name.startsWith(q) || aliases.some(a => a.startsWith(q)))\n scored.push({ command, rank: 0 })\n // Group (source extension) match — `/git-flow` lists every command the\n // git-flow extension contributes. Ranked with name-substring hits so\n // they sit above description/fuzzy noise. Requires ≥2 typed chars so a\n // single letter (`/g`) doesn't flood every command of a same-initial\n // extension above ordinary matches.\n else if (name.includes(q) || aliases.some(a => a.includes(q)) || (group !== undefined && q.length >= 2 && group.startsWith(q)))\n scored.push({ command, rank: 1 })\n else if (desc.includes(q))\n scored.push({ command, rank: 2 })\n else if (fuzzyHits?.has(command))\n scored.push({ command, rank: 3 })\n }\n scored.sort((a, b) => a.rank !== b.rank ? a.rank - b.rank : a.command.name.localeCompare(b.command.name))\n return scored.map<CompletionItem<Command>>(({ command }) => ({\n id: command.name,\n label: command.name,\n description: command.aliases?.length\n ? `${command.description} (alias: ${command.aliases.map(a => `/${a}`).join(', ')})`\n : command.description,\n insertText: `${COMMANDS_TRIGGER}${command.name} `,\n data: command,\n }))\n}\n\n/**\n * Build a commands completion provider against a *live* command list. The\n * getter is re-evaluated per `suggest` so registry toggles / cwd rebuilds\n * take effect without re-instantiating the provider.\n */\nexport function createCommandsCompletionProvider(opts: {\n getCommands: () => readonly Command[]\n}): CompletionProvider<Command> {\n return {\n id: 'commands',\n trigger: COMMANDS_TRIGGER,\n label: 'Commands',\n // Stay active across spaces so `/deploy stag▌` reaches us with query\n // `deploy stag` for ARGUMENT completion (see `allowSpacesInQuery`).\n allowSpacesInQuery: true,\n suggest(query, ctx) {\n // Argument position: `<name> <argsPrefix>` where <name> is a known\n // command that offers completions — and only when the invocation is\n // the whole prompt (leading token), matching submit semantics.\n const spaceIdx = query.search(/\\s/)\n if (spaceIdx !== -1) {\n if (ctx.text.trimStart()[0] !== COMMANDS_TRIGGER)\n return []\n const typed = query.slice(0, spaceIdx).toLowerCase()\n const command = opts.getCommands().find(c =>\n c.name.toLowerCase() === typed || c.aliases?.some(a => a.toLowerCase() === typed))\n if (!command?.completeArgs)\n return []\n const argsPrefix = query.slice(spaceIdx + 1).replace(/^\\s+/, '')\n return Promise.resolve(command.completeArgs(argsPrefix)).then(suggestions =>\n (suggestions ?? []).map(s => ({\n id: `${command.name}:${s.value}`,\n label: s.label ?? s.value,\n ...(s.description !== undefined ? { description: s.description } : {}),\n insertText: `${COMMANDS_TRIGGER}${command.name} ${s.value} `,\n data: command,\n })),\n )\n }\n return scoreCommands(opts.getCommands(), query)\n },\n // Commands are whole-prompt invocations, not inline references.\n parseReferences() {\n return []\n },\n }\n}\n","/**\n * Completion provider that exposes the discovered project file catalog\n * (files AND directories — see `FileEntry.kind`) as `@`-prefixed\n * mentions. Trigger: `@`. Filtering: substring against `name + path`,\n * case-insensitive. Inserted text is `@{path} ` (`@{path}/ ` for\n * directories) so the cursor lands ready for the next token.\n *\n * Provider is pure UI — file *attachment* (reading bytes, injecting into\n * the prompt) happens at the submission boundary, where the host walks\n * `state.references` and decides what to do with each `FileEntry`.\n */\n\nimport type {\n CompletionContext,\n CompletionItem,\n CompletionProvider,\n CompletionReference,\n} from './completion-core'\nimport type { FileEntry } from './files-discovery'\nimport { Fzf } from 'fzf'\n\n/** Trigger character — `@` is the conventional file-mention prefix in chat UIs. */\nexport const FILES_TRIGGER = '@'\n\n/** Cap on returned items. Keeps the popover compact + render-cheap. */\nconst DEFAULT_RESULT_LIMIT = 50\n\n/** Identity formatter — preserves the discovery path verbatim. */\nconst IDENTITY_FORMAT = (entry: FileEntry): string => entry.path\n\n/**\n * Per-catalog fzf instance, keyed on catalog reference identity.\n * `suggest()` runs on every keystroke and `new Fzf(...)` walks the whole\n * catalog (up to ~10k entries on monorepos) to build its match structures\n * — rebuilding that per keystroke dominated the popover's latency. The\n * catalog getter returns a stable array until a re-scan swaps it, so a\n * WeakMap on the array reference invalidates exactly when it should.\n */\nconst fzfByCatalog = new WeakMap<readonly FileEntry[], Fzf<readonly FileEntry[]>>()\n\nfunction fzfFor(catalog: readonly FileEntry[]): Fzf<readonly FileEntry[]> {\n let fzf = fzfByCatalog.get(catalog)\n if (!fzf) {\n fzf = new Fzf(catalog, {\n selector: f => f.name,\n casing: 'case-insensitive',\n })\n fzfByCatalog.set(catalog, fzf)\n }\n return fzf\n}\n\n/**\n * Displayed/inserted form of a catalog entry. Directories carry a\n * trailing `/` so the emitted mention (`@src/chat/`) is visually and\n * semantically unambiguous — both to the user and to the agent's\n * path-resolving tools.\n */\nfunction displayOf(entry: FileEntry, formatPath: (entry: FileEntry) => string): string {\n const base = formatPath(entry)\n return entry.kind === 'dir' && !base.endsWith('/') ? `${base}/` : base\n}\n\n/**\n * Rank-and-slice a file catalog against a query. Hoisted to a module\n * helper so both the sync and async branches of `suggest()` share one\n * implementation (the async branch hits this once the lazy directory\n * walk resolves; sync branch hits it on every keystroke thereafter).\n *\n * `formatPath` rewrites the catalog's project-root-relative path into\n * the form the host wants emitted into the prompt (typically CWD-rel\n * or absolute when launched from a project subdir — see\n * `formatPathForCwd` in `path-display.ts`). Falls back to the raw\n * `entry.path` when omitted.\n */\nfunction scoreFiles(\n catalog: readonly FileEntry[],\n query: string,\n limit: number,\n formatPath: (entry: FileEntry) => string,\n): CompletionItem<FileEntry>[] {\n const q = query.trim().toLowerCase()\n // Pre-pass: fzf over the catalog's basenames feeds the rank-4 fuzzy\n // tier, catching small typos / omissions (`lop.ts` → `loop.ts`).\n // Scoped to basename — a path-wide fuzzy match would surface\n // near-random files on short queries. fzf enforces in-order\n // (subsequence) matching, so the fuzzy tier never degenerates into a\n // bag-of-chars filter. We keep only set membership (not fzf's score):\n // within-tier ordering stays alphabetical, and the Set keeps the loop\n // below O(1) per file.\n const fuzzyHits = q.length > 0\n ? new Set(fzfFor(catalog).find(q).map(r => r.item))\n : null\n const scored: { entry: FileEntry, display: string, rank: number }[] = []\n for (const file of catalog) {\n const display = displayOf(file, formatPath)\n const name = file.name.toLowerCase()\n const path = display.toLowerCase()\n if (q.length === 0) {\n scored.push({ entry: file, display, rank: 5 })\n continue\n }\n if (name === q) {\n scored.push({ entry: file, display, rank: 0 })\n continue\n }\n if (name.startsWith(q)) {\n scored.push({ entry: file, display, rank: 1 })\n continue\n }\n if (name.includes(q)) {\n scored.push({ entry: file, display, rank: 2 })\n continue\n }\n if (path.includes(q)) {\n scored.push({ entry: file, display, rank: 3 })\n continue\n }\n if (fuzzyHits?.has(file)) {\n scored.push({ entry: file, display, rank: 4 })\n continue\n }\n }\n scored.sort((a, b) => {\n if (a.rank !== b.rank)\n return a.rank - b.rank\n return a.display.localeCompare(b.display)\n })\n return scored.slice(0, limit).map<CompletionItem<FileEntry>>(({ entry, display }) => ({\n id: display,\n // Directories carry the trailing `/` on the label too so rows are\n // distinguishable at a glance in the popover.\n label: entry.kind === 'dir' ? `${entry.name}/` : entry.name,\n // Description is the parent directory — gives the user disambiguation\n // signal when multiple files share a basename (`index.ts` × 12).\n //\n // Uses the catalog's RAW project-root-relative path, NOT the\n // cwd-formatted `display`. The cwd-formatted path flips a file's\n // visible shape based on whether it sits above or below\n // `process.cwd()` (absolute parent vs cwd-relative parent vs\n // empty for \"right here\"), which produces a popover that looks\n // half-broken when the same basename exists in multiple project\n // locations: `EDIT_THIS.md /Users/…/zidane` next to plain\n // `EDIT_THIS.md` for a sibling under the cwd. Anchoring the\n // description on `file.path` keeps the disambiguation column\n // stable + project-shaped regardless of where the user launched\n // the TUI from; the inserted text still uses `display` so the\n // tools can resolve it.\n description: parentDir(entry.path),\n insertText: `${FILES_TRIGGER}${display} `,\n data: entry,\n }))\n}\n\n/**\n * Build an `@`-prefixed files completion provider against a *live* catalog.\n *\n * The factory captures a getter so the catalog can be re-scanned (cwd\n * change, manual refresh) without re-instantiating the provider — the\n * App keeps one provider for the lifetime of the prompt block and just\n * mutates the underlying state.\n *\n * `limit` caps the result list so the popover stays bounded on huge\n * monorepos. Filtering is substring on `path` + `name`, case-insensitive,\n * with an fzf-scored basename fuzzy fallback so small typos / omissions\n * (`lop.ts` → `loop.ts`) still surface results; ranking prefers (in\n * order): exact name match, name prefix, name substring, path substring,\n * basename fuzzy match, alphabetical.\n */\nexport function createFilesCompletionProvider(opts: {\n /** Live file catalog. Re-evaluated per call so refreshes take effect immediately. */\n getCatalog: () => readonly FileEntry[]\n /**\n * Optional hook called the first time the host needs the catalog —\n * e.g. when the user opens the `@` popover. Hosts wire this to a\n * lazy directory walk so boot doesn't pay for it in monorepos\n * where the popover may never open. Idempotent contract: callers\n * may invoke it on every `suggest`; the host caches internally.\n *\n * When provided, `suggest()` returns a Promise on the very first\n * invocation if the catalog is still empty — the popover's loading\n * state surfaces while the walk completes; subsequent calls are\n * sync because `getCatalog()` then returns the populated state.\n */\n ensureCatalog?: () => Promise<readonly FileEntry[]>\n /** Max items returned to the popover. Default: 50. */\n limit?: number\n /**\n * Rewrite the catalog's project-root-relative path into the form\n * inserted into the prompt + matched by `parseReferences`. Wire this\n * to `formatPathForCwd` so paths emitted into the buffer line up\n * with the agent's CWD-resolving tools when the TUI launches from a\n * project subdirectory. Default: identity.\n *\n * Stable identity expected — `parseReferences` calls it once per\n * catalog entry per keystroke for the highlight pass; pure\n * pure-function shape keeps the popover responsive on huge repos.\n */\n formatPath?: (entry: FileEntry) => string\n}): CompletionProvider<FileEntry> {\n const limit = opts.limit ?? DEFAULT_RESULT_LIMIT\n const formatPath = opts.formatPath ?? IDENTITY_FORMAT\n return {\n id: 'files',\n trigger: FILES_TRIGGER,\n label: 'Files',\n suggest(query) {\n // Kick off lazy discovery (no-op on subsequent calls). If the\n // host wired a thunk and the catalog isn't ready yet, hand the\n // popover a Promise — it already supports `loading` and refreshes\n // `items` when the promise resolves.\n if (opts.ensureCatalog) {\n const pending = opts.ensureCatalog()\n const current = opts.getCatalog()\n if (current.length === 0) {\n return pending.then(loaded => scoreFiles(loaded, query, limit, formatPath))\n }\n }\n return scoreFiles(opts.getCatalog(), query, limit, formatPath)\n },\n parseReferences(text, _ctx: CompletionContext) {\n const catalog = opts.getCatalog()\n if (catalog.length === 0)\n return []\n // Keyed by the DISPLAYED path (what `insertText` emitted) so a\n // post-format buffer still resolves back to its `FileEntry`.\n // Directories are additionally keyed by their slash-less form so a\n // hand-typed `@src/chat` resolves like the inserted `@src/chat/`\n // (no collision risk — a file and a dir can't share a path).\n const byPath = new Map<string, FileEntry>()\n for (const file of catalog) {\n const display = displayOf(file, formatPath)\n byPath.set(display, file)\n if (file.kind === 'dir')\n byPath.set(formatPath(file), file)\n }\n const refs: CompletionReference<FileEntry>[] = []\n // Match `@<path>` at start-of-buffer or after whitespace. Paths are\n // non-whitespace sequences — files contain `/`, `.`, `-`, etc., so a\n // word-boundary rule won't do. We greedy-match `\\S+` then trim\n // trailing punctuation that's almost never part of the intended\n // reference (sentence end). The trimmed candidate must exist in the\n // catalog for the span to be highlighted — typos don't produce\n // false-positive references.\n // Capture groups: 1 = leading boundary (start-of-buffer or whitespace),\n // 2 = path body without the `@` sigil. `@` itself is matched but not\n // captured because the consumer only needs the raw path to look up\n // the catalog entry.\n const rx = /(^|\\s)@(\\S+)/g\n for (const m of text.matchAll(rx)) {\n const rawCandidate = m[2]\n // Strip trailing `.`, `,`, `;`, `:`, `)` , `]`, `}`, `!`, `?` — when\n // the exact candidate isn't in the catalog but a shorter prefix is,\n // the user almost certainly mentioned the file in regular prose.\n // Single regex replace + slice instead of a per-char loop keeps this\n // O(n) in candidate length rather than O(n²) on pathological tails.\n const stripped = byPath.has(rawCandidate)\n ? rawCandidate\n : rawCandidate.replace(/[.,;:)\\]}!?]+$/, '')\n const file = byPath.get(stripped)\n if (!file)\n continue\n const start = m.index + m[1].length\n // `trimmed` matches the visible \"@<stripped>\" span — recompute its\n // length from `stripped` so we don't over-paint on the trailing punct.\n const trimmedLen = 1 + stripped.length // `@` + path\n refs.push({\n providerId: 'files',\n start,\n end: start + trimmedLen,\n // `itemId` mirrors `suggest()`'s `id` (the displayed path)\n // so the engine's reference ↔ item correlation stays\n // consistent on either side of the formatter. `data.path`\n // still carries the raw project-root-relative path for\n // downstream consumers (`uniqueFilesFromReferences`,\n // submission attach hooks, …). Canonicalized through\n // `displayOf` so a slash-less dir mention still correlates\n // with the suggestion item's id (which carries the `/`).\n itemId: displayOf(file, formatPath),\n data: file,\n })\n }\n return refs\n },\n }\n}\n\n/** Return the parent directory of a forward-slashed path, or `''` for root entries. */\nfunction parentDir(path: string): string {\n const lastSlash = path.lastIndexOf('/')\n return lastSlash <= 0 ? '' : path.slice(0, lastSlash)\n}\n\n/**\n * Walk a reference list and return the deduplicated set of files in\n * first-mention order — input to \"attach these files to the prompt\"\n * downstream logic.\n */\nexport function uniqueFilesFromReferences(\n references: readonly CompletionReference<unknown>[],\n): FileEntry[] {\n const out: FileEntry[] = []\n const seen = new Set<string>()\n for (const ref of references) {\n if (ref.providerId !== 'files')\n continue\n if (seen.has(ref.itemId))\n continue\n seen.add(ref.itemId)\n out.push(ref.data as FileEntry)\n }\n return out\n}\n","/**\n * Completion provider that exposes the discovered skills catalog as\n * slash-commands. Trigger: `/`. Filtering: substring against `name +\n * description`, case-insensitive. Inserted text is `/{name} ` so the\n * cursor lands ready for the next token.\n *\n * Skill activation is **not** performed here — the provider is pure UI.\n * Submission flow at the host (TUI `onSubmitPrompt`) walks the prompt for\n * skill references via `parseReferences` and calls `agent.activateSkill`\n * before `agent.run`.\n */\n\nimport type { SkillConfig } from '../skills'\nimport type {\n CompletionContext,\n CompletionItem,\n CompletionProvider,\n CompletionReference,\n} from './completion-core'\nimport { Fzf } from 'fzf'\n\n/** Trigger character — slash-commands convention. */\nexport const SKILLS_TRIGGER = '/'\n\n/** Valid skill-name shape (matches the parser): lowercase alnum + dashes. */\nconst SKILL_NAME_RX = /^[a-z0-9][a-z0-9-]*$/\n\n/**\n * Per-catalog valid-set + fzf instance, keyed on catalog reference\n * identity — `suggest()` runs per keystroke and both the name filter and\n * `new Fzf(...)` walk the whole catalog. The getter returns a stable\n * array until a reload/toggle swaps it.\n */\nconst fzfByCatalog = new WeakMap<readonly SkillConfig[], { valid: SkillConfig[], fzf: Fzf<SkillConfig[]> }>()\n\nfunction validAndFzfFor(catalog: readonly SkillConfig[]): { valid: SkillConfig[], fzf: Fzf<SkillConfig[]> } {\n let cached = fzfByCatalog.get(catalog)\n if (!cached) {\n const valid = catalog.filter(skill => SKILL_NAME_RX.test(skill.name))\n cached = {\n valid,\n fzf: new Fzf(valid, {\n selector: s => s.name,\n casing: 'case-insensitive',\n }),\n }\n fzfByCatalog.set(catalog, cached)\n }\n return cached\n}\n\n/**\n * Filter + rank visible skills against a query. Hoisted to a module\n * helper so the sync and async branches of `suggest()` share one\n * implementation (the async branch hits this once the lazy SKILL.md\n * scan resolves; sync branch hits it on every keystroke thereafter).\n */\nfunction scoreSkills(\n catalog: readonly SkillConfig[],\n query: string,\n): CompletionItem<SkillConfig>[] {\n const q = query.trim().toLowerCase()\n const { valid, fzf } = validAndFzfFor(catalog)\n // fzf pre-pass over skill *names* so the rank-3 fuzzy tier catches\n // small typos (`reseach` → `research`). Scoped to name only — fuzzy\n // matching against descriptions (free-form sentences) would surface\n // near-random skills on short queries.\n const fuzzyHits = q.length > 0\n ? new Set(fzf.find(q).map(r => r.item))\n : null\n const scored: { skill: SkillConfig, rank: number }[] = []\n for (const skill of valid) {\n const name = skill.name.toLowerCase()\n const desc = skill.description.toLowerCase()\n if (q.length === 0) {\n scored.push({ skill, rank: 4 })\n continue\n }\n if (name.startsWith(q)) {\n scored.push({ skill, rank: 0 })\n continue\n }\n if (name.includes(q)) {\n scored.push({ skill, rank: 1 })\n continue\n }\n if (desc.includes(q)) {\n scored.push({ skill, rank: 2 })\n continue\n }\n if (fuzzyHits?.has(skill)) {\n scored.push({ skill, rank: 3 })\n continue\n }\n }\n scored.sort((a, b) => {\n if (a.rank !== b.rank)\n return a.rank - b.rank\n return a.skill.name.localeCompare(b.skill.name)\n })\n return scored.map<CompletionItem<SkillConfig>>(({ skill }) => ({\n id: skill.name,\n label: skill.name,\n description: skill.description,\n insertText: `${SKILLS_TRIGGER}${skill.name} `,\n data: skill,\n }))\n}\n\n/**\n * Build a slash-command completion provider against a *live* skills\n * catalog. The factory captures a getter so the catalog can change across\n * renders (toggles, reload) without re-instantiating the provider.\n *\n * Pass `getEnabled` to additionally hide skills the user has toggled off\n * — when undefined, every catalog entry is offered.\n */\nexport function createSkillsCompletionProvider(opts: {\n /** Live catalog. Re-evaluated per call so toggles take effect immediately. */\n getCatalog: () => readonly SkillConfig[]\n /** Optional enable-set filter; when undefined every catalog skill is offered. */\n getEnabled?: () => readonly string[] | undefined\n /**\n * Optional hook called the first time the host needs the catalog —\n * typically when the user opens the `/` popover. Mirror of the\n * files provider's `ensureCatalog`; same idempotent contract.\n *\n * Hosts wire this to a lazy SKILL.md scan so the boot path stays\n * free of disk reads in deeply-nested skill trees. Returns a Promise\n * on the very first `suggest()` call when the catalog is still\n * empty so the popover surfaces its loading state.\n */\n ensureCatalog?: () => Promise<readonly SkillConfig[]>\n}): CompletionProvider<SkillConfig> {\n const visible = (): SkillConfig[] => {\n const all = opts.getCatalog()\n const enabled = opts.getEnabled?.()\n if (enabled === undefined)\n return [...all]\n const allow = new Set(enabled)\n return all.filter(s => allow.has(s.name))\n }\n return {\n id: 'skills',\n trigger: SKILLS_TRIGGER,\n label: 'Skills',\n suggest(query) {\n // Lazy-load on first suggest if the host wired a thunk. Same\n // pattern as the files provider — popover loading state covers\n // the gap, subsequent suggests are sync.\n if (opts.ensureCatalog) {\n const pending = opts.ensureCatalog()\n if (opts.getCatalog().length === 0) {\n return pending.then(() => scoreSkills(visible(), query))\n }\n }\n return scoreSkills(visible(), query)\n },\n parseReferences(text, _ctx: CompletionContext) {\n const catalog = visible()\n if (catalog.length === 0)\n return []\n const byName = new Map<string, SkillConfig>()\n for (const skill of catalog) byName.set(skill.name, skill)\n const refs: CompletionReference<SkillConfig>[] = []\n // Match `/name` at start-of-buffer or after whitespace. The lookbehind\n // is implemented manually (no regex `\\b` because `/` isn't a word\n // character) so we work in environments that lack lookbehind support.\n // Grammar must match `SKILL_NAME_RX` — `[a-z0-9-]` only, no `_`. Using\n // `\\w` here would parse `/foo_bar` as a candidate, only for the catalog\n // lookup to drop it; aligning the two grammars keeps the parser honest.\n const rx = /(^|\\s)(\\/([a-z0-9][a-z0-9-]*))/g\n for (const m of text.matchAll(rx)) {\n const name = m[3]\n const skill = byName.get(name)\n if (!skill)\n continue\n const start = m.index + m[1].length\n refs.push({\n providerId: 'skills',\n start,\n end: start + m[2].length,\n itemId: skill.name,\n data: skill,\n })\n }\n return refs\n },\n }\n}\n\n/**\n * Walk a parsed prompt for skill references and return the deduplicated\n * list of skill names — input to `agent.activateSkill(name)` calls on\n * submit.\n */\nexport function uniqueSkillNamesFromReferences(\n references: readonly CompletionReference<unknown>[],\n): string[] {\n const out: string[] = []\n const seen = new Set<string>()\n for (const ref of references) {\n if (ref.providerId !== 'skills')\n continue\n if (seen.has(ref.itemId))\n continue\n seen.add(ref.itemId)\n out.push(ref.itemId)\n }\n return out\n}\n","/**\n * Daemon connection health — the one model behind the status dot in both\n * clients' footers.\n *\n * Three states, because \"connected: boolean\" cannot express the one users\n * actually want to see: a daemon that is being spawned or reconnected is not\n * DOWN, and painting it red for the seconds that takes teaches people to\n * ignore red. So:\n *\n * - `connected` — handshake done, signals live. green (accent)\n * - `connecting` — spawning / reconnecting / first attempt. amber (warn)\n * - `disconnected` — reachable daemon absent, last attempt failed. red (error)\n *\n * Tones are theme SLOTS, not colors, so the dot recolors with the palette on\n * both surfaces. Node-free; re-exported from `zidane/chat/pure`.\n */\nexport type DaemonHealth = 'connected' | 'connecting' | 'disconnected'\n\nexport type DaemonHealthTone = 'accent' | 'warn' | 'error'\n\nexport interface DaemonHealthStyle {\n tone: DaemonHealthTone\n /** Tooltip / accessibility text. The dot itself carries no words. */\n label: string\n}\n\nexport const DAEMON_HEALTH_GLYPH = '●'\n\nexport const DAEMON_HEALTH_STYLE: Readonly<Record<DaemonHealth, DaemonHealthStyle>> = {\n connected: { tone: 'accent', label: 'daemon connected' },\n connecting: { tone: 'warn', label: 'connecting to daemon…' },\n disconnected: { tone: 'error', label: 'daemon unreachable' },\n}\n","// ---------------------------------------------------------------------------\n// Renderer-agnostic markdown text segmenter.\n//\n// `splitMarkdownCodeBlocks` walks a markdown string once and emits an\n// ordered list of prose / fenced-code segments. Useful for any consumer\n// that wants to render fenced code differently from prose (a TUI that\n// wraps fences with a copy header, a GUI that hands fenced bodies to a\n// Monaco-style editor, a renderer that pipes prose through `marked` and\n// fences through Shiki, etc).\n//\n// Lives in `zidane/chat` so future renderer shells get the same\n// segmenter — no OpenTUI dependency, no React dependency, pure\n// string-in / array-out.\n// ---------------------------------------------------------------------------\n\n/**\n * One block returned by {@link splitMarkdownCodeBlocks}. Prose segments\n * carry their original markdown (including blank lines that bracketed\n * the fence) so the surrounding paragraph spacing stays faithful to the\n * original input. Code segments carry the raw body — fence markers and\n * info-string stripped — so a \"copy code\" action lands what the user\n * actually sees, byte-for-byte.\n */\nexport interface MarkdownSegment {\n kind: 'prose' | 'code'\n content: string\n /** Info-string (e.g. `ts`, `python`). Empty when the fence had none. */\n lang?: string\n /**\n * `true` on a code segment whose closing fence hasn't arrived yet —\n * i.e. the trailing block during streaming. Consumers can render this\n * in \"streaming\" mode (no copy affordance, partial-highlight pipeline)\n * until the closer lands and it flips to a regular closed segment.\n */\n open?: boolean\n}\n\n/**\n * Split markdown text into alternating prose / fenced-code segments.\n *\n * Recognizes both ` ``` ` and `~~~` fences, with arbitrary length ≥ 3,\n * matching CommonMark's \"fence indicator must be at least as long to\n * close\" rule. Info-strings (the bit after the opening fence) are kept\n * as the `lang` hint; any trailing whitespace is trimmed. Closing\n * fences are detected on a line of their own (whitespace tolerated).\n *\n * Unclosed fences fall back to emitting the would-be-code body as a\n * trailing prose segment so no content is dropped — finalized markdown\n * isn't expected to ship one, but the fallback keeps the renderer\n * truthful when the model produces malformed output.\n *\n * Exported for unit tests.\n */\nexport function splitMarkdownCodeBlocks(text: string): MarkdownSegment[] {\n const lines = text.split('\\n')\n const segments: MarkdownSegment[] = []\n let prose: string[] = []\n let code: string[] = []\n let inFence = false\n let fenceChar = ''\n let fenceLen = 0\n let lang = ''\n\n // Drop a single trailing/leading blank line off each emitted prose\n // segment. Markdown convention puts a blank line between a paragraph\n // and the fence that follows; without trimming, that blank stacks\n // with the code panel's `marginTop: 1` (and symmetrically with\n // `marginBottom: 1` on the post-fence side), producing a double-blank\n // gap when the renderer adds its own panel margins.\n const flushProse = () => {\n if (prose.length > 0 && prose[prose.length - 1] === '')\n prose.pop()\n if (prose.length > 0) {\n segments.push({ kind: 'prose', content: prose.join('\\n') })\n prose = []\n }\n }\n\n let trimLeadingProseBlank = false\n\n for (const line of lines) {\n if (!inFence) {\n const open = line.match(/^(`{3,}|~{3,})([^\\n`~]*)$/)\n if (open) {\n flushProse()\n inFence = true\n fenceChar = open[1]![0]!\n fenceLen = open[1]!.length\n lang = open[2]!.trim()\n code = []\n continue\n }\n if (trimLeadingProseBlank) {\n trimLeadingProseBlank = false\n if (line === '' && prose.length === 0)\n continue\n }\n prose.push(line)\n }\n else {\n const close = line.match(/^(`{3,}|~{3,})\\s*$/)\n if (close && close[1]![0]! === fenceChar && close[1]!.length >= fenceLen) {\n segments.push({ kind: 'code', content: code.join('\\n'), lang })\n inFence = false\n code = []\n trimLeadingProseBlank = true\n continue\n }\n code.push(line)\n }\n }\n\n if (inFence) {\n prose.push(`${fenceChar.repeat(fenceLen)}${lang}`, ...code)\n }\n flushProse()\n return segments\n}\n\n/**\n * Remove HTML comments from markdown PROSE while leaving fenced code and\n * inline code spans untouched (`<!-- -->` inside a fence or backticks is\n * legitimate content the user must see). Comments may span lines; a line\n * reduced to whitespace by comment removal is dropped entirely so no\n * phantom paragraph gap remains.\n */\nexport function stripHtmlCommentsOutsideCode(text: string): string {\n const lines = text.split('\\n')\n const out: string[] = []\n let inFence = false\n let fenceChar = ''\n let fenceLen = 0\n let inComment = false\n\n for (const line of lines) {\n if (inFence) {\n out.push(line)\n if (isFenceClose(line, fenceChar, fenceLen))\n inFence = false\n continue\n }\n if (!inComment) {\n const open = parseFenceOpen(line)\n if (open) {\n out.push(line)\n inFence = true\n fenceChar = open.char\n fenceLen = open.length\n continue\n }\n }\n\n // Prose line: char scan tracking inline code spans (`…`) and the\n // cross-line comment state.\n let result = ''\n let i = 0\n let spanTicks = 0\n let dropped = false\n while (i < line.length) {\n if (inComment) {\n const end = line.indexOf('-->', i)\n if (end === -1) {\n i = line.length\n break\n }\n i = end + 3\n inComment = false\n continue\n }\n const ch = line[i]!\n if (ch === '`') {\n let run = 1\n while (line[i + run] === '`')\n run++\n if (spanTicks === 0)\n spanTicks = run\n else if (run === spanTicks)\n spanTicks = 0\n result += line.slice(i, i + run)\n i += run\n continue\n }\n if (spanTicks === 0 && line.startsWith('<!--', i)) {\n inComment = true\n dropped = true\n i += 4\n continue\n }\n result += ch\n i++\n }\n\n // A line that held only comment content vanishes with it.\n if (dropped && result.trim() === '' && line.trim() !== '')\n continue\n if (inComment && result.trim() === '' && line.trim() !== '')\n continue\n out.push(result)\n }\n return out.join('\\n')\n}\n\nconst LIST_ITEM_RE = /^( *)(?:[-+*]|\\d+[.)]) +/\n\n/**\n * Lift indented fenced code blocks to column 0 while preserving the code\n * body's relative indentation.\n *\n * OpenTUI's markdown renderNode hook only receives top-level code tokens.\n * A common assistant shape is:\n *\n * - Run this:\n * ```bash\n * command\n * ```\n *\n * Marked parses that as code inside a list token, so the TUI loses the\n * code-panel wrapper and copy affordance. Normalizing just the fence's list\n * indentation keeps the prose readable while routing the snippet through\n * the same top-level renderer as ordinary fences.\n */\nexport function normalizeMarkdownCodeFences(text: string): string {\n const lines = text.split('\\n')\n const out: string[] = []\n const listIndents: number[] = []\n let inFence = false\n let fenceChar = ''\n let fenceLen = 0\n let lift = 0\n\n for (const line of lines) {\n if (inFence) {\n const normalized = stripFenceIndent(line, lift)\n out.push(normalized)\n\n if (isFenceClose(normalized, fenceChar, fenceLen)) {\n inFence = false\n fenceChar = ''\n fenceLen = 0\n lift = 0\n }\n continue\n }\n\n updateListIndentStack(listIndents, line)\n\n const open = parseFenceOpen(line)\n if (!open) {\n out.push(line)\n continue\n }\n\n const activeListIndent = [...listIndents].reverse().find(i => i <= open.indent)\n lift = activeListIndent ?? (open.indent <= 3 ? open.indent : 0)\n\n const normalized = stripFenceIndent(line, lift)\n out.push(normalized)\n inFence = true\n fenceChar = open.char\n fenceLen = open.length\n }\n\n return out.join('\\n')\n}\n\n/**\n * Default per-chunk target for {@link chunkMarkdownForRender}. Chosen from\n * measurement: marked's lexer (which OpenTUI's `<markdown>` runs\n * internally) is O(n²) over paragraph-heavy input — ~500ms at 64KiB,\n * ~2s at 128KiB, ~6s at 256KiB on an M-series laptop — while staying\n * comfortably in the linear zone below ~32KiB (≤ ~200ms). Chunking a\n * large document into ≤24KiB pieces keeps the total render linear in\n * document size with a small constant.\n */\nexport const MARKDOWN_RENDER_CHUNK_TARGET_BYTES = 24_576\n\n/**\n * A blank-line split is only safe when the next block clearly STARTS a\n * new top-level construct. Lines that continue a multi-block construct —\n * list items (loose lists put blank lines between items; splitting would\n * restart ordered-list numbering), blockquote lines, table rows, and\n * indented continuations / indented code — are unsafe, so a chunk grows\n * past the target rather than splitting one of these. Worst case (one\n * giant list) degrades to a single chunk: the pre-chunking behavior.\n */\nfunction isUnsafeChunkBoundary(line: string): boolean {\n return LIST_ITEM_RE.test(line)\n || /^ *>/.test(line)\n || /^ *\\|/.test(line)\n || /^ {4,}/.test(line)\n}\n\n/**\n * Split a large markdown document into render-safe chunks at blank-line\n * boundaries outside code fences, each roughly `targetBytes` long.\n *\n * Rendering the chunks as SIBLING markdown renderables (with a one-row\n * gap standing in for the consumed blank line) is visually equivalent to\n * one renderable, but sidesteps the quadratic lexer cost documented on\n * {@link MARKDOWN_RENDER_CHUNK_TARGET_BYTES}. Chunk boundaries are\n * prefix-stable: appending text (streaming) can only ever change the\n * LAST chunk, so keyed-by-index consumers reconcile cheaply.\n *\n * Returns `[text]` untouched for anything at or under the target.\n */\nexport function chunkMarkdownForRender(text: string, targetBytes: number = MARKDOWN_RENDER_CHUNK_TARGET_BYTES): string[] {\n if (text.length <= targetBytes)\n return [text]\n\n const lines = text.split('\\n')\n const chunks: string[] = []\n let current: string[] = []\n let currentBytes = 0\n let inFence = false\n let fenceChar = ''\n let fenceLen = 0\n\n const push = (line: string): void => {\n current.push(line)\n currentBytes += line.length + 1\n }\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] as string\n\n if (inFence) {\n push(line)\n if (isFenceClose(line, fenceChar, fenceLen))\n inFence = false\n continue\n }\n\n const open = parseFenceOpen(line)\n if (open) {\n push(line)\n inFence = true\n fenceChar = open.char\n fenceLen = open.length\n continue\n }\n\n // Split point: a blank-line run outside a fence, once the current\n // chunk is big enough and the next content starts a safe new block.\n if (line.trim() === '' && currentBytes >= targetBytes && current.length > 0) {\n let next = i + 1\n while (next < lines.length && (lines[next] as string).trim() === '')\n next++\n if (next < lines.length && !isUnsafeChunkBoundary(lines[next] as string)) {\n chunks.push(current.join('\\n'))\n current = []\n currentBytes = 0\n i = next - 1 // consume the blank run; the renderer restores the gap\n continue\n }\n }\n\n push(line)\n }\n\n if (current.length > 0)\n chunks.push(current.join('\\n'))\n return chunks.length > 0 ? chunks : [text]\n}\n\nfunction parseFenceOpen(line: string): { indent: number, char: string, length: number } | null {\n const indent = leadingSpaces(line)\n const char = line[indent]\n if (char !== '`' && char !== '~')\n return null\n\n const length = countRun(line, indent, char)\n if (length < 3)\n return null\n\n const info = line.slice(indent + length)\n if (char === '`' && info.includes('`'))\n return null\n\n return { indent, char, length }\n}\n\nfunction isFenceClose(line: string, fenceChar: string, fenceLen: number): boolean {\n const indent = leadingSpaces(line)\n if (line[indent] !== fenceChar)\n return false\n\n const length = countRun(line, indent, fenceChar)\n if (length < fenceLen)\n return false\n\n return onlySpaces(line, indent + length)\n}\n\nfunction updateListIndentStack(listIndents: number[], line: string): void {\n const contentIndent = leadingSpaces(line)\n if (line.trim().length > 0) {\n while (listIndents.length > 0 && contentIndent < listIndents[listIndents.length - 1]!)\n listIndents.pop()\n }\n\n const item = line.match(LIST_ITEM_RE)\n if (!item)\n return\n\n const indent = item[0]!.length\n if (indent > (listIndents[listIndents.length - 1] ?? 0))\n listIndents.push(indent)\n}\n\nfunction leadingSpaces(line: string): number {\n let i = 0\n while (i < line.length && line[i] === ' ')\n i++\n return i\n}\n\nfunction countRun(line: string, start: number, char: string): number {\n let i = start\n while (i < line.length && line[i] === char)\n i++\n return i - start\n}\n\nfunction onlySpaces(line: string, start: number): boolean {\n for (let i = start; i < line.length; i++) {\n if (line[i] !== ' ')\n return false\n }\n return true\n}\n\nfunction stripFenceIndent(line: string, columns: number): string {\n if (columns <= 0)\n return line\n let i = 0\n while (i < columns && line[i] === ' ')\n i++\n return line.slice(i)\n}\n\n/**\n * Terminate a code fence left open at the end of `text`.\n *\n * A model whose run ends mid-fence (cancelled, truncated, out of tokens) leaves\n * an unterminated fence, and the TUI keys the fenced-code chrome off whether the\n * fence closed — an open one stays a bare body so streaming updates can land in\n * place. Closing it at finalization is what lets the `[lang] … [copy]` header\n * appear on a fence the model never closed.\n *\n * Returns `text` unchanged when nothing is open, which is the common case.\n */\nexport function closeDanglingCodeFence(text: string): string {\n const lines = text.split('\\n')\n let fenceChar = ''\n let fenceLen = 0\n\n for (const line of lines) {\n if (fenceChar) {\n if (isFenceClose(line, fenceChar, fenceLen)) {\n fenceChar = ''\n fenceLen = 0\n }\n continue\n }\n\n const open = parseFenceOpen(line)\n if (open) {\n fenceChar = open.char\n fenceLen = open.length\n }\n }\n\n if (!fenceChar)\n return text\n\n return `${text.endsWith('\\n') ? text : `${text}\\n`}${fenceChar.repeat(fenceLen)}`\n}\n\n/**\n * Whether a marked `code` token's raw text carries its closing fence.\n *\n * marked keeps the closing delimiter in `token.raw` only once the fence has\n * terminated, so this separates \"still streaming the body\" from \"done\". Callers\n * use it to decide whether a fenced block is safe to decorate — see the\n * fenced-code chrome in the TUI, which has to stay off an open fence so the\n * renderer can keep updating it in place.\n *\n * Indented (non-fenced) code blocks have no delimiter to wait for and report as\n * closed.\n *\n * Hot path: runs per code token per streamed delta, so it scans in place rather\n * than building a regex or trimming a copy of the whole token.\n */\nexport function codeTokenHasClosingFence(raw: string): boolean {\n const char = raw[0]\n if (char !== '`' && char !== '~')\n return true\n\n let openLen = 0\n while (raw[openLen] === char)\n openLen++\n\n // marked leaves a trailing newline on a fence that ends the input, so walk\n // back over trailing whitespace before locating the closing line.\n let end = raw.length\n while (end > 0 && isSpaceOrBreak(raw[end - 1] as string))\n end--\n\n let start = end\n while (start > 0 && raw[start - 1] !== '\\n')\n start--\n\n // The opening delimiter is not a closing one.\n if (start === 0)\n return false\n\n // CommonMark allows the closing fence up to three spaces of indent.\n while (start < end && (raw[start] === ' ' || raw[start] === '\\t'))\n start++\n\n if (end - start < openLen)\n return false\n\n for (let i = start; i < end; i++) {\n if (raw[i] !== char)\n return false\n }\n return true\n}\n\nfunction isSpaceOrBreak(ch: string): boolean {\n return ch === '\\n' || ch === '\\r' || ch === ' ' || ch === '\\t'\n}\n","/**\n * Edits to the `enabledMcps` allowlist. Without an explicit list every\n * server is on, so there is nothing to change. Servers that merely appear\n * in a config file stay off once a list exists (they don't opt in\n * silently); a server the user adds in Settings is turned on with it.\n */\n\n/** The list with `name` turned on, or `undefined` when it already is. */\nexport function enabledMcpsWith(list: readonly string[] | undefined, name: string): string[] | undefined {\n return list === undefined || list.includes(name) ? undefined : [...list, name]\n}\n\n/** The list without `name`, or `undefined` when it isn't listed. */\nexport function enabledMcpsWithout(list: readonly string[] | undefined, name: string): string[] | undefined {\n return list?.includes(name) ? list.filter(n => n !== name) : undefined\n}\n","/**\n * Per-server MCP OAuth status tracking, decoupled from the renderer.\n *\n * The TUI keeps a `Record<serverName, McpAuthStatus>` so it can render a\n * \"needs-auth\" / \"authorizing\" / \"error\" badge in the MCP picker. The\n * status map is driven entirely by hooks fired from the agent's MCP\n * bootstrap + the interactive `loginMcpServer` flow — the reducer below\n * is pure, makes no FS or network calls, and is shared between the live\n * TUI store and the test harness.\n *\n * Status lifecycle:\n *\n * idle ──mcp:connect──▶ authed\n * (bootstrap succeeded with stored tokens)\n *\n * idle ──mcp:auth:required──▶ needs-auth\n * (bootstrap saw no/invalid tokens)\n *\n * idle ──401/403, no key of its own──▶ needs-auth (reason 'refused')\n * idle ──401/403 on its own header key──▶ key-refused\n * (see `classifyMcpTest`)\n *\n * needs-auth ──login()──▶ authorizing ──mcp:auth:url──▶ authorizing(url)\n * ──mcp:auth:success──▶ authed\n * ──mcp:auth:error──▶ error\n *\n * any ──logout──▶ idle\n *\n * Multiple servers progress through the lifecycle independently; the map\n * is keyed by `McpServerConfig.name`.\n */\n\nexport type McpAuthStatus\n // Default — never heard anything about this server. Includes both pure\n // stdio servers (no auth concept) and HTTP servers we haven't bootstrapped yet.\n = | { kind: 'idle' }\n // OAuth-required, no usable tokens. Reason maps to the bootstrap signal:\n // - 'no-tokens' — explicit `auth: 'oauth'` config + empty store.\n // - 'auto-promoted' — server returned 401 + RFC 9728 metadata, eligible\n // for OAuth because the user did not set a static Authorization header.\n // - 'refused' — the server answered 401/403 without that metadata (an\n // expired or never finished sign-in, a config without `auth: 'oauth'`).\n | { kind: 'needs-auth', reason: McpNeedsAuthReason }\n // Login flow in flight. `url` is populated as soon as the SDK builds the\n // authorization URL — the modal renders it so the user can re-open the\n // browser tab manually if the automatic open failed (no GUI, restricted\n // sandbox).\n | { kind: 'authorizing', url?: string }\n // Tokens are stored and (most recently) usable. Surface as a check mark.\n | { kind: 'authed' }\n // Last login attempt failed. `error` is the user-facing message — the\n // TUI shows it verbatim so a network blip or revoked token is debuggable\n // without `ZIDANE_DEBUG`.\n | { kind: 'error', error: string }\n // Bootstrap failed for a NON-auth reason — stdio command missing/crashed,\n // http endpoint unreachable. Kept distinct from `error` (login failed) so\n // the picker doesn't offer login/logout on servers where auth is not the\n // problem. Cleared back to idle by a later successful `mcp:connect`.\n | { kind: 'bootstrap-error', error: string }\n // The server refused the key its config sends in headers (401/403 on a\n // server with `headers`). Fixed in mcps.json, not by signing in, so no\n // login is offered. Cleared by a later successful `mcp:connect`.\n | { kind: 'key-refused', error: string }\n\nexport type McpNeedsAuthReason = 'no-tokens' | 'auto-promoted' | 'refused'\n\n/**\n * The status words both apps show for a server, so the desktop app's badge\n * and the TUI's read the same. `idle` says nothing.\n */\nexport const MCP_STATUS_LABEL: Readonly<Record<Exclude<McpAuthStatus['kind'], 'idle'>, string>> = {\n 'authed': 'Signed in',\n 'needs-auth': 'Needs sign-in',\n 'authorizing': 'Signing in…',\n 'error': 'Sign-in failed',\n 'bootstrap-error': 'Couldn\\'t connect',\n 'key-refused': 'Key refused',\n}\n\n/**\n * Map of server name → status. `idle` is the implicit default for any\n * server NOT present in the map, so the renderer treats `undefined` as\n * `{ kind: 'idle' }` and the map can stay sparse.\n */\nexport type McpAuthStateMap = Readonly<Record<string, McpAuthStatus>>\n\n/**\n * Events the reducer accepts. Names mirror the agent hooks 1:1 plus two\n * UI-only verbs (`login:start` / `login:cancel`) so the renderer can\n * optimistically flip a row to `authorizing` before the SDK has emitted\n * `mcp:auth:url` — useful when the loopback callback is slow to bind.\n */\nexport type McpAuthEvent\n = | { type: 'auth-required', name: string, reason: McpNeedsAuthReason }\n | { type: 'auth-url', name: string, url: string }\n | { type: 'auth-success', name: string }\n | { type: 'auth-error', name: string, error: string }\n | { type: 'bootstrap-error', name: string, error: string }\n | { type: 'key-refused', name: string, error: string }\n | { type: 'connected', name: string }\n | { type: 'login:start', name: string }\n | { type: 'login:cancel', name: string }\n | { type: 'logout', name: string }\n | { type: 'reset', name: string }\n\n/**\n * Apply one event to the state map. Pure, immutable — returns a new map\n * with only the affected key reassigned.\n *\n * State transitions are simple \"last write wins\"; we don't gate (e.g.) a\n * `login:start` from overriding `authorizing` because the loop layer\n * never doubles those up — interactive login is serialized in the TUI.\n */\nexport function reduceMcpAuth(state: McpAuthStateMap, event: McpAuthEvent): McpAuthStateMap {\n const next = (status: McpAuthStatus): McpAuthStateMap => ({ ...state, [event.name]: status })\n switch (event.type) {\n case 'auth-required':\n return next({ kind: 'needs-auth', reason: event.reason })\n case 'auth-url':\n return next({ kind: 'authorizing', url: event.url })\n case 'auth-success':\n return next({ kind: 'authed' })\n case 'auth-error':\n return next({ kind: 'error', error: event.error })\n case 'bootstrap-error':\n return next({ kind: 'bootstrap-error', error: event.error })\n case 'key-refused':\n return next({ kind: 'key-refused', error: event.error })\n case 'connected':\n // Only flip to `authed` when this server was OAuth-tracked. A plain\n // stdio bootstrap shouldn't paint every server with a green badge —\n // `idle` means \"nothing to say about auth here\". This matters for\n // the MCP picker's badge column staying signal-dense.\n // A refusal that cleared up without a sign-in (the server let us in\n // after all) has nothing to say about auth: back to idle.\n if (state[event.name]?.kind === 'needs-auth' && (state[event.name] as { reason?: string }).reason === 'refused') {\n const { [event.name]: _, ...rest } = state\n return rest\n }\n if (state[event.name]?.kind === 'authorizing'\n || state[event.name]?.kind === 'needs-auth'\n || state[event.name]?.kind === 'authed') {\n return next({ kind: 'authed' })\n }\n // A successful bootstrap clears a previous bootstrap failure — the\n // server was fixed (file restored, endpoint back up). Back to the\n // sparse-map default rather than a green badge: `idle` means\n // \"nothing to say about auth here\", which is true for stdio.\n if (state[event.name]?.kind === 'bootstrap-error' || state[event.name]?.kind === 'key-refused') {\n const { [event.name]: _, ...rest } = state\n return rest\n }\n return state\n case 'login:start':\n return next({ kind: 'authorizing' })\n case 'login:cancel':\n // Cancellation is treated as \"back to needs-auth\" — the user dismissed\n // the browser flow but the underlying requirement still stands.\n return next({ kind: 'needs-auth', reason: 'no-tokens' })\n case 'logout':\n case 'reset': {\n const { [event.name]: _, ...rest } = state\n return rest\n }\n }\n}\n\n/**\n * The status a failed connection leaves, from `classifyMcpTest`'s answer\n * (never called with `ok`: a connection that worked leaves no failure).\n * A server that asked for OAuth keeps \"sign-in failed\" for an unexplained\n * failure (its tokens are the likely cause, and sign-in stays offered).\n */\nexport function mcpFailureEvent(\n name: string,\n outcome: { kind: 'ok' | 'needs-auth' | 'token-rejected' | 'error', message?: string },\n oauthTagged: boolean,\n): McpAuthEvent {\n if (outcome.kind === 'needs-auth')\n return { type: 'auth-required', name, reason: 'refused' }\n if (outcome.kind === 'token-rejected')\n return { type: 'key-refused', name, error: outcome.message ?? '' }\n return oauthTagged\n ? { type: 'auth-error', name, error: outcome.message ?? '' }\n : { type: 'bootstrap-error', name, error: outcome.message ?? '' }\n}\n\n/** Convenience getter — treats `undefined` as `idle`. */\nexport function getMcpAuthStatus(state: McpAuthStateMap, name: string): McpAuthStatus {\n return state[name] ?? { kind: 'idle' }\n}\n","/**\n * How an MCP server answered a connection attempt, in the words both apps\n * show. Shared by the desktop app's Test (Settings › MCPs) and the TUI's\n * bootstrap / test, so the same server reads the same way in either.\n *\n * ok connected and listed its tools;\n * needs-auth 401/403 with no key of its own: a browser sign-in fixes it\n * (an expired or never finished sign-in included);\n * token-rejected 401/403 on a server that sends its own headers: the key\n * in mcps.json is wrong, a browser sign-in won't help;\n * error anything else (refused, timed out, bad command).\n *\n * Pure: no I/O.\n */\nimport type { McpServerConfig } from '../types'\n\nexport type McpTestOutcomeKind = 'ok' | 'needs-auth' | 'token-rejected' | 'error'\n\nexport interface McpTestResult {\n kind: McpTestOutcomeKind\n tools?: number\n message?: string\n}\n\n/** What to do about a refused key, under the \"Key refused\" headline. */\nexport const MCP_KEY_REFUSED_HINT = 'Check the headers in mcps.json.'\n\n/** A refusal for want of credentials: HTTP 401 / 403, however the SDK words it. */\nexport function isMcpAuthRefusal(error: unknown): boolean {\n const code = (error as { code?: unknown } | null)?.code\n if (code === 401 || code === 403)\n return true\n const message = error instanceof Error ? error.message : String(error ?? '')\n return /\\b(?:401|403)\\b|unauthori[sz]ed|forbidden|invalid_token/i.test(message)\n}\n\n/** The first line of a failure, never empty. */\nexport function mcpFailureLine(error: unknown): string {\n const code = (error as { code?: unknown } | null)?.code\n const message = error instanceof Error && error.message\n ? error.message\n : code !== undefined\n ? `The server answered ${String(code)}.`\n : typeof error === 'string'\n ? error\n : ''\n return message.split('\\n')[0]?.trim() || 'Couldn\\'t connect.'\n}\n\nexport function classifyMcpTest(\n config: Pick<McpServerConfig, 'transport' | 'headers'>,\n result: { authRequired: boolean, error?: unknown, tools?: number },\n): McpTestResult {\n const http = config.transport !== 'stdio'\n const ownKey = Object.keys(config.headers ?? {}).length > 0\n if (http && (result.authRequired || (result.error !== undefined && isMcpAuthRefusal(result.error)))) {\n return ownKey\n ? { kind: 'token-rejected', message: MCP_KEY_REFUSED_HINT }\n : { kind: 'needs-auth', message: 'Sign in to connect.' }\n }\n if (result.error !== undefined)\n return { kind: 'error', message: mcpFailureLine(result.error) }\n return { kind: 'ok', tools: result.tools ?? 0 }\n}\n","/**\n * Cross-provider model catalog — assembly + fuzzy filtering.\n *\n * Renderer-agnostic helpers consumed by `ModelPickerModal` (TUI) and any\n * future UI that wants a unified \"pick a model across all available\n * providers\" experience. Pure: no React, no I/O, no provider construction.\n *\n * The catalog is the flat union of every available provider's models,\n * each entry tagged with the provider it belongs to so the picker can\n * re-issue a `Picked` tuple `{ providerKey, modelId }` on commit.\n */\n\nimport type { ProviderAuth, ProviderKey } from './auth'\nimport type { ModelInfo } from './providers'\n\n/** A model entry as displayed in the cross-provider picker. */\nexport interface CatalogEntry {\n providerKey: ProviderKey\n providerLabel: string\n model: ModelInfo\n /**\n * The provider does not (or no longer) list this model: the entry was\n * synthesized from an `include` pair, so `model` is a stub carrying the id\n * and nothing else. Renderers should say so rather than print stub\n * metadata as if it were real.\n */\n offCatalog?: boolean\n /**\n * Pre-computed lowercase corpus for substring search across the\n * provider key, label, model id, and display name. Built once at\n * catalog-assembly time so filtering on every keystroke is\n * O(catalogSize × queryLength), not O(catalogSize × fieldCount ×\n * lowercase-overhead × queryLength).\n */\n searchCorpus: string\n}\n\n/**\n * Build the unified catalog from a list of available providers.\n *\n * Provider order is preserved (callers typically pass the picker order\n * — alphabetical, auth-detection order, etc.); model order inside each\n * provider matches whatever `modelsFor` returns. The current selection\n * (when set) is bubbled to the top of its provider's section so it\n * shows first without disturbing relative ordering elsewhere.\n *\n * `modelsFor` is injected (not imported from `./providers`) so the same\n * helper works with hosts that supply their own model resolver via\n * `ResolvedConfig.modelsFor`.\n *\n * `include` guarantees a pair is listed even when the provider stopped\n * serving it. Persisted picks outlive catalogs (a provider retires an id, a\n * user typed one by hand), and an entry that isn't in the list can't be\n * selected away from, and the picker would keep re-persisting it. Synthesized\n * entries carry `offCatalog: true` and a stub `ModelInfo`.\n */\nexport function buildModelCatalog(opts: {\n providers: readonly ProviderAuth[]\n modelsFor: (key: ProviderKey) => readonly ModelInfo[]\n /** Optional currently-selected pair — promoted to the top of its provider group. */\n current?: { providerKey: ProviderKey, modelId: string } | null\n /** Pairs that must appear even if unserved, e.g. the active pick + fallback chain. */\n include?: readonly { providerKey: ProviderKey, modelId: string }[]\n}): CatalogEntry[] {\n const entries: CatalogEntry[] = []\n for (const provider of opts.providers) {\n const models = opts.modelsFor(provider.key)\n const missing = missingIdsFor(provider.key, models, opts.include)\n if (models.length === 0 && missing.length === 0)\n continue\n // Promote the currently-selected model to position 0 inside its\n // own provider section so the picker doesn't bury the user's\n // active row at the bottom of a long provider list.\n let ordered: readonly ModelInfo[] = models\n if (opts.current?.providerKey === provider.key) {\n const idx = models.findIndex(m => m.id === opts.current?.modelId)\n if (idx > 0) {\n const next = models.slice()\n const [active] = next.splice(idx, 1)\n next.unshift(active)\n ordered = next\n }\n }\n // Unserved pairs lead their provider's section: they are either the\n // active pick or a chain entry, so burying them under a long served list\n // would defeat the point of listing them at all.\n for (const modelId of missing) {\n const model: ModelInfo = { id: modelId, contextWindow: 0 }\n entries.push({\n providerKey: provider.key,\n providerLabel: provider.label,\n model,\n offCatalog: true,\n searchCorpus: buildSearchCorpus(provider, model),\n })\n }\n for (const model of ordered) {\n entries.push({\n providerKey: provider.key,\n providerLabel: provider.label,\n model,\n searchCorpus: buildSearchCorpus(provider, model),\n })\n }\n }\n return entries\n}\n\n/** Ids `include` asks for on this provider that its own list doesn't serve. */\nfunction missingIdsFor(\n providerKey: ProviderKey,\n models: readonly ModelInfo[],\n include: readonly { providerKey: ProviderKey, modelId: string }[] | undefined,\n): string[] {\n if (!include || include.length === 0)\n return []\n const served = new Set(models.map(m => m.id))\n const out: string[] = []\n for (const pair of include) {\n if (pair.providerKey !== providerKey || !pair.modelId || served.has(pair.modelId) || out.includes(pair.modelId))\n continue\n out.push(pair.modelId)\n }\n return out\n}\n\n/**\n * Filter `catalog` by a user query. Empty / whitespace-only queries\n * pass everything through unchanged (`O(1)` short-circuit). Multi-term\n * queries (space-separated) require EVERY term to appear somewhere in\n * the entry's search corpus — so `\"claude opus\"` matches `claude-opus-4`\n * regardless of how the words are interleaved with provider names.\n *\n * Match is case-insensitive (the corpus is pre-lowercased; the query\n * is lowercased once per call).\n */\nexport function filterModelCatalog(\n catalog: readonly CatalogEntry[],\n query: string,\n): CatalogEntry[] {\n const trimmed = query.trim().toLowerCase()\n if (!trimmed)\n return catalog.slice()\n const terms = trimmed.split(/\\s+/)\n return catalog.filter(entry => terms.every(t => entry.searchCorpus.includes(t)))\n}\n\n/**\n * Find a catalog entry's index by its `{providerKey, modelId}` tuple.\n * Returns `-1` when not present. Useful when re-rendering the picker\n * (a query just narrowed the list, where did the selection land?).\n */\nexport function indexOfEntry(\n catalog: readonly CatalogEntry[],\n target: { providerKey: ProviderKey, modelId: string } | null | undefined,\n): number {\n if (!target)\n return -1\n return catalog.findIndex(\n e => e.providerKey === target.providerKey && e.model.id === target.modelId,\n )\n}\n\n/**\n * Read a query that matched nothing as \"use this model id anyway\".\n *\n * A bare id is meaningless without a provider, so the first term is checked\n * against every provider's key and label (case-insensitive): `xai grok-9` and\n * `Anthropic claude-next` name their provider explicitly, anything else is\n * attributed to `fallbackProviderKey` (the picker's current pick). Returns\n * `null` when nothing usable is left, including when the whole query is just a\n * provider name.\n */\nexport function parseCustomModelQuery(\n query: string,\n // Only `key` + `label` are read. Narrowed so the GUI, which holds providers\n // as a flattened wire shape rather than `ProviderAuth`, can share the parser.\n providers: readonly Pick<ProviderAuth, 'key' | 'label'>[],\n fallbackProviderKey: ProviderKey | null,\n): CustomModelTarget | null {\n const { modelId, named } = splitProviderPrefix(query, providers)\n const provider = named ?? providers.find(p => p.key === fallbackProviderKey)\n if (!provider || !modelId)\n return null\n return { providerKey: provider.key, providerLabel: provider.label, modelId }\n}\n\nexport interface CustomModelTarget {\n providerKey: ProviderKey\n providerLabel: string\n modelId: string\n /** The query named this provider (`xai grok-9`). */\n named?: boolean\n}\n\n/**\n * Every route for a typed model id, one per provider: the provider the query\n * names first (`xai grok-9`), then `fallbackProviderKey` (the current pick),\n * then the rest in the given order. Lets a picker offer \"use this id via…\"\n * for each signed-in provider instead of guessing one. Empty when the query\n * names no model id.\n */\nexport function customModelTargets(\n query: string,\n providers: readonly Pick<ProviderAuth, 'key' | 'label'>[],\n fallbackProviderKey: ProviderKey | null,\n): CustomModelTarget[] {\n const { modelId, named } = splitProviderPrefix(query, providers)\n if (!modelId)\n return []\n const rank = (p: Pick<ProviderAuth, 'key'>): number =>\n p.key === named?.key ? 0 : p.key === fallbackProviderKey ? 1 : 2\n return providers\n .map((p, i) => ({ p, i }))\n .sort((a, b) => rank(a.p) - rank(b.p) || a.i - b.i)\n .map(({ p }) => ({\n providerKey: p.key,\n providerLabel: p.label,\n modelId,\n ...(p.key === named?.key ? { named: true } : {}),\n }))\n}\n\n/**\n * Split an optional leading provider name off a typed query. Longest prefix\n * wins, so a multi-word label (\"OpenAI Codex gpt-9\") beats the bare key it\n * starts with. The trailing space is required: a query that is only a\n * provider name has no id in it and reads as an id itself. Only the prefix\n * is dropped; the rest is kept verbatim, so an id with spaces round-trips.\n */\nfunction splitProviderPrefix<P extends Pick<ProviderAuth, 'key' | 'label'>>(\n query: string,\n providers: readonly P[],\n): { modelId: string, named: P | undefined } {\n const trimmed = query.trim().replace(/\\s+/g, ' ')\n if (!trimmed)\n return { modelId: '', named: undefined }\n const lower = trimmed.toLowerCase()\n const match = providers\n .flatMap(p => [{ provider: p, token: p.label.toLowerCase() }, { provider: p, token: p.key.toLowerCase() }])\n .filter(candidate => lower.startsWith(`${candidate.token} `))\n .sort((a, b) => b.token.length - a.token.length)[0]\n return {\n modelId: match ? trimmed.slice(match.token.length).trim() : trimmed,\n named: match?.provider,\n }\n}\n\nfunction buildSearchCorpus(provider: ProviderAuth, model: ModelInfo): string {\n const parts = [\n provider.key,\n provider.label,\n model.id,\n model.name ?? '',\n model.provider ?? '',\n ]\n return parts.join(' ').toLowerCase()\n}\n","// ---------------------------------------------------------------------------\n// Model lineup: which models of a provider are \"current\".\n//\n// Provider catalogs list every model they ever served (OpenRouter: ~400),\n// with no release dates, so recency is read off the ids themselves. A model\n// id is split into a FAMILY (the words: `claude-opus`, `gpt-luna`,\n// `gemini-flash-lite`), a VERSION (the numbers: `4-5`, `5.6`, `v4.1`,\n// `qwen3.5`), a SIZE (`27b`, `235b-a22b`, `16k`) and noise that marks a\n// snapshot or a routing variant of the same model (`-20251001`,\n// `-2024-05-13`, `-0731`, `-preview`, `-latest`, `:batch`, `:free`).\n//\n// The lineup keeps, per provider and family, the models at the newest\n// version: every size of that version, one entry per size (the plain alias\n// over a dated snapshot over a routing variant). Everything else is\n// \"older\". Pure and data-driven so the GUI and the TUI share one answer.\n// ---------------------------------------------------------------------------\n\n/** Parsed shape of a model id. Exported for tests and for pickers that want to show a family label. */\nexport interface ModelIdParts {\n /** `vendor/` prefix on aggregator ids (`anthropic` in `anthropic/claude-opus-5`), lowercased; '' when absent. */\n vendor: string\n /** The words of the id, lowercased and joined with `-`. */\n family: string\n /** Numeric version segments in order; empty when the id carries none. */\n version: number[]\n /** Size tokens joined with `-` (`27b`, `235b-a22b`); '' when absent. */\n size: string\n /** Dated / numbered snapshot (`20251001`, `2024-05-13` → `20240513`, `0731`); '' for the plain alias. */\n snapshot: string\n /** Routing variant after `:` (`batch`, `free`); '' when absent. */\n variant: string\n}\n\nconst DATE_DASHED = /-(\\d{4})-(\\d{2})-(\\d{2})(?=$|[-:])/\nconst SIZE = /^(?:\\d+(?:\\.\\d+)?[bkm]|a\\d+(?:\\.\\d+)?b|e\\d+b|\\d+x\\d+b)$/\nconst SNAPSHOT = /^\\d{4}$|^\\d{6,8}$/\nconst NUMBER = /^\\d+(?:\\.\\d+)*$/\n/** Zero-padded short number (`001`, `05`): a revision or a date part, never a version. */\nconst PADDED = /^0\\d{1,2}$/\n/** Bedrock's `-v1` / `-v2:0` revision suffix. Only a revision once a version was read. */\nconst REVISION = /^v\\d+$/\n/** `v4.1`, `k2.5`, `r1`, `o3`, `qwen3.5`: letters then a version. */\nconst LETTERS_VERSION = /^([a-z]+)(\\d+(?:\\.\\d+)*)$/\n/** `4o`: a version then letters. */\nconst VERSION_LETTERS = /^(\\d+(?:\\.\\d+)*)([a-z]+)$/\n/** Words that mark a pre-release or an alias of the same model, not a different one. */\nconst NOISE = new Set(['preview', 'latest', 'exp', 'experimental'])\n\nexport function parseModelId(id: string): ModelIdParts {\n let rest = id.toLowerCase()\n let variant = ''\n const colon = rest.indexOf(':')\n if (colon >= 0) {\n variant = rest.slice(colon + 1)\n rest = rest.slice(0, colon)\n }\n let vendor = ''\n const slash = rest.lastIndexOf('/')\n if (slash >= 0) {\n vendor = rest.slice(0, slash)\n rest = rest.slice(slash + 1)\n }\n let snapshot = ''\n const dated = DATE_DASHED.exec(rest)\n if (dated) {\n snapshot = `${dated[1]}${dated[2]}${dated[3]}`\n rest = rest.slice(0, dated.index) + rest.slice(dated.index + dated[0].length)\n }\n\n const words: string[] = []\n const version: number[] = []\n const sizes: string[] = []\n const snapParts: string[] = []\n let afterNoise = false\n const pushVersion = (v: string) => {\n for (const n of v.split('.')) version.push(Number(n))\n }\n for (const token of rest.split(/[-_\\s]+/).filter(Boolean)) {\n if (NOISE.has(token)) {\n afterNoise = true\n continue\n }\n if (SIZE.test(token)) {\n sizes.push(token)\n continue\n }\n // A bare 4 / 6-8 digit token after a version or word is a snapshot\n // (`-0731`, `-2512`, `-20251001`), never a version of its own. So is any\n // number after a pre-release word (`-preview-05-20`, `-preview-09-2025`)\n // and a zero-padded revision after a version (`gemini-2.0-flash-001`).\n const started = words.length > 0 || version.length > 0\n // Bedrock's `-v1` after a version (`claude-opus-4-6-v1`) is a revision too.\n if (started && (SNAPSHOT.test(token) || (afterNoise && NUMBER.test(token)) || (version.length > 0 && (PADDED.test(token) || REVISION.test(token))))) {\n snapParts.push(token)\n continue\n }\n if (NUMBER.test(token)) {\n pushVersion(token)\n continue\n }\n const lv = LETTERS_VERSION.exec(token)\n if (lv) {\n words.push(lv[1]!)\n pushVersion(lv[2]!)\n continue\n }\n const vl = VERSION_LETTERS.exec(token)\n if (vl) {\n pushVersion(vl[1]!)\n words.push(vl[2]!)\n continue\n }\n words.push(token)\n }\n if (!snapshot && snapParts.length > 0) {\n // `mm-yyyy` → `yyyymm`, so snapshots of that shape sort by date.\n snapshot = snapParts.length === 2 && /^\\d{2}$/.test(snapParts[0]!) && /^\\d{4}$/.test(snapParts[1]!)\n ? `${snapParts[1]}${snapParts[0]}`\n : snapParts.join('')\n }\n return { vendor, family: words.join('-'), version, size: sizes.join('-'), snapshot, variant }\n}\n\n/** Numeric, segment by segment; a longer version wins a tie on the shared prefix (`5.5` > `5`). */\nexport function compareModelVersion(a: readonly number[], b: readonly number[]): number {\n const n = Math.max(a.length, b.length)\n for (let i = 0; i < n; i++) {\n const x = a[i]\n const y = b[i]\n if (x === undefined)\n return -1\n if (y === undefined)\n return 1\n if (x !== y)\n return x - y\n }\n return 0\n}\n\n/**\n * Among ids naming the same model (family, version and size equal), the one\n * a picker should show: the plain alias over a dated snapshot, the newest\n * snapshot among snapshots, no routing variant over a variant, then the\n * shorter id. Negative when `a` is preferred.\n */\nfunction preferAlias(a: { id: string, parts: ModelIdParts }, b: { id: string, parts: ModelIdParts }): number {\n const sa = a.parts.snapshot\n const sb = b.parts.snapshot\n if (!sa !== !sb)\n return sa ? 1 : -1\n if (sa !== sb)\n return sa < sb ? 1 : -1\n if (!a.parts.variant !== !b.parts.variant)\n return a.parts.variant ? 1 : -1\n return a.id.length - b.id.length || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)\n}\n\nexport interface LineupEntry {\n providerKey: string\n modelId: string\n}\n\nconst lineupKey = (e: LineupEntry): string => `${e.providerKey}\\u0000${e.modelId}`\n\n/**\n * Keys (`provider\\0model`) of the current models: per provider and family,\n * the newest version, one entry per size. `keep` entries (the active model,\n * fallback chain, off-catalog ids) are always included.\n */\nexport function currentModelKeys(entries: readonly LineupEntry[], keep: readonly LineupEntry[] = []): Set<string> {\n const groups = new Map<string, { id: string, key: string, parts: ModelIdParts }[]>()\n for (const entry of entries) {\n const parts = parseModelId(entry.modelId)\n const group = `${entry.providerKey}\\u0000${parts.vendor}\\u0000${parts.family}`\n const list = groups.get(group)\n const item = { id: entry.modelId, key: lineupKey(entry), parts }\n if (list)\n list.push(item)\n else\n groups.set(group, [item])\n }\n\n const kept = new Set<string>(keep.map(lineupKey))\n for (const list of groups.values()) {\n let newest: number[] = []\n for (const item of list) {\n if (compareModelVersion(item.parts.version, newest) > 0)\n newest = item.parts.version\n }\n const bySize = new Map<string, { id: string, key: string, parts: ModelIdParts }>()\n for (const item of list) {\n if (compareModelVersion(item.parts.version, newest) !== 0)\n continue\n const best = bySize.get(item.parts.size)\n if (!best || preferAlias(item, best) < 0)\n bySize.set(item.parts.size, item)\n }\n for (const item of bySize.values()) kept.add(item.key)\n }\n return kept\n}\n\n/** `entries` in their original order, current models only (see {@link currentModelKeys}). */\nexport function currentModels<T extends LineupEntry>(entries: readonly T[], keep: readonly LineupEntry[] = []): T[] {\n const kept = currentModelKeys(entries, keep)\n return entries.filter(entry => kept.has(lineupKey(entry)))\n}\n","/**\n * Node-free half of provider usage: the wire types and the two presentation\n * helpers every surface needs to RENDER a snapshot.\n *\n * Split out of `provider-usage.ts` because that module reads\n * `credentials.json` and so cannot be reached from `zidane/chat/pure`. The\n * Electron renderer receives snapshots over IPC (main does the fetching) and\n * must draw them with the same rounding and the same \"which window bites\n * first\" rule as the TUI — a renderer that re-derived either would be the\n * duplication that let the TUI and GUI report different facts about one event.\n *\n * `provider-usage.ts` re-exports everything here, so existing importers keep\n * their single import.\n */\n\n/** One rate-limit window on a subscription (e.g. \"5h\", \"weekly\"). */\nexport interface ProviderUsageWindow {\n /** Stable id from the provider, used as a React / list key. */\n id: string\n /** Human label as the provider names it. */\n label: string\n /** 0..100, may be fractional. */\n usedPercent: number\n /** Epoch ms when the window resets, or `null` when the provider omits it. */\n resetsAt: number | null\n}\n\n/** Remaining credits for pay-as-you-go style providers. */\nexport interface ProviderUsageCredits {\n remaining: number\n total: number | null\n}\n\nexport type ProviderUsageStatus = 'ok' | 'unauthorized' | 'unavailable'\n\nexport interface ProviderUsageSnapshot {\n /** Registry key (`anthropic`, `openai`, …). */\n providerKey: string\n /** Display label for the provider. */\n label: string\n /**\n * Credentials-file key of the credential this snapshot was probed with. A\n * provider holding several OAuth accounts yields one snapshot per account;\n * this is what tells them apart (and the stable list key).\n */\n credentialKey: string\n /**\n * Account name for OAuth-backed snapshots (`Default`, `work`, …); `null` for\n * API-key probes. Surfaces show it only when the provider has more than one\n * snapshot, so a single-account provider stays as quiet as before.\n */\n account: string | null\n /** True when this credential is the one requests use (the canonical slot). */\n activeCredential: boolean\n status: ProviderUsageStatus\n /** Plan name when the provider reports one. */\n plan: string | null\n windows: readonly ProviderUsageWindow[]\n credits: ProviderUsageCredits | null\n fetchedAt: number\n error: string | null\n}\n\n/**\n * Whether a snapshot should show its account name: only when another snapshot\n * in the same list belongs to the same provider. One account is the provider.\n */\nexport function showsAccount(snapshot: ProviderUsageSnapshot, all: readonly ProviderUsageSnapshot[]): boolean {\n return snapshot.account !== null && all.some(s => s !== snapshot && s.providerKey === snapshot.providerKey)\n}\n\n/**\n * The snapshot the footer indicator shows for a provider: the one probed with\n * the credential requests use, else the first reported. `null` when none.\n */\nexport function activeSnapshotFor(all: readonly ProviderUsageSnapshot[], providerKey: string): ProviderUsageSnapshot | null {\n const mine = all.filter(s => s.providerKey === providerKey)\n return mine.find(s => s.activeCredential) ?? mine[0] ?? null\n}\n\n/**\n * The window closest to its ceiling, which is the one that will bite first and\n * the only one a single-line indicator has room for. `null` when the snapshot\n * carries no windows.\n */\nexport function mostConstrainedWindow(snapshot: ProviderUsageSnapshot): ProviderUsageWindow | null {\n let worst: ProviderUsageWindow | null = null\n for (const win of snapshot.windows) {\n if (!worst || win.usedPercent > worst.usedPercent)\n worst = win\n }\n return worst\n}\n\n/**\n * Percent for display: integers print bare, fractions keep one decimal (so a\n * status bar never reads `100%` for `99.9`).\n */\nexport function formatUsagePercent(usedPercent: number): string {\n return Number.isInteger(usedPercent) ? String(usedPercent) : usedPercent.toFixed(1)\n}\n\n// ---------------------------------------------------------------------------\n// Presentation rules shared by the TUI panel / footer and the GUI panel /\n// footer. Kept here so the two surfaces cannot drift on thresholds or\n// rounding — a `1d` on one screen and `2d` on the other for the same window\n// would be reporting different facts about one subscription.\n// ---------------------------------------------------------------------------\n\n/**\n * Severity tone for a usage percent. `error` ≥ 85, `warn` ≥ 60, else `ok`.\n * Surfaces map tones to their own palette.\n */\nexport type UsageTone = 'ok' | 'warn' | 'error'\n\nexport function usageTone(usedPercent: number): UsageTone {\n if (usedPercent >= 85)\n return 'error'\n if (usedPercent >= 60)\n return 'warn'\n return 'ok'\n}\n\n/**\n * Time to reset, coarsened to whole days past 24h. `null` when the provider\n * reported no reset, `resetting` once it is due.\n *\n * Every step rounds DOWN, like the percent: 36h reads as `1d`, not `2d`.\n * Overstating the headroom left on a window is the wrong direction to be\n * wrong in.\n */\nexport function resetLabel(resetsAt: number | null, now: number = Date.now()): string | null {\n if (resetsAt === null)\n return null\n const remaining = resetsAt - now\n if (remaining <= 0)\n return 'resetting'\n const minutes = Math.floor(remaining / 60_000)\n if (minutes < 60)\n return `resets in ${Math.max(1, minutes)}m`\n const hours = Math.floor(minutes / 60)\n if (hours < 24) {\n const remMinutes = minutes % 60\n return `resets in ${hours}h${remMinutes > 0 ? `${remMinutes}m` : ''}`\n }\n return `resets in ${Math.max(1, Math.floor(hours / 24))}d`\n}\n\n/**\n * `updated 12s ago` / `updated 3m ago` for the newest snapshot in a list, so a\n * refresh that returns identical numbers is still visibly a refresh. `null`\n * when the list is empty.\n */\nexport function updatedLabel(snapshots: readonly ProviderUsageSnapshot[], now: number = Date.now()): string | null {\n let newest = -Infinity\n for (const s of snapshots)\n newest = Math.max(newest, s.fetchedAt)\n if (!Number.isFinite(newest))\n return null\n const seconds = Math.max(0, Math.floor((now - newest) / 1000))\n if (seconds < 60)\n return `updated ${seconds}s ago`\n return `updated ${Math.floor(seconds / 60)}m ago`\n}\n\n/** Balances are dollars for OpenRouter and opaque units elsewhere. */\nexport function formatCredits(value: number): string {\n return value >= 100 ? value.toFixed(0) : value.toFixed(2)\n}\n\n/** `20.00 / 25.00`, or just the remainder when no total is reported. */\nexport function formatBalance(credits: ProviderUsageCredits): string {\n const remaining = formatCredits(credits.remaining)\n return credits.total === null ? remaining : `${remaining} / ${formatCredits(credits.total)}`\n}\n","/**\n * Spawn-tree ownership for transcript renderers (TUI partition, GUI\n * timeline). A nested worker's lifecycle markers name their spawner in\n * `spawn.parentChildId`; these helpers turn that into \"which worker does\n * this row belong under\", so a grandchild's rows nest inside its spawner\n * instead of reading as a separate worker of the main transcript.\n *\n * Generic over the row shape so the GUI's own `Row` type works too.\n */\n\n/** What the helpers read off a transcript row / event. */\nexport interface SpawnTreeRow {\n kind: string\n childId?: string\n spawn?: { parentChildId?: string }\n}\n\n/** Worker id → the worker that spawned it, from nested spawn markers. */\nexport function spawnParents(rows: Iterable<SpawnTreeRow>): Map<string, string> {\n const parents = new Map<string, string>()\n for (const row of rows) {\n const parent = row.spawn?.parentChildId\n if (row.childId !== undefined && parent !== undefined && (row.kind === 'spawn-start' || row.kind === 'spawn-end'))\n parents.set(row.childId, parent)\n }\n return parents\n}\n\n/**\n * The worker `childId`'s rows belong under: its outermost ancestor that is\n * itself one of the `present` workers (the ones owning rows in this view).\n * A view that already re-based its owner's rows (a worker opened in a fold)\n * leaves that owner out of `present`, so the owner's direct children become\n * the lanes there. `childId` itself when no ancestor is present.\n */\nexport function spawnLane(childId: string, parents: ReadonlyMap<string, string>, present: ReadonlySet<string>): string {\n let lane = childId\n const seen = new Set([lane])\n for (let parent = parents.get(lane); parent !== undefined && present.has(parent) && !seen.has(parent); parent = parents.get(lane)) {\n lane = parent\n seen.add(lane)\n }\n return lane\n}\n\n/**\n * Lane resolver over one view's rows: precomputes the parent map and the\n * present-worker set, then maps a row's `childId` to its lane.\n */\nexport function spawnLaneResolver(rows: readonly SpawnTreeRow[]): (childId: string) => string {\n const parents = spawnParents(rows)\n if (parents.size === 0)\n return childId => childId\n const present = new Set<string>()\n for (const row of rows) {\n if (row.childId !== undefined)\n present.add(row.childId)\n }\n return childId => spawnLane(childId, parents, present)\n}\n","/**\n * Streaming finalize reducers + context-window math — pure transforms.\n *\n * No React, no node — so a browser-context renderer imports these via\n * `zidane/chat/pure`. The `useStreamBuffer` React hook + its smooth-stream\n * ticker live in `./streaming` (main barrel) and re-export these for\n * back-compat; a renderer owns its own ticker against the same reducers.\n */\n\nimport type { TurnUsage } from '../types'\nimport type { Owner, StreamEvent } from './types'\nimport { effectiveInputFromTurn } from '../stats'\nimport { chunkMarkdownForRender } from './markdown-segments'\n\nconst PARENT_OWNER: Owner = 'parent'\n\nexport function ownerOf(event: StreamEvent): Owner {\n return event.childId ?? PARENT_OWNER\n}\n\n/** Is this event owned by a subagent (rather than the top-level agent)? */\nfunction isChildOwned(event: StreamEvent): boolean {\n return event.childId !== undefined || (event.depth ?? 0) > 0\n}\n\n/**\n * Index of the event `owner`'s next delta may coalesce into, or `-1` when the\n * owner has no open lane at the tail.\n *\n * Walks backwards over events owned by OTHER subagents — concurrent siblings\n * whose rows carry no ordering relation to this owner's output, and which a\n * per-owner drain interleaves at ~60Hz — and stops at the first event that is\n * either this owner's or a real ordering boundary (parent output, user\n * prompts, banners). The caller decides whether the event found is mergeable\n * for its kind. A tail-only check splits every concurrent child's message\n * into fragments braided with its siblings'.\n */\nexport function mergeTargetIndex(events: readonly StreamEvent[], owner: Owner): number {\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i]!\n if (ownerOf(event) === owner)\n return i\n if (!isChildOwned(event))\n return -1\n }\n return -1\n}\n\n// ---------------------------------------------------------------------------\n// Streaming-delta merging — the ONE implementation every host shares (the\n// TUI's `useStreamBuffer`, the GUI renderer's stream store).\n//\n// Each event is owned by either the parent agent or a specific subagent\n// (`childId`). Same-owner same-kind text/thinking chunks coalesce into one\n// growing event so a renderer allocates one row per stream, not per delta.\n// The owner's event need not sit at the tail — see {@link mergeTargetIndex}.\n//\n// Generic over the host's event type: rows the reducers rebuild keep every\n// extra field (spread), and rows they mint carry only the base stream fields,\n// so `E`'s additional fields must be optional. `E` is never inferred from\n// `prev` (a bare `[]` would infer `never`): it defaults to `StreamEvent`, and\n// a host with a richer type names it (`appendMarkdownDelta<GuiStreamEvent>`).\n// ---------------------------------------------------------------------------\n\n/**\n * Default segment bound for a growing streaming markdown event. Coalescing\n * copies the ENTIRE accumulated string into fresh state on every drain tick,\n * so one long streamed message costs O(L²) aggregate — past this threshold\n * the event is split and the copy re-bounded. The split reuses\n * {@link chunkMarkdownForRender} (blank-line boundaries outside fences,\n * unsafe-continuation guard), so the finalized segments are byte-identical\n * to the chunks the renderer would have produced inside a single event, and\n * the one-row markdown/markdown margin stands in for the consumed blank line\n * exactly like the renderer's inter-chunk gap. When no safe boundary exists\n * (one giant fence/list) the event keeps growing until one arrives.\n */\nexport const STREAMING_MARKDOWN_SEGMENT_CHARS = 64 * 1024\n\n/**\n * Backoff for over-threshold events `chunkMarkdownForRender` could not\n * split (one giant fence/list): records the text length at the last failed\n * attempt, keyed on the streaming event object (re-keyed onto each tick's\n * replacement). Without it a single unsplittable segment re-runs the full\n * O(L) chunk walk on every drain tick. Growth is geometric (retry at +25%),\n * so total re-chunk work stays O(L) amortized.\n */\nconst unsplittableAtLength = new WeakMap<StreamEvent, number>()\nconst SEGMENT_SPLIT_RETRY_GROWTH = 1.25\n\nexport interface MarkdownDeltaOptions {\n /**\n * Split threshold for a growing block (default\n * {@link STREAMING_MARKDOWN_SEGMENT_CHARS}). `Infinity` keeps one event per\n * streamed message — for a host whose reloaded transcript shows messages\n * whole and whose renderer chunks long text itself.\n */\n segmentChars?: number\n}\n\nexport interface ThinkingDeltaOptions<E> {\n /** Decorate the first row of a newly opened thinking lane (e.g. stamp its start time). */\n onLaneOpen?: (row: E) => E\n}\n\n/**\n * Stamp owner (parent vs subagent) + depth + optional `turnId` onto a\n * freshly-minted event so consumers can identify the producer and the\n * source turn. Parent-owned events leave `childId` / `depth` off; `depth` is\n * also left off when the source never named one.\n */\nfunction tagEvent<E extends StreamEvent>(evt: StreamEvent, owner: Owner, depth: number | undefined, turnId: string | undefined): E {\n const withTurn = turnId ? { ...evt, turnId } : evt\n if (owner === PARENT_OWNER)\n return withTurn as E\n return { ...withTurn, childId: owner, ...(depth !== undefined ? { depth } : {}) } as E\n}\n\n/** Coalesce a markdown delta into `owner`'s open streaming block, or open one. */\nexport function appendMarkdownDelta<E extends StreamEvent = StreamEvent>(\n prev: NoInfer<E>[],\n delta: string,\n owner: Owner,\n depth: number | undefined,\n turnId: string | undefined,\n options: MarkdownDeltaOptions = {},\n): E[] {\n const segmentChars = options.segmentChars ?? STREAMING_MARKDOWN_SEGMENT_CHARS\n const at = mergeTargetIndex(prev, owner)\n const target = at >= 0 ? prev[at]! : undefined\n if (target && target.kind === 'markdown' && target.streaming) {\n const merged = target.text + delta\n const next = prev.slice()\n if (merged.length > segmentChars) {\n const lastFailed = unsplittableAtLength.get(target)\n if (lastFailed === undefined || merged.length > lastFailed * SEGMENT_SPLIT_RETRY_GROWTH) {\n const chunks = chunkMarkdownForRender(merged)\n if (chunks.length > 1) {\n // All segments inherit `target`'s tags (owner/depth/turnId) — they\n // are one coalesced stream, split for memory, not a new source.\n const segments = chunks.map((chunk, i) => i === chunks.length - 1\n ? { ...target, text: chunk }\n : { ...target, text: chunk, streaming: false })\n next.splice(at, 1, ...segments)\n return next\n }\n const grown = { ...target, text: merged }\n unsplittableAtLength.set(grown, merged.length)\n next[at] = grown\n return next\n }\n // Within the backoff window — merge without re-chunking, carrying\n // the failure marker onto the replacement event.\n const grown = { ...target, text: merged }\n unsplittableAtLength.set(grown, lastFailed)\n next[at] = grown\n return next\n }\n next[at] = { ...target, text: merged }\n return next\n }\n return [\n ...prev,\n tagEvent<E>({ kind: 'markdown', text: delta, streaming: true }, owner, depth, turnId),\n ]\n}\n\n/** Coalesce a thinking delta into `owner`'s open lane, one row per line. */\nexport function appendThinkingLines<E extends StreamEvent = StreamEvent>(\n prev: NoInfer<E>[],\n delta: string,\n owner: Owner,\n depth: number | undefined,\n turnId: string | undefined,\n options: ThinkingDeltaOptions<E> = {},\n): E[] {\n const lines = delta.split('\\n')\n const at = mergeTargetIndex(prev, owner)\n const target = at >= 0 ? prev[at]! : undefined\n const row = (text: string) => tagEvent<E>({ kind: 'thinking', text }, owner, depth, turnId)\n\n // Extra lines land right after the merged row rather than at the tail so\n // the owner's thinking lane stays contiguous while siblings stream.\n if (target && target.kind === 'thinking') {\n const next = prev.slice()\n next[at] = { ...target, text: target.text + lines[0] }\n if (lines.length > 1)\n next.splice(at + 1, 0, ...lines.slice(1).map(row))\n return next\n }\n\n const result = [...prev]\n if (lines[0] || lines.length > 1) {\n const first = row(lines[0]!)\n result.push(options.onLaneOpen ? options.onLaneOpen(first) : first)\n }\n\n for (let i = 1; i < lines.length; i++)\n result.push(row(lines[i]!))\n\n return result\n}\n\n/** Flip any trailing streaming markdown blocks (any owner) to finalized. */\nexport function finalizeStreamingMarkdown(events: StreamEvent[]): StreamEvent[] {\n let changed = false\n const next = events.map((e) => {\n if (e.kind === 'markdown' && e.streaming) {\n changed = true\n return { ...e, streaming: false }\n }\n return e\n })\n return changed ? next : events\n}\n\n/** Flip the trailing streaming markdown block for one specific owner. */\nexport function finalizeStreamingMarkdownForOwner(events: StreamEvent[], owner: Owner): StreamEvent[] {\n for (let i = events.length - 1; i >= 0; i--) {\n const e = events[i]\n if (e.kind !== 'markdown')\n continue\n if (!e.streaming)\n continue\n if (ownerOf(e) !== owner)\n continue\n const next = events.slice()\n next[i] = { ...e, streaming: false }\n return next\n }\n return events\n}\n\n/**\n * Effective context size for a single turn.\n *\n * `usage.input` is misleading on its own when prompt caching is active: providers\n * (Anthropic, OpenRouter→Anthropic, Gemini) report `input` as the *new uncached*\n * tokens only — the cached prefix shows up in `cacheRead`, and newly-cached\n * tokens in `cacheCreation`. The model still saw all three buckets, so the real\n * context-window utilization is their sum.\n *\n * Non-caching providers leave `cacheRead`/`cacheCreation` undefined, so this\n * collapses to plain `input` for them.\n */\nexport function turnContextSize(usage: TurnUsage | undefined): number {\n return effectiveInputFromTurn(usage)\n}\n\n// ---------------------------------------------------------------------------\n// Transcript memory cap\n// ---------------------------------------------------------------------------\n\n/**\n * Display-layer transcript bounds. Each rendered event holds live React\n * fibers + OpenTUI renderables + native text buffers even when scrolled\n * off-screen — measured at roughly 0.13 MB RSS per markdown-heavy event —\n * so an uncapped multi-thousand-event session (a normal working day with\n * tool calls) climbs into the hundreds of MB and eventually OOM/thrash.\n *\n * The cap bounds ONLY what is materialized on screen: session turns on\n * disk are complete, and switching sessions / re-activating replays the\n * most recent window again. Trimming happens at TURN boundaries so a\n * turn's rows are never orphaned, and re-caps fold into one cumulative\n * marker rather than stacking markers.\n */\nexport const MAX_TRANSCRIPT_EVENTS = 1_500\n/** Post-trim size — the hysteresis gap keeps re-trims O(rare), not per-append. */\nexport const TRANSCRIPT_TRIM_TO_EVENTS = 1_200\n/**\n * A trim keeps at least this many of the user's own prompts when it can:\n * one long agent run (thousands of tool and subagent events, folded into a\n * single row) would otherwise leave a transcript that opens on one exchange.\n */\nexport const TRANSCRIPT_KEEP_PROMPTS = 10\n\n/**\n * The cumulative count rides IN the marker's display text and is parsed\n * back out on re-cap — deliberately text-as-protocol rather than a new\n * StreamEvent kind or field: 'info' renders everywhere for free (no\n * renderer changes, no persistence shape change — markers are display\n * state and never persisted), and producer + consumer live ten lines\n * apart in this file. Same precedent as task-notification re-synthesis.\n * If markers ever need richer data, THAT is the moment for a dedicated\n * event kind.\n */\nconst HIDDEN_MARKER_RE = /^… (\\d+) earlier transcript items hidden/\n\nexport function hiddenEarlierTranscriptCount(events: readonly StreamEvent[]): number {\n const first = events[0]\n return first?.kind === 'info' ? Number(HIDDEN_MARKER_RE.exec(first.text)?.[1] ?? 0) : 0\n}\n\nfunction hiddenMarkerEvent(count: number): StreamEvent {\n // Copy stays host-neutral: this helper is shared SDK surface, and only\n // the TUI wires a scroll-to-load affordance — promising \"scroll up\" on\n // hosts without one would be a false affordance.\n return {\n kind: 'info',\n text: `… ${count} earlier transcript items hidden to bound memory. The full history stays in the session.`,\n }\n}\n\n/**\n * Swap one turn's rows for its rebuilt ones, in place; `null` when the turn\n * is not on show.\n */\nexport function replaceTranscriptTurnEvents(\n displayed: readonly StreamEvent[],\n rebuilt: readonly StreamEvent[],\n turnId: string,\n): StreamEvent[] | null {\n const replacements = rebuilt.filter(event => event.turnId === turnId)\n let inserted = false\n const patched = displayed.flatMap((event) => {\n if (event.turnId !== turnId)\n return [event]\n if (inserted)\n return []\n inserted = true\n return replacements\n })\n return inserted ? patched : null\n}\n\n/**\n * A run in the transcript: everything from one of the user's own prompts\n * up to the next one. Revealing and capping move in whole runs, so the top\n * of the transcript always opens on a prompt, not halfway through what the\n * agent did for it.\n */\nfunction isRunStart(e: StreamEvent | undefined): boolean {\n return e !== undefined && isTopLevelPrompt(e)\n}\n\n/** A run longer than this many reveal pages on its own is revealed in pieces of that size. */\nconst WHOLE_RUN_REVEAL_PAGES = 5\n\n/**\n * Reveal the earlier history while keeping everything on show: the whole\n * run right before it, and the runs before that while they fit `pageSize`\n * events together (several small runs at once, never part of one). A run\n * longer than {@link WHOLE_RUN_REVEAL_PAGES} pages on its own comes in\n * pieces that size, cut at a turn boundary so a tool call keeps its result.\n * The default transcript is memory-bounded; memory grows only when the user\n * deliberately scrolls into the marker.\n */\nexport function revealEarlierTranscriptEvents(\n all: readonly StreamEvent[],\n displayed: readonly StreamEvent[],\n pageSize: number = 600,\n): StreamEvent[] {\n const hidden = hiddenEarlierTranscriptCount(displayed)\n if (hidden <= 0)\n return displayed as StreamEvent[]\n // Tail preserved by reference — it may include transient live rows that\n // are never persisted (task-notification banners, warn lines).\n const tail = displayed.slice(1)\n // Seam: where the visible tail begins inside the re-materialized history.\n // The marker count was minted against the LIVE display array — which\n // holds those transient rows — so it is NOT a reliable index into `all`.\n // Anchor structurally on the tail's first turn instead (the cap cuts at\n // turn boundaries and never ON a turn-less row, so the tail's head IS\n // that turn's first event); the count is only a fallback for tails\n // without any turn-tagged event.\n const anchorTurnId = tail.find(e => e.turnId !== undefined)?.turnId\n const anchorIndex = anchorTurnId !== undefined ? all.findIndex(e => e.turnId === anchorTurnId) : -1\n const seam = anchorIndex >= 0 ? anchorIndex : Math.min(hidden, all.length)\n if (seam <= 0)\n return displayed as StreamEvent[]\n const page = Math.max(1, pageSize)\n /** Where the run holding `all[end - 1]` starts (0 when no prompt precedes it). */\n const runStart = (end: number): number => {\n let i = end - 1\n while (i > 0 && !isRunStart(all[i]))\n i--\n return i\n }\n let from = runStart(seam)\n if (seam - from > page * WHOLE_RUN_REVEAL_PAGES) {\n // One run too long to bring whole: its last part, from a turn boundary.\n from = seam - page * WHOLE_RUN_REVEAL_PAGES\n while (from < seam - 1 && all[from]?.turnId !== undefined && all[from]?.turnId === all[from - 1]?.turnId)\n from++\n }\n else {\n while (from > 0) {\n const previous = runStart(from)\n if (seam - previous > page)\n break\n from = previous\n }\n }\n const out = [...all.slice(from, seam), ...tail]\n if (from > 0)\n out.unshift(hiddenMarkerEvent(from))\n return out\n}\n\n/** The user's own prompt, not a subagent's. */\nfunction isTopLevelPrompt(e: StreamEvent): boolean {\n return e.kind === 'user-prompt' && !e.depth && (!e.childId || e.childId === 'parent')\n}\n\n/** Index of the `n`-th last top-level user prompt at or after `from` (the earliest one when fewer); -1 with none. */\nfunction nthLastPrompt(events: readonly StreamEvent[], n: number, from: number): number {\n let seen = 0\n let at = -1\n for (let i = events.length - 1; i >= from; i--) {\n const e = events[i]!\n if (isTopLevelPrompt(e)) {\n at = i\n if (++seen >= n)\n break\n }\n }\n return at\n}\n\n/**\n * A transcript's end, with `earlier` events of the whole replay before it:\n * the hidden-count marker in front, as a cap would have left it.\n */\nexport function withEarlierHidden(events: StreamEvent[], earlier: number): StreamEvent[] {\n return earlier > 0 ? [hiddenMarkerEvent(earlier), ...events] : events\n}\n\n/**\n * Whether the end of a transcript (from a turn boundary) is enough for\n * {@link capTranscriptEvents} at the default bounds: capping it behind its\n * hidden-count marker cuts exactly where capping the whole transcript\n * would. Over the cap, and holding the prompts the cut reaches back to.\n */\nexport function coversTranscriptCap(events: readonly StreamEvent[]): boolean {\n if (events.length <= MAX_TRANSCRIPT_EVENTS)\n return false\n let prompts = 0\n for (const e of events) {\n if (isTopLevelPrompt(e) && ++prompts >= TRANSCRIPT_KEEP_PROMPTS)\n return true\n }\n return false\n}\n\n/**\n * Bound a transcript event array for display. Identity below the cap\n * (no re-render churn on the hot append path); above it, drops the\n * oldest events down to {@link TRANSCRIPT_TRIM_TO_EVENTS} — extended to\n * the next turn boundary — and prepends a cumulative hidden-count\n * marker. Callers: the stream buffer's drain commit and every\n * `eventsFromTurns` replay site.\n */\nexport function capTranscriptEvents(\n events: StreamEvent[],\n max: number = MAX_TRANSCRIPT_EVENTS,\n trimTo: number = TRANSCRIPT_TRIM_TO_EVENTS,\n): StreamEvent[] {\n if (events.length <= max)\n return events\n // A custom `max` below the default `trimTo` must still cap: clamp the\n // keep-size to 80% of the cap so the hysteresis gap scales with it.\n // (Without this, `maxTranscriptEvents: 500` would compute a cut point\n // before the array even starts and silently return it uncapped.)\n const keep = Math.max(1, Math.min(trimTo, Math.floor(max * 0.8)))\n\n // Fold a prior marker into the cumulative count instead of stacking.\n let previouslyHidden = 0\n let start = 0\n const first = events[0]\n if (first && first.kind === 'info') {\n const match = HIDDEN_MARKER_RE.exec(first.text)\n if (match) {\n previouslyHidden = Number(match[1]) || 0\n start = 1\n }\n }\n\n // Aim to keep the newest `trimTo` events, then extend the cut forward\n // to the next turn boundary so no turn is ever split mid-rows. Events\n // without a turnId (separators, banners) are boundaries themselves.\n let cut = events.length - keep\n if (cut <= start)\n return events\n // Reach back to the user's last few prompts, up to halfway to the cap:\n // the rest of the gap keeps re-trims rare on the append path.\n const promptAt = nthLastPrompt(events, TRANSCRIPT_KEEP_PROMPTS, start)\n if (promptAt >= 0 && promptAt < cut)\n cut = Math.max(promptAt, events.length - Math.floor((max + keep) / 2), start + 1)\n const turnAtCut = (i: number): string | undefined => events[i]?.turnId\n // Keep whole runs: start what stays on the next prompt (a run that is all\n // of the tail on its own stays, cut at a turn boundary instead).\n if (!isRunStart(events[cut])) {\n let next = cut + 1\n while (next < events.length && !isRunStart(events[next]))\n next++\n if (next < events.length)\n cut = next\n }\n while (cut < events.length) {\n const turn = turnAtCut(cut)\n if (turn === undefined || turn !== turnAtCut(cut - 1))\n break\n cut++\n }\n // Never cut ON a turn-less row (spawn markers, banners): the reveal seam\n // anchors on the tail's first turn-tagged event, so a turn-less tail head\n // would be re-included from the re-materialized history and render twice\n // (worst case an unpaired spawn-start that reads as a phantom live child).\n // Turn-less rows are boundaries themselves, so skipping them keeps the\n // no-split-turn invariant intact.\n while (cut < events.length && turnAtCut(cut) === undefined)\n cut++\n if (cut >= events.length)\n cut = events.length - 1 // pathological turn-less/single-turn flood: keep the last event\n\n const hidden = previouslyHidden + (cut - start)\n return [hiddenMarkerEvent(hidden), ...events.slice(cut)]\n}\n","/**\n * Per-tool display metadata + one-line formatters consumed by any\n * surface that renders a `tool` event in `'formatted'` mode (see\n * `Settings.toolCallDisplay`).\n *\n * Each native tool gets a curated entry — a `displayName` verb that\n * reads in sentence case (e.g. \"Read\", \"Shell\") and a `format` callback\n * that pulls the most informative bits out of the model's raw input to\n * a single scannable line. Unknown tools (MCP servers, host-added\n * tools, future zidane additions) fall back to {@link formatToolCall}\n * returning `null` — the renderer then shows a minimal `↳ <name>` line.\n *\n * Renderer-agnostic: returns plain data (`{ target, meta }`) so the\n * TUI's React/OpenTUI surface and any future GUI consumer can paint\n * the same shape in their own style. Lives in `zidane/chat` because\n * it has no rendering concerns; the TUI just consumes it.\n */\n\nimport { utf8ByteLength } from '../compact/utils'\nimport { formatBytes } from '../format-bytes'\nimport { readFileInputPaths } from '../tools/read-file-targets'\nimport { previewLine } from './format'\nimport { shortSessionId } from './orchestration'\n\nexport interface ToolFormatLine {\n /**\n * Primary target — typically a path, command, pattern, or\n * task description. Renderer paints this in the model accent color\n * so the eye lands on it first.\n */\n target?: string\n /**\n * Secondary annotations rendered after the target, joined with\n * ` · ` separators. Use for line ranges (`L10-25`), limits, flags,\n * or any short suffix that adds context without bloating the line.\n */\n meta?: readonly string[]\n /**\n * Optional SECOND line — the payload behind the action (a prompt sent to\n * another session). Renderers paint it dimmed under the header and clamp\n * it (two lines in the GUI, one terminal row in the TUI); it is never\n * squeezed into the header line, which stays single-line.\n */\n detail?: string\n /**\n * The session this call targets, when the tool addresses one. `target`\n * carries the short id as a fallback; a renderer with the session list in\n * scope shows the session's TITLE instead.\n */\n sessionId?: string\n}\n\nexport interface ToolDisplayMeta {\n /**\n * Title-case display verb (e.g. `Read`, `Shell`, `Edit`). When the\n * label depends on an input field (e.g. `skills_use`'s\n * `mode: 'activate' | 'deactivate'` → `Enable` / `Disable`), supply\n * a function instead and read the field defensively. The function\n * form is called whenever {@link displayNameFor} has the call's\n * input in scope; callers without input fall back to the function's\n * `input: undefined` branch, which should return a stable default.\n */\n displayName: string | ((input: Record<string, unknown> | undefined) => string)\n /**\n * Pull a {@link ToolFormatLine} out of the raw model input. Returns\n * `null` when the shape isn't what the tool expects (typed defensively\n * — we never want a malformed call to crash the transcript).\n */\n format: (input: Record<string, unknown>) => ToolFormatLine | null\n}\n\n// ---------------------------------------------------------------------------\n// Tool registry\n// ---------------------------------------------------------------------------\n\nconst SESSIONS_VERB_LABEL: Readonly<Record<string, string>> = {\n create: 'Create session',\n send: 'Send to session',\n steer: 'Steer session',\n cancel: 'Cancel session',\n read: 'Read session',\n transcript: 'Session transcript',\n list: 'List sessions',\n}\n\nexport const TOOL_DISPLAY: Readonly<Record<string, ToolDisplayMeta>> = {\n // ---- Pure reads ----\n read_file: {\n displayName: 'Read',\n format: (input) => {\n const path = stringField(input, 'path')\n if (!path) {\n // `paths` batch: first file as the target, the rest as a count.\n const paths = readFileInputPaths(input)\n if (paths.length === 0)\n return null\n return { target: paths[0], meta: paths.length > 1 ? [`+${paths.length - 1} more`] : [] }\n }\n const meta: string[] = []\n const offset = numberField(input, 'offset')\n const limit = numberField(input, 'limit')\n if (offset !== undefined && limit !== undefined && limit > 0)\n meta.push(`L${offset}–${offset + limit - 1}`)\n else if (offset !== undefined)\n meta.push(`from L${offset}`)\n else if (limit !== undefined && limit > 0)\n meta.push(`${limit} lines`)\n return { target: path, meta }\n },\n },\n list_files: {\n displayName: 'List',\n format: (input) => {\n const path = stringField(input, 'path') ?? '.'\n return { target: path }\n },\n },\n glob: {\n displayName: 'Glob',\n format: (input) => {\n const pattern = stringField(input, 'pattern')\n if (!pattern)\n return null\n const meta: string[] = []\n const limit = numberField(input, 'limit')\n if (limit !== undefined)\n meta.push(`limit ${limit}`)\n return { target: pattern, meta }\n },\n },\n grep: {\n displayName: 'Grep',\n format: (input) => {\n const pattern = stringField(input, 'pattern')\n if (!pattern)\n return null\n const target = `/${pattern}/`\n const meta: string[] = []\n const path = stringField(input, 'path')\n if (path && path !== '.')\n meta.push(`in ${path}`)\n const glob = stringField(input, 'glob')\n if (glob)\n meta.push(glob)\n const type = stringField(input, 'type')\n if (type)\n meta.push(`type:${type}`)\n if (input['-i'] === true)\n meta.push('case-insensitive')\n const mode = stringField(input, 'output_mode')\n if (mode && mode !== 'files_with_matches')\n meta.push(mode)\n return { target, meta }\n },\n },\n\n // ---- Shell ----\n shell: {\n // Verb switches when the model dispatches a background task — same\n // pattern `skills_use` uses for activate/deactivate. The transcript\n // reads as `↳ Shell (background): npm run dev` so the user can spot\n // backgrounded invocations at a glance without reading the args.\n //\n // With the model's `description` (\"Run the GUI typecheck\"), that is the\n // label, as for Codemode: it says what the call does, and the command\n // itself is the call's (highlighted) input. Without one, the command is\n // the target.\n displayName: (input) => {\n const description = input ? stringField(input, 'description')?.trim() : undefined\n if (description)\n return previewLine(description, 120)\n return input?.run_in_background === true ? 'Shell (background)' : 'Shell'\n },\n format: (input) => {\n const command = stringField(input, 'command')\n if (!command)\n return null\n if (stringField(input, 'description')?.trim())\n return input.run_in_background === true ? { meta: ['background'] } : {}\n return { target: previewLine(command, 200) }\n },\n },\n shell_kill: {\n displayName: 'Kill task',\n format: (input) => {\n const taskId = stringField(input, 'task_id')\n if (!taskId)\n return null\n return { target: taskId }\n },\n },\n wait_task: {\n displayName: 'Wait for task',\n format: (input) => {\n const taskId = stringField(input, 'task_id')\n if (!taskId)\n return null\n const timeoutMs = input.timeout_ms\n return {\n target: taskId,\n meta: typeof timeoutMs === 'number' ? [`${Math.round(timeoutMs / 1000)}s timeout`] : [],\n }\n },\n },\n\n // ---- Edits (renderer falls through to EditDiffBlock when showEditDiffs is on) ----\n edit: {\n displayName: 'Edit',\n format: (input) => {\n const path = stringField(input, 'path')\n if (!path)\n return null\n return {\n target: path,\n meta: input.replace_all === true ? ['replace all'] : [],\n }\n },\n },\n multi_edit: {\n displayName: 'Multi-edit',\n format: (input) => {\n const path = stringField(input, 'path')\n if (!path)\n return null\n const edits = Array.isArray(input.edits) ? input.edits.length : 0\n return {\n target: path,\n meta: edits > 0 ? [`${edits} hunk${edits === 1 ? '' : 's'}`] : [],\n }\n },\n },\n write_file: {\n displayName: 'Write',\n format: (input) => {\n const path = stringField(input, 'path')\n if (!path)\n return null\n const content = stringField(input, 'content')\n const meta: string[] = []\n if (content !== undefined) {\n // Show byte count instead of line count — write_file's main\n // failure mode is \"did you mean to overwrite a 10KB file with\n // a 4-byte one?\", so bytes catch it faster than lines do.\n const bytes = utf8ByteLength(content)\n meta.push(`${formatBytes(bytes)}`)\n }\n return { target: path, meta }\n },\n },\n\n // ---- Spawn / orchestration ----\n spawn: {\n displayName: 'Agent',\n format: (input) => {\n const task = stringField(input, 'task')\n if (!task)\n return null\n // Continuation of a stopped/failed child (`resume: 'child-N'`) —\n // tag the line so a resume is distinguishable from a fresh spawn.\n const resume = stringField(input, 'resume')\n // Generous cap — a pathology guard, not layout: both renderers\n // width-truncate (TUI by terminal columns, GUI by CSS), so a tight\n // char cap here just wasted horizontal room on wide windows.\n return { target: previewLine(task, 200), ...(resume ? { meta: [`resumed ${resume}`] } : {}) }\n },\n },\n\n // ---- Codemode ----\n codemode: {\n // The model's one-line `description` IS the label, in place of the verb:\n // the row reads \"Rank open issues by frustration\", not \"Codemode Rank …\".\n // Without input (group summaries, the context breakdown) or without a\n // description (older sessions) it stays \"Codemode\".\n displayName: (input) => {\n const description = input ? stringField(input, 'description')?.trim() : undefined\n return description ? previewLine(description, 120) : 'Codemode'\n },\n format: (input) => {\n const description = stringField(input, 'description')?.trim()\n const code = stringField(input, 'code')\n const lines = code ? code.split('\\n').filter(line => line.trim() !== '' && !line.trimStart().startsWith('// @options:')) : []\n const meta = lines.length > 0 ? [`${lines.length} line${lines.length === 1 ? '' : 's'}`] : []\n if (description)\n return { meta }\n if (lines.length === 0)\n return null\n // No description: the first line of code stands in as the target.\n return { target: previewLine(lines[0]!.trim(), 120), meta }\n },\n },\n\n // ---- Dev browser ----\n browser_open: {\n displayName: 'Browser',\n format: input => ({ target: stringField(input, 'url') ?? 'open' }),\n },\n browser_navigate: {\n displayName: 'Navigate',\n format: input => ({ target: stringField(input, 'url') ?? stringField(input, 'action') ?? '' }),\n },\n browser_snapshot: { displayName: 'Snapshot', format: () => ({ target: 'page' }) },\n browser_screenshot: {\n displayName: 'Screenshot',\n format: input => ({ target: stringField(input, 'ref') ?? 'viewport' }),\n },\n browser_click: {\n displayName: 'Click',\n format: input => ({ target: browserTarget(input) }),\n },\n browser_type: {\n displayName: 'Type',\n format: (input) => {\n const text = stringField(input, 'text') ?? ''\n const where = browserTarget(input)\n return { target: previewLine(JSON.stringify(text), 80), ...(where ? { meta: [`into ${where}`] } : {}) }\n },\n },\n browser_press: {\n displayName: 'Press',\n format: (input) => {\n const mods = Array.isArray(input.modifiers) ? (input.modifiers as unknown[]).map(String) : []\n return { target: [...mods, stringField(input, 'key') ?? ''].join('+') }\n },\n },\n browser_scroll: {\n displayName: 'Scroll',\n format: input => ({ target: `${numberField(input, 'dx') ?? 0}, ${numberField(input, 'dy') ?? 0}` }),\n },\n browser_wait_for: {\n displayName: 'Wait for',\n format: input => ({\n target: stringField(input, 'text') ?? stringField(input, 'selector') ?? stringField(input, 'urlIncludes') ?? '',\n }),\n },\n browser_evaluate: {\n displayName: 'Evaluate',\n format: input => ({ target: previewLine(stringField(input, 'expression') ?? '', 120) }),\n },\n browser_console: {\n displayName: 'Console',\n format: input => ({ target: stringField(input, 'level') ?? 'all' }),\n },\n\n // ---- Terminals (the session's, shared with the user) ----\n terminal_list: { displayName: 'Terminals', format: () => ({ target: 'list' }) },\n terminal_read: {\n displayName: 'Read terminal',\n format: input => ({ target: stringField(input, 'id') ?? '' }),\n },\n terminal_write: {\n displayName: 'Type in terminal',\n // What goes into the terminal is the point: the text, then the keys.\n format: (input) => {\n const text = stringField(input, 'text')\n const keys = Array.isArray(input.keys) ? (input.keys as unknown[]).map(String).filter(Boolean) : []\n const typed = [text ? previewLine(JSON.stringify(text), 80) : '', ...keys].filter(Boolean).join(' + ')\n const id = stringField(input, 'id')\n return { target: typed || (id ?? ''), ...(id && typed ? { meta: [id] } : {}) }\n },\n },\n\n // ---- Tool search (lazy-tool discovery) ----\n tool_search: {\n displayName: 'Search tools',\n format: (input) => {\n const query = stringField(input, 'query')\n const names = Array.isArray(input.names) ? input.names.length : 0\n if (query)\n return { target: `“${query}”` }\n if (names > 0)\n return { target: `${names} tool${names === 1 ? '' : 's'}` }\n return null\n },\n },\n\n // ---- Stable-tools dispatcher ----\n // Only ever rendered for a MALFORMED envelope: a well-formed `call_tool`\n // is unwrapped before the `tool` event is emitted (live) or replayed\n // (`eventsFromTurns`), so it shows up as the inner tool. This entry keeps\n // the rare shape error readable instead of a bare `↳ call_tool`.\n call_tool: {\n displayName: 'Call tool',\n format: (input) => {\n const name = stringField(input, 'name')\n return name ? { target: name, meta: ['malformed call'] } : null\n },\n },\n\n // ---- Skills ----\n skills_use: {\n // `skills_use` straddles two intents — activation (default) and\n // deactivation (`mode: 'deactivate'`, the zidane extension that lets\n // the model recover from `AgentToolNotAllowedError`). Showing \"Activate\"\n // for both modes hid the deactivation from the transcript and made\n // the model's recovery flow harder to follow. We pick the verb from\n // `input.mode`; absent or unexpected values fall back to \"Enable\" to\n // match the spec's activate-only semantics.\n displayName: (input) => {\n const mode = input ? stringField(input, 'mode') : undefined\n return mode === 'deactivate' ? 'Disable skill' : 'Enable skill'\n },\n format: (input) => {\n const name = stringField(input, 'name')\n if (!name)\n return null\n return { target: name }\n },\n },\n skills_read: {\n displayName: 'Read skill',\n format: (input) => {\n const name = stringField(input, 'name')\n const path = stringField(input, 'path')\n if (!name)\n return null\n return { target: path ? `${name}/${path}` : name }\n },\n },\n skills_run_script: {\n displayName: 'Run script',\n format: (input) => {\n const name = stringField(input, 'name')\n const script = stringField(input, 'script')\n if (!name || !script)\n return null\n const meta: string[] = [`skill ${name}`]\n const args = Array.isArray(input.args) ? input.args : null\n if (args && args.length > 0)\n meta.push(previewLine(args.map(String).join(' '), 80))\n return { target: script, meta }\n },\n },\n\n // ---- Todos ----\n todowrite: {\n displayName: 'Todos',\n format: (input) => {\n const todos = Array.isArray(input.todos) ? input.todos : null\n if (!todos)\n return null\n // Show item count + per-status tally — same shape the tool's\n // `tool_result` summary line uses, so the call line and result\n // line read consistently in the transcript.\n const counts = { pending: 0, in_progress: 0, completed: 0, cancelled: 0 }\n for (const t of todos) {\n if (!t || typeof t !== 'object')\n continue\n const status = (t as Record<string, unknown>).status\n if (typeof status === 'string' && status in counts)\n counts[status as keyof typeof counts] += 1\n }\n const meta: string[] = []\n if (counts.completed)\n meta.push(`${counts.completed} done`)\n if (counts.in_progress)\n meta.push(`${counts.in_progress} in progress`)\n if (counts.pending)\n meta.push(`${counts.pending} pending`)\n if (counts.cancelled)\n meta.push(`${counts.cancelled} cancelled`)\n return { target: `${todos.length} item${todos.length === 1 ? '' : 's'}`, meta }\n },\n },\n todoread: {\n displayName: 'Todos',\n format: () => ({ target: 'read' }),\n },\n\n // ---- Interactions (already surfaced as wizards, but the call line still renders) ----\n ask_user: {\n displayName: 'Ask user',\n format: (input) => {\n const questions = Array.isArray(input.questions) ? input.questions.length : 0\n if (questions === 0)\n return null\n return { target: `${questions} question${questions === 1 ? '' : 's'}` }\n },\n },\n present_plan: {\n displayName: 'Present plan',\n format: (input) => {\n const title = stringField(input, 'title')\n if (!title)\n return null\n return { target: title }\n },\n },\n\n // ---- Orchestration (main session only) ----\n // Reads like the session-event cards: line one is the ACTION and WHO it went\n // to (the session's title when the renderer knows it, short id otherwise);\n // line two is the message itself, clamped — prompts can be paragraphs long.\n sessions: {\n displayName: input => SESSIONS_VERB_LABEL[stringField(input ?? {}, 'verb') ?? ''] ?? 'Sessions',\n format: (input) => {\n const verb = stringField(input, 'verb')\n const id = stringField(input, 'sessionId')\n const limit = numberField(input, 'limit')\n // Every id-bearing verb: the short id is the target's FALLBACK text —\n // renderers that know the session swap in its title via `sessionId`.\n const ref = id ? { target: shortSessionId(id), sessionId: id } : null\n switch (verb) {\n case 'create': {\n const prompt = stringField(input, 'prompt')\n if (!prompt)\n return null\n const cwd = stringField(input, 'cwd')\n return { target: stringField(input, 'title') ?? 'new worker', meta: cwd ? [`in ${cwd}`] : [], detail: prompt }\n }\n case 'send':\n case 'steer': {\n const text = stringField(input, verb === 'send' ? 'prompt' : 'message')\n if (!text || !ref)\n return null\n return { ...ref, detail: text }\n }\n case 'cancel':\n case 'read':\n return ref\n case 'transcript':\n return ref ? { ...ref, meta: limit !== undefined ? [`last ${limit} turns`] : [] } : null\n case 'list':\n return { target: 'all sessions', meta: limit !== undefined ? [`limit ${limit}`] : [] }\n default:\n return null\n }\n },\n },\n}\n\n// ---------------------------------------------------------------------------\n// Public helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the display verb for a tool. Native tools use their curated\n * entry from {@link TOOL_DISPLAY}; everything else gets a sentence-case\n * version of the raw name (`my_host_tool` → `My host tool`) so an MCP /\n * host tool still reads cleanly in the transcript without shouting\n * Title Case at every word.\n *\n * MCP convention: every tool surfaced by `mcp/connectMcpServers` is\n * namespaced as `mcp_<server>_<tool>` (see `src/mcp/index.ts`). The\n * `mcp_` prefix is plumbing — strip it before casing so the label\n * reads as `Github create issue` instead of `Mcp github create issue`.\n * The server name leads, which doubles as a free visual grouping\n * affordance (\"everything starting with `Github` came from the github\n * MCP server\").\n */\nexport function displayNameFor(\n name: string,\n input?: Record<string, unknown>,\n): string {\n const entry = TOOL_DISPLAY[name]\n if (entry) {\n return typeof entry.displayName === 'function'\n ? entry.displayName(input)\n : entry.displayName\n }\n const stripped = name.startsWith('mcp_') ? name.slice(4) : name\n return sentenceCase(stripped)\n}\n\n/**\n * The source code a tool call runs, for renderers that show it highlighted\n * instead of the raw JSON input: Codemode's script as JavaScript, a `shell`\n * / `bash` command as bash (the command alone: the label carries the\n * description, the rest is plumbing). `null` for\n * every other tool and for calls without the code field. `language` is a\n * fence-style name both highlighters accept (Shiki in the GUI, OpenTUI's\n * tree-sitter in the TUI).\n */\nexport function toolInputCode(\n name: string,\n input: Record<string, unknown> | undefined,\n): { code: string, language: string } | null {\n if (!input)\n return null\n if (name === 'codemode') {\n const code = stringField(input, 'code')\n if (!code || code.trim() === '')\n return null\n return { code: code.replace(/^\\n+|\\s+$/g, ''), language: 'javascript' }\n }\n if (name === 'shell' || name === 'bash') {\n const command = stringField(input, 'command')\n if (!command || command.trim() === '')\n return null\n return { code: command.replace(/^\\n+|\\s+$/g, ''), language: 'bash' }\n }\n return null\n}\n\n/**\n * Run a tool's curated formatter and return the result, or `null` when\n * no formatter is registered / the input shape doesn't match. Renderer\n * decides what to do with `null` — typically: show `↳ <displayName>`\n * with no target / meta tail.\n */\nexport function formatToolCall(name: string, input: Record<string, unknown>): ToolFormatLine | null {\n const entry = TOOL_DISPLAY[name]\n if (!entry)\n return null\n try {\n return entry.format(input)\n }\n catch {\n // Defensive — a misshapen `input` should never crash the\n // transcript. Fall back to the unformatted line.\n return null\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/** A browser tool's target as written: ref, selector, or point. */\nfunction browserTarget(input: Record<string, unknown>): string {\n const x = numberField(input, 'x')\n const y = numberField(input, 'y')\n return stringField(input, 'ref') ?? stringField(input, 'selector') ?? (x !== undefined && y !== undefined ? `${x}, ${y}` : '')\n}\n\nfunction stringField(input: Record<string, unknown>, key: string): string | undefined {\n const v = input[key]\n return typeof v === 'string' && v.length > 0 ? v : undefined\n}\n\nfunction numberField(input: Record<string, unknown>, key: string): number | undefined {\n const v = input[key]\n return typeof v === 'number' && Number.isFinite(v) ? v : undefined\n}\n\n/** `snake_case` / `kebab-case` / lowercase → `Sentence case`. */\nfunction sentenceCase(s: string): string {\n const words = s.split(/[-_\\s]+/).filter(Boolean).map(w => w.toLowerCase())\n if (words.length === 0)\n return ''\n words[0] = (words[0][0]?.toUpperCase() ?? '') + words[0].slice(1)\n return words.join(' ')\n}\n"],"mappings":"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"}
|