mandrel 1.93.0 → 2.0.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 (463) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/acceptance-critic.md +129 -0
  3. package/.agents/agents/story-worker.md +161 -0
  4. package/.agents/docs/SDLC.md +489 -1285
  5. package/.agents/docs/agentrc-reference.json +177 -67
  6. package/.agents/docs/configuration.md +108 -136
  7. package/.agents/docs/execution-reference.md +44 -22
  8. package/.agents/docs/quality-gates.md +13 -19
  9. package/.agents/docs/workflows.md +3 -3
  10. package/.agents/instructions.md +107 -108
  11. package/.agents/rules/ci-remediation.md +8 -12
  12. package/.agents/rules/git-conventions-reference.md +224 -0
  13. package/.agents/rules/git-conventions.md +42 -223
  14. package/.agents/rules/security-baseline.md +5 -0
  15. package/.agents/rules/testing-standards.md +106 -13
  16. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  17. package/.agents/schemas/agentrc.schema.json +71 -201
  18. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  20. package/.agents/schemas/risk-verdict.schema.json +0 -13
  21. package/.agents/scripts/acceptance-eval.js +62 -18
  22. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  23. package/.agents/scripts/analyze-execution.js +1 -1
  24. package/.agents/scripts/audit-to-stories.js +7 -7
  25. package/.agents/scripts/boot-sweep.js +1 -1
  26. package/.agents/scripts/check-context-budget.js +62 -5
  27. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  28. package/.agents/scripts/check-prepush-recovery.js +1 -1
  29. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  30. package/.agents/scripts/diagnose-friction.js +0 -6
  31. package/.agents/scripts/lib/Logger.js +6 -10
  32. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  33. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  34. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  35. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  36. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  37. package/.agents/scripts/lib/baselines/reader.js +1 -6
  38. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  39. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  40. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
  41. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  42. package/.agents/scripts/lib/checks/index.js +2 -1
  43. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  44. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  45. package/.agents/scripts/lib/cli-args.js +16 -7
  46. package/.agents/scripts/lib/close-validation/gates.js +160 -22
  47. package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
  48. package/.agents/scripts/lib/config/ci.js +6 -31
  49. package/.agents/scripts/lib/config/delivery-routing.js +103 -0
  50. package/.agents/scripts/lib/config/explain.js +57 -36
  51. package/.agents/scripts/lib/config/limits.js +17 -58
  52. package/.agents/scripts/lib/config/paths.js +0 -2
  53. package/.agents/scripts/lib/config/quality.js +1 -1
  54. package/.agents/scripts/lib/config/runners.js +17 -50
  55. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  56. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  57. package/.agents/scripts/lib/config-resolver.js +3 -8
  58. package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
  59. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
  60. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  61. package/.agents/scripts/lib/dependency-parser.js +3 -2
  62. package/.agents/scripts/lib/doc-tiers.js +39 -4
  63. package/.agents/scripts/lib/duplicate-search.js +211 -41
  64. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  65. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  66. package/.agents/scripts/lib/framework-version.js +2 -3
  67. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  68. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  69. package/.agents/scripts/lib/git-utils.js +32 -6
  70. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  71. package/.agents/scripts/lib/label-constants.js +10 -23
  72. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  73. package/.agents/scripts/lib/observability/active-story-env.js +112 -3
  74. package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
  75. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  76. package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
  77. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  78. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
  79. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
  80. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  81. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
  82. package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
  83. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  84. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  85. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  86. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  87. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  88. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  89. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  90. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  91. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  92. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  93. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  94. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  95. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  96. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  97. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  98. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
  99. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  100. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  101. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  102. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  103. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  104. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  105. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  106. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  107. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  108. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
  109. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  110. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  111. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  112. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  113. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  114. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  115. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  116. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  117. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  118. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  119. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  120. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  121. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  122. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  123. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  124. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  125. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  126. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
  127. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  128. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  129. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  130. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  131. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  132. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  133. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  134. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  135. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  136. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  137. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  138. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  139. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  140. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  141. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  142. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  143. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  144. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  145. package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
  146. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  147. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  148. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  149. package/.agents/scripts/lib/planning-corpus.js +16 -11
  150. package/.agents/scripts/lib/preflight-runner.js +2 -2
  151. package/.agents/scripts/lib/provider-factory.js +1 -1
  152. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  153. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  154. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  155. package/.agents/scripts/lib/story-adjacency.js +11 -14
  156. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  157. package/.agents/scripts/lib/story-plan.js +2 -4
  158. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  159. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  160. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  161. package/.agents/scripts/lib/validation-evidence.js +1 -1
  162. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  163. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  164. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  165. package/.agents/scripts/lint-issue-body.js +71 -40
  166. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  167. package/.agents/scripts/notify.js +4 -3
  168. package/.agents/scripts/plan-context.js +64 -74
  169. package/.agents/scripts/plan-persist.js +121 -280
  170. package/.agents/scripts/plan-run-epilogue.js +97 -0
  171. package/.agents/scripts/post-structured-comment.js +38 -0
  172. package/.agents/scripts/providers/github/issues.js +17 -33
  173. package/.agents/scripts/providers/github/mappers.js +0 -12
  174. package/.agents/scripts/providers/github/tickets.js +2 -5
  175. package/.agents/scripts/resolve-plan-run.js +117 -0
  176. package/.agents/scripts/signals-view.js +24 -19
  177. package/.agents/scripts/single-story-close.js +11 -14
  178. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  179. package/.agents/scripts/single-story-init.js +29 -20
  180. package/.agents/scripts/stories-wave-tick.js +6 -6
  181. package/.agents/scripts/story-plan.js +26 -47
  182. package/.agents/scripts/sync-claude-agents.js +165 -0
  183. package/.agents/scripts/update-ticket-state.js +37 -15
  184. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  185. package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
  186. package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
  187. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
  188. package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
  189. package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
  190. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
  191. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  192. package/.agents/skills/skills.index.json +8 -418
  193. package/.agents/starter-agentrc.json +0 -5
  194. package/.agents/templates/agent-protocol.md +9 -10
  195. package/.agents/workflows/audit-architecture.md +3 -3
  196. package/.agents/workflows/audit-clean-code.md +3 -3
  197. package/.agents/workflows/audit-dependencies.md +3 -3
  198. package/.agents/workflows/audit-devops.md +3 -3
  199. package/.agents/workflows/audit-documentation.md +5 -5
  200. package/.agents/workflows/audit-lighthouse.md +3 -3
  201. package/.agents/workflows/audit-navigability.md +3 -2
  202. package/.agents/workflows/audit-performance.md +3 -3
  203. package/.agents/workflows/audit-privacy.md +3 -3
  204. package/.agents/workflows/audit-quality.md +3 -3
  205. package/.agents/workflows/audit-security.md +3 -3
  206. package/.agents/workflows/audit-seo.md +3 -3
  207. package/.agents/workflows/audit-sre.md +3 -3
  208. package/.agents/workflows/audit-to-stories.md +20 -20
  209. package/.agents/workflows/audit-ux-ui.md +3 -3
  210. package/.agents/workflows/deliver.md +122 -131
  211. package/.agents/workflows/git-cleanup.md +3 -4
  212. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  213. package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
  214. package/.agents/workflows/helpers/code-review.md +70 -193
  215. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  216. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  217. package/.agents/workflows/helpers/diagnose.md +10 -10
  218. package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
  219. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  220. package/.agents/workflows/helpers/signals.md +16 -16
  221. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  222. package/.agents/workflows/mandrel-update.md +3 -2
  223. package/.agents/workflows/plan.md +112 -145
  224. package/.agents/workflows/qa-assist.md +24 -30
  225. package/.agents/workflows/qa-explore.md +29 -38
  226. package/.agents/workflows/qa-run.md +2 -2
  227. package/README.md +9 -8
  228. package/docs/CHANGELOG.md +46 -0
  229. package/lib/cli/registry.js +95 -0
  230. package/lib/migrations/index.js +6 -5
  231. package/package.json +5 -3
  232. package/.agents/personas/architect.md +0 -113
  233. package/.agents/personas/devops-engineer.md +0 -38
  234. package/.agents/personas/engineer-mobile.md +0 -120
  235. package/.agents/personas/engineer-web.md +0 -111
  236. package/.agents/personas/engineer.md +0 -119
  237. package/.agents/personas/product.md +0 -94
  238. package/.agents/personas/project-manager.md +0 -114
  239. package/.agents/personas/qa-engineer.md +0 -95
  240. package/.agents/personas/refactorer.md +0 -113
  241. package/.agents/personas/security-engineer.md +0 -112
  242. package/.agents/personas/sre.md +0 -86
  243. package/.agents/personas/technical-writer.md +0 -101
  244. package/.agents/personas/ux-designer.md +0 -95
  245. package/.agents/schemas/dispatch-manifest.json +0 -232
  246. package/.agents/schemas/epic-spec.schema.json +0 -153
  247. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  248. package/.agents/scripts/dispatcher.js +0 -295
  249. package/.agents/scripts/epic-audit-prepare.js +0 -497
  250. package/.agents/scripts/epic-audit-recheck.js +0 -274
  251. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  252. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  253. package/.agents/scripts/epic-deliver-prepare.js +0 -590
  254. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  255. package/.agents/scripts/epic-plan-clarity.js +0 -211
  256. package/.agents/scripts/epic-plan-decompose.js +0 -54
  257. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  258. package/.agents/scripts/epic-plan-spec.js +0 -64
  259. package/.agents/scripts/epic-reconcile.js +0 -625
  260. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  261. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  262. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  263. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  264. package/.agents/scripts/lib/config/preflight.js +0 -58
  265. package/.agents/scripts/lib/config/retro.js +0 -77
  266. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  267. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  268. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  269. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
  270. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  271. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  272. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  273. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  274. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  275. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  276. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  277. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  278. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  279. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  280. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  281. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  282. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  283. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  284. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  285. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  286. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  287. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  288. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
  289. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  290. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  291. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  292. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  293. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  294. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  295. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  296. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  297. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  298. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  299. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  300. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  301. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  302. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  303. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  304. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  305. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  306. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  307. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  308. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  309. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  310. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  311. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  312. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  313. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
  314. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  315. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  316. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  317. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
  318. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  319. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  320. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  321. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  322. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  323. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  324. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  325. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  326. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  327. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  328. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  329. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  330. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  331. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  332. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  333. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  334. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  335. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
  336. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  337. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  338. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  339. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  340. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  341. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  342. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  343. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  344. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  345. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  346. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  347. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  348. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  349. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  350. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  351. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  352. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  353. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  354. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  355. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  356. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  357. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  358. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  359. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  360. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  361. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
  362. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  363. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  364. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  365. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  366. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  367. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  368. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  369. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  370. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  371. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  372. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  373. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  374. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  375. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  376. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  377. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  378. package/.agents/scripts/lib/spec/index.js +0 -36
  379. package/.agents/scripts/lib/spec/loader.js +0 -425
  380. package/.agents/scripts/lib/spec/state.js +0 -208
  381. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  382. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  383. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  384. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  385. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  386. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  387. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  388. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  389. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  390. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  391. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  392. package/.agents/scripts/lifecycle-emit.js +0 -510
  393. package/.agents/scripts/plan-critics.js +0 -199
  394. package/.agents/scripts/retro-run.js +0 -218
  395. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  396. package/.agents/scripts/story-close.js +0 -294
  397. package/.agents/scripts/story-init.js +0 -599
  398. package/.agents/scripts/story-phase.js +0 -369
  399. package/.agents/scripts/wave-tick.js +0 -335
  400. package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
  401. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
  402. package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
  403. package/.agents/skills/core/code-simplification/SKILL.md +0 -389
  404. package/.agents/skills/core/context-engineering/SKILL.md +0 -309
  405. package/.agents/skills/core/context-engineering/examples.md +0 -58
  406. package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
  407. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  408. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  409. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  410. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  411. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  412. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  413. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
  414. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  415. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
  416. package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
  417. package/.agents/skills/core/idea-refinement/examples.md +0 -437
  418. package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
  419. package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
  420. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
  421. package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
  422. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
  423. package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
  424. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
  425. package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
  426. package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
  427. package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
  428. package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
  429. package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
  430. package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
  431. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
  432. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
  433. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
  434. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
  435. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
  436. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
  437. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
  438. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
  439. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
  440. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
  441. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
  442. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
  443. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
  444. package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
  445. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
  446. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
  447. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
  448. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
  449. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
  450. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
  451. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
  452. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
  453. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
  454. package/.agents/workflows/helpers/deliver-epic.md +0 -955
  455. package/.agents/workflows/helpers/deliver-stories.md +0 -440
  456. package/.agents/workflows/helpers/epic-audit.md +0 -189
  457. package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
  458. package/.agents/workflows/helpers/epic-testing.md +0 -125
  459. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  460. package/.agents/workflows/helpers/plan-epic.md +0 -351
  461. package/.agents/workflows/helpers/plan-story.md +0 -251
  462. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  463. /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
