zidane 8.2.1 → 8.2.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.
Files changed (187) hide show
  1. package/dist/acp-cli.js +8 -8
  2. package/dist/{acp-D7Pr8NGt.js → acp-oYRjlh71.js} +6 -6
  3. package/dist/{acp-D7Pr8NGt.js.map → acp-oYRjlh71.js.map} +1 -1
  4. package/dist/acp.d.ts +2 -2
  5. package/dist/acp.js +1 -1
  6. package/dist/{agent-DecDtKA_.js → agent-CBQglXtH.js} +9 -379
  7. package/dist/agent-CBQglXtH.js.map +1 -0
  8. package/dist/agent.d.ts +1 -1
  9. package/dist/agent.js +1 -1
  10. package/dist/{builtin-artifact-kinds-B_OEgf8b.js → builtin-artifact-kinds-BmorPkgz.js} +36 -9
  11. package/dist/builtin-artifact-kinds-BmorPkgz.js.map +1 -0
  12. package/dist/chat/pure.d.ts +4 -4
  13. package/dist/chat/pure.js +6 -6
  14. package/dist/chat.d.ts +4 -4
  15. package/dist/chat.js +15 -15
  16. package/dist/{cli-shared-Dx4vmif6.js → cli-shared-E5m_pI8A.js} +2 -2
  17. package/dist/{cli-shared-Dx4vmif6.js.map → cli-shared-E5m_pI8A.js.map} +1 -1
  18. package/dist/{client-core-imHuBWV3.d.ts → client-core-EEEX_u6D.d.ts} +24 -5
  19. package/dist/{client-core-imHuBWV3.d.ts.map → client-core-EEEX_u6D.d.ts.map} +1 -1
  20. package/dist/{connection-loop-CdHt3iQi.d.ts → connection-loop-CpgfUmuw.d.ts} +3 -3
  21. package/dist/{connection-loop-CdHt3iQi.d.ts.map → connection-loop-CpgfUmuw.d.ts.map} +1 -1
  22. package/dist/contexts/daytona.d.ts +1 -1
  23. package/dist/contexts/e2b.d.ts +1 -1
  24. package/dist/{credentials-Dti61yoi.js → credentials-B9DfBJP9.js} +11 -7
  25. package/dist/credentials-B9DfBJP9.js.map +1 -0
  26. package/dist/daemon-cli.js +2 -2
  27. package/dist/{dispatcher-vy3J6JMA.js → dispatcher-Bv9-c6I2.js} +28 -14
  28. package/dist/dispatcher-Bv9-c6I2.js.map +1 -0
  29. package/dist/{engine-BN6PjWAW.js → engine-XmoPPB6U.js} +5 -5
  30. package/dist/{engine-BN6PjWAW.js.map → engine-XmoPPB6U.js.map} +1 -1
  31. package/dist/{eval-BaJtxLCW.js → eval-CfQlBR81.js} +2 -2
  32. package/dist/{eval-BaJtxLCW.js.map → eval-CfQlBR81.js.map} +1 -1
  33. package/dist/eval.d.ts +1 -1
  34. package/dist/eval.js +1 -1
  35. package/dist/{executor-CT4oUkg6.js → executor-BhthPE1q.js} +3 -3
  36. package/dist/{executor-CT4oUkg6.js.map → executor-BhthPE1q.js.map} +1 -1
  37. package/dist/{extensions-BKt7lxxv.js → extensions-BgBwogRW.js} +114 -113
  38. package/dist/extensions-BgBwogRW.js.map +1 -0
  39. package/dist/extensions.d.ts +1 -1
  40. package/dist/extensions.js +2 -2
  41. package/dist/{fold-rules-BYedvsH7.d.ts → fold-rules-DSypi36k.d.ts} +2 -2
  42. package/dist/{fold-rules-BYedvsH7.d.ts.map → fold-rules-DSypi36k.d.ts.map} +1 -1
  43. package/dist/google-O6pRnddf.js +881 -0
  44. package/dist/google-O6pRnddf.js.map +1 -0
  45. package/dist/{headless-Ebd1ZEzC.js → headless-R4pbpTkm.js} +3 -3
  46. package/dist/{headless-Ebd1ZEzC.js.map → headless-R4pbpTkm.js.map} +1 -1
  47. package/dist/headless.d.ts +1 -1
  48. package/dist/headless.js +1 -1
  49. package/dist/{host-scoped-settings-Cy_zbmB_.js → host-scoped-settings-C-Nmb6vr.js} +2 -2
  50. package/dist/{host-scoped-settings-Cy_zbmB_.js.map → host-scoped-settings-C-Nmb6vr.js.map} +1 -1
  51. package/dist/{host-signals-Cx2IAbHh.js → host-signals-BFudPyCT.js} +5 -5
  52. package/dist/{host-signals-Cx2IAbHh.js.map → host-signals-BFudPyCT.js.map} +1 -1
  53. package/dist/{index-pc71ADi6.d.ts → index-AqRZ3gEz.d.ts} +71 -4
  54. package/dist/index-AqRZ3gEz.d.ts.map +1 -0
  55. package/dist/{index-Bt_G2Z_2.d.ts → index-CDS7YdUC.d.ts} +5 -5
  56. package/dist/{index-Bt_G2Z_2.d.ts.map → index-CDS7YdUC.d.ts.map} +1 -1
  57. package/dist/{index-CidMTcxS.d.ts → index-DyQyDLX1.d.ts} +167 -10
  58. package/dist/index-DyQyDLX1.d.ts.map +1 -0
  59. package/dist/index.d.ts +3 -3
  60. package/dist/index.js +15 -15
  61. package/dist/ipc/remote.d.ts +5 -5
  62. package/dist/ipc/remote.js +3 -3
  63. package/dist/ipc.d.ts +5 -5
  64. package/dist/ipc.js +7 -7
  65. package/dist/{links-DSZ4uQ5w.js → links-rFaWqS2Y.js} +10 -10
  66. package/dist/{links-DSZ4uQ5w.js.map → links-rFaWqS2Y.js.map} +1 -1
  67. package/dist/{mcp-allowlist-BQ5MvhHi.js → mcp-allowlist-CLXweyxk.js} +14 -3
  68. package/dist/mcp-allowlist-CLXweyxk.js.map +1 -0
  69. package/dist/mcp.d.ts +1 -1
  70. package/dist/{oauth-BSqXgads.js → oauth-7_48zR7n.js} +226 -40
  71. package/dist/oauth-7_48zR7n.js.map +1 -0
  72. package/dist/{openai-dTmPxM6T.js → openai-Rh6u5NXF.js} +121 -2
  73. package/dist/openai-Rh6u5NXF.js.map +1 -0
  74. package/dist/{openrouter-CtZbQDa0.js → openrouter-Dg0yaI-o.js} +91 -2
  75. package/dist/openrouter-Dg0yaI-o.js.map +1 -0
  76. package/dist/output/stream-json.d.ts +1 -1
  77. package/dist/output/terminal.d.ts +1 -1
  78. package/dist/plugins.d.ts +1 -1
  79. package/dist/{presets-EzlHyFSi.js → presets-DXeHsd24.js} +3 -3
  80. package/dist/{presets-EzlHyFSi.js.map → presets-DXeHsd24.js.map} +1 -1
  81. package/dist/presets.d.ts +1 -1
  82. package/dist/presets.js +1 -1
  83. package/dist/{prompts-D2lPHLOV.d.ts → prompts-DmY13jvF.d.ts} +2 -1
  84. package/dist/prompts-DmY13jvF.d.ts.map +1 -0
  85. package/dist/protocol-BIv1Yuvl.js.map +1 -1
  86. package/dist/providers/anthropic.d.ts +1 -1
  87. package/dist/providers/arcee.d.ts +1 -1
  88. package/dist/providers/baseten.d.ts +1 -1
  89. package/dist/providers/cerebras.d.ts +1 -1
  90. package/dist/providers/google.d.ts +1 -1
  91. package/dist/providers/google.js +1 -784
  92. package/dist/providers/local.d.ts +1 -1
  93. package/dist/providers/neuralwatt.d.ts +1 -1
  94. package/dist/providers/openai-compat.d.ts +1 -1
  95. package/dist/providers/openai.d.ts +1 -1
  96. package/dist/providers/openai.js +1 -1
  97. package/dist/providers/openrouter.d.ts +1 -1
  98. package/dist/providers/openrouter.js +1 -1
  99. package/dist/providers/xai.d.ts +1 -1
  100. package/dist/providers/xai.js +1 -101
  101. package/dist/providers.d.ts +2 -2
  102. package/dist/providers.js +6 -5
  103. package/dist/{registry-BBaEgTsX.js → registry-eourRLY2.js} +3 -3
  104. package/dist/{registry-BBaEgTsX.js.map → registry-eourRLY2.js.map} +1 -1
  105. package/dist/{remote-hosts-bO7wOt44.js → remote-hosts-DY2J07ut.js} +4 -4
  106. package/dist/{remote-hosts-bO7wOt44.js.map → remote-hosts-DY2J07ut.js.map} +1 -1
  107. package/dist/restate.d.ts +1 -1
  108. package/dist/{secret-shapes-Cda65uDH.js → secret-shapes-BjW4l6U0.js} +17 -3
  109. package/dist/secret-shapes-BjW4l6U0.js.map +1 -0
  110. package/dist/session/sqlite.d.ts +1 -1
  111. package/dist/{session-factory-BazyVdzj.js → session-factory-CMwIXE-7.js} +5 -5
  112. package/dist/{session-factory-BazyVdzj.js.map → session-factory-CMwIXE-7.js.map} +1 -1
  113. package/dist/session.d.ts +1 -1
  114. package/dist/{settings-keys-zYaer8DY.js → settings-keys-CPdmkTz7.js} +3 -3
  115. package/dist/{settings-keys-zYaer8DY.js.map → settings-keys-CPdmkTz7.js.map} +1 -1
  116. package/dist/{shell-path-od9XHRPt.js → shell-path-B8b3EOtK.js} +3 -3
  117. package/dist/{shell-path-od9XHRPt.js.map → shell-path-B8b3EOtK.js.map} +1 -1
  118. package/dist/{skills-use-D68a1gyZ.js → skills-use-CssTEaIj.js} +375 -2
  119. package/dist/skills-use-CssTEaIj.js.map +1 -0
  120. package/dist/skills.d.ts +1 -1
  121. package/dist/store-L01W0gGI.js.map +1 -1
  122. package/dist/{system-freeze-DXvJpveP.js → system-freeze-Um9ZJiPo.js} +24 -9
  123. package/dist/system-freeze-Um9ZJiPo.js.map +1 -0
  124. package/dist/{todo-edits-CmqNFvLJ.js → todo-edits-BERpCRPj.js} +3 -3
  125. package/dist/{todo-edits-CmqNFvLJ.js.map → todo-edits-BERpCRPj.js.map} +1 -1
  126. package/dist/tools/fetch-url.d.ts +1 -1
  127. package/dist/tools/prompts.d.ts +1 -1
  128. package/dist/tools/prompts.js +7 -0
  129. package/dist/tools/prompts.js.map +1 -1
  130. package/dist/tools/web-search.d.ts +1 -1
  131. package/dist/{tools-9Dpm8F-f.js → tools-pZVFIJ_K.js} +273 -2
  132. package/dist/tools-pZVFIJ_K.js.map +1 -0
  133. package/dist/tools.d.ts +3 -3
  134. package/dist/tools.js +4 -4
  135. package/dist/{transcript-anchors-B3TFJqr_.js → transcript-anchors-jHrg-r-H.js} +10 -10
  136. package/dist/{transcript-anchors-B3TFJqr_.js.map → transcript-anchors-jHrg-r-H.js.map} +1 -1
  137. package/dist/{transcript-reconcile-BC2DbTmp.js → transcript-reconcile-CPdrNbbR.js} +19 -2
  138. package/dist/{transcript-reconcile-BC2DbTmp.js.map → transcript-reconcile-CPdrNbbR.js.map} +1 -1
  139. package/dist/tui.d.ts +7 -7
  140. package/dist/tui.js +25 -23
  141. package/dist/tui.js.map +1 -1
  142. package/dist/{turn-operations-CIFoOebZ.d.ts → turn-operations-DuGtKuc_.d.ts} +10 -3
  143. package/dist/turn-operations-DuGtKuc_.d.ts.map +1 -0
  144. package/dist/{types-iFLlZKd0.d.ts → types-C0PJmBaO.d.ts} +2 -2
  145. package/dist/{types-iFLlZKd0.d.ts.map → types-C0PJmBaO.d.ts.map} +1 -1
  146. package/dist/types-JzccL5GE.js +24 -0
  147. package/dist/types-JzccL5GE.js.map +1 -0
  148. package/dist/types.d.ts +2 -2
  149. package/dist/{url-BTH-HE9Y.js → url-D8KZ7Edw.js} +2 -2
  150. package/dist/{url-BTH-HE9Y.js.map → url-D8KZ7Edw.js.map} +1 -1
  151. package/dist/{version-4T82xRxQ.js → version-bd3DQJkc.js} +2 -2
  152. package/dist/{version-4T82xRxQ.js.map → version-bd3DQJkc.js.map} +1 -1
  153. package/dist/wire-DH77Z-rr.js +80 -0
  154. package/dist/wire-DH77Z-rr.js.map +1 -0
  155. package/dist/{workspace-exec-stream-By8na6vz.js → workspace-exec-stream-CyfYgqAh.js} +4 -4
  156. package/dist/{workspace-exec-stream-By8na6vz.js.map → workspace-exec-stream-CyfYgqAh.js.map} +1 -1
  157. package/dist/{write-file-B4vi3SvQ.js → write-file-QYrcDdl3.js} +3 -3
  158. package/dist/{write-file-B4vi3SvQ.js.map → write-file-QYrcDdl3.js.map} +1 -1
  159. package/dist/{ws-CS312Jpx.js → ws-CURQ2igk.js} +5 -5
  160. package/dist/{ws-CS312Jpx.js.map → ws-CURQ2igk.js.map} +1 -1
  161. package/dist/{ws-client-wWka-Jku.js → ws-client-BVljYbdb.js} +3 -3
  162. package/dist/{ws-client-wWka-Jku.js.map → ws-client-BVljYbdb.js.map} +1 -1
  163. package/dist/xai-CStTwCV2.js +182 -0
  164. package/dist/xai-CStTwCV2.js.map +1 -0
  165. package/docs/ARCHITECTURE.md +1 -0
  166. package/docs/ARTIFACTS.md +1 -1
  167. package/docs/EXTENSIONS.md +9 -5
  168. package/package.json +2 -2
  169. package/dist/agent-DecDtKA_.js.map +0 -1
  170. package/dist/builtin-artifact-kinds-B_OEgf8b.js.map +0 -1
  171. package/dist/credentials-Dti61yoi.js.map +0 -1
  172. package/dist/dispatcher-vy3J6JMA.js.map +0 -1
  173. package/dist/extensions-BKt7lxxv.js.map +0 -1
  174. package/dist/index-CidMTcxS.d.ts.map +0 -1
  175. package/dist/index-pc71ADi6.d.ts.map +0 -1
  176. package/dist/mcp-allowlist-BQ5MvhHi.js.map +0 -1
  177. package/dist/oauth-BSqXgads.js.map +0 -1
  178. package/dist/openai-dTmPxM6T.js.map +0 -1
  179. package/dist/openrouter-CtZbQDa0.js.map +0 -1
  180. package/dist/prompts-D2lPHLOV.d.ts.map +0 -1
  181. package/dist/providers/google.js.map +0 -1
  182. package/dist/providers/xai.js.map +0 -1
  183. package/dist/secret-shapes-Cda65uDH.js.map +0 -1
  184. package/dist/skills-use-D68a1gyZ.js.map +0 -1
  185. package/dist/system-freeze-DXvJpveP.js.map +0 -1
  186. package/dist/tools-9Dpm8F-f.js.map +0 -1
  187. package/dist/turn-operations-CIFoOebZ.d.ts.map +0 -1
