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,489 +0,0 @@
1
- // .agents/scripts/lib/orchestration/finalize/post-handoff-comment.js
2
- /**
3
- * post-handoff-comment.js — finalize helper that upserts the
4
- * `epic-handoff` structured comment on the Epic at the end of the
5
- * bus-owned finalize flow.
6
- *
7
- * The Phase 7.1 prose previously asked operators to leave a free-form
8
- * "PR opened, see #N" comment after `gh pr create`. Lifting that
9
- * into a structured-marker upsert means the comment is:
10
- *
11
- * - addressable by the `epic-handoff` marker (operators and tooling
12
- * can find the canonical PR pointer without scrolling);
13
- * - idempotent under finalize replay (re-invoking the helper edits
14
- * the existing comment rather than fanning out duplicates).
15
- *
16
- * Story #2894 / Task #2909 (Epic #2880).
17
- */
18
-
19
- import fs from 'node:fs/promises';
20
- import path from 'node:path';
21
- import {
22
- epicLedgerPath,
23
- epicPerfReportJsonPath,
24
- } from '../../config/temp-paths.js';
25
- import { Logger } from '../../Logger.js';
26
- import { render as renderLifecycleTrace } from '../lifecycle/trace-logger.js';
27
- import { upsertStructuredComment as defaultUpsertStructuredComment } from '../ticketing.js';
28
-
29
- export const EPIC_HANDOFF_MARKER = 'epic-handoff';
30
-
31
- /**
32
- * Byte budget for the embedded run-trace digest. The digest is the
33
- * `TraceLogger` Summary block only (phase list + per-phase durations +
34
- * event/completed/failed counts), so it is small by construction — but we
35
- * cap it well under GitHub's ~64KB comment limit so a pathological ledger
36
- * with a huge phase list still degrades to a truncated note + the
37
- * relative-path link rather than blowing the comment budget. Story #3669.
38
- */
39
- export const RUN_TRACE_MAX_BYTES = 8000;
40
-
41
- /**
42
- * Format a millisecond duration as a compact wall-clock string for the
43
- * per-wave perf summary lines. Sub-second values render as `<n>ms`;
44
- * second-scale values as `<n.n>s`; minute-scale values as `<m>m<ss>s`.
45
- * Story #3029 / Task #3041.
46
- *
47
- * @param {number} ms
48
- * @returns {string}
49
- */
50
- function formatDurationMs(ms) {
51
- const n = Number.isFinite(ms) ? Math.max(0, Math.floor(ms)) : 0;
52
- if (n < 1000) return `${n}ms`;
53
- if (n < 60000) return `${(n / 1000).toFixed(1)}s`;
54
- const minutes = Math.floor(n / 60000);
55
- const seconds = Math.floor((n % 60000) / 1000);
56
- return `${minutes}m${seconds.toString().padStart(2, '0')}s`;
57
- }
58
-
59
- /**
60
- * Render the Performance Report section appended to the `epic-handoff`
61
- * comment body. Returns an empty string when `perfReport` is null /
62
- * undefined (no JSON on disk → section omitted) so callers can splice
63
- * the result in unconditionally.
64
- *
65
- * Output contract (Story #3029 / Task #3041):
66
- * - `## Performance Report` heading
67
- * - One relative link line to `temp/epic-<id>/epic-perf-report.json`
68
- * - One bullet per wave: `Wave N: <wall> wall / <story> story / util <pct>% [cap binding]`
69
- *
70
- * @param {{
71
- * relativePath: string,
72
- * waveParallelism: Array<{ waveIndex: number, wallClockMs: number, summedStoryMs: number, utilisation: number, capBinding: boolean, verifyConcurrencyCap?: number }>,
73
- * } | null | undefined} perfReport
74
- * @returns {string}
75
- */
76
- export function renderPerfReportSection(perfReport) {
77
- if (!perfReport || typeof perfReport.relativePath !== 'string') return '';
78
- const waves = Array.isArray(perfReport.waveParallelism)
79
- ? perfReport.waveParallelism
80
- : [];
81
- const lines = [];
82
- lines.push('');
83
- lines.push('## Performance Report');
84
- lines.push('');
85
- lines.push(
86
- `Persisted to [\`${perfReport.relativePath}\`](${perfReport.relativePath}).`,
87
- );
88
- lines.push('');
89
- if (waves.length === 0) {
90
- lines.push('No wave-parallelism rows recorded.');
91
- } else {
92
- for (const wave of waves) {
93
- const wall = formatDurationMs(wave.wallClockMs);
94
- const story = formatDurationMs(wave.summedStoryMs);
95
- const util = Number.isFinite(wave.utilisation)
96
- ? (wave.utilisation * 100).toFixed(0)
97
- : '0';
98
- const capLabel = wave.capBinding ? 'cap binding' : 'cap not binding';
99
- lines.push(
100
- `- Wave ${wave.waveIndex}: ${wall} wall / ${story} story / util ${util}% [${capLabel}]`,
101
- );
102
- }
103
- }
104
- return lines.join('\n');
105
- }
106
-
107
- /**
108
- * Slice the `## Summary` block out of the full `lifecycle.md` projection.
109
- * The TraceLogger `render()` output ends with a `## Summary` section (phase
110
- * list, per-phase durations, event/completed/failed counts); everything
111
- * before it is the per-event trace, which the Story explicitly excludes
112
- * from the embedded digest. Returns the Summary body (the lines *after* the
113
- * `## Summary` heading, trimmed) or `''` when no Summary heading is present.
114
- *
115
- * @param {string} fullMarkdown
116
- * @returns {string}
117
- */
118
- function summaryBlockFrom(fullMarkdown) {
119
- const marker = '## Summary';
120
- const idx = fullMarkdown.indexOf(marker);
121
- if (idx < 0) return '';
122
- return fullMarkdown.slice(idx + marker.length).trim();
123
- }
124
-
125
- /**
126
- * Project the canonical lifecycle ledger NDJSON into the compact run-trace
127
- * digest embedded in the handoff comment. Reuses the pure `TraceLogger`
128
- * `render()` projection and keeps only its Summary rollup — never the full
129
- * per-event trace (Story #3669 acceptance).
130
- *
131
- * Pure + read-only: it parses the supplied ledger text and never touches
132
- * the filesystem or mutates the ledger. Returns `null` on:
133
- * - a missing / empty ledger (no emitted records → empty Summary), or
134
- * - a malformed ledger (the underlying `render` throws on bad JSON; we
135
- * swallow it so the section degrades gracefully instead of blocking
136
- * the PR open).
137
- *
138
- * When the projected Summary exceeds `maxBytes`, the digest is truncated on
139
- * a UTF-8-safe boundary and `truncated: true` is set so the renderer can
140
- * append a note and keep the relative-path link to the full `lifecycle.md`.
141
- *
142
- * @param {{
143
- * ledgerText: string,
144
- * epicId: number,
145
- * relativePath: string,
146
- * maxBytes?: number,
147
- * }} args
148
- * @returns {{ digest: string, relativePath: string, truncated: boolean } | null}
149
- */
150
- export function extractRunTraceDigest({
151
- ledgerText,
152
- epicId,
153
- relativePath,
154
- maxBytes = RUN_TRACE_MAX_BYTES,
155
- } = {}) {
156
- if (typeof ledgerText !== 'string' || ledgerText.trim().length === 0) {
157
- return null;
158
- }
159
- let fullMarkdown;
160
- try {
161
- fullMarkdown = renderLifecycleTrace(ledgerText, { epicId });
162
- } catch {
163
- // Malformed ledger (parseLedger throws on bad JSON). Degrade to no
164
- // section rather than propagating and blocking the handoff comment.
165
- return null;
166
- }
167
- const summary = summaryBlockFrom(fullMarkdown);
168
- if (summary.length === 0) return null;
169
-
170
- const budget =
171
- Number.isInteger(maxBytes) && maxBytes > 0 ? maxBytes : RUN_TRACE_MAX_BYTES;
172
- if (Buffer.byteLength(summary, 'utf8') <= budget) {
173
- return { digest: summary, relativePath, truncated: false };
174
- }
175
- // Truncate on a UTF-8-safe boundary: take a byte slice, then drop any
176
- // trailing partial multibyte sequence by decoding with replacement and
177
- // stripping the U+FFFD tail.
178
- const sliced = Buffer.from(summary, 'utf8')
179
- .subarray(0, budget)
180
- .toString('utf8')
181
- .replace(/�+$/u, '');
182
- return { digest: sliced, relativePath, truncated: true };
183
- }
184
-
185
- /**
186
- * Render the "Run trace" digest section appended to the `epic-handoff`
187
- * comment. Returns `''` when `runTrace` is null / malformed so callers can
188
- * splice the result in unconditionally — mirrors `renderPerfReportSection`.
189
- *
190
- * Output contract (Story #3669):
191
- * - `## Run trace` heading
192
- * - One relative link line to `temp/epic-<id>/lifecycle.md`
193
- * - The TraceLogger Summary rollup (phase durations + counts)
194
- * - A truncation note when the projection overflowed the byte budget
195
- *
196
- * @param {{ digest: string, relativePath: string, truncated?: boolean } | null | undefined} runTrace
197
- * @returns {string}
198
- */
199
- export function renderRunTraceSection(runTrace) {
200
- if (
201
- !runTrace ||
202
- typeof runTrace.digest !== 'string' ||
203
- runTrace.digest.length === 0 ||
204
- typeof runTrace.relativePath !== 'string'
205
- ) {
206
- return '';
207
- }
208
- const lines = [];
209
- lines.push('');
210
- lines.push('## Run trace');
211
- lines.push('');
212
- lines.push(
213
- `Full lifecycle companion: [\`${runTrace.relativePath}\`](${runTrace.relativePath}).`,
214
- );
215
- lines.push('');
216
- lines.push(runTrace.digest);
217
- if (runTrace.truncated) {
218
- lines.push('');
219
- lines.push(
220
- `_Digest truncated to fit the comment budget — see [\`${runTrace.relativePath}\`](${runTrace.relativePath}) for the full trace._`,
221
- );
222
- }
223
- return lines.join('\n');
224
- }
225
-
226
- /**
227
- * Default loader: read the canonical `temp/epic-<id>/lifecycle.ndjson`
228
- * ledger from disk and project it into the run-trace digest envelope
229
- * `renderRunTraceSection` expects. Returns `null` on any failure (missing
230
- * file, malformed JSON, empty ledger) so the handoff comment degrades
231
- * gracefully — mirrors `loadPerfReportFromDisk`.
232
- *
233
- * `relativePath` points at the rendered `lifecycle.md` companion (the same
234
- * directory as the ledger), computed relative to `cwd` so consumers can
235
- * follow the link from the rendered comment. Falls back to the absolute
236
- * path when the companion resolves outside `cwd`.
237
- *
238
- * @param {{ epicId: number, config?: object, cwd?: string }} args
239
- * @returns {Promise<{ digest: string, relativePath: string, truncated: boolean } | null>}
240
- */
241
- export async function loadRunTraceFromDisk({
242
- epicId,
243
- config,
244
- cwd = process.cwd(),
245
- } = {}) {
246
- if (!Number.isInteger(epicId) || epicId < 1) return null;
247
- let ledgerAbsPath;
248
- try {
249
- ledgerAbsPath = epicLedgerPath(epicId, config);
250
- } catch {
251
- return null;
252
- }
253
- let ledgerText;
254
- try {
255
- ledgerText = await fs.readFile(ledgerAbsPath, 'utf8');
256
- } catch {
257
- return null;
258
- }
259
- const companionAbsPath = path.join(
260
- path.dirname(ledgerAbsPath),
261
- 'lifecycle.md',
262
- );
263
- let relativePath;
264
- try {
265
- const rel = path.relative(cwd, companionAbsPath);
266
- relativePath =
267
- rel && !rel.startsWith('..') && !path.isAbsolute(rel)
268
- ? rel
269
- : companionAbsPath;
270
- relativePath = relativePath.split(path.sep).join('/');
271
- } catch {
272
- relativePath = companionAbsPath;
273
- }
274
- return extractRunTraceDigest({ ledgerText, epicId, relativePath });
275
- }
276
-
277
- /**
278
- * Render the `epic-handoff` comment body. Pure helper — exported so the
279
- * contract tests can assert the rendered shape without standing up a
280
- * provider.
281
- *
282
- * @param {{ epicId: number, prNumber: number, prUrl?: string|null }} input
283
- * @returns {string} markdown body (without the structured-comment marker
284
- * prefix — the marker is prepended by `upsertStructuredComment`).
285
- */
286
- export function renderHandoffBody({
287
- epicId,
288
- prNumber,
289
- prUrl = null,
290
- perfReport = null,
291
- runTrace = null,
292
- } = {}) {
293
- const lines = [];
294
- lines.push('### 🤝 Epic handoff — PR opened');
295
- lines.push('');
296
- lines.push(`Epic: #${epicId}`);
297
- if (typeof prUrl === 'string' && prUrl.length > 0) {
298
- lines.push(`Pull request: [#${prNumber}](${prUrl})`);
299
- } else {
300
- lines.push(`Pull request: #${prNumber}`);
301
- }
302
- lines.push('');
303
- lines.push(
304
- 'Auto-merge will arm once the watch-and-iterate gate (Phase 8) confirms required checks are green.',
305
- );
306
- // Story #3029 / Task #3041 — Performance Report section. Empty string
307
- // is returned when no perf report is available, so the existing body
308
- // shape is preserved for handoffs that fire before the close tail has
309
- // emitted a report (e.g. legacy replays).
310
- const perfSection = renderPerfReportSection(perfReport);
311
- if (perfSection.length > 0) {
312
- lines.push(perfSection);
313
- }
314
- // Story #3669 — Run trace digest section. Empty string is returned when
315
- // no ledger digest is available (missing/malformed ledger → section
316
- // omitted), so the body shape is preserved for handoffs that fire before
317
- // a ledger exists.
318
- const runTraceSection = renderRunTraceSection(runTrace);
319
- if (runTraceSection.length > 0) {
320
- lines.push(runTraceSection);
321
- }
322
- lines.push('');
323
- lines.push('```json');
324
- lines.push(
325
- JSON.stringify(
326
- { kind: 'epic-handoff', epicId, prNumber, prUrl: prUrl ?? null },
327
- null,
328
- 2,
329
- ),
330
- );
331
- lines.push('```');
332
- return lines.join('\n');
333
- }
334
-
335
- /**
336
- * Default loader: read the canonical `epic-perf-report.json` snapshot
337
- * from disk (when present) and shape it into the
338
- * `{ relativePath, waveParallelism }` envelope `renderPerfReportSection`
339
- * expects. Returns `null` on any failure (missing file, malformed JSON,
340
- * unreadable directory) so the handoff comment degrades gracefully to
341
- * the pre-Story-#3029 body shape rather than blocking the PR open.
342
- *
343
- * `relativePath` is computed relative to `cwd` so consumers cloning the
344
- * repo can follow the link from the rendered comment. When the report
345
- * path resolves outside `cwd`, falls back to the absolute path (rare —
346
- * happens only for callers that point `tempRoot` outside the repo).
347
- *
348
- * @param {{ epicId: number, config?: object, cwd?: string }} args
349
- * @returns {Promise<{ relativePath: string, waveParallelism: Array<object> } | null>}
350
- */
351
- export async function loadPerfReportFromDisk({
352
- epicId,
353
- config,
354
- cwd = process.cwd(),
355
- } = {}) {
356
- if (!Number.isInteger(epicId) || epicId < 1) return null;
357
- let absPath;
358
- try {
359
- absPath = epicPerfReportJsonPath(epicId, config);
360
- } catch {
361
- return null;
362
- }
363
- let raw;
364
- try {
365
- raw = await fs.readFile(absPath, 'utf8');
366
- } catch {
367
- return null;
368
- }
369
- let payload;
370
- try {
371
- payload = JSON.parse(raw);
372
- } catch {
373
- return null;
374
- }
375
- if (!payload || typeof payload !== 'object') return null;
376
- let relativePath;
377
- try {
378
- const rel = path.relative(cwd, absPath);
379
- relativePath =
380
- rel && !rel.startsWith('..') && !path.isAbsolute(rel) ? rel : absPath;
381
- // Normalize Windows backslashes so the rendered Markdown link works
382
- // on both POSIX consumers and Windows operators.
383
- relativePath = relativePath.split(path.sep).join('/');
384
- } catch {
385
- relativePath = absPath;
386
- }
387
- return {
388
- relativePath,
389
- waveParallelism: Array.isArray(payload.waveParallelism)
390
- ? payload.waveParallelism
391
- : [],
392
- };
393
- }
394
-
395
- /**
396
- * Upsert the `epic-handoff` structured comment on the Epic ticket.
397
- *
398
- * @param {object} args
399
- * @param {number} args.epicId
400
- * @param {number} args.prNumber
401
- * @param {string} [args.prUrl]
402
- * @param {object} args.provider — ITicketingProvider used by
403
- * `upsertStructuredComment`.
404
- * @param {Function} [args.upsertStructuredCommentFn] — override for
405
- * tests.
406
- * @param {object} [args.logger]
407
- * @returns {Promise<{ marker: string, commentId: number|null }>}
408
- */
409
- export async function postHandoffComment({
410
- epicId,
411
- prNumber,
412
- prUrl,
413
- provider,
414
- config,
415
- cwd,
416
- perfReport,
417
- runTrace,
418
- loadPerfReportFn = loadPerfReportFromDisk,
419
- loadRunTraceFn = loadRunTraceFromDisk,
420
- upsertStructuredCommentFn = defaultUpsertStructuredComment,
421
- logger = Logger,
422
- } = {}) {
423
- if (!Number.isInteger(epicId) || epicId < 1) {
424
- throw new TypeError(
425
- 'postHandoffComment: epicId must be a positive integer',
426
- );
427
- }
428
- if (!Number.isInteger(prNumber) || prNumber < 1) {
429
- throw new TypeError(
430
- 'postHandoffComment: prNumber must be a positive integer',
431
- );
432
- }
433
- if (!provider) {
434
- throw new TypeError('postHandoffComment: provider is required');
435
- }
436
- // Story #3029 / Task #3041 — if an explicit `perfReport` envelope is
437
- // not supplied, fall back to reading the persisted JSON written by
438
- // the close-tail. Any loader failure resolves to `null` and the
439
- // Performance Report section is silently omitted.
440
- let resolvedPerfReport = perfReport;
441
- if (resolvedPerfReport === undefined) {
442
- try {
443
- resolvedPerfReport = await loadPerfReportFn({ epicId, config, cwd });
444
- } catch (err) {
445
- logger.warn?.(
446
- `[finalize/post-handoff-comment] perf-report load failed for Epic #${epicId} (non-fatal): ${err?.message ?? err}`,
447
- );
448
- resolvedPerfReport = null;
449
- }
450
- }
451
- // Story #3669 — if an explicit `runTrace` envelope is not supplied, fall
452
- // back to projecting the canonical lifecycle ledger from disk. Any loader
453
- // failure resolves to `null` and the Run trace section is silently
454
- // omitted, never blocking the handoff comment / PR open.
455
- let resolvedRunTrace = runTrace;
456
- if (resolvedRunTrace === undefined) {
457
- try {
458
- resolvedRunTrace = await loadRunTraceFn({ epicId, config, cwd });
459
- } catch (err) {
460
- logger.warn?.(
461
- `[finalize/post-handoff-comment] run-trace load failed for Epic #${epicId} (non-fatal): ${err?.message ?? err}`,
462
- );
463
- resolvedRunTrace = null;
464
- }
465
- }
466
- const body = renderHandoffBody({
467
- epicId,
468
- prNumber,
469
- prUrl: prUrl ?? null,
470
- perfReport: resolvedPerfReport,
471
- runTrace: resolvedRunTrace,
472
- });
473
- try {
474
- const result = await upsertStructuredCommentFn(
475
- provider,
476
- epicId,
477
- EPIC_HANDOFF_MARKER,
478
- body,
479
- );
480
- const commentId =
481
- typeof result?.commentId === 'number' ? result.commentId : null;
482
- return { marker: EPIC_HANDOFF_MARKER, commentId };
483
- } catch (err) {
484
- logger.warn?.(
485
- `[finalize/post-handoff-comment] upsert failed for Epic #${epicId}: ${err?.message ?? err}`,
486
- );
487
- throw err;
488
- }
489
- }
@@ -1,88 +0,0 @@
1
- // .agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js
2
- /**
3
- * sanitize-skip-ci.js — pure helper that strips GitHub Actions
4
- * `[skip ci]` markers (and the four variant spellings GitHub honours)
5
- * from a text payload.
6
- *
7
- * Story #3165: `/deliver` Phase 7 opens a PR squashed into `main`
8
- * via `gh pr merge --squash`. Story commits legitimately carry
9
- * `[skip ci]` markers under `delivery.ci.skipForStoryPushes: true` to
10
- * keep CI from firing on the wave's intermediate pushes. When GitHub
11
- * composes the squash commit body by concatenating constituent commit
12
- * messages, those markers propagate into the squash body and suppress
13
- * `ci.yml` + `release-please.yml` on `main` — even though the squash
14
- * subject is just `Epic #<id> (#<pr>)`.
15
- *
16
- * The first defence is to ensure the PR body (assembled by
17
- * `openOrLocatePr` and handed to `gh pr create`) carries no raw
18
- * skip-ci markers, so any tooling that derives the squash body from
19
- * the PR body (or from text that flows through this helper) cannot
20
- * re-introduce the suppression.
21
- *
22
- * Markers stripped (case-insensitive, optional inner spaces, optional
23
- * brackets per GitHub's documented contract — only the bracketed
24
- * forms actually suppress CI, so those are the only forms removed):
25
- *
26
- * - `[skip ci]` / `[ci skip]`
27
- * - `[no ci]`
28
- * - `[skip actions]` / `[actions skip]`
29
- *
30
- * Reference: GitHub Actions docs, "Skipping workflow runs":
31
- * https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs
32
- */
33
-
34
- /**
35
- * Canonical regex list. Frozen so callers can introspect (e.g. a
36
- * contract test that asserts the documented marker set is what the
37
- * sanitizer actually matches) without mutating the SSOT.
38
- *
39
- * Each pattern matches the bracketed form only — bare `skip ci`
40
- * without brackets does NOT suppress CI on GitHub and is left
41
- * untouched.
42
- */
43
- export const SKIP_CI_PATTERNS = Object.freeze([
44
- /\[\s*skip\s+ci\s*\]/gi,
45
- /\[\s*ci\s+skip\s*\]/gi,
46
- /\[\s*no\s+ci\s*\]/gi,
47
- /\[\s*skip\s+actions\s*\]/gi,
48
- /\[\s*actions\s+skip\s*\]/gi,
49
- ]);
50
-
51
- /**
52
- * Strip every GitHub-recognised `[skip ci]` variant from `text`.
53
- *
54
- * Non-string input (null / undefined / number) is returned unchanged
55
- * so the helper can be folded into an optional-body assembly chain
56
- * without forcing the caller to guard.
57
- *
58
- * Multiple consecutive matches collapse cleanly:
59
- * - Each matched marker is replaced with the empty string.
60
- * - Runs of whitespace that the deletion leaves behind on the same
61
- * line collapse to a single space.
62
- * - Trailing whitespace on each line is trimmed.
63
- * - Runs of three or more blank lines collapse to a single blank
64
- * line (so a body that was nothing but markers doesn't leave a
65
- * gaping vertical gap).
66
- *
67
- * The helper is intentionally idempotent: `sanitize(sanitize(x)) ===
68
- * sanitize(x)` for every input.
69
- *
70
- * @param {string} text
71
- * @returns {string}
72
- */
73
- export function sanitizeSkipCiMarkers(text) {
74
- if (typeof text !== 'string') return text;
75
- let out = text;
76
- for (const pattern of SKIP_CI_PATTERNS) {
77
- out = out.replace(pattern, '');
78
- }
79
- // Collapse intra-line whitespace runs left behind by deletions, but
80
- // preserve line boundaries so paragraph structure survives.
81
- out = out
82
- .split('\n')
83
- .map((line) => line.replace(/[ \t]{2,}/g, ' ').replace(/[ \t]+$/g, ''))
84
- .join('\n');
85
- // Collapse runs of 3+ blank lines down to one blank line.
86
- out = out.replace(/\n{3,}/g, '\n\n');
87
- return out;
88
- }