smol-symphony 0.2.0 → 0.3.1

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 (540) 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/bin/symphony.js +22 -786
  11. package/dist/bin/symphony.js.map +1 -1
  12. package/dist/core/actions/context.js +109 -0
  13. package/dist/core/actions/context.js.map +1 -0
  14. package/dist/{actions/parsing.js → core/actions/parse.js} +33 -114
  15. package/dist/core/actions/parse.js.map +1 -0
  16. package/dist/core/actions/plan.js +197 -0
  17. package/dist/core/actions/plan.js.map +1 -0
  18. package/dist/core/actions/predicates.js +111 -0
  19. package/dist/core/actions/predicates.js.map +1 -0
  20. package/dist/core/actions/run-fold.js +248 -0
  21. package/dist/core/actions/run-fold.js.map +1 -0
  22. package/dist/core/actions/template.js +118 -0
  23. package/dist/core/actions/template.js.map +1 -0
  24. package/dist/core/cli/args.js +116 -0
  25. package/dist/core/cli/args.js.map +1 -0
  26. package/dist/core/coerce.js +75 -0
  27. package/dist/core/coerce.js.map +1 -0
  28. package/dist/core/credential/account-id.js +20 -0
  29. package/dist/core/credential/account-id.js.map +1 -0
  30. package/dist/core/credential/adapter-config.js +136 -0
  31. package/dist/core/credential/adapter-config.js.map +1 -0
  32. package/dist/core/credential/availability.js +98 -0
  33. package/dist/core/credential/availability.js.map +1 -0
  34. package/dist/core/credential/extract.js +228 -0
  35. package/dist/core/credential/extract.js.map +1 -0
  36. package/dist/core/credential/fake-creds.js +171 -0
  37. package/dist/core/credential/fake-creds.js.map +1 -0
  38. package/dist/core/credential/identity.js +125 -0
  39. package/dist/core/credential/identity.js.map +1 -0
  40. package/dist/core/credential/shape.js +230 -0
  41. package/dist/core/credential/shape.js.map +1 -0
  42. package/dist/core/credential/strings.js +15 -0
  43. package/dist/core/credential/strings.js.map +1 -0
  44. package/dist/core/doctor/checks.js +303 -0
  45. package/dist/core/doctor/checks.js.map +1 -0
  46. package/dist/core/git/result.js +107 -0
  47. package/dist/core/git/result.js.map +1 -0
  48. package/dist/core/http/decisions.js +225 -0
  49. package/dist/core/http/decisions.js.map +1 -0
  50. package/dist/{http.js → core/http/render.js} +472 -738
  51. package/dist/core/http/render.js.map +1 -0
  52. package/dist/{http-handlers.js → core/http/routes.js} +52 -87
  53. package/dist/core/http/routes.js.map +1 -0
  54. package/dist/core/http/views.js +181 -0
  55. package/dist/core/http/views.js.map +1 -0
  56. package/dist/core/image/managed-image.js +95 -0
  57. package/dist/core/image/managed-image.js.map +1 -0
  58. package/dist/core/issue/file.js +149 -0
  59. package/dist/core/issue/file.js.map +1 -0
  60. package/dist/core/issue/parse.js +210 -0
  61. package/dist/core/issue/parse.js.map +1 -0
  62. package/dist/core/mcp/dispatch.js +239 -0
  63. package/dist/core/mcp/dispatch.js.map +1 -0
  64. package/dist/core/mcp/post-move.js +92 -0
  65. package/dist/core/mcp/post-move.js.map +1 -0
  66. package/dist/core/mcp/protocol.js +293 -0
  67. package/dist/core/mcp/protocol.js.map +1 -0
  68. package/dist/core/mcp/url.js +162 -0
  69. package/dist/core/mcp/url.js.map +1 -0
  70. package/dist/core/path.js +63 -0
  71. package/dist/core/path.js.map +1 -0
  72. package/dist/core/reconcile/image-decide.js +48 -0
  73. package/dist/core/reconcile/image-decide.js.map +1 -0
  74. package/dist/core/reconcile/ledger.js +142 -0
  75. package/dist/core/reconcile/ledger.js.map +1 -0
  76. package/dist/core/reconcile/pr-classify.js +62 -0
  77. package/dist/core/reconcile/pr-classify.js.map +1 -0
  78. package/dist/{reconciler → core/reconcile}/pr-decide.js +25 -12
  79. package/dist/core/reconcile/pr-decide.js.map +1 -0
  80. package/dist/core/reconcile/pr-loop.js +161 -0
  81. package/dist/core/reconcile/pr-loop.js.map +1 -0
  82. package/dist/core/reconcile/pr-notes.js +35 -0
  83. package/dist/core/reconcile/pr-notes.js.map +1 -0
  84. package/dist/core/reconcile/vm-decide.js +70 -0
  85. package/dist/core/reconcile/vm-decide.js.map +1 -0
  86. package/dist/core/reconcile/vm-reap.js +207 -0
  87. package/dist/core/reconcile/vm-reap.js.map +1 -0
  88. package/dist/core/reconcile/workspace-decide.js +162 -0
  89. package/dist/core/reconcile/workspace-decide.js.map +1 -0
  90. package/dist/core/runlog/summary.js +231 -0
  91. package/dist/core/runlog/summary.js.map +1 -0
  92. package/dist/core/runner/dispatch-config.js +95 -0
  93. package/dist/core/runner/dispatch-config.js.map +1 -0
  94. package/dist/core/runner/injection.js +61 -0
  95. package/dist/core/runner/injection.js.map +1 -0
  96. package/dist/core/runner/mise.js +210 -0
  97. package/dist/core/runner/mise.js.map +1 -0
  98. package/dist/core/runner/prompt.js +720 -0
  99. package/dist/core/runner/prompt.js.map +1 -0
  100. package/dist/core/runner/turn.js +242 -0
  101. package/dist/core/runner/turn.js.map +1 -0
  102. package/dist/core/runner/vm-plan.js +390 -0
  103. package/dist/core/runner/vm-plan.js.map +1 -0
  104. package/dist/core/schedule/admission.js +123 -0
  105. package/dist/core/schedule/admission.js.map +1 -0
  106. package/dist/core/schedule/circuit-breaker.js +111 -0
  107. package/dist/core/schedule/circuit-breaker.js.map +1 -0
  108. package/dist/core/schedule/eligibility.js +83 -0
  109. package/dist/core/schedule/eligibility.js.map +1 -0
  110. package/dist/core/schedule/reconcile-issue.js +82 -0
  111. package/dist/core/schedule/reconcile-issue.js.map +1 -0
  112. package/dist/core/schedule/retry.js +96 -0
  113. package/dist/core/schedule/retry.js.map +1 -0
  114. package/dist/core/schedule/sleep-cycle.js +133 -0
  115. package/dist/core/schedule/sleep-cycle.js.map +1 -0
  116. package/dist/core/schedule/slots.js +124 -0
  117. package/dist/core/schedule/slots.js.map +1 -0
  118. package/dist/core/schedule/tick.js +553 -0
  119. package/dist/core/schedule/tick.js.map +1 -0
  120. package/dist/core/schedule/token-fold.js +181 -0
  121. package/dist/core/schedule/token-fold.js.map +1 -0
  122. package/dist/core/state-resolve.js +86 -0
  123. package/dist/core/state-resolve.js.map +1 -0
  124. package/dist/core/vm-guards.js +278 -0
  125. package/dist/core/vm-guards.js.map +1 -0
  126. package/dist/core/workflow/derive.js +107 -0
  127. package/dist/core/workflow/derive.js.map +1 -0
  128. package/dist/core/workflow/parse.js +687 -0
  129. package/dist/core/workflow/parse.js.map +1 -0
  130. package/dist/core/workflow/prompt-probe.js +78 -0
  131. package/dist/core/workflow/prompt-probe.js.map +1 -0
  132. package/dist/core/workflow/validate.js +189 -0
  133. package/dist/core/workflow/validate.js.map +1 -0
  134. package/dist/core/workspace-key.js +19 -0
  135. package/dist/core/workspace-key.js.map +1 -0
  136. package/dist/shell/actions-runner.js +356 -0
  137. package/dist/shell/actions-runner.js.map +1 -0
  138. package/dist/shell/adapter/adapter-registry.js +45 -0
  139. package/dist/shell/adapter/adapter-registry.js.map +1 -0
  140. package/dist/shell/adapter/clock-random.js +96 -0
  141. package/dist/shell/adapter/clock-random.js.map +1 -0
  142. package/dist/shell/adapter/gondolin-dispatch-helpers.js +158 -0
  143. package/dist/shell/adapter/gondolin-dispatch-helpers.js.map +1 -0
  144. package/dist/shell/adapter/gondolin-dispatch.js +385 -0
  145. package/dist/shell/adapter/gondolin-dispatch.js.map +1 -0
  146. package/dist/shell/adapter/gondolin-image-converter.js +233 -0
  147. package/dist/shell/adapter/gondolin-image-converter.js.map +1 -0
  148. package/dist/shell/adapter/gondolin-image-fetch.js +180 -0
  149. package/dist/shell/adapter/gondolin-image-fetch.js.map +1 -0
  150. package/dist/shell/adapter/launcher-asset.js +57 -0
  151. package/dist/shell/adapter/launcher-asset.js.map +1 -0
  152. package/dist/shell/adapter/mise-config-asset.js +65 -0
  153. package/dist/shell/adapter/mise-config-asset.js.map +1 -0
  154. package/dist/shell/adapter/workflow-loader.js +304 -0
  155. package/dist/shell/adapter/workflow-loader.js.map +1 -0
  156. package/dist/shell/cli/doctor.js +268 -0
  157. package/dist/shell/cli/doctor.js.map +1 -0
  158. package/dist/shell/effect-interpreter-families.js +314 -0
  159. package/dist/shell/effect-interpreter-families.js.map +1 -0
  160. package/dist/shell/effect-interpreter.js +29 -0
  161. package/dist/shell/effect-interpreter.js.map +1 -0
  162. package/dist/shell/interp/acp-frame.js +137 -0
  163. package/dist/shell/interp/acp-frame.js.map +1 -0
  164. package/dist/shell/interp/acp-ws-conn.js +320 -0
  165. package/dist/shell/interp/acp-ws-conn.js.map +1 -0
  166. package/dist/shell/interp/acp-ws-frames.js +159 -0
  167. package/dist/shell/interp/acp-ws-frames.js.map +1 -0
  168. package/dist/shell/interp/acp-ws.js +197 -0
  169. package/dist/shell/interp/acp-ws.js.map +1 -0
  170. package/dist/shell/interp/acp.js +319 -0
  171. package/dist/shell/interp/acp.js.map +1 -0
  172. package/dist/shell/interp/credential-defaults.js +128 -0
  173. package/dist/shell/interp/credential-defaults.js.map +1 -0
  174. package/dist/shell/interp/credential-hooks.js +149 -0
  175. package/dist/shell/interp/credential-hooks.js.map +1 -0
  176. package/dist/shell/interp/credential-registry.js +226 -0
  177. package/dist/shell/interp/credential-registry.js.map +1 -0
  178. package/dist/shell/interp/credential.js +103 -0
  179. package/dist/shell/interp/credential.js.map +1 -0
  180. package/dist/shell/interp/gh.js +163 -0
  181. package/dist/shell/interp/gh.js.map +1 -0
  182. package/dist/shell/interp/git.js +28 -0
  183. package/dist/shell/interp/git.js.map +1 -0
  184. package/dist/shell/interp/log.js +213 -0
  185. package/dist/shell/interp/log.js.map +1 -0
  186. package/dist/shell/interp/process.js +178 -0
  187. package/dist/shell/interp/process.js.map +1 -0
  188. package/dist/shell/interp/runlog.js +193 -0
  189. package/dist/shell/interp/runlog.js.map +1 -0
  190. package/dist/shell/interp/timer.js +64 -0
  191. package/dist/shell/interp/timer.js.map +1 -0
  192. package/dist/shell/interp/tracker-disk.js +99 -0
  193. package/dist/shell/interp/tracker-disk.js.map +1 -0
  194. package/dist/shell/interp/tracker-parse.js +71 -0
  195. package/dist/shell/interp/tracker-parse.js.map +1 -0
  196. package/dist/shell/interp/tracker-scan.js +238 -0
  197. package/dist/shell/interp/tracker-scan.js.map +1 -0
  198. package/dist/shell/interp/tracker-write.js +91 -0
  199. package/dist/shell/interp/tracker-write.js.map +1 -0
  200. package/dist/shell/interp/tracker.js +41 -0
  201. package/dist/shell/interp/tracker.js.map +1 -0
  202. package/dist/shell/interp/tty.js +48 -0
  203. package/dist/shell/interp/tty.js.map +1 -0
  204. package/dist/shell/interp/vm.js +199 -0
  205. package/dist/shell/interp/vm.js.map +1 -0
  206. package/dist/shell/interp/workspace.js +310 -0
  207. package/dist/shell/interp/workspace.js.map +1 -0
  208. package/dist/shell/main-acp.js +78 -0
  209. package/dist/shell/main-acp.js.map +1 -0
  210. package/dist/shell/main-adapters.js +222 -0
  211. package/dist/shell/main-adapters.js.map +1 -0
  212. package/dist/shell/main-credential.js +122 -0
  213. package/dist/shell/main-credential.js.map +1 -0
  214. package/dist/shell/main-doctor.js +22 -0
  215. package/dist/shell/main-doctor.js.map +1 -0
  216. package/dist/shell/main-entry.js +46 -0
  217. package/dist/shell/main-entry.js.map +1 -0
  218. package/dist/shell/main-http-csrf.js +45 -0
  219. package/dist/shell/main-http-csrf.js.map +1 -0
  220. package/dist/shell/main-http-handler.js +389 -0
  221. package/dist/shell/main-http-handler.js.map +1 -0
  222. package/dist/shell/main-http-mcp.js +122 -0
  223. package/dist/shell/main-http-mcp.js.map +1 -0
  224. package/dist/shell/main-http-views.js +253 -0
  225. package/dist/shell/main-http-views.js.map +1 -0
  226. package/dist/shell/main-http.js +76 -0
  227. package/dist/shell/main-http.js.map +1 -0
  228. package/dist/shell/main-loops.js +130 -0
  229. package/dist/shell/main-loops.js.map +1 -0
  230. package/dist/shell/main-mcp.js +129 -0
  231. package/dist/shell/main-mcp.js.map +1 -0
  232. package/dist/shell/main-orchestrator.js +120 -0
  233. package/dist/shell/main-orchestrator.js.map +1 -0
  234. package/dist/shell/main-preflight.js +43 -0
  235. package/dist/shell/main-preflight.js.map +1 -0
  236. package/dist/shell/main-reconcilers-helpers.js +244 -0
  237. package/dist/shell/main-reconcilers-helpers.js.map +1 -0
  238. package/dist/shell/main-reconcilers-pr.js +148 -0
  239. package/dist/shell/main-reconcilers-pr.js.map +1 -0
  240. package/dist/shell/main-reconcilers.js +225 -0
  241. package/dist/shell/main-reconcilers.js.map +1 -0
  242. package/dist/shell/main-runner.js +355 -0
  243. package/dist/shell/main-runner.js.map +1 -0
  244. package/dist/shell/main-scaffold.js +116 -0
  245. package/dist/shell/main-scaffold.js.map +1 -0
  246. package/dist/shell/main-shutdown.js +115 -0
  247. package/dist/shell/main-shutdown.js.map +1 -0
  248. package/dist/shell/main-startup.js +48 -0
  249. package/dist/shell/main-startup.js.map +1 -0
  250. package/dist/shell/main-substrates.js +43 -0
  251. package/dist/shell/main-substrates.js.map +1 -0
  252. package/dist/shell/main.js +385 -0
  253. package/dist/shell/main.js.map +1 -0
  254. package/dist/shell/orchestrator-feedback.js +69 -0
  255. package/dist/shell/orchestrator-feedback.js.map +1 -0
  256. package/dist/shell/orchestrator-image.js +167 -0
  257. package/dist/shell/orchestrator-image.js.map +1 -0
  258. package/dist/shell/orchestrator-loop.js +468 -0
  259. package/dist/shell/orchestrator-loop.js.map +1 -0
  260. package/dist/shell/orchestrator-reconcile.js +36 -0
  261. package/dist/shell/orchestrator-reconcile.js.map +1 -0
  262. package/dist/shell/reconciler-loop.js +228 -0
  263. package/dist/shell/reconciler-loop.js.map +1 -0
  264. package/dist/shell/runner-loop-turn.js +301 -0
  265. package/dist/shell/runner-loop-turn.js.map +1 -0
  266. package/dist/shell/runner-loop.js +338 -0
  267. package/dist/shell/runner-loop.js.map +1 -0
  268. package/dist/shell/server/http.js +208 -0
  269. package/dist/shell/server/http.js.map +1 -0
  270. package/dist/shell/server/mcp-runtime-effects.js +237 -0
  271. package/dist/shell/server/mcp-runtime-effects.js.map +1 -0
  272. package/dist/shell/server/mcp-runtime.js +99 -0
  273. package/dist/shell/server/mcp-runtime.js.map +1 -0
  274. package/dist/shell/workspace-key.js +14 -0
  275. package/dist/shell/workspace-key.js.map +1 -0
  276. package/dist/types/acp.js +8 -0
  277. package/dist/types/acp.js.map +1 -0
  278. package/dist/types/actions/plan.js +6 -0
  279. package/dist/types/actions/plan.js.map +1 -0
  280. package/dist/types/actions/predicates.js +6 -0
  281. package/dist/types/actions/predicates.js.map +1 -0
  282. package/dist/types/actions/run-fold.js +8 -0
  283. package/dist/types/actions/run-fold.js.map +1 -0
  284. package/dist/types/actions.js +7 -0
  285. package/dist/types/actions.js.map +1 -0
  286. package/dist/types/adapter/clock-random.js +4 -0
  287. package/dist/types/adapter/clock-random.js.map +1 -0
  288. package/dist/types/adapter/gondolin-image-converter.js +5 -0
  289. package/dist/types/adapter/gondolin-image-converter.js.map +1 -0
  290. package/dist/types/adapter/gondolin-image-fetch.js +5 -0
  291. package/dist/types/adapter/gondolin-image-fetch.js.map +1 -0
  292. package/dist/types/adapter/workflow-loader.js +4 -0
  293. package/dist/types/adapter/workflow-loader.js.map +1 -0
  294. package/dist/types/cli/args.js +8 -0
  295. package/dist/types/cli/args.js.map +1 -0
  296. package/dist/types/config.js +8 -0
  297. package/dist/types/config.js.map +1 -0
  298. package/dist/types/credential-interp.js +6 -0
  299. package/dist/types/credential-interp.js.map +1 -0
  300. package/dist/types/credentials.js +10 -0
  301. package/dist/types/credentials.js.map +1 -0
  302. package/dist/types/doctor.js +7 -0
  303. package/dist/types/doctor.js.map +1 -0
  304. package/dist/types/domain.js +7 -0
  305. package/dist/types/domain.js.map +1 -0
  306. package/dist/types/effect.js +15 -0
  307. package/dist/types/effect.js.map +1 -0
  308. package/dist/types/errors.js +39 -0
  309. package/dist/types/errors.js.map +1 -0
  310. package/dist/types/http/decisions.js +6 -0
  311. package/dist/types/http/decisions.js.map +1 -0
  312. package/dist/types/http/render.js +10 -0
  313. package/dist/types/http/render.js.map +1 -0
  314. package/dist/types/http/views.js +6 -0
  315. package/dist/types/http/views.js.map +1 -0
  316. package/dist/types/http.js +9 -0
  317. package/dist/types/http.js.map +1 -0
  318. package/dist/types/image/managed-image.js +7 -0
  319. package/dist/types/image/managed-image.js.map +1 -0
  320. package/dist/types/interp/effect-interpreter.js +8 -0
  321. package/dist/types/interp/effect-interpreter.js.map +1 -0
  322. package/dist/types/interp/tracker.js +7 -0
  323. package/dist/types/interp/tracker.js.map +1 -0
  324. package/dist/types/issue/file.js +6 -0
  325. package/dist/types/issue/file.js.map +1 -0
  326. package/dist/types/issue/parse.js +8 -0
  327. package/dist/types/issue/parse.js.map +1 -0
  328. package/dist/types/main-acp.js +13 -0
  329. package/dist/types/main-acp.js.map +1 -0
  330. package/dist/types/main-adapters.js +5 -0
  331. package/dist/types/main-adapters.js.map +1 -0
  332. package/dist/types/main-credential.js +21 -0
  333. package/dist/types/main-credential.js.map +1 -0
  334. package/dist/types/main-doctor.js +6 -0
  335. package/dist/types/main-doctor.js.map +1 -0
  336. package/dist/types/main-http-handler.js +12 -0
  337. package/dist/types/main-http-handler.js.map +1 -0
  338. package/dist/types/main-http.js +5 -0
  339. package/dist/types/main-http.js.map +1 -0
  340. package/dist/types/main-loops.js +5 -0
  341. package/dist/types/main-loops.js.map +1 -0
  342. package/dist/types/main-mcp.js +12 -0
  343. package/dist/types/main-mcp.js.map +1 -0
  344. package/dist/types/main-orchestrator.js +5 -0
  345. package/dist/types/main-orchestrator.js.map +1 -0
  346. package/dist/types/main-reconcilers.js +11 -0
  347. package/dist/types/main-reconcilers.js.map +1 -0
  348. package/dist/types/main-runner.js +13 -0
  349. package/dist/types/main-runner.js.map +1 -0
  350. package/dist/types/main-startup.js +5 -0
  351. package/dist/types/main-startup.js.map +1 -0
  352. package/dist/types/main-substrates.js +5 -0
  353. package/dist/types/main-substrates.js.map +1 -0
  354. package/dist/types/mcp/dispatch.js +4 -0
  355. package/dist/types/mcp/dispatch.js.map +1 -0
  356. package/dist/types/mcp/post-move.js +7 -0
  357. package/dist/types/mcp/post-move.js.map +1 -0
  358. package/dist/types/mcp.js +9 -0
  359. package/dist/types/mcp.js.map +1 -0
  360. package/dist/types/ports.js +12 -0
  361. package/dist/types/ports.js.map +1 -0
  362. package/dist/types/reconcile/image-decide.js +5 -0
  363. package/dist/types/reconcile/image-decide.js.map +1 -0
  364. package/dist/types/reconcile/ledger.js +7 -0
  365. package/dist/types/reconcile/ledger.js.map +1 -0
  366. package/dist/types/reconcile/pr-loop.js +8 -0
  367. package/dist/types/reconcile/pr-loop.js.map +1 -0
  368. package/dist/types/reconcile/vm-reap.js +8 -0
  369. package/dist/types/reconcile/vm-reap.js.map +1 -0
  370. package/dist/types/reconcile/workspace-decide.js +7 -0
  371. package/dist/types/reconcile/workspace-decide.js.map +1 -0
  372. package/dist/types/reconcile.js +9 -0
  373. package/dist/types/reconcile.js.map +1 -0
  374. package/dist/types/runlog.js +7 -0
  375. package/dist/types/runlog.js.map +1 -0
  376. package/dist/types/runner/actions-runner.js +12 -0
  377. package/dist/types/runner/actions-runner.js.map +1 -0
  378. package/dist/types/runner/gondolin-dispatch.js +5 -0
  379. package/dist/types/runner/gondolin-dispatch.js.map +1 -0
  380. package/dist/types/runner/injection.js +6 -0
  381. package/dist/types/runner/injection.js.map +1 -0
  382. package/dist/types/runner/runner-loop.js +5 -0
  383. package/dist/types/runner/runner-loop.js.map +1 -0
  384. package/dist/types/runner/turn.js +4 -0
  385. package/dist/types/runner/turn.js.map +1 -0
  386. package/dist/types/runner/vm-plan.js +4 -0
  387. package/dist/types/runner/vm-plan.js.map +1 -0
  388. package/dist/types/runtime.js +9 -0
  389. package/dist/types/runtime.js.map +1 -0
  390. package/dist/types/schedule/admission.js +7 -0
  391. package/dist/types/schedule/admission.js.map +1 -0
  392. package/dist/types/schedule/circuit-breaker.js +2 -0
  393. package/dist/types/schedule/circuit-breaker.js.map +1 -0
  394. package/dist/types/schedule/eligibility.js +9 -0
  395. package/dist/types/schedule/eligibility.js.map +1 -0
  396. package/dist/types/schedule/orchestrator-loop.js +10 -0
  397. package/dist/types/schedule/orchestrator-loop.js.map +1 -0
  398. package/dist/types/schedule/sleep-cycle.js +4 -0
  399. package/dist/types/schedule/sleep-cycle.js.map +1 -0
  400. package/dist/types/schedule/slots.js +8 -0
  401. package/dist/types/schedule/slots.js.map +1 -0
  402. package/dist/types/schedule/tick.js +9 -0
  403. package/dist/types/schedule/tick.js.map +1 -0
  404. package/dist/types/server/mcp-runtime.js +8 -0
  405. package/dist/types/server/mcp-runtime.js.map +1 -0
  406. package/dist/types/workflow/parse.js +4 -0
  407. package/dist/types/workflow/parse.js.map +1 -0
  408. package/package.json +22 -10
  409. package/patches/@earendil-works+gondolin+0.12.0.patch +173 -0
  410. package/prompts/Reflect.md +91 -0
  411. package/prompts/Review.md +97 -0
  412. package/prompts/Todo.md +96 -0
  413. package/prompts/_footer.md +41 -0
  414. package/prompts/_preamble.md +42 -0
  415. package/prompts-minimal/Todo.md +26 -0
  416. package/scripts/postinstall.mjs +63 -0
  417. package/scripts/vm-agent.mjs +312 -90
  418. package/WORKFLOW.md +0 -744
  419. package/dist/acp-bridge.js +0 -324
  420. package/dist/acp-bridge.js.map +0 -1
  421. package/dist/actions/cache.js +0 -191
  422. package/dist/actions/cache.js.map +0 -1
  423. package/dist/actions/effects.js +0 -41
  424. package/dist/actions/effects.js.map +0 -1
  425. package/dist/actions/executor.js +0 -570
  426. package/dist/actions/executor.js.map +0 -1
  427. package/dist/actions/index.js +0 -13
  428. package/dist/actions/index.js.map +0 -1
  429. package/dist/actions/parsing.js.map +0 -1
  430. package/dist/actions/predicate-env.js +0 -27
  431. package/dist/actions/predicate-env.js.map +0 -1
  432. package/dist/actions/predicates.js +0 -49
  433. package/dist/actions/predicates.js.map +0 -1
  434. package/dist/actions/templating.js +0 -66
  435. package/dist/actions/templating.js.map +0 -1
  436. package/dist/actions/types.js +0 -15
  437. package/dist/actions/types.js.map +0 -1
  438. package/dist/agent/acp.js +0 -473
  439. package/dist/agent/acp.js.map +0 -1
  440. package/dist/agent/adapter-names.js +0 -159
  441. package/dist/agent/adapter-names.js.map +0 -1
  442. package/dist/agent/adapters.js +0 -511
  443. package/dist/agent/adapters.js.map +0 -1
  444. package/dist/agent/credential-extractors.js +0 -342
  445. package/dist/agent/credential-extractors.js.map +0 -1
  446. package/dist/agent/credential-secrets.js +0 -628
  447. package/dist/agent/credential-secrets.js.map +0 -1
  448. package/dist/agent/credential-ticker.js +0 -57
  449. package/dist/agent/credential-ticker.js.map +0 -1
  450. package/dist/agent/gondolin-creds-staging.js +0 -356
  451. package/dist/agent/gondolin-creds-staging.js.map +0 -1
  452. package/dist/agent/gondolin-dispatch.js +0 -375
  453. package/dist/agent/gondolin-dispatch.js.map +0 -1
  454. package/dist/agent/gondolin.js +0 -124
  455. package/dist/agent/gondolin.js.map +0 -1
  456. package/dist/agent/runner-decisions.js +0 -134
  457. package/dist/agent/runner-decisions.js.map +0 -1
  458. package/dist/agent/runner.js +0 -1456
  459. package/dist/agent/runner.js.map +0 -1
  460. package/dist/agent/tool-call-summary.js +0 -102
  461. package/dist/agent/tool-call-summary.js.map +0 -1
  462. package/dist/agent/vm-acp-mapping.js +0 -73
  463. package/dist/agent/vm-acp-mapping.js.map +0 -1
  464. package/dist/agent/vm-guards.js +0 -262
  465. package/dist/agent/vm-guards.js.map +0 -1
  466. package/dist/agent/vm-port.js +0 -22
  467. package/dist/agent/vm-port.js.map +0 -1
  468. package/dist/agent/vm-process-registry.js +0 -79
  469. package/dist/agent/vm-process-registry.js.map +0 -1
  470. package/dist/bin/cli-args.js +0 -105
  471. package/dist/bin/cli-args.js.map +0 -1
  472. package/dist/errors.js +0 -15
  473. package/dist/errors.js.map +0 -1
  474. package/dist/http-disk.js +0 -135
  475. package/dist/http-disk.js.map +0 -1
  476. package/dist/http-handlers.js.map +0 -1
  477. package/dist/http.js.map +0 -1
  478. package/dist/issues.js +0 -178
  479. package/dist/issues.js.map +0 -1
  480. package/dist/logging.js +0 -203
  481. package/dist/logging.js.map +0 -1
  482. package/dist/mcp.js +0 -706
  483. package/dist/mcp.js.map +0 -1
  484. package/dist/memory.js +0 -85
  485. package/dist/memory.js.map +0 -1
  486. package/dist/orchestrator-decisions.js +0 -331
  487. package/dist/orchestrator-decisions.js.map +0 -1
  488. package/dist/orchestrator.js +0 -1569
  489. package/dist/orchestrator.js.map +0 -1
  490. package/dist/prompt.js +0 -65
  491. package/dist/prompt.js.map +0 -1
  492. package/dist/reconciler/cache.js +0 -65
  493. package/dist/reconciler/cache.js.map +0 -1
  494. package/dist/reconciler/index.js +0 -448
  495. package/dist/reconciler/index.js.map +0 -1
  496. package/dist/reconciler/ledger.js +0 -131
  497. package/dist/reconciler/ledger.js.map +0 -1
  498. package/dist/reconciler/pr-adapters.js +0 -174
  499. package/dist/reconciler/pr-adapters.js.map +0 -1
  500. package/dist/reconciler/pr-decide.js.map +0 -1
  501. package/dist/reconciler/pr.js +0 -422
  502. package/dist/reconciler/pr.js.map +0 -1
  503. package/dist/reconciler/types.js +0 -12
  504. package/dist/reconciler/types.js.map +0 -1
  505. package/dist/reconciler/vm.js +0 -243
  506. package/dist/reconciler/vm.js.map +0 -1
  507. package/dist/reconciler/workspace-defaults.js +0 -83
  508. package/dist/reconciler/workspace-defaults.js.map +0 -1
  509. package/dist/reconciler/workspace.js +0 -272
  510. package/dist/reconciler/workspace.js.map +0 -1
  511. package/dist/runlog.js +0 -403
  512. package/dist/runlog.js.map +0 -1
  513. package/dist/scaffold.js +0 -165
  514. package/dist/scaffold.js.map +0 -1
  515. package/dist/trackers/local.js +0 -445
  516. package/dist/trackers/local.js.map +0 -1
  517. package/dist/trackers/types.js +0 -10
  518. package/dist/trackers/types.js.map +0 -1
  519. package/dist/types.js +0 -3
  520. package/dist/types.js.map +0 -1
  521. package/dist/util/clock.js +0 -12
  522. package/dist/util/clock.js.map +0 -1
  523. package/dist/util/crypto.js +0 -25
  524. package/dist/util/crypto.js.map +0 -1
  525. package/dist/util/frontmatter.js +0 -70
  526. package/dist/util/frontmatter.js.map +0 -1
  527. package/dist/util/fs-issues.js +0 -22
  528. package/dist/util/fs-issues.js.map +0 -1
  529. package/dist/util/process.js +0 -152
  530. package/dist/util/process.js.map +0 -1
  531. package/dist/util/workspace-key.js +0 -10
  532. package/dist/util/workspace-key.js.map +0 -1
  533. package/dist/workflow-loader.js +0 -147
  534. package/dist/workflow-loader.js.map +0 -1
  535. package/dist/workflow.js +0 -822
  536. package/dist/workflow.js.map +0 -1
  537. package/dist/workspace-types.js +0 -8
  538. package/dist/workspace-types.js.map +0 -1
  539. package/dist/workspace.js +0 -443
  540. package/dist/workspace.js.map +0 -1
