mandrel 1.94.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 (393) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/story-worker.md +12 -13
  3. package/.agents/docs/SDLC.md +489 -1285
  4. package/.agents/docs/agentrc-reference.json +177 -67
  5. package/.agents/docs/configuration.md +104 -138
  6. package/.agents/docs/execution-reference.md +17 -20
  7. package/.agents/docs/quality-gates.md +13 -19
  8. package/.agents/docs/workflows.md +3 -3
  9. package/.agents/instructions.md +70 -81
  10. package/.agents/rules/ci-remediation.md +8 -12
  11. package/.agents/rules/git-conventions-reference.md +6 -7
  12. package/.agents/rules/git-conventions.md +16 -22
  13. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  14. package/.agents/schemas/agentrc.schema.json +54 -214
  15. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  16. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  17. package/.agents/schemas/risk-verdict.schema.json +0 -13
  18. package/.agents/scripts/analyze-execution.js +1 -1
  19. package/.agents/scripts/audit-to-stories.js +7 -7
  20. package/.agents/scripts/boot-sweep.js +1 -1
  21. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  22. package/.agents/scripts/check-prepush-recovery.js +1 -1
  23. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  24. package/.agents/scripts/lib/Logger.js +6 -10
  25. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  26. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  27. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  28. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  29. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  30. package/.agents/scripts/lib/baselines/reader.js +1 -6
  31. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  32. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  33. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  34. package/.agents/scripts/lib/checks/index.js +2 -1
  35. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  36. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  37. package/.agents/scripts/lib/cli-args.js +16 -7
  38. package/.agents/scripts/lib/close-validation/gates.js +2 -2
  39. package/.agents/scripts/lib/config/ci.js +6 -31
  40. package/.agents/scripts/lib/config/delivery-routing.js +45 -29
  41. package/.agents/scripts/lib/config/explain.js +55 -36
  42. package/.agents/scripts/lib/config/limits.js +17 -58
  43. package/.agents/scripts/lib/config/paths.js +0 -2
  44. package/.agents/scripts/lib/config/quality.js +1 -1
  45. package/.agents/scripts/lib/config/runners.js +17 -50
  46. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  47. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  48. package/.agents/scripts/lib/config-resolver.js +2 -7
  49. package/.agents/scripts/lib/config-settings-schema-delivery.js +24 -148
  50. package/.agents/scripts/lib/config-settings-schema-quality.js +8 -14
  51. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  52. package/.agents/scripts/lib/dependency-parser.js +3 -2
  53. package/.agents/scripts/lib/doc-tiers.js +2 -2
  54. package/.agents/scripts/lib/duplicate-search.js +211 -41
  55. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  56. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  57. package/.agents/scripts/lib/framework-version.js +2 -3
  58. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  59. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  60. package/.agents/scripts/lib/git-utils.js +32 -6
  61. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  62. package/.agents/scripts/lib/label-constants.js +10 -23
  63. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  64. package/.agents/scripts/lib/observability/active-story-env.js +1 -1
  65. package/.agents/scripts/lib/observability/hook-heartbeat.js +20 -52
  66. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  67. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  68. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  69. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +8 -5
  70. package/.agents/scripts/lib/orchestration/ceremony-routing.js +83 -20
  71. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  72. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  73. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  74. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  75. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  76. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  77. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  78. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  79. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  80. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  81. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  82. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  83. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  84. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  85. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  86. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  87. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  88. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  89. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  90. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  91. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  92. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  93. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  94. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  95. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +13 -13
  96. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  97. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  98. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  99. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  100. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  101. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  102. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  103. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  104. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  105. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  106. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  107. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  108. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  109. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  110. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  111. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  112. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  113. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  114. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  115. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  116. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  117. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  118. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  119. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  120. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  121. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  122. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  123. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  124. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  125. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  126. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  127. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  128. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  129. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  130. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  131. package/.agents/scripts/lib/orchestration/ticket-validator.js +2 -7
  132. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  133. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  134. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  135. package/.agents/scripts/lib/planning-corpus.js +16 -11
  136. package/.agents/scripts/lib/preflight-runner.js +2 -2
  137. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  138. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  139. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  140. package/.agents/scripts/lib/story-adjacency.js +11 -14
  141. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  142. package/.agents/scripts/lib/story-plan.js +2 -4
  143. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  144. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  145. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  146. package/.agents/scripts/lib/validation-evidence.js +1 -1
  147. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  148. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  149. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  150. package/.agents/scripts/lint-issue-body.js +71 -40
  151. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  152. package/.agents/scripts/notify.js +4 -3
  153. package/.agents/scripts/plan-context.js +64 -74
  154. package/.agents/scripts/plan-persist.js +121 -280
  155. package/.agents/scripts/plan-run-epilogue.js +97 -0
  156. package/.agents/scripts/providers/github/issues.js +17 -33
  157. package/.agents/scripts/providers/github/mappers.js +0 -12
  158. package/.agents/scripts/providers/github/tickets.js +2 -5
  159. package/.agents/scripts/resolve-plan-run.js +117 -0
  160. package/.agents/scripts/signals-view.js +24 -19
  161. package/.agents/scripts/single-story-close.js +11 -14
  162. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  163. package/.agents/scripts/single-story-init.js +29 -20
  164. package/.agents/scripts/stories-wave-tick.js +6 -6
  165. package/.agents/scripts/story-plan.js +26 -47
  166. package/.agents/scripts/update-ticket-state.js +6 -15
  167. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  168. package/.agents/skills/core/idea-refinement/SKILL.md +6 -6
  169. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  170. package/.agents/skills/skills.index.json +3 -43
  171. package/.agents/starter-agentrc.json +0 -5
  172. package/.agents/templates/agent-protocol.md +9 -10
  173. package/.agents/workflows/audit-architecture.md +3 -3
  174. package/.agents/workflows/audit-clean-code.md +3 -3
  175. package/.agents/workflows/audit-dependencies.md +3 -3
  176. package/.agents/workflows/audit-devops.md +3 -3
  177. package/.agents/workflows/audit-documentation.md +5 -5
  178. package/.agents/workflows/audit-lighthouse.md +3 -3
  179. package/.agents/workflows/audit-navigability.md +3 -2
  180. package/.agents/workflows/audit-performance.md +3 -3
  181. package/.agents/workflows/audit-privacy.md +3 -3
  182. package/.agents/workflows/audit-quality.md +3 -3
  183. package/.agents/workflows/audit-security.md +3 -3
  184. package/.agents/workflows/audit-seo.md +3 -3
  185. package/.agents/workflows/audit-sre.md +3 -3
  186. package/.agents/workflows/audit-to-stories.md +20 -20
  187. package/.agents/workflows/audit-ux-ui.md +3 -3
  188. package/.agents/workflows/deliver.md +122 -174
  189. package/.agents/workflows/git-cleanup.md +3 -4
  190. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  191. package/.agents/workflows/helpers/acceptance-self-eval.md +16 -29
  192. package/.agents/workflows/helpers/code-review.md +70 -193
  193. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  194. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  195. package/.agents/workflows/helpers/diagnose.md +10 -10
  196. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  197. package/.agents/workflows/helpers/signals.md +16 -16
  198. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  199. package/.agents/workflows/mandrel-update.md +2 -1
  200. package/.agents/workflows/plan.md +112 -145
  201. package/.agents/workflows/qa-assist.md +24 -30
  202. package/.agents/workflows/qa-explore.md +29 -38
  203. package/.agents/workflows/qa-run.md +2 -2
  204. package/README.md +9 -8
  205. package/docs/CHANGELOG.md +30 -0
  206. package/lib/migrations/index.js +6 -5
  207. package/package.json +2 -2
  208. package/.agents/agents/retro.md +0 -42
  209. package/.agents/personas/architect.md +0 -113
  210. package/.agents/personas/devops-engineer.md +0 -38
  211. package/.agents/personas/engineer.md +0 -33
  212. package/.agents/personas/project-manager.md +0 -114
  213. package/.agents/personas/qa-engineer.md +0 -95
  214. package/.agents/personas/security-engineer.md +0 -111
  215. package/.agents/personas/technical-writer.md +0 -101
  216. package/.agents/schemas/dispatch-manifest.json +0 -232
  217. package/.agents/schemas/epic-spec.schema.json +0 -153
  218. package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
  219. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
  220. package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
  221. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  222. package/.agents/scripts/bookkeeping-reconcile.js +0 -117
  223. package/.agents/scripts/dispatcher.js +0 -295
  224. package/.agents/scripts/epic-audit-prepare.js +0 -497
  225. package/.agents/scripts/epic-audit-recheck.js +0 -274
  226. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  227. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  228. package/.agents/scripts/epic-deliver-prepare.js +0 -852
  229. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  230. package/.agents/scripts/epic-plan-clarity.js +0 -211
  231. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  232. package/.agents/scripts/epic-reconcile.js +0 -625
  233. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  234. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  235. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  236. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  237. package/.agents/scripts/lib/config/preflight.js +0 -58
  238. package/.agents/scripts/lib/config/retro.js +0 -77
  239. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  240. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  241. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  242. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
  243. package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
  244. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  245. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  246. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  247. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  248. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  249. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  250. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  251. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  252. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  253. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  254. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  255. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  256. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  257. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  258. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  259. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  260. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  261. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  262. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
  263. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  264. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  265. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  266. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  267. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  268. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  269. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  270. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  271. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  272. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  273. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  274. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  275. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  276. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  277. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  278. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  279. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  280. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  281. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  282. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  283. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  284. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  285. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  286. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
  287. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  288. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
  289. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  290. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  291. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  292. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
  293. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  294. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  295. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  296. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  297. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  298. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  299. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  300. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  301. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  302. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  303. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  304. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  305. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  306. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  307. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  308. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  309. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  310. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  311. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  312. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  313. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  314. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  315. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  316. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  317. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  318. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  319. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  320. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  321. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  322. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  323. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  324. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  325. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  326. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  327. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  328. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  329. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  330. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  331. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  332. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  333. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  334. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  335. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
  336. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  337. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  338. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  339. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  340. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  341. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  342. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  343. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  344. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  345. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  346. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  347. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  348. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  349. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  350. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  351. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  352. package/.agents/scripts/lib/spec/index.js +0 -36
  353. package/.agents/scripts/lib/spec/loader.js +0 -425
  354. package/.agents/scripts/lib/spec/state.js +0 -208
  355. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  356. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  357. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  358. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  359. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  360. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  361. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  362. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  363. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  364. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  365. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  366. package/.agents/scripts/lifecycle-emit.js +0 -510
  367. package/.agents/scripts/retro-run.js +0 -218
  368. package/.agents/scripts/slice-phase.js +0 -361
  369. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  370. package/.agents/scripts/story-close.js +0 -294
  371. package/.agents/scripts/story-init.js +0 -599
  372. package/.agents/scripts/story-phase.js +0 -369
  373. package/.agents/scripts/wave-tick.js +0 -464
  374. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  375. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  376. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  377. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  378. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  379. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  380. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
  381. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  382. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
  383. package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
  384. package/.agents/workflows/helpers/deliver-epic.md +0 -998
  385. package/.agents/workflows/helpers/deliver-stories.md +0 -450
  386. package/.agents/workflows/helpers/epic-audit.md +0 -189
  387. package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
  388. package/.agents/workflows/helpers/epic-testing.md +0 -125
  389. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  390. package/.agents/workflows/helpers/plan-epic.md +0 -353
  391. package/.agents/workflows/helpers/plan-story.md +0 -251
  392. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  393. /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
