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,412 @@
|
|
|
1
|
+
import { a as errorResponse, o as successResponse, r as createJsonRpcConnection } from "./json-rpc--HXQti1E.js";
|
|
2
|
+
import { D as legacySocketPath, O as probeSocket, c as IpcErrorCode, h as SIGNAL_SEQ_FIELD } from "./settings-keys-Ckf29NeM.js";
|
|
3
|
+
import { d as connectIpcClient, p as createPacedWriter, t as createHostDispatcher } from "./dispatcher-BMlu2BmZ.js";
|
|
4
|
+
import { Buffer } from "node:buffer";
|
|
5
|
+
import { chmodSync, existsSync, mkdirSync, unlinkSync } from "node:fs";
|
|
6
|
+
import { basename, delimiter, dirname } from "node:path";
|
|
7
|
+
import { userInfo } from "node:os";
|
|
8
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
9
|
+
import { createServer } from "node:net";
|
|
10
|
+
import process from "node:process";
|
|
11
|
+
function createRpcPeer(options) {
|
|
12
|
+
return {
|
|
13
|
+
ready: false,
|
|
14
|
+
watching: null,
|
|
15
|
+
send(signal, seq) {
|
|
16
|
+
const buffered = options.buffered();
|
|
17
|
+
const limit = options.highWatermark ?? 8388608;
|
|
18
|
+
if (buffered > limit) {
|
|
19
|
+
console.warn(`${options.label} peer buffered ${buffered} bytes (> ${limit}), closing the stuck connection`);
|
|
20
|
+
options.destroy();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
options.rpc()?.sendNotification("ipc.signal", seq === void 0 ? signal : {
|
|
25
|
+
...signal,
|
|
26
|
+
[SIGNAL_SEQ_FIELD]: seq
|
|
27
|
+
});
|
|
28
|
+
} catch {}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** The JSON-RPC handlers that route one peer's requests and notifications to the dispatcher. */
|
|
33
|
+
function dispatcherHandlers(dispatcher, peer) {
|
|
34
|
+
return {
|
|
35
|
+
onRequest: async (message) => {
|
|
36
|
+
const outcome = await dispatcher.handleRequest(message.method, message.params, peer);
|
|
37
|
+
return outcome.ok ? successResponse(message.id, outcome.result) : errorResponse(message.id, outcome.code, outcome.message, outcome.data);
|
|
38
|
+
},
|
|
39
|
+
onNotification: (message) => dispatcher.handleNotification(message.method, message.params, peer)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/ipc/transports/send-budget.ts
|
|
44
|
+
function isReply(message) {
|
|
45
|
+
return "id" in message && message.id !== void 0 && message.id !== null && ("result" in message || "error" in message);
|
|
46
|
+
}
|
|
47
|
+
function createPeerSend(target, limits) {
|
|
48
|
+
const { maxBuffered, maxMessage, log, label } = limits;
|
|
49
|
+
let replyReserve = 0;
|
|
50
|
+
let stuck = false;
|
|
51
|
+
const markStuck = (why) => {
|
|
52
|
+
if (stuck) return;
|
|
53
|
+
stuck = true;
|
|
54
|
+
limits.stuck(why);
|
|
55
|
+
};
|
|
56
|
+
const backlog = () => {
|
|
57
|
+
const buffered = target.buffered();
|
|
58
|
+
replyReserve = Math.min(replyReserve, buffered);
|
|
59
|
+
return buffered - replyReserve;
|
|
60
|
+
};
|
|
61
|
+
const send = (json, message) => {
|
|
62
|
+
if (stuck) return;
|
|
63
|
+
if (!isReply(message)) {
|
|
64
|
+
if (!target.write(json) || backlog() > maxBuffered) markStuck(`more than ${maxBuffered} bytes of signals unsent`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
let text = json;
|
|
68
|
+
let bytes = Buffer.byteLength(text);
|
|
69
|
+
if (bytes > maxMessage) {
|
|
70
|
+
const id = message.id;
|
|
71
|
+
log(`${label} reply to ${String(id)} is ${bytes} bytes (> ${maxMessage}): answering with an error instead`);
|
|
72
|
+
text = JSON.stringify(errorResponse(id, IpcErrorCode.ResponseTooLarge, `The reply is over ${maxMessage} bytes: ask for less (a transcript: a smaller page).`, {
|
|
73
|
+
bytes,
|
|
74
|
+
maxBytes: maxMessage
|
|
75
|
+
}));
|
|
76
|
+
bytes = Buffer.byteLength(text);
|
|
77
|
+
}
|
|
78
|
+
if (!target.write(text)) {
|
|
79
|
+
markStuck("reply dropped by the transport");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
replyReserve += bytes;
|
|
83
|
+
if (target.buffered() > maxBuffered + 2 * maxMessage) markStuck(`more than ${maxBuffered + 2 * maxMessage} bytes unsent`);
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
backlog,
|
|
87
|
+
send,
|
|
88
|
+
markStuck
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/ipc/daemon/server.ts
|
|
93
|
+
/**
|
|
94
|
+
* Largest reply on the socket by default. Generous: the peer is this user's
|
|
95
|
+
* own window on this machine, and whole-session reads (`sessions.get`) of a
|
|
96
|
+
* long local session with images must keep fitting. The bound is there so
|
|
97
|
+
* one reply cannot grow the write buffer without limit.
|
|
98
|
+
*/
|
|
99
|
+
const SOCKET_MAX_REPLY_BYTES = 268435456;
|
|
100
|
+
async function startIpcDaemon(options) {
|
|
101
|
+
const { socketPath } = options;
|
|
102
|
+
const log = options.onLog ?? (() => void 0);
|
|
103
|
+
const startedAt = Date.now();
|
|
104
|
+
const appVersion = options.appVersion ?? "dev";
|
|
105
|
+
const maxBuffered = options.maxBufferedBytes ?? 8388608;
|
|
106
|
+
const maxMessage = options.maxMessageBytes ?? SOCKET_MAX_REPLY_BYTES;
|
|
107
|
+
const connections = /* @__PURE__ */ new Set();
|
|
108
|
+
let idleTimer;
|
|
109
|
+
let retiring = false;
|
|
110
|
+
let retireTimer;
|
|
111
|
+
const shared = options.dispatcher;
|
|
112
|
+
const dispatcher = shared ?? await createHostDispatcher({
|
|
113
|
+
...options.createEnvironment ? { createEnvironment: options.createEnvironment } : {},
|
|
114
|
+
appVersion,
|
|
115
|
+
startedAt,
|
|
116
|
+
identity: { kind: "daemon" },
|
|
117
|
+
lifecycle: {
|
|
118
|
+
shutdown: () => {
|
|
119
|
+
close().then(() => options.onIdle?.());
|
|
120
|
+
},
|
|
121
|
+
retireWhenIdle,
|
|
122
|
+
isRetiring: () => retiring
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const host = dispatcher.host;
|
|
126
|
+
function retireWhenIdle() {
|
|
127
|
+
if (retiring) return;
|
|
128
|
+
retiring = true;
|
|
129
|
+
log("[ipc-daemon] a newer client attached mid-work; retiring once idle");
|
|
130
|
+
let idlePolls = 0;
|
|
131
|
+
retireTimer = setInterval(() => {
|
|
132
|
+
if (host.hasActiveWork()) {
|
|
133
|
+
idlePolls = 0;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
idlePolls += 1;
|
|
137
|
+
if (idlePolls < 2) return;
|
|
138
|
+
clearInterval(retireTimer);
|
|
139
|
+
close().then(() => options.onIdle?.());
|
|
140
|
+
}, 1e3);
|
|
141
|
+
}
|
|
142
|
+
function armIdleTimer() {
|
|
143
|
+
if (shared || !options.idleShutdownMs || !options.onIdle) return;
|
|
144
|
+
clearTimeout(idleTimer);
|
|
145
|
+
idleTimer = setTimeout(() => {
|
|
146
|
+
if (dispatcher.peerCount() > 0) return;
|
|
147
|
+
if (host.hasActiveWork()) {
|
|
148
|
+
armIdleTimer();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
options.onIdle?.();
|
|
152
|
+
}, options.idleShutdownMs);
|
|
153
|
+
}
|
|
154
|
+
function handleConnection(socket) {
|
|
155
|
+
let connection;
|
|
156
|
+
const writer = createPacedWriter(socket);
|
|
157
|
+
const budget = createPeerSend({
|
|
158
|
+
buffered: writer.buffered,
|
|
159
|
+
write: (json) => {
|
|
160
|
+
writer.write(`${json}\n`);
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
}, {
|
|
164
|
+
maxBuffered,
|
|
165
|
+
maxMessage,
|
|
166
|
+
log,
|
|
167
|
+
label: "[ipc-daemon]",
|
|
168
|
+
stuck: (why) => {
|
|
169
|
+
log(`[ipc-daemon] dropping peer: ${why}`);
|
|
170
|
+
socket.destroy();
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
const peer = createRpcPeer({
|
|
174
|
+
buffered: budget.backlog,
|
|
175
|
+
destroy: () => budget.markStuck("not reading"),
|
|
176
|
+
rpc: () => connection,
|
|
177
|
+
label: "[ipc-daemon]",
|
|
178
|
+
highWatermark: maxBuffered
|
|
179
|
+
});
|
|
180
|
+
const rpc = createJsonRpcConnection({
|
|
181
|
+
input: socket,
|
|
182
|
+
output: socket,
|
|
183
|
+
send: budget.send,
|
|
184
|
+
...dispatcherHandlers(dispatcher, peer),
|
|
185
|
+
onError: (err) => log(`[ipc-daemon] peer error: ${err.message}`)
|
|
186
|
+
});
|
|
187
|
+
connection = rpc;
|
|
188
|
+
const entry = {
|
|
189
|
+
socket,
|
|
190
|
+
connection: rpc
|
|
191
|
+
};
|
|
192
|
+
connections.add(entry);
|
|
193
|
+
dispatcher.addPeer(peer);
|
|
194
|
+
rpc.start();
|
|
195
|
+
log(`[ipc-daemon] peer connected (${dispatcher.peerCount()} total)`);
|
|
196
|
+
const drop = () => {
|
|
197
|
+
if (!connections.delete(entry)) return;
|
|
198
|
+
rpc.close();
|
|
199
|
+
dispatcher.removePeer(peer);
|
|
200
|
+
log(`[ipc-daemon] peer disconnected (${dispatcher.peerCount()} left)`);
|
|
201
|
+
if (dispatcher.peerCount() === 0) armIdleTimer();
|
|
202
|
+
};
|
|
203
|
+
socket.on("close", drop);
|
|
204
|
+
socket.on("error", drop);
|
|
205
|
+
}
|
|
206
|
+
if (existsSync(socketPath)) {
|
|
207
|
+
if (await probeSocket(socketPath)) throw new Error(`A zidane daemon is already listening on ${socketPath}.`);
|
|
208
|
+
if (await probeSocket(socketPath)) throw new Error(`A zidane daemon is already listening on ${socketPath}.`);
|
|
209
|
+
unlinkSync(socketPath);
|
|
210
|
+
}
|
|
211
|
+
const socketDir = dirname(socketPath);
|
|
212
|
+
const dedicatedSocketDir = basename(socketDir) === "daemon" || !existsSync(socketDir);
|
|
213
|
+
mkdirSync(socketDir, {
|
|
214
|
+
recursive: true,
|
|
215
|
+
mode: 448
|
|
216
|
+
});
|
|
217
|
+
if (dedicatedSocketDir) try {
|
|
218
|
+
chmodSync(socketDir, 448);
|
|
219
|
+
} catch {}
|
|
220
|
+
const server = createServer(handleConnection);
|
|
221
|
+
await new Promise((resolvePromise, reject) => {
|
|
222
|
+
server.once("error", reject);
|
|
223
|
+
server.listen(socketPath, () => {
|
|
224
|
+
server.off("error", reject);
|
|
225
|
+
resolvePromise();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
try {
|
|
229
|
+
chmodSync(socketPath, 384);
|
|
230
|
+
} catch {}
|
|
231
|
+
log(`[ipc-daemon] listening on ${socketPath}`);
|
|
232
|
+
let ownsSocketFile = true;
|
|
233
|
+
armIdleTimer();
|
|
234
|
+
const legacyPath = shared ? null : legacySocketPath(socketPath);
|
|
235
|
+
if (legacyPath) (async () => {
|
|
236
|
+
if (!await probeSocket(legacyPath)) return;
|
|
237
|
+
log(`[ipc-daemon] draining legacy daemon on ${legacyPath}`);
|
|
238
|
+
try {
|
|
239
|
+
const survivor = await connectIpcClient({
|
|
240
|
+
socketPath: legacyPath,
|
|
241
|
+
appVersion: `${appVersion}/legacy-drain`,
|
|
242
|
+
drainOnMismatch: true
|
|
243
|
+
});
|
|
244
|
+
await survivor.request("daemon.shutdown", {}).catch(() => void 0);
|
|
245
|
+
survivor.close();
|
|
246
|
+
} catch {}
|
|
247
|
+
})();
|
|
248
|
+
async function doClose() {
|
|
249
|
+
clearTimeout(idleTimer);
|
|
250
|
+
clearInterval(retireTimer);
|
|
251
|
+
if (!shared) await host.drain();
|
|
252
|
+
const stopped = new Promise((resolvePromise) => {
|
|
253
|
+
server.close(() => resolvePromise());
|
|
254
|
+
});
|
|
255
|
+
for (const { connection, socket } of connections) {
|
|
256
|
+
connection.close();
|
|
257
|
+
socket.destroy();
|
|
258
|
+
}
|
|
259
|
+
connections.clear();
|
|
260
|
+
if (!shared) dispatcher.detachAll();
|
|
261
|
+
await stopped;
|
|
262
|
+
if (ownsSocketFile) {
|
|
263
|
+
ownsSocketFile = false;
|
|
264
|
+
try {
|
|
265
|
+
unlinkSync(socketPath);
|
|
266
|
+
} catch {}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
let closePromise = null;
|
|
270
|
+
function close() {
|
|
271
|
+
closePromise ??= doClose();
|
|
272
|
+
return closePromise;
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
socketPath,
|
|
276
|
+
host,
|
|
277
|
+
peerCount: () => dispatcher.peerCount(),
|
|
278
|
+
close
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/ipc/daemon/shell-path.ts
|
|
283
|
+
/**
|
|
284
|
+
* Login-shell PATH for processes not started from a terminal.
|
|
285
|
+
*
|
|
286
|
+
* A Dock/Finder-launched GUI, or a daemon it spawns, inherits launchd's PATH
|
|
287
|
+
* (`/usr/bin:/bin:/usr/sbin:/sbin`), so `node` / `bun` / `yarn` are invisible
|
|
288
|
+
* to agent shell commands. Ask the user's login shell for its PATH and merge
|
|
289
|
+
* it into `process.env.PATH`.
|
|
290
|
+
*
|
|
291
|
+
* Merge, don't replace: a terminal launch may have prepended entries the rc
|
|
292
|
+
* files know nothing about (`nvm use`, direnv, `PATH=... zidane`), and those
|
|
293
|
+
* must survive. Idempotent, so every surface (GUI, daemon) can call it and a
|
|
294
|
+
* daemon spawned by an already-fixed GUI ends up with the same PATH.
|
|
295
|
+
*/
|
|
296
|
+
const DELIMITER = "_ZIDANE_SHELL_ENV_";
|
|
297
|
+
/** A slow rc file costs startup time; a prompting one must never hang the process. */
|
|
298
|
+
const DEFAULT_TIMEOUT_MS = 3e3;
|
|
299
|
+
function defaultShell(env) {
|
|
300
|
+
try {
|
|
301
|
+
const { shell } = userInfo();
|
|
302
|
+
if (shell) return shell;
|
|
303
|
+
} catch {}
|
|
304
|
+
return env.SHELL || (process.platform === "darwin" ? "/bin/zsh" : "/bin/sh");
|
|
305
|
+
}
|
|
306
|
+
function parsePath(stdout) {
|
|
307
|
+
const body = stdout.split(DELIMITER)[1];
|
|
308
|
+
if (body === void 0) return void 0;
|
|
309
|
+
const clean = body.replace(/\u001B\[[0-9;]*[A-Z]/gi, "");
|
|
310
|
+
for (const line of clean.split("\n")) if (line.startsWith("PATH=")) return line.slice(5) || void 0;
|
|
311
|
+
}
|
|
312
|
+
const SHELL_ARGS = ["-ilc", `echo -n "${DELIMITER}"; command env; echo -n "${DELIMITER}"; exit`];
|
|
313
|
+
function shellCandidates(options) {
|
|
314
|
+
const env = options.env ?? process.env;
|
|
315
|
+
return {
|
|
316
|
+
shells: options.shell ? [options.shell] : [.../* @__PURE__ */ new Set([
|
|
317
|
+
defaultShell(env),
|
|
318
|
+
"/bin/zsh",
|
|
319
|
+
"/bin/bash"
|
|
320
|
+
])],
|
|
321
|
+
timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
322
|
+
env: {
|
|
323
|
+
...env,
|
|
324
|
+
DISABLE_AUTO_UPDATE: "true",
|
|
325
|
+
ZSH_TMUX_AUTOSTARTED: "true",
|
|
326
|
+
ZSH_TMUX_AUTOSTART: "false"
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
function shellPath(options = {}) {
|
|
331
|
+
if (process.platform === "win32") return void 0;
|
|
332
|
+
const { shells, env, timeout } = shellCandidates(options);
|
|
333
|
+
for (const shell of shells) {
|
|
334
|
+
const result = spawnSync(shell, SHELL_ARGS, {
|
|
335
|
+
encoding: "utf8",
|
|
336
|
+
timeout,
|
|
337
|
+
stdio: [
|
|
338
|
+
"ignore",
|
|
339
|
+
"pipe",
|
|
340
|
+
"ignore"
|
|
341
|
+
],
|
|
342
|
+
env
|
|
343
|
+
});
|
|
344
|
+
if (result.error || result.status !== 0) continue;
|
|
345
|
+
const path = parsePath(result.stdout);
|
|
346
|
+
if (path) return path;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* {@link shellPath} without blocking the event loop: same shells, args,
|
|
351
|
+
* timeout and parsing, run with `spawn`. For hosts (the GUI main
|
|
352
|
+
* process) that can start on a cached PATH and refresh in the background.
|
|
353
|
+
*/
|
|
354
|
+
async function shellPathAsync(options = {}) {
|
|
355
|
+
if (process.platform === "win32") return void 0;
|
|
356
|
+
const { shells, env, timeout } = shellCandidates(options);
|
|
357
|
+
for (const shell of shells) {
|
|
358
|
+
const stdout = await new Promise((resolve) => {
|
|
359
|
+
const child = spawn(shell, SHELL_ARGS, {
|
|
360
|
+
stdio: [
|
|
361
|
+
"ignore",
|
|
362
|
+
"pipe",
|
|
363
|
+
"ignore"
|
|
364
|
+
],
|
|
365
|
+
env
|
|
366
|
+
});
|
|
367
|
+
let out = "";
|
|
368
|
+
let settled = false;
|
|
369
|
+
let timer;
|
|
370
|
+
const finish = (value) => {
|
|
371
|
+
if (settled) return;
|
|
372
|
+
settled = true;
|
|
373
|
+
clearTimeout(timer);
|
|
374
|
+
resolve(value);
|
|
375
|
+
};
|
|
376
|
+
timer = setTimeout(() => {
|
|
377
|
+
child.kill("SIGTERM");
|
|
378
|
+
finish(void 0);
|
|
379
|
+
}, timeout);
|
|
380
|
+
child.stdout?.setEncoding("utf8");
|
|
381
|
+
child.stdout?.on("data", (chunk) => {
|
|
382
|
+
out += chunk;
|
|
383
|
+
});
|
|
384
|
+
child.on("error", () => finish(void 0));
|
|
385
|
+
child.on("close", (code) => finish(code === 0 ? out : void 0));
|
|
386
|
+
});
|
|
387
|
+
if (stdout === void 0) continue;
|
|
388
|
+
const path = parsePath(stdout);
|
|
389
|
+
if (path) return path;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Entries of `current` the shell doesn't know about (ad-hoc prepends from the
|
|
394
|
+
* launching terminal) stay in front; then the shell's PATH in its own order.
|
|
395
|
+
* From the Dock every launchd entry is already in the shell PATH, so the
|
|
396
|
+
* result is exactly the shell PATH, with the shell's precedence intact.
|
|
397
|
+
*/
|
|
398
|
+
function mergePath(current, shell) {
|
|
399
|
+
const split = (path) => (path ?? "").split(delimiter).filter(Boolean);
|
|
400
|
+
const fromShell = split(shell);
|
|
401
|
+
const known = new Set(fromShell);
|
|
402
|
+
return [.../* @__PURE__ */ new Set([...split(current).filter((entry) => !known.has(entry)), ...fromShell])].join(delimiter);
|
|
403
|
+
}
|
|
404
|
+
/** Merge the login shell's PATH into `process.env.PATH`. No-op on Windows or when no shell answers. */
|
|
405
|
+
function fixPath() {
|
|
406
|
+
const extra = shellPath();
|
|
407
|
+
if (extra) process.env.PATH = mergePath(process.env.PATH, extra);
|
|
408
|
+
}
|
|
409
|
+
//#endregion
|
|
410
|
+
export { startIpcDaemon as a, shellPathAsync as i, mergePath as n, shellPath as r, fixPath as t };
|
|
411
|
+
|
|
412
|
+
//# sourceMappingURL=shell-path-Dqaoow2J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-path-Dqaoow2J.js","names":[],"sources":["../src/ipc/transports/peer-rpc.ts","../src/ipc/transports/send-budget.ts","../src/ipc/daemon/server.ts","../src/ipc/daemon/shell-path.ts"],"sourcesContent":["/**\n * The host side of one JSON-RPC connection, for every wire transport (the\n * unix socket in `../daemon/server.ts`, the WebSocket in `./ws-server.ts`):\n * a dispatcher {@link HostPeer} whose signals go out as `ipc.signal`\n * notifications with a write-backpressure bound, and the request /\n * notification handlers that hand incoming messages to the dispatcher.\n * Framing stays with the transport.\n */\nimport type { JsonRpcConnectionOptions } from '../../acp/json-rpc'\nimport type { AcpPeer, JsonRpcRequest, JsonRpcResponse } from '../../acp/types'\nimport type { HostDispatcher, HostPeer } from '../daemon/dispatcher'\nimport { errorResponse, successResponse } from '../../acp/json-rpc'\nimport { SIGNAL_SEQ_FIELD } from '../protocol'\n\n/**\n * Per-peer write backpressure bound. A wedged peer (e.g. a SIGSTOP'd\n * terminal) stops reading, so fan-out writes pile up in the transport's\n * send buffer without bound and can OOM the host. A peer buffering more\n * than this is dropped: the protocol supports re-attach + backfill, so\n * killing a wedged peer is safe and self-healing.\n */\nexport const PEER_WRITE_HIGH_WATERMARK = 8 * 1024 * 1024\n\nexport interface RpcPeerOptions {\n /** Bytes written to the peer but not yet sent. */\n buffered: () => number\n /** Tear the connection down (its close handler removes the peer). */\n destroy: () => void\n /** The connection's JSON-RPC side; signals are dropped until it exists. */\n rpc: () => Pick<AcpPeer, 'sendNotification'> | undefined\n /** Log prefix, e.g. `[ipc-daemon]`. */\n label: string\n /** Drop the peer past this many buffered bytes. Default {@link PEER_WRITE_HIGH_WATERMARK}. */\n highWatermark?: number\n}\n\nexport function createRpcPeer(options: RpcPeerOptions): HostPeer {\n return {\n ready: false,\n watching: null,\n send(signal, seq) {\n const buffered = options.buffered()\n const limit = options.highWatermark ?? PEER_WRITE_HIGH_WATERMARK\n if (buffered > limit) {\n console.warn(`${options.label} peer buffered ${buffered} bytes (> ${limit}), closing the stuck connection`)\n options.destroy()\n return\n }\n try {\n options.rpc()?.sendNotification('ipc.signal', seq === undefined ? signal : { ...signal, [SIGNAL_SEQ_FIELD]: seq })\n }\n catch {\n // A dying connection (or a signal JSON can't encode) must never take the host down with it.\n }\n },\n }\n}\n\n/** The JSON-RPC handlers that route one peer's requests and notifications to the dispatcher. */\nexport function dispatcherHandlers(dispatcher: HostDispatcher, peer: HostPeer): Pick<JsonRpcConnectionOptions, 'onRequest' | 'onNotification'> {\n return {\n onRequest: async (message: JsonRpcRequest): Promise<JsonRpcResponse> => {\n const outcome = await dispatcher.handleRequest(message.method, message.params, peer)\n return outcome.ok\n ? successResponse(message.id, outcome.result)\n : errorResponse(message.id, outcome.code, outcome.message, outcome.data)\n },\n onNotification: message => dispatcher.handleNotification(message.method, message.params, peer),\n }\n}\n","/**\n * One connection's outgoing budget, for every wire transport (the unix\n * socket in `../daemon/server.ts`, the WebSocket in `./ws-server.ts`).\n *\n * The slow-consumer bound is about pushed signals piling up for a peer that\n * stopped reading, not about one big reply it asked for: reply bytes still\n * queued are set aside (`replyReserve`) when the backlog is measured. The\n * buffer drains in order, so the reserve can only shrink to what is still\n * buffered; a peer that never reads keeps it whole and is dropped once the\n * signals behind it pass the bound. A reply itself is bounded by the message\n * size (over it, an `IpcErrorCode.ResponseTooLarge` error goes instead and\n * the connection stays), and the whole buffer by a hard cap for memory.\n *\n * The reserve is an approximation: it assumes the buffer drains oldest\n * first and only clamps it to what is still buffered, so after a partial\n * drain it may still count reply bytes that already left, and the signals\n * backlog reads low by at most that much. The memory bound, precisely: a\n * reply leaves the whole buffer at most `H = maxBuffered + 2 × maxMessage`\n * (checked after its write), and every signal re-clamps the reserve to what\n * is buffered, so the reserve never exceeds what the buffer held at the\n * first signal after the last reply (at most `H` plus that signal). A\n * signal leaves the measured backlog at most `maxBuffered`, so between\n * sends a peer holds at most `maxBuffered + H = 2 × maxBuffered + 2 ×\n * maxMessage` bytes (plus one signal). The write that crosses a bound is\n * the last: the peer is marked stuck and nothing more goes out.\n */\nimport type { JsonRpcMessage } from '../../acp/types'\nimport { Buffer } from 'node:buffer'\nimport { errorResponse } from '../../acp/json-rpc'\nimport { IpcErrorCode } from '../protocol'\n\n/** What the budget writes to: the transport's buffer and its framing. */\nexport interface SendTarget {\n /** Bytes written but not yet handed to the OS. */\n buffered: () => number\n /** Write one serialized message (the target frames it); `false`: the transport dropped it. */\n write: (json: string) => boolean\n}\n\nexport interface SendLimits {\n /** Signals backlog past which the peer is stuck (replies set aside). */\n maxBuffered: number\n /** Largest reply; a bigger one is answered with `ResponseTooLarge`. */\n maxMessage: number\n /** The peer cannot keep up: tear it down (called once). */\n stuck: (why: string) => void\n log: (line: string) => void\n /** Log prefix, e.g. `[ipc-ws]`. */\n label: string\n}\n\nexport interface PeerSend {\n /** Bytes buffered that are not reply bytes: what the slow-consumer bound measures. */\n backlog: () => number\n /** Send one message (the JSON-RPC endpoint's `send`): replies and the rest apart. */\n send: (json: string, message: JsonRpcMessage) => void\n /** Give up on the peer (once): {@link SendLimits.stuck} runs and nothing more goes out. */\n markStuck: (why: string) => void\n}\n\nfunction isReply(message: JsonRpcMessage): boolean {\n return 'id' in message && message.id !== undefined && message.id !== null && ('result' in message || 'error' in message)\n}\n\nexport function createPeerSend(target: SendTarget, limits: SendLimits): PeerSend {\n const { maxBuffered, maxMessage, log, label } = limits\n let replyReserve = 0\n let stuck = false\n const markStuck = (why: string): void => {\n if (stuck)\n return\n stuck = true\n limits.stuck(why)\n }\n const backlog = (): number => {\n const buffered = target.buffered()\n replyReserve = Math.min(replyReserve, buffered)\n return buffered - replyReserve\n }\n const send = (json: string, message: JsonRpcMessage): void => {\n if (stuck)\n return\n if (!isReply(message)) {\n if (!target.write(json) || backlog() > maxBuffered)\n markStuck(`more than ${maxBuffered} bytes of signals unsent`)\n return\n }\n let text = json\n let bytes = Buffer.byteLength(text)\n if (bytes > maxMessage) {\n const id = (message as { id: string | number }).id\n log(`${label} reply to ${String(id)} is ${bytes} bytes (> ${maxMessage}): answering with an error instead`)\n text = JSON.stringify(errorResponse(id, IpcErrorCode.ResponseTooLarge, `The reply is over ${maxMessage} bytes: ask for less (a transcript: a smaller page).`, { bytes, maxBytes: maxMessage }))\n bytes = Buffer.byteLength(text)\n }\n if (!target.write(text)) {\n markStuck('reply dropped by the transport')\n return\n }\n replyReserve += bytes\n if (target.buffered() > maxBuffered + 2 * maxMessage)\n markStuck(`more than ${maxBuffered + 2 * maxMessage} bytes unsent`)\n }\n return { backlog, send, markStuck }\n}\n","/**\n * Unix-socket JSON-RPC server around a `ChatHost`.\n *\n * One `net.Server`, one JSON-RPC connection per peer (NDJSON framing: a\n * `net.Socket` is both the Readable and the Writable). The method table,\n * per-peer state, signal fan-out and the `ipc.hello` handshake live in the\n * transport-free dispatcher (`./dispatcher`); this module owns only what is\n * specific to the socket and the process: framing, the socket file and its\n * permissions, idle exit, retiring, and draining. Write backpressure (the\n * slow-consumer bound, the reply size) is shared with the WebSocket server\n * (`../transports/send-budget`).\n *\n * Handshake: a peer's first request MUST be `ipc.hello` carrying its\n * protocol version. Mismatched peers get a structured error (code\n * `VERSION_MISMATCH`) and can ask the daemon to drain via `daemon.shutdown`\n * before respawning a fresh one.\n */\nimport type { Server, Socket } from 'node:net'\nimport type { JsonRpcConnection } from '../../acp/json-rpc'\nimport type { ChatHost } from '../../chat/host/engine'\nimport type { HostSignal } from '../protocol'\nimport type { HostDispatcher } from './dispatcher'\nimport type { DaemonEnvironment } from './environment'\nimport { chmodSync, existsSync, mkdirSync, unlinkSync } from 'node:fs'\nimport { createServer } from 'node:net'\nimport { basename, dirname } from 'node:path'\nimport { createJsonRpcConnection } from '../../acp/json-rpc'\nimport { connectIpcClient } from '../client'\nimport { createPacedWriter } from '../transports/paced-writer'\nimport { createRpcPeer, dispatcherHandlers, PEER_WRITE_HIGH_WATERMARK } from '../transports/peer-rpc'\nimport { createPeerSend } from '../transports/send-budget'\nimport { createHostDispatcher } from './dispatcher'\nimport { legacySocketPath, probeSocket } from './lifecycle'\n\n// Canonical home is the protocol module (clients import the codes without\n// pulling the server's module graph); re-exported here for compatibility.\nexport { IpcErrorCode } from '../protocol'\n\nexport interface IpcDaemonOptions {\n socketPath: string\n /**\n * Environment factory — the production daemon uses the disk-backed\n * `createDaemonEnvironment`; tests inject an in-memory one. Receives the\n * broadcast sink wired to peer fan-out.\n */\n createEnvironment?: (broadcast: (signal: HostSignal) => void) => DaemonEnvironment | Promise<DaemonEnvironment>\n appVersion?: string\n /**\n * Called when the daemon has had zero peers for `idleShutdownMs` and no\n * session is running. The CLI exits the process; embedded servers ignore.\n */\n idleShutdownMs?: number\n onIdle?: () => void\n onLog?: (line: string) => void\n /**\n * Serve this already-built host instead of creating one: another front-end\n * (zidane-server's WebSocket) serves it too. Its owner drains it and owns\n * its lifecycle, so `createEnvironment`, `appVersion` and the idle options\n * are ignored, and `close()` only closes this socket's connections.\n */\n dispatcher?: HostDispatcher\n /**\n * A peer with more than this of signals queued for sending (it stopped\n * reading) is dropped; it re-attaches and resumes. Replies are bounded by\n * `maxMessageBytes` instead (`../transports/send-budget`). Default\n * `PEER_WRITE_HIGH_WATERMARK` (8 MiB).\n */\n maxBufferedBytes?: number\n /** A bigger reply goes out as an `IpcErrorCode.ResponseTooLarge` error. Default {@link SOCKET_MAX_REPLY_BYTES}. */\n maxMessageBytes?: number\n}\n\n/**\n * Largest reply on the socket by default. Generous: the peer is this user's\n * own window on this machine, and whole-session reads (`sessions.get`) of a\n * long local session with images must keep fitting. The bound is there so\n * one reply cannot grow the write buffer without limit.\n */\nconst SOCKET_MAX_REPLY_BYTES = 256 * 1024 * 1024\n\nexport interface IpcDaemon {\n socketPath: string\n host: ChatHost\n peerCount: () => number\n close: () => Promise<void>\n}\n\n/** One open socket connection; `close()` ends them all. */\ninterface SocketConnection {\n socket: Socket\n connection: JsonRpcConnection\n}\n\nexport async function startIpcDaemon(options: IpcDaemonOptions): Promise<IpcDaemon> {\n const { socketPath } = options\n const log = options.onLog ?? (() => undefined)\n const startedAt = Date.now()\n const appVersion = options.appVersion ?? 'dev'\n const maxBuffered = options.maxBufferedBytes ?? PEER_WRITE_HIGH_WATERMARK\n const maxMessage = options.maxMessageBytes ?? SOCKET_MAX_REPLY_BYTES\n\n const connections = new Set<SocketConnection>()\n let idleTimer: ReturnType<typeof setTimeout> | undefined\n // See `retireWhenIdle`.\n let retiring = false\n let retireTimer: ReturnType<typeof setInterval> | undefined\n\n const shared = options.dispatcher\n const dispatcher = shared ?? await createHostDispatcher({\n ...(options.createEnvironment ? { createEnvironment: options.createEnvironment } : {}),\n appVersion,\n startedAt,\n identity: { kind: 'daemon' },\n lifecycle: {\n shutdown: () => {\n void close().then(() => options.onIdle?.())\n },\n retireWhenIdle,\n isRetiring: () => retiring,\n },\n })\n const host = dispatcher.host\n\n /* ----------------------------------------------------------------------\n * Socket plumbing\n * -------------------------------------------------------------------- */\n\n /*\n * Retire-when-idle: a NEWER client found this daemon mid-work. Draining\n * now would abort every window's runs (a dev edit under `src/ipc` or an\n * upgrade mid-`/review` did exactly that), so keep serving and exit at\n * the first idle point. Two consecutive idle polls: a queue drain is\n * scheduled just after a dispatch releases, and one poll could land in\n * that gap.\n */\n function retireWhenIdle(): void {\n if (retiring)\n return\n retiring = true\n log('[ipc-daemon] a newer client attached mid-work; retiring once idle')\n let idlePolls = 0\n retireTimer = setInterval(() => {\n if (host.hasActiveWork()) {\n idlePolls = 0\n return\n }\n idlePolls += 1\n if (idlePolls < 2)\n return\n clearInterval(retireTimer)\n void close().then(() => options.onIdle?.())\n }, 1000)\n }\n\n function armIdleTimer(): void {\n if (shared || !options.idleShutdownMs || !options.onIdle)\n return\n clearTimeout(idleTimer)\n idleTimer = setTimeout(() => {\n if (dispatcher.peerCount() > 0)\n return // Peers reconnected — the next last-disconnect re-arms.\n /*\n * Never abort a live run just because every window detached — `/exit`\n * is explicitly \"the run keeps going\". Re-arm and check again later.\n */\n if (host.hasActiveWork()) {\n armIdleTimer()\n return\n }\n options.onIdle?.()\n }, options.idleShutdownMs)\n }\n\n function handleConnection(socket: Socket): void {\n // Assigned right below; a signal can only reach this peer after `ipc.hello`, i.e. once it is set.\n let connection: JsonRpcConnection | undefined\n const writer = createPacedWriter(socket)\n const budget = createPeerSend(\n {\n buffered: writer.buffered,\n // NDJSON: `JSON.stringify` escapes newlines, so a message is one line.\n write: (json) => {\n writer.write(`${json}\\n`)\n return true\n },\n },\n {\n maxBuffered,\n maxMessage,\n log,\n label: '[ipc-daemon]',\n stuck: (why) => {\n log(`[ipc-daemon] dropping peer: ${why}`)\n socket.destroy()\n },\n },\n )\n const peer = createRpcPeer({\n buffered: budget.backlog,\n destroy: () => budget.markStuck('not reading'),\n rpc: () => connection,\n label: '[ipc-daemon]',\n highWatermark: maxBuffered,\n })\n\n const rpc = createJsonRpcConnection({\n input: socket,\n output: socket,\n send: budget.send,\n ...dispatcherHandlers(dispatcher, peer),\n onError: err => log(`[ipc-daemon] peer error: ${err.message}`),\n })\n\n connection = rpc\n const entry: SocketConnection = { socket, connection: rpc }\n connections.add(entry)\n dispatcher.addPeer(peer)\n rpc.start()\n log(`[ipc-daemon] peer connected (${dispatcher.peerCount()} total)`)\n\n const drop = (): void => {\n if (!connections.delete(entry))\n return\n rpc.close()\n dispatcher.removePeer(peer)\n log(`[ipc-daemon] peer disconnected (${dispatcher.peerCount()} left)`)\n if (dispatcher.peerCount() === 0)\n armIdleTimer()\n }\n\n socket.on('close', drop)\n socket.on('error', drop)\n }\n\n /*\n * Stale-socket recovery: a previous daemon that died without cleanup\n * leaves the socket file behind and `listen` would fail EADDRINUSE.\n * Probe before unlinking so a LIVE daemon is never yanked out from\n * under its peers.\n */\n if (existsSync(socketPath)) {\n if (await probeSocket(socketPath))\n throw new Error(`A zidane daemon is already listening on ${socketPath}.`)\n /*\n * Narrow the concurrent-spawn race: another daemon may have bound the\n * socket between the probe above and the unlink below (each probe is a\n * full connect attempt). Re-probe immediately before unlinking and\n * abort startup if something now answers — never yank a live daemon's\n * socket out from under its peers.\n */\n if (await probeSocket(socketPath))\n throw new Error(`A zidane daemon is already listening on ${socketPath}.`)\n unlinkSync(socketPath)\n }\n /*\n * The daemon speaks an unauthenticated RPC surface that can execute tools\n * as the daemon user — restrict access to the owner. The containing dir\n * is created 0700 (belt) and the socket is chmod'd to 0600 right after\n * `listen` (suspenders) so connectability never depends on ambient umask.\n *\n * `mkdirSync`'s mode only applies on CREATION — a pre-existing dir keeps\n * its old mode. When the dir is the DEDICATED daemon dir (the `daemon/`\n * subdir `defaultSocketPath` uses, or one we created fresh for an\n * explicit socket path) chmod it 0700 explicitly. A shared, pre-existing\n * dir (tests pointing the socket at a tmpdir) is left alone — never\n * tighten a directory that also holds unrelated state.\n */\n const socketDir = dirname(socketPath)\n const dedicatedSocketDir = basename(socketDir) === 'daemon' || !existsSync(socketDir)\n mkdirSync(socketDir, { recursive: true, mode: 0o700 })\n if (dedicatedSocketDir) {\n try {\n chmodSync(socketDir, 0o700)\n }\n catch {\n // Best-effort — mirrors the socket chmod below.\n }\n }\n\n const server: Server = createServer(handleConnection)\n await new Promise<void>((resolvePromise, reject) => {\n server.once('error', reject)\n server.listen(socketPath, () => {\n server.off('error', reject)\n resolvePromise()\n })\n })\n try {\n chmodSync(socketPath, 0o600)\n }\n catch {\n // Best-effort on platforms where socket chmod is a no-op (e.g. some\n // network filesystems); the 0700 dir still constrains access.\n }\n log(`[ipc-daemon] listening on ${socketPath}`)\n // We bound the socket, so we own the file — close() unlinks it exactly\n // once. Cleared after the unlink so a file later re-created by a NEW\n // daemon on the same path is never yanked by a stale close.\n let ownsSocketFile = true\n armIdleTimer()\n\n /*\n * One-time v6 migration: drain any daemon still serving the pre-v6\n * socket path (`<stateDir>/daemon.sock`). New clients never probe it,\n * so a `--idle-exit 0` service daemon there would run forever alongside\n * this one — two sets of live agents, run guards, and heartbeat writers\n * against the same sessions.db. Fire-and-forget: version mismatch is\n * the EXPECTED case (a legacy daemon speaks an older protocol) and\n * `drainOnMismatch: true` performs the shutdown for us; a same-version\n * survivor (explicit env overrides) gets an explicit daemon.shutdown.\n */\n const legacyPath = shared ? null : legacySocketPath(socketPath)\n if (legacyPath) {\n void (async () => {\n if (!(await probeSocket(legacyPath)))\n return\n log(`[ipc-daemon] draining legacy daemon on ${legacyPath}`)\n try {\n const survivor = await connectIpcClient({ socketPath: legacyPath, appVersion: `${appVersion}/legacy-drain`, drainOnMismatch: true })\n await survivor.request('daemon.shutdown', {}).catch(() => undefined)\n survivor.close()\n }\n catch {\n // IpcVersionMismatchError = drained by the handshake path; anything\n // else (raced exit, wedged socket) is best-effort — leave it.\n }\n })()\n }\n\n async function doClose(): Promise<void> {\n clearTimeout(idleTimer)\n clearInterval(retireTimer)\n // A shared host is its owner's to drain and detach (see `dispatcher`).\n if (!shared)\n await host.drain()\n // Stop accepting before closing what is open: a connection landing in\n // between would otherwise keep `server.close` waiting forever.\n const stopped = new Promise<void>((resolvePromise) => {\n server.close(() => resolvePromise())\n })\n for (const { connection, socket } of connections) {\n connection.close()\n socket.destroy()\n }\n connections.clear()\n if (!shared)\n dispatcher.detachAll()\n await stopped\n if (ownsSocketFile) {\n ownsSocketFile = false\n try {\n unlinkSync(socketPath)\n }\n catch {\n // already gone\n }\n }\n }\n\n /*\n * Idempotent close: `daemon.shutdown` runs close() and then onIdle, whose\n * CLI implementation calls daemon.close() again — both callers share one\n * drain instead of double-unlinking the socket. Memoized rather than\n * flag-guarded so the second caller awaits actual completion.\n */\n let closePromise: Promise<void> | null = null\n function close(): Promise<void> {\n closePromise ??= doClose()\n return closePromise\n }\n\n return {\n socketPath,\n host,\n peerCount: () => dispatcher.peerCount(),\n close,\n }\n}\n","/**\n * Login-shell PATH for processes not started from a terminal.\n *\n * A Dock/Finder-launched GUI, or a daemon it spawns, inherits launchd's PATH\n * (`/usr/bin:/bin:/usr/sbin:/sbin`), so `node` / `bun` / `yarn` are invisible\n * to agent shell commands. Ask the user's login shell for its PATH and merge\n * it into `process.env.PATH`.\n *\n * Merge, don't replace: a terminal launch may have prepended entries the rc\n * files know nothing about (`nvm use`, direnv, `PATH=... zidane`), and those\n * must survive. Idempotent, so every surface (GUI, daemon) can call it and a\n * daemon spawned by an already-fixed GUI ends up with the same PATH.\n */\nimport { spawn, spawnSync } from 'node:child_process'\nimport { userInfo } from 'node:os'\nimport { delimiter } from 'node:path'\nimport process from 'node:process'\n\nconst DELIMITER = '_ZIDANE_SHELL_ENV_'\n\n/** A slow rc file costs startup time; a prompting one must never hang the process. */\nconst DEFAULT_TIMEOUT_MS = 3_000\n\nfunction defaultShell(env: NodeJS.ProcessEnv): string {\n try {\n const { shell } = userInfo()\n if (shell)\n return shell\n }\n catch {}\n return env.SHELL || (process.platform === 'darwin' ? '/bin/zsh' : '/bin/sh')\n}\n\nfunction parsePath(stdout: string): string | undefined {\n const body = stdout.split(DELIMITER)[1]\n if (body === undefined)\n return undefined\n // eslint-disable-next-line no-control-regex\n const clean = body.replace(/\\u001B\\[[0-9;]*[A-Z]/gi, '')\n for (const line of clean.split('\\n')) {\n if (line.startsWith('PATH='))\n return line.slice('PATH='.length) || undefined\n }\n return undefined\n}\n\n/**\n * PATH as seen by an interactive login shell, or `undefined` when no shell\n * answers in time. Tries the user's shell first, then POSIX fallbacks for\n * non-POSIX defaults (nushell, xonsh) whose `-ilc` differs. An explicit\n * `shell` is tried alone.\n */\nexport interface ShellPathOptions { env?: NodeJS.ProcessEnv, timeoutMs?: number, shell?: string }\n\n// `command env` sidesteps aliases/functions named `env`.\nconst SHELL_ARGS = ['-ilc', `echo -n \"${DELIMITER}\"; command env; echo -n \"${DELIMITER}\"; exit`]\n\nfunction shellCandidates(options: ShellPathOptions): { shells: string[], env: NodeJS.ProcessEnv, timeout: number } {\n const env = options.env ?? process.env\n return {\n shells: options.shell ? [options.shell] : [...new Set([defaultShell(env), '/bin/zsh', '/bin/bash'])],\n timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n env: {\n ...env,\n // Keep oh-my-zsh from blocking on its update prompt / tmux autostart.\n DISABLE_AUTO_UPDATE: 'true',\n ZSH_TMUX_AUTOSTARTED: 'true',\n ZSH_TMUX_AUTOSTART: 'false',\n },\n }\n}\n\nexport function shellPath(options: ShellPathOptions = {}): string | undefined {\n if (process.platform === 'win32')\n return undefined\n const { shells, env, timeout } = shellCandidates(options)\n for (const shell of shells) {\n const result = spawnSync(shell, SHELL_ARGS, {\n encoding: 'utf8',\n timeout,\n stdio: ['ignore', 'pipe', 'ignore'],\n env,\n })\n if (result.error || result.status !== 0)\n continue\n const path = parsePath(result.stdout)\n if (path)\n return path\n }\n return undefined\n}\n\n/**\n * {@link shellPath} without blocking the event loop: same shells, args,\n * timeout and parsing, run with `spawn`. For hosts (the GUI main\n * process) that can start on a cached PATH and refresh in the background.\n */\nexport async function shellPathAsync(options: ShellPathOptions = {}): Promise<string | undefined> {\n if (process.platform === 'win32')\n return undefined\n const { shells, env, timeout } = shellCandidates(options)\n for (const shell of shells) {\n const stdout = await new Promise<string | undefined>((resolve) => {\n // Same stdio as the sync variant: no stdin, stderr discarded.\n const child = spawn(shell, SHELL_ARGS, { stdio: ['ignore', 'pipe', 'ignore'], env })\n let out = ''\n let settled = false\n let timer: ReturnType<typeof setTimeout> | undefined\n const finish = (value: string | undefined): void => {\n if (settled)\n return\n settled = true\n clearTimeout(timer)\n resolve(value)\n }\n timer = setTimeout(() => {\n child.kill('SIGTERM')\n finish(undefined)\n }, timeout)\n child.stdout?.setEncoding('utf8')\n child.stdout?.on('data', (chunk: string) => {\n out += chunk\n })\n child.on('error', () => finish(undefined))\n child.on('close', code => finish(code === 0 ? out : undefined))\n })\n if (stdout === undefined)\n continue\n const path = parsePath(stdout)\n if (path)\n return path\n }\n return undefined\n}\n\n/**\n * Entries of `current` the shell doesn't know about (ad-hoc prepends from the\n * launching terminal) stay in front; then the shell's PATH in its own order.\n * From the Dock every launchd entry is already in the shell PATH, so the\n * result is exactly the shell PATH, with the shell's precedence intact.\n */\nexport function mergePath(current: string | undefined, shell: string | undefined): string {\n const split = (path: string | undefined): string[] => (path ?? '').split(delimiter).filter(Boolean)\n const fromShell = split(shell)\n const known = new Set(fromShell)\n return [...new Set([...split(current).filter(entry => !known.has(entry)), ...fromShell])].join(delimiter)\n}\n\n/** Merge the login shell's PATH into `process.env.PATH`. No-op on Windows or when no shell answers. */\nexport function fixPath(): void {\n const extra = shellPath()\n if (extra)\n process.env.PATH = mergePath(process.env.PATH, extra)\n}\n"],"mappings":"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"}
|