package/dist/eval.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $n as EvalWorkspaceFile, An as CreateEvalAgentOptions, Bn as EvalCaseResult, Cn as defineEval, Dn as createReusableExecutionContext, En as ReusableExecutionContext, Fn as EvalAgentRunStats, Gn as EvalRunReporterOptions, Hn as EvalDefinitionContext, In as EvalAgentStats, Jn as EvalRunUsage, Kn as EvalRunSummary, Ln as createEvalAgent, Mn as EvalAgentMcpServers, Nn as EvalAgentRunOptions, On as artifactPath, Pn as EvalAgentRunResult, Qn as EvalVariantSummary, Rn as EvalArtifacts, Sn as clearRegisteredEvals, Tn as llmJudge, Un as EvalRunMetricAggregate, Vn as EvalDefinition, Wn as EvalRunReporter, Xn as EvalScorer, Yn as EvalScore, Zn as EvalScorerContext, _n as functionalityMetric, _r as efficiencyMetricValues, ar as TrajectoryStepKind, bn as formatEvalRunSummary, br as normalizeMetric, cn as RegisterEvalTestsOptions, cr as EFFICIENCY_METRICS, dn as runEvalCase, dr as MetricDirection, er as EvalWorkspaceOptions, fn as buildEvalRunSummary, fr as MetricEmitter, gn as fileExistsOneOf, gr as defineMetrics, hn as fileExists, hr as computeEvalTagScores, ir as TrajectoryStep, jn as EvalAgent, kn as relativeArtifactPath, ln as createEvalRunReporter, lr as EvalMetric, mn as fileContentQuality, mr as MetricSpecMap, nr as MetricStats, or as buildTrajectory, pn as fileContains, pr as MetricSpec, qn as EvalRunSummaryCase, rr as Trajectory, sn as EvalTestRunner, sr as formatTrajectoryLine, tr as EvalWorkspaceSnapshot, un as registerEvalTests, ur as EvalMetricError, vn as statusCompleted, vr as emitEfficiencyMetrics, wn as LlmJudgeOptions, xn as buildRegisteredEvals, yn as formatEvalCaseSummary, yr as finalizeEvalMetrics, zn as EvalCaseOptions } from "./index-CidMTcxS.js";
1
+ import { $n as EvalWorkspaceFile, An as CreateEvalAgentOptions, Bn as EvalCaseResult, Cn as defineEval, Dn as createReusableExecutionContext, En as ReusableExecutionContext, Fn as EvalAgentRunStats, Gn as EvalRunReporterOptions, Hn as EvalDefinitionContext, In as EvalAgentStats, Jn as EvalRunUsage, Kn as EvalRunSummary, Ln as createEvalAgent, Mn as EvalAgentMcpServers, Nn as EvalAgentRunOptions, On as artifactPath, Pn as EvalAgentRunResult, Qn as EvalVariantSummary, Rn as EvalArtifacts, Sn as clearRegisteredEvals, Tn as llmJudge, Un as EvalRunMetricAggregate, Vn as EvalDefinition, Wn as EvalRunReporter, Xn as EvalScorer, Yn as EvalScore, Zn as EvalScorerContext, _n as functionalityMetric, _r as efficiencyMetricValues, ar as TrajectoryStepKind, bn as formatEvalRunSummary, br as normalizeMetric, cn as RegisterEvalTestsOptions, cr as EFFICIENCY_METRICS, dn as runEvalCase, dr as MetricDirection, er as EvalWorkspaceOptions, fn as buildEvalRunSummary, fr as MetricEmitter, gn as fileExistsOneOf, gr as defineMetrics, hn as fileExists, hr as computeEvalTagScores, ir as TrajectoryStep, jn as EvalAgent, kn as relativeArtifactPath, ln as createEvalRunReporter, lr as EvalMetric, mn as fileContentQuality, mr as MetricSpecMap, nr as MetricStats, or as buildTrajectory, pn as fileContains, pr as MetricSpec, qn as EvalRunSummaryCase, rr as Trajectory, sn as EvalTestRunner, sr as formatTrajectoryLine, tr as EvalWorkspaceSnapshot, un as registerEvalTests, ur as EvalMetricError, vn as statusCompleted, vr as emitEfficiencyMetrics, wn as LlmJudgeOptions, xn as buildRegisteredEvals, yn as formatEvalCaseSummary, yr as finalizeEvalMetrics, zn as EvalCaseOptions } from "./index-DyQyDLX1.js";
2
2
  export { type CreateEvalAgentOptions, EFFICIENCY_METRICS, type EvalAgent, type EvalAgentMcpServers, type EvalAgentRunOptions, type EvalAgentRunResult, type EvalAgentRunStats, type EvalAgentStats, type EvalArtifacts, type EvalCaseOptions, type EvalCaseResult, type EvalDefinition, type EvalDefinitionContext, type EvalMetric, EvalMetricError, type EvalRunMetricAggregate, type EvalRunReporter, type EvalRunReporterOptions, type EvalRunSummary, type EvalRunSummaryCase, type EvalRunUsage, type EvalScore, type EvalScorer, type EvalScorerContext, EvalTestRunner, type EvalVariantSummary, type EvalWorkspaceFile, type EvalWorkspaceOptions, type EvalWorkspaceSnapshot, type LlmJudgeOptions, type MetricDirection, type MetricEmitter, type MetricSpec, type MetricSpecMap, type MetricStats, RegisterEvalTestsOptions, type ReusableExecutionContext, type Trajectory, type TrajectoryStep, type TrajectoryStepKind, artifactPath, buildEvalRunSummary, buildRegisteredEvals, buildTrajectory, clearRegisteredEvals, computeEvalTagScores, createEvalAgent, createEvalRunReporter, createReusableExecutionContext, defineEval, defineMetrics, efficiencyMetricValues, emitEfficiencyMetrics, fileContains, fileContentQuality, fileExists, fileExistsOneOf, finalizeEvalMetrics, formatEvalCaseSummary, formatEvalRunSummary, formatTrajectoryLine, functionalityMetric, llmJudge, normalizeMetric, registerEvalTests, relativeArtifactPath, runEvalCase, statusCompleted };
package/dist/eval.js CHANGED
@@ -1 +1 @@
1
- export { x as EFFICIENCY_METRICS, S as EvalMetricError, k as artifactPath, b as buildEvalRunSummary, i as buildRegisteredEvals, u as buildTrajectory, a as clearRegisteredEvals, C as computeEvalTagScores, c as createEvalAgent, t as createEvalRunReporter, l as createReusableExecutionContext, o as defineEval, w as defineMetrics, T as efficiencyMetricValues, E as emitEfficiencyMetrics, f as fileContains, p as fileContentQuality, m as fileExists, h as fileExistsOneOf, D as finalizeEvalMetrics, v as formatEvalCaseSummary, y as formatEvalRunSummary, d as formatTrajectoryLine, g as functionalityMetric, s as llmJudge, O as normalizeMetric, n as registerEvalTests, A as relativeArtifactPath, r as runEvalCase, _ as statusCompleted } from "./eval-BaJtxLCW.js";
1
+ export { x as EFFICIENCY_METRICS, S as EvalMetricError, k as artifactPath, b as buildEvalRunSummary, i as buildRegisteredEvals, u as buildTrajectory, a as clearRegisteredEvals, C as computeEvalTagScores, c as createEvalAgent, t as createEvalRunReporter, l as createReusableExecutionContext, o as defineEval, w as defineMetrics, T as efficiencyMetricValues, E as emitEfficiencyMetrics, f as fileContains, p as fileContentQuality, m as fileExists, h as fileExistsOneOf, D as finalizeEvalMetrics, v as formatEvalCaseSummary, y as formatEvalRunSummary, d as formatTrajectoryLine, g as functionalityMetric, s as llmJudge, O as normalizeMetric, n as registerEvalTests, A as relativeArtifactPath, r as runEvalCase, _ as statusCompleted } from "./eval-CfQlBR81.js";
@@ -1,8 +1,8 @@
1
1
  import { t as createProcessContext } from "./contexts-Bw06j9eP.js";
2
2
  import { t as resolveStorageDirs } from "./xdg-CJS70jqe.js";
3
3
  import { _ as workspacePath } from "./environment-B4asakh7.js";
4
- import { Dt as teardownWorktree, Et as prepareWorktree, M as createWorkspaceConfinement, N as isInside, _ as sandboxUnreadableDirs, g as resolveSandboxForRoots } from "./oauth-BSqXgads.js";
5
- import { rt as MACHINE_STREAM_CHUNK_BYTES } from "./mcp-allowlist-BQ5MvhHi.js";
4
+ import { Dt as teardownWorktree, Et as prepareWorktree, M as createWorkspaceConfinement, N as isInside, _ as sandboxUnreadableDirs, g as resolveSandboxForRoots } from "./oauth-7_48zR7n.js";
5
+ import { rt as MACHINE_STREAM_CHUNK_BYTES } from "./mcp-allowlist-CLXweyxk.js";
6
6
  import { Buffer } from "node:buffer";
7
7
  import { chmodSync, closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, statSync } from "node:fs";
8
8
  import { isAbsolute, join, resolve } from "node:path";
