mandrel 1.58.0 → 1.60.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 (319) hide show
  1. package/.agents/README.md +100 -98
  2. package/.agents/docs/SDLC.md +140 -141
  3. package/.agents/docs/configuration.md +16 -16
  4. package/.agents/docs/workflows.md +7 -8
  5. package/.agents/instructions.md +12 -11
  6. package/.agents/personas/architect.md +1 -1
  7. package/.agents/personas/product.md +1 -1
  8. package/.agents/personas/project-manager.md +14 -14
  9. package/.agents/personas/technical-writer.md +1 -1
  10. package/.agents/rules/changelog-style.md +5 -5
  11. package/.agents/rules/git-conventions.md +3 -3
  12. package/.agents/schemas/agentrc.schema.json +3 -3
  13. package/.agents/schemas/audit-rules.json +20 -0
  14. package/.agents/schemas/dispatch-manifest.json +4 -4
  15. package/.agents/schemas/epic-spec.schema.json +15 -45
  16. package/.agents/schemas/lifecycle/README.md +1 -1
  17. package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +1 -1
  18. package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +1 -1
  20. package/.agents/schemas/validation-evidence.schema.json +1 -1
  21. package/.agents/scripts/README.md +1 -1
  22. package/.agents/scripts/acceptance-eval.js +21 -4
  23. package/.agents/scripts/acceptance-spec-reconciler.js +2 -2
  24. package/.agents/scripts/analyze-execution.js +2 -2
  25. package/.agents/scripts/assert-branch.js +1 -3
  26. package/.agents/scripts/audit-to-stories.js +1 -1
  27. package/.agents/scripts/bootstrap.js +1 -1
  28. package/.agents/scripts/check-arch-cycles.js +360 -0
  29. package/.agents/scripts/check-doc-links.js +2 -3
  30. package/.agents/scripts/coverage-capture.js +24 -3
  31. package/.agents/scripts/diagnose-friction.js +1 -1
  32. package/.agents/scripts/dispatcher.js +2 -2
  33. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  34. package/.agents/scripts/epic-audit-prepare.js +3 -3
  35. package/.agents/scripts/epic-deliver-note-intervention.js +2 -2
  36. package/.agents/scripts/epic-deliver-preflight.js +11 -9
  37. package/.agents/scripts/epic-deliver-prepare.js +13 -5
  38. package/.agents/scripts/epic-execute-record-wave.js +5 -5
  39. package/.agents/scripts/epic-plan-healthcheck.js +6 -10
  40. package/.agents/scripts/epic-plan-spec-validate.js +1 -1
  41. package/.agents/scripts/epic-reconcile.js +11 -29
  42. package/.agents/scripts/evidence-gate.js +2 -2
  43. package/.agents/scripts/generate-workflows-doc.js +1 -1
  44. package/.agents/scripts/git-rebase-and-resolve.js +1 -1
  45. package/.agents/scripts/hierarchy-gate.js +40 -24
  46. package/.agents/scripts/lib/ITicketingProvider.js +1 -1
  47. package/.agents/scripts/lib/audit-suite/selector.js +1 -1
  48. package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +2 -2
  49. package/.agents/scripts/lib/baseline-snapshot.js +7 -7
  50. package/.agents/scripts/lib/baselines/kinds/coverage.js +33 -149
  51. package/.agents/scripts/lib/baselines/kinds/duplication.js +27 -116
  52. package/.agents/scripts/lib/baselines/kinds/kind-factory.js +192 -0
  53. package/.agents/scripts/lib/baselines/kinds/lighthouse.js +34 -133
  54. package/.agents/scripts/lib/baselines/kinds/maintainability.js +31 -124
  55. package/.agents/scripts/lib/baselines/kinds/mutation.js +25 -111
  56. package/.agents/scripts/lib/baselines/maintainability-baseline-io.js +59 -0
  57. package/.agents/scripts/lib/baselines/maintainability-baseline-save.js +37 -0
  58. package/.agents/scripts/lib/baselines/writer.js +1 -1
  59. package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
  60. package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
  61. package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +1 -1
  62. package/.agents/scripts/lib/bootstrap/branch-protection.js +1 -1
  63. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +1 -1
  64. package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
  65. package/.agents/scripts/lib/close-validation/commands.js +188 -0
  66. package/.agents/scripts/lib/close-validation/gates.js +235 -0
  67. package/.agents/scripts/lib/close-validation/process.js +101 -0
  68. package/.agents/scripts/lib/close-validation/projections/maintainability.js +1 -1
  69. package/.agents/scripts/lib/close-validation/runner.js +325 -0
  70. package/.agents/scripts/lib/close-validation/telemetry.js +70 -0
  71. package/.agents/scripts/lib/codebase-snapshot.js +1 -1
  72. package/.agents/scripts/lib/config/explain.js +1 -1
  73. package/.agents/scripts/lib/config/quality.js +6 -6
  74. package/.agents/scripts/lib/config/runners.js +2 -2
  75. package/.agents/scripts/lib/config/runtime.js +1 -1
  76. package/.agents/scripts/lib/config/temp-paths.js +2 -2
  77. package/.agents/scripts/lib/config-resolver.js +2 -5
  78. package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
  79. package/.agents/scripts/lib/config-settings-schema-quality.js +1 -1
  80. package/.agents/scripts/lib/config-settings-schema.js +3 -3
  81. package/.agents/scripts/lib/coverage-capture.js +147 -4
  82. package/.agents/scripts/lib/cpu-pool.js +14 -0
  83. package/.agents/scripts/lib/crap-utils.js +6 -11
  84. package/.agents/scripts/lib/duplicate-search.js +1 -1
  85. package/.agents/scripts/lib/dynamic-workflow/capability.js +1 -1
  86. package/.agents/scripts/lib/dynamic-workflow/documentation-report-contract.js +87 -0
  87. package/.agents/scripts/lib/epic-plan-clarity.js +1 -1
  88. package/.agents/scripts/lib/epic-plan-ideation.js +1 -1
  89. package/.agents/scripts/lib/feedback-loop/memory-freshness.js +1 -1
  90. package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +1 -1
  91. package/.agents/scripts/lib/findings/classify-finding.js +1 -1
  92. package/.agents/scripts/lib/findings/promote-finding.js +10 -10
  93. package/.agents/scripts/lib/git-utils.js +24 -22
  94. package/.agents/scripts/lib/label-constants.js +3 -4
  95. package/.agents/scripts/lib/label-taxonomy.js +3 -8
  96. package/.agents/scripts/lib/maintainability-engine.js +1 -1
  97. package/.agents/scripts/lib/maintainability-utils.js +4 -187
  98. package/.agents/scripts/lib/observability/perf-report-readers.js +32 -23
  99. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +81 -7
  100. package/.agents/scripts/lib/orchestration/code-review.js +95 -82
  101. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +8 -9
  102. package/.agents/scripts/lib/orchestration/dependency-analyzer.js +3 -3
  103. package/.agents/scripts/lib/orchestration/detectors-phase.js +2 -2
  104. package/.agents/scripts/lib/orchestration/dispatch-engine.js +30 -38
  105. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +14 -37
  106. package/.agents/scripts/lib/orchestration/epic-cleanup.js +1 -1
  107. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +22 -22
  108. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +1 -1
  109. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +7 -21
  110. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +3 -3
  111. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +2 -2
  112. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +206 -58
  113. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +1 -1
  114. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +27 -3
  115. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +1 -1
  116. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +28 -8
  117. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +1 -1
  118. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +3 -3
  119. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +4 -4
  120. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +3 -3
  121. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +13 -41
  122. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +7 -7
  123. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +2 -3
  124. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +2 -8
  125. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +4 -4
  126. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +103 -0
  127. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +22 -64
  128. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +38 -76
  129. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +4 -4
  130. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +10 -10
  131. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +8 -20
  132. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +7 -15
  133. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +72 -41
  134. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +2 -4
  135. package/.agents/scripts/lib/orchestration/file-assumptions.js +6 -5
  136. package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +1 -1
  137. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +2 -2
  138. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +1 -1
  139. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +144 -0
  140. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +1 -1
  141. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +3 -3
  142. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +1 -1
  143. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +1 -1
  144. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +1 -1
  145. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +1 -1
  146. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +1 -1
  147. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
  148. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +1 -1
  149. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +1 -1
  150. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +8 -8
  151. package/.agents/scripts/lib/orchestration/manifest-builder.js +5 -5
  152. package/.agents/scripts/lib/orchestration/parked-follow-ons.js +2 -2
  153. package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +5 -5
  154. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +3 -3
  155. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +3 -3
  156. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +7 -7
  157. package/.agents/scripts/lib/orchestration/preflight-cache.js +36 -13
  158. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +1 -1
  159. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +1 -1
  160. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +2 -2
  161. package/.agents/scripts/lib/orchestration/retro-runner.js +3 -3
  162. package/.agents/scripts/lib/orchestration/review-depth.js +1 -1
  163. package/.agents/scripts/lib/orchestration/review-providers/codex.js +5 -60
  164. package/.agents/scripts/lib/orchestration/review-providers/native.js +7 -6
  165. package/.agents/scripts/lib/orchestration/review-providers/parse-findings.js +105 -0
  166. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +7 -59
  167. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +2 -4
  168. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +1 -1
  169. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +1 -1
  170. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +2 -4
  171. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +32 -35
  172. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +1 -2
  173. package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
  174. package/.agents/scripts/lib/orchestration/spec-renderer.js +36 -73
  175. package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
  176. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +451 -503
  177. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +8 -2
  178. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +47 -2
  179. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +2 -2
  180. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +1 -1
  181. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +358 -54
  182. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +1 -1
  183. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +3 -2
  184. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +32 -5
  185. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +5 -18
  186. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +3 -3
  187. package/.agents/scripts/lib/orchestration/story-close-recovery.js +33 -16
  188. package/.agents/scripts/lib/orchestration/story-reachability.js +47 -0
  189. package/.agents/scripts/lib/orchestration/task-body-validator.js +6 -6
  190. package/.agents/scripts/lib/orchestration/ticket-lease.js +1 -1
  191. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +4 -35
  192. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -10
  193. package/.agents/scripts/lib/orchestration/ticket-validator.js +25 -70
  194. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +44 -73
  195. package/.agents/scripts/lib/orchestration/ticketing/reads.js +16 -7
  196. package/.agents/scripts/lib/orchestration/ticketing/state.js +53 -439
  197. package/.agents/scripts/lib/orchestration/ticketing/transition.js +471 -0
  198. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  199. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +3 -3
  200. package/.agents/scripts/lib/orchestration/wave-record-projection.js +2 -8
  201. package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
  202. package/.agents/scripts/lib/preflight-runner.js +1 -1
  203. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +4 -5
  204. package/.agents/scripts/lib/presentation/manifest-builder.js +28 -34
  205. package/.agents/scripts/lib/presentation/manifest-formatter.js +3 -4
  206. package/.agents/scripts/lib/presentation/manifest-helpers.js +1 -1
  207. package/.agents/scripts/lib/presentation/manifest-procedures.js +4 -4
  208. package/.agents/scripts/lib/presentation/manifest-render-waves.js +4 -23
  209. package/.agents/scripts/lib/presentation/manifest-renderer.js +1 -1
  210. package/.agents/scripts/lib/presentation/manifest-story-views.js +2 -11
  211. package/.agents/scripts/lib/project-root.js +17 -0
  212. package/.agents/scripts/lib/signals/schema.js +1 -1
  213. package/.agents/scripts/lib/spec/index.js +1 -1
  214. package/.agents/scripts/lib/spec/loader.js +2 -2
  215. package/.agents/scripts/lib/spec/state.js +7 -16
  216. package/.agents/scripts/lib/story-adjacency.js +76 -0
  217. package/.agents/scripts/lib/story-init/context-resolver.js +3 -3
  218. package/.agents/scripts/lib/story-init/state-transitioner.js +2 -2
  219. package/.agents/scripts/lib/story-init/task-graph-builder.js +7 -7
  220. package/.agents/scripts/lib/story-lifecycle.js +9 -9
  221. package/.agents/scripts/lib/story-plan.js +1 -1
  222. package/.agents/scripts/lib/templates/decomposer-prompts.js +59 -52
  223. package/.agents/scripts/lib/transpile.js +93 -0
  224. package/.agents/scripts/lib/wave-runner/tick.js +4 -153
  225. package/.agents/scripts/lib/workers/crap-worker.js +1 -1
  226. package/.agents/scripts/lib/workers/maintainability-report-worker.js +1 -1
  227. package/.agents/scripts/lib/worktree/lifecycle/creation.js +20 -2
  228. package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +90 -0
  229. package/.agents/scripts/lib/worktree/lifecycle/reap.js +26 -8
  230. package/.agents/scripts/lib/worktree/node-modules-strategy.js +74 -0
  231. package/.agents/scripts/lifecycle-emit-story-dispatch.js +1 -1
  232. package/.agents/scripts/lifecycle-emit.js +1 -1
  233. package/.agents/scripts/providers/github/board-add.js +1 -1
  234. package/.agents/scripts/providers/github/errors.js +1 -1
  235. package/.agents/scripts/providers/github/mappers.js +2 -2
  236. package/.agents/scripts/providers/github/tickets.js +114 -10
  237. package/.agents/scripts/resync-status-column.js +1 -1
  238. package/.agents/scripts/retro-run.js +2 -2
  239. package/.agents/scripts/run-lint.js +10 -1
  240. package/.agents/scripts/run-tests.js +24 -4
  241. package/.agents/scripts/single-story-init.js +1 -1
  242. package/.agents/scripts/stories-wave-tick.js +13 -10
  243. package/.agents/scripts/story-close.js +1 -1
  244. package/.agents/scripts/story-init.js +162 -26
  245. package/.agents/scripts/story-phase.js +5 -5
  246. package/.agents/scripts/story-plan.js +3 -3
  247. package/.agents/scripts/sync-branch-from-base.js +2 -2
  248. package/.agents/scripts/validate-docs-freshness.js +1 -1
  249. package/.agents/scripts/wave-tick.js +1 -1
  250. package/.agents/skills/core/analyze-execution/SKILL.md +2 -2
  251. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +21 -26
  252. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +23 -56
  253. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +4 -4
  254. package/.agents/skills/core/hydrate-context/SKILL.md +2 -2
  255. package/.agents/skills/core/idea-refinement/SKILL.md +4 -4
  256. package/.agents/skills/core/knowledge-transfer/SKILL.md +2 -2
  257. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +1 -1
  258. package/.agents/skills/core/scope-triage/SKILL.md +9 -10
  259. package/.agents/skills/core/using-agent-skills/SKILL.md +1 -1
  260. package/.agents/skills/skills.index.json +7 -7
  261. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +1 -1
  262. package/.agents/templates/agent-protocol.md +2 -2
  263. package/.agents/workflows/agents-update.md +2 -2
  264. package/.agents/workflows/audit-architecture.md +2 -2
  265. package/.agents/workflows/audit-clean-code.md +2 -2
  266. package/.agents/workflows/audit-dependencies.md +1 -1
  267. package/.agents/workflows/audit-devops.md +1 -1
  268. package/.agents/workflows/audit-documentation.md +226 -0
  269. package/.agents/workflows/audit-lighthouse.md +1 -1
  270. package/.agents/workflows/audit-performance.md +2 -2
  271. package/.agents/workflows/audit-privacy.md +1 -1
  272. package/.agents/workflows/audit-quality.md +2 -2
  273. package/.agents/workflows/audit-security.md +2 -2
  274. package/.agents/workflows/audit-seo.md +1 -1
  275. package/.agents/workflows/audit-sre.md +1 -1
  276. package/.agents/workflows/audit-to-stories.md +10 -10
  277. package/.agents/workflows/audit-ux-ui.md +1 -1
  278. package/.agents/workflows/deliver.md +85 -0
  279. package/.agents/workflows/explain.md +3 -3
  280. package/.agents/workflows/git-merge-pr.md +1 -1
  281. package/.agents/workflows/git-pr-all.md +13 -10
  282. package/.agents/workflows/git-push.md +6 -3
  283. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  284. package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
  285. package/.agents/workflows/helpers/code-review.md +5 -5
  286. package/.agents/workflows/{epic-deliver.md → helpers/deliver-epic.md} +59 -66
  287. package/.agents/workflows/{story-deliver.md → helpers/deliver-stories.md} +25 -25
  288. package/.agents/workflows/helpers/diagnose.md +1 -1
  289. package/.agents/workflows/helpers/epic-audit.md +6 -6
  290. package/.agents/workflows/helpers/epic-deliver-story.md +28 -39
  291. package/.agents/workflows/helpers/epic-plan-decompose.md +23 -23
  292. package/.agents/workflows/helpers/epic-plan-spec.md +6 -6
  293. package/.agents/workflows/helpers/epic-testing.md +3 -3
  294. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  295. package/.agents/workflows/{epic-plan.md → helpers/plan-epic.md} +84 -84
  296. package/.agents/workflows/{story-plan.md → helpers/plan-story.md} +43 -43
  297. package/.agents/workflows/helpers/signals.md +1 -1
  298. package/.agents/workflows/helpers/single-story-deliver.md +12 -11
  299. package/.agents/workflows/helpers/worktree-lifecycle.md +18 -18
  300. package/.agents/workflows/onboard.md +21 -20
  301. package/.agents/workflows/plan.md +89 -0
  302. package/.agents/workflows/qa-explore.md +1 -1
  303. package/.agents/workflows/qa-run-harness.md +1 -1
  304. package/README.md +17 -20
  305. package/docs/CHANGELOG.md +1149 -0
  306. package/lib/cli/__tests__/update-changelog-surface.test.js +357 -0
  307. package/lib/cli/__tests__/update-reexec.test.js +513 -0
  308. package/lib/cli/init.js +338 -0
  309. package/lib/cli/update.js +413 -52
  310. package/package.json +3 -1
  311. package/.agents/scripts/lib/auto-refresh-baselines.js +0 -308
  312. package/.agents/scripts/lib/close-validation.js +0 -897
  313. package/.agents/scripts/lib/orchestration/cascade-grouping.js +0 -275
  314. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter.js +0 -69
  315. package/.agents/scripts/lib/orchestration/reconciler.js +0 -137
  316. package/.agents/scripts/lib/orchestration/story-close/format-autofix-scoped.js +0 -221
  317. package/.agents/scripts/lib/orchestration/story-close/format-autofix-shared.js +0 -123
  318. package/.agents/scripts/lib/task-utils.js +0 -26
  319. package/.agents/scripts/story-deliver-prepare.js +0 -267
