smol-symphony 0.2.0 → 0.3.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 (716) hide show
  1. package/AGENTS.md +41 -22
  2. package/DESIGN.md +494 -273
  3. package/README.md +109 -57
  4. package/SPEC.md +33 -24
  5. package/WORKFLOW.minimal.yaml +34 -0
  6. package/{WORKFLOW.template.md → WORKFLOW.template.yaml} +409 -256
  7. package/WORKFLOW.yaml +487 -0
  8. package/assets/skills/symphony-issues/SKILL.md +136 -0
  9. package/assets/symphony-mise.system.toml +68 -0
  10. package/dist/src/bin/symphony.js +30 -0
  11. package/dist/src/bin/symphony.js.map +1 -0
  12. package/dist/src/core/actions/context.js +109 -0
  13. package/dist/src/core/actions/context.js.map +1 -0
  14. package/dist/{actions/parsing.js → src/core/actions/parse.js} +33 -114
  15. package/dist/src/core/actions/parse.js.map +1 -0
  16. package/dist/src/core/actions/plan.js +197 -0
  17. package/dist/src/core/actions/plan.js.map +1 -0
  18. package/dist/src/core/actions/predicates.js +111 -0
  19. package/dist/src/core/actions/predicates.js.map +1 -0
  20. package/dist/src/core/actions/run-fold.js +248 -0
  21. package/dist/src/core/actions/run-fold.js.map +1 -0
  22. package/dist/src/core/actions/template.js +118 -0
  23. package/dist/src/core/actions/template.js.map +1 -0
  24. package/dist/src/core/cli/args.js +116 -0
  25. package/dist/src/core/cli/args.js.map +1 -0
  26. package/dist/src/core/coerce.js +75 -0
  27. package/dist/src/core/coerce.js.map +1 -0
  28. package/dist/src/core/credential/account-id.js +20 -0
  29. package/dist/src/core/credential/account-id.js.map +1 -0
  30. package/dist/src/core/credential/adapter-config.js +136 -0
  31. package/dist/src/core/credential/adapter-config.js.map +1 -0
  32. package/dist/src/core/credential/availability.js +98 -0
  33. package/dist/src/core/credential/availability.js.map +1 -0
  34. package/dist/src/core/credential/extract.js +228 -0
  35. package/dist/src/core/credential/extract.js.map +1 -0
  36. package/dist/src/core/credential/fake-creds.js +171 -0
  37. package/dist/src/core/credential/fake-creds.js.map +1 -0
  38. package/dist/src/core/credential/identity.js +125 -0
  39. package/dist/src/core/credential/identity.js.map +1 -0
  40. package/dist/src/core/credential/shape.js +230 -0
  41. package/dist/src/core/credential/shape.js.map +1 -0
  42. package/dist/src/core/credential/strings.js +15 -0
  43. package/dist/src/core/credential/strings.js.map +1 -0
  44. package/dist/src/core/doctor/checks.js +303 -0
  45. package/dist/src/core/doctor/checks.js.map +1 -0
  46. package/dist/src/core/git/result.js +107 -0
  47. package/dist/src/core/git/result.js.map +1 -0
  48. package/dist/src/core/http/decisions.js +225 -0
  49. package/dist/src/core/http/decisions.js.map +1 -0
  50. package/dist/{http.js → src/core/http/render.js} +472 -738
  51. package/dist/src/core/http/render.js.map +1 -0
  52. package/dist/{http-handlers.js → src/core/http/routes.js} +52 -87
  53. package/dist/src/core/http/routes.js.map +1 -0
  54. package/dist/src/core/http/views.js +181 -0
  55. package/dist/src/core/http/views.js.map +1 -0
  56. package/dist/src/core/image/managed-image.js +95 -0
  57. package/dist/src/core/image/managed-image.js.map +1 -0
  58. package/dist/src/core/issue/file.js +149 -0
  59. package/dist/src/core/issue/file.js.map +1 -0
  60. package/dist/src/core/issue/parse.js +210 -0
  61. package/dist/src/core/issue/parse.js.map +1 -0
  62. package/dist/src/core/mcp/dispatch.js +239 -0
  63. package/dist/src/core/mcp/dispatch.js.map +1 -0
  64. package/dist/src/core/mcp/post-move.js +92 -0
  65. package/dist/src/core/mcp/post-move.js.map +1 -0
  66. package/dist/src/core/mcp/protocol.js +293 -0
  67. package/dist/src/core/mcp/protocol.js.map +1 -0
  68. package/dist/src/core/mcp/url.js +162 -0
  69. package/dist/src/core/mcp/url.js.map +1 -0
  70. package/dist/src/core/path.js +63 -0
  71. package/dist/src/core/path.js.map +1 -0
  72. package/dist/src/core/reconcile/image-decide.js +48 -0
  73. package/dist/src/core/reconcile/image-decide.js.map +1 -0
  74. package/dist/src/core/reconcile/ledger.js +142 -0
  75. package/dist/src/core/reconcile/ledger.js.map +1 -0
  76. package/dist/src/core/reconcile/pr-classify.js +62 -0
  77. package/dist/src/core/reconcile/pr-classify.js.map +1 -0
  78. package/dist/{reconciler → src/core/reconcile}/pr-decide.js +25 -12
  79. package/dist/src/core/reconcile/pr-decide.js.map +1 -0
  80. package/dist/src/core/reconcile/pr-loop.js +161 -0
  81. package/dist/src/core/reconcile/pr-loop.js.map +1 -0
  82. package/dist/src/core/reconcile/pr-notes.js +35 -0
  83. package/dist/src/core/reconcile/pr-notes.js.map +1 -0
  84. package/dist/src/core/reconcile/vm-decide.js +70 -0
  85. package/dist/src/core/reconcile/vm-decide.js.map +1 -0
  86. package/dist/src/core/reconcile/vm-reap.js +207 -0
  87. package/dist/src/core/reconcile/vm-reap.js.map +1 -0
  88. package/dist/src/core/reconcile/workspace-decide.js +162 -0
  89. package/dist/src/core/reconcile/workspace-decide.js.map +1 -0
  90. package/dist/src/core/runlog/summary.js +231 -0
  91. package/dist/src/core/runlog/summary.js.map +1 -0
  92. package/dist/src/core/runner/dispatch-config.js +95 -0
  93. package/dist/src/core/runner/dispatch-config.js.map +1 -0
  94. package/dist/src/core/runner/injection.js +61 -0
  95. package/dist/src/core/runner/injection.js.map +1 -0
  96. package/dist/src/core/runner/mise.js +210 -0
  97. package/dist/src/core/runner/mise.js.map +1 -0
  98. package/dist/src/core/runner/prompt.js +720 -0
  99. package/dist/src/core/runner/prompt.js.map +1 -0
  100. package/dist/src/core/runner/turn.js +242 -0
  101. package/dist/src/core/runner/turn.js.map +1 -0
  102. package/dist/src/core/runner/vm-plan.js +390 -0
  103. package/dist/src/core/runner/vm-plan.js.map +1 -0
  104. package/dist/src/core/schedule/admission.js +123 -0
  105. package/dist/src/core/schedule/admission.js.map +1 -0
  106. package/dist/src/core/schedule/circuit-breaker.js +111 -0
  107. package/dist/src/core/schedule/circuit-breaker.js.map +1 -0
  108. package/dist/src/core/schedule/eligibility.js +83 -0
  109. package/dist/src/core/schedule/eligibility.js.map +1 -0
  110. package/dist/src/core/schedule/reconcile-issue.js +82 -0
  111. package/dist/src/core/schedule/reconcile-issue.js.map +1 -0
  112. package/dist/src/core/schedule/retry.js +96 -0
  113. package/dist/src/core/schedule/retry.js.map +1 -0
  114. package/dist/src/core/schedule/sleep-cycle.js +133 -0
  115. package/dist/src/core/schedule/sleep-cycle.js.map +1 -0
  116. package/dist/src/core/schedule/slots.js +124 -0
  117. package/dist/src/core/schedule/slots.js.map +1 -0
  118. package/dist/src/core/schedule/tick.js +553 -0
  119. package/dist/src/core/schedule/tick.js.map +1 -0
  120. package/dist/src/core/schedule/token-fold.js +181 -0
  121. package/dist/src/core/schedule/token-fold.js.map +1 -0
  122. package/dist/src/core/state-resolve.js +86 -0
  123. package/dist/src/core/state-resolve.js.map +1 -0
  124. package/dist/src/core/vm-guards.js +278 -0
  125. package/dist/src/core/vm-guards.js.map +1 -0
  126. package/dist/src/core/workflow/derive.js +107 -0
  127. package/dist/src/core/workflow/derive.js.map +1 -0
  128. package/dist/src/core/workflow/parse.js +687 -0
  129. package/dist/src/core/workflow/parse.js.map +1 -0
  130. package/dist/src/core/workflow/prompt-probe.js +78 -0
  131. package/dist/src/core/workflow/prompt-probe.js.map +1 -0
  132. package/dist/src/core/workflow/validate.js +189 -0
  133. package/dist/src/core/workflow/validate.js.map +1 -0
  134. package/dist/src/core/workspace-key.js +19 -0
  135. package/dist/src/core/workspace-key.js.map +1 -0
  136. package/dist/src/shell/actions-runner.js +356 -0
  137. package/dist/src/shell/actions-runner.js.map +1 -0
  138. package/dist/src/shell/adapter/adapter-registry.js +45 -0
  139. package/dist/src/shell/adapter/adapter-registry.js.map +1 -0
  140. package/dist/src/shell/adapter/clock-random.js +96 -0
  141. package/dist/src/shell/adapter/clock-random.js.map +1 -0
  142. package/dist/src/shell/adapter/gondolin-dispatch-helpers.js +158 -0
  143. package/dist/src/shell/adapter/gondolin-dispatch-helpers.js.map +1 -0
  144. package/dist/src/shell/adapter/gondolin-dispatch.js +385 -0
  145. package/dist/src/shell/adapter/gondolin-dispatch.js.map +1 -0
  146. package/dist/src/shell/adapter/gondolin-image-converter.js +233 -0
  147. package/dist/src/shell/adapter/gondolin-image-converter.js.map +1 -0
  148. package/dist/src/shell/adapter/gondolin-image-fetch.js +180 -0
  149. package/dist/src/shell/adapter/gondolin-image-fetch.js.map +1 -0
  150. package/dist/src/shell/adapter/launcher-asset.js +57 -0
  151. package/dist/src/shell/adapter/launcher-asset.js.map +1 -0
  152. package/dist/src/shell/adapter/mise-config-asset.js +65 -0
  153. package/dist/src/shell/adapter/mise-config-asset.js.map +1 -0
  154. package/dist/src/shell/adapter/workflow-loader.js +304 -0
  155. package/dist/src/shell/adapter/workflow-loader.js.map +1 -0
  156. package/dist/src/shell/cli/doctor.js +268 -0
  157. package/dist/src/shell/cli/doctor.js.map +1 -0
  158. package/dist/src/shell/effect-interpreter-families.js +314 -0
  159. package/dist/src/shell/effect-interpreter-families.js.map +1 -0
  160. package/dist/src/shell/effect-interpreter.js +29 -0
  161. package/dist/src/shell/effect-interpreter.js.map +1 -0
  162. package/dist/src/shell/interp/acp-frame.js +137 -0
  163. package/dist/src/shell/interp/acp-frame.js.map +1 -0
  164. package/dist/src/shell/interp/acp-ws-conn.js +320 -0
  165. package/dist/src/shell/interp/acp-ws-conn.js.map +1 -0
  166. package/dist/src/shell/interp/acp-ws-frames.js +159 -0
  167. package/dist/src/shell/interp/acp-ws-frames.js.map +1 -0
  168. package/dist/src/shell/interp/acp-ws.js +197 -0
  169. package/dist/src/shell/interp/acp-ws.js.map +1 -0
  170. package/dist/src/shell/interp/acp.js +319 -0
  171. package/dist/src/shell/interp/acp.js.map +1 -0
  172. package/dist/src/shell/interp/credential-defaults.js +128 -0
  173. package/dist/src/shell/interp/credential-defaults.js.map +1 -0
  174. package/dist/src/shell/interp/credential-hooks.js +149 -0
  175. package/dist/src/shell/interp/credential-hooks.js.map +1 -0
  176. package/dist/src/shell/interp/credential-registry.js +226 -0
  177. package/dist/src/shell/interp/credential-registry.js.map +1 -0
  178. package/dist/src/shell/interp/credential.js +103 -0
  179. package/dist/src/shell/interp/credential.js.map +1 -0
  180. package/dist/src/shell/interp/gh.js +163 -0
  181. package/dist/src/shell/interp/gh.js.map +1 -0
  182. package/dist/src/shell/interp/git.js +28 -0
  183. package/dist/src/shell/interp/git.js.map +1 -0
  184. package/dist/src/shell/interp/log.js +213 -0
  185. package/dist/src/shell/interp/log.js.map +1 -0
  186. package/dist/src/shell/interp/process.js +178 -0
  187. package/dist/src/shell/interp/process.js.map +1 -0
  188. package/dist/src/shell/interp/runlog.js +193 -0
  189. package/dist/src/shell/interp/runlog.js.map +1 -0
  190. package/dist/src/shell/interp/timer.js +64 -0
  191. package/dist/src/shell/interp/timer.js.map +1 -0
  192. package/dist/src/shell/interp/tracker-disk.js +99 -0
  193. package/dist/src/shell/interp/tracker-disk.js.map +1 -0
  194. package/dist/src/shell/interp/tracker-parse.js +71 -0
  195. package/dist/src/shell/interp/tracker-parse.js.map +1 -0
  196. package/dist/src/shell/interp/tracker-scan.js +238 -0
  197. package/dist/src/shell/interp/tracker-scan.js.map +1 -0
  198. package/dist/src/shell/interp/tracker-write.js +91 -0
  199. package/dist/src/shell/interp/tracker-write.js.map +1 -0
  200. package/dist/src/shell/interp/tracker.js +41 -0
  201. package/dist/src/shell/interp/tracker.js.map +1 -0
  202. package/dist/src/shell/interp/tty.js +48 -0
  203. package/dist/src/shell/interp/tty.js.map +1 -0
  204. package/dist/src/shell/interp/vm.js +199 -0
  205. package/dist/src/shell/interp/vm.js.map +1 -0
  206. package/dist/src/shell/interp/workspace.js +310 -0
  207. package/dist/src/shell/interp/workspace.js.map +1 -0
  208. package/dist/src/shell/main-acp.js +78 -0
  209. package/dist/src/shell/main-acp.js.map +1 -0
  210. package/dist/src/shell/main-adapters.js +222 -0
  211. package/dist/src/shell/main-adapters.js.map +1 -0
  212. package/dist/src/shell/main-credential.js +122 -0
  213. package/dist/src/shell/main-credential.js.map +1 -0
  214. package/dist/src/shell/main-doctor.js +22 -0
  215. package/dist/src/shell/main-doctor.js.map +1 -0
  216. package/dist/src/shell/main-entry.js +46 -0
  217. package/dist/src/shell/main-entry.js.map +1 -0
  218. package/dist/src/shell/main-http-csrf.js +45 -0
  219. package/dist/src/shell/main-http-csrf.js.map +1 -0
  220. package/dist/src/shell/main-http-handler.js +389 -0
  221. package/dist/src/shell/main-http-handler.js.map +1 -0
  222. package/dist/src/shell/main-http-mcp.js +122 -0
  223. package/dist/src/shell/main-http-mcp.js.map +1 -0
  224. package/dist/src/shell/main-http-views.js +253 -0
  225. package/dist/src/shell/main-http-views.js.map +1 -0
  226. package/dist/src/shell/main-http.js +76 -0
  227. package/dist/src/shell/main-http.js.map +1 -0
  228. package/dist/src/shell/main-loops.js +130 -0
  229. package/dist/src/shell/main-loops.js.map +1 -0
  230. package/dist/src/shell/main-mcp.js +129 -0
  231. package/dist/src/shell/main-mcp.js.map +1 -0
  232. package/dist/src/shell/main-orchestrator.js +120 -0
  233. package/dist/src/shell/main-orchestrator.js.map +1 -0
  234. package/dist/src/shell/main-preflight.js +43 -0
  235. package/dist/src/shell/main-preflight.js.map +1 -0
  236. package/dist/src/shell/main-reconcilers-helpers.js +244 -0
  237. package/dist/src/shell/main-reconcilers-helpers.js.map +1 -0
  238. package/dist/src/shell/main-reconcilers-pr.js +148 -0
  239. package/dist/src/shell/main-reconcilers-pr.js.map +1 -0
  240. package/dist/src/shell/main-reconcilers.js +225 -0
  241. package/dist/src/shell/main-reconcilers.js.map +1 -0
  242. package/dist/src/shell/main-runner.js +355 -0
  243. package/dist/src/shell/main-runner.js.map +1 -0
  244. package/dist/src/shell/main-scaffold.js +116 -0
  245. package/dist/src/shell/main-scaffold.js.map +1 -0
  246. package/dist/src/shell/main-shutdown.js +115 -0
  247. package/dist/src/shell/main-shutdown.js.map +1 -0
  248. package/dist/src/shell/main-startup.js +48 -0
  249. package/dist/src/shell/main-startup.js.map +1 -0
  250. package/dist/src/shell/main-substrates.js +43 -0
  251. package/dist/src/shell/main-substrates.js.map +1 -0
  252. package/dist/src/shell/main.js +385 -0
  253. package/dist/src/shell/main.js.map +1 -0
  254. package/dist/src/shell/orchestrator-feedback.js +69 -0
  255. package/dist/src/shell/orchestrator-feedback.js.map +1 -0
  256. package/dist/src/shell/orchestrator-image.js +167 -0
  257. package/dist/src/shell/orchestrator-image.js.map +1 -0
  258. package/dist/src/shell/orchestrator-loop.js +468 -0
  259. package/dist/src/shell/orchestrator-loop.js.map +1 -0
  260. package/dist/src/shell/orchestrator-reconcile.js +36 -0
  261. package/dist/src/shell/orchestrator-reconcile.js.map +1 -0
  262. package/dist/src/shell/reconciler-loop.js +228 -0
  263. package/dist/src/shell/reconciler-loop.js.map +1 -0
  264. package/dist/src/shell/runner-loop-turn.js +301 -0
  265. package/dist/src/shell/runner-loop-turn.js.map +1 -0
  266. package/dist/src/shell/runner-loop.js +338 -0
  267. package/dist/src/shell/runner-loop.js.map +1 -0
  268. package/dist/src/shell/server/http.js +208 -0
  269. package/dist/src/shell/server/http.js.map +1 -0
  270. package/dist/src/shell/server/mcp-runtime-effects.js +237 -0
  271. package/dist/src/shell/server/mcp-runtime-effects.js.map +1 -0
  272. package/dist/src/shell/server/mcp-runtime.js +99 -0
  273. package/dist/src/shell/server/mcp-runtime.js.map +1 -0
  274. package/dist/src/shell/workspace-key.js +14 -0
  275. package/dist/src/shell/workspace-key.js.map +1 -0
  276. package/dist/src/types/acp.js +8 -0
  277. package/dist/src/types/acp.js.map +1 -0
  278. package/dist/src/types/actions/plan.js +6 -0
  279. package/dist/src/types/actions/plan.js.map +1 -0
  280. package/dist/src/types/actions/predicates.js +6 -0
  281. package/dist/src/types/actions/predicates.js.map +1 -0
  282. package/dist/src/types/actions/run-fold.js +8 -0
  283. package/dist/src/types/actions/run-fold.js.map +1 -0
  284. package/dist/src/types/actions.js +7 -0
  285. package/dist/src/types/actions.js.map +1 -0
  286. package/dist/src/types/adapter/clock-random.js +4 -0
  287. package/dist/src/types/adapter/clock-random.js.map +1 -0
  288. package/dist/src/types/adapter/gondolin-image-converter.js +5 -0
  289. package/dist/src/types/adapter/gondolin-image-converter.js.map +1 -0
  290. package/dist/src/types/adapter/gondolin-image-fetch.js +5 -0
  291. package/dist/src/types/adapter/gondolin-image-fetch.js.map +1 -0
  292. package/dist/src/types/adapter/workflow-loader.js +4 -0
  293. package/dist/src/types/adapter/workflow-loader.js.map +1 -0
  294. package/dist/src/types/cli/args.js +8 -0
  295. package/dist/src/types/cli/args.js.map +1 -0
  296. package/dist/src/types/config.js +8 -0
  297. package/dist/src/types/config.js.map +1 -0
  298. package/dist/src/types/credential-interp.js +6 -0
  299. package/dist/src/types/credential-interp.js.map +1 -0
  300. package/dist/src/types/credentials.js +10 -0
  301. package/dist/src/types/credentials.js.map +1 -0
  302. package/dist/src/types/doctor.js +7 -0
  303. package/dist/src/types/doctor.js.map +1 -0
  304. package/dist/src/types/domain.js +7 -0
  305. package/dist/src/types/domain.js.map +1 -0
  306. package/dist/src/types/effect.js +15 -0
  307. package/dist/src/types/effect.js.map +1 -0
  308. package/dist/src/types/errors.js +39 -0
  309. package/dist/src/types/errors.js.map +1 -0
  310. package/dist/src/types/http/decisions.js +6 -0
  311. package/dist/src/types/http/decisions.js.map +1 -0
  312. package/dist/src/types/http/render.js +10 -0
  313. package/dist/src/types/http/render.js.map +1 -0
  314. package/dist/src/types/http/views.js +6 -0
  315. package/dist/src/types/http/views.js.map +1 -0
  316. package/dist/src/types/http.js +9 -0
  317. package/dist/src/types/http.js.map +1 -0
  318. package/dist/src/types/image/managed-image.js +7 -0
  319. package/dist/src/types/image/managed-image.js.map +1 -0
  320. package/dist/src/types/interp/effect-interpreter.js +8 -0
  321. package/dist/src/types/interp/effect-interpreter.js.map +1 -0
  322. package/dist/src/types/interp/tracker.js +7 -0
  323. package/dist/src/types/interp/tracker.js.map +1 -0
  324. package/dist/src/types/issue/file.js +6 -0
  325. package/dist/src/types/issue/file.js.map +1 -0
  326. package/dist/src/types/issue/parse.js +8 -0
  327. package/dist/src/types/issue/parse.js.map +1 -0
  328. package/dist/src/types/main-acp.js +13 -0
  329. package/dist/src/types/main-acp.js.map +1 -0
  330. package/dist/src/types/main-adapters.js +5 -0
  331. package/dist/src/types/main-adapters.js.map +1 -0
  332. package/dist/src/types/main-credential.js +21 -0
  333. package/dist/src/types/main-credential.js.map +1 -0
  334. package/dist/src/types/main-doctor.js +6 -0
  335. package/dist/src/types/main-doctor.js.map +1 -0
  336. package/dist/src/types/main-http-handler.js +12 -0
  337. package/dist/src/types/main-http-handler.js.map +1 -0
  338. package/dist/src/types/main-http.js +5 -0
  339. package/dist/src/types/main-http.js.map +1 -0
  340. package/dist/src/types/main-loops.js +5 -0
  341. package/dist/src/types/main-loops.js.map +1 -0
  342. package/dist/src/types/main-mcp.js +12 -0
  343. package/dist/src/types/main-mcp.js.map +1 -0
  344. package/dist/src/types/main-orchestrator.js +5 -0
  345. package/dist/src/types/main-orchestrator.js.map +1 -0
  346. package/dist/src/types/main-reconcilers.js +11 -0
  347. package/dist/src/types/main-reconcilers.js.map +1 -0
  348. package/dist/src/types/main-runner.js +13 -0
  349. package/dist/src/types/main-runner.js.map +1 -0
  350. package/dist/src/types/main-startup.js +5 -0
  351. package/dist/src/types/main-startup.js.map +1 -0
  352. package/dist/src/types/main-substrates.js +5 -0
  353. package/dist/src/types/main-substrates.js.map +1 -0
  354. package/dist/src/types/mcp/dispatch.js +4 -0
  355. package/dist/src/types/mcp/dispatch.js.map +1 -0
  356. package/dist/src/types/mcp/post-move.js +7 -0
  357. package/dist/src/types/mcp/post-move.js.map +1 -0
  358. package/dist/src/types/mcp.js +9 -0
  359. package/dist/src/types/mcp.js.map +1 -0
  360. package/dist/src/types/ports.js +12 -0
  361. package/dist/src/types/ports.js.map +1 -0
  362. package/dist/src/types/reconcile/image-decide.js +5 -0
  363. package/dist/src/types/reconcile/image-decide.js.map +1 -0
  364. package/dist/src/types/reconcile/ledger.js +7 -0
  365. package/dist/src/types/reconcile/ledger.js.map +1 -0
  366. package/dist/src/types/reconcile/pr-loop.js +8 -0
  367. package/dist/src/types/reconcile/pr-loop.js.map +1 -0
  368. package/dist/src/types/reconcile/vm-reap.js +8 -0
  369. package/dist/src/types/reconcile/vm-reap.js.map +1 -0
  370. package/dist/src/types/reconcile/workspace-decide.js +7 -0
  371. package/dist/src/types/reconcile/workspace-decide.js.map +1 -0
  372. package/dist/src/types/reconcile.js +9 -0
  373. package/dist/src/types/reconcile.js.map +1 -0
  374. package/dist/src/types/runlog.js +7 -0
  375. package/dist/src/types/runlog.js.map +1 -0
  376. package/dist/src/types/runner/actions-runner.js +12 -0
  377. package/dist/src/types/runner/actions-runner.js.map +1 -0
  378. package/dist/src/types/runner/gondolin-dispatch.js +5 -0
  379. package/dist/src/types/runner/gondolin-dispatch.js.map +1 -0
  380. package/dist/src/types/runner/injection.js +6 -0
  381. package/dist/src/types/runner/injection.js.map +1 -0
  382. package/dist/src/types/runner/runner-loop.js +5 -0
  383. package/dist/src/types/runner/runner-loop.js.map +1 -0
  384. package/dist/src/types/runner/turn.js +4 -0
  385. package/dist/src/types/runner/turn.js.map +1 -0
  386. package/dist/src/types/runner/vm-plan.js +4 -0
  387. package/dist/src/types/runner/vm-plan.js.map +1 -0
  388. package/dist/src/types/runtime.js +9 -0
  389. package/dist/src/types/runtime.js.map +1 -0
  390. package/dist/src/types/schedule/admission.js +7 -0
  391. package/dist/src/types/schedule/admission.js.map +1 -0
  392. package/dist/src/types/schedule/circuit-breaker.js +2 -0
  393. package/dist/src/types/schedule/circuit-breaker.js.map +1 -0
  394. package/dist/src/types/schedule/eligibility.js +9 -0
  395. package/dist/src/types/schedule/eligibility.js.map +1 -0
  396. package/dist/src/types/schedule/orchestrator-loop.js +10 -0
  397. package/dist/src/types/schedule/orchestrator-loop.js.map +1 -0
  398. package/dist/src/types/schedule/sleep-cycle.js +4 -0
  399. package/dist/src/types/schedule/sleep-cycle.js.map +1 -0
  400. package/dist/src/types/schedule/slots.js +8 -0
  401. package/dist/src/types/schedule/slots.js.map +1 -0
  402. package/dist/src/types/schedule/tick.js +9 -0
  403. package/dist/src/types/schedule/tick.js.map +1 -0
  404. package/dist/src/types/server/mcp-runtime.js +8 -0
  405. package/dist/src/types/server/mcp-runtime.js.map +1 -0
  406. package/dist/src/types/workflow/parse.js +4 -0
  407. package/dist/src/types/workflow/parse.js.map +1 -0
  408. package/dist/tests/core/account-id.test.js +35 -0
  409. package/dist/tests/core/account-id.test.js.map +1 -0
  410. package/dist/tests/core/actions-parse.test.js +176 -0
  411. package/dist/tests/core/actions-parse.test.js.map +1 -0
  412. package/dist/tests/core/adapter-config.test.js +133 -0
  413. package/dist/tests/core/adapter-config.test.js.map +1 -0
  414. package/dist/tests/core/admission.test.js +215 -0
  415. package/dist/tests/core/admission.test.js.map +1 -0
  416. package/dist/tests/core/args.test.js +132 -0
  417. package/dist/tests/core/args.test.js.map +1 -0
  418. package/dist/tests/core/availability.test.js +62 -0
  419. package/dist/tests/core/availability.test.js.map +1 -0
  420. package/dist/tests/core/checks.test.js +395 -0
  421. package/dist/tests/core/checks.test.js.map +1 -0
  422. package/dist/tests/core/circuit-breaker.test.js +172 -0
  423. package/dist/tests/core/circuit-breaker.test.js.map +1 -0
  424. package/dist/tests/core/coerce.test.js +87 -0
  425. package/dist/tests/core/coerce.test.js.map +1 -0
  426. package/dist/tests/core/context.test.js +228 -0
  427. package/dist/tests/core/context.test.js.map +1 -0
  428. package/dist/tests/core/decisions.test.js +310 -0
  429. package/dist/tests/core/decisions.test.js.map +1 -0
  430. package/dist/tests/core/derive.test.js +205 -0
  431. package/dist/tests/core/derive.test.js.map +1 -0
  432. package/dist/tests/core/dispatch-config.test.js +164 -0
  433. package/dist/tests/core/dispatch-config.test.js.map +1 -0
  434. package/dist/tests/core/dispatch.test.js +302 -0
  435. package/dist/tests/core/dispatch.test.js.map +1 -0
  436. package/dist/tests/core/eligibility.test.js +163 -0
  437. package/dist/tests/core/eligibility.test.js.map +1 -0
  438. package/dist/tests/core/extract.test.js +139 -0
  439. package/dist/tests/core/extract.test.js.map +1 -0
  440. package/dist/tests/core/fake-creds.test.js +134 -0
  441. package/dist/tests/core/fake-creds.test.js.map +1 -0
  442. package/dist/tests/core/file.test.js +197 -0
  443. package/dist/tests/core/file.test.js.map +1 -0
  444. package/dist/tests/core/git-result.test.js +113 -0
  445. package/dist/tests/core/git-result.test.js.map +1 -0
  446. package/dist/tests/core/identity.test.js +180 -0
  447. package/dist/tests/core/identity.test.js.map +1 -0
  448. package/dist/tests/core/image-decide.test.js +59 -0
  449. package/dist/tests/core/image-decide.test.js.map +1 -0
  450. package/dist/tests/core/injection.test.js +163 -0
  451. package/dist/tests/core/injection.test.js.map +1 -0
  452. package/dist/tests/core/ledger.test.js +218 -0
  453. package/dist/tests/core/ledger.test.js.map +1 -0
  454. package/dist/tests/core/managed-image.test.js +68 -0
  455. package/dist/tests/core/managed-image.test.js.map +1 -0
  456. package/dist/tests/core/mise.test.js +138 -0
  457. package/dist/tests/core/mise.test.js.map +1 -0
  458. package/dist/tests/core/parse.test.js +174 -0
  459. package/dist/tests/core/parse.test.js.map +1 -0
  460. package/dist/tests/core/path.test.js +50 -0
  461. package/dist/tests/core/path.test.js.map +1 -0
  462. package/dist/tests/core/plan.test.js +218 -0
  463. package/dist/tests/core/plan.test.js.map +1 -0
  464. package/dist/tests/core/post-move.test.js +162 -0
  465. package/dist/tests/core/post-move.test.js.map +1 -0
  466. package/dist/tests/core/pr-classify.test.js +117 -0
  467. package/dist/tests/core/pr-classify.test.js.map +1 -0
  468. package/dist/tests/core/pr-decide.test.js +298 -0
  469. package/dist/tests/core/pr-decide.test.js.map +1 -0
  470. package/dist/tests/core/pr-loop.test.js +301 -0
  471. package/dist/tests/core/pr-loop.test.js.map +1 -0
  472. package/dist/tests/core/pr-notes.test.js +165 -0
  473. package/dist/tests/core/pr-notes.test.js.map +1 -0
  474. package/dist/tests/core/predicates.test.js +154 -0
  475. package/dist/tests/core/predicates.test.js.map +1 -0
  476. package/dist/tests/core/prompt.test.js +189 -0
  477. package/dist/tests/core/prompt.test.js.map +1 -0
  478. package/dist/tests/core/protocol.test.js +195 -0
  479. package/dist/tests/core/protocol.test.js.map +1 -0
  480. package/dist/tests/core/reconcile-issue.test.js +116 -0
  481. package/dist/tests/core/reconcile-issue.test.js.map +1 -0
  482. package/dist/tests/core/render.test.js +549 -0
  483. package/dist/tests/core/render.test.js.map +1 -0
  484. package/dist/tests/core/retry.test.js +186 -0
  485. package/dist/tests/core/retry.test.js.map +1 -0
  486. package/dist/tests/core/routes.test.js +247 -0
  487. package/dist/tests/core/routes.test.js.map +1 -0
  488. package/dist/tests/core/run-fold.test.js +299 -0
  489. package/dist/tests/core/run-fold.test.js.map +1 -0
  490. package/dist/tests/core/shape.test.js +185 -0
  491. package/dist/tests/core/shape.test.js.map +1 -0
  492. package/dist/tests/core/sleep-cycle.test.js +150 -0
  493. package/dist/tests/core/sleep-cycle.test.js.map +1 -0
  494. package/dist/tests/core/slots.test.js +201 -0
  495. package/dist/tests/core/slots.test.js.map +1 -0
  496. package/dist/tests/core/state-resolve.test.js +80 -0
  497. package/dist/tests/core/state-resolve.test.js.map +1 -0
  498. package/dist/tests/core/summary.test.js +200 -0
  499. package/dist/tests/core/summary.test.js.map +1 -0
  500. package/dist/tests/core/template.test.js +116 -0
  501. package/dist/tests/core/template.test.js.map +1 -0
  502. package/dist/tests/core/tick.test.js +558 -0
  503. package/dist/tests/core/tick.test.js.map +1 -0
  504. package/dist/tests/core/token-fold.test.js +176 -0
  505. package/dist/tests/core/token-fold.test.js.map +1 -0
  506. package/dist/tests/core/turn.test.js +388 -0
  507. package/dist/tests/core/turn.test.js.map +1 -0
  508. package/dist/tests/core/url.test.js +118 -0
  509. package/dist/tests/core/url.test.js.map +1 -0
  510. package/dist/tests/core/validate.test.js +247 -0
  511. package/dist/tests/core/validate.test.js.map +1 -0
  512. package/dist/tests/core/views.test.js +252 -0
  513. package/dist/tests/core/views.test.js.map +1 -0
  514. package/dist/tests/core/vm-decide.test.js +110 -0
  515. package/dist/tests/core/vm-decide.test.js.map +1 -0
  516. package/dist/tests/core/vm-guards.test.js +153 -0
  517. package/dist/tests/core/vm-guards.test.js.map +1 -0
  518. package/dist/tests/core/vm-plan.test.js +332 -0
  519. package/dist/tests/core/vm-plan.test.js.map +1 -0
  520. package/dist/tests/core/vm-reap.test.js +196 -0
  521. package/dist/tests/core/vm-reap.test.js.map +1 -0
  522. package/dist/tests/core/workflow-parse.test.js +493 -0
  523. package/dist/tests/core/workflow-parse.test.js.map +1 -0
  524. package/dist/tests/core/workspace-decide.test.js +236 -0
  525. package/dist/tests/core/workspace-decide.test.js.map +1 -0
  526. package/dist/tests/helpers/fixtures.js +167 -0
  527. package/dist/tests/helpers/fixtures.js.map +1 -0
  528. package/dist/tests/shell/acp-substrate.test.js +101 -0
  529. package/dist/tests/shell/acp-substrate.test.js.map +1 -0
  530. package/dist/tests/shell/actions-runner-push.test.js +203 -0
  531. package/dist/tests/shell/actions-runner-push.test.js.map +1 -0
  532. package/dist/tests/shell/credential-hooks.test.js +36 -0
  533. package/dist/tests/shell/credential-hooks.test.js.map +1 -0
  534. package/dist/tests/shell/credential-registry.test.js +165 -0
  535. package/dist/tests/shell/credential-registry.test.js.map +1 -0
  536. package/dist/tests/shell/credential-substrate.test.js +179 -0
  537. package/dist/tests/shell/credential-substrate.test.js.map +1 -0
  538. package/dist/tests/shell/dockerfile-mise-pin.test.js +51 -0
  539. package/dist/tests/shell/dockerfile-mise-pin.test.js.map +1 -0
  540. package/dist/tests/shell/doctor.test.js +101 -0
  541. package/dist/tests/shell/doctor.test.js.map +1 -0
  542. package/dist/tests/shell/effect-vm-create.test.js +52 -0
  543. package/dist/tests/shell/effect-vm-create.test.js.map +1 -0
  544. package/dist/tests/shell/gh-port.test.js +63 -0
  545. package/dist/tests/shell/gh-port.test.js.map +1 -0
  546. package/dist/tests/shell/gondolin-dispatch-guard.test.js +144 -0
  547. package/dist/tests/shell/gondolin-dispatch-guard.test.js.map +1 -0
  548. package/dist/tests/shell/gondolin-dispatch-shquote.test.js +168 -0
  549. package/dist/tests/shell/gondolin-dispatch-shquote.test.js.map +1 -0
  550. package/dist/tests/shell/gondolin-image-converter.test.js +208 -0
  551. package/dist/tests/shell/gondolin-image-converter.test.js.map +1 -0
  552. package/dist/tests/shell/gondolin-image-fetch.test.js +93 -0
  553. package/dist/tests/shell/gondolin-image-fetch.test.js.map +1 -0
  554. package/dist/tests/shell/http-handler.test.js +608 -0
  555. package/dist/tests/shell/http-handler.test.js.map +1 -0
  556. package/dist/tests/shell/http-server.test.js +53 -0
  557. package/dist/tests/shell/http-server.test.js.map +1 -0
  558. package/dist/tests/shell/mcp-runtime.test.js +366 -0
  559. package/dist/tests/shell/mcp-runtime.test.js.map +1 -0
  560. package/dist/tests/shell/mise-config-asset.test.js +87 -0
  561. package/dist/tests/shell/mise-config-asset.test.js.map +1 -0
  562. package/dist/tests/shell/orchestrator-loop.test.js +583 -0
  563. package/dist/tests/shell/orchestrator-loop.test.js.map +1 -0
  564. package/dist/tests/shell/reconciler-passes.test.js +314 -0
  565. package/dist/tests/shell/reconciler-passes.test.js.map +1 -0
  566. package/dist/tests/shell/runner-loop-turn.test.js +97 -0
  567. package/dist/tests/shell/runner-loop-turn.test.js.map +1 -0
  568. package/dist/tests/shell/runner-slice.test.js +536 -0
  569. package/dist/tests/shell/runner-slice.test.js.map +1 -0
  570. package/dist/tests/shell/scaffold.test.js +65 -0
  571. package/dist/tests/shell/scaffold.test.js.map +1 -0
  572. package/dist/tests/shell/tick-config.test.js +83 -0
  573. package/dist/tests/shell/tick-config.test.js.map +1 -0
  574. package/dist/tests/shell/tracker-parse-dates.test.js +44 -0
  575. package/dist/tests/shell/tracker-parse-dates.test.js.map +1 -0
  576. package/dist/tests/shell/tracker-write-issue.test.js +154 -0
  577. package/dist/tests/shell/tracker-write-issue.test.js.map +1 -0
  578. package/dist/tests/shell/workflow-prompt-split.test.js +208 -0
  579. package/dist/tests/shell/workflow-prompt-split.test.js.map +1 -0
  580. package/dist/tests/shell/workspace-live-config.test.js +140 -0
  581. package/dist/tests/shell/workspace-live-config.test.js.map +1 -0
  582. package/package.json +21 -9
  583. package/patches/@earendil-works+gondolin+0.12.0.patch +173 -0
  584. package/prompts/Reflect.md +91 -0
  585. package/prompts/Review.md +97 -0
  586. package/prompts/Todo.md +96 -0
  587. package/prompts/_footer.md +41 -0
  588. package/prompts/_preamble.md +42 -0
  589. package/prompts-minimal/Todo.md +26 -0
  590. package/scripts/postinstall.mjs +63 -0
  591. package/scripts/vm-agent.mjs +312 -90
  592. package/WORKFLOW.md +0 -744
  593. package/dist/acp-bridge.js +0 -324
  594. package/dist/acp-bridge.js.map +0 -1
  595. package/dist/actions/cache.js +0 -191
  596. package/dist/actions/cache.js.map +0 -1
  597. package/dist/actions/effects.js +0 -41
  598. package/dist/actions/effects.js.map +0 -1
  599. package/dist/actions/executor.js +0 -570
  600. package/dist/actions/executor.js.map +0 -1
  601. package/dist/actions/index.js +0 -13
  602. package/dist/actions/index.js.map +0 -1
  603. package/dist/actions/parsing.js.map +0 -1
  604. package/dist/actions/predicate-env.js +0 -27
  605. package/dist/actions/predicate-env.js.map +0 -1
  606. package/dist/actions/predicates.js +0 -49
  607. package/dist/actions/predicates.js.map +0 -1
  608. package/dist/actions/templating.js +0 -66
  609. package/dist/actions/templating.js.map +0 -1
  610. package/dist/actions/types.js +0 -15
  611. package/dist/actions/types.js.map +0 -1
  612. package/dist/agent/acp.js +0 -473
  613. package/dist/agent/acp.js.map +0 -1
  614. package/dist/agent/adapter-names.js +0 -159
  615. package/dist/agent/adapter-names.js.map +0 -1
  616. package/dist/agent/adapters.js +0 -511
  617. package/dist/agent/adapters.js.map +0 -1
  618. package/dist/agent/credential-extractors.js +0 -342
  619. package/dist/agent/credential-extractors.js.map +0 -1
  620. package/dist/agent/credential-secrets.js +0 -628
  621. package/dist/agent/credential-secrets.js.map +0 -1
  622. package/dist/agent/credential-ticker.js +0 -57
  623. package/dist/agent/credential-ticker.js.map +0 -1
  624. package/dist/agent/gondolin-creds-staging.js +0 -356
  625. package/dist/agent/gondolin-creds-staging.js.map +0 -1
  626. package/dist/agent/gondolin-dispatch.js +0 -375
  627. package/dist/agent/gondolin-dispatch.js.map +0 -1
  628. package/dist/agent/gondolin.js +0 -124
  629. package/dist/agent/gondolin.js.map +0 -1
  630. package/dist/agent/runner-decisions.js +0 -134
  631. package/dist/agent/runner-decisions.js.map +0 -1
  632. package/dist/agent/runner.js +0 -1456
  633. package/dist/agent/runner.js.map +0 -1
  634. package/dist/agent/tool-call-summary.js +0 -102
  635. package/dist/agent/tool-call-summary.js.map +0 -1
  636. package/dist/agent/vm-acp-mapping.js +0 -73
  637. package/dist/agent/vm-acp-mapping.js.map +0 -1
  638. package/dist/agent/vm-guards.js +0 -262
  639. package/dist/agent/vm-guards.js.map +0 -1
  640. package/dist/agent/vm-port.js +0 -22
  641. package/dist/agent/vm-port.js.map +0 -1
  642. package/dist/agent/vm-process-registry.js +0 -79
  643. package/dist/agent/vm-process-registry.js.map +0 -1
  644. package/dist/bin/cli-args.js +0 -105
  645. package/dist/bin/cli-args.js.map +0 -1
  646. package/dist/bin/symphony.js +0 -794
  647. package/dist/bin/symphony.js.map +0 -1
  648. package/dist/errors.js +0 -15
  649. package/dist/errors.js.map +0 -1
  650. package/dist/http-disk.js +0 -135
  651. package/dist/http-disk.js.map +0 -1
  652. package/dist/http-handlers.js.map +0 -1
  653. package/dist/http.js.map +0 -1
  654. package/dist/issues.js +0 -178
  655. package/dist/issues.js.map +0 -1
  656. package/dist/logging.js +0 -203
  657. package/dist/logging.js.map +0 -1
  658. package/dist/mcp.js +0 -706
  659. package/dist/mcp.js.map +0 -1
  660. package/dist/memory.js +0 -85
  661. package/dist/memory.js.map +0 -1
  662. package/dist/orchestrator-decisions.js +0 -331
  663. package/dist/orchestrator-decisions.js.map +0 -1
  664. package/dist/orchestrator.js +0 -1569
  665. package/dist/orchestrator.js.map +0 -1
  666. package/dist/prompt.js +0 -65
  667. package/dist/prompt.js.map +0 -1
  668. package/dist/reconciler/cache.js +0 -65
  669. package/dist/reconciler/cache.js.map +0 -1
  670. package/dist/reconciler/index.js +0 -448
  671. package/dist/reconciler/index.js.map +0 -1
  672. package/dist/reconciler/ledger.js +0 -131
  673. package/dist/reconciler/ledger.js.map +0 -1
  674. package/dist/reconciler/pr-adapters.js +0 -174
  675. package/dist/reconciler/pr-adapters.js.map +0 -1
  676. package/dist/reconciler/pr-decide.js.map +0 -1
  677. package/dist/reconciler/pr.js +0 -422
  678. package/dist/reconciler/pr.js.map +0 -1
  679. package/dist/reconciler/types.js +0 -12
  680. package/dist/reconciler/types.js.map +0 -1
  681. package/dist/reconciler/vm.js +0 -243
  682. package/dist/reconciler/vm.js.map +0 -1
  683. package/dist/reconciler/workspace-defaults.js +0 -83
  684. package/dist/reconciler/workspace-defaults.js.map +0 -1
  685. package/dist/reconciler/workspace.js +0 -272
  686. package/dist/reconciler/workspace.js.map +0 -1
  687. package/dist/runlog.js +0 -403
  688. package/dist/runlog.js.map +0 -1
  689. package/dist/scaffold.js +0 -165
  690. package/dist/scaffold.js.map +0 -1
  691. package/dist/trackers/local.js +0 -445
  692. package/dist/trackers/local.js.map +0 -1
  693. package/dist/trackers/types.js +0 -10
  694. package/dist/trackers/types.js.map +0 -1
  695. package/dist/types.js +0 -3
  696. package/dist/types.js.map +0 -1
  697. package/dist/util/clock.js +0 -12
  698. package/dist/util/clock.js.map +0 -1
  699. package/dist/util/crypto.js +0 -25
  700. package/dist/util/crypto.js.map +0 -1
  701. package/dist/util/frontmatter.js +0 -70
  702. package/dist/util/frontmatter.js.map +0 -1
  703. package/dist/util/fs-issues.js +0 -22
  704. package/dist/util/fs-issues.js.map +0 -1
  705. package/dist/util/process.js +0 -152
  706. package/dist/util/process.js.map +0 -1
  707. package/dist/util/workspace-key.js +0 -10
  708. package/dist/util/workspace-key.js.map +0 -1
  709. package/dist/workflow-loader.js +0 -147
  710. package/dist/workflow-loader.js.map +0 -1
  711. package/dist/workflow.js +0 -822
  712. package/dist/workflow.js.map +0 -1
  713. package/dist/workspace-types.js +0 -8
  714. package/dist/workspace-types.js.map +0 -1
  715. package/dist/workspace.js +0 -443
  716. package/dist/workspace.js.map +0 -1
