mandrel 1.94.0 → 2.1.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 (560) hide show
  1. package/.agents/README.md +116 -99
  2. package/.agents/agents/acceptance-critic.md +9 -7
  3. package/.agents/agents/story-worker.md +45 -51
  4. package/.agents/audit-checklists/performance.md +1 -1
  5. package/.agents/docs/SDLC.md +498 -1287
  6. package/.agents/docs/agentrc-reference.json +185 -80
  7. package/.agents/docs/configuration.md +132 -190
  8. package/.agents/docs/execution-reference.md +51 -25
  9. package/.agents/docs/quality-gates.md +25 -33
  10. package/.agents/docs/workflows.md +8 -8
  11. package/.agents/instructions.md +113 -139
  12. package/.agents/rules/ci-remediation.md +11 -15
  13. package/.agents/rules/git-conventions-reference.md +48 -58
  14. package/.agents/rules/git-conventions.md +16 -22
  15. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  16. package/.agents/schemas/agentrc.schema.json +83 -254
  17. package/.agents/schemas/audit-rules.json +59 -1
  18. package/.agents/schemas/audit-rules.schema.json +33 -1
  19. package/.agents/schemas/lifecycle/README.md +1 -2
  20. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  21. package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
  22. package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
  23. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  24. package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
  25. package/.agents/schemas/signal-event.schema.json +3 -3
  26. package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
  27. package/.agents/schemas/validation-evidence.schema.json +1 -1
  28. package/.agents/scripts/acceptance-eval.js +22 -66
  29. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  30. package/.agents/scripts/audit-to-stories.js +7 -7
  31. package/.agents/scripts/boot-sweep.js +1 -1
  32. package/.agents/scripts/bootstrap.js +3 -3
  33. package/.agents/scripts/check-dead-exports.js +43 -104
  34. package/.agents/scripts/check-doc-links.js +2 -2
  35. package/.agents/scripts/check-lifecycle-lint.js +7 -10
  36. package/.agents/scripts/check-workflow-cli-lint.js +91 -0
  37. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  38. package/.agents/scripts/deliver-recover.js +122 -0
  39. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  40. package/.agents/scripts/evidence-gate.js +20 -50
  41. package/.agents/scripts/generate-skills-index.js +17 -1
  42. package/.agents/scripts/generate-workflows-doc.js +4 -4
  43. package/.agents/scripts/lib/ITicketingProvider.js +1 -19
  44. package/.agents/scripts/lib/Logger.js +6 -10
  45. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  46. package/.agents/scripts/lib/audit-suite/selector.js +328 -28
  47. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  48. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  49. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -15
  50. package/.agents/scripts/lib/baselines/reader.js +1 -6
  51. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  52. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
  53. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  54. package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
  55. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
  56. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
  57. package/.agents/scripts/lib/checks/core-bare-clean.js +6 -3
  58. package/.agents/scripts/lib/checks/index.js +3 -2
  59. package/.agents/scripts/lib/checks/loop-health.js +12 -11
  60. package/.agents/scripts/lib/checks/state.js +17 -248
  61. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +26 -24
  62. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
  63. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
  64. package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
  65. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  66. package/.agents/scripts/lib/cli-args.js +39 -9
  67. package/.agents/scripts/lib/close-validation/gates.js +15 -15
  68. package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
  69. package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
  70. package/.agents/scripts/lib/close-validation/runner.js +13 -21
  71. package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
  72. package/.agents/scripts/lib/config/ci.js +6 -31
  73. package/.agents/scripts/lib/config/delivery-routing.js +52 -35
  74. package/.agents/scripts/lib/config/explain.js +61 -48
  75. package/.agents/scripts/lib/config/github.js +7 -5
  76. package/.agents/scripts/lib/config/limits.js +29 -80
  77. package/.agents/scripts/lib/config/paths.js +0 -2
  78. package/.agents/scripts/lib/config/quality.js +12 -15
  79. package/.agents/scripts/lib/config/runners.js +20 -66
  80. package/.agents/scripts/lib/config/temp-paths.js +30 -63
  81. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  82. package/.agents/scripts/lib/config-resolver.js +2 -7
  83. package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
  84. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
  85. package/.agents/scripts/lib/config-settings-schema.js +100 -60
  86. package/.agents/scripts/lib/dead-exports-knip.js +105 -0
  87. package/.agents/scripts/lib/dead-exports-mode.js +51 -0
  88. package/.agents/scripts/lib/dependency-parser.js +3 -2
  89. package/.agents/scripts/lib/doc-tiers.js +2 -2
  90. package/.agents/scripts/lib/duplicate-search.js +242 -41
  91. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  92. package/.agents/scripts/lib/findings/promote-finding.js +23 -14
  93. package/.agents/scripts/lib/format-generated-json.js +97 -0
  94. package/.agents/scripts/lib/framework-version.js +19 -190
  95. package/.agents/scripts/lib/gh-exec.js +8 -0
  96. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  97. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
  98. package/.agents/scripts/lib/git-utils.js +32 -20
  99. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  100. package/.agents/scripts/lib/json-utils.js +1 -2
  101. package/.agents/scripts/lib/label-constants.js +10 -38
  102. package/.agents/scripts/lib/label-taxonomy.js +10 -55
  103. package/.agents/scripts/lib/observability/active-story-env.js +44 -165
  104. package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
  105. package/.agents/scripts/lib/observability/signal-validator.js +4 -4
  106. package/.agents/scripts/lib/observability/signals-writer.js +6 -82
  107. package/.agents/scripts/lib/observability/source-classifier.js +5 -5
  108. package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
  109. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  110. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
  111. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
  112. package/.agents/scripts/lib/orchestration/ceremony-routing.js +105 -44
  113. package/.agents/scripts/lib/orchestration/code-review.js +78 -436
  114. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  115. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
  116. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  117. package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
  118. package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
  119. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  120. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  121. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  122. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
  123. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
  124. package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
  125. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +17 -19
  126. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
  127. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
  128. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  129. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
  130. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
  131. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
  132. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  133. package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
  134. package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
  135. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  136. package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
  137. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
  138. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
  139. package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
  140. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  141. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
  142. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
  143. package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
  144. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
  145. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
  146. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
  147. package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
  148. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  149. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  150. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +52 -51
  151. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  152. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
  153. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  154. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  155. package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
  156. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  157. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  158. package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
  159. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  160. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
  161. package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
  162. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
  163. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  164. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
  165. package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
  166. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
  167. package/.agents/scripts/lib/orchestration/run-epilogue.js +784 -0
  168. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
  169. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
  170. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
  171. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +86 -41
  172. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
  173. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +77 -32
  174. package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
  175. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
  176. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +44 -0
  177. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
  178. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
  179. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +275 -46
  180. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
  181. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  182. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  183. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  184. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  185. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  186. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
  187. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
  188. package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
  189. package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
  190. package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
  191. package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
  192. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  193. package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
  194. package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
  195. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
  196. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
  197. package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
  198. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
  199. package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
  200. package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
  201. package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
  202. package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
  203. package/.agents/scripts/lib/planning-corpus.js +12 -281
  204. package/.agents/scripts/lib/preflight-runner.js +4 -4
  205. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  206. package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
  207. package/.agents/scripts/lib/signals/index.js +4 -17
  208. package/.agents/scripts/lib/signals/read.js +35 -35
  209. package/.agents/scripts/lib/signals/schema.js +8 -11
  210. package/.agents/scripts/lib/signals/span-tree.js +7 -7
  211. package/.agents/scripts/lib/signals/write.js +0 -1
  212. package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
  213. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  214. package/.agents/scripts/lib/skills/parse-skill.js +16 -3
  215. package/.agents/scripts/lib/story-adjacency.js +17 -19
  216. package/.agents/scripts/lib/story-body/story-body.js +130 -75
  217. package/.agents/scripts/lib/story-plan.js +2 -4
  218. package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
  219. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  220. package/.agents/scripts/lib/test-env.js +14 -1
  221. package/.agents/scripts/lib/test-tiers.js +0 -3
  222. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
  223. package/.agents/scripts/lib/validation-evidence.js +32 -60
  224. package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
  225. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  226. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
  227. package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
  228. package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
  229. package/.agents/scripts/lint-issue-body.js +71 -40
  230. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  231. package/.agents/scripts/notify.js +4 -3
  232. package/.agents/scripts/plan-context.js +102 -80
  233. package/.agents/scripts/plan-persist.js +230 -279
  234. package/.agents/scripts/plan-run-epilogue.js +142 -0
  235. package/.agents/scripts/post-structured-comment.js +0 -38
  236. package/.agents/scripts/pr-watch-with-update.js +43 -22
  237. package/.agents/scripts/providers/github/compose.js +0 -1
  238. package/.agents/scripts/providers/github/errors.js +0 -19
  239. package/.agents/scripts/providers/github/issues.js +13 -39
  240. package/.agents/scripts/providers/github/mappers.js +5 -12
  241. package/.agents/scripts/providers/github/sub-issues.js +0 -47
  242. package/.agents/scripts/providers/github/tickets.js +33 -156
  243. package/.agents/scripts/providers/github.js +17 -6
  244. package/.agents/scripts/resolve-stories.js +236 -0
  245. package/.agents/scripts/run-coverage.js +4 -1
  246. package/.agents/scripts/run-lint.js +2 -2
  247. package/.agents/scripts/run-verify.js +31 -2
  248. package/.agents/scripts/signals-view.js +25 -21
  249. package/.agents/scripts/single-story-close.js +178 -26
  250. package/.agents/scripts/single-story-confirm-merge.js +313 -24
  251. package/.agents/scripts/single-story-init.js +35 -30
  252. package/.agents/scripts/stories-wave-tick.js +85 -10
  253. package/.agents/scripts/story-plan.js +28 -49
  254. package/.agents/scripts/update-ticket-state.js +14 -65
  255. package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
  256. package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
  257. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
  258. package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
  259. package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
  260. package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
  261. package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
  262. package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
  263. package/.agents/skills/core/idea-refinement/SKILL.md +9 -9
  264. package/.agents/skills/core/scope-triage/SKILL.md +31 -172
  265. package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
  266. package/.agents/skills/core/security-and-hardening/reference.md +375 -0
  267. package/.agents/skills/skills.index.json +3 -53
  268. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
  269. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
  270. package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
  271. package/.agents/starter-agentrc.json +0 -5
  272. package/.agents/templates/agent-protocol.md +9 -10
  273. package/.agents/workflows/audit-architecture.md +6 -7
  274. package/.agents/workflows/audit-clean-code.md +7 -7
  275. package/.agents/workflows/audit-dependencies.md +3 -3
  276. package/.agents/workflows/audit-devops.md +3 -3
  277. package/.agents/workflows/audit-documentation.md +9 -10
  278. package/.agents/workflows/audit-lighthouse.md +11 -3
  279. package/.agents/workflows/audit-navigability.md +13 -2
  280. package/.agents/workflows/audit-performance.md +5 -6
  281. package/.agents/workflows/audit-privacy.md +3 -3
  282. package/.agents/workflows/audit-quality.md +11 -12
  283. package/.agents/workflows/audit-security.md +4 -5
  284. package/.agents/workflows/audit-seo.md +13 -3
  285. package/.agents/workflows/audit-sre.md +3 -3
  286. package/.agents/workflows/audit-to-stories.md +20 -20
  287. package/.agents/workflows/audit-ux-ui.md +10 -3
  288. package/.agents/workflows/deliver.md +177 -176
  289. package/.agents/workflows/git-cleanup.md +5 -6
  290. package/.agents/workflows/git-deliver.md +1 -1
  291. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  292. package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
  293. package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
  294. package/.agents/workflows/helpers/code-review.md +75 -196
  295. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
  296. package/.agents/workflows/helpers/deliver-story.md +606 -0
  297. package/.agents/workflows/helpers/diagnose.md +10 -10
  298. package/.agents/workflows/helpers/parallel-tooling.md +3 -3
  299. package/.agents/workflows/helpers/signals.md +16 -16
  300. package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
  301. package/.agents/workflows/mandrel-update.md +2 -1
  302. package/.agents/workflows/plan.md +277 -145
  303. package/.agents/workflows/qa-assist.md +27 -33
  304. package/.agents/workflows/qa-explore.md +29 -38
  305. package/.agents/workflows/qa-run.md +2 -6
  306. package/README.md +9 -8
  307. package/bin/mandrel.js +12 -1
  308. package/docs/CHANGELOG.md +70 -0
  309. package/lib/cli/registry.js +262 -19
  310. package/lib/cli/sync-agents.js +157 -0
  311. package/lib/cli/sync-commands.js +115 -6
  312. package/lib/cli/sync.js +168 -6
  313. package/lib/cli/update.js +105 -8
  314. package/lib/cli/version-helpers.js +131 -0
  315. package/lib/migrations/README.md +7 -5
  316. package/lib/migrations/index.js +12 -8
  317. package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
  318. package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
  319. package/package.json +2 -2
  320. package/.agents/agents/retro.md +0 -42
  321. package/.agents/personas/architect.md +0 -113
  322. package/.agents/personas/devops-engineer.md +0 -38
  323. package/.agents/personas/engineer.md +0 -33
  324. package/.agents/personas/project-manager.md +0 -114
  325. package/.agents/personas/qa-engineer.md +0 -95
  326. package/.agents/personas/security-engineer.md +0 -111
  327. package/.agents/personas/technical-writer.md +0 -101
  328. package/.agents/schemas/dispatch-manifest.json +0 -232
  329. package/.agents/schemas/epic-perf-report.schema.json +0 -89
  330. package/.agents/schemas/epic-spec.schema.json +0 -153
  331. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
  332. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
  333. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
  334. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
  335. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
  336. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
  337. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
  338. package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
  339. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
  340. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
  341. package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
  342. package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
  343. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
  344. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
  345. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
  346. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
  347. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
  348. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
  349. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
  350. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
  351. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
  352. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
  353. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
  354. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
  355. package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
  356. package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
  357. package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
  358. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
  359. package/.agents/schemas/risk-verdict.schema.json +0 -66
  360. package/.agents/schemas/story-perf-summary.schema.json +0 -73
  361. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  362. package/.agents/scripts/analyze-execution.js +0 -444
  363. package/.agents/scripts/bookkeeping-reconcile.js +0 -117
  364. package/.agents/scripts/check-prepush-recovery.js +0 -90
  365. package/.agents/scripts/dispatcher.js +0 -295
  366. package/.agents/scripts/epic-audit-prepare.js +0 -497
  367. package/.agents/scripts/epic-audit-recheck.js +0 -274
  368. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  369. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  370. package/.agents/scripts/epic-deliver-prepare.js +0 -852
  371. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  372. package/.agents/scripts/epic-plan-clarity.js +0 -211
  373. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  374. package/.agents/scripts/epic-reconcile.js +0 -625
  375. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  376. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  377. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  378. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  379. package/.agents/scripts/lib/config/preflight.js +0 -58
  380. package/.agents/scripts/lib/config/retro.js +0 -77
  381. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  382. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  383. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  384. package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
  385. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
  386. package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -219
  387. package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
  388. package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
  389. package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
  390. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -270
  391. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
  392. package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
  393. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  394. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  395. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  396. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  397. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  398. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  399. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  400. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  401. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  402. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  403. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  404. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  405. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  406. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  407. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  408. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +0 -105
  409. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  410. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  411. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  412. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
  413. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  414. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  415. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  416. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  417. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  418. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  419. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  420. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  421. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  422. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  423. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  424. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  425. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  426. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +0 -400
  427. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  428. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  429. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  430. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  431. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  432. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  433. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  434. package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
  435. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  436. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  437. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  438. package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
  439. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  440. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
  441. package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
  442. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
  443. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  444. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  445. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  446. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
  447. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  448. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  449. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  450. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  451. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  452. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
  453. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  454. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  455. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  456. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  457. package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
  458. package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
  459. package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
  460. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
  461. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -33
  462. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
  463. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
  464. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
  465. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -396
  466. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  467. package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
  468. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  469. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  470. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  471. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  472. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  473. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  474. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
  475. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  476. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  477. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  478. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  479. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  480. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  481. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  482. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  483. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  484. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  485. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  486. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  487. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  488. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  489. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  490. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  491. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  492. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  493. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  494. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  495. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  496. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  497. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  498. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  499. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  500. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  501. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
  502. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  503. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  504. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  505. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  506. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  507. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  508. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  509. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  510. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  511. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  512. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  513. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  514. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  515. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  516. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  517. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  518. package/.agents/scripts/lib/spec/index.js +0 -36
  519. package/.agents/scripts/lib/spec/loader.js +0 -425
  520. package/.agents/scripts/lib/spec/state.js +0 -208
  521. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  522. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  523. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  524. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  525. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  526. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  527. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  528. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  529. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  530. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  531. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  532. package/.agents/scripts/lifecycle-emit.js +0 -510
  533. package/.agents/scripts/retro-run.js +0 -218
  534. package/.agents/scripts/slice-phase.js +0 -361
  535. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  536. package/.agents/scripts/story-close.js +0 -294
  537. package/.agents/scripts/story-init.js +0 -599
  538. package/.agents/scripts/story-phase.js +0 -369
  539. package/.agents/scripts/wave-tick.js +0 -464
  540. package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
  541. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  542. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  543. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  544. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  545. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  546. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  547. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
  548. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  549. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
  550. package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
  551. package/.agents/workflows/helpers/deliver-epic.md +0 -998
  552. package/.agents/workflows/helpers/deliver-stories.md +0 -450
  553. package/.agents/workflows/helpers/epic-audit.md +0 -189
  554. package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
  555. package/.agents/workflows/helpers/epic-testing.md +0 -125
  556. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  557. package/.agents/workflows/helpers/plan-epic.md +0 -353
  558. package/.agents/workflows/helpers/plan-story.md +0 -251
  559. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  560. package/.agents/workflows/helpers/single-story-deliver.md +0 -557
@@ -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
- });