mandrel 1.93.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/.agents/README.md +59 -73
  2. package/.agents/agents/acceptance-critic.md +129 -0
  3. package/.agents/agents/story-worker.md +161 -0
  4. package/.agents/docs/SDLC.md +489 -1285
  5. package/.agents/docs/agentrc-reference.json +177 -67
  6. package/.agents/docs/configuration.md +108 -136
  7. package/.agents/docs/execution-reference.md +44 -22
  8. package/.agents/docs/quality-gates.md +13 -19
  9. package/.agents/docs/workflows.md +3 -3
  10. package/.agents/instructions.md +107 -108
  11. package/.agents/rules/ci-remediation.md +8 -12
  12. package/.agents/rules/git-conventions-reference.md +224 -0
  13. package/.agents/rules/git-conventions.md +42 -223
  14. package/.agents/rules/security-baseline.md +5 -0
  15. package/.agents/rules/testing-standards.md +106 -13
  16. package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
  17. package/.agents/schemas/agentrc.schema.json +71 -201
  18. package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
  20. package/.agents/schemas/risk-verdict.schema.json +0 -13
  21. package/.agents/scripts/acceptance-eval.js +62 -18
  22. package/.agents/scripts/agents-bootstrap-github.js +1 -1
  23. package/.agents/scripts/analyze-execution.js +1 -1
  24. package/.agents/scripts/audit-to-stories.js +7 -7
  25. package/.agents/scripts/boot-sweep.js +1 -1
  26. package/.agents/scripts/check-context-budget.js +62 -5
  27. package/.agents/scripts/check-lifecycle-lint.js +6 -9
  28. package/.agents/scripts/check-prepush-recovery.js +1 -1
  29. package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
  30. package/.agents/scripts/diagnose-friction.js +0 -6
  31. package/.agents/scripts/lib/Logger.js +6 -10
  32. package/.agents/scripts/lib/audit-suite/runner.js +2 -2
  33. package/.agents/scripts/lib/audit-suite/selector.js +5 -5
  34. package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
  35. package/.agents/scripts/lib/baselines/kernel.js +206 -18
  36. package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -4
  37. package/.agents/scripts/lib/baselines/reader.js +1 -6
  38. package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
  39. package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
  40. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +56 -18
  41. package/.agents/scripts/lib/checks/core-bare-clean.js +2 -2
  42. package/.agents/scripts/lib/checks/index.js +2 -1
  43. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +23 -21
  44. package/.agents/scripts/lib/cli/standard-args.js +13 -22
  45. package/.agents/scripts/lib/cli-args.js +16 -7
  46. package/.agents/scripts/lib/close-validation/gates.js +160 -22
  47. package/.agents/scripts/lib/config/acceptance-eval.js +52 -5
  48. package/.agents/scripts/lib/config/ci.js +6 -31
  49. package/.agents/scripts/lib/config/delivery-routing.js +103 -0
  50. package/.agents/scripts/lib/config/explain.js +57 -36
  51. package/.agents/scripts/lib/config/limits.js +17 -58
  52. package/.agents/scripts/lib/config/paths.js +0 -2
  53. package/.agents/scripts/lib/config/quality.js +1 -1
  54. package/.agents/scripts/lib/config/runners.js +17 -50
  55. package/.agents/scripts/lib/config/temp-paths.js +19 -14
  56. package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
  57. package/.agents/scripts/lib/config-resolver.js +3 -8
  58. package/.agents/scripts/lib/config-settings-schema-delivery.js +46 -136
  59. package/.agents/scripts/lib/config-settings-schema-quality.js +17 -14
  60. package/.agents/scripts/lib/config-settings-schema.js +52 -38
  61. package/.agents/scripts/lib/dependency-parser.js +3 -2
  62. package/.agents/scripts/lib/doc-tiers.js +39 -4
  63. package/.agents/scripts/lib/duplicate-search.js +211 -41
  64. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
  65. package/.agents/scripts/lib/findings/promote-finding.js +5 -5
  66. package/.agents/scripts/lib/framework-version.js +2 -3
  67. package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
  68. package/.agents/scripts/lib/git-branch-lifecycle.js +17 -22
  69. package/.agents/scripts/lib/git-utils.js +32 -6
  70. package/.agents/scripts/lib/github/framework-repo.js +6 -0
  71. package/.agents/scripts/lib/label-constants.js +10 -23
  72. package/.agents/scripts/lib/label-taxonomy.js +9 -43
  73. package/.agents/scripts/lib/observability/active-story-env.js +112 -3
  74. package/.agents/scripts/lib/observability/hook-heartbeat.js +187 -0
  75. package/.agents/scripts/lib/observability/source-classifier.js +3 -3
  76. package/.agents/scripts/lib/observability/tool-trace-hook.js +15 -4
  77. package/.agents/scripts/lib/onboard/init-tail.js +1 -3
  78. package/.agents/scripts/lib/orchestration/acceptance-clusters.js +111 -0
  79. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +32 -4
  80. package/.agents/scripts/lib/orchestration/audit-lens-routing.js +128 -0
  81. package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +273 -0
  82. package/.agents/scripts/lib/orchestration/ceremony-routing.js +204 -0
  83. package/.agents/scripts/lib/orchestration/code-review.js +20 -268
  84. package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
  85. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +1 -1
  86. package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
  87. package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
  88. package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
  89. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
  90. package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +8 -8
  91. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +2 -2
  92. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
  93. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +17 -43
  94. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
  95. package/.agents/scripts/lib/orchestration/merge-block-class.js +1 -1
  96. package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
  97. package/.agents/scripts/lib/orchestration/plan-context.js +248 -266
  98. package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +3 -2
  99. package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +1 -1
  100. package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
  101. package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +61 -0
  102. package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +97 -0
  103. package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +223 -854
  104. package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +361 -0
  105. package/.agents/scripts/lib/orchestration/plan-persist/summary.js +35 -108
  106. package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
  107. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
  108. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +14 -14
  109. package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
  110. package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/risk-verdict.js +3 -4
  111. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +2 -2
  112. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +8 -20
  113. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -2
  114. package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
  115. package/.agents/scripts/lib/orchestration/preflight-cache.js +5 -5
  116. package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
  117. package/.agents/scripts/lib/orchestration/resolve-plan-run.js +155 -0
  118. package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
  119. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +8 -8
  120. package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
  121. package/.agents/scripts/lib/orchestration/review-depth.js +26 -12
  122. package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
  123. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
  124. package/.agents/scripts/lib/orchestration/run-epilogue.js +426 -0
  125. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +1 -1
  126. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +1 -0
  127. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +95 -41
  128. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +16 -13
  129. package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +40 -0
  130. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +11 -3
  131. package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
  132. package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
  133. package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
  134. package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
  135. package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
  136. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +15 -12
  137. package/.agents/scripts/lib/orchestration/story-follow-ups.js +237 -0
  138. package/.agents/scripts/lib/orchestration/story-init-remote.js +47 -0
  139. package/.agents/scripts/lib/orchestration/story-plan-state.js +48 -0
  140. package/.agents/scripts/lib/orchestration/{epic-runner → story-progress}/story-run-progress-writer.js +3 -3
  141. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
  142. package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -18
  143. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +11 -61
  144. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +189 -373
  145. package/.agents/scripts/lib/orchestration/ticket-validator.js +3 -8
  146. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +0 -25
  147. package/.agents/scripts/lib/orchestration/ticketing/reads.js +29 -26
  148. package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -5
  149. package/.agents/scripts/lib/planning-corpus.js +16 -11
  150. package/.agents/scripts/lib/preflight-runner.js +2 -2
  151. package/.agents/scripts/lib/provider-factory.js +1 -1
  152. package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
  153. package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +36 -0
  154. package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
  155. package/.agents/scripts/lib/story-adjacency.js +11 -14
  156. package/.agents/scripts/lib/story-body/story-body.js +124 -70
  157. package/.agents/scripts/lib/story-plan.js +2 -4
  158. package/.agents/scripts/lib/templates/decomposer-prompts.js +46 -45
  159. package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
  160. package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +26 -26
  161. package/.agents/scripts/lib/validation-evidence.js +1 -1
  162. package/.agents/scripts/lib/wave-runner/ready-set.js +6 -6
  163. package/.agents/scripts/lib/workspace-provisioner.js +1 -1
  164. package/.agents/scripts/lib/worktree/lifecycle/reap.js +5 -7
  165. package/.agents/scripts/lint-issue-body.js +71 -40
  166. package/.agents/scripts/mandrel-update-preflight.js +1 -1
  167. package/.agents/scripts/notify.js +4 -3
  168. package/.agents/scripts/plan-context.js +64 -74
  169. package/.agents/scripts/plan-persist.js +121 -280
  170. package/.agents/scripts/plan-run-epilogue.js +97 -0
  171. package/.agents/scripts/post-structured-comment.js +38 -0
  172. package/.agents/scripts/providers/github/issues.js +17 -33
  173. package/.agents/scripts/providers/github/mappers.js +0 -12
  174. package/.agents/scripts/providers/github/tickets.js +2 -5
  175. package/.agents/scripts/resolve-plan-run.js +117 -0
  176. package/.agents/scripts/signals-view.js +24 -19
  177. package/.agents/scripts/single-story-close.js +11 -14
  178. package/.agents/scripts/single-story-confirm-merge.js +39 -23
  179. package/.agents/scripts/single-story-init.js +29 -20
  180. package/.agents/scripts/stories-wave-tick.js +6 -6
  181. package/.agents/scripts/story-plan.js +26 -47
  182. package/.agents/scripts/sync-claude-agents.js +165 -0
  183. package/.agents/scripts/update-ticket-state.js +37 -15
  184. package/.agents/skills/core/analyze-execution/SKILL.md +21 -18
  185. package/.agents/skills/core/api-and-interface-design/SKILL.md +5 -3
  186. package/.agents/skills/core/code-review-and-quality/SKILL.md +63 -7
  187. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +1 -1
  188. package/.agents/skills/core/gates-and-baselines/SKILL.md +149 -0
  189. package/.agents/skills/core/idea-refinement/SKILL.md +8 -14
  190. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +7 -7
  191. package/.agents/skills/core/scope-triage/SKILL.md +28 -172
  192. package/.agents/skills/skills.index.json +8 -418
  193. package/.agents/starter-agentrc.json +0 -5
  194. package/.agents/templates/agent-protocol.md +9 -10
  195. package/.agents/workflows/audit-architecture.md +3 -3
  196. package/.agents/workflows/audit-clean-code.md +3 -3
  197. package/.agents/workflows/audit-dependencies.md +3 -3
  198. package/.agents/workflows/audit-devops.md +3 -3
  199. package/.agents/workflows/audit-documentation.md +5 -5
  200. package/.agents/workflows/audit-lighthouse.md +3 -3
  201. package/.agents/workflows/audit-navigability.md +3 -2
  202. package/.agents/workflows/audit-performance.md +3 -3
  203. package/.agents/workflows/audit-privacy.md +3 -3
  204. package/.agents/workflows/audit-quality.md +3 -3
  205. package/.agents/workflows/audit-security.md +3 -3
  206. package/.agents/workflows/audit-seo.md +3 -3
  207. package/.agents/workflows/audit-sre.md +3 -3
  208. package/.agents/workflows/audit-to-stories.md +20 -20
  209. package/.agents/workflows/audit-ux-ui.md +3 -3
  210. package/.agents/workflows/deliver.md +122 -131
  211. package/.agents/workflows/git-cleanup.md +3 -4
  212. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  213. package/.agents/workflows/helpers/acceptance-self-eval.md +52 -40
  214. package/.agents/workflows/helpers/code-review.md +70 -193
  215. package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +12 -14
  216. package/.agents/workflows/helpers/{single-story-deliver.md → deliver-story.md} +113 -139
  217. package/.agents/workflows/helpers/diagnose.md +10 -10
  218. package/.agents/workflows/helpers/mandrel-sync-config.md +1 -1
  219. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  220. package/.agents/workflows/helpers/signals.md +16 -16
  221. package/.agents/workflows/helpers/worktree-lifecycle.md +48 -64
  222. package/.agents/workflows/mandrel-update.md +3 -2
  223. package/.agents/workflows/plan.md +112 -145
  224. package/.agents/workflows/qa-assist.md +24 -30
  225. package/.agents/workflows/qa-explore.md +29 -38
  226. package/.agents/workflows/qa-run.md +2 -2
  227. package/README.md +9 -8
  228. package/docs/CHANGELOG.md +46 -0
  229. package/lib/cli/registry.js +95 -0
  230. package/lib/migrations/index.js +6 -5
  231. package/package.json +5 -3
  232. package/.agents/personas/architect.md +0 -113
  233. package/.agents/personas/devops-engineer.md +0 -38
  234. package/.agents/personas/engineer-mobile.md +0 -120
  235. package/.agents/personas/engineer-web.md +0 -111
  236. package/.agents/personas/engineer.md +0 -119
  237. package/.agents/personas/product.md +0 -94
  238. package/.agents/personas/project-manager.md +0 -114
  239. package/.agents/personas/qa-engineer.md +0 -95
  240. package/.agents/personas/refactorer.md +0 -113
  241. package/.agents/personas/security-engineer.md +0 -112
  242. package/.agents/personas/sre.md +0 -86
  243. package/.agents/personas/technical-writer.md +0 -101
  244. package/.agents/personas/ux-designer.md +0 -95
  245. package/.agents/schemas/dispatch-manifest.json +0 -232
  246. package/.agents/schemas/epic-spec.schema.json +0 -153
  247. package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
  248. package/.agents/scripts/dispatcher.js +0 -295
  249. package/.agents/scripts/epic-audit-prepare.js +0 -497
  250. package/.agents/scripts/epic-audit-recheck.js +0 -274
  251. package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
  252. package/.agents/scripts/epic-deliver-preflight.js +0 -462
  253. package/.agents/scripts/epic-deliver-prepare.js +0 -590
  254. package/.agents/scripts/epic-execute-record-wave.js +0 -449
  255. package/.agents/scripts/epic-plan-clarity.js +0 -211
  256. package/.agents/scripts/epic-plan-decompose.js +0 -54
  257. package/.agents/scripts/epic-plan-healthcheck.js +0 -581
  258. package/.agents/scripts/epic-plan-spec.js +0 -64
  259. package/.agents/scripts/epic-reconcile.js +0 -625
  260. package/.agents/scripts/lib/baseline-snapshot.js +0 -979
  261. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
  262. package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
  263. package/.agents/scripts/lib/config/lifecycle.js +0 -40
  264. package/.agents/scripts/lib/config/preflight.js +0 -58
  265. package/.agents/scripts/lib/config/retro.js +0 -77
  266. package/.agents/scripts/lib/epic-merge-lock.js +0 -322
  267. package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
  268. package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
  269. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -660
  270. package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
  271. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
  272. package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
  273. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
  274. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
  275. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
  276. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
  277. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
  278. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
  279. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
  280. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
  281. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
  282. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
  283. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
  284. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
  285. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
  286. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
  287. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
  288. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -388
  289. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
  290. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
  291. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
  292. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
  293. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
  294. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
  295. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
  296. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
  297. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
  298. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
  299. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
  300. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
  301. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
  302. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
  303. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
  304. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
  305. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
  306. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
  307. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
  308. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
  309. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
  310. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
  311. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
  312. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
  313. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -384
  314. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
  315. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
  316. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
  317. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -278
  318. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
  319. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
  320. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
  321. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
  322. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
  323. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
  324. package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
  325. package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
  326. package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
  327. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
  328. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
  329. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
  330. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
  331. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
  332. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
  333. package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
  334. package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
  335. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +0 -109
  336. package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
  337. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
  338. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
  339. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
  340. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
  341. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
  342. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
  343. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
  344. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
  345. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
  346. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
  347. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
  348. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
  349. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
  350. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
  351. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
  352. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
  353. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
  354. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
  355. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
  356. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
  357. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
  358. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
  359. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
  360. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
  361. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -301
  362. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
  363. package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
  364. package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
  365. package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
  366. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
  367. package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
  368. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
  369. package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
  370. package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
  371. package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
  372. package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
  373. package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
  374. package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
  375. package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
  376. package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
  377. package/.agents/scripts/lib/push-epic-retry.js +0 -209
  378. package/.agents/scripts/lib/spec/index.js +0 -36
  379. package/.agents/scripts/lib/spec/loader.js +0 -425
  380. package/.agents/scripts/lib/spec/state.js +0 -208
  381. package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
  382. package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
  383. package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
  384. package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
  385. package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
  386. package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
  387. package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
  388. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
  389. package/.agents/scripts/lib/wave-runner/tick.js +0 -754
  390. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
  391. package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
  392. package/.agents/scripts/lifecycle-emit.js +0 -510
  393. package/.agents/scripts/plan-critics.js +0 -199
  394. package/.agents/scripts/retro-run.js +0 -218
  395. package/.agents/scripts/standalone-feedback-rollup.js +0 -188
  396. package/.agents/scripts/story-close.js +0 -294
  397. package/.agents/scripts/story-init.js +0 -599
  398. package/.agents/scripts/story-phase.js +0 -369
  399. package/.agents/scripts/wave-tick.js +0 -335
  400. package/.agents/skills/core/baseline-refresh/SKILL.md +0 -181
  401. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +0 -274
  402. package/.agents/skills/core/ci-cd-and-automation/examples.md +0 -211
  403. package/.agents/skills/core/code-simplification/SKILL.md +0 -389
  404. package/.agents/skills/core/context-engineering/SKILL.md +0 -309
  405. package/.agents/skills/core/context-engineering/examples.md +0 -58
  406. package/.agents/skills/core/deprecation-and-migration/SKILL.md +0 -250
  407. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
  408. package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
  409. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
  410. package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
  411. package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
  412. package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
  413. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -413
  414. package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
  415. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +0 -357
  416. package/.agents/skills/core/hydrate-context/SKILL.md +0 -123
  417. package/.agents/skills/core/idea-refinement/examples.md +0 -437
  418. package/.agents/skills/core/idea-refinement/frameworks.md +0 -135
  419. package/.agents/skills/core/incremental-implementation/SKILL.md +0 -271
  420. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +0 -213
  421. package/.agents/skills/core/knowledge-transfer/SKILL.md +0 -180
  422. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +0 -117
  423. package/.agents/skills/core/performance-optimization/SKILL.md +0 -314
  424. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +0 -277
  425. package/.agents/skills/core/property-based-testing/SKILL.md +0 -148
  426. package/.agents/skills/core/refactoring-discipline/SKILL.md +0 -111
  427. package/.agents/skills/core/shipping-and-launch/SKILL.md +0 -328
  428. package/.agents/skills/core/spec-driven-development/SKILL.md +0 -252
  429. package/.agents/skills/core/test-driven-development/SKILL.md +0 -475
  430. package/.agents/skills/core/using-agent-skills/SKILL.md +0 -232
  431. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +0 -31
  432. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +0 -51
  433. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +0 -76
  434. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +0 -31
  435. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +0 -33
  436. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +0 -31
  437. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +0 -51
  438. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +0 -54
  439. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +0 -29
  440. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +0 -30
  441. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +0 -57
  442. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +0 -9
  443. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +0 -48
  444. package/.agents/skills/stack/frontend/astro/SKILL.md +0 -62
  445. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +0 -30
  446. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +0 -29
  447. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +0 -50
  448. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +0 -58
  449. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +0 -34
  450. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +0 -51
  451. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +0 -199
  452. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +0 -68
  453. package/.agents/workflows/helpers/deliver-epic-reference.md +0 -534
  454. package/.agents/workflows/helpers/deliver-epic.md +0 -955
  455. package/.agents/workflows/helpers/deliver-stories.md +0 -440
  456. package/.agents/workflows/helpers/epic-audit.md +0 -189
  457. package/.agents/workflows/helpers/epic-deliver-story.md +0 -427
  458. package/.agents/workflows/helpers/epic-testing.md +0 -125
  459. package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
  460. package/.agents/workflows/helpers/plan-epic.md +0 -351
  461. package/.agents/workflows/helpers/plan-story.md +0 -251
  462. package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
  463. /package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +0 -0
