mandrel 1.59.0 → 1.61.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 (267) hide show
  1. package/.agents/README.md +86 -44
  2. package/.agents/docs/SDLC.md +135 -141
  3. package/.agents/docs/configuration.md +77 -20
  4. package/.agents/docs/quality-gates.md +796 -0
  5. package/.agents/docs/workflows.md +6 -9
  6. package/.agents/instructions.md +12 -11
  7. package/.agents/personas/architect.md +1 -1
  8. package/.agents/personas/product.md +1 -1
  9. package/.agents/personas/project-manager.md +14 -14
  10. package/.agents/personas/technical-writer.md +1 -1
  11. package/.agents/rules/changelog-style.md +5 -5
  12. package/.agents/rules/git-conventions.md +3 -3
  13. package/.agents/runtime-deps.json +2 -2
  14. package/.agents/schemas/agentrc.schema.json +3 -3
  15. package/.agents/schemas/dispatch-manifest.json +4 -4
  16. package/.agents/schemas/epic-spec.schema.json +15 -45
  17. package/.agents/schemas/lifecycle/README.md +1 -1
  18. package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +1 -1
  19. package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +1 -1
  20. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +1 -1
  21. package/.agents/schemas/validation-evidence.schema.json +1 -1
  22. package/.agents/scripts/README.md +2 -2
  23. package/.agents/scripts/acceptance-eval.js +1 -1
  24. package/.agents/scripts/acceptance-spec-reconciler.js +2 -2
  25. package/.agents/scripts/agents-bootstrap-github.js +23 -119
  26. package/.agents/scripts/analyze-execution.js +2 -2
  27. package/.agents/scripts/audit-to-stories.js +1 -1
  28. package/.agents/scripts/check-doc-links.js +2 -3
  29. package/.agents/scripts/diagnose-friction.js +1 -1
  30. package/.agents/scripts/dispatcher.js +2 -2
  31. package/.agents/scripts/drain-pending-cleanup.js +1 -1
  32. package/.agents/scripts/epic-audit-prepare.js +3 -3
  33. package/.agents/scripts/epic-deliver-note-intervention.js +2 -2
  34. package/.agents/scripts/epic-deliver-preflight.js +6 -6
  35. package/.agents/scripts/epic-deliver-prepare.js +1 -1
  36. package/.agents/scripts/epic-execute-record-wave.js +4 -4
  37. package/.agents/scripts/epic-plan-healthcheck.js +6 -10
  38. package/.agents/scripts/epic-plan-spec-validate.js +1 -1
  39. package/.agents/scripts/epic-reconcile.js +11 -29
  40. package/.agents/scripts/evidence-gate.js +1 -1
  41. package/.agents/scripts/generate-workflows-doc.js +1 -1
  42. package/.agents/scripts/hierarchy-gate.js +7 -11
  43. package/.agents/scripts/lib/ITicketingProvider.js +1 -1
  44. package/.agents/scripts/lib/audit-suite/selector.js +1 -1
  45. package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +2 -2
  46. package/.agents/scripts/lib/baseline-snapshot.js +7 -7
  47. package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
  48. package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
  49. package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +1 -1
  50. package/.agents/scripts/lib/bootstrap/branch-protection.js +1 -1
  51. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +47 -1
  52. package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
  53. package/.agents/scripts/lib/bootstrap/gh-preflight.js +7 -9
  54. package/.agents/scripts/lib/bootstrap/manifest.js +21 -1
  55. package/.agents/scripts/lib/bootstrap/merge-methods.js +31 -16
  56. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +32 -11
  57. package/.agents/scripts/lib/codebase-snapshot.js +1 -1
  58. package/.agents/scripts/lib/config/explain.js +1 -1
  59. package/.agents/scripts/lib/config/runners.js +2 -2
  60. package/.agents/scripts/lib/config/runtime.js +1 -1
  61. package/.agents/scripts/lib/config/sync-agentrc.js +1 -1
  62. package/.agents/scripts/lib/config/temp-paths.js +2 -2
  63. package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
  64. package/.agents/scripts/lib/config-settings-schema-quality.js +1 -1
  65. package/.agents/scripts/lib/config-settings-schema.js +3 -3
  66. package/.agents/scripts/lib/detect-package-manager.js +72 -0
  67. package/.agents/scripts/lib/duplicate-search.js +1 -1
  68. package/.agents/scripts/lib/dynamic-workflow/capability.js +1 -1
  69. package/.agents/scripts/lib/epic-plan-clarity.js +1 -1
  70. package/.agents/scripts/lib/epic-plan-ideation.js +1 -1
  71. package/.agents/scripts/lib/errors/index.js +4 -4
  72. package/.agents/scripts/lib/feedback-loop/memory-freshness.js +1 -1
  73. package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +1 -1
  74. package/.agents/scripts/lib/findings/classify-finding.js +1 -1
  75. package/.agents/scripts/lib/findings/promote-finding.js +10 -10
  76. package/.agents/scripts/lib/label-constants.js +3 -4
  77. package/.agents/scripts/lib/label-taxonomy.js +5 -10
  78. package/.agents/scripts/lib/onboard/detect-stack.js +10 -10
  79. package/.agents/scripts/lib/onboard/init-tail.js +218 -0
  80. package/.agents/scripts/lib/onboard/scaffold-docs.js +18 -3
  81. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +1 -1
  82. package/.agents/scripts/lib/orchestration/code-review.js +5 -5
  83. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +8 -9
  84. package/.agents/scripts/lib/orchestration/dependency-analyzer.js +3 -3
  85. package/.agents/scripts/lib/orchestration/detectors-phase.js +2 -2
  86. package/.agents/scripts/lib/orchestration/dispatch-engine.js +30 -38
  87. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +9 -25
  88. package/.agents/scripts/lib/orchestration/epic-cleanup.js +1 -1
  89. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +8 -8
  90. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +1 -1
  91. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +7 -21
  92. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +3 -3
  93. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +26 -13
  94. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +1 -1
  95. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +1 -1
  96. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +2 -2
  97. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +1 -1
  98. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +3 -3
  99. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +4 -4
  100. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +3 -3
  101. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +6 -21
  102. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +7 -7
  103. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +1 -1
  104. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +2 -2
  105. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +4 -4
  106. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +4 -4
  107. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +8 -8
  108. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +4 -4
  109. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +7 -15
  110. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +72 -41
  111. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +2 -4
  112. package/.agents/scripts/lib/orchestration/file-assumptions.js +2 -2
  113. package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +1 -1
  114. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +2 -2
  115. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +1 -1
  116. package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -3
  117. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +1 -1
  118. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +1 -1
  119. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +1 -1
  120. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +1 -1
  121. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +1 -1
  122. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +1 -1
  123. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +1 -1
  124. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
  125. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +1 -1
  126. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +1 -1
  127. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +1 -1
  128. package/.agents/scripts/lib/orchestration/manifest-builder.js +5 -5
  129. package/.agents/scripts/lib/orchestration/parked-follow-ons.js +2 -2
  130. package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +5 -5
  131. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +3 -3
  132. package/.agents/scripts/lib/orchestration/preflight-cache.js +1 -1
  133. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +1 -1
  134. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +1 -1
  135. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +2 -2
  136. package/.agents/scripts/lib/orchestration/retro-runner.js +3 -3
  137. package/.agents/scripts/lib/orchestration/review-depth.js +1 -1
  138. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +1 -1
  139. package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
  140. package/.agents/scripts/lib/orchestration/spec-renderer.js +36 -73
  141. package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
  142. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +1 -1
  143. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +2 -2
  144. package/.agents/scripts/lib/orchestration/task-body-validator.js +6 -6
  145. package/.agents/scripts/lib/orchestration/ticket-lease.js +1 -1
  146. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +2 -2
  147. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -10
  148. package/.agents/scripts/lib/orchestration/ticket-validator.js +25 -70
  149. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +5 -12
  150. package/.agents/scripts/lib/orchestration/ticketing/reads.js +8 -8
  151. package/.agents/scripts/lib/orchestration/ticketing/state.js +3 -3
  152. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +2 -2
  153. package/.agents/scripts/lib/orchestration/wave-record-projection.js +1 -1
  154. package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
  155. package/.agents/scripts/lib/preflight-runner.js +1 -1
  156. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +4 -5
  157. package/.agents/scripts/lib/presentation/manifest-builder.js +28 -34
  158. package/.agents/scripts/lib/presentation/manifest-formatter.js +3 -4
  159. package/.agents/scripts/lib/presentation/manifest-helpers.js +1 -1
  160. package/.agents/scripts/lib/presentation/manifest-procedures.js +4 -4
  161. package/.agents/scripts/lib/presentation/manifest-render-waves.js +4 -23
  162. package/.agents/scripts/lib/presentation/manifest-renderer.js +1 -1
  163. package/.agents/scripts/lib/presentation/manifest-story-views.js +2 -11
  164. package/.agents/scripts/lib/runtime-deps/preflight.js +6 -6
  165. package/.agents/scripts/lib/signals/schema.js +1 -1
  166. package/.agents/scripts/lib/spec/index.js +1 -1
  167. package/.agents/scripts/lib/spec/loader.js +2 -2
  168. package/.agents/scripts/lib/spec/state.js +7 -16
  169. package/.agents/scripts/lib/story-init/context-resolver.js +3 -3
  170. package/.agents/scripts/lib/story-init/state-transitioner.js +2 -2
  171. package/.agents/scripts/lib/story-init/task-graph-builder.js +7 -7
  172. package/.agents/scripts/lib/story-lifecycle.js +8 -8
  173. package/.agents/scripts/lib/story-plan.js +1 -1
  174. package/.agents/scripts/lib/templates/decomposer-prompts.js +59 -52
  175. package/.agents/scripts/lib/wave-runner/tick.js +1 -1
  176. package/.agents/scripts/lib/worktree/node-modules-strategy.js +5 -2
  177. package/.agents/scripts/lifecycle-emit-story-dispatch.js +1 -1
  178. package/.agents/scripts/lifecycle-emit.js +1 -1
  179. package/.agents/scripts/providers/github/board-add.js +1 -1
  180. package/.agents/scripts/providers/github/errors.js +1 -1
  181. package/.agents/scripts/providers/github/mappers.js +2 -2
  182. package/.agents/scripts/providers/github/tickets.js +4 -4
  183. package/.agents/scripts/resync-status-column.js +1 -1
  184. package/.agents/scripts/retro-run.js +2 -2
  185. package/.agents/scripts/run-lint.js +1 -1
  186. package/.agents/scripts/single-story-init.js +1 -1
  187. package/.agents/scripts/stories-wave-tick.js +5 -5
  188. package/.agents/scripts/story-close.js +1 -1
  189. package/.agents/scripts/story-init.js +13 -16
  190. package/.agents/scripts/story-phase.js +5 -5
  191. package/.agents/scripts/story-plan.js +3 -3
  192. package/.agents/scripts/sync-branch-from-base.js +1 -1
  193. package/.agents/scripts/validate-docs-freshness.js +1 -1
  194. package/.agents/scripts/wave-tick.js +1 -1
  195. package/.agents/skills/core/analyze-execution/SKILL.md +2 -2
  196. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +21 -26
  197. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +23 -56
  198. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +4 -4
  199. package/.agents/skills/core/hydrate-context/SKILL.md +2 -2
  200. package/.agents/skills/core/idea-refinement/SKILL.md +4 -4
  201. package/.agents/skills/core/knowledge-transfer/SKILL.md +2 -2
  202. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +1 -1
  203. package/.agents/skills/core/scope-triage/SKILL.md +9 -10
  204. package/.agents/skills/core/using-agent-skills/SKILL.md +1 -1
  205. package/.agents/skills/skills.index.json +7 -7
  206. package/.agents/templates/agent-protocol.md +2 -2
  207. package/.agents/workflows/agents-update.md +16 -31
  208. package/.agents/workflows/audit-architecture.md +2 -2
  209. package/.agents/workflows/audit-clean-code.md +2 -2
  210. package/.agents/workflows/audit-dependencies.md +1 -1
  211. package/.agents/workflows/audit-devops.md +1 -1
  212. package/.agents/workflows/audit-documentation.md +2 -2
  213. package/.agents/workflows/audit-lighthouse.md +1 -1
  214. package/.agents/workflows/audit-performance.md +2 -2
  215. package/.agents/workflows/audit-privacy.md +1 -1
  216. package/.agents/workflows/audit-quality.md +2 -2
  217. package/.agents/workflows/audit-security.md +2 -2
  218. package/.agents/workflows/audit-seo.md +1 -1
  219. package/.agents/workflows/audit-sre.md +1 -1
  220. package/.agents/workflows/audit-to-stories.md +10 -10
  221. package/.agents/workflows/audit-ux-ui.md +1 -1
  222. package/.agents/workflows/deliver.md +85 -0
  223. package/.agents/workflows/explain.md +3 -3
  224. package/.agents/workflows/git-merge-pr.md +1 -1
  225. package/.agents/workflows/git-pr-all.md +13 -10
  226. package/.agents/workflows/git-push.md +6 -3
  227. package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
  228. package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
  229. package/.agents/workflows/helpers/agents-sync-config.md +3 -2
  230. package/.agents/workflows/helpers/code-review.md +5 -5
  231. package/.agents/workflows/{epic-deliver.md → helpers/deliver-epic.md} +43 -43
  232. package/.agents/workflows/{story-deliver.md → helpers/deliver-stories.md} +25 -25
  233. package/.agents/workflows/helpers/diagnose.md +1 -1
  234. package/.agents/workflows/helpers/epic-audit.md +6 -6
  235. package/.agents/workflows/helpers/epic-deliver-story.md +13 -13
  236. package/.agents/workflows/helpers/epic-plan-decompose.md +23 -23
  237. package/.agents/workflows/helpers/epic-plan-spec.md +6 -6
  238. package/.agents/workflows/helpers/epic-testing.md +3 -3
  239. package/.agents/workflows/helpers/parallel-tooling.md +1 -1
  240. package/.agents/workflows/{epic-plan.md → helpers/plan-epic.md} +84 -84
  241. package/.agents/workflows/{story-plan.md → helpers/plan-story.md} +43 -43
  242. package/.agents/workflows/helpers/signals.md +1 -1
  243. package/.agents/workflows/helpers/single-story-deliver.md +11 -11
  244. package/.agents/workflows/helpers/worktree-lifecycle.md +18 -18
  245. package/.agents/workflows/plan.md +131 -0
  246. package/.agents/workflows/qa-explore.md +1 -1
  247. package/.agents/workflows/qa-run-harness.md +1 -1
  248. package/README.md +19 -39
  249. package/bin/mandrel.js +235 -16
  250. package/docs/CHANGELOG.md +1173 -0
  251. package/lib/cli/doctor.js +45 -3
  252. package/lib/cli/init.js +97 -36
  253. package/lib/cli/registry.js +41 -145
  254. package/lib/cli/sync.js +122 -23
  255. package/lib/cli/uninstall.js +42 -7
  256. package/lib/cli/update.js +524 -210
  257. package/lib/cli/version-helpers.js +59 -0
  258. package/package.json +7 -6
  259. package/.agents/scripts/lib/orchestration/reconciler.js +0 -137
  260. package/.agents/workflows/onboard.md +0 -208
  261. package/lib/cli/__tests__/migrate.test.js +0 -268
  262. package/lib/cli/__tests__/sync-local-zone.test.js +0 -247
  263. package/lib/cli/__tests__/sync.test.js +0 -372
  264. package/lib/cli/__tests__/update-major.test.js +0 -217
  265. package/lib/cli/__tests__/update.test.js +0 -696
  266. package/lib/cli/__tests__/version-check.test.js +0 -398
  267. package/lib/migrations/__tests__/index.test.js +0 -216
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * .agents/scripts/hierarchy-gate.js — Hierarchy Completeness Gate
5
5
  *
