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,209 +0,0 @@
1
- /**
2
- * push-epic-retry.js — Bounded retry for concurrent epic-branch pushes.
3
- *
4
- * story-close holds a per-Epic filesystem lock for the rebase / merge /
5
- * push sequence, but that lock is local to one machine. N sprint sessions on
6
- * different machines (or different Claude Code web workers) will not see each
7
- * other's lock and can race on `origin/epic/<id>`. Whoever pushes second will
8
- * be rejected with a non-fast-forward error.
9
- *
10
- * This module provides `pushEpicWithRetry`: first push attempt is a direct
11
- * `git push` — single-session behaviour is byte-identical to pre-change code.
12
- * Only on a non-fast-forward rejection do we enter the retry loop: fetch the
13
- * advanced remote, reset local epic onto `origin/<epic>`, reapply the story
14
- * merge, and retry the push. A real content conflict during re-apply is
15
- * non-recoverable: we abort the merge (restoring a clean tree) and throw a
16
- * `PushRetryConflictError` naming the conflicting files.
17
- */
18
-
19
- import { DEFAULT_STORY_MERGE_RETRY } from './config/runners.js';
20
-
21
- /**
22
- * Stderr patterns git emits when `git push` is rejected because the remote
23
- * tip has advanced beyond our local branch head. Only these patterns trigger
24
- * a retry; every other push error surfaces immediately so we do not mask
25
- * permission denials, protected-branch rejections, or network errors behind
26
- * a retry loop.
27
- */
28
- const NON_FAST_FORWARD_PATTERNS = [
29
- /non-fast-forward/i,
30
- /fetch first/i,
31
- /failed to push some refs/i,
32
- /\[rejected\]/,
33
- /Updates were rejected/i,
34
- ];
35
-
36
- export function isNonFastForwardPush(stderr) {
37
- if (!stderr) return false;
38
- return NON_FAST_FORWARD_PATTERNS.some((p) => p.test(stderr));
39
- }
40
-
41
- /**
42
- * Thrown when the retry loop's re-apply step (`git merge --no-ff story-<id>`
43
- * onto the freshly-fetched epic tip) hits a real content conflict. The
44
- * caller should surface this to the operator — we do not attempt automated
45
- * resolution. The merge is aborted before throwing so the working tree is
46
- * clean and recoverable.
47
- */
48
- export class PushRetryConflictError extends Error {
49
- constructor(conflictFiles, gitStderr) {
50
- const fileList = conflictFiles.length
51
- ? conflictFiles.join(', ')
52
- : '(unknown)';
53
- super(
54
- `Content conflict while reapplying story merge onto origin/epic. ` +
55
- `Conflicting file(s): ${fileList}. ` +
56
- `The merge has been aborted and the working tree is clean — no ` +
57
- `half-merged files remain. Resolve manually by rebasing the story ` +
58
- `branch onto the updated epic, committing, and re-running ` +
59
- `story-close.\n\n` +
60
- `git stderr:\n${gitStderr}`,
61
- );
62
- this.name = 'PushRetryConflictError';
63
- this.conflictFiles = conflictFiles;
64
- }
65
- }
66
-
67
- /** Re-apply the story merge during a non-ff retry, optionally pinning the
68
- * conventional-commit subject so the post-merge `(resolves #N)` grep keeps
69
- * finding the merge commit (without it, git falls back to its default
70
- * `Merge branch …` subject and the grep misses). */
71
- function runRetryMerge({ cwd, git, storyBranch, mergeMessage }) {
72
- return mergeMessage
73
- ? git.gitSpawn(cwd, 'merge', '--no-ff', '-m', mergeMessage, storyBranch)
74
- : git.gitSpawn(cwd, 'merge', '--no-ff', '--no-edit', storyBranch);
75
- }
76
-
77
- /** Collect the list of files with unmerged paths after a failed merge. */
78
- function collectConflictFiles(cwd, git) {
79
- const result = git.gitSpawn(cwd, 'diff', '--name-only', '--diff-filter=U');
80
- if (result.status !== 0 || !result.stdout) return [];
81
- return result.stdout
82
- .split(/\r?\n/)
83
- .map((s) => s.trim())
84
- .filter(Boolean);
85
- }
86
-
87
- /**
88
- * Push `epicBranch` with a bounded retry on non-fast-forward rejections.
89
- *
90
- * The first attempt is a direct push (no fetch, no reapply) so single-session
91
- * runs behave identically to the pre-change path. Retries fetch the advanced
92
- * remote, reset local `<epicBranch>` to `origin/<epicBranch>`, and reapply
93
- * `<storyBranch>` via `merge --no-ff --no-edit`.
94
- *
95
- * @param {object} opts
96
- * @param {string} opts.cwd
97
- * @param {string} opts.epicBranch
98
- * @param {string} opts.storyBranch
99
- * @param {{ maxAttempts?: number, backoffMs?: number[] }} [opts.storyMergeRetry]
100
- * @param {{ gitSpawn: (cwd: string, ...args: string[]) => { status: number, stdout: string, stderr: string } }} opts.git
101
- * @param {(ms: number) => Promise<void>} [opts.sleep]
102
- * @param {(msg: string) => void} [opts.log]
103
- * @returns {Promise<{ ok: boolean, attempts: number, reason?: string, result: object }>}
104
- * @throws {PushRetryConflictError} On content conflict during re-apply.
105
- */
106
- export async function pushEpicWithRetry({
107
- cwd,
108
- epicBranch,
109
- storyBranch,
110
- storyMergeRetry,
111
- git,
112
- sleep = (ms) => new Promise((r) => setTimeout(r, ms)),
113
- log = () => {},
114
- mergeMessage = null,
115
- }) {
116
- if (!cwd) throw new Error('pushEpicWithRetry: cwd is required');
117
- if (!epicBranch) throw new Error('pushEpicWithRetry: epicBranch is required');
118
- if (!storyBranch)
119
- throw new Error('pushEpicWithRetry: storyBranch is required');
120
- if (!git || typeof git.gitSpawn !== 'function') {
121
- throw new Error('pushEpicWithRetry: git.gitSpawn injection is required');
122
- }
123
-
124
- const maxAttempts =
125
- storyMergeRetry?.maxAttempts ?? DEFAULT_STORY_MERGE_RETRY.maxAttempts;
126
- const backoffMs =
127
- storyMergeRetry?.backoffMs ?? DEFAULT_STORY_MERGE_RETRY.backoffMs;
128
-
129
- let lastResult;
130
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
131
- lastResult = git.gitSpawn(cwd, 'push', '--no-verify', 'origin', epicBranch);
132
- if (lastResult.status === 0) {
133
- return { ok: true, attempts: attempt, result: lastResult };
134
- }
135
-
136
- if (!isNonFastForwardPush(lastResult.stderr)) {
137
- return {
138
- ok: false,
139
- attempts: attempt,
140
- result: lastResult,
141
- reason: 'non-retryable-push-error',
142
- };
143
- }
144
-
145
- if (attempt === maxAttempts) {
146
- return {
147
- ok: false,
148
- attempts: attempt,
149
- result: lastResult,
150
- reason: 'retry-exhausted',
151
- };
152
- }
153
-
154
- const backoff = backoffMs[Math.min(attempt - 1, backoffMs.length - 1)] ?? 0;
155
- log(
156
- `[push-epic-retry] Push rejected (non-fast-forward) on attempt ` +
157
- `${attempt}/${maxAttempts}; fetching remote and reapplying after ` +
158
- `${backoff}ms backoff.`,
159
- );
160
- await sleep(backoff);
161
-
162
- const fetchResult = git.gitSpawn(cwd, 'fetch', 'origin', epicBranch);
163
- if (fetchResult.status !== 0) {
164
- return {
165
- ok: false,
166
- attempts: attempt,
167
- result: fetchResult,
168
- reason: 'fetch-failed',
169
- };
170
- }
171
-
172
- const resetResult = git.gitSpawn(
173
- cwd,
174
- 'reset',
175
- '--hard',
176
- `origin/${epicBranch}`,
177
- );
178
- if (resetResult.status !== 0) {
179
- return {
180
- ok: false,
181
- attempts: attempt,
182
- result: resetResult,
183
- reason: 'reset-failed',
184
- };
185
- }
186
-
187
- const mergeResult = runRetryMerge({
188
- cwd,
189
- git,
190
- storyBranch,
191
- mergeMessage,
192
- });
193
- if (mergeResult.status !== 0) {
194
- const conflicts = collectConflictFiles(cwd, git);
195
- git.gitSpawn(cwd, 'merge', '--abort');
196
- throw new PushRetryConflictError(
197
- conflicts,
198
- mergeResult.stderr || mergeResult.stdout || '',
199
- );
200
- }
201
- }
202
-
203
- return {
204
- ok: false,
205
- attempts: maxAttempts,
206
- result: lastResult,
207
- reason: 'retry-exhausted',
208
- };
209
- }
@@ -1,36 +0,0 @@
1
- /**
2
- * lib/spec/index.js — public surface for the spec I/O module.
3
- *
4
- * Re-exports the loader (and, in Wave 1, future spec utilities) so
5
- * downstream consumers — the reconciler, the rewritten /plan, the
6
- * wave-runner — can `import * from '../lib/spec/index.js'` without
7
- * reaching into individual submodules.
8
- *
9
- * The module intentionally re-exports only the public surface defined
10
- * by Story #1491; the loader's internal helpers (`_resetValidatorCacheForTests`,
11
- * `sortKeysDeep`, `renderStateJson`) remain importable from
12
- * `./loader.js` directly for tests but are not part of the consumer
13
- * contract.
14
- */
15
-
16
- export {
17
- loadSpec,
18
- loadState,
19
- SpecNotFoundError,
20
- SpecParseError,
21
- SpecValidationError,
22
- specPath,
23
- statePath,
24
- writeSpec,
25
- writeState,
26
- } from './loader.js';
27
-
28
- export {
29
- buildState,
30
- canonicalise,
31
- canonicalStringify,
32
- hashSpecEntry,
33
- iterSpecEntries,
34
- projectMapping,
35
- sha256Hex,
36
- } from './state.js';
@@ -1,425 +0,0 @@
1
- /**
2
- * lib/spec/loader.js — spec + state file I/O for the epic-spec reconciler.
3
- *
4
- * Owns the two files that bracket the structural SSOT migration (Epic
5
- * #1182 / Tech Spec #1483):
6
- *
7
- * - `temp/epic-<epic-id>/<epic-id>.yaml` — declarative spec (regenerated)
8
- * - `temp/epic-<epic-id>/<epic-id>.state.json` — slug→issue mapping (observed)
9
- *
10
- * Both files live under the per-Epic ephemeral tree `temp/epic-<id>/`
11
- * (already gitignored) so /plan reruns don't churn a tracked path
12
- * and so concurrent Epics never collide on a single shared directory.
13
- * Tests inject `opts.epicsDir` to point at a sandbox; the default for
14
- * production callers is derived from `lib/config/temp-paths.js#epicTempDir`.
15
- *
16
- * The module is intentionally a thin, dependency-light I/O layer:
17
- *
18
- * • `loadSpec(epicId)` → parses YAML, validates against
19
- * `.agents/schemas/epic-spec.schema.json` (Ajv2020). Throws a
20
- * `SpecValidationError` carrying the offending JSON Pointer paths
21
- * when the spec is structurally invalid. Missing file throws
22
- * `SpecNotFoundError`.
23
- * • `loadState(epicId)` → returns `{ epicId, mapping: {} }` (with
24
- * `lastReconciledAt` omitted) when the state file is missing, so
25
- * callers can start reconciling against a fresh Epic without a
26
- * pre-existing state file.
27
- * • `writeState(epicId, state)` → writes pretty-printed JSON with
28
- * deterministically sorted keys (recursive). Repeated writes of an
29
- * equivalent state produce a byte-identical file. Trailing newline
30
- * included so the file behaves well under git + POSIX `cat`.
31
- *
32
- * The loader does **not** make any GitHub calls; it is pure file I/O
33
- * over the two on-disk artefacts. The reconciler (Wave 1) layers diff
34
- * + apply on top of this surface.
35
- *
36
- * All public functions accept an optional `{ epicsDir, schemaPath, fs }`
37
- * options bag so tests can point the loader at a sandbox directory
38
- * without monkey-patching `process.cwd()` or the project schema path.
39
- *
40
- * Cross-references:
41
- * - Schema: `.agents/schemas/epic-spec.schema.json` (Story #1490)
42
- * - Fixtures: `tests/fixtures/epic-specs/*.json` (Story #1490)
43
- * - Tech Spec §"`.agents/epics/<epic-id>.yaml` (spec)" + §"state.json"
44
- */
45
-
46
- import {
47
- existsSync as defaultExistsSync,
48
- mkdirSync as defaultMkdirSync,
49
- readFileSync as defaultReadFileSync,
50
- writeFileSync as defaultWriteFileSync,
51
- } from 'node:fs';
52
- import path from 'node:path';
53
- import { fileURLToPath } from 'node:url';
54
- import Ajv2020 from 'ajv/dist/2020.js';
55
- import addFormats from 'ajv-formats';
56
- import yaml from 'js-yaml';
57
-
58
- import { epicTempDir } from '../config/temp-paths.js';
59
-
60
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
61
-
62
- // scripts/lib/spec/ → scripts/lib/ → scripts/ → .agents/
63
- const PROJECT_AGENTS_DIR = path.resolve(__dirname, '..', '..', '..');
64
- const DEFAULT_SCHEMA_PATH = path.join(
65
- PROJECT_AGENTS_DIR,
66
- 'schemas',
67
- 'epic-spec.schema.json',
68
- );
69
-
70
- // Resolve the default per-Epic spec directory under `temp/epic-<id>/`.
71
- // Caller-injected `opts.epicsDir` still wins for tests and any external
72
- // tooling that wants to point at a sandbox. Production callers omit the
73
- // option and route through this helper.
74
- function defaultEpicsDir(epicId) {
75
- return epicTempDir(epicId);
76
- }
77
-
78
- const defaultFsAdapter = Object.freeze({
79
- existsSync: defaultExistsSync,
80
- mkdirSync: defaultMkdirSync,
81
- readFileSync: defaultReadFileSync,
82
- writeFileSync: defaultWriteFileSync,
83
- });
84
-
85
- let cachedValidator = null;
86
- let cachedValidatorKey = null;
87
-
88
- /**
89
- * Compile (and cache) the Ajv2020 validator for the epic-spec schema.
90
- * Cached by absolute schema path so tests can swap to a sandbox schema.
91
- *
92
- * @param {string} schemaPath
93
- * @param {{ readFileSync: typeof defaultReadFileSync }} fs
94
- * @returns {(data: unknown) => boolean}
95
- */
96
- function getValidator(schemaPath, fs) {
97
- if (cachedValidator && cachedValidatorKey === schemaPath) {
98
- return cachedValidator;
99
- }
100
- const ajv = new Ajv2020({ allErrors: true, strict: false });
101
- addFormats(ajv);
102
- const schema = JSON.parse(fs.readFileSync(schemaPath, 'utf8'));
103
- cachedValidator = ajv.compile(schema);
104
- cachedValidatorKey = schemaPath;
105
- return cachedValidator;
106
- }
107
-
108
- /**
109
- * Test-only hook: drop the cached validator so a subsequent call
110
- * recompiles. Safe to leave exported — production code never invokes it.
111
- */
112
- export function _resetValidatorCacheForTests() {
113
- cachedValidator = null;
114
- cachedValidatorKey = null;
115
- }
116
-
117
- /**
118
- * Structured error raised by `loadSpec` when the YAML parses but fails
119
- * schema validation. The Ajv error list is normalised to an array of
120
- * `{ path, message }` so callers (reconciler CLI, tests) can render the
121
- * offending JSON Pointer without re-parsing the Ajv envelope.
122
- */
123
- export class SpecValidationError extends Error {
124
- /**
125
- * @param {string} epicId
126
- * @param {Array<{path: string, message: string, params?: object}>} issues
127
- */
128
- constructor(epicId, issues) {
129
- const head = issues[0] ?? { path: '/', message: 'unknown' };
130
- super(
131
- `Spec for epic ${epicId} failed schema validation at ${head.path}: ${head.message}`,
132
- );
133
- this.name = 'SpecValidationError';
134
- this.epicId = epicId;
135
- this.issues = issues;
136
- }
137
- }
138
-
139
- /**
140
- * Raised by `loadSpec` when the on-disk YAML file does not exist.
141
- */
142
- export class SpecNotFoundError extends Error {
143
- /**
144
- * @param {string} epicId
145
- * @param {string} filePath
146
- */
147
- constructor(epicId, filePath) {
148
- super(`Spec file missing for epic ${epicId}: ${filePath}`);
149
- this.name = 'SpecNotFoundError';
150
- this.epicId = epicId;
151
- this.filePath = filePath;
152
- }
153
- }
154
-
155
- /**
156
- * Raised by `loadSpec` when the file exists but is not parseable YAML.
157
- */
158
- export class SpecParseError extends Error {
159
- /**
160
- * @param {string} epicId
161
- * @param {string} filePath
162
- * @param {Error} cause
163
- */
164
- constructor(epicId, filePath, cause) {
165
- super(
166
- `Spec file for epic ${epicId} is not valid YAML (${filePath}): ${cause.message}`,
167
- );
168
- this.name = 'SpecParseError';
169
- this.epicId = epicId;
170
- this.filePath = filePath;
171
- this.cause = cause;
172
- }
173
- }
174
-
175
- function resolveOpts(epicId, opts = {}) {
176
- return {
177
- epicsDir: opts.epicsDir ?? defaultEpicsDir(epicId),
178
- schemaPath: opts.schemaPath ?? DEFAULT_SCHEMA_PATH,
179
- fs: opts.fs ?? defaultFsAdapter,
180
- };
181
- }
182
-
183
- /**
184
- * Resolve the on-disk spec path for `epicId` under the configured
185
- * epics dir. Exported for tests and for the reconciler CLI's error
186
- * messages.
187
- *
188
- * @param {number|string} epicId
189
- * @param {{epicsDir?: string}} [opts]
190
- * @returns {string}
191
- */
192
- export function specPath(epicId, opts = {}) {
193
- const { epicsDir } = resolveOpts(epicId, opts);
194
- return path.join(epicsDir, `${String(epicId)}.yaml`);
195
- }
196
-
197
- /**
198
- * Resolve the on-disk state path for `epicId` under the configured
199
- * epics dir.
200
- *
201
- * @param {number|string} epicId
202
- * @param {{epicsDir?: string}} [opts]
203
- * @returns {string}
204
- */
205
- export function statePath(epicId, opts = {}) {
206
- const { epicsDir } = resolveOpts(epicId, opts);
207
- return path.join(epicsDir, `${String(epicId)}.state.json`);
208
- }
209
-
210
- /**
211
- * Convert Ajv's error array into the loader's `{ path, message }`
212
- * shape. Ajv2020 uses `instancePath` for the JSON Pointer into the
213
- * data; for `required` errors it leaves the missing property in
214
- * `params.missingProperty` rather than the path, so we append it so
215
- * the caller sees `/epic` instead of `` (root) for the canonical
216
- * `epic required` failure.
217
- *
218
- * @param {Array<{instancePath:string,message:string,keyword:string,params?:Record<string,unknown>}>} ajvErrors
219
- * @returns {Array<{path:string,message:string,params?:object}>}
220
- */
221
- function normaliseAjvErrors(ajvErrors) {
222
- return ajvErrors.map((err) => {
223
- let p = err.instancePath || '/';
224
- if (
225
- err.keyword === 'required' &&
226
- typeof err.params?.missingProperty === 'string'
227
- ) {
228
- const sep = p === '/' ? '' : '/';
229
- p = `${p}${sep}${err.params.missingProperty}`;
230
- }
231
- return {
232
- path: p,
233
- message: err.message ?? 'validation failed',
234
- params: err.params,
235
- };
236
- });
237
- }
238
-
239
- /**
240
- * Load and validate the spec YAML for `epicId`. Returns the parsed
241
- * JavaScript object on success. Throws `SpecNotFoundError`,
242
- * `SpecParseError`, or `SpecValidationError` otherwise.
243
- *
244
- * @param {number|string} epicId
245
- * @param {{epicsDir?: string, schemaPath?: string, fs?: typeof defaultFsAdapter}} [opts]
246
- * @returns {object}
247
- */
248
- export function loadSpec(epicId, opts = {}) {
249
- const { schemaPath, fs } = resolveOpts(epicId, opts);
250
- const filePath = specPath(epicId, opts);
251
-
252
- if (!fs.existsSync(filePath)) {
253
- throw new SpecNotFoundError(String(epicId), filePath);
254
- }
255
-
256
- const raw = fs.readFileSync(filePath, 'utf8');
257
- let parsed;
258
- try {
259
- parsed = yaml.load(raw, { filename: filePath });
260
- } catch (err) {
261
- throw new SpecParseError(String(epicId), filePath, err);
262
- }
263
-
264
- if (parsed == null || typeof parsed !== 'object') {
265
- throw new SpecValidationError(String(epicId), [
266
- {
267
- path: '/',
268
- message: 'spec root must be an object',
269
- },
270
- ]);
271
- }
272
-
273
- const validate = getValidator(schemaPath, fs);
274
- const ok = validate(parsed);
275
- if (!ok) {
276
- throw new SpecValidationError(
277
- String(epicId),
278
- normaliseAjvErrors(validate.errors ?? []),
279
- );
280
- }
281
-
282
- return parsed;
283
- }
284
-
285
- /**
286
- * Empty-state default. `loadState` returns this shape when the state
287
- * file does not exist; callers can rely on `mapping` being a plain
288
- * object (never undefined).
289
- *
290
- * @param {number|string} epicId
291
- * @returns {{epicId: number, mapping: Record<string, never>}}
292
- */
293
- function emptyState(epicId) {
294
- return { epicId: Number(epicId), mapping: {} };
295
- }
296
-
297
- /**
298
- * Load the state file for `epicId`. Returns an empty mapping when the
299
- * file is missing (the canonical "fresh Epic" case the reconciler
300
- * faces on first apply). Throws if the file exists but is not valid
301
- * JSON.
302
- *
303
- * @param {number|string} epicId
304
- * @param {{epicsDir?: string, fs?: typeof defaultFsAdapter}} [opts]
305
- * @returns {{epicId: number, mapping: object, lastReconciledAt?: string}}
306
- */
307
- export function loadState(epicId, opts = {}) {
308
- const { fs } = resolveOpts(epicId, opts);
309
- const filePath = statePath(epicId, opts);
310
-
311
- if (!fs.existsSync(filePath)) {
312
- return emptyState(epicId);
313
- }
314
-
315
- const raw = fs.readFileSync(filePath, 'utf8');
316
- return JSON.parse(raw);
317
- }
318
-
319
- /**
320
- * Recursively sort object keys (arrays preserve order). Returns a new
321
- * value with the same shape — leaves are returned unchanged.
322
- *
323
- * Exported for `state-writer.js` so the hashing path can share the
324
- * exact same canonicalisation as the file writer.
325
- *
326
- * @param {unknown} value
327
- * @returns {unknown}
328
- */
329
- export function sortKeysDeep(value) {
330
- if (Array.isArray(value)) {
331
- return value.map(sortKeysDeep);
332
- }
333
- if (value && typeof value === 'object') {
334
- const out = {};
335
- for (const key of Object.keys(value).sort()) {
336
- out[key] = sortKeysDeep(value[key]);
337
- }
338
- return out;
339
- }
340
- return value;
341
- }
342
-
343
- /**
344
- * Render `state` to deterministic JSON. Public so the test suite can
345
- * assert the byte-identical-roundtrip property without re-implementing
346
- * the formatter.
347
- *
348
- * @param {object} state
349
- * @returns {string} pretty-printed JSON, terminated by a single newline.
350
- */
351
- export function renderStateJson(state) {
352
- return `${JSON.stringify(sortKeysDeep(state), null, 2)}\n`;
353
- }
354
-
355
- /**
356
- * Write the state file for `epicId`. Creates the parent directory
357
- * lazily. Object keys are recursively sorted so re-writing the same
358
- * logical state produces a byte-identical file (AC: "diffs stay
359
- * stable", "byte-identical when written twice").
360
- *
361
- * Returns the absolute path written so callers can log it.
362
- *
363
- * @param {number|string} epicId
364
- * @param {object} state
365
- * @param {{epicsDir?: string, fs?: typeof defaultFsAdapter}} [opts]
366
- * @returns {string}
367
- */
368
- export function writeState(epicId, state, opts = {}) {
369
- const { epicsDir, fs } = resolveOpts(epicId, opts);
370
- if (!fs.existsSync(epicsDir)) {
371
- fs.mkdirSync(epicsDir, { recursive: true });
372
- }
373
- const filePath = statePath(epicId, opts);
374
- fs.writeFileSync(filePath, renderStateJson(state), 'utf8');
375
- return filePath;
376
- }
377
-
378
- /**
379
- * Write the spec YAML file for `epicId`. Creates the parent directory
380
- * lazily and emits a top-level `$schema` reference so editors with
381
- * YAML-schema autocomplete (e.g. the Red Hat YAML extension) resolve
382
- * the schema from the file itself.
383
- *
384
- * Story #1498 / Task #1525 introduced this writer so the rewritten
385
- * `/plan` halves can persist the spec from the decomposer's
386
- * ticket-array projection (`renderSpec`) without reaching into raw
387
- * `js-yaml` calls scattered across the planning scripts.
388
- *
389
- * The function validates the spec via the same Ajv2020 compiler the
390
- * loader caches — a malformed spec is rejected synchronously instead of
391
- * being persisted and tripping `loadSpec` on the next reconciler run.
392
- *
393
- * @param {number|string} epicId
394
- * @param {object} spec spec object matching `epic-spec.schema.json`.
395
- * @param {{epicsDir?: string, schemaPath?: string, fs?: typeof defaultFsAdapter}} [opts]
396
- * @returns {string} the absolute path written.
397
- */
398
- export function writeSpec(epicId, spec, opts = {}) {
399
- const { epicsDir, schemaPath, fs } = resolveOpts(epicId, opts);
400
- if (!spec || typeof spec !== 'object') {
401
- throw new TypeError('[writeSpec] spec must be an object');
402
- }
403
- const validate = getValidator(schemaPath, fs);
404
- const ok = validate(spec);
405
- if (!ok) {
406
- throw new SpecValidationError(
407
- String(epicId),
408
- normaliseAjvErrors(validate.errors ?? []),
409
- );
410
- }
411
- if (!fs.existsSync(epicsDir)) {
412
- fs.mkdirSync(epicsDir, { recursive: true });
413
- }
414
- const filePath = specPath(epicId, opts);
415
- // Lazy require: `js-yaml` is already a runtime dep of the loader, but
416
- // keeping the import top-level would force every consumer of `loader.js`
417
- // to pay the parse cost even when they only need state helpers.
418
- const yamlDump = yaml.dump(spec, {
419
- noRefs: true,
420
- sortKeys: false,
421
- lineWidth: 120,
422
- });
423
- fs.writeFileSync(filePath, yamlDump, 'utf8');
424
- return filePath;
425
- }