zidane 7.2.4 → 8.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +34 -6
- package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
- package/dist/acp-DQDhi2dj.js.map +1 -0
- package/dist/acp-cli.d.ts +1 -1
- package/dist/acp-cli.js +9 -66
- package/dist/acp-cli.js.map +1 -1
- package/dist/acp.d.ts +10 -590
- package/dist/acp.d.ts.map +1 -1
- package/dist/acp.js +3 -3
- package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
- package/dist/agent-DSLNmBp0.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -2
- package/dist/aliasing-lVFbm81n.js +217 -0
- package/dist/aliasing-lVFbm81n.js.map +1 -0
- package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
- package/dist/anthropic-CD00LhUP.js.map +1 -0
- package/dist/artifacts-CV2hUKnL.js.map +1 -1
- package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
- package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
- package/dist/call-tool-dHlbGOIY.js +70 -0
- package/dist/call-tool-dHlbGOIY.js.map +1 -0
- package/dist/chat/pure.d.ts +372 -6
- package/dist/chat/pure.d.ts.map +1 -1
- package/dist/chat/pure.js +35 -244
- package/dist/chat/pure.js.map +1 -1
- package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
- package/dist/chat-JPJJ8uu5.js.map +1 -0
- package/dist/chat.d.ts +4 -6
- package/dist/chat.js +23 -12
- package/dist/cli-shared-C-YCaglL.js +159 -0
- package/dist/cli-shared-C-YCaglL.js.map +1 -0
- package/dist/client-core-BQSyDALT.d.ts +2115 -0
- package/dist/client-core-BQSyDALT.d.ts.map +1 -0
- package/dist/codemode-worker.d.ts +1 -0
- package/dist/codemode-worker.js +155 -0
- package/dist/codemode-worker.js.map +1 -0
- package/dist/codemode.d.ts +352 -0
- package/dist/codemode.d.ts.map +1 -0
- package/dist/codemode.js +5 -0
- package/dist/connection-Dr-Js4yZ.d.ts +28 -0
- package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
- package/dist/connection-loop-gdh22LTI.js +112 -0
- package/dist/connection-loop-gdh22LTI.js.map +1 -0
- package/dist/context-segments-BHKlagL6.js +1016 -0
- package/dist/context-segments-BHKlagL6.js.map +1 -0
- package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
- package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
- package/dist/contexts/daytona.d.ts +19 -8
- package/dist/contexts/daytona.d.ts.map +1 -1
- package/dist/contexts/daytona.js +1 -440
- package/dist/contexts/docker.d.ts +36 -7
- package/dist/contexts/docker.d.ts.map +1 -1
- package/dist/contexts/docker.js +1 -456
- package/dist/contexts/e2b.d.ts +68 -13
- package/dist/contexts/e2b.d.ts.map +1 -1
- package/dist/contexts/e2b.js +1 -382
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/contexts/sandbox.js +5 -0
- package/dist/contexts/sandbox.js.map +1 -1
- package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
- package/dist/contexts-d7UolYot.js.map +1 -0
- package/dist/contexts.d.ts +3 -3
- package/dist/contexts.js +1 -1
- package/dist/cred-keys-GpBg71cP.js +105 -0
- package/dist/cred-keys-GpBg71cP.js.map +1 -0
- package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
- package/dist/credentials-JttEuRON.js.map +1 -0
- package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
- package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
- package/dist/daemon-cli.d.ts +1 -1
- package/dist/daemon-cli.js +3 -2
- package/dist/daemon-cli.js.map +1 -1
- package/dist/daytona-DG3omipZ.js +513 -0
- package/dist/daytona-DG3omipZ.js.map +1 -0
- package/dist/defaults-Cx3zvDOV.js +23 -0
- package/dist/defaults-Cx3zvDOV.js.map +1 -0
- package/dist/dispatcher-BMlu2BmZ.js +4941 -0
- package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
- package/dist/docker-BZhMMJUp.js +727 -0
- package/dist/docker-BZhMMJUp.js.map +1 -0
- package/dist/e2b-CEVOdRib.js +480 -0
- package/dist/e2b-CEVOdRib.js.map +1 -0
- package/dist/edit-utils-EGosADZq.js +234 -0
- package/dist/edit-utils-EGosADZq.js.map +1 -0
- package/dist/environment-8wsKE2Ln.js +214 -0
- package/dist/environment-8wsKE2Ln.js.map +1 -0
- package/dist/eval-BNcvle_J.js +1595 -0
- package/dist/eval-BNcvle_J.js.map +1 -0
- package/dist/eval.d.ts +2 -2
- package/dist/eval.js +1 -1489
- package/dist/executor-Cx5-8yqi.js +621 -0
- package/dist/executor-Cx5-8yqi.js.map +1 -0
- package/dist/extension-authoring-DyGGmq9V.js +385 -0
- package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
- package/dist/extensions.d.ts +2 -2
- package/dist/extensions.js +3 -3
- package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
- package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
- package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
- package/dist/format-C2NQEVUH.js.map +1 -0
- package/dist/format-bytes-C7tfc3Zm.js +55 -0
- package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
- package/dist/headless-C_rNUuYC.js +960 -0
- package/dist/headless-C_rNUuYC.js.map +1 -0
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -413
- package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
- package/dist/history-search-CcYzF8-0.js.map +1 -0
- package/dist/history-search-worker.d.ts +1 -1
- package/dist/history-search-worker.js +1 -1
- package/dist/host-D7NrI03V.js +378 -0
- package/dist/host-D7NrI03V.js.map +1 -0
- package/dist/host-signals-BcP5QKUD.js +118 -0
- package/dist/host-signals-BcP5QKUD.js.map +1 -0
- package/dist/identity-CwfO8K-t.js +26 -0
- package/dist/identity-CwfO8K-t.js.map +1 -0
- package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
- package/dist/index-BGe1fQT7.d.ts.map +1 -0
- package/dist/index-BVQsIKGn.d.ts +448 -0
- package/dist/index-BVQsIKGn.d.ts.map +1 -0
- package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
- package/dist/index-CHABJd-L.d.ts.map +1 -0
- package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
- package/dist/index-D6a7qXpg.d.ts.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +27 -23
- package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
- package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
- package/dist/ipc/remote.d.ts +313 -0
- package/dist/ipc/remote.d.ts.map +1 -0
- package/dist/ipc/remote.js +4 -0
- package/dist/ipc.d.ts +6 -964
- package/dist/ipc.js +403 -4
- package/dist/ipc.js.map +1 -0
- package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
- package/dist/isolation-D9L650W5.d.ts.map +1 -0
- package/dist/json-rpc--HXQti1E.js +350 -0
- package/dist/json-rpc--HXQti1E.js.map +1 -0
- package/dist/links-j8rED1sR.js +603 -0
- package/dist/links-j8rED1sR.js.map +1 -0
- package/dist/local-terminal-D8QThwo_.js +252 -0
- package/dist/local-terminal-D8QThwo_.js.map +1 -0
- package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
- package/dist/logger-Gtqlayx8.js.map +1 -0
- package/dist/logs-view-CWG8aUAG.js.map +1 -1
- package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
- package/dist/mcp-_wecH9Qe.js.map +1 -0
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +2 -2
- package/dist/media-sniff-UKijEaiQ.js.map +1 -1
- package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
- package/dist/messages-BqiwcD2Q.js.map +1 -0
- package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
- package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
- package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
- package/dist/openai-compat-CFrpH7uq.js.map +1 -0
- package/dist/orchestration-BCGmB8Ps.js +511 -0
- package/dist/orchestration-BCGmB8Ps.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -2
- package/dist/output/stream-json.d.ts.map +1 -1
- package/dist/output/stream-json.js +1 -1
- package/dist/output/terminal.d.ts +1 -2
- package/dist/output/terminal.d.ts.map +1 -1
- package/dist/output/terminal.js +13 -7
- package/dist/output/terminal.js.map +1 -1
- package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
- package/dist/plugins-DS7mahzZ.js.map +1 -0
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +1 -2
- package/dist/prelude-Cxo4t74B.js +517 -0
- package/dist/prelude-Cxo4t74B.js.map +1 -0
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -2
- package/dist/project-root-B8zADr4o.js +167 -0
- package/dist/project-root-B8zADr4o.js.map +1 -0
- package/dist/project-user-paths-BSgtrRxl.js +58 -0
- package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
- package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
- package/dist/prompts-DYcvqShf.d.ts.map +1 -0
- package/dist/protocol-DnhqqSmE.js +13 -0
- package/dist/protocol-DnhqqSmE.js.map +1 -0
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +1 -2
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/arcee.js +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/baseten.js +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/cerebras.js +3 -2
- package/dist/providers/cerebras.js.map +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/local.js +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai-compat.js +1 -2
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +15 -12
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +3 -2
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +3 -3
- package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
- package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +4 -4
- package/dist/registry-D6ShBWJU.js +5234 -0
- package/dist/registry-D6ShBWJU.js.map +1 -0
- package/dist/remote-hosts-BtA_9ZGp.js +97 -0
- package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
- package/dist/restate.d.ts +2 -3
- package/dist/restate.d.ts.map +1 -1
- package/dist/restate.js +631 -572
- package/dist/restate.js.map +1 -1
- package/dist/run-summary-CklLiZ4y.js +288 -0
- package/dist/run-summary-CklLiZ4y.js.map +1 -0
- package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
- package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
- package/dist/session/sqlite.d.ts +1 -2
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +1 -616
- package/dist/session-factory-BUGY5P40.js +1576 -0
- package/dist/session-factory-BUGY5P40.js.map +1 -0
- package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
- package/dist/session-xh9JXu6i.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/settings-keys-Ckf29NeM.js +677 -0
- package/dist/settings-keys-Ckf29NeM.js.map +1 -0
- package/dist/shell-path-Dqaoow2J.js +412 -0
- package/dist/shell-path-Dqaoow2J.js.map +1 -0
- package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
- package/dist/skills-DKqZJm4X.js.map +1 -0
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -2
- package/dist/source-mPExaUm8.js +381 -0
- package/dist/source-mPExaUm8.js.map +1 -0
- package/dist/sqlite-DV1DQzN2.js +698 -0
- package/dist/sqlite-DV1DQzN2.js.map +1 -0
- package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
- package/dist/src-BRMYRJib.js.map +1 -0
- package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
- package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
- package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
- package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
- package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
- package/dist/timeout-DEaqslLO.d.ts.map +1 -1
- package/dist/todo-edits-Dn251YUP.js +1790 -0
- package/dist/todo-edits-Dn251YUP.js.map +1 -0
- package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
- package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
- package/dist/tool-state-Dku6YqAB.js +989 -0
- package/dist/tool-state-Dku6YqAB.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -2
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +1 -2
- package/dist/tools/prompts.d.ts +1 -1
- package/dist/tools/prompts.js +7 -7
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/web-search.d.ts +1 -2
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +2 -2
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools-_DnT3AGM.js +578 -0
- package/dist/tools-_DnT3AGM.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +4 -2
- package/dist/tui.d.ts +534 -517
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +34933 -27242
- package/dist/tui.js.map +1 -1
- package/dist/turn-operations-B8sokwi5.js +333 -0
- package/dist/turn-operations-B8sokwi5.js.map +1 -0
- package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
- package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
- package/dist/types-C7ZFOztE.d.ts +132 -0
- package/dist/types-C7ZFOztE.d.ts.map +1 -0
- package/dist/types-CH5XpIHw.js +114 -0
- package/dist/types-CH5XpIHw.js.map +1 -0
- package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
- package/dist/types-Cu0ZGDu9.js.map +1 -0
- package/dist/types-IqegbJEE.d.ts +624 -0
- package/dist/types-IqegbJEE.d.ts.map +1 -0
- package/dist/types.d.ts +4 -4
- package/dist/types.js +1 -1
- package/dist/url-D8HCl65b.js +1259 -0
- package/dist/url-D8HCl65b.js.map +1 -0
- package/dist/wasm-BVT-j5cl.js +33 -0
- package/dist/wasm-BVT-j5cl.js.map +1 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
- package/dist/ws-CIHMvlSh.js +952 -0
- package/dist/ws-CIHMvlSh.js.map +1 -0
- package/dist/ws-client-N7NxzvQp.js +230 -0
- package/dist/ws-client-N7NxzvQp.js.map +1 -0
- package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
- package/dist/xai-CvJTeLrI.js.map +1 -0
- package/dist/xdg-zweed0-t.js +117 -0
- package/dist/xdg-zweed0-t.js.map +1 -0
- package/docs/ACP.md +52 -0
- package/docs/ARCHITECTURE.md +103 -6
- package/docs/ARTIFACTS.md +8 -4
- package/docs/CHAT.md +165 -14
- package/docs/EXECUTION_CONTEXT.md +8 -0
- package/docs/EXTENSIONS.md +123 -2
- package/docs/HEADLESS.md +2 -0
- package/docs/IPC.md +775 -64
- package/docs/MACHINES.md +456 -0
- package/docs/PANELS.md +3 -0
- package/docs/README.md +4 -0
- package/docs/RESTATE.md +3 -2
- package/docs/RUN_IN_BACKGROUND.md +10 -2
- package/docs/SERVER.md +1085 -0
- package/docs/SKILL.md +6 -1
- package/docs/TERMINAL.md +75 -0
- package/docs/TUI.md +65 -14
- package/package.json +58 -26
- package/scripts/eval.ts +4 -0
- package/dist/acp-D-tVyUjw.js.map +0 -1
- package/dist/agent-D0zZnGbt.js.map +0 -1
- package/dist/anthropic-C2aole0G.js.map +0 -1
- package/dist/approvals-DKaJZYlm.js.map +0 -1
- package/dist/atomic-write-B7zr1ddF.js.map +0 -1
- package/dist/auth-BG2rVKSt.js.map +0 -1
- package/dist/completion-core-BRo86R_L.js.map +0 -1
- package/dist/contexts/daytona.js.map +0 -1
- package/dist/contexts/docker.js.map +0 -1
- package/dist/contexts/e2b.js.map +0 -1
- package/dist/contexts-CRE9pw07.js.map +0 -1
- package/dist/eval.js.map +0 -1
- package/dist/format-BF745pLL.js.map +0 -1
- package/dist/glob-DluQFSw1.js +0 -270
- package/dist/glob-DluQFSw1.js.map +0 -1
- package/dist/headless.js.map +0 -1
- package/dist/history-search-C4bk1Wz_.js.map +0 -1
- package/dist/index-BgN1T3lk.d.ts.map +0 -1
- package/dist/index-C37_ppWv.d.ts.map +0 -1
- package/dist/index-C6NEd5y_.d.ts.map +0 -1
- package/dist/ipc-zVSyo6K1.js +0 -331
- package/dist/ipc-zVSyo6K1.js.map +0 -1
- package/dist/ipc.d.ts.map +0 -1
- package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
- package/dist/json-rpc-rSWMUh9b.js +0 -192
- package/dist/json-rpc-rSWMUh9b.js.map +0 -1
- package/dist/logger--C1VQjwJ.js.map +0 -1
- package/dist/mcp-CgNd-f3F.js.map +0 -1
- package/dist/messages-2jcOA_5R.js.map +0 -1
- package/dist/openai-compat-Dy56weK8.js.map +0 -1
- package/dist/output-cap-C9zukcCj.js +0 -100
- package/dist/output-cap-C9zukcCj.js.map +0 -1
- package/dist/panels-B6gRk4bf.js +0 -789
- package/dist/panels-B6gRk4bf.js.map +0 -1
- package/dist/plugins-gbI7SBA6.js.map +0 -1
- package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
- package/dist/run-summary-BU_NgwUT.js +0 -269
- package/dist/run-summary-BU_NgwUT.js.map +0 -1
- package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
- package/dist/session/sqlite.js.map +0 -1
- package/dist/session-BqRP1hS7.js.map +0 -1
- package/dist/shell-path-h5czzllR.js +0 -1549
- package/dist/shell-path-h5czzllR.js.map +0 -1
- package/dist/skills-BC3dodWp.js.map +0 -1
- package/dist/src-CkNQKFKr.js.map +0 -1
- package/dist/todo-edits-UOwgxGKu.js +0 -528
- package/dist/todo-edits-UOwgxGKu.js.map +0 -1
- package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
- package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
- package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
- package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
- package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
- package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
- package/dist/turn-operations-DrbJlpq9.js.map +0 -1
- package/dist/types-CWgENVLY.js.map +0 -1
- package/dist/xai-CazjStOK.js.map +0 -1
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
import { t as alwaysQuote } from "./shell-quote-BmnhZmdM.js";
|
|
2
|
+
import { c as DEFAULT_MAX_OUTPUT_BUFFER, f as outputExceededMessage, i as localTerminalProcess, l as appendCapped, n as endLocalPty, r as hasLocalPty, s as spawnLocalPty, t as TERMINAL_ENV } from "./local-terminal-D8QThwo_.js";
|
|
3
|
+
import { n as globFilesViaShell, t as fileSizeViaExec } from "./exec-file-size-BRpoB6Io.js";
|
|
4
|
+
import { Buffer } from "node:buffer";
|
|
5
|
+
import { existsSync, mkdirSync, realpathSync, statSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { posix } from "node:path";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
9
|
+
//#region src/contexts/docker-exec.ts
|
|
10
|
+
function createDockerExecCapped(s) {
|
|
11
|
+
const { containers, defaultLimits } = s;
|
|
12
|
+
/**
|
|
13
|
+
* The exec transport with an explicit output cap. The public `exec`
|
|
14
|
+
* uses the shared 10MB default; `readFile` passes headroom above the
|
|
15
|
+
* whole-read tool ceiling so docker's EFFECTIVE read limit matches
|
|
16
|
+
* every other context (the fileSize probe refuses oversized files
|
|
17
|
+
* before this ever runs — the transport cap is the safety net for
|
|
18
|
+
* probe-failure paths, not the primary bound).
|
|
19
|
+
*/
|
|
20
|
+
async function execCapped(handle, command, options, maxBuffer) {
|
|
21
|
+
const ref = containers.get(handle.id);
|
|
22
|
+
if (!ref) throw new Error(`Container ${handle.id} not found`);
|
|
23
|
+
const execCwd = options?.cwd ?? handle.cwd;
|
|
24
|
+
const env = options?.env ? Object.entries(options.env).map(([k, v]) => `${k}=${v}`) : [];
|
|
25
|
+
const timeout = options?.timeout ?? defaultLimits?.timeout ?? 30;
|
|
26
|
+
const exec = await ref.container.exec({
|
|
27
|
+
Cmd: [
|
|
28
|
+
"timeout",
|
|
29
|
+
String(timeout),
|
|
30
|
+
"sh",
|
|
31
|
+
"-c",
|
|
32
|
+
command
|
|
33
|
+
],
|
|
34
|
+
WorkingDir: execCwd,
|
|
35
|
+
Env: env,
|
|
36
|
+
AttachStdout: true,
|
|
37
|
+
AttachStderr: true
|
|
38
|
+
});
|
|
39
|
+
const stream = await exec.start({ Detach: false });
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
const stdoutSlot = {
|
|
42
|
+
text: "",
|
|
43
|
+
bytes: 0
|
|
44
|
+
};
|
|
45
|
+
const stderrSlot = {
|
|
46
|
+
text: "",
|
|
47
|
+
bytes: 0
|
|
48
|
+
};
|
|
49
|
+
let resolved = false;
|
|
50
|
+
const overflow = () => {
|
|
51
|
+
if (resolved) return;
|
|
52
|
+
resolved = true;
|
|
53
|
+
try {
|
|
54
|
+
stream.destroy?.();
|
|
55
|
+
} catch {}
|
|
56
|
+
resolve({
|
|
57
|
+
stdout: stdoutSlot.text,
|
|
58
|
+
stderr: `${stderrSlot.text ? `${stderrSlot.text}\n` : ""}${outputExceededMessage(maxBuffer, "stream detached (server-side timeout reaps the process)")}`,
|
|
59
|
+
exitCode: 143
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
const cappedWrite = (slot) => (chunk) => {
|
|
63
|
+
const buf = typeof chunk === "string" ? Buffer.from(chunk, "utf-8") : chunk;
|
|
64
|
+
if (appendCapped(slot, buf, maxBuffer) !== "ok") overflow();
|
|
65
|
+
return true;
|
|
66
|
+
};
|
|
67
|
+
const stdoutSink = {
|
|
68
|
+
write: cappedWrite(stdoutSlot),
|
|
69
|
+
end() {},
|
|
70
|
+
on() {},
|
|
71
|
+
once() {},
|
|
72
|
+
emit() {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const stderrSink = {
|
|
77
|
+
write: cappedWrite(stderrSlot),
|
|
78
|
+
end() {},
|
|
79
|
+
on() {},
|
|
80
|
+
once() {},
|
|
81
|
+
emit() {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
try {
|
|
86
|
+
ref.docker.modem.demuxStream(stream, stdoutSink, stderrSink);
|
|
87
|
+
} catch {
|
|
88
|
+
stream.on("data", (chunk) => {
|
|
89
|
+
cappedWrite(stdoutSlot)(chunk);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const timer = setTimeout(() => {
|
|
93
|
+
if (resolved) return;
|
|
94
|
+
resolved = true;
|
|
95
|
+
try {
|
|
96
|
+
stream.destroy?.();
|
|
97
|
+
} catch {}
|
|
98
|
+
resolve({
|
|
99
|
+
stdout: stdoutSlot.text,
|
|
100
|
+
stderr: stderrSlot.text ? `${stderrSlot.text}\n[timeout]` : "[timeout]",
|
|
101
|
+
exitCode: 124
|
|
102
|
+
});
|
|
103
|
+
}, timeout * 1e3 + 1e3);
|
|
104
|
+
stream.on("end", async () => {
|
|
105
|
+
if (resolved) return;
|
|
106
|
+
resolved = true;
|
|
107
|
+
clearTimeout(timer);
|
|
108
|
+
let exitCode;
|
|
109
|
+
let inspectNote = "";
|
|
110
|
+
try {
|
|
111
|
+
const inspect = await exec.inspect();
|
|
112
|
+
if (inspect.ExitCode == null) {
|
|
113
|
+
exitCode = -1;
|
|
114
|
+
inspectNote = "[exit code unavailable: exec still marked running by daemon]";
|
|
115
|
+
} else exitCode = inspect.ExitCode;
|
|
116
|
+
} catch (err) {
|
|
117
|
+
exitCode = -1;
|
|
118
|
+
inspectNote = `[exit code unavailable: exec inspect failed: ${err?.message ?? String(err)}]`;
|
|
119
|
+
}
|
|
120
|
+
resolve({
|
|
121
|
+
stdout: stdoutSlot.text,
|
|
122
|
+
stderr: inspectNote ? stderrSlot.text ? `${stderrSlot.text}\n${inspectNote}` : inspectNote : stderrSlot.text,
|
|
123
|
+
exitCode
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
stream.on("error", (err) => {
|
|
127
|
+
if (resolved) return;
|
|
128
|
+
resolved = true;
|
|
129
|
+
clearTimeout(timer);
|
|
130
|
+
resolve({
|
|
131
|
+
stdout: stdoutSlot.text,
|
|
132
|
+
stderr: stderrSlot.text ? `${stderrSlot.text}\n${err.message}` : err.message,
|
|
133
|
+
exitCode: 1
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return execCapped;
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region src/contexts/docker-files.ts
|
|
142
|
+
/**
|
|
143
|
+
* `readFile` transport cap: headroom above the whole-read tool ceiling
|
|
144
|
+
* (256MB in tools/whole-read-guard.ts) so tool policy — not the docker
|
|
145
|
+
* transport — decides read limits, keeping refusal behavior consistent
|
|
146
|
+
* across contexts. Still bounded: a probe-failure path can't buffer
|
|
147
|
+
* more than this into host memory.
|
|
148
|
+
*/
|
|
149
|
+
const READ_FILE_MAX_BUFFER = 536870912;
|
|
150
|
+
function dockerFileMethods(s, execCapped) {
|
|
151
|
+
const { containers } = s;
|
|
152
|
+
return {
|
|
153
|
+
async fileSize(handle, path) {
|
|
154
|
+
return fileSizeViaExec((command) => execCapped(handle, command, void 0, DEFAULT_MAX_OUTPUT_BUFFER), path);
|
|
155
|
+
},
|
|
156
|
+
async readFile(handle, path) {
|
|
157
|
+
const result = await execCapped(handle, `cat ${alwaysQuote(path)}`, void 0, READ_FILE_MAX_BUFFER);
|
|
158
|
+
if (result.exitCode !== 0) throw new Error(`Failed to read file: ${result.stderr}`);
|
|
159
|
+
return result.stdout;
|
|
160
|
+
},
|
|
161
|
+
async writeFile(handle, path, content, encoding = "utf-8") {
|
|
162
|
+
const bytes = typeof content === "string" ? Buffer.from(content, encoding) : content;
|
|
163
|
+
const ref = containers.get(handle.id);
|
|
164
|
+
if (!ref) throw new Error(`Container ${handle.id} not found`);
|
|
165
|
+
const dest = posix.isAbsolute(path) ? path : posix.join(handle.cwd, path);
|
|
166
|
+
const dir = posix.dirname(dest);
|
|
167
|
+
const name = posix.basename(dest);
|
|
168
|
+
if (!name || name === "." || name === ".." || path.endsWith("/")) throw new Error(`Failed to write file: invalid path ${path}`);
|
|
169
|
+
const mkdir = await s.ctx.exec(handle, `mkdir -p ${alwaysQuote(dir)}`);
|
|
170
|
+
if (mkdir.exitCode !== 0) throw new Error(`Failed to write file: ${mkdir.stderr}`);
|
|
171
|
+
const stagedName = `.zidane-write-${Math.random().toString(36).slice(2, 10)}.tmp`;
|
|
172
|
+
const staged = posix.join(dir, stagedName);
|
|
173
|
+
try {
|
|
174
|
+
await ref.container.putArchive(await packTarFile(stagedName, bytes), { path: dir });
|
|
175
|
+
} catch (err) {
|
|
176
|
+
throw new Error(`Failed to write file: ${err instanceof Error ? err.message : String(err)}`);
|
|
177
|
+
}
|
|
178
|
+
const write = await s.ctx.exec(handle, `cat ${alwaysQuote(staged)} > ${alwaysQuote(dest)}; rc=$?; rm -f ${alwaysQuote(staged)}; exit $rc`);
|
|
179
|
+
if (write.exitCode !== 0) {
|
|
180
|
+
await s.ctx.exec(handle, `rm -f ${alwaysQuote(staged)}`).catch(() => {});
|
|
181
|
+
throw new Error(`Failed to write file: ${write.stderr}`);
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
async listFiles(handle, path, options) {
|
|
185
|
+
if (options?.glob) return globFilesViaShell(path, (command) => s.ctx.exec(handle, command), options?.limit ?? 1e3);
|
|
186
|
+
const result = await s.ctx.exec(handle, `ls -1p ${alwaysQuote(path)}`);
|
|
187
|
+
if (result.exitCode !== 0) throw new Error(result.stderr.trim() || `ls failed with exit ${result.exitCode}`);
|
|
188
|
+
return result.stdout.trim().split("\n").filter(Boolean);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Pack a single file into an in-memory tar archive for `putArchive`, via
|
|
194
|
+
* `tar-stream` (the same battle-tested packer the dockerode ecosystem uses
|
|
195
|
+
* for build contexts). Optional peer dependency, loaded lazily like
|
|
196
|
+
* dockerode itself so the module graph stays lean for non-docker users.
|
|
197
|
+
*/
|
|
198
|
+
async function packTarFile(name, data) {
|
|
199
|
+
let pack;
|
|
200
|
+
try {
|
|
201
|
+
pack = (await import("tar-stream")).pack;
|
|
202
|
+
} catch {
|
|
203
|
+
throw new Error("tar-stream is required for Docker writeFile. Install it with: bun add tar-stream");
|
|
204
|
+
}
|
|
205
|
+
const tar = pack();
|
|
206
|
+
tar.entry({ name }, data);
|
|
207
|
+
tar.finalize();
|
|
208
|
+
const chunks = [];
|
|
209
|
+
for await (const chunk of tar) chunks.push(chunk);
|
|
210
|
+
return Buffer.concat(chunks);
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/contexts/docker-spawn.ts
|
|
214
|
+
/**
|
|
215
|
+
* Format one {@link ContextMount} as a dockerode `HostConfig.Binds` entry.
|
|
216
|
+
* Supports read-only (`:ro`) and SELinux shared-label (`:z`) options; the two
|
|
217
|
+
* are mutually exclusive (a read-only mount can't also be a shared rw mount).
|
|
218
|
+
*/
|
|
219
|
+
function formatBindMount(mount) {
|
|
220
|
+
if (!mount.source) throw new Error("Docker mount source is required");
|
|
221
|
+
if (!mount.target || !mount.target.startsWith("/")) throw new Error(`Docker mount target must be an absolute path: ${mount.target}`);
|
|
222
|
+
if (mount.readonly && mount.shared) throw new Error(`Docker mount cannot be both readonly and shared: ${mount.target}`);
|
|
223
|
+
const opts = mount.readonly ? ":ro" : mount.shared ? ":z" : "";
|
|
224
|
+
return `${mount.source}:${mount.target}${opts}`;
|
|
225
|
+
}
|
|
226
|
+
/** Assemble dockerode `HostConfig.Binds` from the context's `mounts`. */
|
|
227
|
+
function buildBindSpecs(mounts) {
|
|
228
|
+
return mounts.map(formatBindMount);
|
|
229
|
+
}
|
|
230
|
+
function dockerSpawnMethods(s) {
|
|
231
|
+
const { config, containers, defaultImage, defaultCwd, defaultEnv, defaultLimits, defaultMounts, defaultName } = s;
|
|
232
|
+
async function getDockerode() {
|
|
233
|
+
try {
|
|
234
|
+
const Dockerode = (await import("dockerode")).default;
|
|
235
|
+
return new Dockerode();
|
|
236
|
+
} catch {
|
|
237
|
+
throw new Error("dockerode is required for Docker execution context. Install it with: bun add dockerode");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return { async spawn(overrides) {
|
|
241
|
+
const docker = await getDockerode();
|
|
242
|
+
const id = `docker-${++s.counter}`;
|
|
243
|
+
const image = overrides?.image ?? defaultImage;
|
|
244
|
+
const cwd = overrides?.cwd ?? defaultCwd;
|
|
245
|
+
const mounts = [...defaultMounts, ...overrides?.mounts ?? []];
|
|
246
|
+
const name = overrides?.name ?? defaultName;
|
|
247
|
+
try {
|
|
248
|
+
await docker.getImage(image).inspect();
|
|
249
|
+
} catch {
|
|
250
|
+
await new Promise((resolve, reject) => {
|
|
251
|
+
docker.pull(image, (err, stream) => {
|
|
252
|
+
if (err) return reject(err);
|
|
253
|
+
docker.modem.followProgress(stream, (err2) => {
|
|
254
|
+
err2 ? reject(err2) : resolve();
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
const limits = {
|
|
260
|
+
...defaultLimits,
|
|
261
|
+
...overrides?.limits
|
|
262
|
+
};
|
|
263
|
+
const hostConfig = {};
|
|
264
|
+
if (limits?.memory) hostConfig.Memory = limits.memory * 1024 * 1024;
|
|
265
|
+
if (limits?.cpu) hostConfig.NanoCpus = Number.parseFloat(limits.cpu) * 1e9;
|
|
266
|
+
const hardening = {
|
|
267
|
+
...config?.hardening,
|
|
268
|
+
...overrides?.hardening
|
|
269
|
+
};
|
|
270
|
+
if (hardening.dropAllCapabilities) hostConfig.CapDrop = ["ALL"];
|
|
271
|
+
if (hardening.noNewPrivileges) hostConfig.SecurityOpt = ["no-new-privileges"];
|
|
272
|
+
if (hardening.readonlyRootfs) hostConfig.ReadonlyRootfs = true;
|
|
273
|
+
if (hardening.pidsLimit != null) hostConfig.PidsLimit = hardening.pidsLimit;
|
|
274
|
+
const env = {
|
|
275
|
+
...defaultEnv,
|
|
276
|
+
...overrides?.env
|
|
277
|
+
};
|
|
278
|
+
const bindSpecs = buildBindSpecs(mounts);
|
|
279
|
+
if (bindSpecs.length > 0) hostConfig.Binds = bindSpecs;
|
|
280
|
+
const portSpec = overrides?.ports ?? config?.ports;
|
|
281
|
+
const exposedPorts = {};
|
|
282
|
+
const portBindings = {};
|
|
283
|
+
if (portSpec?.length) {
|
|
284
|
+
for (const p of portSpec) {
|
|
285
|
+
const key = `${p.container}/${p.proto ?? "tcp"}`;
|
|
286
|
+
exposedPorts[key] = {};
|
|
287
|
+
portBindings[key] = [{ HostPort: p.host == null ? "" : String(p.host) }];
|
|
288
|
+
}
|
|
289
|
+
hostConfig.PortBindings = portBindings;
|
|
290
|
+
}
|
|
291
|
+
const user = overrides?.user ?? config?.user;
|
|
292
|
+
const network = overrides?.network ?? config?.network;
|
|
293
|
+
if (network) hostConfig.NetworkMode = network;
|
|
294
|
+
const labels = {
|
|
295
|
+
...config?.labels,
|
|
296
|
+
...overrides?.labels
|
|
297
|
+
};
|
|
298
|
+
const container = await docker.createContainer({
|
|
299
|
+
...name ? { name: `${name}-${s.counter}-${Math.random().toString(36).slice(2, 8)}` } : {},
|
|
300
|
+
Image: image,
|
|
301
|
+
Cmd: ["sleep", "infinity"],
|
|
302
|
+
WorkingDir: cwd,
|
|
303
|
+
Env: Object.entries(env).map(([k, v]) => `${k}=${v}`),
|
|
304
|
+
HostConfig: hostConfig,
|
|
305
|
+
...Object.keys(exposedPorts).length ? { ExposedPorts: exposedPorts } : {},
|
|
306
|
+
...user ? { User: user } : {},
|
|
307
|
+
...Object.keys(labels).length ? { Labels: labels } : {}
|
|
308
|
+
});
|
|
309
|
+
try {
|
|
310
|
+
await container.start();
|
|
311
|
+
} catch (err) {
|
|
312
|
+
await container.remove({ force: true }).catch(() => {});
|
|
313
|
+
throw err;
|
|
314
|
+
}
|
|
315
|
+
const handle = {
|
|
316
|
+
id,
|
|
317
|
+
type: "docker",
|
|
318
|
+
cwd
|
|
319
|
+
};
|
|
320
|
+
containers.set(id, {
|
|
321
|
+
handle,
|
|
322
|
+
container,
|
|
323
|
+
docker
|
|
324
|
+
});
|
|
325
|
+
return handle;
|
|
326
|
+
} };
|
|
327
|
+
}
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region src/contexts/docker-state.ts
|
|
330
|
+
function createDockerState(config) {
|
|
331
|
+
return {
|
|
332
|
+
config,
|
|
333
|
+
counter: 0,
|
|
334
|
+
containers: /* @__PURE__ */ new Map(),
|
|
335
|
+
defaultImage: config?.image ?? "oven/bun:latest",
|
|
336
|
+
defaultCwd: config?.cwd ?? "/workspace",
|
|
337
|
+
defaultEnv: config?.env,
|
|
338
|
+
defaultLimits: config?.limits,
|
|
339
|
+
defaultMounts: config?.mounts ?? [],
|
|
340
|
+
defaultName: config?.name,
|
|
341
|
+
ctx: void 0
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/contexts/docker-stream.ts
|
|
346
|
+
function dockerStreamMethods(s, execCapped) {
|
|
347
|
+
const { containers } = s;
|
|
348
|
+
return {
|
|
349
|
+
/**
|
|
350
|
+
* Live bidirectional stream to a process in the container — see
|
|
351
|
+
* `ExecutionContext.execStream` for the seam contract.
|
|
352
|
+
*
|
|
353
|
+
* Spawns the `docker exec -i` CLI (see the runtime note in the body for
|
|
354
|
+
* why dockerode's hijack API is off the table), which adds a requirement
|
|
355
|
+
* the rest of this context doesn't have: the docker CLI must be on
|
|
356
|
+
* PATH — everything else here talks straight to the daemon socket.
|
|
357
|
+
* Deliberately NOT wrapped in coreutils `timeout` the way `execCapped`
|
|
358
|
+
* is — this seam's whole purpose is processes that outlive a single
|
|
359
|
+
* request.
|
|
360
|
+
*/
|
|
361
|
+
async execStream(handle, command, options) {
|
|
362
|
+
const ref = containers.get(handle.id);
|
|
363
|
+
if (!ref) throw new Error(`Container ${handle.id} not found`);
|
|
364
|
+
options?.signal?.throwIfAborted();
|
|
365
|
+
const spawnChild = (await import("node:child_process")).spawn;
|
|
366
|
+
const { randomBytes } = await import("node:crypto");
|
|
367
|
+
const pidFile = `/tmp/.zidane-stream-${randomBytes(6).toString("hex")}.pid`;
|
|
368
|
+
const envPrefix = Object.entries(options?.env ?? {}).map(([k, v]) => `${k}=${alwaysQuote(v)} `).join("");
|
|
369
|
+
const leaderScript = `echo $$ > ${pidFile}; exec ${envPrefix ? `env ${envPrefix}` : ""}sh -c ${alwaysQuote(command)}`;
|
|
370
|
+
const quotedLeader = alwaysQuote(leaderScript);
|
|
371
|
+
const inner = `if setsid -w true 2>/dev/null; then exec setsid -w sh -c ${quotedLeader}; else exec sh -c ${quotedLeader}; fi`;
|
|
372
|
+
const child = spawnChild("docker", [
|
|
373
|
+
"exec",
|
|
374
|
+
"-i",
|
|
375
|
+
"-w",
|
|
376
|
+
options?.cwd ?? handle.cwd,
|
|
377
|
+
ref.container.id,
|
|
378
|
+
"sh",
|
|
379
|
+
"-c",
|
|
380
|
+
inner
|
|
381
|
+
], { stdio: [
|
|
382
|
+
"pipe",
|
|
383
|
+
"pipe",
|
|
384
|
+
"pipe"
|
|
385
|
+
] });
|
|
386
|
+
let spawnError = null;
|
|
387
|
+
child.on("error", (err) => {
|
|
388
|
+
spawnError = err;
|
|
389
|
+
});
|
|
390
|
+
const exited = new Promise((resolveExit) => {
|
|
391
|
+
child.once("close", (code, signalName) => {
|
|
392
|
+
resolveExit(code ?? (signalName === "SIGTERM" ? 143 : signalName ? 128 : 1));
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
let pid = -1;
|
|
396
|
+
for (let attempt = 0; attempt < 20 && pid <= 0; attempt++) {
|
|
397
|
+
const probe = await execCapped(handle, `cat ${pidFile} 2>/dev/null || true`, void 0, 4096).catch(() => null);
|
|
398
|
+
const parsed = Number.parseInt(probe?.stdout.trim() ?? "", 10);
|
|
399
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
400
|
+
pid = parsed;
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
if (child.exitCode !== null) break;
|
|
404
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
405
|
+
}
|
|
406
|
+
const kill = async () => {
|
|
407
|
+
if (pid > 0) await execCapped(handle, `kill -TERM -${pid} 2>/dev/null || kill -TERM ${pid} 2>/dev/null || true`, void 0, 4096).catch(() => {});
|
|
408
|
+
await execCapped(handle, `rm -f ${pidFile}`, void 0, 4096).catch(() => {});
|
|
409
|
+
if (child.exitCode === null && child.signalCode === null) child.kill("SIGTERM");
|
|
410
|
+
};
|
|
411
|
+
if (options?.signal) {
|
|
412
|
+
if (options.signal.aborted) kill();
|
|
413
|
+
else {
|
|
414
|
+
const onAbort = () => {
|
|
415
|
+
kill();
|
|
416
|
+
};
|
|
417
|
+
const detach = () => options.signal.removeEventListener("abort", onAbort);
|
|
418
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
419
|
+
exited.then(detach, detach);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
pid,
|
|
424
|
+
stdout: child.stdout,
|
|
425
|
+
stderr: child.stderr,
|
|
426
|
+
write: async (data) => {
|
|
427
|
+
if (spawnError) throw spawnError;
|
|
428
|
+
const stdin = child.stdin;
|
|
429
|
+
if (!stdin || stdin.destroyed) throw new Error(`execStream: stdin is closed (container ${handle.id})`);
|
|
430
|
+
await new Promise((resolveWrite, rejectWrite) => {
|
|
431
|
+
stdin.write(data, (err) => err ? rejectWrite(err) : resolveWrite());
|
|
432
|
+
});
|
|
433
|
+
},
|
|
434
|
+
kill,
|
|
435
|
+
exited
|
|
436
|
+
};
|
|
437
|
+
} };
|
|
438
|
+
}
|
|
439
|
+
function dockerTerminalMethods(s, execCapped) {
|
|
440
|
+
const { containers } = s;
|
|
441
|
+
return {
|
|
442
|
+
/**
|
|
443
|
+
* A shell in the container: `docker exec -it` driven by a local PTY, so
|
|
444
|
+
* the CLI sees a real terminal and forwards resizes. Same CLI route as
|
|
445
|
+
* `execStream` (dockerode's interactive exec doesn't work under Bun).
|
|
446
|
+
* Closing the CLI doesn't end the exec'd shell, so the shell records
|
|
447
|
+
* its pid (a session leader under `-t`) and `kill` hangs up its group.
|
|
448
|
+
*/
|
|
449
|
+
...hasLocalPty() ? { async openTerminal(handle, options) {
|
|
450
|
+
const ref = containers.get(handle.id);
|
|
451
|
+
if (!ref) throw new Error(`Container ${handle.id} not found`);
|
|
452
|
+
const { randomBytes } = await import("node:crypto");
|
|
453
|
+
const token = randomBytes(6).toString("hex");
|
|
454
|
+
const pidFile = `/tmp/.zidane-tty-${token}.pid`;
|
|
455
|
+
const leader = `echo $$ > ${pidFile}; if command -v bash >/dev/null 2>&1; then exec bash -l; else exec sh -l; fi`;
|
|
456
|
+
const envArgs = Object.entries({
|
|
457
|
+
...options.env,
|
|
458
|
+
...TERMINAL_ENV
|
|
459
|
+
}).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
460
|
+
const cliEnv = {};
|
|
461
|
+
for (const [k, v] of Object.entries(process.env)) if (typeof v === "string") cliEnv[k] = v;
|
|
462
|
+
const pty = spawnLocalPty([
|
|
463
|
+
"docker",
|
|
464
|
+
"exec",
|
|
465
|
+
"-it",
|
|
466
|
+
"-w",
|
|
467
|
+
options.cwd ?? handle.cwd,
|
|
468
|
+
...envArgs,
|
|
469
|
+
ref.container.id,
|
|
470
|
+
"sh",
|
|
471
|
+
"-c",
|
|
472
|
+
leader
|
|
473
|
+
], {
|
|
474
|
+
cwd: process.cwd(),
|
|
475
|
+
env: cliEnv,
|
|
476
|
+
cols: options.cols,
|
|
477
|
+
rows: options.rows,
|
|
478
|
+
onData: options.onData
|
|
479
|
+
});
|
|
480
|
+
pty.exited.then(() => execCapped(handle, `rm -f ${pidFile}`, void 0, 4096).catch(() => {}));
|
|
481
|
+
const kill = async () => {
|
|
482
|
+
const probe = await execCapped(handle, `cat ${pidFile} 2>/dev/null || true`, void 0, 4096).catch(() => null);
|
|
483
|
+
const pid = Number.parseInt(probe?.stdout.trim() ?? "", 10);
|
|
484
|
+
if (Number.isFinite(pid) && pid > 0) await execCapped(handle, `kill -HUP -${pid} 2>/dev/null || kill -HUP ${pid} 2>/dev/null || true`, void 0, 4096).catch(() => {});
|
|
485
|
+
await execCapped(handle, `rm -f ${pidFile}`, void 0, 4096).catch(() => {});
|
|
486
|
+
await endLocalPty(pty);
|
|
487
|
+
};
|
|
488
|
+
return localTerminalProcess(pty, {
|
|
489
|
+
id: `docker-${token}`,
|
|
490
|
+
localPid: false,
|
|
491
|
+
kill
|
|
492
|
+
});
|
|
493
|
+
} } : {} };
|
|
494
|
+
}
|
|
495
|
+
//#endregion
|
|
496
|
+
//#region src/contexts/docker.ts
|
|
497
|
+
/**
|
|
498
|
+
* dockerode surfaces HTTP errors with a `statusCode`. 304 = container
|
|
499
|
+
* already stopped, 404 = already gone — both are fine during teardown.
|
|
500
|
+
*/
|
|
501
|
+
function isGoneOrAlreadyStopped(err) {
|
|
502
|
+
const code = err?.statusCode;
|
|
503
|
+
return code === 304 || code === 404;
|
|
504
|
+
}
|
|
505
|
+
function createDockerContext(config) {
|
|
506
|
+
const s = createDockerState(config);
|
|
507
|
+
const { containers } = s;
|
|
508
|
+
const execCapped = createDockerExecCapped(s);
|
|
509
|
+
const spawnM = dockerSpawnMethods(s);
|
|
510
|
+
const streamM = dockerStreamMethods(s, execCapped);
|
|
511
|
+
const files = dockerFileMethods(s, execCapped);
|
|
512
|
+
const ctx = {
|
|
513
|
+
type: "docker",
|
|
514
|
+
capabilities: {
|
|
515
|
+
shell: true,
|
|
516
|
+
filesystem: true,
|
|
517
|
+
glob: true,
|
|
518
|
+
network: true,
|
|
519
|
+
gpu: false,
|
|
520
|
+
stream: true
|
|
521
|
+
},
|
|
522
|
+
spawn: spawnM.spawn,
|
|
523
|
+
async exec(handle, command, options) {
|
|
524
|
+
return execCapped(handle, command, options, DEFAULT_MAX_OUTPUT_BUFFER);
|
|
525
|
+
},
|
|
526
|
+
execStream: streamM.execStream,
|
|
527
|
+
...dockerTerminalMethods(s, execCapped),
|
|
528
|
+
fileSize: files.fileSize,
|
|
529
|
+
readFile: files.readFile,
|
|
530
|
+
writeFile: files.writeFile,
|
|
531
|
+
listFiles: files.listFiles,
|
|
532
|
+
async getMappedPort(handle, containerPort) {
|
|
533
|
+
const ref = containers.get(handle.id);
|
|
534
|
+
if (!ref) return null;
|
|
535
|
+
const bindings = (await ref.container.inspect())?.NetworkSettings?.Ports ?? {};
|
|
536
|
+
for (const proto of ["tcp", "udp"]) {
|
|
537
|
+
const list = bindings[`${containerPort}/${proto}`];
|
|
538
|
+
if (Array.isArray(list) && list.length > 0 && list[0]?.HostPort) return Number.parseInt(list[0].HostPort, 10);
|
|
539
|
+
}
|
|
540
|
+
return null;
|
|
541
|
+
},
|
|
542
|
+
async destroy(handle) {
|
|
543
|
+
const ref = containers.get(handle.id);
|
|
544
|
+
if (!ref) return;
|
|
545
|
+
try {
|
|
546
|
+
try {
|
|
547
|
+
await ref.container.stop({ t: 5 });
|
|
548
|
+
} catch {}
|
|
549
|
+
try {
|
|
550
|
+
await ref.container.remove({ force: true });
|
|
551
|
+
} catch (err) {
|
|
552
|
+
if (!isGoneOrAlreadyStopped(err)) throw err;
|
|
553
|
+
}
|
|
554
|
+
} finally {
|
|
555
|
+
containers.delete(handle.id);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
s.ctx = ctx;
|
|
560
|
+
return ctx;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Path-equal bind mounts that make a HOST working directory usable inside a
|
|
564
|
+
* container: the enclosing git worktree (or `cwd` itself outside git) at the
|
|
565
|
+
* same absolute path, plus the git common dir when it lives outside that
|
|
566
|
+
* tree (a linked worktree's `.git` file points there — without it, git fails
|
|
567
|
+
* in the container). Path-equal keeps host-side features (diffs, artifacts,
|
|
568
|
+
* `@`-paths) valid for the same absolute paths the agent sees.
|
|
569
|
+
*
|
|
570
|
+
* The git dir's `hooks/` and `config` (plus `config.worktree` when present or
|
|
571
|
+
* enabled) are overlaid read-only — created empty first if absent: host-side git
|
|
572
|
+
* (zidane's own diff/workspace calls included) would otherwise run hooks or
|
|
573
|
+
* `core.fsmonitor` / `core.hooksPath` planted from inside the container.
|
|
574
|
+
* Deliberate cost: git commands that WRITE config fail inside the container —
|
|
575
|
+
* `git push -u` / `--set-upstream`, `git branch --set-upstream-to`,
|
|
576
|
+
* `git remote add`, `git config …`. Commits, fetches and a plain
|
|
577
|
+
* `git push <remote> <branch>` work; environments that publish a branch must
|
|
578
|
+
* push without recording an upstream.
|
|
579
|
+
*
|
|
580
|
+
* Returns `[]` when `cwd` is not an existing host directory, so a
|
|
581
|
+
* container-only path (`--cwd /workspace`) keeps its historical meaning, and
|
|
582
|
+
* when the tree to mount is `/`, `$HOME`, or an ancestor of `$HOME` (too broad
|
|
583
|
+
* to hand a container read-write). A git root that is too broad falls back to
|
|
584
|
+
* `cwd` alone (no git dir), so a dotfiles repo at `$HOME` doesn't blank every
|
|
585
|
+
* project under it.
|
|
586
|
+
*/
|
|
587
|
+
function hostWorkspaceMounts(cwd) {
|
|
588
|
+
if (!posix.isAbsolute(cwd) || !isHostDirectory(cwd)) return [];
|
|
589
|
+
const rootMount = workspaceRootMount(cwd, gitProbe(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
|
|
590
|
+
if (isTooBroadToMount(rootMount.source)) {
|
|
591
|
+
const cwdMount = {
|
|
592
|
+
source: safeRealpath(cwd),
|
|
593
|
+
target: cwd
|
|
594
|
+
};
|
|
595
|
+
return isTooBroadToMount(cwdMount.source) ? [] : [cwdMount];
|
|
596
|
+
}
|
|
597
|
+
const mounts = [rootMount];
|
|
598
|
+
const commonDir = gitProbe(cwd, ["rev-parse", "--git-common-dir"]);
|
|
599
|
+
if (commonDir) {
|
|
600
|
+
const realCommon = safeRealpath(commonDir);
|
|
601
|
+
let commonTarget;
|
|
602
|
+
if (isWithin(realCommon, rootMount.source)) commonTarget = posix.join(rootMount.target, posix.relative(rootMount.source, realCommon));
|
|
603
|
+
else {
|
|
604
|
+
mounts.push({
|
|
605
|
+
source: commonDir,
|
|
606
|
+
target: commonDir
|
|
607
|
+
});
|
|
608
|
+
commonTarget = commonDir;
|
|
609
|
+
}
|
|
610
|
+
const overlay = (source) => {
|
|
611
|
+
if (isWithin(source, realCommon)) mounts.push({
|
|
612
|
+
source,
|
|
613
|
+
target: posix.join(commonTarget, posix.relative(realCommon, source)),
|
|
614
|
+
readonly: true
|
|
615
|
+
});
|
|
616
|
+
};
|
|
617
|
+
if (ensureHostPath(posix.join(realCommon, "hooks"), "dir")) overlay(posix.join(realCommon, "hooks"));
|
|
618
|
+
if (ensureHostPath(posix.join(realCommon, "config"), "file")) overlay(posix.join(realCommon, "config"));
|
|
619
|
+
const worktreeConfig = gitProbe(cwd, [
|
|
620
|
+
"rev-parse",
|
|
621
|
+
"--git-path",
|
|
622
|
+
"config.worktree"
|
|
623
|
+
]);
|
|
624
|
+
if (worktreeConfig) {
|
|
625
|
+
const real = posix.join(safeRealpath(posix.dirname(worktreeConfig)), posix.basename(worktreeConfig));
|
|
626
|
+
if (existsSync(real) || worktreeConfigEnabled(cwd) && ensureHostPath(real, "file")) overlay(real);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return mounts;
|
|
630
|
+
}
|
|
631
|
+
/** Create an empty dir / file at `path` if absent. `false` when it can't exist. */
|
|
632
|
+
function ensureHostPath(path, kind) {
|
|
633
|
+
try {
|
|
634
|
+
if (kind === "dir") mkdirSync(path, { recursive: true });
|
|
635
|
+
else if (!existsSync(path)) writeFileSync(path, "", { flag: "a" });
|
|
636
|
+
return true;
|
|
637
|
+
} catch {
|
|
638
|
+
return existsSync(path);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
function worktreeConfigEnabled(cwd) {
|
|
642
|
+
try {
|
|
643
|
+
return execFileSync("git", [
|
|
644
|
+
"config",
|
|
645
|
+
"--bool",
|
|
646
|
+
"--get",
|
|
647
|
+
"extensions.worktreeConfig"
|
|
648
|
+
], {
|
|
649
|
+
cwd,
|
|
650
|
+
timeout: 1e3,
|
|
651
|
+
encoding: "utf8",
|
|
652
|
+
stdio: [
|
|
653
|
+
"ignore",
|
|
654
|
+
"pipe",
|
|
655
|
+
"ignore"
|
|
656
|
+
]
|
|
657
|
+
}).trim() === "true";
|
|
658
|
+
} catch {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
function isTooBroadToMount(source) {
|
|
663
|
+
const real = safeRealpath(source);
|
|
664
|
+
return real === "/" || isWithin(safeRealpath(homedir()), real);
|
|
665
|
+
}
|
|
666
|
+
function safeRealpath(path) {
|
|
667
|
+
try {
|
|
668
|
+
return realpathSync(path);
|
|
669
|
+
} catch {
|
|
670
|
+
return path;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
function workspaceRootMount(cwd, root) {
|
|
674
|
+
try {
|
|
675
|
+
const realCwd = realpathSync(cwd);
|
|
676
|
+
if (root === cwd || realCwd === cwd) return {
|
|
677
|
+
source: root,
|
|
678
|
+
target: root
|
|
679
|
+
};
|
|
680
|
+
const candidate = posix.resolve(cwd, posix.relative(realCwd, root));
|
|
681
|
+
if (isWithin(cwd, candidate) && realpathSync(candidate) === realpathSync(root)) return {
|
|
682
|
+
source: root,
|
|
683
|
+
target: candidate
|
|
684
|
+
};
|
|
685
|
+
return {
|
|
686
|
+
source: realCwd,
|
|
687
|
+
target: cwd
|
|
688
|
+
};
|
|
689
|
+
} catch {
|
|
690
|
+
return {
|
|
691
|
+
source: root,
|
|
692
|
+
target: root
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
function isHostDirectory(path) {
|
|
697
|
+
try {
|
|
698
|
+
return statSync(path).isDirectory();
|
|
699
|
+
} catch {
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function isWithin(child, parent) {
|
|
704
|
+
const rel = posix.relative(parent, child);
|
|
705
|
+
return rel === "" || !rel.startsWith("..") && !posix.isAbsolute(rel);
|
|
706
|
+
}
|
|
707
|
+
function gitProbe(cwd, args) {
|
|
708
|
+
try {
|
|
709
|
+
const out = execFileSync("git", args, {
|
|
710
|
+
cwd,
|
|
711
|
+
timeout: 1e3,
|
|
712
|
+
encoding: "utf8",
|
|
713
|
+
stdio: [
|
|
714
|
+
"ignore",
|
|
715
|
+
"pipe",
|
|
716
|
+
"ignore"
|
|
717
|
+
]
|
|
718
|
+
}).trim();
|
|
719
|
+
return out ? posix.resolve(cwd, out) : null;
|
|
720
|
+
} catch {
|
|
721
|
+
return null;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
//#endregion
|
|
725
|
+
export { packTarFile as a, READ_FILE_MAX_BUFFER as i, hostWorkspaceMounts as n, buildBindSpecs as r, createDockerContext as t };
|
|
726
|
+
|
|
727
|
+
//# sourceMappingURL=docker-BZhMMJUp.js.map
|