@@ -1,243 +0,0 @@
1
- // VM reaper resource (issue 33 / reconciler stage 2; Gondolin migration Phase 4).
2
- // Owns the lifecycle of `symphony-*` VMs: anything outside the orchestrator's
3
- // intended set is an orphan and gets reaped.
4
- //
5
- // Observation source = Gondolin's session registry, NOT the earlier CLI machine
6
- // registry + `_boot-vm` /proc scraping. Gondolin owns one host runner process
7
- // per VM and tracks it in a session registry keyed by uuid, carrying the
8
- // `sessionLabel` the orchestrator minted (`symphony-<identifier>`) and the host
9
- // `pid`. The reaper reaps in two complementary ways:
10
- //
11
- // 1. STALE sessions (dead-pid orphans + orphan socket files) are collected by
12
- // Gondolin's own `gc()` — the shell calls it at the start of each pass.
13
- // This subsumes the old "`machine delete -f` succeeded but left the worker
14
- // alive" cleanup: Gondolin reconciles its own registry against live pids.
15
- // 2. LIVE orphans — a session whose host process is still alive but whose
16
- // `symphony-` label is NOT in the intended set (a botched teardown, or a
17
- // SIGKILL'd symphony whose runner child survived) — are reaped HERE by
18
- // SIGTERM→SIGKILL on the host `pid`. `gc()` can't touch these because the
19
- // pid is alive; only the orchestrator knows the intended set.
20
- //
21
- // Label safety: a session with no label, or a label outside the
22
- // `symphony-` namespace (an operator's own VM, a sibling tool's session), is
23
- // never touched. The reaper acts only on confidently-symphony-owned, never-
24
- // intended sessions.
25
- //
26
- // Effects-as-data (issue 69): the decision of WHAT to do is a pure function
27
- // (`decideVm`) of the observed session state; HOW it's done (Gondolin gc,
28
- // listSessions, process.kill, sleep) is the shell's job. This module is
29
- // import-pure: no `node:fs`, no timers, no adapter imports. The reaper's local
30
- // session shape (`ReaperSession`) is declared here — mirroring the existing
31
- // `VmRegistryPort` local-interface convention — so vm.ts never reaches for the
32
- // concrete `VmClient` adapter or the `vm-port` module; the shell adapts
33
- // `VmClient.listSessions()` → `ReaperSession[]`.
34
- import { log } from '../logging.js';
35
- import { ResourceActionLedger } from './ledger.js';
36
- // Domain constant. Every VM the orchestrator creates is labelled with this
37
- // prefix (the runner mints `sessionLabel = symphony-<identifier>`); the reaper
38
- // only acts on labels that match. The vm-port adapter mirrors the same value —
39
- // keep them in sync.
40
- export const SYMPHONY_VM_PREFIX = 'symphony-';
41
- const DEFAULT_KILL_GRACE_MS = 3_000;
42
- const MAX_ACTION_HISTORY = 32;
43
- /**
44
- * Pure decision: given the observed Gondolin session state, return the effects
45
- * the shell should apply. No IO, no clock reads, no logging.
46
- *
47
- * Effect rule:
48
- * • Session has a `label` that starts with SYMPHONY_VM_PREFIX and isn't
49
- * intended, AND a sane, non-self host pid → `kill_session` (SIGTERM→SIGKILL
50
- * its host pid).
51
- *
52
- * Pid safety: a host signal is only ever emitted for a `pid` that is a safe
53
- * positive integer and is NOT the reaper's own pid. This matters because the
54
- * shell delivers the signal with `process.kill(pid, sig)`, which signals the
55
- * whole PROCESS GROUP for `pid <= 0` and would target the orchestrator itself
56
- * for `pid === selfPid`. A session carrying a `0`/`NaN`/negative/self pid is a
57
- * registry anomaly, never a legitimate orphan, so it is left untouched here.
58
- *
59
- * Anything outside the symphony-prefixed namespace — a session with no label,
60
- * or a label that doesn't start with the prefix — is left untouched (operator
61
- * VMs, sibling tools' sessions). STALE/dead-pid sessions and orphan sockets are
62
- * NOT this function's concern; Gondolin's `gc()` collects them in the shell
63
- * before the live session set reaches here.
64
- */
65
- export function decideVm(state) {
66
- const out = [];
67
- for (const s of state.sessions) {
68
- const label = s.label;
69
- if (label === undefined)
70
- continue;
71
- if (!label.startsWith(SYMPHONY_VM_PREFIX))
72
- continue;
73
- if (state.intended.has(label))
74
- continue;
75
- // Pid safety: skip anomalous pids (0/NaN/negative — process-group / invalid)
76
- // and never signal the reaper's own process.
77
- if (!Number.isSafeInteger(s.pid) || s.pid <= 0)
78
- continue;
79
- if (s.pid === state.selfPid)
80
- continue;
81
- out.push({ kind: 'kill_session', pid: s.pid, label });
82
- }
83
- return out;
84
- }
85
- /**
86
- * VM resource. Desired = orchestrator's intended VM (session-label) set.
87
- * Actual = Gondolin's live session set (filtered by `symphony-` label).
88
- * `reconcile()` is the thin shell loop: gc → observe → `decideVm` → apply.
89
- *
90
- * Independent of bake (`dependsOn: []`). Doesn't gate dispatch.
91
- */
92
- export class VmResource {
93
- opts;
94
- id = 'vm';
95
- dependsOn = [];
96
- gc;
97
- listSessions;
98
- killProcess;
99
- killGraceMs;
100
- selfPid;
101
- ledger = new ResourceActionLedger(this.id, { maxHistory: MAX_ACTION_HISTORY });
102
- lastError = null;
103
- constructor(opts) {
104
- this.opts = opts;
105
- this.gc = opts.gc;
106
- this.listSessions = opts.listSessions;
107
- this.killProcess = opts.killProcess;
108
- this.killGraceMs = opts.killGraceMs ?? DEFAULT_KILL_GRACE_MS;
109
- this.selfPid = opts.selfPid;
110
- }
111
- ready() {
112
- // VM reaping is a janitorial task — it doesn't gate dispatch. The bake
113
- // resource is the only thing dispatch waits on today; reaping just runs
114
- // alongside.
115
- return true;
116
- }
117
- async reconcile() {
118
- const desired = this.opts.intended.intendedVmNames();
119
- // Gondolin's own GC first: collect STALE (dead-pid) sessions + orphan
120
- // sockets. This subsumes the earlier "worker survived the daemon
121
- // destroy" cleanup — Gondolin reconciles its registry against live pids.
122
- await this.runGc();
123
- // Now enumerate the LIVE session set. `decideVm` compares it against the
124
- // intended set; survivors with a never-intended `symphony-` label are
125
- // LIVE orphans (alive pid, so gc() can't reach them) and get SIGTERM'd.
126
- const sessions = await this.observeSessions();
127
- const effects = decideVm({ intended: desired, sessions, selfPid: this.selfPid });
128
- if (effects.length === 0)
129
- return;
130
- log.info('vm reaper: killing orphan sessions', { orphans: effects.length });
131
- await Promise.all(effects.map((e) => this.killSession(e)));
132
- }
133
- snapshot() {
134
- return {
135
- id: this.id,
136
- ready: true,
137
- desired_hash: null,
138
- last_error: this.lastError,
139
- actions: this.ledger.snapshot(),
140
- };
141
- }
142
- async runGc() {
143
- try {
144
- const reaped = await this.gc();
145
- if (reaped > 0)
146
- log.info('vm reaper: gondolin gc collected stale sessions', { reaped });
147
- }
148
- catch (err) {
149
- const msg = err.message;
150
- this.lastError = `gondolin gc failed: ${msg}`;
151
- log.warn('vm reaper: gondolin gc failed', { error: msg });
152
- }
153
- }
154
- async observeSessions() {
155
- try {
156
- return await this.listSessions();
157
- }
158
- catch (err) {
159
- const msg = err.message;
160
- this.lastError = `session enumeration failed: ${msg}`;
161
- log.warn('vm reaper: session enumeration failed', { error: msg });
162
- return [];
163
- }
164
- }
165
- async killSession(e) {
166
- const key = `kill_session:${e.pid}`;
167
- // Belt-and-suspenders: `decideVm` already excludes self / anomalous pids,
168
- // but a bad pid reaching the actual `process.kill` is catastrophic
169
- // (`pid <= 0` signals the whole process group; `selfPid` signals the
170
- // orchestrator). Guard once more before the signal ever leaves the shell.
171
- if (e.pid === this.selfPid || !Number.isSafeInteger(e.pid) || e.pid <= 0) {
172
- const msg = `refused to signal unsafe pid ${e.pid}`;
173
- this.lastError = msg;
174
- this.ledger.start(key);
175
- this.ledger.error(key, msg);
176
- log.warn('vm reaper: refused unsafe pid', { pid: e.pid, label: e.label, self_pid: this.selfPid });
177
- return;
178
- }
179
- this.ledger.start(key);
180
- // SIGTERM. If the process is already gone (ESRCH) treat as success.
181
- try {
182
- this.killProcess(e.pid, 'SIGTERM');
183
- }
184
- catch (err) {
185
- const code = err.code;
186
- if (code === 'ESRCH') {
187
- this.ledger.done(key);
188
- return;
189
- }
190
- const msg = err.message;
191
- this.lastError = msg;
192
- this.ledger.error(key, msg);
193
- log.warn('vm reaper: SIGTERM failed', { pid: e.pid, label: e.label, error: msg });
194
- return;
195
- }
196
- // Inline timer (rather than `node:timers/promises`) keeps the file
197
- // adapter-import-free for the functional-core lint.
198
- await new Promise((resolve) => { setTimeout(resolve, this.killGraceMs); });
199
- // Probe with signal 0 — throws ESRCH if the process has exited. If it's
200
- // still alive, escalate to SIGKILL.
201
- let alive = false;
202
- try {
203
- this.killProcess(e.pid, 0);
204
- alive = true;
205
- }
206
- catch (err) {
207
- const code = err.code;
208
- if (code !== 'ESRCH') {
209
- // EPERM and friends — assume alive but unkillable; surface as an error.
210
- const msg = err.message;
211
- this.lastError = msg;
212
- this.ledger.error(key, msg);
213
- log.warn('vm reaper: alive-probe failed', { pid: e.pid, error: msg });
214
- return;
215
- }
216
- }
217
- if (!alive) {
218
- this.ledger.done(key);
219
- return;
220
- }
221
- try {
222
- this.killProcess(e.pid, 'SIGKILL');
223
- this.ledger.done(key);
224
- log.info('vm reaper: SIGKILL applied after grace', {
225
- pid: e.pid,
226
- label: e.label,
227
- grace_ms: this.killGraceMs,
228
- });
229
- }
230
- catch (err) {
231
- const code = err.code;
232
- if (code === 'ESRCH') {
233
- this.ledger.done(key);
234
- return;
235
- }
236
- const msg = err.message;
237
- this.lastError = msg;
238
- this.ledger.error(key, msg);
239
- log.warn('vm reaper: SIGKILL failed', { pid: e.pid, label: e.label, error: msg });
240
- }
241
- }
242
- }
243
- //# sourceMappingURL=vm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vm.js","sourceRoot":"","sources":["../../src/reconciler/vm.ts"],"names":[],"mappings":"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"}
@@ -1,83 +0,0 @@
1
- // Workspace resource adapters (shell). Concrete fs + git implementations of
2
- // the listing / inspection / removal ports declared on {@link WorkspaceResource}.
3
- // Lifted from workspace.ts (issue 86) so the core resource no longer imports
4
- // `node:fs/promises` or `util/process`. Production wiring lives in
5
- // `reconciler/index.ts`; tests pass stubs and reach for these helpers only
6
- // when they want the real fs/git path.
7
- import { readdir, rm, stat } from 'node:fs/promises';
8
- import path from 'node:path';
9
- import { runProcess } from '../util/process.js';
10
- /**
11
- * Enumerate workspace dirs under `root`. Non-directories are filtered out.
12
- * ENOENT on the root → empty list (cold start). Other errors propagate so the
13
- * resource records them in `last_error` rather than reaping every workspace
14
- * on a transient FS hiccup.
15
- */
16
- export async function defaultListWorkspaceDirs(root) {
17
- let entries;
18
- try {
19
- entries = await readdir(root);
20
- }
21
- catch (err) {
22
- if (err.code === 'ENOENT')
23
- return [];
24
- throw err;
25
- }
26
- const out = [];
27
- for (const name of entries) {
28
- const p = path.join(root, name);
29
- try {
30
- const st = await stat(p);
31
- if (st.isDirectory())
32
- out.push({ name, path: p });
33
- }
34
- catch {
35
- // Entry vanished mid-pass; next reconcile picks it up.
36
- }
37
- }
38
- return out;
39
- }
40
- /**
41
- * Default inspector. All git invocations are workspace-local; drift detection
42
- * lives in the resource (compares `workspaceBaseSha` to the source repo's
43
- * current base SHA). Returns `head: null` for anything that doesn't look like
44
- * a git repo — the caller treats that as "don't touch this dir."
45
- */
46
- export async function defaultInspectWorkspace(workspacePath, baseBranch) {
47
- const head = await runGitCapture(workspacePath, ['rev-parse', 'HEAD']);
48
- if (head.exit !== 0 || head.stdout.trim().length === 0) {
49
- return { head: null, workspaceBaseSha: null, hasUncommitted: false, commitsAheadOfBase: 0 };
50
- }
51
- const headSha = head.stdout.trim();
52
- const status = await runGitCapture(workspacePath, ['status', '--porcelain']);
53
- const hasUncommitted = status.exit === 0 && status.stdout.length > 0;
54
- // Workspace's frozen view of the base branch — the SHA that was current in
55
- // the source repo at clone time. The setup pipeline cuts the agent branch
56
- // from this ref, so it's always present unless an operator manually deleted it.
57
- const wsBase = await runGitCapture(workspacePath, ['rev-parse', baseBranch]);
58
- const workspaceBaseSha = wsBase.exit === 0 && wsBase.stdout.trim().length > 0 ? wsBase.stdout.trim() : null;
59
- let aheadCount = 0;
60
- if (workspaceBaseSha !== null) {
61
- // `<base>..HEAD` walks only objects the workspace itself owns — no cross-repo
62
- // reachability needed. Exits non-zero only for malformed refs; treat that
63
- // as 0 commits ahead rather than poisoning the snapshot.
64
- const ahead = await runGitCapture(workspacePath, [
65
- 'rev-list',
66
- '--count',
67
- `${workspaceBaseSha}..${headSha}`,
68
- ]);
69
- aheadCount = ahead.exit === 0 ? Number(ahead.stdout.trim()) || 0 : 0;
70
- }
71
- return { head: headSha, workspaceBaseSha, hasUncommitted, commitsAheadOfBase: aheadCount };
72
- }
73
- /** Default removal: `rm -rf` the dir. Production wraps `WorkspaceManager.remove`; the two-callback design lets tests pass a stub. */
74
- export async function defaultRemoveWorkspace(workspaceRoot, identifier) {
75
- await rm(path.join(workspaceRoot, identifier), { recursive: true, force: true });
76
- }
77
- // Thin shape adapter over runProcess: the inspector reads `result.exit`
78
- // (vs. `exit_code`) and uses a tighter 16 KiB cap than runProcess's default.
79
- async function runGitCapture(cwd, args) {
80
- const r = await runProcess('git', args, { cwd, maxBytes: 16_384, appendErrorToStderr: false });
81
- return { exit: r.exit_code ?? -1, stdout: r.stdout, stderr: r.stderr };
82
- }
83
- //# sourceMappingURL=workspace-defaults.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"workspace-defaults.js","sourceRoot":"","sources":["../../src/reconciler/workspace-defaults.ts"],"names":[],"mappings":"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"}
@@ -1,272 +0,0 @@
1
- // Workspace resource (issue 34 / reconciler stage 3). Owns the lifecycle of
2
- // per-issue workspace directories under `workspace.root`. Replaces the
3
- // orchestrator's old `startupTerminalCleanup` sweep with a continuous-converge
4
- // resource that also surfaces drift between an active workspace's HEAD and the
5
- // current base branch tip.
6
- //
7
- // What this resource owns:
8
- // • Removing workspace dirs that no longer correspond to any non-terminal
9
- // issue file. The old startup sweep only fired once on boot; here it runs
10
- // on every reconcile tick.
11
- // • Creating workspace dirs for non-terminal issues that don't yet have one
12
- // on disk. The action body (clone source repo, cut `agent/<id>`, optional
13
- // origin restore) is delegated to `WorkspaceManager.ensureFor` so
14
- // dispatch-time and reconciler-driven eager creation share a single code
15
- // path. Idempotency / race safety is enforced inside `ensureFor` via a
16
- // per-identifier in-flight promise lock.
17
- // • Reporting drift between an active workspace's HEAD and the current
18
- // base-branch tip (e.g. base advanced while the issue was paused). v1 is
19
- // non-destructive: drift is surfaced as a `stale` / `stuck` annotation in
20
- // the snapshot and the workspace is left on disk. Re-clone (or any other
21
- // destructive recovery) is explicitly opt-in via an operator action or
22
- // per-issue label and is out of scope for this stage.
23
- //
24
- // Race-condition rule (same shape as VmResource): the intended set comes
25
- // from a provider the orchestrator implements. It returns both the active
26
- // issue identifiers (long-lived desired set) AND the identifiers currently
27
- // in-flight (running + claimed). The in-flight slice covers the window
28
- // between "tick claims an issue" and "tracker shows it as active" — without
29
- // it, a brand-new issue's workspace could be reaped seconds after creation
30
- // because the reconciler raced ahead of the tracker read.
31
- import { sanitizeWorkspaceKey } from '../util/workspace-key.js';
32
- import { log } from '../logging.js';
33
- import { ResourceActionLedger } from './ledger.js';
34
- const MAX_ACTION_HISTORY = 32;
35
- /**
36
- * Workspace resource. Desired = active issue workspaces (set of sanitized
37
- * identifiers from the tracker plus in-flight allocations). Actual = dirs
38
- * under `workspace.root`. Diff drives two converging actions plus two
39
- * snapshot annotations:
40
- *
41
- * • create_workspace — identifier in the desired set with no matching dir
42
- * on disk. Delegates to `WorkspaceManager.ensureFor`,
43
- * which runs the canonical clone+branch+remote setup.
44
- * • remove_workspace — dir has no matching non-terminal issue.
45
- * • mark_stale — dir matches but HEAD is behind base and the
46
- * workspace has no uncommitted / ahead work. Non-
47
- * destructive: re-clone is operator-triggered in v1.
48
- * • mark_stuck — dir matches but HEAD is behind base AND has
49
- * uncommitted changes or commits ahead of base. Non-
50
- * destructive; surfaced so the operator can intervene
51
- * before any rebuild attempt.
52
- *
53
- * `dependsOn: ['base_ref']` is informational. v1 doesn't ship a base_ref
54
- * resource; the BaseRefProvider is a direct dependency call.
55
- */
56
- export class WorkspaceResource {
57
- opts;
58
- id = 'workspace';
59
- dependsOn = [];
60
- ledger = new ResourceActionLedger(this.id, { maxHistory: MAX_ACTION_HISTORY });
61
- lastError = null;
62
- staleCount = 0;
63
- stuckCount = 0;
64
- createdCount = 0;
65
- constructor(opts) {
66
- this.opts = opts;
67
- }
68
- ready() {
69
- // Janitorial; doesn't gate dispatch (bake is the only dispatch gate today).
70
- return true;
71
- }
72
- async reconcile() {
73
- // Read the desired set up front. Even if `listWorkspaces` returns the
74
- // empty set (workspace.root not yet created), we still want to create
75
- // dirs for every active identifier — the create path will mkdir the root
76
- // via `ensureFor`. Pulling this before the listing collapses the two
77
- // branches into one flow.
78
- //
79
- // Fail closed when the tracker read throws: we must NOT treat the empty
80
- // set as the desired state. Reaping every workspace on a transient
81
- // tracker hiccup is the regression this contract closes. Catch here,
82
- // surface as last_error, and bail — the next pass retries.
83
- let active;
84
- try {
85
- active = await this.opts.intended.activeIdentifiers();
86
- }
87
- catch (err) {
88
- const msg = err.message;
89
- this.lastError = `active_fetch_failed: ${msg}`;
90
- log.warn('workspace reconcile: active fetch failed', { error: msg });
91
- return;
92
- }
93
- const inFlight = this.opts.intended.inFlightIdentifiers();
94
- // Map sanitized key → { identifier, state } so the create callback gets
95
- // the operator-visible identifier AND the current state name (used by the
96
- // orchestrator's merge-state guard). Sanitize-then-set so
97
- // the dir-name comparison matches `workspacePathFor`'s post-sanitize
98
- // layout. Active issues take precedence over in-flight in case of
99
- // overlap so the tracker's authoritative state wins over an in-flight
100
- // entry that may carry a target_state (where the issue is going, not
101
- // where it currently lives).
102
- const wanted = new Map();
103
- for (const [id, state] of inFlight) {
104
- wanted.set(sanitizeWorkspaceKey(id), { identifier: id, state });
105
- }
106
- for (const [id, state] of active) {
107
- wanted.set(sanitizeWorkspaceKey(id), { identifier: id, state });
108
- }
109
- let entries;
110
- try {
111
- entries = await this.opts.listWorkspaces();
112
- }
113
- catch (err) {
114
- this.lastError = `workspace_root_read_failed: ${err.message}`;
115
- log.warn('workspace reconcile: list failed', { error: err.message });
116
- return;
117
- }
118
- let baseRef = null;
119
- if (this.opts.baseRef) {
120
- try {
121
- baseRef = await this.opts.baseRef.currentBaseRef();
122
- }
123
- catch (err) {
124
- log.debug('workspace reconcile: base ref lookup failed', {
125
- error: err.message,
126
- });
127
- baseRef = null;
128
- }
129
- }
130
- this.staleCount = 0;
131
- this.stuckCount = 0;
132
- this.createdCount = 0;
133
- // Reset lastError at the start of every pass so a transient stale/stuck
134
- // condition that has since resolved doesn't keep haunting the snapshot.
135
- // Errors raised during this pass below will repopulate it.
136
- this.lastError = null;
137
- // Track which desired identifiers already exist on disk so the
138
- // create-loop below only fires for the missing ones.
139
- const present = new Set();
140
- for (const { name, path: dirPath } of entries) {
141
- if (!wanted.has(name)) {
142
- await this.runRemove(name, 'stale_issue');
143
- continue;
144
- }
145
- present.add(name);
146
- // In the desired set. Check for drift (non-destructive). No baseRef
147
- // means we can't compare; just skip and treat the workspace as ok.
148
- if (baseRef === null)
149
- continue;
150
- let inspection;
151
- try {
152
- inspection = await this.opts.inspect(dirPath, baseRef.branch);
153
- }
154
- catch (err) {
155
- log.debug('workspace reconcile: inspect failed', {
156
- identifier: name,
157
- error: err.message,
158
- });
159
- continue;
160
- }
161
- if (inspection.head === null)
162
- continue;
163
- // Workspace has no local copy of the base branch — operator likely
164
- // deleted it. Skip drift detection rather than guess.
165
- if (inspection.workspaceBaseSha === null)
166
- continue;
167
- // Drift = workspace's frozen base SHA disagrees with source's current
168
- // base SHA. Any disagreement counts (fast-forward, divergence, rewind
169
- // all surface as "the operator's base moved out from under us"); the
170
- // operator can decide what to do.
171
- if (inspection.workspaceBaseSha === baseRef.sha)
172
- continue;
173
- // Drift detected. v1 never auto-removes for drift; we annotate and move
174
- // on so the operator can decide whether to relaunch the workspace.
175
- if (inspection.hasUncommitted || inspection.commitsAheadOfBase > 0) {
176
- this.stuckCount += 1;
177
- const reason = inspection.hasUncommitted
178
- ? 'uncommitted changes present'
179
- : `${inspection.commitsAheadOfBase} commit(s) ahead of base`;
180
- const msg = `workspace ${name} stuck: base advanced and ${reason}`;
181
- this.lastError = msg;
182
- this.recordMark(name, 'stuck', reason);
183
- log.warn('workspace reconcile: stuck (drift, agent work present)', {
184
- identifier: name,
185
- reason,
186
- });
187
- continue;
188
- }
189
- this.staleCount += 1;
190
- const staleReason = 'base advanced past workspace HEAD; re-clone is opt-in';
191
- this.lastError = `workspace ${name} stale: ${staleReason}`;
192
- this.recordMark(name, 'stale', staleReason);
193
- log.info('workspace reconcile: stale (drift, no agent work to lose)', {
194
- identifier: name,
195
- reason: staleReason,
196
- });
197
- }
198
- // Create any desired identifier that has no dir on disk. The create
199
- // callback is optional so test harnesses that exercise only the reaper
200
- // can skip it; production wires `WorkspaceManager.ensureFor`, which is
201
- // idempotent (per-identifier lock + dir-exists check) so a concurrent
202
- // dispatch call coalesces into the same setup pass.
203
- if (this.opts.create) {
204
- for (const [key, { identifier, state }] of wanted) {
205
- if (present.has(key))
206
- continue;
207
- await this.runCreate(identifier, key, state);
208
- }
209
- }
210
- }
211
- snapshot() {
212
- return {
213
- id: this.id,
214
- ready: true,
215
- desired_hash: null,
216
- last_error: this.lastError,
217
- actions: this.ledger.snapshot(),
218
- };
219
- }
220
- /** Test helper: number of workspaces marked stale on the last reconcile pass. */
221
- staleOnLastPass() {
222
- return this.staleCount;
223
- }
224
- /** Test helper: number of workspaces marked stuck on the last reconcile pass. */
225
- stuckOnLastPass() {
226
- return this.stuckCount;
227
- }
228
- /** Test helper: number of workspaces created on the last reconcile pass. */
229
- createdOnLastPass() {
230
- return this.createdCount;
231
- }
232
- async runCreate(identifier, sanitizedKey, state) {
233
- if (!this.opts.create)
234
- return;
235
- // Action key uses the sanitized identifier (matches what
236
- // remove_workspace uses) so dashboards can correlate the two
237
- // operations on the same workspace dir.
238
- const actionKey = `create_workspace:${sanitizedKey}`;
239
- const res = await this.ledger.run(actionKey, () => this.opts.create(identifier, state));
240
- if (res.ok) {
241
- this.createdCount += 1;
242
- log.info('workspace reconcile: created', { identifier, state });
243
- }
244
- else {
245
- this.lastError = res.error;
246
- log.warn('workspace reconcile: create failed', { identifier, state, error: res.error });
247
- }
248
- }
249
- async runRemove(identifier, reason) {
250
- const actionKey = `remove_workspace:${identifier}`;
251
- const res = await this.ledger.run(actionKey, () => this.opts.remove(identifier, reason));
252
- if (res.ok) {
253
- log.info('workspace reconcile: removed', { identifier, reason });
254
- }
255
- else {
256
- this.lastError = res.error;
257
- log.warn('workspace reconcile: remove failed', { identifier, reason, error: res.error });
258
- }
259
- }
260
- /**
261
- * Record a non-destructive drift annotation in the action ledger so the
262
- * dashboard can render "stale" / "stuck" badges per workspace without the
263
- * janitor touching disk. `mark_stale:<id>` and `mark_stuck:<id>` are the
264
- * v1 surfaces; the reason rides on the action's `error` field for parity
265
- * with the existing snapshot-error shape, even though it isn't a hard
266
- * failure.
267
- */
268
- recordMark(identifier, status, reason) {
269
- this.ledger.record(`mark_${status}:${identifier}`, 'done', reason);
270
- }
271
- }
272
- //# sourceMappingURL=workspace.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/reconciler/workspace.ts"],"names":[],"mappings":"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"}