zidane 7.2.4 → 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 -27242
- 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-zVSyo6K1.js +0 -331
- package/dist/ipc-zVSyo6K1.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-h5czzllR.js +0 -1549
- package/dist/shell-path-h5czzllR.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,3089 @@
|
|
|
1
|
+
import { Bp as Settings, Fd as CompletionProvider, Gh as ProviderAuth, Gy as SessionTurn, Id as CompletionReference, Jg as CacheBreakInfo, Kh as ProviderKey, Pp as Owner, Vp as StreamEvent, Wb as SkillConfig, Wd as Command, Xh as ModelInfo, Zb as Session$1, ab as ToolResultContent, by as JsonValue, jp as EditPayload, kp as EditOutcome, mb as TurnUsage, t as Preset, xy as McpServerConfig, yh as EnvironmentConfig, zp as SessionMeta } from "./index-BGe1fQT7.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/chat/color-gradient.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Blend two hex colors in HSL space with shortest-path hue interpolation.
|
|
6
|
+
* `t` ∈ [0, 1]; `t=0` returns `from`, `t=1` returns `to`.
|
|
7
|
+
*/
|
|
8
|
+
declare function blendHsl(from: string, to: string, t: number): string;
|
|
9
|
+
/**
|
|
10
|
+
* Static gradient ramp of length `n` going from `from` (index 0) to
|
|
11
|
+
* `to` (index n-1) in HSL space. For the cycling A→B→A→B ramp the
|
|
12
|
+
* throbber uses, see `buildCycleRamp` in `src/tui/crush-throbber.tsx`.
|
|
13
|
+
*/
|
|
14
|
+
declare function buildLinearRamp(from: string, to: string, n: number): string[];
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/chat/completion-chats.d.ts
|
|
17
|
+
declare const CHATS_TRIGGER = "#";
|
|
18
|
+
type ChatReferenceScope = 'project' | 'all';
|
|
19
|
+
interface ChatReferenceEntry {
|
|
20
|
+
id: string;
|
|
21
|
+
title: string;
|
|
22
|
+
turnCount: number;
|
|
23
|
+
userMessageCount: number;
|
|
24
|
+
runCount: number;
|
|
25
|
+
projectRoot?: string;
|
|
26
|
+
updatedAt: number;
|
|
27
|
+
/** Optional (store-dependent); shown as a hint when > 0. */
|
|
28
|
+
artifactCount?: number;
|
|
29
|
+
}
|
|
30
|
+
interface ChatReferenceData {
|
|
31
|
+
entry: ChatReferenceEntry;
|
|
32
|
+
token: string;
|
|
33
|
+
}
|
|
34
|
+
declare function createChatsCompletionProvider(opts: {
|
|
35
|
+
getCatalog: () => readonly ChatReferenceEntry[];
|
|
36
|
+
getReferenceCatalog?: () => readonly ChatReferenceEntry[];
|
|
37
|
+
getScope?: () => ChatReferenceScope;
|
|
38
|
+
ensureCatalog?: () => Promise<readonly ChatReferenceEntry[]>;
|
|
39
|
+
limit?: number;
|
|
40
|
+
}): CompletionProvider<ChatReferenceData>;
|
|
41
|
+
declare function uniqueChatIdsFromReferences(references: readonly CompletionReference<unknown>[]): string[];
|
|
42
|
+
declare function chatReferenceTokensFromText(text: string): string[];
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/chat/completion-commands.d.ts
|
|
45
|
+
/** Trigger character — shared with skills. */
|
|
46
|
+
declare const COMMANDS_TRIGGER = "/";
|
|
47
|
+
/**
|
|
48
|
+
* Build a commands completion provider against a *live* command list. The
|
|
49
|
+
* getter is re-evaluated per `suggest` so registry toggles / cwd rebuilds
|
|
50
|
+
* take effect without re-instantiating the provider.
|
|
51
|
+
*/
|
|
52
|
+
declare function createCommandsCompletionProvider(opts: {
|
|
53
|
+
getCommands: () => readonly Command[];
|
|
54
|
+
}): CompletionProvider<Command>;
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/chat/files-discovery.d.ts
|
|
57
|
+
/**
|
|
58
|
+
* Project file discovery for the `@`-prefixed files completion provider.
|
|
59
|
+
*
|
|
60
|
+
* Primary strategy — `git ls-files --cached --others --exclude-standard`.
|
|
61
|
+
* Git already understands `.gitignore`, `.git/info/exclude`, and global
|
|
62
|
+
* excludes, so we get correctness for free + sub-second performance on
|
|
63
|
+
* even huge monorepos. Falls back to a depth-limited filesystem walk when
|
|
64
|
+
* git isn't available or the directory isn't a repo.
|
|
65
|
+
*
|
|
66
|
+
* Pure: callers cache the returned list (e.g. in App state) and pass it
|
|
67
|
+
* into the provider's `getCatalog`. The list is a snapshot — refresh on
|
|
68
|
+
* cwd change or via a user-driven action.
|
|
69
|
+
*/
|
|
70
|
+
/** One row in the project file catalog. `path` is forward-slashed + relative to `cwd`. */
|
|
71
|
+
interface FileEntry {
|
|
72
|
+
/** Forward-slashed relative path from the discovery cwd. Stable across OSes. No trailing slash for dirs. */
|
|
73
|
+
path: string;
|
|
74
|
+
/** Basename — used for prefix ranking in the completion provider. */
|
|
75
|
+
name: string;
|
|
76
|
+
/** Source — `git` when listed via `git ls-files`, `fs` from the walk fallback. */
|
|
77
|
+
source: 'git' | 'fs';
|
|
78
|
+
/**
|
|
79
|
+
* Entry kind. Directories are derived from the discovered file paths
|
|
80
|
+
* (every ancestor of a listed file), so only directories that contain
|
|
81
|
+
* at least one non-ignored file appear — mirroring `git ls-files`
|
|
82
|
+
* semantics, which never lists empty or fully-ignored dirs.
|
|
83
|
+
*/
|
|
84
|
+
kind: 'file' | 'dir';
|
|
85
|
+
}
|
|
86
|
+
/** Options for `listProjectFiles`. */
|
|
87
|
+
interface ListProjectFilesOptions {
|
|
88
|
+
/** Discovery root. Default: `process.cwd()`. */
|
|
89
|
+
cwd?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Cap on discovered files. Default: 10,000. Bigger lists fall back to
|
|
92
|
+
* a truncated set. Derived directory entries are appended on top with
|
|
93
|
+
* their own equal cap, so the returned array can exceed `maxFiles`
|
|
94
|
+
* (bounded by 2×).
|
|
95
|
+
*/
|
|
96
|
+
maxFiles?: number;
|
|
97
|
+
/** Aborts the scan early. Useful when re-running on rapid project switches. */
|
|
98
|
+
signal?: AbortSignal;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Discover every non-ignored file under `cwd`, plus the directories that
|
|
102
|
+
* contain them (derived from the file paths, `kind: 'dir'`). Tries
|
|
103
|
+
* `git ls-files` first; on failure (no git, not a repo, abort) walks the
|
|
104
|
+
* fs with a hand-rolled skip list.
|
|
105
|
+
*
|
|
106
|
+
* Errors are not thrown — the function always returns an array (possibly
|
|
107
|
+
* empty). Callers wanting failure diagnostics can opt into them via
|
|
108
|
+
* `ZIDANE_DEBUG`.
|
|
109
|
+
*/
|
|
110
|
+
declare function listProjectFiles(opts?: ListProjectFilesOptions): Promise<FileEntry[]>;
|
|
111
|
+
/**
|
|
112
|
+
* File entries (plus their ancestor dirs) from relative paths — what
|
|
113
|
+
* {@link listProjectFiles} returns, for lists produced elsewhere (a remote
|
|
114
|
+
* sandbox's `git ls-files`).
|
|
115
|
+
*/
|
|
116
|
+
declare function fileEntriesFromPaths(paths: readonly string[], source?: 'git' | 'fs', maxFiles?: number): FileEntry[];
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/chat/completion-files.d.ts
|
|
119
|
+
/** Trigger character — `@` is the conventional file-mention prefix in chat UIs. */
|
|
120
|
+
declare const FILES_TRIGGER = "@";
|
|
121
|
+
/**
|
|
122
|
+
* Build an `@`-prefixed files completion provider against a *live* catalog.
|
|
123
|
+
*
|
|
124
|
+
* The factory captures a getter so the catalog can be re-scanned (cwd
|
|
125
|
+
* change, manual refresh) without re-instantiating the provider — the
|
|
126
|
+
* App keeps one provider for the lifetime of the prompt block and just
|
|
127
|
+
* mutates the underlying state.
|
|
128
|
+
*
|
|
129
|
+
* `limit` caps the result list so the popover stays bounded on huge
|
|
130
|
+
* monorepos. Filtering is substring on `path` + `name`, case-insensitive,
|
|
131
|
+
* with an fzf-scored basename fuzzy fallback so small typos / omissions
|
|
132
|
+
* (`lop.ts` → `loop.ts`) still surface results; ranking prefers (in
|
|
133
|
+
* order): exact name match, name prefix, name substring, path substring,
|
|
134
|
+
* basename fuzzy match, alphabetical.
|
|
135
|
+
*/
|
|
136
|
+
declare function createFilesCompletionProvider(opts: {
|
|
137
|
+
/** Live file catalog. Re-evaluated per call so refreshes take effect immediately. */
|
|
138
|
+
getCatalog: () => readonly FileEntry[];
|
|
139
|
+
/**
|
|
140
|
+
* Optional hook called the first time the host needs the catalog —
|
|
141
|
+
* e.g. when the user opens the `@` popover. Hosts wire this to a
|
|
142
|
+
* lazy directory walk so boot doesn't pay for it in monorepos
|
|
143
|
+
* where the popover may never open. Idempotent contract: callers
|
|
144
|
+
* may invoke it on every `suggest`; the host caches internally.
|
|
145
|
+
*
|
|
146
|
+
* When provided, `suggest()` returns a Promise on the very first
|
|
147
|
+
* invocation if the catalog is still empty — the popover's loading
|
|
148
|
+
* state surfaces while the walk completes; subsequent calls are
|
|
149
|
+
* sync because `getCatalog()` then returns the populated state.
|
|
150
|
+
*/
|
|
151
|
+
ensureCatalog?: () => Promise<readonly FileEntry[]>;
|
|
152
|
+
/** Max items returned to the popover. Default: 50. */
|
|
153
|
+
limit?: number;
|
|
154
|
+
/**
|
|
155
|
+
* Rewrite the catalog's project-root-relative path into the form
|
|
156
|
+
* inserted into the prompt + matched by `parseReferences`. Wire this
|
|
157
|
+
* to `formatPathForCwd` so paths emitted into the buffer line up
|
|
158
|
+
* with the agent's CWD-resolving tools when the TUI launches from a
|
|
159
|
+
* project subdirectory. Default: identity.
|
|
160
|
+
*
|
|
161
|
+
* Stable identity expected — `parseReferences` calls it once per
|
|
162
|
+
* catalog entry per keystroke for the highlight pass; pure
|
|
163
|
+
* pure-function shape keeps the popover responsive on huge repos.
|
|
164
|
+
*/
|
|
165
|
+
formatPath?: (entry: FileEntry) => string;
|
|
166
|
+
}): CompletionProvider<FileEntry>;
|
|
167
|
+
/**
|
|
168
|
+
* Walk a reference list and return the deduplicated set of files in
|
|
169
|
+
* first-mention order — input to "attach these files to the prompt"
|
|
170
|
+
* downstream logic.
|
|
171
|
+
*/
|
|
172
|
+
declare function uniqueFilesFromReferences(references: readonly CompletionReference<unknown>[]): FileEntry[];
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/chat/completion-skills.d.ts
|
|
175
|
+
/** Trigger character — slash-commands convention. */
|
|
176
|
+
declare const SKILLS_TRIGGER = "/";
|
|
177
|
+
/**
|
|
178
|
+
* Build a slash-command completion provider against a *live* skills
|
|
179
|
+
* catalog. The factory captures a getter so the catalog can change across
|
|
180
|
+
* renders (toggles, reload) without re-instantiating the provider.
|
|
181
|
+
*
|
|
182
|
+
* Pass `getEnabled` to additionally hide skills the user has toggled off
|
|
183
|
+
* — when undefined, every catalog entry is offered.
|
|
184
|
+
*/
|
|
185
|
+
declare function createSkillsCompletionProvider(opts: {
|
|
186
|
+
/** Live catalog. Re-evaluated per call so toggles take effect immediately. */
|
|
187
|
+
getCatalog: () => readonly SkillConfig[];
|
|
188
|
+
/** Optional enable-set filter; when undefined every catalog skill is offered. */
|
|
189
|
+
getEnabled?: () => readonly string[] | undefined;
|
|
190
|
+
/**
|
|
191
|
+
* Optional hook called the first time the host needs the catalog —
|
|
192
|
+
* typically when the user opens the `/` popover. Mirror of the
|
|
193
|
+
* files provider's `ensureCatalog`; same idempotent contract.
|
|
194
|
+
*
|
|
195
|
+
* Hosts wire this to a lazy SKILL.md scan so the boot path stays
|
|
196
|
+
* free of disk reads in deeply-nested skill trees. Returns a Promise
|
|
197
|
+
* on the very first `suggest()` call when the catalog is still
|
|
198
|
+
* empty so the popover surfaces its loading state.
|
|
199
|
+
*/
|
|
200
|
+
ensureCatalog?: () => Promise<readonly SkillConfig[]>;
|
|
201
|
+
}): CompletionProvider<SkillConfig>;
|
|
202
|
+
/**
|
|
203
|
+
* Walk a parsed prompt for skill references and return the deduplicated
|
|
204
|
+
* list of skill names — input to `agent.activateSkill(name)` calls on
|
|
205
|
+
* submit.
|
|
206
|
+
*/
|
|
207
|
+
declare function uniqueSkillNamesFromReferences(references: readonly CompletionReference<unknown>[]): string[];
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region src/chat/keybinding-spec.d.ts
|
|
210
|
+
/**
|
|
211
|
+
* The `keybindings.json` spec grammar (`"ctrl+shift+o"`, `"ctrl+w | cmd+w"`),
|
|
212
|
+
* shared by the TUI (`./keybindings`) and the GUI renderer (through
|
|
213
|
+
* `zidane/chat/pure`) so one file parses the same on both surfaces. No node
|
|
214
|
+
* imports: the matchers live with each surface's key-event shape.
|
|
215
|
+
*/
|
|
216
|
+
/** Parsed shape of a `"ctrl+shift+o"` spec. */
|
|
217
|
+
interface ParsedBinding {
|
|
218
|
+
ctrl: boolean;
|
|
219
|
+
shift: boolean;
|
|
220
|
+
alt: boolean;
|
|
221
|
+
meta: boolean;
|
|
222
|
+
/** The key name (e.g. `'o'`, `'tab'`, `'escape'`). Always lowercase. */
|
|
223
|
+
name: string;
|
|
224
|
+
}
|
|
225
|
+
/** A key name as the parser canonicalizes it (`'Enter'` → `'return'`, `'ArrowLeft'` → `'left'`). */
|
|
226
|
+
declare function canonicalKeyName(key: string): string;
|
|
227
|
+
/**
|
|
228
|
+
* The chords one binding lists. A binding may name several, any of which
|
|
229
|
+
* fires the action: `"ctrl+w | cmd+w"` (or, in `keybindings.json`, an array).
|
|
230
|
+
* A `|` right after a `+` / `-` is the key itself (`ctrl+|`).
|
|
231
|
+
*/
|
|
232
|
+
declare function bindingAlternatives(spec: string | undefined | null): string[];
|
|
233
|
+
/** Every chord of `spec` that parses (see {@link bindingAlternatives}). */
|
|
234
|
+
declare function parseBindingSpecs(spec: string | undefined | null): ParsedBinding[];
|
|
235
|
+
/**
|
|
236
|
+
* The spec's first valid chord (callers that pre-parse one binding). Use
|
|
237
|
+
* {@link parseBindingSpecs} to honour every alternative.
|
|
238
|
+
*/
|
|
239
|
+
declare function parseBindingSpec(spec: string | undefined | null): ParsedBinding | null;
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/chat/turn-selection.d.ts
|
|
242
|
+
/** Tools whose `tool-result` event is suppressed when `showEditDiffs` is on. */
|
|
243
|
+
declare const EDIT_TOOL_NAMES: ReadonlySet<string>;
|
|
244
|
+
/**
|
|
245
|
+
* Keep turn-selection mode alive after deleting its active row. Prefer the
|
|
246
|
+
* row that slides into the deleted index; at the tail, select the new last
|
|
247
|
+
* row. Returns null only when no selectable rows survive.
|
|
248
|
+
*/
|
|
249
|
+
declare function selectionAfterTurnRemoval(before: readonly string[], removedId: string, after: readonly string[]): string | null;
|
|
250
|
+
/**
|
|
251
|
+
* Recognize a tool-result body as carrying NON-success information so the
|
|
252
|
+
* renderer doesn't suppress it under `showEditDiffs`. Three categories:
|
|
253
|
+
*
|
|
254
|
+
* - `edit` → "Edit error: …"
|
|
255
|
+
* - `write_file` permission errors wrapped by the loop → "Tool failed: …"
|
|
256
|
+
* - `multi_edit` → legacy single-line error `multi_edit error: …`, OR
|
|
257
|
+
* a result carrying an `<edit-outcomes>…</edit-outcomes>` annotation
|
|
258
|
+
* block. The TUI only appends the annotation when at least one hunk
|
|
259
|
+
* was NOT applied, so its mere presence is the signal — the result
|
|
260
|
+
* body needs to stay visible next to the diff so the user can read
|
|
261
|
+
* denial / skip / failure reasons longer than the per-hunk badge.
|
|
262
|
+
* - Fully-denied gate emit (`[fully denied] <edit-outcomes>…`) likewise
|
|
263
|
+
* stays visible.
|
|
264
|
+
*
|
|
265
|
+
* Exported for unit-testability of the visibility matrix.
|
|
266
|
+
*/
|
|
267
|
+
declare function isEditErrorResult(text: string): boolean;
|
|
268
|
+
/**
|
|
269
|
+
* `callId` prefix minted by the TUI's `!` bash mode (see `runBashMode`
|
|
270
|
+
* in `src/tui/commands/run-bash-mode.ts`). The prefix is the durable signal — it survives
|
|
271
|
+
* persistence and replay — that a `shell` tool exchange was USER-initiated,
|
|
272
|
+
* so renderers can keep it visible even when the tool-display settings
|
|
273
|
+
* hide model-driven plumbing: the user typed the command and expects to
|
|
274
|
+
* see it and what it printed.
|
|
275
|
+
*/
|
|
276
|
+
declare const BASH_CALL_ID_PREFIX = "bash_";
|
|
277
|
+
/** Is this event a user-initiated `!` bash exchange (vs. a model-driven shell call)? */
|
|
278
|
+
declare function isUserBashEvent(event: Pick<StreamEvent, 'tool' | 'callId'>): boolean;
|
|
279
|
+
/**
|
|
280
|
+
* Retro-tag live `user-prompt` events with the id of their persisted turn.
|
|
281
|
+
*
|
|
282
|
+
* Live prompt echoes are appended to the stream BEFORE `agent.run()` mints
|
|
283
|
+
* and persists the user turn, so they carry no `turnId` — which makes them
|
|
284
|
+
* invisible to select-turn navigation, hover, and click (all keyed on
|
|
285
|
+
* `turnId`), while the SAME prompt becomes selectable after a session reload
|
|
286
|
+
* (replay tags every event). Hosts call this when the seeded turns land
|
|
287
|
+
* (e.g. the `session:turns` hook, which fires right after the prompt turn
|
|
288
|
+
* persists, before the first model turn).
|
|
289
|
+
*
|
|
290
|
+
* Matching rule, per prompt-bearing turn: the NEWEST `user-prompt` event
|
|
291
|
+
* that has no `turnId` yet and whose text equals one of the turn's text
|
|
292
|
+
* blocks — or the turn's `display` echo when the caller supplies one
|
|
293
|
+
* (run-minted prompt turns never carry `display` themselves; the TUI's
|
|
294
|
+
* command `runAgent` path injects the origin display onto a copy after the
|
|
295
|
+
* sub-run resolves, since the echo event's text is the short display line,
|
|
296
|
+
* not the full prompt). A prompt turn qualifies with at least one non-blank
|
|
297
|
+
* text block, OR — the attachment-only submit — with media blocks
|
|
298
|
+
* (document/image/audio/video) and no tool plumbing; the latter matches the
|
|
299
|
+
* newest untagged blank-text event that carries attachment chips. Tool-
|
|
300
|
+
* result-only user turns contribute nothing and synthetic loop-continue
|
|
301
|
+
* turns match no untagged event, so both fall through harmlessly.
|
|
302
|
+
*
|
|
303
|
+
* Pure — returns the SAME array instance when nothing matched, so hosts
|
|
304
|
+
* can cheaply skip a re-render.
|
|
305
|
+
*/
|
|
306
|
+
declare function retagUserPromptEvents(events: readonly StreamEvent[], appendedTurns: readonly SessionTurn[]): readonly StreamEvent[];
|
|
307
|
+
/**
|
|
308
|
+
* Reduce persisted turns to the prompt refs the retag needs, dropping
|
|
309
|
+
* non-prompt turns (assistant, tool results) entirely.
|
|
310
|
+
*
|
|
311
|
+
* Shared by the in-process path and the daemon broadcast so both select the
|
|
312
|
+
* same turns as "prompts" — a divergence here would make a prompt selectable
|
|
313
|
+
* on one surface and not the other.
|
|
314
|
+
*/
|
|
315
|
+
declare function promptTurnRefs(turns: readonly SessionTurn[]): PromptTurnRef[];
|
|
316
|
+
/**
|
|
317
|
+
* The minimum a prompt turn must carry to be matched against its live echo.
|
|
318
|
+
*
|
|
319
|
+
* Exists because the daemon has to send this over a wire: a full `SessionTurn`
|
|
320
|
+
* carries every content block, including base64 image and document payloads,
|
|
321
|
+
* which would be megabytes per prompt to ship for the sake of attaching an id.
|
|
322
|
+
*/
|
|
323
|
+
interface PromptTurnRef {
|
|
324
|
+
id: string;
|
|
325
|
+
/** Text blocks plus the `display` override, if any. */
|
|
326
|
+
texts: readonly string[];
|
|
327
|
+
attachmentOnly: boolean;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Attach persisted turn ids to the live `user-prompt` events they correspond
|
|
331
|
+
* to, so a just-sent prompt becomes selectable (hover, click, edit, delete)
|
|
332
|
+
* without waiting for a session reload.
|
|
333
|
+
*
|
|
334
|
+
* Matching is newest-first and one-to-one: identical prompt text sent twice
|
|
335
|
+
* must bind to two different turns, so each ref consumes exactly one untagged
|
|
336
|
+
* event.
|
|
337
|
+
*/
|
|
338
|
+
declare function retagUserPromptEventsFromRefs(events: readonly StreamEvent[], refs: readonly PromptTurnRef[]): readonly StreamEvent[];
|
|
339
|
+
/**
|
|
340
|
+
* Per-event visibility — filters honor user toggles and the
|
|
341
|
+
* `hideSubagentOutput` setting. When subagent output is hidden:
|
|
342
|
+
* - Child-agent events are filtered down to the `spawn-start` /
|
|
343
|
+
* `spawn-end` markers so the user still sees "🌱 working… 🌳 done".
|
|
344
|
+
* - The parent's `tool-result` for `spawn` is hidden too. Its body
|
|
345
|
+
* duplicates `spawn-end`'s stats line *and* the parent's next
|
|
346
|
+
* markdown turn; showing it again produces an extra
|
|
347
|
+
* `┃ [sub-agent child-1] Completed …` block users just want gone.
|
|
348
|
+
*
|
|
349
|
+
* Renderer-agnostic — returns plain `boolean` so TUI / GUI consumers
|
|
350
|
+
* can filter events identically.
|
|
351
|
+
*/
|
|
352
|
+
/** `notice.label` the host stamps on prompt-cache break/expiry rows (`host/notices/index.ts`). */
|
|
353
|
+
declare const CACHE_NOTICE_LABEL = "cache";
|
|
354
|
+
declare function isVisible(event: StreamEvent, settings: Settings): boolean;
|
|
355
|
+
/**
|
|
356
|
+
* Build the `resultTurnId → owningAssistantTurnId` map used by the select-
|
|
357
|
+
* turn mode to coalesce a tool-call's surrounding turns into ONE navigation
|
|
358
|
+
* stop.
|
|
359
|
+
*
|
|
360
|
+
* Protocol shape: every `tool_call` block in an assistant turn is closed by
|
|
361
|
+
* a matching `tool_result` block in the *next* user turn (the agent loop's
|
|
362
|
+
* history validator depends on this). When the next user turn's only events
|
|
363
|
+
* are `tool-result`s — i.e. it's pure plumbing for the prior assistant
|
|
364
|
+
* turn — we map it back to that assistant turn here. The select-turn nav
|
|
365
|
+
* index ({@link selectableTurnIds}) skips owned turns, and the renderer's
|
|
366
|
+
* highlight gate ({@link isTurnHighlighted}) extends the selection accent
|
|
367
|
+
* from the assistant turn to the events of any turn it owns. Net effect:
|
|
368
|
+
*
|
|
369
|
+
* - Navigation never lands the cursor on a result-only turn whose own
|
|
370
|
+
* events may be hidden by `showToolResults: false` — the cursor
|
|
371
|
+
* wouldn't be visible.
|
|
372
|
+
* - Selecting an assistant turn highlights the call AND its result as
|
|
373
|
+
* one unit, matching the user's mental model of "one message".
|
|
374
|
+
*
|
|
375
|
+
* Owner-lookup is conservative: result-only turns with no matching prior
|
|
376
|
+
* assistant turn (orphaned — usually because the parent was deleted)
|
|
377
|
+
* stay selectable so the user can act on them via the turn-details modal.
|
|
378
|
+
*
|
|
379
|
+
* Subagent (`childId` set) events are ignored — they live in a separate
|
|
380
|
+
* conversation tree.
|
|
381
|
+
*/
|
|
382
|
+
declare function turnSelectionOwnership(events: readonly StreamEvent[]): Map<string, string>;
|
|
383
|
+
/**
|
|
384
|
+
* Render-time check: should `event` paint with the selection accent?
|
|
385
|
+
*
|
|
386
|
+
* `true` when the event's own turn is selected, OR when the selected turn
|
|
387
|
+
* `owns` the event's turn via {@link turnSelectionOwnership} (the call and
|
|
388
|
+
* its tool-result rows highlight together). `false` when nothing is
|
|
389
|
+
* selected or the relationship doesn't apply.
|
|
390
|
+
*
|
|
391
|
+
* Pure. Renderer-agnostic — the TUI's `<Transcript>` uses it; a GUI's
|
|
392
|
+
* equivalent walks the same rule.
|
|
393
|
+
*/
|
|
394
|
+
declare function isTurnHighlighted(event: Pick<StreamEvent, 'turnId'>, selectedTurnId: string | null, ownership: ReadonlyMap<string, string>): boolean;
|
|
395
|
+
/**
|
|
396
|
+
* Ownership for "one selection stop per message": result-only turns fold
|
|
397
|
+
* into their assistant turn (`turnSelectionOwnership`), and turns that only
|
|
398
|
+
* did work (thinking, tool calls, worker markers) fold into the answer that
|
|
399
|
+
* follows them in the same exchange. "Read three files, then answered" is
|
|
400
|
+
* one stop, so ↑ moves one visible message at a time. An exchange that ends
|
|
401
|
+
* in work alone stops on its first work turn. Same rule as the GUI's
|
|
402
|
+
* `computeSelectStops`.
|
|
403
|
+
*/
|
|
404
|
+
declare function messageSelectionOwnership(events: readonly StreamEvent[]): Map<string, string>;
|
|
405
|
+
/**
|
|
406
|
+
* Deduplicated, in-order list of **parent-conversation** turn ids that appear
|
|
407
|
+
* in a rendered transcript — the navigation index for the TUI's select-turn
|
|
408
|
+
* mode. Three classes of turns are deliberately skipped:
|
|
409
|
+
*
|
|
410
|
+
* - **Subagent turns** (`childId` set). Nested execution detail; the
|
|
411
|
+
* user's mental model of a "message" is the conversational exchange,
|
|
412
|
+
* not each spawn turn. Also filtered out by `isVisible` under
|
|
413
|
+
* `hideSubagentOutput: true` — selecting them would highlight nothing.
|
|
414
|
+
* - **Result-only turns** — see {@link turnSelectionOwnership}. These get
|
|
415
|
+
* coalesced into the assistant turn that emitted their tool_calls.
|
|
416
|
+
* - **Settings-hidden turns** (when `settings` is supplied). A turn whose
|
|
417
|
+
* every event fails {@link isVisible} would render no rows — landing
|
|
418
|
+
* the cursor there hides it from the user entirely. The check is opt-
|
|
419
|
+
* in so SDK callers without a Settings object keep the legacy
|
|
420
|
+
* "everything visible" behavior.
|
|
421
|
+
*
|
|
422
|
+
* Synthetic events (separator, spawn-start, spawn-end) have no `turnId` and
|
|
423
|
+
* are skipped naturally.
|
|
424
|
+
*/
|
|
425
|
+
declare function selectableTurnIds(events: readonly StreamEvent[], settings?: Settings, visible?: (event: StreamEvent) => boolean, opts?: {
|
|
426
|
+
byMessage?: boolean;
|
|
427
|
+
}): string[];
|
|
428
|
+
//#endregion
|
|
429
|
+
//#region src/chat/cred-keys.d.ts
|
|
430
|
+
/**
|
|
431
|
+
* Credential-file key arithmetic, split from `./credentials` so the rules can
|
|
432
|
+
* be enforced where credentials themselves must not be pulled in.
|
|
433
|
+
*
|
|
434
|
+
* `./credentials` reaches the provider registry (and through it the pi-ai
|
|
435
|
+
* factories) for `credKeyOf`; the extension loader — an edge entrypoint that
|
|
436
|
+
* validates descriptor keys at registration time — must stay clear of that
|
|
437
|
+
* graph. This module is string arithmetic with no imports.
|
|
438
|
+
*/
|
|
439
|
+
/**
|
|
440
|
+
* Separator between a provider's canonical key and a slot qualifier. Every
|
|
441
|
+
* non-canonical slot (`#alt`, `#account:N`) starts with it, so the character is
|
|
442
|
+
* reserved in descriptor credential keys outright.
|
|
443
|
+
*/
|
|
444
|
+
declare const CRED_KEY_SLOT_SEPARATOR = "#";
|
|
445
|
+
/**
|
|
446
|
+
* Reserved suffix marking a provider's SECOND credential slot.
|
|
447
|
+
*
|
|
448
|
+
* Not usable as (or as the tail of) a descriptor's credential key: `foo#alt`
|
|
449
|
+
* holds `foo`'s alternate credential, so a provider claiming that name would
|
|
450
|
+
* share storage with it.
|
|
451
|
+
*/
|
|
452
|
+
declare const ALTERNATE_CRED_KEY_SUFFIX = "#alt";
|
|
453
|
+
/**
|
|
454
|
+
* Reserved infix marking one of a provider's ADDITIONAL OAuth accounts:
|
|
455
|
+
* `foo#account:1`, `foo#account:2`, …
|
|
456
|
+
*/
|
|
457
|
+
declare const ACCOUNT_CRED_KEY_INFIX = "#account:";
|
|
458
|
+
/**
|
|
459
|
+
* File key holding a provider's second credential, when it has one of each kind.
|
|
460
|
+
*
|
|
461
|
+
* The canonical key always holds the credential the user prefers; this sibling
|
|
462
|
+
* holds the other. That one invariant is what makes preference selection free:
|
|
463
|
+
* every existing reader (`applyApiKeyEnv`, the harness provider factories)
|
|
464
|
+
* already resolves the canonical key, so "switch priority" is just moving two
|
|
465
|
+
* objects between two keys — no precedence flag to interpret, no resolution
|
|
466
|
+
* order to keep in sync across layers.
|
|
467
|
+
*
|
|
468
|
+
* A sibling key rather than a nested field because the canonical entry gets
|
|
469
|
+
* REPLACED wholesale on token refresh; anything nested inside it would be
|
|
470
|
+
* dropped by the next rotation. And older zidane versions look credentials up
|
|
471
|
+
* by `credKeyOf`, so a suffixed key is simply invisible to them — they read the
|
|
472
|
+
* preferred credential and behave exactly as before, which is why this needs no
|
|
473
|
+
* migration or schema version.
|
|
474
|
+
*/
|
|
475
|
+
declare function alternateCredKey(fileKey: string): string;
|
|
476
|
+
/**
|
|
477
|
+
* File key holding one of a provider's non-active OAuth accounts.
|
|
478
|
+
*
|
|
479
|
+
* Same sibling-key reasoning as {@link alternateCredKey}: the canonical key is
|
|
480
|
+
* the active one, so a provider with three OAuth grants stores the active one
|
|
481
|
+
* canonically and the other two under `#account:N`. `#alt` stays dedicated to
|
|
482
|
+
* the other-kind (API key) alternate so files written by builds that predate
|
|
483
|
+
* multi-account keep meaning the same thing.
|
|
484
|
+
*/
|
|
485
|
+
declare function accountCredKey(fileKey: string, n: number): string;
|
|
486
|
+
/** True when `key` is one of `fileKey`'s `#account:N` slots. */
|
|
487
|
+
declare function isAccountCredKey(fileKey: string, key: string): boolean;
|
|
488
|
+
/**
|
|
489
|
+
* Name shown for an OAuth account that was never given one.
|
|
490
|
+
*
|
|
491
|
+
* Also what a first OAuth login is stored under, so a second account has
|
|
492
|
+
* something to be told apart from. Pre-multi-account files hold unnamed
|
|
493
|
+
* grants; {@link oauthAccountLabel} makes them read the same.
|
|
494
|
+
*/
|
|
495
|
+
declare const DEFAULT_OAUTH_ACCOUNT_LABEL = "Default";
|
|
496
|
+
/** Trimmed user-given account name, or {@link DEFAULT_OAUTH_ACCOUNT_LABEL}. */
|
|
497
|
+
declare function oauthAccountLabel(credential: {
|
|
498
|
+
label?: unknown;
|
|
499
|
+
}): string;
|
|
500
|
+
/**
|
|
501
|
+
* True when a key claims a reserved slot namespace.
|
|
502
|
+
*
|
|
503
|
+
* Built-in keys are plain identifiers (`anthropic`, `openai-codex`), but
|
|
504
|
+
* `ProviderDescriptor.key` / `credentialFileKey` are open strings — so the
|
|
505
|
+
* reservation is checked, not assumed.
|
|
506
|
+
*/
|
|
507
|
+
declare function isReservedCredKey(fileKey: string): boolean;
|
|
508
|
+
//#endregion
|
|
509
|
+
//#region src/chat/daemon-health.d.ts
|
|
510
|
+
/**
|
|
511
|
+
* Daemon connection health — the one model behind the status dot in both
|
|
512
|
+
* clients' footers.
|
|
513
|
+
*
|
|
514
|
+
* Three states, because "connected: boolean" cannot express the one users
|
|
515
|
+
* actually want to see: a daemon that is being spawned or reconnected is not
|
|
516
|
+
* DOWN, and painting it red for the seconds that takes teaches people to
|
|
517
|
+
* ignore red. So:
|
|
518
|
+
*
|
|
519
|
+
* - `connected` — handshake done, signals live. green (accent)
|
|
520
|
+
* - `connecting` — spawning / reconnecting / first attempt. amber (warn)
|
|
521
|
+
* - `disconnected` — reachable daemon absent, last attempt failed. red (error)
|
|
522
|
+
*
|
|
523
|
+
* Tones are theme SLOTS, not colors, so the dot recolors with the palette on
|
|
524
|
+
* both surfaces. Node-free; re-exported from `zidane/chat/pure`.
|
|
525
|
+
*/
|
|
526
|
+
type DaemonHealth = 'connected' | 'connecting' | 'disconnected';
|
|
527
|
+
type DaemonHealthTone = 'accent' | 'warn' | 'error';
|
|
528
|
+
interface DaemonHealthStyle {
|
|
529
|
+
tone: DaemonHealthTone;
|
|
530
|
+
/** Tooltip / accessibility text. The dot itself carries no words. */
|
|
531
|
+
label: string;
|
|
532
|
+
}
|
|
533
|
+
declare const DAEMON_HEALTH_GLYPH = "●";
|
|
534
|
+
declare const DAEMON_HEALTH_STYLE: Readonly<Record<DaemonHealth, DaemonHealthStyle>>;
|
|
535
|
+
//#endregion
|
|
536
|
+
//#region src/chat/safe-mode-context.d.ts
|
|
537
|
+
/**
|
|
538
|
+
* Outcome of an approval prompt. Four bulk decisions match the original
|
|
539
|
+
* single-edit modal contract; `partial` is the multi-edit branch — the
|
|
540
|
+
* user accepted a subset of an `edit` / `multi_edit` / `write_file` call.
|
|
541
|
+
*
|
|
542
|
+
* `partial.mask` is 1:1 with the call's hunks (in input order): `true`
|
|
543
|
+
* means apply, `false` means deny. The gate handler walks the mask to
|
|
544
|
+
* build per-hunk outcomes; the TUI rebinds `ctx.input.edits` to the
|
|
545
|
+
* approved subset and the renderer reconstructs the full per-hunk view
|
|
546
|
+
* from the `<edit-outcomes>` annotation appended to the tool result.
|
|
547
|
+
*/
|
|
548
|
+
type ApprovalDecision = 'accept-once' | 'accept-session' | 'accept-safelist' | 'deny' | {
|
|
549
|
+
kind: 'partial';
|
|
550
|
+
mask: readonly boolean[];
|
|
551
|
+
};
|
|
552
|
+
/**
|
|
553
|
+
* Identifies the caller behind an approval prompt — the parent agent or
|
|
554
|
+
* a specific subagent (`child-N`). The modal's right-side title pins the
|
|
555
|
+
* label so the user knows which agent issued the call when subagents
|
|
556
|
+
* bubble their gates up through the parent's hook bus.
|
|
557
|
+
*/
|
|
558
|
+
type ApprovalOriginator = {
|
|
559
|
+
kind: 'parent';
|
|
560
|
+
} | {
|
|
561
|
+
kind: 'child';
|
|
562
|
+
label: string;
|
|
563
|
+
};
|
|
564
|
+
interface ApprovalRequest {
|
|
565
|
+
id: string;
|
|
566
|
+
tool: string;
|
|
567
|
+
input: Record<string, unknown>;
|
|
568
|
+
resolve: (decision: ApprovalDecision) => void;
|
|
569
|
+
/** Caller attribution. Absent ≡ `{ kind: 'parent' }`. */
|
|
570
|
+
originator?: ApprovalOriginator;
|
|
571
|
+
/**
|
|
572
|
+
* Cross-window correlation id (the daemon's approval request id) for
|
|
573
|
+
* entries surfaced by the daemon runtime. Lets `dropByCorrelation`
|
|
574
|
+
* retract this entry when ANOTHER window resolves the same shared
|
|
575
|
+
* approval, without re-sending a decision. Absent for local-runtime
|
|
576
|
+
* approvals.
|
|
577
|
+
*/
|
|
578
|
+
correlationId?: string;
|
|
579
|
+
}
|
|
580
|
+
/** Function signature consumed by `tool:gate` handlers + the child-tool wrap. */
|
|
581
|
+
type RequestApproval = (tool: string, input: Record<string, unknown>, originator?: ApprovalOriginator, correlationId?: string) => Promise<ApprovalDecision>;
|
|
582
|
+
interface SafeModeActions {
|
|
583
|
+
/** Request a decision; resolves once the user picks. */
|
|
584
|
+
requestApproval: RequestApproval;
|
|
585
|
+
/** Resolve the head and shift the queue forward. */
|
|
586
|
+
resolveHead: (decision: ApprovalDecision) => void;
|
|
587
|
+
/** Resolve all pending with `deny`. Used on abort / hard exit. */
|
|
588
|
+
denyAll: () => void;
|
|
589
|
+
/**
|
|
590
|
+
* Remove the entry whose `correlationId` matches, WITHOUT resolving it
|
|
591
|
+
* (the daemon already did, in another window). No-op when absent.
|
|
592
|
+
*/
|
|
593
|
+
dropByCorrelation: (correlationId: string) => void;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Owns the queue + actions. Splits the value across two contexts so a queue
|
|
597
|
+
* change doesn't invalidate every callback memo that closes over the actions.
|
|
598
|
+
*/
|
|
599
|
+
declare function SafeModeProvider({ children }: {
|
|
600
|
+
children: ReactNode;
|
|
601
|
+
}): import("react").JSX.Element;
|
|
602
|
+
declare function useSafeModeQueue(): readonly ApprovalRequest[];
|
|
603
|
+
declare function useSafeModeActions(): SafeModeActions;
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region src/chat/edit-approval.d.ts
|
|
606
|
+
/**
|
|
607
|
+
* Convert a per-hunk approval mask into an `EditOutcome[]`. `true` →
|
|
608
|
+
* `applied`; `false` → `denied` with the supplied reason.
|
|
609
|
+
*
|
|
610
|
+
* Length is `Math.max(mask.length, fallbackLength)` so callers passing a
|
|
611
|
+
* shorter mask still get a fully-populated array — missing entries
|
|
612
|
+
* default to applied, matching the "no decision => keep" convention.
|
|
613
|
+
*/
|
|
614
|
+
declare function maskToOutcomeKinds(mask: readonly boolean[], fallbackLength: number, deniedReason?: string): EditOutcome[];
|
|
615
|
+
/**
|
|
616
|
+
* Apply an `ApprovalDecision` to a payload, returning the resolved
|
|
617
|
+
* per-hunk outcomes + the gate-level verdict.
|
|
618
|
+
*
|
|
619
|
+
* Pure — does not mutate `input` or `payload`. The TUI's `applyGate`
|
|
620
|
+
* consumes the result: stashes `outcomes` in the pending-annotation map
|
|
621
|
+
* (keyed by callId) so `tool:transform` can append the
|
|
622
|
+
* `<edit-outcomes>` block to the tool result, rebinds `ctx.input.edits`
|
|
623
|
+
* to the approved subset for `partial`, and emits the `syntheticEvent`
|
|
624
|
+
* for fully-denied or fully-blocked calls.
|
|
625
|
+
*/
|
|
626
|
+
interface ResolvedApproval {
|
|
627
|
+
/** Final state of every hunk after the decision (1:1 with payload.hunks). */
|
|
628
|
+
outcomes: EditOutcome[];
|
|
629
|
+
/** True when no hunk will be applied — gate should `block` the call. */
|
|
630
|
+
shouldBlock: boolean;
|
|
631
|
+
/**
|
|
632
|
+
* Synthetic `EditPayload` to render in the transcript. Identical to the
|
|
633
|
+
* incoming payload but with `outcomes` set so the renderer can badge
|
|
634
|
+
* each hunk. Only meaningful when at least one hunk was denied —
|
|
635
|
+
* an all-applied decision returns `null` here and the normal
|
|
636
|
+
* `tool:before` event suffices.
|
|
637
|
+
*/
|
|
638
|
+
syntheticEvent: EditPayload | null;
|
|
639
|
+
}
|
|
640
|
+
declare function resolveApprovalForPayload(decision: ApprovalDecision, payload: EditPayload): ResolvedApproval;
|
|
641
|
+
/**
|
|
642
|
+
* Render an `EditOutcome[]` as the wire-format annotation block. Returns
|
|
643
|
+
* the body to APPEND to a tool result; callers join with a leading
|
|
644
|
+
* `\n\n` separator. Idempotent on missing reasons — bare `applied` lines
|
|
645
|
+
* stay terse.
|
|
646
|
+
*/
|
|
647
|
+
declare function buildEditOutcomesAnnotation(outcomes: readonly EditOutcome[]): string;
|
|
648
|
+
/**
|
|
649
|
+
* Parse an `<edit-outcomes>…</edit-outcomes>` annotation block out of a
|
|
650
|
+
* tool result body. Returns the outcomes keyed by 1-based hunk index, or
|
|
651
|
+
* `null` when the block is missing / malformed.
|
|
652
|
+
*
|
|
653
|
+
* Anchored on the explicit tag pair so the parser doesn't false-positive
|
|
654
|
+
* on natural prose that happens to contain `#1 applied`.
|
|
655
|
+
*/
|
|
656
|
+
declare function parseEditOutcomesFromResult(result: string | readonly ToolResultContent[]): EditOutcome[] | null;
|
|
657
|
+
/**
|
|
658
|
+
* Strip the first `<edit-outcomes>…</edit-outcomes>` block out of a tool
|
|
659
|
+
* result body, returning the surrounding text. Used by the
|
|
660
|
+
* `tool:transform` hook to peel a body-emitted annotation before
|
|
661
|
+
* re-appending the merged (approval ∪ body) version — otherwise the
|
|
662
|
+
* result would carry two annotation blocks and
|
|
663
|
+
* {@link parseEditOutcomesFromResult} would only see the first.
|
|
664
|
+
*
|
|
665
|
+
* Anchored on the same `\n<edit-outcomes>\n` / start-of-string newline
|
|
666
|
+
* shape the parser uses, so prose that incidentally mentions
|
|
667
|
+
* `<edit-outcomes>` (e.g. a model summarizing its own format) isn't
|
|
668
|
+
* mistakenly stripped. Trims a single leading `\n\n` separator when
|
|
669
|
+
* present so successive strips don't leave dangling blank lines.
|
|
670
|
+
* Idempotent on inputs that don't contain a properly-anchored block.
|
|
671
|
+
*/
|
|
672
|
+
declare function stripEditOutcomesAnnotation(text: string): string;
|
|
673
|
+
/**
|
|
674
|
+
* Merge body-side outcomes (keyed against the approved subset the tool
|
|
675
|
+
* actually ran on, in subset-position order) into approval-side outcomes
|
|
676
|
+
* (1:1 with the model's ORIGINAL `edits` list, with `denied` entries for
|
|
677
|
+
* every hunk the user dropped).
|
|
678
|
+
*
|
|
679
|
+
* Algorithm: walk the approval array; every `applied` placeholder
|
|
680
|
+
* corresponds to one approved hunk that the body ran. Consume body's
|
|
681
|
+
* outcomes in order against those placeholders. Non-`applied` approval
|
|
682
|
+
* entries (`denied`, `skipped`) stay untouched — they describe gate-
|
|
683
|
+
* level decisions the body never saw.
|
|
684
|
+
*
|
|
685
|
+
* Pure. Returns a fresh array; never mutates either input.
|
|
686
|
+
*
|
|
687
|
+
* Edge cases:
|
|
688
|
+
* - `body` is empty / shorter than the approved count → remaining
|
|
689
|
+
* approval `applied` placeholders stay as `applied` (the body ran
|
|
690
|
+
* happily; absence of a body entry means nothing failed).
|
|
691
|
+
* - `body` longer than approved count → trailing body entries are
|
|
692
|
+
* ignored. Shouldn't happen in practice (body sees the rebound
|
|
693
|
+
* subset), but the guard keeps the merge total-pure.
|
|
694
|
+
*/
|
|
695
|
+
declare function mergeApprovalAndBodyOutcomes(approval: readonly EditOutcome[], body: readonly EditOutcome[] | null): EditOutcome[];
|
|
696
|
+
/**
|
|
697
|
+
* Rewrite a `multi_edit` body header so the totals reflect the model's
|
|
698
|
+
* ORIGINAL edit list (the merged outcomes count) instead of the subset
|
|
699
|
+
* the body actually saw after gate rebinding. Without this, a partially
|
|
700
|
+
* approved call surfaces a misleading `applied 2 of 2 edits` (subset
|
|
701
|
+
* counts) on the wire even when the original was `applied 2 of 3`.
|
|
702
|
+
*
|
|
703
|
+
* Three body-side shapes are handled (matching `multi_edit`'s emit):
|
|
704
|
+
* 1. `Edited <path>: applied N edits (R replacements).`
|
|
705
|
+
* 2. `Edited <path>: applied N of M edits (R replacements).`
|
|
706
|
+
* 3. `multi_edit error: no edits applied to <path> (M attempted).`
|
|
707
|
+
*
|
|
708
|
+
* The replacements count is preserved verbatim — it's a body-side stat
|
|
709
|
+
* the chat layer can't recompute. When the first line doesn't look like
|
|
710
|
+
* any of the three shapes (e.g. an unrelated error preamble bubbled up),
|
|
711
|
+
* the text is returned unchanged.
|
|
712
|
+
*/
|
|
713
|
+
declare function rewriteMultiEditHeader(text: string, merged: readonly EditOutcome[], path: string): string;
|
|
714
|
+
/**
|
|
715
|
+
* Aggregate counts for the transcript's summary badge (`3 applied · 1
|
|
716
|
+
* denied · 1 skipped`). Exported so renderers don't reimplement the
|
|
717
|
+
* tally. Pure / O(n).
|
|
718
|
+
*/
|
|
719
|
+
declare function summarizeOutcomes(outcomes: readonly EditOutcome[] | undefined): {
|
|
720
|
+
applied: number;
|
|
721
|
+
denied: number;
|
|
722
|
+
skipped: number;
|
|
723
|
+
failed: number;
|
|
724
|
+
pending: number;
|
|
725
|
+
total: number;
|
|
726
|
+
};
|
|
727
|
+
//#endregion
|
|
728
|
+
//#region src/tools/edit-utils.d.ts
|
|
729
|
+
/**
|
|
730
|
+
* Locate the actual substring in `haystack` that corresponds to `needle`,
|
|
731
|
+
* recovering from typographical mismatch on six escalating fallbacks:
|
|
732
|
+
*
|
|
733
|
+
* 1. Exact substring match (the happy path — no transformation).
|
|
734
|
+
* 2. Curly-quote normalization on both sides — when the model emits straight
|
|
735
|
+
* quotes but the file has curly ones (or vice versa), the slice of the
|
|
736
|
+
* file at the matched position carries the file's actual typography.
|
|
737
|
+
* 3. Anthropic-sanitization undo on the needle — the model's `<n>` becomes
|
|
738
|
+
* the file's `<name>`, etc.
|
|
739
|
+
* 4. Combined: desanitize + quote normalization on the needle.
|
|
740
|
+
* 5. Line-number-prefix strip — when the model pasted a numbered `read_file`
|
|
741
|
+
* chunk verbatim into `old_string` and the file carries no such prefix.
|
|
742
|
+
* 6. Combined: line-number strip + quote normalization — paste-back of a
|
|
743
|
+
* numbered chunk against a file whose typography differs from the model's.
|
|
744
|
+
*
|
|
745
|
+
* Returns `{ actual, occurrences }` — `actual` is the string that exists in
|
|
746
|
+
* the file (use this to do the actual replace; preserves the file's
|
|
747
|
+
* typography). `occurrences` is the count of those matches in the file.
|
|
748
|
+
*
|
|
749
|
+
* Fallbacks 3-4 (desanitize-class) only fire when the transformed needle is
|
|
750
|
+
* UNIQUE in the file — they rewrite the needle's meaning rather than its
|
|
751
|
+
* typography, so an ambiguous match risks silently retargeting the wrong
|
|
752
|
+
* text (see the inline comment at step 3).
|
|
753
|
+
*
|
|
754
|
+
* Returns `null` when no recovery worked.
|
|
755
|
+
*/
|
|
756
|
+
interface ResolvedMatch {
|
|
757
|
+
actual: string;
|
|
758
|
+
occurrences: number;
|
|
759
|
+
/** Recovery path — `'exact'` when no transformation was applied. */
|
|
760
|
+
via: 'exact' | 'quotes' | 'desanitize' | 'quotes+desanitize' | 'line-numbers' | 'quotes+line-numbers';
|
|
761
|
+
}
|
|
762
|
+
//#endregion
|
|
763
|
+
//#region src/chat/edit-diff.d.ts
|
|
764
|
+
declare function extractEditPayload(name: string, input: Record<string, unknown>, priorContent?: string): EditPayload | undefined;
|
|
765
|
+
type DiffOp = 'context' | 'add' | 'remove';
|
|
766
|
+
interface DiffLine {
|
|
767
|
+
op: DiffOp;
|
|
768
|
+
text: string;
|
|
769
|
+
}
|
|
770
|
+
declare function computeLineDiff(oldString: string, newString: string): DiffLine[];
|
|
771
|
+
/**
|
|
772
|
+
* Split a string into lines preserving empty lines but dropping the
|
|
773
|
+
* implicit trailing `""` produced by a final `\n`. Exported only for
|
|
774
|
+
* its tests — callers should use `computeLineDiff`.
|
|
775
|
+
*/
|
|
776
|
+
declare function splitLines(s: string): string[];
|
|
777
|
+
interface InlineSegment {
|
|
778
|
+
text: string;
|
|
779
|
+
changed: boolean;
|
|
780
|
+
}
|
|
781
|
+
interface InlineDiff {
|
|
782
|
+
oldSegments: InlineSegment[];
|
|
783
|
+
newSegments: InlineSegment[];
|
|
784
|
+
}
|
|
785
|
+
declare function computeInlineDiff(oldLine: string, newLine: string): InlineDiff;
|
|
786
|
+
/**
|
|
787
|
+
* Tokenize on word / non-word boundaries. Each run of `\w+` is one
|
|
788
|
+
* token; each run of `\W+` (whitespace, punctuation) is another. This
|
|
789
|
+
* gives the right granularity for renames (`oldName` → `newName`) and
|
|
790
|
+
* for symbol swaps (`+ → -`) without exploding into per-char segments.
|
|
791
|
+
*
|
|
792
|
+
* Exported only for its tests.
|
|
793
|
+
*/
|
|
794
|
+
declare function tokenize(s: string): string[];
|
|
795
|
+
/**
|
|
796
|
+
* Apply the payload's hunks against `priorContent` and return the
|
|
797
|
+
* resulting file body. Mirrors the agent's tool-side semantics:
|
|
798
|
+
* - `replaceAll === true` → `String.replaceAll`
|
|
799
|
+
* - otherwise → first-occurrence `String.replace`
|
|
800
|
+
*
|
|
801
|
+
* Hunks are applied in order — a `multi_edit` later hunk operates on
|
|
802
|
+
* the output of the earlier ones, just like the actual tool.
|
|
803
|
+
*/
|
|
804
|
+
declare function applyEditPayload(payload: EditPayload, priorContent: string): string;
|
|
805
|
+
/**
|
|
806
|
+
* Like `buildUnifiedDiff` but operating against the full file content
|
|
807
|
+
* so the diff carries *real* file line numbers and configurable
|
|
808
|
+
* surrounding context.
|
|
809
|
+
*
|
|
810
|
+
* Strategy:
|
|
811
|
+
* 1. Apply the payload to `priorContent` → `newContent`.
|
|
812
|
+
* 2. Run `computeLineDiff` over the whole file.
|
|
813
|
+
* 3. Group non-context ops into hunks, padding each with up to
|
|
814
|
+
* `contextLines` of context above and below. Adjacent hunks
|
|
815
|
+
* whose context regions touch are merged so we don't emit two
|
|
816
|
+
* `@@` headers separated by zero context lines.
|
|
817
|
+
*
|
|
818
|
+
* The output line numbers in the `@@` header are 1-based and reflect
|
|
819
|
+
* the change's position in the actual file — what the user expects
|
|
820
|
+
* when reading a diff alongside their editor.
|
|
821
|
+
*
|
|
822
|
+
* For `write_file` creating a new file (priorContent === ''), this
|
|
823
|
+
* falls back to the same `--- /dev/null` convention as
|
|
824
|
+
* `buildUnifiedDiff`.
|
|
825
|
+
*/
|
|
826
|
+
declare function buildContextualDiff(payload: EditPayload, priorContent: string, contextLines?: number): string;
|
|
827
|
+
interface EditHunkSummary {
|
|
828
|
+
/** 1-based line number in the new file where the change starts; undefined when unknown (no priorContent). */
|
|
829
|
+
line?: number;
|
|
830
|
+
/** Number of lines added in this hunk. */
|
|
831
|
+
added: number;
|
|
832
|
+
/** Number of lines removed in this hunk. */
|
|
833
|
+
removed: number;
|
|
834
|
+
/** First removed line preview (trimmed, may be empty for pure additions). */
|
|
835
|
+
firstOld?: string;
|
|
836
|
+
/** First added line preview (trimmed, may be empty for pure deletions). */
|
|
837
|
+
firstNew?: string;
|
|
838
|
+
}
|
|
839
|
+
interface EditSummary {
|
|
840
|
+
totalAdded: number;
|
|
841
|
+
totalRemoved: number;
|
|
842
|
+
hunks: EditHunkSummary[];
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Build a per-hunk digest used by the compact diff view.
|
|
846
|
+
*
|
|
847
|
+
* Strategy:
|
|
848
|
+
* - When `priorContent` is present and the payload describes a real
|
|
849
|
+
* file transformation, compute the contextual diff once, then walk
|
|
850
|
+
* the LCS ops splitting at runs of `add` / `remove` to anchor each
|
|
851
|
+
* summary entry to the **real** file line. This guarantees the
|
|
852
|
+
* summary's `L<n>` matches what the user sees in their editor.
|
|
853
|
+
* - Otherwise, fall back to per-hunk LCS over the (oldString,
|
|
854
|
+
* newString) snippet pair. Line numbers are absent because the
|
|
855
|
+
* snippet has no file position.
|
|
856
|
+
*/
|
|
857
|
+
declare function summarizeEditPayload(payload: EditPayload): EditSummary;
|
|
858
|
+
interface HunkResolution {
|
|
859
|
+
/**
|
|
860
|
+
* True when the tool body would find this hunk's `old_string` AND apply
|
|
861
|
+
* it without ambiguity. False when `resolveOldString` returned null OR
|
|
862
|
+
* the match was ambiguous (multiple occurrences and `replace_all` off).
|
|
863
|
+
*/
|
|
864
|
+
resolved: boolean;
|
|
865
|
+
/** Path the resolver took — `'exact'` when no recovery was needed. */
|
|
866
|
+
via?: ResolvedMatch['via'];
|
|
867
|
+
/** Match count in the running content for the hunk. */
|
|
868
|
+
occurrences?: number;
|
|
869
|
+
/** True when the resolver found >1 match without `replace_all`. */
|
|
870
|
+
ambiguous?: boolean;
|
|
871
|
+
}
|
|
872
|
+
interface PreviewResult {
|
|
873
|
+
/** Full unified diff of the (resolvable) hunks against `priorContent`. */
|
|
874
|
+
diffText: string;
|
|
875
|
+
/** 1:1 with `payload.hunks`. */
|
|
876
|
+
resolution: HunkResolution[];
|
|
877
|
+
/**
|
|
878
|
+
* Per-hunk isolated diff text rendered against the cumulative content
|
|
879
|
+
* after applying all earlier resolved hunks. Useful for the modal's
|
|
880
|
+
* focused-hunk view so hunk #N's preview reflects the state hunks
|
|
881
|
+
* 1..N-1 will leave the file in (same as the tool's order).
|
|
882
|
+
*/
|
|
883
|
+
perHunkDiff: string[];
|
|
884
|
+
/**
|
|
885
|
+
* Resolved hunks with `oldString` rewritten to the haystack's actual
|
|
886
|
+
* bytes and `newString` re-styled to preserve curly-quote typography
|
|
887
|
+
* / line-prefix conventions. Pass this to `buildContextualDiff` to
|
|
888
|
+
* paint the unified diff.
|
|
889
|
+
*/
|
|
890
|
+
resolvedPayload: EditPayload;
|
|
891
|
+
}
|
|
892
|
+
declare function previewEditPayload(payload: EditPayload, priorContent: string, contextLines?: number): PreviewResult;
|
|
893
|
+
declare function buildUnifiedDiff(payload: EditPayload): string;
|
|
894
|
+
declare function filetypeFromPath(path: string): string | undefined;
|
|
895
|
+
//#endregion
|
|
896
|
+
//#region src/chat/feature-gate.d.ts
|
|
897
|
+
/**
|
|
898
|
+
* Opt-in feature gates: an experimental feature is one boolean setting
|
|
899
|
+
* (default off) plus a kill-switch env var that wins over it.
|
|
900
|
+
*
|
|
901
|
+
* The kill switch exists so a bug in the gated path can never lock the user
|
|
902
|
+
* out: the ungated path is always one flag away, even when the settings UI
|
|
903
|
+
* itself is unreachable. Each gate names its flag (`--no-daemon`,
|
|
904
|
+
* `--no-remote`); the CLI's {@link applyKillSwitchFlags} exports the env var
|
|
905
|
+
* for the process, so child processes inherit the switch too.
|
|
906
|
+
*
|
|
907
|
+
* Node-free on purpose (re-exported from `zidane/chat/pure`): the TUI and the
|
|
908
|
+
* GUI main process share one definition per gate, so both read the same
|
|
909
|
+
* setting and honor the same kill switch.
|
|
910
|
+
*/
|
|
911
|
+
type Env = Record<string, string | undefined>;
|
|
912
|
+
interface FeatureGateOptions<K extends string> {
|
|
913
|
+
/** Settings key holding the opt-in. Only a literal `true` enables. */
|
|
914
|
+
setting: K;
|
|
915
|
+
/** Env var that disables the feature when set to `'1'`, whatever the setting says. */
|
|
916
|
+
killSwitchEnv: string;
|
|
917
|
+
/** The `zidane` flag that sets {@link killSwitchEnv} for the launch (`--no-…`). */
|
|
918
|
+
flag: string;
|
|
919
|
+
}
|
|
920
|
+
interface FeatureGate<K extends string> {
|
|
921
|
+
readonly setting: K;
|
|
922
|
+
readonly killSwitchEnv: string;
|
|
923
|
+
readonly flag: string;
|
|
924
|
+
/** The kill-switch env var is set to `'1'`. */
|
|
925
|
+
isKilled: (env?: Env) => boolean;
|
|
926
|
+
/** Setting is `true` and the kill switch is not engaged. */
|
|
927
|
+
isEnabled: (settings: Partial<Record<K, unknown>>, env?: Env) => boolean;
|
|
928
|
+
}
|
|
929
|
+
declare function defineFeatureGate<K extends string>({ setting, killSwitchEnv, flag }: FeatureGateOptions<K>): FeatureGate<K>;
|
|
930
|
+
/**
|
|
931
|
+
* The shared daemon runtime. `ZIDANE_NO_DAEMON=1` is set by
|
|
932
|
+
* `zidane --no-daemon`.
|
|
933
|
+
*/
|
|
934
|
+
declare const daemonGate: FeatureGate<"useDaemon">;
|
|
935
|
+
/**
|
|
936
|
+
* Remote hosts (zidane-server). The setting ("Remote hosts")
|
|
937
|
+
* gates the saved servers: the Hosts settings, the per-host session groups
|
|
938
|
+
* and picking a host for a new session. Connecting through an explicit `--host` /
|
|
939
|
+
* `ZIDANE_HOST_URL` is its own opt-in, but `ZIDANE_NO_REMOTE=1` still wins
|
|
940
|
+
* over it (`src/tui/host-target.ts`). `ZIDANE_NO_REMOTE=1` is set by
|
|
941
|
+
* `zidane --no-remote`.
|
|
942
|
+
*/
|
|
943
|
+
declare const remoteHostsGate: FeatureGate<"remoteHosts">;
|
|
944
|
+
/** Every gate, so a client can report which kill switches are engaged. */
|
|
945
|
+
declare const FEATURE_GATES: readonly FeatureGate<string>[];
|
|
946
|
+
/**
|
|
947
|
+
* The kill-switch env vars engaged in `env`, sorted. The GUI main process
|
|
948
|
+
* hands this to its renderer (which has no `process.env`) so settings rows
|
|
949
|
+
* can say why they are inert.
|
|
950
|
+
*/
|
|
951
|
+
declare function engagedKillSwitches(env?: Env): string[];
|
|
952
|
+
/** `name` is set to `'1'` in `env`: the kill-switch test, for a row that only knows the variable. */
|
|
953
|
+
declare function isKillSwitchEngaged(name: string, env?: Env): boolean;
|
|
954
|
+
//#endregion
|
|
955
|
+
//#region src/chat/footer-chips.d.ts
|
|
956
|
+
/**
|
|
957
|
+
* `warn` = a real cache break (a named dimension changed, so it was
|
|
958
|
+
* avoidable); `dim` = ordinary TTL expiry, which is not anyone's fault and
|
|
959
|
+
* should not shout.
|
|
960
|
+
*/
|
|
961
|
+
type CacheChipTone = 'warn' | 'dim';
|
|
962
|
+
interface CacheChipContent {
|
|
963
|
+
tone: CacheChipTone;
|
|
964
|
+
/** Leading glyph. Kept out of `label` so a surface can style it separately. */
|
|
965
|
+
glyph: string;
|
|
966
|
+
label: string;
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Build the chip for a cache break.
|
|
970
|
+
*
|
|
971
|
+
* `costUsd` is OPTIONAL and omitted entirely on a rate miss — never rendered
|
|
972
|
+
* as `$0.00`. A fabricated zero would read as "this was free", which is the
|
|
973
|
+
* opposite of what the chip exists to say. When present it is prefixed `~`
|
|
974
|
+
* because it is an estimate (registry rates × re-billed prefix), and clamped
|
|
975
|
+
* to `<0.01` rather than rounding a real charge down to nothing.
|
|
976
|
+
*/
|
|
977
|
+
declare function cacheBreakChip(info: CacheBreakInfo & {
|
|
978
|
+
costUsd?: number;
|
|
979
|
+
}): CacheChipContent;
|
|
980
|
+
/**
|
|
981
|
+
* Transcript-row text for a persisted cache-break notice. Multi-line, one
|
|
982
|
+
* fact per line, so both hosts can show a short headline and fold or list
|
|
983
|
+
* the rest:
|
|
984
|
+
*
|
|
985
|
+
* cache break ↑116.9k tokens ~$0.48
|
|
986
|
+
* messagePrefix: message 16 of 41→43 rewritten
|
|
987
|
+
* likely compaction or history trimming
|
|
988
|
+
*
|
|
989
|
+
* The footer chip stays terse; the row carries the culprit so a break is
|
|
990
|
+
* diagnosable from the transcript. Only the headline on a TTL / eviction
|
|
991
|
+
* break (nothing was done wrong).
|
|
992
|
+
*/
|
|
993
|
+
declare function cacheBreakNoticeText(info: CacheBreakInfo & {
|
|
994
|
+
costUsd?: number;
|
|
995
|
+
}): string;
|
|
996
|
+
/**
|
|
997
|
+
* Provider-retry label — `retrying 2/5`, or `retrying 2/5 · child-3` when the
|
|
998
|
+
* stalled stream belongs to a subagent rather than the parent.
|
|
999
|
+
*
|
|
1000
|
+
* Naming the source matters: with subagents in flight, an unattributed
|
|
1001
|
+
* "retrying" leaves the user unable to tell whether their own turn is stuck or
|
|
1002
|
+
* a delegated worker is.
|
|
1003
|
+
*/
|
|
1004
|
+
declare function retryLabel(info: {
|
|
1005
|
+
attempt: number;
|
|
1006
|
+
max: number;
|
|
1007
|
+
source: string;
|
|
1008
|
+
}): string;
|
|
1009
|
+
/**
|
|
1010
|
+
* Footer label while a compaction summary is being generated:
|
|
1011
|
+
* `Compacting...`, then `~12k` once the loop reports a token estimate, then
|
|
1012
|
+
* ` · 8s` once a second has passed. Same rule on every surface so a
|
|
1013
|
+
* minutes-long compaction of a large transcript reads as progress — not a
|
|
1014
|
+
* hang — identically in the TUI and the GUI.
|
|
1015
|
+
*
|
|
1016
|
+
* `now` is injectable so callers driving a 1 Hz tick don't have to re-read
|
|
1017
|
+
* the clock, and so tests are deterministic.
|
|
1018
|
+
*/
|
|
1019
|
+
/**
|
|
1020
|
+
* The live run readout: `1m 15s · ↓1.2k · 41 tok/s`. Time runs from the
|
|
1021
|
+
* run's start, the count covers the whole run (settled turns plus the one
|
|
1022
|
+
* streaming), and the rate is the honest windowed figure from
|
|
1023
|
+
* `stepStreamRate` (`null` until it has one). `↓~` marks a count that is
|
|
1024
|
+
* still the character heuristic. A tool-only stretch shows just the time.
|
|
1025
|
+
*
|
|
1026
|
+
* `detail` drops the least useful part first when space runs out:
|
|
1027
|
+
* `'full'` → `'count'` (no rate) → `'time'`.
|
|
1028
|
+
*/
|
|
1029
|
+
declare function runStatusLabel(run: {
|
|
1030
|
+
elapsedSec: number;
|
|
1031
|
+
outputTokens: number;
|
|
1032
|
+
estimated: boolean;
|
|
1033
|
+
rate: number | null;
|
|
1034
|
+
}, detail?: 'full' | 'count' | 'time'): string;
|
|
1035
|
+
/**
|
|
1036
|
+
* Live counter for one streaming turn: `↓1.2k`, `↓~1.2k` for the character
|
|
1037
|
+
* heuristic, `↓1.2k · 41 tok/s` when an honest rate is passed in (see
|
|
1038
|
+
* `stepStreamRate`; dividing tokens by time since the request counted the
|
|
1039
|
+
* wait for the first token and the estimate correction). Empty until the
|
|
1040
|
+
* first token.
|
|
1041
|
+
*/
|
|
1042
|
+
declare function streamingLabel(progress: {
|
|
1043
|
+
outputTokens: number;
|
|
1044
|
+
estimated: boolean;
|
|
1045
|
+
} | null | undefined, opts?: {
|
|
1046
|
+
rate?: number | null;
|
|
1047
|
+
}): string;
|
|
1048
|
+
/**
|
|
1049
|
+
* Session cost while a turn streams: settled figure plus the running estimate
|
|
1050
|
+
* for the in-flight turn. `estimated` tells the surface to render it dimmed
|
|
1051
|
+
* (the number will move, then snap to the settled value at turn end). `null`
|
|
1052
|
+
* when there is nothing to show — never `$0.00`.
|
|
1053
|
+
*/
|
|
1054
|
+
declare function liveSessionCost(settledUsd: number, progress: {
|
|
1055
|
+
estCostUsd?: number;
|
|
1056
|
+
} | null | undefined): {
|
|
1057
|
+
usd: number;
|
|
1058
|
+
estimated: boolean;
|
|
1059
|
+
} | null;
|
|
1060
|
+
declare function compactingLabel(estTokens: number | null | undefined, startedAt: number | null | undefined, now?: number): string;
|
|
1061
|
+
//#endregion
|
|
1062
|
+
//#region src/chat/history-search.d.ts
|
|
1063
|
+
interface HighlightRange {
|
|
1064
|
+
start: number;
|
|
1065
|
+
end: number;
|
|
1066
|
+
}
|
|
1067
|
+
interface HighlightSegment {
|
|
1068
|
+
text: string;
|
|
1069
|
+
highlighted: boolean;
|
|
1070
|
+
}
|
|
1071
|
+
interface SearchExcerpt {
|
|
1072
|
+
text: string;
|
|
1073
|
+
highlighted: HighlightRange[];
|
|
1074
|
+
}
|
|
1075
|
+
interface SearchTurnMatch {
|
|
1076
|
+
turn: SessionTurn;
|
|
1077
|
+
text: string;
|
|
1078
|
+
highlighted: HighlightRange[];
|
|
1079
|
+
excerpts: SearchExcerpt[];
|
|
1080
|
+
score: number;
|
|
1081
|
+
matchKind: 'exact-phrase' | 'exact-terms' | 'fuzzy';
|
|
1082
|
+
}
|
|
1083
|
+
type SearchTurnResult = SearchTurnMatch;
|
|
1084
|
+
interface SearchSessionResult {
|
|
1085
|
+
id: string;
|
|
1086
|
+
score: number;
|
|
1087
|
+
matchKind: 'exact-phrase' | 'exact-terms' | 'fuzzy';
|
|
1088
|
+
turn: SessionTurn;
|
|
1089
|
+
text: string;
|
|
1090
|
+
highlighted: HighlightRange[];
|
|
1091
|
+
excerpts: SearchExcerpt[];
|
|
1092
|
+
}
|
|
1093
|
+
interface SessionSearchExcerpt extends SearchExcerpt {
|
|
1094
|
+
turnId: string;
|
|
1095
|
+
role: SessionTurn['role'];
|
|
1096
|
+
}
|
|
1097
|
+
/** Aggregated row-level match used by the conversations list. */
|
|
1098
|
+
interface SessionHistoryMatch {
|
|
1099
|
+
score: number;
|
|
1100
|
+
matchedTurnIds: string[];
|
|
1101
|
+
excerpts: SessionSearchExcerpt[];
|
|
1102
|
+
}
|
|
1103
|
+
interface IndexedSearchTurn {
|
|
1104
|
+
turn: SessionTurn;
|
|
1105
|
+
/** Attachment/base64-free text shown in search results. */
|
|
1106
|
+
text: string;
|
|
1107
|
+
/** Pre-normalized once, reused for every query. */
|
|
1108
|
+
lowerText: string;
|
|
1109
|
+
}
|
|
1110
|
+
interface SessionSearchIndex {
|
|
1111
|
+
turns: IndexedSearchTurn[];
|
|
1112
|
+
}
|
|
1113
|
+
declare function buildSessionSearchIndex(turns: readonly SessionTurn[]): SessionSearchIndex;
|
|
1114
|
+
/** Yielding index builder for TUI callers — never monopolizes a frame. */
|
|
1115
|
+
declare function buildSessionSearchIndexAsync(turns: readonly SessionTurn[], options?: {
|
|
1116
|
+
yieldEvery?: number;
|
|
1117
|
+
onProgress?: (indexed: number, total: number) => void;
|
|
1118
|
+
signal?: AbortSignal;
|
|
1119
|
+
}): Promise<SessionSearchIndex>;
|
|
1120
|
+
declare function searchSessionIndex(index: SessionSearchIndex, query: string, limit?: number): SearchTurnMatch[];
|
|
1121
|
+
/** Yielding matcher for very large indexes; progress is checked per chunk. */
|
|
1122
|
+
declare function searchSessionIndexAsync(index: SessionSearchIndex, query: string, options?: {
|
|
1123
|
+
limit?: number;
|
|
1124
|
+
yieldEvery?: number;
|
|
1125
|
+
onProgress?: (searched: number, total: number) => void;
|
|
1126
|
+
signal?: AbortSignal;
|
|
1127
|
+
}): Promise<SearchTurnMatch[]>;
|
|
1128
|
+
declare function searchTurns(turns: readonly SessionTurn[], query: string, limit?: number): SearchTurnMatch[];
|
|
1129
|
+
declare function searchSessionTurns(turns: readonly SessionTurn[], query: string, maxExcerpts?: number): SearchSessionResult[];
|
|
1130
|
+
declare function searchSessionHistory(turns: readonly SessionTurn[], query: string, maxExcerpts?: number): SessionHistoryMatch | null;
|
|
1131
|
+
declare function searchSessionHistoryIndex(index: SessionSearchIndex, query: string, maxExcerpts?: number): SessionHistoryMatch | null;
|
|
1132
|
+
declare function searchSessionHistoryIndexAsync(index: SessionSearchIndex, query: string, maxExcerpts?: number, onProgress?: (searched: number, total: number) => void, signal?: AbortSignal): Promise<SessionHistoryMatch | null>;
|
|
1133
|
+
/**
|
|
1134
|
+
* `contentMatches` are keyed by `keyOf(meta)`: the bare id by default, a
|
|
1135
|
+
* (host, id) session key for a list across hosts (twins are two rows).
|
|
1136
|
+
*/
|
|
1137
|
+
declare function filterSessionSearchCatalog(sessions: readonly SessionMeta[], query: string, contentMatches: ReadonlyMap<string, SessionHistoryMatch>, keyOf?: (meta: SessionMeta) => string): SessionMeta[];
|
|
1138
|
+
declare function searchHighlightRanges(text: string, query: string): HighlightRange[];
|
|
1139
|
+
declare function highlightSegments(text: string, ranges: readonly HighlightRange[]): HighlightSegment[];
|
|
1140
|
+
/**
|
|
1141
|
+
* Search-specific serializer. Unlike `turnAsText`, it never serializes media,
|
|
1142
|
+
* document attachments, encrypted reasoning, or base64-looking payloads.
|
|
1143
|
+
*/
|
|
1144
|
+
declare function searchableTurnText(turn: SessionTurn): string;
|
|
1145
|
+
//#endregion
|
|
1146
|
+
//#region src/chat/browser/protocol.d.ts
|
|
1147
|
+
/**
|
|
1148
|
+
* The dev browser's automation contract: what the agent's `browser_*` tools
|
|
1149
|
+
* send, what the GUI (the process that owns the page) answers. Plain data
|
|
1150
|
+
* both ways, so it crosses the daemon socket and IPC unchanged.
|
|
1151
|
+
*/
|
|
1152
|
+
/** A target on the page: a snapshot ref (preferred), a CSS selector / `text=` / `role=` locator, or a point. */
|
|
1153
|
+
interface BrowserTarget {
|
|
1154
|
+
ref?: string;
|
|
1155
|
+
selector?: string;
|
|
1156
|
+
x?: number;
|
|
1157
|
+
y?: number;
|
|
1158
|
+
}
|
|
1159
|
+
type BrowserWaitUntil = 'load' | 'domcontentloaded' | 'none';
|
|
1160
|
+
interface BrowserOpInputs {
|
|
1161
|
+
open: {
|
|
1162
|
+
url?: string;
|
|
1163
|
+
show?: boolean;
|
|
1164
|
+
};
|
|
1165
|
+
navigate: {
|
|
1166
|
+
url?: string;
|
|
1167
|
+
action?: 'back' | 'forward' | 'reload';
|
|
1168
|
+
waitUntil?: BrowserWaitUntil;
|
|
1169
|
+
timeoutMs?: number;
|
|
1170
|
+
};
|
|
1171
|
+
snapshot: Record<string, never>;
|
|
1172
|
+
screenshot: {
|
|
1173
|
+
ref?: string;
|
|
1174
|
+
};
|
|
1175
|
+
click: BrowserTarget & {
|
|
1176
|
+
timeoutMs?: number;
|
|
1177
|
+
};
|
|
1178
|
+
type: BrowserTarget & {
|
|
1179
|
+
text: string;
|
|
1180
|
+
clear?: boolean;
|
|
1181
|
+
submit?: boolean;
|
|
1182
|
+
timeoutMs?: number;
|
|
1183
|
+
};
|
|
1184
|
+
press: {
|
|
1185
|
+
key: string;
|
|
1186
|
+
modifiers?: ('Alt' | 'Control' | 'Meta' | 'Shift')[];
|
|
1187
|
+
};
|
|
1188
|
+
scroll: BrowserTarget & {
|
|
1189
|
+
dx?: number;
|
|
1190
|
+
dy?: number;
|
|
1191
|
+
};
|
|
1192
|
+
wait_for: {
|
|
1193
|
+
text?: string;
|
|
1194
|
+
selector?: string;
|
|
1195
|
+
urlIncludes?: string;
|
|
1196
|
+
timeoutMs?: number;
|
|
1197
|
+
};
|
|
1198
|
+
evaluate: {
|
|
1199
|
+
expression: string;
|
|
1200
|
+
};
|
|
1201
|
+
console: {
|
|
1202
|
+
since?: number;
|
|
1203
|
+
level?: 'error' | 'warning' | 'all';
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
type BrowserOp = keyof BrowserOpInputs;
|
|
1207
|
+
declare const BROWSER_OPS: readonly ["open", "navigate", "snapshot", "screenshot", "click", "type", "press", "scroll", "wait_for", "evaluate", "console"];
|
|
1208
|
+
interface BrowserStatus {
|
|
1209
|
+
url: string;
|
|
1210
|
+
title: string;
|
|
1211
|
+
loading: boolean;
|
|
1212
|
+
viewport?: {
|
|
1213
|
+
width: number;
|
|
1214
|
+
height: number;
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
/** What changed on the page because of an action; the agent reads this instead of re-snapshotting every step. */
|
|
1218
|
+
interface BrowserChange {
|
|
1219
|
+
/** The element acted on, by its accessible name (or tag when it has none). */
|
|
1220
|
+
target?: string;
|
|
1221
|
+
url?: string;
|
|
1222
|
+
title?: string;
|
|
1223
|
+
/** A JavaScript dialog the page opened, and what was done with it. */
|
|
1224
|
+
dialog?: {
|
|
1225
|
+
type: string;
|
|
1226
|
+
message: string;
|
|
1227
|
+
handled: 'accepted' | 'dismissed';
|
|
1228
|
+
};
|
|
1229
|
+
/** Console errors and failed requests since the action started. */
|
|
1230
|
+
errors?: string[];
|
|
1231
|
+
/** The page navigated or changed a lot: refs from the last snapshot may be gone. */
|
|
1232
|
+
refsStale?: boolean;
|
|
1233
|
+
}
|
|
1234
|
+
interface BrowserConsoleEntry {
|
|
1235
|
+
seq: number;
|
|
1236
|
+
level: 'error' | 'warning' | 'info' | 'log' | 'debug';
|
|
1237
|
+
text: string;
|
|
1238
|
+
/** Set for failed network requests. */
|
|
1239
|
+
url?: string;
|
|
1240
|
+
}
|
|
1241
|
+
interface BrowserSnapshot {
|
|
1242
|
+
status: BrowserStatus;
|
|
1243
|
+
/** One line per interactive or landmark element, `[ref=eN]` on the ones you can act on. */
|
|
1244
|
+
outline: string;
|
|
1245
|
+
/** Elements left out because of the cap. */
|
|
1246
|
+
truncated: number;
|
|
1247
|
+
text: string;
|
|
1248
|
+
errors: string[];
|
|
1249
|
+
}
|
|
1250
|
+
interface BrowserScreenshot {
|
|
1251
|
+
/** Base64 JPEG. */
|
|
1252
|
+
data: string;
|
|
1253
|
+
mediaType: 'image/jpeg';
|
|
1254
|
+
width: number;
|
|
1255
|
+
height: number;
|
|
1256
|
+
/** Image pixels per CSS pixel: divide image coordinates by this to click. */
|
|
1257
|
+
scale: number;
|
|
1258
|
+
}
|
|
1259
|
+
interface BrowserOpResults {
|
|
1260
|
+
open: BrowserStatus;
|
|
1261
|
+
navigate: BrowserStatus;
|
|
1262
|
+
snapshot: BrowserSnapshot;
|
|
1263
|
+
screenshot: BrowserScreenshot;
|
|
1264
|
+
click: BrowserChange;
|
|
1265
|
+
type: BrowserChange;
|
|
1266
|
+
press: BrowserChange;
|
|
1267
|
+
scroll: BrowserChange & {
|
|
1268
|
+
scrollX?: number;
|
|
1269
|
+
scrollY?: number;
|
|
1270
|
+
};
|
|
1271
|
+
wait_for: BrowserStatus;
|
|
1272
|
+
evaluate: {
|
|
1273
|
+
value: unknown;
|
|
1274
|
+
};
|
|
1275
|
+
console: {
|
|
1276
|
+
entries: BrowserConsoleEntry[];
|
|
1277
|
+
next: number;
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
type BrowserErrorCode = 'no_browser' | 'no_page' | 'stale_ref' | 'not_found' | 'not_actionable' | 'invalid_url' | 'invalid_input' | 'timeout' | 'interrupted' | 'cancelled' | 'too_large' | 'failed';
|
|
1281
|
+
interface BrowserRequest<O extends BrowserOp = BrowserOp> {
|
|
1282
|
+
requestId: string;
|
|
1283
|
+
sessionId: string;
|
|
1284
|
+
op: O;
|
|
1285
|
+
input: BrowserOpInputs[O];
|
|
1286
|
+
timeoutMs: number;
|
|
1287
|
+
}
|
|
1288
|
+
type BrowserResponse<O extends BrowserOp = BrowserOp> = {
|
|
1289
|
+
ok: true;
|
|
1290
|
+
result: BrowserOpResults[O];
|
|
1291
|
+
} | {
|
|
1292
|
+
ok: false;
|
|
1293
|
+
error: {
|
|
1294
|
+
code: BrowserErrorCode;
|
|
1295
|
+
message: string;
|
|
1296
|
+
};
|
|
1297
|
+
};
|
|
1298
|
+
declare class BrowserOpError extends Error {
|
|
1299
|
+
readonly code: BrowserErrorCode;
|
|
1300
|
+
constructor(code: BrowserErrorCode, message: string);
|
|
1301
|
+
}
|
|
1302
|
+
/** Default and ceiling for an action's own wait (element to become actionable, text to appear). */
|
|
1303
|
+
declare const BROWSER_ACTION_TIMEOUT_MS = 5000;
|
|
1304
|
+
declare const BROWSER_WAIT_TIMEOUT_MS = 10000;
|
|
1305
|
+
declare const BROWSER_MAX_WAIT_MS = 30000;
|
|
1306
|
+
/** How long the host waits for a page to mount and register before `open` gives up. */
|
|
1307
|
+
declare const BROWSER_OPEN_MOUNT_MS = 15000;
|
|
1308
|
+
/** Transport budget on top of the action's own wait. */
|
|
1309
|
+
declare const BROWSER_REQUEST_SLACK_MS = 5000;
|
|
1310
|
+
declare const BROWSER_EVALUATE_MAX_BYTES: number;
|
|
1311
|
+
declare const BROWSER_OUTLINE_MAX_ELEMENTS = 250;
|
|
1312
|
+
declare const BROWSER_TEXT_MAX_CHARS = 8000;
|
|
1313
|
+
//#endregion
|
|
1314
|
+
//#region src/chat/machine-protocol.d.ts
|
|
1315
|
+
/** Bumped on an incompatible change; a host refuses another major. */
|
|
1316
|
+
declare const MACHINE_PROTOCOL_VERSION = 1;
|
|
1317
|
+
interface MachineRoot {
|
|
1318
|
+
path: string;
|
|
1319
|
+
label?: string;
|
|
1320
|
+
}
|
|
1321
|
+
interface MachineCapabilities {
|
|
1322
|
+
shell: boolean;
|
|
1323
|
+
terminals: boolean;
|
|
1324
|
+
background: boolean;
|
|
1325
|
+
worktrees: boolean;
|
|
1326
|
+
/** `exec.stream*` (live stdin/stdout: context-scoped MCP servers). Absent on older machines. */
|
|
1327
|
+
stream?: boolean;
|
|
1328
|
+
/** The machine runs every command under its own OS sandbox (its user's `sandbox*` settings). */
|
|
1329
|
+
sandboxed?: boolean;
|
|
1330
|
+
}
|
|
1331
|
+
interface MachineRegisterParams {
|
|
1332
|
+
machineId: string;
|
|
1333
|
+
name: string;
|
|
1334
|
+
roots: MachineRoot[];
|
|
1335
|
+
capabilities: MachineCapabilities;
|
|
1336
|
+
version: string;
|
|
1337
|
+
protocolVersion: number;
|
|
1338
|
+
}
|
|
1339
|
+
interface MachineRegisterResult {
|
|
1340
|
+
machineId: string;
|
|
1341
|
+
hostId?: string;
|
|
1342
|
+
}
|
|
1343
|
+
/** A handle as the host names it: the machine rebuilds an unknown one (it restarted). */
|
|
1344
|
+
interface MachineHandleRef {
|
|
1345
|
+
id: string;
|
|
1346
|
+
cwd: string;
|
|
1347
|
+
}
|
|
1348
|
+
interface MachineListOptions {
|
|
1349
|
+
glob?: boolean;
|
|
1350
|
+
limit?: number;
|
|
1351
|
+
metadata?: boolean;
|
|
1352
|
+
gitignore?: boolean;
|
|
1353
|
+
}
|
|
1354
|
+
interface MachineTaskHandle {
|
|
1355
|
+
taskId: string;
|
|
1356
|
+
pid: number;
|
|
1357
|
+
outputPath: string;
|
|
1358
|
+
}
|
|
1359
|
+
/** A machine's worktree, on its filesystem. */
|
|
1360
|
+
interface MachineWorktreeRef {
|
|
1361
|
+
path: string;
|
|
1362
|
+
repoRoot: string;
|
|
1363
|
+
}
|
|
1364
|
+
/** Requests the host sends to a machine: params → result. */
|
|
1365
|
+
interface MachineMethods {
|
|
1366
|
+
'machine.ping': {
|
|
1367
|
+
params: Record<string, never>;
|
|
1368
|
+
result: {
|
|
1369
|
+
ok: true;
|
|
1370
|
+
};
|
|
1371
|
+
};
|
|
1372
|
+
'exec.spawn': {
|
|
1373
|
+
params: {
|
|
1374
|
+
handle: MachineHandleRef;
|
|
1375
|
+
};
|
|
1376
|
+
result: {
|
|
1377
|
+
id: string;
|
|
1378
|
+
cwd: string;
|
|
1379
|
+
};
|
|
1380
|
+
};
|
|
1381
|
+
'exec.run': {
|
|
1382
|
+
params: {
|
|
1383
|
+
handle: MachineHandleRef;
|
|
1384
|
+
callId: string;
|
|
1385
|
+
command: string;
|
|
1386
|
+
cwd?: string;
|
|
1387
|
+
env?: Record<string, string>;
|
|
1388
|
+
timeout?: number;
|
|
1389
|
+
};
|
|
1390
|
+
result: {
|
|
1391
|
+
stdout: string;
|
|
1392
|
+
stderr: string;
|
|
1393
|
+
exitCode: number;
|
|
1394
|
+
};
|
|
1395
|
+
};
|
|
1396
|
+
'exec.cancel': {
|
|
1397
|
+
params: {
|
|
1398
|
+
callId: string;
|
|
1399
|
+
};
|
|
1400
|
+
result: {
|
|
1401
|
+
cancelled: boolean;
|
|
1402
|
+
};
|
|
1403
|
+
};
|
|
1404
|
+
'exec.destroy': {
|
|
1405
|
+
params: {
|
|
1406
|
+
handle: MachineHandleRef;
|
|
1407
|
+
};
|
|
1408
|
+
result: {
|
|
1409
|
+
ok: true;
|
|
1410
|
+
};
|
|
1411
|
+
};
|
|
1412
|
+
/** Start a live process; its output comes as `exec.stream.data` / `exec.stream.exit`, `exec.cancel` kills it. */
|
|
1413
|
+
'exec.stream': {
|
|
1414
|
+
params: {
|
|
1415
|
+
handle: MachineHandleRef;
|
|
1416
|
+
callId: string;
|
|
1417
|
+
command: string;
|
|
1418
|
+
cwd?: string;
|
|
1419
|
+
env?: Record<string, string>;
|
|
1420
|
+
};
|
|
1421
|
+
result: {
|
|
1422
|
+
pid: number;
|
|
1423
|
+
};
|
|
1424
|
+
};
|
|
1425
|
+
'exec.stream.write': {
|
|
1426
|
+
params: {
|
|
1427
|
+
callId: string;
|
|
1428
|
+
data: string;
|
|
1429
|
+
};
|
|
1430
|
+
result: {
|
|
1431
|
+
ok: true;
|
|
1432
|
+
};
|
|
1433
|
+
};
|
|
1434
|
+
'fs.read': {
|
|
1435
|
+
params: {
|
|
1436
|
+
handle: MachineHandleRef;
|
|
1437
|
+
path: string;
|
|
1438
|
+
binary?: boolean;
|
|
1439
|
+
};
|
|
1440
|
+
result: {
|
|
1441
|
+
content: string;
|
|
1442
|
+
};
|
|
1443
|
+
};
|
|
1444
|
+
'fs.write': {
|
|
1445
|
+
params: {
|
|
1446
|
+
handle: MachineHandleRef;
|
|
1447
|
+
path: string;
|
|
1448
|
+
content: string;
|
|
1449
|
+
};
|
|
1450
|
+
result: {
|
|
1451
|
+
ok: true;
|
|
1452
|
+
};
|
|
1453
|
+
};
|
|
1454
|
+
'fs.list': {
|
|
1455
|
+
params: {
|
|
1456
|
+
handle: MachineHandleRef;
|
|
1457
|
+
path: string;
|
|
1458
|
+
options?: MachineListOptions;
|
|
1459
|
+
};
|
|
1460
|
+
result: {
|
|
1461
|
+
entries: Array<string | {
|
|
1462
|
+
path: string;
|
|
1463
|
+
size?: number;
|
|
1464
|
+
mtimeMs?: number;
|
|
1465
|
+
}>;
|
|
1466
|
+
};
|
|
1467
|
+
};
|
|
1468
|
+
'fs.size': {
|
|
1469
|
+
params: {
|
|
1470
|
+
handle: MachineHandleRef;
|
|
1471
|
+
path: string;
|
|
1472
|
+
};
|
|
1473
|
+
result: {
|
|
1474
|
+
size: number | null;
|
|
1475
|
+
};
|
|
1476
|
+
};
|
|
1477
|
+
'bg.start': {
|
|
1478
|
+
params: {
|
|
1479
|
+
handle: MachineHandleRef;
|
|
1480
|
+
command: string;
|
|
1481
|
+
cwd?: string;
|
|
1482
|
+
env?: Record<string, string>;
|
|
1483
|
+
maxOutputBytes?: number;
|
|
1484
|
+
};
|
|
1485
|
+
result: MachineTaskHandle;
|
|
1486
|
+
};
|
|
1487
|
+
'bg.list': {
|
|
1488
|
+
params: {
|
|
1489
|
+
handle: MachineHandleRef;
|
|
1490
|
+
};
|
|
1491
|
+
result: {
|
|
1492
|
+
tasks: JsonValue[];
|
|
1493
|
+
};
|
|
1494
|
+
};
|
|
1495
|
+
'bg.kill': {
|
|
1496
|
+
params: {
|
|
1497
|
+
handle: MachineHandleRef;
|
|
1498
|
+
taskId: string;
|
|
1499
|
+
};
|
|
1500
|
+
result: {
|
|
1501
|
+
exit: JsonValue | null;
|
|
1502
|
+
};
|
|
1503
|
+
};
|
|
1504
|
+
'bg.wait': {
|
|
1505
|
+
params: {
|
|
1506
|
+
handle: MachineHandleRef;
|
|
1507
|
+
taskId: string;
|
|
1508
|
+
timeoutMs?: number;
|
|
1509
|
+
};
|
|
1510
|
+
result: {
|
|
1511
|
+
exit: JsonValue | null;
|
|
1512
|
+
};
|
|
1513
|
+
};
|
|
1514
|
+
'terminal.open': {
|
|
1515
|
+
params: {
|
|
1516
|
+
handle: MachineHandleRef;
|
|
1517
|
+
cols: number;
|
|
1518
|
+
rows: number;
|
|
1519
|
+
cwd?: string;
|
|
1520
|
+
};
|
|
1521
|
+
result: {
|
|
1522
|
+
terminalId: string;
|
|
1523
|
+
};
|
|
1524
|
+
};
|
|
1525
|
+
'terminal.attach': {
|
|
1526
|
+
params: {
|
|
1527
|
+
terminalId: string;
|
|
1528
|
+
};
|
|
1529
|
+
result: {
|
|
1530
|
+
attached: boolean;
|
|
1531
|
+
backlog: string;
|
|
1532
|
+
total: number;
|
|
1533
|
+
};
|
|
1534
|
+
};
|
|
1535
|
+
'terminal.write': {
|
|
1536
|
+
params: {
|
|
1537
|
+
terminalId: string;
|
|
1538
|
+
data: string;
|
|
1539
|
+
};
|
|
1540
|
+
result: {
|
|
1541
|
+
ok: true;
|
|
1542
|
+
};
|
|
1543
|
+
};
|
|
1544
|
+
'terminal.resize': {
|
|
1545
|
+
params: {
|
|
1546
|
+
terminalId: string;
|
|
1547
|
+
cols: number;
|
|
1548
|
+
rows: number;
|
|
1549
|
+
};
|
|
1550
|
+
result: {
|
|
1551
|
+
ok: true;
|
|
1552
|
+
};
|
|
1553
|
+
};
|
|
1554
|
+
'terminal.kill': {
|
|
1555
|
+
params: {
|
|
1556
|
+
terminalId: string;
|
|
1557
|
+
};
|
|
1558
|
+
result: {
|
|
1559
|
+
ok: true;
|
|
1560
|
+
};
|
|
1561
|
+
};
|
|
1562
|
+
'terminal.detach': {
|
|
1563
|
+
params: {
|
|
1564
|
+
terminalId: string;
|
|
1565
|
+
};
|
|
1566
|
+
result: {
|
|
1567
|
+
ok: true;
|
|
1568
|
+
};
|
|
1569
|
+
};
|
|
1570
|
+
'env.checkFolder': {
|
|
1571
|
+
params: {
|
|
1572
|
+
cwd: string;
|
|
1573
|
+
};
|
|
1574
|
+
result: {
|
|
1575
|
+
cwd: string;
|
|
1576
|
+
};
|
|
1577
|
+
};
|
|
1578
|
+
'env.prepareWorktree': {
|
|
1579
|
+
params: {
|
|
1580
|
+
cwd: string;
|
|
1581
|
+
branch: string;
|
|
1582
|
+
base?: string;
|
|
1583
|
+
config: EnvironmentConfig;
|
|
1584
|
+
};
|
|
1585
|
+
result: {
|
|
1586
|
+
cwd: string;
|
|
1587
|
+
branch: string;
|
|
1588
|
+
base: string;
|
|
1589
|
+
ref: MachineWorktreeRef;
|
|
1590
|
+
};
|
|
1591
|
+
};
|
|
1592
|
+
'env.teardownWorktree': {
|
|
1593
|
+
params: {
|
|
1594
|
+
ref: MachineWorktreeRef;
|
|
1595
|
+
branch?: string;
|
|
1596
|
+
config: EnvironmentConfig;
|
|
1597
|
+
};
|
|
1598
|
+
result: {
|
|
1599
|
+
removed: boolean;
|
|
1600
|
+
reason?: string;
|
|
1601
|
+
};
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
type MachineMethodName = keyof MachineMethods;
|
|
1605
|
+
type MachineParams<M extends MachineMethodName> = MachineMethods[M]['params'];
|
|
1606
|
+
type MachineResult<M extends MachineMethodName> = MachineMethods[M]['result'];
|
|
1607
|
+
/** Error codes of the machine protocol (JSON-RPC server-error range, apart from `IpcErrorCode`). */
|
|
1608
|
+
declare const MachineErrorCode: {
|
|
1609
|
+
/** A machine connection called a client method, or a client a machine one. */
|
|
1610
|
+
readonly MethodNotAllowed: -32040;
|
|
1611
|
+
/** `machine.register` from another major `MACHINE_PROTOCOL_VERSION`. */
|
|
1612
|
+
readonly VersionSkew: -32041;
|
|
1613
|
+
/** The name is held by another machine on this host. */
|
|
1614
|
+
readonly NameTaken: -32042;
|
|
1615
|
+
/** A path or cwd outside the machine's roots, or in its data dir. */
|
|
1616
|
+
readonly OutsideRoots: -32043;
|
|
1617
|
+
/** The machine id is bound to another (live) token, or this token was used by the machine before the host forgot it. */
|
|
1618
|
+
readonly IdBound: -32044;
|
|
1619
|
+
/** No room now (a capacity limit): try again later, unlike a refusal. */
|
|
1620
|
+
readonly Busy: -32045;
|
|
1621
|
+
};
|
|
1622
|
+
/** A machine as clients see it (`machines.list`, `environments.list`). */
|
|
1623
|
+
interface MachineInfo {
|
|
1624
|
+
id: string;
|
|
1625
|
+
name: string;
|
|
1626
|
+
roots: MachineRoot[];
|
|
1627
|
+
status: 'online' | 'offline';
|
|
1628
|
+
lastSeen?: number;
|
|
1629
|
+
version?: string;
|
|
1630
|
+
/** What it registered with (absent: never connected since this host recorded it). */
|
|
1631
|
+
capabilities?: Partial<MachineCapabilities>;
|
|
1632
|
+
}
|
|
1633
|
+
/** `machine:status` payload. */
|
|
1634
|
+
interface MachineStatusChange {
|
|
1635
|
+
machineId: string;
|
|
1636
|
+
name: string;
|
|
1637
|
+
status: 'online' | 'offline';
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* What a local host's machine links are doing (`machines.links.status`,
|
|
1641
|
+
* `machine:links`): this computer shared with a saved server (it is the
|
|
1642
|
+
* machine), and saved servers used as machines (`local@<server>`, the
|
|
1643
|
+
* reverse direction over this host's own client connection).
|
|
1644
|
+
*/
|
|
1645
|
+
type MachineLinkState = 'connecting' | 'connected' | 'reconnecting' | 'offline' | 'auth-refused' | 'identity' | 'refused';
|
|
1646
|
+
interface MachineShareStatus {
|
|
1647
|
+
/** The saved server's host id. */
|
|
1648
|
+
hostId: string;
|
|
1649
|
+
/** This computer's name there (`local@<name>`). */
|
|
1650
|
+
name: string;
|
|
1651
|
+
roots: string[];
|
|
1652
|
+
state: MachineLinkState;
|
|
1653
|
+
/** Why it is not connected. Never a token. */
|
|
1654
|
+
detail?: string;
|
|
1655
|
+
}
|
|
1656
|
+
interface MachineUseStatus {
|
|
1657
|
+
hostId: string;
|
|
1658
|
+
state: MachineLinkState;
|
|
1659
|
+
detail?: string;
|
|
1660
|
+
/** The server's machine name on this host, once attached. */
|
|
1661
|
+
machineName?: string;
|
|
1662
|
+
}
|
|
1663
|
+
interface MachineLinksStatus {
|
|
1664
|
+
shares: MachineShareStatus[];
|
|
1665
|
+
uses: MachineUseStatus[];
|
|
1666
|
+
}
|
|
1667
|
+
/** A machine name from a free-form one (a server's display name): the valid characters kept, the rest dashed. */
|
|
1668
|
+
declare function toMachineName(raw: string): string;
|
|
1669
|
+
/** A machine-qualified environment kind: `<base>@<machine name>`. */
|
|
1670
|
+
declare function machineKind(base: 'local' | 'worktree', name: string): string;
|
|
1671
|
+
/** `{ base, name }` of a machine-qualified kind, `null` for any other. */
|
|
1672
|
+
declare function parseMachineKind(kind: string): {
|
|
1673
|
+
base: 'local' | 'worktree';
|
|
1674
|
+
name: string;
|
|
1675
|
+
} | null;
|
|
1676
|
+
/** A machine name: one path-safe segment, so `local@<name>` is unambiguous. */
|
|
1677
|
+
declare function isValidMachineName(name: string): boolean;
|
|
1678
|
+
//#endregion
|
|
1679
|
+
//#region src/chat/terminal/protocol.d.ts
|
|
1680
|
+
/**
|
|
1681
|
+
* Terminals: the contract between the host that runs them (the daemon) and
|
|
1682
|
+
* the clients that show them (the GUI's drawer and panel tab). Pure types
|
|
1683
|
+
* and limits, safe for a renderer bundle.
|
|
1684
|
+
*
|
|
1685
|
+
* Output travels as text with a running character offset: a client knows
|
|
1686
|
+
* where each chunk starts, drops what it already has, and acknowledges what
|
|
1687
|
+
* it wrote. The host stops sending to clients that fall a window behind and
|
|
1688
|
+
* later resets them from history instead of queueing without end.
|
|
1689
|
+
*/
|
|
1690
|
+
/** Who started it: the user, or the agent (a background `shell` task). */
|
|
1691
|
+
type TerminalOwner = 'user' | 'agent';
|
|
1692
|
+
/** Where it runs: the session's environment, or this machine in the project. */
|
|
1693
|
+
type TerminalTarget = 'session' | 'local';
|
|
1694
|
+
/**
|
|
1695
|
+
* `paused`: not connected right now (the sandbox paused, or the host
|
|
1696
|
+
* restarted) but it can be found again; opening it reconnects.
|
|
1697
|
+
*/
|
|
1698
|
+
type TerminalStatus = 'starting' | 'running' | 'paused' | 'exited' | 'error';
|
|
1699
|
+
interface TerminalInfo {
|
|
1700
|
+
id: string;
|
|
1701
|
+
sessionId: string;
|
|
1702
|
+
/** Stable name ("Terminal 2", or the agent's command). */
|
|
1703
|
+
label: string;
|
|
1704
|
+
/** Title the program set (OSC 0/2), if any. */
|
|
1705
|
+
title?: string;
|
|
1706
|
+
/** The program in the foreground, for terminals on this machine. */
|
|
1707
|
+
program?: string;
|
|
1708
|
+
owner: TerminalOwner;
|
|
1709
|
+
target: TerminalTarget;
|
|
1710
|
+
/** Environment kind it runs in (`local`, `worktree`, `docker`, `e2b`, …). */
|
|
1711
|
+
environment: string;
|
|
1712
|
+
cwd: string;
|
|
1713
|
+
status: TerminalStatus;
|
|
1714
|
+
exitCode?: number;
|
|
1715
|
+
error?: string;
|
|
1716
|
+
cols: number;
|
|
1717
|
+
rows: number;
|
|
1718
|
+
/**
|
|
1719
|
+
* Bumped on every size change: signals and attach replies reach a view by
|
|
1720
|
+
* different routes, so it keeps the newest size, not the last to arrive.
|
|
1721
|
+
*/
|
|
1722
|
+
sizeSeq: number;
|
|
1723
|
+
/** The agent's terminal tools skip it. */
|
|
1724
|
+
hiddenFromAgent: boolean;
|
|
1725
|
+
/** The background task it runs (agent terminals). */
|
|
1726
|
+
taskId?: string;
|
|
1727
|
+
createdAt: number;
|
|
1728
|
+
lastActivityAt: number;
|
|
1729
|
+
}
|
|
1730
|
+
interface TerminalSessionState {
|
|
1731
|
+
/** False when this host can't run terminals (the GUI without the daemon). */
|
|
1732
|
+
available: boolean;
|
|
1733
|
+
/** Why not, when `available` is false. */
|
|
1734
|
+
reason?: string;
|
|
1735
|
+
/** Kind of the session's environment, and whether it runs somewhere else. */
|
|
1736
|
+
environment: {
|
|
1737
|
+
kind: string;
|
|
1738
|
+
remote: boolean;
|
|
1739
|
+
};
|
|
1740
|
+
terminals: TerminalInfo[];
|
|
1741
|
+
}
|
|
1742
|
+
interface TerminalOpenInput {
|
|
1743
|
+
sessionId: string;
|
|
1744
|
+
target?: TerminalTarget;
|
|
1745
|
+
cols: number;
|
|
1746
|
+
rows: number;
|
|
1747
|
+
}
|
|
1748
|
+
/** What a client needs to start showing a terminal: its history, and where live output resumes. */
|
|
1749
|
+
interface TerminalAttachResult {
|
|
1750
|
+
terminal: TerminalInfo;
|
|
1751
|
+
data: string;
|
|
1752
|
+
offset: number;
|
|
1753
|
+
}
|
|
1754
|
+
/** The agent's view: plain text lines, with a cursor for the next read. */
|
|
1755
|
+
interface TerminalReadResult {
|
|
1756
|
+
terminal: TerminalInfo;
|
|
1757
|
+
text: string;
|
|
1758
|
+
/** Pass as `since` to get only newer lines. */
|
|
1759
|
+
next: number;
|
|
1760
|
+
/** Lines dropped from the front because of the size cap. */
|
|
1761
|
+
truncated: number;
|
|
1762
|
+
}
|
|
1763
|
+
/** Characters a client may be behind before the host stops sending to it. */
|
|
1764
|
+
declare const TERMINAL_OUTPUT_WINDOW: number;
|
|
1765
|
+
/** History kept per terminal for new views (characters). */
|
|
1766
|
+
declare const TERMINAL_HISTORY_MAX_CHARS: number;
|
|
1767
|
+
/** Plain-text lines kept per terminal for the agent. */
|
|
1768
|
+
declare const TERMINAL_TEXT_MAX_LINES = 5000;
|
|
1769
|
+
/** Most the agent gets from one read (characters). */
|
|
1770
|
+
declare const TERMINAL_READ_MAX_CHARS: number;
|
|
1771
|
+
/** Terminals a session may have open at once. */
|
|
1772
|
+
declare const TERMINAL_MAX_PER_SESSION = 12;
|
|
1773
|
+
declare class TerminalError extends Error {
|
|
1774
|
+
readonly code: 'unavailable' | 'not_found' | 'limit' | 'not_running' | 'failed';
|
|
1775
|
+
constructor(code: 'unavailable' | 'not_found' | 'limit' | 'not_running' | 'failed', message: string);
|
|
1776
|
+
}
|
|
1777
|
+
//#endregion
|
|
1778
|
+
//#region src/chat/todo-glyphs.d.ts
|
|
1779
|
+
declare const TODO_STATUS_GLYPHS: Readonly<Record<TodoStatus, string>>;
|
|
1780
|
+
//#endregion
|
|
1781
|
+
//#region src/chat/todos.d.ts
|
|
1782
|
+
/** Todos live in session metadata and are memory-only here: any session, store-less snapshots included. */
|
|
1783
|
+
type Session = Omit<Session$1, 'save'>;
|
|
1784
|
+
declare const TODOWRITE_TOOL = "todowrite";
|
|
1785
|
+
declare const TODOREAD_TOOL = "todoread";
|
|
1786
|
+
/** True when `name` is one of the todo tool canonical names. */
|
|
1787
|
+
declare function isTodoTool(name: string): boolean;
|
|
1788
|
+
/** `session.metadata[TODOS_METADATA_KEY]: TodosBag` — see {@link TodosBag}. */
|
|
1789
|
+
declare const TODOS_METADATA_KEY = "todos";
|
|
1790
|
+
/** `session.metadata[TODO_WRITE_COUNTS_METADATA_KEY]: CountsBag` — mirrors `TodosBag` shape. */
|
|
1791
|
+
declare const TODO_WRITE_COUNTS_METADATA_KEY = "todoWriteCounts";
|
|
1792
|
+
type TodoStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled';
|
|
1793
|
+
interface TodoItem {
|
|
1794
|
+
/** Stable id — the model picks it. Reusing an id replaces that item. */
|
|
1795
|
+
id: string;
|
|
1796
|
+
/** One-line task summary (Markdown allowed; renderers may sanitize). */
|
|
1797
|
+
content: string;
|
|
1798
|
+
status: TodoStatus;
|
|
1799
|
+
}
|
|
1800
|
+
/**
|
|
1801
|
+
* On-disk shape at `session.metadata[TODOS_METADATA_KEY]`.
|
|
1802
|
+
*
|
|
1803
|
+
* Sub-fields are absent (not empty) when they carry no data — keeps the
|
|
1804
|
+
* persisted metadata clean and lets `JSON.stringify` skip empty bags
|
|
1805
|
+
* entirely on session save.
|
|
1806
|
+
*/
|
|
1807
|
+
interface TodosBag {
|
|
1808
|
+
/** Top-level slot — shared across runs whose `parentRunId` is unset. */
|
|
1809
|
+
session?: TodoItem[];
|
|
1810
|
+
/** Per-subagent-run slots, keyed by the child run's id. */
|
|
1811
|
+
byRun?: Record<string, TodoItem[]>;
|
|
1812
|
+
/**
|
|
1813
|
+
* Most-recent non-empty list per slot — sidecar for UI surfaces, NOT
|
|
1814
|
+
* visible to `todoread`. Updated on every non-empty write; **preserved**
|
|
1815
|
+
* across the auto-clear path. Lets the modal keep showing "what was just
|
|
1816
|
+
* completed" after a fully-done batch wipes the live slot. Empty writes
|
|
1817
|
+
* never touch the archive — clearing the live list shouldn't erase the
|
|
1818
|
+
* audit trail.
|
|
1819
|
+
*/
|
|
1820
|
+
archive?: {
|
|
1821
|
+
session?: TodoItem[];
|
|
1822
|
+
byRun?: Record<string, TodoItem[]>;
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1825
|
+
/**
|
|
1826
|
+
* Default ceiling on a single todo list. Exported so every write boundary caps
|
|
1827
|
+
* identically — a boundary with a different cap would let a list through that
|
|
1828
|
+
* the tool would have truncated.
|
|
1829
|
+
*/
|
|
1830
|
+
declare const DEFAULT_MAX_TODO_ITEMS = 100;
|
|
1831
|
+
interface CreateTodoToolsOptions {
|
|
1832
|
+
/**
|
|
1833
|
+
* Maximum item count per `todowrite`. Excess items are truncated by the
|
|
1834
|
+
* recursive validator and reported back to the model in the tool_result.
|
|
1835
|
+
*
|
|
1836
|
+
* Default: `100`. The default is generous; a planning agent that exceeds
|
|
1837
|
+
* 100 items per call is usually flailing.
|
|
1838
|
+
*/
|
|
1839
|
+
maxItems?: number;
|
|
1840
|
+
/**
|
|
1841
|
+
* Per-run cap on `todowrite` calls, plumbed into `behavior.toolBudgets`.
|
|
1842
|
+
* `onMaxWrites` chooses the reaction (steer / block) — see
|
|
1843
|
+
* {@link AgentBehavior.toolBudgets} for the contract.
|
|
1844
|
+
*
|
|
1845
|
+
* **Default: `0` (no cap).** `todowrite` is a state-transition tool —
|
|
1846
|
+
* a legitimate run of an N-item list needs at least `N + 1` calls
|
|
1847
|
+
* (initial plan + one transition per item) to complete, so a hard
|
|
1848
|
+
* cap punishes the legitimate path. The nudges that DO apply are the
|
|
1849
|
+
* `remindAfter` reminder (soft, in-band) and the identical-payload
|
|
1850
|
+
* dedup check (silent, structural). Hosts that want a true hard cap
|
|
1851
|
+
* can opt in by setting `maxWritesPerRun: N`.
|
|
1852
|
+
*
|
|
1853
|
+
* **Counting semantics** (when opted in): the budget counts every
|
|
1854
|
+
* dispatched call, including dedup substitutes (zidane spec). The
|
|
1855
|
+
* {@link remindAfter} counter counts execute-only dispatches —
|
|
1856
|
+
* dedup hits replay the prior result and never reach the tool body.
|
|
1857
|
+
* Use this budget (not the reminder) as the hard limit.
|
|
1858
|
+
*/
|
|
1859
|
+
maxWritesPerRun?: number;
|
|
1860
|
+
onMaxWrites?: 'steer' | 'block';
|
|
1861
|
+
/**
|
|
1862
|
+
* Hard stop for **consecutive identical** `todowrite` payloads — the
|
|
1863
|
+
* exact loop the in-body `dedupIdentical` check only *whispers* about
|
|
1864
|
+
* ("No change — N items already tracked"). Plumbs a run-scoped
|
|
1865
|
+
* `behavior.dedupTools.todowrite` entry in `block-after` mode: the
|
|
1866
|
+
* gate replays the unchanged result for the first `N - 1` identical
|
|
1867
|
+
* calls, then refuses the `N`th (and every subsequent identical one)
|
|
1868
|
+
* with a `Blocked: …` tool_result so the model breaks out instead of
|
|
1869
|
+
* re-checkpointing forever.
|
|
1870
|
+
*
|
|
1871
|
+
* This is safe to leave on by default — unlike {@link maxWritesPerRun}
|
|
1872
|
+
* it only ever blocks a payload byte-identical to the one already
|
|
1873
|
+
* tracked, so a legitimate "finish the N-item plan" run (which writes
|
|
1874
|
+
* a *different* list each transition) is never touched. The counter
|
|
1875
|
+
* resets the moment the model writes anything different.
|
|
1876
|
+
*
|
|
1877
|
+
* Run-scoped via `DedupToolConfig.scope: 'run'`, so a parent and a
|
|
1878
|
+
* subagent writing the same list never share the counter — the precise
|
|
1879
|
+
* conflation that kept `todowrite` off `behavior.dedupTools` before.
|
|
1880
|
+
*
|
|
1881
|
+
* Set to `0` to opt out (e.g. a host that installs its own loop
|
|
1882
|
+
* hardening). Default: `5`. Values `< 2` are clamped to `2` by the
|
|
1883
|
+
* dedup middleware (a threshold of 1 would block the first call).
|
|
1884
|
+
*/
|
|
1885
|
+
maxIdenticalWrites?: number;
|
|
1886
|
+
/**
|
|
1887
|
+
* Custom refusal text for the {@link maxIdenticalWrites} block. Receives
|
|
1888
|
+
* the 1-indexed identical-call count (including the blocked call). Leave
|
|
1889
|
+
* unset for the built-in "you've written the same list N times in a
|
|
1890
|
+
* row" message.
|
|
1891
|
+
*/
|
|
1892
|
+
identicalBlockReason?: (count: number) => string;
|
|
1893
|
+
/**
|
|
1894
|
+
* Append a "you've checkpointed N times — only call this at significant
|
|
1895
|
+
* task transitions" nudge to the tool_result once `todowrite` has fired
|
|
1896
|
+
* this many times in the current run. The nudge rides on the result
|
|
1897
|
+
* string, so the model sees it on its next turn without `system:transform`
|
|
1898
|
+
* plumbing.
|
|
1899
|
+
*
|
|
1900
|
+
* Counts only executed dispatches (dedup hits skip the tool body and so
|
|
1901
|
+
* skip the increment). For a hard cap that also covers dedup hits, use
|
|
1902
|
+
* {@link maxWritesPerRun}.
|
|
1903
|
+
*
|
|
1904
|
+
* Set to `0` to opt out. Default: `3`.
|
|
1905
|
+
*/
|
|
1906
|
+
remindAfter?: number;
|
|
1907
|
+
/**
|
|
1908
|
+
* Custom reminder text. Receives the post-call count and the items that
|
|
1909
|
+
* were just written. Return `''` (or `undefined`) to suppress the reminder
|
|
1910
|
+
* for this specific call. Default text nudges towards "back to executing,
|
|
1911
|
+
* not re-planning."
|
|
1912
|
+
*/
|
|
1913
|
+
reminderText?: (count: number, items: readonly TodoItem[]) => string | undefined;
|
|
1914
|
+
/**
|
|
1915
|
+
* Short-circuit the tool body when the incoming payload is identical to
|
|
1916
|
+
* the **current slot** (session-shared for top-level runs, per-run for
|
|
1917
|
+
* subagents). The model gets a "No change — N items already tracked."
|
|
1918
|
+
* acknowledgment instead of a fresh "Updated N items." line.
|
|
1919
|
+
* Default: `true`.
|
|
1920
|
+
*
|
|
1921
|
+
* Read `session.metadata.todos` via {@link getTodosForRun} for the
|
|
1922
|
+
* comparison — so the resolution naturally follows the keying rule
|
|
1923
|
+
* (top-level reads the session slot, subagent reads its own). Does
|
|
1924
|
+
* NOT plumb through `behavior.dedupTools`: that cache lives at the
|
|
1925
|
+
* gate, is keyed per session, and would conflate top-level + subagent
|
|
1926
|
+
* re-writes of structurally identical payloads.
|
|
1927
|
+
*
|
|
1928
|
+
* Counter advances on identical re-writes regardless — the model
|
|
1929
|
+
* called the tool, that's a call. Lets the reminder threshold catch
|
|
1930
|
+
* spam. Set `false` to skip the check entirely (every call rewrites
|
|
1931
|
+
* the slot, useful when state-shape comparisons are pointless for
|
|
1932
|
+
* your usage).
|
|
1933
|
+
*/
|
|
1934
|
+
dedupIdentical?: boolean;
|
|
1935
|
+
/**
|
|
1936
|
+
* Override the JSON-schema-level descriptions surfaced to the model.
|
|
1937
|
+
* Useful for telemetry experiments. Leave unset to inherit the built-in
|
|
1938
|
+
* doctrine prose.
|
|
1939
|
+
*/
|
|
1940
|
+
writeDescription?: string;
|
|
1941
|
+
readDescription?: string;
|
|
1942
|
+
}
|
|
1943
|
+
/**
|
|
1944
|
+
* Read the active list for `runId`. Top-level runs see the session-shared
|
|
1945
|
+
* slot; subagent runs see their own. Returns a fresh `[]` (not stored in
|
|
1946
|
+
* metadata) when no slot exists — the caller can mutate the result
|
|
1947
|
+
* without affecting state.
|
|
1948
|
+
*/
|
|
1949
|
+
declare function getTodosForRun(session: Session, runId: string): TodoItem[];
|
|
1950
|
+
/**
|
|
1951
|
+
* Replace the active list for `runId`. Routes to the session-shared slot
|
|
1952
|
+
* for top-level runs and to the per-run slot for subagents. Empty arrays
|
|
1953
|
+
* delete the slot entirely so persisted metadata stays clean.
|
|
1954
|
+
*
|
|
1955
|
+
* Side effect: a **non-empty** write also stashes the same list into
|
|
1956
|
+
* `bag.archive` (same routing). Empty writes never touch the archive —
|
|
1957
|
+
* clearing the live list (whether explicitly or via the tool's auto-
|
|
1958
|
+
* clear) preserves the "last shown" snapshot so UI surfaces can keep
|
|
1959
|
+
* rendering what was just completed. See {@link getArchivedTodosForRun}.
|
|
1960
|
+
*
|
|
1961
|
+
* `opts.clearArchive` opts OUT of that preservation, and exists because the
|
|
1962
|
+
* archive is only the right answer for the AUTO-CLEAR path. UI surfaces render
|
|
1963
|
+
* `todos.length > 0 ? todos : archive`, so a user who deletes every todo would
|
|
1964
|
+
* otherwise watch the archive fall straight back into view with the same items
|
|
1965
|
+
* — a destructive action they confirmed, with no visible effect, and the footer
|
|
1966
|
+
* chip still counting the list they just deleted. Pass it for user-initiated
|
|
1967
|
+
* writes; leave it off for the tool.
|
|
1968
|
+
*/
|
|
1969
|
+
declare function setTodosForRun(session: Session, runId: string, items: readonly TodoItem[], opts?: {
|
|
1970
|
+
clearArchive?: boolean;
|
|
1971
|
+
}): void;
|
|
1972
|
+
/**
|
|
1973
|
+
* Read the archived (most-recent non-empty) list for `runId`. Same slot
|
|
1974
|
+
* routing as {@link getTodosForRun}, but reads `bag.archive` instead of
|
|
1975
|
+
* the live slot. Returns a fresh `[]` when no archive exists.
|
|
1976
|
+
*
|
|
1977
|
+
* UI surfaces use this to keep showing "what was just completed" after
|
|
1978
|
+
* the live list auto-clears. The model never sees the archive — it's a
|
|
1979
|
+
* read-only sidecar for human-facing rendering.
|
|
1980
|
+
*/
|
|
1981
|
+
declare function getArchivedTodosForRun(session: Session, runId: string): TodoItem[];
|
|
1982
|
+
/**
|
|
1983
|
+
* Reconcile `session.metadata.todos.byRun` (live + archive) against
|
|
1984
|
+
* `session.runs`. Drops subagent slots whose runId isn't in the run
|
|
1985
|
+
* list. The top-level `session` slot is unaffected — it's session-
|
|
1986
|
+
* scoped, not per-run, so there's no orphan to GC.
|
|
1987
|
+
*
|
|
1988
|
+
* Useful after `session.setRuns()` (fork / restore) or to GC stale
|
|
1989
|
+
* metadata mutated by an external caller. Also prunes the parallel
|
|
1990
|
+
* counter bag so the two don't drift.
|
|
1991
|
+
*
|
|
1992
|
+
* `dropped` reports the live-byRun orphans only (archive-only orphans
|
|
1993
|
+
* are silently swept). The live half is the contract callers actually
|
|
1994
|
+
* observe.
|
|
1995
|
+
*/
|
|
1996
|
+
declare function pruneTodosByRun(session: Session): {
|
|
1997
|
+
dropped: readonly string[];
|
|
1998
|
+
};
|
|
1999
|
+
/**
|
|
2000
|
+
* Build a `Preset` carrying the `{ todowrite, todoread }` tool pair.
|
|
2001
|
+
*
|
|
2002
|
+
* Loop hardening is layered, soft → hard:
|
|
2003
|
+
* 1. **In-body identical dedup** (`dedupIdentical`, on) — resolves
|
|
2004
|
+
* against the active slot (session-shared for top-level runs,
|
|
2005
|
+
* per-run for subagents) and returns "No change — N items already
|
|
2006
|
+
* tracked." Advisory; the model can ignore it.
|
|
2007
|
+
* 2. **In-band reminder** (`remindAfter`, on) — appends a "you've
|
|
2008
|
+
* checkpointed N times" nudge to the result. Also advisory.
|
|
2009
|
+
* 3. **Consecutive-identical hard block** (`maxIdenticalWrites`, ON by
|
|
2010
|
+
* default) — a run-scoped `behavior.dedupTools.todowrite` entry in
|
|
2011
|
+
* `block-after` mode. After N byte-identical writes in a row the
|
|
2012
|
+
* gate refuses with `Blocked: …` and the body never runs. This is
|
|
2013
|
+
* the real loop breaker, and it's safe-by-default precisely because
|
|
2014
|
+
* it only fires on *identical* payloads — a legitimate N-item plan
|
|
2015
|
+
* writes a *different* list each step and never trips it.
|
|
2016
|
+
*
|
|
2017
|
+
* By default the preset adds **no** `toolBudgets` entry — a blanket
|
|
2018
|
+
* per-call cap is the wrong abstraction for a state-transition tool (it
|
|
2019
|
+
* punishes the legitimate "finish the N-item plan" path). Hosts that
|
|
2020
|
+
* want a ceiling on *all* writes (not just identical ones) pass
|
|
2021
|
+
* `maxWritesPerRun: N` explicitly; the factory then also plumbs a
|
|
2022
|
+
* `behavior.toolBudgets.todowrite` entry.
|
|
2023
|
+
*
|
|
2024
|
+
* Returning a `Preset` (not a bare tool map) lets the result flow
|
|
2025
|
+
* through {@link composePresets} unchanged. `behavior.dedupTools` and
|
|
2026
|
+
* `behavior.toolBudgets` are tool-name-keyed records that
|
|
2027
|
+
* `composePresets` deep-merges, so a caller's entries for other tools
|
|
2028
|
+
* survive the layering, and a caller's override for `todowrite` itself
|
|
2029
|
+
* wins by being placed later in the chain.
|
|
2030
|
+
*
|
|
2031
|
+
* ```ts
|
|
2032
|
+
* import { basic, composePresets } from 'zidane/presets'
|
|
2033
|
+
* import { createTodoTools } from 'zidane/chat'
|
|
2034
|
+
*
|
|
2035
|
+
* // Default: soft dedup + reminder + a run-scoped hard block after 5
|
|
2036
|
+
* // identical writes in a row.
|
|
2037
|
+
* createAgent({ ...composePresets(basic, createTodoTools()), provider })
|
|
2038
|
+
*
|
|
2039
|
+
* // Tune (or disable) the identical-write block.
|
|
2040
|
+
* createTodoTools({ maxIdenticalWrites: 3 }) // stricter
|
|
2041
|
+
* createTodoTools({ maxIdenticalWrites: 0 }) // off — soft signals only
|
|
2042
|
+
*
|
|
2043
|
+
* // Opt-in blanket cap on *all* writes (counts distinct ones too).
|
|
2044
|
+
* createAgent({
|
|
2045
|
+
* ...composePresets(basic, createTodoTools({ maxWritesPerRun: 20 })),
|
|
2046
|
+
* provider,
|
|
2047
|
+
* })
|
|
2048
|
+
* ```
|
|
2049
|
+
*
|
|
2050
|
+
* For the trivial "just add the tools to an existing config" case, plain
|
|
2051
|
+
* spread is also fine — the returned `Preset` sets `tools` plus a
|
|
2052
|
+
* `behavior` block (carrying the default identical-write dedup):
|
|
2053
|
+
*
|
|
2054
|
+
* ```ts
|
|
2055
|
+
* createAgent({ ...basic, ...createTodoTools(), provider })
|
|
2056
|
+
* ```
|
|
2057
|
+
*/
|
|
2058
|
+
declare function createTodoTools(options?: CreateTodoToolsOptions): Preset;
|
|
2059
|
+
/**
|
|
2060
|
+
* Validate an untrusted todo list, dropping malformed rows and capping length.
|
|
2061
|
+
*
|
|
2062
|
+
* The single validator for every write/read boundary: model tool input,
|
|
2063
|
+
* persisted metadata on read, and user edits arriving over IPC. Keeping them on
|
|
2064
|
+
* one implementation is what makes "well-formed" mean the same thing at each —
|
|
2065
|
+
* a boundary that only picked fields (as `normalizeItem` does) would admit an
|
|
2066
|
+
* invalid `status` that the read path then silently drops, so the write appears
|
|
2067
|
+
* to succeed and the row vanishes with nothing reported.
|
|
2068
|
+
*/
|
|
2069
|
+
declare function sanitizeTodoItems(raw: readonly unknown[], cap?: number): TodoItem[];
|
|
2070
|
+
interface TodoTally {
|
|
2071
|
+
pending: number;
|
|
2072
|
+
in_progress: number;
|
|
2073
|
+
completed: number;
|
|
2074
|
+
cancelled: number;
|
|
2075
|
+
}
|
|
2076
|
+
interface ActiveTodosState {
|
|
2077
|
+
/** Run the slice came from. `null` ⇒ no session / no runs / no active run. */
|
|
2078
|
+
runId: string | null;
|
|
2079
|
+
/**
|
|
2080
|
+
* Live list — what `todoread` would return. Empty when the slot was
|
|
2081
|
+
* cleared (e.g. auto-clear after every item completed) or never
|
|
2082
|
+
* written. Source of truth for the model's view.
|
|
2083
|
+
*/
|
|
2084
|
+
todos: readonly TodoItem[];
|
|
2085
|
+
/**
|
|
2086
|
+
* Most-recent non-empty list for the active slot, preserved across
|
|
2087
|
+
* auto-clear. Equals `todos` when the live list is non-empty;
|
|
2088
|
+
* otherwise the last batch that was shown (commonly the all-`completed`
|
|
2089
|
+
* close-out). UI surfaces fall back to this when `todos` is empty so
|
|
2090
|
+
* the user can still glance back at "what was just finished" — until
|
|
2091
|
+
* the model writes a new list. Empty array when no list was ever
|
|
2092
|
+
* written for this slot.
|
|
2093
|
+
*/
|
|
2094
|
+
archive: readonly TodoItem[];
|
|
2095
|
+
/**
|
|
2096
|
+
* The first `in_progress` item from `todos` (the **live** list), when
|
|
2097
|
+
* one exists. Drives the inline indicator above the prompt. Always
|
|
2098
|
+
* `null` when the live list is empty — even if the archive carries
|
|
2099
|
+
* an in-progress item, that item is by definition stale.
|
|
2100
|
+
*/
|
|
2101
|
+
inProgress: TodoItem | null;
|
|
2102
|
+
/**
|
|
2103
|
+
* Per-status counts. Computed over `todos` when non-empty, else over
|
|
2104
|
+
* `archive`. Zeros only when both are empty. Lets the modal header
|
|
2105
|
+
* show a meaningful tally for the archived "last batch" view.
|
|
2106
|
+
*/
|
|
2107
|
+
tally: TodoTally;
|
|
2108
|
+
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Pick the "active" run for UI surfaces that show one slot at a time
|
|
2111
|
+
* (todos indicator, todos modal, footer ctx indicator). The resolved
|
|
2112
|
+
* runId then routes through {@link getTodosForRun} — top-level runs
|
|
2113
|
+
* land on the session-shared slot, subagent runs on their own.
|
|
2114
|
+
*
|
|
2115
|
+
* - A currently-running run wins (latest-started one if several).
|
|
2116
|
+
* - Otherwise the most recently appended run wins.
|
|
2117
|
+
* - `null` when the session has no runs.
|
|
2118
|
+
*
|
|
2119
|
+
* Mirrors the "most recent thing that mattered" policy that drives
|
|
2120
|
+
* `lastContextSizeFromTurns` — but walks `session.runs` rather than
|
|
2121
|
+
* `session.turns` because the active todo slot is a function of the
|
|
2122
|
+
* run, not of message history.
|
|
2123
|
+
*/
|
|
2124
|
+
declare function pickActiveRunId(session: Session | null | undefined): string | null;
|
|
2125
|
+
/**
|
|
2126
|
+
* Pure selector — derive the active-todos state from a session snapshot.
|
|
2127
|
+
* Used by {@link useActiveTodos} and directly testable without React.
|
|
2128
|
+
*
|
|
2129
|
+
* Resolves both `todos` (live, model-facing) and `archive` (last
|
|
2130
|
+
* non-empty snapshot for UI fallback). The tally folds over whichever
|
|
2131
|
+
* list is non-empty; `inProgress` is sourced strictly from `todos`
|
|
2132
|
+
* because an archived in-progress item is by definition stale.
|
|
2133
|
+
*/
|
|
2134
|
+
declare function selectActiveTodos(session: Session | null | undefined): ActiveTodosState;
|
|
2135
|
+
/**
|
|
2136
|
+
* React hook — active-todos state for the supplied session. Recomputes
|
|
2137
|
+
* on every parent re-render; the work is O(runs + todos), both bounded
|
|
2138
|
+
* by small constants in practice.
|
|
2139
|
+
*
|
|
2140
|
+
* Why no memoization: `Session.runs` is mutated in place by `completeRun`
|
|
2141
|
+
* / `abortRun` (status flips without changing array length or item
|
|
2142
|
+
* identity), so any memo keyed off length / bag identity would silently
|
|
2143
|
+
* return stale state when e.g. a child subagent run completes and the
|
|
2144
|
+
* "active" run should reflow to the parent. The selector is cheap
|
|
2145
|
+
* enough that running it every parent render is the simpler, correct
|
|
2146
|
+
* answer — see `selectActiveTodos` for the O(n) cost.
|
|
2147
|
+
*
|
|
2148
|
+
* The hook lives in `chat/` so a GUI consumer can mount it verbatim.
|
|
2149
|
+
* Renderer-agnostic — no `@opentui/*` imports.
|
|
2150
|
+
*/
|
|
2151
|
+
declare function useActiveTodos(session: Session | null | undefined): ActiveTodosState;
|
|
2152
|
+
//#endregion
|
|
2153
|
+
//#region src/chat/hosts/types.d.ts
|
|
2154
|
+
/**
|
|
2155
|
+
* The client's host registry, as data: the hosts a window can connect to
|
|
2156
|
+
* besides its own (zidane-servers on other machines). Node-free, re-exported
|
|
2157
|
+
* from `zidane/chat/pure` for the GUI renderer.
|
|
2158
|
+
*/
|
|
2159
|
+
/** One saved host. Tokens are not here: see `hostCredentialKey`. */
|
|
2160
|
+
interface HostEntry {
|
|
2161
|
+
/** The server's `hostId` (`ipc.hello`): `add` verifies the host before saving it. */
|
|
2162
|
+
id: string;
|
|
2163
|
+
/** Display name: the one given at `add` or `rename`, else the server's. */
|
|
2164
|
+
name: string;
|
|
2165
|
+
/** `wss://…`, or `ws://` to loopback. */
|
|
2166
|
+
url: string;
|
|
2167
|
+
/** Epoch ms. */
|
|
2168
|
+
addedAt: number;
|
|
2169
|
+
/** Epoch ms of the last successful `add` / `test`. */
|
|
2170
|
+
lastConnectedAt?: number;
|
|
2171
|
+
hostKind?: 'server';
|
|
2172
|
+
/** The server's own name (`hostName`) at the last successful connect. */
|
|
2173
|
+
serverName?: string;
|
|
2174
|
+
/** The server's zidane version at the last successful connect. */
|
|
2175
|
+
serverVersion?: string;
|
|
2176
|
+
}
|
|
2177
|
+
/**
|
|
2178
|
+
* Why a host could not be added or tested:
|
|
2179
|
+
* - `invalid-url`: not `wss://`, or `ws://` off loopback; nothing was dialed.
|
|
2180
|
+
* - `invalid-token`: empty.
|
|
2181
|
+
* - `invalid-name`: an empty name.
|
|
2182
|
+
* - `auth`: the server refused the token (401) or the connection (403).
|
|
2183
|
+
* - `unreachable`: nothing answered (refused, DNS, timeout, closed).
|
|
2184
|
+
* - `tls`: the TLS handshake failed (certificate).
|
|
2185
|
+
* - `protocol`: something answered but not a zidane-server this client can
|
|
2186
|
+
* talk to (protocol version, no host identity, not a server).
|
|
2187
|
+
* - `identity`: a different host answers at the saved URL.
|
|
2188
|
+
* - `unknown-host`: no saved host has this id.
|
|
2189
|
+
*/
|
|
2190
|
+
type HostErrorCode = 'invalid-url' | 'invalid-token' | 'invalid-name' | 'auth' | 'unreachable' | 'tls' | 'protocol' | 'identity' | 'unknown-host';
|
|
2191
|
+
/** The identity a host reports (`hostRefOf(hello)`). */
|
|
2192
|
+
interface HostIdentity {
|
|
2193
|
+
id: string;
|
|
2194
|
+
kind: 'in-process' | 'daemon' | 'server';
|
|
2195
|
+
name: string;
|
|
2196
|
+
}
|
|
2197
|
+
type HostProbeResult = {
|
|
2198
|
+
ok: true;
|
|
2199
|
+
hostRef: HostIdentity;
|
|
2200
|
+
serverVersion?: string;
|
|
2201
|
+
latencyMs: number;
|
|
2202
|
+
} | {
|
|
2203
|
+
ok: false;
|
|
2204
|
+
error: HostErrorCode;
|
|
2205
|
+
message: string;
|
|
2206
|
+
};
|
|
2207
|
+
/** `test(id)`: the probe's answer, checked against the saved entry. */
|
|
2208
|
+
type HostTestResult = HostProbeResult;
|
|
2209
|
+
/** Connects to `url` with `token`, says who answered (or why it failed), disconnects. Never throws. */
|
|
2210
|
+
type HostProbe = (target: {
|
|
2211
|
+
url: string;
|
|
2212
|
+
token: string;
|
|
2213
|
+
}) => Promise<HostProbeResult>;
|
|
2214
|
+
/** A refused `add` / `rename`; `code` says why. */
|
|
2215
|
+
declare class HostRegistryError extends Error {
|
|
2216
|
+
readonly code: HostErrorCode;
|
|
2217
|
+
constructor(code: HostErrorCode, message: string);
|
|
2218
|
+
}
|
|
2219
|
+
//#endregion
|
|
2220
|
+
//#region src/chat/hosts/url.d.ts
|
|
2221
|
+
declare class RemoteHostError extends Error {
|
|
2222
|
+
constructor(message: string);
|
|
2223
|
+
}
|
|
2224
|
+
/** Scheme, host, port and path of a URL (token-looking path segments redacted): what is safe to show or log. */
|
|
2225
|
+
declare function displayHostUrl(raw: string): string;
|
|
2226
|
+
/** Validate and normalize a host URL (no trailing slash); throws {@link RemoteHostError}. */
|
|
2227
|
+
declare function parseRemoteHostUrl(raw: string): string;
|
|
2228
|
+
//#endregion
|
|
2229
|
+
//#region src/chat/markdown-segments.d.ts
|
|
2230
|
+
/**
|
|
2231
|
+
* One block returned by {@link splitMarkdownCodeBlocks}. Prose segments
|
|
2232
|
+
* carry their original markdown (including blank lines that bracketed
|
|
2233
|
+
* the fence) so the surrounding paragraph spacing stays faithful to the
|
|
2234
|
+
* original input. Code segments carry the raw body — fence markers and
|
|
2235
|
+
* info-string stripped — so a "copy code" action lands what the user
|
|
2236
|
+
* actually sees, byte-for-byte.
|
|
2237
|
+
*/
|
|
2238
|
+
interface MarkdownSegment {
|
|
2239
|
+
kind: 'prose' | 'code';
|
|
2240
|
+
content: string;
|
|
2241
|
+
/** Info-string (e.g. `ts`, `python`). Empty when the fence had none. */
|
|
2242
|
+
lang?: string;
|
|
2243
|
+
/**
|
|
2244
|
+
* `true` on a code segment whose closing fence hasn't arrived yet —
|
|
2245
|
+
* i.e. the trailing block during streaming. Consumers can render this
|
|
2246
|
+
* in "streaming" mode (no copy affordance, partial-highlight pipeline)
|
|
2247
|
+
* until the closer lands and it flips to a regular closed segment.
|
|
2248
|
+
*/
|
|
2249
|
+
open?: boolean;
|
|
2250
|
+
}
|
|
2251
|
+
/**
|
|
2252
|
+
* Split markdown text into alternating prose / fenced-code segments.
|
|
2253
|
+
*
|
|
2254
|
+
* Recognizes both ` ``` ` and `~~~` fences, with arbitrary length ≥ 3,
|
|
2255
|
+
* matching CommonMark's "fence indicator must be at least as long to
|
|
2256
|
+
* close" rule. Info-strings (the bit after the opening fence) are kept
|
|
2257
|
+
* as the `lang` hint; any trailing whitespace is trimmed. Closing
|
|
2258
|
+
* fences are detected on a line of their own (whitespace tolerated).
|
|
2259
|
+
*
|
|
2260
|
+
* Unclosed fences fall back to emitting the would-be-code body as a
|
|
2261
|
+
* trailing prose segment so no content is dropped — finalized markdown
|
|
2262
|
+
* isn't expected to ship one, but the fallback keeps the renderer
|
|
2263
|
+
* truthful when the model produces malformed output.
|
|
2264
|
+
*
|
|
2265
|
+
* Exported for unit tests.
|
|
2266
|
+
*/
|
|
2267
|
+
declare function splitMarkdownCodeBlocks(text: string): MarkdownSegment[];
|
|
2268
|
+
/**
|
|
2269
|
+
* Lift indented fenced code blocks to column 0 while preserving the code
|
|
2270
|
+
* body's relative indentation.
|
|
2271
|
+
*
|
|
2272
|
+
* OpenTUI's markdown renderNode hook only receives top-level code tokens.
|
|
2273
|
+
* A common assistant shape is:
|
|
2274
|
+
*
|
|
2275
|
+
* - Run this:
|
|
2276
|
+
* ```bash
|
|
2277
|
+
* command
|
|
2278
|
+
* ```
|
|
2279
|
+
*
|
|
2280
|
+
* Marked parses that as code inside a list token, so the TUI loses the
|
|
2281
|
+
* code-panel wrapper and copy affordance. Normalizing just the fence's list
|
|
2282
|
+
* indentation keeps the prose readable while routing the snippet through
|
|
2283
|
+
* the same top-level renderer as ordinary fences.
|
|
2284
|
+
*/
|
|
2285
|
+
declare function normalizeMarkdownCodeFences(text: string): string;
|
|
2286
|
+
/**
|
|
2287
|
+
* Default per-chunk target for {@link chunkMarkdownForRender}. Chosen from
|
|
2288
|
+
* measurement: marked's lexer (which OpenTUI's `<markdown>` runs
|
|
2289
|
+
* internally) is O(n²) over paragraph-heavy input — ~500ms at 64KiB,
|
|
2290
|
+
* ~2s at 128KiB, ~6s at 256KiB on an M-series laptop — while staying
|
|
2291
|
+
* comfortably in the linear zone below ~32KiB (≤ ~200ms). Chunking a
|
|
2292
|
+
* large document into ≤24KiB pieces keeps the total render linear in
|
|
2293
|
+
* document size with a small constant.
|
|
2294
|
+
*/
|
|
2295
|
+
declare const MARKDOWN_RENDER_CHUNK_TARGET_BYTES = 24576;
|
|
2296
|
+
/**
|
|
2297
|
+
* Split a large markdown document into render-safe chunks at blank-line
|
|
2298
|
+
* boundaries outside code fences, each roughly `targetBytes` long.
|
|
2299
|
+
*
|
|
2300
|
+
* Rendering the chunks as SIBLING markdown renderables (with a one-row
|
|
2301
|
+
* gap standing in for the consumed blank line) is visually equivalent to
|
|
2302
|
+
* one renderable, but sidesteps the quadratic lexer cost documented on
|
|
2303
|
+
* {@link MARKDOWN_RENDER_CHUNK_TARGET_BYTES}. Chunk boundaries are
|
|
2304
|
+
* prefix-stable: appending text (streaming) can only ever change the
|
|
2305
|
+
* LAST chunk, so keyed-by-index consumers reconcile cheaply.
|
|
2306
|
+
*
|
|
2307
|
+
* Returns `[text]` untouched for anything at or under the target.
|
|
2308
|
+
*/
|
|
2309
|
+
declare function chunkMarkdownForRender(text: string, targetBytes?: number): string[];
|
|
2310
|
+
//#endregion
|
|
2311
|
+
//#region src/chat/mcp-allowlist.d.ts
|
|
2312
|
+
/**
|
|
2313
|
+
* Edits to the `enabledMcps` allowlist. Without an explicit list every
|
|
2314
|
+
* server is on, so there is nothing to change. Servers that merely appear
|
|
2315
|
+
* in a config file stay off once a list exists (they don't opt in
|
|
2316
|
+
* silently); a server the user adds in Settings is turned on with it.
|
|
2317
|
+
*/
|
|
2318
|
+
/** The list with `name` turned on, or `undefined` when it already is. */
|
|
2319
|
+
declare function enabledMcpsWith(list: readonly string[] | undefined, name: string): string[] | undefined;
|
|
2320
|
+
/** The list without `name`, or `undefined` when it isn't listed. */
|
|
2321
|
+
declare function enabledMcpsWithout(list: readonly string[] | undefined, name: string): string[] | undefined;
|
|
2322
|
+
//#endregion
|
|
2323
|
+
//#region src/chat/mcp-auth-state.d.ts
|
|
2324
|
+
/**
|
|
2325
|
+
* Per-server MCP OAuth status tracking, decoupled from the renderer.
|
|
2326
|
+
*
|
|
2327
|
+
* The TUI keeps a `Record<serverName, McpAuthStatus>` so it can render a
|
|
2328
|
+
* "needs-auth" / "authorizing" / "error" badge in the MCP picker. The
|
|
2329
|
+
* status map is driven entirely by hooks fired from the agent's MCP
|
|
2330
|
+
* bootstrap + the interactive `loginMcpServer` flow — the reducer below
|
|
2331
|
+
* is pure, makes no FS or network calls, and is shared between the live
|
|
2332
|
+
* TUI store and the test harness.
|
|
2333
|
+
*
|
|
2334
|
+
* Status lifecycle:
|
|
2335
|
+
*
|
|
2336
|
+
* idle ──mcp:connect──▶ authed
|
|
2337
|
+
* (bootstrap succeeded with stored tokens)
|
|
2338
|
+
*
|
|
2339
|
+
* idle ──mcp:auth:required──▶ needs-auth
|
|
2340
|
+
* (bootstrap saw no/invalid tokens)
|
|
2341
|
+
*
|
|
2342
|
+
* idle ──401/403, no key of its own──▶ needs-auth (reason 'refused')
|
|
2343
|
+
* idle ──401/403 on its own header key──▶ key-refused
|
|
2344
|
+
* (see `classifyMcpTest`)
|
|
2345
|
+
*
|
|
2346
|
+
* needs-auth ──login()──▶ authorizing ──mcp:auth:url──▶ authorizing(url)
|
|
2347
|
+
* ──mcp:auth:success──▶ authed
|
|
2348
|
+
* ──mcp:auth:error──▶ error
|
|
2349
|
+
*
|
|
2350
|
+
* any ──logout──▶ idle
|
|
2351
|
+
*
|
|
2352
|
+
* Multiple servers progress through the lifecycle independently; the map
|
|
2353
|
+
* is keyed by `McpServerConfig.name`.
|
|
2354
|
+
*/
|
|
2355
|
+
type McpAuthStatus = {
|
|
2356
|
+
kind: 'idle';
|
|
2357
|
+
} | {
|
|
2358
|
+
kind: 'needs-auth';
|
|
2359
|
+
reason: McpNeedsAuthReason;
|
|
2360
|
+
} | {
|
|
2361
|
+
kind: 'authorizing';
|
|
2362
|
+
url?: string;
|
|
2363
|
+
} | {
|
|
2364
|
+
kind: 'authed';
|
|
2365
|
+
} | {
|
|
2366
|
+
kind: 'error';
|
|
2367
|
+
error: string;
|
|
2368
|
+
} | {
|
|
2369
|
+
kind: 'bootstrap-error';
|
|
2370
|
+
error: string;
|
|
2371
|
+
} | {
|
|
2372
|
+
kind: 'key-refused';
|
|
2373
|
+
error: string;
|
|
2374
|
+
};
|
|
2375
|
+
type McpNeedsAuthReason = 'no-tokens' | 'auto-promoted' | 'refused';
|
|
2376
|
+
/**
|
|
2377
|
+
* The status words both apps show for a server, so the desktop app's badge
|
|
2378
|
+
* and the TUI's read the same. `idle` says nothing.
|
|
2379
|
+
*/
|
|
2380
|
+
declare const MCP_STATUS_LABEL: Readonly<Record<Exclude<McpAuthStatus['kind'], 'idle'>, string>>;
|
|
2381
|
+
/**
|
|
2382
|
+
* Map of server name → status. `idle` is the implicit default for any
|
|
2383
|
+
* server NOT present in the map, so the renderer treats `undefined` as
|
|
2384
|
+
* `{ kind: 'idle' }` and the map can stay sparse.
|
|
2385
|
+
*/
|
|
2386
|
+
type McpAuthStateMap = Readonly<Record<string, McpAuthStatus>>;
|
|
2387
|
+
/**
|
|
2388
|
+
* Events the reducer accepts. Names mirror the agent hooks 1:1 plus two
|
|
2389
|
+
* UI-only verbs (`login:start` / `login:cancel`) so the renderer can
|
|
2390
|
+
* optimistically flip a row to `authorizing` before the SDK has emitted
|
|
2391
|
+
* `mcp:auth:url` — useful when the loopback callback is slow to bind.
|
|
2392
|
+
*/
|
|
2393
|
+
type McpAuthEvent = {
|
|
2394
|
+
type: 'auth-required';
|
|
2395
|
+
name: string;
|
|
2396
|
+
reason: McpNeedsAuthReason;
|
|
2397
|
+
} | {
|
|
2398
|
+
type: 'auth-url';
|
|
2399
|
+
name: string;
|
|
2400
|
+
url: string;
|
|
2401
|
+
} | {
|
|
2402
|
+
type: 'auth-success';
|
|
2403
|
+
name: string;
|
|
2404
|
+
} | {
|
|
2405
|
+
type: 'auth-error';
|
|
2406
|
+
name: string;
|
|
2407
|
+
error: string;
|
|
2408
|
+
} | {
|
|
2409
|
+
type: 'bootstrap-error';
|
|
2410
|
+
name: string;
|
|
2411
|
+
error: string;
|
|
2412
|
+
} | {
|
|
2413
|
+
type: 'key-refused';
|
|
2414
|
+
name: string;
|
|
2415
|
+
error: string;
|
|
2416
|
+
} | {
|
|
2417
|
+
type: 'connected';
|
|
2418
|
+
name: string;
|
|
2419
|
+
} | {
|
|
2420
|
+
type: 'login:start';
|
|
2421
|
+
name: string;
|
|
2422
|
+
} | {
|
|
2423
|
+
type: 'login:cancel';
|
|
2424
|
+
name: string;
|
|
2425
|
+
} | {
|
|
2426
|
+
type: 'logout';
|
|
2427
|
+
name: string;
|
|
2428
|
+
} | {
|
|
2429
|
+
type: 'reset';
|
|
2430
|
+
name: string;
|
|
2431
|
+
};
|
|
2432
|
+
/**
|
|
2433
|
+
* Apply one event to the state map. Pure, immutable — returns a new map
|
|
2434
|
+
* with only the affected key reassigned.
|
|
2435
|
+
*
|
|
2436
|
+
* State transitions are simple "last write wins"; we don't gate (e.g.) a
|
|
2437
|
+
* `login:start` from overriding `authorizing` because the loop layer
|
|
2438
|
+
* never doubles those up — interactive login is serialized in the TUI.
|
|
2439
|
+
*/
|
|
2440
|
+
declare function reduceMcpAuth(state: McpAuthStateMap, event: McpAuthEvent): McpAuthStateMap;
|
|
2441
|
+
/**
|
|
2442
|
+
* The status a failed connection leaves, from `classifyMcpTest`'s answer
|
|
2443
|
+
* (never called with `ok`: a connection that worked leaves no failure).
|
|
2444
|
+
* A server that asked for OAuth keeps "sign-in failed" for an unexplained
|
|
2445
|
+
* failure (its tokens are the likely cause, and sign-in stays offered).
|
|
2446
|
+
*/
|
|
2447
|
+
declare function mcpFailureEvent(name: string, outcome: {
|
|
2448
|
+
kind: 'ok' | 'needs-auth' | 'token-rejected' | 'error';
|
|
2449
|
+
message?: string;
|
|
2450
|
+
}, oauthTagged: boolean): McpAuthEvent;
|
|
2451
|
+
/** Convenience getter — treats `undefined` as `idle`. */
|
|
2452
|
+
declare function getMcpAuthStatus(state: McpAuthStateMap, name: string): McpAuthStatus;
|
|
2453
|
+
//#endregion
|
|
2454
|
+
//#region src/chat/mcp-test-outcome.d.ts
|
|
2455
|
+
type McpTestOutcomeKind = 'ok' | 'needs-auth' | 'token-rejected' | 'error';
|
|
2456
|
+
interface McpTestResult {
|
|
2457
|
+
kind: McpTestOutcomeKind;
|
|
2458
|
+
tools?: number;
|
|
2459
|
+
message?: string;
|
|
2460
|
+
}
|
|
2461
|
+
/** What to do about a refused key, under the "Key refused" headline. */
|
|
2462
|
+
declare const MCP_KEY_REFUSED_HINT = "Check the headers in mcps.json.";
|
|
2463
|
+
/** A refusal for want of credentials: HTTP 401 / 403, however the SDK words it. */
|
|
2464
|
+
declare function isMcpAuthRefusal(error: unknown): boolean;
|
|
2465
|
+
/** The first line of a failure, never empty. */
|
|
2466
|
+
declare function mcpFailureLine(error: unknown): string;
|
|
2467
|
+
declare function classifyMcpTest(config: Pick<McpServerConfig, 'transport' | 'headers'>, result: {
|
|
2468
|
+
authRequired: boolean;
|
|
2469
|
+
error?: unknown;
|
|
2470
|
+
tools?: number;
|
|
2471
|
+
}): McpTestResult;
|
|
2472
|
+
//#endregion
|
|
2473
|
+
//#region src/chat/model-catalog.d.ts
|
|
2474
|
+
/** A model entry as displayed in the cross-provider picker. */
|
|
2475
|
+
interface CatalogEntry {
|
|
2476
|
+
providerKey: ProviderKey;
|
|
2477
|
+
providerLabel: string;
|
|
2478
|
+
model: ModelInfo;
|
|
2479
|
+
/**
|
|
2480
|
+
* The provider does not (or no longer) list this model: the entry was
|
|
2481
|
+
* synthesized from an `include` pair, so `model` is a stub carrying the id
|
|
2482
|
+
* and nothing else. Renderers should say so rather than print stub
|
|
2483
|
+
* metadata as if it were real.
|
|
2484
|
+
*/
|
|
2485
|
+
offCatalog?: boolean;
|
|
2486
|
+
/**
|
|
2487
|
+
* Pre-computed lowercase corpus for substring search across the
|
|
2488
|
+
* provider key, label, model id, and display name. Built once at
|
|
2489
|
+
* catalog-assembly time so filtering on every keystroke is
|
|
2490
|
+
* O(catalogSize × queryLength), not O(catalogSize × fieldCount ×
|
|
2491
|
+
* lowercase-overhead × queryLength).
|
|
2492
|
+
*/
|
|
2493
|
+
searchCorpus: string;
|
|
2494
|
+
}
|
|
2495
|
+
/**
|
|
2496
|
+
* Build the unified catalog from a list of available providers.
|
|
2497
|
+
*
|
|
2498
|
+
* Provider order is preserved (callers typically pass the picker order
|
|
2499
|
+
* — alphabetical, auth-detection order, etc.); model order inside each
|
|
2500
|
+
* provider matches whatever `modelsFor` returns. The current selection
|
|
2501
|
+
* (when set) is bubbled to the top of its provider's section so it
|
|
2502
|
+
* shows first without disturbing relative ordering elsewhere.
|
|
2503
|
+
*
|
|
2504
|
+
* `modelsFor` is injected (not imported from `./providers`) so the same
|
|
2505
|
+
* helper works with hosts that supply their own model resolver via
|
|
2506
|
+
* `ResolvedConfig.modelsFor`.
|
|
2507
|
+
*
|
|
2508
|
+
* `include` guarantees a pair is listed even when the provider stopped
|
|
2509
|
+
* serving it. Persisted picks outlive catalogs (a provider retires an id, a
|
|
2510
|
+
* user typed one by hand), and an entry that isn't in the list can't be
|
|
2511
|
+
* selected away from, and the picker would keep re-persisting it. Synthesized
|
|
2512
|
+
* entries carry `offCatalog: true` and a stub `ModelInfo`.
|
|
2513
|
+
*/
|
|
2514
|
+
declare function buildModelCatalog(opts: {
|
|
2515
|
+
providers: readonly ProviderAuth[];
|
|
2516
|
+
modelsFor: (key: ProviderKey) => readonly ModelInfo[];
|
|
2517
|
+
/** Optional currently-selected pair — promoted to the top of its provider group. */
|
|
2518
|
+
current?: {
|
|
2519
|
+
providerKey: ProviderKey;
|
|
2520
|
+
modelId: string;
|
|
2521
|
+
} | null;
|
|
2522
|
+
/** Pairs that must appear even if unserved, e.g. the active pick + fallback chain. */
|
|
2523
|
+
include?: readonly {
|
|
2524
|
+
providerKey: ProviderKey;
|
|
2525
|
+
modelId: string;
|
|
2526
|
+
}[];
|
|
2527
|
+
}): CatalogEntry[];
|
|
2528
|
+
/**
|
|
2529
|
+
* Filter `catalog` by a user query. Empty / whitespace-only queries
|
|
2530
|
+
* pass everything through unchanged (`O(1)` short-circuit). Multi-term
|
|
2531
|
+
* queries (space-separated) require EVERY term to appear somewhere in
|
|
2532
|
+
* the entry's search corpus — so `"claude opus"` matches `claude-opus-4`
|
|
2533
|
+
* regardless of how the words are interleaved with provider names.
|
|
2534
|
+
*
|
|
2535
|
+
* Match is case-insensitive (the corpus is pre-lowercased; the query
|
|
2536
|
+
* is lowercased once per call).
|
|
2537
|
+
*/
|
|
2538
|
+
declare function filterModelCatalog(catalog: readonly CatalogEntry[], query: string): CatalogEntry[];
|
|
2539
|
+
/**
|
|
2540
|
+
* Find a catalog entry's index by its `{providerKey, modelId}` tuple.
|
|
2541
|
+
* Returns `-1` when not present. Useful when re-rendering the picker
|
|
2542
|
+
* (a query just narrowed the list, where did the selection land?).
|
|
2543
|
+
*/
|
|
2544
|
+
declare function indexOfEntry(catalog: readonly CatalogEntry[], target: {
|
|
2545
|
+
providerKey: ProviderKey;
|
|
2546
|
+
modelId: string;
|
|
2547
|
+
} | null | undefined): number;
|
|
2548
|
+
/**
|
|
2549
|
+
* Read a query that matched nothing as "use this model id anyway".
|
|
2550
|
+
*
|
|
2551
|
+
* A bare id is meaningless without a provider, so the first term is checked
|
|
2552
|
+
* against every provider's key and label (case-insensitive): `xai grok-9` and
|
|
2553
|
+
* `Anthropic claude-next` name their provider explicitly, anything else is
|
|
2554
|
+
* attributed to `fallbackProviderKey` (the picker's current pick). Returns
|
|
2555
|
+
* `null` when nothing usable is left, including when the whole query is just a
|
|
2556
|
+
* provider name.
|
|
2557
|
+
*/
|
|
2558
|
+
declare function parseCustomModelQuery(query: string, providers: readonly Pick<ProviderAuth, 'key' | 'label'>[], fallbackProviderKey: ProviderKey | null): CustomModelTarget | null;
|
|
2559
|
+
interface CustomModelTarget {
|
|
2560
|
+
providerKey: ProviderKey;
|
|
2561
|
+
providerLabel: string;
|
|
2562
|
+
modelId: string;
|
|
2563
|
+
/** The query named this provider (`xai grok-9`). */
|
|
2564
|
+
named?: boolean;
|
|
2565
|
+
}
|
|
2566
|
+
/**
|
|
2567
|
+
* Every route for a typed model id, one per provider: the provider the query
|
|
2568
|
+
* names first (`xai grok-9`), then `fallbackProviderKey` (the current pick),
|
|
2569
|
+
* then the rest in the given order. Lets a picker offer "use this id via…"
|
|
2570
|
+
* for each signed-in provider instead of guessing one. Empty when the query
|
|
2571
|
+
* names no model id.
|
|
2572
|
+
*/
|
|
2573
|
+
declare function customModelTargets(query: string, providers: readonly Pick<ProviderAuth, 'key' | 'label'>[], fallbackProviderKey: ProviderKey | null): CustomModelTarget[];
|
|
2574
|
+
//#endregion
|
|
2575
|
+
//#region src/chat/model-lineup.d.ts
|
|
2576
|
+
/** Parsed shape of a model id. Exported for tests and for pickers that want to show a family label. */
|
|
2577
|
+
interface ModelIdParts {
|
|
2578
|
+
/** `vendor/` prefix on aggregator ids (`anthropic` in `anthropic/claude-opus-5`), lowercased; '' when absent. */
|
|
2579
|
+
vendor: string;
|
|
2580
|
+
/** The words of the id, lowercased and joined with `-`. */
|
|
2581
|
+
family: string;
|
|
2582
|
+
/** Numeric version segments in order; empty when the id carries none. */
|
|
2583
|
+
version: number[];
|
|
2584
|
+
/** Size tokens joined with `-` (`27b`, `235b-a22b`); '' when absent. */
|
|
2585
|
+
size: string;
|
|
2586
|
+
/** Dated / numbered snapshot (`20251001`, `2024-05-13` → `20240513`, `0731`); '' for the plain alias. */
|
|
2587
|
+
snapshot: string;
|
|
2588
|
+
/** Routing variant after `:` (`batch`, `free`); '' when absent. */
|
|
2589
|
+
variant: string;
|
|
2590
|
+
}
|
|
2591
|
+
declare function parseModelId(id: string): ModelIdParts;
|
|
2592
|
+
/** Numeric, segment by segment; a longer version wins a tie on the shared prefix (`5.5` > `5`). */
|
|
2593
|
+
declare function compareModelVersion(a: readonly number[], b: readonly number[]): number;
|
|
2594
|
+
interface LineupEntry {
|
|
2595
|
+
providerKey: string;
|
|
2596
|
+
modelId: string;
|
|
2597
|
+
}
|
|
2598
|
+
/**
|
|
2599
|
+
* Keys (`provider\0model`) of the current models: per provider and family,
|
|
2600
|
+
* the newest version, one entry per size. `keep` entries (the active model,
|
|
2601
|
+
* fallback chain, off-catalog ids) are always included.
|
|
2602
|
+
*/
|
|
2603
|
+
declare function currentModelKeys(entries: readonly LineupEntry[], keep?: readonly LineupEntry[]): Set<string>;
|
|
2604
|
+
/** `entries` in their original order, current models only (see {@link currentModelKeys}). */
|
|
2605
|
+
declare function currentModels<T extends LineupEntry>(entries: readonly T[], keep?: readonly LineupEntry[]): T[];
|
|
2606
|
+
//#endregion
|
|
2607
|
+
//#region src/chat/prompt-segments.d.ts
|
|
2608
|
+
/**
|
|
2609
|
+
* Pure string + reference math for rendering a submitted prompt with chip
|
|
2610
|
+
* pills around completion references. Renderer-agnostic — the TUI walks
|
|
2611
|
+
* the segments into OpenTUI `<text>` nodes, a GUI walks them into JSX
|
|
2612
|
+
* spans + `<span class="chip">` pills. No layout engine assumptions.
|
|
2613
|
+
*/
|
|
2614
|
+
/**
|
|
2615
|
+
* Highlight span — half-open `[start, end)` over the source string.
|
|
2616
|
+
*
|
|
2617
|
+
* Offsets are JS string indices (UTF-16 code units) — the same convention used
|
|
2618
|
+
* everywhere else in the chat layer (`text[i]`, `m.index`, `String.slice`).
|
|
2619
|
+
* Surrogate pairs that straddle a span boundary would render malformed, but
|
|
2620
|
+
* realistic prompts in this surface (terminal text + ASCII triggers) keep that
|
|
2621
|
+
* risk theoretical; callers feeding emoji-heavy content should normalize to
|
|
2622
|
+
* codepoint walks upstream.
|
|
2623
|
+
*/
|
|
2624
|
+
interface PromptSegmentRef {
|
|
2625
|
+
start: number;
|
|
2626
|
+
end: number;
|
|
2627
|
+
/** Provider id tagging this span (`'skills'`, `'files'`, …). Free-form. */
|
|
2628
|
+
providerId: string;
|
|
2629
|
+
}
|
|
2630
|
+
/**
|
|
2631
|
+
* One atomic unit emitted by {@link splitPromptSegments}. Plain segments
|
|
2632
|
+
* are word-sized so wraps land cleanly between words; chip segments
|
|
2633
|
+
* carry the source `providerId` (`'skills'`, `'files'`, …) so renderers
|
|
2634
|
+
* can pick per-kind colors without re-walking the ref list.
|
|
2635
|
+
*/
|
|
2636
|
+
type PromptSegment = {
|
|
2637
|
+
kind: 'plain';
|
|
2638
|
+
text: string;
|
|
2639
|
+
} | {
|
|
2640
|
+
kind: 'chip';
|
|
2641
|
+
text: string;
|
|
2642
|
+
providerId: string;
|
|
2643
|
+
};
|
|
2644
|
+
/**
|
|
2645
|
+
* Split a prompt buffer into word-sized atomic segments suitable for a
|
|
2646
|
+
* flex-row + flex-wrap renderer (TUI) or a `display: inline` flow with
|
|
2647
|
+
* inline-block chips (GUI). Each chip becomes one segment (atomic —
|
|
2648
|
+
* never broken across rows); each plain run is split into "word +
|
|
2649
|
+
* trailing space" units so wraps land at clean word boundaries.
|
|
2650
|
+
*
|
|
2651
|
+
* Robust to:
|
|
2652
|
+
* - Overlapping refs — sorted by start; later refs that overlap are
|
|
2653
|
+
* dropped via the first-wins rule.
|
|
2654
|
+
* - Out-of-bounds refs — dropped entirely when `end > text.length` or
|
|
2655
|
+
* `start >= text.length`. Partial clipping would silently truncate
|
|
2656
|
+
* a chip's label; the caller is in a better position to surface the
|
|
2657
|
+
* mismatch (typically a stale `refs` array referencing a previous text).
|
|
2658
|
+
* - Whitespace-only plain runs — emitted as their own plain segment
|
|
2659
|
+
* so chip-adjacent-to-chip cases keep the original spacing.
|
|
2660
|
+
*
|
|
2661
|
+
* Word splitter rationale: `\S+\s*` keeps trailing whitespace attached
|
|
2662
|
+
* to its preceding word so wrap boundaries land between words (cleanly).
|
|
2663
|
+
* A leading-whitespace-only segment is captured by `\s+` so we don't
|
|
2664
|
+
* drop it entirely when the plain run starts with a space.
|
|
2665
|
+
*/
|
|
2666
|
+
declare function splitPromptSegments(text: string, refs: readonly PromptSegmentRef[]): PromptSegment[];
|
|
2667
|
+
/**
|
|
2668
|
+
* File-mention refs recovered from a prompt's text: `@<path>` at the start
|
|
2669
|
+
* or after whitespace, where the path looks like one (has a `/` or a `.`),
|
|
2670
|
+
* trailing punctuation excluded (the files completion's own rule).
|
|
2671
|
+
*
|
|
2672
|
+
* Refs are known only to the client that sent the prompt, which typed the
|
|
2673
|
+
* mention through a completion. The persisted turn and the send echo other
|
|
2674
|
+
* windows receive carry the text alone, so without this a prompt's chips
|
|
2675
|
+
* existed in the sender's live transcript only: gone after a reload, never
|
|
2676
|
+
* shown in another window or the TUI. Replay and the echo fill refs from
|
|
2677
|
+
* this when the event has none, so every client paints the same prompt.
|
|
2678
|
+
* Skills and chats mentions are not inferred: their tokens (`/name`,
|
|
2679
|
+
* `#token`) are ordinary text too often to guess without the catalogs.
|
|
2680
|
+
*/
|
|
2681
|
+
declare function inferPromptRefs(text: string): PromptSegmentRef[];
|
|
2682
|
+
/**
|
|
2683
|
+
* The segments cut into the lines the user typed. A flex-wrap row cannot
|
|
2684
|
+
* break on a newline inside one of its items, so each line renders as its
|
|
2685
|
+
* own row; an empty array is a blank line.
|
|
2686
|
+
*/
|
|
2687
|
+
declare function promptSegmentLines(segments: readonly PromptSegment[]): PromptSegment[][];
|
|
2688
|
+
//#endregion
|
|
2689
|
+
//#region src/chat/provider-usage-format.d.ts
|
|
2690
|
+
/**
|
|
2691
|
+
* Node-free half of provider usage: the wire types and the two presentation
|
|
2692
|
+
* helpers every surface needs to RENDER a snapshot.
|
|
2693
|
+
*
|
|
2694
|
+
* Split out of `provider-usage.ts` because that module reads
|
|
2695
|
+
* `credentials.json` and so cannot be reached from `zidane/chat/pure`. The
|
|
2696
|
+
* Electron renderer receives snapshots over IPC (main does the fetching) and
|
|
2697
|
+
* must draw them with the same rounding and the same "which window bites
|
|
2698
|
+
* first" rule as the TUI — a renderer that re-derived either would be the
|
|
2699
|
+
* duplication that let the TUI and GUI report different facts about one event.
|
|
2700
|
+
*
|
|
2701
|
+
* `provider-usage.ts` re-exports everything here, so existing importers keep
|
|
2702
|
+
* their single import.
|
|
2703
|
+
*/
|
|
2704
|
+
/** One rate-limit window on a subscription (e.g. "5h", "weekly"). */
|
|
2705
|
+
interface ProviderUsageWindow {
|
|
2706
|
+
/** Stable id from the provider, used as a React / list key. */
|
|
2707
|
+
id: string;
|
|
2708
|
+
/** Human label as the provider names it. */
|
|
2709
|
+
label: string;
|
|
2710
|
+
/** 0..100, may be fractional. */
|
|
2711
|
+
usedPercent: number;
|
|
2712
|
+
/** Epoch ms when the window resets, or `null` when the provider omits it. */
|
|
2713
|
+
resetsAt: number | null;
|
|
2714
|
+
}
|
|
2715
|
+
/** Remaining credits for pay-as-you-go style providers. */
|
|
2716
|
+
interface ProviderUsageCredits {
|
|
2717
|
+
remaining: number;
|
|
2718
|
+
total: number | null;
|
|
2719
|
+
}
|
|
2720
|
+
type ProviderUsageStatus = 'ok' | 'unauthorized' | 'unavailable';
|
|
2721
|
+
interface ProviderUsageSnapshot {
|
|
2722
|
+
/** Registry key (`anthropic`, `openai`, …). */
|
|
2723
|
+
providerKey: string;
|
|
2724
|
+
/** Display label for the provider. */
|
|
2725
|
+
label: string;
|
|
2726
|
+
/**
|
|
2727
|
+
* Credentials-file key of the credential this snapshot was probed with. A
|
|
2728
|
+
* provider holding several OAuth accounts yields one snapshot per account;
|
|
2729
|
+
* this is what tells them apart (and the stable list key).
|
|
2730
|
+
*/
|
|
2731
|
+
credentialKey: string;
|
|
2732
|
+
/**
|
|
2733
|
+
* Account name for OAuth-backed snapshots (`Default`, `work`, …); `null` for
|
|
2734
|
+
* API-key probes. Surfaces show it only when the provider has more than one
|
|
2735
|
+
* snapshot, so a single-account provider stays as quiet as before.
|
|
2736
|
+
*/
|
|
2737
|
+
account: string | null;
|
|
2738
|
+
/** True when this credential is the one requests use (the canonical slot). */
|
|
2739
|
+
activeCredential: boolean;
|
|
2740
|
+
status: ProviderUsageStatus;
|
|
2741
|
+
/** Plan name when the provider reports one. */
|
|
2742
|
+
plan: string | null;
|
|
2743
|
+
windows: readonly ProviderUsageWindow[];
|
|
2744
|
+
credits: ProviderUsageCredits | null;
|
|
2745
|
+
fetchedAt: number;
|
|
2746
|
+
error: string | null;
|
|
2747
|
+
}
|
|
2748
|
+
/**
|
|
2749
|
+
* Whether a snapshot should show its account name: only when another snapshot
|
|
2750
|
+
* in the same list belongs to the same provider. One account is the provider.
|
|
2751
|
+
*/
|
|
2752
|
+
declare function showsAccount(snapshot: ProviderUsageSnapshot, all: readonly ProviderUsageSnapshot[]): boolean;
|
|
2753
|
+
/**
|
|
2754
|
+
* The snapshot the footer indicator shows for a provider: the one probed with
|
|
2755
|
+
* the credential requests use, else the first reported. `null` when none.
|
|
2756
|
+
*/
|
|
2757
|
+
declare function activeSnapshotFor(all: readonly ProviderUsageSnapshot[], providerKey: string): ProviderUsageSnapshot | null;
|
|
2758
|
+
/**
|
|
2759
|
+
* The window closest to its ceiling, which is the one that will bite first and
|
|
2760
|
+
* the only one a single-line indicator has room for. `null` when the snapshot
|
|
2761
|
+
* carries no windows.
|
|
2762
|
+
*/
|
|
2763
|
+
declare function mostConstrainedWindow(snapshot: ProviderUsageSnapshot): ProviderUsageWindow | null;
|
|
2764
|
+
/**
|
|
2765
|
+
* Percent for display: integers print bare, fractions keep one decimal (so a
|
|
2766
|
+
* status bar never reads `100%` for `99.9`).
|
|
2767
|
+
*/
|
|
2768
|
+
declare function formatUsagePercent(usedPercent: number): string;
|
|
2769
|
+
/**
|
|
2770
|
+
* Severity tone for a usage percent. `error` ≥ 85, `warn` ≥ 60, else `ok`.
|
|
2771
|
+
* Surfaces map tones to their own palette.
|
|
2772
|
+
*/
|
|
2773
|
+
type UsageTone = 'ok' | 'warn' | 'error';
|
|
2774
|
+
declare function usageTone(usedPercent: number): UsageTone;
|
|
2775
|
+
/**
|
|
2776
|
+
* Time to reset, coarsened to whole days past 24h. `null` when the provider
|
|
2777
|
+
* reported no reset, `resetting` once it is due.
|
|
2778
|
+
*
|
|
2779
|
+
* Every step rounds DOWN, like the percent: 36h reads as `1d`, not `2d`.
|
|
2780
|
+
* Overstating the headroom left on a window is the wrong direction to be
|
|
2781
|
+
* wrong in.
|
|
2782
|
+
*/
|
|
2783
|
+
declare function resetLabel(resetsAt: number | null, now?: number): string | null;
|
|
2784
|
+
/**
|
|
2785
|
+
* `updated 12s ago` / `updated 3m ago` for the newest snapshot in a list, so a
|
|
2786
|
+
* refresh that returns identical numbers is still visibly a refresh. `null`
|
|
2787
|
+
* when the list is empty.
|
|
2788
|
+
*/
|
|
2789
|
+
declare function updatedLabel(snapshots: readonly ProviderUsageSnapshot[], now?: number): string | null;
|
|
2790
|
+
/** Balances are dollars for OpenRouter and opaque units elsewhere. */
|
|
2791
|
+
declare function formatCredits(value: number): string;
|
|
2792
|
+
/** `20.00 / 25.00`, or just the remainder when no total is reported. */
|
|
2793
|
+
declare function formatBalance(credits: ProviderUsageCredits): string;
|
|
2794
|
+
//#endregion
|
|
2795
|
+
//#region src/chat/settings-defaults.d.ts
|
|
2796
|
+
declare const DEFAULT_SETTINGS: Settings;
|
|
2797
|
+
//#endregion
|
|
2798
|
+
//#region src/chat/spawn-tree.d.ts
|
|
2799
|
+
/**
|
|
2800
|
+
* Spawn-tree ownership for transcript renderers (TUI partition, GUI
|
|
2801
|
+
* timeline). A nested worker's lifecycle markers name their spawner in
|
|
2802
|
+
* `spawn.parentChildId`; these helpers turn that into "which worker does
|
|
2803
|
+
* this row belong under", so a grandchild's rows nest inside its spawner
|
|
2804
|
+
* instead of reading as a separate worker of the main transcript.
|
|
2805
|
+
*
|
|
2806
|
+
* Generic over the row shape so the GUI's own `Row` type works too.
|
|
2807
|
+
*/
|
|
2808
|
+
/** What the helpers read off a transcript row / event. */
|
|
2809
|
+
interface SpawnTreeRow {
|
|
2810
|
+
kind: string;
|
|
2811
|
+
childId?: string;
|
|
2812
|
+
spawn?: {
|
|
2813
|
+
parentChildId?: string;
|
|
2814
|
+
};
|
|
2815
|
+
}
|
|
2816
|
+
/** Worker id → the worker that spawned it, from nested spawn markers. */
|
|
2817
|
+
declare function spawnParents(rows: Iterable<SpawnTreeRow>): Map<string, string>;
|
|
2818
|
+
/**
|
|
2819
|
+
* The worker `childId`'s rows belong under: its outermost ancestor that is
|
|
2820
|
+
* itself one of the `present` workers (the ones owning rows in this view).
|
|
2821
|
+
* A view that already re-based its owner's rows (a worker opened in a fold)
|
|
2822
|
+
* leaves that owner out of `present`, so the owner's direct children become
|
|
2823
|
+
* the lanes there. `childId` itself when no ancestor is present.
|
|
2824
|
+
*/
|
|
2825
|
+
declare function spawnLane(childId: string, parents: ReadonlyMap<string, string>, present: ReadonlySet<string>): string;
|
|
2826
|
+
/**
|
|
2827
|
+
* Lane resolver over one view's rows: precomputes the parent map and the
|
|
2828
|
+
* present-worker set, then maps a row's `childId` to its lane.
|
|
2829
|
+
*/
|
|
2830
|
+
declare function spawnLaneResolver(rows: readonly SpawnTreeRow[]): (childId: string) => string;
|
|
2831
|
+
//#endregion
|
|
2832
|
+
//#region src/chat/streaming-pure.d.ts
|
|
2833
|
+
declare function ownerOf(event: StreamEvent): Owner;
|
|
2834
|
+
/**
|
|
2835
|
+
* Index of the event `owner`'s next delta may coalesce into, or `-1` when the
|
|
2836
|
+
* owner has no open lane at the tail.
|
|
2837
|
+
*
|
|
2838
|
+
* Walks backwards over events owned by OTHER subagents — concurrent siblings
|
|
2839
|
+
* whose rows carry no ordering relation to this owner's output, and which a
|
|
2840
|
+
* per-owner drain interleaves at ~60Hz — and stops at the first event that is
|
|
2841
|
+
* either this owner's or a real ordering boundary (parent output, user
|
|
2842
|
+
* prompts, banners). The caller decides whether the event found is mergeable
|
|
2843
|
+
* for its kind. A tail-only check splits every concurrent child's message
|
|
2844
|
+
* into fragments braided with its siblings'.
|
|
2845
|
+
*/
|
|
2846
|
+
declare function mergeTargetIndex(events: readonly StreamEvent[], owner: Owner): number;
|
|
2847
|
+
/**
|
|
2848
|
+
* Default segment bound for a growing streaming markdown event. Coalescing
|
|
2849
|
+
* copies the ENTIRE accumulated string into fresh state on every drain tick,
|
|
2850
|
+
* so one long streamed message costs O(L²) aggregate — past this threshold
|
|
2851
|
+
* the event is split and the copy re-bounded. The split reuses
|
|
2852
|
+
* {@link chunkMarkdownForRender} (blank-line boundaries outside fences,
|
|
2853
|
+
* unsafe-continuation guard), so the finalized segments are byte-identical
|
|
2854
|
+
* to the chunks the renderer would have produced inside a single event, and
|
|
2855
|
+
* the one-row markdown/markdown margin stands in for the consumed blank line
|
|
2856
|
+
* exactly like the renderer's inter-chunk gap. When no safe boundary exists
|
|
2857
|
+
* (one giant fence/list) the event keeps growing until one arrives.
|
|
2858
|
+
*/
|
|
2859
|
+
declare const STREAMING_MARKDOWN_SEGMENT_CHARS: number;
|
|
2860
|
+
interface MarkdownDeltaOptions {
|
|
2861
|
+
/**
|
|
2862
|
+
* Split threshold for a growing block (default
|
|
2863
|
+
* {@link STREAMING_MARKDOWN_SEGMENT_CHARS}). `Infinity` keeps one event per
|
|
2864
|
+
* streamed message — for a host whose reloaded transcript shows messages
|
|
2865
|
+
* whole and whose renderer chunks long text itself.
|
|
2866
|
+
*/
|
|
2867
|
+
segmentChars?: number;
|
|
2868
|
+
}
|
|
2869
|
+
interface ThinkingDeltaOptions<E> {
|
|
2870
|
+
/** Decorate the first row of a newly opened thinking lane (e.g. stamp its start time). */
|
|
2871
|
+
onLaneOpen?: (row: E) => E;
|
|
2872
|
+
}
|
|
2873
|
+
/** Coalesce a markdown delta into `owner`'s open streaming block, or open one. */
|
|
2874
|
+
declare function appendMarkdownDelta<E extends StreamEvent = StreamEvent>(prev: NoInfer<E>[], delta: string, owner: Owner, depth: number | undefined, turnId: string | undefined, options?: MarkdownDeltaOptions): E[];
|
|
2875
|
+
/** Coalesce a thinking delta into `owner`'s open lane, one row per line. */
|
|
2876
|
+
declare function appendThinkingLines<E extends StreamEvent = StreamEvent>(prev: NoInfer<E>[], delta: string, owner: Owner, depth: number | undefined, turnId: string | undefined, options?: ThinkingDeltaOptions<E>): E[];
|
|
2877
|
+
/** Flip any trailing streaming markdown blocks (any owner) to finalized. */
|
|
2878
|
+
declare function finalizeStreamingMarkdown(events: StreamEvent[]): StreamEvent[];
|
|
2879
|
+
/** Flip the trailing streaming markdown block for one specific owner. */
|
|
2880
|
+
declare function finalizeStreamingMarkdownForOwner(events: StreamEvent[], owner: Owner): StreamEvent[];
|
|
2881
|
+
/**
|
|
2882
|
+
* Effective context size for a single turn.
|
|
2883
|
+
*
|
|
2884
|
+
* `usage.input` is misleading on its own when prompt caching is active: providers
|
|
2885
|
+
* (Anthropic, OpenRouter→Anthropic, Gemini) report `input` as the *new uncached*
|
|
2886
|
+
* tokens only — the cached prefix shows up in `cacheRead`, and newly-cached
|
|
2887
|
+
* tokens in `cacheCreation`. The model still saw all three buckets, so the real
|
|
2888
|
+
* context-window utilization is their sum.
|
|
2889
|
+
*
|
|
2890
|
+
* Non-caching providers leave `cacheRead`/`cacheCreation` undefined, so this
|
|
2891
|
+
* collapses to plain `input` for them.
|
|
2892
|
+
*/
|
|
2893
|
+
declare function turnContextSize(usage: TurnUsage | undefined): number;
|
|
2894
|
+
/**
|
|
2895
|
+
* Display-layer transcript bounds. Each rendered event holds live React
|
|
2896
|
+
* fibers + OpenTUI renderables + native text buffers even when scrolled
|
|
2897
|
+
* off-screen — measured at roughly 0.13 MB RSS per markdown-heavy event —
|
|
2898
|
+
* so an uncapped multi-thousand-event session (a normal working day with
|
|
2899
|
+
* tool calls) climbs into the hundreds of MB and eventually OOM/thrash.
|
|
2900
|
+
*
|
|
2901
|
+
* The cap bounds ONLY what is materialized on screen: session turns on
|
|
2902
|
+
* disk are complete, and switching sessions / re-activating replays the
|
|
2903
|
+
* most recent window again. Trimming happens at TURN boundaries so a
|
|
2904
|
+
* turn's rows are never orphaned, and re-caps fold into one cumulative
|
|
2905
|
+
* marker rather than stacking markers.
|
|
2906
|
+
*/
|
|
2907
|
+
declare const MAX_TRANSCRIPT_EVENTS = 1500;
|
|
2908
|
+
/** Post-trim size — the hysteresis gap keeps re-trims O(rare), not per-append. */
|
|
2909
|
+
declare const TRANSCRIPT_TRIM_TO_EVENTS = 1200;
|
|
2910
|
+
/**
|
|
2911
|
+
* Bound a transcript event array for display. Identity below the cap
|
|
2912
|
+
* (no re-render churn on the hot append path); above it, drops the
|
|
2913
|
+
* oldest events down to {@link TRANSCRIPT_TRIM_TO_EVENTS} — extended to
|
|
2914
|
+
* the next turn boundary — and prepends a cumulative hidden-count
|
|
2915
|
+
* marker. Callers: the stream buffer's drain commit and every
|
|
2916
|
+
* `eventsFromTurns` replay site.
|
|
2917
|
+
*/
|
|
2918
|
+
declare function capTranscriptEvents(events: StreamEvent[], max?: number, trimTo?: number): StreamEvent[];
|
|
2919
|
+
//#endregion
|
|
2920
|
+
//#region src/chat/tool-formatters.d.ts
|
|
2921
|
+
/**
|
|
2922
|
+
* Per-tool display metadata + one-line formatters consumed by any
|
|
2923
|
+
* surface that renders a `tool` event in `'formatted'` mode (see
|
|
2924
|
+
* `Settings.toolCallDisplay`).
|
|
2925
|
+
*
|
|
2926
|
+
* Each native tool gets a curated entry — a `displayName` verb that
|
|
2927
|
+
* reads in sentence case (e.g. "Read", "Shell") and a `format` callback
|
|
2928
|
+
* that pulls the most informative bits out of the model's raw input to
|
|
2929
|
+
* a single scannable line. Unknown tools (MCP servers, host-added
|
|
2930
|
+
* tools, future zidane additions) fall back to {@link formatToolCall}
|
|
2931
|
+
* returning `null` — the renderer then shows a minimal `↳ <name>` line.
|
|
2932
|
+
*
|
|
2933
|
+
* Renderer-agnostic: returns plain data (`{ target, meta }`) so the
|
|
2934
|
+
* TUI's React/OpenTUI surface and any future GUI consumer can paint
|
|
2935
|
+
* the same shape in their own style. Lives in `zidane/chat` because
|
|
2936
|
+
* it has no rendering concerns; the TUI just consumes it.
|
|
2937
|
+
*/
|
|
2938
|
+
interface ToolFormatLine {
|
|
2939
|
+
/**
|
|
2940
|
+
* Primary target — typically a path, command, pattern, or
|
|
2941
|
+
* task description. Renderer paints this in the model accent color
|
|
2942
|
+
* so the eye lands on it first.
|
|
2943
|
+
*/
|
|
2944
|
+
target?: string;
|
|
2945
|
+
/**
|
|
2946
|
+
* Secondary annotations rendered after the target, joined with
|
|
2947
|
+
* ` · ` separators. Use for line ranges (`L10-25`), limits, flags,
|
|
2948
|
+
* or any short suffix that adds context without bloating the line.
|
|
2949
|
+
*/
|
|
2950
|
+
meta?: readonly string[];
|
|
2951
|
+
/**
|
|
2952
|
+
* Optional SECOND line — the payload behind the action (a prompt sent to
|
|
2953
|
+
* another session). Renderers paint it dimmed under the header and clamp
|
|
2954
|
+
* it (two lines in the GUI, one terminal row in the TUI); it is never
|
|
2955
|
+
* squeezed into the header line, which stays single-line.
|
|
2956
|
+
*/
|
|
2957
|
+
detail?: string;
|
|
2958
|
+
/**
|
|
2959
|
+
* The session this call targets, when the tool addresses one. `target`
|
|
2960
|
+
* carries the short id as a fallback; a renderer with the session list in
|
|
2961
|
+
* scope shows the session's TITLE instead.
|
|
2962
|
+
*/
|
|
2963
|
+
sessionId?: string;
|
|
2964
|
+
}
|
|
2965
|
+
interface ToolDisplayMeta {
|
|
2966
|
+
/**
|
|
2967
|
+
* Title-case display verb (e.g. `Read`, `Shell`, `Edit`). When the
|
|
2968
|
+
* label depends on an input field (e.g. `skills_use`'s
|
|
2969
|
+
* `mode: 'activate' | 'deactivate'` → `Enable` / `Disable`), supply
|
|
2970
|
+
* a function instead and read the field defensively. The function
|
|
2971
|
+
* form is called whenever {@link displayNameFor} has the call's
|
|
2972
|
+
* input in scope; callers without input fall back to the function's
|
|
2973
|
+
* `input: undefined` branch, which should return a stable default.
|
|
2974
|
+
*/
|
|
2975
|
+
displayName: string | ((input: Record<string, unknown> | undefined) => string);
|
|
2976
|
+
/**
|
|
2977
|
+
* Pull a {@link ToolFormatLine} out of the raw model input. Returns
|
|
2978
|
+
* `null` when the shape isn't what the tool expects (typed defensively
|
|
2979
|
+
* — we never want a malformed call to crash the transcript).
|
|
2980
|
+
*/
|
|
2981
|
+
format: (input: Record<string, unknown>) => ToolFormatLine | null;
|
|
2982
|
+
}
|
|
2983
|
+
declare const TOOL_DISPLAY: Readonly<Record<string, ToolDisplayMeta>>;
|
|
2984
|
+
/**
|
|
2985
|
+
* Resolve the display verb for a tool. Native tools use their curated
|
|
2986
|
+
* entry from {@link TOOL_DISPLAY}; everything else gets a sentence-case
|
|
2987
|
+
* version of the raw name (`my_host_tool` → `My host tool`) so an MCP /
|
|
2988
|
+
* host tool still reads cleanly in the transcript without shouting
|
|
2989
|
+
* Title Case at every word.
|
|
2990
|
+
*
|
|
2991
|
+
* MCP convention: every tool surfaced by `mcp/connectMcpServers` is
|
|
2992
|
+
* namespaced as `mcp_<server>_<tool>` (see `src/mcp/index.ts`). The
|
|
2993
|
+
* `mcp_` prefix is plumbing — strip it before casing so the label
|
|
2994
|
+
* reads as `Github create issue` instead of `Mcp github create issue`.
|
|
2995
|
+
* The server name leads, which doubles as a free visual grouping
|
|
2996
|
+
* affordance ("everything starting with `Github` came from the github
|
|
2997
|
+
* MCP server").
|
|
2998
|
+
*/
|
|
2999
|
+
declare function displayNameFor(name: string, input?: Record<string, unknown>): string;
|
|
3000
|
+
/**
|
|
3001
|
+
* The source code a tool call runs, for renderers that show it highlighted
|
|
3002
|
+
* instead of the raw JSON input: Codemode's script as JavaScript, a `shell`
|
|
3003
|
+
* / `bash` command as bash (the command alone: the label carries the
|
|
3004
|
+
* description, the rest is plumbing). `null` for
|
|
3005
|
+
* every other tool and for calls without the code field. `language` is a
|
|
3006
|
+
* fence-style name both highlighters accept (Shiki in the GUI, OpenTUI's
|
|
3007
|
+
* tree-sitter in the TUI).
|
|
3008
|
+
*/
|
|
3009
|
+
declare function toolInputCode(name: string, input: Record<string, unknown> | undefined): {
|
|
3010
|
+
code: string;
|
|
3011
|
+
language: string;
|
|
3012
|
+
} | null;
|
|
3013
|
+
/**
|
|
3014
|
+
* Run a tool's curated formatter and return the result, or `null` when
|
|
3015
|
+
* no formatter is registered / the input shape doesn't match. Renderer
|
|
3016
|
+
* decides what to do with `null` — typically: show `↳ <displayName>`
|
|
3017
|
+
* with no target / meta tail.
|
|
3018
|
+
*/
|
|
3019
|
+
declare function formatToolCall(name: string, input: Record<string, unknown>): ToolFormatLine | null;
|
|
3020
|
+
//#endregion
|
|
3021
|
+
//#region src/chat/turn-operations.d.ts
|
|
3022
|
+
/**
|
|
3023
|
+
* Fork — keep every turn up to and including `turnId`, then strip any
|
|
3024
|
+
* `tool_call` blocks left without a matching `tool_result` in the slice.
|
|
3025
|
+
*
|
|
3026
|
+
* Semantics:
|
|
3027
|
+
* - Include the selected turn ("branch from HERE" mental model — the
|
|
3028
|
+
* user wants the selected message to be the latest in the fork).
|
|
3029
|
+
* - If the selected turn is an assistant turn with unresolved
|
|
3030
|
+
* `tool_call` blocks (their `tool_result`s live in turns AFTER the
|
|
3031
|
+
* slice), strip those calls. Otherwise the fork would post an
|
|
3032
|
+
* assistant turn with no matching tool results, breaking the next
|
|
3033
|
+
* provider call.
|
|
3034
|
+
* - Drop turns that become empty (all blocks stripped).
|
|
3035
|
+
*
|
|
3036
|
+
* Returns `null` when `turnId` doesn't exist in `turns` — caller should
|
|
3037
|
+
* surface a "turn not found" error rather than silently no-op.
|
|
3038
|
+
*/
|
|
3039
|
+
declare function truncateTurnsAt(turns: readonly SessionTurn[], turnId: string): SessionTurn[] | null;
|
|
3040
|
+
/**
|
|
3041
|
+
* Delete — remove the turn with `turnId` and any tool blocks left
|
|
3042
|
+
* orphaned by the removal. Returns `null` when `turnId` doesn't exist.
|
|
3043
|
+
*
|
|
3044
|
+
* Strategy:
|
|
3045
|
+
* 1. Drop the target turn.
|
|
3046
|
+
* 2. Scan the remaining turns for `tool_call`s without a matching
|
|
3047
|
+
* `tool_result` (orphaned by removing the user turn that carried
|
|
3048
|
+
* the result), and `tool_result`s without a matching `tool_call`
|
|
3049
|
+
* (orphaned by removing the assistant turn that issued the call).
|
|
3050
|
+
* Strip both sides.
|
|
3051
|
+
* 3. Drop turns whose content is now empty.
|
|
3052
|
+
*
|
|
3053
|
+
* This guarantees the resulting history is protocol-clean — a follow-up
|
|
3054
|
+
* `agent.run()` against the modified session can post turns without the
|
|
3055
|
+
* provider rejecting the history.
|
|
3056
|
+
*/
|
|
3057
|
+
declare function deleteTurnSafely(turns: readonly SessionTurn[], turnId: string): SessionTurn[] | null;
|
|
3058
|
+
/**
|
|
3059
|
+
* Replace a turn's text with `newText`, keeping every non-text block (tool
|
|
3060
|
+
* calls, tool results, thinking, images) where it was. All text blocks
|
|
3061
|
+
* collapse into one, placed where the first text block was; an empty or
|
|
3062
|
+
* whitespace-only `newText` removes the text and keeps the rest.
|
|
3063
|
+
*
|
|
3064
|
+
* Returns `null` when the turn is missing or has no text to edit, so callers
|
|
3065
|
+
* can report it. Untouched turns keep their identity (a store can rewrite
|
|
3066
|
+
* only the edited row).
|
|
3067
|
+
*/
|
|
3068
|
+
declare function replaceTurnTextBlocks(turns: readonly SessionTurn[], turnId: string, newText: string): SessionTurn[] | null;
|
|
3069
|
+
/**
|
|
3070
|
+
* Serialize a turn's content to a clean text representation suited for
|
|
3071
|
+
* the clipboard. Joins text + thinking blocks verbatim; tool calls and
|
|
3072
|
+
* tool results get bracketed labels so the user can paste a readable
|
|
3073
|
+
* record of what happened without losing structure.
|
|
3074
|
+
*
|
|
3075
|
+
* Empty turns return `''`.
|
|
3076
|
+
*/
|
|
3077
|
+
declare function turnAsText(turn: SessionTurn): string;
|
|
3078
|
+
/**
|
|
3079
|
+
* Count turns before / after the one identified by `turnId` in the
|
|
3080
|
+
* given list. Returns `null` when the id is missing. Used to label the
|
|
3081
|
+
* turn-details modal with `N before · M after`.
|
|
3082
|
+
*/
|
|
3083
|
+
declare function countNeighbors(turnIds: readonly string[], turnId: string): {
|
|
3084
|
+
before: number;
|
|
3085
|
+
after: number;
|
|
3086
|
+
} | null;
|
|
3087
|
+
//#endregion
|
|
3088
|
+
export { currentModels as $, retagUserPromptEventsFromRefs as $i, BrowserOpInputs as $n, InlineSegment as $r, isTodoTool as $t, ProviderUsageCredits as A, DaemonHealth as Ai, MachineResult as An, CacheChipContent as Ar, displayHostUrl as At, resetLabel as B, isReservedCredKey as Bi, BROWSER_EVALUATE_MAX_BYTES as Bn, FeatureGate as Br, CreateTodoToolsOptions as Bt, ownerOf as C, ChatReferenceScope as Ca, RequestApproval as Ci, MachineInfo as Cn, searchSessionHistoryIndex as Cr, enabledMcpsWithout as Ct, spawnLaneResolver as D, blendHsl as Da, useSafeModeQueue as Di, MachineParams as Dn, searchSessionTurns as Dr, normalizeMarkdownCodeFences as Dt, spawnLane as E, uniqueChatIdsFromReferences as Ea, useSafeModeActions as Ei, MachineMethodName as En, searchSessionIndexAsync as Er, chunkMarkdownForRender as Et, activeSnapshotFor as F, CRED_KEY_SLOT_SEPARATOR as Fi, isValidMachineName as Fn, liveSessionCost as Fr, HostProbe as Ft, PromptSegmentRef as G, PromptTurnRef as Gi, BROWSER_REQUEST_SLACK_MS as Gn, isKillSwitchEngaged as Gr, TODO_WRITE_COUNTS_METADATA_KEY as Gt, updatedLabel as H, BASH_CALL_ID_PREFIX as Hi, BROWSER_OPEN_MOUNT_MS as Hn, daemonGate as Hr, TODOREAD_TOOL as Ht, formatBalance as I, DEFAULT_OAUTH_ACCOUNT_LABEL as Ii, machineKind as In, retryLabel as Ir, HostProbeResult as It, splitPromptSegments as J, isUserBashEvent as Ji, BrowserChange as Jn, DiffOp as Jr, TodoTally as Jt, inferPromptRefs as K, isEditErrorResult as Ki, BROWSER_TEXT_MAX_CHARS as Kn, remoteHostsGate as Kr, TodoItem as Kt, formatCredits as L, accountCredKey as Li, parseMachineKind as Ln, runStatusLabel as Lr, HostRegistryError as Lt, ProviderUsageStatus as M, DaemonHealthTone as Mi, MachineShareStatus as Mn, cacheBreakChip as Mr, HostEntry as Mt, ProviderUsageWindow as N, ACCOUNT_CRED_KEY_INFIX as Ni, MachineStatusChange as Nn, cacheBreakNoticeText as Nr, HostErrorCode as Nt, spawnParents as O, buildLinearRamp as Oa, DAEMON_HEALTH_GLYPH as Oi, MachineRegisterParams as On, searchTurns as Or, splitMarkdownCodeBlocks as Ot, UsageTone as P, ALTERNATE_CRED_KEY_SUFFIX as Pi, MachineUseStatus as Pn, compactingLabel as Pr, HostIdentity as Pt, currentModelKeys as Q, retagUserPromptEvents as Qi, BrowserOpError as Qn, InlineDiff as Qr, getTodosForRun as Qt, formatUsagePercent as R, alternateCredKey as Ri, toMachineName as Rn, streamingLabel as Rr, HostTestResult as Rt, mergeTargetIndex as S, ChatReferenceEntry as Sa, ApprovalRequest as Si, MachineErrorCode as Sn, searchSessionHistory as Sr, enabledMcpsWith as St, SpawnTreeRow as T, createChatsCompletionProvider as Ta, SafeModeProvider as Ti, MachineLinksStatus as Tn, searchSessionIndex as Tr, MarkdownSegment as Tt, usageTone as U, CACHE_NOTICE_LABEL as Ui, BROWSER_OPS as Un, defineFeatureGate as Ur, TODOS_METADATA_KEY as Ut, showsAccount as V, oauthAccountLabel as Vi, BROWSER_MAX_WAIT_MS as Vn, FeatureGateOptions as Vr, DEFAULT_MAX_TODO_ITEMS as Vt, PromptSegment as W, EDIT_TOOL_NAMES as Wi, BROWSER_OUTLINE_MAX_ELEMENTS as Wn, engagedKillSwitches as Wr, TODOWRITE_TOOL as Wt, ModelIdParts as X, messageSelectionOwnership as Xi, BrowserErrorCode as Xn, EditSummary as Xr, createTodoTools as Xt, LineupEntry as Y, isVisible as Yi, BrowserConsoleEntry as Yn, EditHunkSummary as Yr, TodosBag as Yt, compareModelVersion as Z, promptTurnRefs as Zi, BrowserOp as Zn, HunkResolution as Zr, getArchivedTodosForRun as Zt, appendMarkdownDelta as _, listProjectFiles as _a, resolveApprovalForPayload as _i, TerminalReadResult as _n, buildSessionSearchIndex as _r, McpAuthStatus as _t, turnAsText as a, canonicalKeyName as aa, computeLineDiff as ai, useActiveTodos as an, BrowserStatus as ar, filterModelCatalog as at, finalizeStreamingMarkdown as b, CHATS_TRIGGER as ba, summarizeOutcomes as bi, TerminalTarget as bn, highlightSegments as br, mcpFailureEvent as bt, ToolFormatLine as c, SKILLS_TRIGGER as ca, previewEditPayload as ci, TERMINAL_MAX_PER_SESSION as cn, HighlightRange as cr, MCP_KEY_REFUSED_HINT as ct, toolInputCode as d, FILES_TRIGGER as da, tokenize as di, TERMINAL_TEXT_MAX_LINES as dn, SearchExcerpt as dr, classifyMcpTest as dt, selectableTurnIds as ea, PreviewResult as ei, pickActiveRunId as en, BrowserOpResults as er, parseModelId as et, MAX_TRANSCRIPT_EVENTS as f, createFilesCompletionProvider as fa, ResolvedApproval as fi, TerminalAttachResult as fn, SearchSessionResult as fr, isMcpAuthRefusal as ft, ThinkingDeltaOptions as g, fileEntriesFromPaths as ga, parseEditOutcomesFromResult as gi, TerminalOwner as gn, SessionSearchIndex as gr, McpAuthStateMap as gt, TRANSCRIPT_TRIM_TO_EVENTS as h, ListProjectFilesOptions as ha, mergeApprovalAndBodyOutcomes as hi, TerminalOpenInput as hn, SessionSearchExcerpt as hr, McpAuthEvent as ht, truncateTurnsAt as i, bindingAlternatives as ia, computeInlineDiff as ii, setTodosForRun as in, BrowserSnapshot as ir, customModelTargets as it, ProviderUsageSnapshot as j, DaemonHealthStyle as ji, MachineRoot as jn, CacheChipTone as jr, parseRemoteHostUrl as jt, DEFAULT_SETTINGS as k, DAEMON_HEALTH_STYLE as ki, MachineRegisterResult as kn, searchableTurnText as kr, RemoteHostError as kt, displayNameFor as l, createSkillsCompletionProvider as la, splitLines as li, TERMINAL_OUTPUT_WINDOW as ln, HighlightSegment as lr, McpTestOutcomeKind as lt, STREAMING_MARKDOWN_SEGMENT_CHARS as m, FileEntry as ma, maskToOutcomeKinds as mi, TerminalInfo as mn, SessionHistoryMatch as mr, MCP_STATUS_LABEL as mt, deleteTurnSafely as n, turnSelectionOwnership as na, buildContextualDiff as ni, sanitizeTodoItems as nn, BrowserResponse as nr, CustomModelTarget as nt, TOOL_DISPLAY as o, parseBindingSpec as oa, extractEditPayload as oi, TODO_STATUS_GLYPHS as on, BrowserTarget as or, indexOfEntry as ot, MarkdownDeltaOptions as p, uniqueFilesFromReferences as pa, buildEditOutcomesAnnotation as pi, TerminalError as pn, SearchTurnResult as pr, mcpFailureLine as pt, promptSegmentLines as q, isTurnHighlighted as qi, BROWSER_WAIT_TIMEOUT_MS as qn, DiffLine as qr, TodoStatus as qt, replaceTurnTextBlocks as r, ParsedBinding as ra, buildUnifiedDiff as ri, selectActiveTodos as rn, BrowserScreenshot as rr, buildModelCatalog as rt, ToolDisplayMeta as s, parseBindingSpecs as sa, filetypeFromPath as si, TERMINAL_HISTORY_MAX_CHARS as sn, BrowserWaitUntil as sr, parseCustomModelQuery as st, countNeighbors as t, selectionAfterTurnRemoval as ta, applyEditPayload as ti, pruneTodosByRun as tn, BrowserRequest as tr, CatalogEntry as tt, formatToolCall as u, uniqueSkillNamesFromReferences as ua, summarizeEditPayload as ui, TERMINAL_READ_MAX_CHARS as un, IndexedSearchTurn as ur, McpTestResult as ut, appendThinkingLines as v, COMMANDS_TRIGGER as va, rewriteMultiEditHeader as vi, TerminalSessionState as vn, buildSessionSearchIndexAsync as vr, McpNeedsAuthReason as vt, turnContextSize as w, chatReferenceTokensFromText as wa, SafeModeActions as wi, MachineLinkState as wn, searchSessionHistoryIndexAsync as wr, MARKDOWN_RENDER_CHUNK_TARGET_BYTES as wt, finalizeStreamingMarkdownForOwner as x, ChatReferenceData as xa, ApprovalDecision as xi, MACHINE_PROTOCOL_VERSION as xn, searchHighlightRanges as xr, reduceMcpAuth as xt, capTranscriptEvents as y, createCommandsCompletionProvider as ya, stripEditOutcomesAnnotation as yi, TerminalStatus as yn, filterSessionSearchCatalog as yr, getMcpAuthStatus as yt, mostConstrainedWindow as z, isAccountCredKey as zi, BROWSER_ACTION_TIMEOUT_MS as zn, FEATURE_GATES as zr, ActiveTodosState as zt };
|
|
3089
|
+
//# sourceMappingURL=turn-operations-DQX5ZZni.d.ts.map
|