@the-open-engine/zeroshot 6.38.0 → 6.39.0

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 (381) hide show
  1. package/cli/event-copy.js +8 -7
  2. package/cli/event-copy.ts +12 -0
  3. package/cli/index.js +7 -31
  4. package/cli/json-export.js +61 -64
  5. package/cli/json-export.ts +112 -0
  6. package/cli/message-formatter-utils.js +68 -56
  7. package/cli/message-formatter-utils.ts +121 -0
  8. package/cli/message-formatters-normal.js +124 -259
  9. package/cli/message-formatters-normal.ts +250 -0
  10. package/cli/message-formatters-watch.js +81 -84
  11. package/cli/message-formatters-watch.ts +189 -0
  12. package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
  13. package/lib/agent-cli-provider/adapters/codex.js +3 -1
  14. package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
  15. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  16. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  17. package/lib/cluster/generated/protocol.d.cts +8 -0
  18. package/lib/cluster/generated/protocol.d.mts +8 -0
  19. package/lib/cluster/generated/protocol.d.ts +8 -0
  20. package/lib/clusters-registry.d.ts +23 -0
  21. package/lib/clusters-registry.js +17 -29
  22. package/lib/completion.d.ts +12 -0
  23. package/lib/completion.js +84 -94
  24. package/lib/compose-utils.d.ts +32 -0
  25. package/lib/compose-utils.js +57 -72
  26. package/lib/detached-startup.d.ts +83 -0
  27. package/lib/detached-startup.js +231 -302
  28. package/lib/docker-config.d.ts +43 -0
  29. package/lib/docker-config.js +150 -325
  30. package/lib/docker-env-auth.d.ts +17 -0
  31. package/lib/docker-env-auth.js +75 -0
  32. package/lib/git-remote-utils.d.ts +48 -0
  33. package/lib/git-remote-utils.js +147 -213
  34. package/lib/id-detector.d.ts +15 -0
  35. package/lib/id-detector.js +37 -41
  36. package/lib/path-check.d.ts +30 -0
  37. package/lib/path-check.js +42 -45
  38. package/lib/process-liveness.d.ts +16 -0
  39. package/lib/process-liveness.js +19 -12
  40. package/lib/provider-credential-path.d.ts +16 -0
  41. package/lib/provider-credential-path.js +31 -29
  42. package/lib/provider-defaults.d.ts +30 -0
  43. package/lib/provider-defaults.js +47 -42
  44. package/lib/provider-detection.d.ts +11 -0
  45. package/lib/provider-detection.js +91 -54
  46. package/lib/provider-names.d.ts +38 -0
  47. package/lib/provider-names.js +56 -64
  48. package/lib/repo-settings.d.ts +28 -0
  49. package/lib/repo-settings.js +83 -59
  50. package/lib/run-mode.d.ts +21 -0
  51. package/lib/run-mode.js +21 -20
  52. package/lib/run-plan.d.ts +28 -0
  53. package/lib/run-plan.js +17 -16
  54. package/lib/settings/claude-auth.d.ts +35 -0
  55. package/lib/settings/claude-auth.js +30 -47
  56. package/lib/settings-defaults.d.ts +20 -0
  57. package/lib/settings-defaults.js +149 -0
  58. package/lib/settings-error.d.ts +7 -0
  59. package/lib/settings-error.js +8 -0
  60. package/lib/settings-issue-providers.d.ts +10 -0
  61. package/lib/settings-issue-providers.js +12 -0
  62. package/lib/settings-models.d.ts +22 -0
  63. package/lib/settings-models.js +93 -0
  64. package/lib/settings-storage.d.ts +23 -0
  65. package/lib/settings-storage.js +205 -0
  66. package/lib/settings-validation.d.ts +7 -0
  67. package/lib/settings-validation.js +182 -0
  68. package/lib/settings.d.ts +29 -0
  69. package/lib/settings.js +41 -736
  70. package/lib/setup-apply-types.d.ts +66 -0
  71. package/lib/setup-apply-types.js +2 -0
  72. package/lib/setup-apply.d.ts +39 -0
  73. package/lib/setup-apply.js +267 -264
  74. package/lib/setup-journal.d.ts +41 -0
  75. package/lib/setup-journal.js +119 -76
  76. package/lib/setup-plan-types.d.ts +102 -0
  77. package/lib/setup-plan-types.js +2 -0
  78. package/lib/setup-plan.d.ts +30 -0
  79. package/lib/setup-plan.js +300 -324
  80. package/lib/setup-undo.d.ts +44 -0
  81. package/lib/setup-undo.js +61 -74
  82. package/lib/start-cluster-config.d.ts +26 -0
  83. package/lib/start-cluster-config.js +56 -0
  84. package/lib/start-cluster-environment.d.ts +40 -0
  85. package/lib/start-cluster-environment.js +134 -0
  86. package/lib/start-cluster-run-options.d.ts +53 -0
  87. package/lib/start-cluster-run-options.js +147 -0
  88. package/lib/start-cluster.d.ts +64 -0
  89. package/lib/start-cluster.js +98 -454
  90. package/lib/stream-json-parser.d.ts +17 -0
  91. package/lib/stream-json-parser.js +51 -52
  92. package/npm-shrinkwrap.json +2 -2
  93. package/package.json +12 -6
  94. package/scripts/postinstall.js +27 -0
  95. package/scripts/rust-distribution.js +23 -14
  96. package/src/agent/agent-command-proofs-context.js +35 -45
  97. package/src/agent/agent-command-proofs-context.ts +87 -0
  98. package/src/agent/agent-config-settings.js +19 -0
  99. package/src/agent/agent-config-settings.ts +41 -0
  100. package/src/agent/agent-config.js +122 -231
  101. package/src/agent/agent-config.ts +285 -0
  102. package/src/agent/agent-context-builder.js +38 -273
  103. package/src/agent/agent-context-builder.ts +51 -0
  104. package/src/agent/agent-context-environment-sections.js +105 -0
  105. package/src/agent/agent-context-environment-sections.ts +134 -0
  106. package/src/agent/agent-context-packs.js +165 -0
  107. package/src/agent/agent-context-packs.ts +296 -0
  108. package/src/agent/agent-context-prompt-sections.js +100 -0
  109. package/src/agent/agent-context-prompt-sections.ts +148 -0
  110. package/src/agent/agent-context-sections.js +25 -334
  111. package/src/agent/agent-context-sections.ts +36 -0
  112. package/src/agent/agent-context-sources.js +96 -149
  113. package/src/agent/agent-context-sources.ts +253 -0
  114. package/src/agent/agent-context-types.js +2 -0
  115. package/src/agent/agent-context-types.ts +132 -0
  116. package/src/agent/agent-context-validation-sections.js +73 -0
  117. package/src/agent/agent-context-validation-sections.ts +129 -0
  118. package/src/agent/agent-input-injector.js +99 -118
  119. package/src/agent/agent-input-injector.ts +195 -0
  120. package/src/agent/agent-liveness-poll.js +74 -78
  121. package/src/agent/agent-liveness-poll.ts +163 -0
  122. package/src/agent/agent-quality-gate-schema.js +77 -86
  123. package/src/agent/agent-quality-gate-schema.ts +135 -0
  124. package/src/agent/agent-quality-gates-context.js +44 -50
  125. package/src/agent/agent-quality-gates-context.ts +91 -0
  126. package/src/agent/agent-stuck-detector.js +171 -239
  127. package/src/agent/agent-stuck-detector.ts +288 -0
  128. package/src/agent/agent-trigger-evaluator.js +29 -46
  129. package/src/agent/agent-trigger-evaluator.ts +98 -0
  130. package/src/agent/context-metrics.js +110 -141
  131. package/src/agent/context-metrics.ts +261 -0
  132. package/src/agent/context-pack-builder.js +72 -358
  133. package/src/agent/context-pack-builder.ts +105 -0
  134. package/src/agent/context-pack-core.js +70 -0
  135. package/src/agent/context-pack-core.ts +96 -0
  136. package/src/agent/context-pack-selection.js +119 -0
  137. package/src/agent/context-pack-selection.ts +187 -0
  138. package/src/agent/context-pack-truncation.js +139 -0
  139. package/src/agent/context-pack-truncation.ts +208 -0
  140. package/src/agent/context-pack-types.js +2 -0
  141. package/src/agent/context-pack-types.ts +98 -0
  142. package/src/agent/context-replay-policy.js +30 -39
  143. package/src/agent/context-replay-policy.ts +71 -0
  144. package/src/agent/critical-agent-policy.js +6 -10
  145. package/src/agent/critical-agent-policy.ts +20 -0
  146. package/src/agent/guidance-queue.js +74 -87
  147. package/src/agent/guidance-queue.ts +166 -0
  148. package/src/agent/output-extraction-error-detail.js +45 -0
  149. package/src/agent/output-extraction-error-detail.ts +49 -0
  150. package/src/agent/output-extraction-failures.js +125 -0
  151. package/src/agent/output-extraction-failures.ts +149 -0
  152. package/src/agent/output-extraction-json.js +234 -0
  153. package/src/agent/output-extraction-json.ts +235 -0
  154. package/src/agent/output-extraction-pi.js +124 -0
  155. package/src/agent/output-extraction-pi.ts +137 -0
  156. package/src/agent/output-extraction-types.js +2 -0
  157. package/src/agent/output-extraction-types.ts +49 -0
  158. package/src/agent/output-extraction.js +17 -617
  159. package/src/agent/output-extraction.ts +30 -0
  160. package/src/agent/output-reformatter-errors.js +83 -0
  161. package/src/agent/output-reformatter-errors.ts +106 -0
  162. package/src/agent/output-reformatter-types.js +2 -0
  163. package/src/agent/output-reformatter-types.ts +86 -0
  164. package/src/agent/output-reformatter.js +140 -185
  165. package/src/agent/output-reformatter.ts +238 -0
  166. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  167. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  168. package/src/agent/pi-terminal-lifecycle.js +186 -206
  169. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  170. package/src/agent/provider-control-plane.js +22 -21
  171. package/src/agent/provider-control-plane.ts +52 -0
  172. package/src/agent/provider-terminal-failure-types.js +2 -0
  173. package/src/agent/provider-terminal-failure-types.ts +60 -0
  174. package/src/agent/provider-terminal-failure.js +194 -191
  175. package/src/agent/provider-terminal-failure.ts +262 -0
  176. package/src/agent/rate-limit-backoff.js +31 -74
  177. package/src/agent/rate-limit-backoff.ts +71 -0
  178. package/src/agent/schema-utils.js +85 -125
  179. package/src/agent/schema-utils.ts +148 -0
  180. package/src/agent/structured-output-error.js +34 -33
  181. package/src/agent/structured-output-error.ts +105 -0
  182. package/src/agent/validation-platform.js +27 -27
  183. package/src/agent/validation-platform.ts +49 -0
  184. package/src/agent-cli-provider/adapters/codex.ts +3 -1
  185. package/src/attach/attach-client.js +232 -405
  186. package/src/attach/attach-client.ts +300 -0
  187. package/src/attach/attach-server-cleanup.js +43 -0
  188. package/src/attach/attach-server-cleanup.ts +39 -0
  189. package/src/attach/attach-server-clients.js +117 -0
  190. package/src/attach/attach-server-clients.ts +122 -0
  191. package/src/attach/attach-server-events.js +38 -0
  192. package/src/attach/attach-server-events.ts +36 -0
  193. package/src/attach/attach-server-pty.js +45 -0
  194. package/src/attach/attach-server-pty.ts +64 -0
  195. package/src/attach/attach-server-runtime.js +73 -0
  196. package/src/attach/attach-server-runtime.ts +62 -0
  197. package/src/attach/attach-server-socket.js +28 -0
  198. package/src/attach/attach-server-socket.ts +23 -0
  199. package/src/attach/attach-server-types.js +2 -0
  200. package/src/attach/attach-server-types.ts +82 -0
  201. package/src/attach/attach-server.js +106 -523
  202. package/src/attach/attach-server.ts +158 -0
  203. package/src/attach/index.js +18 -35
  204. package/src/attach/index.ts +18 -0
  205. package/src/attach/protocol.js +95 -184
  206. package/src/attach/protocol.ts +181 -0
  207. package/src/attach/ring-buffer.js +76 -102
  208. package/src/attach/ring-buffer.ts +109 -0
  209. package/src/attach/send-input.js +64 -75
  210. package/src/attach/send-input.ts +94 -0
  211. package/src/attach/socket-discovery.js +164 -218
  212. package/src/attach/socket-discovery.ts +230 -0
  213. package/src/attach/socket-paths.js +42 -61
  214. package/src/attach/socket-paths.ts +81 -0
  215. package/src/claude-credentials.js +51 -54
  216. package/src/claude-credentials.ts +89 -0
  217. package/src/cluster/generated/protocol-schema.ts +1 -1
  218. package/src/cluster/generated/protocol.ts +2 -1
  219. package/src/command-proofs.js +110 -141
  220. package/src/command-proofs.ts +216 -0
  221. package/src/config-router.js +81 -73
  222. package/src/config-router.ts +131 -0
  223. package/src/copy-worker.js +53 -29
  224. package/src/copy-worker.ts +75 -0
  225. package/src/darwin-keychain-boundary.js +80 -111
  226. package/src/darwin-keychain-boundary.ts +148 -0
  227. package/src/guidance-topics.js +4 -5
  228. package/src/guidance-topics.ts +10 -0
  229. package/src/input-helpers.js +33 -54
  230. package/src/input-helpers.ts +58 -0
  231. package/src/ledger-sequence.js +45 -48
  232. package/src/ledger-sequence.ts +63 -0
  233. package/src/legacy-lib/clusters-registry.ts +40 -0
  234. package/src/legacy-lib/completion.ts +148 -0
  235. package/src/legacy-lib/compose-utils.ts +102 -0
  236. package/src/legacy-lib/detached-startup.ts +449 -0
  237. package/src/legacy-lib/docker-config.ts +282 -0
  238. package/src/legacy-lib/docker-env-auth.ts +116 -0
  239. package/src/legacy-lib/git-remote-utils.ts +244 -0
  240. package/src/legacy-lib/id-detector.ts +57 -0
  241. package/src/legacy-lib/js-yaml.d.ts +3 -0
  242. package/src/legacy-lib/omelette.d.ts +15 -0
  243. package/src/legacy-lib/path-check.ts +89 -0
  244. package/src/legacy-lib/process-liveness.ts +36 -0
  245. package/src/legacy-lib/provider-credential-path.ts +57 -0
  246. package/src/legacy-lib/provider-defaults.ts +114 -0
  247. package/src/legacy-lib/provider-detection.ts +67 -0
  248. package/src/legacy-lib/provider-names.ts +126 -0
  249. package/src/legacy-lib/repo-settings.ts +88 -0
  250. package/src/legacy-lib/run-mode.ts +58 -0
  251. package/src/legacy-lib/run-plan.ts +49 -0
  252. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  253. package/src/legacy-lib/settings-defaults.ts +212 -0
  254. package/src/legacy-lib/settings-error.ts +8 -0
  255. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  256. package/src/legacy-lib/settings-models.ts +124 -0
  257. package/src/legacy-lib/settings-storage.ts +277 -0
  258. package/src/legacy-lib/settings-validation.ts +220 -0
  259. package/src/legacy-lib/settings.ts +87 -0
  260. package/src/legacy-lib/setup-apply-types.ts +70 -0
  261. package/src/legacy-lib/setup-apply.ts +456 -0
  262. package/src/legacy-lib/setup-journal.ts +185 -0
  263. package/src/legacy-lib/setup-plan-types.ts +96 -0
  264. package/src/legacy-lib/setup-plan.ts +500 -0
  265. package/src/legacy-lib/setup-undo.ts +142 -0
  266. package/src/legacy-lib/start-cluster-config.ts +124 -0
  267. package/src/legacy-lib/start-cluster-environment.ts +165 -0
  268. package/src/legacy-lib/start-cluster-run-options.ts +279 -0
  269. package/src/legacy-lib/start-cluster.ts +237 -0
  270. package/src/legacy-lib/stream-json-parser.ts +88 -0
  271. package/src/message-buffer.js +55 -71
  272. package/src/message-buffer.ts +107 -0
  273. package/src/message-bus-bridge.js +92 -133
  274. package/src/message-bus-bridge.ts +149 -0
  275. package/src/name-generator-shared.js +220 -0
  276. package/src/name-generator-shared.ts +231 -0
  277. package/src/name-generator.js +8 -217
  278. package/src/name-generator.ts +27 -0
  279. package/src/omp-blob-root.js +83 -64
  280. package/src/omp-blob-root.ts +116 -0
  281. package/src/omp-config-overlay.js +65 -38
  282. package/src/omp-config-overlay.ts +110 -0
  283. package/src/omp-execution-fingerprint.js +38 -43
  284. package/src/omp-execution-fingerprint.ts +92 -0
  285. package/src/omp-session-limits.js +10 -15
  286. package/src/omp-session-limits.ts +53 -0
  287. package/src/omp-session-partition.js +2 -2
  288. package/src/omp-session-verifier.js +1 -1
  289. package/src/orchestrator.js +19 -4
  290. package/src/providers/anthropic/index.js +3 -1
  291. package/src/providers/anthropic/index.ts +13 -0
  292. package/src/providers/capabilities.js +19 -27
  293. package/src/providers/capabilities.ts +44 -0
  294. package/src/providers/google/index.js +3 -1
  295. package/src/providers/google/index.ts +13 -0
  296. package/src/providers/openai/index.js +3 -1
  297. package/src/providers/openai/index.ts +13 -0
  298. package/src/providers/opencode/index.js +3 -1
  299. package/src/providers/opencode/index.ts +13 -0
  300. package/src/quality-gates.js +67 -127
  301. package/src/quality-gates.ts +149 -0
  302. package/src/repo-settings-access.js +40 -0
  303. package/src/repo-settings-access.ts +64 -0
  304. package/src/schemas/sub-cluster.js +127 -183
  305. package/src/schemas/sub-cluster.ts +238 -0
  306. package/src/state-snapshot-normalization.js +224 -0
  307. package/src/state-snapshot-normalization.ts +222 -0
  308. package/src/state-snapshot.js +192 -359
  309. package/src/state-snapshot.ts +291 -0
  310. package/src/state-snapshotter.js +118 -130
  311. package/src/state-snapshotter.ts +167 -0
  312. package/src/sub-cluster-wrapper.js +4 -13
  313. package/src/task-run-model-args.js +87 -124
  314. package/src/task-run-model-args.ts +204 -0
  315. package/src/task-runner.js +5 -25
  316. package/src/task-runner.ts +28 -0
  317. package/src/task-startup-error.js +73 -58
  318. package/src/task-startup-error.ts +126 -0
  319. package/src/template-validation/consensus-gate-contracts.js +2 -0
  320. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  321. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  322. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  323. package/src/template-validation/consensus-gate-stage.js +34 -0
  324. package/src/template-validation/consensus-gate-stage.ts +56 -0
  325. package/src/template-validation/random-topology-contracts.js +2 -0
  326. package/src/template-validation/random-topology-contracts.ts +54 -0
  327. package/src/template-validation/random-topology-dispatch.js +25 -0
  328. package/src/template-validation/random-topology-dispatch.ts +33 -0
  329. package/src/template-validation/random-topology-message-loop.js +53 -0
  330. package/src/template-validation/random-topology-message-loop.ts +73 -0
  331. package/src/template-validation/random-topology-operations.js +79 -0
  332. package/src/template-validation/random-topology-operations.ts +101 -0
  333. package/src/template-validation/random-topology-runtime.js +25 -0
  334. package/src/template-validation/random-topology-runtime.ts +43 -0
  335. package/src/template-validation/random-topology-scenario.js +52 -0
  336. package/src/template-validation/random-topology-scenario.ts +57 -0
  337. package/src/template-validation/random-topology-schema.js +159 -0
  338. package/src/template-validation/random-topology-schema.ts +190 -0
  339. package/src/template-validation/random-topology-state.js +28 -0
  340. package/src/template-validation/random-topology-state.ts +30 -0
  341. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  342. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  343. package/src/template-validation/random-topology-trigger.js +75 -0
  344. package/src/template-validation/random-topology-trigger.ts +88 -0
  345. package/src/template-validation/report-formatter.js +40 -46
  346. package/src/template-validation/report-formatter.ts +101 -0
  347. package/src/template-validation/simulate-consensus-gates.js +111 -302
  348. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  349. package/src/template-validation/simulate-random-topology.js +26 -519
  350. package/src/template-validation/simulate-random-topology.ts +57 -0
  351. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  352. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  353. package/src/template-validation/simulation-agent-runtime.js +25 -0
  354. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  355. package/src/template-validation/simulation-agent.js +29 -0
  356. package/src/template-validation/simulation-agent.ts +73 -0
  357. package/src/template-validation/simulation-runtime.js +34 -0
  358. package/src/template-validation/simulation-runtime.ts +72 -0
  359. package/src/template-validation/two-stage-contracts.js +2 -0
  360. package/src/template-validation/two-stage-contracts.ts +41 -0
  361. package/src/template-validation/two-stage-inputs.js +21 -0
  362. package/src/template-validation/two-stage-inputs.ts +29 -0
  363. package/src/template-validation/two-stage-results.js +30 -0
  364. package/src/template-validation/two-stage-results.ts +40 -0
  365. package/src/template-validation/two-stage-scenario.js +86 -0
  366. package/src/template-validation/two-stage-scenario.ts +120 -0
  367. package/src/worktree-claude-config.js +182 -220
  368. package/src/worktree-claude-config.ts +272 -0
  369. package/src/worktree-tooling-env.js +103 -125
  370. package/src/worktree-tooling-env.ts +142 -0
  371. package/task-lib/completion.js +2 -3
  372. package/task-lib/completion.ts +9 -0
  373. package/task-lib/config.js +1 -4
  374. package/task-lib/config.ts +11 -0
  375. package/task-lib/name-generator.js +4 -226
  376. package/task-lib/name-generator.ts +11 -0
  377. package/task-lib/omp-session-cleanup.js +1 -1
  378. package/task-lib/omp-storage-root.js +8 -12
  379. package/task-lib/omp-storage-root.ts +62 -0
  380. package/task-lib/process-termination.js +143 -166
  381. package/task-lib/process-termination.ts +268 -0