6
- * Walks the Epic's full sub-issue graph (Features → Stories) and verifies
6
+ * Walks the Epic's full sub-issue graph (Stories) and verifies
7
7
  * every descendant is closed. Where the wave gate asks "did the sprint
8
8
  * complete what it committed to?" (manifest view), this gate asks "is
9
9
  * anything still open under this Epic?" (live GitHub graph view).
@@ -16,14 +16,13 @@
16
16
  * top-level Stories outside the Epic's sub-issue graph.
17
17
  *
18
18
  * Per ticket type the rule is:
19
- * - Features — must be closed.
20
19
  * - Stories — must be closed.
21
20
  * - Auxiliary (context::prd, context::tech-spec) — ignored.
22
21
  * These are closed by the operator after the Epic PR merges, so
23
22
  * requiring them closed here would block every Epic.
24
23
  *
25
- * **3-tier hierarchy (Epic #3078).** Mandrel ships only Epic / Feature /
26
- * Story tickets. `getSubTickets(<storyId>)` returns `[]`; the walk
24
+ * **2-tier hierarchy (Story #4041).** Mandrel ships only Epic / Story
25
+ * tickets. `getSubTickets(<storyId>)` returns `[]`; the walk
27
26
  * terminates at the Story. Acceptance criteria live inline on the
28
27
  * Story body.
29
28
  *
@@ -53,7 +52,6 @@ const SUB_TICKET_FETCH_CONCURRENCY = 4;
53
52
  function classify(ticket) {
54
53
  const labels = ticket.labels ?? [];
55
54
  if (labels.includes(TYPE_LABELS.STORY)) return 'story';
56
- if (labels.includes(TYPE_LABELS.FEATURE)) return 'feature';
57
55
  if (
58
56
  labels.includes(CONTEXT_LABELS.PRD) ||
59
57
  labels.includes(CONTEXT_LABELS.TECH_SPEC)
@@ -80,7 +78,7 @@ async function collectDescendants(provider, epicId) {
80
78
  const out = [];
81
79
  // Level-order BFS: each round fetches the whole frontier's children with a
82
80
  // bounded-parallel map instead of one awaited round-trip per node. Stories
83
- // are 3-tier leaves (no sub-issues by contract), so they are never expanded
81
+ // are leaves (no sub-issues by contract), so they are never expanded
84
82
  // — that skip alone removes the largest class of wasted GraphQL calls.
85
83
  let frontier = [epicId];
86
84
  while (frontier.length > 0) {
@@ -126,7 +124,7 @@ export async function runHierarchyGate({ epicId, injectedProvider } = {}) {
126
124
  process.exit(2);
127
125
  }
128
126
 
129
- const failures = { feature: [], story: [], other: [] };
127
+ const failures = { story: [], other: [] };
130
128
  let auxiliaryDeferred = 0;
131
129
  for (const ticket of descendants) {
132
130
  const kind = classify(ticket);
@@ -144,15 +142,13 @@ export async function runHierarchyGate({ epicId, injectedProvider } = {}) {
144
142
  }
145
143
  }
146
144
 
147
- const totalOpen =
148
- failures.feature.length + failures.story.length + failures.other.length;
145
+ const totalOpen = failures.story.length + failures.other.length;
149
146
 
150
147
  if (totalOpen > 0) {
151
148
  Logger.error(
152
149
  `[hierarchy-gate] ❌ Hierarchy-completeness gate FAILED for Epic #${epicId}: ${totalOpen} descendant(s) incomplete.`,
153
150
  );
154
151
  const sections = [
155
- ['feature', 'Features'],
156
152
  ['story', 'Stories'],
157
153
  ['other', 'Untyped descendants'],
158
154
  ];
@@ -163,7 +159,7 @@ export async function runHierarchyGate({ epicId, injectedProvider } = {}) {
163
159
  Logger.error(` - #${item.id} (${item.reason}) — ${item.title}`);
164
160
  }
165
161
  }
166
- Logger.error('\nClose the open descendants and re-run `/epic-deliver`.');
162
+ Logger.error('\nClose the open descendants and re-run `/deliver`.');
167
163
  process.exit(1);
168
164
  }
169
165
 
@@ -154,7 +154,7 @@ export class ITicketingProvider {
154
154
  /**
155
155
  * Create a child ticket within an Epic's structural hierarchy.
156
156
  *
157
- * @param {number} parentId - GitHub Issue number of the immediate structural parent (e.g. Epic, Feature, or Story).
157
+ * @param {number} parentId - GitHub Issue number of the immediate structural parent (e.g. Epic or Story).
158
158
  * @param {{
159
159
  * epicId: number,
160
160
  * title: string,
@@ -60,7 +60,7 @@ export function matchesAnyFilePattern(patterns, files) {
60
60
  * callers MUST pass the requested Epic's own branch ref (e.g.
61
61
  * `refs/heads/epic/<id>`) so the change set is pinned to that Epic's branch
62
62
  * rather than whatever HEAD the shared checkout happens to sit on. Under two
63
- * concurrent `/epic-deliver` runs sharing one checkout, diffing against
63
+ * concurrent `/deliver` runs sharing one checkout, diffing against
64
64
  * `HEAD` silently resolves the *other* Epic's change set (Story #3362). When
65
65
  * `headRef` cannot be resolved in the repo, the selector returns a
66
66
  * `degraded: true` envelope (or hard-fails in gate-mode) instead of diffing
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * lib/audit-to-stories/seed-epic-from-findings.js
3
3
  *
4
- * Build the `--idea`-shaped seed markdown that `/epic-plan` Phase 1
4
+ * Build the `--idea`-shaped seed markdown that `/plan` Phase 1
5
5
  * consumes when the operator picks the Single-Epic grouping mode.
6
6
  *
7
7
  * The seed renders the canonical one-pager sections so the idea-refinement
@@ -10,7 +10,7 @@
10
10
  * - Recommended Direction (rollup of recommendations by dimension)
11
11
  * - Key Assumptions (carries the source-report links forward)
12
12
  * - MVP Scope (the proposed Stories, one bullet per group)
13
- * - Key Files (explicit file paths so /epic-plan Phase 7 decompose
13
+ * - Key Files (explicit file paths so /plan Phase 7 decompose
14
14
  * has concrete anchors)
15
15
  * - Not Doing (out-of-scope items by convention)
16
16
  *
@@ -28,8 +28,8 @@ import { calculateAll, scanDirectory } from './maintainability-utils.js';
28
28
  * baseline-snapshot.js — per-Epic baseline lifecycle helpers.
29
29
  *
30
30
  * Story #1396 (Epic #1386). The Epic-snapshot scheme freezes the maintainability
31
- * and crap baselines at /epic-plan time and reconciles them back to `main`
32
- * at /epic-deliver time. Two helpers, both pure-ish (deterministic given the
31
+ * and crap baselines at /plan time and reconciles them back to `main`
32
+ * at /deliver time. Two helpers, both pure-ish (deterministic given the
33
33
  * working tree + injected I/O):
34
34
  *
35
35
  * - forkMainToEpic({ epicId, cwd }) — copies the tracked main baselines
@@ -37,20 +37,20 @@ import { calculateAll, scanDirectory } from './maintainability-utils.js';
37
37
  * source content produces the same destination bytes (no fs churn). When
38
38
  * the source baseline is missing, emits a warn through the injected
39
39
  * logger and returns `{ written: false, reason: 'source-missing' }` for
40
- * that file — callers (e.g. /epic-plan Phase 7) treat the absence as
40
+ * that file — callers (e.g. /plan Phase 7) treat the absence as
41
41
  * non-fatal and stay in `--full-scope` mode.
42
42
  *
43
43
  * - regenerateMainFromTree({ cwd }) — re-scores maintainability + crap
44
44
  * against the current working tree and writes the result to the tracked
45
45
  * main baseline paths. Returns `{ didChange, paths }` where `didChange`
46
46
  * is true iff any baseline file's content differs from what's already on
47
- * disk. Callers in /epic-deliver use `didChange === false` to skip the
47
+ * disk. Callers in /deliver use `didChange === false` to skip the
48
48
  * `baseline-refresh: epic-<id>` commit.
49
49
  *
50
50
  * Lifecycle note (Story #1467): per-epic ratchet snapshots are ephemeral
51
51
  * scratch state under the `temp/epic-<id>/baselines/` namespace, NOT committed
52
52
  * artifacts. They inherit the existing per-epic temp-tree cleanup contract —
53
- * `/epic-deliver` reaps the parent `temp/epic-<id>/` directory on merge, so
53
+ * `/deliver` reaps the parent `temp/epic-<id>/` directory on merge, so
54
54
  * no manual prune is required. Earlier versions of this module wrote under
55
55
  * `baselines/epic/<id>/`, which committed them to git and accumulated obsolete
56
56
  * snapshots forever.
@@ -103,7 +103,7 @@ export function epicSnapshotPathFor({ epicId, kind, cwd = process.cwd() }) {
103
103
  * - Source baseline missing → returned per-file `{ written: false,
104
104
  * reason: 'source-missing' }`. Logger warn fires once per missing file.
105
105
  * Caller stays in `--full-scope` mode.
106
- * - Source unreadable / not parseable → throws. Re-running /epic-plan
106
+ * - Source unreadable / not parseable → throws. Re-running /plan
107
107
  * with `--force` after fixing the source recovers.
108
108
  *
109
109
  * @param {{
@@ -428,7 +428,7 @@ export function commitSnapshotsToEpicBranch({
428
428
  * via `delivery.quality.gates.crap.coveragePath`. When coverage is missing and
429
429
  * `requireCoverage` is true, the crap regeneration is skipped (didChange stays
430
430
  * false for that file) and a warn is emitted — the operator is expected to run
431
- * `npm run test:coverage` before /epic-deliver if a refresh is anticipated.
431
+ * `npm run test:coverage` before /deliver if a refresh is anticipated.
432
432
  *
433
433
  * @param {{
434
434
  * cwd?: string,
@@ -13,7 +13,7 @@
13
13
  * The verification is **static**: we inspect `package.json` for a known BDD
14
14
  * runner dependency, and consult a small lookup table of which runners
15
15
  * support which pending/skip tag. We do not boot the runner. This keeps
16
- * `/epic-plan` Phase 7 hermetic and offline.
16
+ * `/plan` Phase 7 hermetic and offline.
17
17
  *
18
18
  * **Workspace awareness (Story #2956).** In a pnpm / npm / yarn monorepo the
19
19
  * BDD runner is rarely a root devDependency — it lives in the workspace
@@ -1,5 +1,5 @@
1
1
  /**
2
- * bdd-scenario-scanner.js — Gherkin scenario index for /epic-plan Phase 7.
2
+ * bdd-scenario-scanner.js — Gherkin scenario index for /plan Phase 7.
3
3
  *
4
4
  * Story #2637 (sibling to #2634 codebase-snapshot, #2635 spec-freshness,
5
5
  * #2636 file-assumption gate). The Acceptance Engineer step of
@@ -7,7 +7,7 @@
7
7
  * alone — it never inspects the consumer project's existing `.feature`
8
8
  * files. Planned ACs frequently duplicate scenarios that already exist or
9
9
  * re-specify behaviour the codebase already proves; the duplication is
10
- * only discovered (at best) during `/story-deliver` or (at worst) after
10
+ * only discovered (at best) during `/deliver` or (at worst) after
11
11
  * a redundant PR ships.
12
12
  *
13
13
  * `scanBddScenarios` walks every configured feature root, parses each
@@ -20,7 +20,7 @@
20
20
  * have a matching scenario.
21
21
  *
22
22
  * Determinism is load-bearing: the matcher is keyword-based, not
23
- * embedding-based, so re-running `/epic-plan` against the same
23
+ * embedding-based, so re-running `/plan` against the same
24
24
  * acceptance spec produces the same disposition annotations.
25
25
  */
26
26
 
@@ -15,7 +15,7 @@
15
15
  *
16
16
  * All three shapes are relocated under `<repoRoot>/temp/epic/<id>/baselines/`,
17
17
  * where they inherit the existing per-epic temp-tree cleanup contract:
18
- * `/epic-deliver` reaps `temp/epic/<id>/` on merge, so the ratchet snapshots
18
+ * `/deliver` reaps `temp/epic/<id>/` on merge, so the ratchet snapshots
19
19
  * are ephemeral scratch state — never committed, no manual prune.
20
20
  *
21
21
  * The main-tracked `baselines/{maintainability,crap}.json` files are NOT
@@ -7,7 +7,7 @@
7
7
  * - `enforce_admins: true` — admins do not bypass the prGate suite.
8
8
  * - `required_pull_request_reviews.required_approving_review_count: 0` —
9
9
  * CI is the gate; the operator monitors and iterates the open PR
10
- * to green via `/epic-deliver`'s Phase 7 watch loop.
10
+ * to green via `/deliver`'s Phase 7 watch loop.
11
11
  *
12
12
  * Behaviour rules
13
13
  * ---------------
@@ -14,7 +14,7 @@
14
14
  * `--full-scope` so a self-diff doesn't degrade to "no files in diff".
15
15
  *
16
16
  * 2. **Pass `--epic-ref` where the firing site is Epic-aware.** Inside
17
- * `/story-deliver` the close-validation chain already threads
17
+ * `/deliver` the close-validation chain already threads
18
18
  * `--epic-ref epic/<id>`; on CI the equivalent surface is the PR's
19
19
  * base branch. The template wires `--epic-ref ${EPIC_REF}` through an
20
20
  * env var the workflow computes from `github.head_ref` (story-N
@@ -28,6 +28,9 @@
28
28
  * @module bootstrap/ci-workflow-template
29
29
  */
30
30
 
31
+ import fs from 'node:fs';
32
+ import path from 'node:path';
33
+
31
34
  /**
32
35
  * @typedef {object} CiTemplateOptions
33
36
  * @property {string} [nodeVersion='22'] - Node major to install via setup-node.
@@ -169,3 +172,46 @@ ${crapBlock}`;
169
172
  * path without re-deriving it.
170
173
  */
171
174
  export const CI_WORKFLOW_RELATIVE_PATH = '.github/workflows/ci.yml';
175
+
176
+ /**
177
+ * Render the stabilized-quality-gates CI workflow template into a project
178
+ * checkout. Idempotent on the byte level: when `.github/workflows/ci.yml`
179
+ * already matches the rendered template, no write occurs and the action is
180
+ * `unchanged`. When the file is absent the action is `created`. When the
181
+ * file exists with operator-authored differences the helper preserves it
182
+ * and returns `custom-workflow-skip` along with the rendered body so the
183
+ * bootstrap caller (or `/agents-update`) can offer a side-by-side diff.
184
+ *
185
+ * Network-free; safe to invoke under tests with a tmp `projectRoot`.
186
+ *
187
+ * Moved from `agents-bootstrap-github.js` to this module so it lives
188
+ * alongside `renderCiWorkflow` and `CI_WORKFLOW_RELATIVE_PATH`
189
+ * (Story #4048 B2 — dead-code deletion from the bootstrap entry point).
190
+ *
191
+ * @param {object} args
192
+ * @param {string} args.projectRoot - Repo root (must contain or accept
193
+ * `.github/workflows/`).
194
+ * @param {object} [args.template] - Forwarded to `renderCiWorkflow`.
195
+ * @param {boolean} [args.write=true] - When `false`, the helper computes
196
+ * the would-be action without touching disk. Used by the
197
+ * bootstrap CLI's dry-run mode.
198
+ * @returns {{ action: 'created'|'unchanged'|'custom-workflow-skip',
199
+ * path: string, rendered: string }}
200
+ */
201
+ export function ensureCiWorkflow(args) {
202
+ const projectRoot = args.projectRoot;
203
+ const rendered = renderCiWorkflow(args.template);
204
+ const target = path.join(projectRoot, CI_WORKFLOW_RELATIVE_PATH);
205
+ if (!fs.existsSync(target)) {
206
+ if (args.write !== false) {
207
+ fs.mkdirSync(path.dirname(target), { recursive: true });
208
+ fs.writeFileSync(target, rendered, 'utf8');
209
+ }
210
+ return { action: 'created', path: target, rendered };
211
+ }
212
+ const existing = fs.readFileSync(target, 'utf8');
213
+ if (existing === rendered) {
214
+ return { action: 'unchanged', path: target, rendered };
215
+ }
216
+ return { action: 'custom-workflow-skip', path: target, rendered };
217
+ }
@@ -112,8 +112,8 @@ export function buildManualInstructions({ stagePaths, baseBranch }) {
112
112
  ` git push -u origin ${baseBranch}`,
113
113
  '',
114
114
  'Story delivery runs in git worktrees that check out tracked files only,',
115
- 'so the .agents/ wiring MUST be committed before any /story-deliver or',
116
- '/epic-deliver run — otherwise the worktree has no scripts and breaks.',
115
+ 'so the .agents/ wiring MUST be committed before any /deliver or',
116
+ '/deliver run — otherwise the worktree has no scripts and breaks.',
117
117
  ].join('\n');
118
118
  }
119
119
 
@@ -38,14 +38,12 @@ const GH_SCOPES_UNREADABLE_NOTE =
38
38
  * Framework runtime deps the consumer must have installed in
39
39
  * `node_modules/` before this script reaches the dynamic
40
40
  * `config-resolver` import. `ajv` is the sentinel — if it cannot
41
- * resolve, the operator skipped `/agents-bootstrap-project` (or its
42
- * Step 2c/2d dependency-install never ran). The list mirrors the floor
43
- * in `agents-bootstrap-project.md` Step 2c; keep them in sync.
41
+ * resolve, the framework runtime dependencies are not installed.
44
42
  */
45
43
  const REQUIRED_RUNTIME_DEPS = Object.freeze(['ajv']);
46
44
 
47
45
  const RUNTIME_DEPS_HINT =
48
- 'Run `/agents-bootstrap-project` (or `node .agents/scripts/agents-bootstrap-project.js` when present) to merge the framework runtime dependencies into your package.json and install them, then re-run this command.';
46
+ 'Run `mandrel init` (for a fresh project) or `npm install mandrel` (for an existing one) to install the framework runtime dependencies, then re-run this command.';
49
47
 
50
48
  /**
51
49
  * Default runner: synchronously execs `gh <args>` and returns
@@ -273,12 +271,12 @@ function classifyProjectScopes(scopeLine) {
273
271
  /**
274
272
  * Preflight the framework's runtime dependencies before dynamic-importing
275
273
  * `config-resolver.js` (which transitively pulls in `ajv` via
276
- * `config-settings-schema.js`). A fresh consumer who skipped
277
- * `/agents-bootstrap-project` will not have `ajv` installed, and the
278
- * raw `ERR_MODULE_NOT_FOUND` from the dynamic import is opaque. This
274
+ * `config-settings-schema.js`). A consumer who has not installed the
275
+ * framework runtime deps will not have `ajv` available, and the raw
276
+ * `ERR_MODULE_NOT_FOUND` from the dynamic import is opaque. This
279
277
  * preflight converts that into a {@link MissingRuntimeDepsError} that
280
- * names the missing packages and points the operator at the right
281
- * workflow.
278
+ * names the missing packages and points the operator at the correct
279
+ * remediation (`mandrel init` / `npm install mandrel`).
282
280
  *
283
281
  * The `resolver` seam lets tests inject a stub without touching the real
284
282
  * module graph; production uses `import.meta.resolve(specifier)`.
@@ -150,7 +150,17 @@ export function buildMutationManifest(ctx = {}) {
150
150
 
151
151
  // --- repo-config ------------------------------------------------------
152
152
  // Local repository configuration files the bootstrap seeds or extends.
153
+ // Also includes git-init, which is the most irreversible local mutation
154
+ // the bootstrap performs (B1 — uninstall ledger must record it).
153
155
  entries.push(
156
+ {
157
+ phaseGroup: PHASE_GROUPS.REPO_CONFIG,
158
+ target: rel('.git'),
159
+ action: 'run',
160
+ detail:
161
+ 'Initialize the local git repository (git init + first commit) when absent. No-op when already a git repo.',
162
+ reversible: false,
163
+ },
154
164
  {
155
165
  phaseGroup: PHASE_GROUPS.REPO_CONFIG,
156
166
  target: rel('package.json'),
@@ -209,6 +219,16 @@ export function buildMutationManifest(ctx = {}) {
209
219
  ? `${ctx.answers.owner}/${ctx.answers.repo}`
210
220
  : 'the GitHub repository';
211
221
  entries.push(
222
+ {
223
+ // B1: GitHub repo creation is the most irreversible remote mutation —
224
+ // record it so the uninstall ledger always lists it.
225
+ phaseGroup: PHASE_GROUPS.GITHUB_ADMIN,
226
+ target: `${repoSlug} (repo)`,
227
+ action: 'create',
228
+ detail:
229
+ 'Create the GitHub repository (gh repo create --source=. --push) when absent. No-op when already pushed.',
230
+ reversible: false,
231
+ },
212
232
  {
213
233
  phaseGroup: PHASE_GROUPS.GITHUB_ADMIN,
214
234
  target: `${repoSlug} labels`,
@@ -238,7 +258,7 @@ export function buildMutationManifest(ctx = {}) {
238
258
  target: `${repoSlug} merge methods`,
239
259
  action: 'configure',
240
260
  detail:
241
- 'Set the allowed pull-request merge methods to the framework stance.',
261
+ 'Set the allowed pull-request merge methods to the framework stance (squash-only, auto-merge enabled).',
242
262
  reversible: false,
243
263
  },
244
264
  );
@@ -17,10 +17,13 @@
17
17
  * No drift (live settings already match the target): no-op, returns
18
18
  * `{ status: 'unchanged' }`.
19
19
  *
20
- * Drift (any field differs from the target stance): routes the proposed
21
- * payload through `hitlConfirm`. On approval, PATCH is issued. On
22
- * decline or non-TTY (the gate returns false), the module returns
23
- * `{ status: 'skipped', reason: 'hitl-declined' }` without writing.
20
+ * Drift (any field differs from the target stance): when a `hitlConfirm`
21
+ * gate is supplied, the proposed payload routes through it — on approval
22
+ * the PATCH is issued; on decline the module returns
23
+ * `{ status: 'skipped', reason: 'hitl-declined' }` without writing (a loud
24
+ * decline, never silent). When NO gate is supplied (non-TTY, no operator
25
+ * present — Story #4045 A4), the framework stance is default-applied with
26
+ * an explicit log line.
24
27
  */
25
28
 
26
29
  export const TARGET_MERGE_METHODS = Object.freeze({
@@ -81,20 +84,32 @@ export async function applyMergeMethods({
81
84
  return { status: 'unchanged' };
82
85
  }
83
86
 
84
- const approved =
85
- typeof hitlConfirm === 'function'
86
- ? await hitlConfirm({
87
- summary:
88
- 'Repo merge-method settings diverge from the framework hands-off-pipeline stance.',
89
- current,
90
- proposed: target,
91
- })
92
- : false;
93
- if (!approved) {
87
+ let approved;
88
+ if (typeof hitlConfirm === 'function') {
89
+ approved = await hitlConfirm({
90
+ summary:
91
+ 'Repo merge-method settings diverge from the framework hands-off-pipeline stance.',
92
+ current,
93
+ proposed: target,
94
+ });
95
+ if (!approved) {
96
+ log(
97
+ '[bootstrap] Merge methods: HITL declined — leaving operator settings ' +
98
+ 'untouched. Note: auto-merge will remain disabled until the merge-method ' +
99
+ 'settings match the framework stance (allow_squash_merge: true, ' +
100
+ 'allow_auto_merge: true, delete_branch_on_merge: true).',
101
+ );
102
+ return { status: 'skipped', reason: 'hitl-declined', diff };
103
+ }
104
+ } else {
105
+ // Non-TTY: no operator present to confirm. Default-apply the framework
106
+ // stance and log explicitly so the consequence is never silent.
94
107
  log(
95
- '[bootstrap] Merge methods: drift detected; HITL declined / non-TTY — leaving operator settings untouched.',
108
+ '[bootstrap] Merge methods: non-TTY — applying framework stance automatically ' +
109
+ '(allow_squash_merge, allow_auto_merge, delete_branch_on_merge). ' +
110
+ 'To opt out, pass a hitlConfirm gate or set github.mergeMethods overrides in .agentrc.json.',
96
111
  );
97
- return { status: 'skipped', reason: 'hitl-declined', diff };
112
+ approved = true;
98
113
  }
99
114
 
100
115
  try {
@@ -1,6 +1,5 @@
1
1
  /**
2
- * bootstrap/project-bootstrap — deterministic port of the
3
- * `/agents-bootstrap-project` workflow (Story #2074, hard cutover).
2
+ * bootstrap/project-bootstrap — deterministic project bootstrap steps.
4
3
  *
5
4
  * Each exported `ensure*` function is one step of the bootstrap. Every step
6
5
  * is idempotent and additive — re-running on an already-bootstrapped clone
@@ -16,6 +15,8 @@ import { spawnSync as defaultSpawnSync } from 'node:child_process';
16
15
  import fs from 'node:fs';
17
16
  import os from 'node:os';
18
17
  import path from 'node:path';
18
+ import { pathToFileURL } from 'node:url';
19
+ import { detectPackageManager as detectPm } from '../detect-package-manager.js';
19
20
  import { LEDGER_RELATIVE_PATH } from './install-ledger.js';
20
21
  import { PHASE_GROUPS, previewMutationManifest } from './manifest.js';
21
22
  import { applyQualityBootstrap } from './quality-bootstrap.js';
@@ -61,8 +62,8 @@ export const GITIGNORE_BLOCKS = Object.freeze({
61
62
  block:
62
63
  '\n# Project-scoped MCP config carries secrets — keep out of git.\n.mcp.json\n',
63
64
  },
64
- // Story #3894: `.env` holds real secrets (`/onboard` instructs operators to
65
- // put `GITHUB_TOKEN` here). It MUST be ignored by default so a cold-start
65
+ // Story #3894: `.env` holds real secrets (`mandrel init` instructs operators
66
+ // to put `GITHUB_TOKEN` here). It MUST be ignored by default so a cold-start
66
67
  // provision never stages/pushes it. The pattern matches a bare `.env` (with
67
68
  // an optional trailing slash) but deliberately NOT `.env.example`, the
68
69
  // committed placeholder that `security-baseline.md` § Secrets Management
@@ -112,7 +113,23 @@ function writeJson(p, obj, fsImpl = fs) {
112
113
  fsImpl.writeFileSync(p, `${JSON.stringify(obj, null, 2)}\n`, 'utf8');
113
114
  }
114
115
 
115
- /** Matches root `package.json` `engines.node`. */
116
+ /**
117
+ * The minimum Node.js patch version mandrel requires.
118
+ *
119
+ * Rationale: `22.22.1` is the Node 22 LTS patch that ships with the
120
+ * `node:sqlite` built-in (`--experimental-sqlite` removed from flag
121
+ * requirement in 22.5.0, but the module stabilised at 22.22.1 per the
122
+ * Node 22 LTS changelog). Pinning to this patch prevents silent failures on
123
+ * older 22.x installs that lack the built-in. CI exercises `node-version: 22`
124
+ * which resolves to the latest 22.x (always ≥ 22.22.1 in the current GHA
125
+ * environment), so CI validates the contract without exercising the exact
126
+ * patch floor — the floor is enforced at install time, not in CI.
127
+ *
128
+ * Single source of truth: `registry.js` and any other consumer MUST import
129
+ * this constant rather than duplicating it.
130
+ *
131
+ * Matches `package.json` `engines.node` (`>=22.22.1 <25`).
132
+ */
116
133
  export const REQUIRED_NODE_FLOOR = '22.22.1';
117
134
  export const REQUIRED_NODE_CEILING_MAJOR = 25;
118
135
 
@@ -152,16 +169,18 @@ export function checkNodeVersion(version = process.versions.node) {
152
169
 
153
170
  /**
154
171
  * Detect the package manager based on lockfile presence. Defaults to
155
- * `npm` when no lock is found.
172
+ * `npm` when no lock is found (including the `null` case from the shared
173
+ * helper where no Node manifest exists at all).
174
+ *
175
+ * Delegates to the shared `detectPackageManager` helper
176
+ * (Story #4048 B3 — one implementation per concept).
156
177
  *
157
178
  * @param {string} projectRoot
158
179
  * @param {typeof fs} [fsImpl]
180
+ * @returns {'pnpm'|'yarn'|'npm'}
159
181
  */
160
182
  export function detectPackageManager(projectRoot, fsImpl = fs) {
161
- if (fsImpl.existsSync(path.join(projectRoot, 'pnpm-lock.yaml')))
162
- return 'pnpm';
163
- if (fsImpl.existsSync(path.join(projectRoot, 'yarn.lock'))) return 'yarn';
164
- return 'npm';
183
+ return detectPm(projectRoot, (p) => fsImpl.existsSync(p)) ?? 'npm';
165
184
  }
166
185
 
167
186
  /**
@@ -328,7 +347,9 @@ export async function validateAgentrc(ctx) {
328
347
  if (!fsImpl.existsSync(schemaModule)) {
329
348
  return { ok: false, errors: ['config-settings-schema.js not found'] };
330
349
  }
331
- const mod = await import(`file://${schemaModule.replace(/\\/g, '/')}`);
350
+ // pathToFileURL handles Windows drive letters and percent-encoding
351
+ // correctly (same fix as commit 2e3d210b in lib/transpile.js).
352
+ const mod = await import(pathToFileURL(schemaModule).href);
332
353
  const validate = mod.getAgentrcValidator();
333
354
  const data = readJsonIfExists(
334
355
  path.join(ctx.projectRoot, '.agentrc.json'),
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * codebase-snapshot.js — Bounded structural view of the consumer repo.
3
3
  *
4
- * Story #2634 (sibling to #2635 spec-freshness). `/epic-plan` Phase 7
4
+ * Story #2634 (sibling to #2635 spec-freshness). `/plan` Phase 7
5
5
  * authors PRD + Tech Spec from documentation alone — `architecture.md`,
6
6
  * `data-dictionary.md`, `decisions.md`, `patterns.md`. When those docs
7
7
  * drift from the real source tree, the Architect persona cites modules
@@ -113,7 +113,7 @@ const KEY_MEANINGS = Object.freeze({
113
113
 
114
114
  // planning.*
115
115
  'planning.maxTickets':
116
- 'Upper bound on tickets a single /epic-plan run may create.',
116
+ 'Upper bound on tickets a single /plan run may create.',
117
117
  'planning.context.maxBytes':
118
118
  'Byte budget for the planning-context payload before summary mode kicks in.',
119
119
  'planning.context.summaryMode':
@@ -29,7 +29,7 @@ export const DEFAULT_DECOMPOSER = Object.freeze({
29
29
  * host has adequate parallel-agent quota, operators should raise
30
30
  * `delivery.deliverRunner.concurrencyCap` — wall-clock time falls
31
31
  * proportionally to the extra concurrency. The safe default is a tuning
32
- * knob, not a performance ceiling. See `epic-deliver.md` § Phase 2b and
32
+ * knob, not a performance ceiling. See `helpers/deliver-epic.md` § Phase 2b and
33
33
  * `agentrc-reference.json` `delivery.deliverRunner.concurrencyCap` for details.
34
34
  *
35
35
  * **`verifyConcurrencyCap`** (Epic #3019 Tech Spec §1.4 / Story #3024) is a
@@ -44,7 +44,7 @@ const DEFAULT_DELIVER_RUNNER = Object.freeze({
44
44
  });
45
45
 
46
46
  /**
47
- * Default auto-fix loop ceilings for /epic-deliver Phase 4 (epic-audit)
47
+ * Default auto-fix loop ceilings for /deliver Phase 4 (epic-audit)
48
48
  * and Phase 5 (code-review). Operators override via
49
49
  * `delivery.epicAudit.*` and `delivery.codeReview.*` in `.agentrc.json`
50
50
  * (Story #2611, Epic #2586).
@@ -77,7 +77,7 @@ export function resolveWorkingPath({
77
77
 
78
78
  /**
79
79
  * One-shot environment-aware runtime resolution. Returns the trio of runtime
80
- * signals consumed across `/epic-deliver`: whether worktree isolation is on
80
+ * signals consumed across `/deliver`: whether worktree isolation is on
81
81
  * for this process, the session id for claim labels, and whether we're in a
82
82
  * Claude Code web session. Each signal also records its **source** so the
83
83
  * `story-init` startup log can name why the value is what it is.
@@ -69,7 +69,7 @@ export function syncAgentrc(opts) {
69
69
  status: 'missing-config',
70
70
  changes: [],
71
71
  errors: [
72
- `No .agentrc.json at ${configPath}. Run /agents-bootstrap-project first.`,
72
+ `No .agentrc.json at ${configPath}. Run \`mandrel init\` (new project) or \`node .agents/scripts/bootstrap.js\` to create it.`,
73
73
  ],
74
74
  configPath,
75
75
  wrote: false,
@@ -44,7 +44,7 @@
44
44
  * parent of `git rev-parse --git-common-dir`) rather than `process.cwd()`.
45
45
  * Without this, a story child that `cd`s into `.worktrees/story-<id>/` before
46
46
  * calling `story-phase.js` would append `story.heartbeat` records to
47
- * `<worktree>/temp/epic-N/lifecycle.ndjson`, while the `/epic-deliver` host
47
+ * `<worktree>/temp/epic-N/lifecycle.ndjson`, while the `/deliver` host
48
48
  * (running from the main checkout) reads the main-checkout copy — so the
49
49
  * idle-watchdog never sees heartbeats and the Epic-lease guard silently
50
50
  * reclaims live foreign claims (the audit-#3513 bug class). Anchoring the
@@ -335,7 +335,7 @@ export const epicPerfReportPath = (eid, config) =>
335
335
 
336
336
  /**
337
337
  * `temp/epic-<eid>/epic-perf-report.json` — canonical JSON snapshot of
338
- * the `epic-perf-report` payload persisted at /epic-deliver close
338
+ * the `epic-perf-report` payload persisted at /deliver close
339
339
  * (Epic #3019 / Story #3029 / Task #3040). When present alongside the
340
340
  * `epic-perf-report` structured comment, the report is discoverable
341
341
  * from the file system without round-tripping the ticketing provider,
@@ -203,7 +203,7 @@ const MERGE_WATCH_SCHEMA = {
203
203
  };
204
204
 
205
205
  /**
206
- * `delivery.epicAudit` — bounded-retry knobs for /epic-deliver Phase 4
206
+ * `delivery.epicAudit` — bounded-retry knobs for /deliver Phase 4
207
207
  * (epic-audit). `maxFixAttempts` caps how many times the auto-fix loop
208
208
  * retries a single finding (Story #2611, Epic #2586). `maxFixScopeFiles`
209
209
  * caps how many files a single auto-fix may touch before escalating to
@@ -237,7 +237,7 @@ const CI_DELIVERY_SCHEMA = {
237
237
  // Story #2899 (Epic #2880) — `delivery.preflight.*` thresholds consumed
238
238
  // by `epic-deliver-preflight.js`. When any value is exceeded the CLI
239
239
  // surfaces a breach in its envelope and the workflow flips the Epic to
240
- // `agent::blocked` (see /epic-deliver Phase 1 prelude).
240
+ // `agent::blocked` (see /deliver Phase 1 prelude).
241
241
  const PREFLIGHT_SCHEMA = {
242
242
  type: 'object',
243
243
  properties: {
@@ -102,7 +102,7 @@ export const QUALITY_SCHEMA = {
102
102
 
103
103
  /**
104
104
  * `delivery.codeReview` — sibling to `delivery.epicAudit`. Same bounded
105
- * retry + scope cap, applied to /epic-deliver Phase 5 (code-review).
105
+ * retry + scope cap, applied to /deliver Phase 5 (code-review).
106
106
  */
107
107
  export const CODE_REVIEW_SCHEMA = {
108
108
  type: 'object',