@@ -0,0 +1,68 @@
1
+ # Symphony-bundled mise (jdx/mise) SYSTEM config — issue 209.
2
+ #
3
+ # The orchestrator stages this file into EVERY agent VM at /etc/mise/config.toml
4
+ # (mise's SYSTEM config = LOWEST precedence; applies everywhere, overridable per
5
+ # project). It is the SINGLE source of truth for the agent runtime (node) + the ACP
6
+ # agent CLIs — read off the host's OWN disk at boot and staged per-dispatch (like the
7
+ # vm-agent launcher), so it is decoupled from the image digest. Bump a pin HERE and
8
+ # restart symphony; NO `npm run build:image` + digest repin is needed. That decoupling
9
+ # is the whole point of issue 209: agent-CLI versioning is no longer coupled to the
10
+ # base image.
11
+ #
12
+ # Pins MUST match the versions the host ACP transport speaks. ALL agent CLIs are
13
+ # pinned DELIBERATELY: an unpinned bump can silently change codex's Responses-API
14
+ # transport, opencode's acp/custom-provider behavior, or Claude Code's model-stream
15
+ # handling (an unpinned claude-code 2.1.156 -> 2.1.160 once stalled dispatches mid-turn,
16
+ # idle on the /v1/messages stream until the stall reaper killed them). Bump these
17
+ # consciously, not by drift.
18
+ #
19
+ # node stays >= 21: the in-VM launcher needs the global WHATWG WebSocket. The agent
20
+ # runtime node is resolved system-scoped (`mise which node` from `/`), so a consuming
21
+ # repo's mise.toml can override `node` for the PROJECT's build/test (the workspace
22
+ # shims) WITHOUT downgrading the agent itself.
23
+ #
24
+ # A consuming repo's own mise.toml / .tool-versions (HIGHER precedence) ADDS project
25
+ # toolchains (rust, go, kotlin+gradle, a different node, ...) on top of this set;
26
+ # `mise install` with cwd = workspace installs the MERGED system + project tool set
27
+ # into the shared, home-based, warm-cached data dir.
28
+ #
29
+ # The `npm:` backend installs an npm package and exposes its bins as mise shims; node
30
+ # comes from mise's core node backend (nodejs.org prebuilts).
31
+ #
32
+ # ── npm lifecycle scripts (load-bearing — issue 209 review) ──────────────────────
33
+ # mise's `npm:` backend installs with `--ignore-scripts=true` by DEFAULT (a supply-
34
+ # chain hardening default; see mise.jdx.dev/dev-tools/backends/npm). That SUPPRESSES
35
+ # the package `postinstall` hooks that some agent CLIs use to materialize their native
36
+ # binary, so a plain string pin would `mise install` cleanly but then fail at RUNTIME
37
+ # when the CLI tries to exec a missing/stub binary. Two of our pins ship a native
38
+ # binary via a `postinstall` (verified against the registry metadata for the pinned
39
+ # versions):
40
+ # • @anthropic-ai/claude-code → "postinstall": "node install.cjs" (bin: claude.exe)
41
+ # • opencode-ai → "postinstall": "node ./postinstall.mjs" (bin: opencode.exe)
42
+ # @openai/codex + @zed-industries/codex-acp ship their native binary via
43
+ # optionalDependencies platform packages resolved at runtime by a JS bin shim
44
+ # (bin/codex.js, bin/codex-acp.js) and declare NO install script; they don't strictly
45
+ # need scripts, but we enable them UNIFORMLY across the native-binary CLIs so the
46
+ # contract is robust to version drift and to the platform packages' own install steps.
47
+ # @agentclientprotocol/claude-agent-acp is pure JS (ships dist/) with no native binary
48
+ # and no install hook, so it stays a plain pin.
49
+ #
50
+ # Opting back in uses the per-tool `npm_args = "--ignore-scripts=false"` option, which
51
+ # ONLY takes effect when npm is the active package manager — hence the explicit
52
+ # `[settings.npm] package_manager = "npm"` below. `auto` (the default) would fall back
53
+ # to npm TODAY (the base image ships no bun/pnpm), but a future baked package manager
54
+ # would silently switch and re-suppress scripts; pinning npm locks the contract.
55
+
56
+ [settings.npm]
57
+ # Force npm as the npm-backend installer so the per-tool `npm_args` below reliably
58
+ # apply (bun/pnpm ignore npm_args and don't run lifecycle scripts by default). The
59
+ # base image ships only `mise`; npm comes from the `node` install above.
60
+ package_manager = "npm"
61
+
62
+ [tools]
63
+ node = "24"
64
+ "npm:@anthropic-ai/claude-code" = { version = "2.1.156", npm_args = "--ignore-scripts=false" }
65
+ "npm:@openai/codex" = { version = "0.135.0", npm_args = "--ignore-scripts=false" }
66
+ "npm:@agentclientprotocol/claude-agent-acp" = "0.39.0"
67
+ "npm:@zed-industries/codex-acp" = { version = "0.15.0", npm_args = "--ignore-scripts=false" }
68
+ "npm:opencode-ai" = { version = "1.15.12", npm_args = "--ignore-scripts=false" }
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ // FCIS rewrite — the `symphony` binary ENTRYPOINT.
3
+ //
4
+ // Usage:
5
+ // symphony [path-to-WORKFLOW.yaml] [--port <port>] [--reconcile-force] [--verbose]
6
+ // symphony doctor [path-to-WORKFLOW.yaml] [--port <port>]
7
+ // symphony reconcile [path-to-WORKFLOW.yaml] [--force] [--port <port>]
8
+ //
9
+ // This file is intentionally a one-liner: the ENTIRE composition lives in the
10
+ // single composition root (src/shell/main.ts — the one file allowed to import the
11
+ // functional core). All this entrypoint does is invoke that root's `main()` and
12
+ // translate an unhandled rejection into a non-zero exit. Keeping it this thin
13
+ // means `package.json`'s `bin` target (dist/bin/symphony.js) and the `tsx`
14
+ // dev/start scripts share exactly the wiring path the tests exercise via
15
+ // `main(argv)`.
16
+ //
17
+ // package.json declares: "bin": { "symphony": "dist/bin/symphony.js" }
18
+ // and dev scripts run this file directly via tsx (src/bin/symphony.ts).
19
+ import process from 'node:process';
20
+ import { main } from '../shell/main.js';
21
+ // The composition root installs its own SIGINT/SIGTERM graceful-shutdown handlers
22
+ // and owns every process.exit on the preflight / bind-failure paths. Here we only
23
+ // backstop a thrown/ rejected main() — a startup failure that escaped bailStartup
24
+ // — with a fatal log + non-zero exit so the operator sees the cause.
25
+ main(process.argv.slice(2)).catch((err) => {
26
+ const e = err;
27
+ process.stderr.write(`fatal: ${e.message}\n${e.stack ?? ''}\n`);
28
+ process.exit(1);
29
+ });
30
+ //# sourceMappingURL=symphony.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symphony.js","sourceRoot":"","sources":["../../../src/bin/symphony.ts"],"names":[],"mappings":";AACA,mDAAmD;AACnD,EAAE;AACF,SAAS;AACT,qFAAqF;AACrF,+DAA+D;AAC/D,yEAAyE;AACzE,EAAE;AACF,8EAA8E;AAC9E,kFAAkF;AAClF,gFAAgF;AAChF,8EAA8E;AAC9E,2EAA2E;AAC3E,yEAAyE;AACzE,gBAAgB;AAChB,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AAExE,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,kFAAkF;AAClF,kFAAkF;AAClF,kFAAkF;AAClF,qEAAqE;AACrE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACjD,MAAM,CAAC,GAAG,GAAY,CAAC;IACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,IAAI,CAAC,CAAC;IAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,109 @@
1
+ // FCIS rewrite — pure ActionContext derivation + forwarded-env computation.
2
+ //
3
+ // Ports the two pure helpers from the original
4
+ // `src/agent/runner-decisions.ts` (`deriveActionContext`, `computeForwardedEnv`)
5
+ // plus the credential-strip filter the runner used to layer on top of
6
+ // `computeForwardedEnv` via `src/agent/vm-guards.ts:stripCredentialEnv`.
7
+ //
8
+ // In the original the runner did:
9
+ // stripCredentialEnv(computeForwardedEnv(forward_env, undefined, readEnv))
10
+ // `stripCredentialEnv` is itself a pure string-name filter (no IO), so the
11
+ // FCIS design folds the strip directly into the pure core function: the single
12
+ // `computeForwardedEnv` here returns the boot env with EVERY credential-bearing
13
+ // var already removed. The credential policy itself (`isCredentialEnvName`) is
14
+ // the ONE wired into the running app — it lives in `core/vm-guards.ts` and is
15
+ // re-exported here (no duplicate). The guest holds only placeholders Gondolin
16
+ // substitutes at egress (host-only refresh / placeholder-only guest invariant),
17
+ // so a real token must never enter the forwarded boot env. `readEnv` is injected
18
+ // so the function stays deterministic and unit-testable (no `process.env` in core).
19
+ //
20
+ // HARD CONSTRAINTS (gate-enforced):
21
+ // - 100% SYNCHRONOUS. No async/await/Promise anywhere.
22
+ // - No IO, no node: imports, no process/fetch, no wall clock, no randomness.
23
+ // - Imports ONLY from src/types/** and other pure-core modules (vm-guards).
24
+ /**
25
+ * Map a `RunningEntryView` snapshot + optional staged `SYMPHONY_*` env into the
26
+ * `ActionContext` the actions executor consumes. Mirrors the prior inline
27
+ * fallback chain in the original `buildActionContext` / `deriveActionContext`
28
+ * so a Done state reads `$branch` from the action-template namespace (the staged
29
+ * `SYMPHONY_*` env feeds the fallbacks).
30
+ *
31
+ * Fallback chain (highest → lowest precedence) per field:
32
+ * branch SYMPHONY_BRANCH → `agent/<identifier>`
33
+ * base_branch SYMPHONY_BASE_BRANCH → view.base_branch_at_dispatch → input.baseBranchDefault → 'main'
34
+ * repo repoEnv (SYMPHONY_REPO)→ view.github_repo_at_dispatch → input.repoDefault → null
35
+ * pr_title SYMPHONY_PR_TITLE → `<id>: <title>` (or `<id>` if untitled)
36
+ * pr_body_file SYMPHONY_PR_BODY_FILE → ''
37
+ */
38
+ export function deriveActionContext(input) {
39
+ const { view, extraEnv } = input;
40
+ const issueId = view.issue.id;
41
+ const issueTitle = view.issue.title;
42
+ const trimmedTitle = issueTitle.trim();
43
+ const defaultPrTitle = trimmedTitle.length > 0 ? `${issueId}: ${trimmedTitle}` : issueId;
44
+ // SYMPHONY_REPO wins; then the dispatch-pinned repo; then the live
45
+ // workspace.github_repo default; null when none is set. The cfg fallback is
46
+ // load-bearing because the dispatch-time pin (github_repo_at_dispatch) is not
47
+ // populated yet — without it a Done transition resolves $repo to null and
48
+ // silently skips push_branch / create_pr_if_missing. Mirrors runner-loop.ts's
49
+ // `|| cfg.workspace.github_repo` for the clone path.
50
+ const repoEnv = input.repoEnv;
51
+ const repoFromEnv = repoEnv && repoEnv.length > 0 ? repoEnv : null;
52
+ const repoPinned = view.github_repo_at_dispatch;
53
+ const repoFromPin = repoPinned && repoPinned.length > 0 ? repoPinned : null;
54
+ const repoDefault = input.repoDefault && input.repoDefault.length > 0 ? input.repoDefault : null;
55
+ const repo = repoFromEnv ?? repoFromPin ?? repoDefault;
56
+ // base_branch: staged env → dispatch-pinned base → live workspace.base_branch
57
+ // default → 'main' (the original's literal floor). Same cfg-fallback rationale
58
+ // as $repo: the dispatch-time pin isn't populated yet.
59
+ const pinnedBase = view.base_branch_at_dispatch;
60
+ const baseDefault = input.baseBranchDefault && input.baseBranchDefault.length > 0 ? input.baseBranchDefault : 'main';
61
+ const baseBranch = extraEnv?.SYMPHONY_BASE_BRANCH ?? (pinnedBase.length > 0 ? pinnedBase : baseDefault);
62
+ return {
63
+ identifier: view.identifier,
64
+ workspace: view.workspace_path,
65
+ branch: extraEnv?.SYMPHONY_BRANCH ?? `agent/${view.identifier}`,
66
+ base_branch: baseBranch,
67
+ issue_title: issueTitle,
68
+ issue_body: view.issue.description ?? '',
69
+ repo,
70
+ pr_title: extraEnv?.SYMPHONY_PR_TITLE ?? defaultPrTitle,
71
+ pr_body_file: extraEnv?.SYMPHONY_PR_BODY_FILE ?? '',
72
+ };
73
+ }
74
+ // ─── Forwarded boot env (with credential strip folded in) ────────────────────
75
+ // The strict boot-env credential policy lives canonically in core/vm-guards.ts
76
+ // (the copy actually wired into the running app via runner/vm-plan.ts). It is
77
+ // imported for `computeForwardedEnv` AND re-exported here so this module's
78
+ // importers (and its test) keep the `actions/context.js` specifier without a
79
+ // duplicate definition + duplicate named-set/prefix/suffix constants.
80
+ // vm-guards.ts is pure core, so importing it from another pure-core module is
81
+ // allowed.
82
+ import { isCredentialEnvName } from '../vm-guards.js';
83
+ export { isCredentialEnvName };
84
+ /**
85
+ * Compute the VM boot env from the `forward_env` list, dropping `omitVar` when
86
+ * set AND every credential-bearing var (strict boot-env policy). `omitVar` lets
87
+ * a caller exclude a single var by name; the runner strips all credential vars
88
+ * uniformly (the guest holds only a placeholder Gondolin substitutes at egress),
89
+ * so callers pass `omitVar = undefined` and rely on the credential filter.
90
+ * `readEnv` is injected so this stays deterministic and unit-testable (no
91
+ * `process.env` in core).
92
+ *
93
+ * A name that survives the credential filter but reads as empty/undefined is
94
+ * skipped (the original only forwarded vars with a non-empty value).
95
+ */
96
+ export function computeForwardedEnv(forwardList, omitVar, readEnv) {
97
+ const env = {};
98
+ for (const k of forwardList) {
99
+ if (k === omitVar)
100
+ continue;
101
+ if (isCredentialEnvName(k))
102
+ continue;
103
+ const v = readEnv(k);
104
+ if (v && v.length > 0)
105
+ env[k] = v;
106
+ }
107
+ return env;
108
+ }
109
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../src/core/actions/context.ts"],"names":[],"mappings":"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"}
@@ -1,30 +1,20 @@
1
- // Parse a per-state `actions:` block into typed records (issue 36).
1
+ // FCIS rewrite — pure parser for per-state `actions:` blocks.
2
2
  //