@@ -0,0 +1,142 @@
1
+ /**
2
+ * `zeroshot setup undo` — reverts writes made by `zeroshot setup apply` using
3
+ * the journal recorded at apply time (lib/setup-journal.js).
4
+ *
5
+ * Three-way conflict rule per journaled write, comparing `current` against
6
+ * `appliedValue`:
7
+ * - current === appliedValue -> restore priorValue (delete if null)
8
+ * - current === priorValue -> already-restored (no-op)
9
+ * - otherwise (changed elsewhere) -> skipped-modified, never clobbered
10
+ */
11
+
12
+ import setupJournal = require('./setup-journal');
13
+
14
+ type SettingsRecord = Record<string, unknown>;
15
+ type UndoStatus = 'already-restored' | 'skipped-modified' | 'deleted' | 'restored';
16
+
17
+ interface JournalEntry {
18
+ readonly appliedAt: string;
19
+ readonly appliedValue: unknown;
20
+ readonly path: string;
21
+ readonly priorValue: unknown;
22
+ readonly repoRoot: string | null;
23
+ readonly scope: string;
24
+ readonly [key: string]: unknown;
25
+ }
26
+
27
+ interface SetupJournalFacade {
28
+ deepEqual(left: unknown, right: unknown): boolean;
29
+ deleteNestedKey(target: SettingsRecord, pathStr: string): void;
30
+ getNestedValue(source: SettingsRecord, pathStr: string): unknown;
31
+ loadJournal(): { entries: JournalEntry[] };
32
+ setNestedValue(target: SettingsRecord, pathStr: string, value: unknown): void;
33
+ }
34
+
35
+ const {
36
+ loadJournal,
37
+ getNestedValue,
38
+ setNestedValue,
39
+ deleteNestedKey,
40
+ deepEqual,
41
+ }: SetupJournalFacade = setupJournal;
42
+
43
+ interface UndoResult extends JournalEntry {
44
+ current?: unknown;
45
+ status: UndoStatus;
46
+ wouldRestore?: unknown;
47
+ }
48
+
49
+ interface UndoDependencies {
50
+ mutateSettings<T>(mutator: (settings: SettingsRecord) => T): T;
51
+ readRepoSettings(repoRoot: string | null): { settings: SettingsRecord | null };
52
+ writeRepoSettings(repoRoot: string | null, settings: SettingsRecord): unknown;
53
+ }
54
+
55
+ interface UndoParams {
56
+ deps?: Partial<UndoDependencies>;
57
+ }
58
+
59
+ function defaultUndoDeps(): UndoDependencies {
60
+ // These CommonJS paths intentionally resolve beside the emitted module in lib/.
61
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
62
+ const { mutateSettings }: Pick<UndoDependencies, 'mutateSettings'> = require('./settings');
63
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
64
+ const {
65
+ readRepoSettings,
66
+ writeRepoSettings,
67
+ }: Pick<UndoDependencies, 'readRepoSettings' | 'writeRepoSettings'> =
68
+ require('./repo-settings');
69
+
70
+ return { mutateSettings, readRepoSettings, writeRepoSettings };
71
+ }
72
+
73
+ /**
74
+ * Undo every journaled write, per the three-way conflict rule.
75
+ */
76
+ function undo({ deps = {} }: UndoParams = {}): Array<UndoResult | undefined> {
77
+ const resolvedDeps: UndoDependencies = { ...defaultUndoDeps(), ...deps };
78
+ const journal = loadJournal();
79
+
80
+ const repoSettingsCache = new Map<string | null, SettingsRecord>();
81
+ const dirtyRepoRoots = new Set<string | null>();
82
+
83
+ function repoSettingsFor(repoRoot: string | null): SettingsRecord {
84
+ const cachedSettings = repoSettingsCache.get(repoRoot);
85
+ if (cachedSettings) {
86
+ return cachedSettings;
87
+ }
88
+ const { settings } = resolvedDeps.readRepoSettings(repoRoot);
89
+ const resolvedSettings = settings || {};
90
+ repoSettingsCache.set(repoRoot, resolvedSettings);
91
+ return resolvedSettings;
92
+ }
93
+
94
+ function restoreEntry(entry: JournalEntry, settingsObj: SettingsRecord): UndoResult {
95
+ const current = getNestedValue(settingsObj, entry.path) ?? null;
96
+ if (deepEqual(current, entry.priorValue)) {
97
+ return { ...entry, status: 'already-restored' };
98
+ }
99
+ if (!deepEqual(current, entry.appliedValue)) {
100
+ return { ...entry, status: 'skipped-modified', current, wouldRestore: entry.priorValue };
101
+ }
102
+ if (entry.priorValue === null) {
103
+ deleteNestedKey(settingsObj, entry.path);
104
+ } else {
105
+ setNestedValue(settingsObj, entry.path, entry.priorValue);
106
+ }
107
+ return { ...entry, status: entry.priorValue === null ? 'deleted' : 'restored' };
108
+ }
109
+
110
+ const resultsByIndex = new Map<number, UndoResult | undefined>();
111
+ const globalEntries = journal.entries
112
+ .map((entry, index) => ({ entry, index }))
113
+ .filter(({ entry }) => entry.scope === 'global');
114
+
115
+ if (globalEntries.length > 0) {
116
+ const globalResults = resolvedDeps.mutateSettings((freshGlobalSettings) => {
117
+ return globalEntries.map(({ entry }) => restoreEntry(entry, freshGlobalSettings));
118
+ });
119
+ globalEntries.forEach(({ index }, resultIndex) => {
120
+ resultsByIndex.set(index, globalResults[resultIndex]);
121
+ });
122
+ }
123
+
124
+ journal.entries.forEach((entry, index) => {
125
+ if (entry.scope !== 'repo') return;
126
+ const result = restoreEntry(entry, repoSettingsFor(entry.repoRoot));
127
+ resultsByIndex.set(index, result);
128
+ if (result.status === 'restored' || result.status === 'deleted') {
129
+ dirtyRepoRoots.add(entry.repoRoot);
130
+ }
131
+ });
132
+
133
+ for (const repoRoot of dirtyRepoRoots) {
134
+ resolvedDeps.writeRepoSettings(repoRoot, repoSettingsFor(repoRoot));
135
+ }
136
+
137
+ // Journal entries are left in place (not cleared) so a re-run reports
138
+ // 'already-restored' instead of finding nothing to undo.
139
+ return journal.entries.map((_, index) => resultsByIndex.get(index));
140
+ }
141
+
142
+ export = { undo };
@@ -0,0 +1,124 @@
1
+ import path = require('path');
2
+
3
+ interface ClusterConfig extends Record<string, unknown> {
4
+ defaultLevel?: unknown;
5
+ defaultProvider?: string;
6
+ forceLevel?: unknown;
7
+ forceProvider?: string;
8
+ params?: Record<string, unknown>;
9
+ }
10
+
11
+ interface ProviderSettings {
12
+ defaultLevel?: unknown;
13
+ }
14
+
15
+ interface Settings {
16
+ defaultProvider?: string;
17
+ providerSettings?: Record<string, ProviderSettings>;
18
+ }
19
+
20
+ interface ProviderNamesFacade {
21
+ getDefaultProviderId(): string;
22
+ normalizeProviderName(name: string): string;
23
+ }
24
+
25
+ interface ProviderFacade {
26
+ getDefaultLevel(): unknown;
27
+ }
28
+
29
+ interface ProvidersFacade {
30
+ getProvider(providerId: string): ProviderFacade;
31
+ }
32
+
33
+ interface TemplateResolverFacade {
34
+ resolveTemplate(config: ClusterConfig, params: Record<string, unknown>): ClusterConfig;
35
+ }
36
+
37
+ interface TemplateResolverConstructor {
38
+ new (templatesRoot: string): TemplateResolverFacade;
39
+ }
40
+
41
+ interface OrchestratorFacade {
42
+ loadConfig(configPath: string): ClusterConfig;
43
+ }
44
+
45
+ interface ChalkFacade {
46
+ dim(message: string): string;
47
+ }
48
+
49
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
50
+ const chalk: ChalkFacade = require('chalk');
51
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
52
+ const providerNames: ProviderNamesFacade = require('./provider-names');
53
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
54
+ const providers: ProvidersFacade = require('../src/providers');
55
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
56
+ const TemplateResolver: TemplateResolverConstructor = require('../src/template-resolver');
57
+
58
+ const { normalizeProviderName, getDefaultProviderId } = providerNames;
59
+ const { getProvider } = providers;
60
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
61
+
62
+ function resolveConfigPath(configName: string): string {
63
+ if (path.isAbsolute(configName) || configName.startsWith('./') || configName.startsWith('../')) {
64
+ return path.resolve(process.cwd(), configName);
65
+ }
66
+ if (configName.endsWith('.json')) {
67
+ return path.join(PACKAGE_ROOT, 'cluster-templates', configName);
68
+ }
69
+ return path.join(PACKAGE_ROOT, 'cluster-templates', `${configName}.json`);
70
+ }
71
+
72
+ function ensureConfigProviderDefaults(config: ClusterConfig, settings: Settings): void {
73
+ if (!config.defaultProvider) {
74
+ config.defaultProvider = settings.defaultProvider || getDefaultProviderId();
75
+ }
76
+ config.defaultProvider = normalizeProviderName(config.defaultProvider) || getDefaultProviderId();
77
+ }
78
+
79
+ function applyProviderOverrideToConfig(
80
+ config: ClusterConfig,
81
+ providerOverride: string,
82
+ settings: Settings
83
+ ): void {
84
+ const provider = getProvider(providerOverride);
85
+ const providerSettings = settings.providerSettings?.[providerOverride] || {};
86
+ config.forceProvider = providerOverride;
87
+ config.defaultProvider = providerOverride;
88
+ config.forceLevel = providerSettings.defaultLevel || provider.getDefaultLevel();
89
+ config.defaultLevel = config.forceLevel;
90
+ console.log(chalk.dim(`Provider override: ${providerOverride} (all agents)`));
91
+ }
92
+
93
+ function resolveParameterizedConfigFile(config: ClusterConfig): ClusterConfig {
94
+ if (!config?.params || Object.keys(config.params).length === 0) {
95
+ return config;
96
+ }
97
+
98
+ const resolver = new TemplateResolver(path.join(PACKAGE_ROOT, 'cluster-templates'));
99
+ return resolver.resolveTemplate(config, {});
100
+ }
101
+
102
+ function prepareClusterConfig(
103
+ config: ClusterConfig,
104
+ settings: Settings = {},
105
+ providerOverride?: string | null
106
+ ): ClusterConfig {
107
+ const prepared = resolveParameterizedConfigFile(config);
108
+ ensureConfigProviderDefaults(prepared, settings);
109
+ if (providerOverride) {
110
+ applyProviderOverrideToConfig(prepared, providerOverride, settings);
111
+ }
112
+ return prepared;
113
+ }
114
+
115
+ function loadClusterConfig(
116
+ orchestrator: OrchestratorFacade,
117
+ configPath: string,
118
+ settings: Settings = {},
119
+ providerOverride?: string | null
120
+ ): ClusterConfig {
121
+ return prepareClusterConfig(orchestrator.loadConfig(configPath), settings, providerOverride);
122
+ }
123
+
124
+ export = { resolveConfigPath, prepareClusterConfig, loadClusterConfig };
@@ -0,0 +1,165 @@
1
+ import { spawnSync } from 'child_process';
2
+
3
+ type CloseIssueMode = 'auto' | 'always' | 'never';
4
+
5
+ interface RunOptions extends Record<string, unknown> {
6
+ closeIssue?: unknown;
7
+ dockerImage?: unknown;
8
+ isolation?: unknown;
9
+ mergeQueue?: unknown;
10
+ mount?: readonly string[] | null;
11
+ noIsolation?: unknown;
12
+ prBase?: unknown;
13
+ }
14
+
15
+ interface MountSpec {
16
+ host: string;
17
+ container: string;
18
+ readonly: boolean;
19
+ }
20
+
21
+ function firstTruthy<T>(...values: T[]): T | undefined {
22
+ return values.find(Boolean);
23
+ }
24
+
25
+ function anyTruthy(...values: unknown[]): boolean {
26
+ return values.some(Boolean);
27
+ }
28
+
29
+ function optionalValue<T>(value: T): T | undefined {
30
+ return value || undefined;
31
+ }
32
+
33
+ function detectGitRepoRoot(): string {
34
+ try {
35
+ const result = spawnSync('git', ['rev-parse', '--show-toplevel'], {
36
+ encoding: 'utf8',
37
+ stdio: ['pipe', 'pipe', 'pipe'],
38
+ });
39
+ if (result.status !== 0) {
40
+ return process.cwd();
41
+ }
42
+ return result.stdout.trim();
43
+ } catch {
44
+ return process.cwd();
45
+ }
46
+ }
47
+
48
+ function resolveTargetCwd(): string | undefined {
49
+ return firstTruthy(process.env.ZEROSHOT_CWD, detectGitRepoRoot());
50
+ }
51
+
52
+ function resolveOptionalString(value: unknown): string | undefined {
53
+ if (typeof value !== 'string') return undefined;
54
+ const trimmed = value.trim();
55
+ return trimmed.length > 0 ? trimmed : undefined;
56
+ }
57
+
58
+ function resolveEnvBool(value: unknown): boolean | undefined {
59
+ if (typeof value !== 'string') return undefined;
60
+ const trimmed = value.trim().toLowerCase();
61
+ if (trimmed === '1' || trimmed === 'true' || trimmed === 'yes') return true;
62
+ if (trimmed === '0' || trimmed === 'false' || trimmed === 'no') return false;
63
+ return undefined;
64
+ }
65
+
66
+ function resolveCloseIssueMode(value: unknown): CloseIssueMode | undefined {
67
+ const trimmed = resolveOptionalString(value);
68
+ if (!trimmed) return undefined;
69
+ const normalized = trimmed.toLowerCase();
70
+ if (normalized === 'auto' || normalized === 'always' || normalized === 'never') {
71
+ return normalized;
72
+ }
73
+ return undefined;
74
+ }
75
+
76
+ function isRunOptions(value: unknown): value is RunOptions {
77
+ return Boolean(value) && typeof value === 'object';
78
+ }
79
+
80
+ function parseRunOptionsEnv(): RunOptions | null {
81
+ const raw = resolveOptionalString(process.env.ZEROSHOT_RUN_OPTIONS);
82
+ if (!raw) return null;
83
+ try {
84
+ const parsed: unknown = JSON.parse(raw);
85
+ if (!isRunOptions(parsed)) {
86
+ return null;
87
+ }
88
+ return parsed;
89
+ } catch {
90
+ return null;
91
+ }
92
+ }
93
+
94
+ function parseMountSpecs(specs: readonly string[]): MountSpec[] {
95
+ return specs.map((spec) => {
96
+ const parts = spec.split(':');
97
+ if (parts.length < 2) {
98
+ throw new Error(`Invalid mount spec: "${spec}". Format: host:container[:ro]`);
99
+ }
100
+ const [host, container] = parts;
101
+ if (host === undefined || container === undefined) {
102
+ throw new Error(`Invalid mount spec: "${spec}". Format: host:container[:ro]`);
103
+ }
104
+ const readonly = parts[2] === 'ro';
105
+ return { host, container, readonly };
106
+ });
107
+ }
108
+
109
+ const RUN_MODE_KEYS = ['docker', 'worktree', 'pr', 'ship', 'noIsolation', 'isolation'] as const;
110
+
111
+ function hasExplicitRunMode(options: RunOptions): boolean {
112
+ return RUN_MODE_KEYS.some(
113
+ (key) => options[key] === true || (key === 'isolation' && options[key] === false)
114
+ );
115
+ }
116
+
117
+ function mergeRunOptions(options: RunOptions): RunOptions {
118
+ const envRunOptions = parseRunOptionsEnv();
119
+ if (!envRunOptions) return options;
120
+ if (!hasExplicitRunMode(options)) return { ...envRunOptions, ...options };
121
+ const withoutEnvMode = { ...envRunOptions };
122
+ for (const key of RUN_MODE_KEYS) delete withoutEnvMode[key];
123
+ return { ...withoutEnvMode, ...options };
124
+ }
125
+
126
+ function resolveMergeQueue(options: RunOptions): boolean | undefined {
127
+ if (typeof options.mergeQueue === 'boolean') {
128
+ return options.mergeQueue;
129
+ }
130
+ return resolveEnvBool(process.env.ZEROSHOT_MERGE_QUEUE);
131
+ }
132
+
133
+ function resolvePrBase(options: RunOptions): string | undefined {
134
+ return (
135
+ resolveOptionalString(options.prBase) ||
136
+ resolveOptionalString(process.env.ZEROSHOT_PR_BASE) ||
137
+ undefined
138
+ );
139
+ }
140
+
141
+ function resolveCloseIssue(options: RunOptions): CloseIssueMode | undefined {
142
+ return (
143
+ resolveCloseIssueMode(options.closeIssue) ||
144
+ resolveCloseIssueMode(process.env.ZEROSHOT_CLOSE_ISSUE) ||
145
+ undefined
146
+ );
147
+ }
148
+
149
+ function resolveMounts(options: RunOptions): MountSpec[] | undefined {
150
+ return options.mount ? parseMountSpecs(options.mount) : undefined;
151
+ }
152
+
153
+ export = {
154
+ firstTruthy,
155
+ anyTruthy,
156
+ optionalValue,
157
+ detectGitRepoRoot,
158
+ resolveTargetCwd,
159
+ resolveEnvBool,
160
+ mergeRunOptions,
161
+ resolveMergeQueue,
162
+ resolvePrBase,
163
+ resolveCloseIssue,
164
+ resolveMounts,
165
+ };
@@ -0,0 +1,279 @@
1
+ type RunIsolation = 'none' | 'worktree' | 'docker';
2
+ type RunDelivery = 'none' | 'pr' | 'ship';
3
+
4
+ interface RunPlan {
5
+ isolation: RunIsolation;
6
+ delivery: RunDelivery;
7
+ autoMerge: boolean;
8
+ }
9
+
10
+ interface Settings extends Record<string, unknown> {
11
+ defaultIsolation?: string;
12
+ defaultDelivery?: string;
13
+ }
14
+
15
+ interface RunOptions extends Record<string, unknown> {
16
+ autoMerge?: unknown;
17
+ autoPush?: unknown;
18
+ closeIssue?: unknown;
19
+ containerHome?: unknown;
20
+ cwd?: unknown;
21
+ docker?: unknown;
22
+ dockerImage?: unknown;
23
+ isolation?: unknown;
24
+ mergeQueue?: unknown;
25
+ mount?: readonly string[] | null;
26
+ mounts?: unknown;
27
+ noIsolation?: unknown;
28
+ noMounts?: unknown;
29
+ pr?: unknown;
30
+ prBase?: unknown;
31
+ preparedWorktree?: unknown;
32
+ requiredQualityGates?: unknown;
33
+ ship?: unknown;
34
+ worktree?: unknown;
35
+ }
36
+
37
+ interface RunPlanFacade {
38
+ resolveRunPlan(options?: RunOptions): Readonly<RunPlan>;
39
+ }
40
+
41
+ interface RunModeFacade {
42
+ runModeFromPlan(plan: RunPlan): string | null;
43
+ }
44
+
45
+ interface EnvironmentFacade {
46
+ firstTruthy<T>(...values: T[]): T | undefined;
47
+ anyTruthy(...values: unknown[]): boolean;
48
+ optionalValue<T>(value: T): T | undefined;
49
+ detectGitRepoRoot(): string;
50
+ resolveTargetCwd(): string | undefined;
51
+ resolveEnvBool(value: unknown): boolean | undefined;
52
+ mergeRunOptions(options: RunOptions): RunOptions;
53
+ resolveMergeQueue(options: RunOptions): boolean | undefined;
54
+ resolvePrBase(options: RunOptions): string | undefined;
55
+ resolveCloseIssue(options: RunOptions): 'auto' | 'always' | 'never' | undefined;
56
+ resolveMounts(options: RunOptions):
57
+ | Array<{ host: string; container: string; readonly: boolean }>
58
+ | undefined;
59
+ }
60
+
61
+ interface BuildStartOptionsArgs {
62
+ clusterId?: unknown;
63
+ options?: RunOptions;
64
+ settings?: Settings;
65
+ providerOverride?: unknown;
66
+ modelOverride?: unknown;
67
+ forceProvider?: unknown;
68
+ }
69
+
70
+ interface BuildTrustedStartOptionsArgs extends BuildStartOptionsArgs {
71
+ plan?: RunPlan | null;
72
+ }
73
+
74
+ interface BuildStartOptionsFromPlanArgs extends BuildStartOptionsArgs {
75
+ plan: RunPlan;
76
+ options: RunOptions;
77
+ settings: Settings;
78
+ preparedWorktree?: unknown;
79
+ environment: boolean;
80
+ }
81
+
82
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
83
+ const runPlan: RunPlanFacade = require('./run-plan');
84
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
85
+ const runMode: RunModeFacade = require('./run-mode');
86
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
87
+ const environmentHelpers: EnvironmentFacade = require('./start-cluster-environment');
88
+
89
+ const { resolveRunPlan } = runPlan;
90
+ const { runModeFromPlan } = runMode;
91
+ const {
92
+ firstTruthy,
93
+ anyTruthy,
94
+ optionalValue,
95
+ detectGitRepoRoot,
96
+ resolveTargetCwd,
97
+ resolveEnvBool,
98
+ mergeRunOptions,
99
+ resolveMergeQueue,
100
+ resolvePrBase,
101
+ resolveCloseIssue,
102
+ resolveMounts,
103
+ } = environmentHelpers;
104
+
105
+ function isRunIsolation(value: string): value is RunIsolation {
106
+ return value === 'none' || value === 'worktree' || value === 'docker';
107
+ }
108
+
109
+ function isRunDelivery(value: string): value is RunDelivery {
110
+ return value === 'none' || value === 'pr' || value === 'ship';
111
+ }
112
+
113
+ function validateSavedRunModes(settings: Settings): {
114
+ isolation: RunIsolation;
115
+ delivery: RunDelivery;
116
+ } {
117
+ const isolation = settings.defaultIsolation || 'none';
118
+ const delivery = settings.defaultDelivery || 'none';
119
+ if (!isRunIsolation(isolation)) {
120
+ throw new Error(`Invalid saved isolation mode: ${isolation}`);
121
+ }
122
+ if (!isRunDelivery(delivery)) {
123
+ throw new Error(`Invalid saved delivery mode: ${delivery}`);
124
+ }
125
+ return { isolation, delivery };
126
+ }
127
+
128
+ function resolveEffectiveIsolation(options: RunOptions, savedIsolation: RunIsolation): RunIsolation {
129
+ if (options.noIsolation === true || options.isolation === false) return 'none';
130
+ if (options.docker === true) return 'docker';
131
+ if (options.worktree === true || options.pr === true || options.ship === true) return 'worktree';
132
+ if (resolveEnvBool(process.env.ZEROSHOT_DOCKER) === true) return 'docker';
133
+ if (resolveEnvBool(process.env.ZEROSHOT_WORKTREE) === true) return 'worktree';
134
+ return savedIsolation;
135
+ }
136
+
137
+ function resolveEffectiveDelivery(options: RunOptions, savedDelivery: RunDelivery): RunDelivery {
138
+ if (options.ship === true || options.autoMerge === true) return 'ship';
139
+ if (options.pr === true || resolveEnvBool(process.env.ZEROSHOT_PR) === true) return 'pr';
140
+ return savedDelivery;
141
+ }
142
+
143
+ function resolveEffectiveRunPlan(
144
+ options: RunOptions = {},
145
+ settings: Settings = {}
146
+ ): Readonly<RunPlan> {
147
+ const mergedOptions = mergeRunOptions(options);
148
+ const noIsolation = mergedOptions.noIsolation === true || mergedOptions.isolation === false;
149
+ const conflicts = ['docker', 'worktree', 'pr', 'ship'].filter(
150
+ (key) => mergedOptions[key] === true
151
+ );
152
+ if (noIsolation && conflicts.length > 0) {
153
+ throw new Error(`--no-isolation conflicts with --${conflicts.join(', --')}`);
154
+ }
155
+
156
+ const saved = validateSavedRunModes(settings);
157
+ let isolation = resolveEffectiveIsolation(mergedOptions, saved.isolation);
158
+ const delivery = resolveEffectiveDelivery(mergedOptions, saved.delivery);
159
+ if (delivery !== 'none' && isolation === 'none') {
160
+ if (noIsolation) {
161
+ throw new Error(`--no-isolation conflicts with saved delivery mode "${delivery}"`);
162
+ }
163
+ isolation = 'worktree';
164
+ }
165
+ return resolveRunPlan({
166
+ docker: isolation === 'docker',
167
+ worktree: isolation === 'worktree',
168
+ pr: delivery === 'pr',
169
+ ship: delivery === 'ship',
170
+ });
171
+ }
172
+
173
+ function buildStartOptionsFromPlan({
174
+ clusterId,
175
+ plan,
176
+ options,
177
+ settings,
178
+ providerOverride,
179
+ modelOverride,
180
+ forceProvider,
181
+ preparedWorktree,
182
+ environment,
183
+ }: BuildStartOptionsFromPlanArgs): Readonly<Record<string, unknown>> {
184
+ const targetCwd = environment ? resolveTargetCwd() : options.cwd;
185
+ return Object.freeze({
186
+ clusterId,
187
+ cwd: targetCwd,
188
+ isolation: plan.isolation === 'docker',
189
+ isolationImage: environment
190
+ ? firstTruthy(options.dockerImage, process.env.ZEROSHOT_DOCKER_IMAGE)
191
+ : optionalValue(options.dockerImage),
192
+ worktree: plan.isolation === 'worktree',
193
+ preparedWorktree: preparedWorktree || undefined,
194
+ autoPr: plan.delivery !== 'none',
195
+ autoMerge: plan.autoMerge,
196
+ autoPush: environment ? process.env.ZEROSHOT_PUSH === '1' : options.autoPush === true,
197
+ modelOverride: optionalValue(modelOverride),
198
+ providerOverride: optionalValue(providerOverride),
199
+ noMounts: anyTruthy(options.mounts === false, options.noMounts === true),
200
+ mounts: resolveMounts(options),
201
+ containerHome: optionalValue(options.containerHome),
202
+ forceProvider: optionalValue(forceProvider),
203
+ prBase: environment ? resolvePrBase(options) : optionalValue(options.prBase),
204
+ mergeQueue: environment ? resolveMergeQueue(options) : optionalValue(options.mergeQueue),
205
+ closeIssue: environment ? resolveCloseIssue(options) : optionalValue(options.closeIssue),
206
+ ship: plan.delivery === 'ship',
207
+ runMode: runModeFromPlan(plan),
208
+ requiredQualityGates: options.requiredQualityGates,
209
+ settings,
210
+ });
211
+ }
212
+
213
+ function buildStartOptions({
214
+ clusterId,
215
+ options = {},
216
+ settings = {},
217
+ providerOverride,
218
+ modelOverride,
219
+ forceProvider,
220
+ }: BuildStartOptionsArgs): Readonly<Record<string, unknown>> {
221
+ const mergedOptions = mergeRunOptions(options);
222
+ const plan = resolveEffectiveRunPlan(options, settings);
223
+ return buildStartOptionsFromPlan({
224
+ clusterId,
225
+ plan,
226
+ options: mergedOptions,
227
+ settings,
228
+ providerOverride,
229
+ modelOverride,
230
+ forceProvider,
231
+ environment: true,
232
+ });
233
+ }
234
+
235
+ function buildTrustedStartOptions({
236
+ clusterId,
237
+ plan,
238
+ options = {},
239
+ settings = {},
240
+ providerOverride,
241
+ modelOverride,
242
+ forceProvider,
243
+ }: BuildTrustedStartOptionsArgs): Readonly<Record<string, unknown>> {
244
+ if (!plan || !Object.isFrozen(plan)) {
245
+ throw new Error('Trusted start requires a frozen canonical run plan');
246
+ }
247
+ const canonical = resolveRunPlan({
248
+ docker: plan.isolation === 'docker',
249
+ worktree: plan.isolation === 'worktree',
250
+ pr: plan.delivery === 'pr',
251
+ ship: plan.delivery === 'ship',
252
+ });
253
+ if (
254
+ canonical.isolation !== plan.isolation ||
255
+ canonical.delivery !== plan.delivery ||
256
+ canonical.autoMerge !== plan.autoMerge
257
+ ) {
258
+ throw new Error('Trusted start plan is not canonical');
259
+ }
260
+ if (canonical.isolation === 'none') {
261
+ throw new Error('Trusted worker start requires worktree or docker isolation');
262
+ }
263
+ if (options.preparedWorktree && canonical.isolation !== 'worktree') {
264
+ throw new Error('Prepared worktree requires canonical worktree isolation');
265
+ }
266
+ return buildStartOptionsFromPlan({
267
+ clusterId,
268
+ plan: canonical,
269
+ options,
270
+ settings,
271
+ providerOverride,
272
+ modelOverride,
273
+ forceProvider,
274
+ preparedWorktree: options.preparedWorktree,
275
+ environment: false,
276
+ });
277
+ }
278
+
279
+ export = { buildStartOptions, buildTrustedStartOptions, resolveEffectiveRunPlan, detectGitRepoRoot };