zidane 7.2.5 → 8.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +34 -6
- package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
- package/dist/acp-DQDhi2dj.js.map +1 -0
- package/dist/acp-cli.d.ts +1 -1
- package/dist/acp-cli.js +9 -66
- package/dist/acp-cli.js.map +1 -1
- package/dist/acp.d.ts +10 -590
- package/dist/acp.d.ts.map +1 -1
- package/dist/acp.js +3 -3
- package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
- package/dist/agent-DSLNmBp0.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -2
- package/dist/aliasing-lVFbm81n.js +217 -0
- package/dist/aliasing-lVFbm81n.js.map +1 -0
- package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
- package/dist/anthropic-CD00LhUP.js.map +1 -0
- package/dist/artifacts-CV2hUKnL.js.map +1 -1
- package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
- package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
- package/dist/call-tool-dHlbGOIY.js +70 -0
- package/dist/call-tool-dHlbGOIY.js.map +1 -0
- package/dist/chat/pure.d.ts +372 -6
- package/dist/chat/pure.d.ts.map +1 -1
- package/dist/chat/pure.js +35 -244
- package/dist/chat/pure.js.map +1 -1
- package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
- package/dist/chat-JPJJ8uu5.js.map +1 -0
- package/dist/chat.d.ts +4 -6
- package/dist/chat.js +23 -12
- package/dist/cli-shared-C-YCaglL.js +159 -0
- package/dist/cli-shared-C-YCaglL.js.map +1 -0
- package/dist/client-core-BQSyDALT.d.ts +2115 -0
- package/dist/client-core-BQSyDALT.d.ts.map +1 -0
- package/dist/codemode-worker.d.ts +1 -0
- package/dist/codemode-worker.js +155 -0
- package/dist/codemode-worker.js.map +1 -0
- package/dist/codemode.d.ts +352 -0
- package/dist/codemode.d.ts.map +1 -0
- package/dist/codemode.js +5 -0
- package/dist/connection-Dr-Js4yZ.d.ts +28 -0
- package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
- package/dist/connection-loop-gdh22LTI.js +112 -0
- package/dist/connection-loop-gdh22LTI.js.map +1 -0
- package/dist/context-segments-BHKlagL6.js +1016 -0
- package/dist/context-segments-BHKlagL6.js.map +1 -0
- package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
- package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
- package/dist/contexts/daytona.d.ts +19 -8
- package/dist/contexts/daytona.d.ts.map +1 -1
- package/dist/contexts/daytona.js +1 -440
- package/dist/contexts/docker.d.ts +36 -7
- package/dist/contexts/docker.d.ts.map +1 -1
- package/dist/contexts/docker.js +1 -456
- package/dist/contexts/e2b.d.ts +68 -13
- package/dist/contexts/e2b.d.ts.map +1 -1
- package/dist/contexts/e2b.js +1 -382
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/contexts/sandbox.js +5 -0
- package/dist/contexts/sandbox.js.map +1 -1
- package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
- package/dist/contexts-d7UolYot.js.map +1 -0
- package/dist/contexts.d.ts +3 -3
- package/dist/contexts.js +1 -1
- package/dist/cred-keys-GpBg71cP.js +105 -0
- package/dist/cred-keys-GpBg71cP.js.map +1 -0
- package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
- package/dist/credentials-JttEuRON.js.map +1 -0
- package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
- package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
- package/dist/daemon-cli.d.ts +1 -1
- package/dist/daemon-cli.js +3 -2
- package/dist/daemon-cli.js.map +1 -1
- package/dist/daytona-DG3omipZ.js +513 -0
- package/dist/daytona-DG3omipZ.js.map +1 -0
- package/dist/defaults-Cx3zvDOV.js +23 -0
- package/dist/defaults-Cx3zvDOV.js.map +1 -0
- package/dist/dispatcher-BMlu2BmZ.js +4941 -0
- package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
- package/dist/docker-BZhMMJUp.js +727 -0
- package/dist/docker-BZhMMJUp.js.map +1 -0
- package/dist/e2b-CEVOdRib.js +480 -0
- package/dist/e2b-CEVOdRib.js.map +1 -0
- package/dist/edit-utils-EGosADZq.js +234 -0
- package/dist/edit-utils-EGosADZq.js.map +1 -0
- package/dist/environment-8wsKE2Ln.js +214 -0
- package/dist/environment-8wsKE2Ln.js.map +1 -0
- package/dist/eval-BNcvle_J.js +1595 -0
- package/dist/eval-BNcvle_J.js.map +1 -0
- package/dist/eval.d.ts +2 -2
- package/dist/eval.js +1 -1489
- package/dist/executor-Cx5-8yqi.js +621 -0
- package/dist/executor-Cx5-8yqi.js.map +1 -0
- package/dist/extension-authoring-DyGGmq9V.js +385 -0
- package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
- package/dist/extensions.d.ts +2 -2
- package/dist/extensions.js +3 -3
- package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
- package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
- package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
- package/dist/format-C2NQEVUH.js.map +1 -0
- package/dist/format-bytes-C7tfc3Zm.js +55 -0
- package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
- package/dist/headless-C_rNUuYC.js +960 -0
- package/dist/headless-C_rNUuYC.js.map +1 -0
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -413
- package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
- package/dist/history-search-CcYzF8-0.js.map +1 -0
- package/dist/history-search-worker.d.ts +1 -1
- package/dist/history-search-worker.js +1 -1
- package/dist/host-D7NrI03V.js +378 -0
- package/dist/host-D7NrI03V.js.map +1 -0
- package/dist/host-signals-BcP5QKUD.js +118 -0
- package/dist/host-signals-BcP5QKUD.js.map +1 -0
- package/dist/identity-CwfO8K-t.js +26 -0
- package/dist/identity-CwfO8K-t.js.map +1 -0
- package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
- package/dist/index-BGe1fQT7.d.ts.map +1 -0
- package/dist/index-BVQsIKGn.d.ts +448 -0
- package/dist/index-BVQsIKGn.d.ts.map +1 -0
- package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
- package/dist/index-CHABJd-L.d.ts.map +1 -0
- package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
- package/dist/index-D6a7qXpg.d.ts.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +27 -23
- package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
- package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
- package/dist/ipc/remote.d.ts +313 -0
- package/dist/ipc/remote.d.ts.map +1 -0
- package/dist/ipc/remote.js +4 -0
- package/dist/ipc.d.ts +6 -964
- package/dist/ipc.js +403 -4
- package/dist/ipc.js.map +1 -0
- package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
- package/dist/isolation-D9L650W5.d.ts.map +1 -0
- package/dist/json-rpc--HXQti1E.js +350 -0
- package/dist/json-rpc--HXQti1E.js.map +1 -0
- package/dist/links-j8rED1sR.js +603 -0
- package/dist/links-j8rED1sR.js.map +1 -0
- package/dist/local-terminal-D8QThwo_.js +252 -0
- package/dist/local-terminal-D8QThwo_.js.map +1 -0
- package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
- package/dist/logger-Gtqlayx8.js.map +1 -0
- package/dist/logs-view-CWG8aUAG.js.map +1 -1
- package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
- package/dist/mcp-_wecH9Qe.js.map +1 -0
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +2 -2
- package/dist/media-sniff-UKijEaiQ.js.map +1 -1
- package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
- package/dist/messages-BqiwcD2Q.js.map +1 -0
- package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
- package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
- package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
- package/dist/openai-compat-CFrpH7uq.js.map +1 -0
- package/dist/orchestration-BCGmB8Ps.js +511 -0
- package/dist/orchestration-BCGmB8Ps.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -2
- package/dist/output/stream-json.d.ts.map +1 -1
- package/dist/output/stream-json.js +1 -1
- package/dist/output/terminal.d.ts +1 -2
- package/dist/output/terminal.d.ts.map +1 -1
- package/dist/output/terminal.js +13 -7
- package/dist/output/terminal.js.map +1 -1
- package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
- package/dist/plugins-DS7mahzZ.js.map +1 -0
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +1 -2
- package/dist/prelude-Cxo4t74B.js +517 -0
- package/dist/prelude-Cxo4t74B.js.map +1 -0
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -2
- package/dist/project-root-B8zADr4o.js +167 -0
- package/dist/project-root-B8zADr4o.js.map +1 -0
- package/dist/project-user-paths-BSgtrRxl.js +58 -0
- package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
- package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
- package/dist/prompts-DYcvqShf.d.ts.map +1 -0
- package/dist/protocol-DnhqqSmE.js +13 -0
- package/dist/protocol-DnhqqSmE.js.map +1 -0
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +1 -2
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/arcee.js +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/baseten.js +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/cerebras.js +3 -2
- package/dist/providers/cerebras.js.map +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/local.js +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai-compat.js +1 -2
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +15 -12
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +3 -2
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +3 -3
- package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
- package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +4 -4
- package/dist/registry-D6ShBWJU.js +5234 -0
- package/dist/registry-D6ShBWJU.js.map +1 -0
- package/dist/remote-hosts-BtA_9ZGp.js +97 -0
- package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
- package/dist/restate.d.ts +2 -3
- package/dist/restate.d.ts.map +1 -1
- package/dist/restate.js +631 -572
- package/dist/restate.js.map +1 -1
- package/dist/run-summary-CklLiZ4y.js +288 -0
- package/dist/run-summary-CklLiZ4y.js.map +1 -0
- package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
- package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
- package/dist/session/sqlite.d.ts +1 -2
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +1 -616
- package/dist/session-factory-BUGY5P40.js +1576 -0
- package/dist/session-factory-BUGY5P40.js.map +1 -0
- package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
- package/dist/session-xh9JXu6i.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/settings-keys-Ckf29NeM.js +677 -0
- package/dist/settings-keys-Ckf29NeM.js.map +1 -0
- package/dist/shell-path-Dqaoow2J.js +412 -0
- package/dist/shell-path-Dqaoow2J.js.map +1 -0
- package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
- package/dist/skills-DKqZJm4X.js.map +1 -0
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -2
- package/dist/source-mPExaUm8.js +381 -0
- package/dist/source-mPExaUm8.js.map +1 -0
- package/dist/sqlite-DV1DQzN2.js +698 -0
- package/dist/sqlite-DV1DQzN2.js.map +1 -0
- package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
- package/dist/src-BRMYRJib.js.map +1 -0
- package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
- package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
- package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
- package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
- package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
- package/dist/timeout-DEaqslLO.d.ts.map +1 -1
- package/dist/todo-edits-Dn251YUP.js +1790 -0
- package/dist/todo-edits-Dn251YUP.js.map +1 -0
- package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
- package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
- package/dist/tool-state-Dku6YqAB.js +989 -0
- package/dist/tool-state-Dku6YqAB.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -2
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +1 -2
- package/dist/tools/prompts.d.ts +1 -1
- package/dist/tools/prompts.js +7 -7
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/web-search.d.ts +1 -2
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +2 -2
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools-_DnT3AGM.js +578 -0
- package/dist/tools-_DnT3AGM.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +4 -2
- package/dist/tui.d.ts +534 -517
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +34933 -27243
- package/dist/tui.js.map +1 -1
- package/dist/turn-operations-B8sokwi5.js +333 -0
- package/dist/turn-operations-B8sokwi5.js.map +1 -0
- package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
- package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
- package/dist/types-C7ZFOztE.d.ts +132 -0
- package/dist/types-C7ZFOztE.d.ts.map +1 -0
- package/dist/types-CH5XpIHw.js +114 -0
- package/dist/types-CH5XpIHw.js.map +1 -0
- package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
- package/dist/types-Cu0ZGDu9.js.map +1 -0
- package/dist/types-IqegbJEE.d.ts +624 -0
- package/dist/types-IqegbJEE.d.ts.map +1 -0
- package/dist/types.d.ts +4 -4
- package/dist/types.js +1 -1
- package/dist/url-D8HCl65b.js +1259 -0
- package/dist/url-D8HCl65b.js.map +1 -0
- package/dist/wasm-BVT-j5cl.js +33 -0
- package/dist/wasm-BVT-j5cl.js.map +1 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
- package/dist/ws-CIHMvlSh.js +952 -0
- package/dist/ws-CIHMvlSh.js.map +1 -0
- package/dist/ws-client-N7NxzvQp.js +230 -0
- package/dist/ws-client-N7NxzvQp.js.map +1 -0
- package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
- package/dist/xai-CvJTeLrI.js.map +1 -0
- package/dist/xdg-zweed0-t.js +117 -0
- package/dist/xdg-zweed0-t.js.map +1 -0
- package/docs/ACP.md +52 -0
- package/docs/ARCHITECTURE.md +103 -6
- package/docs/ARTIFACTS.md +8 -4
- package/docs/CHAT.md +165 -14
- package/docs/EXECUTION_CONTEXT.md +8 -0
- package/docs/EXTENSIONS.md +123 -2
- package/docs/HEADLESS.md +2 -0
- package/docs/IPC.md +775 -64
- package/docs/MACHINES.md +456 -0
- package/docs/PANELS.md +3 -0
- package/docs/README.md +4 -0
- package/docs/RESTATE.md +3 -2
- package/docs/RUN_IN_BACKGROUND.md +10 -2
- package/docs/SERVER.md +1085 -0
- package/docs/SKILL.md +6 -1
- package/docs/TERMINAL.md +75 -0
- package/docs/TUI.md +65 -14
- package/package.json +58 -26
- package/scripts/eval.ts +4 -0
- package/dist/acp-D-tVyUjw.js.map +0 -1
- package/dist/agent-D0zZnGbt.js.map +0 -1
- package/dist/anthropic-C2aole0G.js.map +0 -1
- package/dist/approvals-DKaJZYlm.js.map +0 -1
- package/dist/atomic-write-B7zr1ddF.js.map +0 -1
- package/dist/auth-BG2rVKSt.js.map +0 -1
- package/dist/completion-core-BRo86R_L.js.map +0 -1
- package/dist/contexts/daytona.js.map +0 -1
- package/dist/contexts/docker.js.map +0 -1
- package/dist/contexts/e2b.js.map +0 -1
- package/dist/contexts-CRE9pw07.js.map +0 -1
- package/dist/eval.js.map +0 -1
- package/dist/format-BF745pLL.js.map +0 -1
- package/dist/glob-DluQFSw1.js +0 -270
- package/dist/glob-DluQFSw1.js.map +0 -1
- package/dist/headless.js.map +0 -1
- package/dist/history-search-C4bk1Wz_.js.map +0 -1
- package/dist/index-BgN1T3lk.d.ts.map +0 -1
- package/dist/index-C37_ppWv.d.ts.map +0 -1
- package/dist/index-C6NEd5y_.d.ts.map +0 -1
- package/dist/ipc-BKVIIOqH.js +0 -331
- package/dist/ipc-BKVIIOqH.js.map +0 -1
- package/dist/ipc.d.ts.map +0 -1
- package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
- package/dist/json-rpc-rSWMUh9b.js +0 -192
- package/dist/json-rpc-rSWMUh9b.js.map +0 -1
- package/dist/logger--C1VQjwJ.js.map +0 -1
- package/dist/mcp-CgNd-f3F.js.map +0 -1
- package/dist/messages-2jcOA_5R.js.map +0 -1
- package/dist/openai-compat-Dy56weK8.js.map +0 -1
- package/dist/output-cap-C9zukcCj.js +0 -100
- package/dist/output-cap-C9zukcCj.js.map +0 -1
- package/dist/panels-B6gRk4bf.js +0 -789
- package/dist/panels-B6gRk4bf.js.map +0 -1
- package/dist/plugins-gbI7SBA6.js.map +0 -1
- package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
- package/dist/run-summary-BU_NgwUT.js +0 -269
- package/dist/run-summary-BU_NgwUT.js.map +0 -1
- package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
- package/dist/session/sqlite.js.map +0 -1
- package/dist/session-BqRP1hS7.js.map +0 -1
- package/dist/shell-path-DfdXrGg9.js +0 -1549
- package/dist/shell-path-DfdXrGg9.js.map +0 -1
- package/dist/skills-BC3dodWp.js.map +0 -1
- package/dist/src-CkNQKFKr.js.map +0 -1
- package/dist/todo-edits-UOwgxGKu.js +0 -528
- package/dist/todo-edits-UOwgxGKu.js.map +0 -1
- package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
- package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
- package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
- package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
- package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
- package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
- package/dist/turn-operations-DrbJlpq9.js.map +0 -1
- package/dist/types-CWgENVLY.js.map +0 -1
- package/dist/xai-CazjStOK.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor-Cx5-8yqi.js","names":[],"sources":["../src/ipc/machine/params.ts","../src/ipc/machine/streams.ts","../src/ipc/machine/task-logs.ts","../src/ipc/machine/terminals.ts","../src/ipc/machine/executor.ts"],"sourcesContent":["/**\n * Shape checks for what a host sends a machine. The host is not trusted: a\n * malformed request is refused before anything runs.\n */\nimport type { MachineHandleRef } from '../../chat/machine-protocol'\n\nexport type Params = Record<string, unknown>\n\nexport function paramsOf(value: unknown): Params {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw new Error('Invalid params: expected an object.')\n return value as Params\n}\n\nexport function str(params: Params, key: string): string {\n const value = params[key]\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optStr(params: Params, key: string): string | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optNum(params: Params, key: string): number | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'number' || !Number.isFinite(value))\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function num(params: Params, key: string): number {\n const value = optNum(params, key)\n if (value === undefined)\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function optEnv(params: Params, key: string): Record<string, string> | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (!value || typeof value !== 'object' || Array.isArray(value) || Object.values(value).some(v => typeof v !== 'string'))\n throw new Error(`Invalid params: \"${key}\" must map names to strings.`)\n return value as Record<string, string>\n}\n\nexport function handleRef(params: Params): MachineHandleRef {\n const handle = params.handle as Partial<MachineHandleRef> | undefined\n if (!handle || typeof handle.id !== 'string' || typeof handle.cwd !== 'string' || handle.id.length > 200)\n throw new Error('Invalid params: \"handle\" must be { id, cwd }.')\n return { id: handle.id, cwd: handle.cwd }\n}\n","/**\n * Live processes a machine runs for its host (`exec.stream`, `docs/MACHINES.md`):\n * `execStream` of its process context, its stdout / stderr sent as\n * `exec.stream.data` notifications (chunks of at most\n * `MACHINE_STREAM_CHUNK_BYTES`), then one `exec.stream.exit` once both are\n * drained. Bounded (`MACHINE_MAX_STREAMS`); a lost host link kills them all:\n * a stream carries a live protocol (a stdio MCP server), output it can't\n * deliver would desynchronize it.\n */\nimport type { ExecutionContext, ExecutionHandle, StreamHandle } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\nimport { MACHINE_MAX_STREAMS, MACHINE_STREAM_CHUNK_BYTES } from '../../chat/machine-protocol'\n\nexport interface MachineStreams {\n start: (context: ExecutionContext, handle: ExecutionHandle, input: { callId: string, command: string, cwd?: string, env?: Record<string, string> }) => Promise<{ pid: number }>\n write: (callId: string, data: string) => Promise<void>\n /** `exec.cancel` of a stream: `false` when no stream has this id. */\n kill: (callId: string) => boolean\n /** The host link dropped. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineStreams(options: {\n send: (method: 'exec.stream.data' | 'exec.stream.exit', params: Record<string, unknown>) => boolean\n}): MachineStreams {\n const streams = new Map<string, StreamHandle>()\n\n async function pump(callId: string, name: 'stdout' | 'stderr', source: AsyncIterable<Uint8Array> | undefined): Promise<void> {\n if (!source)\n return\n for await (const chunk of source) {\n for (let at = 0; at < chunk.byteLength; at += MACHINE_STREAM_CHUNK_BYTES) {\n const data = Buffer.from(chunk.subarray(at, at + MACHINE_STREAM_CHUNK_BYTES)).toString('base64')\n if (!options.send('exec.stream.data', { callId, stream: name, data }))\n void streams.get(callId)?.kill()\n }\n }\n }\n\n const kill = (callId: string): boolean => {\n const stream = streams.get(callId)\n if (!stream)\n return false\n void stream.kill().catch(() => undefined)\n return true\n }\n\n return {\n async start(context, handle, { callId, command, cwd, env }) {\n if (!context.execStream)\n throw new Error('This machine cannot stream processes.')\n if (streams.has(callId))\n throw new Error(`A stream \"${callId}\" already runs.`)\n if (streams.size >= MACHINE_MAX_STREAMS)\n throw new Error(`This machine already runs ${MACHINE_MAX_STREAMS} live processes.`)\n const stream = await context.execStream(handle, command, { ...(cwd ? { cwd } : {}), ...(env ? { env } : {}) })\n streams.set(callId, stream)\n void Promise.all([pump(callId, 'stdout', stream.stdout), pump(callId, 'stderr', stream.stderr), stream.exited])\n .catch(() => undefined)\n .then(async () => {\n const code = await stream.exited\n streams.delete(callId)\n options.send('exec.stream.exit', { callId, code })\n })\n return { pid: stream.pid }\n },\n async write(callId, data) {\n const stream = streams.get(callId)\n if (!stream)\n throw new Error(`No live process \"${callId}\" on this machine.`)\n const bytes = Buffer.from(data, 'base64')\n if (bytes.byteLength > MACHINE_STREAM_CHUNK_BYTES)\n throw new Error(`exec.stream.write: at most ${MACHINE_STREAM_CHUNK_BYTES} bytes per call.`)\n await stream.write(bytes)\n },\n kill,\n linkLost() {\n for (const callId of streams.keys())\n kill(callId)\n },\n async closeAll() {\n const all = [...streams.values()]\n streams.clear()\n await Promise.all(all.map(stream => stream.kill().catch(() => undefined)))\n },\n }\n}\n","/**\n * The machine's background-task logs (`<data dir>/tasks/`): the one place in\n * its data dir the host may read, and only the logs of tasks this machine\n * started. A command run for the host can reach that folder (no sandbox, or\n * a sandbox that allows the data dir's parent), so a log path is never\n * trusted as a path: it is opened without following a symlink, must be a\n * regular file, and its real path must be the same file inside the tasks\n * dir. Otherwise `ln -sf ~/.zidane/credentials.json <log>` would make the\n * (unsandboxed) machine process read anything for the host.\n */\nimport { Buffer } from 'node:buffer'\nimport { chmodSync, closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { isInside } from '../../chat/workspace-confinement'\n\nconst NO_FOLLOW = constants.O_NOFOLLOW ?? 0\n\nexport interface TaskLogs {\n /** The folder a handle's task logs go in: made owner-only, refused when it is not a real folder in the tasks dir. */\n outputDir: (handleId: string) => string\n add: (path: string) => void\n has: (path: string) => boolean\n count: () => number\n read: (path: string, binary: boolean) => string\n size: (path: string) => number\n}\n\n/** `path` made (or kept) an owner-only real folder; a symlink there is refused, never followed. */\nfunction ownerOnlyDir(path: string): void {\n mkdirSync(path, { recursive: true, mode: 0o700 })\n const stat = lstatSync(path)\n if (!stat.isDirectory() || stat.isSymbolicLink())\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n chmodSync(path, 0o700)\n}\n\nexport function createTaskLogs(dataDir: string): TaskLogs {\n const dir = join(dataDir, 'tasks')\n ownerOnlyDir(dir)\n const realDir = realpathSync.native(dir)\n const known = new Set<string>()\n const refused = (path: string): Error => new Error(`${path} is not a task log of this machine.`)\n\n /** An fd on the log at `path`, checked as the module header says; the caller closes it. */\n const open = (path: string): number => {\n let fd: number\n try {\n fd = openSync(path, constants.O_RDONLY | NO_FOLLOW)\n }\n catch {\n throw refused(path)\n }\n try {\n const opened = fstatSync(fd)\n const real = realpathSync.native(path)\n const named = statSync(real)\n if (!opened.isFile() || !isInside(realDir, real) || named.ino !== opened.ino || named.dev !== opened.dev)\n throw refused(path)\n return fd\n }\n catch {\n closeSync(fd)\n throw refused(path)\n }\n }\n\n const withLog = <T>(path: string, fn: (fd: number) => T): T => {\n const fd = open(path)\n try {\n return fn(fd)\n }\n finally {\n closeSync(fd)\n }\n }\n\n return {\n outputDir(handleId) {\n const path = join(dir, Buffer.from(handleId).toString('hex').slice(0, 64))\n ownerOnlyDir(path)\n if (!isInside(realDir, realpathSync.native(path)))\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n return path\n },\n add: path => void known.add(path),\n has: path => known.has(path),\n count: () => known.size,\n read: (path, binary) => withLog(path, fd => (binary ? readFileSync(fd).toString('base64') : readFileSync(fd, 'utf8'))),\n size: path => withLog(path, fd => fstatSync(fd).size),\n }\n}\n","/**\n * PTYs a machine runs for its host. They outlive the host link for a grace\n * period, buffering their output (bounded), so a host that reconnects\n * reattaches with the backlog; past the grace they are killed.\n */\nimport type { ExecutionContext, ExecutionHandle, TerminalProcess } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\n\nexport const MACHINE_MAX_TERMINALS = 16\nexport const MACHINE_TERMINAL_BACKLOG_BYTES = 256 * 1024\nexport const MACHINE_TERMINAL_GRACE_MS = 5 * 60 * 1000\n\ninterface Entry {\n process: TerminalProcess\n backlog: Buffer[]\n backlogBytes: number\n /** Bytes produced since it opened. */\n total: number\n graceTimer?: ReturnType<typeof setTimeout>\n}\n\nexport interface MachineTerminals {\n open: (context: ExecutionContext, handle: ExecutionHandle, options: { cols: number, rows: number, cwd?: string }) => Promise<string>\n attach: (terminalId: string) => { attached: boolean, backlog: string, total: number }\n write: (terminalId: string, data: string) => void\n resize: (terminalId: string, cols: number, rows: number) => void\n kill: (terminalId: string) => Promise<void>\n /** The host link dropped: start every terminal's grace period. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineTerminals(options: {\n /** Live output to the host; `false` when the link is down. */\n send: (method: 'terminal.data' | 'terminal.exit', params: Record<string, unknown>) => boolean\n graceMs?: number\n}): MachineTerminals {\n const terminals = new Map<string, Entry>()\n const graceMs = options.graceMs ?? MACHINE_TERMINAL_GRACE_MS\n\n const entry = (terminalId: string): Entry => {\n const found = terminals.get(terminalId)\n if (!found)\n throw new Error(`No terminal \"${terminalId}\" on this machine.`)\n return found\n }\n\n const remember = (e: Entry, data: Uint8Array): void => {\n e.backlog.push(Buffer.from(data))\n e.backlogBytes += data.byteLength\n e.total += data.byteLength\n while (e.backlogBytes > MACHINE_TERMINAL_BACKLOG_BYTES && e.backlog.length > 1)\n e.backlogBytes -= e.backlog.shift()!.byteLength\n }\n\n const kill = async (terminalId: string): Promise<void> => {\n const e = terminals.get(terminalId)\n if (!e)\n return\n terminals.delete(terminalId)\n clearTimeout(e.graceTimer)\n await e.process.kill().catch(() => undefined)\n }\n\n return {\n async open(context, handle, { cols, rows, cwd }) {\n if (!context.openTerminal)\n throw new Error('This machine has no terminal support (it needs Bun).')\n if (terminals.size >= MACHINE_MAX_TERMINALS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TERMINALS} terminals.`)\n const holder: { id?: string } = {}\n const pending: Uint8Array[] = []\n const process = await context.openTerminal(handle, {\n cols,\n rows,\n ...(cwd ? { cwd } : {}),\n onData: (data) => {\n const e = holder.id ? terminals.get(holder.id) : undefined\n if (!e) {\n pending.push(data)\n return\n }\n remember(e, data)\n options.send('terminal.data', { terminalId: holder.id, data: Buffer.from(data).toString('base64') })\n },\n })\n holder.id = process.id\n const e: Entry = { process, backlog: [], backlogBytes: 0, total: 0 }\n terminals.set(process.id, e)\n for (const data of pending)\n remember(e, data)\n void process.exited.then((code) => {\n if (terminals.get(process.id) !== e)\n return\n terminals.delete(process.id)\n clearTimeout(e.graceTimer)\n options.send('terminal.exit', { terminalId: process.id, code })\n })\n return process.id\n },\n attach(terminalId) {\n const e = terminals.get(terminalId)\n if (!e)\n return { attached: false, backlog: '', total: 0 }\n clearTimeout(e.graceTimer)\n e.graceTimer = undefined\n return { attached: true, backlog: Buffer.concat(e.backlog).toString('base64'), total: e.total }\n },\n write: (terminalId, data) => entry(terminalId).process.write(Buffer.from(data, 'base64')),\n resize: (terminalId, cols, rows) => entry(terminalId).process.resize(cols, rows),\n kill,\n linkLost() {\n for (const [id, e] of terminals) {\n clearTimeout(e.graceTimer)\n e.graceTimer = setTimeout(() => void kill(id), graceMs)\n e.graceTimer.unref?.()\n }\n },\n async closeAll() {\n await Promise.all([...terminals.keys()].map(kill))\n },\n }\n}\n","/**\n * What a machine runs for its host (`docs/MACHINES.md` § Machine side): the\n * machine protocol's host→machine methods, served from one `process`\n * execution context, behind a guard that never trusts the host. Every handle\n * cwd, command cwd and file path resolves against the handle's cwd and must\n * real-path into a declared root (symlinks followed), never into the\n * machine's data dir; the one exception is reading a log file of a\n * background task this machine started (`./task-logs.ts`: opened without\n * following symlinks, checked to be that file).\n *\n * Transport-free: the agent (`./agent.ts`) feeds it requests and gives it a\n * `notify` toward the host, which is `false` while the link is down (task\n * exits are then queued until {@link MachineExecutor.linkUp}).\n */\nimport type { MachineRoot } from '../../chat/machine-protocol'\nimport type { LooseSandboxSettings } from '../../chat/sandbox-settings'\nimport type { WorkspaceConfinement } from '../../chat/workspace-confinement'\nimport type { ExecutionContext, ExecutionHandle, TaskExitInfo } from '../../contexts/types'\nimport type { Params } from './params'\nimport { Buffer } from 'node:buffer'\nimport { mkdirSync, realpathSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { workspacePath } from '../../chat/environment'\nimport { prepareWorktree, teardownWorktree } from '../../chat/environments'\nimport { resolveSandboxForRoots, sandboxUnreadableDirs } from '../../chat/sandbox-settings'\nimport { createWorkspaceConfinement, isInside } from '../../chat/workspace-confinement'\nimport { resolveStorageDirs } from '../../chat/xdg'\nimport { createProcessContext } from '../../contexts/process'\nimport { handleRef, num, optEnv, optNum, optStr, paramsOf, str } from './params'\nimport { createMachineStreams } from './streams'\nimport { createTaskLogs } from './task-logs'\nimport { createMachineTerminals } from './terminals'\n\nexport const MACHINE_MAX_TASKS = 64\nexport const MACHINE_TASK_OUTPUT_BYTES = 8 * 1024 * 1024\nconst MAX_PENDING_EXITS = 256\nconst GLOB_CHARS = /[*?[\\]{}]/\n\nexport interface MachineExecutorOptions {\n roots: readonly MachineRoot[]\n /** The machine's own data dir: never reachable by file ops. */\n dataDir: string\n /** A notification to the host; `false` when the link is down. */\n notify: (method: string, params: Record<string, unknown>) => boolean\n /** Terminals' grace after the link drops. */\n terminalGraceMs?: number\n /**\n * The machine user's own `sandbox*` settings (`docs/MACHINES.md` §\n * Sandbox): applied to every command this machine runs, whatever the host.\n */\n sandbox?: LooseSandboxSettings\n /**\n * The machine user's zidane data dir: private to file operations (with the\n * rest of {@link machinePrivateDirs}) and its credential files hidden from\n * sandboxed commands.\n */\n credentialsDataDir?: string\n}\n\n/**\n * What file operations never reach, whatever the roots (`docs/MACHINES.md` §\n * Security model): zidane's own folders as this process resolves them (data,\n * config, state, cache: credentials, tokens, extensions, plugins, skills,\n * mcps.json, SYSTEM.md, the machine's data, sync files), the default\n * `~/.zidane`, the given data dir (a server's `--data-dir`), and the\n * credential folders the sandbox hides (`~/.ssh`, `~/.aws`, …).\n */\nexport function machinePrivateDirs(zidaneDataDir?: string): string[] {\n const storage = resolveStorageDirs()\n return [...new Set([\n ...(zidaneDataDir ? [zidaneDataDir] : []),\n storage.dataDir,\n storage.configDir,\n storage.stateDir,\n storage.cacheDir,\n join(homedir(), '.zidane'),\n ...sandboxUnreadableDirs(zidaneDataDir),\n ])]\n}\n\nexport interface MachineExecutor {\n /** Serve one host request; throws (the agent turns it into a JSON-RPC error). */\n handle: (method: string, params: unknown) => Promise<unknown>\n /** The host link is (back) up: re-send what was queued. */\n linkUp: () => void\n /** The host link dropped: terminals start their grace. */\n linkLost: () => void\n close: () => Promise<void>\n /** The OS sandbox the machine applies, and why it can't when it is on but unavailable. */\n sandbox: { on: boolean, warning?: string }\n}\n\n/** The static directory of a glob (`/a/b/**\\/*.ts` → `/a/b`). */\nfunction globBase(path: string): string {\n const segments = path.split('/')\n const index = segments.findIndex(s => GLOB_CHARS.test(s))\n return index < 0 ? path : segments.slice(0, index).join('/') || '/'\n}\n\n/**\n * A folder a user offers to share (`zidane machine share --root`, a share\n * link): its real path must exist and not be, or be inside, a private\n * folder (a root there would lend what {@link machinePrivateDirs} keeps out).\n * Returns the real path.\n */\nexport function shareableRoot(root: string, zidaneDataDir?: string): string {\n let real: string\n try {\n real = realpathSync.native(root)\n }\n catch {\n throw new Error(`${root} does not exist.`)\n }\n const hidden = machinePrivateDirs(zidaneDataDir).map(realPathOr).find(dir => isInside(dir, real))\n if (hidden)\n throw new Error(`${root} is inside ${hidden} (zidane's own data or credentials): share a folder outside it.`)\n return real\n}\n\nfunction realPathOr(path: string): string {\n try {\n return realpathSync.native(path)\n }\n catch {\n return path\n }\n}\n\nexport function machineConfinement(roots: readonly MachineRoot[], dataDir: string, privateDirs: readonly string[] = []): WorkspaceConfinement {\n // Worktrees made in the data dir's `worktrees/` are workspace content; nothing else there is.\n const worktrees = join(dataDir, 'worktrees')\n mkdirSync(worktrees, { recursive: true })\n return createWorkspaceConfinement([...roots.map(root => root.path), worktrees], {\n dataDir,\n privateDirs,\n names: { roots: 'the machine\\'s roots', dataDir: 'the machine\\'s data dir, which the host can\\'t reach' },\n })\n}\n\n/**\n * A listing's entries whose real path is reachable: a traversal can follow a\n * symlinked folder out of the roots, or walk into a private one, from a base\n * that passed the check.\n */\nfunction reachableEntries<T>(confinement: WorkspaceConfinement, base: string, entries: readonly T[]): T[] {\n return entries.filter((entry) => {\n const path = typeof entry === 'string' ? entry : (entry as { path?: unknown }).path\n if (typeof path !== 'string')\n return false\n try {\n confinement.checkPath(isAbsolute(path) ? path : resolve(base, path))\n return true\n }\n catch {\n return false\n }\n })\n}\n\n/** `fs.list`: a path or glob under the handle's cwd, no `..` in a pattern, only reachable entries back. */\nasync function listReachable(context: ExecutionContext, confinement: WorkspaceConfinement, handle: ExecutionHandle, params: Params): Promise<unknown[]> {\n const pattern = str(params, 'path')\n if (GLOB_CHARS.test(pattern) && pattern.split(/[/\\\\]/).includes('..'))\n throw new Error(`\"${pattern}\": a pattern can't climb with \"..\".`)\n const path = workspacePath(handle.cwd, pattern)\n confinement.checkPath(globBase(path))\n const raw = params.options && typeof params.options === 'object' ? params.options as Record<string, unknown> : {}\n const listOptions = {\n ...(typeof raw.glob === 'boolean' ? { glob: raw.glob } : {}),\n ...(typeof raw.limit === 'number' ? { limit: raw.limit } : {}),\n ...(typeof raw.metadata === 'boolean' ? { metadata: raw.metadata } : {}),\n ...(typeof raw.gitignore === 'boolean' ? { gitignore: raw.gitignore } : {}),\n }\n return reachableEntries(confinement, globBase(path), await context.listFiles(handle, path, listOptions))\n}\n\n/** One process context for every handle, under the machine user's own sandbox when it is on. */\nfunction sandboxedContext(options: MachineExecutorOptions, confinement: WorkspaceConfinement): { sandbox: ReturnType<typeof resolveSandboxForRoots>, context: ExecutionContext } {\n const sandbox = resolveSandboxForRoots(options.sandbox ?? { sandbox: false }, confinement.roots, {\n ...(options.credentialsDataDir ? { dataDir: options.credentialsDataDir } : {}),\n // Not the task logs: the machine process writes them, and a command able to write there could swap one for a symlink.\n })\n return { sandbox, context: createProcessContext({ cwd: confinement.roots[0]!, ...(sandbox.isolation ? { isolation: sandbox.isolation } : {}) }) }\n}\n\nexport function createMachineExecutor(options: MachineExecutorOptions): MachineExecutor {\n const confinement = machineConfinement(options.roots, options.dataDir, machinePrivateDirs(options.credentialsDataDir))\n const { sandbox, context } = sandboxedContext(options, confinement)\n const handles = new Map<string, ExecutionHandle>()\n const calls = new Map<string, AbortController>()\n const taskLogs = createTaskLogs(options.dataDir)\n const pendingExits: Array<Record<string, unknown>> = []\n const terminals = createMachineTerminals({ send: options.notify, ...(options.terminalGraceMs !== undefined ? { graceMs: options.terminalGraceMs } : {}) })\n const streams = createMachineStreams({ send: options.notify })\n\n /** A handle's cwd, checked on every call (not only at spawn): the host names it each time. */\n async function handleFor(params: Params): Promise<ExecutionHandle> {\n const ref = handleRef(params)\n const cwd = confinement.resolveFolder(ref.cwd)\n const existing = handles.get(ref.id)\n if (existing && existing.cwd === cwd)\n return existing\n const handle = await context.spawn({ cwd })\n handles.set(ref.id, handle)\n // The id now names another folder: the old handle (and its tasks) would otherwise live on unreachable.\n if (existing)\n await context.destroy(existing).catch(() => undefined)\n return handle\n }\n\n /** `path` resolved like the context resolves it, then confined. */\n function checked(handle: ExecutionHandle, path: string): string {\n const absolute = workspacePath(handle.cwd, path)\n confinement.checkPath(absolute)\n return absolute\n }\n\n /** A log of a task this machine started, by its path (never through the context: see `./task-logs.ts`). */\n const taskLog = (handle: ExecutionHandle, path: string): string | undefined => {\n const absolute = workspacePath(handle.cwd, path)\n return taskLogs.has(absolute) ? absolute : undefined\n }\n\n const cwdOption = (handle: ExecutionHandle, params: Params): { cwd?: string } => {\n const cwd = optStr(params, 'cwd')\n return cwd === undefined ? {} : { cwd: confinement.resolveFolder(workspacePath(handle.cwd, cwd)) }\n }\n\n const sendExit = (exit: Record<string, unknown>): void => {\n if (options.notify('task.exit', exit))\n return\n pendingExits.push(exit)\n if (pendingExits.length > MAX_PENDING_EXITS)\n pendingExits.shift()\n }\n\n const methods: Record<string, (params: Params) => Promise<unknown>> = {\n 'machine.ping': async () => ({ ok: true }),\n 'exec.spawn': async (params) => {\n const handle = await handleFor(params)\n return { id: handleRef(params).id, cwd: handle.cwd }\n },\n 'exec.run': async (params) => {\n const handle = await handleFor(params)\n const callId = str(params, 'callId')\n // A second call under one id would take over its cancel: the first could no longer be stopped.\n if (calls.has(callId))\n throw new Error(`A call \"${callId}\" is already running.`)\n const controller = new AbortController()\n calls.set(callId, controller)\n try {\n const env = optEnv(params, 'env')\n const timeout = optNum(params, 'timeout')\n return await context.exec(handle, str(params, 'command'), { ...cwdOption(handle, params), ...(env ? { env } : {}), ...(timeout !== undefined ? { timeout } : {}), signal: controller.signal })\n }\n finally {\n calls.delete(callId)\n }\n },\n 'exec.cancel': async (params) => {\n const callId = str(params, 'callId')\n const controller = calls.get(callId)\n controller?.abort()\n return { cancelled: controller !== undefined || streams.kill(callId) }\n },\n 'exec.stream': async (params) => {\n const handle = await handleFor(params)\n const env = optEnv(params, 'env')\n return streams.start(context, handle, { callId: str(params, 'callId'), command: str(params, 'command'), ...cwdOption(handle, params), ...(env ? { env } : {}) })\n },\n 'exec.stream.write': async (params) => {\n await streams.write(str(params, 'callId'), str(params, 'data'))\n return { ok: true }\n },\n 'exec.destroy': async (params) => {\n const ref = handleRef(params)\n const handle = handles.get(ref.id)\n handles.delete(ref.id)\n if (handle)\n await context.destroy(handle)\n return { ok: true }\n },\n 'fs.read': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n if (log)\n return { content: taskLogs.read(log, params.binary === true) }\n const path = checked(handle, str(params, 'path'))\n if (params.binary === true)\n return { content: Buffer.from(await context.readFileBinary!(handle, path)).toString('base64') }\n return { content: await context.readFile(handle, path) }\n },\n 'fs.write': async (params) => {\n const handle = await handleFor(params)\n await context.writeFile(handle, checked(handle, str(params, 'path')), Buffer.from(str(params, 'content'), 'base64'))\n return { ok: true }\n },\n 'fs.list': async params => ({ entries: await listReachable(context, confinement, await handleFor(params), params) }),\n 'fs.size': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n return { size: log ? taskLogs.size(log) : await context.fileSize!(handle, checked(handle, str(params, 'path'))) }\n },\n 'bg.start': async (params) => {\n const handle = await handleFor(params)\n const running = (await context.listBackground!(handle)).filter(t => t.status === 'running').length\n if (taskLogs.count() >= MACHINE_MAX_TASKS * 4 || running >= MACHINE_MAX_TASKS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TASKS} background tasks.`)\n const env = optEnv(params, 'env')\n const cap = optNum(params, 'maxOutputBytes')\n const task = await context.execBackground!(handle, str(params, 'command'), {\n ...cwdOption(handle, params),\n ...(env ? { env } : {}),\n outputDir: taskLogs.outputDir(handleRef(params).id),\n maxOutputBytes: Math.min(cap && cap > 0 ? cap : MACHINE_TASK_OUTPUT_BYTES, MACHINE_TASK_OUTPUT_BYTES),\n onExit: (info: TaskExitInfo) => sendExit({ taskId: info.taskId, exit: { ...info } }),\n })\n taskLogs.add(task.outputPath)\n return { taskId: task.taskId, pid: task.pid, outputPath: task.outputPath }\n },\n 'bg.list': async params => ({ tasks: await context.listBackground!(await handleFor(params)) }),\n 'bg.kill': async params => ({ exit: await context.killBackground!(await handleFor(params), str(params, 'taskId')) }),\n 'bg.wait': async (params) => {\n const timeoutMs = optNum(params, 'timeoutMs')\n return { exit: await context.waitBackground!(await handleFor(params), str(params, 'taskId'), timeoutMs !== undefined ? { timeoutMs } : {}) }\n },\n 'terminal.open': async (params) => {\n const handle = await handleFor(params)\n const terminalId = await terminals.open(context, handle, { cols: num(params, 'cols'), rows: num(params, 'rows'), ...cwdOption(handle, params) })\n return { terminalId }\n },\n 'terminal.attach': async params => terminals.attach(str(params, 'terminalId')),\n 'terminal.write': async (params) => {\n terminals.write(str(params, 'terminalId'), str(params, 'data'))\n return { ok: true }\n },\n 'terminal.resize': async (params) => {\n terminals.resize(str(params, 'terminalId'), num(params, 'cols'), num(params, 'rows'))\n return { ok: true }\n },\n 'terminal.kill': async (params) => {\n await terminals.kill(str(params, 'terminalId'))\n return { ok: true }\n },\n // The host stops viewing; the PTY keeps running (as after a lost link, without the grace).\n 'terminal.detach': async () => ({ ok: true }),\n 'env.checkFolder': async params => ({ cwd: confinement.resolveFolder(str(params, 'cwd')) }),\n 'env.prepareWorktree': async (params) => {\n const cwd = confinement.resolveFolder(str(params, 'cwd'))\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n const base = optStr(params, 'base')\n const prepared = await prepareWorktree({ cwd, environment: { kind: 'worktree', state: 'provisioning', branch: str(params, 'branch'), ...(base ? { base } : {}) }, config }, options.dataDir)\n const ref = prepared.environment?.ref as { path: string, repoRoot: string }\n confinement.resolveFolder(ref.path)\n return { cwd: prepared.cwd ?? ref.path, branch: prepared.environment?.branch, base: prepared.environment?.base, ref }\n },\n 'env.teardownWorktree': async (params) => {\n const ref = (params.ref ?? {}) as { path?: unknown, repoRoot?: unknown }\n if (typeof ref.path !== 'string' || typeof ref.repoRoot !== 'string')\n throw new Error('Invalid params: \"ref\" must be { path, repoRoot }.')\n confinement.checkPath(ref.path)\n confinement.resolveFolder(ref.repoRoot)\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n return teardownWorktree({ path: ref.path, repoRoot: ref.repoRoot }, optStr(params, 'branch'), config)\n },\n }\n\n return {\n async handle(method, raw) {\n if (!Object.hasOwn(methods, method))\n throw new Error(`Unknown machine method \"${method}\".`)\n return methods[method]!(paramsOf(raw))\n },\n linkUp() {\n while (pendingExits.length > 0) {\n if (!options.notify('task.exit', pendingExits[0]!))\n return\n pendingExits.shift()\n }\n },\n sandbox: { on: sandbox.isolation !== undefined, ...(sandbox.warning ? { warning: sandbox.warning } : {}) },\n linkLost: () => {\n terminals.linkLost()\n streams.linkLost()\n },\n async close() {\n for (const controller of calls.values())\n controller.abort()\n await streams.closeAll()\n await terminals.closeAll()\n await Promise.all([...handles.values()].map(handle => context.destroy(handle).catch(() => undefined)))\n handles.clear()\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { t as defineSkill } from "./skills-DKqZJm4X.js";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
//#region src/extension-authoring.ts
|
|
7
|
+
/**
|
|
8
|
+
* Session-metadata key marking an "edit / create extension" session. The value
|
|
9
|
+
* is an {@link ExtensionEditMarker}. Both hosts stamp it at session creation so
|
|
10
|
+
* the agent build can scope the docs skill to exactly these sessions (and it
|
|
11
|
+
* survives reload because metadata is persisted).
|
|
12
|
+
*/
|
|
13
|
+
const EXTENSION_EDIT_METADATA_KEY = "zidane.extensionEdit";
|
|
14
|
+
/** Name of the inline docs skill auto-activated in extension edit sessions. */
|
|
15
|
+
const ZIDANE_EXTENSION_SKILL_NAME = "zidane-extension";
|
|
16
|
+
/**
|
|
17
|
+
* Session-metadata key marking an "edit skill" session — the skill-editing
|
|
18
|
+
* counterpart of {@link EXTENSION_EDIT_METADATA_KEY}. The value is a
|
|
19
|
+
* {@link SkillEditMarker}. Stamped at session creation by both hosts (via
|
|
20
|
+
* {@link editSessionMetadata}); persisted metadata means it survives reload.
|
|
21
|
+
*/
|
|
22
|
+
const SKILL_EDIT_METADATA_KEY = "zidane.skillEdit";
|
|
23
|
+
/** Name of the inline preset skill auto-activated in skill edit sessions. */
|
|
24
|
+
const ZIDANE_SKILL_EDIT_SKILL_NAME = "zidane-skill";
|
|
25
|
+
/**
|
|
26
|
+
* THE canonical seed for "open an editing session with preset context" —
|
|
27
|
+
* the session metadata both hosts stamp at creation time. The engines read
|
|
28
|
+
* the marker back and inject + auto-activate the matching inline preset
|
|
29
|
+
* skill ({@link buildZidaneExtensionSkill} / {@link buildZidaneSkillEditSkill}),
|
|
30
|
+
* so the preset rides as real conversation context from turn one.
|
|
31
|
+
*/
|
|
32
|
+
function editSessionMetadata(target) {
|
|
33
|
+
return target.kind === "extension" ? { [EXTENSION_EDIT_METADATA_KEY]: { dir: target.dir } } : { [SKILL_EDIT_METADATA_KEY]: {
|
|
34
|
+
dir: target.dir,
|
|
35
|
+
name: target.name
|
|
36
|
+
} };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse a persisted {@link SkillEditMarker} back out of session metadata.
|
|
40
|
+
* Tolerant: anything that isn't `{ dir: string, name: string }` → `null`
|
|
41
|
+
* (older sessions, manual metadata edits, type drift).
|
|
42
|
+
*/
|
|
43
|
+
function readSkillEditMarker(raw) {
|
|
44
|
+
if (typeof raw !== "object" || raw === null) return null;
|
|
45
|
+
const { dir, name } = raw;
|
|
46
|
+
if (typeof dir !== "string" || dir.length === 0 || typeof name !== "string" || name.length === 0) return null;
|
|
47
|
+
return {
|
|
48
|
+
dir,
|
|
49
|
+
name
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Minimal valid extension module for a freshly-created extension. `name` MUST
|
|
54
|
+
* equal the folder name or the loader rejects it (see `src/extensions/discovery`).
|
|
55
|
+
* Does nothing by default — the author registers contributions via `ctx.*`
|
|
56
|
+
* inside `setup`; the auto-activated docs skill guides them from there.
|
|
57
|
+
*/
|
|
58
|
+
function extensionScaffold(name) {
|
|
59
|
+
return `import { defineExtension } from 'zidane'
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* ${name} — a zidane extension.
|
|
63
|
+
*
|
|
64
|
+
* Register tools / hooks / skills / MCP servers / subagents / config / themes /
|
|
65
|
+
* agents / keybindings via the \`ctx\` surface inside \`setup\`.
|
|
66
|
+
*
|
|
67
|
+
* Authoring reference: activate the \`${ZIDANE_EXTENSION_SKILL_NAME}\` skill — it carries
|
|
68
|
+
* the full \`ctx\` API + invariants and is available whenever you open this
|
|
69
|
+
* folder in zidane (or run \`zidane\` from inside it).
|
|
70
|
+
*/
|
|
71
|
+
export default defineExtension({
|
|
72
|
+
name: '${name}',
|
|
73
|
+
setup(ctx) {
|
|
74
|
+
// e.g. ctx.registerTool('${name}_hello', {
|
|
75
|
+
// spec: { name: '${name}_hello', description: 'say hi', inputSchema: { type: 'object', properties: {} } },
|
|
76
|
+
// isConcurrencySafe: true,
|
|
77
|
+
// async execute() { return 'hello from ${name}' },
|
|
78
|
+
// })
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Locate the shipped `docs/` directory (`docs/EXTENSIONS.md` + siblings).
|
|
85
|
+
*
|
|
86
|
+
* The docs ship via `package.json` `files`, so an installed consumer has
|
|
87
|
+
* `<root>/node_modules/zidane/docs` and the repo itself has `<repo>/docs`.
|
|
88
|
+
* Returns the first existing candidate, or `null` (the skill then falls back to
|
|
89
|
+
* the literal `node_modules/zidane/docs` hint, which the model's file tools can
|
|
90
|
+
* still attempt from cwd).
|
|
91
|
+
*/
|
|
92
|
+
function resolveExtensionDocsDir(cwd = process.cwd()) {
|
|
93
|
+
const candidates = [];
|
|
94
|
+
try {
|
|
95
|
+
const req = createRequire(import.meta.url);
|
|
96
|
+
candidates.push(join(dirname(req.resolve("zidane/package.json")), "docs"));
|
|
97
|
+
} catch {}
|
|
98
|
+
try {
|
|
99
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
100
|
+
for (let i = 0; i < 6; i++) {
|
|
101
|
+
if (existsSync(join(dir, "docs", "EXTENSIONS.md"))) {
|
|
102
|
+
candidates.push(join(dir, "docs"));
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
dir = dirname(dir);
|
|
106
|
+
}
|
|
107
|
+
} catch {}
|
|
108
|
+
candidates.push(join(cwd, "node_modules", "zidane", "docs"));
|
|
109
|
+
for (const candidate of candidates) if (existsSync(join(candidate, "EXTENSIONS.md"))) return candidate;
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
/** Entry-file probe order for an extension dir (mirrors the loader's discovery). */
|
|
113
|
+
const EXTENSION_ENTRY_FILES = [
|
|
114
|
+
"index.ts",
|
|
115
|
+
"index.tsx",
|
|
116
|
+
"index.mjs",
|
|
117
|
+
"index.js"
|
|
118
|
+
];
|
|
119
|
+
/**
|
|
120
|
+
* If `cwd` sits inside a zidane extension, return that extension's root dir,
|
|
121
|
+
* else `null`. Mirrors the discovery layout
|
|
122
|
+
* `<scope>/.{agents,zidane}/extensions/<name>/` — the root is the `<name>` dir
|
|
123
|
+
* (parent `extensions`, grandparent `.agents` / `.zidane`) holding an entry
|
|
124
|
+
* file. Walks up from `cwd`, so the nearest enclosing extension wins. Lets the
|
|
125
|
+
* hosts surface the authoring skill for a plain `zidane` launched from an
|
|
126
|
+
* extension folder, not just sessions opened through the edit/create flow.
|
|
127
|
+
*/
|
|
128
|
+
function extensionDirForCwd(cwd = process.cwd()) {
|
|
129
|
+
let dir = resolve(cwd);
|
|
130
|
+
for (let i = 0; i < 64; i++) {
|
|
131
|
+
const parent = dirname(dir);
|
|
132
|
+
if (basename(parent) === "extensions" && (basename(dirname(parent)) === ".agents" || basename(dirname(parent)) === ".zidane") && EXTENSION_ENTRY_FILES.some((f) => existsSync(join(dir, f)))) return dir;
|
|
133
|
+
if (parent === dir) break;
|
|
134
|
+
dir = parent;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The authoring reference embedded into the skill body. Kept INLINE (not a
|
|
140
|
+
* filesystem path) on purpose: a `bun build --compile` TUI binary has no
|
|
141
|
+
* resolvable `node_modules/zidane/docs`, no real `import.meta.url`, and the
|
|
142
|
+
* edited extension's own cwd has no `node_modules` — so a path reference dead-
|
|
143
|
+
* ends there. The model gets the API verbatim on activation regardless of host.
|
|
144
|
+
*
|
|
145
|
+
* Mirrors `ExtensionContext` (src/extensions/types.ts) — keep in sync when the
|
|
146
|
+
* `ctx.*` surface changes.
|
|
147
|
+
*/
|
|
148
|
+
const EXTENSION_AUTHORING_CHEATSHEET = `## defineExtension
|
|
149
|
+
|
|
150
|
+
A zidane extension is a module at \`<scope>/.{agents,zidane}/extensions/<name>/index.{ts,tsx,mjs,js}\`
|
|
151
|
+
that default-exports \`defineExtension({ ... })\`. It runs in-process in the host (TUI / GUI / SDK).
|
|
152
|
+
|
|
153
|
+
\`\`\`ts
|
|
154
|
+
import { defineExtension } from 'zidane'
|
|
155
|
+
|
|
156
|
+
export default defineExtension({
|
|
157
|
+
name: 'my-ext', // MUST equal the folder name
|
|
158
|
+
apiVersion: 1, // optional; omitted means v1
|
|
159
|
+
version: '0.1.0', // optional — shown in Settings → Extensions
|
|
160
|
+
displayName: 'My Ext', // optional UI label
|
|
161
|
+
description: 'what it does',
|
|
162
|
+
capabilities: ['tools'], // optional descriptive manifest labels
|
|
163
|
+
permissions: [], // optional descriptive labels; not a sandbox
|
|
164
|
+
setup(ctx) { /* register everything here; may be async */ },
|
|
165
|
+
teardown() {}, // optional, reserved (no hot-reload yet)
|
|
166
|
+
})
|
|
167
|
+
\`\`\`
|
|
168
|
+
|
|
169
|
+
Zero-import form — required INSIDE compiled binaries, which can't \`import 'zidane'\` at runtime:
|
|
170
|
+
\`\`\`ts
|
|
171
|
+
import type { ExtensionContext } from 'zidane' // type-only: erased at runtime
|
|
172
|
+
export default {
|
|
173
|
+
name: 'my-ext',
|
|
174
|
+
setup(ctx: ExtensionContext) { /* ... */ },
|
|
175
|
+
}
|
|
176
|
+
\`\`\`
|
|
177
|
+
|
|
178
|
+
## ctx surface (call everything inside setup)
|
|
179
|
+
|
|
180
|
+
Identity / utilities:
|
|
181
|
+
- ctx.name / ctx.version / ctx.dir / ctx.scope ('project' | 'user' | 'inline' | 'builtin')
|
|
182
|
+
- ctx.logger — Logger namespaced \`extension:<name>\`
|
|
183
|
+
- ctx.config — read THIS extension's config, default-first: \`ctx.config.get(key)\`
|
|
184
|
+
- ctx.paths — cwd/projectRoot/dataDir/cacheDir/configDir/stateDir
|
|
185
|
+
- ctx.storage.path(scope, ...segments) — extension-scoped storage path
|
|
186
|
+
- ctx.session — JSON-only per-session state: get / set / delete
|
|
187
|
+
|
|
188
|
+
Renderer-agnostic registration:
|
|
189
|
+
- ctx.registerTool(name, toolDef)
|
|
190
|
+
- ctx.registerHook(event, handler) — an AgentHooks event; fires on the PARENT agent (use child:* for subagents)
|
|
191
|
+
- ctx.registerMcpServer(config)
|
|
192
|
+
- ctx.registerSkill(skillConfig) — a defineSkill() shape
|
|
193
|
+
- ctx.registerCompletionProvider(provider) — single-char '/' '@' '!' trigger
|
|
194
|
+
- ctx.tui.notify(text, { tone? }) — one-shot transcript line (info/warn/error); buffered pre-mount
|
|
195
|
+
- ctx.tui.setStatus(text | null, { loader?, timeout? }) — single dim status line (transcript-tail slot); loader glyph, auto-clear ms
|
|
196
|
+
- ctx.tui.setBanner(lines | null, { timeout? }) — short block above the prompt (stacked with the todo indicator); auto-clear ms
|
|
197
|
+
- ctx.submitPrompt(text, { delivery? }) — submit as the user: 'auto' (run-or-queue), 'steer', 'followUp'; false when detached
|
|
198
|
+
- ctx.registerToolPolicy({ tools?, decide }) — gate tool calls: allow / { block } / { patch } (patches re-validated by the loop)
|
|
199
|
+
- ctx.registerToolResultTransform(fn) — middleware over finished tool results (chained)
|
|
200
|
+
- ctx.registerContextTransform(fn) — rewrite wire messages before each provider call
|
|
201
|
+
- ctx.registerPromptTransform(fn) — transform or consume submitted prompts (after / commands, before skills)
|
|
202
|
+
- ctx.runtime / ctx.sessions — late-bound host controls: model()/thinking()/setThinking(), sessions list/switch/create
|
|
203
|
+
- ctx.appendNote(blocks) — durable display-only transcript note (command-output block vocabulary)
|
|
204
|
+
- ctx.workspace.exec/readFile/writeFile/listFiles/fileSize — shell + files through the SESSION'S execution context (sandbox-correct; host child_process silently targets the wrong filesystem under docker/e2b). Detached ⇒ rejects; guard with \`await ctx.workspace.available()\`.
|
|
205
|
+
- ctx.tui.registerToolRenderer({ tools?, render }) — custom view for tool-result rows; return null to fall through to the default. View-layer only: never persisted, error-bounded per row, TUI-scoped.
|
|
206
|
+
- ctx.tui.registerRenderer(id, render) + emit/appendNote \`custom: { renderer, data }\` blocks — custom components in the transcript. \`data\` must be JSON-safe (it persists); the block's \`text\` is the MANDATORY markdown fallback (disabled extension, headless host, GUI, renderer throw). appendNote auto-prefixes bare ids; command emit needs \`<ext>/<id>\`.
|
|
207
|
+
- Renderer components: import \`react\` / \`@opentui/react\` BARE (never as your own dependency) — the host maps them to its live instances at load time, so hooks work. Async data: render() stays sync; return a component that fetches with useState/useEffect.
|
|
208
|
+
- Renderer async caching: \`useSessionState(id, initial)\` (per-row, session-persisted — rehydrates on reload) + \`useRowVisible()\` (latched viewport gate) from \`zidane/tui\` — fetch once, only when scrolled in.
|
|
209
|
+
- ctx.registerCommand(command) — a '/<name>' workflow (handler or steps[]); step ctx: emit (local output),
|
|
210
|
+
runAgent (interactive sub-run), generateData (silent zod/JSON-Schema JSON),
|
|
211
|
+
session? (read-only turns/runs view), interaction? (confirm / askUser forms /
|
|
212
|
+
presentPlan approval — both optional; guard for bare hosts)
|
|
213
|
+
- ctx.registerTheme(theme)
|
|
214
|
+
- ctx.registerAgent(profile) — extra agent profile in the picker
|
|
215
|
+
- ctx.registerSubagent(def) — spawnable subagent (the spawn tool's subagent_type)
|
|
216
|
+
- ctx.registerSubagentOverride(name, fn) — edit/delete an existing subagent
|
|
217
|
+
- ctx.registerProvider(descriptor)
|
|
218
|
+
- ctx.registerSystemPromptFragment(text)
|
|
219
|
+
- ctx.registerContextBreakdownSection(fn) — render extension-owned rows in the context panel
|
|
220
|
+
- ctx.registerContextPanelSection(section) — richer context panel section with rows/load
|
|
221
|
+
- ctx.registerToolResultMetadata(registration) — project namespaced tool-result metadata into context
|
|
222
|
+
- ctx.registerRunTransform(fn) — sync rewrite of agent.run options
|
|
223
|
+
- ctx.registerBehaviorTransform(fn) — sync rewrite of resolved behavior
|
|
224
|
+
- ctx.registerProviderMiddleware(fn) — wrap provider instances
|
|
225
|
+
- ctx.registerToolCatalogTransform(fn) — shape/hide/rename tools before disclosure/execution
|
|
226
|
+
- ctx.registerMcpConfigTransform(fn) — rewrite MCP server configs before connect
|
|
227
|
+
- ctx.registerSkillPolicy(policy) — auto-activate skills by run context
|
|
228
|
+
- ctx.registerConfigCategory(category)
|
|
229
|
+
- ctx.registerConfigItem([categoryId,] item) — typed setting; supports scope/onChange metadata
|
|
230
|
+
|
|
231
|
+
TUI-only (ctx.tui.* — silently ignored on non-TUI hosts):
|
|
232
|
+
- ctx.tui.registerKeybinding(binding)
|
|
233
|
+
- ctx.tui.registerFooterHint(hint)
|
|
234
|
+
- ctx.tui.registerModal(modal) — keep UI lazy: \`node: () => import('./panel')\`
|
|
235
|
+
|
|
236
|
+
GUI-only:
|
|
237
|
+
- ctx.gui.registerPanel(panel) — collected, not rendered yet
|
|
238
|
+
|
|
239
|
+
Completion providers may also implement submit hooks:
|
|
240
|
+
- resolveReferences(refs, ctx, signal)
|
|
241
|
+
- onSubmit({ text, cursor, references }, signal)
|
|
242
|
+
Both TUI and GUI call these before dispatching a submitted prompt.
|
|
243
|
+
|
|
244
|
+
## ToolDef shape
|
|
245
|
+
\`\`\`ts
|
|
246
|
+
ctx.registerTool('my_tool', {
|
|
247
|
+
spec: { name: 'my_tool', description: '...', inputSchema: { type: 'object', properties: {} } },
|
|
248
|
+
isConcurrencySafe: true, // default false (barrier/write); true = read-only, fans out in parallel
|
|
249
|
+
async execute(args) { return 'result' },
|
|
250
|
+
})
|
|
251
|
+
\`\`\`
|
|
252
|
+
|
|
253
|
+
## Invariants
|
|
254
|
+
- The folder name MUST equal \`name\`, or the loader rejects the extension.
|
|
255
|
+
- Optional metadata lives in \`extension.json\` or \`package.json#zidane\`; unsupported \`apiVersion\` is rejected.
|
|
256
|
+
- Export as \`default\` (or a named \`extension\` export).
|
|
257
|
+
- Register ONLY inside \`setup\` — calls after it resolves are dropped (logger.warn).
|
|
258
|
+
- A throw in \`setup\` is caught and shown on the extension's Settings row; the rest of boot continues.
|
|
259
|
+
- Discovery order, first per name wins: project \`.agents\` → project \`.zidane\` → \`~/.agents\` → \`~/.zidane\`.
|
|
260
|
+
- \`/reload\` is a TRUE hot-reload: re-discover + re-run setup, and each extension's module graph is re-imported fresh — code edits (deep imports included) apply live. Module-level state resets; clean up external resources in \`teardown\`.
|
|
261
|
+
|
|
262
|
+
## Distribution
|
|
263
|
+
- Users install via Settings → Extensions → \`ctrl+g\` (source input + scope picker) — GitHub (\`owner/repo[#ref][:sub/dir]\`, tree URLs) or npm (\`pkg[@version]\`, exact versions / dist-tags).
|
|
264
|
+
- Update / remove: Settings → Extensions, \`ctrl+u\` / \`ctrl+x\` on the focused row (update replays the recorded \`.install.json\` provenance in place, skipping when the recorded commit/version still matches the remote).
|
|
265
|
+
- Shape your repo/package as a root \`index.ts\` (single extension) or \`extensions/<name>/index.*\` dirs (collection).
|
|
266
|
+
- Reference packages to copy: \`extensions/git-flow\` in the zidane repo (zero-dep \`/commit\` command) and \`extensions/headroom\` (hooks + tool + config).
|
|
267
|
+
- Declare runtime deps in \`package.json#dependencies\` — installed with bun/npm/… WITHOUT lifecycle scripts; don't rely on postinstall.
|
|
268
|
+
- The installed folder is named from your exported \`definition.name\` — pick it to be folder-safe ([A-Za-z0-9_.-]).`;
|
|
269
|
+
/** Preset preamble for "edit / create extension" sessions. */
|
|
270
|
+
const EXTENSION_EDIT_PRESET = "You are authoring / editing a zidane extension. Authoritative API reference:";
|
|
271
|
+
/** Preset preamble for "edit skill" sessions — same spirit, skill-flavored. */
|
|
272
|
+
function skillEditPreset(marker) {
|
|
273
|
+
return `We are going to work on ${marker.name}, in ${marker.dir} directory, next messages will be requests at modifying and improving the skill or understanding how it works better.`;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* The inline `zidane-extension` skill. Carries the authoring reference IN its
|
|
277
|
+
* body ({@link EXTENSION_AUTHORING_CHEATSHEET}) so it works in every host —
|
|
278
|
+
* incl. compiled binaries where the on-disk docs aren't resolvable. The shipped
|
|
279
|
+
* `EXTENSIONS.md` (prose long-form) is appended as a "see also" only when found
|
|
280
|
+
* on disk. `source: 'inline'` (the `defineSkill` default) survives the
|
|
281
|
+
* project-trust gate.
|
|
282
|
+
*/
|
|
283
|
+
function buildZidaneExtensionSkill(opts = {}) {
|
|
284
|
+
const docsDir = resolveExtensionDocsDir(opts.cwd);
|
|
285
|
+
const seeAlso = docsDir ? `\n\n---\nFull prose reference on disk: ${join(docsDir, "EXTENSIONS.md")}\nSibling docs cover related surfaces (ARCHITECTURE.md, CHAT.md, TUI.md, SKILL.md, HEADLESS.md, …).` : "\n\n---\nFuller prose reference, when present: node_modules/zidane/docs/EXTENSIONS.md (often absent in compiled binaries — the API above is authoritative).";
|
|
286
|
+
return defineSkill({
|
|
287
|
+
name: ZIDANE_EXTENSION_SKILL_NAME,
|
|
288
|
+
description: "Authoring or editing a zidane extension (a module calling defineExtension, under .zidane/extensions/** or .agents/extensions/**). Carries the extension authoring reference.",
|
|
289
|
+
instructions: `${EXTENSION_EDIT_PRESET}\n\n${EXTENSION_AUTHORING_CHEATSHEET}${seeAlso}`
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Inject the `zidane-extension` skill into an already-merged {@link SkillsConfig}.
|
|
294
|
+
*
|
|
295
|
+
* Call this on the FINAL merged skills object (after folding extension / preset
|
|
296
|
+
* skills): `composePresets` is last-wins on `catalog`, so injecting earlier
|
|
297
|
+
* would be silently dropped whenever an extension also contributes skills.
|
|
298
|
+
*
|
|
299
|
+
* Adds the skill to the catalog and, when an `enabled` allowlist is in force,
|
|
300
|
+
* force-includes the name so the allowlist filter can't hide it (mirrors how
|
|
301
|
+
* extension-contributed skill names are force-included). When skills are fully
|
|
302
|
+
* disabled (`enabled === false`), the edit session still gets just this skill.
|
|
303
|
+
*/
|
|
304
|
+
function withZidaneExtensionSkill(skills, opts = {}) {
|
|
305
|
+
return injectInlineSkill(skills, buildZidaneExtensionSkill(opts));
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Compact skill-authoring reference embedded into the skill-edit skill body.
|
|
309
|
+
* Inline for the same reason as {@link EXTENSION_AUTHORING_CHEATSHEET}: works
|
|
310
|
+
* in compiled binaries where on-disk docs don't resolve.
|
|
311
|
+
*/
|
|
312
|
+
const SKILL_AUTHORING_CHEATSHEET = `## SKILL.md anatomy
|
|
313
|
+
|
|
314
|
+
A skill is a directory holding a \`SKILL.md\` (YAML frontmatter + markdown body)
|
|
315
|
+
per the Agent Skills standard (agentskills.io/specification):
|
|
316
|
+
|
|
317
|
+
\`\`\`md
|
|
318
|
+
---
|
|
319
|
+
name: my-skill # 1-64 chars, lowercase alphanumeric + hyphens; SHOULD match the directory name
|
|
320
|
+
description: what it does AND when to use it (drives activation — 1-1024 chars)
|
|
321
|
+
license: MIT # optional
|
|
322
|
+
compatibility: … # optional environment requirements
|
|
323
|
+
allowed-tools: # optional — restricts the agent to these tools while active
|
|
324
|
+
- read_file
|
|
325
|
+
metadata: # optional flat string map; zidane-specific keys use the \`zidane.\` prefix
|
|
326
|
+
some-key: value
|
|
327
|
+
---
|
|
328
|
+
The body is the skill's instructions — injected into context when the skill
|
|
329
|
+
is activated. Keep it token-lean: move depth into references/.
|
|
330
|
+
\`\`\`
|
|
331
|
+
|
|
332
|
+
## Bundled resources (all optional, discovered automatically)
|
|
333
|
+
- \`references/\` — docs loaded on demand via \`skills_read\`
|
|
334
|
+
- \`scripts/\` — executables run via \`skills_run_script\` (honor shebangs)
|
|
335
|
+
- \`assets/\` — templates / static files
|
|
336
|
+
|
|
337
|
+
## Guidance
|
|
338
|
+
- The description is the activation trigger — write it for the ROUTER ("use when …"), the body for the ACTIVATED agent.
|
|
339
|
+
- Prefer small bodies + lazy references over one giant SKILL.md.
|
|
340
|
+
- Shell interpolation (exclamation mark + backtick-quoted command) in the body runs at activation — use sparingly; hosts may gate or disable it.
|
|
341
|
+
- Validate names: mismatched frontmatter name vs directory loads with a warning diagnostic.`;
|
|
342
|
+
/**
|
|
343
|
+
* The inline skill auto-activated in "edit skill" sessions. Body = the
|
|
344
|
+
* session preset (which skill, which directory, what the next messages will
|
|
345
|
+
* be about) + a compact SKILL.md authoring reference — the skill-editing
|
|
346
|
+
* counterpart of {@link buildZidaneExtensionSkill}.
|
|
347
|
+
*/
|
|
348
|
+
function buildZidaneSkillEditSkill(marker, opts = {}) {
|
|
349
|
+
const docsDir = resolveExtensionDocsDir(opts.cwd);
|
|
350
|
+
const seeAlso = docsDir && existsSync(join(docsDir, "SKILL.md")) ? `\n\n---\nFull prose reference on disk: ${join(docsDir, "SKILL.md")}` : "";
|
|
351
|
+
return defineSkill({
|
|
352
|
+
name: ZIDANE_SKILL_EDIT_SKILL_NAME,
|
|
353
|
+
description: `Editing or improving the "${marker.name}" agent skill (its SKILL.md, references, scripts, and assets). Carries the skill-authoring reference for this edit session.`,
|
|
354
|
+
instructions: `${skillEditPreset(marker)}\n\n${SKILL_AUTHORING_CHEATSHEET}${seeAlso}`
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Inject the skill-edit preset skill into an already-merged {@link SkillsConfig}.
|
|
359
|
+
* Same contract as {@link withZidaneExtensionSkill} — call on the FINAL merged
|
|
360
|
+
* skills object.
|
|
361
|
+
*/
|
|
362
|
+
function withZidaneSkillEditSkill(skills, marker, opts = {}) {
|
|
363
|
+
return injectInlineSkill(skills, buildZidaneSkillEditSkill(marker, opts));
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Shared injector: add `skill` to the catalog and, when an `enabled`
|
|
367
|
+
* allowlist is in force, force-include its name so the filter can't hide it
|
|
368
|
+
* (mirrors how extension-contributed skill names are force-included). When
|
|
369
|
+
* skills are fully disabled (`enabled === false`), the edit session still
|
|
370
|
+
* gets just this skill.
|
|
371
|
+
*/
|
|
372
|
+
function injectInlineSkill(skills, skill) {
|
|
373
|
+
const catalog = [...skills.catalog ?? [], skill];
|
|
374
|
+
const enabled = skills.enabled;
|
|
375
|
+
const nextEnabled = enabled === void 0 ? void 0 : Array.isArray(enabled) ? enabled.includes(skill.name) ? enabled : [...enabled, skill.name] : [skill.name];
|
|
376
|
+
return {
|
|
377
|
+
...skills,
|
|
378
|
+
catalog,
|
|
379
|
+
...nextEnabled !== void 0 ? { enabled: nextEnabled } : {}
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
//#endregion
|
|
383
|
+
export { buildZidaneExtensionSkill as a, extensionDirForCwd as c, resolveExtensionDocsDir as d, withZidaneExtensionSkill as f, ZIDANE_SKILL_EDIT_SKILL_NAME as i, extensionScaffold as l, SKILL_EDIT_METADATA_KEY as n, buildZidaneSkillEditSkill as o, withZidaneSkillEditSkill as p, ZIDANE_EXTENSION_SKILL_NAME as r, editSessionMetadata as s, EXTENSION_EDIT_METADATA_KEY as t, readSkillEditMarker as u };
|
|
384
|
+
|
|
385
|
+
//# sourceMappingURL=extension-authoring-DyGGmq9V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-authoring-DyGGmq9V.js","names":[],"sources":["../src/extension-authoring.ts"],"sourcesContent":["/**\n * Host glue for the \"edit / create extension\" and \"edit skill\" authoring\n * flows (TUI + GUI).\n *\n * Pure, renderer-neutral helpers consumed by the hosts — deliberately kept OUT\n * of `src/extensions/**` (the extension loader / registry core) so the\n * authoring UX can never entangle with discovery / registration. Imports only\n * the skills lib and node builtins.\n *\n * - {@link extensionScaffold} — minimal `index.ts` for a new extension.\n * - {@link resolveExtensionDocsDir} — locate the shipped `docs/` directory.\n * - {@link buildZidaneExtensionSkill} — the inline extension docs skill.\n * - {@link buildZidaneSkillEditSkill} — the inline skill-editing skill.\n * - {@link withZidaneExtensionSkill} / {@link withZidaneSkillEditSkill}\n * — inject either into a `SkillsConfig`.\n * - {@link editSessionMetadata} — the ONE canonical \"open an editing session\n * with preset context\" seed both hosts stamp at session creation.\n * - {@link EXTENSION_EDIT_METADATA_KEY} / {@link SKILL_EDIT_METADATA_KEY} /\n * {@link ZIDANE_EXTENSION_SKILL_NAME} / {@link ZIDANE_SKILL_EDIT_SKILL_NAME}\n * — constants shared by both hosts.\n */\nimport type { SkillConfig, SkillsConfig } from './skills'\nimport { existsSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { basename, dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { defineSkill } from './skills'\n\n/**\n * Session-metadata key marking an \"edit / create extension\" session. The value\n * is an {@link ExtensionEditMarker}. Both hosts stamp it at session creation so\n * the agent build can scope the docs skill to exactly these sessions (and it\n * survives reload because metadata is persisted).\n */\nexport const EXTENSION_EDIT_METADATA_KEY = 'zidane.extensionEdit'\n\n/** Name of the inline docs skill auto-activated in extension edit sessions. */\nexport const ZIDANE_EXTENSION_SKILL_NAME = 'zidane-extension'\n\n/**\n * Session-metadata key marking an \"edit skill\" session — the skill-editing\n * counterpart of {@link EXTENSION_EDIT_METADATA_KEY}. The value is a\n * {@link SkillEditMarker}. Stamped at session creation by both hosts (via\n * {@link editSessionMetadata}); persisted metadata means it survives reload.\n */\nexport const SKILL_EDIT_METADATA_KEY = 'zidane.skillEdit'\n\n/** Name of the inline preset skill auto-activated in skill edit sessions. */\nexport const ZIDANE_SKILL_EDIT_SKILL_NAME = 'zidane-skill'\n\n/** Per-edit-session marker persisted on `session.metadata[EXTENSION_EDIT_METADATA_KEY]`. */\nexport interface ExtensionEditMarker {\n /** Absolute path to the extension's directory (the session's cwd). */\n dir: string\n}\n\n/** Per-edit-session marker persisted on `session.metadata[SKILL_EDIT_METADATA_KEY]`. */\nexport interface SkillEditMarker {\n /** Absolute path to the skill's directory (the session's cwd). */\n dir: string\n /** The skill's name (frontmatter-first, as discovered). */\n name: string\n}\n\n/**\n * What an editing session targets. `dir` becomes the session's cwd; `name`\n * feeds the preset wording (and the skill marker).\n */\nexport interface EditSessionTarget {\n kind: 'extension' | 'skill'\n name: string\n dir: string\n}\n\n/**\n * THE canonical seed for \"open an editing session with preset context\" —\n * the session metadata both hosts stamp at creation time. The engines read\n * the marker back and inject + auto-activate the matching inline preset\n * skill ({@link buildZidaneExtensionSkill} / {@link buildZidaneSkillEditSkill}),\n * so the preset rides as real conversation context from turn one.\n */\nexport function editSessionMetadata(target: EditSessionTarget): Record<string, unknown> {\n return target.kind === 'extension'\n ? { [EXTENSION_EDIT_METADATA_KEY]: { dir: target.dir } satisfies ExtensionEditMarker }\n : { [SKILL_EDIT_METADATA_KEY]: { dir: target.dir, name: target.name } satisfies SkillEditMarker }\n}\n\n/**\n * Parse a persisted {@link SkillEditMarker} back out of session metadata.\n * Tolerant: anything that isn't `{ dir: string, name: string }` → `null`\n * (older sessions, manual metadata edits, type drift).\n */\nexport function readSkillEditMarker(raw: unknown): SkillEditMarker | null {\n if (typeof raw !== 'object' || raw === null)\n return null\n const { dir, name } = raw as Record<string, unknown>\n if (typeof dir !== 'string' || dir.length === 0 || typeof name !== 'string' || name.length === 0)\n return null\n return { dir, name }\n}\n\n/**\n * Minimal valid extension module for a freshly-created extension. `name` MUST\n * equal the folder name or the loader rejects it (see `src/extensions/discovery`).\n * Does nothing by default — the author registers contributions via `ctx.*`\n * inside `setup`; the auto-activated docs skill guides them from there.\n */\nexport function extensionScaffold(name: string): string {\n return `import { defineExtension } from 'zidane'\n\n/**\n * ${name} — a zidane extension.\n *\n * Register tools / hooks / skills / MCP servers / subagents / config / themes /\n * agents / keybindings via the \\`ctx\\` surface inside \\`setup\\`.\n *\n * Authoring reference: activate the \\`${ZIDANE_EXTENSION_SKILL_NAME}\\` skill — it carries\n * the full \\`ctx\\` API + invariants and is available whenever you open this\n * folder in zidane (or run \\`zidane\\` from inside it).\n */\nexport default defineExtension({\n name: '${name}',\n setup(ctx) {\n // e.g. ctx.registerTool('${name}_hello', {\n // spec: { name: '${name}_hello', description: 'say hi', inputSchema: { type: 'object', properties: {} } },\n // isConcurrencySafe: true,\n // async execute() { return 'hello from ${name}' },\n // })\n },\n})\n`\n}\n\n/**\n * Locate the shipped `docs/` directory (`docs/EXTENSIONS.md` + siblings).\n *\n * The docs ship via `package.json` `files`, so an installed consumer has\n * `<root>/node_modules/zidane/docs` and the repo itself has `<repo>/docs`.\n * Returns the first existing candidate, or `null` (the skill then falls back to\n * the literal `node_modules/zidane/docs` hint, which the model's file tools can\n * still attempt from cwd).\n */\nexport function resolveExtensionDocsDir(cwd: string = process.cwd()): string | null {\n const candidates: string[] = []\n\n // 1) The installed (or self-linked) zidane package, via its package.json\n // (exposed through `exports[\"./package.json\"]`).\n try {\n const req = createRequire(import.meta.url)\n candidates.push(join(dirname(req.resolve('zidane/package.json')), 'docs'))\n }\n catch {\n // No resolvable package (compiled binary / odd layout) — fall through.\n }\n\n // 2) Relative to this module: `dist/extension-authoring.js` -> `../docs`, or\n // walking up from `src/` when running from source.\n try {\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 6; i++) {\n if (existsSync(join(dir, 'docs', 'EXTENSIONS.md'))) {\n candidates.push(join(dir, 'docs'))\n break\n }\n dir = dirname(dir)\n }\n }\n catch {\n // `import.meta.url` is virtual under `bun build --compile` — fall through.\n }\n\n // 3) cwd-relative — the project the author is actually editing.\n candidates.push(join(cwd, 'node_modules', 'zidane', 'docs'))\n\n for (const candidate of candidates) {\n if (existsSync(join(candidate, 'EXTENSIONS.md')))\n return candidate\n }\n return null\n}\n\n/** Entry-file probe order for an extension dir (mirrors the loader's discovery). */\nconst EXTENSION_ENTRY_FILES = ['index.ts', 'index.tsx', 'index.mjs', 'index.js'] as const\n\n/**\n * If `cwd` sits inside a zidane extension, return that extension's root dir,\n * else `null`. Mirrors the discovery layout\n * `<scope>/.{agents,zidane}/extensions/<name>/` — the root is the `<name>` dir\n * (parent `extensions`, grandparent `.agents` / `.zidane`) holding an entry\n * file. Walks up from `cwd`, so the nearest enclosing extension wins. Lets the\n * hosts surface the authoring skill for a plain `zidane` launched from an\n * extension folder, not just sessions opened through the edit/create flow.\n */\nexport function extensionDirForCwd(cwd: string = process.cwd()): string | null {\n let dir = resolve(cwd)\n // Bounded walk to the filesystem root (the `parent === dir` guard is the real\n // terminator; the cap is just belt-and-braces against pathological inputs).\n for (let i = 0; i < 64; i++) {\n const parent = dirname(dir)\n if (\n basename(parent) === 'extensions'\n && (basename(dirname(parent)) === '.agents' || basename(dirname(parent)) === '.zidane')\n && EXTENSION_ENTRY_FILES.some(f => existsSync(join(dir, f)))\n ) {\n return dir\n }\n if (parent === dir)\n break\n dir = parent\n }\n return null\n}\n\n/**\n * The authoring reference embedded into the skill body. Kept INLINE (not a\n * filesystem path) on purpose: a `bun build --compile` TUI binary has no\n * resolvable `node_modules/zidane/docs`, no real `import.meta.url`, and the\n * edited extension's own cwd has no `node_modules` — so a path reference dead-\n * ends there. The model gets the API verbatim on activation regardless of host.\n *\n * Mirrors `ExtensionContext` (src/extensions/types.ts) — keep in sync when the\n * `ctx.*` surface changes.\n */\nconst EXTENSION_AUTHORING_CHEATSHEET = `## defineExtension\n\nA zidane extension is a module at \\`<scope>/.{agents,zidane}/extensions/<name>/index.{ts,tsx,mjs,js}\\`\nthat default-exports \\`defineExtension({ ... })\\`. It runs in-process in the host (TUI / GUI / SDK).\n\n\\`\\`\\`ts\nimport { defineExtension } from 'zidane'\n\nexport default defineExtension({\n name: 'my-ext', // MUST equal the folder name\n apiVersion: 1, // optional; omitted means v1\n version: '0.1.0', // optional — shown in Settings → Extensions\n displayName: 'My Ext', // optional UI label\n description: 'what it does',\n capabilities: ['tools'], // optional descriptive manifest labels\n permissions: [], // optional descriptive labels; not a sandbox\n setup(ctx) { /* register everything here; may be async */ },\n teardown() {}, // optional, reserved (no hot-reload yet)\n})\n\\`\\`\\`\n\nZero-import form — required INSIDE compiled binaries, which can't \\`import 'zidane'\\` at runtime:\n\\`\\`\\`ts\nimport type { ExtensionContext } from 'zidane' // type-only: erased at runtime\nexport default {\n name: 'my-ext',\n setup(ctx: ExtensionContext) { /* ... */ },\n}\n\\`\\`\\`\n\n## ctx surface (call everything inside setup)\n\nIdentity / utilities:\n- ctx.name / ctx.version / ctx.dir / ctx.scope ('project' | 'user' | 'inline' | 'builtin')\n- ctx.logger — Logger namespaced \\`extension:<name>\\`\n- ctx.config — read THIS extension's config, default-first: \\`ctx.config.get(key)\\`\n- ctx.paths — cwd/projectRoot/dataDir/cacheDir/configDir/stateDir\n- ctx.storage.path(scope, ...segments) — extension-scoped storage path\n- ctx.session — JSON-only per-session state: get / set / delete\n\nRenderer-agnostic registration:\n- ctx.registerTool(name, toolDef)\n- ctx.registerHook(event, handler) — an AgentHooks event; fires on the PARENT agent (use child:* for subagents)\n- ctx.registerMcpServer(config)\n- ctx.registerSkill(skillConfig) — a defineSkill() shape\n- ctx.registerCompletionProvider(provider) — single-char '/' '@' '!' trigger\n- ctx.tui.notify(text, { tone? }) — one-shot transcript line (info/warn/error); buffered pre-mount\n- ctx.tui.setStatus(text | null, { loader?, timeout? }) — single dim status line (transcript-tail slot); loader glyph, auto-clear ms\n- ctx.tui.setBanner(lines | null, { timeout? }) — short block above the prompt (stacked with the todo indicator); auto-clear ms\n- ctx.submitPrompt(text, { delivery? }) — submit as the user: 'auto' (run-or-queue), 'steer', 'followUp'; false when detached\n- ctx.registerToolPolicy({ tools?, decide }) — gate tool calls: allow / { block } / { patch } (patches re-validated by the loop)\n- ctx.registerToolResultTransform(fn) — middleware over finished tool results (chained)\n- ctx.registerContextTransform(fn) — rewrite wire messages before each provider call\n- ctx.registerPromptTransform(fn) — transform or consume submitted prompts (after / commands, before skills)\n- ctx.runtime / ctx.sessions — late-bound host controls: model()/thinking()/setThinking(), sessions list/switch/create\n- ctx.appendNote(blocks) — durable display-only transcript note (command-output block vocabulary)\n- ctx.workspace.exec/readFile/writeFile/listFiles/fileSize — shell + files through the SESSION'S execution context (sandbox-correct; host child_process silently targets the wrong filesystem under docker/e2b). Detached ⇒ rejects; guard with \\`await ctx.workspace.available()\\`.\n- ctx.tui.registerToolRenderer({ tools?, render }) — custom view for tool-result rows; return null to fall through to the default. View-layer only: never persisted, error-bounded per row, TUI-scoped.\n- ctx.tui.registerRenderer(id, render) + emit/appendNote \\`custom: { renderer, data }\\` blocks — custom components in the transcript. \\`data\\` must be JSON-safe (it persists); the block's \\`text\\` is the MANDATORY markdown fallback (disabled extension, headless host, GUI, renderer throw). appendNote auto-prefixes bare ids; command emit needs \\`<ext>/<id>\\`.\n- Renderer components: import \\`react\\` / \\`@opentui/react\\` BARE (never as your own dependency) — the host maps them to its live instances at load time, so hooks work. Async data: render() stays sync; return a component that fetches with useState/useEffect.\n- Renderer async caching: \\`useSessionState(id, initial)\\` (per-row, session-persisted — rehydrates on reload) + \\`useRowVisible()\\` (latched viewport gate) from \\`zidane/tui\\` — fetch once, only when scrolled in.\n- ctx.registerCommand(command) — a '/<name>' workflow (handler or steps[]); step ctx: emit (local output),\n runAgent (interactive sub-run), generateData (silent zod/JSON-Schema JSON),\n session? (read-only turns/runs view), interaction? (confirm / askUser forms /\n presentPlan approval — both optional; guard for bare hosts)\n- ctx.registerTheme(theme)\n- ctx.registerAgent(profile) — extra agent profile in the picker\n- ctx.registerSubagent(def) — spawnable subagent (the spawn tool's subagent_type)\n- ctx.registerSubagentOverride(name, fn) — edit/delete an existing subagent\n- ctx.registerProvider(descriptor)\n- ctx.registerSystemPromptFragment(text)\n- ctx.registerContextBreakdownSection(fn) — render extension-owned rows in the context panel\n- ctx.registerContextPanelSection(section) — richer context panel section with rows/load\n- ctx.registerToolResultMetadata(registration) — project namespaced tool-result metadata into context\n- ctx.registerRunTransform(fn) — sync rewrite of agent.run options\n- ctx.registerBehaviorTransform(fn) — sync rewrite of resolved behavior\n- ctx.registerProviderMiddleware(fn) — wrap provider instances\n- ctx.registerToolCatalogTransform(fn) — shape/hide/rename tools before disclosure/execution\n- ctx.registerMcpConfigTransform(fn) — rewrite MCP server configs before connect\n- ctx.registerSkillPolicy(policy) — auto-activate skills by run context\n- ctx.registerConfigCategory(category)\n- ctx.registerConfigItem([categoryId,] item) — typed setting; supports scope/onChange metadata\n\nTUI-only (ctx.tui.* — silently ignored on non-TUI hosts):\n- ctx.tui.registerKeybinding(binding)\n- ctx.tui.registerFooterHint(hint)\n- ctx.tui.registerModal(modal) — keep UI lazy: \\`node: () => import('./panel')\\`\n\nGUI-only:\n- ctx.gui.registerPanel(panel) — collected, not rendered yet\n\nCompletion providers may also implement submit hooks:\n- resolveReferences(refs, ctx, signal)\n- onSubmit({ text, cursor, references }, signal)\nBoth TUI and GUI call these before dispatching a submitted prompt.\n\n## ToolDef shape\n\\`\\`\\`ts\nctx.registerTool('my_tool', {\n spec: { name: 'my_tool', description: '...', inputSchema: { type: 'object', properties: {} } },\n isConcurrencySafe: true, // default false (barrier/write); true = read-only, fans out in parallel\n async execute(args) { return 'result' },\n})\n\\`\\`\\`\n\n## Invariants\n- The folder name MUST equal \\`name\\`, or the loader rejects the extension.\n- Optional metadata lives in \\`extension.json\\` or \\`package.json#zidane\\`; unsupported \\`apiVersion\\` is rejected.\n- Export as \\`default\\` (or a named \\`extension\\` export).\n- Register ONLY inside \\`setup\\` — calls after it resolves are dropped (logger.warn).\n- A throw in \\`setup\\` is caught and shown on the extension's Settings row; the rest of boot continues.\n- Discovery order, first per name wins: project \\`.agents\\` → project \\`.zidane\\` → \\`~/.agents\\` → \\`~/.zidane\\`.\n- \\`/reload\\` is a TRUE hot-reload: re-discover + re-run setup, and each extension's module graph is re-imported fresh — code edits (deep imports included) apply live. Module-level state resets; clean up external resources in \\`teardown\\`.\n\n## Distribution\n- Users install via Settings → Extensions → \\`ctrl+g\\` (source input + scope picker) — GitHub (\\`owner/repo[#ref][:sub/dir]\\`, tree URLs) or npm (\\`pkg[@version]\\`, exact versions / dist-tags).\n- Update / remove: Settings → Extensions, \\`ctrl+u\\` / \\`ctrl+x\\` on the focused row (update replays the recorded \\`.install.json\\` provenance in place, skipping when the recorded commit/version still matches the remote).\n- Shape your repo/package as a root \\`index.ts\\` (single extension) or \\`extensions/<name>/index.*\\` dirs (collection).\n- Reference packages to copy: \\`extensions/git-flow\\` in the zidane repo (zero-dep \\`/commit\\` command) and \\`extensions/headroom\\` (hooks + tool + config).\n- Declare runtime deps in \\`package.json#dependencies\\` — installed with bun/npm/… WITHOUT lifecycle scripts; don't rely on postinstall.\n- The installed folder is named from your exported \\`definition.name\\` — pick it to be folder-safe ([A-Za-z0-9_.-]).`\n\n// ---------------------------------------------------------------------------\n// Edit-session presets — the first line of each inline skill's instructions.\n// Kept next to each other so the two flows stay phrased consistently.\n// ---------------------------------------------------------------------------\n\n/** Preset preamble for \"edit / create extension\" sessions. */\nconst EXTENSION_EDIT_PRESET\n = 'You are authoring / editing a zidane extension. Authoritative API reference:'\n\n/** Preset preamble for \"edit skill\" sessions — same spirit, skill-flavored. */\nfunction skillEditPreset(marker: SkillEditMarker): string {\n return `We are going to work on ${marker.name}, in ${marker.dir} directory, `\n + 'next messages will be requests at modifying and improving the skill or '\n + 'understanding how it works better.'\n}\n\n/**\n * The inline `zidane-extension` skill. Carries the authoring reference IN its\n * body ({@link EXTENSION_AUTHORING_CHEATSHEET}) so it works in every host —\n * incl. compiled binaries where the on-disk docs aren't resolvable. The shipped\n * `EXTENSIONS.md` (prose long-form) is appended as a \"see also\" only when found\n * on disk. `source: 'inline'` (the `defineSkill` default) survives the\n * project-trust gate.\n */\nexport function buildZidaneExtensionSkill(opts: { cwd?: string } = {}): SkillConfig {\n const docsDir = resolveExtensionDocsDir(opts.cwd)\n const seeAlso = docsDir\n ? `\\n\\n---\\nFull prose reference on disk: ${join(docsDir, 'EXTENSIONS.md')}\\n`\n + 'Sibling docs cover related surfaces (ARCHITECTURE.md, CHAT.md, TUI.md, SKILL.md, HEADLESS.md, …).'\n : '\\n\\n---\\nFuller prose reference, when present: node_modules/zidane/docs/EXTENSIONS.md '\n + '(often absent in compiled binaries — the API above is authoritative).'\n return defineSkill({\n name: ZIDANE_EXTENSION_SKILL_NAME,\n description:\n 'Authoring or editing a zidane extension (a module calling defineExtension, under '\n + '.zidane/extensions/** or .agents/extensions/**). Carries the extension authoring reference.',\n instructions: `${EXTENSION_EDIT_PRESET}\\n\\n${EXTENSION_AUTHORING_CHEATSHEET}${seeAlso}`,\n })\n}\n\n/**\n * Inject the `zidane-extension` skill into an already-merged {@link SkillsConfig}.\n *\n * Call this on the FINAL merged skills object (after folding extension / preset\n * skills): `composePresets` is last-wins on `catalog`, so injecting earlier\n * would be silently dropped whenever an extension also contributes skills.\n *\n * Adds the skill to the catalog and, when an `enabled` allowlist is in force,\n * force-includes the name so the allowlist filter can't hide it (mirrors how\n * extension-contributed skill names are force-included). When skills are fully\n * disabled (`enabled === false`), the edit session still gets just this skill.\n */\nexport function withZidaneExtensionSkill(skills: SkillsConfig, opts: { cwd?: string } = {}): SkillsConfig {\n return injectInlineSkill(skills, buildZidaneExtensionSkill(opts))\n}\n\n/**\n * Compact skill-authoring reference embedded into the skill-edit skill body.\n * Inline for the same reason as {@link EXTENSION_AUTHORING_CHEATSHEET}: works\n * in compiled binaries where on-disk docs don't resolve.\n */\nconst SKILL_AUTHORING_CHEATSHEET = `## SKILL.md anatomy\n\nA skill is a directory holding a \\`SKILL.md\\` (YAML frontmatter + markdown body)\nper the Agent Skills standard (agentskills.io/specification):\n\n\\`\\`\\`md\n---\nname: my-skill # 1-64 chars, lowercase alphanumeric + hyphens; SHOULD match the directory name\ndescription: what it does AND when to use it (drives activation — 1-1024 chars)\nlicense: MIT # optional\ncompatibility: … # optional environment requirements\nallowed-tools: # optional — restricts the agent to these tools while active\n - read_file\nmetadata: # optional flat string map; zidane-specific keys use the \\`zidane.\\` prefix\n some-key: value\n---\nThe body is the skill's instructions — injected into context when the skill\nis activated. Keep it token-lean: move depth into references/.\n\\`\\`\\`\n\n## Bundled resources (all optional, discovered automatically)\n- \\`references/\\` — docs loaded on demand via \\`skills_read\\`\n- \\`scripts/\\` — executables run via \\`skills_run_script\\` (honor shebangs)\n- \\`assets/\\` — templates / static files\n\n## Guidance\n- The description is the activation trigger — write it for the ROUTER (\"use when …\"), the body for the ACTIVATED agent.\n- Prefer small bodies + lazy references over one giant SKILL.md.\n- Shell interpolation (exclamation mark + backtick-quoted command) in the body runs at activation — use sparingly; hosts may gate or disable it.\n- Validate names: mismatched frontmatter name vs directory loads with a warning diagnostic.`\n\n/**\n * The inline skill auto-activated in \"edit skill\" sessions. Body = the\n * session preset (which skill, which directory, what the next messages will\n * be about) + a compact SKILL.md authoring reference — the skill-editing\n * counterpart of {@link buildZidaneExtensionSkill}.\n */\nexport function buildZidaneSkillEditSkill(marker: SkillEditMarker, opts: { cwd?: string } = {}): SkillConfig {\n const docsDir = resolveExtensionDocsDir(opts.cwd)\n const seeAlso = docsDir && existsSync(join(docsDir, 'SKILL.md'))\n ? `\\n\\n---\\nFull prose reference on disk: ${join(docsDir, 'SKILL.md')}`\n : ''\n return defineSkill({\n name: ZIDANE_SKILL_EDIT_SKILL_NAME,\n description:\n `Editing or improving the \"${marker.name}\" agent skill (its SKILL.md, references, `\n + 'scripts, and assets). Carries the skill-authoring reference for this edit session.',\n instructions: `${skillEditPreset(marker)}\\n\\n${SKILL_AUTHORING_CHEATSHEET}${seeAlso}`,\n })\n}\n\n/**\n * Inject the skill-edit preset skill into an already-merged {@link SkillsConfig}.\n * Same contract as {@link withZidaneExtensionSkill} — call on the FINAL merged\n * skills object.\n */\nexport function withZidaneSkillEditSkill(\n skills: SkillsConfig,\n marker: SkillEditMarker,\n opts: { cwd?: string } = {},\n): SkillsConfig {\n return injectInlineSkill(skills, buildZidaneSkillEditSkill(marker, opts))\n}\n\n/**\n * Shared injector: add `skill` to the catalog and, when an `enabled`\n * allowlist is in force, force-include its name so the filter can't hide it\n * (mirrors how extension-contributed skill names are force-included). When\n * skills are fully disabled (`enabled === false`), the edit session still\n * gets just this skill.\n */\nfunction injectInlineSkill(skills: SkillsConfig, skill: SkillConfig): SkillsConfig {\n const catalog = [...(skills.catalog ?? []), skill]\n const enabled = skills.enabled\n const nextEnabled: SkillsConfig['enabled']\n = enabled === undefined\n ? undefined\n : Array.isArray(enabled)\n ? (enabled.includes(skill.name) ? enabled : [...enabled, skill.name])\n : [skill.name]\n return {\n ...skills,\n catalog,\n ...(nextEnabled !== undefined ? { enabled: nextEnabled } : {}),\n }\n}\n"],"mappings":"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"}
|