3
- // Lifts the YAML shape into the closed `WorkflowAction` union, validating
4
- // each kind's required fields up-front so a missing `head:` on
5
- // `create_pr_if_missing` (or a misspelled `kind:`) fails at workflow load
6
- // instead of at the first dispatch into the terminal state.
7
- import { WorkflowError } from '../errors.js';
3
+ // Functional core: every export here is a pure, synchronous (data) -> data
4
+ // function. No IO, no clock, no randomness, no node: imports. Imports only from
5
+ // src/types. Lifts the YAML shape of a per-state `actions:` block into the
6
+ // closed `WorkflowAction` union, validating each kind's required fields up-front
7
+ // so a missing `head:` on `create_pr_if_missing` (or a misspelled `kind:`) fails
8
+ // at workflow load instead of at the first dispatch into the terminal state.
9
+ //
10
+ // Ported faithfully from the original src/actions/parsing.ts.
11
+ import { WorkflowError } from '../../types/errors.js';
12
+ import { asString, asInt } from '../coerce.js';
8
13
  const KNOWN_KINDS = [
9
14
  'push_branch',
10
15
  'create_pr_if_missing',
11
- 'ensure_branch',
12
- 'checkout',
13
- 'merge',
14
- 'delete_branch',
15
16
  'run_in_vm',
16
- 'propose_followup',
17
17
  ];
