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,1016 @@
|
|
|
1
|
+
import { n as estimateTokens } from "./utils-ngQzYzZD.js";
|
|
2
|
+
//#region src/extensions/badge-actions.ts
|
|
3
|
+
const MAX_TEXT = 65536;
|
|
4
|
+
const MAX_ITEMS_PER_SOURCE = 8;
|
|
5
|
+
const GROUP_ORDER = {
|
|
6
|
+
copy: 0,
|
|
7
|
+
prompt: 1,
|
|
8
|
+
open: 2,
|
|
9
|
+
more: 3
|
|
10
|
+
};
|
|
11
|
+
function isWebUrl(href) {
|
|
12
|
+
return href !== void 0 && /^https?:\/\//i.test(href);
|
|
13
|
+
}
|
|
14
|
+
function str$1(v, max) {
|
|
15
|
+
return typeof v === "string" && v.length > 0 && v.length <= max ? v : void 0;
|
|
16
|
+
}
|
|
17
|
+
/** A target from across a boundary (the GUI renderer), reduced to its known, bounded fields; `null` when unusable. */
|
|
18
|
+
function normalizeBadgeTarget(raw) {
|
|
19
|
+
const t = raw && typeof raw === "object" ? raw : null;
|
|
20
|
+
if (!t) return null;
|
|
21
|
+
const kind = [
|
|
22
|
+
"link",
|
|
23
|
+
"file",
|
|
24
|
+
"commit",
|
|
25
|
+
"pull_request",
|
|
26
|
+
"branch",
|
|
27
|
+
"reference",
|
|
28
|
+
"artifact"
|
|
29
|
+
].find((k) => k === t.kind);
|
|
30
|
+
const text = str$1(t.text, 2048);
|
|
31
|
+
if (!kind || !text) return null;
|
|
32
|
+
const href = str$1(t.href, 4096);
|
|
33
|
+
const prompt = str$1(t.prompt, MAX_TEXT);
|
|
34
|
+
const sessionId = str$1(t.sessionId, 512);
|
|
35
|
+
const a = t.artifact && typeof t.artifact === "object" ? t.artifact : void 0;
|
|
36
|
+
const artifactKind = str$1(a?.kind, 64);
|
|
37
|
+
const artifactUri = str$1(a?.uri, 2048);
|
|
38
|
+
const r = t.reference && typeof t.reference === "object" ? t.reference : void 0;
|
|
39
|
+
const providerId = str$1(r?.providerId, 128);
|
|
40
|
+
const key = str$1(r?.key, 512);
|
|
41
|
+
return {
|
|
42
|
+
kind,
|
|
43
|
+
text,
|
|
44
|
+
...href ? { href } : {},
|
|
45
|
+
...prompt ? { prompt } : {},
|
|
46
|
+
...artifactKind && artifactUri ? { artifact: {
|
|
47
|
+
kind: artifactKind,
|
|
48
|
+
uri: artifactUri
|
|
49
|
+
} } : {},
|
|
50
|
+
...providerId && key ? { reference: {
|
|
51
|
+
providerId,
|
|
52
|
+
key
|
|
53
|
+
} } : {},
|
|
54
|
+
...sessionId ? { sessionId } : {}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** What "Add to prompt" inserts for a target. */
|
|
58
|
+
function badgePromptText(target) {
|
|
59
|
+
if (target.prompt) return target.prompt;
|
|
60
|
+
if (target.kind === "file" && target.href) return `@${target.href}`;
|
|
61
|
+
if (isWebUrl(target.href) && target.kind === "link") return target.href;
|
|
62
|
+
return target.text;
|
|
63
|
+
}
|
|
64
|
+
/** The built-in actions for a target (host-implemented; see {@link builtinBadgeEffect}). */
|
|
65
|
+
function builtinBadgeActions(target) {
|
|
66
|
+
const items = [];
|
|
67
|
+
const web = isWebUrl(target.href);
|
|
68
|
+
if (web) items.push({
|
|
69
|
+
id: "copy-url",
|
|
70
|
+
label: "Copy URL",
|
|
71
|
+
group: "copy",
|
|
72
|
+
shortcut: "C",
|
|
73
|
+
source: "builtin"
|
|
74
|
+
});
|
|
75
|
+
else if (target.kind === "file" && target.href) items.push({
|
|
76
|
+
id: "copy-path",
|
|
77
|
+
label: "Copy path",
|
|
78
|
+
group: "copy",
|
|
79
|
+
shortcut: "C",
|
|
80
|
+
source: "builtin"
|
|
81
|
+
});
|
|
82
|
+
if (target.kind === "commit") items.push({
|
|
83
|
+
id: "copy-text",
|
|
84
|
+
label: "Copy SHA",
|
|
85
|
+
group: "copy",
|
|
86
|
+
...web ? {} : { shortcut: "C" },
|
|
87
|
+
source: "builtin"
|
|
88
|
+
});
|
|
89
|
+
else if (!web && target.kind !== "file") items.push({
|
|
90
|
+
id: "copy-text",
|
|
91
|
+
label: "Copy",
|
|
92
|
+
group: "copy",
|
|
93
|
+
shortcut: "C",
|
|
94
|
+
source: "builtin"
|
|
95
|
+
});
|
|
96
|
+
items.push({
|
|
97
|
+
id: "add-to-prompt",
|
|
98
|
+
label: "Add to prompt",
|
|
99
|
+
group: "prompt",
|
|
100
|
+
shortcut: "P",
|
|
101
|
+
source: "builtin"
|
|
102
|
+
});
|
|
103
|
+
if (web) items.push({
|
|
104
|
+
id: "open-browser",
|
|
105
|
+
label: "Open in browser",
|
|
106
|
+
group: "open",
|
|
107
|
+
shortcut: "O",
|
|
108
|
+
source: "builtin"
|
|
109
|
+
});
|
|
110
|
+
else if (target.kind === "file" && target.href) items.push({
|
|
111
|
+
id: "open-file",
|
|
112
|
+
label: "Open",
|
|
113
|
+
group: "open",
|
|
114
|
+
shortcut: "O",
|
|
115
|
+
source: "builtin"
|
|
116
|
+
});
|
|
117
|
+
return items;
|
|
118
|
+
}
|
|
119
|
+
/** The effect of a built-in action; `undefined` for an id that isn't one (or doesn't apply). */
|
|
120
|
+
function builtinBadgeEffect(actionId, target) {
|
|
121
|
+
switch (actionId) {
|
|
122
|
+
case "copy-url": return isWebUrl(target.href) ? { copy: target.href } : void 0;
|
|
123
|
+
case "copy-path": return target.kind === "file" && target.href ? { copy: target.href } : void 0;
|
|
124
|
+
case "copy-text": return { copy: target.text };
|
|
125
|
+
case "add-to-prompt": return { insert: badgePromptText(target) };
|
|
126
|
+
case "open-browser": return isWebUrl(target.href) ? { open: target.href } : void 0;
|
|
127
|
+
case "open-file": return target.kind === "file" && target.href ? { open: target.href } : void 0;
|
|
128
|
+
default: return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function matches(entry, target) {
|
|
132
|
+
const m = entry.value.match;
|
|
133
|
+
if (!m) return true;
|
|
134
|
+
if (m.kinds && !m.kinds.includes(target.kind)) return false;
|
|
135
|
+
if (m.artifactKinds && (!target.artifact || !m.artifactKinds.includes(target.artifact.kind))) return false;
|
|
136
|
+
if (m.references) {
|
|
137
|
+
const id = target.reference?.providerId;
|
|
138
|
+
if (!id || !m.references.includes(id)) return false;
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Extension items for a target, in registration order, after validation:
|
|
144
|
+
* ids and labels must be non-empty strings, ids unique per source, at most
|
|
145
|
+
* eight per source. A throwing `actions` contributes nothing.
|
|
146
|
+
*/
|
|
147
|
+
function extensionBadgeActions(target, registry) {
|
|
148
|
+
const out = [];
|
|
149
|
+
for (const entry of registry.badgeActions) {
|
|
150
|
+
if (!matches(entry, target)) continue;
|
|
151
|
+
let listed;
|
|
152
|
+
try {
|
|
153
|
+
listed = entry.value.actions(target);
|
|
154
|
+
} catch {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const seen = /* @__PURE__ */ new Set();
|
|
158
|
+
for (const action of listed ?? []) {
|
|
159
|
+
if (seen.size >= MAX_ITEMS_PER_SOURCE) break;
|
|
160
|
+
const id = str$1(action?.id, 64);
|
|
161
|
+
const label = str$1(action?.label, 80);
|
|
162
|
+
if (!id || !label || seen.has(id)) continue;
|
|
163
|
+
seen.add(id);
|
|
164
|
+
const group = action.group && action.group in GROUP_ORDER ? action.group : "more";
|
|
165
|
+
const shortcut = str$1(action.shortcut, 1);
|
|
166
|
+
out.push({
|
|
167
|
+
id,
|
|
168
|
+
label,
|
|
169
|
+
group,
|
|
170
|
+
...shortcut ? { shortcut } : {},
|
|
171
|
+
source: entry.value.id
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The full menu: built-ins then extension items, ordered by group (stable
|
|
179
|
+
* within a group). An extension shortcut that collides with an earlier one
|
|
180
|
+
* is dropped, never the item.
|
|
181
|
+
*/
|
|
182
|
+
function badgeMenu(target, registry) {
|
|
183
|
+
return mergeBadgeMenu([...builtinBadgeActions(target), ...registry ? extensionBadgeActions(target, registry) : []]);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Order items the way {@link badgeMenu} does: by group, stable within one,
|
|
187
|
+
* later colliding shortcuts dropped. For hosts that get the built-ins and the
|
|
188
|
+
* extension items separately (the GUI renderer asks main for the latter).
|
|
189
|
+
*/
|
|
190
|
+
function mergeBadgeMenu(all) {
|
|
191
|
+
const sorted = all.map((item, i) => ({
|
|
192
|
+
item,
|
|
193
|
+
i
|
|
194
|
+
})).sort((a, b) => GROUP_ORDER[a.item.group ?? "more"] - GROUP_ORDER[b.item.group ?? "more"] || a.i - b.i).map(({ item }) => item);
|
|
195
|
+
const taken = /* @__PURE__ */ new Set();
|
|
196
|
+
return sorted.map((item) => {
|
|
197
|
+
if (!item.shortcut) return item;
|
|
198
|
+
const key = item.shortcut.toUpperCase();
|
|
199
|
+
if (taken.has(key)) {
|
|
200
|
+
const { shortcut: _drop, ...rest } = item;
|
|
201
|
+
return rest;
|
|
202
|
+
}
|
|
203
|
+
taken.add(key);
|
|
204
|
+
return item;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/** An effect from extension code, reduced to known, bounded string fields. */
|
|
208
|
+
function normalizeBadgeEffect(raw) {
|
|
209
|
+
const e = raw && typeof raw === "object" ? raw : {};
|
|
210
|
+
const copy = str$1(e.copy, MAX_TEXT);
|
|
211
|
+
const insert = str$1(e.insert, MAX_TEXT);
|
|
212
|
+
const open = str$1(e.open, 4096);
|
|
213
|
+
const notice = str$1(e.notice, 280);
|
|
214
|
+
return {
|
|
215
|
+
...copy ? { copy } : {},
|
|
216
|
+
...insert ? { insert } : {},
|
|
217
|
+
...open && (/^https?:\/\//i.test(open) || open.startsWith("/")) ? { open } : {},
|
|
218
|
+
...notice ? { notice } : {}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Run one menu item: a built-in resolves locally, an extension item runs its
|
|
223
|
+
* registration's `run` (8 s deadline). Never throws: failures come back as a
|
|
224
|
+
* `notice`.
|
|
225
|
+
*/
|
|
226
|
+
async function runBadgeAction(source, actionId, target, registry, ctx = {}) {
|
|
227
|
+
if (source === "builtin") return builtinBadgeEffect(actionId, target) ?? { notice: "Not available for this badge." };
|
|
228
|
+
const entry = registry?.badgeActions.find((e) => e.value.id === source);
|
|
229
|
+
if (!entry || !matches(entry, target)) return { notice: "This action is no longer available." };
|
|
230
|
+
const signal = AbortSignal.timeout(8e3);
|
|
231
|
+
try {
|
|
232
|
+
return normalizeBadgeEffect(await Promise.race([Promise.resolve(entry.value.run(actionId, target, {
|
|
233
|
+
...ctx,
|
|
234
|
+
signal
|
|
235
|
+
})), new Promise((_, reject) => signal.addEventListener("abort", () => reject(/* @__PURE__ */ new Error("Timed out.")), { once: true }))]));
|
|
236
|
+
} catch (err) {
|
|
237
|
+
return { notice: err instanceof Error ? err.message : String(err) };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* The target for an artifact row (Artifacts panel / rail): its kind's
|
|
242
|
+
* badge kind (commit, pull request, file; `artifact` for the rest), the
|
|
243
|
+
* row's title and link, and what "Add to prompt" inserts: a commit's SHA,
|
|
244
|
+
* a file's path, the link, else the label.
|
|
245
|
+
*/
|
|
246
|
+
function artifactBadgeTarget(artifact, row) {
|
|
247
|
+
const kind = artifact.kind === "commit" ? "commit" : artifact.kind === "pull_request" ? "pull_request" : artifact.kind === "file" ? "file" : "artifact";
|
|
248
|
+
const sha = kind === "commit" ? /^git:commit:([0-9a-f]{7,40})$/.exec(artifact.uri)?.[1] : void 0;
|
|
249
|
+
return {
|
|
250
|
+
kind,
|
|
251
|
+
text: sha ? sha.slice(0, 7) : row.title,
|
|
252
|
+
...row.href ? { href: row.href } : {},
|
|
253
|
+
...sha ? { prompt: sha } : kind === "artifact" && !row.href ? { prompt: artifact.label } : {},
|
|
254
|
+
artifact: {
|
|
255
|
+
kind: artifact.kind,
|
|
256
|
+
uri: artifact.uri
|
|
257
|
+
},
|
|
258
|
+
...artifact.sessionId ? { sessionId: artifact.sessionId } : {}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/** The target for a session badge (or one row of its card): GUI sidebar, TUI sessions list. */
|
|
262
|
+
function sessionBadgeTarget(sessionId, entry, row) {
|
|
263
|
+
const { badge } = entry;
|
|
264
|
+
const uri = row?.uri ?? badge.card?.rows[0]?.uri ?? entry.kind;
|
|
265
|
+
const href = row ? row.href : badge.href;
|
|
266
|
+
const prompt = row ? row.prompt ?? row.href ?? row.lead : badge.prompt ?? badge.href;
|
|
267
|
+
return {
|
|
268
|
+
kind: "artifact",
|
|
269
|
+
text: row ? row.lead ?? row.title : badge.text,
|
|
270
|
+
...href ? { href } : {},
|
|
271
|
+
...prompt ? { prompt } : {},
|
|
272
|
+
artifact: {
|
|
273
|
+
kind: entry.kind,
|
|
274
|
+
uri
|
|
275
|
+
},
|
|
276
|
+
sessionId
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
//#endregion
|
|
280
|
+
//#region src/chat/keybinding-spec.ts
|
|
281
|
+
/**
|
|
282
|
+
* Aliases the parser accepts on input so the on-disk format can be
|
|
283
|
+
* forgiving (different terminals + docs label modifiers + keys
|
|
284
|
+
* differently). Output names are canonicalized to one form per key so a
|
|
285
|
+
* matcher only has to compare one canonical against an event's key name.
|
|
286
|
+
* Unknown names pass through verbatim, which is useful for
|
|
287
|
+
* terminal-specific keys we don't have to enumerate.
|
|
288
|
+
*/
|
|
289
|
+
const NAME_ALIASES = {
|
|
290
|
+
"esc": "escape",
|
|
291
|
+
"enter": "return",
|
|
292
|
+
"ret": "return",
|
|
293
|
+
"space": "space",
|
|
294
|
+
"spc": "space",
|
|
295
|
+
"del": "delete",
|
|
296
|
+
"ins": "insert",
|
|
297
|
+
"pgup": "pageup",
|
|
298
|
+
"pgdn": "pagedown",
|
|
299
|
+
"pagup": "pageup",
|
|
300
|
+
"pagedn": "pagedown",
|
|
301
|
+
"plus": "=",
|
|
302
|
+
"+": "=",
|
|
303
|
+
"minus": "-",
|
|
304
|
+
"{": "[",
|
|
305
|
+
"}": "]",
|
|
306
|
+
"~": "`",
|
|
307
|
+
"arrowleft": "left",
|
|
308
|
+
"arrowright": "right",
|
|
309
|
+
"arrowup": "up",
|
|
310
|
+
"arrowdown": "down"
|
|
311
|
+
};
|
|
312
|
+
const MODIFIER_ALIASES = {
|
|
313
|
+
ctrl: "ctrl",
|
|
314
|
+
control: "ctrl",
|
|
315
|
+
shift: "shift",
|
|
316
|
+
alt: "alt",
|
|
317
|
+
option: "alt",
|
|
318
|
+
opt: "alt",
|
|
319
|
+
meta: "meta",
|
|
320
|
+
cmd: "meta",
|
|
321
|
+
command: "meta",
|
|
322
|
+
super: "meta",
|
|
323
|
+
win: "meta"
|
|
324
|
+
};
|
|
325
|
+
/** A key name as the parser canonicalizes it (`'Enter'` → `'return'`, `'ArrowLeft'` → `'left'`). */
|
|
326
|
+
function canonicalKeyName(key) {
|
|
327
|
+
const lower = key.toLowerCase();
|
|
328
|
+
return NAME_ALIASES[lower] ?? lower;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* The chords one binding lists. A binding may name several, any of which
|
|
332
|
+
* fires the action: `"ctrl+w | cmd+w"` (or, in `keybindings.json`, an array).
|
|
333
|
+
* A `|` right after a `+` / `-` is the key itself (`ctrl+|`).
|
|
334
|
+
*/
|
|
335
|
+
function bindingAlternatives(spec) {
|
|
336
|
+
if (typeof spec !== "string") return [];
|
|
337
|
+
return spec.split(/(?<![+\-])\|/).map((part) => part.trim()).filter(Boolean);
|
|
338
|
+
}
|
|
339
|
+
/** Every chord of `spec` that parses (see {@link bindingAlternatives}). */
|
|
340
|
+
function parseBindingSpecs(spec) {
|
|
341
|
+
return bindingAlternatives(spec).map(parseOneSpec).filter((p) => p !== null);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* The spec's first valid chord (callers that pre-parse one binding). Use
|
|
345
|
+
* {@link parseBindingSpecs} to honour every alternative.
|
|
346
|
+
*/
|
|
347
|
+
function parseBindingSpec(spec) {
|
|
348
|
+
return parseBindingSpecs(spec)[0] ?? null;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Parse one `'ctrl+shift+o'`-style chord. Returns `null` for empty /
|
|
352
|
+
* malformed inputs; the caller falls back to the default for that action.
|
|
353
|
+
*
|
|
354
|
+
* Tolerant by design:
|
|
355
|
+
* - Case-insensitive (`Ctrl+O` → same as `ctrl+o`).
|
|
356
|
+
* - Modifier order doesn't matter (`shift+ctrl+o` works).
|
|
357
|
+
* - Mixed `+` and `-` separators allowed (`ctrl-o`, `ctrl+o`).
|
|
358
|
+
* - Trailing / leading whitespace is stripped.
|
|
359
|
+
* - Duplicate modifiers collapse silently.
|
|
360
|
+
*/
|
|
361
|
+
function parseOneSpec(spec) {
|
|
362
|
+
const trimmed = spec.trim().toLowerCase();
|
|
363
|
+
if (!trimmed) return null;
|
|
364
|
+
const parts = trimmed.split(/[+\-]/).map((p) => p.trim()).filter(Boolean);
|
|
365
|
+
if (parts.length === 0) return null;
|
|
366
|
+
const result = {
|
|
367
|
+
ctrl: false,
|
|
368
|
+
shift: false,
|
|
369
|
+
alt: false,
|
|
370
|
+
meta: false,
|
|
371
|
+
name: ""
|
|
372
|
+
};
|
|
373
|
+
for (const part of parts) {
|
|
374
|
+
const modifier = MODIFIER_ALIASES[part];
|
|
375
|
+
if (modifier) {
|
|
376
|
+
result[modifier] = true;
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
if (result.name) return null;
|
|
380
|
+
result.name = NAME_ALIASES[part] ?? part;
|
|
381
|
+
}
|
|
382
|
+
if (!result.name) return null;
|
|
383
|
+
return result;
|
|
384
|
+
}
|
|
385
|
+
//#endregion
|
|
386
|
+
//#region src/extensions/references.ts
|
|
387
|
+
const ALLOWED_FLAGS = /* @__PURE__ */ new Set([
|
|
388
|
+
"i",
|
|
389
|
+
"u",
|
|
390
|
+
"m",
|
|
391
|
+
"s"
|
|
392
|
+
]);
|
|
393
|
+
const MAX_MATCHES = 200;
|
|
394
|
+
/** Compile a pattern, or `null` when its source doesn't parse. */
|
|
395
|
+
function compileReferencePattern(pattern) {
|
|
396
|
+
const flags = [...new Set([...pattern.flags ?? ""].filter((f) => ALLOWED_FLAGS.has(f)))].join("");
|
|
397
|
+
try {
|
|
398
|
+
return new RegExp(pattern.regex, `g${flags}`);
|
|
399
|
+
} catch {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function expandKey(template, m) {
|
|
404
|
+
return template.replace(/\$(\d)/g, (_, d) => m[Number(d)] ?? "").trim();
|
|
405
|
+
}
|
|
406
|
+
const compiled = /* @__PURE__ */ new WeakMap();
|
|
407
|
+
function compiledPatterns(provider) {
|
|
408
|
+
let list = compiled.get(provider.patterns);
|
|
409
|
+
if (!list) {
|
|
410
|
+
list = provider.patterns.flatMap((p) => {
|
|
411
|
+
const re = compileReferencePattern(p);
|
|
412
|
+
return re ? [[re, p.key ?? "$0"]] : [];
|
|
413
|
+
});
|
|
414
|
+
compiled.set(provider.patterns, list);
|
|
415
|
+
}
|
|
416
|
+
return list;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Every reference in `text` for the providers that scan `surface`, sorted,
|
|
420
|
+
* without overlaps: the earliest start wins, then the longest, then the
|
|
421
|
+
* earlier provider. Zero-length matches are skipped.
|
|
422
|
+
*/
|
|
423
|
+
function findReferences(text, providers, surface) {
|
|
424
|
+
if (!text || providers.length === 0) return [];
|
|
425
|
+
const found = [];
|
|
426
|
+
providers.forEach((provider, rank) => {
|
|
427
|
+
if (surface && provider.surfaces && !provider.surfaces.includes(surface)) return;
|
|
428
|
+
for (const [re, template] of compiledPatterns(provider)) {
|
|
429
|
+
re.lastIndex = 0;
|
|
430
|
+
let m;
|
|
431
|
+
let n = 0;
|
|
432
|
+
while ((m = re.exec(text)) && n++ < MAX_MATCHES) {
|
|
433
|
+
if (m[0].length === 0) {
|
|
434
|
+
re.lastIndex++;
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
const key = expandKey(template, m);
|
|
438
|
+
if (key) found.push({
|
|
439
|
+
start: m.index,
|
|
440
|
+
end: m.index + m[0].length,
|
|
441
|
+
providerId: provider.id,
|
|
442
|
+
key,
|
|
443
|
+
rank
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
found.sort((a, b) => a.start - b.start || b.end - b.start - (a.end - a.start) || a.rank - b.rank);
|
|
449
|
+
const out = [];
|
|
450
|
+
let cursor = 0;
|
|
451
|
+
for (const { rank: _rank, ...match } of found) {
|
|
452
|
+
if (match.start < cursor) continue;
|
|
453
|
+
out.push(match);
|
|
454
|
+
cursor = match.end;
|
|
455
|
+
}
|
|
456
|
+
return out;
|
|
457
|
+
}
|
|
458
|
+
/** The registry's providers as wire data, in registration order. */
|
|
459
|
+
function referenceProviderWires(registry) {
|
|
460
|
+
return registry.references.map(({ value }) => ({
|
|
461
|
+
id: value.id,
|
|
462
|
+
patterns: value.patterns.map((p) => ({
|
|
463
|
+
regex: p.regex,
|
|
464
|
+
...p.flags ? { flags: p.flags } : {},
|
|
465
|
+
...p.key ? { key: p.key } : {}
|
|
466
|
+
})),
|
|
467
|
+
...value.surfaces ? { surfaces: [...value.surfaces] } : {}
|
|
468
|
+
}));
|
|
469
|
+
}
|
|
470
|
+
/** A view clipped to bounds and stripped of anything not JSON-safe. */
|
|
471
|
+
function normalizeView(view) {
|
|
472
|
+
if (!view || typeof view.label !== "string" || !view.label) return null;
|
|
473
|
+
const str = (v, max) => typeof v === "string" && v ? v.slice(0, max) : void 0;
|
|
474
|
+
const icon = view.icon && (str(view.icon.gui, 128) || str(view.icon.tui, 8)) ? {
|
|
475
|
+
...str(view.icon.gui, 128) ? { gui: str(view.icon.gui, 128) } : {},
|
|
476
|
+
...str(view.icon.tui, 8) ? { tui: str(view.icon.tui, 8) } : {}
|
|
477
|
+
} : void 0;
|
|
478
|
+
const tone = view.tone && [
|
|
479
|
+
"muted",
|
|
480
|
+
"subtle",
|
|
481
|
+
"accent",
|
|
482
|
+
"success",
|
|
483
|
+
"warn",
|
|
484
|
+
"danger"
|
|
485
|
+
].includes(view.tone) ? view.tone : void 0;
|
|
486
|
+
const status = str(view.status, 64);
|
|
487
|
+
const title = str(view.title, 512);
|
|
488
|
+
const href = str(view.href, 2048);
|
|
489
|
+
return {
|
|
490
|
+
label: view.label.slice(0, 128),
|
|
491
|
+
...icon ? { icon } : {},
|
|
492
|
+
...tone ? { tone } : {},
|
|
493
|
+
...status ? { status } : {},
|
|
494
|
+
...title ? { title } : {},
|
|
495
|
+
...href ? { href } : {}
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
/** A cached resolver over the registry's providers. */
|
|
499
|
+
function createReferenceResolver(registry, options = {}) {
|
|
500
|
+
const ttl = options.ttlMs ?? 3e5;
|
|
501
|
+
const missTtl = options.missTtlMs ?? 6e4;
|
|
502
|
+
const timeoutMs = options.timeoutMs ?? 8e3;
|
|
503
|
+
const now = options.now ?? Date.now;
|
|
504
|
+
const cache = /* @__PURE__ */ new Map();
|
|
505
|
+
const inflight = /* @__PURE__ */ new Map();
|
|
506
|
+
const byId = (id) => registry.references.find((c) => c.value.id === id)?.value;
|
|
507
|
+
return {
|
|
508
|
+
resolve: async (providerId, key) => {
|
|
509
|
+
const provider = byId(providerId);
|
|
510
|
+
if (!provider) return null;
|
|
511
|
+
const id = `${providerId}\u0000${key}`;
|
|
512
|
+
const hit = cache.get(id);
|
|
513
|
+
if (hit && now() - hit.at < (hit.view ? ttl : missTtl)) return hit.view;
|
|
514
|
+
const pending = inflight.get(id);
|
|
515
|
+
if (pending) return pending;
|
|
516
|
+
const run = (async () => {
|
|
517
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
518
|
+
try {
|
|
519
|
+
const view = normalizeView(await provider.resolve(key, { signal }));
|
|
520
|
+
cache.set(id, {
|
|
521
|
+
view,
|
|
522
|
+
at: now()
|
|
523
|
+
});
|
|
524
|
+
return view;
|
|
525
|
+
} catch {
|
|
526
|
+
return hit?.view ?? null;
|
|
527
|
+
} finally {
|
|
528
|
+
inflight.delete(id);
|
|
529
|
+
}
|
|
530
|
+
})();
|
|
531
|
+
inflight.set(id, run);
|
|
532
|
+
return run;
|
|
533
|
+
},
|
|
534
|
+
clear: () => cache.clear()
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
//#endregion
|
|
538
|
+
//#region src/extensions/panels.ts
|
|
539
|
+
/**
|
|
540
|
+
* A load context from across a boundary (the GUI renderer), reduced to its
|
|
541
|
+
* known string fields. Hosts run it before handing the context to `load` /
|
|
542
|
+
* `onAction`.
|
|
543
|
+
*/
|
|
544
|
+
function normalizePanelLoadContext(raw) {
|
|
545
|
+
const ctx = raw && typeof raw === "object" ? raw : {};
|
|
546
|
+
const str = (v, max) => typeof v === "string" && v && v.length <= max ? v : void 0;
|
|
547
|
+
const sessionId = str(ctx.sessionId, 512);
|
|
548
|
+
const cwd = str(ctx.cwd, 4096);
|
|
549
|
+
const focusRaw = ctx.focus && typeof ctx.focus === "object" ? ctx.focus : void 0;
|
|
550
|
+
const kind = str(focusRaw?.kind, 64);
|
|
551
|
+
const uri = str(focusRaw?.uri, 2048);
|
|
552
|
+
return {
|
|
553
|
+
...sessionId ? { sessionId } : {},
|
|
554
|
+
...cwd ? { cwd } : {},
|
|
555
|
+
...kind || uri ? { focus: {
|
|
556
|
+
...kind ? { kind } : {},
|
|
557
|
+
...uri ? { uri } : {}
|
|
558
|
+
} } : {}
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
/** Caps applied before content crosses IPC or reaches a renderer. */
|
|
562
|
+
const PANEL_CONTENT_LIMITS = {
|
|
563
|
+
sections: 32,
|
|
564
|
+
itemsPerSection: 200,
|
|
565
|
+
actions: 8,
|
|
566
|
+
/** Per string field. */
|
|
567
|
+
textChars: 2e4,
|
|
568
|
+
/** Whole payload, JSON-serialised. */
|
|
569
|
+
bytes: 524288
|
|
570
|
+
};
|
|
571
|
+
function str(v, max = PANEL_CONTENT_LIMITS.textChars) {
|
|
572
|
+
return typeof v === "string" ? v.length > max ? `${v.slice(0, max - 1)}…` : v : void 0;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Coerce whatever `load()` returned into a well-formed `PanelContent`:
|
|
576
|
+
* unknown item kinds and malformed entries are dropped, strings are
|
|
577
|
+
* trimmed to the caps, and the whole thing is size-bounded. Never throws.
|
|
578
|
+
*/
|
|
579
|
+
function normalizePanelContent(input) {
|
|
580
|
+
const empty = { sections: [] };
|
|
581
|
+
if (!input || typeof input !== "object") return empty;
|
|
582
|
+
const o = input;
|
|
583
|
+
const sections = [];
|
|
584
|
+
if (Array.isArray(o.sections)) for (const raw of o.sections.slice(0, PANEL_CONTENT_LIMITS.sections)) {
|
|
585
|
+
const s = normalizeSection(raw, sections.length);
|
|
586
|
+
if (s) sections.push(s);
|
|
587
|
+
}
|
|
588
|
+
const actions = [];
|
|
589
|
+
if (Array.isArray(o.actions)) {
|
|
590
|
+
for (const raw of o.actions.slice(0, PANEL_CONTENT_LIMITS.actions)) if (raw && typeof raw === "object") {
|
|
591
|
+
const a = raw;
|
|
592
|
+
const id = str(a.id, 200);
|
|
593
|
+
const label = str(a.label, 200);
|
|
594
|
+
if (id && label) actions.push({
|
|
595
|
+
id,
|
|
596
|
+
label,
|
|
597
|
+
...a.tone === "danger" ? { tone: "danger" } : {}
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
const out = { sections };
|
|
602
|
+
const title = str(o.title, 200);
|
|
603
|
+
if (title) out.title = title;
|
|
604
|
+
if (typeof o.badge === "number" && Number.isFinite(o.badge)) out.badge = o.badge;
|
|
605
|
+
else if (typeof o.badge === "string" && o.badge) out.badge = o.badge.slice(0, 12);
|
|
606
|
+
if (actions.length > 0) out.actions = actions;
|
|
607
|
+
const emptyText = str(o.empty, 500);
|
|
608
|
+
if (emptyText) out.empty = emptyText;
|
|
609
|
+
return enforceBytes(out);
|
|
610
|
+
}
|
|
611
|
+
function normalizeSection(raw, index) {
|
|
612
|
+
if (!raw || typeof raw !== "object") return null;
|
|
613
|
+
const s = raw;
|
|
614
|
+
const items = [];
|
|
615
|
+
if (Array.isArray(s.items)) for (const item of s.items.slice(0, PANEL_CONTENT_LIMITS.itemsPerSection)) {
|
|
616
|
+
const n = normalizeItem(item);
|
|
617
|
+
if (n) items.push(n);
|
|
618
|
+
}
|
|
619
|
+
const out = {
|
|
620
|
+
id: str(s.id, 200) ?? `section-${index}`,
|
|
621
|
+
items
|
|
622
|
+
};
|
|
623
|
+
const title = str(s.title, 200);
|
|
624
|
+
if (title) out.title = title;
|
|
625
|
+
if (s.collapsed === true) out.collapsed = true;
|
|
626
|
+
return out;
|
|
627
|
+
}
|
|
628
|
+
function normalizeItem(raw) {
|
|
629
|
+
if (!raw || typeof raw !== "object") return null;
|
|
630
|
+
const i = raw;
|
|
631
|
+
switch (i.kind) {
|
|
632
|
+
case "row": {
|
|
633
|
+
const title = str(i.title, 500);
|
|
634
|
+
if (!title) return null;
|
|
635
|
+
const out = {
|
|
636
|
+
kind: "row",
|
|
637
|
+
title
|
|
638
|
+
};
|
|
639
|
+
const id = str(i.id, 200);
|
|
640
|
+
const subtitle = str(i.subtitle, 1e3);
|
|
641
|
+
const href = str(i.href, 2e3);
|
|
642
|
+
const status = str(i.status, 60);
|
|
643
|
+
const actionId = str(i.actionId, 200);
|
|
644
|
+
if (id) out.id = id;
|
|
645
|
+
if (subtitle) out.subtitle = subtitle;
|
|
646
|
+
if (href) out.href = href;
|
|
647
|
+
if (status) out.status = status;
|
|
648
|
+
if (actionId) out.actionId = actionId;
|
|
649
|
+
if (Array.isArray(i.badges)) out.badges = i.badges.filter(isBadge).slice(0, 8);
|
|
650
|
+
if (i.payload !== void 0 && isJsonValue(i.payload)) out.payload = i.payload;
|
|
651
|
+
return out;
|
|
652
|
+
}
|
|
653
|
+
case "markdown": {
|
|
654
|
+
const text = str(i.text);
|
|
655
|
+
return text === void 0 ? null : {
|
|
656
|
+
kind: "markdown",
|
|
657
|
+
text
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
case "kv":
|
|
661
|
+
if (!Array.isArray(i.rows)) return null;
|
|
662
|
+
return {
|
|
663
|
+
kind: "kv",
|
|
664
|
+
rows: i.rows.map((r) => {
|
|
665
|
+
if (!r || typeof r !== "object") return null;
|
|
666
|
+
const row = r;
|
|
667
|
+
const label = str(row.label, 200);
|
|
668
|
+
const value = str(row.value, 2e3);
|
|
669
|
+
return label !== void 0 && value !== void 0 ? {
|
|
670
|
+
label,
|
|
671
|
+
value
|
|
672
|
+
} : null;
|
|
673
|
+
}).filter((r) => r !== null).slice(0, PANEL_CONTENT_LIMITS.itemsPerSection)
|
|
674
|
+
};
|
|
675
|
+
case "custom": {
|
|
676
|
+
const renderer = str(i.renderer, 200);
|
|
677
|
+
const fallback = str(i.fallback);
|
|
678
|
+
if (!renderer || fallback === void 0) return null;
|
|
679
|
+
const out = {
|
|
680
|
+
kind: "custom",
|
|
681
|
+
renderer,
|
|
682
|
+
fallback
|
|
683
|
+
};
|
|
684
|
+
if (i.data !== void 0 && isJsonValue(i.data)) out.data = i.data;
|
|
685
|
+
return out;
|
|
686
|
+
}
|
|
687
|
+
default: return null;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
function isBadge(v) {
|
|
691
|
+
return Boolean(v && typeof v === "object" && typeof v.text === "string");
|
|
692
|
+
}
|
|
693
|
+
function isJsonValue(v) {
|
|
694
|
+
try {
|
|
695
|
+
JSON.stringify(v);
|
|
696
|
+
return v !== void 0 && typeof v !== "function" && typeof v !== "symbol";
|
|
697
|
+
} catch {
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Trim sections from the end until the payload fits the byte budget. A
|
|
703
|
+
* panel that overflows keeps its first sections and gets an `empty`-style
|
|
704
|
+
* note appended so the truncation is visible.
|
|
705
|
+
*/
|
|
706
|
+
function enforceBytes(content) {
|
|
707
|
+
const size = (c) => JSON.stringify(c).length;
|
|
708
|
+
if (size(content) <= PANEL_CONTENT_LIMITS.bytes) return content;
|
|
709
|
+
const sections = [...content.sections];
|
|
710
|
+
while (sections.length > 0 && size({
|
|
711
|
+
...content,
|
|
712
|
+
sections
|
|
713
|
+
}) > PANEL_CONTENT_LIMITS.bytes) sections.pop();
|
|
714
|
+
return {
|
|
715
|
+
...content,
|
|
716
|
+
sections: [...sections, {
|
|
717
|
+
id: "truncated",
|
|
718
|
+
items: [{
|
|
719
|
+
kind: "markdown",
|
|
720
|
+
text: "_Panel content truncated (too large)._"
|
|
721
|
+
}]
|
|
722
|
+
}]
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
/** Tab badge as shown next to the label; `undefined` when nothing to show. */
|
|
726
|
+
function panelBadgeText(badge) {
|
|
727
|
+
if (badge === void 0 || badge === 0 || badge === "") return void 0;
|
|
728
|
+
if (typeof badge === "number") return badge > 99 ? "99+" : String(badge);
|
|
729
|
+
return badge;
|
|
730
|
+
}
|
|
731
|
+
//#endregion
|
|
732
|
+
//#region src/chat/context-breakdown.ts
|
|
733
|
+
const LABELS = {
|
|
734
|
+
systemPrompt: "System prompt",
|
|
735
|
+
rules: "Rules (AGENTS.md)",
|
|
736
|
+
tools: "Tool definitions",
|
|
737
|
+
mcpTools: "MCP tools",
|
|
738
|
+
mcpInstructions: "MCP instructions",
|
|
739
|
+
skills: "Skills",
|
|
740
|
+
subagentDefs: "Searchable tools catalog",
|
|
741
|
+
conversation: "Conversation",
|
|
742
|
+
mcpToolsDeferred: "MCP tools (deferred)",
|
|
743
|
+
toolsDeferred: "System tools (deferred)",
|
|
744
|
+
autocompactBuffer: "Autocompact buffer",
|
|
745
|
+
freeSpace: "Free space"
|
|
746
|
+
};
|
|
747
|
+
/** Sum the heuristic token sizes of a list of strings. */
|
|
748
|
+
function sumEstimate(parts) {
|
|
749
|
+
let total = 0;
|
|
750
|
+
for (const p of parts) total += estimateTokens(p);
|
|
751
|
+
return total;
|
|
752
|
+
}
|
|
753
|
+
function mcpGroupTokens(group) {
|
|
754
|
+
const items = group.tools.map((t) => ({
|
|
755
|
+
id: `${group.server}:${t.name}`,
|
|
756
|
+
label: t.name,
|
|
757
|
+
tokens: estimateTokens(t.json),
|
|
758
|
+
estimated: true,
|
|
759
|
+
...t.description ? { description: t.description } : {},
|
|
760
|
+
group: group.server
|
|
761
|
+
}));
|
|
762
|
+
let total = 0;
|
|
763
|
+
for (const it of items) total += it.tokens;
|
|
764
|
+
return {
|
|
765
|
+
total,
|
|
766
|
+
items
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Shape a {@link ContextSnapshot} into a render-ready {@link ContextBreakdown}.
|
|
771
|
+
*
|
|
772
|
+
* Live categories (system prompt, tools, MCP tools/instructions, skills,
|
|
773
|
+
* memory, searchable-tools catalog, conversation) sum to `snapshot.used` — `conversation`
|
|
774
|
+
* absorbs the remainder so the bar matches the provider-reported total exactly.
|
|
775
|
+
* Deferred + autocompact + free-space buckets follow.
|
|
776
|
+
*
|
|
777
|
+
* When `snapshot.exact` carries provider counts, the matching categories use
|
|
778
|
+
* them (system, tools) and drop their `estimated` flag; everything else stays
|
|
779
|
+
* on the heuristic.
|
|
780
|
+
*/
|
|
781
|
+
function buildContextBreakdown(snapshot) {
|
|
782
|
+
const exact = snapshot.exact;
|
|
783
|
+
const systemExact = typeof exact?.system === "number";
|
|
784
|
+
const rulesTokens = snapshot.rulesBlock ? estimateTokens(snapshot.rulesBlock) : 0;
|
|
785
|
+
const rulesItems = (snapshot.rulesFiles ?? []).map((f) => ({
|
|
786
|
+
id: f.path,
|
|
787
|
+
label: f.path,
|
|
788
|
+
tokens: 0,
|
|
789
|
+
estimated: false
|
|
790
|
+
}));
|
|
791
|
+
const skillsTokens = snapshot.skillsCatalog ? estimateTokens(snapshot.skillsCatalog) : 0;
|
|
792
|
+
const mcpInstructionsTokens = snapshot.mcpInstructions ? estimateTokens(snapshot.mcpInstructions) : 0;
|
|
793
|
+
const subagentTokens = snapshot.subagentDefs ? estimateTokens(snapshot.subagentDefs) : 0;
|
|
794
|
+
const embeddedSubsections = rulesTokens + skillsTokens + mcpInstructionsTokens + subagentTokens;
|
|
795
|
+
const systemTotal = systemExact ? exact.system : estimateTokens(snapshot.system);
|
|
796
|
+
const baseSystemTokens = Math.max(0, systemTotal - embeddedSubsections);
|
|
797
|
+
const nativeToolsEst = sumEstimate(snapshot.toolsJson);
|
|
798
|
+
const mcpDisclosed = snapshot.mcpGroups.map(mcpGroupTokens);
|
|
799
|
+
const mcpToolsEst = mcpDisclosed.reduce((a, g) => a + g.total, 0);
|
|
800
|
+
let nativeToolsTokens = nativeToolsEst;
|
|
801
|
+
let mcpToolsTokens = mcpToolsEst;
|
|
802
|
+
let toolsEstimated = true;
|
|
803
|
+
if (systemExact && typeof exact?.systemAndTools === "number") {
|
|
804
|
+
const exactToolsTotal = Math.max(0, exact.systemAndTools - exact.system);
|
|
805
|
+
const estTotal = nativeToolsEst + mcpToolsEst;
|
|
806
|
+
if (estTotal > 0) {
|
|
807
|
+
nativeToolsTokens = Math.round(exactToolsTotal * (nativeToolsEst / estTotal));
|
|
808
|
+
mcpToolsTokens = exactToolsTotal - nativeToolsTokens;
|
|
809
|
+
} else {
|
|
810
|
+
nativeToolsTokens = exactToolsTotal;
|
|
811
|
+
mcpToolsTokens = 0;
|
|
812
|
+
}
|
|
813
|
+
toolsEstimated = false;
|
|
814
|
+
}
|
|
815
|
+
const live = [];
|
|
816
|
+
const push = (id, tokens, estimated, items) => {
|
|
817
|
+
if (tokens <= 0 && !items?.length) return;
|
|
818
|
+
live.push({
|
|
819
|
+
id,
|
|
820
|
+
label: LABELS[id],
|
|
821
|
+
tokens: Math.max(0, tokens),
|
|
822
|
+
estimated,
|
|
823
|
+
...items?.length ? { items } : {}
|
|
824
|
+
});
|
|
825
|
+
};
|
|
826
|
+
push("systemPrompt", baseSystemTokens, !systemExact);
|
|
827
|
+
push("rules", rulesTokens, true, rulesItems);
|
|
828
|
+
push("skills", skillsTokens, true);
|
|
829
|
+
push("mcpInstructions", mcpInstructionsTokens, true);
|
|
830
|
+
push("subagentDefs", subagentTokens, true);
|
|
831
|
+
push("tools", nativeToolsTokens, toolsEstimated, snapshot.toolItems?.map((t) => ({
|
|
832
|
+
id: t.name,
|
|
833
|
+
label: t.name,
|
|
834
|
+
tokens: estimateTokens(t.json),
|
|
835
|
+
estimated: true,
|
|
836
|
+
...t.description ? { description: t.description } : {}
|
|
837
|
+
})));
|
|
838
|
+
push("mcpTools", mcpToolsTokens, toolsEstimated, mcpDisclosed.flatMap((g) => g.items));
|
|
839
|
+
const accountedStatic = live.reduce((a, c) => a + c.tokens, 0);
|
|
840
|
+
push("conversation", Math.max(0, snapshot.used - accountedStatic), !(systemExact && !toolsEstimated));
|
|
841
|
+
const deferred = [];
|
|
842
|
+
const deferredNativeTools = sumEstimate(snapshot.deferredToolsJson);
|
|
843
|
+
if (deferredNativeTools > 0) deferred.push({
|
|
844
|
+
id: "toolsDeferred",
|
|
845
|
+
label: LABELS.toolsDeferred,
|
|
846
|
+
tokens: deferredNativeTools,
|
|
847
|
+
estimated: true,
|
|
848
|
+
deferred: true
|
|
849
|
+
});
|
|
850
|
+
const deferredMcp = snapshot.deferredMcpGroups.map(mcpGroupTokens);
|
|
851
|
+
const deferredMcpTotal = deferredMcp.reduce((a, g) => a + g.total, 0);
|
|
852
|
+
if (deferredMcpTotal > 0) deferred.push({
|
|
853
|
+
id: "mcpToolsDeferred",
|
|
854
|
+
label: LABELS.mcpToolsDeferred,
|
|
855
|
+
tokens: deferredMcpTotal,
|
|
856
|
+
estimated: true,
|
|
857
|
+
deferred: true,
|
|
858
|
+
items: deferredMcp.flatMap((g) => g.items)
|
|
859
|
+
});
|
|
860
|
+
if (snapshot.autocompactBuffer > 0) deferred.push({
|
|
861
|
+
id: "autocompactBuffer",
|
|
862
|
+
label: LABELS.autocompactBuffer,
|
|
863
|
+
tokens: snapshot.autocompactBuffer,
|
|
864
|
+
estimated: false,
|
|
865
|
+
deferred: true
|
|
866
|
+
});
|
|
867
|
+
const free = Math.max(0, snapshot.effectiveWindow - snapshot.used);
|
|
868
|
+
deferred.push({
|
|
869
|
+
id: "freeSpace",
|
|
870
|
+
label: LABELS.freeSpace,
|
|
871
|
+
tokens: free,
|
|
872
|
+
estimated: false,
|
|
873
|
+
deferred: true
|
|
874
|
+
});
|
|
875
|
+
const categories = [...live, ...deferred];
|
|
876
|
+
const hasEstimates = live.some((c) => c.estimated && c.tokens > 0);
|
|
877
|
+
const fraction = snapshot.effectiveWindow > 0 ? Math.max(0, Math.min(1, snapshot.used / snapshot.effectiveWindow)) : 0;
|
|
878
|
+
return {
|
|
879
|
+
modelId: snapshot.modelId,
|
|
880
|
+
used: snapshot.used,
|
|
881
|
+
effectiveWindow: snapshot.effectiveWindow,
|
|
882
|
+
fraction,
|
|
883
|
+
categories,
|
|
884
|
+
hasEstimates,
|
|
885
|
+
...snapshot.usage ? { usage: snapshot.usage } : {},
|
|
886
|
+
...snapshot.extensionSections?.length ? { extensionSections: snapshot.extensionSections } : {},
|
|
887
|
+
...snapshot.activeSkills?.length ? { activeSkills: snapshot.activeSkills } : {}
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
//#endregion
|
|
891
|
+
//#region src/chat/context-segments.ts
|
|
892
|
+
/**
|
|
893
|
+
* Context segments — pure transforms.
|
|
894
|
+
*
|
|
895
|
+
* Sibling to `context-breakdown.ts`: where that module answers "how many
|
|
896
|
+
* tokens is each part of my context", this one answers "what IS each part,
|
|
897
|
+
* and where did it come from". It turns the same assembled-prompt pieces into
|
|
898
|
+
* a flat list of {@link ContextSegment}s carrying the actual TEXT plus its
|
|
899
|
+
* provenance, so a UI can list every chunk loaded by default in a session,
|
|
900
|
+
* let the user read it, and open the file behind it when there is one.
|
|
901
|
+
*
|
|
902
|
+
* No React, no node — a browser-context renderer imports these via
|
|
903
|
+
* `zidane/chat/pure`.
|
|
904
|
+
*
|
|
905
|
+
* Provenance is honest about what can and can't be opened:
|
|
906
|
+
* - `'file'` — a real path on disk (AGENTS.md / CLAUDE.md / ruler md).
|
|
907
|
+
* The only origin that carries `path`, hence the only one
|
|
908
|
+
* a host can hand to `$EDITOR`.
|
|
909
|
+
* - `'built-in'` — compiled into the binary (base doctrine).
|
|
910
|
+
* - `'generated'` — assembled at prompt time from discovered state (the
|
|
911
|
+
* skills catalog is rendered from the skill manifests,
|
|
912
|
+
* the searchable-tools catalog from lazy MCP tools).
|
|
913
|
+
* - `'mcp'` — served by a remote MCP server at connect time.
|
|
914
|
+
*/
|
|
915
|
+
/**
|
|
916
|
+
* Remove the first occurrence of `part` from `whole`, collapsing the blank-line
|
|
917
|
+
* run left AT THE JOIN.
|
|
918
|
+
*
|
|
919
|
+
* Used to carve the rules block out of the base system so the "System prompt"
|
|
920
|
+
* segment reports only doctrine + env. Substring-based because that's the
|
|
921
|
+
* contract the assembly documents (`rulesBlock` IS a substring of
|
|
922
|
+
* `baseSystem`); a miss leaves `whole` untouched, which degrades to
|
|
923
|
+
* over-reporting the base row rather than dropping text on the floor.
|
|
924
|
+
*
|
|
925
|
+
* The collapse is deliberately scoped to the seam. An earlier version ran
|
|
926
|
+
* `/\n{3,}/g` over the whole result, which rewrote blank-line runs ANYWHERE in
|
|
927
|
+
* the doctrine — and this tab exists precisely so the user can read what is in
|
|
928
|
+
* context, not a reflowed approximation of it. Interior bytes now survive
|
|
929
|
+
* verbatim; only the newlines that met when `part` was excised are normalized,
|
|
930
|
+
* plus a `trim()` so a segment can't open or close on blank lines.
|
|
931
|
+
*/
|
|
932
|
+
function removeFirst(whole, part) {
|
|
933
|
+
if (!part) return whole;
|
|
934
|
+
const at = whole.indexOf(part);
|
|
935
|
+
if (at < 0) return whole;
|
|
936
|
+
const before = whole.slice(0, at);
|
|
937
|
+
const after = whole.slice(at + part.length);
|
|
938
|
+
const trailing = /\n*$/.exec(before)?.[0] ?? "";
|
|
939
|
+
const leading = /^\n*/.exec(after)?.[0] ?? "";
|
|
940
|
+
const seam = trailing.length + leading.length >= 2 ? "\n\n" : `${trailing}${leading}`;
|
|
941
|
+
return `${before.slice(0, before.length - trailing.length)}${seam}${after.slice(leading.length)}`.trim();
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Best-effort display name for an instruction file: its basename, with the
|
|
945
|
+
* parent directory prefixed when the basename alone would be ambiguous
|
|
946
|
+
* (`AGENTS.md` appears at up to four paths per scope). Path-separator handling
|
|
947
|
+
* covers both POSIX and Windows so this stays node-free.
|
|
948
|
+
*/
|
|
949
|
+
function fileLabel(path) {
|
|
950
|
+
const parts = path.split(/[/\\]/).filter(Boolean);
|
|
951
|
+
const base = parts.at(-1) ?? path;
|
|
952
|
+
const parent = parts.at(-2);
|
|
953
|
+
return parent?.startsWith(".") ? `${parent}/${base}` : base;
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Shape assembled-prompt pieces into a flat, render-ready segment list.
|
|
957
|
+
*
|
|
958
|
+
* Order is prompt order — base doctrine, then instruction files (broadest
|
|
959
|
+
* scope first, as `discoverAgentsMd` returns them), then the appended
|
|
960
|
+
* catalogs. Empty / whitespace-only pieces are dropped so the list never
|
|
961
|
+
* shows a zero-byte row.
|
|
962
|
+
*/
|
|
963
|
+
function buildContextSegments(input) {
|
|
964
|
+
const segments = [];
|
|
965
|
+
const push = (seg) => {
|
|
966
|
+
if (!seg.text.trim()) return;
|
|
967
|
+
segments.push({
|
|
968
|
+
...seg,
|
|
969
|
+
tokens: estimateTokens(seg.text)
|
|
970
|
+
});
|
|
971
|
+
};
|
|
972
|
+
const base = input.baseSystem ?? input.system ?? "";
|
|
973
|
+
const overridden = input.systemPath !== void 0;
|
|
974
|
+
push({
|
|
975
|
+
id: "system",
|
|
976
|
+
label: "System prompt",
|
|
977
|
+
origin: overridden ? "file" : "built-in",
|
|
978
|
+
detail: overridden ? "SYSTEM.md override + environment" : "doctrine + environment",
|
|
979
|
+
text: input.rulesBlock ? removeFirst(base, input.rulesBlock) : base,
|
|
980
|
+
...input.systemPath !== void 0 ? { path: input.systemPath } : {}
|
|
981
|
+
});
|
|
982
|
+
for (const file of input.rulesFiles ?? []) push({
|
|
983
|
+
id: `rules:${file.path}`,
|
|
984
|
+
label: fileLabel(file.path),
|
|
985
|
+
origin: "file",
|
|
986
|
+
...file.source ? { detail: file.source } : {},
|
|
987
|
+
text: file.contents,
|
|
988
|
+
path: file.path
|
|
989
|
+
});
|
|
990
|
+
push({
|
|
991
|
+
id: "skills",
|
|
992
|
+
label: "Skills catalog",
|
|
993
|
+
origin: "generated",
|
|
994
|
+
detail: "name + description per skill (bodies load on activation)",
|
|
995
|
+
text: input.skillsCatalog ?? ""
|
|
996
|
+
});
|
|
997
|
+
push({
|
|
998
|
+
id: "mcp-instructions",
|
|
999
|
+
label: "MCP instructions",
|
|
1000
|
+
origin: "mcp",
|
|
1001
|
+
detail: "served by the connected servers",
|
|
1002
|
+
text: input.mcpInstructions ?? ""
|
|
1003
|
+
});
|
|
1004
|
+
push({
|
|
1005
|
+
id: "subagent-defs",
|
|
1006
|
+
label: "Searchable tools",
|
|
1007
|
+
origin: "generated",
|
|
1008
|
+
detail: "name + description per lazy MCP tool (schemas load via tool_search)",
|
|
1009
|
+
text: input.subagentDefs ?? ""
|
|
1010
|
+
});
|
|
1011
|
+
return segments;
|
|
1012
|
+
}
|
|
1013
|
+
//#endregion
|
|
1014
|
+
export { normalizeBadgeTarget as C, normalizeBadgeEffect as S, sessionBadgeTarget as T, badgePromptText as _, normalizePanelLoadContext as a, extensionBadgeActions as b, createReferenceResolver as c, bindingAlternatives as d, canonicalKeyName as f, badgeMenu as g, artifactBadgeTarget as h, normalizePanelContent as i, findReferences as l, parseBindingSpecs as m, buildContextBreakdown as n, panelBadgeText as o, parseBindingSpec as p, PANEL_CONTENT_LIMITS as r, compileReferencePattern as s, buildContextSegments as t, referenceProviderWires as u, builtinBadgeActions as v, runBadgeAction as w, mergeBadgeMenu as x, builtinBadgeEffect as y };
|
|
1015
|
+
|
|
1016
|
+
//# sourceMappingURL=context-segments-BHKlagL6.js.map
|