@@ -1,658 +0,0 @@
1
- /**
2
- * merge-runner.js — collapse the duplicated epic-merge-lock try/finally and
3
- * the duplicated `pushEpicWithRetry` + `PushRetryConflictError` envelope
4
- * into two reusable helpers used by both finalizeMerge and
5
- * completeInProgressMerge.
6
- *
7
- * Extracted from story-close.js (Story #955, Theme A part 1) so the close
8
- * orchestrator becomes a thin CLI shell.
9
- *
10
- * `withEpicMergeLock` wraps acquire → user fn → release in a single
11
- * try/finally with consistent `🔒 Acquired` / `🔓 Released` log lines.
12
- * Acquisition failure throws a single, operator-actionable Error mentioning
13
- * the lock-file path so a stale lock can be cleared by hand.
14
- *
15
- * `pushEpicAndHandleConflicts` wraps `pushEpicWithRetry` + the
16
- * `PushRetryConflictError` → throw envelope, plus the retry-exhausted / * generic-failure → throw envelope used by `runFinalizeMerge`. The resume
17
- * path (`runResumeMerge`) shares the same envelope but routes generic
18
- * failures through the `describeResumePushFailure` helper for consistent
19
- * operator-facing copy (see `comment-bodies.js`). Errors thrown from these
20
- * helpers reach the `runAsCli` boundary in `story-close.js` and are mapped
21
- * to `process.exit(1)` (Story #959 — close-tail scripts must throw rather
22
- * than route through the logger's fatal sink, see
23
- * `.agents/instructions.md`).
24
- *
25
- * Both helpers are dependency-injected: the lock acquire/release pair and
26
- * the push retry runner are parameters so unit tests can pin behaviour
27
- * without spawning the close script. Default arguments point at the
28
- * production wiring from `lib/epic-merge-lock.js` + `lib/push-epic-retry.js`.
29
- */
30
-
31
- import fs from 'node:fs';
32
- import path from 'node:path';
33
- import { getRunners as defaultGetRunners } from '../../config/runners.js';
34
- import { resolveWorkingPath } from '../../config-resolver.js';
35
- import {
36
- acquireEpicMergeLock as defaultAcquire,
37
- releaseEpicMergeLock as defaultRelease,
38
- resolveGitCommonDir,
39
- } from '../../epic-merge-lock.js';
40
- import { mergeFeatureBranch } from '../../git-merge-orchestrator.js';
41
- import {
42
- gitSpawn as defaultGitSpawn,
43
- gitSync as defaultGitSync,
44
- } from '../../git-utils.js';
45
- import { Logger as DefaultLogger } from '../../Logger.js';
46
- import {
47
- pushEpicWithRetry as defaultPushEpicWithRetry,
48
- PushRetryConflictError,
49
- } from '../../push-epic-retry.js';
50
- import {
51
- buildResumeMergeCommitMsg,
52
- describeResumePushFailure,
53
- } from './comment-bodies.js';
54
- import {
55
- buildMergeMessageWithCap,
56
- loadHeaderMaxLength,
57
- } from './merge-subject.js';
58
- import {
59
- assertNoForeignEpicLock as defaultAssertNoForeignEpicLock,
60
- assertSharedCheckoutAvailable as defaultAssertSharedCheckoutAvailable,
61
- } from './shared-checkout-guard.js';
62
-
63
- /**
64
- * Render the lock-file path for a given main-repo `cwd` + `epicId`. Pure;
65
- * exported so the operator-facing error message stays a single source of
66
- * truth.
67
- */
68
- export function lockPathDisplay(cwd, epicId) {
69
- return path.join(resolveGitCommonDir(cwd), `epic-${epicId}.merge.lock`);
70
- }
71
-
72
- /**
73
- * Best-effort `story.blocked` lifecycle emit (Story #2241 / Task #2247).
74
- * Used by the merge runner's failure paths to surface a typed `reason`
75
- * on the bus before re-throwing. The bus is optional — every legacy
76
- * caller and the existing unit fixtures pass `null` — and emit failures
77
- * are swallowed so the original throw (which the operator must see)
78
- * always reaches `runAsCli`.
79
- *
80
- * Exported so the wider story-close path (and the spawn-timeout helper
81
- * in `story-close.js`) can use the same low-friction wrapper.
82
- *
83
- * @param {{
84
- * bus?: object|null,
85
- * storyId: number|string,
86
- * reason: string,
87
- * logger?: { warn?: Function },
88
- * }} args
89
- * @returns {Promise<void>}
90
- */
91
- export async function emitStoryBlockedSafe({ bus, storyId, reason, logger }) {
92
- if (!bus) return;
93
- try {
94
- await bus.emit('story.blocked', {
95
- storyId: Number(storyId),
96
- reason: String(reason),
97
- });
98
- } catch (err) {
99
- logger?.warn?.(
100
- `[story-close] ⚠️ story.blocked emit failed for #${storyId} (swallowed): ${err?.message ?? err}`,
101
- );
102
- }
103
- }
104
-
105
- /**
106
- * Canonical "blocked close-result" envelope builder used by all four
107
- * pre-merge and merge-phase blocked exits (Story #3638 — duplication
108
- * noted by audit fe90dd9c36fc).
109
- *
110
- * The four previously-parallel patterns each:
111
- * 1. Build a `{ success: false, status: 'blocked', phase, reason, …extra }` result.
112
- * 2. Call `emitStoryBlockedSafe` (best-effort bus emit, optional).
113
- * 3. Print the `--- STORY CLOSE RESULT ---` banner via `Logger.info`.
114
- * 4. Call `progress('BLOCKED', blockedMessage)` for the operator-facing line.
115
- *
116
- * This helper centralises all four steps so callers supply only their
117
- * domain-specific fields via `extra` and the human-facing `blockedMessage`.
118
- * Bus emission is skipped when `bus` is `null`/`undefined` (the same
119
- * semantics as `emitStoryBlockedSafe`).
120
- *
121
- * @param {{
122
- * storyId: number|string,
123
- * phase: string,
124
- * reason: string,
125
- * extra?: object,
126
- * bus?: object|null,
127
- * progress: (tag: string, msg: string) => void,
128
- * blockedMessage: string,
129
- * logger?: { info?: Function, warn?: Function },
130
- * }} args
131
- * @returns {Promise<{ success: false, status: 'blocked', phase: string, reason: string, [key: string]: unknown }>}
132
- */
133
- export async function emitBlockedCloseResult({
134
- storyId,
135
- phase,
136
- reason,
137
- extra = {},
138
- bus = null,
139
- progress,
140
- blockedMessage,
141
- logger = DefaultLogger,
142
- }) {
143
- const result = { success: false, status: 'blocked', phase, reason, ...extra };
144
- await emitStoryBlockedSafe({ bus, storyId, reason, logger });
145
- logger.info?.(
146
- `\n--- STORY CLOSE RESULT ---\n${JSON.stringify(result, null, 2)}\n--- END RESULT ---\n`,
147
- );
148
- progress('BLOCKED', blockedMessage);
149
- return result;
150
- }
151
-
152
- /**
153
- * Acquire the per-Epic filesystem merge lock, run `fn(handle)` inside a
154
- * try/finally, and always release. Logs `🔒 Acquired ...` at acquire and
155
- * `🔓 Released epic-merge lock` on release via the supplied `log` sink.
156
- *
157
- * @template T
158
- * @param {number|string} epicId
159
- * @param {{
160
- * repoRoot: string,
161
- * timeoutMs?: number,
162
- * log?: (tag: string, msg: string) => void,
163
- * acquire?: typeof defaultAcquire,
164
- * release?: typeof defaultRelease,
165
- * }} opts
166
- * @param {(handle: object) => Promise<T> | T} fn
167
- * @returns {Promise<T>}
168
- */
169
- export async function withEpicMergeLock(
170
- epicId,
171
- {
172
- repoRoot,
173
- timeoutMs = 60_000,
174
- log = () => {},
175
- acquire = defaultAcquire,
176
- release = defaultRelease,
177
- },
178
- fn,
179
- ) {
180
- log('LOCK', `Acquiring epic-merge lock for epic #${epicId}...`);
181
- let lockHandle;
182
- try {
183
- lockHandle = await acquire(epicId, { repoRoot, timeoutMs });
184
- } catch (err) {
185
- throw new Error(
186
- `Could not acquire epic-merge lock for epic #${epicId}: ${err.message}. ` +
187
- `Another story closure may be in progress, or a stale lock is present at ` +
188
- `${lockPathDisplay(repoRoot, epicId)} — inspect and remove it manually if no ` +
189
- `other process is running.`,
190
- );
191
- }
192
- log('LOCK', `🔒 Acquired ${path.basename(lockHandle.filePath)}`);
193
- try {
194
- return await fn(lockHandle);
195
- } finally {
196
- release(lockHandle);
197
- log('LOCK', '🔓 Released epic-merge lock');
198
- }
199
- }
200
-
201
- /**
202
- * Push the Epic branch with retry, surfacing `PushRetryConflictError` and
203
- * generic failure modes by throwing an `Error` (Story #959 — see file
204
- * header). Used by both `runFinalizeMerge` (post-merge push) and
205
- * `runResumeMerge` (resume-after-conflict push).
206
- *
207
- * The two callers diverge only on how they format generic-failure copy:
208
- * - finalize path inlines the `retries-exhausted vs other-reason` switch
209
- * directly,
210
- * - resume path routes through `describeResumePushFailure`.
211
- *
212
- * Pass `mode: 'resume'` to use the resume-style copy.
213
- *
214
- * @param {{
215
- * cwd: string,
216
- * epicBranch: string,
217
- * storyBranch: string,
218
- * config: object,
219
- * log?: (msg: string) => void,
220
- * mode?: 'finalize' | 'resume',
221
- * pushEpicWithRetry?: typeof defaultPushEpicWithRetry,
222
- * git?: { gitSpawn: typeof defaultGitSpawn },
223
- * getRunners?: (config: object) => any,
224
- * }} opts
225
- * @returns {Promise<{ ok: boolean, attempts: number, reason?: string, result?: object }>}
226
- */
227
- export async function pushEpicAndHandleConflicts({
228
- cwd,
229
- epicBranch,
230
- storyBranch,
231
- config,
232
- log = () => {},
233
- mode = 'finalize',
234
- mergeMessage = null,
235
- pushEpicWithRetry = defaultPushEpicWithRetry,
236
- git = { gitSpawn: defaultGitSpawn },
237
- getRunners = defaultGetRunners,
238
- }) {
239
- let pushOutcome;
240
- try {
241
- pushOutcome = await pushEpicWithRetry({
242
- cwd,
243
- epicBranch,
244
- storyBranch,
245
- storyMergeRetry: getRunners(config).storyMergeRetry,
246
- git,
247
- log,
248
- mergeMessage,
249
- });
250
- } catch (err) {
251
- if (err instanceof PushRetryConflictError) {
252
- throw new Error(err.message);
253
- }
254
- throw err;
255
- }
256
-
257
- if (!pushOutcome.ok) {
258
- if (mode === 'resume') {
259
- const fatal = describeResumePushFailure(pushOutcome);
260
- if (fatal) throw new Error(fatal);
261
- } else {
262
- const reasonLabel =
263
- pushOutcome.reason === 'retry-exhausted'
264
- ? `retries exhausted after ${pushOutcome.attempts} attempt(s)`
265
- : pushOutcome.reason;
266
- throw new Error(
267
- `Push failed (${reasonLabel}): ${pushOutcome.result?.stderr || pushOutcome.result?.stdout || 'unknown'}`,
268
- );
269
- }
270
- }
271
- return pushOutcome;
272
- }
273
-
274
- // ---------------------------------------------------------------------------
275
- // Story-close merge sequencing
276
- // ---------------------------------------------------------------------------
277
- //
278
- // `runFinalizeMerge` and `runResumeMerge` previously lived inline in
279
- // `story-close.js`. They both take the per-Epic merge lock, then either
280
- // rebase + merge + push (finalize path) or commit-the-pending-merge + push
281
- // (resume path). Extracted from story-close.js (Story #956, Theme A finishing
282
- // touch) so the close orchestrator becomes a thin CLI shell. Both helpers
283
- // take the same dependency-injection seams as withEpicMergeLock /
284
- // pushEpicAndHandleConflicts so tests can pin behaviour without spawning
285
- // the script.
286
-
287
- /**
288
- * Pre-merge rebase of the Story branch onto `origin/<epicBranch>`.
289
- *
290
- * Parallel wave execution lets two Stories land on the Epic between the time
291
- * a later Story branched off and the time it closes. Rebasing the Story on
292
- * the latest Epic before the close-merge shrinks the conflict surface to the
293
- * Story's real delta and lets `mergeFeatureBranch`'s minor-conflict auto-
294
- * resolve apply surgically instead of against stale base content.
295
- *
296
- * Runs inside the per-story worktree so it does not disturb the main
297
- * checkout. On any failure (fetch error, rebase conflict) the rebase is
298
- * aborted and the caller falls through to the plain merge path, which will
299
- * surface the same conflict via triage.
300
- *
301
- * @returns {{ rebased: boolean, reason?: string }}
302
- */
303
- function resolveStoryWorktreePath({ config, storyId, repoRoot }) {
304
- const wtConfig = config?.delivery?.worktreeIsolation;
305
- if (!wtConfig?.enabled) return { reason: 'isolation-disabled' };
306
- const wtPath = resolveWorkingPath({
307
- worktreeEnabled: true,
308
- repoRoot,
309
- storyId,
310
- worktreeRoot: wtConfig.root,
311
- });
312
- if (!fs.existsSync(wtPath)) return { reason: 'worktree-missing' };
313
- return { wtPath };
314
- }
315
-
316
- function runFetchOrigin({ wtPath, epicBranch, log, gitSpawn }) {
317
- const fetch = gitSpawn(wtPath, 'fetch', 'origin', epicBranch);
318
- if (fetch.status === 0) return true;
319
- log('GIT', `⚠️ fetch origin ${epicBranch} failed; skipping pre-merge rebase`);
320
- return false;
321
- }
322
-
323
- function runRebaseAndAbortOnConflict({ wtPath, epicBranch, log, gitSpawn }) {
324
- const rebase = gitSpawn(wtPath, 'rebase', `origin/${epicBranch}`);
325
- if (rebase.status === 0) return true;
326
- gitSpawn(wtPath, 'rebase', '--abort');
327
- log('GIT', '⚠️ rebase conflicted; aborted — merge triage will handle overlap');
328
- return false;
329
- }
330
-
331
- export function rebaseStoryOnEpic({
332
- config,
333
- storyId,
334
- epicBranch,
335
- storyBranch,
336
- repoRoot,
337
- log = () => {},
338
- gitSpawn = defaultGitSpawn,
339
- }) {
340
- const wt = resolveStoryWorktreePath({ config, storyId, repoRoot });
341
- if (!wt.wtPath) return { rebased: false, reason: wt.reason };
342
- const { wtPath } = wt;
343
-
344
- log('GIT', `Rebasing ${storyBranch} onto origin/${epicBranch}...`);
345
- if (!runFetchOrigin({ wtPath, epicBranch, log, gitSpawn })) {
346
- return { rebased: false, reason: 'fetch-failed' };
347
- }
348
- if (!runRebaseAndAbortOnConflict({ wtPath, epicBranch, log, gitSpawn })) {
349
- return { rebased: false, reason: 'rebase-conflict' };
350
- }
351
- log('GIT', `✅ Rebased ${storyBranch} onto origin/${epicBranch}`);
352
- return { rebased: true };
353
- }
354
-
355
- /**
356
- * Run the finalize-path merge: optional rebase, checkout + pull --rebase,
357
- * merge --no-ff, push (with retry/conflict handling). Branch cleanup is
358
- * deferred to after worktree reap (git refuses to delete a branch still
359
- * checked out by a worktree).
360
- *
361
- * The caller (story-close.js) holds the per-Epic merge lock across the
362
- * entire close flow, so this helper no longer acquires it itself.
363
- *
364
- * @param {{
365
- * epicBranch: string,
366
- * storyBranch: string,
367
- * storyTitle: string,
368
- * storyId: number|string,
369
- * epicId: number|string,
370
- * cwd: string,
371
- * config: object,
372
- * log?: (tag: string, msg: string) => void,
373
- * logger?: { error: (msg: string) => void },
374
- * gitSync?: typeof defaultGitSync,
375
- * gitSpawn?: typeof defaultGitSpawn,
376
- * }} opts
377
- */
378
- async function buildMergeMessage(storyTitle, storyId, { cwd, logger }) {
379
- const headerMaxLength = await loadHeaderMaxLength(cwd, { logger });
380
- const { message } = buildMergeMessageWithCap({
381
- type: 'feat',
382
- title: storyTitle,
383
- storyId,
384
- headerMaxLength,
385
- logger,
386
- });
387
- return message;
388
- }
389
-
390
- function buildVerboseMergeLogger(logger) {
391
- return (_level, _ctx, msg, meta) => {
392
- const tail = meta ? ` ${JSON.stringify(meta)}` : '';
393
- logger.error(`[merge] ${msg}${tail}`);
394
- };
395
- }
396
-
397
- function throwOnMajorConflict({ result, epicBranch }) {
398
- if (result.merged || !result.major) return;
399
- throw new Error(
400
- `Major merge conflict on story close: ` +
401
- `${result.conflicts.files} file(s), ${result.conflicts.lines} marker(s). ` +
402
- `Conflicting files: ${result.conflicts.fileList.join(', ')}. ` +
403
- `Merge has been aborted. Resolve manually on ${epicBranch}, then ` +
404
- `re-run this script.`,
405
- );
406
- }
407
-
408
- function logMergeOutcome({ result, log }) {
409
- if (!result.autoResolved) {
410
- log('GIT', '✅ Merge successful');
411
- return;
412
- }
413
- log(
414
- 'GIT',
415
- `✅ Merge completed with auto-resolved minor conflicts ` +
416
- `(${result.conflicts.files} file(s) resolved to theirs)`,
417
- );
418
- for (const f of result.autoResolvedFiles ?? []) {
419
- log(
420
- 'GIT',
421
- ` ↳ auto-resolved ${f.file} (${f.discardedLines} base line(s) discarded; trailer in merge commit)`,
422
- );
423
- }
424
- }
425
-
426
- export async function runFinalizeMerge({
427
- epicBranch,
428
- storyBranch,
429
- storyTitle,
430
- storyId,
431
- epicId,
432
- cwd,
433
- config,
434
- bus = null,
435
- log = () => {},
436
- logger = DefaultLogger,
437
- gitSync = defaultGitSync,
438
- gitSpawn = defaultGitSpawn,
439
- assertSharedCheckoutAvailable = defaultAssertSharedCheckoutAvailable,
440
- }) {
441
- rebaseStoryOnEpic({
442
- config,
443
- storyId,
444
- epicBranch,
445
- storyBranch,
446
- repoRoot: cwd,
447
- log,
448
- gitSpawn,
449
- });
450
-
451
- // Story #4460 — cross-epic shared-checkout guard. Runs AFTER the
452
- // per-Epic merge lock is already held (acquired around the whole close
453
- // flow in story-close.js) so it composes with, rather than replaces,
454
- // that same-epic serialization. Fails fast with an actionable
455
- // diagnostic instead of letting a raw `git checkout` error surface
456
- // when another epic's merge phase (or unrelated dirt) holds the
457
- // shared checkout.
458
- assertSharedCheckoutAvailable({ cwd, epicId, gitSpawn });
459
-
460
- log('GIT', `Checking out ${epicBranch}...`);
461
- gitSync(cwd, 'checkout', epicBranch);
462
- gitSpawn(cwd, 'pull', '--rebase', 'origin', epicBranch);
463
-
464
- log('GIT', `Merging ${storyBranch} into ${epicBranch} (--no-ff)...`);
465
- const mergeMessage = await buildMergeMessage(storyTitle, storyId, {
466
- cwd,
467
- logger,
468
- });
469
- const result = mergeFeatureBranch(
470
- cwd,
471
- storyBranch,
472
- buildVerboseMergeLogger(logger),
473
- { message: mergeMessage },
474
- );
475
-
476
- // Story #2241 / Task #2247 — surface a `story.blocked` lifecycle emit
477
- // on the typed merge-failure paths before re-throwing so the bus
478
- // ledger (and any subscribed BlockerHandler listener) sees the
479
- // typed reason. The emit is best-effort; the throw is the canonical
480
- // signal that the close was halted.
481
- try {
482
- throwOnMajorConflict({ result, epicBranch });
483
- } catch (err) {
484
- await emitStoryBlockedSafe({
485
- bus,
486
- storyId,
487
- reason: 'merge-conflict:major',
488
- logger,
489
- });
490
- throw err;
491
- }
492
- logMergeOutcome({ result, log });
493
-
494
- log('GIT', `Pushing ${epicBranch}...`);
495
- let pushOutcome;
496
- try {
497
- pushOutcome = await pushEpicAndHandleConflicts({
498
- cwd,
499
- epicBranch,
500
- storyBranch,
501
- config,
502
- log: (msg) => log('GIT', msg),
503
- mode: 'finalize',
504
- mergeMessage,
505
- });
506
- } catch (err) {
507
- await emitStoryBlockedSafe({
508
- bus,
509
- storyId,
510
- reason: 'push-failed:finalize',
511
- logger,
512
- });
513
- throw err;
514
- }
515
- if (pushOutcome.attempts > 1) {
516
- log(
517
- 'GIT',
518
- `✅ Push succeeded on attempt ${pushOutcome.attempts} after sibling session landed on ${epicBranch}`,
519
- );
520
- }
521
- }
522
-
523
- /**
524
- * Commit a pending in-progress merge (resume path) using the
525
- * conventional-commit subject from `buildResumeMergeCommitMsg`. No-op when
526
- * `.git/MERGE_HEAD` is absent (merge already committed by the operator).
527
- */
528
- function isMergePending(cwd) {
529
- return fs.existsSync(path.join(cwd, '.git', 'MERGE_HEAD'));
530
- }
531
-
532
- function commitPendingMerge({
533
- cwd,
534
- storyTitle,
535
- storyId,
536
- gitSpawn,
537
- headerMaxLength,
538
- logger,
539
- }) {
540
- return gitSpawn(
541
- cwd,
542
- 'commit',
543
- '--no-verify',
544
- '-m',
545
- buildResumeMergeCommitMsg(storyTitle, storyId, {
546
- headerMaxLength,
547
- logger,
548
- }),
549
- );
550
- }
551
-
552
- export async function finalizeMergeIfPending({
553
- cwd,
554
- epicBranch,
555
- storyBranch,
556
- storyTitle,
557
- storyId,
558
- log = () => {},
559
- gitSpawn = defaultGitSpawn,
560
- logger = DefaultLogger,
561
- }) {
562
- if (!isMergePending(cwd)) {
563
- log(
564
- 'GIT',
565
- '⚠️ No MERGE_HEAD found — merge already committed; proceeding to push',
566
- );
567
- return;
568
- }
569
- log('GIT', 'Finalizing in-progress merge (git commit --no-verify)');
570
- const headerMaxLength = await loadHeaderMaxLength(cwd, { logger });
571
- const commit = commitPendingMerge({
572
- cwd,
573
- storyTitle,
574
- storyId,
575
- gitSpawn,
576
- headerMaxLength,
577
- logger,
578
- });
579
- if (commit.status !== 0) {
580
- throw new Error(
581
- `Failed to finalize merge commit: ${commit.stderr || commit.stdout || 'unknown'}. ` +
582
- `Check that all conflicts are resolved and staged on ${epicBranch}.`,
583
- );
584
- }
585
- log('GIT', `✅ Merge of ${storyBranch} finalized on ${epicBranch}`);
586
- }
587
-
588
- /**
589
- * Run the resume-path merge: finalize the in-progress merge (if any), then
590
- * push. Used by `runStoryClose` when prior state is `partial-merge`. The
591
- * caller holds the per-Epic merge lock across the entire close flow.
592
- */
593
- export async function runResumeMerge({
594
- cwd,
595
- epicBranch,
596
- storyBranch,
597
- storyTitle,
598
- storyId,
599
- epicId,
600
- config,
601
- bus = null,
602
- logger = DefaultLogger,
603
- log = () => {},
604
- gitSpawn = defaultGitSpawn,
605
- assertNoForeignEpicLockFn = defaultAssertNoForeignEpicLock,
606
- }) {
607
- // Story #4460 follow-up: the resume path re-enters the shared checkout
608
- // just like the finalize path, so another epic's live merge phase is
609
- // the same hazard here. Only the foreign-lock half of the guard runs —
610
- // a resume's own partial merge legitimately leaves the tree dirty, so
611
- // the dirty-tree probe would false-positive against our own state.
612
- assertNoForeignEpicLockFn({ cwd, epicId });
613
-
614
- const resumeMergeMessage = await buildMergeMessage(storyTitle, storyId, {
615
- cwd,
616
- logger,
617
- });
618
- try {
619
- await finalizeMergeIfPending({
620
- cwd,
621
- epicBranch,
622
- storyBranch,
623
- storyTitle,
624
- storyId,
625
- log,
626
- gitSpawn,
627
- logger,
628
- });
629
- } catch (err) {
630
- await emitStoryBlockedSafe({
631
- bus,
632
- storyId,
633
- reason: 'merge-finalize-failed:resume',
634
- logger,
635
- });
636
- throw err;
637
- }
638
- log('GIT', `Pushing ${epicBranch}...`);
639
- try {
640
- await pushEpicAndHandleConflicts({
641
- cwd,
642
- epicBranch,
643
- storyBranch,
644
- config,
645
- log: (msg) => log('GIT', msg),
646
- mode: 'resume',
647
- mergeMessage: resumeMergeMessage,
648
- });
649
- } catch (err) {
650
- await emitStoryBlockedSafe({
651
- bus,
652
- storyId,
653
- reason: 'push-failed:resume',
654
- logger,
655
- });
656
- throw err;
657
- }
658
- }