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
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
|
-
|
|
3
2
|
//#region src/contexts/types.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Lifetime guarantee of background tasks started through
|
|
@@ -144,8 +143,11 @@ interface SpawnConfig {
|
|
|
144
143
|
mounts?: ContextMount[];
|
|
145
144
|
/** Resource limits */
|
|
146
145
|
limits?: {
|
|
147
|
-
/** Memory limit in MB */
|
|
148
|
-
|
|
146
|
+
/** Memory limit in MB */
|
|
147
|
+
memory?: number;
|
|
148
|
+
/** CPU limit (e.g. '1.0' = 1 core) */
|
|
149
|
+
cpu?: string;
|
|
150
|
+
/** Timeout in seconds for the entire context lifetime */
|
|
149
151
|
timeout?: number;
|
|
150
152
|
};
|
|
151
153
|
/** Sandbox provider config (only for 'sandbox' context) */
|
|
@@ -339,7 +341,8 @@ interface ExecutionContext {
|
|
|
339
341
|
* Must already exist OR be creatable by the context — the
|
|
340
342
|
* implementation handles `mkdir -p` defensively.
|
|
341
343
|
*/
|
|
342
|
-
outputDir: string;
|
|
344
|
+
outputDir: string;
|
|
345
|
+
/** Push-style exit callback. Optional — see the method doc. */
|
|
343
346
|
onExit?: (info: TaskExitInfo) => void;
|
|
344
347
|
/**
|
|
345
348
|
* Cap on bytes written to the output file. Beyond the cap the
|
|
@@ -355,8 +358,15 @@ interface ExecutionContext {
|
|
|
355
358
|
* consumer decides (typically by telling the model the task may
|
|
356
359
|
* be stuck at an interactive prompt). Unset = no watchdog.
|
|
357
360
|
*/
|
|
358
|
-
stallTimeoutMs?: number;
|
|
361
|
+
stallTimeoutMs?: number;
|
|
362
|
+
/** One-shot stall callback — see `stallTimeoutMs`. */
|
|
359
363
|
onStall?: (info: TaskStallInfo) => void;
|
|
364
|
+
/**
|
|
365
|
+
* Run the task in a terminal — see {@link BackgroundTerminalOptions}.
|
|
366
|
+
* Contexts without terminal support ignore it and use pipes; check
|
|
367
|
+
* {@link TaskHandle.terminal} to know which one happened.
|
|
368
|
+
*/
|
|
369
|
+
terminal?: BackgroundTerminalOptions;
|
|
360
370
|
}) => Promise<TaskHandle>;
|
|
361
371
|
/**
|
|
362
372
|
* Open a LIVE bidirectional byte stream to a long-lived process in the
|
|
@@ -405,9 +415,29 @@ interface ExecutionContext {
|
|
|
405
415
|
*/
|
|
406
416
|
execStream?: (handle: ExecutionHandle, command: string, options?: {
|
|
407
417
|
cwd?: string;
|
|
408
|
-
env?: Record<string, string>;
|
|
418
|
+
env?: Record<string, string>;
|
|
419
|
+
/** Aborts startup and kills the child once running. */
|
|
409
420
|
signal?: AbortSignal;
|
|
410
421
|
}) => Promise<StreamHandle>;
|
|
422
|
+
/**
|
|
423
|
+
* Open an interactive terminal (a PTY running the user's login shell) in
|
|
424
|
+
* the context: on the host, in the container, in the sandbox. For people,
|
|
425
|
+
* not protocols: the opposite of {@link execStream}, which defeats every
|
|
426
|
+
* terminal semantic this one keeps (echo, line editing, job control,
|
|
427
|
+
* window size).
|
|
428
|
+
*
|
|
429
|
+
* Optional: a context without a PTY primitive (or a runtime without one:
|
|
430
|
+
* the local contexts need Bun) leaves it undefined, and callers offer no
|
|
431
|
+
* terminal rather than falling back to a host shell.
|
|
432
|
+
*/
|
|
433
|
+
openTerminal?: (handle: ExecutionHandle, options: TerminalOptions) => Promise<TerminalProcess>;
|
|
434
|
+
/**
|
|
435
|
+
* Re-attach to a terminal opened earlier, by its {@link TerminalProcess.id},
|
|
436
|
+
* after the host lost the connection (daemon restart, paused sandbox).
|
|
437
|
+
* Resolves `null` when it is gone. Only contexts whose terminals outlive
|
|
438
|
+
* the host (remote sandboxes) implement it.
|
|
439
|
+
*/
|
|
440
|
+
reconnectTerminal?: (handle: ExecutionHandle, id: string, options: TerminalOptions) => Promise<TerminalProcess | null>;
|
|
411
441
|
/**
|
|
412
442
|
* SIGTERM the whole process group of a running background task.
|
|
413
443
|
* Idempotent — second call returns `null` (or the cached exit info).
|
|
@@ -453,17 +483,24 @@ interface ExecutionContext {
|
|
|
453
483
|
* subagent's destroy() — matching shell semantics, where a `&`-ed
|
|
454
484
|
* command outlives the parent process.
|
|
455
485
|
*
|
|
486
|
+
* With `fromHandle === toHandle` ownership stays put and only the
|
|
487
|
+
* callbacks are rebound: a host that keeps one handle across agent
|
|
488
|
+
* rebuilds (`chat/execution-cache.ts`) hands the running tasks to the
|
|
489
|
+
* freshly built agent this way.
|
|
490
|
+
*
|
|
456
491
|
* Side effects:
|
|
457
492
|
* - The task's `handleId` is rewritten, so subsequent
|
|
458
493
|
* `listBackground(toHandle)` / `killBackground(toHandle, …)` /
|
|
459
494
|
* `destroy(toHandle)` see it (and `fromHandle`-scoped operations
|
|
460
495
|
* don't).
|
|
461
|
-
* - When `newOnExit`
|
|
462
|
-
* REPLACED with
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
*
|
|
496
|
+
* - When `newOnExit` / `newOnStall` are provided, the task's OWNER
|
|
497
|
+
* callbacks are REPLACED with them. Critical: they were captured
|
|
498
|
+
* against the spawning agent's hook bus, which is about to be
|
|
499
|
+
* destroyed; without rewiring, the new owner never learns when the
|
|
500
|
+
* task terminates or stalls. Pass closures that fire the new owner's
|
|
501
|
+
* `background:exit` / `background:stall` hooks. In-flight
|
|
502
|
+
* `killBackground` / `waitBackground` resolvers are not owner
|
|
503
|
+
* callbacks and keep firing.
|
|
467
504
|
*
|
|
468
505
|
* Returns the entries that were actually reassigned (running tasks
|
|
469
506
|
* only; terminated ones stay where they are). Implementations that
|
|
@@ -471,7 +508,7 @@ interface ExecutionContext {
|
|
|
471
508
|
* (spawn.ts) falls back to the current behavior of killing child
|
|
472
509
|
* tasks at subagent shutdown.
|
|
473
510
|
*/
|
|
474
|
-
reassignBackgroundTasks?: (fromHandle: ExecutionHandle, toHandle: ExecutionHandle, newOnExit?: (info: TaskExitInfo) => void) => Promise<readonly TaskEntry[]>;
|
|
511
|
+
reassignBackgroundTasks?: (fromHandle: ExecutionHandle, toHandle: ExecutionHandle, newOnExit?: (info: TaskExitInfo) => void, newOnStall?: (info: TaskStallInfo) => void) => Promise<readonly TaskEntry[]>;
|
|
475
512
|
/** Read a file from the context's filesystem */
|
|
476
513
|
readFile: (handle: ExecutionHandle, path: string) => Promise<string>;
|
|
477
514
|
/**
|
|
@@ -561,6 +598,52 @@ interface ExecutionContext {
|
|
|
561
598
|
* The status is a coarse-grained signal; the exit code carries the
|
|
562
599
|
* fine-grained detail (e.g. `143 = SIGTERM` for `'killed'`).
|
|
563
600
|
*/
|
|
601
|
+
interface TerminalOptions {
|
|
602
|
+
/** Working directory; defaults to the handle's cwd. */
|
|
603
|
+
cwd?: string;
|
|
604
|
+
cols: number;
|
|
605
|
+
rows: number;
|
|
606
|
+
/** Extra environment on top of what the context's commands get. */
|
|
607
|
+
env?: Record<string, string>;
|
|
608
|
+
/** Variables to drop from the inherited environment (local contexts). */
|
|
609
|
+
unsetEnv?: readonly string[];
|
|
610
|
+
/** Raw terminal output. Called synchronously; never slowed by the consumer. */
|
|
611
|
+
onData: (data: Uint8Array) => void;
|
|
612
|
+
}
|
|
613
|
+
interface TerminalProcess {
|
|
614
|
+
/** Opaque id for {@link ExecutionContext.reconnectTerminal}. */
|
|
615
|
+
id: string;
|
|
616
|
+
/** Whether {@link ExecutionContext.reconnectTerminal} can find it again later. */
|
|
617
|
+
reconnectable: boolean;
|
|
618
|
+
/** Host pid of the shell, when it runs on this machine (for labels). */
|
|
619
|
+
localPid?: number;
|
|
620
|
+
write: (data: string | Uint8Array) => void;
|
|
621
|
+
resize: (cols: number, rows: number) => void;
|
|
622
|
+
/** End the shell and everything it started. Idempotent. */
|
|
623
|
+
kill: () => Promise<void>;
|
|
624
|
+
/** Let go without ending it (a remote PTY keeps running for a reconnect). */
|
|
625
|
+
detach: () => Promise<void>;
|
|
626
|
+
/** Resolves once with the exit code; `-1` when the connection was lost instead. */
|
|
627
|
+
exited: Promise<number>;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Terminal mode for {@link ExecutionContext.execBackground}: run the task in
|
|
631
|
+
* a PTY instead of pipes, so it behaves as it would for a person (colors,
|
|
632
|
+
* progress, tools that insist on a TTY) and can be watched and typed into.
|
|
633
|
+
* The log file still receives the output, with terminal control sequences
|
|
634
|
+
* removed, and the registry (kill, wait, list, reassign) is unchanged.
|
|
635
|
+
*/
|
|
636
|
+
interface BackgroundTerminalOptions {
|
|
637
|
+
cols: number;
|
|
638
|
+
rows: number;
|
|
639
|
+
/** Raw output as it arrives (the log gets the stripped text). */
|
|
640
|
+
onData: (data: Uint8Array) => void;
|
|
641
|
+
/** Receives the functions to type into and resize the task's terminal. */
|
|
642
|
+
onReady?: (io: {
|
|
643
|
+
write: (data: string | Uint8Array) => void;
|
|
644
|
+
resize: (cols: number, rows: number) => void;
|
|
645
|
+
}) => void;
|
|
646
|
+
}
|
|
564
647
|
type BackgroundTaskStatus = 'running' | 'exited' | 'killed';
|
|
565
648
|
/**
|
|
566
649
|
* Returned synchronously by `execBackground` — the handle the model and
|
|
@@ -582,6 +665,8 @@ interface TaskHandle {
|
|
|
582
665
|
pid: number;
|
|
583
666
|
/** Absolute path to the log file the context is streaming output into. */
|
|
584
667
|
outputPath: string;
|
|
668
|
+
/** True when the task runs in a terminal (`execBackground`'s `terminal` option was honored). */
|
|
669
|
+
terminal?: boolean;
|
|
585
670
|
}
|
|
586
671
|
/**
|
|
587
672
|
* A live bidirectional stream to a process in the context. Returned by
|
|
@@ -765,5 +850,5 @@ declare function resolveWritableRootsAsync(cwd: string, options?: Omit<ResolveWr
|
|
|
765
850
|
gitCommonDir?: (cwd: string) => Promise<string | null>;
|
|
766
851
|
}): Promise<string[]>;
|
|
767
852
|
//#endregion
|
|
768
|
-
export {
|
|
769
|
-
//# sourceMappingURL=isolation-
|
|
853
|
+
export { TaskExitInfo as C, TerminalProcess as D, TerminalOptions as E, resolveDetachedTasksCapability as O, TaskEntry as S, TaskStallInfo as T, ListFileMetadata as _, resolveWritableRoots as a, SpawnConfig as b, BackgroundTerminalOptions as c, ContextMount as d, ContextType as f, ExecutionHandle as g, ExecutionContext as h, parseAllowWriteSetting as i, ContextCapabilities as l, ExecResult as m, IsolationPolicy as n, resolveWritableRootsAsync as o, DetachedTasksCapability as p, isolationAvailability as r, BackgroundTaskStatus as s, IsolationBackend as t, ContextHardening as u, ListFilesEntry as v, TaskHandle as w, StreamHandle as x, ListFilesOptions as y };
|
|
854
|
+
//# sourceMappingURL=isolation-D9L650W5.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isolation-D9L650W5.d.ts","names":[],"sources":["../src/contexts/types.ts","../src/contexts/isolation.ts"],"mappings":"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"}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
//#region src/acp/json-rpc.ts
|
|
3
|
+
function createJsonRpcEndpoint(options) {
|
|
4
|
+
const endpoint = createEndpointCore(options);
|
|
5
|
+
return {
|
|
6
|
+
...endpoint,
|
|
7
|
+
receive(text) {
|
|
8
|
+
let message;
|
|
9
|
+
try {
|
|
10
|
+
message = JSON.parse(text);
|
|
11
|
+
} catch (err) {
|
|
12
|
+
endpoint.writeMessage(errorResponse(null, -32700, err instanceof Error ? err.message : String(err)));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
endpoint.handleParsed(message);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function createJsonRpcConnection(options) {
|
|
20
|
+
const frames = createFrameBuffer();
|
|
21
|
+
const endpoint = createEndpointCore({
|
|
22
|
+
...options,
|
|
23
|
+
send: options.send ?? ((json) => {
|
|
24
|
+
if (options.framing === "content-length") {
|
|
25
|
+
const bytes = Buffer.byteLength(json);
|
|
26
|
+
options.output.write(`Content-Length: ${bytes}\r\n\r\n${json}`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
options.output.write(`${json}\n`);
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
const { writeMessage, handleParsed } = endpoint;
|
|
33
|
+
let deferred;
|
|
34
|
+
let closing = false;
|
|
35
|
+
let stopped = false;
|
|
36
|
+
const finish = () => {
|
|
37
|
+
if (stopped) return;
|
|
38
|
+
stopped = true;
|
|
39
|
+
clearImmediate(deferred);
|
|
40
|
+
endpoint.close();
|
|
41
|
+
};
|
|
42
|
+
const drain = () => {
|
|
43
|
+
deferred = void 0;
|
|
44
|
+
for (;;) {
|
|
45
|
+
if (stopped) return;
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = frames.next();
|
|
49
|
+
} catch (err) {
|
|
50
|
+
frames.dropThroughNewline();
|
|
51
|
+
writeMessage(errorResponse(null, -32700, err instanceof Error ? err.message : String(err)));
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (!parsed) {
|
|
55
|
+
if (closing) finish();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
handleParsed(parsed.message);
|
|
59
|
+
if (isResponse(parsed.message)) {
|
|
60
|
+
deferred = setImmediate(drain);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const onData = (chunk) => {
|
|
66
|
+
if (!frames.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk)) return;
|
|
67
|
+
if (deferred) return;
|
|
68
|
+
drain();
|
|
69
|
+
};
|
|
70
|
+
const onError = (err) => {
|
|
71
|
+
options.onError?.(err);
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
start() {
|
|
75
|
+
options.input.on("data", onData);
|
|
76
|
+
options.input.on("error", onError);
|
|
77
|
+
},
|
|
78
|
+
close() {
|
|
79
|
+
if (closing) return;
|
|
80
|
+
closing = true;
|
|
81
|
+
options.input.off("data", onData);
|
|
82
|
+
options.input.off("error", onError);
|
|
83
|
+
endpoint.seal();
|
|
84
|
+
if (!deferred) finish();
|
|
85
|
+
},
|
|
86
|
+
sendNotification: endpoint.sendNotification,
|
|
87
|
+
sendRequest: endpoint.sendRequest
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** The framing-free half both shapes share: ids, pending requests, dispatch of parsed messages. */
|
|
91
|
+
function createEndpointCore(options) {
|
|
92
|
+
let nextId = 1;
|
|
93
|
+
/** No more sending, no new requests (`seal`, `close`). */
|
|
94
|
+
let closed = false;
|
|
95
|
+
const pending = /* @__PURE__ */ new Map();
|
|
96
|
+
const reportError = (err) => {
|
|
97
|
+
options.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* A reply is written from a dispatch nobody awaits: an unencodable result
|
|
101
|
+
* is answered with an internal error, and a transport that throws on send
|
|
102
|
+
* (a socket torn down under the reply) is reported through `onError`. Our
|
|
103
|
+
* own requests and notifications throw to their caller, as before.
|
|
104
|
+
*/
|
|
105
|
+
const writeMessage = (message) => {
|
|
106
|
+
if (closed) return;
|
|
107
|
+
const reply = "result" in message || "error" in message;
|
|
108
|
+
let json;
|
|
109
|
+
try {
|
|
110
|
+
json = JSON.stringify({
|
|
111
|
+
...message,
|
|
112
|
+
jsonrpc: "2.0"
|
|
113
|
+
});
|
|
114
|
+
} catch (err) {
|
|
115
|
+
if (!("result" in message)) throw err;
|
|
116
|
+
writeMessage(errorResponse(message.id, -32603, err instanceof Error ? err.message : String(err)));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
options.send(json, message);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
if (!reply) throw err;
|
|
123
|
+
reportError(err);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const handleParsed = async (message) => {
|
|
127
|
+
if (!isObject(message)) {
|
|
128
|
+
writeMessage(errorResponse(null, -32600, "Invalid JSON-RPC message."));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const msg = message;
|
|
132
|
+
if ("id" in msg && ("result" in msg || "error" in msg)) {
|
|
133
|
+
const request = pending.get(msg.id);
|
|
134
|
+
if (!request) return;
|
|
135
|
+
pending.delete(msg.id);
|
|
136
|
+
if ("error" in msg && msg.error) request.reject(new JsonRpcRemoteError(msg.error.message, msg.error.code, msg.error.data));
|
|
137
|
+
else request.resolve(msg.result);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (typeof msg.method !== "string") {
|
|
141
|
+
writeMessage(errorResponse(("id" in msg ? msg.id : null) ?? null, -32600, "Missing JSON-RPC method."));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if ("id" in msg) {
|
|
145
|
+
try {
|
|
146
|
+
const response = await options.onRequest(msg);
|
|
147
|
+
if (response) writeMessage(response);
|
|
148
|
+
} catch (err) {
|
|
149
|
+
writeMessage(errorResponse(msg.id, -32603, err instanceof Error ? err.message : String(err)));
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
await options.onNotification?.(msg);
|
|
155
|
+
} catch (err) {
|
|
156
|
+
reportError(err);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
return {
|
|
160
|
+
writeMessage,
|
|
161
|
+
/** Dispatch one parsed message; what it can't answer goes to `onError`, never an unhandled rejection. */
|
|
162
|
+
handleParsed: (message) => {
|
|
163
|
+
handleParsed(message).catch(reportError);
|
|
164
|
+
},
|
|
165
|
+
/** Stop sending and refuse new requests; pending ones stay until `close` (a reply already received may settle them). */
|
|
166
|
+
seal() {
|
|
167
|
+
closed = true;
|
|
168
|
+
},
|
|
169
|
+
close() {
|
|
170
|
+
closed = true;
|
|
171
|
+
for (const request of pending.values()) request.reject(new JsonRpcConnectionClosedError());
|
|
172
|
+
pending.clear();
|
|
173
|
+
},
|
|
174
|
+
sendNotification(method, params) {
|
|
175
|
+
writeMessage({
|
|
176
|
+
jsonrpc: "2.0",
|
|
177
|
+
method,
|
|
178
|
+
...params !== void 0 ? { params } : {}
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
sendRequest(method, params) {
|
|
182
|
+
if (closed) return Promise.reject(new JsonRpcConnectionClosedError({ sent: false }));
|
|
183
|
+
const id = nextId++;
|
|
184
|
+
writeMessage({
|
|
185
|
+
jsonrpc: "2.0",
|
|
186
|
+
id,
|
|
187
|
+
method,
|
|
188
|
+
...params !== void 0 ? { params } : {}
|
|
189
|
+
});
|
|
190
|
+
return new Promise((resolve, reject) => {
|
|
191
|
+
pending.set(id, {
|
|
192
|
+
resolve,
|
|
193
|
+
reject
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* The transport closed while requests were in flight. Distinct from
|
|
201
|
+
* {@link JsonRpcRemoteError} because it is not a reply — nothing on the other
|
|
202
|
+
* side said anything — and callers must be able to tell "the daemon rejected
|
|
203
|
+
* this" from "the daemon went away" without parsing a message string. Every
|
|
204
|
+
* pending request is rejected with one of these on `close()`, and so is every
|
|
205
|
+
* request made after it.
|
|
206
|
+
*
|
|
207
|
+
* `sent`: whether the request may have reached the other side. `false` only
|
|
208
|
+
* when it was refused before being written (the connection was already
|
|
209
|
+
* closed), so a caller can retry a non-idempotent call elsewhere safely.
|
|
210
|
+
*/
|
|
211
|
+
var JsonRpcConnectionClosedError = class extends Error {
|
|
212
|
+
sent;
|
|
213
|
+
constructor(options = {}) {
|
|
214
|
+
super("JSON-RPC connection closed.");
|
|
215
|
+
this.name = "JsonRpcConnectionClosedError";
|
|
216
|
+
this.sent = options.sent ?? true;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
var JsonRpcRemoteError = class extends Error {
|
|
220
|
+
code;
|
|
221
|
+
data;
|
|
222
|
+
constructor(message, code, data) {
|
|
223
|
+
super(message);
|
|
224
|
+
this.code = code;
|
|
225
|
+
this.data = data;
|
|
226
|
+
this.name = "JsonRpcRemoteError";
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
function successResponse(id, result = {}) {
|
|
230
|
+
return {
|
|
231
|
+
jsonrpc: "2.0",
|
|
232
|
+
id,
|
|
233
|
+
result
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function errorResponse(id, code, message, data) {
|
|
237
|
+
return {
|
|
238
|
+
jsonrpc: "2.0",
|
|
239
|
+
id,
|
|
240
|
+
error: {
|
|
241
|
+
code,
|
|
242
|
+
message,
|
|
243
|
+
...data !== void 0 ? { data } : {}
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
const HEADER_DELIMITER = "\r\n\r\n";
|
|
248
|
+
const NEWLINE = 10;
|
|
249
|
+
/**
|
|
250
|
+
* Receive buffer for both framings. Incoming chunks are only listed; they are
|
|
251
|
+
* concatenated when a frame can actually have completed: a newline arrived
|
|
252
|
+
* (every NDJSON line and every header block ends in one) or, while a
|
|
253
|
+
* Content-Length body is incomplete, once enough bytes are buffered. The
|
|
254
|
+
* header-delimiter search resumes where the previous one stopped instead of
|
|
255
|
+
* rescanning from byte 0. Parsing itself is {@link readNextMessage}, unchanged.
|
|
256
|
+
*/
|
|
257
|
+
function createFrameBuffer() {
|
|
258
|
+
let buffer = Buffer.alloc(0);
|
|
259
|
+
let chunks = [];
|
|
260
|
+
let chunkBytes = 0;
|
|
261
|
+
let delimiterFreeBefore = 0;
|
|
262
|
+
let needBytes = 0;
|
|
263
|
+
let newlineSeen = false;
|
|
264
|
+
const consume = (bytes) => {
|
|
265
|
+
buffer = buffer.subarray(bytes);
|
|
266
|
+
delimiterFreeBefore = Math.max(0, delimiterFreeBefore - bytes);
|
|
267
|
+
};
|
|
268
|
+
const findHeaderEnd = (input) => {
|
|
269
|
+
const at = input.indexOf(HEADER_DELIMITER, delimiterFreeBefore);
|
|
270
|
+
if (at < 0) delimiterFreeBefore = Math.max(0, input.length - 3);
|
|
271
|
+
return at;
|
|
272
|
+
};
|
|
273
|
+
return {
|
|
274
|
+
/** Buffer a chunk; true when a frame may now be complete and `next()` should run. */
|
|
275
|
+
push(chunk) {
|
|
276
|
+
if (chunk.length === 0) return false;
|
|
277
|
+
chunks.push(chunk);
|
|
278
|
+
chunkBytes += chunk.length;
|
|
279
|
+
if (!newlineSeen && chunk.includes(NEWLINE)) newlineSeen = true;
|
|
280
|
+
if (needBytes > 0) return buffer.length + chunkBytes >= needBytes;
|
|
281
|
+
return newlineSeen;
|
|
282
|
+
},
|
|
283
|
+
/** Next complete message, or null when more bytes are needed. Throws on a malformed frame. */
|
|
284
|
+
next() {
|
|
285
|
+
if (chunks.length > 0) {
|
|
286
|
+
buffer = Buffer.concat([buffer, ...chunks]);
|
|
287
|
+
chunks = [];
|
|
288
|
+
chunkBytes = 0;
|
|
289
|
+
}
|
|
290
|
+
const parsed = readNextMessage(buffer, findHeaderEnd);
|
|
291
|
+
if (parsed === null || "needBytes" in parsed) {
|
|
292
|
+
needBytes = parsed?.needBytes ?? 0;
|
|
293
|
+
newlineSeen = false;
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
needBytes = 0;
|
|
297
|
+
consume(parsed.consumed);
|
|
298
|
+
return { message: parsed.message };
|
|
299
|
+
},
|
|
300
|
+
/** Parse-error resync: drop through the first newline (everything when there is none). */
|
|
301
|
+
dropThroughNewline() {
|
|
302
|
+
const newline = buffer.indexOf(NEWLINE);
|
|
303
|
+
consume(newline >= 0 ? newline + 1 : buffer.length);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function readNextMessage(input, findHeaderEnd) {
|
|
308
|
+
if (input.length === 0) return null;
|
|
309
|
+
const headerEnd = findHeaderEnd(input);
|
|
310
|
+
if (headerEnd >= 0) {
|
|
311
|
+
const header = input.subarray(0, headerEnd).toString("utf8");
|
|
312
|
+
const match = /^Content-Length:\s*(\d+)/im.exec(header);
|
|
313
|
+
if (!match) return readLineMessage(input);
|
|
314
|
+
const length = Number(match[1]);
|
|
315
|
+
const bodyStart = headerEnd + 4;
|
|
316
|
+
const bodyEnd = bodyStart + length;
|
|
317
|
+
if (input.length < bodyEnd) return { needBytes: bodyEnd };
|
|
318
|
+
const body = input.subarray(bodyStart, bodyEnd).toString("utf8");
|
|
319
|
+
return {
|
|
320
|
+
message: JSON.parse(body),
|
|
321
|
+
consumed: bodyEnd
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (/^Content-Length:/i.test(input.subarray(0, Math.min(input.length, 32)).toString("utf8"))) return null;
|
|
325
|
+
return readLineMessage(input);
|
|
326
|
+
}
|
|
327
|
+
function readLineMessage(input) {
|
|
328
|
+
let offset = 0;
|
|
329
|
+
for (;;) {
|
|
330
|
+
const lineEnd = input.indexOf(NEWLINE, offset);
|
|
331
|
+
if (lineEnd < 0) return null;
|
|
332
|
+
const line = input.subarray(offset, lineEnd).toString("utf8").trim();
|
|
333
|
+
offset = lineEnd + 1;
|
|
334
|
+
if (line.length === 0) continue;
|
|
335
|
+
return {
|
|
336
|
+
message: JSON.parse(line),
|
|
337
|
+
consumed: offset
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function isResponse(message) {
|
|
342
|
+
return isObject(message) && "id" in message && ("result" in message || "error" in message);
|
|
343
|
+
}
|
|
344
|
+
function isObject(value) {
|
|
345
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
346
|
+
}
|
|
347
|
+
//#endregion
|
|
348
|
+
export { errorResponse as a, createJsonRpcEndpoint as i, JsonRpcRemoteError as n, successResponse as o, createJsonRpcConnection as r, JsonRpcConnectionClosedError as t };
|
|
349
|
+
|
|
350
|
+
//# sourceMappingURL=json-rpc--HXQti1E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-rpc--HXQti1E.js","names":[],"sources":["../src/acp/json-rpc.ts"],"sourcesContent":["import type { Readable, Writable } from 'node:stream'\nimport type { AcpPeer, JsonRpcFailure, JsonRpcId, JsonRpcMessage, JsonRpcRequest, JsonRpcResponse } from './types'\nimport { Buffer } from 'node:buffer'\nimport { AcpErrorCode } from './types'\n\nexport interface JsonRpcConnectionOptions {\n input: Readable\n output: Writable\n onRequest: (message: JsonRpcRequest) => Promise<JsonRpcResponse | null | undefined> | JsonRpcResponse | null | undefined\n onNotification?: (message: JsonRpcMessage & { method: string, id?: undefined }) => void | Promise<void>\n framing?: 'content-length' | 'newline'\n onError?: (error: Error) => void\n /**\n * Write each serialized message yourself instead of to `output` (framing\n * included): a transport that budgets replies and the rest apart\n * (`src/ipc/transports/send-budget.ts`). `message` is what was serialized.\n */\n send?: (json: string, message: JsonRpcMessage) => void\n}\n\nexport interface JsonRpcConnection extends AcpPeer {\n start: () => void\n close: () => void\n}\n\n/**\n * JSON-RPC over a message transport (one message per frame, e.g. a WebSocket):\n * the request / response / notification logic of {@link createJsonRpcConnection}\n * without the byte-stream framing.\n */\nexport interface JsonRpcEndpointOptions {\n /**\n * Write one serialized message (a single JSON text). `message` is what was\n * serialized, for a transport that treats replies and the rest apart.\n */\n send: (json: string, message: JsonRpcMessage) => void\n onRequest: JsonRpcConnectionOptions['onRequest']\n onNotification?: JsonRpcConnectionOptions['onNotification']\n onError?: (error: Error) => void\n}\n\nexport interface JsonRpcEndpoint extends AcpPeer {\n /** Handle one received frame's text; a frame that is not JSON is answered with a parse error. */\n receive: (text: string) => void\n /** Stop sending and reject every pending request with {@link JsonRpcConnectionClosedError}. */\n close: () => void\n}\n\ninterface PendingRequest {\n resolve: (value: unknown) => void\n reject: (error: Error) => void\n}\n\nexport function createJsonRpcEndpoint(options: JsonRpcEndpointOptions): JsonRpcEndpoint {\n const endpoint = createEndpointCore(options)\n return {\n ...endpoint,\n receive(text) {\n let message: unknown\n try {\n message = JSON.parse(text)\n }\n catch (err) {\n endpoint.writeMessage(errorResponse(null, AcpErrorCode.ParseError, err instanceof Error ? err.message : String(err)))\n return\n }\n endpoint.handleParsed(message)\n },\n }\n}\n\nexport function createJsonRpcConnection(options: JsonRpcConnectionOptions): JsonRpcConnection {\n const frames = createFrameBuffer()\n const endpoint = createEndpointCore({\n ...options,\n send: options.send ?? ((json) => {\n // ACP stdio framing is newline-delimited JSON (NDJSON) and is the default.\n // `JSON.stringify` escapes any embedded newline, so a serialized message is\n // always a single line. LSP-style `Content-Length` framing is opt-in for\n // non-ACP transports only.\n if (options.framing === 'content-length') {\n const bytes = Buffer.byteLength(json)\n options.output.write(`Content-Length: ${bytes}\\r\\n\\r\\n${json}`)\n return\n }\n options.output.write(`${json}\\n`)\n }),\n })\n const { writeMessage, handleParsed } = endpoint\n\n /*\n * Frames are dispatched in wire order, but a response is only OBSERVED once\n * the promise it settles has run its continuations (microtasks), while a\n * request or notification reaches its handler synchronously. When a busy\n * reader gets \"response, then notification\" in one chunk, dispatching both\n * in one pass lets the notification overtake the answer it followed (e.g. an\n * `ipc.signal` the host emitted after answering). So after a response the\n * rest of the buffer waits one macrotask: the caller's continuation runs\n * first, exactly as if the frames had arrived in separate reads.\n *\n * `close()` stops reading, but frames already received in full are still\n * delivered, the same way (a reply, a notification and EOF can arrive in\n * one chunk, and the owner closes on EOF before the held notification's\n * turn). Then the endpoint closes: what is still pending is rejected.\n */\n let deferred: ReturnType<typeof setImmediate> | undefined\n let closing = false\n let stopped = false\n\n const finish = (): void => {\n if (stopped)\n return\n stopped = true\n clearImmediate(deferred)\n endpoint.close()\n }\n\n const drain = (): void => {\n deferred = undefined\n for (;;) {\n if (stopped)\n return\n let parsed: { message: unknown } | null\n try {\n parsed = frames.next()\n }\n catch (err) {\n // Resync to the next newline: drop ONLY the malformed line instead\n // of zeroing the whole receive buffer, so one bad line can't discard\n // well-formed messages already buffered behind it. A parse error\n // implies a complete (newline-terminated) line was seen, so this\n // always consumes at least one byte — the loop can't spin.\n frames.dropThroughNewline()\n writeMessage(errorResponse(null, AcpErrorCode.ParseError, err instanceof Error ? err.message : String(err)))\n continue\n }\n if (!parsed) {\n if (closing)\n finish()\n return\n }\n handleParsed(parsed.message)\n if (isResponse(parsed.message)) {\n deferred = setImmediate(drain)\n return\n }\n }\n }\n\n const onData = (chunk: Buffer | string): void => {\n // Skips the parse entirely while no frame can have completed, so a large\n // message split into many chunks is concatenated once, not per chunk.\n if (!frames.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk))\n return\n // Frames are held behind a response: the scheduled drain reads this chunk after them.\n if (deferred)\n return\n drain()\n }\n\n const onError = (err: Error): void => {\n options.onError?.(err)\n }\n\n return {\n start() {\n options.input.on('data', onData)\n options.input.on('error', onError)\n },\n close() {\n if (closing)\n return\n closing = true\n options.input.off('data', onData)\n options.input.off('error', onError)\n // Nothing more goes out; replies to frames still held can still settle their requests.\n endpoint.seal()\n // Frames held behind a response: the scheduled drain delivers them, then finishes.\n if (!deferred)\n finish()\n },\n sendNotification: endpoint.sendNotification,\n sendRequest: endpoint.sendRequest,\n }\n}\n\n/** The framing-free half both shapes share: ids, pending requests, dispatch of parsed messages. */\nfunction createEndpointCore(options: JsonRpcEndpointOptions) {\n let nextId = 1\n /** No more sending, no new requests (`seal`, `close`). */\n let closed = false\n const pending = new Map<JsonRpcId, PendingRequest>()\n\n const reportError = (err: unknown): void => {\n options.onError?.(err instanceof Error ? err : new Error(String(err)))\n }\n\n /**\n * A reply is written from a dispatch nobody awaits: an unencodable result\n * is answered with an internal error, and a transport that throws on send\n * (a socket torn down under the reply) is reported through `onError`. Our\n * own requests and notifications throw to their caller, as before.\n */\n const writeMessage = (message: JsonRpcMessage): void => {\n if (closed)\n return\n const reply = 'result' in message || 'error' in message\n let json: string\n try {\n json = JSON.stringify({ ...message, jsonrpc: '2.0' })\n }\n catch (err) {\n if (!('result' in message))\n throw err\n writeMessage(errorResponse(message.id, AcpErrorCode.InternalError, err instanceof Error ? err.message : String(err)))\n return\n }\n try {\n options.send(json, message)\n }\n catch (err) {\n if (!reply)\n throw err\n reportError(err)\n }\n }\n\n const handleParsed = async (message: unknown): Promise<void> => {\n if (!isObject(message)) {\n writeMessage(errorResponse(null, AcpErrorCode.InvalidRequest, 'Invalid JSON-RPC message.'))\n return\n }\n\n const msg = message as unknown as JsonRpcMessage\n if ('id' in msg && ('result' in msg || 'error' in msg)) {\n const request = pending.get(msg.id)\n if (!request)\n return\n pending.delete(msg.id)\n if ('error' in msg && msg.error) {\n request.reject(new JsonRpcRemoteError(msg.error.message, msg.error.code, msg.error.data))\n }\n else {\n request.resolve((msg as { result?: unknown }).result)\n }\n return\n }\n\n if (typeof (msg as { method?: unknown }).method !== 'string') {\n writeMessage(errorResponse(('id' in msg ? msg.id : null) ?? null, AcpErrorCode.InvalidRequest, 'Missing JSON-RPC method.'))\n return\n }\n\n if ('id' in msg) {\n try {\n const response = await options.onRequest(msg as JsonRpcRequest)\n if (response)\n writeMessage(response)\n }\n catch (err) {\n writeMessage(errorResponse(msg.id, AcpErrorCode.InternalError, err instanceof Error ? err.message : String(err)))\n }\n return\n }\n\n try {\n await options.onNotification?.(msg as JsonRpcMessage & { method: string, id?: undefined })\n }\n catch (err) {\n reportError(err)\n }\n }\n\n return {\n writeMessage,\n /** Dispatch one parsed message; what it can't answer goes to `onError`, never an unhandled rejection. */\n handleParsed: (message: unknown): void => {\n handleParsed(message).catch(reportError)\n },\n /** Stop sending and refuse new requests; pending ones stay until `close` (a reply already received may settle them). */\n seal() {\n closed = true\n },\n close() {\n closed = true\n for (const request of pending.values())\n request.reject(new JsonRpcConnectionClosedError())\n pending.clear()\n },\n sendNotification(method: string, params?: unknown) {\n writeMessage({ jsonrpc: '2.0', method, ...(params !== undefined ? { params } : {}) })\n },\n sendRequest(method: string, params?: unknown) {\n if (closed)\n return Promise.reject(new JsonRpcConnectionClosedError({ sent: false }))\n const id = nextId++\n writeMessage({ jsonrpc: '2.0', id, method, ...(params !== undefined ? { params } : {}) })\n return new Promise((resolve, reject) => {\n pending.set(id, { resolve, reject })\n })\n },\n }\n}\n\n/**\n * The transport closed while requests were in flight. Distinct from\n * {@link JsonRpcRemoteError} because it is not a reply — nothing on the other\n * side said anything — and callers must be able to tell \"the daemon rejected\n * this\" from \"the daemon went away\" without parsing a message string. Every\n * pending request is rejected with one of these on `close()`, and so is every\n * request made after it.\n *\n * `sent`: whether the request may have reached the other side. `false` only\n * when it was refused before being written (the connection was already\n * closed), so a caller can retry a non-idempotent call elsewhere safely.\n */\nexport class JsonRpcConnectionClosedError extends Error {\n readonly sent: boolean\n constructor(options: { sent?: boolean } = {}) {\n super('JSON-RPC connection closed.')\n this.name = 'JsonRpcConnectionClosedError'\n this.sent = options.sent ?? true\n }\n}\n\nexport class JsonRpcRemoteError extends Error {\n constructor(message: string, readonly code: number, readonly data?: unknown) {\n super(message)\n this.name = 'JsonRpcRemoteError'\n }\n}\n\nexport function successResponse(id: JsonRpcId, result: unknown = {}): JsonRpcResponse {\n return { jsonrpc: '2.0', id, result }\n}\n\nexport function errorResponse(id: JsonRpcId, code: number, message: string, data?: unknown): JsonRpcFailure {\n return {\n jsonrpc: '2.0',\n id,\n error: {\n code,\n message,\n ...(data !== undefined ? { data } : {}),\n },\n }\n}\n\nconst HEADER_DELIMITER = '\\r\\n\\r\\n'\nconst NEWLINE = 0x0A\n\n/**\n * Receive buffer for both framings. Incoming chunks are only listed; they are\n * concatenated when a frame can actually have completed: a newline arrived\n * (every NDJSON line and every header block ends in one) or, while a\n * Content-Length body is incomplete, once enough bytes are buffered. The\n * header-delimiter search resumes where the previous one stopped instead of\n * rescanning from byte 0. Parsing itself is {@link readNextMessage}, unchanged.\n */\nexport function createFrameBuffer() {\n let buffer: Buffer<ArrayBufferLike> = Buffer.alloc(0)\n let chunks: Buffer[] = []\n let chunkBytes = 0\n // No header delimiter starts before this offset of `buffer`.\n let delimiterFreeBefore = 0\n // Byte count `buffer` must reach for the pending Content-Length frame; 0 = none pending.\n let needBytes = 0\n let newlineSeen = false\n\n const consume = (bytes: number): void => {\n buffer = buffer.subarray(bytes)\n delimiterFreeBefore = Math.max(0, delimiterFreeBefore - bytes)\n }\n\n const findHeaderEnd = (input: Buffer<ArrayBufferLike>): number => {\n const at = input.indexOf(HEADER_DELIMITER, delimiterFreeBefore)\n if (at < 0)\n delimiterFreeBefore = Math.max(0, input.length - (HEADER_DELIMITER.length - 1))\n return at\n }\n\n return {\n /** Buffer a chunk; true when a frame may now be complete and `next()` should run. */\n push(chunk: Buffer): boolean {\n if (chunk.length === 0)\n return false\n chunks.push(chunk)\n chunkBytes += chunk.length\n if (!newlineSeen && chunk.includes(NEWLINE))\n newlineSeen = true\n if (needBytes > 0)\n return buffer.length + chunkBytes >= needBytes\n return newlineSeen\n },\n /** Next complete message, or null when more bytes are needed. Throws on a malformed frame. */\n next(): { message: unknown } | null {\n if (chunks.length > 0) {\n buffer = Buffer.concat([buffer, ...chunks])\n chunks = []\n chunkBytes = 0\n }\n const parsed = readNextMessage(buffer, findHeaderEnd)\n if (parsed === null || 'needBytes' in parsed) {\n needBytes = parsed?.needBytes ?? 0\n newlineSeen = false\n return null\n }\n needBytes = 0\n consume(parsed.consumed)\n return { message: parsed.message }\n },\n /** Parse-error resync: drop through the first newline (everything when there is none). */\n dropThroughNewline(): void {\n const newline = buffer.indexOf(NEWLINE)\n consume(newline >= 0 ? newline + 1 : buffer.length)\n },\n }\n}\n\ntype ReadResult = { message: unknown, consumed: number } | { needBytes: number } | null\n\nfunction readNextMessage(input: Buffer<ArrayBufferLike>, findHeaderEnd: (input: Buffer<ArrayBufferLike>) => number): ReadResult {\n if (input.length === 0)\n return null\n\n const headerEnd = findHeaderEnd(input)\n if (headerEnd >= 0) {\n const header = input.subarray(0, headerEnd).toString('utf8')\n const match = /^Content-Length:\\s*(\\d+)/im.exec(header)\n if (!match)\n return readLineMessage(input)\n const length = Number(match[1])\n const bodyStart = headerEnd + 4\n const bodyEnd = bodyStart + length\n if (input.length < bodyEnd)\n return { needBytes: bodyEnd }\n const body = input.subarray(bodyStart, bodyEnd).toString('utf8')\n return { message: JSON.parse(body), consumed: bodyEnd }\n }\n\n if (/^Content-Length:/i.test(input.subarray(0, Math.min(input.length, 32)).toString('utf8')))\n return null\n\n return readLineMessage(input)\n}\n\nfunction readLineMessage(input: Buffer<ArrayBufferLike>): ReadResult {\n let offset = 0\n // Skip blank lines: NDJSON streams may contain stray newlines (e.g. a keep-\n // alive or a trailing separator). Emitting an error for those would be wrong.\n for (;;) {\n const lineEnd = input.indexOf(NEWLINE, offset)\n if (lineEnd < 0)\n return null\n const line = input.subarray(offset, lineEnd).toString('utf8').trim()\n offset = lineEnd + 1\n if (line.length === 0)\n continue\n return { message: JSON.parse(line), consumed: offset }\n }\n}\n\nfunction isResponse(message: unknown): boolean {\n return isObject(message) && 'id' in message && ('result' in message || 'error' in message)\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n"],"mappings":"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"}
|