18
- function asString(v) {
19
- return typeof v === 'string' ? v : null;
20
- }
21
- function asInt(v) {
22
- if (typeof v === 'number' && Number.isFinite(v))
23
- return Math.trunc(v);
24
- if (typeof v === 'string' && /^-?\d+$/.test(v))
25
- return parseInt(v, 10);
26
- return null;
27
- }
28
18
  function expectString(stateName, idx, kind, key, v) {
29
19
  const s = asString(v);
30
20
  if (s === null || s.length === 0) {
@@ -70,13 +60,14 @@ function parseErrorPolicy(stateName, idx, raw) {
70
60
  out.retry = { count, backoff_ms: backoff };
71
61
  }
72
62
  if (m.then !== undefined) {
63
+ const thenRouteTo = typeof m.then === 'object' && m.then !== null && !Array.isArray(m.then)
64
+ ? m.then.route_to
65
+ : undefined;
73
66
  if (m.then === 'abort') {
74
67
  out.then = 'abort';
75
68
  }
76
- else if (typeof m.then === 'object' &&
77
- !Array.isArray(m.then) &&
78
- typeof m.then.route_to === 'string') {
79
- out.then = { route_to: m.then.route_to };
69
+ else if (typeof thenRouteTo === 'string') {
70
+ out.then = { route_to: thenRouteTo };
80
71
  }
81
72
  else {
82
73
  throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] "on_error.then" must be "abort" or {route_to: <state>}`);
@@ -123,75 +114,21 @@ function parseAction(stateName, idx, raw) {
123
114
  body_from: expectString(stateName, idx, kind, 'body_from', m.body_from),
124
115
  ...cleanBase,
125
116
  };
126
- case 'ensure_branch':
127
- return {
128
- kind: 'ensure_branch',
129
- name: expectString(stateName, idx, kind, 'name', m.name),
130
- seed_from: asString(m.seed_from) ?? undefined,
131
- ...cleanBase,
132
- };
133
- case 'checkout':
134
- return {
135
- kind: 'checkout',
136
- ref: expectString(stateName, idx, kind, 'ref', m.ref),
137
- ...cleanBase,
138
- };
139
- case 'merge': {
140
- const onConflictRaw = m.on_conflict;
141
- let onConflict;
142
- if (onConflictRaw === 'abort') {
143
- onConflict = 'abort';
144
- }
145
- else if (typeof onConflictRaw === 'object' &&
146
- onConflictRaw !== null &&
147
- !Array.isArray(onConflictRaw) &&
148
- typeof onConflictRaw.route_to === 'string') {
149
- onConflict = { route_to: onConflictRaw.route_to };
150
- }
151
- else {
152
- throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] (merge): "on_conflict" must be "abort" or {route_to: <state>}`);
153
- }
154
- return {
155
- kind: 'merge',
156
- source: expectString(stateName, idx, kind, 'source', m.source),
157
- target: expectString(stateName, idx, kind, 'target', m.target),
158
- on_conflict: onConflict,
159
- ...cleanBase,
160
- };
161
- }
162
- case 'delete_branch': {
163
- const scope = asString(m.scope);
164
- if (scope !== 'local' && scope !== 'remote' && scope !== 'both') {
165
- throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] (delete_branch): "scope" must be one of local|remote|both`);
166
- }
167
- const remote = asString(m.remote) ?? undefined;
168
- if ((scope === 'remote' || scope === 'both') && !remote) {
169
- throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] (delete_branch): "remote" is required when scope includes "remote"`);
170
- }
171
- return {
172
- kind: 'delete_branch',
173
- name: expectString(stateName, idx, kind, 'name', m.name),
174
- scope,
175
- remote,
176
- ...cleanBase,
177
- };
178
- }
179
117
  case 'run_in_vm': {
180
118
  const name = asString(m.name);
181
119
  if (!name || name.length === 0) {
182
- throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] (run_in_vm): "name" is required (used by cache + rerun CLI)`);
120
+ throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] (run_in_vm): "name" is required (run-log label + snapshot key)`);
183
121
  }