@@ -1,221 +0,0 @@
1
- /**
2
- * format-autofix-scoped.js — Story #2533: scoped biome-format auto-apply
3
- * inside story-close's pre-merge gate chain.
4
- *
5
- * Background. The whole-tree `runFormatAutofix` (sibling module) heals
6
- * drift across `.` before the gate chain runs. That step is intentionally
7
- * broad because it covers files (JSON / YAML / config) that lint-staged
8
- * does not glob. This module is the narrower companion: it scopes
9
- * `biome format --write` to the **changed-file set** between the Epic
10
- * branch and the Story branch and folds any auto-fixed paths into a
11
- * dedicated commit on the Story branch *before* `biome ci` runs in the
12
- * gate chain.
13
- *
14
- * Why scoped + warn-level. The Tech Spec (Epic #2527, Story 5) calls out
15
- * that format diffs introduced by Story commits should never surface to
16
- * Phase 3 close-validation. The whole-tree autofix already covers that,
17
- * but emits `info` so operators routinely miss it. This module emits
18
- * `Logger.warn` naming the auto-fixed files so the signal is visible in
19
- * the close transcript and downstream ledger.
20
- *
21
- * Dependencies are injected so unit tests pin behaviour without spawning
22
- * git or biome.
23
- */
24
-
25
- import { execFileSync } from 'node:child_process';
26
-
27
- import { diffNameOnly } from '../../changed-files.js';
28
- import { Logger as DefaultLogger } from '../../Logger.js';
29
- import {
30
- commitDirtyPaths,
31
- currentBranch,
32
- listDirtyPaths,
33
- resolveFormatterCmd,
34
- } from './format-autofix-shared.js';
35
-
36
- const TAG = '[format-autofix-scoped]';
37
-
38
- /**
39
- * List the files changed between `epicBranch` and `storyBranch` using the
40
- * three-dot merge-base diff. Delegates parsing to `diffNameOnly` from
41
- * `changed-files.js` so the stdout → path-list conversion lives in one place.
42
- *
43
- * The `git` parameter uses the caller's local interface:
44
- * `(args: string[], opts: object) => string`. A bridge adapter wraps it into
45
- * the `gitSpawn(cwd, ...args)` shape that `diffNameOnly` expects.
46
- *
47
- * @param {{ cwd: string, epicBranch: string, storyBranch: string, git: Function }} opts
48
- * @returns {string[]}
49
- */
50
- function listChangedFiles({ cwd, epicBranch, storyBranch, git }) {
51
- // Bridge the (args, opts) → string interface into gitSpawn(cwd, ...args).
52
- const gitSpawn = (_cwd, ...args) => {
53
- try {
54
- const stdout = git(args, {
55
- cwd: _cwd,
56
- encoding: 'utf8',
57
- stdio: ['ignore', 'pipe', 'ignore'],
58
- });
59
- return { status: 0, stdout: stdout ?? '', stderr: '' };
60
- } catch (err) {
61
- return {
62
- status: err.status ?? 1,
63
- stdout: err.stdout ?? '',
64
- stderr: err.stderr ?? err.message,
65
- };
66
- }
67
- };
68
- return diffNameOnly({
69
- range: `${epicBranch}...${storyBranch}`,
70
- cwd,
71
- gitSpawn,
72
- });
73
- }
74
-
75
- /**
76
- * Run `biome format --write <changedFiles>` on the Epic→Story diff. If
77
- * any file is modified, stage and commit the changes on the Story branch
78
- * with a conventional `fix(story-close):` subject and emit a
79
- * `Logger.warn` naming the auto-fixed files. Returns a structured
80
- * envelope so callers can log a single line.
81
- *
82
- * No-op envelopes:
83
- * - `{ ran: false, reason: 'no-changed-files' }` — empty diff.
84
- * - `{ ran: false, reason: 'dirty-tree' }` — refused to
85
- * absorb pre-existing edits.
86
- * - `{ ran: true, committed: false }` — formatter
87
- * was clean.
88
- *
89
- * **Worktree scope (Story #3907).** All git + formatter operations run in
90
- * `worktreePath` (the Story worktree where `story-<id>` is checked out), not
91
- * `cwd` (the main checkout). The earlier implementation ran every step
92
- * against `cwd`, so the `git add -u` + `git commit` could land an unreviewed
93
- * `fix(story-close):` commit on whatever branch the main checkout happened to
94
- * have out — including `main`. Before committing, the worktree's checked-out
95
- * branch is asserted to equal `storyBranch`; a mismatch refuses to commit and
96
- * returns `{ ran: true, committed: false, reason: 'wrong-branch' }` so a
97
- * stale-state checkout can never absorb the autofix into the wrong history.
98
- * `worktreePath` defaults to `cwd` for the resume/legacy callers that have no
99
- * separate worktree.
100
- *
101
- * @param {{
102
- * cwd: string,
103
- * worktreePath?: string,
104
- * storyId: number|string,
105
- * epicBranch: string,
106
- * storyBranch: string,
107
- * config?: object,
108
- * logger?: object,
109
- * spawnSync?: typeof execFileSync,
110
- * gitSync?: (args: string[], opts: object) => string,
111
- * }} opts
112
- * @returns {{
113
- * ran: boolean,
114
- * committed: boolean,
115
- * sha?: string,
116
- * modifiedPaths?: string[],
117
- * reason?: string,
118
- * }}
119
- */
120
- export function runScopedFormatAutofix({
121
- cwd,
122
- worktreePath,
123
- storyId,
124
- epicBranch,
125
- storyBranch,
126
- config,
127
- logger = DefaultLogger,
128
- spawnSync = execFileSync,
129
- gitSync,
130
- } = {}) {
131
- if (!cwd) throw new Error('runScopedFormatAutofix: cwd is required');
132
- if (!epicBranch)
133
- throw new Error('runScopedFormatAutofix: epicBranch is required');
134
- if (!storyBranch)
135
- throw new Error('runScopedFormatAutofix: storyBranch is required');
136
-
137
- // Story #3907 — the formatter writes + the commit must land in the Story
138
- // worktree, never the main checkout. Fall back to `cwd` only for callers
139
- // that do not run under worktree isolation.
140
- const workTree = worktreePath || cwd;
141
-
142
- const git = gitSync ?? ((args, opts) => spawnSync('git', args, opts));
143
-
144
- // Resolve the formatter base command (e.g. `npx biome format --write`).
145
- // We drop a trailing `.` so we can append the changed-file set explicitly.
146
- const { writeCmdString, writeCmd, writeArgs } = resolveFormatterCmd({
147
- commands: config?.project?.commands,
148
- dropTrailingDot: true,
149
- });
150
-
151
- const changed = listChangedFiles({
152
- cwd: workTree,
153
- epicBranch,
154
- storyBranch,
155
- git,
156
- });
157
- if (changed.length === 0) {
158
- logger.info?.(
159
- `${TAG} skipped — no changed files between ${epicBranch} and ${storyBranch}.`,
160
- );
161
- return { ran: false, committed: false, reason: 'no-changed-files' };
162
- }
163
-
164
- const dirtyBefore = listDirtyPaths(workTree, git);
165
- if (dirtyBefore.length) {
166
- logger.info?.(
167
- `${TAG} skipped — working tree dirty before scoped autofix (${dirtyBefore.length} paths).`,
168
- );
169
- return { ran: false, committed: false, reason: 'dirty-tree' };
170
- }
171
-
172
- // Run the formatter against the changed-file set. We tolerate non-zero
173
- // exit because the downstream check gate is the source of truth for
174
- // "did formatting succeed".
175
- try {
176
- spawnSync(writeCmd, [...writeArgs, ...changed], {
177
- cwd: workTree,
178
- stdio: ['ignore', 'pipe', 'pipe'],
179
- encoding: 'utf8',
180
- });
181
- } catch (err) {
182
- logger.warn?.(
183
- `${TAG} \`${writeCmdString}\` on ${changed.length} changed file(s) exited non-zero (${err?.status ?? 'unknown'}); falling through to the format check gate.`,
184
- );
185
- }
186
-
187
- const dirtyAfter = listDirtyPaths(workTree, git);
188
- if (!dirtyAfter.length) {
189
- logger.info?.(
190
- `${TAG} no format drift on ${changed.length} changed file(s).`,
191
- );
192
- return { ran: true, committed: false };
193
- }
194
-
195
- // Story #3907 — assert the worktree is actually on `storyBranch` before we
196
- // stage + commit. Without this guard a stale-state checkout (or a
197
- // mis-wired `cwd`) could absorb the autofix onto the wrong branch (incl.
198
- // `main`). A mismatch refuses to commit and leaves the format drift for the
199
- // downstream check gate to surface.
200
- const onBranch = currentBranch(workTree, git);
201
- if (onBranch !== storyBranch) {
202
- logger.warn?.(
203
- `${TAG} refusing to commit — worktree ${workTree} is on "${onBranch ?? 'unknown'}", expected "${storyBranch}". ` +
204
- `${dirtyAfter.length} format-drift path(s) left for the check gate.`,
205
- );
206
- return { ran: true, committed: false, reason: 'wrong-branch' };
207
- }
208
-
209
- // Stage every modified path and commit. Hooks must run; do not pass
210
- // --no-verify (project policy: never skip git hooks).
211
- const subject = `fix(story-close): auto-apply biome format in scoped lint (story #${storyId})`;
212
- const sha = commitDirtyPaths({ cwd: workTree, git, subject });
213
-
214
- // The warn-level emission is the Tech Spec contract — operators read
215
- // this line in the close transcript to know auto-fix landed in the
216
- // close commit, and downstream ledger inspectors filter on it.
217
- logger.warn?.(
218
- `${TAG} auto-applied biome format to ${dirtyAfter.length} path(s) on story #${storyId}: ${dirtyAfter.join(', ')}; committed as ${sha}.`,
219
- );
220
- return { ran: true, committed: true, sha, modifiedPaths: dirtyAfter };
221
- }
@@ -1,123 +0,0 @@
1
- /**
2
- * format-autofix-shared.js — Story #3332 (Epic #3316): single-source the
3
- * git/formatter plumbing shared by the two format-autofix forks.
4
- *
5
- * `format-autofix.js` (whole-tree heal) and `format-autofix-scoped.js`
6
- * (Epic→Story changed-file heal) historically each carried their own copy
7
- * of the porcelain-status parse, the formatter-command resolution, and the
8
- * stage→commit→rev-parse sequence. The three forked helpers are
9
- * byte-for-byte equivalent apart from cosmetics, so a fix to (say) the
10
- * porcelain-line slice had to land twice. This module is the single home
11
- * for all three; the two forks now differ only in file-scope, commit
12
- * subject, and log level.
13
- *
14
- * Every helper takes an injected `git` runner (`(args, opts) => string`) so
15
- * unit tests pin behaviour without spawning git.
16
- */
17
-
18
- import { resolveFormatWriteCommand } from '../../close-validation.js';
19
-
20
- /**
21
- * Run `git status --porcelain` and return the list of changed paths.
22
- *
23
- * Porcelain lines are `XY <path>` — exactly two status chars, one space,
24
- * then the path. Leading whitespace inside the status pair is significant
25
- * (e.g. ` M file` for unstaged-modified) so we slice a fixed 3 chars off
26
- * the front rather than trimming.
27
- *
28
- * @param {string} cwd
29
- * @param {(args: string[], opts: object) => string} git
30
- * @returns {string[]}
31
- */
32
- export function listDirtyPaths(cwd, git) {
33
- const out = git(['status', '--porcelain'], {
34
- cwd,
35
- encoding: 'utf8',
36
- stdio: ['ignore', 'pipe', 'ignore'],
37
- });
38
- return out
39
- .split('\n')
40
- .filter((line) => line.length >= 4)
41
- .map((line) => line.slice(3));
42
- }
43
-
44
- /**
45
- * Resolve the formatter write command from `project.commands.formatWrite`
46
- * (falling back to the historical `npx biome format --write .`) and split
47
- * it into an executable + argv pair ready for `execFileSync`.
48
- *
49
- * The whole-tree fork runs the command verbatim (keeping the trailing `.`
50
- * so biome formats the entire tree). The scoped fork appends an explicit
51
- * changed-file set, so it passes `dropTrailingDot: true` to strip the `.`
52
- * before its file list.
53
- *
54
- * @param {{
55
- * commands?: object,
56
- * dropTrailingDot?: boolean,
57
- * }} [opts]
58
- * @returns {{ writeCmdString: string, writeCmd: string, writeArgs: string[] }}
59
- */
60
- export function resolveFormatterCmd({
61
- commands,
62
- dropTrailingDot = false,
63
- } = {}) {
64
- // `resolveFormatWriteCommand` reads `config.project.commands`; wrap the
65
- // caller-supplied `commands` map into that canonical shape.
66
- const writeCmdString = resolveFormatWriteCommand({ project: { commands } });
67
- const parts = writeCmdString.split(/\s+/).filter(Boolean);
68
- if (dropTrailingDot && parts[parts.length - 1] === '.') parts.pop();
69
- const [writeCmd, ...writeArgs] = parts;
70
- return { writeCmdString, writeCmd, writeArgs };
71
- }
72
-
73
- /**
74
- * Resolve the branch currently checked out at `cwd` via
75
- * `git rev-parse --abbrev-ref HEAD`. Returns the trimmed branch name, or
76
- * `null` when the call fails or the tree is in a detached-HEAD state
77
- * (`HEAD`). Used as the commit-target guard before
78
- * {@link commitDirtyPaths} writes a scoped-autofix commit, so the commit
79
- * can never land on the wrong branch (e.g. the main checkout's `main`).
80
- *
81
- * @param {string} cwd
82
- * @param {(args: string[], opts: object) => string} git
83
- * @returns {string|null}
84
- */
85
- export function currentBranch(cwd, git) {
86
- try {
87
- const out = git(['rev-parse', '--abbrev-ref', 'HEAD'], {
88
- cwd,
89
- encoding: 'utf8',
90
- stdio: ['ignore', 'pipe', 'ignore'],
91
- });
92
- const branch = (out ?? '').toString().trim();
93
- if (!branch || branch === 'HEAD') return null;
94
- return branch;
95
- } catch {
96
- return null;
97
- }
98
- }
99
-
100
- /**
101
- * Stage every modified path (`git add -u`), commit with the caller-supplied
102
- * `subject`, and return the short HEAD SHA. Hooks must run; we never pass
103
- * `--no-verify` (project policy: never skip git hooks).
104
- *
105
- * @param {{
106
- * cwd: string,
107
- * git: (args: string[], opts: object) => string,
108
- * subject: string,
109
- * }} opts
110
- * @returns {string} short HEAD SHA of the new commit
111
- */
112
- export function commitDirtyPaths({ cwd, git, subject }) {
113
- git(['add', '-u'], { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
114
- git(['commit', '-m', subject], {
115
- cwd,
116
- stdio: ['ignore', 'pipe', 'pipe'],
117
- });
118
- return git(['rev-parse', '--short', 'HEAD'], {
119
- cwd,
120
- encoding: 'utf8',
121
- stdio: ['ignore', 'pipe', 'ignore'],
122
- }).trim();
123
- }
@@ -1,26 +0,0 @@
1
- /**
2
- * task-utils.js
3
- *
4
- * Shared utilities for inspecting task objects throughout the pipeline.
5
- * Centralises the bookend-detection predicate so that any future addition of a
6
- * new bookend type only requires a change in one place.
7
- */
8
-
9
- /**
10
- * Returns true when the given task is a bookend (lifecycle-management) task.
11
- *
12
- * Bookend tasks are distinguished from regular development tasks by one of the
13
- * following flags being truthy:
14
- * - isQA — automated testing phase
15
- * - isCodeReview — architectural review phase
16
- * - isRetro — retrospective phase
17
- * - isCloseSprint — sprint close-out + tagging phase
18
- *
19
- * @param {object} task - A task object from the sprint manifest.
20
- * @returns {boolean}
21
- */
22
- export function isBookendTask(task) {
23
- return Boolean(
24
- task.isQA || task.isCodeReview || task.isRetro || task.isCloseSprint,
25
- );
26
- }
@@ -1,267 +0,0 @@
1
- #!/usr/bin/env node
2
- /* node:coverage ignore file */
3
-
4
- /**
5
- * story-deliver-prepare.js — post-init / pre-implementation prep step.
6
- *
7
- * After `story-init.js` has prepared the worktree and the operator (or
8
- * sub-agent) has `cd`'d into the workCwd, this CLI consolidates the three
9
- * things `/story-deliver` Step 0.5/0.6 used to express in English prose:
10
- *
11
- * 1. Read the `story-init` structured comment off the Story ticket via
12
- * `findStructuredComment`. The comment carries `workCwd`, the install
13
- * tri-state, and the canonical task list — re-derived here so a
14
- * resumed run doesn't have to retain `story-init` stdout.
15
- *
16
- * 2. Apply the `dependenciesInstalled` tri-state truth table:
17
- * - `'true'` → install already succeeded; skip.
18
- * - `'false'` → install was attempted and failed; run the install
19
- * command (default `npm ci`; `project.commands`
20
- * doesn't carry a dedicated `install` key today —
21
- * the `commands.test` adjacency is the spec hook for
22
- * a future override).
23
- * - `'skipped'` → no per-worktree install was performed (single-tree
24
- * or symlink/pnpm-store strategy); trust the strategy.
25
- *
26
- * 3. Render the initial Story-phase snapshot with every Story phase
27
- * (init/implement/validate/close) pinned to `pending` and
28
- * `phase: 'init'` via `upsertStoryRunProgress`. Story #3909 — this is
29
- * render-only: no `story-run-progress` comment is posted (that redundant
30
- * mid-flight surface was deleted).
31
- *
32
- * Stdout: a single JSON envelope `{ workCwd, dependenciesInstalled,
33
- * installAction, snapshot, renderedBody }` so the caller can decide what to
34
- * do next. `renderedBody` is the markdown body for the initial Story-phase
35
- * table — `/story-deliver` relays it as a chat message at the start of each
36
- * Story so operators see it before the first commit lands.
37
- */
38
-
39
- import { parseArgs } from 'node:util';
40
-
41
- import { runAsCli } from './lib/cli-utils.js';
42
- import { resolveConfig } from './lib/config-resolver.js';
43
- import { runInstallCommand } from './lib/install-cmd-parser.js';
44
- import {
45
- defaultStoryPhases,
46
- STORY_RUN_PROGRESS_TYPE,
47
- upsertStoryRunProgress,
48
- } from './lib/orchestration/epic-runner/story-run-progress-writer.js';
49
- import { parseFencedJsonComment } from './lib/orchestration/structured-comment-parser.js';
50
- import { findStructuredComment } from './lib/orchestration/ticketing.js';
51
- import { createProvider } from './lib/provider-factory.js';
52
- import { notify } from './notify.js';
53
-
54
- const HELP = `Usage: node .agents/scripts/story-deliver-prepare.js \\
55
- --story <id> [--cwd <workCwd>] [--skip-install] [--install-cmd "<cmd>"]
56
-
57
- Reads the story-init structured comment off Story #<id>, runs the install
58
- command when dependenciesInstalled === 'false', then renders the initial
59
- Story-phase snapshot (phase=init, every Story phase pending) for chat relay.
60
- No story-run-progress comment is posted (Story #3909).
61
- `;
62
-
63
- const VALID_INSTALLED_STATES = new Set(['true', 'false', 'skipped']);
64
-
65
- /**
66
- * Apply the dependenciesInstalled tri-state to derive the next install action.
67
- * Pure helper — exposes the Step 0.5 truth table as data so tests can pin
68
- * each branch without spinning up a child process.
69
- *
70
- * @param {'true' | 'false' | 'skipped'} dependenciesInstalled
71
- * @param {{ skipInstall?: boolean }} [options]
72
- * @returns {'skip' | 'install'}
73
- */
74
- export function deriveInstallAction(dependenciesInstalled, options = {}) {
75
- if (!VALID_INSTALLED_STATES.has(dependenciesInstalled)) {
76
- throw new RangeError(
77
- `deriveInstallAction: dependenciesInstalled "${dependenciesInstalled}" must be one of: ${[...VALID_INSTALLED_STATES].join(', ')}`,
78
- );
79
- }
80
- if (options.skipInstall) return 'skip';
81
- return dependenciesInstalled === 'false' ? 'install' : 'skip';
82
- }
83
-
84
- /**
85
- * Resolve the install command to run when `dependenciesInstalled === 'false'`.
86
- * `project.commands` does not currently carry a dedicated install key,
87
- * so this defaults to `npm ci`. Operators can override per-invocation via
88
- * `--install-cmd` (mirrors the spec note about a `commands.test`-adjacent
89
- * future override).
90
- *
91
- * @param {{ override?: string }} [options]
92
- * @returns {string}
93
- */
94
- export function resolveInstallCommand(options = {}) {
95
- const trimmed = options.override?.trim();
96
- if (trimmed) {
97
- return trimmed;
98
- }
99
- return 'npm ci';
100
- }
101
-
102
- /**
103
- * Hydrate the `story-init` payload off the Story ticket. Returns `null` when
104
- * the comment can't be located (the operator must run `story-init` first).
105
- *
106
- * @param {{ provider: object, storyId: number }} args
107
- * @returns {Promise<object | null>}
108
- */
109
- export async function readStoryInitComment({ provider, storyId }) {
110
- const comment = await findStructuredComment(provider, storyId, 'story-init');
111
- if (!comment) return null;
112
- const payload = parseFencedJsonComment(comment);
113
- if (!payload || typeof payload !== 'object') return null;
114
- return payload;
115
- }
116
-
117
- /**
118
- * End-to-end prepare. DI-friendly: tests pass `provider`, `runner`, and
119
- * skip the real network/child-process side effects.
120
- *
121
- * @param {{
122
- * storyId: number,
123
- * cwd?: string,
124
- * skipInstall?: boolean,
125
- * installCmd?: string,
126
- * provider?: object,
127
- * runInstall?: (cmd: string, cwd: string) => { status: number, stderr?: string },
128
- * }} args
129
- * @returns {Promise<{
130
- * storyId: number,
131
- * workCwd: string,
132
- * dependenciesInstalled: string,
133
- * installAction: 'skip' | 'install',
134
- * installCmd: string | null,
135
- * installResult: { status: number, stderr?: string } | null,
136
- * snapshot: object,
137
- * renderedBody: string,
138
- * }>}
139
- */
140
- export async function runStoryDeliverPrepare(args) {
141
- const {
142
- storyId,
143
- cwd: cwdOverride,
144
- skipInstall = false,
145
- installCmd: installCmdOverride,
146
- provider: providerOverride,
147
- runInstall: runInstallOverride,
148
- } = args ?? {};
149
-
150
- if (!Number.isInteger(storyId) || storyId <= 0) {
151
- throw new TypeError(
152
- 'runStoryDeliverPrepare: --story must be a positive integer',
153
- );
154
- }
155
-
156
- const config = providerOverride ? null : resolveConfig();
157
- const provider = providerOverride ?? createProvider(config);
158
- const notifyFn = providerOverride
159
- ? null
160
- : (ticketId, payload, opts = {}) =>
161
- notify(ticketId, payload, {
162
- config,
163
- provider,
164
- ...opts,
165
- });
166
-
167
- // 1. Hydrate the story-init payload off the Story ticket.
168
- const initPayload = await readStoryInitComment({ provider, storyId });
169
- if (!initPayload) {
170
- throw new Error(
171
- `runStoryDeliverPrepare: no story-init comment found on #${storyId}; ` +
172
- `run \`node .agents/scripts/story-init.js --story ${storyId}\` first.`,
173
- );
174
- }
175
- const dependenciesInstalled = String(
176
- initPayload.dependenciesInstalled ?? 'skipped',
177
- );
178
- const workCwd = String(initPayload.workCwd ?? cwdOverride ?? process.cwd());
179
-
180
- // 2. Apply the install tri-state.
181
- const installAction = deriveInstallAction(dependenciesInstalled, {
182
- skipInstall,
183
- });
184
- let installCmd = null;
185
- let installResult = null;
186
- if (installAction === 'install') {
187
- installCmd = resolveInstallCommand({ override: installCmdOverride });
188
- installResult = (runInstallOverride ?? runInstallCommand)(
189
- installCmd,
190
- workCwd,
191
- );
192
- if (installResult.status !== 0) {
193
- throw new Error(
194
- `runStoryDeliverPrepare: install command \`${installCmd}\` failed with status ${installResult.status}: ${installResult.stderr ?? ''}`,
195
- );
196
- }
197
- }
198
-
199
- // 3. Render the initial Story-phase snapshot (render-only; Story #3909
200
- // deleted the redundant story-run-progress comment).
201
- //
202
- // Under the 3-tier hierarchy (Epic → Feature → Story) the
203
- // inline-acceptance Story is the only ticket shape: Stories have no
204
- // child Tasks, so the snapshot is always the Story-phase `phases[]`
205
- // shape (init/implement/validate/close pinned to `pending`).
206
- const hierarchy = String(initPayload.hierarchy ?? '3-tier');
207
- const branch = String(initPayload.storyBranch ?? `story-${storyId}`);
208
-
209
- const phases = defaultStoryPhases();
210
- const { body: renderedBody, payload: snapshot } =
211
- await upsertStoryRunProgress({
212
- provider,
213
- storyId,
214
- branch,
215
- phase: 'init',
216
- phases,
217
- notify: notifyFn,
218
- });
219
-
220
- return {
221
- storyId,
222
- workCwd,
223
- dependenciesInstalled,
224
- installAction,
225
- installCmd,
226
- installResult,
227
- hierarchy,
228
- snapshot,
229
- renderedBody,
230
- };
231
- }
232
-
233
- export function parseArgv(argv) {
234
- const { values } = parseArgs({
235
- args: argv,
236
- options: {
237
- story: { type: 'string' },
238
- cwd: { type: 'string' },
239
- 'skip-install': { type: 'boolean' },
240
- 'install-cmd': { type: 'string' },
241
- help: { type: 'boolean' },
242
- },
243
- strict: false,
244
- });
245
- return {
246
- help: Boolean(values.help),
247
- storyId: Number.parseInt(values.story ?? '', 10),
248
- cwd: values.cwd,
249
- skipInstall: Boolean(values['skip-install']),
250
- installCmd: values['install-cmd'],
251
- };
252
- }
253
-
254
- export async function main(argv = process.argv.slice(2)) {
255
- const parsed = parseArgv(argv);
256
- if (parsed.help) {
257
- process.stdout.write(HELP);
258
- return;
259
- }
260
- const envelope = await runStoryDeliverPrepare(parsed);
261
- process.stdout.write(`${JSON.stringify(envelope, null, 2)}\n`);
262
- }
263
-
264
- // Re-export for symmetry with the other prepare-suite CLIs.
265
- export { STORY_RUN_PROGRESS_TYPE };
266
-
267
- runAsCli(import.meta.url, main, { source: 'story-deliver-prepare' });