@@ -1,369 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * story-phase.js — phase snapshot + heartbeat writer (2-tier).
5
- *
6
- * Replaces the deleted per-Task progress writer from the 4-tier era
7
- * (removed under #3157). `/deliver` calls this CLI at each Story-
8
- * level phase transition (init → implementing → closing → done, or any
9
- * → blocked). Each call:
10
- *
11
- * 1. Renders the Story-phase snapshot for the requested phase (canonical
12
- * init/implement/validate/close progression in the `phases[]` payload)
13
- * and returns its markdown body for chat relay. Story #3909 — this no
14
- * longer posts a `story-run-progress` comment (the redundant mid-flight
15
- * progress surface was deleted); the snapshot is render-only.
16
- * 2. Appends one `story.heartbeat` lifecycle record to
17
- * `temp/epic-<epicId>/lifecycle.ndjson` so `/deliver`'s
18
- * §2e Idle Watchdog (`wave-tick.js --check-idle 30`) can confirm
19
- * forward progress without polling the Story comment.
20
- *
21
- * The heartbeat emit is best-effort: a missing/unreachable ledger,
22
- * schema-validation hiccup, or absent `Epic: #N` body reference is
23
- * logged and swallowed — the labels remain the source of truth, the
24
- * ledger record is observability.
25
- *
26
- * CLI:
27
- * --story <id> Story ID (required).
28
- * --phase <init|implementing|closing|blocked|done>
29
- * Phase the Story is entering (required).
30
- * --epic <id> Parent Epic id from the Step 0 envelope.
31
- * When supplied, skips the readEpicIdFromStory
32
- * GitHub read.
33
- * --branch <name> Story branch from the Step 0 envelope.
34
- * When supplied, skips the resolveStoryBranch
35
- * GitHub read.
36
- * --no-heartbeat Suppress the lifecycle emit (tests).
37
- *
38
- * Stdout: a single JSON envelope
39
- * { ok: true, storyId, phase, epicId, branch, heartbeatEmitted,
40
- * ledgerPath, renderedBody }
41
- *
42
- * `renderedBody` is the markdown body upserted onto the Story so the
43
- * caller can relay it to chat verbatim (mirrors the contract the deleted
44
- * per-Task progress writer exposed and that `/deliver` Step 1 / 3
45
- * already documents).
46
- */
47
-
48
- import { parseArgs } from 'node:util';
49
-
50
- import { runAsCli } from './lib/cli-utils.js';
51
- import { resolveConfig } from './lib/config-resolver.js';
52
- import { Logger } from './lib/Logger.js';
53
- import {
54
- defaultStoryPhases,
55
- STORY_PHASE_ORDER,
56
- upsertStoryRunProgress,
57
- } from './lib/orchestration/epic-runner/story-run-progress-writer.js';
58
- import { emitStoryHeartbeat } from './lib/orchestration/lifecycle/emit-story-heartbeat.js';
59
- import { parseFencedJsonComment } from './lib/orchestration/structured-comment-parser.js';
60
- import { normalizeOperatorHandle } from './lib/orchestration/ticket-lease.js';
61
- import { findStructuredComment } from './lib/orchestration/ticketing.js';
62
- import { createProvider } from './lib/provider-factory.js';
63
- import { resolveStoryHierarchy } from './lib/story-lifecycle.js';
64
- import { notify } from './notify.js';
65
-
66
- const VALID_PHASES = new Set([
67
- 'init',
68
- 'implementing',
69
- 'closing',
70
- 'blocked',
71
- 'done',
72
- ]);
73
-
74
- const HELP = `Usage: node .agents/scripts/story-phase.js \\
75
- --story <id> --phase <init|implementing|closing|blocked|done> \\
76
- [--epic <id>] [--branch <name>] [--no-heartbeat]
77
-
78
- Renders the Story-phase snapshot for Story #<id> at the requested phase
79
- (returned as renderedBody for chat relay; no comment is posted) and
80
- (unless --no-heartbeat) appends one story.heartbeat record to the parent
81
- Epic's lifecycle ledger so the Idle Watchdog can confirm the Story is alive.
82
-
83
- --epic / --branch let the caller pass the parent Epic id and Story branch
84
- from story-init.js's Step 0 envelope, skipping the GitHub reads
85
- (readEpicIdFromStory / resolveStoryBranch) that would otherwise re-fetch
86
- these immutable values on every phase call. Omit both for interactive use.
87
- `;
88
-
89
- /**
90
- * Map the workflow-level `--phase` value to the canonical phases[] row
91
- * progression carried in the snapshot payload (init/implement/validate/
92
- * close). The mapping is monotonic: each later phase marks every earlier
93
- * row `done`, the current row `in-progress` (or `done` when the workflow
94
- * phase itself is `done`), and any later rows `pending`. `blocked` leaves
95
- * the in-progress row marked in-progress (the blocker is reflected in the
96
- * header phase, not the row table).
97
- *
98
- * @param {string} workflowPhase
99
- * @returns {Array<{ name: string, status: string, startedAt: string|null, endedAt: string|null }>}
100
- */
101
- export function phasesForWorkflowPhase(workflowPhase, now = new Date()) {
102
- const ts = now.toISOString();
103
- const phases = defaultStoryPhases();
104
-
105
- // Anchor row that should be "current" for each workflow phase.
106
- const currentByPhase = {
107
- init: 'init',
108
- implementing: 'implement',
109
- closing: 'validate',
110
- blocked: 'implement',
111
- done: 'close',
112
- };
113
- const current = currentByPhase[workflowPhase];
114
- const currentIdx = STORY_PHASE_ORDER.indexOf(current);
115
-
116
- for (let i = 0; i < phases.length; i++) {
117
- if (i < currentIdx) {
118
- phases[i].status = 'done';
119
- phases[i].startedAt = ts;
120
- phases[i].endedAt = ts;
121
- } else if (i === currentIdx) {
122
- if (workflowPhase === 'done') {
123
- phases[i].status = 'done';
124
- phases[i].startedAt = ts;
125
- phases[i].endedAt = ts;
126
- } else {
127
- phases[i].status = 'in-progress';
128
- phases[i].startedAt = ts;
129
- }
130
- }
131
- }
132
- return phases;
133
- }
134
-
135
- /**
136
- * Hydrate the parent Epic id off the Story ticket body. Returns null when
137
- * the Story has no `Epic: #N` reference (the heartbeat emit will be
138
- * skipped because there is no Epic-scoped ledger path to write to).
139
- *
140
- * @param {{ provider: object, storyId: number }} args
141
- * @returns {Promise<number|null>}
142
- */
143
- export async function readEpicIdFromStory({ provider, storyId }) {
144
- const story = await provider.getTicket(storyId);
145
- const { epicId } = resolveStoryHierarchy(story?.body ?? '');
146
- return epicId ?? null;
147
- }
148
-
149
- /**
150
- * Hydrate the prior story-run-progress branch off the Story ticket so a
151
- * resumed run preserves the branch name rather than re-deriving it.
152
- * Falls back to `story-<id>` when no prior snapshot exists.
153
- */
154
- async function resolveStoryBranch({ provider, storyId }) {
155
- const snapshot = await findStructuredComment(
156
- provider,
157
- storyId,
158
- 'story-run-progress',
159
- );
160
- if (snapshot) {
161
- const parsed = parseFencedJsonComment(snapshot);
162
- if (parsed && typeof parsed.branch === 'string' && parsed.branch) {
163
- return parsed.branch;
164
- }
165
- }
166
- const initComment = await findStructuredComment(
167
- provider,
168
- storyId,
169
- 'story-init',
170
- );
171
- if (initComment) {
172
- const parsed = parseFencedJsonComment(initComment);
173
- if (
174
- parsed &&
175
- typeof parsed.storyBranch === 'string' &&
176
- parsed.storyBranch
177
- ) {
178
- return parsed.storyBranch;
179
- }
180
- }
181
- return `story-${storyId}`;
182
- }
183
-
184
- /**
185
- * Best-effort `story.heartbeat` emit for one phase transition. Resolves the
186
- * lease-owner handle the SAME way the lease primitive does
187
- * (`normalizeOperatorHandle(github.operatorHandle)`) and stamps it as
188
- * `operator` so `latestHeartbeatForOwner({ epicId, owner })` resolves a real
189
- * heartbeat — without it `isClaimLive(null)` is false and /deliver
190
- * silently reclaims a live foreign claim (audit #3513). The field is attached
191
- * only when a handle resolves, preserving the "omit when absent" shape for
192
- * repos that have not configured `github.operatorHandle`. A failed append is
193
- * logged and swallowed: the heartbeat is observability, not state.
194
- *
195
- * @param {{ storyId: number, epicId: number, phase: string, config: object|null, ledgerPath?: string, timestamp: string }} args
196
- * @returns {{ heartbeatEmitted: boolean, ledgerPath: string|null }}
197
- */
198
- function emitHeartbeatBestEffort({
199
- storyId,
200
- epicId,
201
- phase,
202
- config,
203
- ledgerPath,
204
- timestamp,
205
- }) {
206
- const operator = normalizeOperatorHandle(config?.github?.operatorHandle);
207
- try {
208
- const res = emitStoryHeartbeat({
209
- storyId,
210
- epicId,
211
- phase,
212
- timestamp,
213
- ...(operator !== null ? { operator } : {}),
214
- config: config ?? undefined,
215
- ledgerPath,
216
- });
217
- return { heartbeatEmitted: true, ledgerPath: res.ledgerPath };
218
- } catch (err) {
219
- Logger.warn(
220
- `[story-phase] story.heartbeat emit failed (continuing): ${err.message}`,
221
- );
222
- return { heartbeatEmitted: false, ledgerPath: null };
223
- }
224
- }
225
-
226
- /**
227
- * End-to-end phase writer. DI-friendly: tests pass `provider`, override
228
- * the ledger path, and skip the heartbeat as needed.
229
- *
230
- * When `epicId` / `branch` are supplied (the `/deliver` worker passes them
231
- * from `story-init.js`'s Step 0 envelope), the corresponding GitHub read is
232
- * skipped entirely: `epicId` short-circuits `readEpicIdFromStory` and
233
- * `branch` short-circuits `resolveStoryBranch`. Omit both for interactive
234
- * use to restore the original GitHub-read resolution.
235
- *
236
- * @param {{
237
- * storyId: number,
238
- * phase: string,
239
- * epicId?: number|null,
240
- * branch?: string,
241
- * noHeartbeat?: boolean,
242
- * provider?: object,
243
- * config?: object,
244
- * ledgerPath?: string,
245
- * now?: Date,
246
- * }} args
247
- */
248
- export async function runStoryPhase(args) {
249
- const {
250
- storyId,
251
- phase,
252
- epicId: epicIdOverride,
253
- branch: branchOverride,
254
- noHeartbeat = false,
255
- provider: providerOverride,
256
- config: configOverride,
257
- ledgerPath: ledgerPathOverride,
258
- now = new Date(),
259
- } = args ?? {};
260
-
261
- if (!Number.isInteger(storyId) || storyId <= 0) {
262
- throw new Error('runStoryPhase: --story must be a positive integer');
263
- }
264
- if (!VALID_PHASES.has(phase)) {
265
- throw new Error(
266
- `runStoryPhase: --phase "${phase}" must be one of: ${[...VALID_PHASES].join(', ')}`,
267
- );
268
- }
269
-
270
- const config = configOverride ?? (providerOverride ? null : resolveConfig());
271
- const provider = providerOverride ?? createProvider(config);
272
- const notifyFn = providerOverride
273
- ? null
274
- : (ticketId, payload, opts = {}) =>
275
- notify(ticketId, payload, { config, provider, ...opts });
276
-
277
- // When the Step 0 envelope supplied the branch / epicId (the /deliver
278
- // worker passes them via --branch / --epic), skip the GitHub reads that
279
- // would otherwise re-fetch these immutable values on every phase call.
280
- const branch =
281
- typeof branchOverride === 'string' && branchOverride
282
- ? branchOverride
283
- : await resolveStoryBranch({ provider, storyId });
284
- const epicId =
285
- epicIdOverride !== undefined
286
- ? epicIdOverride
287
- : await readEpicIdFromStory({ provider, storyId });
288
- const phases = phasesForWorkflowPhase(phase, now);
289
-
290
- const { body: renderedBody, payload: snapshot } =
291
- await upsertStoryRunProgress({
292
- provider,
293
- storyId,
294
- branch,
295
- phase,
296
- phases,
297
- epicId: epicId ?? undefined,
298
- updatedAt: now.toISOString(),
299
- notify: notifyFn,
300
- });
301
-
302
- let heartbeatEmitted = false;
303
- let ledgerPath = null;
304
- if (!noHeartbeat && epicId) {
305
- ({ heartbeatEmitted, ledgerPath } = emitHeartbeatBestEffort({
306
- storyId,
307
- epicId,
308
- phase,
309
- config,
310
- ledgerPath: ledgerPathOverride,
311
- timestamp: now.toISOString(),
312
- }));
313
- }
314
-
315
- return {
316
- ok: true,
317
- storyId,
318
- phase,
319
- epicId,
320
- branch,
321
- heartbeatEmitted,
322
- ledgerPath,
323
- snapshot,
324
- renderedBody,
325
- };
326
- }
327
-
328
- export function parseArgv(argv) {
329
- const { values } = parseArgs({
330
- args: argv,
331
- options: {
332
- story: { type: 'string' },
333
- phase: { type: 'string' },
334
- epic: { type: 'string' },
335
- branch: { type: 'string' },
336
- 'no-heartbeat': { type: 'boolean' },
337
- help: { type: 'boolean' },
338
- },
339
- strict: false,
340
- });
341
- // `--epic` absent → leave `epicId` undefined so runStoryPhase falls back to
342
- // the readEpicIdFromStory GitHub read. `--branch` absent → leave `branch`
343
- // undefined so it falls back to resolveStoryBranch.
344
- const parsed = {
345
- help: Boolean(values.help),
346
- storyId: Number.parseInt(values.story ?? '', 10),
347
- phase: values.phase,
348
- noHeartbeat: Boolean(values['no-heartbeat']),
349
- };
350
- if (values.epic !== undefined) {
351
- parsed.epicId = Number.parseInt(values.epic, 10);
352
- }
353
- if (typeof values.branch === 'string' && values.branch) {
354
- parsed.branch = values.branch;
355
- }
356
- return parsed;
357
- }
358
-
359
- export async function main(argv = process.argv.slice(2)) {
360
- const parsed = parseArgv(argv);
361
- if (parsed.help) {
362
- process.stdout.write(HELP);
363
- return;
364
- }
365
- const envelope = await runStoryPhase(parsed);
366
- process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
367
- }
368
-
369
- runAsCli(import.meta.url, main, { source: 'story-phase' });
@@ -1,335 +0,0 @@
1
- #!/usr/bin/env node
2
- /* node:coverage ignore file */
3
-
4
- /**
5
- * wave-tick.js — thin CLI shim around `lib/wave-runner/tick.js`.
6
- *
7
- * Reads the `epic-run-state` checkpoint plus fresh Story labels and
8
- * prints one `WaveTickResult` envelope. The slash-command operator
9
- * (`/deliver`) consumes the envelope to decide whether to dispatch
10
- * the next wave, observe in-flight stories, or finalize the Epic.
11
- *
12
- * Usage:
13
- * node .agents/scripts/wave-tick.js --epic <epicId> [--check-idle <minutes>]
14
- *
15
- * The tick is stateless — "loop until terminal" is the caller's job
16
- * (today: the markdown's wave loop).
17
- *
18
- * Output: one JSON object on stdout. Schema in `lib/wave-runner/tick.js`.
19
- */
20
-
21
- import { execFileSync } from 'node:child_process';
22
- import { existsSync, readFileSync } from 'node:fs';
23
- import { parseArgs } from 'node:util';
24
-
25
- import { runAsCli } from './lib/cli-utils.js';
26
- import { epicLedgerPath } from './lib/config/temp-paths.js';
27
- import { resolveConfig } from './lib/config-resolver.js';
28
- import { Logger } from './lib/Logger.js';
29
- import { createProvider } from './lib/provider-factory.js';
30
- import { tick } from './lib/wave-runner/tick.js';
31
-
32
- const HELP = `Usage: node .agents/scripts/wave-tick.js --epic <epicId> [--check-idle <minutes>]
33
-
34
- Stateless wave-loop planner. Reads the epic-run-state checkpoint on
35
- Epic #<id>, evaluates the live story-label state, and prints one
36
- WaveTickResult envelope describing the next dispatchable action.
37
-
38
- When --check-idle <minutes> is supplied, the planner skips the normal
39
- WaveTickResult emit and instead scans the per-Epic lifecycle ledger
40
- (temp/epic-<id>/lifecycle.ndjson) for in-flight Stories whose most
41
- recent lifecycle event is older than the threshold. Emits a single
42
- JSON envelope on stdout and exits non-zero when at least one stalled
43
- Story is detected. The envelope shape mirrors the wave-stall
44
- structured-comment payload so the slash-command host can post it
45
- verbatim.
46
- `;
47
-
48
- export async function runWaveTickCli({
49
- epicId,
50
- cwd,
51
- injectedProvider,
52
- injectedConfig,
53
- } = {}) {
54
- if (!Number.isInteger(epicId) || epicId <= 0) {
55
- throw new TypeError('runWaveTickCli: --epic must be a positive integer');
56
- }
57
-
58
- const config = injectedConfig ?? resolveConfig({ cwd });
59
- const provider = injectedProvider ?? createProvider(config);
60
-
61
- const result = await tick({
62
- epic: epicId,
63
- collaborators: { provider },
64
- ctx: { config },
65
- });
66
-
67
- return result;
68
- }
69
-
70
- /**
71
- * Scan the per-Epic lifecycle ledger and compute, per in-flight Story,
72
- * the timestamp of its most recent lifecycle event. A Story is
73
- * "in-flight" when the ledger carries a `story.dispatch.start` record
74
- * without a matching `story.dispatch.end`. Any other `story.*` event
75
- * (notably `story.heartbeat` from Story #3057) refreshes the Story's
76
- * last-event timestamp.
77
- *
78
- * Pure helper — exported for unit tests.
79
- *
80
- * @param {string} ledgerPath Absolute path to `lifecycle.ndjson`.
81
- * @returns {Map<number, string>} `storyId → ISO-8601 timestamp`. Empty
82
- * when the ledger is missing, unreadable, or carries no in-flight
83
- * Stories.
84
- */
85
- export function readLedgerLastEvents(ledgerPath) {
86
- if (!ledgerPath || !existsSync(ledgerPath)) return new Map();
87
- let raw;
88
- try {
89
- raw = readFileSync(ledgerPath, 'utf8');
90
- } catch {
91
- return new Map();
92
- }
93
- if (!raw) return new Map();
94
- const started = new Set();
95
- const ended = new Set();
96
- const lastTs = new Map();
97
- for (const line of raw.split(/\r?\n/)) {
98
- if (!line) continue;
99
- let record;
100
- try {
101
- record = JSON.parse(line);
102
- } catch {
103
- continue;
104
- }
105
- if (!record || record.kind !== 'emitted') continue;
106
- const event = typeof record.event === 'string' ? record.event : '';
107
- if (!event.startsWith('story.')) continue;
108
- const storyId = record.payload?.storyId;
109
- if (!Number.isInteger(storyId) || storyId <= 0) continue;
110
- if (event === 'story.dispatch.start') started.add(storyId);
111
- else if (event === 'story.dispatch.end') ended.add(storyId);
112
- const ts = typeof record.ts === 'string' ? record.ts : null;
113
- if (ts) {
114
- const prior = lastTs.get(storyId);
115
- if (!prior || prior < ts) lastTs.set(storyId, ts);
116
- }
117
- }
118
- const out = new Map();
119
- for (const id of started) {
120
- if (ended.has(id)) continue;
121
- const ts = lastTs.get(id);
122
- if (ts) out.set(id, ts);
123
- }
124
- return out;
125
- }
126
-
127
- /**
128
- * Deterministic branch-activity resolver (Story #3900). Returns the epoch-ms
129
- * timestamp of the most recent commit on `story-<storyId>` via
130
- * `git log -1 --format=%cI`, or `null` when the branch does not exist, has no
131
- * commits, or git is unavailable.
132
- *
133
- * This is the secondary liveness signal the idle watchdog consults before
134
- * flagging a Story as stalled: a healthy long-running Story routinely exceeds
135
- * the heartbeat threshold during `implementing → closing` (heartbeats fire
136
- * only at phase transitions), but its branch keeps gaining commits. A recent
137
- * commit is hard, deterministic evidence of forward progress that does not
138
- * depend on a heartbeat landing in the ledger. Pure-ish (shells out to git)
139
- * and injectable so unit tests never spawn a subprocess.
140
- *
141
- * @param {number} storyId
142
- * @param {{ cwd?: string, exec?: typeof execFileSync }} [deps]
143
- * @returns {number|null} epoch-ms of the last commit, or null.
144
- */
145
- export function branchLastCommitMs(storyId, deps = {}) {
146
- const exec = deps.exec ?? execFileSync;
147
- const cwd = deps.cwd ?? process.cwd();
148
- try {
149
- const out = exec(
150
- 'git',
151
- ['log', '-1', '--format=%cI', `story-${storyId}`, '--'],
152
- { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] },
153
- ).trim();
154
- if (!out) return null;
155
- const ms = Date.parse(out);
156
- return Number.isFinite(ms) ? ms : null;
157
- } catch {
158
- // Branch absent / git unavailable — no deterministic signal.
159
- return null;
160
- }
161
- }
162
-
163
- /**
164
- * Build the wave-stall envelope. Pure helper — exported for unit tests.
165
- *
166
- * A Story whose latest ledger event is older than the threshold is *not*
167
- * flagged as stalled when its `story-<id>` branch carries a commit newer
168
- * than the threshold (Story #3900). Branch commits are deterministic
169
- * forward-progress evidence that survives the heartbeat-cadence gap during
170
- * `implementing → closing`, so consulting them eliminates the false-positive
171
- * re-dispatch hazard (two agents on one branch) the watchdog otherwise
172
- * manufactures for every healthy long-running Story.
173
- *
174
- * @param {object} args
175
- * @param {number} args.epicId
176
- * @param {number} args.thresholdMinutes
177
- * @param {Map<number, string>} args.lastEvents `storyId → ISO-8601 ts`
178
- * from {@link readLedgerLastEvents}.
179
- * @param {Date} args.now Reference clock for the staleness comparison.
180
- * @param {(storyId: number) => (number|null)} [args.branchActivity]
181
- * Resolver for the last commit epoch-ms on `story-<id>`. Defaults to
182
- * {@link branchLastCommitMs}. Injected for tests.
183
- * @returns {{
184
- * kind: 'wave-stall',
185
- * epicId: number,
186
- * thresholdMinutes: number,
187
- * checkedAt: string,
188
- * stalled: Array<{storyId: number, lastEventAt: string, idleMinutes: number}>,
189
- * inFlight: number[]
190
- * }}
191
- */
192
- export function buildWaveStallEnvelope({
193
- epicId,
194
- thresholdMinutes,
195
- lastEvents,
196
- now,
197
- branchActivity = branchLastCommitMs,
198
- }) {
199
- const checkedAt = now.toISOString();
200
- const thresholdMs = thresholdMinutes * 60 * 1000;
201
- const stalled = [];
202
- const inFlight = [];
203
- for (const [storyId, ts] of lastEvents) {
204
- inFlight.push(storyId);
205
- const eventMs = Date.parse(ts);
206
- if (!Number.isFinite(eventMs)) continue;
207
- const idleMs = now.getTime() - eventMs;
208
- if (idleMs < thresholdMs) continue;
209
-
210
- // Ledger says idle — consult the branch as a deterministic liveness
211
- // signal before declaring a stall. A recent commit means the Story is
212
- // making progress despite the heartbeat-cadence gap.
213
- const commitMs = branchActivity(storyId);
214
- if (
215
- typeof commitMs === 'number' &&
216
- Number.isFinite(commitMs) &&
217
- now.getTime() - commitMs < thresholdMs
218
- ) {
219
- continue;
220
- }
221
-
222
- stalled.push({
223
- storyId,
224
- lastEventAt: ts,
225
- idleMinutes: Math.floor(idleMs / 60000),
226
- });
227
- }
228
- inFlight.sort((a, b) => a - b);
229
- stalled.sort((a, b) => a.storyId - b.storyId);
230
- return {
231
- kind: 'wave-stall',
232
- epicId,
233
- thresholdMinutes,
234
- checkedAt,
235
- stalled,
236
- inFlight,
237
- };
238
- }
239
-
240
- /**
241
- * Run the `--check-idle` path. Exported so unit tests can drive the
242
- * branch without spawning the CLI subprocess.
243
- *
244
- * @param {object} args
245
- * @param {number} args.epicId
246
- * @param {number} args.thresholdMinutes
247
- * @param {string} [args.ledgerPath] Override for tests; defaults to the
248
- * canonical `temp/epic-<id>/lifecycle.ndjson`.
249
- * @param {Date} [args.now] Override for tests; defaults to wall clock.
250
- * @param {object} [args.config] Optional resolved config for tempRoot.
251
- * @param {(storyId: number) => (number|null)} [args.branchActivity]
252
- * Branch-liveness resolver; defaults to {@link branchLastCommitMs}.
253
- * Injected for tests so the watchdog never spawns git.
254
- * @returns {{envelope: object, stalledCount: number}}
255
- */
256
- export function runCheckIdle({
257
- epicId,
258
- thresholdMinutes,
259
- ledgerPath,
260
- now = new Date(),
261
- config,
262
- branchActivity = branchLastCommitMs,
263
- }) {
264
- if (!Number.isInteger(epicId) || epicId <= 0) {
265
- throw new TypeError('runCheckIdle: epicId must be a positive integer');
266
- }
267
- if (!Number.isInteger(thresholdMinutes) || thresholdMinutes <= 0) {
268
- throw new TypeError(
269
- 'runCheckIdle: thresholdMinutes must be a positive integer',
270
- );
271
- }
272
- const resolvedPath = ledgerPath ?? epicLedgerPath(epicId, config);
273
- const lastEvents = readLedgerLastEvents(resolvedPath);
274
- const envelope = buildWaveStallEnvelope({
275
- epicId,
276
- thresholdMinutes,
277
- lastEvents,
278
- now,
279
- branchActivity,
280
- });
281
- return { envelope, stalledCount: envelope.stalled.length };
282
- }
283
-
284
- async function main(argv) {
285
- const { values } = parseArgs({
286
- args: argv,
287
- options: {
288
- epic: { type: 'string' },
289
- 'check-idle': { type: 'string' },
290
- help: { type: 'boolean', short: 'h' },
291
- },
292
- strict: false,
293
- allowPositionals: true,
294
- });
295
-
296
- if (values.help) {
297
- process.stdout.write(`${HELP}\n`);
298
- return;
299
- }
300
-
301
- const epicId = Number.parseInt(
302
- String(values.epic ?? '').replace(/^#/, ''),
303
- 10,
304
- );
305
- if (!Number.isInteger(epicId) || epicId <= 0) {
306
- Logger.error('wave-tick: --epic <id> is required (positive integer)');
307
- process.exitCode = 2;
308
- return;
309
- }
310
-
311
- if (values['check-idle'] !== undefined) {
312
- const thresholdMinutes = Number.parseInt(String(values['check-idle']), 10);
313
- if (!Number.isInteger(thresholdMinutes) || thresholdMinutes <= 0) {
314
- Logger.error(
315
- 'wave-tick: --check-idle <minutes> must be a positive integer',
316
- );
317
- process.exitCode = 2;
318
- return;
319
- }
320
- const { envelope, stalledCount } = runCheckIdle({
321
- epicId,
322
- thresholdMinutes,
323
- });
324
- process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
325
- process.exitCode = stalledCount > 0 ? 1 : 0;
326
- return;
327
- }
328
-
329
- const result = await runWaveTickCli({ epicId });
330
- process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
331
- }
332
-
333
- runAsCli(import.meta.url, () => main(process.argv.slice(2)), {
334
- source: 'wave-tick',
335
- });