184
- // Names are used as a path segment in the cache layout
185
- // (`<root>/actions/run_in_vm/<name>/<hash>/result.json`). Restrict to a
186
- // safe identifier set so `--check=<name>` is unambiguous and no name
187
- // can escape the namespace (e.g. via `..`). The cache layer also
188
- // defensively encodes unsafe chars, but rejecting at parse time keeps
189
- // the CLI surface honest.
122
+ // The name labels the action's run-log output + snapshot key. Restrict it
123
+ // to a safe identifier set so the label is unambiguous and free of path
124
+ // separators / leading dots.
190
125
  if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name)) {
191
126
  throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] (run_in_vm): "name" must match /^[A-Za-z0-9][A-Za-z0-9._-]*$/ (got: ${JSON.stringify(name)})`);
192
127
  }
193
128
  const cmdRaw = m.cmd;
194
- if (!Array.isArray(cmdRaw) || cmdRaw.length === 0 || !cmdRaw.every((s) => typeof s === 'string')) {
129
+ if (!Array.isArray(cmdRaw) ||
130
+ cmdRaw.length === 0 ||
131
+ !cmdRaw.every((s) => typeof s === 'string')) {
195
132
  throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] (run_in_vm): "cmd" must be a non-empty list of strings`);
196
133
  }
