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,149 @@
1
+ // FCIS rewrite — pure issue-file serialization.
2
+ //
3
+ // Functional-core port of the original `src/issues.ts:writeIssueFile`. The
4
+ // original was async and performed real fs IO: it mkdir'd the state dir,
5
+ // `readdir`'d every state directory to discover taken numeric identifiers
6
+ // (collision avoidance), `stat`'d an explicit identifier's target path to
7
+ // reject duplicates, and finally `writeFile`'d the rendered Markdown.
8
+ //
9
+ // In the FCIS layout all of that IO moves OUT of this module:
10
+ // - The existing-identifier discovery (a `readdir` walk) is performed by the
11
+ // shell and the resulting SET is SUPPLIED here as plain data
12
+ // (`existingIdentifiers`). This module only DECIDES which id to take.
13
+ // - The wall-clock `created_at` / `updated_at` stamp is injected as a plain
14
+ // ISO string (`nowIso`) — no `Date.now()` / clock read inside core.
15
+ // - The actual file write becomes a `tracker.write_issue` Effect the caller
16
+ // executes; this module ALSO returns the fully-rendered file `content` and
17
+ // the composed `path` so a shell that prefers a raw `fs.write_file` (or
18
+ // wants to surface the content in a dashboard) needn't re-derive them.
19
+ //
20
+ // Pure + synchronous: (data) -> data + Effect[]. Imports ONLY from src/types.
21
+ import { sanitizeWorkspaceKey } from '../workspace-key.js';
22
+ // Identifier sanitizer (SPEC §5.5 Invariant 3) is the canonical core util.
23
+ const sanitizeIdentifier = sanitizeWorkspaceKey;
24
+ // POSIX-style path join. Core may not import `node:path`; the tracker root is
25
+ // always a real on-disk path and the segments here never contain `..`, so a
26
+ // simple single-slash join is faithful. Strips a trailing slash per segment so
27
+ // `root/` + `state` doesn't produce `root//state`, and keeps an absolute root's
28
+ // leading slash.
29
+ function joinPath(...segments) {
30
+ const lead = segments[0]?.startsWith('/') ? '/' : '';
31
+ const parts = segments.map((s) => s.replace(/^\/+|\/+$/g, '')).filter((s) => s.length > 0);
32
+ return lead + parts.join('/');
33
+ }
34
+ /**
35
+ * Render a YAML scalar/array value the way the original serializer did:
36
+ * - arrays → `[<json>, <json>, …]`
37
+ * - strings → JSON-quoted (escapes + always double-quoted)
38
+ * - other → `String(v)` (numbers, booleans)
39
+ */
40
+ function renderYamlValue(v) {
41
+ if (Array.isArray(v)) {
42
+ return `[${v.map((x) => JSON.stringify(x)).join(', ')}]`;
43
+ }
44
+ if (typeof v === 'string') {
45
+ return JSON.stringify(v);
46
+ }
47
+ return String(v);
48
+ }
49
+ /**
50
+ * Pure issue-file serializer. Decides the identifier (sanitize an explicit one
51
+ * or pick the next free numeric over `existingIdentifiers`), renders the YAML
52
+ * front matter + body, composes the path, and returns a `tracker.write_issue`
53
+ * Effect for the shell to execute. Never throws: refusals come back as a
54
+ * `{ error }` result the caller maps to a structured rejection.
55
+ *
56
+ * Mirrors the original `writeIssueFile` decision branches exactly:
57
+ * - explicit identifier → sanitize; reject empty; reject collision
58
+ * - no identifier → count up from 1 to the first id not in the set
59
+ */
60
+ export function composeIssueFile(input) {
61
+ const stateDir = joinPath(input.trackerRoot, input.state);
62
+ let identifier;
63
+ const explicit = (input.identifier ?? '').trim();
64
+ if (explicit.length > 0) {
65
+ identifier = sanitizeIdentifier(explicit);
66
+ if (identifier.length === 0) {
67
+ return {
68
+ ok: false,
69
+ error: {
70
+ code: 'empty_identifier',
71
+ message: 'identifier must contain at least one allowed character',
72
+ },
73
+ };
74
+ }
75
+ const filePath = joinPath(stateDir, `${identifier}.md`);
76
+ if (input.existingIdentifiers.has(identifier)) {
77
+ return {
78
+ ok: false,
79
+ error: {
80
+ code: 'identifier_exists',
81
+ message: `issue ${identifier} already exists at ${filePath}`,
82
+ identifier,
83
+ path: filePath,
84
+ },
85
+ };
86
+ }
87
+ }
88
+ else {
89
+ // No identifier supplied → pick the next free numeric identifier by counting
90
+ // up from 1. Title-slug files from prior cycles are inert: only numeric
91
+ // basenames consume IDs (legacy `add-changelog.md` never claims a slot).
92
+ let n = 1;
93
+ while (input.existingIdentifiers.has(String(n)))
94
+ n += 1;
95
+ identifier = String(n);
96
+ }
97
+ const filePath = joinPath(stateDir, `${identifier}.md`);
98
+ // Standard front matter, in the original's declaration order, then the
99
+ // caller's extras (which may override — preserving the original's merge).
100
+ const fm = {
101
+ id: identifier,
102
+ identifier,
103
+ title: input.title,
104
+ created_at: input.nowIso,
105
+ updated_at: input.nowIso,
106
+ };
107
+ if (typeof input.priority === 'number')
108
+ fm.priority = input.priority;
109
+ if (input.labels && input.labels.length > 0)
110
+ fm.labels = input.labels;
111
+ if (input.blocked_by && input.blocked_by.length > 0)
112
+ fm.blocked_by = input.blocked_by;
113
+ if (input.extra_front_matter) {
114
+ for (const [k, v] of Object.entries(input.extra_front_matter)) {
115
+ fm[k] = v;
116
+ }
117
+ }
118
+ const yamlLines = ['---'];
119
+ for (const [k, v] of Object.entries(fm)) {
120
+ yamlLines.push(`${k}: ${renderYamlValue(v)}`);
121
+ }
122
+ yamlLines.push('---', '');
123
+ const body = (input.description ?? '').trim();
124
+ const content = yamlLines.join('\n') + (body.length > 0 ? body + '\n' : '');
125
+ const writeEffect = {
126
+ family: 'tracker',
127
+ kind: 'write_issue',
128
+ trackerRoot: input.trackerRoot,
129
+ identifier,
130
+ state: input.state,
131
+ title: input.title,
132
+ ...(input.description !== undefined ? { description: input.description } : {}),
133
+ ...(input.priority !== undefined ? { priority: input.priority } : {}),
134
+ ...(input.labels !== undefined ? { labels: input.labels } : {}),
135
+ ...(input.blocked_by !== undefined ? { blocked_by: input.blocked_by } : {}),
136
+ ...(input.extra_front_matter !== undefined ? { extraFrontMatter: input.extra_front_matter } : {}),
137
+ };
138
+ return {
139
+ ok: true,
140
+ result: {
141
+ path: filePath,
142
+ identifier,
143
+ state: input.state,
144
+ content,
145
+ effects: [writeEffect],
146
+ },
147
+ };
148
+ }
149
+ //# sourceMappingURL=file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.js","sourceRoot":"","sources":["../../../../src/core/issue/file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,210 @@
1
+ // FCIS rewrite — pure issue parsing & selection core (SPEC §3.2).
2
+ //
3
+ // Ports the *decision* half of the original `src/trackers/local.ts` (parse +
4
+ // normalize + active-candidate filter + multi-match disambiguation) and the
5
+ // pure collision-pick from `src/issues.ts` (`writeIssueFile`'s next-free-id
6
+ // loop), with the impureCoreRisk removed: the existing-identifier SET is
7
+ // supplied by the shell (which owns the readdir), NOT scanned here.
8
+ //
9
+ // HARD CONSTRAINTS (gate-enforced):
10
+ // - 100% SYNCHRONOUS. No async/await/Promise anywhere.
11
+ // - No IO, no node: imports, no process/fetch, no wall clock, no randomness.
12
+ // - Imports ONLY from src/types/**.
13
+ //
14
+ // The YAML decode itself lives in the shell tracker adapter (it needs the
15
+ // `yaml` userland lib, which core may not import). The shell hands us the
16
+ // already-decoded front-matter map + body + state-from-dir + filename; this
17
+ // module turns that into a normalized `Issue` and makes every selection
18
+ // decision as pure data-in / data-out.
19
+ import { TrackerError, NoHoldingStateError } from '../../types/errors.js';
20
+ import { asString, asStringList, asInt, asTimestamp } from '../coerce.js';
21
+ // Front-matter coercers (asString/asStringList/asInt/asTimestamp) are the
22
+ // canonical ones from core/coerce.ts. NOTE(drift resolved): the old local copy
23
+ // of `asInt` here used `Number.isInteger` (rejecting a fractional priority);
24
+ // the canonical `asInt` truncates (isFinite + Math.trunc), matching the rest
25
+ // of the codebase. See core/coerce.ts header + tests/core/coerce.test.ts.
26
+ // ─── id derivation ───────────────────────────────────────────────────────────
27
+ /**
28
+ * Canonical id of a raw file: front-matter `id` when non-blank, else the
29
+ * filename stem. Exported because the shell's transition path resolves the
30
+ * caller-supplied issueId against this same key.
31
+ */
32
+ export function idOf(raw) {
33
+ const fmId = asString(raw.frontMatter['id']);
34
+ return fmId && fmId.trim().length > 0 ? fmId : raw.identifier;
35
+ }
36
+ // ─── normalize (build Issue objects, resolving blocker states) ───────────────
37
+ /**
38
+ * Build a blocker lookup keyed by every alias a `blocked_by` entry might use:
39
+ * the front-matter `identifier`, the canonical `id`, and the filename stem.
40
+ * Pure: derived solely from `all`. Last-write-wins mirrors the original.
41
+ */
42
+ function buildBlockerIndex(all) {
43
+ const byKey = new Map();
44
+ for (const r of all) {
45
+ const ident = asString(r.frontMatter['identifier']) ?? r.identifier;
46
+ byKey.set(ident, r);
47
+ byKey.set(idOf(r), r);
48
+ byKey.set(r.identifier, r);
49
+ }
50
+ return byKey;
51
+ }
52
+ function toIssue(raw, byKey) {
53
+ const fm = raw.frontMatter;
54
+ const id = idOf(raw);
55
+ const identifier = asString(fm['identifier']) ?? raw.identifier;
56
+ const title = asString(fm['title']) ?? identifier;
57
+ const priority = asInt(fm['priority']);
58
+ const labels = asStringList(fm['labels']).map((s) => s.toLowerCase());
59
+ const branch_name = asString(fm['branch_name']);
60
+ const url = asString(fm['url']);
61
+ const created_at = asTimestamp(fm['created_at']);
62
+ const updated_at = asTimestamp(fm['updated_at']);
63
+ const description = raw.description.length > 0 ? raw.description : null;
64
+ const blockerIdents = asStringList(fm['blocked_by']);
65
+ const blocked_by = blockerIdents.map((ident) => {
66
+ const found = byKey.get(ident);
67
+ if (found) {
68
+ const foundIdent = asString(found.frontMatter['identifier']) ?? found.identifier;
69
+ return {
70
+ id: idOf(found),
71
+ identifier: foundIdent,
72
+ state: found.state,
73
+ };
74
+ }
75
+ return { id: null, identifier: ident, state: null };
76
+ });
77
+ return {
78
+ id,
79
+ identifier,
80
+ title,
81
+ description,
82
+ priority,
83
+ state: raw.state,
84
+ branch_name,
85
+ url,
86
+ labels,
87
+ blocked_by,
88
+ created_at,
89
+ updated_at,
90
+ };
91
+ }
92
+ /**
93
+ * Normalize `target` raw files into `Issue`s, resolving blocker states against
94
+ * the full `all` view. The original passed both sets so a candidate's
95
+ * `blocked_by` could reference an issue outside the candidate window.
96
+ */
97
+ export function normalizeIssues(target, all) {
98
+ const byKey = buildBlockerIndex(all);
99
+ return target.map((r) => toIssue(r, byKey));
100
+ }
101
+ /** Parse a single raw file into an `Issue` (blockers resolved only against the file itself). */
102
+ export function parseIssue(raw) {
103
+ return toIssue(raw, buildBlockerIndex([raw]));
104
+ }
105
+ // ─── state-role helpers (ported from src/issues.ts) ──────────────────────────
106
+ /** Names of every state with `role`, in declaration order. */
107
+ function statesWithRole(states, role) {
108
+ return Object.entries(states).filter(([, cfg]) => cfg.role === role).map(([name]) => name);
109
+ }
110
+ /** Names of every `role: active` state, in declaration order. */
111
+ export function activeStateNames(states) {
112
+ return statesWithRole(states, 'active');
113
+ }
114
+ /** Names of every `role: terminal` state, in declaration order. */
115
+ export function terminalStateNames(states) {
116
+ return statesWithRole(states, 'terminal');
117
+ }
118
+ /**
119
+ * First declared `role: holding` state in declaration order (where triage /
120
+ * agent-proposed issues land). Throws `NoHoldingStateError` when none is
121
+ * declared — callers that surface this to agents should map it to a structured
122
+ * `no_holding_state` error.
123
+ */
124
+ export function pickHoldingState(states) {
125
+ for (const [name, cfg] of Object.entries(states)) {
126
+ if (cfg.role === 'holding')
127
+ return name;
128
+ }
129
+ throw new NoHoldingStateError('no holding state declared in workflow');
130
+ }
131
+ // ─── active-candidate filtering ──────────────────────────────────────────────
132
+ /**
133
+ * Select the active-but-not-terminal candidates and normalize them. Mirrors
134
+ * the original `fetchCandidateIssues`: state comparison is case-insensitive
135
+ * (SPEC §3.2 "Normalized Issue State"), and a state that is BOTH active and
136
+ * terminal (a malformed config) is excluded — the `!terminal` guard wins.
137
+ */
138
+ export function selectCandidateIssues(all, states) {
139
+ const active = new Set(activeStateNames(states).map((s) => s.toLowerCase()));
140
+ const terminal = new Set(terminalStateNames(states).map((s) => s.toLowerCase()));
141
+ const filtered = all.filter((raw) => {
142
+ const s = raw.state.toLowerCase();
143
+ return active.has(s) && !terminal.has(s);
144
+ });
145
+ return normalizeIssues(filtered, all);
146
+ }
147
+ /** Select & normalize every file whose state is in `stateNames` (case-insensitive). */
148
+ export function selectIssuesByStates(all, stateNames) {
149
+ if (stateNames.length === 0)
150
+ return [];
151
+ const want = new Set(stateNames.map((s) => s.toLowerCase()));
152
+ const filtered = all.filter((raw) => want.has(raw.state.toLowerCase()));
153
+ return normalizeIssues(filtered, all);
154
+ }
155
+ /** Select & normalize every file whose canonical id is in `issueIds`. */
156
+ export function selectIssuesByIds(all, issueIds) {
157
+ if (issueIds.length === 0)
158
+ return [];
159
+ const want = new Set(issueIds);
160
+ const filtered = all.filter((raw) => want.has(idOf(raw)));
161
+ return normalizeIssues(filtered, all);
162
+ }
163
+ // ─── multi-match disambiguation (ported from resolveMatch) ───────────────────
164
+ /**
165
+ * Resolve the single raw file that matches `issueId`. Multiple files can share
166
+ * an id when a stale terminal copy survives alongside a live active copy;
167
+ * `readdir` ordering is filesystem-dependent, so we refuse to guess. When more
168
+ * than one candidate matches, prefer the copy whose state equals the
169
+ * caller-supplied `fromState`; if that still doesn't resolve to exactly one,
170
+ * throw `TrackerError('local_issue_ambiguous')`.
171
+ *
172
+ * `candidates` is the pre-filtered set (state in: all files with `idOf === issueId`).
173
+ * Throws `TrackerError('local_issue_not_found')` when empty.
174
+ */
175
+ export function resolveMatch(candidates, issueId, fromState) {
176
+ if (candidates.length === 0) {
177
+ throw new TrackerError('local_issue_not_found', `no issue file matches id ${issueId}`);
178
+ }
179
+ if (candidates.length === 1)
180
+ return candidates[0];
181
+ const preferred = fromState
182
+ ? candidates.filter((raw) => raw.state.toLowerCase() === fromState.toLowerCase())
183
+ : [];
184
+ if (preferred.length === 1)
185
+ return preferred[0];
186
+ const statesStr = candidates.map((raw) => raw.state).join(', ');
187
+ throw new TrackerError('local_issue_ambiguous', `multiple issue files match id ${issueId} across states [${statesStr}]; pass fromState to disambiguate`);
188
+ }
189
+ /** All raw files whose canonical id equals `issueId` (the input `resolveMatch` expects). */
190
+ export function matchingCandidates(all, issueId) {
191
+ return all.filter((raw) => idOf(raw) === issueId);
192
+ }
193
+ // ─── next-free-identifier collision pick (pure half of writeIssueFile) ───────
194
+ /**
195
+ * Pick the next free numeric identifier given the existing-identifier SET (the
196
+ * shell's readdir supplies it — impureCoreRisk fix: NO scan here). Counts up
197
+ * from 1 until it finds a basename not present in `existing`. Title-slug files
198
+ * from prior cycles are inert: only numeric basenames consume IDs.
199
+ *
200
+ * `existing` should be the union of identifiers across ALL state directories,
201
+ * so a `Done/3.md` can't silently shadow a freshly created `Todo/3.md` once it
202
+ * moves out of Todo (faithful to `collectExistingIdentifiers`).
203
+ */
204
+ export function pickNextNumericIdentifier(existing) {
205
+ let n = 1;
206
+ while (existing.has(String(n)))
207
+ n += 1;
208
+ return String(n);
209
+ }
210
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../../src/core/issue/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,239 @@
1
+ // FCIS rewrite — pure MCP tools/call PRE-move decider (ported from src/mcp.ts:
2
+ // callTransition / callRequestHumanSteering / callProposeIssue). `decideToolCall`
3
+ // is a pure synchronous (data) -> {response, effects} function: it does no IO,
4
+ // reads no clock, holds no Promise.
5
+ //
6
+ // The keystone of the FCIS split — what is and is NOT decided here:
7
+ // * VALIDATION (data-only) IS decided here: declared-state + `allowed_transitions`
8
+ // gate, the non-empty/single-line arg checks, and the "steering already
9
+ // pending" guard. A rejection is the synchronous tool-result (`isError: true`,
10
+ // plus a structured payload for the transition rejections), with NO effects.
11
+ // * The MOVE is an EFFECT: a valid transition emits `move_state` +
12
+ // `set_transitioned`; the shell runs the move, folds the resolved
13
+ // {fromState,toState}, builds the success response, and decides `defer_cleanup`
14
+ // (the post-move cleanup gate lives in the core/mcp fold, not here).
15
+ // * The steering AWAITER Promise is never held here (desync fix, issue 151):
16
+ // we emit `stash_steering` + `await_steering`; the shell parks the awaiter and
17
+ // flips `steering_requested` only once it is live.
18
+ // * `propose_issue` emits `write_issue` with validated fields only; the shell
19
+ // stamps `proposed_at` from its injected Clock (orig: `isoFromClock(this.now)`).
20
+ import { resolveDeclaredName, isInFlowTransition } from '../state-resolve.js';
21
+ import { makeError } from './protocol.js';
22
+ // ─── Top-level dispatch ─────────────────────────────────────────────────────
23
+ /**
24
+ * Decide a single `tools/call`. Returns the synchronous response and/or the
25
+ * effects to perform. Unknown tool names produce a JSON-RPC method-not-found
26
+ * error (matching the original `unknown tool: <name>` branch).
27
+ */
28
+ export function decideToolCall(id, toolName, args, view, states) {
29
+ switch (toolName) {
30
+ case 'transition':
31
+ return decideTransition(id, args, view, states);
32
+ case 'request_human_steering':
33
+ return decideRequestHumanSteering(id, args, view);
34
+ case 'propose_issue':
35
+ return decideProposeIssue(id, args, view, states);
36
+ default:
37
+ return { response: makeError(id, -32601, `unknown tool: ${toolName}`), effects: [] };
38
+ }
39
+ }
40
+ // ─── transition ─────────────────────────────────────────────────────────────
41
+ /**
42
+ * `transition({ to_state, notes? })`. Validate the target against the declared
43
+ * states + the current state's `allowed_transitions`, then emit the move.
44
+ *
45
+ * Validation rejections return a tool-result error (the structured ones for
46
+ * `unknown_state` / `transition_not_allowed` carry the machine-readable payload
47
+ * the agent reads to pick a valid target next call). On success, `response` is
48
+ * null and `effects` carries `move_state` + `set_transitioned`.
49
+ */
50
+ export function decideTransition(id, args, view, states) {
51
+ const toStateRaw = typeof args.to_state === 'string' ? args.to_state.trim() : '';
52
+ const notes = typeof args.notes === 'string' ? args.notes : '';
53
+ if (!toStateRaw) {
54
+ return rejectText(id, 'to_state is required and must be a non-empty string');
55
+ }
56
+ if (!view.trackerSupportsMove) {
57
+ return rejectText(id, 'this tracker does not support state transitions');
58
+ }
59
+ const declaredNames = states.order;
60
+ const canonicalTarget = canonicalStateName(states, toStateRaw);
61
+ if (canonicalTarget === null) {
62
+ const text = `state "${toStateRaw}" is not declared. declared: ${declaredNames.length > 0 ? declaredNames.join(', ') : '<none>'}`;
63
+ return rejectStructured(id, text, {
64
+ error: 'unknown_state',
65
+ declared_states: declaredNames,
66
+ });
67
+ }
68
+ // `allowed_transitions: null | undefined` ⇒ any declared state reachable; a
69
+ // present array restricts (empty array ⇒ no transitions out). Validate only
70
+ // when the CURRENT state canonicalizes to a declared state with a list. The
71
+ // in-flow test is the ONE predicate shared with the operator's soft-warning
72
+ // move endpoint (isInFlowTransition, src/core/state-resolve.ts) — the agent
73
+ // path HARD-rejects exactly what the operator path only warns on (issue 126).
74
+ // A self-transition is always in-flow (the predicate short-circuits it).
75
+ const canonicalFrom = canonicalStateName(states, view.fromState);
76
+ if (canonicalFrom !== null) {
77
+ const allowed = states.views[canonicalFrom].allowed_transitions;
78
+ if (allowed && !isInFlowTransition(allowed, canonicalFrom, canonicalTarget)) {
79
+ const text = `transition to "${canonicalTarget}" is not allowed from "${canonicalFrom}". allowed: ${allowed.length > 0 ? allowed.join(', ') : '<none>'}`;
80
+ return rejectStructured(id, text, {
81
+ error: 'transition_not_allowed',
82
+ from_state: canonicalFrom,
83
+ requested_to_state: canonicalTarget,
84
+ allowed_transitions: allowed,
85
+ });
86
+ }
87
+ }
88
+ // Valid. Emit the move (the shell runs the tracker file-move and folds the
89
+ // resolved {fromState,toState} back to build the success response + decide
90
+ // cleanup). `set_transitioned` flips the post-turn exit flag. The decider
91
+ // does NOT build the success response (it depends on the resolved tracker
92
+ // result) → response: null.
93
+ const effects = [
94
+ {
95
+ kind: 'move_state',
96
+ issueId: view.issueId,
97
+ toState: canonicalTarget,
98
+ fromRoot: view.trackerRootSnapshot,
99
+ fromState: view.fromState,
100
+ notes,
101
+ actor: view.actor,
102
+ },
103
+ { kind: 'set_transitioned' },
104
+ ];
105
+ return { response: null, effects };
106
+ }
107
+ // ─── request_human_steering ───────────────────────────────────────────────
108
+ /**
109
+ * `request_human_steering({ question, context? })`. Validate the question and
110
+ * the "already pending" guard, then emit `stash_steering` + `await_steering`.
111
+ *
112
+ * The decider returns a READY ack response (the original returned the ack
113
+ * synchronously — the question is merely queued; the turn ends and the human
114
+ * reply arrives as the next turn's prompt). The awaiter Promise + the
115
+ * `steering_requested` flag flip both live in the shell (issue 151).
116
+ */
117
+ export function decideRequestHumanSteering(id, args, view) {
118
+ const question = typeof args.question === 'string' ? args.question.trim() : '';
119
+ const context = typeof args.context === 'string' ? args.context.trim() : '';
120
+ if (!question) {
121
+ return rejectText(id, 'question is required and must be a non-empty string');
122
+ }
123
+ // Guard on the stashed question (awaiter-liveness desync fix, issue 151): a
124
+ // non-null pending question means an unanswered request is already out.
125
+ if (view.steeringPending) {
126
+ return rejectText(id, 'a steering request is already pending for this issue; end the turn and wait for the response');
127
+ }
128
+ const effects = [
129
+ { kind: 'stash_steering', question, context: context.length > 0 ? context : null },
130
+ { kind: 'await_steering' },
131
+ ];
132
+ const ack = 'Question queued. End this turn now. The human response will arrive as the prompt for your next turn.';
133
+ return { response: toolResult(id, ack, false), effects };
134
+ }
135
+ // ─── propose_issue ──────────────────────────────────────────────────────────
136
+ /**
137
+ * `propose_issue({ title, description?, labels?, priority? })`. Validate the
138
+ * title (non-empty single line), resolve the landing holding state, then emit
139
+ * the `write_issue` effect. The shell stamps `proposed_at` from its Clock and
140
+ * builds the success response from the written {identifier,state,path}; on a
141
+ * valid propose this decider returns `response: null` (the identifier isn't
142
+ * known until the file is written).
143
+ *
144
+ * Two rejections are decided here purely:
145
+ * - missing/multiline title (text tool-error)
146
+ * - unresolvable tracker root (text tool-error)
147
+ * - no declared holding state (structured `no_holding_state` tool-error)
148
+ */
149
+ export function decideProposeIssue(id, args, view, states) {
150
+ const titleRaw = typeof args.title === 'string' ? args.title.trim() : '';
151
+ const description = typeof args.description === 'string' ? args.description : '';
152
+ if (!titleRaw) {
153
+ return rejectText(id, 'title is required and must be a non-empty string');
154
+ }
155
+ if (titleRaw.includes('\n')) {
156
+ return rejectText(id, 'title must be a single line (no embedded newlines)');
157
+ }
158
+ const labels = Array.isArray(args.labels)
159
+ ? args.labels.filter((x) => typeof x === 'string')
160
+ : [];
161
+ const priority = typeof args.priority === 'number' && Number.isFinite(args.priority) ? args.priority : null;
162
+ // Original resolved root := dispatch snapshot ?? tracker.currentRoot(); the
163
+ // shell projects that already-resolved value into `trackerRootSnapshot`, so a
164
+ // null here is the genuine "no resolvable root" case.
165
+ if (view.trackerRootSnapshot === null) {
166
+ return rejectText(id, 'tracker root is not available; cannot create issue files (is this a non-local tracker?)');
167
+ }
168
+ // Landing state must exist (first declared `holding` state). Core resolves the
169
+ // actual landing name HERE (strict, declaration-order) and carries it on the
170
+ // effect so the shell writer never re-resolves it with a divergent fallback.
171
+ const landingState = pickHoldingState(states);
172
+ if (landingState === null) {
173
+ return rejectStructured(id, 'cannot propose issue: workflow has no holding-role state declared', {
174
+ error: 'no_holding_state',
175
+ declared_states: states.order,
176
+ });
177
+ }
178
+ const effects = [
179
+ {
180
+ kind: 'write_issue',
181
+ title: titleRaw,
182
+ description: description.length > 0 ? description : null,
183
+ labels,
184
+ priority,
185
+ proposedBy: view.identifier,
186
+ landingState,
187
+ },
188
+ ];
189
+ return { response: null, effects };
190
+ }
191
+ // ─── Pure helpers ───────────────────────────────────────────────────────────
192
+ /**
193
+ * Canonical declared name for `name` (exact match wins, else a case-insensitive
194
+ * scan in declaration order). Thin adapter over the canonical
195
+ * {@link resolveDeclaredName} (core/state-resolve.ts) keyed by the MCP states
196
+ * view's declared-name `order`. Returns null when no declared state matches.
197
+ */
198
+ export function canonicalStateName(states, name) {
199
+ return resolveDeclaredName(states.order, name);
200
+ }
201
+ /**
202
+ * First declared `holding` state in declaration order, or null when none is
203
+ * declared. Pure mirror of core/states.pickHoldingState, but returns null (the
204
+ * caller turns that into the structured `no_holding_state` rejection) rather
205
+ * than a NoHoldingStateError value, since the original surfaced it as a tool
206
+ * error to the agent rather than throwing.
207
+ */
208
+ function pickHoldingState(states) {
209
+ for (const name of states.order) {
210
+ const v = states.views[name];
211
+ if (v && v.role === 'holding')
212
+ return name;
213
+ }
214
+ return null;
215
+ }
216
+ // ─── Response constructors (pure value objects) ───────────────────────────────
217
+ // `makeError` (the JSON-RPC error envelope) is imported from ./protocol.js — the
218
+ // canonical home — rather than re-inlined here (it was byte-identical).
219
+ /**
220
+ * MCP convention: tool results (success OR error) are a `result`, not a JSON-RPC
221
+ * error. `isError` marks a tool failure; the optional `structuredContent` slot
222
+ * carries the machine-readable recovery payload (transition + no_holding_state
223
+ * rejections) the agent reads to pick a valid next call.
224
+ */
225
+ function toolResult(id, text, isError, structuredContent) {
226
+ const result = { content: [{ type: 'text', text }], isError };
227
+ if (structuredContent)
228
+ result.structuredContent = structuredContent;
229
+ return { jsonrpc: '2.0', id, result };
230
+ }
231
+ /** Plain-text tool-error decision with no effects. */
232
+ function rejectText(id, message) {
233
+ return { response: toolResult(id, message, true), effects: [] };
234
+ }
235
+ /** Structured tool-error decision (text + machine-readable payload), no effects. */
236
+ function rejectStructured(id, text, json) {
237
+ return { response: toolResult(id, text, true, json), effects: [] };
238
+ }
239
+ //# sourceMappingURL=dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../../../src/core/mcp/dispatch.ts"],"names":[],"mappings":"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"}