@@ -1,581 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /* node:coverage ignore file */
4
-
5
- /**
6
- * epic-plan-healthcheck.js — Post-Plan Readiness Check
7
- *
8
- * Library home of `runPlanHealthcheck`, the **inline** blocking check the
9
- * collapsed persist surface runs as the `agent::ready` exit condition
10
- * (`plan-persist.js` step 9 — the authoritative invocation since Epic
11
- * #4474 retired the standalone Phase 10 workflow step). The CLI form
12
- * remains for manual re-validation and the opt-in slow paths below; no
13
- * workflow mandates running it standalone.
14
- *
15
- * Modes (additive — the fast checks below always run):
16
- * (default) — config validation + git remote check only.
17
- * Targets <2s.
18
- * --paranoid — adds ticket-hierarchy revalidation plus a
19
- * navigability-reachability semantic check (silent
20
- * no-op unless `planning.navigation.routeGlobs` is
21
- * configured).
22
- * --prime-install — adds the pnpm content-addressable-store priming
23
- * path (up to 300s).
24
- *
25
- * Output: a single line of structured JSON on stdout —
26
- * { ok, degraded, reason, checks: [{name, ok, durationMs, detail}] }
27
- *
28
- * The script always exits 0; callers decide whether to act on `ok: false`.
29
- * The plan is already committed to GitHub, so failing the script does not
30
- * un-create tickets.
31
- *
32
- * Usage:
33
- * node epic-plan-healthcheck.js --epic <EPIC_ID> \
34
- * [--paranoid] [--prime-install] [--dry-run]
35
- *
36
- * @see .agents/workflows/helpers/plan-epic.md (persist step — inline gate)
37
- */
38
-
39
- import { spawnSync } from 'node:child_process';
40
- import fs from 'node:fs';
41
- import path from 'node:path';
42
- import { parseArgs } from 'node:util';
43
- import { parseTicketId } from './lib/cli-args.js';
44
- import { runAsCli } from './lib/cli-utils.js';
45
- import {
46
- PROJECT_ROOT,
47
- resolveConfig,
48
- validateOrchestrationConfig,
49
- } from './lib/config-resolver.js';
50
- import { gitSpawn } from './lib/git-utils.js';
51
- import { Logger } from './lib/Logger.js';
52
- import { TYPE_LABELS } from './lib/label-constants.js';
53
- import { recordPlanInvocation } from './lib/orchestration/plan-metrics.js';
54
- import { createProvider } from './lib/provider-factory.js';
55
-
56
- const progress = Logger.createProgress('plan-healthcheck', { stderr: true });
57
-
58
- // ---------------------------------------------------------------------------
59
- // CLI parsing
60
- // ---------------------------------------------------------------------------
61
-
62
- /**
63
- * Parse the healthcheck-specific CLI surface. Kept local to the script so the
64
- * shared `parseSprintArgs` helper does not have to learn about every script's
65
- * private flags.
66
- *
67
- * @param {string[]} [argv]
68
- * @returns {{ epicId: number|null, paranoid: boolean,
69
- * primeInstall: boolean, dryRun: boolean }}
70
- */
71
- function parseHealthcheckArgs(argv = process.argv) {
72
- const { values, positionals } = parseArgs({
73
- args: argv.slice(2),
74
- options: {
75
- epic: { type: 'string', short: 'e' },
76
- paranoid: { type: 'boolean', default: false },
77
- 'prime-install': { type: 'boolean', default: false },
78
- 'dry-run': { type: 'boolean', default: false },
79
- },
80
- allowPositionals: true,
81
- strict: false,
82
- });
83
-
84
- return {
85
- epicId: parseTicketId(values.epic) ?? parseTicketId(positionals[0]),
86
- paranoid: !!values.paranoid,
87
- primeInstall: !!values['prime-install'],
88
- dryRun: !!values['dry-run'],
89
- };
90
- }
91
-
92
- // ---------------------------------------------------------------------------
93
- // Individual checks
94
- //
95
- // Each check returns { ok: boolean, detail: string }. The orchestrator wraps
96
- // it with `name` and `durationMs` for the structured output.
97
- // ---------------------------------------------------------------------------
98
-
99
- /** Validate the resolved `.agentrc.json` config. */
100
- function checkConfig(config) {
101
- try {
102
- validateOrchestrationConfig(config);
103
- return { ok: true, detail: 'Config is valid.' };
104
- } catch (err) {
105
- return { ok: false, detail: `Config validation failed: ${err.message}` };
106
- }
107
- }
108
-
109
- /** Verify `origin` is reachable and `baseBranch` exists on it. */
110
- function checkGitRemote(baseBranch, cwd) {
111
- const remote = gitSpawn(
112
- cwd,
113
- 'ls-remote',
114
- '--exit-code',
115
- 'origin',
116
- baseBranch,
117
- );
118
- if (remote.status === 0) {
119
- return {
120
- ok: true,
121
- detail: `Remote reachable, base branch '${baseBranch}' exists.`,
122
- };
123
- }
124
- if (
125
- remote.stderr.includes('Could not resolve host') ||
126
- remote.stderr.includes('unable to access')
127
- ) {
128
- return {
129
- ok: false,
130
- detail: `Git remote 'origin' is not reachable: ${remote.stderr.slice(0, 200)}`,
131
- };
132
- }
133
- return {
134
- ok: false,
135
- detail: `Base branch '${baseBranch}' not found on origin.`,
136
- };
137
- }
138
-
139
- /**
140
- * Detect whether a Story body carries an inline `## Acceptance` section with
141
- * at least one checklist item. Epic #3078 — under 2-tier hierarchy, Stories
142
- * carry acceptance inline, so the hierarchy check uses this signal as the
143
- * mark of a complete, executable Story.
144
- *
145
- * @param {string} body
146
- * @returns {boolean}
147
- */
148
- function hasInlineAcceptance(body) {
149
- if (typeof body !== 'string' || body.length === 0) return false;
150
- const match = body.match(/^##\s+Acceptance\s*$/im);
151
- if (!match) return false;
152
- const tail = body.slice(match.index + match[0].length);
153
- // Capture until the next top-level `## ` heading (or EOF).
154
- const sectionEnd = tail.search(/^##\s+\S/m);
155
- const section = sectionEnd === -1 ? tail : tail.slice(0, sectionEnd);
156
- // A non-empty acceptance section needs at least one bullet (with or
157
- // without a checkbox marker).
158
- return /^\s*-\s+(?:\[[ xX]\]\s+)?\S/m.test(section);
159
- }
160
-
161
- /**
162
- * Validate Epic ticket hierarchy. 2-tier is the only supported hierarchy
163
- * after Task #3154 deleted `planning.hierarchy`: every Story must carry an
164
- * inline `## Acceptance` checklist; there is no Task layer to graph.
165
- *
166
- * @param {object} provider
167
- * @param {number|null} epicId
168
- */
169
- async function checkTickets(provider, epicId) {
170
- if (!epicId) {
171
- return {
172
- ok: false,
173
- detail: '--paranoid requires --epic <ID> to fetch the ticket hierarchy.',
174
- };
175
- }
176
-
177
- let tickets;
178
- try {
179
- tickets = await provider.getSubTickets(epicId);
180
- } catch (err) {
181
- return {
182
- ok: false,
183
- detail: `Could not fetch Epic #${epicId} tickets: ${err.message}`,
184
- };
185
- }
186
-
187
- if (tickets.length === 0) {
188
- return { ok: false, detail: `Epic #${epicId} has no child tickets.` };
189
- }
190
-
191
- const stories = tickets.filter((t) => t.labels.includes(TYPE_LABELS.STORY));
192
-
193
- const errors = [];
194
- if (stories.length === 0) errors.push('no type::story tickets');
195
-
196
- const missingAcceptance = stories.filter(
197
- (s) => !hasInlineAcceptance(s.body ?? ''),
198
- );
199
- if (missingAcceptance.length > 0) {
200
- const ids = missingAcceptance.map((s) => `#${s.id}`).join(', ');
201
- errors.push(
202
- `${missingAcceptance.length} story/stories missing inline acceptance: ${ids}`,
203
- );
204
- }
205
-
206
- if (errors.length > 0) {
207
- return { ok: false, detail: errors.join('; ') };
208
- }
209
-
210
- const missingComplexity = stories.filter(
211
- (s) => !s.labels.some((l) => l.startsWith('complexity::')),
212
- );
213
- const advisory =
214
- missingComplexity.length > 0
215
- ? ` (advisory: ${missingComplexity.length} story/stories missing complexity label)`
216
- : '';
217
-
218
- return {
219
- ok: true,
220
- detail: `${stories.length} stories (2-tier, inline acceptance) — hierarchy valid${advisory}.`,
221
- };
222
- }
223
-
224
- /**
225
- * Resolve the navigation config that drives the reachability check.
226
- *
227
- * The check is opt-in: a consumer that has not configured
228
- * `planning.navigation.routeGlobs` gets a silent no-op (F7 / AC-13). The
229
- * nav-registry token list is what a route-adding Story is expected to
230
- * reference somewhere in its body or `## Acceptance` section.
231
- *
232
- * @param {object} config Resolved `.agentrc.json`.
233
- * @returns {{ routeGlobs: string[], navRegistry: string[] }}
234
- */
235
- function resolveNavConfig(config) {
236
- const nav = config?.planning?.navigation ?? {};
237
- const toList = (v) =>
238
- (Array.isArray(v) ? v : v == null ? [] : [v])
239
- .filter((s) => typeof s === 'string' && s.trim().length > 0)
240
- .map((s) => s.trim());
241
- return {
242
- routeGlobs: toList(nav.routeGlobs),
243
- navRegistry: toList(nav.navRegistry),
244
- };
245
- }
246
-
247
- /**
248
- * Translate a route glob (`pages/**`, `app/**\/route.ts`) into a RegExp that
249
- * matches a path string. Supports `**` (any depth, including `/`), `*` (any
250
- * run of non-separator chars), and `?` (single non-separator char). All other
251
- * characters are matched literally.
252
- *
253
- * @param {string} glob
254
- * @returns {RegExp}
255
- */
256
- function globToRegExp(glob) {
257
- // Collapse adjacent `**` segments before compiling. `**/**` and `***` both
258
- // mean "any depth", but compiling them literally emits adjacent `.*` runs
259
- // (`.*/.*` / `.*.*`) that backtrack catastrophically on a long non-matching
260
- // path. Collapsing to a single `**` preserves semantics and keeps the
261
- // matcher linear (ReDoS hardening — Epic #4131 audit follow-up).
262
- const normalized = glob
263
- .replace(/\*\*(?:\/\*\*)+/g, '**')
264
- .replace(/\*{3,}/g, '**');
265
- let re = '';
266
- for (let i = 0; i < normalized.length; i++) {
267
- const ch = normalized[i];
268
- if (ch === '*') {
269
- if (normalized[i + 1] === '*') {
270
- re += '.*';
271
- i++;
272
- } else {
273
- re += '[^/]*';
274
- }
275
- } else if (ch === '?') {
276
- re += '[^/]';
277
- } else {
278
- re += ch.replace(/[.+^${}()|[\]\\]/g, '\\$&');
279
- }
280
- }
281
- return new RegExp(`^${re}$`);
282
- }
283
-
284
- /**
285
- * Extract the candidate route-touching paths a Story declares. Reads the
286
- * `## Changes` block (the decompose-author emits one `{"path":...}` JSON
287
- * object per bullet) and falls back to any bare ```` `path/like/this` ````
288
- * inline-code spans in the body.
289
- *
290
- * @param {string} body
291
- * @returns {string[]}
292
- */
293
- function extractStoryPaths(body) {
294
- if (typeof body !== 'string' || body.length === 0) return [];
295
- const paths = new Set();
296
- // `{"path":"pages/foo.tsx", ...}` change descriptors.
297
- for (const m of body.matchAll(/"path"\s*:\s*"([^"]+)"/g)) {
298
- paths.add(m[1]);
299
- }
300
- // Inline-code spans that look like a path (contain a slash or a dotted ext).
301
- for (const m of body.matchAll(/`([^`]+)`/g)) {
302
- const token = m[1].trim();
303
- if (/[/.]/.test(token) && !token.includes(' ')) paths.add(token);
304
- }
305
- return [...paths];
306
- }
307
-
308
- /**
309
- * Return the `## Acceptance` + full-body text a Story is expected to reference
310
- * the nav registry from. The whole body is searched (the registry can be cited
311
- * in the Goal, Changes, or Acceptance), so this just lower-cases the body once.
312
- *
313
- * @param {string} body
314
- * @returns {string}
315
- */
316
- function referenceableText(body) {
317
- return typeof body === 'string' ? body.toLowerCase() : '';
318
- }
319
-
320
- /**
321
- * Navigability-reachability semantic check (F7 / AC-8).
322
- *
323
- * Flags every Story that adds a route (touches a path matching a configured
324
- * `planning.navigation.routeGlobs` entry) but whose body / acceptance never
325
- * references the configured nav registry. Silent no-op (returns ok with an
326
- * explicit detail) when no route-glob config is present.
327
- *
328
- * @param {object} provider
329
- * @param {number|null} epicId
330
- * @param {object} config
331
- */
332
- async function checkReachability(provider, epicId, config) {
333
- const { routeGlobs, navRegistry } = resolveNavConfig(config);
334
-
335
- // Opt-in: unconfigured consumers degrade to a silent no-op.
336
- if (routeGlobs.length === 0) {
337
- return {
338
- ok: true,
339
- detail: 'No planning.navigation.routeGlobs configured — skipped.',
340
- };
341
- }
342
-
343
- if (!epicId) {
344
- return {
345
- ok: false,
346
- detail:
347
- 'reachability check requires --epic <ID> to fetch the ticket hierarchy.',
348
- };
349
- }
350
-
351
- let tickets;
352
- try {
353
- tickets = await provider.getSubTickets(epicId);
354
- } catch (err) {
355
- return {
356
- ok: false,
357
- detail: `Could not fetch Epic #${epicId} tickets: ${err.message}`,
358
- };
359
- }
360
-
361
- const stories = tickets.filter((t) => t.labels.includes(TYPE_LABELS.STORY));
362
- const matchers = routeGlobs.map(globToRegExp);
363
- const registryTokens = navRegistry.map((t) => t.toLowerCase());
364
-
365
- const flagged = [];
366
- for (const story of stories) {
367
- const body = story.body ?? '';
368
- const addsRoute = extractStoryPaths(body).some((p) =>
369
- matchers.some((rx) => rx.test(p)),
370
- );
371
- if (!addsRoute) continue;
372
-
373
- const text = referenceableText(body);
374
- // When no explicit registry token is configured, fall back to the
375
- // generic "nav registry" phrase so a route-adding Story is still
376
- // expected to mention the navigation surface.
377
- const tokens =
378
- registryTokens.length > 0
379
- ? registryTokens
380
- : ['nav registry', 'navigation'];
381
- const referencesRegistry = tokens.some((tok) => text.includes(tok));
382
- if (!referencesRegistry) flagged.push(`#${story.id}`);
383
- }
384
-
385
- if (flagged.length > 0) {
386
- const registryHint =
387
- navRegistry.length > 0 ? navRegistry.join(', ') : 'the nav registry';
388
- return {
389
- ok: false,
390
- detail: `${flagged.length} route-adding story/stories never reference ${registryHint}: ${flagged.join(', ')}`,
391
- };
392
- }
393
-
394
- return {
395
- ok: true,
396
- detail: `${stories.length} stories scanned — every route-adding story references the nav registry.`,
397
- };
398
- }
399
-
400
- /** Prime the pnpm content-addressable store via `pnpm install --frozen-lockfile`. */
401
- function primePnpmStore(cwd, dryRun) {
402
- const lockFile = path.join(cwd, 'pnpm-lock.yaml');
403
- if (!fs.existsSync(lockFile)) {
404
- return {
405
- ok: false,
406
- detail: 'No pnpm-lock.yaml found — cannot prime store.',
407
- };
408
- }
409
- if (dryRun) {
410
- return { ok: true, detail: 'pnpm store prime skipped (dry-run).' };
411
- }
412
-
413
- progress('PRIME', 'Priming pnpm content-addressable store...');
414
- const start = Date.now();
415
- const result = spawnSync('pnpm', ['install', '--frozen-lockfile'], {
416
- cwd,
417
- stdio: 'pipe',
418
- encoding: 'utf-8',
419
- shell: process.platform === 'win32',
420
- timeout: 300_000,
421
- });
422
- const elapsed = ((Date.now() - start) / 1000).toFixed(1);
423
-
424
- if (result.status === 0) {
425
- return { ok: true, detail: `pnpm store primed in ${elapsed}s.` };
426
- }
427
- const reason =
428
- result.signal === 'SIGTERM'
429
- ? `timeout after ${elapsed}s`
430
- : `exit ${result.status}`;
431
- return {
432
- ok: false,
433
- detail: `pnpm store prime failed (${reason}). First worktree install will be slower. stderr: ${(result.stderr ?? '').slice(0, 300)}`,
434
- };
435
- }
436
-
437
- // ---------------------------------------------------------------------------
438
- // Orchestration
439
- // ---------------------------------------------------------------------------
440
-
441
- async function timed(name, fn) {
442
- const start = Date.now();
443
- const { ok, detail } = await fn();
444
- return { name, ok, durationMs: Date.now() - start, detail };
445
- }
446
-
447
- /**
448
- * Run the post-plan health check.
449
- *
450
- * @param {object} [opts]
451
- * @param {number} [opts.epicId] Epic ID (required for --paranoid).
452
- * @param {boolean} [opts.paranoid] Add ticket-hierarchy revalidation.
453
- * @param {boolean} [opts.primeInstall] Add pnpm-store priming.
454
- * @param {boolean} [opts.dryRun] Skip real install side effects.
455
- * @param {object} [opts.injectedProvider] Test-only injection point.
456
- * @param {object} [opts.injectedConfig] Test-only injection point.
457
- * @returns {Promise<{ok: boolean, degraded: boolean, reason: string|null,
458
- * checks: Array<{name: string, ok: boolean, durationMs: number, detail: string}>}>}
459
- */
460
- // exported for tests — direct-unit coverage of the reachability semantics.
461
- // (`resolveNavConfig` / `extractStoryPaths` / `globToRegExp` are also the
462
- // shared mechanics of the persist-side draft reachability check —
463
- // `lib/orchestration/plan-reachability.js`, Epic #4474 PR6 — so the two
464
- // surfaces can never drift apart.)
465
- export { checkReachability, extractStoryPaths, globToRegExp, resolveNavConfig };
466
-
467
- // exported for tests — Story-level reuse runner reserved for future test coverage
468
- export async function runPlanHealthcheck(opts = {}) {
469
- const ARG_KEYS = ['epicId', 'paranoid', 'primeInstall', 'dryRun'];
470
- const hasExplicitArgs = ARG_KEYS.some((k) => Object.hasOwn(opts, k));
471
- const parsed = hasExplicitArgs
472
- ? {
473
- epicId: opts.epicId ?? null,
474
- paranoid: !!opts.paranoid,
475
- primeInstall: !!opts.primeInstall,
476
- dryRun: !!opts.dryRun,
477
- }
478
- : parseHealthcheckArgs();
479
-
480
- const { epicId, paranoid, primeInstall, dryRun } = parsed;
481
- const cwd = PROJECT_ROOT;
482
-
483
- const config = opts.injectedConfig || resolveConfig();
484
- const baseBranch = config.project?.baseBranch ?? 'main';
485
-
486
- progress(
487
- 'HEALTH',
488
- `Running post-plan health check${epicId ? ` for Epic #${epicId}` : ''} (mode=${paranoid ? 'paranoid' : 'fast'}${primeInstall ? '+prime-install' : ''})...`,
489
- );
490
-
491
- const checks = [];
492
-
493
- // Fast lane: config + git remote always run.
494
- progress('CHECK', 'Validating resolved config...');
495
- checks.push(await timed('config', async () => checkConfig(config)));
496
-
497
- progress('CHECK', 'Checking git remote...');
498
- checks.push(
499
- await timed('git-remote', async () => checkGitRemote(baseBranch, cwd)),
500
- );
501
-
502
- // Paranoid lane: ticket-hierarchy revalidation (2-tier only) plus the
503
- // navigability-reachability semantic check (silent no-op when unconfigured).
504
- if (paranoid) {
505
- const provider = opts.injectedProvider || createProvider(config);
506
- progress('CHECK', 'Validating ticket hierarchy...');
507
- checks.push(
508
- await timed('ticket-hierarchy', () => checkTickets(provider, epicId)),
509
- );
510
- progress('CHECK', 'Checking route-reachability (nav registry)...');
511
- checks.push(
512
- await timed('reachability', () =>
513
- checkReachability(provider, epicId, config),
514
- ),
515
- );
516
- }
517
-
518
- // Optional pnpm-store priming.
519
- if (primeInstall) {
520
- progress('CHECK', 'Priming pnpm store...');
521
- checks.push(
522
- await timed('prime-install', async () => primePnpmStore(cwd, dryRun)),
523
- );
524
- }
525
-
526
- const failed = checks.filter((c) => !c.ok);
527
- const ok = failed.length === 0;
528
- const result = {
529
- ok,
530
- degraded: !ok,
531
- reason: ok ? null : failed.map((c) => `${c.name}: ${c.detail}`).join('; '),
532
- checks,
533
- };
534
-
535
- if (ok) {
536
- progress('HEALTH', `All ${checks.length} check(s) passed.`);
537
- } else {
538
- progress(
539
- 'HEALTH',
540
- `${failed.length} of ${checks.length} check(s) failed: ${failed.map((c) => c.name).join(', ')}.`,
541
- );
542
- }
543
-
544
- // The structured result is the only thing on stdout.
545
- Logger.info(JSON.stringify(result));
546
-
547
- return result;
548
- }
549
-
550
- // ---------------------------------------------------------------------------
551
- // Main guard
552
- // ---------------------------------------------------------------------------
553
-
554
- /**
555
- * CLI wrapper: stamp the plan-metrics ledger (#4474 PR1) around the direct
556
- * invocation only. In-process callers (the decompose persist gate imports
557
- * `runPlanHealthcheck` directly) are already covered by their own CLI's
558
- * stamp — wrapping here too would double-count the inline gate.
559
- */
560
- async function cliMain() {
561
- const { epicId } = parseHealthcheckArgs();
562
- let config;
563
- try {
564
- config = resolveConfig();
565
- } catch {
566
- config = undefined;
567
- }
568
- return recordPlanInvocation(
569
- {
570
- cli: 'epic-plan-healthcheck',
571
- mode: 'healthcheck',
572
- epicId: epicId ?? null,
573
- config,
574
- },
575
- () => runPlanHealthcheck(),
576
- );
577
- }
578
-
579
- runAsCli(import.meta.url, cliMain, {
580
- source: 'epic-plan-healthcheck',
581
- });