197
134
  const envRaw = m.env;
@@ -224,33 +161,6 @@ function parseAction(stateName, idx, raw) {
224
161
  action.timeout = timeout;
225
162
  return action;
226
163
  }
227
- case 'propose_followup': {
228
- const labelsRaw = m.labels;
229
- let labels;
230
- if (labelsRaw !== undefined) {
231
- if (!Array.isArray(labelsRaw) || !labelsRaw.every((s) => typeof s === 'string')) {
232
- throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] (propose_followup): "labels" must be a list of strings`);
233
- }
234
- labels = labelsRaw;
235
- }
236
- const priority = m.priority === undefined ? undefined : asInt(m.priority);
237
- if (m.priority !== undefined && priority === null) {
238
- throw new WorkflowError('workflow_parse_error', `state "${stateName}": actions[${idx}] (propose_followup): "priority" must be an integer`);
239
- }
240
- const action = {
241
- kind: 'propose_followup',
242
- title: expectString(stateName, idx, kind, 'title', m.title),
243
- ...cleanBase,
244
- };
245
- const body = asString(m.body);
246
- if (body !== null)
247
- action.body = body;
248
- if (labels !== undefined)
249
- action.labels = labels;
250
- if (priority !== undefined && priority !== null)
251
- action.priority = priority;
252
- return action;
253
- }
254
164
  default: {
255
165
  // Exhaustiveness check at the type level — adding a new kind to the union
256
166
  // without extending this switch is a TypeScript error.
@@ -260,6 +170,15 @@ function parseAction(stateName, idx, raw) {
260
170
  }
261
171
  }
262
172
  }
173
+ /**
174
+ * Lift a per-state `actions:` YAML block into the typed `WorkflowAction` union.
175
+ *
176
+ * - `undefined` (no `actions:` key) -> `undefined`.
177
+ * - `null` (declared but empty) -> `[]`.
178
+ * - Any non-list -> throws `WorkflowError('workflow_parse_error', ...)`.
179
+ *
180
+ * Each entry is validated per-kind; the first invalid entry throws.
181
+ */
263
182
  export function parseActionsBlock(stateName, raw) {
264
183
  if (raw === undefined)
265
184
  return undefined;
@@ -270,4 +189,4 @@ export function parseActionsBlock(stateName, raw) {
270
189
  }
271
190
  return raw.map((entry, idx) => parseAction(stateName, idx, entry));
272
191
  }
273
- //# sourceMappingURL=parsing.js.map
192
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../../src/core/actions/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ // FCIS rewrite — pure action planner (ported from src/actions/effects.ts +
2
+ // the per-kind appliers in src/actions/executor.ts of the reference
3
+ // orchestrator).
4
+ //
5
+ // FUNCTIONAL CORE. Every function here is SYNCHRONOUS and pure: (data) -> data.
6
+ // No IO, no async/await/Promise, no clock, no randomness, no Effects executed.
7
+ // Imports ONLY from src/types (NodeNext ESM → .js extensions on relative
8
+ // imports) plus the sibling pure core helpers (template.ts, predicates.ts).
9
+ //
10
+ // WHAT MOVED INTO CORE (vs. the reference):
11
+ // • The reference `planActions` (src/actions/effects.ts) only rendered each
12
+ // action and emitted a `{ kind:'run' | 'render_failed' }` envelope; the
13
+ // ACTUAL git/gh/vm decisions lived in the async per-kind appliers in
14
+ // executor.ts (applyPushBranch, applyMerge, …). Those appliers WERE the
15
+ // side-effect-deciding logic interleaved with IO.
16
+ // • Here the per-kind mapping is lifted into the pure core: each rendered
17
+ // action is mapped to its git/gh/vm/tracker `Effect[]` SEQUENCE as DATA.
18
+ // The shell becomes a dumb interpreter that runs the emitted effects and
19
+ // folds outcomes back (the conditional branches the appliers used to take
20
+ // — "PR already exists? skip create", "non-fast-forward? force-with-lease"
21
+ // — are still in the shell's run-fold, but the candidate effects, including
22
+ // the NFF fallback sub-sequence, are produced here as data).
23
+ //
24
+ // The push_branch NFF (non-fast-forward) recovery is the keystone (mustFix, all
25
+ // judges): the planner emits BOTH the plain push and the force-with-lease
26
+ // fallback sub-sequence (fetch → rev-parse → push_force_with_lease) as data, so
27
+ // the shell never has to decide what the recovery looks like — only WHETHER to
28
+ // take it (on a non-fast-forward push result).
29
+ import { renderTree } from './template.js';
30
+ import { evaluatePredicate } from './predicates.js';
31
+ // ─── defaults (mirror src/actions/effects.ts) ────────────────────────────────
32
+ const DEFAULT_RETRY_COUNT = 3;
33
+ const DEFAULT_RETRY_BACKOFF_MS = 1_000;
34
+ /** Reference default per-command timeout (executor.ts defaultCommandTimeoutMs). */
35
+ const DEFAULT_COMMAND_TIMEOUT_MS = 300_000;
36
+ /**
37
+ * Pure planner — same inputs always produce the same `PlannedAction[]`.
38
+ *
39
+ * Faithful to src/actions/effects.ts:planActions for the envelope + snapshot
40
+ * keying; extended to emit the per-kind Effect sequence as data.
41
+ */
42
+ export function planActions(actions, ctx, opts) {
43
+ return actions.map((action, index) => planOne(action, index, ctx, opts));
44
+ }
45
+ function planOne(action, index, ctx, opts) {
46
+ const snapshotKey = actionSnapshotKey(action, index);
47
+ const r = renderTree(action, ctx);
48
+ if (!r.ok) {
49
+ return { kind: 'render_failed', snapshotKey, error: r.error };
50
+ }
51
+ const rendered = r.value;
52
+ const predicate = evaluatePredicate(actionPredicate(rendered), ctx, opts.workspacePath);
53
+ const { effects, nffFallback } = mapEffects(rendered, opts);
54
+ return {
55
+ kind: 'run',
56
+ snapshotKey,
57
+ actionKind: rendered.kind,
58
+ rendered,
59
+ predicate,
60
+ policy: normalizePolicy(actionPolicy(rendered)),
61
+ effects,
62
+ nffFallback,
63
+ };
64
+ }
65
+ // ─── snapshot keying (faithful to actionSnapshotKey) ──────────────────────────
66
+ function actionSnapshotKey(action, idx) {
67
+ if (action.name && action.name.length > 0)
68
+ return `${action.kind}:${action.name}`;
69
+ return `${action.kind}:#${idx}`;
70
+ }
71
+ // ─── policy normalization (faithful to effectivePolicy) ───────────────────────
72
+ // NOTE: the new NormalizedActionPolicy shape (src/types/actions.ts) flattens the
73
+ // reference `{ retry: { count, backoff_ms } }` into `{ retryCount, backoffMs }`.
74
+ function normalizePolicy(p) {
75
+ return {
76
+ retryCount: p?.retry?.count ?? DEFAULT_RETRY_COUNT,
77
+ backoffMs: p?.retry?.backoff_ms ?? DEFAULT_RETRY_BACKOFF_MS,
78
+ then: p?.then ?? 'abort',
79
+ };
80
+ }
81
+ // BaseAction carries `if`/`on_error` but the discriminated union has no shared
82
+ // accessor; read them positionally without widening to `any`.
83
+ function actionPredicate(a) {
84
+ return a.if;
85
+ }
86
+ function actionPolicy(a) {
87
+ return a.on_error;
88
+ }
89
+ function mapEffects(action, opts) {
90
+ switch (action.kind) {
91
+ case 'push_branch':
92
+ return mapPushBranch(action, opts);
93
+ case 'create_pr_if_missing':
94
+ return mapCreatePrIfMissing(action, opts);
95
+ case 'run_in_vm':
96
+ return mapRunInVm(action, opts);
97
+ default: {
98
+ // Exhaustiveness guard — a new kind without a mapping is a compile error.
99
+ const _exhaustive = action;
100
+ void _exhaustive;
101
+ return { effects: [], nffFallback: null };
102
+ }
103
+ }
104
+ }
105
+ // push_branch — `git push -u <remote> <ref>`, with the non-fast-forward
106
+ // recovery (fetch → rev-parse remote-tracking → push_force_with_lease) emitted
107
+ // as a SEPARATE data sub-sequence. Mirrors applyPushBranch + isNonFastForward.
108
+ //
109
+ // The reference resolved the remote SHA at runtime (it read the live remote-
110
+ // tracking ref). Core cannot read the remote, so `expectedRemoteSha` is a
111
+ // placeholder ('') the shell rewrites with the SHA the preceding rev_parse
112
+ // returns. The lease keeps the force-push safe under a true concurrent push.
113
+ function mapPushBranch(action, opts) {
114
+ const cwd = opts.workspacePath;
115
+ const effects = [
116
+ { family: 'git', kind: 'push', cwd, remote: action.remote, ref: action.ref },
117
+ ];
118
+ const remoteTrackingRef = `refs/remotes/${action.remote}/${action.ref}`;
119
+ const nffFallback = [
120
+ { family: 'git', kind: 'fetch', cwd, remote: action.remote, ref: action.ref },
121
+ { family: 'git', kind: 'rev_parse', cwd, ref: remoteTrackingRef },
122
+ {
123
+ family: 'git',
124
+ kind: 'push_force_with_lease',
125
+ cwd,
126
+ remote: action.remote,
127
+ ref: action.ref,
128
+ // Placeholder; shell substitutes the SHA from the rev_parse above.
129
+ expectedRemoteSha: '',
130
+ },
131
+ ];
132
+ return { effects, nffFallback };
133
+ }
134
+ // create_pr_if_missing — `gh pr list/view` then `gh pr create` if missing.
135
+ // Mirrors applyCreatePrIfMissing. The reference probed `gh pr view <head>`
136
+ // (non-zero ⇒ open one). The effect union models the probe as
137
+ // `gh.pr_list_for_branch` (head branch → existing PR?), and the create as
138
+ // `gh.pr_create`. The shell skips the create when the probe finds a PR.
139
+ //
140
+ // body_from / `--body-file` vs `--body`: the reference decided this at runtime
141
+ // by stat-ing the body string against the workspace (looksLikeFile). Core
142
+ // cannot stat, so it carries `bodyIsFile` as a STRUCTURAL guess (a single-line
143
+ // path-shaped value); the shell confirms the file exists before choosing the
144
+ // flag. A multi-line body is unambiguously NOT a file.
145
+ function mapCreatePrIfMissing(action, opts) {
146
+ const cwd = opts.workspacePath;
147
+ const effects = [
148
+ { family: 'gh', kind: 'pr_list_for_branch', cwd, branch: action.head },
149
+ {
150
+ family: 'gh',
151
+ kind: 'pr_create',
152
+ cwd,
153
+ base: action.base,
154
+ head: action.head,
155
+ title: action.title_from,
156
+ bodyOrFile: action.body_from,
157
+ bodyIsFile: looksLikeFilePath(action.body_from),
158
+ },
159
+ ];
160
+ return { effects, nffFallback: null };
161
+ }
162
+ // run_in_vm — a plain uncached `vm.exec` on the live per-issue VM. Mirrors
163
+ // applyRunInVm / executeRunInVm. The exec timeout mirrors executeRunInVm:
164
+ // action.timeout (seconds) overrides the bound default (ms).
165
+ function mapRunInVm(action, opts) {
166
+ const env = action.env ?? {};
167
+ const timeoutMs = action.timeout !== undefined
168
+ ? action.timeout * 1000
169
+ : (opts.defaultCommandTimeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS);
170
+ const effects = [
171
+ // vmId is a placeholder the shell binds to the per-issue VM at exec time
172
+ // (core has no handle to the live VM). workdir is the workspace mount.
173
+ {
174
+ family: 'vm',
175
+ kind: 'exec',
176
+ vmId: '',
177
+ command: action.cmd,
178
+ workdir: opts.workspacePath,
179
+ env,
180
+ timeoutMs,
181
+ },
182
+ ];
183
+ return { effects, nffFallback: null };
184
+ }
185
+ // ─── helpers ──────────────────────────────────────────────────────────────────
186
+ /**
187
+ * Structural guess at whether a `body_from` value names a file (so the shell
188
+ * passes `--body-file` rather than `--body`). The reference (looksLikeFile)
189
+ * stat-ed the path against the workspace — an IO read core cannot do — so here
190
+ * we only rule OUT the unambiguous non-paths: empty strings and multi-line
191
+ * bodies. A single-line value is FLAGGED as file-shaped; the shell confirms the
192
+ * file exists before committing to `--body-file`.
193
+ */
194
+ function looksLikeFilePath(value) {
195
+ return value.length > 0 && !value.includes('\n');
196
+ }
197
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../../src/core/actions/plan.ts"],"names":[],"mappings":"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"}