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 @@
|
|
|
1
|
+
{"version":3,"file":"url-D8HCl65b.js","names":[],"sources":["../src/chat/browser/url.ts","../src/chat/command-notes.ts","../src/chat/edit-approval.ts","../src/chat/edit-diff.ts","../src/chat/prompt-segments.ts","../src/chat/settings-defaults.ts","../src/chat/hosts/types.ts","../src/chat/secret-shapes.ts","../src/chat/hosts/url.ts"],"sourcesContent":["/**\n * What the dev browser will load. It is a browser for the app you are\n * building, not the web at large: http(s) only, bare local addresses\n * default to http, anything that looks like a host gets https. Shared by the\n * GUI address bar and the agent's `browser_open` / `browser_navigate`.\n */\n\nconst LOCAL_HOST = /^(?:localhost|127(?:\\.\\d{1,3}){3}|0\\.0\\.0\\.0|\\[::1\\]|[\\w-]+\\.localhost)(?::\\d+)?(?:[/?#]|$)/i\nconst HOST_LIKE = /^(?:[\\w-]+\\.)+[a-z]{2,}(?::\\d+)?(?:[/?#]|$)/i\nconst PORT_ONLY = /^:?(\\d{2,5})([/?#].*)?$/\n\n/** Normalize address-bar input to a loadable URL, or `null` when it is not one. */\nexport function normalizeBrowserUrl(input: string): string | null {\n const text = input.trim()\n if (!text)\n return null\n // `:5173` or `5173` means a local dev server.\n const port = PORT_ONLY.exec(text)\n if (port)\n return canonical(`http://localhost:${port[1]}${port[2] ?? ''}`)\n if (/^[a-z][a-z\\d+.-]*:\\/\\//i.test(text))\n return isAllowedBrowserUrl(text) ? canonical(text) : null\n if (/\\s/.test(text))\n return null\n if (LOCAL_HOST.test(text))\n return canonical(`http://${text}`)\n if (HOST_LIKE.test(text))\n return canonical(`https://${text}`)\n return null\n}\n\n/** Only http(s) pages (and the blank page) ever load in the dev browser. */\nexport function isAllowedBrowserUrl(url: string): boolean {\n if (url === 'about:blank')\n return true\n try {\n const { protocol } = new URL(url)\n return protocol === 'http:' || protocol === 'https:'\n }\n catch {\n return false\n }\n}\n\n/** A loopback address: the dev servers the browser exists for. */\nexport function isLocalBrowserUrl(url: string): boolean {\n try {\n const host = new URL(url).hostname\n return host === 'localhost' || host.endsWith('.localhost') || host === '0.0.0.0' || host === '[::1]' || /^127(?:\\.\\d{1,3}){3}$/.test(host)\n }\n catch {\n return false\n }\n}\n\nfunction canonical(url: string): string | null {\n try {\n return new URL(url).toString()\n }\n catch {\n return null\n }\n}\n","/**\n * How a `/` command reads in the transcript: the invocation is the user's\n * prompt, everything the command did is that one exchange, and the notes it\n * left for the model (`ctx.appendContext`) close it as one quiet receipt\n * line. Shared by the live hosts, the replay in `eventsFromTurns`, and both\n * renderers, so the shape cannot drift between them.\n */\nimport type { StreamEvent } from './types'\n\n/** The persisted invocation header block: `` `❯ /commit args` ``. */\nexport function commandHeaderBlock(invocation: string): string {\n return `\\`❯ ${invocation}\\``\n}\n\n/** `/name args` from a persisted header block, or null when the text is not one. */\nexport function parseCommandHeader(text: string): string | null {\n const match = /^`❯ (\\/[\\s\\S]+)`$/.exec(text.trim())\n return match ? match[1]! : null\n}\n\nconst PREFIX_SEPARATOR = /^\\s*(?:[:·—-]\\s*)?/\n\n/**\n * The receipt text for one note. Older displays repeat the command\n * (`/commit: 83dfea7`, `/review — 3 reviewers, fixes applied`); the prompt\n * bubble above already names it, so the prefix goes, and a leftover ` — `\n * reads as ` · `. A note without a display shows its first line.\n */\nexport function commandNoteText(display: string | undefined, text: string, invocation?: string): string {\n let line = (display ?? text.split('\\n').find(l => l.trim()) ?? '').trim()\n const name = invocation?.split(/\\s/, 1)[0]\n const prefixes = [invocation, name].filter((p): p is string => Boolean(p))\n const prefix = prefixes.find(p => line.startsWith(p))\n ?? /^\\/[\\w.:-]+/.exec(line)?.[0]\n if (prefix) {\n const rest = line.slice(prefix.length).replace(PREFIX_SEPARATOR, '')\n // Older /commit displays were the bare sha.\n if (rest)\n line = /^[0-9a-f]{7,40}$/.test(rest) ? `committed ${rest}` : rest\n }\n line = line.replace(/\\s+—\\s+/g, ' · ')\n return line.length > 160 ? `${line.slice(0, 159)}…` : line\n}\n\n/**\n * The `display` a context note persists with: the command's marker, its\n * first line when it gave none, or `''` for a model-only note\n * (`display: false`), which shows nothing.\n */\nexport function noteDisplay(display: string | false | undefined, text: string): string {\n return display === false ? '' : (display ?? commandNoteText(undefined, text))\n}\n\n/** A command step label: the display as given, minus any leftover ` — `. */\nexport function commandStepLabel(display: string): string {\n return display.replace(/\\s+—\\s+/g, ' · ')\n}\n\nconst merged = new WeakMap<StreamEvent, { key: string, event: StreamEvent }>()\n\nfunction isTopPrompt(event: StreamEvent): boolean {\n return event.kind === 'user-prompt' && !event.childId && (event.depth ?? 0) === 0\n}\n\n/**\n * One receipt line per exchange: every `command-note` in an exchange moves\n * to its end and joins into a single event (`committed 83dfea7 · pushed to\n * origin/main`). Returns `events` itself when there is nothing to merge;\n * the merged event keeps its identity while its notes do not change, so\n * memoised rows stay put.\n */\nexport function gatherCommandNotes<E extends StreamEvent>(events: readonly E[]): readonly E[] {\n if (!events.some(e => e.kind === 'command-note'))\n return events\n const out: E[] = []\n let notes: E[] = []\n const flush = () => {\n if (notes.length === 0)\n return\n const first = notes[0]!\n const key = notes.map(n => n.text).join('\\u0000')\n let event = first\n if (notes.length > 1) {\n const cached = merged.get(first)\n event = cached?.key === key ? cached.event as E : { ...first, text: notes.map(n => n.text).join(' · ') }\n merged.set(first, { key, event })\n }\n // Ahead of the separators that close the exchange.\n let at = out.length\n while (at > 0 && out[at - 1]!.kind === 'separator')\n at--\n out.splice(at, 0, event)\n notes = []\n }\n for (const event of events) {\n if (isTopPrompt(event))\n flush()\n if (event.kind === 'command-note' && !event.childId) {\n notes.push(event)\n continue\n }\n out.push(event)\n }\n flush()\n return out.length === events.length && out.every((e, i) => e === events[i]) ? events : out\n}\n","/**\n * Pure helpers for the file-edit approval gate.\n *\n * Lives in `chat/` (not `tui/`) so unit tests can exercise the decision\n * logic without mounting React. The chat host binds these helpers in\n * `applyGate` (`chat/host/approval-gate/index.ts`) and the edit-result\n * transform (`chat/host/edits/index.ts`); replay code\n * (`eventsFromTurns`) reuses the result parser.\n */\n\nimport type { ToolResultContent } from '../types'\nimport type { ApprovalDecision } from './safe-mode-context'\nimport type { EditOutcome, EditOutcomeKind, EditPayload } from './types'\n\n/**\n * Convert a per-hunk approval mask into an `EditOutcome[]`. `true` →\n * `applied`; `false` → `denied` with the supplied reason.\n *\n * Length is `Math.max(mask.length, fallbackLength)` so callers passing a\n * shorter mask still get a fully-populated array — missing entries\n * default to applied, matching the \"no decision => keep\" convention.\n */\nexport function maskToOutcomeKinds(\n mask: readonly boolean[],\n fallbackLength: number,\n deniedReason = 'denied by user',\n): EditOutcome[] {\n const len = Math.max(mask.length, fallbackLength)\n const out: EditOutcome[] = []\n for (let i = 0; i < len; i++) {\n const keep = i < mask.length ? mask[i] : true\n out.push(keep ? { kind: 'applied' } : { kind: 'denied', reason: deniedReason })\n }\n return out\n}\n\n/**\n * Apply an `ApprovalDecision` to a payload, returning the resolved\n * per-hunk outcomes + the gate-level verdict.\n *\n * Pure — does not mutate `input` or `payload`. The TUI's `applyGate`\n * consumes the result: stashes `outcomes` in the pending-annotation map\n * (keyed by callId) so `tool:transform` can append the\n * `<edit-outcomes>` block to the tool result, rebinds `ctx.input.edits`\n * to the approved subset for `partial`, and emits the `syntheticEvent`\n * for fully-denied or fully-blocked calls.\n */\nexport interface ResolvedApproval {\n /** Final state of every hunk after the decision (1:1 with payload.hunks). */\n outcomes: EditOutcome[]\n /** True when no hunk will be applied — gate should `block` the call. */\n shouldBlock: boolean\n /**\n * Synthetic `EditPayload` to render in the transcript. Identical to the\n * incoming payload but with `outcomes` set so the renderer can badge\n * each hunk. Only meaningful when at least one hunk was denied —\n * an all-applied decision returns `null` here and the normal\n * `tool:before` event suffices.\n */\n syntheticEvent: EditPayload | null\n}\n\nexport function resolveApprovalForPayload(\n decision: ApprovalDecision,\n payload: EditPayload,\n): ResolvedApproval {\n const total = payload.hunks.length\n\n if (decision === 'deny') {\n const outcomes: EditOutcome[] = Array.from(\n { length: total },\n () => ({ kind: 'denied' as const, reason: 'denied by user' }),\n )\n return {\n outcomes,\n shouldBlock: true,\n syntheticEvent: { ...payload, outcomes },\n }\n }\n\n if (typeof decision === 'object' && decision.kind === 'partial') {\n const outcomes = maskToOutcomeKinds(decision.mask, total)\n const anyApplied = outcomes.some(o => o.kind === 'applied')\n return {\n outcomes,\n shouldBlock: !anyApplied,\n syntheticEvent: { ...payload, outcomes },\n }\n }\n\n // accept-once / accept-session / accept-safelist: every hunk applies.\n // No synthetic event — `tool:before` will paint the standard payload.\n return {\n outcomes: Array.from({ length: total }, () => ({ kind: 'applied' as const })),\n shouldBlock: false,\n syntheticEvent: null,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Result annotation — XML-like sentinel block appended to edit tool\n// results so the renderer (live + replay) can reconstruct per-hunk\n// outcomes without a host-side side-channel on `tool_call.input`.\n//\n// Shape (one block per call):\n//\n// <edit-outcomes>\n// #1 applied\n// #2 denied: denied by user\n// #3 applied\n// </edit-outcomes>\n//\n// - Opening + closing tags each on their own line.\n// - One line per hunk: `#<1-based index> <kind>[: <reason>]`.\n// - `kind` is one of `applied | denied | skipped | failed`.\n//\n// The TUI's `tool:transform` hook appends the block when at least one\n// hunk is NOT applied — an all-applied call needs no annotation since\n// the legacy summary line conveys the same information.\n// ---------------------------------------------------------------------------\n\n/** Sentinel tags used by {@link buildEditOutcomesAnnotation} / parser. */\nconst ANNOTATION_OPEN = '<edit-outcomes>'\nconst ANNOTATION_CLOSE = '</edit-outcomes>'\n\nconst OUTCOME_KIND_RE = /^applied|denied|skipped|failed$/\nconst OUTCOME_LINE_RE = /^#(\\d+) (applied|denied|skipped|failed)(?:: ?(.*))?$/\n\n/**\n * Render an `EditOutcome[]` as the wire-format annotation block. Returns\n * the body to APPEND to a tool result; callers join with a leading\n * `\\n\\n` separator. Idempotent on missing reasons — bare `applied` lines\n * stay terse.\n */\nexport function buildEditOutcomesAnnotation(outcomes: readonly EditOutcome[]): string {\n const lines: string[] = [ANNOTATION_OPEN]\n for (let i = 0; i < outcomes.length; i++) {\n const o = outcomes[i]\n if (!OUTCOME_KIND_RE.test(o.kind))\n continue\n const reason = o.reason ? `: ${o.reason}` : ''\n lines.push(`#${i + 1} ${o.kind}${reason}`)\n }\n lines.push(ANNOTATION_CLOSE)\n return lines.join('\\n')\n}\n\n/**\n * Parse an `<edit-outcomes>…</edit-outcomes>` annotation block out of a\n * tool result body. Returns the outcomes keyed by 1-based hunk index, or\n * `null` when the block is missing / malformed.\n *\n * Anchored on the explicit tag pair so the parser doesn't false-positive\n * on natural prose that happens to contain `#1 applied`.\n */\nexport function parseEditOutcomesFromResult(\n result: string | readonly ToolResultContent[],\n): EditOutcome[] | null {\n const text = typeof result === 'string'\n ? result\n : result\n .filter((b): b is Extract<ToolResultContent, { type: 'text' }> => b.type === 'text')\n .map(b => b.text)\n .join('\\n')\n\n if (!text)\n return null\n\n const openIdx = text.indexOf(`\\n${ANNOTATION_OPEN}\\n`)\n const startIdx = openIdx >= 0 ? openIdx + 1 : (text.startsWith(`${ANNOTATION_OPEN}\\n`) ? 0 : -1)\n if (startIdx < 0)\n return null\n\n const closeNeedle = `\\n${ANNOTATION_CLOSE}`\n const closeIdx = text.indexOf(closeNeedle, startIdx)\n if (closeIdx < 0)\n return null\n\n const body = text.slice(startIdx + ANNOTATION_OPEN.length + 1, closeIdx)\n const found: Array<{ idx: number, outcome: EditOutcome }> = []\n for (const line of body.split('\\n')) {\n if (line.length === 0)\n continue\n const m = OUTCOME_LINE_RE.exec(line)\n if (!m)\n return null\n const idx = Number.parseInt(m[1], 10)\n if (!Number.isFinite(idx) || idx < 1)\n return null\n const kind = m[2] as EditOutcomeKind\n const reason = m[3]?.trim()\n found.push({\n idx,\n outcome: {\n kind,\n ...(reason ? { reason } : {}),\n },\n })\n }\n\n if (found.length === 0)\n return null\n\n const maxIdx = Math.max(...found.map(f => f.idx))\n const outcomes: EditOutcome[] = Array.from({ length: maxIdx }, () => ({ kind: 'applied' }))\n for (const { idx, outcome } of found)\n outcomes[idx - 1] = outcome\n return outcomes\n}\n\n/**\n * Strip the first `<edit-outcomes>…</edit-outcomes>` block out of a tool\n * result body, returning the surrounding text. Used by the\n * `tool:transform` hook to peel a body-emitted annotation before\n * re-appending the merged (approval ∪ body) version — otherwise the\n * result would carry two annotation blocks and\n * {@link parseEditOutcomesFromResult} would only see the first.\n *\n * Anchored on the same `\\n<edit-outcomes>\\n` / start-of-string newline\n * shape the parser uses, so prose that incidentally mentions\n * `<edit-outcomes>` (e.g. a model summarizing its own format) isn't\n * mistakenly stripped. Trims a single leading `\\n\\n` separator when\n * present so successive strips don't leave dangling blank lines.\n * Idempotent on inputs that don't contain a properly-anchored block.\n */\nexport function stripEditOutcomesAnnotation(text: string): string {\n // Mirror `parseEditOutcomesFromResult`'s anchor: either preceded by\n // a newline (the common case after a `\\n\\n` separator from the body)\n // OR at the very start of the body. A bare `<edit-outcomes>` inside\n // prose without that surrounding newline shape stays untouched.\n const newlineNeedle = `\\n${ANNOTATION_OPEN}\\n`\n const newlineIdx = text.indexOf(newlineNeedle)\n let openIdx: number\n if (newlineIdx >= 0)\n openIdx = newlineIdx + 1\n else if (text.startsWith(`${ANNOTATION_OPEN}\\n`))\n openIdx = 0\n else\n return text\n\n const closeIdx = text.indexOf(ANNOTATION_CLOSE, openIdx)\n if (closeIdx < 0)\n return text\n const blockEnd = closeIdx + ANNOTATION_CLOSE.length\n // Eat one preceding `\\n\\n` separator (the shape the writer emits)\n // so the trimmed text doesn't end with an awkward double newline.\n const sepStart = openIdx >= 2 && text.slice(openIdx - 2, openIdx) === '\\n\\n'\n ? openIdx - 2\n : openIdx\n return text.slice(0, sepStart) + text.slice(blockEnd)\n}\n\n/**\n * Merge body-side outcomes (keyed against the approved subset the tool\n * actually ran on, in subset-position order) into approval-side outcomes\n * (1:1 with the model's ORIGINAL `edits` list, with `denied` entries for\n * every hunk the user dropped).\n *\n * Algorithm: walk the approval array; every `applied` placeholder\n * corresponds to one approved hunk that the body ran. Consume body's\n * outcomes in order against those placeholders. Non-`applied` approval\n * entries (`denied`, `skipped`) stay untouched — they describe gate-\n * level decisions the body never saw.\n *\n * Pure. Returns a fresh array; never mutates either input.\n *\n * Edge cases:\n * - `body` is empty / shorter than the approved count → remaining\n * approval `applied` placeholders stay as `applied` (the body ran\n * happily; absence of a body entry means nothing failed).\n * - `body` longer than approved count → trailing body entries are\n * ignored. Shouldn't happen in practice (body sees the rebound\n * subset), but the guard keeps the merge total-pure.\n */\nexport function mergeApprovalAndBodyOutcomes(\n approval: readonly EditOutcome[],\n body: readonly EditOutcome[] | null,\n): EditOutcome[] {\n if (!body || body.length === 0)\n return approval.slice()\n const out: EditOutcome[] = []\n let bi = 0\n for (const entry of approval) {\n if (entry.kind === 'applied' && bi < body.length) {\n out.push(body[bi])\n bi++\n }\n else {\n out.push(entry)\n }\n }\n return out\n}\n\n/**\n * Rewrite a `multi_edit` body header so the totals reflect the model's\n * ORIGINAL edit list (the merged outcomes count) instead of the subset\n * the body actually saw after gate rebinding. Without this, a partially\n * approved call surfaces a misleading `applied 2 of 2 edits` (subset\n * counts) on the wire even when the original was `applied 2 of 3`.\n *\n * Three body-side shapes are handled (matching `multi_edit`'s emit):\n * 1. `Edited <path>: applied N edits (R replacements).`\n * 2. `Edited <path>: applied N of M edits (R replacements).`\n * 3. `multi_edit error: no edits applied to <path> (M attempted).`\n *\n * The replacements count is preserved verbatim — it's a body-side stat\n * the chat layer can't recompute. When the first line doesn't look like\n * any of the three shapes (e.g. an unrelated error preamble bubbled up),\n * the text is returned unchanged.\n */\nexport function rewriteMultiEditHeader(\n text: string,\n merged: readonly EditOutcome[],\n path: string,\n): string {\n const newlineIdx = text.indexOf('\\n')\n const firstLine = newlineIdx < 0 ? text : text.slice(0, newlineIdx)\n const rest = newlineIdx < 0 ? '' : text.slice(newlineIdx)\n\n // Match either success shape (with or without \"of M\") and capture R.\n // The path component uses `.+` greedy so colons (Windows `C:\\…`) and\n // parens (unusual but valid filenames) don't trip the match — the\n // regex engine backtracks to find the longest path that still lets\n // `: applied N…` line up against the trailing structure.\n const successMatch = firstLine.match(\n /^Edited .+: applied \\d+(?: of \\d+)? edits? \\((\\d+) replacement/,\n )\n // Match the all-failed shape (no replacements stat, defaults to 0).\n // `startsWith` instead of regex: the prefix is unique enough and\n // sidesteps the same path-content escaping concerns.\n const isFailedShape = firstLine.startsWith('multi_edit error: no edits applied to ')\n && firstLine.endsWith(' attempted).')\n if (!successMatch && !isFailedShape)\n return text\n\n const replacements = successMatch ? Number.parseInt(successMatch[1], 10) || 0 : 0\n const counts = summarizeOutcomes(merged)\n const applied = counts.applied\n const total = merged.length\n\n let newHeader: string\n if (applied === total) {\n newHeader = `Edited ${path}: applied ${total} edit${total === 1 ? '' : 's'} (${replacements} replacement${replacements === 1 ? '' : 's'}).`\n }\n else if (applied > 0) {\n newHeader = `Edited ${path}: applied ${applied} of ${total} edits (${replacements} replacement${replacements === 1 ? '' : 's'}).`\n }\n else {\n newHeader = `multi_edit error: no edits applied to ${path} (${total} attempted).`\n }\n\n return newHeader + rest\n}\n\n/**\n * Aggregate counts for the transcript's summary badge (`3 applied · 1\n * denied · 1 skipped`). Exported so renderers don't reimplement the\n * tally. Pure / O(n).\n */\nexport function summarizeOutcomes(outcomes: readonly EditOutcome[] | undefined): {\n applied: number\n denied: number\n skipped: number\n failed: number\n pending: number\n total: number\n} {\n const counts = { applied: 0, denied: 0, skipped: 0, failed: 0, pending: 0 }\n if (!outcomes)\n return { ...counts, total: 0 }\n for (const o of outcomes)\n counts[o.kind] += 1\n return { ...counts, total: outcomes.length }\n}\n","import type { ResolvedMatch } from '../tools/edit-utils'\nimport type { EditHunk, EditPayload } from './types'\nimport { resolveOldString, styleReplacementForVia } from '../tools/edit-utils'\n\n// ---------------------------------------------------------------------------\n// extractEditPayload — pulls `EditPayload` out of a tool call's raw input.\n//\n// Used by both the live `tool:before` hook and the historical replay path\n// (`eventsFromTurns`). Returns `undefined` when the tool isn't one of the\n// supported edit tools, or when the input shape is unexpected — in either\n// case the renderer falls back to the unstructured `↳ name(args)` line.\n//\n// Outcomes are NOT pulled from input — they live on the paired tool_result\n// text via the `<edit-outcomes>` annotation block written by the TUI's\n// `tool:transform` hook. `eventsFromTurns` pairs call ↔ result by callId\n// and attaches outcomes after the fact via `parseEditOutcomesFromResult`.\n//\n// `write_file` needs the *previous* on-disk content to render a diff;\n// that's the caller's responsibility (the TUI's hook reads it before the\n// tool runs). Pass it as `priorContent`; an empty string is fine for a\n// fresh create. Historical replay has no priorContent and falls through\n// to `oldString: ''` — every line renders as an addition, matching\n// `git diff` for newly-added files.\n// ---------------------------------------------------------------------------\n\ninterface EditStepInput {\n old_string: unknown\n new_string: unknown\n replace_all?: unknown\n}\n\nexport function extractEditPayload(\n name: string,\n input: Record<string, unknown>,\n priorContent?: string,\n): EditPayload | undefined {\n const path = input.path\n if (typeof path !== 'string' || path === '')\n return undefined\n\n if (name === 'edit') {\n const oldString = input.old_string\n const newString = input.new_string\n if (typeof oldString !== 'string' || typeof newString !== 'string')\n return undefined\n const hunks: EditHunk[] = [{\n oldString,\n newString,\n ...(input.replace_all === true ? { replaceAll: true } : {}),\n }]\n return {\n tool: 'edit',\n path,\n hunks,\n ...(priorContent !== undefined ? { priorContent } : {}),\n }\n }\n\n if (name === 'multi_edit') {\n const steps = input.edits\n if (!Array.isArray(steps) || steps.length === 0)\n return undefined\n const hunks: EditHunk[] = []\n for (const raw of steps as EditStepInput[]) {\n if (typeof raw?.old_string !== 'string' || typeof raw?.new_string !== 'string')\n return undefined\n hunks.push({\n oldString: raw.old_string,\n newString: raw.new_string,\n ...(raw.replace_all === true ? { replaceAll: true } : {}),\n })\n }\n return {\n tool: 'multi_edit',\n path,\n hunks,\n ...(priorContent !== undefined ? { priorContent } : {}),\n }\n }\n\n if (name === 'write_file') {\n const content = input.content\n if (typeof content !== 'string')\n return undefined\n const hunks: EditHunk[] = [{ oldString: priorContent ?? '', newString: content }]\n return {\n tool: 'write_file',\n path,\n hunks,\n ...(priorContent !== undefined ? { priorContent } : {}),\n }\n }\n\n return undefined\n}\n\n// ---------------------------------------------------------------------------\n// Line diff — LCS table walk, returns a sequence of `context | add | remove`\n// rows. Backed by the standard 2-D dynamic-programming LCS — O(n·m) time\n// and memory — but ONLY over the changed core: common prefix and suffix\n// lines are trimmed first, so a one-hunk edit to a 76k-line file costs a\n// table over the hunk, not the file. `buildContextualDiff` feeds WHOLE\n// FILES through here (the showEditDiffs / edit-approval render path);\n// without the trim, a 76k-line file demanded a 76k×76k ≈ 5.8-billion-cell\n// table — tens of GB — which OOM'd the TUI outright on real reports.\n//\n// When the trimmed core is still over {@link LCS_CELL_BUDGET} (two\n// genuinely unrelated large texts — e.g. `write_file` replacing a big\n// file wholesale), the diff degrades to a coarse replace (all removes,\n// then all adds) instead of allocating the table: a valid, just\n// non-minimal, diff — O(n+m) and bounded.\n//\n// Trailing newline policy: a string ending with `\\n` produces a trailing\n// empty `\"\"` line after split. We trim it so a single-line edit doesn't\n// emit a phantom empty `+` row below the actual content.\n// ---------------------------------------------------------------------------\n\n/**\n * LCS table cell budget shared by the line- and token-level diffs. 4M\n * cells ≈ low tens of MB of `number[]` rows — imperceptible — while\n * anything needing more (multi-thousand-line change cores) wouldn't\n * produce a human-readable minimal diff anyway.\n */\nconst LCS_CELL_BUDGET = 4_000_000\n\nexport type DiffOp = 'context' | 'add' | 'remove'\n\nexport interface DiffLine {\n op: DiffOp\n text: string\n}\n\nexport function computeLineDiff(oldString: string, newString: string): DiffLine[] {\n const oldLines = splitLines(oldString)\n const newLines = splitLines(newString)\n\n // Trim the common prefix/suffix — the LCS table only ever sees the\n // changed core. Exactness is preserved: identical flanking lines are\n // context in ANY minimal diff.\n let lo = 0\n while (lo < oldLines.length && lo < newLines.length && oldLines[lo] === newLines[lo])\n lo++\n let oldHi = oldLines.length\n let newHi = newLines.length\n while (oldHi > lo && newHi > lo && oldLines[oldHi - 1] === newLines[newHi - 1]) {\n oldHi--\n newHi--\n }\n\n const out: DiffLine[] = []\n for (let k = 0; k < lo; k++)\n out.push({ op: 'context', text: oldLines[k] })\n\n const n = oldHi - lo\n const m = newHi - lo\n if ((n + 1) * (m + 1) > LCS_CELL_BUDGET) {\n // Core too large for a minimal diff — coarse replace, same\n // remove-block-then-add-block ordering the LCS walk produces for\n // fully-changed regions.\n for (let k = lo; k < oldHi; k++)\n out.push({ op: 'remove', text: oldLines[k] })\n for (let k = lo; k < newHi; k++)\n out.push({ op: 'add', text: newLines[k] })\n }\n else if (n > 0 || m > 0) {\n appendLcsDiff(out, oldLines, newLines, lo, oldHi, newHi)\n }\n\n for (let k = oldHi; k < oldLines.length; k++)\n out.push({ op: 'context', text: oldLines[k] })\n return out\n}\n\n/**\n * The classic LCS table + reverse walk over `old[lo..oldHi) ×\n * new[lo..newHi)`, appending ops to `out` in forward order. Diagonals at\n * equal lines → context; otherwise step into the higher of (up, left)\n * and emit remove/add respectively. Ties break so adjacent remove/add\n * pairs stay grouped (the intra-line highlighter pairs them up).\n */\nfunction appendLcsDiff(\n out: DiffLine[],\n oldLines: readonly string[],\n newLines: readonly string[],\n lo: number,\n oldHi: number,\n newHi: number,\n): void {\n const n = oldHi - lo\n const m = newHi - lo\n const lcs: number[][] = Array.from({ length: n + 1 }, () => Array.from<number>({ length: m + 1 }).fill(0))\n for (let i = 0; i < n; i++) {\n for (let j = 0; j < m; j++) {\n lcs[i + 1][j + 1] = oldLines[lo + i] === newLines[lo + j]\n ? lcs[i][j] + 1\n : Math.max(lcs[i][j + 1], lcs[i + 1][j])\n }\n }\n\n const core: DiffLine[] = []\n let i = n\n let j = m\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && oldLines[lo + i - 1] === newLines[lo + j - 1]) {\n core.push({ op: 'context', text: oldLines[lo + i - 1] })\n i--\n j--\n continue\n }\n if (j > 0 && (i === 0 || lcs[i][j - 1] >= lcs[i - 1][j])) {\n core.push({ op: 'add', text: newLines[lo + j - 1] })\n j--\n continue\n }\n core.push({ op: 'remove', text: oldLines[lo + i - 1] })\n i--\n }\n core.reverse()\n out.push(...core)\n}\n\n/**\n * Split a string into lines preserving empty lines but dropping the\n * implicit trailing `\"\"` produced by a final `\\n`. Exported only for\n * its tests — callers should use `computeLineDiff`.\n */\nexport function splitLines(s: string): string[] {\n if (s === '')\n return []\n const parts = s.split('\\n')\n if (parts[parts.length - 1] === '')\n parts.pop()\n return parts\n}\n\n// ---------------------------------------------------------------------------\n// Inline diff — word-level segments for a paired (remove, add) row.\n//\n// Same LCS recipe over **word tokens** so the renderer can bold the\n// genuinely-different runs inside each line. Tokenization keeps runs of\n// word characters + non-word characters as separate units so a rename\n// like `oldName → newName` highlights the single token rather than the\n// whole word boundary.\n//\n// Returns parallel segment arrays for the old and new lines — same\n// segment order, `changed: true` on the diverging tokens. Renderer\n// renders unchanged tokens in the line's base fg + changed tokens in\n// a brighter accent (with the row's bg still tinted).\n// ---------------------------------------------------------------------------\n\nexport interface InlineSegment {\n text: string\n changed: boolean\n}\n\nexport interface InlineDiff {\n oldSegments: InlineSegment[]\n newSegments: InlineSegment[]\n}\n\nexport function computeInlineDiff(oldLine: string, newLine: string): InlineDiff {\n const oldTokens = tokenize(oldLine)\n const newTokens = tokenize(newLine)\n\n const n = oldTokens.length\n const m = newTokens.length\n // Same cell budget as the line diff — a paired remove/add of two\n // megabyte-scale single lines (minified bundles) would otherwise\n // allocate a token² table. Degrade to \"whole line changed\": correct,\n // just unhighlighted.\n if ((n + 1) * (m + 1) > LCS_CELL_BUDGET) {\n return {\n oldSegments: oldLine === '' ? [] : [{ text: oldLine, changed: true }],\n newSegments: newLine === '' ? [] : [{ text: newLine, changed: true }],\n }\n }\n const lcs: number[][] = Array.from({ length: n + 1 }, () => Array.from<number>({ length: m + 1 }).fill(0))\n for (let i = 0; i < n; i++) {\n for (let j = 0; j < m; j++) {\n lcs[i + 1][j + 1] = oldTokens[i] === newTokens[j]\n ? lcs[i][j] + 1\n : Math.max(lcs[i][j + 1], lcs[i + 1][j])\n }\n }\n\n // Walk table — same as computeLineDiff but emit segments tagged\n // changed/unchanged into the side they belong to.\n const oldSegments: InlineSegment[] = []\n const newSegments: InlineSegment[] = []\n let i = n\n let j = m\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && oldTokens[i - 1] === newTokens[j - 1]) {\n pushSegment(oldSegments, { text: oldTokens[i - 1], changed: false })\n pushSegment(newSegments, { text: newTokens[j - 1], changed: false })\n i--\n j--\n continue\n }\n if (j > 0 && (i === 0 || lcs[i][j - 1] >= lcs[i - 1][j])) {\n pushSegment(newSegments, { text: newTokens[j - 1], changed: true })\n j--\n continue\n }\n pushSegment(oldSegments, { text: oldTokens[i - 1], changed: true })\n i--\n }\n oldSegments.reverse()\n newSegments.reverse()\n return { oldSegments, newSegments }\n}\n\n/**\n * Coalesce adjacent same-state segments so the renderer emits one\n * `<span>` per run instead of one per token — keeps the React tree\n * shallow on dense lines without changing the visual output.\n *\n * Walking direction is reverse (we push during the reverse walk, then\n * the caller reverses the array), so we coalesce against the *tail*.\n */\nfunction pushSegment(buf: InlineSegment[], seg: InlineSegment): void {\n const tail = buf[buf.length - 1]\n if (tail && tail.changed === seg.changed)\n tail.text = seg.text + tail.text\n else\n buf.push(seg)\n}\n\n/**\n * Tokenize on word / non-word boundaries. Each run of `\\w+` is one\n * token; each run of `\\W+` (whitespace, punctuation) is another. This\n * gives the right granularity for renames (`oldName` → `newName`) and\n * for symbol swaps (`+ → -`) without exploding into per-char segments.\n *\n * Exported only for its tests.\n */\nexport function tokenize(s: string): string[] {\n if (s === '')\n return []\n const out: string[] = []\n // Greedy: alternating word / non-word runs. Avoids per-char tokens\n // which would inflate the LCS table on long lines.\n const re = /\\w+|\\W+/g\n for (const match of s.matchAll(re))\n out.push(match[0])\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Unified diff serialization — feeds OpenTUI's native `<diff>` renderable.\n//\n// `<diff>` parses standard unified diff syntax (`--- a/path`, `+++ b/path`,\n// `@@ -l,n +l,m @@`, then `[ +-]<line>` rows) and handles per-language\n// syntax highlighting + bg coloring + wrap. We build the string from our\n// `EditPayload` and let the renderable do the rest.\n//\n// Line numbers in the chunk header are SYNTHETIC. `edit` only carries an\n// `old_string` snippet (no file position), `multi_edit` sequential edits\n// invalidate each other's positions, and `write_file` always starts at\n// line 1. Synthetic `@@ -1,N +1,M @@` is correct enough for the visual\n// gutter; users read the path in the header for context.\n//\n// New-file convention: when `oldString === ''` we emit `--- /dev/null`\n// and `@@ -0,0 +1,n @@`, matching `git diff` for newly added files.\n// ---------------------------------------------------------------------------\n\n/**\n * Apply the payload's hunks against `priorContent` and return the\n * resulting file body. Mirrors the agent's tool-side semantics:\n * - `replaceAll === true` → `String.replaceAll`\n * - otherwise → first-occurrence `String.replace`\n *\n * Hunks are applied in order — a `multi_edit` later hunk operates on\n * the output of the earlier ones, just like the actual tool.\n */\nexport function applyEditPayload(payload: EditPayload, priorContent: string): string {\n let out = priorContent\n for (const hunk of payload.hunks) {\n out = hunk.replaceAll\n ? out.replaceAll(hunk.oldString, hunk.newString)\n : out.replace(hunk.oldString, hunk.newString)\n }\n return out\n}\n\n/**\n * Like `buildUnifiedDiff` but operating against the full file content\n * so the diff carries *real* file line numbers and configurable\n * surrounding context.\n *\n * Strategy:\n * 1. Apply the payload to `priorContent` → `newContent`.\n * 2. Run `computeLineDiff` over the whole file.\n * 3. Group non-context ops into hunks, padding each with up to\n * `contextLines` of context above and below. Adjacent hunks\n * whose context regions touch are merged so we don't emit two\n * `@@` headers separated by zero context lines.\n *\n * The output line numbers in the `@@` header are 1-based and reflect\n * the change's position in the actual file — what the user expects\n * when reading a diff alongside their editor.\n *\n * For `write_file` creating a new file (priorContent === ''), this\n * falls back to the same `--- /dev/null` convention as\n * `buildUnifiedDiff`.\n */\nexport function buildContextualDiff(\n payload: EditPayload,\n priorContent: string,\n contextLines = 3,\n): string {\n const newContent = applyEditPayload(payload, priorContent)\n const isNewFile = priorContent === ''\n const ops = computeLineDiff(priorContent, newContent)\n\n // Pre-compute 1-based file line numbers for each op. `oldLine[i]` is\n // the original-file line `ops[i]` corresponds to (for context /\n // remove ops; undefined for adds since they don't exist in the old).\n // Same for `newLine[i]`. Add-only and remove-only ops still need a\n // base anchor for the hunk header, which we read off the *next*\n // context/anchor line — captured by tracking running counters.\n const oldLineFor: number[] = []\n const newLineFor: number[] = []\n let ol = 1\n let nl = 1\n for (const op of ops) {\n oldLineFor.push(ol)\n newLineFor.push(nl)\n if (op.op !== 'add')\n ol++\n if (op.op !== 'remove')\n nl++\n }\n\n // Group indices of change ops into hunks with `contextLines` padding.\n // Each entry: `[startIdx, endIdx]` inclusive into `ops`.\n const hunks: Array<[number, number]> = []\n for (let i = 0; i < ops.length; i++) {\n if (ops[i].op === 'context')\n continue\n const start = Math.max(0, i - contextLines)\n const end = Math.min(ops.length - 1, i + contextLines)\n const last = hunks[hunks.length - 1]\n if (last && start <= last[1] + 1)\n last[1] = Math.max(last[1], end)\n else\n hunks.push([start, end])\n }\n\n // No-op edit (e.g. `edit` with old_string === new_string) → empty diff.\n if (hunks.length === 0)\n return ''\n\n const parts: string[] = []\n parts.push(isNewFile ? '--- /dev/null' : `--- a/${payload.path}`)\n parts.push(`+++ b/${payload.path}`)\n\n for (const [start, end] of hunks) {\n const slice = ops.slice(start, end + 1)\n const oldCount = slice.filter(l => l.op !== 'add').length\n const newCount = slice.filter(l => l.op !== 'remove').length\n // For hunks that contain only adds (oldCount === 0), git emits the\n // line *before* the insertion, with count 0. We replicate that by\n // using `oldLineFor[start] - 1` clamped at 0.\n const oldStart = oldCount === 0\n ? Math.max(0, oldLineFor[start] - 1)\n : oldLineFor[start]\n const newStart = newCount === 0\n ? Math.max(0, newLineFor[start] - 1)\n : newLineFor[start]\n parts.push(`@@ -${oldStart},${oldCount} +${newStart},${newCount} @@`)\n for (const line of slice) {\n const prefix = line.op === 'add' ? '+' : line.op === 'remove' ? '-' : ' '\n parts.push(`${prefix}${line.text}`)\n }\n }\n return `${parts.join('\\n')}\\n`\n}\n\n// ---------------------------------------------------------------------------\n// summarizeEditPayload — compact-mode digest of an edit call.\n//\n// Produces per-hunk stats + a one-line preview suitable for the\n// transcript's compact diff view (`Settings.editDiffDisplay === 'compact'`).\n// Uses `priorContent` when available so each summary entry carries the\n// real file line number; falls back to per-hunk LCS over the snippet\n// pair when priorContent is absent (historical replay).\n//\n// Multi-file safety: this only summarizes the payload it's handed; the\n// caller is responsible for separating per-file payloads.\n// ---------------------------------------------------------------------------\n\nexport interface EditHunkSummary {\n /** 1-based line number in the new file where the change starts; undefined when unknown (no priorContent). */\n line?: number\n /** Number of lines added in this hunk. */\n added: number\n /** Number of lines removed in this hunk. */\n removed: number\n /** First removed line preview (trimmed, may be empty for pure additions). */\n firstOld?: string\n /** First added line preview (trimmed, may be empty for pure deletions). */\n firstNew?: string\n}\n\nexport interface EditSummary {\n totalAdded: number\n totalRemoved: number\n hunks: EditHunkSummary[]\n}\n\n/**\n * Build a per-hunk digest used by the compact diff view.\n *\n * Strategy:\n * - When `priorContent` is present and the payload describes a real\n * file transformation, compute the contextual diff once, then walk\n * the LCS ops splitting at runs of `add` / `remove` to anchor each\n * summary entry to the **real** file line. This guarantees the\n * summary's `L<n>` matches what the user sees in their editor.\n * - Otherwise, fall back to per-hunk LCS over the (oldString,\n * newString) snippet pair. Line numbers are absent because the\n * snippet has no file position.\n */\nexport function summarizeEditPayload(payload: EditPayload): EditSummary {\n const prior = payload.priorContent\n if (prior !== undefined) {\n const newContent = applyEditPayload(payload, prior)\n const ops = computeLineDiff(prior, newContent)\n return summarizeOpsByHunk(ops)\n }\n\n // No prior content — diff each (oldString, newString) snippet pair\n // in isolation. Line numbers can't be derived; we still get\n // meaningful +/− counts and a first-line preview.\n const hunks: EditHunkSummary[] = []\n let totalAdded = 0\n let totalRemoved = 0\n for (const hunk of payload.hunks) {\n const ops = computeLineDiff(hunk.oldString, hunk.newString)\n let added = 0\n let removed = 0\n let firstOld: string | undefined\n let firstNew: string | undefined\n for (const op of ops) {\n if (op.op === 'add') {\n added++\n if (firstNew === undefined)\n firstNew = op.text\n }\n else if (op.op === 'remove') {\n removed++\n if (firstOld === undefined)\n firstOld = op.text\n }\n }\n totalAdded += added\n totalRemoved += removed\n hunks.push({\n added,\n removed,\n ...(firstOld !== undefined ? { firstOld } : {}),\n ...(firstNew !== undefined ? { firstNew } : {}),\n })\n }\n return { totalAdded, totalRemoved, hunks }\n}\n\n/**\n * Walk an LCS op stream and emit one summary entry per *run* of\n * non-context ops, with the new-file line number where each run\n * starts. Adjacent add/remove ops collapse into the same entry —\n * matches git's hunk grouping at zero context.\n */\nfunction summarizeOpsByHunk(ops: readonly DiffLine[]): EditSummary {\n const hunks: EditHunkSummary[] = []\n let totalAdded = 0\n let totalRemoved = 0\n let nl = 1\n let i = 0\n while (i < ops.length) {\n const op = ops[i]\n if (op.op === 'context') {\n nl++\n i++\n continue\n }\n const runStartLine = nl\n let added = 0\n let removed = 0\n let firstOld: string | undefined\n let firstNew: string | undefined\n while (i < ops.length && ops[i].op !== 'context') {\n const cur = ops[i]\n if (cur.op === 'add') {\n added++\n if (firstNew === undefined)\n firstNew = cur.text\n nl++\n }\n else {\n removed++\n if (firstOld === undefined)\n firstOld = cur.text\n }\n i++\n }\n totalAdded += added\n totalRemoved += removed\n hunks.push({\n line: runStartLine,\n added,\n removed,\n ...(firstOld !== undefined ? { firstOld } : {}),\n ...(firstNew !== undefined ? { firstNew } : {}),\n })\n }\n return { totalAdded, totalRemoved, hunks }\n}\n\n// ---------------------------------------------------------------------------\n// previewEditPayload — model-faithful preview that mirrors the tool body's\n// lenient resolver (curly-quote recovery, line-number-prefix stripping,\n// model-side `<n>`→`<name>` desanitize). The naive `applyEditPayload`\n// only does exact `String.replace`, which renders a blank diff whenever\n// the model emits an `old_string` the tool body would still recover via\n// `resolveOldString`. The modal uses this so what the user previews\n// matches what the tool would actually apply.\n//\n// Returns per-hunk `resolution` metadata so the modal can:\n// - mark hunks the tool wouldn't find (`resolved: false`) with a\n// warning glyph in the list,\n// - render an explanatory fallback panel instead of an empty diff box.\n// ---------------------------------------------------------------------------\n\nexport interface HunkResolution {\n /**\n * True when the tool body would find this hunk's `old_string` AND apply\n * it without ambiguity. False when `resolveOldString` returned null OR\n * the match was ambiguous (multiple occurrences and `replace_all` off).\n */\n resolved: boolean\n /** Path the resolver took — `'exact'` when no recovery was needed. */\n via?: ResolvedMatch['via']\n /** Match count in the running content for the hunk. */\n occurrences?: number\n /** True when the resolver found >1 match without `replace_all`. */\n ambiguous?: boolean\n}\n\nexport interface PreviewResult {\n /** Full unified diff of the (resolvable) hunks against `priorContent`. */\n diffText: string\n /** 1:1 with `payload.hunks`. */\n resolution: HunkResolution[]\n /**\n * Per-hunk isolated diff text rendered against the cumulative content\n * after applying all earlier resolved hunks. Useful for the modal's\n * focused-hunk view so hunk #N's preview reflects the state hunks\n * 1..N-1 will leave the file in (same as the tool's order).\n */\n perHunkDiff: string[]\n /**\n * Resolved hunks with `oldString` rewritten to the haystack's actual\n * bytes and `newString` re-styled to preserve curly-quote typography\n * / line-prefix conventions. Pass this to `buildContextualDiff` to\n * paint the unified diff.\n */\n resolvedPayload: EditPayload\n}\n\nexport function previewEditPayload(\n payload: EditPayload,\n priorContent: string,\n contextLines = 3,\n): PreviewResult {\n const resolution: HunkResolution[] = []\n const resolvedHunks: EditHunk[] = []\n const perHunkDiff: string[] = []\n let running = priorContent\n\n for (const hunk of payload.hunks) {\n // `write_file` synthesizes a hunk with `oldString = priorContent`,\n // which is always a perfect match by construction.\n if (hunk.oldString === '' || hunk.oldString === running) {\n resolution.push({ resolved: true, via: 'exact', occurrences: 1 })\n resolvedHunks.push(hunk)\n perHunkDiff.push(buildContextualDiff(\n { ...payload, hunks: [hunk] },\n running,\n contextLines,\n ))\n running = hunk.newString\n continue\n }\n\n const match = resolveOldString(running, hunk.oldString)\n if (!match) {\n resolution.push({ resolved: false })\n resolvedHunks.push(hunk)\n perHunkDiff.push('')\n continue\n }\n\n const ambiguous = match.occurrences > 1 && !hunk.replaceAll\n const styledNew = styleReplacementForVia(hunk.newString, match.via, match.actual)\n const resolvedHunk: EditHunk = {\n oldString: match.actual,\n newString: styledNew,\n ...(hunk.replaceAll ? { replaceAll: true } : {}),\n }\n resolution.push({\n resolved: !ambiguous,\n via: match.via,\n occurrences: match.occurrences,\n ...(ambiguous ? { ambiguous: true } : {}),\n })\n resolvedHunks.push(resolvedHunk)\n // Ambiguous matches paint nothing — the tool would reject the call;\n // the modal renders the `UnresolvedHunkPanel` instead so the user\n // can see what went wrong rather than a misleading first-occurrence\n // preview.\n perHunkDiff.push(ambiguous\n ? ''\n : buildContextualDiff(\n { ...payload, hunks: [resolvedHunk] },\n running,\n contextLines,\n ))\n if (!ambiguous) {\n running = hunk.replaceAll\n ? running.replaceAll(match.actual, styledNew)\n : running.replace(match.actual, styledNew)\n }\n }\n\n const resolvedPayload: EditPayload = { ...payload, hunks: resolvedHunks }\n // Whole-payload diff renders only the hunks the tool would actually\n // apply. Ambiguous + unresolved hunks are surfaced via `resolution`\n // instead — letting them through here would paint misleading\n // first-occurrence diffs.\n const applicableHunks = resolvedHunks.filter((_, i) => resolution[i].resolved)\n const diffText = applicableHunks.length === 0\n ? ''\n : buildContextualDiff(\n { ...payload, hunks: applicableHunks },\n priorContent,\n contextLines,\n )\n\n return { diffText, resolution, perHunkDiff, resolvedPayload }\n}\n\n// ---------------------------------------------------------------------------\n// Render clip — bound a unified-diff string before it reaches the native\n// <diff> renderable. The renderable materializes row buffers, word-wrap\n// layout, and (when a grammar matches) tree-sitter highlight state for\n// EVERY line it is handed — a scrollbox around it only bounds the\n// VIEWPORT, not the allocation. A wholesale rewrite of a 76k-line file\n// produces a ~150k-line diff that measured >1 GB of native RSS for a\n// single transcript row, and the kernel SIGKILLs the TUI under that\n// pressure (macOS jetsam) before any JS error can surface.\n//\n// Line- AND size-capped: minified single-line files blow the size side\n// long before the line side, and a SINGLE line at or above the budget is\n// hard-truncated (not admitted whole) — otherwise a `-<20MB minified line>`\n// row would hand the renderable one line whose word-wrap layout is\n// hundreds of thousands of wrapped rows, re-creating the blowup this\n// exists to prevent. Clipping is display-only — the tool applied (or will\n// apply) the full change regardless — so callers render the returned\n// `hiddenLines` as a footer so the reader knows the tail exists.\n//\n// The size budget counts UTF-16 CODE UNITS (`String.length`), not bytes:\n// this module is re-exported through `chat/pure` (no-node contract), so\n// `Buffer.byteLength` is unavailable and per-line `TextEncoder` encoding\n// would allocate on the hot render path. Code units under-count multi-byte\n// text by at most 3× (UTF-8) / equal (UTF-16 BMP), so the real ceiling is\n// ~3× the budget — still bounded, which is all this guard needs.\n// ---------------------------------------------------------------------------\n\nexport interface ClippedDiff {\n /** The (possibly clipped) diff text. Original string identity when nothing was cut. */\n text: string\n /** Diff lines dropped from the tail. `0` = complete. */\n hiddenLines: number\n /** Total diff lines (excluding the trailing-newline phantom). */\n totalLines: number\n}\n\n/** Default line budget for transcript diff rows. */\nexport const DIFF_RENDER_MAX_LINES = 600\n/** Default size budget (UTF-16 code units) for transcript diff rows. */\nexport const DIFF_RENDER_MAX_BYTES = 512 * 1024\n/** Marker appended to a line hard-truncated mid-content by the size cap. */\nconst CLIP_LINE_MARKER = ' …⟨line clipped⟩'\n\n/**\n * Truncate `line` so it fits `budget` code units including the marker,\n * without splitting a UTF-16 surrogate pair. Returns the line unchanged\n * when it already fits.\n */\nfunction clipLine(line: string, budget: number): string {\n if (line.length <= budget)\n return line\n let end = Math.max(0, budget - CLIP_LINE_MARKER.length)\n // Don't slice between a high/low surrogate — step back off a lone high.\n const code = line.charCodeAt(end - 1)\n if (end > 0 && code >= 0xD800 && code <= 0xDBFF)\n end--\n return line.slice(0, end) + CLIP_LINE_MARKER\n}\n\nexport function clipDiffForRender(\n diff: string,\n maxLines: number = DIFF_RENDER_MAX_LINES,\n maxBytes: number = DIFF_RENDER_MAX_BYTES,\n): ClippedDiff {\n const lines = diff.split('\\n')\n // The diff builders always terminate with `\\n`, so `split` yields a\n // phantom empty final element — don't count it in the total the footer\n // reports (mirrors computeLineDiff's trailing-newline policy).\n const totalLines = lines.length > 0 && lines[lines.length - 1] === ''\n ? lines.length - 1\n : lines.length\n if (totalLines <= maxLines && diff.length <= maxBytes)\n return { text: diff, hiddenLines: 0, totalLines }\n\n const kept: string[] = []\n let used = 0\n for (let i = 0; i < totalLines; i++) {\n if (kept.length >= maxLines)\n break\n const line = lines[i]\n const cost = line.length + 1 // '\\n' rejoin\n if (used + cost > maxBytes) {\n // First line already over budget → hard-truncate it so the\n // renderable never sees an oversized single line. Any later line\n // that would overflow just ends the clip (the tail is hidden).\n if (kept.length === 0)\n kept.push(clipLine(line, maxBytes))\n break\n }\n kept.push(line)\n used += cost\n }\n return { text: kept.join('\\n'), hiddenLines: totalLines - kept.length, totalLines }\n}\n\nexport function buildUnifiedDiff(payload: EditPayload): string {\n const parts: string[] = []\n const isNewFile = payload.tool === 'write_file' && payload.hunks[0]?.oldString === ''\n // File header. Both `---` and `+++` lines are mandatory per the parser\n // (see `Missing \"--- ...\"` throw in the upstream parseDiff).\n parts.push(isNewFile ? `--- /dev/null` : `--- a/${payload.path}`)\n parts.push(`+++ b/${payload.path}`)\n\n for (const hunk of payload.hunks) {\n const lines = computeLineDiff(hunk.oldString, hunk.newString)\n const oldCount = lines.filter(l => l.op !== 'add').length\n const newCount = lines.filter(l => l.op !== 'remove').length\n const oldStart = oldCount === 0 ? 0 : 1\n const newStart = newCount === 0 ? 0 : 1\n parts.push(`@@ -${oldStart},${oldCount} +${newStart},${newCount} @@`)\n for (const line of lines) {\n const prefix = line.op === 'add' ? '+' : line.op === 'remove' ? '-' : ' '\n parts.push(`${prefix}${line.text}`)\n }\n }\n return `${parts.join('\\n')}\\n`\n}\n\n// ---------------------------------------------------------------------------\n// File extension → tree-sitter filetype name.\n//\n// Names must match what `setupTreeSitter` registered (see\n// `src/tui/tree-sitter.ts`'s `EXTRA_PARSERS` / `LOCAL_PARSERS`) plus what\n// OpenTUI ships out of the box (`typescript`, `javascript`, `markdown`,\n// `zig`). JSX/TSX are registered as `javascriptreact`/`typescriptreact`\n// aliases of the JS/TS parsers, not `jsx`/`tsx` — passing the fence-style\n// name to the `<diff>` renderable's `filetype` prop silently misses (falls\n// back to plain text, no error). Unknown extensions return `undefined`.\n// ---------------------------------------------------------------------------\n\nconst FILETYPE_BY_EXT: Readonly<Record<string, string>> = {\n ts: 'typescript',\n mts: 'typescript',\n cts: 'typescript',\n tsx: 'typescriptreact',\n js: 'javascript',\n mjs: 'javascript',\n cjs: 'javascript',\n jsx: 'javascriptreact',\n py: 'python',\n pyi: 'python',\n rs: 'rust',\n go: 'go',\n json: 'json',\n jsonc: 'json',\n sh: 'bash',\n bash: 'bash',\n zsh: 'bash',\n yaml: 'yaml',\n yml: 'yaml',\n html: 'html',\n htm: 'html',\n css: 'css',\n md: 'markdown',\n markdown: 'markdown',\n zig: 'zig',\n lua: 'lua',\n toml: 'toml',\n sql: 'sql',\n}\n\nexport function filetypeFromPath(path: string): string | undefined {\n // Strip query / fragment so `path?ts=…` style references still match.\n const cleaned = path.split(/[?#]/, 1)[0]\n const lastDot = cleaned.lastIndexOf('.')\n if (lastDot === -1 || lastDot === cleaned.length - 1)\n return undefined\n const ext = cleaned.slice(lastDot + 1).toLowerCase()\n return FILETYPE_BY_EXT[ext]\n}\n","/**\n * Pure string + reference math for rendering a submitted prompt with chip\n * pills around completion references. Renderer-agnostic — the TUI walks\n * the segments into OpenTUI `<text>` nodes, a GUI walks them into JSX\n * spans + `<span class=\"chip\">` pills. No layout engine assumptions.\n */\n\n/**\n * Highlight span — half-open `[start, end)` over the source string.\n *\n * Offsets are JS string indices (UTF-16 code units) — the same convention used\n * everywhere else in the chat layer (`text[i]`, `m.index`, `String.slice`).\n * Surrogate pairs that straddle a span boundary would render malformed, but\n * realistic prompts in this surface (terminal text + ASCII triggers) keep that\n * risk theoretical; callers feeding emoji-heavy content should normalize to\n * codepoint walks upstream.\n */\nexport interface PromptSegmentRef {\n start: number\n end: number\n /** Provider id tagging this span (`'skills'`, `'files'`, …). Free-form. */\n providerId: string\n}\n\n/**\n * One atomic unit emitted by {@link splitPromptSegments}. Plain segments\n * are word-sized so wraps land cleanly between words; chip segments\n * carry the source `providerId` (`'skills'`, `'files'`, …) so renderers\n * can pick per-kind colors without re-walking the ref list.\n */\nexport type PromptSegment\n = | { kind: 'plain', text: string }\n | { kind: 'chip', text: string, providerId: string }\n\n/**\n * Split a prompt buffer into word-sized atomic segments suitable for a\n * flex-row + flex-wrap renderer (TUI) or a `display: inline` flow with\n * inline-block chips (GUI). Each chip becomes one segment (atomic —\n * never broken across rows); each plain run is split into \"word +\n * trailing space\" units so wraps land at clean word boundaries.\n *\n * Robust to:\n * - Overlapping refs — sorted by start; later refs that overlap are\n * dropped via the first-wins rule.\n * - Out-of-bounds refs — dropped entirely when `end > text.length` or\n * `start >= text.length`. Partial clipping would silently truncate\n * a chip's label; the caller is in a better position to surface the\n * mismatch (typically a stale `refs` array referencing a previous text).\n * - Whitespace-only plain runs — emitted as their own plain segment\n * so chip-adjacent-to-chip cases keep the original spacing.\n *\n * Word splitter rationale: `\\S+\\s*` keeps trailing whitespace attached\n * to its preceding word so wrap boundaries land between words (cleanly).\n * A leading-whitespace-only segment is captured by `\\s+` so we don't\n * drop it entirely when the plain run starts with a space.\n */\nexport function splitPromptSegments(\n text: string,\n refs: readonly PromptSegmentRef[],\n): PromptSegment[] {\n const sorted = [...refs]\n .filter(r => r.end > r.start && r.start < text.length && r.end <= text.length)\n .sort((a, b) => a.start - b.start)\n const out: PromptSegment[] = []\n let cursor = 0\n for (const ref of sorted) {\n if (ref.start < cursor)\n continue // overlapping with a previous ref — drop\n if (ref.start > cursor) {\n const matches = text.slice(cursor, ref.start).match(/\\S+\\s*|\\s+/g) ?? []\n for (const m of matches)\n out.push({ kind: 'plain', text: m })\n }\n out.push({ kind: 'chip', text: text.slice(ref.start, ref.end), providerId: ref.providerId })\n cursor = ref.end\n }\n if (cursor < text.length) {\n const matches = text.slice(cursor).match(/\\S+\\s*|\\s+/g) ?? []\n for (const m of matches)\n out.push({ kind: 'plain', text: m })\n }\n return out\n}\n\n/**\n * File-mention refs recovered from a prompt's text: `@<path>` at the start\n * or after whitespace, where the path looks like one (has a `/` or a `.`),\n * trailing punctuation excluded (the files completion's own rule).\n *\n * Refs are known only to the client that sent the prompt, which typed the\n * mention through a completion. The persisted turn and the send echo other\n * windows receive carry the text alone, so without this a prompt's chips\n * existed in the sender's live transcript only: gone after a reload, never\n * shown in another window or the TUI. Replay and the echo fill refs from\n * this when the event has none, so every client paints the same prompt.\n * Skills and chats mentions are not inferred: their tokens (`/name`,\n * `#token`) are ordinary text too often to guess without the catalogs.\n */\nexport function inferPromptRefs(text: string): PromptSegmentRef[] {\n const refs: PromptSegmentRef[] = []\n for (const m of text.matchAll(/(^|\\s)@(\\S+)/g)) {\n const path = m[2]!.replace(/[.,;:)\\]}!?'\"]+$/, '')\n if (!/[/.]/.test(path) || path.includes('@'))\n continue\n const start = m.index! + m[1]!.length\n refs.push({ start, end: start + 1 + path.length, providerId: 'files' })\n }\n return refs\n}\n\n/**\n * The segments cut into the lines the user typed. A flex-wrap row cannot\n * break on a newline inside one of its items, so each line renders as its\n * own row; an empty array is a blank line.\n */\nexport function promptSegmentLines(segments: readonly PromptSegment[]): PromptSegment[][] {\n const lines: PromptSegment[][] = [[]]\n for (const segment of segments) {\n if (segment.kind !== 'plain') {\n lines[lines.length - 1]!.push(segment)\n continue\n }\n segment.text.split('\\n').forEach((part, i) => {\n if (i > 0)\n lines.push([])\n if (part)\n lines[lines.length - 1]!.push({ kind: 'plain', text: part })\n })\n }\n return lines\n}\n","/**\n * The canonical `Settings` defaults, in a leaf with no React and no node\n * imports so `zidane/chat/pure` (the GUI renderer) shares the same object.\n */\nimport type { Settings } from './types'\n\nexport const DEFAULT_SETTINGS: Settings = {\n showThinking: true,\n // Tool calls render as clean per-tool summaries by default — `↳ Read\n // src/foo.ts` instead of `↳ read_file({\"path\":\"src/foo.ts\"})`. Flip\n // to `'full'` for the JSON-debug view, `'hidden'` to drop them.\n toolCallDisplay: 'formatted',\n showToolResults: true,\n // Off by default — collapsing every exchange's tool calls into one\n // summary row is an opinionated density trade-off; the historical\n // per-row transcript stays the out-of-the-box behavior.\n groupToolCalls: false,\n // `!` shell output renders a 10-line tail window by default; the toggle\n // shows every line (display-only — the persisted result stays trimmed).\n showFullShellOutput: false,\n showRunReceipt: true,\n showCacheNotices: true,\n safeMode: true,\n // Off by default — the daemon-backed window is currently the minimal\n // attach UI; the in-process TUI stays the default until the full\n // front-end speaks the daemon protocol.\n useDaemon: false,\n // Off; Settings → Remote hosts (see `remoteHostsGate`).\n remoteHosts: false,\n orchestration: false,\n // Off by default — project extensions (`<project>/.zidane/extensions`)\n // execute arbitrary local code, so they stay gated until the user opts\n // in. Replaces the legacy `ZIDANE_TRUST_PROJECT_EXTENSIONS=1` env flag,\n // which is still honored as a fallback.\n loadProjectExtensions: false,\n // Off by default — foreign MCP entries are stdio commands from files\n // zidane doesn't own, so importing them is an explicit opt-in.\n importForeignConfigs: false,\n // On by default — `.ruler/` is an intentional committed config source\n // (see the Settings doc), unlike the per-tool state files above.\n importRulerConfigs: true,\n hideSubagentOutput: true,\n // On by default — when the agent's providers expose a model catalog, the\n // spawn tool gains a `model` field (+ `model_search`) so the main model\n // can delegate mechanical work to cheaper models. Flip off to force\n // children onto the parent's model, exactly as before the feature.\n subagentModels: true,\n // On by default — mid-run prompts wait in the queue until the run ends.\n // Off steers them into the live run.\n queueMessages: true,\n // `DEFAULT_THEME.id`, spelled out so this leaf does not pull the theme tables.\n theme: 'default',\n // Off by default — the sessions list filters to the current project\n // (git root / cwd) so the user only sees the conversations relevant\n // to where they're working. Toggle on to inspect or jump across\n // projects, plus see pre-tagging legacy sessions.\n showAllProjects: false,\n // On by default — match the historical \"the TUI picks up where you\n // left off\" behavior. Users who prefer a clean slate on launch can\n // flip this off; resume-on-launch then falls through to the sessions\n // list (or a fresh session when the list is empty).\n resumeLastSession: true,\n // On by default — large tool results (>8 KiB) get written to disk and\n // replaced inline with a `<persisted-output>` stub. Shrinks the prompt\n // prefix on shell/grep-heavy sessions; the model can still re-read the\n // full payload via `read_file` on the persisted path. Flip off to keep\n // every tool result inline regardless of size (matches pre-feature\n // behavior — also useful when debugging tool output).\n persistToolResults: true,\n // Off by default: surfaced MCP tools are appended to the tool list (the\n // historical behavior). On = `toolSearch.mode: 'dispatch'`, invoking them\n // through `call_tool` so discovery never rewrites the prompt cache.\n stableToolList: false,\n // Off by default: `codemode` is opt-in. On = `behavior.codemode: true`.\n codemode: false,\n // Off by default — the OS sandbox (Seatbelt / bwrap) changes what shell\n // commands may write and read, which breaks tools that cache under `~`\n // until the user widens `sandboxAllowWrite`. Explicit opt-in; the shell\n // path stays byte-identical to before while it's off.\n sandbox: false,\n // Allow by default: denying network breaks `bun install` / `git fetch` /\n // `gh` on day one. The setting description is explicit that write\n // containment alone does not stop exfiltration.\n sandboxNetwork: 'allow',\n sandboxAllowWrite: '',\n // On by default — auto-fire compaction once the latest turn's input\n // usage crosses `autoCompactThreshold` of the effective context window.\n // The shipped `compactConversation` is otherwise manual-only; without\n // this trigger most users never reach for `/compact` and let sessions\n // degrade silently.\n autoCompact: true,\n // 80% of the effective window — comfortable headroom before the model\n // hits the wall, aligned with Claude Code's `AUTOCOMPACT_BUFFER_TOKENS`\n // (~167k of 200k = 83.5%). The settings modal cycles 0.6 / 0.7 / 0.8 /\n // 0.9 so users can tune down for verbose workflows (frequent\n // compactions) or up for context-heavy ones (delay until near full).\n autoCompactThreshold: 0.8,\n // Output / runaway caps — all default to \"off\" (model-driven, uncapped) so\n // the agent follows the model's output to completion out of the box. Opt\n // into any ceiling from the Settings modal; the budget breakers\n // (`maxCostUsd` / `maxTotalTokens` / `maxWallMs`) and `maxTurns` arm only\n // when set to a positive value.\n resumeOnMaxTokens: false,\n maxOutputTokens: 0,\n maxTurns: 0,\n // 0 = library default (3 attempts). Exposed so flaky-network / heavily\n // rate-limited setups can raise the budget without an SDK override.\n retryMaxAttempts: 0,\n maxCostUsd: 0,\n maxTotalTokens: 0,\n maxWallMinutes: 0,\n // Anthropic only. Server-side drop of replayed thinking whose prefix\n // changed — the request succeeds instead of failing with a 400.\n thinkingBinding: 'drop_block',\n // On by default — `edit` / `multi_edit` / `write_file` calls render as\n // a unified diff. The paired success result is suppressed (the diff\n // already shows it worked); errors still surface. Flip off to keep\n // the raw `↳ edit({\"path\":\"…\",\"old_string\":\"…\"})` JSON dump.\n showEditDiffs: true,\n // Full unified diff in the transcript by default. Switch to `'compact'`\n // for a one-line per-hunk summary (file path + `+N −M` + first\n // changed line preview) — much quieter on edit-heavy turns; the\n // approval modal still shows the full diff when safeMode prompts fire.\n editDiffDisplay: 'full',\n // The historical per-row transcript. `'compact'` folds each exchange's\n // thinking and tool calls behind one row and keeps only the prose.\n transcriptDensity: 'full',\n // Off by default — the compaction boundary card stays metadata-only\n // (⎯⎯ N turns compacted · model · tokens). Flip on to also render the\n // LLM-generated summary text under the card, so you can audit exactly\n // what context the model carries forward across the boundary.\n showCompactionSummary: false,\n // '' = summarize on the main model. Set from the settings modal's\n // \"Compaction model\" action row via the cross-provider model picker.\n compactionModel: '',\n // 60fps target — matches most displays, doubles OpenTUI's stock 30fps\n // default for visibly snappier scroll + modal animations + cursor.\n // Settings modal cycles 30 / 60 / 120; applied live via the renderer's\n // `targetFps` / `maxFps` setters.\n targetFps: 60,\n // On by default — clicks, hovers, and wheel scrolling work throughout\n // the TUI. Off releases the mouse to the terminal emulator (native\n // selection / copy / scrollback) by disabling mouse reporting at the\n // renderer, which turns off every clickable surface at once.\n mouseInteractions: true,\n // Ask by default. Skip keeps the tools but resolves them automatically;\n // Disabled strips both tools on the next session activation.\n interactionMode: 'ask',\n // On by default — the assistant's streaming text drips in at a smooth\n // cadence (typewriter effect) instead of landing in batches. The\n // display rate is capped + bursts when behind; turn boundaries flush\n // remaining content immediately so completion is never delayed.\n smoothStreaming: true,\n // Off by default: no logs directory or file is created until the user\n // opts in. The in-TUI Logs panel works regardless (in-memory buffer).\n fileLogging: false,\n // On by default — the inline indicator above the prompt is a single\n // muted line (\"▸ <in-progress todo>\"), only present while the active\n // run has an `in_progress` item. Users who don't want even that\n // subtle line flip this off; the explicit `ctrl+t` modal still works.\n showTodoIndicator: true,\n showUsageIndicator: true,\n // Off by default — the streaming throbber (cycling hex/symbol glyphs)\n // is a stylistic flourish, not a load-bearing affordance. Streaming\n // already shows itself through the prompt's status row and the\n // incremental markdown updates, so we keep the transcript calm out\n // of the box and let users opt back in.\n showThrobber: false,\n // On by default — the detectors are command-gated (never free text) and\n // recording is best-effort; off hides every artifact surface at once.\n artifacts: true,\n browser: true,\n browserAgent: true,\n browserAutoShow: true,\n terminal: true,\n terminalAgent: true,\n terminalAgentTasks: true,\n closeTerminalOnCleanExit: true,\n confirmGitSync: true,\n sidebarRunDetails: true,\n openIn: 'editor',\n // On by default — one warm-cache HTTP roundtrip per 24 h, never\n // blocks boot, swallows errors. CI / NO_UPDATE_NOTIFIER / ZIDANE_NO_UPDATE\n // force-disable. The explicit `zidane upgrade` subcommand bypasses\n // this toggle.\n checkForUpdates: true,\n // On by default — no request until a provider is picked, and only for\n // providers already signed in. ZIDANE_NO_USAGE_CHECK / CI force-disable;\n // with the toggle off the panel's ctrl+r still fetches on demand.\n subscriptionUsage: true,\n // `'full'` by default — match the historical chat-screen chrome with\n // every shortcut advertised in the bottom bar, prompt overlay, and\n // title meta. `'minimal'` is the explicit opt-in for the lighter\n // surface (agent / model / keybindings + `@` / `/` triggers).\n uiMode: 'full',\n // `'both'` by default — merge `~/.agents`, `~/.zidane`, `~/.claude`\n // user files with project-local `AGENTS.md` / `CLAUDE.md`. Flip to\n // `'user'` for cross-repo defaults only, `'project'` to scope down\n // when running zidane against an unfamiliar codebase.\n userInstructionsScope: 'both',\n ctrlCBehavior: 'quit',\n // Off by default — leave the terminal title alone so launching zidane\n // doesn't clobber whatever the user's shell set. Opt into `'app'`\n // (always \"zidane\"), `'session'` (track the active session title), or\n // `'icon-session'` (`{sessionIcon} · {title}`) from the UI settings tab.\n terminalTitle: 'off',\n // Free-text icon prefixed onto the title in `'icon-session'` mode.\n // Empty falls back to ⚽ (see the title effect in the TUI shell).\n sessionIcon: '',\n // Swap-in icon while the agent waits on user input (tool approval,\n // ask_user / present_plan). Empty falls back to ⚠️. Same\n // `'icon-session'`-only scope as `sessionIcon`.\n attentionIcon: '',\n // Swap-in icon while a run is in flight (streaming/working). Empty\n // falls back to ⚡. Loses to `attentionIcon` when the run is blocked\n // on user input. Same `'icon-session'`-only scope as `sessionIcon`.\n activeIcon: '',\n // On by default — preserves the historical paste-as-attachment\n // pipeline (drag-and-drop a file → image/binary attachment,\n // multiline paste → `paste.txt` document attachment). Flip off\n // and every paste lands inline in the textarea verbatim.\n attachmentsEnabled: true,\n // On by default — pressing the `openExternalEditor` key (ctrl+g) opens\n // the current prompt draft in `$EDITOR` / `$VISUAL` and reloads it on\n // save, git-style. Inert until that key is pressed, and degrades to a\n // notice when no editor is configured, so on-by-default is safe. Flip\n // off to make the key fall through to its normal textarea behavior.\n externalEditor: true,\n // Off by default — ghost text at the cursor is opinionated enough that\n // users should opt in. Providers only run while the prompt is focused\n // and the completion popup is closed.\n inlineAutocomplete: false,\n // `enabledSkills` / `enabledMcps` deliberately default to `undefined`\n // (NOT `[]`): every discovered skill + server is enabled until the user\n // explicitly toggles. The Settings modal seeds the allowlist with the\n // current discovery on first toggle so future additions don't auto-opt\n // out.\n //\n // `disabledMcpTools` is a per-server DENY-LIST (opposite polarity from\n // the `enabledX` allowlists above) — missing key / empty array means\n // every advertised tool is enabled. That polarity flip is deliberate:\n // a new tool shipped by an MCP server we already trust should auto-\n // enable, the same way a new server we explicitly added shouldn't.\n // Default is `undefined` (no per-tool customization).\n}\n","/**\n * The client's host registry, as data: the hosts a window can connect to\n * besides its own (zidane-servers on other machines). Node-free, re-exported\n * from `zidane/chat/pure` for the GUI renderer.\n */\n\n/** One saved host. Tokens are not here: see `hostCredentialKey`. */\nexport interface HostEntry {\n /** The server's `hostId` (`ipc.hello`): `add` verifies the host before saving it. */\n id: string\n /** Display name: the one given at `add` or `rename`, else the server's. */\n name: string\n /** `wss://…`, or `ws://` to loopback. */\n url: string\n /** Epoch ms. */\n addedAt: number\n /** Epoch ms of the last successful `add` / `test`. */\n lastConnectedAt?: number\n hostKind?: 'server'\n /** The server's own name (`hostName`) at the last successful connect. */\n serverName?: string\n /** The server's zidane version at the last successful connect. */\n serverVersion?: string\n}\n\n/**\n * Why a host could not be added or tested:\n * - `invalid-url`: not `wss://`, or `ws://` off loopback; nothing was dialed.\n * - `invalid-token`: empty.\n * - `invalid-name`: an empty name.\n * - `auth`: the server refused the token (401) or the connection (403).\n * - `unreachable`: nothing answered (refused, DNS, timeout, closed).\n * - `tls`: the TLS handshake failed (certificate).\n * - `protocol`: something answered but not a zidane-server this client can\n * talk to (protocol version, no host identity, not a server).\n * - `identity`: a different host answers at the saved URL.\n * - `unknown-host`: no saved host has this id.\n */\nexport type HostErrorCode = 'invalid-url' | 'invalid-token' | 'invalid-name' | 'auth' | 'unreachable' | 'tls' | 'protocol' | 'identity' | 'unknown-host'\n\n/** The identity a host reports (`hostRefOf(hello)`). */\nexport interface HostIdentity {\n id: string\n kind: 'in-process' | 'daemon' | 'server'\n name: string\n}\n\nexport type HostProbeResult\n = | { ok: true, hostRef: HostIdentity, serverVersion?: string, latencyMs: number }\n | { ok: false, error: HostErrorCode, message: string }\n\n/** `test(id)`: the probe's answer, checked against the saved entry. */\nexport type HostTestResult = HostProbeResult\n\n/** Connects to `url` with `token`, says who answered (or why it failed), disconnects. Never throws. */\nexport type HostProbe = (target: { url: string, token: string }) => Promise<HostProbeResult>\n\n/** A refused `add` / `rename`; `code` says why. */\nexport class HostRegistryError extends Error {\n constructor(readonly code: HostErrorCode, message: string) {\n super(message)\n this.name = 'HostRegistryError'\n }\n}\n","/**\n * What a credential looks like, as pure predicates: secret-looking names\n * (`--api-key`, `DB_PASS`, `\"apiKey\"`), known token shapes (`sk-…`,\n * `ghp_…`, `zds_…`) and high-entropy values. Shared by everything that must\n * keep a token out of what it shows or saves: the host's MCP catalog\n * redaction (`src/ipc/daemon/redact.ts`) and the remote host URL check\n * (`./hosts/url.ts`). Node-free.\n *\n * Over-matching an ordinary word is a cosmetic loss; under-matching leaks a\n * credential, so the rules lean wide, but stay off file paths, package names\n * and plain words (`passthrough`, `bypass`, `keymap`).\n */\n\n/**\n * A secret-looking name: a flag (`--auth-token`), a variable (`DB_PASS`), a\n * JSON key (`apiKey`) or a connection-string key (`Password`). `pass` and\n * `key` count only as a whole word or a `-` / `_` segment at the end.\n */\nconst SECRET_NAME = /token|secret|passw(?:or)?d|passphrase|pwd|api[-_]?key|access[-_]?key|private[-_]?key|auth|credential|bearer|cookie|(?:^|[-_])(?:pass|key)$/i\n\n/** Token prefixes issued by common services, with enough body to be a credential. */\nexport const KNOWN_TOKEN = /(?<![\\w-])(?:sk-[\\w-]{16,}|sk_(?:live|test)_\\w{16,}|gh[pousr]_\\w{20,}|github_pat_\\w{20,}|xox[abposr]-[\\w-]{10,}|(?:AKIA|ASIA)[0-9A-Z]{16}|glpat-[\\w-]{20,}|zds_[\\w-]{20,}|AIza[\\w-]{30,})/g\n\nexport function isSecretName(name: string): boolean {\n return SECRET_NAME.test(name)\n}\n\n/** A known token shape somewhere in `value`. */\nfunction containsKnownToken(value: string): boolean {\n KNOWN_TOKEN.lastIndex = 0\n return KNOWN_TOKEN.test(value)\n}\n\nfunction entropy(value: string): number {\n const counts = new Map<string, number>()\n for (const char of value)\n counts.set(char, (counts.get(char) ?? 0) + 1)\n let bits = 0\n for (const count of counts.values()) {\n const p = count / value.length\n bits -= p * Math.log2(p)\n }\n return bits\n}\n\n/**\n * A whole value that looks like a credential: a known token shape, a long\n * hex / UUID-like id, or a long random mix of cases and digits. Words joined\n * by dashes (`server-2024-edition`) and paths stay readable.\n */\nexport function looksLikeSecret(value: string): boolean {\n KNOWN_TOKEN.lastIndex = 0\n const known = KNOWN_TOKEN.exec(value)\n if (known && known[0] === value)\n return true\n if (value.length < 20 || !/^[\\w\\-+=.~]+$/.test(value) || !/\\d/.test(value) || !/[a-z]/i.test(value))\n return false\n const digits = value.replace(/\\D/g, '').length\n if (/^[\\da-f-]+$/i.test(value))\n return digits / value.length >= 0.25\n return /[a-z]/.test(value) && /[A-Z]/.test(value) && entropy(value) >= 4\n}\n\nfunction safeDecode(segment: string): string {\n try {\n return decodeURIComponent(segment)\n }\n catch {\n return segment\n }\n}\n\n/** A URL path segment that carries a credential (as is, or percent-decoded). */\nexport function isSecretPathSegment(segment: string): boolean {\n const decoded = safeDecode(segment)\n return looksLikeSecret(segment) || looksLikeSecret(decoded) || containsKnownToken(decoded)\n}\n","/**\n * Host URLs a client accepts: `wss://`, or `ws://` to this machine only (a\n * token must not cross the network in the clear), with no credentials in\n * them: no `user:pass@`, no query string, no fragment, no token-looking\n * path segment (`wss://h/zds_…`, a long random id: the shapes the MCP\n * catalog redacts, `../secret-shapes`). Tokens go in the token field, and a\n * URL ends up in hosts.json, error messages and the GUI's renderer.\n * Messages show {@link displayHostUrl}, never the input. Node-free.\n */\nimport { isSecretPathSegment } from '../secret-shapes'\n\nexport class RemoteHostError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'RemoteHostError'\n }\n}\n\n/**\n * A loopback host: `localhost`, `127.x.x.x` or `::1` (bracketed, as in a URL,\n * or bare, as an interface to bind). The one check for both ends: a client\n * allowing `ws://`, a server refusing to listen in the clear.\n */\nexport function isLoopbackHost(host: string): boolean {\n const bare = host.startsWith('[') && host.endsWith(']') ? host.slice(1, -1) : host\n return bare === 'localhost' || bare === '::1' || /^127\\.\\d+\\.\\d+\\.\\d+$/.test(bare)\n}\n\n/** Shown in place of a path segment that looks like a credential. */\nconst REDACTED_SEGMENT = '<redacted>'\n\n/** Scheme, host, port and path of a URL (token-looking path segments redacted): what is safe to show or log. */\nexport function displayHostUrl(raw: string): string {\n try {\n const url = new URL(raw.trim())\n const path = url.pathname.split('/').map(segment => isSecretPathSegment(segment) ? REDACTED_SEGMENT : segment).join('/')\n return `${url.protocol}//${url.host}${path.replace(/\\/$/, '')}`\n }\n catch {\n return '<invalid URL>'\n }\n}\n\n/** `raw` carries something {@link parseRemoteHostUrl} refuses as a credential (userinfo, query, fragment, a token-looking path segment). */\nexport function urlCarriesSecrets(raw: string): boolean {\n if (/[@?#]/.test(raw))\n return true\n try {\n return new URL(raw.trim()).pathname.split('/').some(isSecretPathSegment)\n }\n catch {\n return false\n }\n}\n\n/** Validate and normalize a host URL (no trailing slash); throws {@link RemoteHostError}. */\nexport function parseRemoteHostUrl(raw: string): string {\n let url: URL\n try {\n url = new URL(raw.trim())\n }\n catch {\n throw new RemoteHostError('Invalid host URL: expected wss://host[:port].')\n }\n const shown = displayHostUrl(raw)\n if (url.username !== '' || url.password !== '')\n throw new RemoteHostError(`Host URLs can't carry a user or password (${shown}): put the token in the token field (or --token-file), not in the URL.`)\n if (url.search !== '' || raw.includes('?'))\n throw new RemoteHostError(`Host URLs can't carry a query string (${shown}): remove it; a token goes in the token field (or --token-file).`)\n if (url.hash !== '' || raw.includes('#'))\n throw new RemoteHostError(`Host URLs can't carry a fragment (${shown}): remove it.`)\n if (url.pathname.split('/').some(isSecretPathSegment))\n throw new RemoteHostError(`Host URLs can't carry a token in their path (${url.protocol}//${url.host}): remove it; a token goes in the token field (or --token-file).`)\n if (url.protocol === 'wss:' || (url.protocol === 'ws:' && isLoopbackHost(url.hostname)))\n return url.href.replace(/\\/$/, '')\n if (url.protocol === 'ws:')\n throw new RemoteHostError(`Refusing ws://${url.host}: the token would travel unencrypted. Use wss:// (ws:// is only for 127.0.0.1 / localhost).`)\n throw new RemoteHostError(`Invalid host URL ${shown}: expected wss://host[:port].`)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.js";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
//#region src/codemode/wasm.ts
|
|
5
|
+
var wasm_exports = /* @__PURE__ */ __exportAll({ loadQuickJSWasm: () => loadQuickJSWasm });
|
|
6
|
+
const modules = /* @__PURE__ */ new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Read and compile the QuickJS wasm once per path. `path` defaults to the file in the installed
|
|
9
|
+
* `quickjs-wasi` package (an optional peer dependency); pass it when the file lives elsewhere, for
|
|
10
|
+
* example embedded in a Bun compiled executable. A failed load is retried on the next call.
|
|
11
|
+
*/
|
|
12
|
+
function loadQuickJSWasm(path) {
|
|
13
|
+
let resolved;
|
|
14
|
+
try {
|
|
15
|
+
resolved = path ?? createRequire(import.meta.url).resolve("quickjs-wasi/quickjs.wasm");
|
|
16
|
+
} catch (error) {
|
|
17
|
+
return Promise.reject(/* @__PURE__ */ new Error(`codemode needs the optional peer dependency \`quickjs-wasi\`: ${error instanceof Error ? error.message : String(error)}`));
|
|
18
|
+
}
|
|
19
|
+
let module = modules.get(resolved);
|
|
20
|
+
if (!module) {
|
|
21
|
+
const { WebAssembly } = globalThis;
|
|
22
|
+
module = readFile(resolved).then((bytes) => WebAssembly.compile(bytes)).catch((error) => {
|
|
23
|
+
modules.delete(resolved);
|
|
24
|
+
throw error;
|
|
25
|
+
});
|
|
26
|
+
modules.set(resolved, module);
|
|
27
|
+
}
|
|
28
|
+
return module;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { wasm_exports as n, loadQuickJSWasm as t };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=wasm-BVT-j5cl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasm-BVT-j5cl.js","names":[],"sources":["../src/codemode/wasm.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\n\n/**\n * A compiled `WebAssembly.Module` of `quickjs-wasi/quickjs.wasm`. Typed opaquely so callers don't\n * need the DOM lib for the WebAssembly globals.\n */\nexport type CodemodeWasmModule = object\n\ninterface WebAssemblyGlobal {\n compile: (bytes: Uint8Array) => Promise<CodemodeWasmModule>\n}\n\nconst modules = new Map<string, Promise<CodemodeWasmModule>>()\n\n/**\n * Read and compile the QuickJS wasm once per path. `path` defaults to the file in the installed\n * `quickjs-wasi` package (an optional peer dependency); pass it when the file lives elsewhere, for\n * example embedded in a Bun compiled executable. A failed load is retried on the next call.\n */\nexport function loadQuickJSWasm(path?: string): Promise<CodemodeWasmModule> {\n let resolved: string\n try {\n resolved = path ?? createRequire(import.meta.url).resolve('quickjs-wasi/quickjs.wasm')\n }\n catch (error) {\n return Promise.reject(new Error(`codemode needs the optional peer dependency \\`quickjs-wasi\\`: ${error instanceof Error ? error.message : String(error)}`))\n }\n let module = modules.get(resolved)\n if (!module) {\n const { WebAssembly } = globalThis as unknown as { WebAssembly: WebAssemblyGlobal }\n module = readFile(resolved)\n .then(bytes => WebAssembly.compile(bytes))\n .catch((error: unknown) => {\n modules.delete(resolved)\n throw error\n })\n modules.set(resolved, module)\n }\n return module\n}\n"],"mappings":";;;;;AAaA,MAAM,0BAAU,IAAI,IAAyC;;;;;;AAO7D,SAAgB,gBAAgB,MAA4C;CAC1E,IAAI;CACJ,IAAI;EACF,WAAW,QAAQ,cAAc,YAAY,GAAG,CAAC,CAAC,QAAQ,2BAA2B;CACvF,SACO,OAAO;EACZ,OAAO,QAAQ,uBAAO,IAAI,MAAM,iEAAiE,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG,CAAC;CAC5J;CACA,IAAI,SAAS,QAAQ,IAAI,QAAQ;CACjC,IAAI,CAAC,QAAQ;EACX,MAAM,EAAE,gBAAgB;EACxB,SAAS,SAAS,QAAQ,CAAC,CACxB,MAAK,UAAS,YAAY,QAAQ,KAAK,CAAC,CAAC,CACzC,OAAO,UAAmB;GACzB,QAAQ,OAAO,QAAQ;GACvB,MAAM;EACR,CAAC;EACH,QAAQ,IAAI,UAAU,MAAM;CAC9B;CACA,OAAO;AACT"}
|