zidane 9.1.1 → 9.1.3
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/dist/{acp-Di9WvMDF.js → acp-CeCavNlg.js} +7 -7
- package/dist/{acp-Di9WvMDF.js.map → acp-CeCavNlg.js.map} +1 -1
- package/dist/acp-cli.js +5 -5
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-DJhpTS-B.js → agent-Dh_XZ7fj.js} +74 -19
- package/dist/agent-Dh_XZ7fj.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{auth-store-port-DFgf22oo.js → auth-store-port-BKpjlJ8a.js} +2 -2
- package/dist/{auth-store-port-DFgf22oo.js.map → auth-store-port-BKpjlJ8a.js.map} +1 -1
- package/dist/{auto-update-restart-BFB7Ek87.js → auto-update-restart-CQJtndMG.js} +277 -41
- package/dist/auto-update-restart-CQJtndMG.js.map +1 -0
- package/dist/{browser-BcoCCB_n.js → browser-BkdeKnxO.js} +56 -2
- package/dist/browser-BkdeKnxO.js.map +1 -0
- package/dist/{browser-entry-ypi8CyE-.d.ts → browser-entry-BCwruqNa.d.ts} +10 -10
- package/dist/{browser-entry-ypi8CyE-.d.ts.map → browser-entry-BCwruqNa.d.ts.map} +1 -1
- package/dist/channels.d.ts +5 -5
- package/dist/chat/browser.d.ts +4 -4
- package/dist/chat/browser.js +6 -6
- package/dist/chat/pure.d.ts +5 -5
- package/dist/chat/pure.js +8 -8
- package/dist/chat.d.ts +5 -5
- package/dist/chat.js +55 -55
- package/dist/chat.js.map +1 -1
- package/dist/{cli-shared-CabruH8Z.js → cli-shared-DeRHgYvl.js} +4 -4
- package/dist/{cli-shared-CabruH8Z.js.map → cli-shared-DeRHgYvl.js.map} +1 -1
- package/dist/cli-style-DBEm6CyT.js +105 -0
- package/dist/cli-style-DBEm6CyT.js.map +1 -0
- package/dist/{client-core-CIixwznM.d.ts → client-core-C_4m_oL6.d.ts} +4 -4
- package/dist/{client-core-CIixwznM.d.ts.map → client-core-C_4m_oL6.d.ts.map} +1 -1
- package/dist/{client-CCaIXWue.d.ts → client-ygTASGis.d.ts} +2 -2
- package/dist/{client-CCaIXWue.d.ts.map → client-ygTASGis.d.ts.map} +1 -1
- package/dist/codemode-worker.js +8 -5
- package/dist/codemode-worker.js.map +1 -1
- package/dist/codemode.d.ts +16 -0
- package/dist/codemode.d.ts.map +1 -1
- package/dist/codemode.js +2 -2
- package/dist/{connection-loop-QmWL-fJf.d.ts → connection-loop-D_pRONCr.d.ts} +4 -4
- package/dist/{connection-loop-QmWL-fJf.d.ts.map → connection-loop-D_pRONCr.d.ts.map} +1 -1
- package/dist/contexts/daytona.d.ts +3 -3
- package/dist/contexts/docker.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +2 -2
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/{contexts-C72b0mMa.js → contexts-DLZTSRHU.js} +17 -106
- package/dist/contexts-DLZTSRHU.js.map +1 -0
- package/dist/contexts.d.ts +4 -4
- package/dist/contexts.js +2 -2
- package/dist/{credentials-wwETW8rI.js → credentials-Bqg-qNBM.js} +2 -2
- package/dist/{credentials-wwETW8rI.js.map → credentials-Bqg-qNBM.js.map} +1 -1
- package/dist/{cwd-picker-CcekODCt.js → cwd-picker-BsHA6HKv.js} +4 -4
- package/dist/{cwd-picker-CcekODCt.js.map → cwd-picker-BsHA6HKv.js.map} +1 -1
- package/dist/daemon-cli.js +4 -3
- package/dist/daemon-cli.js.map +1 -1
- package/dist/{decisions-CXmK0nz9.js → decisions-hsw5XS2g.js} +3 -1
- package/dist/decisions-hsw5XS2g.js.map +1 -0
- package/dist/{discovery-DycXFxdA.js → discovery-CX7nbMCn.js} +4 -4
- package/dist/{discovery-DycXFxdA.js.map → discovery-CX7nbMCn.js.map} +1 -1
- package/dist/durable/sqlite.d.ts +2 -2
- package/dist/durable.d.ts +1 -1
- package/dist/{engine-VQ86XGdG.js → engine-CxBGgU94.js} +6 -6
- package/dist/{engine-VQ86XGdG.js.map → engine-CxBGgU94.js.map} +1 -1
- package/dist/{eval-Bod0I1W_.js → eval-CfGUDAkN.js} +3 -3
- package/dist/{eval-Bod0I1W_.js.map → eval-CfGUDAkN.js.map} +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/{executor-C7RQrkEq.js → executor-j_LFRBwS.js} +4 -4
- package/dist/{executor-C7RQrkEq.js.map → executor-j_LFRBwS.js.map} +1 -1
- package/dist/{extension-mark-BqKdEZwF.js → extension-mark-_rhkDWL5.js} +9 -6
- package/dist/extension-mark-_rhkDWL5.js.map +1 -0
- package/dist/extensions/testing.d.ts +1 -1
- package/dist/extensions/testing.js +2 -2
- package/dist/{extensions-BCx4QuGB.js → extensions-ADlhBQ_1.js} +8 -8
- package/dist/{extensions-BCx4QuGB.js.map → extensions-ADlhBQ_1.js.map} +1 -1
- package/dist/{extensions-client-D8tEAcMw.d.ts → extensions-client-D4Q2XRKV.d.ts} +31 -5
- package/dist/extensions-client-D4Q2XRKV.d.ts.map +1 -0
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +6 -6
- package/dist/{fold-rules-DvLK8pbf.d.ts → fold-rules-1DpDwG9h.d.ts} +2 -2
- package/dist/{fold-rules-DvLK8pbf.d.ts.map → fold-rules-1DpDwG9h.d.ts.map} +1 -1
- package/dist/{google-Crva32sk.js → google-B-Dhmzzf.js} +2 -2
- package/dist/{google-Crva32sk.js.map → google-B-Dhmzzf.js.map} +1 -1
- package/dist/{headless-CCm-jLLT.js → headless-CQm19BL0.js} +4 -4
- package/dist/{headless-CCm-jLLT.js.map → headless-CQm19BL0.js.map} +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/history-worker.js +1 -1
- package/dist/{host-wO_6GW0y.js → host-C61ntFBC.js} +276 -103
- package/dist/host-C61ntFBC.js.map +1 -0
- package/dist/{host-BHMs9jsN.js → host-DEoEzQal.js} +13 -4
- package/dist/host-DEoEzQal.js.map +1 -0
- package/dist/{host-scoped-settings-CrbcqOkP.js → host-scoped-settings-WBYaCork.js} +2 -2
- package/dist/{host-scoped-settings-CrbcqOkP.js.map → host-scoped-settings-WBYaCork.js.map} +1 -1
- package/dist/{host-signals-Jsjd_-4g.js → host-signals-Cb2TlGtN.js} +5 -5
- package/dist/{host-signals-Jsjd_-4g.js.map → host-signals-Cb2TlGtN.js.map} +1 -1
- package/dist/{host-version-CNAr9pov.js → host-version-BIx4CuBM.js} +2 -2
- package/dist/{host-version-CNAr9pov.js.map → host-version-BIx4CuBM.js.map} +1 -1
- package/dist/{index-C6nnKu32.d.ts → index-B0PLo9jn.d.ts} +4 -4
- package/dist/{index-C6nnKu32.d.ts.map → index-B0PLo9jn.d.ts.map} +1 -1
- package/dist/{index-Djnc8Peh.d.ts → index-De4x-s76.d.ts} +14 -14
- package/dist/{index-Djnc8Peh.d.ts.map → index-De4x-s76.d.ts.map} +1 -1
- package/dist/{index-CGbOWa7y.d.ts → index-WlE93Q6d.d.ts} +411 -3
- package/dist/index-WlE93Q6d.d.ts.map +1 -0
- package/dist/{index-CCf_WeTQ.d.ts → index-f-XWIoYo.d.ts} +2 -2
- package/dist/{index-CCf_WeTQ.d.ts.map → index-f-XWIoYo.d.ts.map} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +17 -17
- package/dist/ipc/browser-types.d.ts +304 -7
- package/dist/ipc/browser-types.d.ts.map +1 -1
- package/dist/ipc/browser.d.ts +4 -4
- package/dist/ipc/browser.js +2 -2
- package/dist/ipc/remote.d.ts +6 -6
- package/dist/ipc/remote.js +3 -3
- package/dist/{ipc-BzWhIybr.js → ipc-DiH_P-wr.js} +4 -4
- package/dist/{ipc-BzWhIybr.js.map → ipc-DiH_P-wr.js.map} +1 -1
- package/dist/ipc.d.ts +10 -10
- package/dist/ipc.js +8 -8
- package/dist/{json-Dj-YATkZ.js → json-BjClr43H.js} +2 -20
- package/dist/json-BjClr43H.js.map +1 -0
- package/dist/{links-CJG_rFvf.js → links-BbC_lOnn.js} +9 -9
- package/dist/{links-CJG_rFvf.js.map → links-BbC_lOnn.js.map} +1 -1
- package/dist/{loaded-entry-DTURJo_R.js → loaded-entry-C0vkCVNQ.js} +2 -2
- package/dist/{loaded-entry-DTURJo_R.js.map → loaded-entry-C0vkCVNQ.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/{media-type-BtA0cbfI.d.ts → media-type-ZSmAGHvg.d.ts} +188 -7
- package/dist/media-type-ZSmAGHvg.d.ts.map +1 -0
- package/dist/{memory-DuVGrzbl.js → memory-C3w8nO8f.js} +132 -31
- package/dist/memory-C3w8nO8f.js.map +1 -0
- package/dist/model-test-CAtJ76kM.js.map +1 -1
- package/dist/{move-session-kylExJ5H.js → move-session-D7ILECs-.js} +4 -4
- package/dist/{move-session-kylExJ5H.js.map → move-session-D7ILECs-.js.map} +1 -1
- package/dist/{nested-call-record-DlzPeTB7.js → nested-call-record-OayszZBQ.js} +4 -3
- package/dist/nested-call-record-OayszZBQ.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/{path-display-COVV71Yu.js → path-display-DRAEpKOU.js} +3 -3
- package/dist/{path-display-COVV71Yu.js.map → path-display-DRAEpKOU.js.map} +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/{prelude-CVKoUzV8.js → prelude-BwiSR1uA.js} +16 -5
- package/dist/prelude-BwiSR1uA.js.map +1 -0
- package/dist/{presets-CBt6rFfS.js → presets-CMY43nUP.js} +3 -3
- package/dist/{presets-CBt6rFfS.js.map → presets-CMY43nUP.js.map} +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/{protocol-CEVqBO-q.d.ts → protocol-C2lqKuMd.d.ts} +50 -7
- package/dist/protocol-C2lqKuMd.d.ts.map +1 -0
- package/dist/protocol-DOGyHgLQ.js.map +1 -1
- package/dist/protocol-NSllElLw.js.map +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/google.js +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/neuralwatt.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/{providers-Z0TaBp1O.js → providers-CpXV_uLE.js} +5 -5
- package/dist/providers-CpXV_uLE.js.map +1 -0
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +1 -1
- package/dist/{readonly-db-D7Z-k0pQ.js → readonly-db-DrbT8tX6.js} +2 -2
- package/dist/{readonly-db-D7Z-k0pQ.js.map → readonly-db-DrbT8tX6.js.map} +1 -1
- package/dist/{registry-BKjeBnoy.js → registry-CJHvmvaP.js} +2 -2
- package/dist/{registry-BKjeBnoy.js.map → registry-CJHvmvaP.js.map} +1 -1
- package/dist/{registry-B6Ww76iW.js → registry-CN6JlZKj.js} +2 -2
- package/dist/{registry-B6Ww76iW.js.map → registry-CN6JlZKj.js.map} +1 -1
- package/dist/{registry-B9INJwJR.js → registry-CnnKaY9s.js} +324 -39
- package/dist/registry-CnnKaY9s.js.map +1 -0
- package/dist/{remote-hosts-BMWoHCWO.js → remote-hosts-DoO9CJUQ.js} +4 -4
- package/dist/{remote-hosts-BMWoHCWO.js.map → remote-hosts-DoO9CJUQ.js.map} +1 -1
- package/dist/{repo-url-D4Dr8NfZ.js → repo-url-DLjjuVk_.js} +169 -2
- package/dist/repo-url-DLjjuVk_.js.map +1 -0
- package/dist/restate.d.ts +2 -2
- package/dist/{sandbox-BwiPGKF7.d.ts → sandbox-B4OW6oNx.d.ts} +2 -2
- package/dist/{sandbox-BwiPGKF7.d.ts.map → sandbox-B4OW6oNx.d.ts.map} +1 -1
- package/dist/script-progress-CrZ507Qq.js +900 -0
- package/dist/script-progress-CrZ507Qq.js.map +1 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/{setting-BQBSyUq0.js → setting-D_FpKFMw.js} +6 -6
- package/dist/{setting-BQBSyUq0.js.map → setting-D_FpKFMw.js.map} +1 -1
- package/dist/{settings-catalog-4IU2i_jG.js → settings-catalog-DEZlXP51.js} +14 -2
- package/dist/settings-catalog-DEZlXP51.js.map +1 -0
- package/dist/{settings-keys-iI_Y-7MC.js → settings-keys-CW2UgHgb.js} +3 -3
- package/dist/{settings-keys-iI_Y-7MC.js.map → settings-keys-CW2UgHgb.js.map} +1 -1
- package/dist/{skills-CFXRItJ6.js → skills-CEbosUlM.js} +2 -2
- package/dist/{skills-CFXRItJ6.js.map → skills-CEbosUlM.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +1 -1
- package/dist/{source-Bl1Z501r.js → source-3ZnEPOSa.js} +3 -2
- package/dist/source-3ZnEPOSa.js.map +1 -0
- package/dist/{sqlite-runtime-BZ2L4RaG.d.ts → sqlite-runtime-CS_LBaAN.d.ts} +2 -2
- package/dist/sqlite-runtime-CS_LBaAN.d.ts.map +1 -0
- package/dist/{src-BY_ND2xn.js → src-BmTXDta8.js} +2 -2
- package/dist/{src-BY_ND2xn.js.map → src-BmTXDta8.js.map} +1 -1
- package/dist/{store-C6gI7FfZ.js → store-ByCDaKgJ.js} +14 -3
- package/dist/store-ByCDaKgJ.js.map +1 -0
- package/dist/{system-freeze-m5o1sGIM.js → system-freeze-XgDPIwQS.js} +3 -3
- package/dist/{system-freeze-m5o1sGIM.js.map → system-freeze-XgDPIwQS.js.map} +1 -1
- package/dist/{todo-edits-CbukbjyV.js → todo-edits-Dyj32ds6.js} +4 -3
- package/dist/todo-edits-Dyj32ds6.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/{tools-CVTGhggj.js → tools-BsrGQ8K4.js} +2 -2
- package/dist/{tools-CVTGhggj.js.map → tools-BsrGQ8K4.js.map} +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +3 -3
- package/dist/{transcript-anchors-CiSi_UBn.js → transcript-anchors-DMjvyUjk.js} +3 -3
- package/dist/{transcript-anchors-CiSi_UBn.js.map → transcript-anchors-DMjvyUjk.js.map} +1 -1
- package/dist/{transcript-reconcile-jbSBjLq2.js → transcript-reconcile-DpQO85wl.js} +3 -3
- package/dist/{transcript-reconcile-jbSBjLq2.js.map → transcript-reconcile-DpQO85wl.js.map} +1 -1
- package/dist/tui.d.ts +9 -9
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +289 -38
- package/dist/tui.js.map +1 -1
- package/dist/{types-bDQagoiL.d.ts → types-2HrgolQz.d.ts} +20 -8
- package/dist/types-2HrgolQz.d.ts.map +1 -0
- package/dist/types-4q1bFG53.js +122 -0
- package/dist/types-4q1bFG53.js.map +1 -0
- package/dist/{types-DnRd9_cA.d.ts → types-SXqk6hLD.d.ts} +3 -3
- package/dist/{types-DnRd9_cA.d.ts.map → types-SXqk6hLD.d.ts.map} +1 -1
- package/dist/types-myxheQkw.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/{usage-summary-BfcXjiSM.js → usage-summary-BM7B3JdI.js} +2 -2
- package/dist/{usage-summary-BfcXjiSM.js.map → usage-summary-BM7B3JdI.js.map} +1 -1
- package/dist/{version-DqqqvHDP.js → version-szdW1Od9.js} +2 -2
- package/dist/{version-DqqqvHDP.js.map → version-szdW1Od9.js.map} +1 -1
- package/dist/{wait-task-BX4NcOOm.js → wait-task-BiI5UaZQ.js} +13 -3
- package/dist/wait-task-BiI5UaZQ.js.map +1 -0
- package/dist/{wire-CLm2rMK0.js → wire-C3l9jl9x.js} +2 -2
- package/dist/{wire-CLm2rMK0.js.map → wire-C3l9jl9x.js.map} +1 -1
- package/dist/{write-file-0E6TUJ9A.js → write-file-Dquu7MzB.js} +5 -3
- package/dist/write-file-Dquu7MzB.js.map +1 -0
- package/dist/{ws-DfGGYQ4W.js → ws-CEHi0CiB.js} +4 -4
- package/dist/{ws-DfGGYQ4W.js.map → ws-CEHi0CiB.js.map} +1 -1
- package/dist/{ws-client-CFMbhsNq.js → ws-client-t8XNWxcq.js} +2 -2
- package/dist/{ws-client-CFMbhsNq.js.map → ws-client-t8XNWxcq.js.map} +1 -1
- package/docs/CHAT.md +55 -0
- package/docs/CODEMODE.md +37 -0
- package/docs/EXTENSIONS.md +8 -6
- package/docs/RELEASE-NOTES-NEXT.md +48 -1
- package/docs/RELEASE.md +9 -1
- package/package.json +2 -3
- package/dist/agent-DJhpTS-B.js.map +0 -1
- package/dist/auto-update-restart-BFB7Ek87.js.map +0 -1
- package/dist/browser-BcoCCB_n.js.map +0 -1
- package/dist/contexts-C72b0mMa.js.map +0 -1
- package/dist/decisions-CXmK0nz9.js.map +0 -1
- package/dist/extension-mark-BqKdEZwF.js.map +0 -1
- package/dist/extensions-client-D8tEAcMw.d.ts.map +0 -1
- package/dist/host-BHMs9jsN.js.map +0 -1
- package/dist/host-wO_6GW0y.js.map +0 -1
- package/dist/index-CGbOWa7y.d.ts.map +0 -1
- package/dist/json-Dj-YATkZ.js.map +0 -1
- package/dist/media-type-BtA0cbfI.d.ts.map +0 -1
- package/dist/memory-DuVGrzbl.js.map +0 -1
- package/dist/nested-call-events-BYk8XvGX.js +0 -182
- package/dist/nested-call-events-BYk8XvGX.js.map +0 -1
- package/dist/nested-call-record-DlzPeTB7.js.map +0 -1
- package/dist/prelude-CVKoUzV8.js.map +0 -1
- package/dist/protocol-CEVqBO-q.d.ts.map +0 -1
- package/dist/providers-Z0TaBp1O.js.map +0 -1
- package/dist/registry-B9INJwJR.js.map +0 -1
- package/dist/repo-url-D4Dr8NfZ.js.map +0 -1
- package/dist/settings-catalog-4IU2i_jG.js.map +0 -1
- package/dist/source-Bl1Z501r.js.map +0 -1
- package/dist/sqlite-runtime-BZ2L4RaG.d.ts.map +0 -1
- package/dist/store-C6gI7FfZ.js.map +0 -1
- package/dist/todo-edits-CbukbjyV.js.map +0 -1
- package/dist/types-DTMEhKJO.js +0 -14
- package/dist/types-DTMEhKJO.js.map +0 -1
- package/dist/types-bDQagoiL.d.ts.map +0 -1
- package/dist/wait-task-BX4NcOOm.js.map +0 -1
- package/dist/write-file-0E6TUJ9A.js.map +0 -1
- package/scripts/eval.ts +0 -179
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"links-CJG_rFvf.js","names":[],"sources":["../src/ipc/machine/agent.ts","../src/ipc/machine/reverse.ts","../src/ipc/machine/share-lock.ts","../src/ipc/machine/links.ts"],"sourcesContent":["/**\n * The machine agent (`docs/MACHINES.md` § Machine side): dials its host with\n * a machine-scoped token, registers, and serves the host's execution\n * requests through the confined executor (`./executor.ts`) until stopped.\n * Reconnects with the hosts' connection loop (backoff; a refused token, a\n * different host at the URL, or a refused registration stop it for good).\n *\n * The CLI (`./cli.ts`, `zidane machine share`) runs it in the foreground;\n * `./links.ts` starts it from the local daemon / in-process host.\n */\nimport type { HostConnectionStatus } from '../../chat/hosts/connection'\nimport type { MachineRegisterParams, MachineRegisterResult, MachineRoot } from '../../chat/machine-protocol'\nimport type { IpcClient } from '../transports/client-core'\nimport type { MachineExecutor, MachineExecutorOptions } from './executor'\nimport { mkdirSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { JsonRpcRemoteError } from '../../acp/json-rpc'\nimport { writeJsonFileAtomic } from '../../atomic-write'\nimport { HostIdentityError } from '../../chat/hosts/connection'\nimport { displayHostUrl } from '../../chat/hosts/url'\nimport { isValidMachineName, MACHINE_PROTOCOL_VERSION, MachineErrorCode } from '../../chat/machine-protocol'\nimport { ZIDANE_VERSION } from '../../version'\nimport { keepHostConnected } from '../hosts/connection-loop'\nimport { IpcVersionMismatchError } from '../transports/client-core'\nimport { connectWsClient, HostAuthError } from '../transports/ws-client'\nimport { createMachineExecutor, shareableRoot } from './executor'\nimport { machineIdentity } from './identity'\n\nexport { machineIdentity } from './identity'\n\nexport interface MachineAgentOptions {\n /** `ws://` / `wss://` URL of the host. */\n hostUrl: string\n /** A `machine`-scoped token of that host. */\n token: string\n /** Display name, and the suffix of its environment kinds (`local@<name>`). */\n name: string\n /** Folders the host may use; absolute, existing. */\n roots: ReadonlyArray<string | MachineRoot>\n /** This machine's data dir: its id, the host it pinned, task logs. Only its `worktrees/` and task logs are reachable by the host. */\n dataDir: string\n appVersion?: string\n /** Every status change (`connected`, `reconnecting`, `auth-refused`, …) and why it failed. */\n onStatus?: (status: HostConnectionStatus, detail?: string) => void\n /** Backoff bounds and heartbeat (tests shrink them). */\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n terminalGraceMs?: number\n /** This machine user's `sandbox*` settings: every command the host sends runs under them (`docs/MACHINES.md` § Sandbox). */\n sandbox?: MachineExecutorOptions['sandbox']\n /** This machine user's zidane data dir: never shared (a root can't be in it, file ops never reach it), and its credential files are hidden from sandboxed commands. */\n credentialsDataDir?: string\n /** This computer's GPU names (`capabilities.gpu`); asked once, before the first registration. */\n gpu?: () => Promise<string[]>\n /** After each registration: the host's version (`ipc.hello`'s `appVersion`). */\n onHostVersion?: (version: string | undefined) => void\n}\n\nexport interface MachineAgent {\n machineId: string\n status: () => HostConnectionStatus\n /** Reconnect now (after a fix on the host side). */\n retry: () => void\n stop: () => Promise<void>\n /** The host's version, once it answered. */\n hostVersion: () => string | undefined\n /** What runs on this machine now (see {@link MachineExecutor.activity}). */\n activity: MachineExecutor['activity']\n}\n\n/** A registration the host refused for good (its name taken, another protocol). */\nclass MachineRegisterError extends Error {\n constructor(message: string, readonly forGood: boolean) {\n super(message)\n this.name = 'MachineRegisterError'\n }\n}\n\nfunction normalizeRoots(roots: MachineAgentOptions['roots'], zidaneDataDir: string | undefined): MachineRoot[] {\n if (roots.length === 0)\n throw new Error('Share at least one folder (--root).')\n return roots.map((root) => {\n const entry = typeof root === 'string' ? { path: root } : root\n const real = shareableRoot(entry.path, zidaneDataDir)\n if (!statSync(real).isDirectory())\n throw new Error(`Root ${entry.path} is not a folder.`)\n return { path: real, ...(entry.label ? { label: entry.label } : {}) }\n })\n}\n\n/** The host id this machine pinned for `url` (the first host that answered there). */\nfunction pinnedHosts(dataDir: string): { get: (url: string) => string | undefined, set: (url: string, hostId: string) => void } {\n const file = join(dataDir, 'machine-hosts.json')\n const read = (): Record<string, string> => {\n try {\n return JSON.parse(readFileSync(file, 'utf8')) as Record<string, string>\n }\n catch {\n return {}\n }\n }\n return {\n get: url => read()[url],\n set: (url, hostId) => writeJsonFileAtomic(file, { ...read(), [url]: hostId }, { ensureDir: true, mode: 0o600 }),\n }\n}\n\nexport function startMachineAgent(options: MachineAgentOptions): MachineAgent {\n if (!isValidMachineName(options.name))\n throw new Error(`\"${options.name}\" is not a valid machine name: 1 to 64 letters, digits, \".\", \"-\" or \"_\".`)\n mkdirSync(options.dataDir, { recursive: true, mode: 0o700 })\n const dataDir = realpathSync.native(options.dataDir)\n const roots = normalizeRoots(options.roots, options.credentialsDataDir)\n const machineId = machineIdentity(dataDir)\n const pins = pinnedHosts(dataDir)\n const url = options.hostUrl\n let client: IpcClient | null = null\n let status: HostConnectionStatus = 'connecting'\n let hostVersion: string | undefined\n let gpu: Promise<string[]> | undefined\n\n const executor = createMachineExecutor({\n roots,\n dataDir,\n ...(options.terminalGraceMs !== undefined ? { terminalGraceMs: options.terminalGraceMs } : {}),\n ...(options.sandbox ? { sandbox: options.sandbox } : {}),\n ...(options.credentialsDataDir ? { credentialsDataDir: options.credentialsDataDir } : {}),\n notify: (method, params) => {\n if (!client)\n return false\n try {\n (client.notify as unknown as (m: string, p: unknown) => void)(method, params)\n return true\n }\n catch {\n return false\n }\n },\n })\n\n const register: MachineRegisterParams = {\n machineId,\n name: options.name,\n roots,\n capabilities: { shell: true, terminals: typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined', background: true, worktrees: true, stream: true, entries: true, sandboxed: executor.sandbox.on },\n version: options.appVersion ?? ZIDANE_VERSION,\n protocolVersion: MACHINE_PROTOCOL_VERSION,\n }\n\n const loop = keepHostConnected({\n minDelayMs: options.minDelayMs ?? 1000,\n maxDelayMs: options.maxDelayMs ?? 30_000,\n async connect({ signal, onClose }) {\n const expectHostId = pins.get(url)\n const connected = await connectWsClient({\n url,\n token: options.token,\n signal,\n onClose,\n appVersion: register.version,\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n ...(expectHostId ? { expectHostId } : {}),\n serve: {\n request: (method, params) => executor.handle(method, params),\n notification: (method, params) => void executor.handle(method, params).catch(() => undefined),\n },\n })\n gpu ??= options.gpu ? options.gpu().catch(() => []) : Promise.resolve([])\n const gpuNames = await gpu\n const params: MachineRegisterParams = gpuNames.length > 0 ? { ...register, capabilities: { ...register.capabilities, gpu: gpuNames } } : register\n try {\n await (connected.request as unknown as (m: string, p: unknown) => Promise<MachineRegisterResult>)('machine.register', params)\n }\n catch (err) {\n connected.close()\n const code = err instanceof JsonRpcRemoteError ? err.code : undefined\n throw new MachineRegisterError(`${displayHostUrl(url)} refused this machine: ${(err as Error).message}`, code === MachineErrorCode.NameTaken || code === MachineErrorCode.VersionSkew || code === MachineErrorCode.IdBound)\n }\n if (!expectHostId && connected.hello.hostId)\n pins.set(url, connected.hello.hostId)\n hostVersion = connected.hello.appVersion\n options.onHostVersion?.(hostVersion)\n return connected\n },\n classify: (err) => {\n if (err instanceof HostIdentityError)\n return 'identity'\n if (err instanceof HostAuthError || (err instanceof MachineRegisterError && err.forGood))\n return 'auth'\n return err instanceof IpcVersionMismatchError ? 'protocol' : 'retry'\n },\n update: (patch) => {\n if (patch.client !== undefined)\n client = patch.client\n if (patch.status) {\n status = patch.status\n options.onStatus?.(patch.status, patch.error)\n }\n },\n onConnected: () => executor.linkUp(),\n onDisconnected: () => executor.linkLost(),\n })\n\n return {\n machineId,\n status: () => status,\n retry: () => loop.retry(),\n hostVersion: () => hostVersion,\n activity: () => executor.activity(),\n async stop() {\n loop.stop()\n await executor.close()\n },\n }\n}\n","/**\n * A saved server used as a machine of this local host (`local@<server>`,\n * `docs/MACHINES.md` § Reverse direction). A local host has no listener, so\n * it dials the server as a client (its saved client token), asks it to lend\n * itself (`machine.attach`), and registers it in its own machine registry\n * with a connection that sends each host→machine request as `machine.call`.\n * The server's notifications come back as `machine:notification` signals.\n * Reconnects with the hosts' connection loop; a refused token, another host\n * at the URL, or a server that does not lend itself stop it for good.\n */\nimport type { AttachedMachine, MachineConnection, MachineRegistry } from '../../chat/host/machines'\nimport type { MachineLinkState } from '../../chat/machine-protocol'\nimport type { JsonValue } from '../../types'\nimport type { IpcClient } from '../transports/client-core'\nimport { JsonRpcConnectionClosedError, JsonRpcRemoteError } from '../../acp/json-rpc'\nimport { MachineLinkLostError } from '../../chat/host/machines'\nimport { HostIdentityError } from '../../chat/hosts/connection'\nimport { displayHostUrl } from '../../chat/hosts/url'\nimport { MachineErrorCode } from '../../chat/machine-protocol'\nimport { keepHostConnected } from '../hosts/connection-loop'\nimport { connectWsClient, HostAuthError } from '../transports/ws-client'\n\nexport interface ServerMachineOptions {\n machines: MachineRegistry\n url: string\n /** The saved server's client token. */\n token: string\n /** The saved server's host id: another host at the URL is refused. */\n expectHostId: string\n /** This host's id (the server keys its executor by it, so tasks survive a reconnect). */\n localHostId: string\n appVersion?: string\n onState: (state: MachineLinkState, detail?: string, machineName?: string) => void\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n}\n\nexport interface ServerMachine {\n retry: () => void\n stop: () => void\n}\n\n/** The server refused to lend itself (`allowAsMachine` off, a name taken here): for good. A busy server is retried. */\nclass AttachRefusedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AttachRefusedError'\n }\n}\n\nfunction connectionOver(client: IpcClient): MachineConnection {\n return {\n async request(method, params) {\n try {\n return await client.request('machine.call', { method, params: (params ?? {}) as JsonValue })\n }\n catch (err) {\n if (err instanceof JsonRpcConnectionClosedError)\n throw new MachineLinkLostError()\n throw err instanceof JsonRpcRemoteError ? new Error(err.message) : err\n }\n },\n notify: (method, params) => client.notify('machine.call', { method, params: (params ?? {}) as JsonValue }),\n close: () => client.close(),\n }\n}\n\nexport function startServerMachine(options: ServerMachineOptions): ServerMachine {\n let attached: AttachedMachine | undefined\n const where = displayHostUrl(options.url)\n\n const detach = (): void => {\n attached?.closed()\n attached = undefined\n }\n\n const loop = keepHostConnected({\n ...(options.minDelayMs !== undefined ? { minDelayMs: options.minDelayMs } : {}),\n ...(options.maxDelayMs !== undefined ? { maxDelayMs: options.maxDelayMs } : {}),\n async connect({ signal, onClose }) {\n const client = await connectWsClient({\n url: options.url,\n token: options.token,\n expectHostId: options.expectHostId,\n signal,\n onClose,\n ...(options.appVersion ? { appVersion: options.appVersion } : {}),\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n })\n // Subscribed before attaching: the server re-sends queued task exits while it answers `machine.attach`.\n const early: Array<{ method: string, params: unknown }> = []\n let current: AttachedMachine | undefined\n client.onSignal((s) => {\n if (s.kind !== 'machine:notification')\n return\n if (current)\n current.notification(s.method, s.params)\n else if (early.length < 1024)\n early.push({ method: s.method, params: s.params })\n })\n try {\n const params = await client.request('machine.attach', { hostId: options.localHostId })\n detach()\n current = options.machines.attach(params, connectionOver(client), { server: options.expectHostId })\n attached = current\n for (const { method, params: p } of early.splice(0))\n current.notification(method, p)\n options.onState('connected', undefined, params.name)\n }\n catch (err) {\n client.close()\n // No room there now (a capacity limit) or the link dropped: the loop retries with backoff.\n if (err instanceof JsonRpcConnectionClosedError || (err instanceof JsonRpcRemoteError && err.code === MachineErrorCode.Busy))\n throw new Error(`${where} can't lend itself right now: ${(err as Error).message}`)\n throw new AttachRefusedError(`${where} refused to be a machine: ${(err as Error).message}`)\n }\n return client\n },\n classify: err => (err instanceof HostIdentityError ? 'identity' : err instanceof HostAuthError || err instanceof AttachRefusedError ? 'auth' : 'retry'),\n update: (patch) => {\n if (!patch.status || patch.status === 'connected')\n return\n options.onState(patch.status === 'auth-refused' && patch.error?.includes('refused to be a machine') ? 'refused' : patch.status, patch.error)\n },\n onDisconnected: detach,\n })\n\n return {\n retry: () => loop.retry(),\n stop() {\n loop.stop()\n detach()\n },\n }\n}\n","/**\n * `machine-links.lock`: which process runs this computer's shares (one\n * machine id, one connection; two processes sharing it would keep replacing\n * each other's). Exclusive by construction, not by a read-then-write:\n *\n * - taking a free lock is an exclusive create (`wx`): one contender wins;\n * - the record names its holder (`pid`) and a per-process `nonce`; the\n * holder touches the file on every check, so a holder is stale when its\n * pid is gone OR the file went untouched for {@link STALE_MS} (a reused\n * pid never touches it);\n * - a stale lock is moved aside (an atomic rename to a name of our own),\n * checked to be the very record judged stale, then the exclusive create\n * runs again; a live lock moved aside by mistake is put back without\n * clobbering (`link`, which fails if the name is taken);\n * - a holder re-reads the record on every check: another nonce there means\n * it lost the lock, and the caller stops its shares;\n * - release removes the file only when it still carries this nonce.\n */\nimport { randomBytes } from 'node:crypto'\nimport { closeSync, linkSync, openSync, readFileSync, renameSync, rmSync, statSync, utimesSync, writeSync } from 'node:fs'\nimport process from 'node:process'\n\n/** A holder that has not touched its lock for this long is gone (its pid may be reused). */\nexport const SHARE_LOCK_STALE_MS = 30_000\n\ninterface LockRecord {\n pid: number\n nonce: string\n}\n\nexport interface ShareLock {\n /** Hold the lock (taking it when free or stale); `false` when another live process holds it. */\n acquire: () => boolean\n /** Whether this process held it at the last {@link acquire}. */\n held: () => boolean\n /** Remove the lock when this process still holds it; whether it did. */\n release: () => boolean\n}\n\nexport interface ShareLockOptions {\n /** Test seams. */\n pid?: number\n alive?: (pid: number) => boolean\n now?: () => number\n staleMs?: number\n}\n\nfunction processAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n }\n catch (err) {\n return (err as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\nfunction readRecord(file: string): { record?: LockRecord, mtimeMs: number } | undefined {\n try {\n const mtimeMs = statSync(file).mtimeMs\n const raw = JSON.parse(readFileSync(file, 'utf8')) as Partial<LockRecord>\n return { mtimeMs, ...(typeof raw.pid === 'number' && typeof raw.nonce === 'string' ? { record: { pid: raw.pid, nonce: raw.nonce } } : {}) }\n }\n catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT')\n return undefined\n // Unreadable or half-written: judged by its age alone.\n try {\n return { mtimeMs: statSync(file).mtimeMs }\n }\n catch {\n return undefined\n }\n }\n}\n\nexport function createShareLock(file: string, options: ShareLockOptions = {}): ShareLock {\n const pid = options.pid ?? process.pid\n const alive = options.alive ?? processAlive\n const now = options.now ?? Date.now\n const staleMs = options.staleMs ?? SHARE_LOCK_STALE_MS\n const nonce = randomBytes(12).toString('hex')\n let holding = false\n\n const create = (): boolean => {\n let fd: number\n try {\n fd = openSync(file, 'wx', 0o600)\n }\n catch {\n return false\n }\n try {\n writeSync(fd, JSON.stringify({ pid, nonce }))\n }\n finally {\n closeSync(fd)\n }\n return true\n }\n\n const ours = (): boolean => readRecord(file)?.record?.nonce === nonce\n\n const stale = (found: { record?: LockRecord, mtimeMs: number }): boolean =>\n now() - found.mtimeMs > staleMs || (found.record !== undefined && !alive(found.record.pid))\n\n /** Move a stale lock aside; `true` when the record moved is the one judged stale. */\n const evict = (judged: { record?: LockRecord, mtimeMs: number }): boolean => {\n const aside = `${file}.${nonce}.stale`\n try {\n renameSync(file, aside)\n }\n catch {\n return false\n }\n const moved = readRecord(aside)\n const same = moved?.record?.nonce === judged.record?.nonce && moved?.mtimeMs === judged.mtimeMs\n if (!same) {\n // A live lock taken meanwhile: put it back, never over a newer one.\n try {\n linkSync(aside, file)\n }\n catch {\n // Someone holds the name again; that holder's own check settles it.\n }\n }\n rmSync(aside, { force: true })\n return same\n }\n\n return {\n acquire() {\n if (holding) {\n if (ours()) {\n try {\n const at = new Date(now())\n utimesSync(file, at, at)\n }\n catch {\n // The touch is best effort; the record still names this process.\n }\n return true\n }\n holding = false\n }\n if (create()) {\n holding = true\n return true\n }\n const found = readRecord(file)\n if (found && !stale(found))\n return false\n if (found && !evict(found))\n return false\n holding = create()\n return holding\n },\n held: () => holding,\n release() {\n const mine = holding && ours()\n if (mine)\n rmSync(file, { force: true })\n holding = false\n return mine\n },\n }\n}\n","/**\n * A local host's machine links (`docs/MACHINES.md` § Client UI), loaded only\n * behind remote hosts:\n *\n * - **Shares**: this computer lent to a saved server (a machine agent in\n * this process, with the machine token stored under `machine:<hostId>`).\n * One process runs them for the whole computer: the holder of\n * `machine-links.lock` (the daemon, or the first window's in-process\n * host; exclusive, `./share-lock.ts`). Two processes sharing one computer\n * under one machine id would keep replacing each other's connection, so a\n * process that finds it lost the lock stops its shares at once.\n * - **Uses**: a saved server lent to THIS host (`local@<server>`), over its\n * own client connection. Per host process: each host has its own machine\n * registry, so each attaches under its own instance id.\n *\n * The wanted links live in `<dataDir>/machine-links.json` (any process writes\n * it); every process re-reads it every {@link POLL_MS}, the holder applies the\n * shares and publishes their state in `machine-links-status.json`. Tokens\n * are never in either file.\n */\nimport type { MachineRegistry } from '../../chat/host/machines'\nimport type { HostEntry } from '../../chat/hosts/types'\nimport type { MachineLinksStatus, MachineLinkState, MachineShareStatus, MachineUseStatus } from '../../chat/machine-protocol'\nimport type { LooseSandboxSettings } from '../../chat/sandbox-settings'\nimport type { MachineAgent } from './agent'\nimport type { ServerMachine } from './reverse'\nimport { randomBytes } from 'node:crypto'\nimport { existsSync, readFileSync, rmSync } from 'node:fs'\nimport { isAbsolute, join } from 'node:path'\nimport { OWNER_ONLY, writeJsonFileAtomic } from '../../atomic-write'\nimport { readCredentialEntry, writeCredentialEntry } from '../../chat/credentials'\nimport { createHostRegistry, hostsFilePath } from '../../chat/hosts'\nimport { isValidMachineName, machineCredentialKey } from '../../chat/machine-protocol'\nimport { startMachineAgent } from './agent'\nimport { shareableRoot } from './executor'\nimport { startServerMachine } from './reverse'\nimport { createShareLock } from './share-lock'\n\nconst POLL_MS = 2000\nconst CONFIG_FILE = 'machine-links.json'\nconst STATUS_FILE = 'machine-links-status.json'\nconst LOCK_FILE = 'machine-links.lock'\nconst MAX_ROOTS = 32\n\ninterface ShareConfig {\n hostId: string\n name: string\n roots: string[]\n}\n\ninterface LinksConfig {\n version: 1\n shares: ShareConfig[]\n uses: string[]\n}\n\nexport interface MachineLinksOptions {\n /** The host's data dir: saved hosts, credentials, these files. */\n dataDir: string\n machines: MachineRegistry\n /** This host's id (`ipc.hello`). */\n hostId: string | undefined\n /** This user's settings: a share applies their `sandbox*` to what it runs (`docs/MACHINES.md` § Sandbox). */\n settings?: () => LooseSandboxSettings\n /** Every status change, for `machine:links`. */\n onChange: (status: MachineLinksStatus) => void\n appVersion?: string\n /** Connection pacing (tests shrink them). */\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n pollMs?: number\n}\n\nexport interface MachineLinks {\n status: () => MachineLinksStatus\n startShare: (input: { hostId: string, name: string, roots: string[], token?: string }) => MachineLinksStatus\n stopShare: (hostId: string) => MachineLinksStatus\n setUse: (hostId: string, enabled: boolean) => MachineLinksStatus\n /** Stop everything (remote hosts turned off, or the host closes); the wanted links stay saved. */\n close: () => Promise<void>\n}\n\nfunction readJson<T>(file: string, fallback: T): T {\n try {\n return existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) as T : fallback\n }\n catch {\n return fallback\n }\n}\n\nfunction readConfig(file: string): LinksConfig {\n const raw = readJson<Partial<LinksConfig>>(file, {})\n const shares = Array.isArray(raw.shares)\n ? raw.shares.filter((s): s is ShareConfig => !!s && typeof s.hostId === 'string' && typeof s.name === 'string' && Array.isArray(s.roots) && s.roots.every(r => typeof r === 'string'))\n : []\n const uses = Array.isArray(raw.uses) ? raw.uses.filter((u): u is string => typeof u === 'string') : []\n return { version: 1, shares, uses }\n}\n\n/** The saved servers' ids; `undefined` when `hosts.json` can't be read now (never mistaken for \"every server removed\"). */\nfunction savedHostIds(dataDir: string): Set<string> | undefined {\n const file = hostsFilePath(dataDir)\n if (!existsSync(file))\n return new Set()\n try {\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as { hosts?: unknown }\n if (!Array.isArray(parsed.hosts))\n return undefined\n return new Set(parsed.hosts.map(h => (h as { id?: unknown } | null)?.id).filter((id): id is string => typeof id === 'string'))\n }\n catch {\n return undefined\n }\n}\n\n/**\n * A share's name and roots, as a client sent them: every root absolute,\n * existing, and not (by its real path) zidane's data dir, inside it, or a\n * credentials folder (`./executor`'s `shareableRoot`).\n */\nexport function checkShareInput(input: { name: string, roots: string[] }, zidaneDataDir: string): void {\n if (!isValidMachineName(input.name))\n throw new Error(`\"${input.name}\" is not a valid machine name: 1 to 64 letters, digits, \".\", \"-\" or \"_\".`)\n if (!Array.isArray(input.roots) || input.roots.length === 0)\n throw new Error('Share at least one folder.')\n if (input.roots.length > MAX_ROOTS)\n throw new Error(`Share at most ${MAX_ROOTS} folders.`)\n for (const root of input.roots) {\n if (typeof root !== 'string' || !isAbsolute(root))\n throw new Error(`${String(root)} is not an absolute folder path.`)\n shareableRoot(root, zidaneDataDir)\n }\n}\n\nexport function startMachineLinks(options: MachineLinksOptions): MachineLinks {\n const { dataDir, machines } = options\n const configFile = join(dataDir, CONFIG_FILE)\n const statusFile = join(dataDir, STATUS_FILE)\n const lock = createShareLock(join(dataDir, LOCK_FILE))\n // Reading entries and tokens needs no probe: nothing is dialed here but the links themselves.\n const hosts = createHostRegistry({ dataDir, probe: async () => ({ ok: false, error: 'unreachable', message: 'not probed here' }) })\n const instance = `${(options.hostId ?? 'local').slice(0, 40)}-${randomBytes(4).toString('hex')}`\n const pacing = {\n ...(options.minDelayMs !== undefined ? { minDelayMs: options.minDelayMs } : {}),\n ...(options.maxDelayMs !== undefined ? { maxDelayMs: options.maxDelayMs } : {}),\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n }\n\n const shares = new Map<string, { config: ShareConfig, agent?: MachineAgent, status: MachineShareStatus }>()\n const uses = new Map<string, { link?: ServerMachine, status: MachineUseStatus }>()\n let holder = false\n let closed = false\n let lastPublished = ''\n\n const ownStatus = (): MachineLinksStatus => ({ shares: [...shares.values()].map(s => s.status), uses: [...uses.values()].map(u => u.status) })\n\n /** Shares as the holder reports them (another process may run them). */\n const status = (): MachineLinksStatus => {\n const own = ownStatus()\n if (holder)\n return own\n const config = readConfig(configFile)\n const published = readJson<Partial<MachineLinksStatus>>(statusFile, {})\n const known = new Map((published.shares ?? []).map(s => [s.hostId, s]))\n return {\n shares: config.shares.map(s => known.get(s.hostId) ?? { hostId: s.hostId, name: s.name, roots: s.roots, state: 'connecting' as const, detail: 'waiting for the zidane process that shares this computer' }),\n uses: own.uses,\n }\n }\n\n const publish = (): void => {\n if (closed)\n return\n const snapshot = status()\n const text = JSON.stringify(snapshot)\n if (holder) {\n try {\n writeJsonFileAtomic(statusFile, { shares: snapshot.shares }, OWNER_ONLY)\n }\n catch {\n // Best effort: other processes show \"waiting\" until it lands.\n }\n }\n if (text === lastPublished)\n return\n lastPublished = text\n options.onChange(snapshot)\n }\n\n const entry = (hostId: string): HostEntry => {\n const found = hosts.get(hostId)\n if (!found)\n throw new Error(`No saved server \"${hostId}\": add it on the Hosts page first.`)\n return found\n }\n\n function runShare(config: ShareConfig): void {\n const status: MachineShareStatus = { hostId: config.hostId, name: config.name, roots: config.roots, state: 'connecting' }\n const share: { config: ShareConfig, agent?: MachineAgent, status: MachineShareStatus } = { config, status }\n shares.set(config.hostId, share)\n const set = (state: MachineLinkState, detail?: string): void => {\n share.status = { ...status, state, ...(detail && state !== 'connected' ? { detail } : {}) }\n publish()\n }\n try {\n const server = entry(config.hostId)\n const cred = readCredentialEntry(dataDir, machineCredentialKey(config.hostId))\n const token = cred?.kind === 'apikey' ? cred.value : undefined\n if (!token)\n throw new Error(`No machine token saved for ${server.name}.`)\n share.agent = startMachineAgent({ hostUrl: server.url, token, name: config.name, roots: config.roots, dataDir: join(dataDir, 'machine'), credentialsDataDir: dataDir, ...(options.settings ? { sandbox: options.settings() } : {}), ...pacing, ...(options.appVersion ? { appVersion: options.appVersion } : {}), onStatus: (state, detail) => set(state, detail) })\n }\n catch (err) {\n set('refused', (err as Error).message)\n }\n }\n\n function runUse(hostId: string): void {\n const use: { link?: ServerMachine, status: MachineUseStatus } = { status: { hostId, state: 'connecting' } }\n uses.set(hostId, use)\n const set = (state: MachineLinkState, detail?: string, machineName?: string): void => {\n use.status = { hostId, state, ...(detail && state !== 'connected' ? { detail } : {}), ...(machineName ?? use.status.machineName ? { machineName: machineName ?? use.status.machineName } : {}) }\n publish()\n }\n try {\n const server = entry(hostId)\n const token = hosts.token(hostId)\n if (!token)\n throw new Error(`No token saved for ${server.name}: add it again.`)\n use.link = startServerMachine({ machines, url: server.url, token, expectHostId: hostId, localHostId: instance, ...pacing, ...(options.appVersion ? { appVersion: options.appVersion } : {}), onState: set })\n }\n catch (err) {\n set('refused', (err as Error).message)\n }\n }\n\n const stopShare = async (hostId: string): Promise<void> => {\n const share = shares.get(hostId)\n shares.delete(hostId)\n await share?.agent?.stop()\n }\n\n /** Bring the running links in line with the saved config. */\n function reconcile(): void {\n if (closed)\n return\n const config = readConfig(configFile)\n // A used server removed from the saved hosts (by any window or the TUI): stop using it.\n const saved = savedHostIds(dataDir)\n if (saved && config.uses.some(hostId => !saved.has(hostId))) {\n config.uses = config.uses.filter(hostId => saved.has(hostId))\n writeJsonFileAtomic(configFile, config, OWNER_ONLY)\n }\n holder = lock.acquire()\n if (!holder) {\n // Lost the lock (or never had it): another process runs this computer's shares, never two.\n for (const hostId of [...shares.keys()])\n void stopShare(hostId)\n }\n else {\n const wanted = new Map(config.shares.map(s => [s.hostId, s]))\n for (const [hostId, share] of shares) {\n const want = wanted.get(hostId)\n if (!want || JSON.stringify(want) !== JSON.stringify(share.config))\n void stopShare(hostId)\n }\n for (const share of config.shares) {\n if (!shares.has(share.hostId))\n runShare(share)\n }\n }\n const wantedUses = new Set(config.uses)\n for (const [hostId, use] of uses) {\n if (!wantedUses.has(hostId)) {\n use.link?.stop()\n uses.delete(hostId)\n }\n }\n for (const hostId of config.uses) {\n if (!uses.has(hostId))\n runUse(hostId)\n }\n // ...and forget the machine it was here, once its link is stopped (a live link would attach it again).\n if (saved)\n machines.forgetRemovedServers(saved)\n publish()\n }\n\n const writeConfig = (mutate: (config: LinksConfig) => void): MachineLinksStatus => {\n const config = readConfig(configFile)\n mutate(config)\n writeJsonFileAtomic(configFile, config, OWNER_ONLY)\n reconcile()\n return status()\n }\n\n reconcile()\n const timer = setInterval(reconcile, options.pollMs ?? POLL_MS)\n timer.unref?.()\n\n return {\n status,\n startShare(input) {\n checkShareInput(input, dataDir)\n const server = entry(input.hostId)\n const token = input.token?.trim()\n if (token)\n writeCredentialEntry(dataDir, machineCredentialKey(input.hostId), { kind: 'apikey', value: token })\n else if (readCredentialEntry(dataDir, machineCredentialKey(input.hostId))?.kind !== 'apikey')\n throw new Error(`No machine token for ${server.name}: create one there (zidane server token create --scope machine) or let this window create it.`)\n return writeConfig((config) => {\n config.shares = [...config.shares.filter(s => s.hostId !== input.hostId), { hostId: input.hostId, name: input.name, roots: [...input.roots] }]\n })\n },\n stopShare(hostId) {\n return writeConfig((config) => {\n config.shares = config.shares.filter(s => s.hostId !== hostId)\n })\n },\n setUse(hostId, enabled) {\n if (enabled) {\n const server = entry(hostId)\n if (!hosts.token(hostId))\n throw new Error(`No token saved for ${server.name}: add it again.`)\n }\n return writeConfig((config) => {\n config.uses = enabled ? [...new Set([...config.uses, hostId])] : config.uses.filter(u => u !== hostId)\n })\n },\n async close() {\n if (closed)\n return\n closed = true\n clearInterval(timer)\n for (const use of uses.values())\n use.link?.stop()\n uses.clear()\n await Promise.all([...shares.keys()].map(stopShare))\n // Only the holder's own files: a process that lost the lock leaves the new holder's alone.\n if (lock.release())\n rmSync(statusFile, { force: true })\n },\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"links-BbC_lOnn.js","names":[],"sources":["../src/ipc/machine/agent.ts","../src/ipc/machine/reverse.ts","../src/ipc/machine/share-lock.ts","../src/ipc/machine/links.ts"],"sourcesContent":["/**\n * The machine agent (`docs/MACHINES.md` § Machine side): dials its host with\n * a machine-scoped token, registers, and serves the host's execution\n * requests through the confined executor (`./executor.ts`) until stopped.\n * Reconnects with the hosts' connection loop (backoff; a refused token, a\n * different host at the URL, or a refused registration stop it for good).\n *\n * The CLI (`./cli.ts`, `zidane machine share`) runs it in the foreground;\n * `./links.ts` starts it from the local daemon / in-process host.\n */\nimport type { HostConnectionStatus } from '../../chat/hosts/connection'\nimport type { MachineRegisterParams, MachineRegisterResult, MachineRoot } from '../../chat/machine-protocol'\nimport type { IpcClient } from '../transports/client-core'\nimport type { MachineExecutor, MachineExecutorOptions } from './executor'\nimport { mkdirSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { JsonRpcRemoteError } from '../../acp/json-rpc'\nimport { writeJsonFileAtomic } from '../../atomic-write'\nimport { HostIdentityError } from '../../chat/hosts/connection'\nimport { displayHostUrl } from '../../chat/hosts/url'\nimport { isValidMachineName, MACHINE_PROTOCOL_VERSION, MachineErrorCode } from '../../chat/machine-protocol'\nimport { ZIDANE_VERSION } from '../../version'\nimport { keepHostConnected } from '../hosts/connection-loop'\nimport { IpcVersionMismatchError } from '../transports/client-core'\nimport { connectWsClient, HostAuthError } from '../transports/ws-client'\nimport { createMachineExecutor, shareableRoot } from './executor'\nimport { machineIdentity } from './identity'\n\nexport { machineIdentity } from './identity'\n\nexport interface MachineAgentOptions {\n /** `ws://` / `wss://` URL of the host. */\n hostUrl: string\n /** A `machine`-scoped token of that host. */\n token: string\n /** Display name, and the suffix of its environment kinds (`local@<name>`). */\n name: string\n /** Folders the host may use; absolute, existing. */\n roots: ReadonlyArray<string | MachineRoot>\n /** This machine's data dir: its id, the host it pinned, task logs. Only its `worktrees/` and task logs are reachable by the host. */\n dataDir: string\n appVersion?: string\n /** Every status change (`connected`, `reconnecting`, `auth-refused`, …) and why it failed. */\n onStatus?: (status: HostConnectionStatus, detail?: string) => void\n /** Backoff bounds and heartbeat (tests shrink them). */\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n terminalGraceMs?: number\n /** This machine user's `sandbox*` settings: every command the host sends runs under them (`docs/MACHINES.md` § Sandbox). */\n sandbox?: MachineExecutorOptions['sandbox']\n /** This machine user's zidane data dir: never shared (a root can't be in it, file ops never reach it), and its credential files are hidden from sandboxed commands. */\n credentialsDataDir?: string\n /** This computer's GPU names (`capabilities.gpu`); asked once, before the first registration. */\n gpu?: () => Promise<string[]>\n /** After each registration: the host's version (`ipc.hello`'s `appVersion`). */\n onHostVersion?: (version: string | undefined) => void\n}\n\nexport interface MachineAgent {\n machineId: string\n status: () => HostConnectionStatus\n /** Reconnect now (after a fix on the host side). */\n retry: () => void\n stop: () => Promise<void>\n /** The host's version, once it answered. */\n hostVersion: () => string | undefined\n /** What runs on this machine now (see {@link MachineExecutor.activity}). */\n activity: MachineExecutor['activity']\n}\n\n/** A registration the host refused for good (its name taken, another protocol). */\nclass MachineRegisterError extends Error {\n constructor(message: string, readonly forGood: boolean) {\n super(message)\n this.name = 'MachineRegisterError'\n }\n}\n\nfunction normalizeRoots(roots: MachineAgentOptions['roots'], zidaneDataDir: string | undefined): MachineRoot[] {\n if (roots.length === 0)\n throw new Error('Share at least one folder (--root).')\n return roots.map((root) => {\n const entry = typeof root === 'string' ? { path: root } : root\n const real = shareableRoot(entry.path, zidaneDataDir)\n if (!statSync(real).isDirectory())\n throw new Error(`Root ${entry.path} is not a folder.`)\n return { path: real, ...(entry.label ? { label: entry.label } : {}) }\n })\n}\n\n/** The host id this machine pinned for `url` (the first host that answered there). */\nfunction pinnedHosts(dataDir: string): { get: (url: string) => string | undefined, set: (url: string, hostId: string) => void } {\n const file = join(dataDir, 'machine-hosts.json')\n const read = (): Record<string, string> => {\n try {\n return JSON.parse(readFileSync(file, 'utf8')) as Record<string, string>\n }\n catch {\n return {}\n }\n }\n return {\n get: url => read()[url],\n set: (url, hostId) => writeJsonFileAtomic(file, { ...read(), [url]: hostId }, { ensureDir: true, mode: 0o600 }),\n }\n}\n\nexport function startMachineAgent(options: MachineAgentOptions): MachineAgent {\n if (!isValidMachineName(options.name))\n throw new Error(`\"${options.name}\" is not a valid machine name: 1 to 64 letters, digits, \".\", \"-\" or \"_\".`)\n mkdirSync(options.dataDir, { recursive: true, mode: 0o700 })\n const dataDir = realpathSync.native(options.dataDir)\n const roots = normalizeRoots(options.roots, options.credentialsDataDir)\n const machineId = machineIdentity(dataDir)\n const pins = pinnedHosts(dataDir)\n const url = options.hostUrl\n let client: IpcClient | null = null\n let status: HostConnectionStatus = 'connecting'\n let hostVersion: string | undefined\n let gpu: Promise<string[]> | undefined\n\n const executor = createMachineExecutor({\n roots,\n dataDir,\n ...(options.terminalGraceMs !== undefined ? { terminalGraceMs: options.terminalGraceMs } : {}),\n ...(options.sandbox ? { sandbox: options.sandbox } : {}),\n ...(options.credentialsDataDir ? { credentialsDataDir: options.credentialsDataDir } : {}),\n notify: (method, params) => {\n if (!client)\n return false\n try {\n (client.notify as unknown as (m: string, p: unknown) => void)(method, params)\n return true\n }\n catch {\n return false\n }\n },\n })\n\n const register: MachineRegisterParams = {\n machineId,\n name: options.name,\n roots,\n capabilities: { shell: true, terminals: typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined', background: true, worktrees: true, stream: true, entries: true, sandboxed: executor.sandbox.on },\n version: options.appVersion ?? ZIDANE_VERSION,\n protocolVersion: MACHINE_PROTOCOL_VERSION,\n }\n\n const loop = keepHostConnected({\n minDelayMs: options.minDelayMs ?? 1000,\n maxDelayMs: options.maxDelayMs ?? 30_000,\n async connect({ signal, onClose }) {\n const expectHostId = pins.get(url)\n const connected = await connectWsClient({\n url,\n token: options.token,\n signal,\n onClose,\n appVersion: register.version,\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n ...(expectHostId ? { expectHostId } : {}),\n serve: {\n request: (method, params) => executor.handle(method, params),\n notification: (method, params) => void executor.handle(method, params).catch(() => undefined),\n },\n })\n gpu ??= options.gpu ? options.gpu().catch(() => []) : Promise.resolve([])\n const gpuNames = await gpu\n const params: MachineRegisterParams = gpuNames.length > 0 ? { ...register, capabilities: { ...register.capabilities, gpu: gpuNames } } : register\n try {\n await (connected.request as unknown as (m: string, p: unknown) => Promise<MachineRegisterResult>)('machine.register', params)\n }\n catch (err) {\n connected.close()\n const code = err instanceof JsonRpcRemoteError ? err.code : undefined\n throw new MachineRegisterError(`${displayHostUrl(url)} refused this machine: ${(err as Error).message}`, code === MachineErrorCode.NameTaken || code === MachineErrorCode.VersionSkew || code === MachineErrorCode.IdBound)\n }\n if (!expectHostId && connected.hello.hostId)\n pins.set(url, connected.hello.hostId)\n hostVersion = connected.hello.appVersion\n options.onHostVersion?.(hostVersion)\n return connected\n },\n classify: (err) => {\n if (err instanceof HostIdentityError)\n return 'identity'\n if (err instanceof HostAuthError || (err instanceof MachineRegisterError && err.forGood))\n return 'auth'\n return err instanceof IpcVersionMismatchError ? 'protocol' : 'retry'\n },\n update: (patch) => {\n if (patch.client !== undefined)\n client = patch.client\n if (patch.status) {\n status = patch.status\n options.onStatus?.(patch.status, patch.error)\n }\n },\n onConnected: () => executor.linkUp(),\n onDisconnected: () => executor.linkLost(),\n })\n\n return {\n machineId,\n status: () => status,\n retry: () => loop.retry(),\n hostVersion: () => hostVersion,\n activity: () => executor.activity(),\n async stop() {\n loop.stop()\n await executor.close()\n },\n }\n}\n","/**\n * A saved server used as a machine of this local host (`local@<server>`,\n * `docs/MACHINES.md` § Reverse direction). A local host has no listener, so\n * it dials the server as a client (its saved client token), asks it to lend\n * itself (`machine.attach`), and registers it in its own machine registry\n * with a connection that sends each host→machine request as `machine.call`.\n * The server's notifications come back as `machine:notification` signals.\n * Reconnects with the hosts' connection loop; a refused token, another host\n * at the URL, or a server that does not lend itself stop it for good.\n */\nimport type { AttachedMachine, MachineConnection, MachineRegistry } from '../../chat/host/machines'\nimport type { MachineLinkState } from '../../chat/machine-protocol'\nimport type { JsonValue } from '../../types'\nimport type { IpcClient } from '../transports/client-core'\nimport { JsonRpcConnectionClosedError, JsonRpcRemoteError } from '../../acp/json-rpc'\nimport { MachineLinkLostError } from '../../chat/host/machines'\nimport { HostIdentityError } from '../../chat/hosts/connection'\nimport { displayHostUrl } from '../../chat/hosts/url'\nimport { MachineErrorCode } from '../../chat/machine-protocol'\nimport { keepHostConnected } from '../hosts/connection-loop'\nimport { connectWsClient, HostAuthError } from '../transports/ws-client'\n\nexport interface ServerMachineOptions {\n machines: MachineRegistry\n url: string\n /** The saved server's client token. */\n token: string\n /** The saved server's host id: another host at the URL is refused. */\n expectHostId: string\n /** This host's id (the server keys its executor by it, so tasks survive a reconnect). */\n localHostId: string\n appVersion?: string\n onState: (state: MachineLinkState, detail?: string, machineName?: string) => void\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n}\n\nexport interface ServerMachine {\n retry: () => void\n stop: () => void\n}\n\n/** The server refused to lend itself (`allowAsMachine` off, a name taken here): for good. A busy server is retried. */\nclass AttachRefusedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'AttachRefusedError'\n }\n}\n\nfunction connectionOver(client: IpcClient): MachineConnection {\n return {\n async request(method, params) {\n try {\n return await client.request('machine.call', { method, params: (params ?? {}) as JsonValue })\n }\n catch (err) {\n if (err instanceof JsonRpcConnectionClosedError)\n throw new MachineLinkLostError()\n throw err instanceof JsonRpcRemoteError ? new Error(err.message) : err\n }\n },\n notify: (method, params) => client.notify('machine.call', { method, params: (params ?? {}) as JsonValue }),\n close: () => client.close(),\n }\n}\n\nexport function startServerMachine(options: ServerMachineOptions): ServerMachine {\n let attached: AttachedMachine | undefined\n const where = displayHostUrl(options.url)\n\n const detach = (): void => {\n attached?.closed()\n attached = undefined\n }\n\n const loop = keepHostConnected({\n ...(options.minDelayMs !== undefined ? { minDelayMs: options.minDelayMs } : {}),\n ...(options.maxDelayMs !== undefined ? { maxDelayMs: options.maxDelayMs } : {}),\n async connect({ signal, onClose }) {\n const client = await connectWsClient({\n url: options.url,\n token: options.token,\n expectHostId: options.expectHostId,\n signal,\n onClose,\n ...(options.appVersion ? { appVersion: options.appVersion } : {}),\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n })\n // Subscribed before attaching: the server re-sends queued task exits while it answers `machine.attach`.\n const early: Array<{ method: string, params: unknown }> = []\n let current: AttachedMachine | undefined\n client.onSignal((s) => {\n if (s.kind !== 'machine:notification')\n return\n if (current)\n current.notification(s.method, s.params)\n else if (early.length < 1024)\n early.push({ method: s.method, params: s.params })\n })\n try {\n const params = await client.request('machine.attach', { hostId: options.localHostId })\n detach()\n current = options.machines.attach(params, connectionOver(client), { server: options.expectHostId })\n attached = current\n for (const { method, params: p } of early.splice(0))\n current.notification(method, p)\n options.onState('connected', undefined, params.name)\n }\n catch (err) {\n client.close()\n // No room there now (a capacity limit) or the link dropped: the loop retries with backoff.\n if (err instanceof JsonRpcConnectionClosedError || (err instanceof JsonRpcRemoteError && err.code === MachineErrorCode.Busy))\n throw new Error(`${where} can't lend itself right now: ${(err as Error).message}`)\n throw new AttachRefusedError(`${where} refused to be a machine: ${(err as Error).message}`)\n }\n return client\n },\n classify: err => (err instanceof HostIdentityError ? 'identity' : err instanceof HostAuthError || err instanceof AttachRefusedError ? 'auth' : 'retry'),\n update: (patch) => {\n if (!patch.status || patch.status === 'connected')\n return\n options.onState(patch.status === 'auth-refused' && patch.error?.includes('refused to be a machine') ? 'refused' : patch.status, patch.error)\n },\n onDisconnected: detach,\n })\n\n return {\n retry: () => loop.retry(),\n stop() {\n loop.stop()\n detach()\n },\n }\n}\n","/**\n * `machine-links.lock`: which process runs this computer's shares (one\n * machine id, one connection; two processes sharing it would keep replacing\n * each other's). Exclusive by construction, not by a read-then-write:\n *\n * - taking a free lock is an exclusive create (`wx`): one contender wins;\n * - the record names its holder (`pid`) and a per-process `nonce`; the\n * holder touches the file on every check, so a holder is stale when its\n * pid is gone OR the file went untouched for {@link STALE_MS} (a reused\n * pid never touches it);\n * - a stale lock is moved aside (an atomic rename to a name of our own),\n * checked to be the very record judged stale, then the exclusive create\n * runs again; a live lock moved aside by mistake is put back without\n * clobbering (`link`, which fails if the name is taken);\n * - a holder re-reads the record on every check: another nonce there means\n * it lost the lock, and the caller stops its shares;\n * - release removes the file only when it still carries this nonce.\n */\nimport { randomBytes } from 'node:crypto'\nimport { closeSync, linkSync, openSync, readFileSync, renameSync, rmSync, statSync, utimesSync, writeSync } from 'node:fs'\nimport process from 'node:process'\n\n/** A holder that has not touched its lock for this long is gone (its pid may be reused). */\nexport const SHARE_LOCK_STALE_MS = 30_000\n\ninterface LockRecord {\n pid: number\n nonce: string\n}\n\nexport interface ShareLock {\n /** Hold the lock (taking it when free or stale); `false` when another live process holds it. */\n acquire: () => boolean\n /** Whether this process held it at the last {@link acquire}. */\n held: () => boolean\n /** Remove the lock when this process still holds it; whether it did. */\n release: () => boolean\n}\n\nexport interface ShareLockOptions {\n /** Test seams. */\n pid?: number\n alive?: (pid: number) => boolean\n now?: () => number\n staleMs?: number\n}\n\nfunction processAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n }\n catch (err) {\n return (err as NodeJS.ErrnoException).code === 'EPERM'\n }\n}\n\nfunction readRecord(file: string): { record?: LockRecord, mtimeMs: number } | undefined {\n try {\n const mtimeMs = statSync(file).mtimeMs\n const raw = JSON.parse(readFileSync(file, 'utf8')) as Partial<LockRecord>\n return { mtimeMs, ...(typeof raw.pid === 'number' && typeof raw.nonce === 'string' ? { record: { pid: raw.pid, nonce: raw.nonce } } : {}) }\n }\n catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT')\n return undefined\n // Unreadable or half-written: judged by its age alone.\n try {\n return { mtimeMs: statSync(file).mtimeMs }\n }\n catch {\n return undefined\n }\n }\n}\n\nexport function createShareLock(file: string, options: ShareLockOptions = {}): ShareLock {\n const pid = options.pid ?? process.pid\n const alive = options.alive ?? processAlive\n const now = options.now ?? Date.now\n const staleMs = options.staleMs ?? SHARE_LOCK_STALE_MS\n const nonce = randomBytes(12).toString('hex')\n let holding = false\n\n const create = (): boolean => {\n let fd: number\n try {\n fd = openSync(file, 'wx', 0o600)\n }\n catch {\n return false\n }\n try {\n writeSync(fd, JSON.stringify({ pid, nonce }))\n }\n finally {\n closeSync(fd)\n }\n return true\n }\n\n const ours = (): boolean => readRecord(file)?.record?.nonce === nonce\n\n const stale = (found: { record?: LockRecord, mtimeMs: number }): boolean =>\n now() - found.mtimeMs > staleMs || (found.record !== undefined && !alive(found.record.pid))\n\n /** Move a stale lock aside; `true` when the record moved is the one judged stale. */\n const evict = (judged: { record?: LockRecord, mtimeMs: number }): boolean => {\n const aside = `${file}.${nonce}.stale`\n try {\n renameSync(file, aside)\n }\n catch {\n return false\n }\n const moved = readRecord(aside)\n const same = moved?.record?.nonce === judged.record?.nonce && moved?.mtimeMs === judged.mtimeMs\n if (!same) {\n // A live lock taken meanwhile: put it back, never over a newer one.\n try {\n linkSync(aside, file)\n }\n catch {\n // Someone holds the name again; that holder's own check settles it.\n }\n }\n rmSync(aside, { force: true })\n return same\n }\n\n return {\n acquire() {\n if (holding) {\n if (ours()) {\n try {\n const at = new Date(now())\n utimesSync(file, at, at)\n }\n catch {\n // The touch is best effort; the record still names this process.\n }\n return true\n }\n holding = false\n }\n if (create()) {\n holding = true\n return true\n }\n const found = readRecord(file)\n if (found && !stale(found))\n return false\n if (found && !evict(found))\n return false\n holding = create()\n return holding\n },\n held: () => holding,\n release() {\n const mine = holding && ours()\n if (mine)\n rmSync(file, { force: true })\n holding = false\n return mine\n },\n }\n}\n","/**\n * A local host's machine links (`docs/MACHINES.md` § Client UI), loaded only\n * behind remote hosts:\n *\n * - **Shares**: this computer lent to a saved server (a machine agent in\n * this process, with the machine token stored under `machine:<hostId>`).\n * One process runs them for the whole computer: the holder of\n * `machine-links.lock` (the daemon, or the first window's in-process\n * host; exclusive, `./share-lock.ts`). Two processes sharing one computer\n * under one machine id would keep replacing each other's connection, so a\n * process that finds it lost the lock stops its shares at once.\n * - **Uses**: a saved server lent to THIS host (`local@<server>`), over its\n * own client connection. Per host process: each host has its own machine\n * registry, so each attaches under its own instance id.\n *\n * The wanted links live in `<dataDir>/machine-links.json` (any process writes\n * it); every process re-reads it every {@link POLL_MS}, the holder applies the\n * shares and publishes their state in `machine-links-status.json`. Tokens\n * are never in either file.\n */\nimport type { MachineRegistry } from '../../chat/host/machines'\nimport type { HostEntry } from '../../chat/hosts/types'\nimport type { MachineLinksStatus, MachineLinkState, MachineShareStatus, MachineUseStatus } from '../../chat/machine-protocol'\nimport type { LooseSandboxSettings } from '../../chat/sandbox-settings'\nimport type { MachineAgent } from './agent'\nimport type { ServerMachine } from './reverse'\nimport { randomBytes } from 'node:crypto'\nimport { existsSync, readFileSync, rmSync } from 'node:fs'\nimport { isAbsolute, join } from 'node:path'\nimport { OWNER_ONLY, writeJsonFileAtomic } from '../../atomic-write'\nimport { readCredentialEntry, writeCredentialEntry } from '../../chat/credentials'\nimport { createHostRegistry, hostsFilePath } from '../../chat/hosts'\nimport { isValidMachineName, machineCredentialKey } from '../../chat/machine-protocol'\nimport { startMachineAgent } from './agent'\nimport { shareableRoot } from './executor'\nimport { startServerMachine } from './reverse'\nimport { createShareLock } from './share-lock'\n\nconst POLL_MS = 2000\nconst CONFIG_FILE = 'machine-links.json'\nconst STATUS_FILE = 'machine-links-status.json'\nconst LOCK_FILE = 'machine-links.lock'\nconst MAX_ROOTS = 32\n\ninterface ShareConfig {\n hostId: string\n name: string\n roots: string[]\n}\n\ninterface LinksConfig {\n version: 1\n shares: ShareConfig[]\n uses: string[]\n}\n\nexport interface MachineLinksOptions {\n /** The host's data dir: saved hosts, credentials, these files. */\n dataDir: string\n machines: MachineRegistry\n /** This host's id (`ipc.hello`). */\n hostId: string | undefined\n /** This user's settings: a share applies their `sandbox*` to what it runs (`docs/MACHINES.md` § Sandbox). */\n settings?: () => LooseSandboxSettings\n /** Every status change, for `machine:links`. */\n onChange: (status: MachineLinksStatus) => void\n appVersion?: string\n /** Connection pacing (tests shrink them). */\n minDelayMs?: number\n maxDelayMs?: number\n heartbeatMs?: number\n pollMs?: number\n}\n\nexport interface MachineLinks {\n status: () => MachineLinksStatus\n startShare: (input: { hostId: string, name: string, roots: string[], token?: string }) => MachineLinksStatus\n stopShare: (hostId: string) => MachineLinksStatus\n setUse: (hostId: string, enabled: boolean) => MachineLinksStatus\n /** Stop everything (remote hosts turned off, or the host closes); the wanted links stay saved. */\n close: () => Promise<void>\n}\n\nfunction readJson<T>(file: string, fallback: T): T {\n try {\n return existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) as T : fallback\n }\n catch {\n return fallback\n }\n}\n\nfunction readConfig(file: string): LinksConfig {\n const raw = readJson<Partial<LinksConfig>>(file, {})\n const shares = Array.isArray(raw.shares)\n ? raw.shares.filter((s): s is ShareConfig => !!s && typeof s.hostId === 'string' && typeof s.name === 'string' && Array.isArray(s.roots) && s.roots.every(r => typeof r === 'string'))\n : []\n const uses = Array.isArray(raw.uses) ? raw.uses.filter((u): u is string => typeof u === 'string') : []\n return { version: 1, shares, uses }\n}\n\n/** The saved servers' ids; `undefined` when `hosts.json` can't be read now (never mistaken for \"every server removed\"). */\nfunction savedHostIds(dataDir: string): Set<string> | undefined {\n const file = hostsFilePath(dataDir)\n if (!existsSync(file))\n return new Set()\n try {\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as { hosts?: unknown }\n if (!Array.isArray(parsed.hosts))\n return undefined\n return new Set(parsed.hosts.map(h => (h as { id?: unknown } | null)?.id).filter((id): id is string => typeof id === 'string'))\n }\n catch {\n return undefined\n }\n}\n\n/**\n * A share's name and roots, as a client sent them: every root absolute,\n * existing, and not (by its real path) zidane's data dir, inside it, or a\n * credentials folder (`./executor`'s `shareableRoot`).\n */\nexport function checkShareInput(input: { name: string, roots: string[] }, zidaneDataDir: string): void {\n if (!isValidMachineName(input.name))\n throw new Error(`\"${input.name}\" is not a valid machine name: 1 to 64 letters, digits, \".\", \"-\" or \"_\".`)\n if (!Array.isArray(input.roots) || input.roots.length === 0)\n throw new Error('Share at least one folder.')\n if (input.roots.length > MAX_ROOTS)\n throw new Error(`Share at most ${MAX_ROOTS} folders.`)\n for (const root of input.roots) {\n if (typeof root !== 'string' || !isAbsolute(root))\n throw new Error(`${String(root)} is not an absolute folder path.`)\n shareableRoot(root, zidaneDataDir)\n }\n}\n\nexport function startMachineLinks(options: MachineLinksOptions): MachineLinks {\n const { dataDir, machines } = options\n const configFile = join(dataDir, CONFIG_FILE)\n const statusFile = join(dataDir, STATUS_FILE)\n const lock = createShareLock(join(dataDir, LOCK_FILE))\n // Reading entries and tokens needs no probe: nothing is dialed here but the links themselves.\n const hosts = createHostRegistry({ dataDir, probe: async () => ({ ok: false, error: 'unreachable', message: 'not probed here' }) })\n const instance = `${(options.hostId ?? 'local').slice(0, 40)}-${randomBytes(4).toString('hex')}`\n const pacing = {\n ...(options.minDelayMs !== undefined ? { minDelayMs: options.minDelayMs } : {}),\n ...(options.maxDelayMs !== undefined ? { maxDelayMs: options.maxDelayMs } : {}),\n ...(options.heartbeatMs !== undefined ? { heartbeatMs: options.heartbeatMs } : {}),\n }\n\n const shares = new Map<string, { config: ShareConfig, agent?: MachineAgent, status: MachineShareStatus }>()\n const uses = new Map<string, { link?: ServerMachine, status: MachineUseStatus }>()\n let holder = false\n let closed = false\n let lastPublished = ''\n\n const ownStatus = (): MachineLinksStatus => ({ shares: [...shares.values()].map(s => s.status), uses: [...uses.values()].map(u => u.status) })\n\n /** Shares as the holder reports them (another process may run them). */\n const status = (): MachineLinksStatus => {\n const own = ownStatus()\n if (holder)\n return own\n const config = readConfig(configFile)\n const published = readJson<Partial<MachineLinksStatus>>(statusFile, {})\n const known = new Map((published.shares ?? []).map(s => [s.hostId, s]))\n return {\n shares: config.shares.map(s => known.get(s.hostId) ?? { hostId: s.hostId, name: s.name, roots: s.roots, state: 'connecting' as const, detail: 'waiting for the zidane process that shares this computer' }),\n uses: own.uses,\n }\n }\n\n const publish = (): void => {\n if (closed)\n return\n const snapshot = status()\n const text = JSON.stringify(snapshot)\n if (holder) {\n try {\n writeJsonFileAtomic(statusFile, { shares: snapshot.shares }, OWNER_ONLY)\n }\n catch {\n // Best effort: other processes show \"waiting\" until it lands.\n }\n }\n if (text === lastPublished)\n return\n lastPublished = text\n options.onChange(snapshot)\n }\n\n const entry = (hostId: string): HostEntry => {\n const found = hosts.get(hostId)\n if (!found)\n throw new Error(`No saved server \"${hostId}\": add it on the Hosts page first.`)\n return found\n }\n\n function runShare(config: ShareConfig): void {\n const status: MachineShareStatus = { hostId: config.hostId, name: config.name, roots: config.roots, state: 'connecting' }\n const share: { config: ShareConfig, agent?: MachineAgent, status: MachineShareStatus } = { config, status }\n shares.set(config.hostId, share)\n const set = (state: MachineLinkState, detail?: string): void => {\n share.status = { ...status, state, ...(detail && state !== 'connected' ? { detail } : {}) }\n publish()\n }\n try {\n const server = entry(config.hostId)\n const cred = readCredentialEntry(dataDir, machineCredentialKey(config.hostId))\n const token = cred?.kind === 'apikey' ? cred.value : undefined\n if (!token)\n throw new Error(`No machine token saved for ${server.name}.`)\n share.agent = startMachineAgent({ hostUrl: server.url, token, name: config.name, roots: config.roots, dataDir: join(dataDir, 'machine'), credentialsDataDir: dataDir, ...(options.settings ? { sandbox: options.settings() } : {}), ...pacing, ...(options.appVersion ? { appVersion: options.appVersion } : {}), onStatus: (state, detail) => set(state, detail) })\n }\n catch (err) {\n set('refused', (err as Error).message)\n }\n }\n\n function runUse(hostId: string): void {\n const use: { link?: ServerMachine, status: MachineUseStatus } = { status: { hostId, state: 'connecting' } }\n uses.set(hostId, use)\n const set = (state: MachineLinkState, detail?: string, machineName?: string): void => {\n use.status = { hostId, state, ...(detail && state !== 'connected' ? { detail } : {}), ...(machineName ?? use.status.machineName ? { machineName: machineName ?? use.status.machineName } : {}) }\n publish()\n }\n try {\n const server = entry(hostId)\n const token = hosts.token(hostId)\n if (!token)\n throw new Error(`No token saved for ${server.name}: add it again.`)\n use.link = startServerMachine({ machines, url: server.url, token, expectHostId: hostId, localHostId: instance, ...pacing, ...(options.appVersion ? { appVersion: options.appVersion } : {}), onState: set })\n }\n catch (err) {\n set('refused', (err as Error).message)\n }\n }\n\n const stopShare = async (hostId: string): Promise<void> => {\n const share = shares.get(hostId)\n shares.delete(hostId)\n await share?.agent?.stop()\n }\n\n /** Bring the running links in line with the saved config. */\n function reconcile(): void {\n if (closed)\n return\n const config = readConfig(configFile)\n // A used server removed from the saved hosts (by any window or the TUI): stop using it.\n const saved = savedHostIds(dataDir)\n if (saved && config.uses.some(hostId => !saved.has(hostId))) {\n config.uses = config.uses.filter(hostId => saved.has(hostId))\n writeJsonFileAtomic(configFile, config, OWNER_ONLY)\n }\n holder = lock.acquire()\n if (!holder) {\n // Lost the lock (or never had it): another process runs this computer's shares, never two.\n for (const hostId of [...shares.keys()])\n void stopShare(hostId)\n }\n else {\n const wanted = new Map(config.shares.map(s => [s.hostId, s]))\n for (const [hostId, share] of shares) {\n const want = wanted.get(hostId)\n if (!want || JSON.stringify(want) !== JSON.stringify(share.config))\n void stopShare(hostId)\n }\n for (const share of config.shares) {\n if (!shares.has(share.hostId))\n runShare(share)\n }\n }\n const wantedUses = new Set(config.uses)\n for (const [hostId, use] of uses) {\n if (!wantedUses.has(hostId)) {\n use.link?.stop()\n uses.delete(hostId)\n }\n }\n for (const hostId of config.uses) {\n if (!uses.has(hostId))\n runUse(hostId)\n }\n // ...and forget the machine it was here, once its link is stopped (a live link would attach it again).\n if (saved)\n machines.forgetRemovedServers(saved)\n publish()\n }\n\n const writeConfig = (mutate: (config: LinksConfig) => void): MachineLinksStatus => {\n const config = readConfig(configFile)\n mutate(config)\n writeJsonFileAtomic(configFile, config, OWNER_ONLY)\n reconcile()\n return status()\n }\n\n reconcile()\n const timer = setInterval(reconcile, options.pollMs ?? POLL_MS)\n timer.unref?.()\n\n return {\n status,\n startShare(input) {\n checkShareInput(input, dataDir)\n const server = entry(input.hostId)\n const token = input.token?.trim()\n if (token)\n writeCredentialEntry(dataDir, machineCredentialKey(input.hostId), { kind: 'apikey', value: token })\n else if (readCredentialEntry(dataDir, machineCredentialKey(input.hostId))?.kind !== 'apikey')\n throw new Error(`No machine token for ${server.name}: create one there (zidane server token create --scope machine) or let this window create it.`)\n return writeConfig((config) => {\n config.shares = [...config.shares.filter(s => s.hostId !== input.hostId), { hostId: input.hostId, name: input.name, roots: [...input.roots] }]\n })\n },\n stopShare(hostId) {\n return writeConfig((config) => {\n config.shares = config.shares.filter(s => s.hostId !== hostId)\n })\n },\n setUse(hostId, enabled) {\n if (enabled) {\n const server = entry(hostId)\n if (!hosts.token(hostId))\n throw new Error(`No token saved for ${server.name}: add it again.`)\n }\n return writeConfig((config) => {\n config.uses = enabled ? [...new Set([...config.uses, hostId])] : config.uses.filter(u => u !== hostId)\n })\n },\n async close() {\n if (closed)\n return\n closed = true\n clearInterval(timer)\n for (const use of uses.values())\n use.link?.stop()\n uses.clear()\n await Promise.all([...shares.keys()].map(stopShare))\n // Only the holder's own files: a process that lost the lock leaves the new holder's alone.\n if (lock.release())\n rmSync(statusFile, { force: true })\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-BhDjJH2R.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Bt as looksLikeDefinition } from "./registry-CnnKaY9s.js";
|
|
3
3
|
//#region src/extensions/runtime/loaded-entry.ts
|
|
4
4
|
var loaded_entry_exports = /* @__PURE__ */ __exportAll({
|
|
5
5
|
NO_DEFINITION_ERROR: () => NO_DEFINITION_ERROR,
|
|
@@ -73,4 +73,4 @@ function runtimeEntryOf(loaded, enabled) {
|
|
|
73
73
|
//#endregion
|
|
74
74
|
export { runtimeLoadedExtension as a, runtimeEntryOf as i, isRuntimeLoadedExtension as n, loaded_entry_exports as r, NO_DEFINITION_ERROR as t };
|
|
75
75
|
|
|
76
|
-
//# sourceMappingURL=loaded-entry-
|
|
76
|
+
//# sourceMappingURL=loaded-entry-C0vkCVNQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loaded-entry-
|
|
1
|
+
{"version":3,"file":"loaded-entry-C0vkCVNQ.js","names":[],"sources":["../src/extensions/runtime/loaded-entry.ts"],"sourcesContent":["/**\n * How a discovered or inline extension rides in the `LoadedExtension` list\n * until `buildExtensionRegistry` hands it to the runtime. Kept apart from\n * the runtime so discovery can tag entries without loading the runtime's\n * module graph.\n */\n\nimport type { ExtensionSource } from '../api/core'\nimport type { ExtensionManifest, LoadedExtension, LoadedExtensionSource } from '../types'\nimport type { RuntimeEntry } from './host'\nimport { looksLikeDefinition } from './validate-definition'\n\n/** The load error of an entry that reached the runtime with neither a definition nor an error of its own. */\nexport const NO_DEFINITION_ERROR = 'Not an extension definition (expected an object with `apiVersion: 1`).'\n\n/** A discovered or inline extension, carried in the `LoadedExtension` list until the runtime takes it. */\nexport interface RuntimeLoadedExtension extends LoadedExtension {\n /** The module's default export (validated by the runtime). */\n runtime: { definition: unknown }\n}\n\n/**\n * Whether a loaded entry carries a module for the runtime (as opposed to a\n * load error).\n *\n * @param entry - An entry from discovery or `inlineLoadedExtension`.\n */\nexport function isRuntimeLoadedExtension(entry: LoadedExtension): entry is RuntimeLoadedExtension {\n return !!(entry as Partial<RuntimeLoadedExtension>).runtime\n}\n\n/**\n * Wraps a definition as a `LoadedExtension` entry for the runtime.\n *\n * @param definition - The module's default export (`apiVersion: 1`).\n * @param where - Folder name, folder, source and manifest.\n * @param where.name - The persisted identity (folder name, else the id).\n * @param where.dir - The extension's folder.\n * @param where.source - Where it was found.\n * @param where.manifest - Its manifest, when it has one.\n * @returns The entry.\n */\nexport function runtimeLoadedExtension(definition: unknown, where: { name?: string, dir?: string, source: LoadedExtensionSource, manifest?: ExtensionManifest }): RuntimeLoadedExtension {\n const def = looksLikeDefinition(definition) ? definition : undefined\n const name = where.name ?? def?.id ?? declaredName(definition)\n return {\n name,\n source: where.source,\n ...(where.dir !== undefined ? { dir: where.dir } : {}),\n ...(where.manifest ? { manifest: where.manifest } : {}),\n ...(def ? { definition: def } : {}),\n runtime: { definition },\n }\n}\n\n/** The `id` (else `name`) a definition that fails validation declares, for its inactive row. */\nfunction declaredName(definition: unknown): string {\n const v = (definition && typeof definition === 'object' ? definition : {}) as { id?: unknown, name?: unknown }\n return typeof v.id === 'string' ? v.id : typeof v.name === 'string' ? v.name : 'unknown'\n}\n\n/**\n * A discovered entry as the runtime loads it: its module, or its import\n * error (`RuntimeEntry.error`).\n *\n * @param loaded - An entry from discovery or {@link loadExtensionFolder}.\n * @param enabled - Whether it may run (`false`: listed disabled).\n * @returns The runtime entry.\n */\nexport function runtimeEntryOf(loaded: LoadedExtension, enabled?: boolean): RuntimeEntry {\n const source: ExtensionSource = loaded.source\n const base = { source, ...(loaded.dir !== undefined ? { dir: loaded.dir } : {}), ...(loaded.manifest ? { manifest: loaded.manifest } : {}), ...(enabled !== undefined ? { enabled } : {}) }\n if (isRuntimeLoadedExtension(loaded))\n return { ...base, definition: loaded.runtime.definition }\n return { ...base, definition: undefined, error: loaded.error ?? NO_DEFINITION_ERROR }\n}\n"],"mappings":";;;;;;;;;;AAaA,MAAa,sBAAsB;;;;;;;AAcnC,SAAgB,yBAAyB,OAAyD;CAChG,OAAO,CAAC,CAAE,MAA0C;AACtD;;;;;;;;;;;;AAaA,SAAgB,uBAAuB,YAAqB,OAA6H;CACvL,MAAM,MAAM,oBAAoB,UAAU,IAAI,aAAa,KAAA;CAE3D,OAAO;EACL,MAFW,MAAM,QAAQ,KAAK,MAAM,aAAa,UAAU;EAG3D,QAAQ,MAAM;EACd,GAAI,MAAM,QAAQ,KAAA,IAAY,EAAE,KAAK,MAAM,IAAI,IAAI,CAAC;EACpD,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;EACrD,GAAI,MAAM,EAAE,YAAY,IAAI,IAAI,CAAC;EACjC,SAAS,EAAE,WAAW;CACxB;AACF;;AAGA,SAAS,aAAa,YAA6B;CACjD,MAAM,IAAK,cAAc,OAAO,eAAe,WAAW,aAAa,CAAC;CACxE,OAAO,OAAO,EAAE,OAAO,WAAW,EAAE,KAAK,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO;AACjF;;;;;;;;;AAUA,SAAgB,eAAe,QAAyB,SAAiC;CAEvF,MAAM,OAAO;EAAE,QADiB,OAAO;EAChB,GAAI,OAAO,QAAQ,KAAA,IAAY,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;EAAI,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;EAAI,GAAI,YAAY,KAAA,IAAY,EAAE,QAAQ,IAAI,CAAC;CAAG;CAC1L,IAAI,yBAAyB,MAAM,GACjC,OAAO;EAAE,GAAG;EAAM,YAAY,OAAO,QAAQ;CAAW;CAC1D,OAAO;EAAE,GAAG;EAAM,YAAY,KAAA;EAAW,OAAO,OAAO,SAAA;CAA6B;AACtF"}
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $F as McpExecutionBinding, BF as deriveMcpToolMeta, FF as ConnectMcpServersOptions, HF as wrapDiscoveredMcpTools, IF as McpConnection, JF as resolveTransportConfig, KF as normalizeMcpServers, LF as connectMcpServers, QF as originPinnedFetch, RF as normalizeMcpBlocks, UF as expandEnvPlaceholders, VF as nonOwningMcpView, WF as expandMcpConfigEnv, XF as PinnedFetch, YF as withoutEnvPlaceholders, ZF as isAllowedRemoteUrl, aI as McpServerMatch, cI as createMcpServerPool, dP as McpServerConfig, eI as attachStderrWarnPump, iI as McpServerInstance, nI as MCP_POOL_IDLE_CLOSE_MS, oI as McpServerPool, pP as McpToolSchema, rI as MCP_POOL_KILL_SWITCH, sI as McpServerPoolOptions, tI as createStderrLineEmitter, uP as McpOAuthClientConfig, zF as resultToString } from "./index-WlE93Q6d.js";
|
|
2
2
|
export { ConnectMcpServersOptions, MCP_POOL_IDLE_CLOSE_MS, MCP_POOL_KILL_SWITCH, McpConnection, type McpExecutionBinding, type McpOAuthClientConfig, type McpServerConfig, type McpServerInstance, type McpServerMatch, type McpServerPool, type McpServerPoolOptions, type McpToolSchema, type PinnedFetch, attachStderrWarnPump, connectMcpServers, createMcpServerPool, createStderrLineEmitter, deriveMcpToolMeta, expandEnvPlaceholders, expandMcpConfigEnv, isAllowedRemoteUrl, nonOwningMcpView, normalizeMcpBlocks, normalizeMcpServers, originPinnedFetch, resolveTransportConfig, resultToString, withoutEnvPlaceholders, wrapDiscoveredMcpTools };
|