@@ -618,4 +618,4 @@ function createMachineExecutor(options) {
618
618
  //#endregion
619
619
  export { createMachineExecutor, shareableRoot };
620
620
 
621
- //# sourceMappingURL=executor-CT4oUkg6.js.map
621
+ //# sourceMappingURL=executor-BhthPE1q.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor-CT4oUkg6.js","names":[],"sources":["../src/ipc/machine/params.ts","../src/ipc/machine/streams.ts","../src/ipc/machine/task-logs.ts","../src/ipc/machine/terminals.ts","../src/ipc/machine/executor.ts"],"sourcesContent":["/**\n * Shape checks for what a host sends a machine. The host is not trusted: a\n * malformed request is refused before anything runs.\n */\nimport type { MachineHandleRef } from '../../chat/machine-protocol'\n\nexport type Params = Record<string, unknown>\n\nexport function paramsOf(value: unknown): Params {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw new Error('Invalid params: expected an object.')\n return value as Params\n}\n\nexport function str(params: Params, key: string): string {\n const value = params[key]\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optStr(params: Params, key: string): string | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optNum(params: Params, key: string): number | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'number' || !Number.isFinite(value))\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function num(params: Params, key: string): number {\n const value = optNum(params, key)\n if (value === undefined)\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function optEnv(params: Params, key: string): Record<string, string> | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (!value || typeof value !== 'object' || Array.isArray(value) || Object.values(value).some(v => typeof v !== 'string'))\n throw new Error(`Invalid params: \"${key}\" must map names to strings.`)\n return value as Record<string, string>\n}\n\nexport function handleRef(params: Params): MachineHandleRef {\n const handle = params.handle as Partial<MachineHandleRef> | undefined\n if (!handle || typeof handle.id !== 'string' || typeof handle.cwd !== 'string' || handle.id.length > 200)\n throw new Error('Invalid params: \"handle\" must be { id, cwd }.')\n return { id: handle.id, cwd: handle.cwd }\n}\n","/**\n * Live processes a machine runs for its host (`exec.stream`, `docs/MACHINES.md`):\n * `execStream` of its process context, its stdout / stderr sent as\n * `exec.stream.data` notifications (chunks of at most\n * `MACHINE_STREAM_CHUNK_BYTES`), then one `exec.stream.exit` once both are\n * drained. Bounded (`MACHINE_MAX_STREAMS`); a lost host link kills them all:\n * a stream carries a live protocol (a stdio MCP server), output it can't\n * deliver would desynchronize it.\n */\nimport type { ExecutionContext, ExecutionHandle, StreamHandle } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\nimport { MACHINE_MAX_STREAMS, MACHINE_STREAM_CHUNK_BYTES } from '../../chat/machine-protocol'\n\nexport interface MachineStreams {\n start: (context: ExecutionContext, handle: ExecutionHandle, input: { callId: string, command: string, cwd?: string, env?: Record<string, string> }) => Promise<{ pid: number }>\n write: (callId: string, data: string) => Promise<void>\n /** `exec.cancel` of a stream: `false` when no stream has this id. */\n kill: (callId: string) => boolean\n /** The host link dropped. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineStreams(options: {\n send: (method: 'exec.stream.data' | 'exec.stream.exit', params: Record<string, unknown>) => boolean\n}): MachineStreams {\n const streams = new Map<string, StreamHandle>()\n\n async function pump(callId: string, name: 'stdout' | 'stderr', source: AsyncIterable<Uint8Array> | undefined): Promise<void> {\n if (!source)\n return\n for await (const chunk of source) {\n for (let at = 0; at < chunk.byteLength; at += MACHINE_STREAM_CHUNK_BYTES) {\n const data = Buffer.from(chunk.subarray(at, at + MACHINE_STREAM_CHUNK_BYTES)).toString('base64')\n if (!options.send('exec.stream.data', { callId, stream: name, data }))\n void streams.get(callId)?.kill()\n }\n }\n }\n\n const kill = (callId: string): boolean => {\n const stream = streams.get(callId)\n if (!stream)\n return false\n void stream.kill().catch(() => undefined)\n return true\n }\n\n return {\n async start(context, handle, { callId, command, cwd, env }) {\n if (!context.execStream)\n throw new Error('This machine cannot stream processes.')\n if (streams.has(callId))\n throw new Error(`A stream \"${callId}\" already runs.`)\n if (streams.size >= MACHINE_MAX_STREAMS)\n throw new Error(`This machine already runs ${MACHINE_MAX_STREAMS} live processes.`)\n const stream = await context.execStream(handle, command, { ...(cwd ? { cwd } : {}), ...(env ? { env } : {}) })\n streams.set(callId, stream)\n void Promise.all([pump(callId, 'stdout', stream.stdout), pump(callId, 'stderr', stream.stderr), stream.exited])\n .catch(() => undefined)\n .then(async () => {\n const code = await stream.exited\n streams.delete(callId)\n options.send('exec.stream.exit', { callId, code })\n })\n return { pid: stream.pid }\n },\n async write(callId, data) {\n const stream = streams.get(callId)\n if (!stream)\n throw new Error(`No live process \"${callId}\" on this machine.`)\n const bytes = Buffer.from(data, 'base64')\n if (bytes.byteLength > MACHINE_STREAM_CHUNK_BYTES)\n throw new Error(`exec.stream.write: at most ${MACHINE_STREAM_CHUNK_BYTES} bytes per call.`)\n await stream.write(bytes)\n },\n kill,\n linkLost() {\n for (const callId of streams.keys())\n kill(callId)\n },\n async closeAll() {\n const all = [...streams.values()]\n streams.clear()\n await Promise.all(all.map(stream => stream.kill().catch(() => undefined)))\n },\n }\n}\n","/**\n * The machine's background-task logs (`<data dir>/tasks/`): the one place in\n * its data dir the host may read, and only the logs of tasks this machine\n * started. A command run for the host can reach that folder (no sandbox, or\n * a sandbox that allows the data dir's parent), so a log path is never\n * trusted as a path: it is opened without following a symlink, must be a\n * regular file, and its real path must be the same file inside the tasks\n * dir. Otherwise `ln -sf ~/.zidane/credentials.json <log>` would make the\n * (unsandboxed) machine process read anything for the host.\n */\nimport { Buffer } from 'node:buffer'\nimport { chmodSync, closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { isInside } from '../../chat/workspace-confinement'\n\nconst NO_FOLLOW = constants.O_NOFOLLOW ?? 0\n\nexport interface TaskLogs {\n /** The folder a handle's task logs go in: made owner-only, refused when it is not a real folder in the tasks dir. */\n outputDir: (handleId: string) => string\n add: (path: string) => void\n has: (path: string) => boolean\n count: () => number\n read: (path: string, binary: boolean) => string\n size: (path: string) => number\n}\n\n/** `path` made (or kept) an owner-only real folder; a symlink there is refused, never followed. */\nfunction ownerOnlyDir(path: string): void {\n mkdirSync(path, { recursive: true, mode: 0o700 })\n const stat = lstatSync(path)\n if (!stat.isDirectory() || stat.isSymbolicLink())\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n chmodSync(path, 0o700)\n}\n\nexport function createTaskLogs(dataDir: string): TaskLogs {\n const dir = join(dataDir, 'tasks')\n ownerOnlyDir(dir)\n const realDir = realpathSync.native(dir)\n const known = new Set<string>()\n const refused = (path: string): Error => new Error(`${path} is not a task log of this machine.`)\n\n /** An fd on the log at `path`, checked as the module header says; the caller closes it. */\n const open = (path: string): number => {\n let fd: number\n try {\n fd = openSync(path, constants.O_RDONLY | NO_FOLLOW)\n }\n catch {\n throw refused(path)\n }\n try {\n const opened = fstatSync(fd)\n const real = realpathSync.native(path)\n const named = statSync(real)\n if (!opened.isFile() || !isInside(realDir, real) || named.ino !== opened.ino || named.dev !== opened.dev)\n throw refused(path)\n return fd\n }\n catch {\n closeSync(fd)\n throw refused(path)\n }\n }\n\n const withLog = <T>(path: string, fn: (fd: number) => T): T => {\n const fd = open(path)\n try {\n return fn(fd)\n }\n finally {\n closeSync(fd)\n }\n }\n\n return {\n outputDir(handleId) {\n const path = join(dir, Buffer.from(handleId).toString('hex').slice(0, 64))\n ownerOnlyDir(path)\n if (!isInside(realDir, realpathSync.native(path)))\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n return path\n },\n add: path => void known.add(path),\n has: path => known.has(path),\n count: () => known.size,\n read: (path, binary) => withLog(path, fd => (binary ? readFileSync(fd).toString('base64') : readFileSync(fd, 'utf8'))),\n size: path => withLog(path, fd => fstatSync(fd).size),\n }\n}\n","/**\n * PTYs a machine runs for its host. They outlive the host link for a grace\n * period, buffering their output (bounded), so a host that reconnects\n * reattaches with the backlog; past the grace they are killed.\n */\nimport type { ExecutionContext, ExecutionHandle, TerminalProcess } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\n\nexport const MACHINE_MAX_TERMINALS = 16\nexport const MACHINE_TERMINAL_BACKLOG_BYTES = 256 * 1024\nexport const MACHINE_TERMINAL_GRACE_MS = 5 * 60 * 1000\n\ninterface Entry {\n process: TerminalProcess\n backlog: Buffer[]\n backlogBytes: number\n /** Bytes produced since it opened. */\n total: number\n graceTimer?: ReturnType<typeof setTimeout>\n}\n\nexport interface MachineTerminals {\n open: (context: ExecutionContext, handle: ExecutionHandle, options: { cols: number, rows: number, cwd?: string }) => Promise<string>\n attach: (terminalId: string) => { attached: boolean, backlog: string, total: number }\n write: (terminalId: string, data: string) => void\n resize: (terminalId: string, cols: number, rows: number) => void\n kill: (terminalId: string) => Promise<void>\n /** The host link dropped: start every terminal's grace period. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineTerminals(options: {\n /** Live output to the host; `false` when the link is down. */\n send: (method: 'terminal.data' | 'terminal.exit', params: Record<string, unknown>) => boolean\n graceMs?: number\n}): MachineTerminals {\n const terminals = new Map<string, Entry>()\n const graceMs = options.graceMs ?? MACHINE_TERMINAL_GRACE_MS\n\n const entry = (terminalId: string): Entry => {\n const found = terminals.get(terminalId)\n if (!found)\n throw new Error(`No terminal \"${terminalId}\" on this machine.`)\n return found\n }\n\n const remember = (e: Entry, data: Uint8Array): void => {\n e.backlog.push(Buffer.from(data))\n e.backlogBytes += data.byteLength\n e.total += data.byteLength\n while (e.backlogBytes > MACHINE_TERMINAL_BACKLOG_BYTES && e.backlog.length > 1)\n e.backlogBytes -= e.backlog.shift()!.byteLength\n }\n\n const kill = async (terminalId: string): Promise<void> => {\n const e = terminals.get(terminalId)\n if (!e)\n return\n terminals.delete(terminalId)\n clearTimeout(e.graceTimer)\n await e.process.kill().catch(() => undefined)\n }\n\n return {\n async open(context, handle, { cols, rows, cwd }) {\n if (!context.openTerminal)\n throw new Error('This machine has no terminal support (it needs Bun).')\n if (terminals.size >= MACHINE_MAX_TERMINALS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TERMINALS} terminals.`)\n const holder: { id?: string } = {}\n const pending: Uint8Array[] = []\n const process = await context.openTerminal(handle, {\n cols,\n rows,\n ...(cwd ? { cwd } : {}),\n onData: (data) => {\n const e = holder.id ? terminals.get(holder.id) : undefined\n if (!e) {\n pending.push(data)\n return\n }\n remember(e, data)\n options.send('terminal.data', { terminalId: holder.id, data: Buffer.from(data).toString('base64') })\n },\n })\n holder.id = process.id\n const e: Entry = { process, backlog: [], backlogBytes: 0, total: 0 }\n terminals.set(process.id, e)\n for (const data of pending)\n remember(e, data)\n void process.exited.then((code) => {\n if (terminals.get(process.id) !== e)\n return\n terminals.delete(process.id)\n clearTimeout(e.graceTimer)\n options.send('terminal.exit', { terminalId: process.id, code })\n })\n return process.id\n },\n attach(terminalId) {\n const e = terminals.get(terminalId)\n if (!e)\n return { attached: false, backlog: '', total: 0 }\n clearTimeout(e.graceTimer)\n e.graceTimer = undefined\n return { attached: true, backlog: Buffer.concat(e.backlog).toString('base64'), total: e.total }\n },\n write: (terminalId, data) => entry(terminalId).process.write(Buffer.from(data, 'base64')),\n resize: (terminalId, cols, rows) => entry(terminalId).process.resize(cols, rows),\n kill,\n linkLost() {\n for (const [id, e] of terminals) {\n clearTimeout(e.graceTimer)\n e.graceTimer = setTimeout(() => void kill(id), graceMs)\n e.graceTimer.unref?.()\n }\n },\n async closeAll() {\n await Promise.all([...terminals.keys()].map(kill))\n },\n }\n}\n","/**\n * What a machine runs for its host (`docs/MACHINES.md` § Machine side): the\n * machine protocol's host→machine methods, served from one `process`\n * execution context, behind a guard that never trusts the host. Every handle\n * cwd, command cwd and file path resolves against the handle's cwd and must\n * real-path into a declared root (symlinks followed), never into the\n * machine's data dir; the one exception is reading a log file of a\n * background task this machine started (`./task-logs.ts`: opened without\n * following symlinks, checked to be that file).\n *\n * Transport-free: the agent (`./agent.ts`) feeds it requests and gives it a\n * `notify` toward the host, which is `false` while the link is down (task\n * exits are then queued until {@link MachineExecutor.linkUp}).\n */\nimport type { MachineRoot } from '../../chat/machine-protocol'\nimport type { LooseSandboxSettings } from '../../chat/sandbox-settings'\nimport type { WorkspaceConfinement } from '../../chat/workspace-confinement'\nimport type { ExecutionContext, ExecutionHandle, TaskExitInfo } from '../../contexts/types'\nimport type { Params } from './params'\nimport { Buffer } from 'node:buffer'\nimport { mkdirSync, realpathSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { workspacePath } from '../../chat/environment'\nimport { prepareWorktree, teardownWorktree } from '../../chat/environments'\nimport { resolveSandboxForRoots, sandboxUnreadableDirs } from '../../chat/sandbox-settings'\nimport { createWorkspaceConfinement, isInside } from '../../chat/workspace-confinement'\nimport { resolveStorageDirs } from '../../chat/xdg'\nimport { createProcessContext } from '../../contexts/process'\nimport { handleRef, num, optEnv, optNum, optStr, paramsOf, str } from './params'\nimport { createMachineStreams } from './streams'\nimport { createTaskLogs } from './task-logs'\nimport { createMachineTerminals } from './terminals'\n\nexport const MACHINE_MAX_TASKS = 64\nexport const MACHINE_TASK_OUTPUT_BYTES = 8 * 1024 * 1024\nconst MAX_PENDING_EXITS = 256\nconst GLOB_CHARS = /[*?[\\]{}]/\n\nexport interface MachineExecutorOptions {\n roots: readonly MachineRoot[]\n /** The machine's own data dir: never reachable by file ops. */\n dataDir: string\n /** A notification to the host; `false` when the link is down. */\n notify: (method: string, params: Record<string, unknown>) => boolean\n /** Terminals' grace after the link drops. */\n terminalGraceMs?: number\n /**\n * The machine user's own `sandbox*` settings (`docs/MACHINES.md` §\n * Sandbox): applied to every command this machine runs, whatever the host.\n */\n sandbox?: LooseSandboxSettings\n /**\n * The machine user's zidane data dir: private to file operations (with the\n * rest of {@link machinePrivateDirs}) and its credential files hidden from\n * sandboxed commands.\n */\n credentialsDataDir?: string\n}\n\n/**\n * What file operations never reach, whatever the roots (`docs/MACHINES.md` §\n * Security model): zidane's own folders as this process resolves them (data,\n * config, state, cache: credentials, tokens, extensions, plugins, skills,\n * mcps.json, SYSTEM.md, the machine's data, sync files), the default\n * `~/.zidane`, the given data dir (a server's `--data-dir`), and the\n * credential folders the sandbox hides (`~/.ssh`, `~/.aws`, …).\n */\nexport function machinePrivateDirs(zidaneDataDir?: string): string[] {\n const storage = resolveStorageDirs()\n return [...new Set([\n ...(zidaneDataDir ? [zidaneDataDir] : []),\n storage.dataDir,\n storage.configDir,\n storage.stateDir,\n storage.cacheDir,\n join(homedir(), '.zidane'),\n ...sandboxUnreadableDirs(zidaneDataDir),\n ])]\n}\n\nexport interface MachineExecutor {\n /** Serve one host request; throws (the agent turns it into a JSON-RPC error). */\n handle: (method: string, params: unknown) => Promise<unknown>\n /** The host link is (back) up: re-send what was queued. */\n linkUp: () => void\n /** The host link dropped: terminals start their grace. */\n linkLost: () => void\n close: () => Promise<void>\n /** The OS sandbox the machine applies, and why it can't when it is on but unavailable. */\n sandbox: { on: boolean, warning?: string }\n}\n\n/** The static directory of a glob (`/a/b/**\\/*.ts` → `/a/b`). */\nfunction globBase(path: string): string {\n const segments = path.split('/')\n const index = segments.findIndex(s => GLOB_CHARS.test(s))\n return index < 0 ? path : segments.slice(0, index).join('/') || '/'\n}\n\n/**\n * A folder a user offers to share (`zidane machine share --root`, a share\n * link): its real path must exist and not be, or be inside, a private\n * folder (a root there would lend what {@link machinePrivateDirs} keeps out).\n * Returns the real path.\n */\nexport function shareableRoot(root: string, zidaneDataDir?: string): string {\n let real: string\n try {\n real = realpathSync.native(root)\n }\n catch {\n throw new Error(`${root} does not exist.`)\n }\n const hidden = machinePrivateDirs(zidaneDataDir).map(realPathOr).find(dir => isInside(dir, real))\n if (hidden)\n throw new Error(`${root} is inside ${hidden} (zidane's own data or credentials): share a folder outside it.`)\n return real\n}\n\nfunction realPathOr(path: string): string {\n try {\n return realpathSync.native(path)\n }\n catch {\n return path\n }\n}\n\nexport function machineConfinement(roots: readonly MachineRoot[], dataDir: string, privateDirs: readonly string[] = []): WorkspaceConfinement {\n // Worktrees made in the data dir's `worktrees/` are workspace content; nothing else there is.\n const worktrees = join(dataDir, 'worktrees')\n mkdirSync(worktrees, { recursive: true })\n return createWorkspaceConfinement([...roots.map(root => root.path), worktrees], {\n dataDir,\n privateDirs,\n names: { roots: 'the machine\\'s roots', dataDir: 'the machine\\'s data dir, which the host can\\'t reach' },\n })\n}\n\n/**\n * A listing's entries whose real path is reachable: a traversal can follow a\n * symlinked folder out of the roots, or walk into a private one, from a base\n * that passed the check.\n */\nfunction reachableEntries<T>(confinement: WorkspaceConfinement, base: string, entries: readonly T[]): T[] {\n return entries.filter((entry) => {\n const path = typeof entry === 'string' ? entry : (entry as { path?: unknown }).path\n if (typeof path !== 'string')\n return false\n try {\n confinement.checkPath(isAbsolute(path) ? path : resolve(base, path))\n return true\n }\n catch {\n return false\n }\n })\n}\n\n/** `fs.list`: a path or glob under the handle's cwd, no `..` in a pattern, only reachable entries back. */\nasync function listReachable(context: ExecutionContext, confinement: WorkspaceConfinement, handle: ExecutionHandle, params: Params): Promise<unknown[]> {\n const pattern = str(params, 'path')\n if (GLOB_CHARS.test(pattern) && pattern.split(/[/\\\\]/).includes('..'))\n throw new Error(`\"${pattern}\": a pattern can't climb with \"..\".`)\n const path = workspacePath(handle.cwd, pattern)\n confinement.checkPath(globBase(path))\n const raw = params.options && typeof params.options === 'object' ? params.options as Record<string, unknown> : {}\n const listOptions = {\n ...(typeof raw.glob === 'boolean' ? { glob: raw.glob } : {}),\n ...(typeof raw.limit === 'number' ? { limit: raw.limit } : {}),\n ...(typeof raw.metadata === 'boolean' ? { metadata: raw.metadata } : {}),\n ...(typeof raw.gitignore === 'boolean' ? { gitignore: raw.gitignore } : {}),\n }\n return reachableEntries(confinement, globBase(path), await context.listFiles(handle, path, listOptions))\n}\n\n/** One process context for every handle, under the machine user's own sandbox when it is on. */\nfunction sandboxedContext(options: MachineExecutorOptions, confinement: WorkspaceConfinement): { sandbox: ReturnType<typeof resolveSandboxForRoots>, context: ExecutionContext } {\n const sandbox = resolveSandboxForRoots(options.sandbox ?? { sandbox: false }, confinement.roots, {\n ...(options.credentialsDataDir ? { dataDir: options.credentialsDataDir } : {}),\n // Not the task logs: the machine process writes them, and a command able to write there could swap one for a symlink.\n })\n return { sandbox, context: createProcessContext({ cwd: confinement.roots[0]!, ...(sandbox.isolation ? { isolation: sandbox.isolation } : {}) }) }\n}\n\nexport function createMachineExecutor(options: MachineExecutorOptions): MachineExecutor {\n const confinement = machineConfinement(options.roots, options.dataDir, machinePrivateDirs(options.credentialsDataDir))\n const { sandbox, context } = sandboxedContext(options, confinement)\n const handles = new Map<string, ExecutionHandle>()\n const calls = new Map<string, AbortController>()\n const taskLogs = createTaskLogs(options.dataDir)\n const pendingExits: Array<Record<string, unknown>> = []\n const terminals = createMachineTerminals({ send: options.notify, ...(options.terminalGraceMs !== undefined ? { graceMs: options.terminalGraceMs } : {}) })\n const streams = createMachineStreams({ send: options.notify })\n\n /** A handle's cwd, checked on every call (not only at spawn): the host names it each time. */\n async function handleFor(params: Params): Promise<ExecutionHandle> {\n const ref = handleRef(params)\n const cwd = confinement.resolveFolder(ref.cwd)\n const existing = handles.get(ref.id)\n if (existing && existing.cwd === cwd)\n return existing\n const handle = await context.spawn({ cwd })\n handles.set(ref.id, handle)\n // The id now names another folder: the old handle (and its tasks) would otherwise live on unreachable.\n if (existing)\n await context.destroy(existing).catch(() => undefined)\n return handle\n }\n\n /** `path` resolved like the context resolves it, then confined. */\n function checked(handle: ExecutionHandle, path: string): string {\n const absolute = workspacePath(handle.cwd, path)\n confinement.checkPath(absolute)\n return absolute\n }\n\n /** A log of a task this machine started, by its path (never through the context: see `./task-logs.ts`). */\n const taskLog = (handle: ExecutionHandle, path: string): string | undefined => {\n const absolute = workspacePath(handle.cwd, path)\n return taskLogs.has(absolute) ? absolute : undefined\n }\n\n const cwdOption = (handle: ExecutionHandle, params: Params): { cwd?: string } => {\n const cwd = optStr(params, 'cwd')\n return cwd === undefined ? {} : { cwd: confinement.resolveFolder(workspacePath(handle.cwd, cwd)) }\n }\n\n const sendExit = (exit: Record<string, unknown>): void => {\n if (options.notify('task.exit', exit))\n return\n pendingExits.push(exit)\n if (pendingExits.length > MAX_PENDING_EXITS)\n pendingExits.shift()\n }\n\n const methods: Record<string, (params: Params) => Promise<unknown>> = {\n 'machine.ping': async () => ({ ok: true }),\n 'exec.spawn': async (params) => {\n const handle = await handleFor(params)\n return { id: handleRef(params).id, cwd: handle.cwd }\n },\n 'exec.run': async (params) => {\n const handle = await handleFor(params)\n const callId = str(params, 'callId')\n // A second call under one id would take over its cancel: the first could no longer be stopped.\n if (calls.has(callId))\n throw new Error(`A call \"${callId}\" is already running.`)\n const controller = new AbortController()\n calls.set(callId, controller)\n try {\n const env = optEnv(params, 'env')\n const timeout = optNum(params, 'timeout')\n return await context.exec(handle, str(params, 'command'), { ...cwdOption(handle, params), ...(env ? { env } : {}), ...(timeout !== undefined ? { timeout } : {}), signal: controller.signal })\n }\n finally {\n calls.delete(callId)\n }\n },\n 'exec.cancel': async (params) => {\n const callId = str(params, 'callId')\n const controller = calls.get(callId)\n controller?.abort()\n return { cancelled: controller !== undefined || streams.kill(callId) }\n },\n 'exec.stream': async (params) => {\n const handle = await handleFor(params)\n const env = optEnv(params, 'env')\n return streams.start(context, handle, { callId: str(params, 'callId'), command: str(params, 'command'), ...cwdOption(handle, params), ...(env ? { env } : {}) })\n },\n 'exec.stream.write': async (params) => {\n await streams.write(str(params, 'callId'), str(params, 'data'))\n return { ok: true }\n },\n 'exec.destroy': async (params) => {\n const ref = handleRef(params)\n const handle = handles.get(ref.id)\n handles.delete(ref.id)\n if (handle)\n await context.destroy(handle)\n return { ok: true }\n },\n 'fs.read': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n if (log)\n return { content: taskLogs.read(log, params.binary === true) }\n const path = checked(handle, str(params, 'path'))\n if (params.binary === true)\n return { content: Buffer.from(await context.readFileBinary!(handle, path)).toString('base64') }\n return { content: await context.readFile(handle, path) }\n },\n 'fs.write': async (params) => {\n const handle = await handleFor(params)\n await context.writeFile(handle, checked(handle, str(params, 'path')), Buffer.from(str(params, 'content'), 'base64'))\n return { ok: true }\n },\n 'fs.list': async params => ({ entries: await listReachable(context, confinement, await handleFor(params), params) }),\n 'fs.size': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n return { size: log ? taskLogs.size(log) : await context.fileSize!(handle, checked(handle, str(params, 'path'))) }\n },\n 'bg.start': async (params) => {\n const handle = await handleFor(params)\n const running = (await context.listBackground!(handle)).filter(t => t.status === 'running').length\n if (taskLogs.count() >= MACHINE_MAX_TASKS * 4 || running >= MACHINE_MAX_TASKS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TASKS} background tasks.`)\n const env = optEnv(params, 'env')\n const cap = optNum(params, 'maxOutputBytes')\n const task = await context.execBackground!(handle, str(params, 'command'), {\n ...cwdOption(handle, params),\n ...(env ? { env } : {}),\n outputDir: taskLogs.outputDir(handleRef(params).id),\n maxOutputBytes: Math.min(cap && cap > 0 ? cap : MACHINE_TASK_OUTPUT_BYTES, MACHINE_TASK_OUTPUT_BYTES),\n onExit: (info: TaskExitInfo) => sendExit({ taskId: info.taskId, exit: { ...info } }),\n })\n taskLogs.add(task.outputPath)\n return { taskId: task.taskId, pid: task.pid, outputPath: task.outputPath }\n },\n 'bg.list': async params => ({ tasks: await context.listBackground!(await handleFor(params)) }),\n 'bg.kill': async params => ({ exit: await context.killBackground!(await handleFor(params), str(params, 'taskId')) }),\n 'bg.wait': async (params) => {\n const timeoutMs = optNum(params, 'timeoutMs')\n return { exit: await context.waitBackground!(await handleFor(params), str(params, 'taskId'), timeoutMs !== undefined ? { timeoutMs } : {}) }\n },\n 'terminal.open': async (params) => {\n const handle = await handleFor(params)\n const terminalId = await terminals.open(context, handle, { cols: num(params, 'cols'), rows: num(params, 'rows'), ...cwdOption(handle, params) })\n return { terminalId }\n },\n 'terminal.attach': async params => terminals.attach(str(params, 'terminalId')),\n 'terminal.write': async (params) => {\n terminals.write(str(params, 'terminalId'), str(params, 'data'))\n return { ok: true }\n },\n 'terminal.resize': async (params) => {\n terminals.resize(str(params, 'terminalId'), num(params, 'cols'), num(params, 'rows'))\n return { ok: true }\n },\n 'terminal.kill': async (params) => {\n await terminals.kill(str(params, 'terminalId'))\n return { ok: true }\n },\n // The host stops viewing; the PTY keeps running (as after a lost link, without the grace).\n 'terminal.detach': async () => ({ ok: true }),\n 'env.checkFolder': async params => ({ cwd: confinement.resolveFolder(str(params, 'cwd')) }),\n 'env.prepareWorktree': async (params) => {\n const cwd = confinement.resolveFolder(str(params, 'cwd'))\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n const base = optStr(params, 'base')\n const prepared = await prepareWorktree({ cwd, environment: { kind: 'worktree', state: 'provisioning', branch: str(params, 'branch'), ...(base ? { base } : {}) }, config }, options.dataDir)\n const ref = prepared.environment?.ref as { path: string, repoRoot: string }\n confinement.resolveFolder(ref.path)\n return { cwd: prepared.cwd ?? ref.path, branch: prepared.environment?.branch, base: prepared.environment?.base, ref }\n },\n 'env.teardownWorktree': async (params) => {\n const ref = (params.ref ?? {}) as { path?: unknown, repoRoot?: unknown }\n if (typeof ref.path !== 'string' || typeof ref.repoRoot !== 'string')\n throw new Error('Invalid params: \"ref\" must be { path, repoRoot }.')\n confinement.checkPath(ref.path)\n confinement.resolveFolder(ref.repoRoot)\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n return teardownWorktree({ path: ref.path, repoRoot: ref.repoRoot }, optStr(params, 'branch'), config)\n },\n }\n\n return {\n async handle(method, raw) {\n if (!Object.hasOwn(methods, method))\n throw new Error(`Unknown machine method \"${method}\".`)\n return methods[method]!(paramsOf(raw))\n },\n linkUp() {\n while (pendingExits.length > 0) {\n if (!options.notify('task.exit', pendingExits[0]!))\n return\n pendingExits.shift()\n }\n },\n sandbox: { on: sandbox.isolation !== undefined, ...(sandbox.warning ? { warning: sandbox.warning } : {}) },\n linkLost: () => {\n terminals.linkLost()\n streams.linkLost()\n },\n async close() {\n for (const controller of calls.values())\n controller.abort()\n await streams.closeAll()\n await terminals.closeAll()\n await Promise.all([...handles.values()].map(handle => context.destroy(handle).catch(() => undefined)))\n handles.clear()\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"executor-BhthPE1q.js","names":[],"sources":["../src/ipc/machine/params.ts","../src/ipc/machine/streams.ts","../src/ipc/machine/task-logs.ts","../src/ipc/machine/terminals.ts","../src/ipc/machine/executor.ts"],"sourcesContent":["/**\n * Shape checks for what a host sends a machine. The host is not trusted: a\n * malformed request is refused before anything runs.\n */\nimport type { MachineHandleRef } from '../../chat/machine-protocol'\n\nexport type Params = Record<string, unknown>\n\nexport function paramsOf(value: unknown): Params {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw new Error('Invalid params: expected an object.')\n return value as Params\n}\n\nexport function str(params: Params, key: string): string {\n const value = params[key]\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optStr(params: Params, key: string): string | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'string')\n throw new Error(`Invalid params: \"${key}\" must be a string.`)\n return value\n}\n\nexport function optNum(params: Params, key: string): number | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (typeof value !== 'number' || !Number.isFinite(value))\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function num(params: Params, key: string): number {\n const value = optNum(params, key)\n if (value === undefined)\n throw new Error(`Invalid params: \"${key}\" must be a number.`)\n return value\n}\n\nexport function optEnv(params: Params, key: string): Record<string, string> | undefined {\n const value = params[key]\n if (value === undefined)\n return undefined\n if (!value || typeof value !== 'object' || Array.isArray(value) || Object.values(value).some(v => typeof v !== 'string'))\n throw new Error(`Invalid params: \"${key}\" must map names to strings.`)\n return value as Record<string, string>\n}\n\nexport function handleRef(params: Params): MachineHandleRef {\n const handle = params.handle as Partial<MachineHandleRef> | undefined\n if (!handle || typeof handle.id !== 'string' || typeof handle.cwd !== 'string' || handle.id.length > 200)\n throw new Error('Invalid params: \"handle\" must be { id, cwd }.')\n return { id: handle.id, cwd: handle.cwd }\n}\n","/**\n * Live processes a machine runs for its host (`exec.stream`, `docs/MACHINES.md`):\n * `execStream` of its process context, its stdout / stderr sent as\n * `exec.stream.data` notifications (chunks of at most\n * `MACHINE_STREAM_CHUNK_BYTES`), then one `exec.stream.exit` once both are\n * drained. Bounded (`MACHINE_MAX_STREAMS`); a lost host link kills them all:\n * a stream carries a live protocol (a stdio MCP server), output it can't\n * deliver would desynchronize it.\n */\nimport type { ExecutionContext, ExecutionHandle, StreamHandle } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\nimport { MACHINE_MAX_STREAMS, MACHINE_STREAM_CHUNK_BYTES } from '../../chat/machine-protocol'\n\nexport interface MachineStreams {\n start: (context: ExecutionContext, handle: ExecutionHandle, input: { callId: string, command: string, cwd?: string, env?: Record<string, string> }) => Promise<{ pid: number }>\n write: (callId: string, data: string) => Promise<void>\n /** `exec.cancel` of a stream: `false` when no stream has this id. */\n kill: (callId: string) => boolean\n /** The host link dropped. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineStreams(options: {\n send: (method: 'exec.stream.data' | 'exec.stream.exit', params: Record<string, unknown>) => boolean\n}): MachineStreams {\n const streams = new Map<string, StreamHandle>()\n\n async function pump(callId: string, name: 'stdout' | 'stderr', source: AsyncIterable<Uint8Array> | undefined): Promise<void> {\n if (!source)\n return\n for await (const chunk of source) {\n for (let at = 0; at < chunk.byteLength; at += MACHINE_STREAM_CHUNK_BYTES) {\n const data = Buffer.from(chunk.subarray(at, at + MACHINE_STREAM_CHUNK_BYTES)).toString('base64')\n if (!options.send('exec.stream.data', { callId, stream: name, data }))\n void streams.get(callId)?.kill()\n }\n }\n }\n\n const kill = (callId: string): boolean => {\n const stream = streams.get(callId)\n if (!stream)\n return false\n void stream.kill().catch(() => undefined)\n return true\n }\n\n return {\n async start(context, handle, { callId, command, cwd, env }) {\n if (!context.execStream)\n throw new Error('This machine cannot stream processes.')\n if (streams.has(callId))\n throw new Error(`A stream \"${callId}\" already runs.`)\n if (streams.size >= MACHINE_MAX_STREAMS)\n throw new Error(`This machine already runs ${MACHINE_MAX_STREAMS} live processes.`)\n const stream = await context.execStream(handle, command, { ...(cwd ? { cwd } : {}), ...(env ? { env } : {}) })\n streams.set(callId, stream)\n void Promise.all([pump(callId, 'stdout', stream.stdout), pump(callId, 'stderr', stream.stderr), stream.exited])\n .catch(() => undefined)\n .then(async () => {\n const code = await stream.exited\n streams.delete(callId)\n options.send('exec.stream.exit', { callId, code })\n })\n return { pid: stream.pid }\n },\n async write(callId, data) {\n const stream = streams.get(callId)\n if (!stream)\n throw new Error(`No live process \"${callId}\" on this machine.`)\n const bytes = Buffer.from(data, 'base64')\n if (bytes.byteLength > MACHINE_STREAM_CHUNK_BYTES)\n throw new Error(`exec.stream.write: at most ${MACHINE_STREAM_CHUNK_BYTES} bytes per call.`)\n await stream.write(bytes)\n },\n kill,\n linkLost() {\n for (const callId of streams.keys())\n kill(callId)\n },\n async closeAll() {\n const all = [...streams.values()]\n streams.clear()\n await Promise.all(all.map(stream => stream.kill().catch(() => undefined)))\n },\n }\n}\n","/**\n * The machine's background-task logs (`<data dir>/tasks/`): the one place in\n * its data dir the host may read, and only the logs of tasks this machine\n * started. A command run for the host can reach that folder (no sandbox, or\n * a sandbox that allows the data dir's parent), so a log path is never\n * trusted as a path: it is opened without following a symlink, must be a\n * regular file, and its real path must be the same file inside the tasks\n * dir. Otherwise `ln -sf ~/.zidane/credentials.json <log>` would make the\n * (unsandboxed) machine process read anything for the host.\n */\nimport { Buffer } from 'node:buffer'\nimport { chmodSync, closeSync, constants, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { isInside } from '../../chat/workspace-confinement'\n\nconst NO_FOLLOW = constants.O_NOFOLLOW ?? 0\n\nexport interface TaskLogs {\n /** The folder a handle's task logs go in: made owner-only, refused when it is not a real folder in the tasks dir. */\n outputDir: (handleId: string) => string\n add: (path: string) => void\n has: (path: string) => boolean\n count: () => number\n read: (path: string, binary: boolean) => string\n size: (path: string) => number\n}\n\n/** `path` made (or kept) an owner-only real folder; a symlink there is refused, never followed. */\nfunction ownerOnlyDir(path: string): void {\n mkdirSync(path, { recursive: true, mode: 0o700 })\n const stat = lstatSync(path)\n if (!stat.isDirectory() || stat.isSymbolicLink())\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n chmodSync(path, 0o700)\n}\n\nexport function createTaskLogs(dataDir: string): TaskLogs {\n const dir = join(dataDir, 'tasks')\n ownerOnlyDir(dir)\n const realDir = realpathSync.native(dir)\n const known = new Set<string>()\n const refused = (path: string): Error => new Error(`${path} is not a task log of this machine.`)\n\n /** An fd on the log at `path`, checked as the module header says; the caller closes it. */\n const open = (path: string): number => {\n let fd: number\n try {\n fd = openSync(path, constants.O_RDONLY | NO_FOLLOW)\n }\n catch {\n throw refused(path)\n }\n try {\n const opened = fstatSync(fd)\n const real = realpathSync.native(path)\n const named = statSync(real)\n if (!opened.isFile() || !isInside(realDir, real) || named.ino !== opened.ino || named.dev !== opened.dev)\n throw refused(path)\n return fd\n }\n catch {\n closeSync(fd)\n throw refused(path)\n }\n }\n\n const withLog = <T>(path: string, fn: (fd: number) => T): T => {\n const fd = open(path)\n try {\n return fn(fd)\n }\n finally {\n closeSync(fd)\n }\n }\n\n return {\n outputDir(handleId) {\n const path = join(dir, Buffer.from(handleId).toString('hex').slice(0, 64))\n ownerOnlyDir(path)\n if (!isInside(realDir, realpathSync.native(path)))\n throw new Error(`${path} is not a folder of this machine's task logs.`)\n return path\n },\n add: path => void known.add(path),\n has: path => known.has(path),\n count: () => known.size,\n read: (path, binary) => withLog(path, fd => (binary ? readFileSync(fd).toString('base64') : readFileSync(fd, 'utf8'))),\n size: path => withLog(path, fd => fstatSync(fd).size),\n }\n}\n","/**\n * PTYs a machine runs for its host. They outlive the host link for a grace\n * period, buffering their output (bounded), so a host that reconnects\n * reattaches with the backlog; past the grace they are killed.\n */\nimport type { ExecutionContext, ExecutionHandle, TerminalProcess } from '../../contexts/types'\nimport { Buffer } from 'node:buffer'\n\nexport const MACHINE_MAX_TERMINALS = 16\nexport const MACHINE_TERMINAL_BACKLOG_BYTES = 256 * 1024\nexport const MACHINE_TERMINAL_GRACE_MS = 5 * 60 * 1000\n\ninterface Entry {\n process: TerminalProcess\n backlog: Buffer[]\n backlogBytes: number\n /** Bytes produced since it opened. */\n total: number\n graceTimer?: ReturnType<typeof setTimeout>\n}\n\nexport interface MachineTerminals {\n open: (context: ExecutionContext, handle: ExecutionHandle, options: { cols: number, rows: number, cwd?: string }) => Promise<string>\n attach: (terminalId: string) => { attached: boolean, backlog: string, total: number }\n write: (terminalId: string, data: string) => void\n resize: (terminalId: string, cols: number, rows: number) => void\n kill: (terminalId: string) => Promise<void>\n /** The host link dropped: start every terminal's grace period. */\n linkLost: () => void\n closeAll: () => Promise<void>\n}\n\nexport function createMachineTerminals(options: {\n /** Live output to the host; `false` when the link is down. */\n send: (method: 'terminal.data' | 'terminal.exit', params: Record<string, unknown>) => boolean\n graceMs?: number\n}): MachineTerminals {\n const terminals = new Map<string, Entry>()\n const graceMs = options.graceMs ?? MACHINE_TERMINAL_GRACE_MS\n\n const entry = (terminalId: string): Entry => {\n const found = terminals.get(terminalId)\n if (!found)\n throw new Error(`No terminal \"${terminalId}\" on this machine.`)\n return found\n }\n\n const remember = (e: Entry, data: Uint8Array): void => {\n e.backlog.push(Buffer.from(data))\n e.backlogBytes += data.byteLength\n e.total += data.byteLength\n while (e.backlogBytes > MACHINE_TERMINAL_BACKLOG_BYTES && e.backlog.length > 1)\n e.backlogBytes -= e.backlog.shift()!.byteLength\n }\n\n const kill = async (terminalId: string): Promise<void> => {\n const e = terminals.get(terminalId)\n if (!e)\n return\n terminals.delete(terminalId)\n clearTimeout(e.graceTimer)\n await e.process.kill().catch(() => undefined)\n }\n\n return {\n async open(context, handle, { cols, rows, cwd }) {\n if (!context.openTerminal)\n throw new Error('This machine has no terminal support (it needs Bun).')\n if (terminals.size >= MACHINE_MAX_TERMINALS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TERMINALS} terminals.`)\n const holder: { id?: string } = {}\n const pending: Uint8Array[] = []\n const process = await context.openTerminal(handle, {\n cols,\n rows,\n ...(cwd ? { cwd } : {}),\n onData: (data) => {\n const e = holder.id ? terminals.get(holder.id) : undefined\n if (!e) {\n pending.push(data)\n return\n }\n remember(e, data)\n options.send('terminal.data', { terminalId: holder.id, data: Buffer.from(data).toString('base64') })\n },\n })\n holder.id = process.id\n const e: Entry = { process, backlog: [], backlogBytes: 0, total: 0 }\n terminals.set(process.id, e)\n for (const data of pending)\n remember(e, data)\n void process.exited.then((code) => {\n if (terminals.get(process.id) !== e)\n return\n terminals.delete(process.id)\n clearTimeout(e.graceTimer)\n options.send('terminal.exit', { terminalId: process.id, code })\n })\n return process.id\n },\n attach(terminalId) {\n const e = terminals.get(terminalId)\n if (!e)\n return { attached: false, backlog: '', total: 0 }\n clearTimeout(e.graceTimer)\n e.graceTimer = undefined\n return { attached: true, backlog: Buffer.concat(e.backlog).toString('base64'), total: e.total }\n },\n write: (terminalId, data) => entry(terminalId).process.write(Buffer.from(data, 'base64')),\n resize: (terminalId, cols, rows) => entry(terminalId).process.resize(cols, rows),\n kill,\n linkLost() {\n for (const [id, e] of terminals) {\n clearTimeout(e.graceTimer)\n e.graceTimer = setTimeout(() => void kill(id), graceMs)\n e.graceTimer.unref?.()\n }\n },\n async closeAll() {\n await Promise.all([...terminals.keys()].map(kill))\n },\n }\n}\n","/**\n * What a machine runs for its host (`docs/MACHINES.md` § Machine side): the\n * machine protocol's host→machine methods, served from one `process`\n * execution context, behind a guard that never trusts the host. Every handle\n * cwd, command cwd and file path resolves against the handle's cwd and must\n * real-path into a declared root (symlinks followed), never into the\n * machine's data dir; the one exception is reading a log file of a\n * background task this machine started (`./task-logs.ts`: opened without\n * following symlinks, checked to be that file).\n *\n * Transport-free: the agent (`./agent.ts`) feeds it requests and gives it a\n * `notify` toward the host, which is `false` while the link is down (task\n * exits are then queued until {@link MachineExecutor.linkUp}).\n */\nimport type { MachineRoot } from '../../chat/machine-protocol'\nimport type { LooseSandboxSettings } from '../../chat/sandbox-settings'\nimport type { WorkspaceConfinement } from '../../chat/workspace-confinement'\nimport type { ExecutionContext, ExecutionHandle, TaskExitInfo } from '../../contexts/types'\nimport type { Params } from './params'\nimport { Buffer } from 'node:buffer'\nimport { mkdirSync, realpathSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { workspacePath } from '../../chat/environment'\nimport { prepareWorktree, teardownWorktree } from '../../chat/environments'\nimport { resolveSandboxForRoots, sandboxUnreadableDirs } from '../../chat/sandbox-settings'\nimport { createWorkspaceConfinement, isInside } from '../../chat/workspace-confinement'\nimport { resolveStorageDirs } from '../../chat/xdg'\nimport { createProcessContext } from '../../contexts/process'\nimport { handleRef, num, optEnv, optNum, optStr, paramsOf, str } from './params'\nimport { createMachineStreams } from './streams'\nimport { createTaskLogs } from './task-logs'\nimport { createMachineTerminals } from './terminals'\n\nexport const MACHINE_MAX_TASKS = 64\nexport const MACHINE_TASK_OUTPUT_BYTES = 8 * 1024 * 1024\nconst MAX_PENDING_EXITS = 256\nconst GLOB_CHARS = /[*?[\\]{}]/\n\nexport interface MachineExecutorOptions {\n roots: readonly MachineRoot[]\n /** The machine's own data dir: never reachable by file ops. */\n dataDir: string\n /** A notification to the host; `false` when the link is down. */\n notify: (method: string, params: Record<string, unknown>) => boolean\n /** Terminals' grace after the link drops. */\n terminalGraceMs?: number\n /**\n * The machine user's own `sandbox*` settings (`docs/MACHINES.md` §\n * Sandbox): applied to every command this machine runs, whatever the host.\n */\n sandbox?: LooseSandboxSettings\n /**\n * The machine user's zidane data dir: private to file operations (with the\n * rest of {@link machinePrivateDirs}) and its credential files hidden from\n * sandboxed commands.\n */\n credentialsDataDir?: string\n}\n\n/**\n * What file operations never reach, whatever the roots (`docs/MACHINES.md` §\n * Security model): zidane's own folders as this process resolves them (data,\n * config, state, cache: credentials, tokens, extensions, plugins, skills,\n * mcps.json, SYSTEM.md, the machine's data, sync files), the default\n * `~/.zidane`, the given data dir (a server's `--data-dir`), and the\n * credential folders the sandbox hides (`~/.ssh`, `~/.aws`, …).\n */\nexport function machinePrivateDirs(zidaneDataDir?: string): string[] {\n const storage = resolveStorageDirs()\n return [...new Set([\n ...(zidaneDataDir ? [zidaneDataDir] : []),\n storage.dataDir,\n storage.configDir,\n storage.stateDir,\n storage.cacheDir,\n join(homedir(), '.zidane'),\n ...sandboxUnreadableDirs(zidaneDataDir),\n ])]\n}\n\nexport interface MachineExecutor {\n /** Serve one host request; throws (the agent turns it into a JSON-RPC error). */\n handle: (method: string, params: unknown) => Promise<unknown>\n /** The host link is (back) up: re-send what was queued. */\n linkUp: () => void\n /** The host link dropped: terminals start their grace. */\n linkLost: () => void\n close: () => Promise<void>\n /** The OS sandbox the machine applies, and why it can't when it is on but unavailable. */\n sandbox: { on: boolean, warning?: string }\n}\n\n/** The static directory of a glob (`/a/b/**\\/*.ts` → `/a/b`). */\nfunction globBase(path: string): string {\n const segments = path.split('/')\n const index = segments.findIndex(s => GLOB_CHARS.test(s))\n return index < 0 ? path : segments.slice(0, index).join('/') || '/'\n}\n\n/**\n * A folder a user offers to share (`zidane machine share --root`, a share\n * link): its real path must exist and not be, or be inside, a private\n * folder (a root there would lend what {@link machinePrivateDirs} keeps out).\n * Returns the real path.\n */\nexport function shareableRoot(root: string, zidaneDataDir?: string): string {\n let real: string\n try {\n real = realpathSync.native(root)\n }\n catch {\n throw new Error(`${root} does not exist.`)\n }\n const hidden = machinePrivateDirs(zidaneDataDir).map(realPathOr).find(dir => isInside(dir, real))\n if (hidden)\n throw new Error(`${root} is inside ${hidden} (zidane's own data or credentials): share a folder outside it.`)\n return real\n}\n\nfunction realPathOr(path: string): string {\n try {\n return realpathSync.native(path)\n }\n catch {\n return path\n }\n}\n\nexport function machineConfinement(roots: readonly MachineRoot[], dataDir: string, privateDirs: readonly string[] = []): WorkspaceConfinement {\n // Worktrees made in the data dir's `worktrees/` are workspace content; nothing else there is.\n const worktrees = join(dataDir, 'worktrees')\n mkdirSync(worktrees, { recursive: true })\n return createWorkspaceConfinement([...roots.map(root => root.path), worktrees], {\n dataDir,\n privateDirs,\n names: { roots: 'the machine\\'s roots', dataDir: 'the machine\\'s data dir, which the host can\\'t reach' },\n })\n}\n\n/**\n * A listing's entries whose real path is reachable: a traversal can follow a\n * symlinked folder out of the roots, or walk into a private one, from a base\n * that passed the check.\n */\nfunction reachableEntries<T>(confinement: WorkspaceConfinement, base: string, entries: readonly T[]): T[] {\n return entries.filter((entry) => {\n const path = typeof entry === 'string' ? entry : (entry as { path?: unknown }).path\n if (typeof path !== 'string')\n return false\n try {\n confinement.checkPath(isAbsolute(path) ? path : resolve(base, path))\n return true\n }\n catch {\n return false\n }\n })\n}\n\n/** `fs.list`: a path or glob under the handle's cwd, no `..` in a pattern, only reachable entries back. */\nasync function listReachable(context: ExecutionContext, confinement: WorkspaceConfinement, handle: ExecutionHandle, params: Params): Promise<unknown[]> {\n const pattern = str(params, 'path')\n if (GLOB_CHARS.test(pattern) && pattern.split(/[/\\\\]/).includes('..'))\n throw new Error(`\"${pattern}\": a pattern can't climb with \"..\".`)\n const path = workspacePath(handle.cwd, pattern)\n confinement.checkPath(globBase(path))\n const raw = params.options && typeof params.options === 'object' ? params.options as Record<string, unknown> : {}\n const listOptions = {\n ...(typeof raw.glob === 'boolean' ? { glob: raw.glob } : {}),\n ...(typeof raw.limit === 'number' ? { limit: raw.limit } : {}),\n ...(typeof raw.metadata === 'boolean' ? { metadata: raw.metadata } : {}),\n ...(typeof raw.gitignore === 'boolean' ? { gitignore: raw.gitignore } : {}),\n }\n return reachableEntries(confinement, globBase(path), await context.listFiles(handle, path, listOptions))\n}\n\n/** One process context for every handle, under the machine user's own sandbox when it is on. */\nfunction sandboxedContext(options: MachineExecutorOptions, confinement: WorkspaceConfinement): { sandbox: ReturnType<typeof resolveSandboxForRoots>, context: ExecutionContext } {\n const sandbox = resolveSandboxForRoots(options.sandbox ?? { sandbox: false }, confinement.roots, {\n ...(options.credentialsDataDir ? { dataDir: options.credentialsDataDir } : {}),\n // Not the task logs: the machine process writes them, and a command able to write there could swap one for a symlink.\n })\n return { sandbox, context: createProcessContext({ cwd: confinement.roots[0]!, ...(sandbox.isolation ? { isolation: sandbox.isolation } : {}) }) }\n}\n\nexport function createMachineExecutor(options: MachineExecutorOptions): MachineExecutor {\n const confinement = machineConfinement(options.roots, options.dataDir, machinePrivateDirs(options.credentialsDataDir))\n const { sandbox, context } = sandboxedContext(options, confinement)\n const handles = new Map<string, ExecutionHandle>()\n const calls = new Map<string, AbortController>()\n const taskLogs = createTaskLogs(options.dataDir)\n const pendingExits: Array<Record<string, unknown>> = []\n const terminals = createMachineTerminals({ send: options.notify, ...(options.terminalGraceMs !== undefined ? { graceMs: options.terminalGraceMs } : {}) })\n const streams = createMachineStreams({ send: options.notify })\n\n /** A handle's cwd, checked on every call (not only at spawn): the host names it each time. */\n async function handleFor(params: Params): Promise<ExecutionHandle> {\n const ref = handleRef(params)\n const cwd = confinement.resolveFolder(ref.cwd)\n const existing = handles.get(ref.id)\n if (existing && existing.cwd === cwd)\n return existing\n const handle = await context.spawn({ cwd })\n handles.set(ref.id, handle)\n // The id now names another folder: the old handle (and its tasks) would otherwise live on unreachable.\n if (existing)\n await context.destroy(existing).catch(() => undefined)\n return handle\n }\n\n /** `path` resolved like the context resolves it, then confined. */\n function checked(handle: ExecutionHandle, path: string): string {\n const absolute = workspacePath(handle.cwd, path)\n confinement.checkPath(absolute)\n return absolute\n }\n\n /** A log of a task this machine started, by its path (never through the context: see `./task-logs.ts`). */\n const taskLog = (handle: ExecutionHandle, path: string): string | undefined => {\n const absolute = workspacePath(handle.cwd, path)\n return taskLogs.has(absolute) ? absolute : undefined\n }\n\n const cwdOption = (handle: ExecutionHandle, params: Params): { cwd?: string } => {\n const cwd = optStr(params, 'cwd')\n return cwd === undefined ? {} : { cwd: confinement.resolveFolder(workspacePath(handle.cwd, cwd)) }\n }\n\n const sendExit = (exit: Record<string, unknown>): void => {\n if (options.notify('task.exit', exit))\n return\n pendingExits.push(exit)\n if (pendingExits.length > MAX_PENDING_EXITS)\n pendingExits.shift()\n }\n\n const methods: Record<string, (params: Params) => Promise<unknown>> = {\n 'machine.ping': async () => ({ ok: true }),\n 'exec.spawn': async (params) => {\n const handle = await handleFor(params)\n return { id: handleRef(params).id, cwd: handle.cwd }\n },\n 'exec.run': async (params) => {\n const handle = await handleFor(params)\n const callId = str(params, 'callId')\n // A second call under one id would take over its cancel: the first could no longer be stopped.\n if (calls.has(callId))\n throw new Error(`A call \"${callId}\" is already running.`)\n const controller = new AbortController()\n calls.set(callId, controller)\n try {\n const env = optEnv(params, 'env')\n const timeout = optNum(params, 'timeout')\n return await context.exec(handle, str(params, 'command'), { ...cwdOption(handle, params), ...(env ? { env } : {}), ...(timeout !== undefined ? { timeout } : {}), signal: controller.signal })\n }\n finally {\n calls.delete(callId)\n }\n },\n 'exec.cancel': async (params) => {\n const callId = str(params, 'callId')\n const controller = calls.get(callId)\n controller?.abort()\n return { cancelled: controller !== undefined || streams.kill(callId) }\n },\n 'exec.stream': async (params) => {\n const handle = await handleFor(params)\n const env = optEnv(params, 'env')\n return streams.start(context, handle, { callId: str(params, 'callId'), command: str(params, 'command'), ...cwdOption(handle, params), ...(env ? { env } : {}) })\n },\n 'exec.stream.write': async (params) => {\n await streams.write(str(params, 'callId'), str(params, 'data'))\n return { ok: true }\n },\n 'exec.destroy': async (params) => {\n const ref = handleRef(params)\n const handle = handles.get(ref.id)\n handles.delete(ref.id)\n if (handle)\n await context.destroy(handle)\n return { ok: true }\n },\n 'fs.read': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n if (log)\n return { content: taskLogs.read(log, params.binary === true) }\n const path = checked(handle, str(params, 'path'))\n if (params.binary === true)\n return { content: Buffer.from(await context.readFileBinary!(handle, path)).toString('base64') }\n return { content: await context.readFile(handle, path) }\n },\n 'fs.write': async (params) => {\n const handle = await handleFor(params)\n await context.writeFile(handle, checked(handle, str(params, 'path')), Buffer.from(str(params, 'content'), 'base64'))\n return { ok: true }\n },\n 'fs.list': async params => ({ entries: await listReachable(context, confinement, await handleFor(params), params) }),\n 'fs.size': async (params) => {\n const handle = await handleFor(params)\n const log = taskLog(handle, str(params, 'path'))\n return { size: log ? taskLogs.size(log) : await context.fileSize!(handle, checked(handle, str(params, 'path'))) }\n },\n 'bg.start': async (params) => {\n const handle = await handleFor(params)\n const running = (await context.listBackground!(handle)).filter(t => t.status === 'running').length\n if (taskLogs.count() >= MACHINE_MAX_TASKS * 4 || running >= MACHINE_MAX_TASKS)\n throw new Error(`This machine already runs ${MACHINE_MAX_TASKS} background tasks.`)\n const env = optEnv(params, 'env')\n const cap = optNum(params, 'maxOutputBytes')\n const task = await context.execBackground!(handle, str(params, 'command'), {\n ...cwdOption(handle, params),\n ...(env ? { env } : {}),\n outputDir: taskLogs.outputDir(handleRef(params).id),\n maxOutputBytes: Math.min(cap && cap > 0 ? cap : MACHINE_TASK_OUTPUT_BYTES, MACHINE_TASK_OUTPUT_BYTES),\n onExit: (info: TaskExitInfo) => sendExit({ taskId: info.taskId, exit: { ...info } }),\n })\n taskLogs.add(task.outputPath)\n return { taskId: task.taskId, pid: task.pid, outputPath: task.outputPath }\n },\n 'bg.list': async params => ({ tasks: await context.listBackground!(await handleFor(params)) }),\n 'bg.kill': async params => ({ exit: await context.killBackground!(await handleFor(params), str(params, 'taskId')) }),\n 'bg.wait': async (params) => {\n const timeoutMs = optNum(params, 'timeoutMs')\n return { exit: await context.waitBackground!(await handleFor(params), str(params, 'taskId'), timeoutMs !== undefined ? { timeoutMs } : {}) }\n },\n 'terminal.open': async (params) => {\n const handle = await handleFor(params)\n const terminalId = await terminals.open(context, handle, { cols: num(params, 'cols'), rows: num(params, 'rows'), ...cwdOption(handle, params) })\n return { terminalId }\n },\n 'terminal.attach': async params => terminals.attach(str(params, 'terminalId')),\n 'terminal.write': async (params) => {\n terminals.write(str(params, 'terminalId'), str(params, 'data'))\n return { ok: true }\n },\n 'terminal.resize': async (params) => {\n terminals.resize(str(params, 'terminalId'), num(params, 'cols'), num(params, 'rows'))\n return { ok: true }\n },\n 'terminal.kill': async (params) => {\n await terminals.kill(str(params, 'terminalId'))\n return { ok: true }\n },\n // The host stops viewing; the PTY keeps running (as after a lost link, without the grace).\n 'terminal.detach': async () => ({ ok: true }),\n 'env.checkFolder': async params => ({ cwd: confinement.resolveFolder(str(params, 'cwd')) }),\n 'env.prepareWorktree': async (params) => {\n const cwd = confinement.resolveFolder(str(params, 'cwd'))\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n const base = optStr(params, 'base')\n const prepared = await prepareWorktree({ cwd, environment: { kind: 'worktree', state: 'provisioning', branch: str(params, 'branch'), ...(base ? { base } : {}) }, config }, options.dataDir)\n const ref = prepared.environment?.ref as { path: string, repoRoot: string }\n confinement.resolveFolder(ref.path)\n return { cwd: prepared.cwd ?? ref.path, branch: prepared.environment?.branch, base: prepared.environment?.base, ref }\n },\n 'env.teardownWorktree': async (params) => {\n const ref = (params.ref ?? {}) as { path?: unknown, repoRoot?: unknown }\n if (typeof ref.path !== 'string' || typeof ref.repoRoot !== 'string')\n throw new Error('Invalid params: \"ref\" must be { path, repoRoot }.')\n confinement.checkPath(ref.path)\n confinement.resolveFolder(ref.repoRoot)\n const config = (params.config && typeof params.config === 'object' ? params.config : {}) as Record<string, string | number | boolean>\n return teardownWorktree({ path: ref.path, repoRoot: ref.repoRoot }, optStr(params, 'branch'), config)\n },\n }\n\n return {\n async handle(method, raw) {\n if (!Object.hasOwn(methods, method))\n throw new Error(`Unknown machine method \"${method}\".`)\n return methods[method]!(paramsOf(raw))\n },\n linkUp() {\n while (pendingExits.length > 0) {\n if (!options.notify('task.exit', pendingExits[0]!))\n return\n pendingExits.shift()\n }\n },\n sandbox: { on: sandbox.isolation !== undefined, ...(sandbox.warning ? { warning: sandbox.warning } : {}) },\n linkLost: () => {\n terminals.linkLost()\n streams.linkLost()\n },\n async close() {\n for (const controller of calls.values())\n controller.abort()\n await streams.closeAll()\n await terminals.closeAll()\n await Promise.all([...handles.values()].map(handle => context.destroy(handle).catch(() => undefined)))\n handles.clear()\n },\n }\n}\n"],"mappings":"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"}
@@ -4,11 +4,11 @@ import { a as ARTIFACT_KIND_PATTERN, u as normalizeArtifactInput } from "./metad
4
4
  import { a as getExtensionSessionState, c as setExtensionSessionState, n as currentExtensionSession, r as deleteExtensionSessionState } from "./session-7TUHs42_.js";
5
5
  import { n as writeFileAtomic } from "./atomic-write-Ijgf2Mhc.js";
6
6
  import { t as projectUserPaths } from "./project-user-paths-DWqZyUgb.js";
7
- import { p as createArtifactDetectHook } from "./builtin-artifact-kinds-B_OEgf8b.js";
7
+ import { p as createArtifactDetectHook } from "./builtin-artifact-kinds-BmorPkgz.js";
8
8
  import { _ as parseInstallSource, d as InstallSourceError, g as lastLine, h as fetchInstallSource, m as defaultWhich, p as defaultExec, v as resolveNpmVersion, y as resolveSubdirRoot } from "./skills-DxT9Cnkt.js";
9
9
  import { c as compileReferencePattern, g as parseBindingSpecs, h as parseBindingSpec, n as isExtensionPanelScope, p as bindingAlternatives } from "./panels-B_DfAx68.js";
10
10
  import { r as createLogger, t as consoleSink } from "./logger-RZVCk9Ow.js";
11
- import { t as ZIDANE_VERSION } from "./version-4T82xRxQ.js";
11
+ import { t as ZIDANE_VERSION } from "./version-bd3DQJkc.js";
12
12
  import { t as resolveStorageDirs } from "./xdg-CJS70jqe.js";
13
13
  import { a as getOAuthProvider, c as registerOAuthProvider, l as unregisterOAuthProvider, t as BUILTIN_OAUTH_PROVIDER_IDS } from "./oauth-registry-DbsGvj6u.js";
14
14
  import { d as isReservedCredKey } from "./cred-keys-C0KaSRp7.js";
@@ -361,7 +361,7 @@ function toWireConfigSchema(registry) {
361
361
  * @returns The same `definition`.
362
362
  * @example
363
363
  * ```ts
364
- * import { defineExtension } from 'zidane/extensions'
364
+ * import { defineExtension } from 'zidane'
365
365
  *
366
366
  * export default defineExtension({
367
367
  * name: 'hello',
@@ -375,6 +375,69 @@ function defineExtension(definition) {
375
375
  return definition;
376
376
  }
377
377
  //#endregion
378
+ //#region src/extensions/host-modules.ts
379
+ /** Specifier → source, first registration wins. Bounded by the distinct specifiers hosts register. */
380
+ const sources = /* @__PURE__ */ new Map();
381
+ /** Resolved exports for every registered specifier; reset when a registration adds one. */
382
+ let resolved;
383
+ function toExports(mod) {
384
+ return {
385
+ ...mod,
386
+ default: mod.default ?? mod
387
+ };
388
+ }
389
+ /**
390
+ * Map bare import specifiers to the host's live module objects for every
391
+ * subsequently-imported module (extensions included). No-op outside Bun
392
+ * and for already-registered specifiers. Call BEFORE the first extension
393
+ * import (the TUI does, at startup).
394
+ *
395
+ * @param modules - Bare import specifiers mapped to a module object, or to a function that resolves one.
396
+ * @example
397
+ * ```ts
398
+ * import * as React from 'react'
399
+ * import { registerExtensionHostModules } from 'zidane/extensions'
400
+ *
401
+ * registerExtensionHostModules({ react: React })
402
+ * ```
403
+ */
404
+ function registerExtensionHostModules(modules) {
405
+ const fresh = Object.entries(modules).filter(([specifier]) => !sources.has(specifier));
406
+ if (fresh.length === 0) return;
407
+ for (const [specifier, source] of fresh) sources.set(specifier, source);
408
+ resolved = void 0;
409
+ const bun = globalThis.Bun;
410
+ if (typeof bun?.plugin !== "function") return;
411
+ bun.plugin({
412
+ name: `zidane-host-modules(${fresh.map(([s]) => s).join(",")})`,
413
+ setup(build) {
414
+ for (const [specifier, source] of fresh) build.module(specifier, async () => {
415
+ return {
416
+ exports: toExports(typeof source === "function" ? await source() : source),
417
+ loader: "object"
418
+ };
419
+ });
420
+ }
421
+ });
422
+ }
423
+ /**
424
+ * Every registered host module, resolved to its exports record (lazy
425
+ * sources awaited once and memoized). The Node extension loader passes
426
+ * this as jiti `virtualModules`; Bun hosts never need it. A rejected
427
+ * lazy source clears the memo so the next load retries.
428
+ */
429
+ function resolveExtensionHostModules() {
430
+ const pending = resolved ?? (async () => {
431
+ const entries = await Promise.all([...sources].map(async ([specifier, source]) => [specifier, toExports(typeof source === "function" ? await source() : source)]));
432
+ return Object.fromEntries(entries);
433
+ })();
434
+ resolved = pending;
435
+ pending.catch(() => {
436
+ if (resolved === pending) resolved = void 0;
437
+ });
438
+ return pending;
439
+ }
440
+ //#endregion
378
441
  //#region src/extensions/host-version.ts
379
442
  /**
380
443
  * The zidane an extension needs, checked before it loads.
@@ -818,8 +881,8 @@ function selectExtensionEntries(entries, opts) {
818
881
  }
819
882
  const requireForCache = createRequire(import.meta.url);
820
883
  /**
821
- * Monotonic import generation — appended as a query so each discovery
822
- * pass gets a fresh ENTRY module. The query alone is not enough: relative
884
+ * Bun only: monotonic import generation, appended as a query so each
885
+ * discovery pass gets a fresh ENTRY module. The query alone is not enough: relative
823
886
  * imports resolve to plain file paths and hit the cache, which is why
824
887
  * {@link evictModuleGraph} runs first. Both together are what makes
825
888
  * `/reload` a true hot-reload (verified empirically: query-only keeps
@@ -827,10 +890,11 @@ const requireForCache = createRequire(import.meta.url);
827
890
  */
828
891
  let importGeneration = 0;
829
892
  /**
830
- * Evict everything under `dir` from Bun's module cache (`require.cache`
831
- * deletion covers the ES registry for these keys). This refreshes the
832
- * extension's RELATIVE import graph; the entry itself is refreshed by the
833
- * generation query above. The extension's own `node_modules` are evicted
893
+ * Evict everything under `dir` from the module cache. Under Bun,
894
+ * `require.cache` deletion covers the ES registry for these keys and the
895
+ * entry itself is refreshed by the generation query above; under Node,
896
+ * jiti keeps the whole graph there, entry included, so eviction alone
897
+ * refreshes it. The extension's own `node_modules` are evicted
834
898
  * too so a dependency bump applies on update without a restart.
835
899
  */
836
900
  function evictModuleGraph(dir) {
@@ -848,66 +912,45 @@ function evictModuleGraph(dir) {
848
912
  }
849
913
  }
850
914
  /**
851
- * Node-only resolver shim for TypeScript extensions. Bun resolves an
852
- * extensionless relative import (`./commit`) to `commit.ts` natively, so
853
- * multi-file TS extensions Just Work under the TUI — but Node's ESM
854
- * resolver does not, so the SAME extension errored in any Node host
855
- * (the Electron GUI) with "Cannot find module …/commit" while its
856
- * single-file siblings loaded fine via type stripping. The hook retries
857
- * a FAILED relative extensionless resolution with `.ts` then
858
- * `/index.ts` appended; it never fires for resolutions that succeed, so
859
- * host-app and node_modules resolution are untouched.
915
+ * Import an extension entry fresh from disk, its relative import graph
916
+ * included. Every import of an extension goes through here (discovery and
917
+ * install validation), so both runtimes get the same reload semantics.
860
918
  *
861
- * `module.registerHooks` (sync, in-thread) needs Node ≥ 22.15 — absent
862
- * (or under Bun, where the fallback is native) this is a silent no-op
863
- * and multi-file TS extensions keep failing with the resolver's own
864
- * error.
865
- */
866
- let nodeTsResolutionInstall;
867
- /**
868
- * File-URL prefixes of extension dirs the retry may fire under. Scoping
869
- * by the importing module's parent keeps the hook inert for the host
870
- * app's own failed resolutions — a host relying on a failed-resolution
871
- * catch path must never silently load an unexpected `.ts` file.
919
+ * Bun: native `import()` — `.ts`/`.tsx`, extensionless relative imports
920
+ * and host modules (`Bun.plugin`) all resolve natively.
921
+ *
922
+ * Node (the Electron GUI): jiti, NOT native `import()`. Node's ESM cache
923
+ * can't be evicted, so a cache-busting query per reload would pin every
924
+ * generation's module graph for the life of the process. jiti evaluates
925
+ * the graph as CJS into `require.cache`, which {@link evictModuleGraph}
926
+ * clears — old generations become collectible once their registry is
927
+ * disposed (asserted by test/extensions/node-reload.test.ts). Stable URLs
928
+ * also keep the cache flat. jiti additionally gives Node full TS/TSX and
929
+ * `./foo` → `foo.ts` resolution, and maps the host's modules
930
+ * (`'zidane'`, …) through `virtualModules` to the LIVE instances.
931
+ * `fsCache: false`: no transpile output accumulating in tmp per edit.
872
932
  */
873
- const nodeTsResolutionParents = /* @__PURE__ */ new Set();
933
+ async function importExtensionEntry(entryPath, dir) {
934
+ evictModuleGraph(dir);
935
+ if (typeof Bun !== "undefined") {
936
+ importGeneration += 1;
937
+ return import(`${pathToFileURL(entryPath).href}?zidane-gen=${importGeneration}`);
938
+ }
939
+ const [{ createJiti }, virtualModules] = await Promise.all([import("jiti"), resolveExtensionHostModules()]);
940
+ return createJiti(entryPath, {
941
+ moduleCache: true,
942
+ fsCache: false,
943
+ interopDefault: false,
944
+ virtualModules
945
+ }).import(entryPath);
946
+ }
874
947
  /**
875
- * Install the Node resolver shim (see above) once and allow it under `extensionDir`.
876
- * No-op under Bun. Resolves when the hook is installed, or when Node cannot install it.
948
+ * Drop an extension directory's modules from the cache without importing
949
+ * again — for a one-off import whose directory is about to move or be
950
+ * deleted (install validation), so nothing stays pinned under that path.
877
951
  */
878
- function ensureNodeTsExtensionResolution(extensionDir) {
879
- if (typeof Bun !== "undefined") return Promise.resolve();
880
- try {
881
- const physicalDir = realpathSync(extensionDir);
882
- for (const dir of [extensionDir, physicalDir]) nodeTsResolutionParents.add(pathToFileURL(dir.endsWith(sep) ? dir : dir + sep).href);
883
- } catch {}
884
- nodeTsResolutionInstall ??= installNodeTsResolution();
885
- return nodeTsResolutionInstall;
886
- }
887
- async function installNodeTsResolution() {
888
- try {
889
- const registerHooks = (await import("node:module")).registerHooks;
890
- if (typeof registerHooks !== "function") return;
891
- registerHooks({ resolve(specifier, context, nextResolve) {
892
- try {
893
- return nextResolve(specifier, context);
894
- } catch (err) {
895
- const relative = specifier.startsWith("./") || specifier.startsWith("../");
896
- const extensionless = !/\.[cm]?[jt]sx?$/.test(specifier) && !specifier.endsWith(".json");
897
- const parent = context?.parentURL ?? "";
898
- const underExtension = [...nodeTsResolutionParents].some((prefix) => parent.startsWith(prefix));
899
- if (relative && extensionless && underExtension) {
900
- try {
901
- return nextResolve(`${specifier}.ts`, context);
902
- } catch {}
903
- try {
904
- return nextResolve(`${specifier}/index.ts`, context);
905
- } catch {}
906
- }
907
- throw err;
908
- }
909
- } });
910
- } catch {}
952
+ function releaseExtensionModules(dir) {
953
+ evictModuleGraph(dir);
911
954
  }
912
955
  /**
913
956
  * Import + validate a single extension entry. Always returns a
@@ -925,10 +968,7 @@ async function loadExtensionFromDisk(entry, timeoutMs, sink) {
925
968
  };
926
969
  if (version) createLogger(sink, { extension: entry.name }).warn(version.message);
927
970
  try {
928
- await ensureNodeTsExtensionResolution(entry.dir);
929
- evictModuleGraph(entry.dir);
930
- importGeneration += 1;
931
- const definition = pickExtensionDefinition(await withTimeout(import(`${pathToFileURL(entry.entry).href}?zidane-gen=${importGeneration}`), timeoutMs, `Timed out importing ${entry.entry} after ${timeoutMs}ms. The module's top-level code may still be running; an import can't be cancelled.`));
971
+ const definition = pickExtensionDefinition(await withTimeout(importExtensionEntry(entry.entry, entry.dir), timeoutMs, `Timed out importing ${entry.entry} after ${timeoutMs}ms. The module's top-level code may still be running; an import can't be cancelled.`));
932
972
  if (!definition) return {
933
973
  name: entry.name,
934
974
  dir: entry.dir,
@@ -1057,46 +1097,6 @@ function isExtensionManifest(value) {
1057
1097
  return (v.name === void 0 || typeof v.name === "string") && (v.displayName === void 0 || typeof v.displayName === "string") && (v.description === void 0 || typeof v.description === "string") && (v.permissions === void 0 || isStringArray(v.permissions)) && (v.capabilities === void 0 || isStringArray(v.capabilities));
1058
1098
  }
1059
1099
  //#endregion
1060
- //#region src/extensions/host-modules.ts
1061
- const registered = /* @__PURE__ */ new Set();
1062
- /**
1063
- * Map bare import specifiers to the host's live module objects for every
1064
- * subsequently-imported module (extensions included). No-op outside Bun
1065
- * and for already-registered specifiers. Call BEFORE the first extension
1066
- * import (the TUI does, at startup).
1067
- *
1068
- * @param modules - Bare import specifiers mapped to a module object, or to a function that resolves one.
1069
- * @example
1070
- * ```ts
1071
- * import * as React from 'react'
1072
- * import { registerExtensionHostModules } from 'zidane/extensions'
1073
- *
1074
- * registerExtensionHostModules({ react: React })
1075
- * ```
1076
- */
1077
- function registerExtensionHostModules(modules) {
1078
- const bun = globalThis.Bun;
1079
- if (typeof bun?.plugin !== "function") return;
1080
- const fresh = Object.entries(modules).filter(([specifier]) => !registered.has(specifier));
1081
- if (fresh.length === 0) return;
1082
- for (const [specifier] of fresh) registered.add(specifier);
1083
- bun.plugin({
1084
- name: `zidane-host-modules(${fresh.map(([s]) => s).join(",")})`,
1085
- setup(build) {
1086
- for (const [specifier, source] of fresh) build.module(specifier, async () => {
1087
- const mod = typeof source === "function" ? await source() : source;
1088
- return {
1089
- exports: {
1090
- ...mod,
1091
- default: mod.default ?? mod
1092
- },
1093
- loader: "object"
1094
- };
1095
- });
1096
- }
1097
- });
1098
- }
1099
- //#endregion
1100
1100
  //#region src/chat/keybindings.ts
1101
1101
  /**
1102
1102
  * The canonical action catalog. Order is the source of truth for the
@@ -4399,10 +4399,11 @@ async function validateCandidate(candidate, timeoutMs) {
4399
4399
  if (version?.level === "error") throw new ExtensionInstallError("validate-failed", version.message);
4400
4400
  let mod;
4401
4401
  try {
4402
- await ensureNodeTsExtensionResolution(candidate.dir);
4403
- mod = await withTimeout(import(`${pathToFileURL(entry).href}?zidane-install=${Date.now()}`), timeoutMs, `Timed out importing ${entry} after ${timeoutMs}ms.`);
4402
+ mod = await withTimeout(importExtensionEntry(entry, candidate.dir), timeoutMs, `Timed out importing ${entry} after ${timeoutMs}ms.`);
4404
4403
  } catch (err) {
4405
4404
  throw new ExtensionInstallError("validate-failed", `Cannot import the extension: ${errorMessage(err)}`);
4405
+ } finally {
4406
+ releaseExtensionModules(candidate.dir);
4406
4407
  }
4407
4408
  const m = mod ?? {};
4408
4409
  const definition = isExtensionDefinition(m.default) ? m.default : isExtensionDefinition(m.extension) ? m.extension : null;
@@ -4484,6 +4485,6 @@ function createExtensionPromptBridge() {
4484
4485
  };
4485
4486
  }
4486
4487
  //#endregion
4487
- export { sanitizeExtensionConfigActionPatch as $, keybindingsPath as A, defaultExtensionScanPaths as B, DEFAULT_KEYBINDINGS as C, ensureKeybindingsFile as D, KEYBINDING_KEY_COL_WIDTH as E, readKeybindingsRaw as F, scanExtensionDirectories as G, inlineLoadedExtension as H, resolveExtensionKeybindings as I, coerceExtensionConfigInput as J, defineExtension as K, stripJsonComments as L, mergeKeybindings as M, normalizeBindingValue as N, formatBindingForDisplay as O, readKeybindings as P, resolveExtensionConfigValue as Q, registerExtensionHostModules as R, createWorkspaceSurface as S, KEYBINDING_DEF_BY_ACTION as T, isExtensionDefinition as U, discoverExtensions as V, parseExtensionScanPathEnv as W, isValidExtensionConfigValue as X, isValidExtensionConfigItem as Y, resolveExtensionConfig as Z, createMcpSurface as _, listExtensionCandidates as a, createArtifactsSurface as b, removeInstalledExtension as c, buildExtensionRegistry as d, toWireConfigSchema as et, disposeExtensionRegistry as f, partitionExtensionCatalog as g, mergeContributions as h, installExtensionFromSpec as i, matchesBinding as j, groupBindings as k, updateInstalledExtension as l, filterRegistryPlugins as m, ExtensionInstallError as n, createExtensionBus as nt, parseExtensionInstallSource as o, filterExtensionRegistry as p, clampExtensionConfigNumber as q, fetchExtensionSource as r, serializedPayloadBytes as rt, readExtensionInstallProvenance as s, createExtensionPromptBridge as t, EXTENSION_BUS_MAX_PAYLOAD_BYTES as tt, discoverAndBuildExtensionRegistry as u, MAX_COMPOSER_BADGES as v, KEYBINDING_DEFS as w, createExtensionHostRuntimeBridge as x, createExtensionHud as y, ENTRY_CANDIDATES as z };
4488
+ export { sanitizeExtensionConfigActionPatch as $, keybindingsPath as A, discoverExtensions as B, DEFAULT_KEYBINDINGS as C, ensureKeybindingsFile as D, KEYBINDING_KEY_COL_WIDTH as E, readKeybindingsRaw as F, registerExtensionHostModules as G, isExtensionDefinition as H, resolveExtensionKeybindings as I, coerceExtensionConfigInput as J, defineExtension as K, stripJsonComments as L, mergeKeybindings as M, normalizeBindingValue as N, formatBindingForDisplay as O, readKeybindings as P, resolveExtensionConfigValue as Q, ENTRY_CANDIDATES as R, createWorkspaceSurface as S, KEYBINDING_DEF_BY_ACTION as T, parseExtensionScanPathEnv as U, inlineLoadedExtension as V, scanExtensionDirectories as W, isValidExtensionConfigValue as X, isValidExtensionConfigItem as Y, resolveExtensionConfig as Z, createMcpSurface as _, listExtensionCandidates as a, createArtifactsSurface as b, removeInstalledExtension as c, buildExtensionRegistry as d, toWireConfigSchema as et, disposeExtensionRegistry as f, partitionExtensionCatalog as g, mergeContributions as h, installExtensionFromSpec as i, matchesBinding as j, groupBindings as k, updateInstalledExtension as l, filterRegistryPlugins as m, ExtensionInstallError as n, createExtensionBus as nt, parseExtensionInstallSource as o, filterExtensionRegistry as p, clampExtensionConfigNumber as q, fetchExtensionSource as r, serializedPayloadBytes as rt, readExtensionInstallProvenance as s, createExtensionPromptBridge as t, EXTENSION_BUS_MAX_PAYLOAD_BYTES as tt, discoverAndBuildExtensionRegistry as u, MAX_COMPOSER_BADGES as v, KEYBINDING_DEFS as w, createExtensionHostRuntimeBridge as x, createExtensionHud as y, defaultExtensionScanPaths as z };
4488
4489
 
4489
- //# sourceMappingURL=extensions-BKt7lxxv.js.map
4490
+ //# sourceMappingURL=extensions-BgBwogRW.js.map