mandrel 1.57.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 (843) hide show
  1. package/.agents/README.md +954 -0
  2. package/.agents/docs/SDLC.md +1420 -0
  3. package/.agents/docs/agentrc-reference.json +278 -0
  4. package/.agents/docs/configuration.md +1040 -0
  5. package/.agents/docs/workflows.md +59 -0
  6. package/.agents/instructions.md +384 -0
  7. package/.agents/personas/architect.md +107 -0
  8. package/.agents/personas/devops-engineer.md +36 -0
  9. package/.agents/personas/engineer-mobile.md +119 -0
  10. package/.agents/personas/engineer-web.md +110 -0
  11. package/.agents/personas/engineer.md +90 -0
  12. package/.agents/personas/product.md +88 -0
  13. package/.agents/personas/project-manager.md +110 -0
  14. package/.agents/personas/qa-engineer.md +91 -0
  15. package/.agents/personas/refactorer.md +110 -0
  16. package/.agents/personas/security-engineer.md +112 -0
  17. package/.agents/personas/sre.md +86 -0
  18. package/.agents/personas/technical-writer.md +100 -0
  19. package/.agents/personas/ux-designer.md +95 -0
  20. package/.agents/rules/api-conventions.md +75 -0
  21. package/.agents/rules/changelog-style.md +238 -0
  22. package/.agents/rules/gherkin-standards.md +146 -0
  23. package/.agents/rules/git-conventions.md +146 -0
  24. package/.agents/rules/orchestration-error-handling.md +35 -0
  25. package/.agents/rules/security-baseline.md +92 -0
  26. package/.agents/rules/shell-conventions.md +70 -0
  27. package/.agents/rules/test-seams.md +59 -0
  28. package/.agents/rules/testing-standards.md +177 -0
  29. package/.agents/runtime-deps.json +18 -0
  30. package/.agents/schemas/acceptance-eval-verdict.schema.json +93 -0
  31. package/.agents/schemas/agentrc.schema.json +1583 -0
  32. package/.agents/schemas/audit-results.schema.json +69 -0
  33. package/.agents/schemas/audit-rules.json +134 -0
  34. package/.agents/schemas/audit-rules.schema.json +69 -0
  35. package/.agents/schemas/baselines/baseline-envelope.schema.json +44 -0
  36. package/.agents/schemas/baselines/bundle-size.schema.json +47 -0
  37. package/.agents/schemas/baselines/coverage.schema.json +50 -0
  38. package/.agents/schemas/baselines/crap.schema.json +52 -0
  39. package/.agents/schemas/baselines/duplication.schema.json +62 -0
  40. package/.agents/schemas/baselines/lighthouse.schema.json +59 -0
  41. package/.agents/schemas/baselines/lint.schema.json +47 -0
  42. package/.agents/schemas/baselines/maintainability.schema.json +71 -0
  43. package/.agents/schemas/baselines/mutation.schema.json +52 -0
  44. package/.agents/schemas/crap-baseline.schema.json +57 -0
  45. package/.agents/schemas/crap-report.schema.json +102 -0
  46. package/.agents/schemas/dispatch-manifest.json +232 -0
  47. package/.agents/schemas/epic-perf-report.schema.json +89 -0
  48. package/.agents/schemas/epic-spec.schema.json +183 -0
  49. package/.agents/schemas/friction-event.schema.json +56 -0
  50. package/.agents/schemas/lifecycle/README.md +18 -0
  51. package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +13 -0
  52. package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +13 -0
  53. package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +13 -0
  54. package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +12 -0
  55. package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +13 -0
  56. package/.agents/schemas/lifecycle/checkpoint.written.schema.json +13 -0
  57. package/.agents/schemas/lifecycle/close-validate.end.schema.json +18 -0
  58. package/.agents/schemas/lifecycle/close-validate.start.schema.json +13 -0
  59. package/.agents/schemas/lifecycle/code-review.end.schema.json +30 -0
  60. package/.agents/schemas/lifecycle/code-review.start.schema.json +12 -0
  61. package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +14 -0
  62. package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +13 -0
  63. package/.agents/schemas/lifecycle/epic.blocked.schema.json +13 -0
  64. package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +12 -0
  65. package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +12 -0
  66. package/.agents/schemas/lifecycle/epic.close.end.schema.json +12 -0
  67. package/.agents/schemas/lifecycle/epic.complete.schema.json +13 -0
  68. package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +13 -0
  69. package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +12 -0
  70. package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +13 -0
  71. package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +14 -0
  72. package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +17 -0
  73. package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +15 -0
  74. package/.agents/schemas/lifecycle/epic.plan.end.schema.json +18 -0
  75. package/.agents/schemas/lifecycle/epic.plan.start.schema.json +12 -0
  76. package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +16 -0
  77. package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +12 -0
  78. package/.agents/schemas/lifecycle/epic.watch.end.schema.json +28 -0
  79. package/.agents/schemas/lifecycle/epic.watch.start.schema.json +16 -0
  80. package/.agents/schemas/lifecycle/intervention.recorded.schema.json +15 -0
  81. package/.agents/schemas/lifecycle/ledger-record.schema.json +59 -0
  82. package/.agents/schemas/lifecycle/notification.emitted.schema.json +18 -0
  83. package/.agents/schemas/lifecycle/pr.created.schema.json +14 -0
  84. package/.agents/schemas/lifecycle/retro.end.schema.json +16 -0
  85. package/.agents/schemas/lifecycle/retro.start.schema.json +12 -0
  86. package/.agents/schemas/lifecycle/story.blocked.schema.json +13 -0
  87. package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +17 -0
  88. package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +15 -0
  89. package/.agents/schemas/lifecycle/story.heartbeat.schema.json +20 -0
  90. package/.agents/schemas/lifecycle/story.merged.schema.json +13 -0
  91. package/.agents/schemas/mi-report.schema.json +58 -0
  92. package/.agents/schemas/model-attribution.schema.json +49 -0
  93. package/.agents/schemas/qa-finding.schema.json +133 -0
  94. package/.agents/schemas/qa-ledger.schema.json +89 -0
  95. package/.agents/schemas/risk-verdict.schema.json +53 -0
  96. package/.agents/schemas/signal-event.schema.json +58 -0
  97. package/.agents/schemas/skill.schema.json +31 -0
  98. package/.agents/schemas/skills-index.schema.json +81 -0
  99. package/.agents/schemas/story-perf-summary.schema.json +73 -0
  100. package/.agents/schemas/validation-evidence.schema.json +78 -0
  101. package/.agents/scripts/README.md +93 -0
  102. package/.agents/scripts/acceptance-eval.js +284 -0
  103. package/.agents/scripts/acceptance-spec-reconciler.js +556 -0
  104. package/.agents/scripts/agents-bootstrap-github.js +634 -0
  105. package/.agents/scripts/analyze-execution.js +369 -0
  106. package/.agents/scripts/assert-branch.js +83 -0
  107. package/.agents/scripts/audit-labels-bootstrap.js +253 -0
  108. package/.agents/scripts/audit-to-stories.js +257 -0
  109. package/.agents/scripts/bootstrap.js +1378 -0
  110. package/.agents/scripts/check-baselines.js +81 -0
  111. package/.agents/scripts/check-dead-exports.js +311 -0
  112. package/.agents/scripts/check-doc-links.js +401 -0
  113. package/.agents/scripts/check-gherkin-placeholders.js +663 -0
  114. package/.agents/scripts/check-lifecycle-doc-drift.js +402 -0
  115. package/.agents/scripts/check-lifecycle-lint.js +379 -0
  116. package/.agents/scripts/check-prepush-recovery.js +90 -0
  117. package/.agents/scripts/check-windows-git-perf.js +138 -0
  118. package/.agents/scripts/cleanup-repo-test-temp.js +67 -0
  119. package/.agents/scripts/coverage-capture.js +112 -0
  120. package/.agents/scripts/detect-merges.js +111 -0
  121. package/.agents/scripts/diagnose-friction.js +257 -0
  122. package/.agents/scripts/diagnose.js +240 -0
  123. package/.agents/scripts/dispatcher.js +295 -0
  124. package/.agents/scripts/drain-pending-cleanup.js +147 -0
  125. package/.agents/scripts/epic-audit-prepare.js +419 -0
  126. package/.agents/scripts/epic-audit-recheck.js +241 -0
  127. package/.agents/scripts/epic-deliver-note-intervention.js +192 -0
  128. package/.agents/scripts/epic-deliver-preflight.js +407 -0
  129. package/.agents/scripts/epic-deliver-prepare.js +383 -0
  130. package/.agents/scripts/epic-execute-record-wave.js +463 -0
  131. package/.agents/scripts/epic-plan-clarity.js +201 -0
  132. package/.agents/scripts/epic-plan-decompose.js +79 -0
  133. package/.agents/scripts/epic-plan-healthcheck.js +363 -0
  134. package/.agents/scripts/epic-plan-spec-validate.js +111 -0
  135. package/.agents/scripts/epic-plan-spec.js +198 -0
  136. package/.agents/scripts/epic-reconcile.js +637 -0
  137. package/.agents/scripts/evidence-gate.js +235 -0
  138. package/.agents/scripts/generate-config-docs.js +516 -0
  139. package/.agents/scripts/generate-lifecycle-docs.js +224 -0
  140. package/.agents/scripts/generate-skills-index.js +252 -0
  141. package/.agents/scripts/generate-workflows-doc.js +168 -0
  142. package/.agents/scripts/git-cleanup.js +124 -0
  143. package/.agents/scripts/git-pr-quality-gate.js +203 -0
  144. package/.agents/scripts/git-rebase-and-resolve.js +234 -0
  145. package/.agents/scripts/hierarchy-gate.js +176 -0
  146. package/.agents/scripts/hydrate-context.js +179 -0
  147. package/.agents/scripts/install-matrix-assert.js +282 -0
  148. package/.agents/scripts/lib/Graph.js +326 -0
  149. package/.agents/scripts/lib/ITicketingProvider.js +349 -0
  150. package/.agents/scripts/lib/Logger.js +194 -0
  151. package/.agents/scripts/lib/audit-suite/cli.js +64 -0
  152. package/.agents/scripts/lib/audit-suite/findings.js +164 -0
  153. package/.agents/scripts/lib/audit-suite/frontmatter-lint.js +32 -0
  154. package/.agents/scripts/lib/audit-suite/frontmatter.js +110 -0
  155. package/.agents/scripts/lib/audit-suite/index.js +22 -0
  156. package/.agents/scripts/lib/audit-suite/runner.js +233 -0
  157. package/.agents/scripts/lib/audit-suite/selector.js +235 -0
  158. package/.agents/scripts/lib/audit-suite/substitutions.js +124 -0
  159. package/.agents/scripts/lib/audit-suite/workflow-loader.js +49 -0
  160. package/.agents/scripts/lib/audit-to-stories/build-story-body.js +130 -0
  161. package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +114 -0
  162. package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +93 -0
  163. package/.agents/scripts/lib/audit-to-stories/group-findings.js +265 -0
  164. package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +246 -0
  165. package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +160 -0
  166. package/.agents/scripts/lib/auto-refresh-baselines.js +308 -0
  167. package/.agents/scripts/lib/baseline-loader.js +0 -0
  168. package/.agents/scripts/lib/baseline-schema-registry.js +69 -0
  169. package/.agents/scripts/lib/baseline-snapshot.js +716 -0
  170. package/.agents/scripts/lib/baselines/component-matcher.js +21 -0
  171. package/.agents/scripts/lib/baselines/components.js +126 -0
  172. package/.agents/scripts/lib/baselines/diff-scope-cli.js +203 -0
  173. package/.agents/scripts/lib/baselines/duplication-scanner.js +220 -0
  174. package/.agents/scripts/lib/baselines/env-overrides.js +129 -0
  175. package/.agents/scripts/lib/baselines/envelope.js +368 -0
  176. package/.agents/scripts/lib/baselines/exit-codes.js +89 -0
  177. package/.agents/scripts/lib/baselines/git-base.js +0 -0
  178. package/.agents/scripts/lib/baselines/kernel.js +111 -0
  179. package/.agents/scripts/lib/baselines/kinds/_shared-metric.js +220 -0
  180. package/.agents/scripts/lib/baselines/kinds/bundle-size.js +157 -0
  181. package/.agents/scripts/lib/baselines/kinds/coverage.js +194 -0
  182. package/.agents/scripts/lib/baselines/kinds/crap.js +555 -0
  183. package/.agents/scripts/lib/baselines/kinds/duplication.js +197 -0
  184. package/.agents/scripts/lib/baselines/kinds/lighthouse.js +185 -0
  185. package/.agents/scripts/lib/baselines/kinds/lint.js +172 -0
  186. package/.agents/scripts/lib/baselines/kinds/maintainability.js +340 -0
  187. package/.agents/scripts/lib/baselines/kinds/mutation.js +153 -0
  188. package/.agents/scripts/lib/baselines/path-canon.js +279 -0
  189. package/.agents/scripts/lib/baselines/preview-gates.js +298 -0
  190. package/.agents/scripts/lib/baselines/reader.js +321 -0
  191. package/.agents/scripts/lib/baselines/refresh-service.js +733 -0
  192. package/.agents/scripts/lib/baselines/scope.js +291 -0
  193. package/.agents/scripts/lib/baselines/writer.js +312 -0
  194. package/.agents/scripts/lib/bdd-runner-detect.js +417 -0
  195. package/.agents/scripts/lib/bdd-scenario-scanner.js +310 -0
  196. package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +202 -0
  197. package/.agents/scripts/lib/bootstrap/branch-protection.js +222 -0
  198. package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +171 -0
  199. package/.agents/scripts/lib/bootstrap/commit-push.js +146 -0
  200. package/.agents/scripts/lib/bootstrap/gh-list.js +153 -0
  201. package/.agents/scripts/lib/bootstrap/gh-preflight.js +306 -0
  202. package/.agents/scripts/lib/bootstrap/hitl-confirm.js +89 -0
  203. package/.agents/scripts/lib/bootstrap/install-ledger.js +174 -0
  204. package/.agents/scripts/lib/bootstrap/manifest.js +272 -0
  205. package/.agents/scripts/lib/bootstrap/merge-methods.js +108 -0
  206. package/.agents/scripts/lib/bootstrap/preflight.js +195 -0
  207. package/.agents/scripts/lib/bootstrap/project-bootstrap.js +801 -0
  208. package/.agents/scripts/lib/bootstrap/prompt.js +480 -0
  209. package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +370 -0
  210. package/.agents/scripts/lib/bootstrap/summary.js +75 -0
  211. package/.agents/scripts/lib/bootstrap/workflow-audit.js +256 -0
  212. package/.agents/scripts/lib/branch-name-guard.js +98 -0
  213. package/.agents/scripts/lib/c8-cli-path.js +21 -0
  214. package/.agents/scripts/lib/changed-files.js +184 -0
  215. package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +104 -0
  216. package/.agents/scripts/lib/checks/core-bare-clean.js +48 -0
  217. package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +54 -0
  218. package/.agents/scripts/lib/checks/index.js +288 -0
  219. package/.agents/scripts/lib/checks/push-hook-parity.js +106 -0
  220. package/.agents/scripts/lib/checks/stale-origin-epic.js +49 -0
  221. package/.agents/scripts/lib/checks/state.js +558 -0
  222. package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +186 -0
  223. package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +182 -0
  224. package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +92 -0
  225. package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +81 -0
  226. package/.agents/scripts/lib/checks/worktree-residue-biome.js +55 -0
  227. package/.agents/scripts/lib/cli/parse-numeric.js +60 -0
  228. package/.agents/scripts/lib/cli/standard-args.js +351 -0
  229. package/.agents/scripts/lib/cli-args.js +286 -0
  230. package/.agents/scripts/lib/cli-utils.js +69 -0
  231. package/.agents/scripts/lib/close-validation/projections/head-sha.js +44 -0
  232. package/.agents/scripts/lib/close-validation/projections/inputs.js +86 -0
  233. package/.agents/scripts/lib/close-validation/projections/maintainability.js +286 -0
  234. package/.agents/scripts/lib/close-validation.js +897 -0
  235. package/.agents/scripts/lib/codebase-snapshot.js +513 -0
  236. package/.agents/scripts/lib/command-header.js +33 -0
  237. package/.agents/scripts/lib/config/acceptance-eval.js +95 -0
  238. package/.agents/scripts/lib/config/baselines.js +60 -0
  239. package/.agents/scripts/lib/config/ci.js +30 -0
  240. package/.agents/scripts/lib/config/commands.js +36 -0
  241. package/.agents/scripts/lib/config/defaults.js +119 -0
  242. package/.agents/scripts/lib/config/explain.js +348 -0
  243. package/.agents/scripts/lib/config/gates/bundle-size.schema.js +23 -0
  244. package/.agents/scripts/lib/config/gates/coverage.schema.js +18 -0
  245. package/.agents/scripts/lib/config/gates/crap.schema.js +33 -0
  246. package/.agents/scripts/lib/config/gates/duplication.schema.js +26 -0
  247. package/.agents/scripts/lib/config/gates/index.js +36 -0
  248. package/.agents/scripts/lib/config/gates/lighthouse.schema.js +23 -0
  249. package/.agents/scripts/lib/config/gates/lint.schema.js +9 -0
  250. package/.agents/scripts/lib/config/gates/maintainability.schema.js +20 -0
  251. package/.agents/scripts/lib/config/gates/mutation.schema.js +12 -0
  252. package/.agents/scripts/lib/config/gates/shared.js +117 -0
  253. package/.agents/scripts/lib/config/github.js +122 -0
  254. package/.agents/scripts/lib/config/lifecycle.js +40 -0
  255. package/.agents/scripts/lib/config/limits.js +211 -0
  256. package/.agents/scripts/lib/config/paths.js +73 -0
  257. package/.agents/scripts/lib/config/preflight.js +58 -0
  258. package/.agents/scripts/lib/config/quality.js +665 -0
  259. package/.agents/scripts/lib/config/retro.js +77 -0
  260. package/.agents/scripts/lib/config/runners.js +105 -0
  261. package/.agents/scripts/lib/config/runtime.js +167 -0
  262. package/.agents/scripts/lib/config/shared.js +46 -0
  263. package/.agents/scripts/lib/config/sync-agentrc.js +243 -0
  264. package/.agents/scripts/lib/config/temp-paths.js +373 -0
  265. package/.agents/scripts/lib/config/validate-orchestration.js +81 -0
  266. package/.agents/scripts/lib/config/worktree-isolation.js +80 -0
  267. package/.agents/scripts/lib/config-resolver.js +298 -0
  268. package/.agents/scripts/lib/config-schema-shared.js +32 -0
  269. package/.agents/scripts/lib/config-schema.js +20 -0
  270. package/.agents/scripts/lib/config-settings-schema-delivery.js +332 -0
  271. package/.agents/scripts/lib/config-settings-schema-quality.js +165 -0
  272. package/.agents/scripts/lib/config-settings-schema.js +420 -0
  273. package/.agents/scripts/lib/coverage-baseline.js +352 -0
  274. package/.agents/scripts/lib/coverage-capture.js +195 -0
  275. package/.agents/scripts/lib/coverage-utils.js +239 -0
  276. package/.agents/scripts/lib/cpu-pool.js +223 -0
  277. package/.agents/scripts/lib/crap-engine.js +119 -0
  278. package/.agents/scripts/lib/crap-utils.js +479 -0
  279. package/.agents/scripts/lib/degraded-mode.js +69 -0
  280. package/.agents/scripts/lib/dependency-parser.js +129 -0
  281. package/.agents/scripts/lib/duplicate-search.js +189 -0
  282. package/.agents/scripts/lib/dynamic-workflow/architecture-report-contract.js +70 -0
  283. package/.agents/scripts/lib/dynamic-workflow/audit-orchestrator.js +197 -0
  284. package/.agents/scripts/lib/dynamic-workflow/capability.js +396 -0
  285. package/.agents/scripts/lib/dynamic-workflow/clean-code-report-contract.js +80 -0
  286. package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +72 -0
  287. package/.agents/scripts/lib/dynamic-workflow/quality-report-contract.js +90 -0
  288. package/.agents/scripts/lib/dynamic-workflow/report-contract-core.js +43 -0
  289. package/.agents/scripts/lib/dynamic-workflow/security-report-contract.js +83 -0
  290. package/.agents/scripts/lib/env-loader.js +52 -0
  291. package/.agents/scripts/lib/epic-merge-lock.js +239 -0
  292. package/.agents/scripts/lib/epic-plan-clarity.js +142 -0
  293. package/.agents/scripts/lib/epic-plan-ideation.js +228 -0
  294. package/.agents/scripts/lib/error-redactor.js +125 -0
  295. package/.agents/scripts/lib/errors/index.js +67 -0
  296. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +230 -0
  297. package/.agents/scripts/lib/feedback-loop/code-review-graduator.js +207 -0
  298. package/.agents/scripts/lib/feedback-loop/graduator-core.js +421 -0
  299. package/.agents/scripts/lib/feedback-loop/memory-freshness.js +480 -0
  300. package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +229 -0
  301. package/.agents/scripts/lib/findings/classify-finding.js +195 -0
  302. package/.agents/scripts/lib/findings/promote-finding.js +353 -0
  303. package/.agents/scripts/lib/findings/route-finding.js +283 -0
  304. package/.agents/scripts/lib/findings/semantic-issue-search.js +179 -0
  305. package/.agents/scripts/lib/findings/severity.js +102 -0
  306. package/.agents/scripts/lib/gates/baseline-store.js +106 -0
  307. package/.agents/scripts/lib/gates/friction.js +43 -0
  308. package/.agents/scripts/lib/gh-exec.js +553 -0
  309. package/.agents/scripts/lib/git/cached-fetch.js +0 -0
  310. package/.agents/scripts/lib/git/sync-from-base.js +162 -0
  311. package/.agents/scripts/lib/git-branch-cleanup.js +213 -0
  312. package/.agents/scripts/lib/git-branch-lifecycle.js +353 -0
  313. package/.agents/scripts/lib/git-merge-orchestrator.js +261 -0
  314. package/.agents/scripts/lib/git-utils.js +363 -0
  315. package/.agents/scripts/lib/github-url.js +29 -0
  316. package/.agents/scripts/lib/install-cmd-parser.js +51 -0
  317. package/.agents/scripts/lib/issue-link-parser.js +74 -0
  318. package/.agents/scripts/lib/json-utils.js +60 -0
  319. package/.agents/scripts/lib/label-constants.js +169 -0
  320. package/.agents/scripts/lib/label-taxonomy.js +200 -0
  321. package/.agents/scripts/lib/maintainability-engine.js +164 -0
  322. package/.agents/scripts/lib/maintainability-utils.js +343 -0
  323. package/.agents/scripts/lib/mandrel-catalog.js +170 -0
  324. package/.agents/scripts/lib/mutation/baseline-snapshot.js +238 -0
  325. package/.agents/scripts/lib/mutation/config-detector.js +119 -0
  326. package/.agents/scripts/lib/mutation/stryker-runner.js +306 -0
  327. package/.agents/scripts/lib/mutation/survivor-report.js +160 -0
  328. package/.agents/scripts/lib/notifications/notifier.js +75 -0
  329. package/.agents/scripts/lib/observability/active-story-env.js +182 -0
  330. package/.agents/scripts/lib/observability/baseline-refresh-rate.js +221 -0
  331. package/.agents/scripts/lib/observability/perf-aggregator.js +887 -0
  332. package/.agents/scripts/lib/observability/perf-report-readers.js +319 -0
  333. package/.agents/scripts/lib/observability/perf-report-render.js +182 -0
  334. package/.agents/scripts/lib/observability/signals-writer.js +296 -0
  335. package/.agents/scripts/lib/observability/source-classifier.js +103 -0
  336. package/.agents/scripts/lib/observability/tool-trace-hook.js +417 -0
  337. package/.agents/scripts/lib/onboard/detect-stack.js +300 -0
  338. package/.agents/scripts/lib/onboard/scaffold-docs.js +128 -0
  339. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +173 -0
  340. package/.agents/scripts/lib/orchestration/cascade-grouping.js +275 -0
  341. package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +131 -0
  342. package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +80 -0
  343. package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +132 -0
  344. package/.agents/scripts/lib/orchestration/check-baselines/phases/friction.js +142 -0
  345. package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +149 -0
  346. package/.agents/scripts/lib/orchestration/check-baselines/phases/pipeline.js +158 -0
  347. package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +56 -0
  348. package/.agents/scripts/lib/orchestration/code-review.js +652 -0
  349. package/.agents/scripts/lib/orchestration/column-sync.js +286 -0
  350. package/.agents/scripts/lib/orchestration/context-envelope.js +280 -0
  351. package/.agents/scripts/lib/orchestration/context-hydration-engine.js +581 -0
  352. package/.agents/scripts/lib/orchestration/dependency-analyzer.js +88 -0
  353. package/.agents/scripts/lib/orchestration/detectors-phase.js +188 -0
  354. package/.agents/scripts/lib/orchestration/dispatch-engine.js +144 -0
  355. package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +206 -0
  356. package/.agents/scripts/lib/orchestration/doc-reader.js +94 -0
  357. package/.agents/scripts/lib/orchestration/epic-cleanup.js +473 -0
  358. package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +310 -0
  359. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/cli.js +167 -0
  360. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +151 -0
  361. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +74 -0
  362. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +78 -0
  363. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +72 -0
  364. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +155 -0
  365. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +321 -0
  366. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +75 -0
  367. package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +86 -0
  368. package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +235 -0
  369. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +197 -0
  370. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/cli-args.js +48 -0
  371. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +94 -0
  372. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +414 -0
  373. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +55 -0
  374. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +105 -0
  375. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +235 -0
  376. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +120 -0
  377. package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +118 -0
  378. package/.agents/scripts/lib/orchestration/epic-run-state-store.js +295 -0
  379. package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +186 -0
  380. package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +50 -0
  381. package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +146 -0
  382. package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +110 -0
  383. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +392 -0
  384. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +217 -0
  385. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +235 -0
  386. package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter.js +69 -0
  387. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +32 -0
  388. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +291 -0
  389. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +175 -0
  390. package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +37 -0
  391. package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +127 -0
  392. package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +400 -0
  393. package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +285 -0
  394. package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +66 -0
  395. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +797 -0
  396. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +619 -0
  397. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +335 -0
  398. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +230 -0
  399. package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +363 -0
  400. package/.agents/scripts/lib/orchestration/error-journal.js +139 -0
  401. package/.agents/scripts/lib/orchestration/file-assumption-enum.js +31 -0
  402. package/.agents/scripts/lib/orchestration/file-assumptions.js +506 -0
  403. package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +116 -0
  404. package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +241 -0
  405. package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +489 -0
  406. package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +88 -0
  407. package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-reap.js +219 -0
  408. package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches.js +309 -0
  409. package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +99 -0
  410. package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +123 -0
  411. package/.agents/scripts/lib/orchestration/git-cleanup/phases/filters.js +57 -0
  412. package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes-ff.js +114 -0
  413. package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes.js +426 -0
  414. package/.agents/scripts/lib/orchestration/git-cleanup/phases/parse-args.js +84 -0
  415. package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +365 -0
  416. package/.agents/scripts/lib/orchestration/git-cleanup/phases/prompts.js +72 -0
  417. package/.agents/scripts/lib/orchestration/git-cleanup/phases/prune.js +69 -0
  418. package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +214 -0
  419. package/.agents/scripts/lib/orchestration/git-cleanup/phases/stashes.js +137 -0
  420. package/.agents/scripts/lib/orchestration/label-transitions.js +43 -0
  421. package/.agents/scripts/lib/orchestration/lifecycle/bus.js +309 -0
  422. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +147 -0
  423. package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +155 -0
  424. package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +226 -0
  425. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +69 -0
  426. package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +378 -0
  427. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +248 -0
  428. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +527 -0
  429. package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +259 -0
  430. package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +278 -0
  431. package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +355 -0
  432. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +647 -0
  433. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +331 -0
  434. package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +140 -0
  435. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +421 -0
  436. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +168 -0
  437. package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +668 -0
  438. package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +322 -0
  439. package/.agents/scripts/lib/orchestration/lint-baseline-service.js +114 -0
  440. package/.agents/scripts/lib/orchestration/manifest-builder.js +216 -0
  441. package/.agents/scripts/lib/orchestration/model-attribution.js +390 -0
  442. package/.agents/scripts/lib/orchestration/parked-follow-ons.js +147 -0
  443. package/.agents/scripts/lib/orchestration/phase-runner.js +87 -0
  444. package/.agents/scripts/lib/orchestration/plan-review-routing.js +63 -0
  445. package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +86 -0
  446. package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +212 -0
  447. package/.agents/scripts/lib/orchestration/planning-context-budget.js +213 -0
  448. package/.agents/scripts/lib/orchestration/planning-risk.js +155 -0
  449. package/.agents/scripts/lib/orchestration/planning-state-manager.js +318 -0
  450. package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +56 -0
  451. package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +33 -0
  452. package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +78 -0
  453. package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +68 -0
  454. package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +118 -0
  455. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +396 -0
  456. package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +205 -0
  457. package/.agents/scripts/lib/orchestration/pr-base-guard.js +47 -0
  458. package/.agents/scripts/lib/orchestration/preflight-cache.js +164 -0
  459. package/.agents/scripts/lib/orchestration/reassert-status-column.js +202 -0
  460. package/.agents/scripts/lib/orchestration/reconciler.js +137 -0
  461. package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +152 -0
  462. package/.agents/scripts/lib/orchestration/recut.js +56 -0
  463. package/.agents/scripts/lib/orchestration/resolves-token.js +127 -0
  464. package/.agents/scripts/lib/orchestration/retro/phases/checks.js +94 -0
  465. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +448 -0
  466. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +335 -0
  467. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +133 -0
  468. package/.agents/scripts/lib/orchestration/retro-heuristics.js +57 -0
  469. package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +275 -0
  470. package/.agents/scripts/lib/orchestration/retro-proposals.js +395 -0
  471. package/.agents/scripts/lib/orchestration/retro-runner.js +171 -0
  472. package/.agents/scripts/lib/orchestration/review-depth.js +93 -0
  473. package/.agents/scripts/lib/orchestration/review-providers/codex.js +363 -0
  474. package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +205 -0
  475. package/.agents/scripts/lib/orchestration/review-providers/native.js +805 -0
  476. package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +73 -0
  477. package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +396 -0
  478. package/.agents/scripts/lib/orchestration/review-providers/security-review.js +373 -0
  479. package/.agents/scripts/lib/orchestration/review-providers/types.js +89 -0
  480. package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +107 -0
  481. package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +159 -0
  482. package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +194 -0
  483. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +81 -0
  484. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +190 -0
  485. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +70 -0
  486. package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +106 -0
  487. package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +42 -0
  488. package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +73 -0
  489. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +225 -0
  490. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +315 -0
  491. package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +149 -0
  492. package/.agents/scripts/lib/orchestration/skill-capsule-loader.js +110 -0
  493. package/.agents/scripts/lib/orchestration/spec-freshness.js +320 -0
  494. package/.agents/scripts/lib/orchestration/spec-renderer.js +456 -0
  495. package/.agents/scripts/lib/orchestration/spec-section-validator.js +80 -0
  496. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +797 -0
  497. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +163 -0
  498. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +152 -0
  499. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +387 -0
  500. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +266 -0
  501. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +48 -0
  502. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +67 -0
  503. package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +161 -0
  504. package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +117 -0
  505. package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +86 -0
  506. package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +147 -0
  507. package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +142 -0
  508. package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +62 -0
  509. package/.agents/scripts/lib/orchestration/story-close/format-autofix-scoped.js +221 -0
  510. package/.agents/scripts/lib/orchestration/story-close/format-autofix-shared.js +123 -0
  511. package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +216 -0
  512. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +636 -0
  513. package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +198 -0
  514. package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +105 -0
  515. package/.agents/scripts/lib/orchestration/story-close/phases/close.js +222 -0
  516. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +220 -0
  517. package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +291 -0
  518. package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +234 -0
  519. package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +110 -0
  520. package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +86 -0
  521. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +112 -0
  522. package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +157 -0
  523. package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +434 -0
  524. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +290 -0
  525. package/.agents/scripts/lib/orchestration/story-close-recovery.js +643 -0
  526. package/.agents/scripts/lib/orchestration/structured-comment-parser.js +67 -0
  527. package/.agents/scripts/lib/orchestration/task-body-validator.js +391 -0
  528. package/.agents/scripts/lib/orchestration/ticket-lease.js +358 -0
  529. package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +783 -0
  530. package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +367 -0
  531. package/.agents/scripts/lib/orchestration/ticket-validator.js +691 -0
  532. package/.agents/scripts/lib/orchestration/ticketing/bulk.js +723 -0
  533. package/.agents/scripts/lib/orchestration/ticketing/reads.js +474 -0
  534. package/.agents/scripts/lib/orchestration/ticketing/state.js +559 -0
  535. package/.agents/scripts/lib/orchestration/ticketing.js +55 -0
  536. package/.agents/scripts/lib/orchestration/wave-marker.js +28 -0
  537. package/.agents/scripts/lib/orchestration/wave-record-io.js +277 -0
  538. package/.agents/scripts/lib/orchestration/wave-record-notifications.js +189 -0
  539. package/.agents/scripts/lib/orchestration/wave-record-projection.js +423 -0
  540. package/.agents/scripts/lib/path-security.js +25 -0
  541. package/.agents/scripts/lib/plan-phase-cleanup.js +125 -0
  542. package/.agents/scripts/lib/preflight-runner.js +196 -0
  543. package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +95 -0
  544. package/.agents/scripts/lib/presentation/manifest-builder.js +245 -0
  545. package/.agents/scripts/lib/presentation/manifest-formatter.js +243 -0
  546. package/.agents/scripts/lib/presentation/manifest-helpers.js +213 -0
  547. package/.agents/scripts/lib/presentation/manifest-persistence.js +262 -0
  548. package/.agents/scripts/lib/presentation/manifest-procedures.js +55 -0
  549. package/.agents/scripts/lib/presentation/manifest-render-waves.js +252 -0
  550. package/.agents/scripts/lib/presentation/manifest-renderer.js +188 -0
  551. package/.agents/scripts/lib/presentation/manifest-story-views.js +119 -0
  552. package/.agents/scripts/lib/provider-factory.js +80 -0
  553. package/.agents/scripts/lib/push-epic-retry.js +209 -0
  554. package/.agents/scripts/lib/qa/console-allowlist.js +151 -0
  555. package/.agents/scripts/lib/qa/coverage-report.js +181 -0
  556. package/.agents/scripts/lib/qa/coverage-verdict.js +296 -0
  557. package/.agents/scripts/lib/qa/propose-missing-test.js +95 -0
  558. package/.agents/scripts/lib/qa/qa-context-hydrator.js +296 -0
  559. package/.agents/scripts/lib/qa/qa-session.js +197 -0
  560. package/.agents/scripts/lib/qa/redact-evidence.js +245 -0
  561. package/.agents/scripts/lib/qa/resolve-qa-contract.js +190 -0
  562. package/.agents/scripts/lib/qa/resolve-selection.js +373 -0
  563. package/.agents/scripts/lib/runtime-deps/ensure-installed.js +100 -0
  564. package/.agents/scripts/lib/runtime-deps/manifest.js +96 -0
  565. package/.agents/scripts/lib/runtime-deps/preflight.js +78 -0
  566. package/.agents/scripts/lib/runtime-deps/scan-imports.js +202 -0
  567. package/.agents/scripts/lib/signals/detectors/common.js +36 -0
  568. package/.agents/scripts/lib/signals/detectors/hotspot.js +298 -0
  569. package/.agents/scripts/lib/signals/detectors/index.js +14 -0
  570. package/.agents/scripts/lib/signals/detectors/retry.js +289 -0
  571. package/.agents/scripts/lib/signals/detectors/rework.js +204 -0
  572. package/.agents/scripts/lib/signals/index.js +39 -0
  573. package/.agents/scripts/lib/signals/read.js +268 -0
  574. package/.agents/scripts/lib/signals/schema.js +225 -0
  575. package/.agents/scripts/lib/signals/span-tree.js +290 -0
  576. package/.agents/scripts/lib/signals/write.js +19 -0
  577. package/.agents/scripts/lib/single-story/confirm-merge.js +201 -0
  578. package/.agents/scripts/lib/single-story/story-merged-notify.js +126 -0
  579. package/.agents/scripts/lib/single-story-sweep/protection.js +274 -0
  580. package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +169 -0
  581. package/.agents/scripts/lib/single-story-sweep.js +329 -0
  582. package/.agents/scripts/lib/skills/parse-skill.js +202 -0
  583. package/.agents/scripts/lib/skills/walk-skill-files.js +56 -0
  584. package/.agents/scripts/lib/spec/index.js +36 -0
  585. package/.agents/scripts/lib/spec/loader.js +425 -0
  586. package/.agents/scripts/lib/spec/state.js +217 -0
  587. package/.agents/scripts/lib/story-body/story-body.js +743 -0
  588. package/.agents/scripts/lib/story-init/blocker-validator.js +68 -0
  589. package/.agents/scripts/lib/story-init/branch-initializer.js +422 -0
  590. package/.agents/scripts/lib/story-init/context-resolver.js +92 -0
  591. package/.agents/scripts/lib/story-init/donor-precheck.js +207 -0
  592. package/.agents/scripts/lib/story-init/hierarchy-tracer.js +36 -0
  593. package/.agents/scripts/lib/story-init/state-transitioner.js +80 -0
  594. package/.agents/scripts/lib/story-init/task-graph-builder.js +114 -0
  595. package/.agents/scripts/lib/story-init/transition-summary.js +34 -0
  596. package/.agents/scripts/lib/story-lifecycle.js +186 -0
  597. package/.agents/scripts/lib/story-plan.js +246 -0
  598. package/.agents/scripts/lib/task-utils.js +26 -0
  599. package/.agents/scripts/lib/templates/decomposer-prompts.js +168 -0
  600. package/.agents/scripts/lib/test-env.js +30 -0
  601. package/.agents/scripts/lib/test-isolate/env-snapshot-loader.js +52 -0
  602. package/.agents/scripts/lib/test-isolate/list-files.js +90 -0
  603. package/.agents/scripts/lib/test-isolate/parse-tap.js +75 -0
  604. package/.agents/scripts/lib/test-isolate/runner.js +483 -0
  605. package/.agents/scripts/lib/test-profile/parse-tap.js +136 -0
  606. package/.agents/scripts/lib/test-profile/render-report.js +45 -0
  607. package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +35 -0
  608. package/.agents/scripts/lib/test-tiers.js +94 -0
  609. package/.agents/scripts/lib/util/concurrent-map.js +59 -0
  610. package/.agents/scripts/lib/util/phase-timer-state.js +72 -0
  611. package/.agents/scripts/lib/util/phase-timer.js +163 -0
  612. package/.agents/scripts/lib/util/poll-loop.js +86 -0
  613. package/.agents/scripts/lib/util/with-timeout.js +32 -0
  614. package/.agents/scripts/lib/validation-evidence.js +323 -0
  615. package/.agents/scripts/lib/wave-runner/tick.js +665 -0
  616. package/.agents/scripts/lib/wave-runner/wave-checkpoint.js +91 -0
  617. package/.agents/scripts/lib/wave-runner/wave-runner-error.js +19 -0
  618. package/.agents/scripts/lib/workers/crap-worker.js +197 -0
  619. package/.agents/scripts/lib/workers/maintainability-report-worker.js +137 -0
  620. package/.agents/scripts/lib/workers/maintainability-worker.js +79 -0
  621. package/.agents/scripts/lib/workspace-provisioner.js +189 -0
  622. package/.agents/scripts/lib/worktree/bootstrapper.js +48 -0
  623. package/.agents/scripts/lib/worktree/inspector.js +140 -0
  624. package/.agents/scripts/lib/worktree/lifecycle/creation.js +118 -0
  625. package/.agents/scripts/lib/worktree/lifecycle/drift-detection.js +62 -0
  626. package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +276 -0
  627. package/.agents/scripts/lib/worktree/lifecycle/gc.js +49 -0
  628. package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +178 -0
  629. package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +264 -0
  630. package/.agents/scripts/lib/worktree/lifecycle/precheck.js +100 -0
  631. package/.agents/scripts/lib/worktree/lifecycle/reap.js +588 -0
  632. package/.agents/scripts/lib/worktree/lifecycle/registry-sync.js +124 -0
  633. package/.agents/scripts/lib/worktree/lifecycle/shared.js +26 -0
  634. package/.agents/scripts/lib/worktree/lifecycle-manager.js +40 -0
  635. package/.agents/scripts/lib/worktree/node-modules-strategy.js +349 -0
  636. package/.agents/scripts/lib/worktree-manager.js +243 -0
  637. package/.agents/scripts/lifecycle-diff.js +206 -0
  638. package/.agents/scripts/lifecycle-emit-story-dispatch.js +194 -0
  639. package/.agents/scripts/lifecycle-emit.js +479 -0
  640. package/.agents/scripts/lint-baseline.js +507 -0
  641. package/.agents/scripts/lint-label-vocabulary.js +237 -0
  642. package/.agents/scripts/loc-delta.js +205 -0
  643. package/.agents/scripts/notify.js +307 -0
  644. package/.agents/scripts/package.json +3 -0
  645. package/.agents/scripts/post-structured-comment.js +127 -0
  646. package/.agents/scripts/pr-watch-with-update.js +152 -0
  647. package/.agents/scripts/providers/github/auth.js +65 -0
  648. package/.agents/scripts/providers/github/board-add.js +63 -0
  649. package/.agents/scripts/providers/github/branch-protection.js +186 -0
  650. package/.agents/scripts/providers/github/cache.js +72 -0
  651. package/.agents/scripts/providers/github/comments.js +131 -0
  652. package/.agents/scripts/providers/github/compose.js +111 -0
  653. package/.agents/scripts/providers/github/errors.js +242 -0
  654. package/.agents/scripts/providers/github/issues.js +242 -0
  655. package/.agents/scripts/providers/github/labels.js +179 -0
  656. package/.agents/scripts/providers/github/mappers.js +126 -0
  657. package/.agents/scripts/providers/github/merge-methods.js +82 -0
  658. package/.agents/scripts/providers/github/project-board.js +47 -0
  659. package/.agents/scripts/providers/github/projects-v2-graphql.js +472 -0
  660. package/.agents/scripts/providers/github/prs.js +103 -0
  661. package/.agents/scripts/providers/github/request-helpers.js +110 -0
  662. package/.agents/scripts/providers/github/sub-issues.js +369 -0
  663. package/.agents/scripts/providers/github/tickets.js +381 -0
  664. package/.agents/scripts/providers/github/transient-retry.js +62 -0
  665. package/.agents/scripts/providers/github.js +157 -0
  666. package/.agents/scripts/quality-preview.js +327 -0
  667. package/.agents/scripts/quality-watch.js +223 -0
  668. package/.agents/scripts/render-manifest.js +143 -0
  669. package/.agents/scripts/resync-status-column.js +176 -0
  670. package/.agents/scripts/retro-run.js +167 -0
  671. package/.agents/scripts/run-audit-suite.js +97 -0
  672. package/.agents/scripts/run-coverage.js +103 -0
  673. package/.agents/scripts/run-lint.js +94 -0
  674. package/.agents/scripts/run-test-profile.js +126 -0
  675. package/.agents/scripts/run-tests.js +185 -0
  676. package/.agents/scripts/run-verify.js +56 -0
  677. package/.agents/scripts/select-audits.js +155 -0
  678. package/.agents/scripts/signals-view.js +294 -0
  679. package/.agents/scripts/single-story-close.js +83 -0
  680. package/.agents/scripts/single-story-confirm-merge.js +183 -0
  681. package/.agents/scripts/single-story-init.js +692 -0
  682. package/.agents/scripts/stories-wave-tick.js +415 -0
  683. package/.agents/scripts/story-close.js +246 -0
  684. package/.agents/scripts/story-deliver-prepare.js +267 -0
  685. package/.agents/scripts/story-init.js +516 -0
  686. package/.agents/scripts/story-phase.js +327 -0
  687. package/.agents/scripts/story-plan.js +284 -0
  688. package/.agents/scripts/sync-agentrc.js +71 -0
  689. package/.agents/scripts/sync-branch-from-base.js +138 -0
  690. package/.agents/scripts/sync-claude-commands.js +151 -0
  691. package/.agents/scripts/test-isolate.js +222 -0
  692. package/.agents/scripts/test-wrapper.js +108 -0
  693. package/.agents/scripts/update-coverage-baseline.js +129 -0
  694. package/.agents/scripts/update-crap-baseline.js +177 -0
  695. package/.agents/scripts/update-duplication-baseline.js +134 -0
  696. package/.agents/scripts/update-maintainability-baseline.js +183 -0
  697. package/.agents/scripts/update-mutation-baseline.js +189 -0
  698. package/.agents/scripts/update-ticket-state.js +107 -0
  699. package/.agents/scripts/validate-docs-freshness.js +259 -0
  700. package/.agents/scripts/validate-skills.js +278 -0
  701. package/.agents/scripts/wave-tick.js +335 -0
  702. package/.agents/skills/core/analyze-execution/SKILL.md +98 -0
  703. package/.agents/skills/core/api-and-interface-design/SKILL.md +327 -0
  704. package/.agents/skills/core/baseline-refresh/SKILL.md +181 -0
  705. package/.agents/skills/core/browser-testing-with-devtools/SKILL.md +352 -0
  706. package/.agents/skills/core/ci-cd-and-automation/SKILL.md +274 -0
  707. package/.agents/skills/core/ci-cd-and-automation/examples.md +211 -0
  708. package/.agents/skills/core/code-review-and-quality/SKILL.md +421 -0
  709. package/.agents/skills/core/code-simplification/SKILL.md +389 -0
  710. package/.agents/skills/core/context-engineering/SKILL.md +309 -0
  711. package/.agents/skills/core/context-engineering/examples.md +58 -0
  712. package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +338 -0
  713. package/.agents/skills/core/deprecation-and-migration/SKILL.md +250 -0
  714. package/.agents/skills/core/diagnose-friction/SKILL.md +79 -0
  715. package/.agents/skills/core/documentation-and-adrs/SKILL.md +323 -0
  716. package/.agents/skills/core/epic-plan-consolidate/SKILL.md +145 -0
  717. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +425 -0
  718. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +393 -0
  719. package/.agents/skills/core/frontend-ui-engineering/SKILL.md +357 -0
  720. package/.agents/skills/core/git-workflow-and-versioning/SKILL.md +352 -0
  721. package/.agents/skills/core/hydrate-context/SKILL.md +118 -0
  722. package/.agents/skills/core/idea-refinement/SKILL.md +317 -0
  723. package/.agents/skills/core/idea-refinement/examples.md +437 -0
  724. package/.agents/skills/core/idea-refinement/frameworks.md +135 -0
  725. package/.agents/skills/core/idea-refinement/refinement-criteria.md +155 -0
  726. package/.agents/skills/core/idea-refinement/scripts/idea-refine.sh +15 -0
  727. package/.agents/skills/core/incremental-implementation/SKILL.md +271 -0
  728. package/.agents/skills/core/introducing-a-baseline-gate/SKILL.md +213 -0
  729. package/.agents/skills/core/knowledge-transfer/SKILL.md +175 -0
  730. package/.agents/skills/core/mutation-survivor-remediation/SKILL.md +117 -0
  731. package/.agents/skills/core/performance-optimization/SKILL.md +314 -0
  732. package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +277 -0
  733. package/.agents/skills/core/property-based-testing/SKILL.md +148 -0
  734. package/.agents/skills/core/qa-coverage-mapping/SKILL.md +105 -0
  735. package/.agents/skills/core/refactoring-discipline/SKILL.md +111 -0
  736. package/.agents/skills/core/scope-triage/SKILL.md +127 -0
  737. package/.agents/skills/core/security-and-hardening/SKILL.md +400 -0
  738. package/.agents/skills/core/shipping-and-launch/SKILL.md +328 -0
  739. package/.agents/skills/core/spec-driven-development/SKILL.md +252 -0
  740. package/.agents/skills/core/test-driven-development/SKILL.md +475 -0
  741. package/.agents/skills/core/using-agent-skills/SKILL.md +232 -0
  742. package/.agents/skills/skills.index.json +596 -0
  743. package/.agents/skills/stack/architecture/monorepo-path-strategist/SKILL.md +31 -0
  744. package/.agents/skills/stack/architecture/structured-output-zod/SKILL.md +51 -0
  745. package/.agents/skills/stack/architecture/subagent-orchestration/SKILL.md +48 -0
  746. package/.agents/skills/stack/backend/cloudflare-hono-architect/SKILL.md +31 -0
  747. package/.agents/skills/stack/backend/cloudflare-hono-architect/examples/route-template.ts +33 -0
  748. package/.agents/skills/stack/backend/cloudflare-queue-manager/SKILL.md +31 -0
  749. package/.agents/skills/stack/backend/cloudflare-workers/SKILL.md +51 -0
  750. package/.agents/skills/stack/backend/highlevel-crm/SKILL.md +54 -0
  751. package/.agents/skills/stack/backend/sqlite-drizzle-expert/SKILL.md +29 -0
  752. package/.agents/skills/stack/backend/sqlite-drizzle-expert/examples/schema-template.ts +30 -0
  753. package/.agents/skills/stack/backend/stripe-integration/SKILL.md +57 -0
  754. package/.agents/skills/stack/backend/stripe-integration/scripts/listen-stripe.sh +9 -0
  755. package/.agents/skills/stack/backend/turso-sqlite/SKILL.md +48 -0
  756. package/.agents/skills/stack/frontend/astro/SKILL.md +62 -0
  757. package/.agents/skills/stack/frontend/astro-react-island-strategist/SKILL.md +30 -0
  758. package/.agents/skills/stack/frontend/expo-react-native-developer/SKILL.md +29 -0
  759. package/.agents/skills/stack/frontend/google-analytics-v4/SKILL.md +50 -0
  760. package/.agents/skills/stack/frontend/tailwind-v4/SKILL.md +58 -0
  761. package/.agents/skills/stack/frontend/ui-accessibility-engineer/SKILL.md +34 -0
  762. package/.agents/skills/stack/qa/audit-accessibility/SKILL.md +51 -0
  763. package/.agents/skills/stack/qa/gherkin-authoring/SKILL.md +257 -0
  764. package/.agents/skills/stack/qa/gherkin-authoring/examples/invoice-issue.feature +41 -0
  765. package/.agents/skills/stack/qa/lighthouse-baseline/SKILL.md +199 -0
  766. package/.agents/skills/stack/qa/playwright/SKILL.md +50 -0
  767. package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +188 -0
  768. package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +142 -0
  769. package/.agents/skills/stack/qa/qa-harness/SKILL.md +220 -0
  770. package/.agents/skills/stack/qa/vitest/SKILL.md +51 -0
  771. package/.agents/skills/stack/security/backend-security-patterns/SKILL.md +68 -0
  772. package/.agents/starter-agentrc.json +22 -0
  773. package/.agents/templates/agent-protocol.md +72 -0
  774. package/.agents/templates/docs/architecture.md +30 -0
  775. package/.agents/templates/docs/decisions.md +24 -0
  776. package/.agents/templates/epic-from-idea.md +21 -0
  777. package/.agents/templates/single-story-body.md +17 -0
  778. package/.agents/workflows/agents-update.md +415 -0
  779. package/.agents/workflows/audit-architecture.md +312 -0
  780. package/.agents/workflows/audit-clean-code.md +179 -0
  781. package/.agents/workflows/audit-dependencies.md +91 -0
  782. package/.agents/workflows/audit-devops.md +110 -0
  783. package/.agents/workflows/audit-lighthouse.md +260 -0
  784. package/.agents/workflows/audit-performance.md +161 -0
  785. package/.agents/workflows/audit-privacy.md +104 -0
  786. package/.agents/workflows/audit-quality.md +191 -0
  787. package/.agents/workflows/audit-security.md +156 -0
  788. package/.agents/workflows/audit-seo.md +118 -0
  789. package/.agents/workflows/audit-sre.md +139 -0
  790. package/.agents/workflows/audit-to-stories.md +257 -0
  791. package/.agents/workflows/audit-ux-ui.md +102 -0
  792. package/.agents/workflows/epic-deliver.md +864 -0
  793. package/.agents/workflows/epic-plan.md +998 -0
  794. package/.agents/workflows/explain.md +118 -0
  795. package/.agents/workflows/git-cleanup.md +250 -0
  796. package/.agents/workflows/git-commit-all.md +15 -0
  797. package/.agents/workflows/git-merge-pr.md +377 -0
  798. package/.agents/workflows/git-pr-all.md +278 -0
  799. package/.agents/workflows/git-push.md +60 -0
  800. package/.agents/workflows/helpers/_merge-conflict-template.md +54 -0
  801. package/.agents/workflows/helpers/acceptance-self-eval.md +74 -0
  802. package/.agents/workflows/helpers/agents-sync-config.md +129 -0
  803. package/.agents/workflows/helpers/code-quality-guardrails.md +101 -0
  804. package/.agents/workflows/helpers/code-review.md +370 -0
  805. package/.agents/workflows/helpers/diagnose.md +117 -0
  806. package/.agents/workflows/helpers/epic-audit.md +295 -0
  807. package/.agents/workflows/helpers/epic-deliver-story.md +370 -0
  808. package/.agents/workflows/helpers/epic-plan-decompose.md +199 -0
  809. package/.agents/workflows/helpers/epic-plan-spec.md +184 -0
  810. package/.agents/workflows/helpers/epic-testing.md +125 -0
  811. package/.agents/workflows/helpers/parallel-tooling.md +88 -0
  812. package/.agents/workflows/helpers/signals.md +112 -0
  813. package/.agents/workflows/helpers/single-story-deliver.md +636 -0
  814. package/.agents/workflows/helpers/worktree-lifecycle.md +317 -0
  815. package/.agents/workflows/onboard.md +207 -0
  816. package/.agents/workflows/qa-assist.md +293 -0
  817. package/.agents/workflows/qa-explore.md +350 -0
  818. package/.agents/workflows/qa-run-harness.md +288 -0
  819. package/.agents/workflows/story-deliver.md +327 -0
  820. package/.agents/workflows/story-plan.md +233 -0
  821. package/LICENSE +21 -0
  822. package/README.md +193 -0
  823. package/bin/mandrel.js +56 -0
  824. package/bin/postinstall.js +195 -0
  825. package/lib/cli/__tests__/migrate.test.js +268 -0
  826. package/lib/cli/__tests__/sync-local-zone.test.js +247 -0
  827. package/lib/cli/__tests__/sync.test.js +372 -0
  828. package/lib/cli/__tests__/update-major.test.js +217 -0
  829. package/lib/cli/__tests__/update.test.js +696 -0
  830. package/lib/cli/__tests__/version-check.test.js +398 -0
  831. package/lib/cli/doctor.js +124 -0
  832. package/lib/cli/explain.js +107 -0
  833. package/lib/cli/migrate.js +260 -0
  834. package/lib/cli/registry.js +830 -0
  835. package/lib/cli/sync-commands.js +50 -0
  836. package/lib/cli/sync.js +200 -0
  837. package/lib/cli/uninstall.js +795 -0
  838. package/lib/cli/update.js +854 -0
  839. package/lib/cli/version-check.js +206 -0
  840. package/lib/migrations/README.md +69 -0
  841. package/lib/migrations/__tests__/index.test.js +216 -0
  842. package/lib/migrations/index.js +164 -0
  843. package/package.json +105 -0
@@ -0,0 +1,801 @@
1
+ /**
2
+ * bootstrap/project-bootstrap — deterministic port of the
3
+ * `/agents-bootstrap-project` workflow (Story #2074, hard cutover).
4
+ *
5
+ * Each exported `ensure*` function is one step of the bootstrap. Every step
6
+ * is idempotent and additive — re-running on an already-bootstrapped clone
7
+ * produces zero file mutations and zero network I/O.
8
+ *
9
+ * Injectable seams: every function that performs filesystem I/O or spawns a
10
+ * child process accepts an optional `fsImpl` / `spawnImpl` default-param so
11
+ * unit tests can stub I/O without touching the real filesystem. The seam
12
+ * contract is defined in `.agents/rules/test-seams.md`.
13
+ */
14
+
15
+ import { spawnSync as defaultSpawnSync } from 'node:child_process';
16
+ import fs from 'node:fs';
17
+ import os from 'node:os';
18
+ import path from 'node:path';
19
+ import { LEDGER_RELATIVE_PATH } from './install-ledger.js';
20
+ import { PHASE_GROUPS, previewMutationManifest } from './manifest.js';
21
+ import { applyQualityBootstrap } from './quality-bootstrap.js';
22
+
23
+ export const SYNC_COMMAND = 'node .agents/scripts/sync-claude-commands.js';
24
+
25
+ export const BOOTSTRAP_COMMAND = 'node .agents/scripts/bootstrap.js';
26
+
27
+ /**
28
+ * Marker that identifies the framework's system-prompt import inside a
29
+ * consumer `CLAUDE.md`. The wiring step keys idempotence off this exact
30
+ * import path so a re-run never duplicates the import line.
31
+ */
32
+ export const SYSTEM_PROMPT_IMPORT = '@.agents/instructions.md';
33
+
34
+ /**
35
+ * Import block appended to an existing `CLAUDE.md` that lacks the import.
36
+ * Mirrors the root `CLAUDE.md` shape (a `## System Prompt` heading above
37
+ * the import) so the consumer file reads the same as this repo's own.
38
+ */
39
+ export const SYSTEM_PROMPT_BLOCK = `## System Prompt
40
+
41
+ ${SYSTEM_PROMPT_IMPORT}
42
+ `;
43
+
44
+ /**
45
+ * Full `CLAUDE.md` body written when the consumer has no `CLAUDE.md` at
46
+ * all. A bare title plus the import block is enough for Claude Code to
47
+ * hydrate the framework system prompt on cold start.
48
+ */
49
+ export const SYSTEM_PROMPT_CLAUDE_MD = `# Agent Protocols
50
+
51
+ ${SYSTEM_PROMPT_BLOCK}`;
52
+
53
+ export const GITIGNORE_BLOCKS = Object.freeze({
54
+ commands: {
55
+ pattern: /^\s*\.claude\/commands\/?\s*$/m,
56
+ block:
57
+ '\n# Claude Code command projection is generated from .agents/workflows/ — do not commit.\n.claude/commands/\n',
58
+ },
59
+ mcp: {
60
+ pattern: /^\s*\.mcp\.json\s*$/m,
61
+ block:
62
+ '\n# Project-scoped MCP config carries secrets — keep out of git.\n.mcp.json\n',
63
+ },
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
66
+ // provision never stages/pushes it. The pattern matches a bare `.env` (with
67
+ // an optional trailing slash) but deliberately NOT `.env.example`, the
68
+ // committed placeholder that `security-baseline.md` § Secrets Management
69
+ // exempts.
70
+ env: {
71
+ pattern: /^\s*\.env\/?\s*$/m,
72
+ block:
73
+ '\n# Secrets live in .env (e.g. GITHUB_TOKEN) — never commit it. Only .env.example (placeholders) is checked in.\n.env\n',
74
+ },
75
+ // Story #3894: the install ledger is a per-clone install record, not a
76
+ // checked-in source artifact. `install-ledger.js` documents that the
77
+ // bootstrap `.gitignore` step ignores it — key the entry off the exact
78
+ // `LEDGER_RELATIVE_PATH` constant so the doc and code never drift again.
79
+ installLedger: {
80
+ pattern: new RegExp(
81
+ `^\\s*${LEDGER_RELATIVE_PATH.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*$`,
82
+ 'm',
83
+ ),
84
+ block: `\n# Per-clone install record written by bootstrap — not a source artifact.\n${LEDGER_RELATIVE_PATH}\n`,
85
+ },
86
+ });
87
+
88
+ /**
89
+ * Read a JSON file if it exists; return null when missing. Accepts an
90
+ * injectable `fsImpl` so callers can stub filesystem access in tests.
91
+ *
92
+ * @param {string} p
93
+ * @param {typeof fs} [fsImpl]
94
+ * @returns {object|null}
95
+ */
96
+ function readJsonIfExists(p, fsImpl = fs) {
97
+ if (!fsImpl.existsSync(p)) return null;
98
+ return JSON.parse(fsImpl.readFileSync(p, 'utf8'));
99
+ }
100
+
101
+ /**
102
+ * Write a pretty-printed JSON file, creating parent directories as needed.
103
+ * Accepts an injectable `fsImpl` so callers can stub filesystem access in
104
+ * tests.
105
+ *
106
+ * @param {string} p
107
+ * @param {object} obj
108
+ * @param {typeof fs} [fsImpl]
109
+ */
110
+ function writeJson(p, obj, fsImpl = fs) {
111
+ fsImpl.mkdirSync(path.dirname(p), { recursive: true });
112
+ fsImpl.writeFileSync(p, `${JSON.stringify(obj, null, 2)}\n`, 'utf8');
113
+ }
114
+
115
+ /** Matches root `package.json` `engines.node`. */
116
+ export const REQUIRED_NODE_FLOOR = '22.22.1';
117
+ export const REQUIRED_NODE_CEILING_MAJOR = 25;
118
+
119
+ /**
120
+ * Return true when `version` satisfies `>=22.22.1 <25` (same as `engines`).
121
+ *
122
+ * @param {string} version
123
+ * @returns {boolean}
124
+ */
125
+ export function satisfiesNodeEngine(version) {
126
+ const [majorRaw, minorRaw, patchRaw] = version.split('.');
127
+ const major = Number.parseInt(majorRaw, 10) || 0;
128
+ const minor = Number.parseInt(minorRaw, 10) || 0;
129
+ const patch = Number.parseInt(patchRaw, 10) || 0;
130
+ if (major >= REQUIRED_NODE_CEILING_MAJOR) return false;
131
+ if (major > 22) return true;
132
+ if (major < 22) return false;
133
+ if (minor > 22) return true;
134
+ if (minor < 22) return false;
135
+ return patch >= 1;
136
+ }
137
+
138
+ /**
139
+ * Step 1 — Verify Node satisfies `engines.node`. Returns `{ ok, version,
140
+ * required }` so the CLI can report the detected version regardless of
141
+ * whether the check passed.
142
+ *
143
+ * @param {string} [version=process.versions.node]
144
+ */
145
+ export function checkNodeVersion(version = process.versions.node) {
146
+ return {
147
+ ok: satisfiesNodeEngine(version),
148
+ version,
149
+ required: REQUIRED_NODE_FLOOR,
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Detect the package manager based on lockfile presence. Defaults to
155
+ * `npm` when no lock is found.
156
+ *
157
+ * @param {string} projectRoot
158
+ * @param {typeof fs} [fsImpl]
159
+ */
160
+ 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';
165
+ }
166
+
167
+ /**
168
+ * Step 2a/2b/2c — Ensure `package.json` exists and carries the
169
+ * `sync:commands` + `prepare` + `bootstrap` scripts. The consumer manifest
170
+ * is never mutated with framework runtime dependencies: those arrive
171
+ * transitively via the `mandrel` package, so bootstrap leaves the
172
+ * `dependencies` block untouched (Story #3466). Returns the per-key outcome
173
+ * the caller can render.
174
+ *
175
+ * @param {object} ctx
176
+ * @param {typeof fs} [ctx.fsImpl]
177
+ */
178
+ export function ensurePackageJson(ctx) {
179
+ const { fsImpl = fs } = ctx;
180
+ const pkgPath = path.join(ctx.projectRoot, 'package.json');
181
+ const projectName = path.basename(path.resolve(ctx.projectRoot));
182
+ const outcomes = {
183
+ created: false,
184
+ scriptsSyncCommands: 'already-present',
185
+ scriptsPrepare: 'already-present',
186
+ scriptsBootstrap: 'already-present',
187
+ };
188
+ let pkg = readJsonIfExists(pkgPath, fsImpl);
189
+ if (!pkg) {
190
+ pkg = {
191
+ name: projectName,
192
+ version: '0.0.0',
193
+ private: true,
194
+ type: 'module',
195
+ };
196
+ outcomes.created = true;
197
+ }
198
+ pkg.scripts = pkg.scripts ?? {};
199
+ if (!pkg.scripts['sync:commands']) {
200
+ pkg.scripts['sync:commands'] = SYNC_COMMAND;
201
+ outcomes.scriptsSyncCommands = 'added';
202
+ }
203
+ const prepare = pkg.scripts.prepare;
204
+ if (!prepare) {
205
+ pkg.scripts.prepare = SYNC_COMMAND;
206
+ outcomes.scriptsPrepare = 'added';
207
+ } else if (!prepare.includes('sync-claude-commands.js')) {
208
+ pkg.scripts.prepare = `${prepare} && ${SYNC_COMMAND}`;
209
+ outcomes.scriptsPrepare = 'appended';
210
+ }
211
+ // Expose a discoverable `npm run bootstrap` alias for the framework
212
+ // setup command. An operator-defined `bootstrap` script always wins —
213
+ // we only seed the default when the key is absent.
214
+ if (!pkg.scripts.bootstrap) {
215
+ pkg.scripts.bootstrap = BOOTSTRAP_COMMAND;
216
+ outcomes.scriptsBootstrap = 'added';
217
+ }
218
+ const mutated =
219
+ outcomes.created ||
220
+ outcomes.scriptsSyncCommands === 'added' ||
221
+ outcomes.scriptsPrepare !== 'already-present' ||
222
+ outcomes.scriptsBootstrap === 'added';
223
+ if (mutated) writeJson(pkgPath, pkg, fsImpl);
224
+ return { ...outcomes, path: pkgPath, mutated };
225
+ }
226
+
227
+ /**
228
+ * Step 2d — Install dependencies when the framework's sentinel module is
229
+ * unresolvable. Bootstrap no longer seeds framework deps into the consumer
230
+ * manifest (Story #3466) — they arrive transitively via `mandrel`
231
+ * — so the install is triggered purely by an empty/stale `node_modules`.
232
+ * Returns `{ ran, manager, skipped, reason }`.
233
+ *
234
+ * @param {object} ctx
235
+ * @param {typeof fs} [ctx.fsImpl]
236
+ * @param {typeof defaultSpawnSync} [ctx.spawnImpl]
237
+ */
238
+ export function ensureDependenciesInstalled(ctx) {
239
+ const { fsImpl = fs, spawnImpl = defaultSpawnSync } = ctx;
240
+ const manager = detectPackageManager(ctx.projectRoot, fsImpl);
241
+ const sentinel = path.join(
242
+ ctx.projectRoot,
243
+ 'node_modules',
244
+ 'ajv',
245
+ 'package.json',
246
+ );
247
+ const needsInstall = !fsImpl.existsSync(sentinel);
248
+ if (!needsInstall) {
249
+ return { ran: false, manager, skipped: true, reason: 'already-installed' };
250
+ }
251
+ if (ctx.skipInstall) {
252
+ return { ran: false, manager, skipped: true, reason: 'skip-install-flag' };
253
+ }
254
+ const result = spawnImpl(manager, ['install'], {
255
+ cwd: ctx.projectRoot,
256
+ stdio: ctx.quiet ? 'ignore' : 'inherit',
257
+ shell: process.platform === 'win32',
258
+ });
259
+ if (result.status !== 0) {
260
+ throw new Error(
261
+ `[bootstrap] ${manager} install failed (exit ${result.status}). Resolve the install error and re-run.`,
262
+ );
263
+ }
264
+ return { ran: true, manager, skipped: false };
265
+ }
266
+
267
+ /**
268
+ * Step 2.5a — Seed `.agentrc.json` when missing.
269
+ *
270
+ * Seeds from the bundled `starter-agentrc.json` reference, applying the
271
+ * operator-identity placeholder substitution (`[OWNER]` / `[REPO]` /
272
+ * `[USERNAME]`) and the `baseBranch` override. (Story #3690 removed the
273
+ * named config-profile seeding path — the starter reference is the single
274
+ * seed source.)
275
+ *
276
+ * An existing `.agentrc.json` is never overwritten — operator wins.
277
+ *
278
+ * @param {object} ctx
279
+ * @param {typeof fs} [ctx.fsImpl]
280
+ * @returns {{ action: string, path: string, source?: string }}
281
+ */
282
+ export function ensureAgentrc(ctx) {
283
+ const { fsImpl = fs } = ctx;
284
+ const target = path.join(ctx.projectRoot, '.agentrc.json');
285
+ if (fsImpl.existsSync(target)) {
286
+ return { action: 'already-present', path: target };
287
+ }
288
+ const starter = path.join(
289
+ ctx.agentRoot ?? path.join(ctx.projectRoot, '.agents'),
290
+ 'starter-agentrc.json',
291
+ );
292
+ if (!fsImpl.existsSync(starter)) {
293
+ return { action: 'missing-starter', path: target };
294
+ }
295
+ let body = fsImpl.readFileSync(starter, 'utf8');
296
+ body = body
297
+ .replace(/\[OWNER\]/g, ctx.answers.owner)
298
+ .replace(/\[REPO\]/g, ctx.answers.repo)
299
+ .replace(/\[USERNAME\]/g, ctx.answers.operatorHandle ?? ctx.answers.owner);
300
+ // The starter pins baseBranch to "main"; if the operator chose a
301
+ // different default, update the seeded copy so the per-clone config
302
+ // matches the live remote HEAD.
303
+ if (ctx.answers.baseBranch && ctx.answers.baseBranch !== 'main') {
304
+ body = body.replace(
305
+ /"baseBranch":\s*"main"/,
306
+ `"baseBranch": "${ctx.answers.baseBranch}"`,
307
+ );
308
+ }
309
+ fsImpl.writeFileSync(target, body, 'utf8');
310
+ return { action: 'seeded', path: target, source: 'starter' };
311
+ }
312
+
313
+ /**
314
+ * Step 2.5b — Validate `.agentrc.json` against the framework's AJV schema.
315
+ * Returns `{ ok, errors }`. Caller decides whether to abort.
316
+ *
317
+ * @param {object} ctx
318
+ * @param {typeof fs} [ctx.fsImpl]
319
+ */
320
+ export async function validateAgentrc(ctx) {
321
+ const { fsImpl = fs } = ctx;
322
+ const schemaModule = path.join(
323
+ ctx.agentRoot ?? path.join(ctx.projectRoot, '.agents'),
324
+ 'scripts',
325
+ 'lib',
326
+ 'config-settings-schema.js',
327
+ );
328
+ if (!fsImpl.existsSync(schemaModule)) {
329
+ return { ok: false, errors: ['config-settings-schema.js not found'] };
330
+ }
331
+ const mod = await import(`file://${schemaModule.replace(/\\/g, '/')}`);
332
+ const validate = mod.getAgentrcValidator();
333
+ const data = readJsonIfExists(
334
+ path.join(ctx.projectRoot, '.agentrc.json'),
335
+ fsImpl,
336
+ );
337
+ if (!data) return { ok: false, errors: ['.agentrc.json missing'] };
338
+ const ok = validate(data);
339
+ return { ok: !!ok, errors: ok ? [] : (validate.errors ?? []) };
340
+ }
341
+
342
+ /**
343
+ * Step 3 — Merge the `UserPromptSubmit` sync hook into `.claude/settings.json`.
344
+ * Returns `{ action }`.
345
+ *
346
+ * The sync hook keeps the generated flat `/<name>` command tree
347
+ * (`.claude/commands/`) current. The flat projection needs no plugin
348
+ * enablement keys — it loads in every Claude Code environment, including those
349
+ * where the plugin system (`/plugin`) is unavailable (the #3576 plugin cutover
350
+ * was reverted for exactly that reason).
351
+ *
352
+ * @param {object} ctx
353
+ * @param {typeof fs} [ctx.fsImpl]
354
+ */
355
+ export function ensureClaudeSettings(ctx) {
356
+ const { fsImpl = fs } = ctx;
357
+ const target = path.join(ctx.projectRoot, '.claude', 'settings.json');
358
+ const hook = { type: 'command', command: SYNC_COMMAND };
359
+ if (!fsImpl.existsSync(target)) {
360
+ fsImpl.mkdirSync(path.dirname(target), { recursive: true });
361
+ const fresh = {
362
+ hooks: {
363
+ UserPromptSubmit: [{ hooks: [hook] }],
364
+ },
365
+ };
366
+ writeJson(target, fresh, fsImpl);
367
+ return { action: 'created', path: target };
368
+ }
369
+ const settings = readJsonIfExists(target, fsImpl);
370
+ settings.hooks = settings.hooks ?? {};
371
+ settings.hooks.UserPromptSubmit = settings.hooks.UserPromptSubmit ?? [];
372
+ const hookAlready = settings.hooks.UserPromptSubmit.some((group) =>
373
+ (group?.hooks ?? []).some(
374
+ (h) =>
375
+ typeof h?.command === 'string' &&
376
+ h.command.includes('sync-claude-commands.js'),
377
+ ),
378
+ );
379
+ let mutated = false;
380
+ if (!hookAlready) {
381
+ settings.hooks.UserPromptSubmit.push({ hooks: [hook] });
382
+ mutated = true;
383
+ }
384
+ if (!mutated) return { action: 'already-present', path: target };
385
+ writeJson(target, settings, fsImpl);
386
+ return { action: 'merged', path: target };
387
+ }
388
+
389
+ /**
390
+ * Step 4 + Step 8 — Ensure `.gitignore` carries every {@link GITIGNORE_BLOCKS}
391
+ * entry (`.claude/commands/`, `.mcp.json`, `.env`, and the per-clone install
392
+ * ledger). Each block is marker-keyed off a presence pattern, so a re-run is a
393
+ * zero-mutation no-op and never appends a duplicate block. Returns a per-block
394
+ * outcome (`added` | `already-present`).
395
+ *
396
+ * @param {object} ctx
397
+ * @param {typeof fs} [ctx.fsImpl]
398
+ */
399
+ export function ensureGitignore(ctx) {
400
+ const { fsImpl = fs } = ctx;
401
+ const target = path.join(ctx.projectRoot, '.gitignore');
402
+ const existing = fsImpl.existsSync(target)
403
+ ? fsImpl.readFileSync(target, 'utf8')
404
+ : '';
405
+ let body = existing;
406
+ const outcomes = {};
407
+ for (const [key, def] of Object.entries(GITIGNORE_BLOCKS)) {
408
+ if (def.pattern.test(body)) {
409
+ outcomes[key] = 'already-present';
410
+ continue;
411
+ }
412
+ body =
413
+ (body.length > 0 && !body.endsWith('\n') ? `${body}\n` : body) +
414
+ def.block;
415
+ outcomes[key] = 'added';
416
+ }
417
+ if (body !== existing) fsImpl.writeFileSync(target, body, 'utf8');
418
+ return { ...outcomes, path: target };
419
+ }
420
+
421
+ /**
422
+ * Step 5 — Run the sync script. Step 6 (parity) is enforced by the
423
+ * sync script itself (it removes stale entries and writes from the
424
+ * single source of truth), so a successful exit equals parity.
425
+ *
426
+ * Returns `{ ok, stdout }`.
427
+ *
428
+ * @param {object} ctx
429
+ * @param {typeof defaultSpawnSync} [ctx.spawnImpl]
430
+ */
431
+ export function runSyncCommands(ctx) {
432
+ const { spawnImpl = defaultSpawnSync } = ctx;
433
+ const script = path.join(
434
+ ctx.agentRoot ?? path.join(ctx.projectRoot, '.agents'),
435
+ 'scripts',
436
+ 'sync-claude-commands.js',
437
+ );
438
+ const result = spawnImpl(process.execPath, [script], {
439
+ cwd: ctx.projectRoot,
440
+ encoding: 'utf8',
441
+ });
442
+ if (result.status !== 0) {
443
+ throw new Error(
444
+ `[bootstrap] sync-claude-commands.js failed (exit ${result.status}): ${(
445
+ result.stderr ?? ''
446
+ )
447
+ .trim()
448
+ .slice(0, 400)}`,
449
+ );
450
+ }
451
+ return { ok: true, stdout: (result.stdout ?? '').trim() };
452
+ }
453
+
454
+ /**
455
+ * Step 6 — Parity check between `.agents/workflows/*.md` and the generated
456
+ * flat command tree `.claude/commands/*.md`. Step 5's sync already enforces
457
+ * this; this is a belt-and-braces verification that the command projection
458
+ * covers every top-level workflow.
459
+ *
460
+ * @param {object} ctx
461
+ * @param {typeof fs} [ctx.fsImpl]
462
+ */
463
+ export function checkParity(ctx) {
464
+ const { fsImpl = fs } = ctx;
465
+ const workflowsDir = path.join(
466
+ ctx.agentRoot ?? path.join(ctx.projectRoot, '.agents'),
467
+ 'workflows',
468
+ );
469
+ const commandsDir = path.join(ctx.projectRoot, '.claude', 'commands');
470
+ const list = (dir) =>
471
+ fsImpl.existsSync(dir)
472
+ ? fsImpl
473
+ .readdirSync(dir, { withFileTypes: true })
474
+ .filter((e) => e.isFile() && e.name.endsWith('.md'))
475
+ .map((e) => e.name.replace(/\.md$/, ''))
476
+ .sort()
477
+ : [];
478
+ const workflows = new Set(list(workflowsDir));
479
+ const commands = new Set(list(commandsDir));
480
+ const missingCommand = [...workflows].filter((n) => !commands.has(n));
481
+ const orphanCommand = [...commands].filter((n) => !workflows.has(n));
482
+ return {
483
+ ok: missingCommand.length === 0 && orphanCommand.length === 0,
484
+ missingCommand,
485
+ orphanCommand,
486
+ };
487
+ }
488
+
489
+ /**
490
+ * Step 8.5 — Wire the framework system prompt into a consumer `CLAUDE.md`.
491
+ *
492
+ * Claude Code hydrates its always-loaded context from a project-root
493
+ * `CLAUDE.md`; without the `@.agents/instructions.md` import the framework
494
+ * system prompt never loads on cold start. This step makes that wiring
495
+ * automatic and idempotent:
496
+ *
497
+ * - No `CLAUDE.md` at all → write a minimal one carrying the import.
498
+ * - `CLAUDE.md` exists but lacks the import → append the import block.
499
+ * - `CLAUDE.md` already imports it → no-op (no duplicate import line).
500
+ *
501
+ * Idempotence is keyed off the literal `SYSTEM_PROMPT_IMPORT` path, so a
502
+ * re-run on an already-wired file is a guaranteed zero-mutation no-op.
503
+ *
504
+ * Returns `{ action, path }` where `action` is one of `created`,
505
+ * `appended`, or `already-present`.
506
+ *
507
+ * @param {object} ctx
508
+ * @param {typeof fs} [ctx.fsImpl]
509
+ */
510
+ export function ensureSystemPromptWiring(ctx) {
511
+ const { fsImpl = fs } = ctx;
512
+ const target = path.join(ctx.projectRoot, 'CLAUDE.md');
513
+ if (!fsImpl.existsSync(target)) {
514
+ fsImpl.writeFileSync(target, SYSTEM_PROMPT_CLAUDE_MD, 'utf8');
515
+ return { action: 'created', path: target };
516
+ }
517
+ const existing = fsImpl.readFileSync(target, 'utf8');
518
+ if (existing.includes(SYSTEM_PROMPT_IMPORT)) {
519
+ return { action: 'already-present', path: target };
520
+ }
521
+ const separator = existing.length > 0 && !existing.endsWith('\n') ? '\n' : '';
522
+ fsImpl.writeFileSync(
523
+ target,
524
+ `${existing}${separator}\n${SYSTEM_PROMPT_BLOCK}`,
525
+ 'utf8',
526
+ );
527
+ return { action: 'appended', path: target };
528
+ }
529
+
530
+ /**
531
+ * Step 9 — Windows git-perf hints (warn-only). On non-Windows this is a
532
+ * silent no-op. On Windows the check probes three settings and reports
533
+ * which are missing; it never mutates global git config.
534
+ *
535
+ * @param {object} ctx
536
+ * @param {typeof fs} [ctx.fsImpl]
537
+ * @param {typeof defaultSpawnSync} [ctx.spawnImpl]
538
+ */
539
+ export function checkWindowsGitPerf(ctx) {
540
+ const { fsImpl = fs, spawnImpl = defaultSpawnSync } = ctx;
541
+ if (os.platform() !== 'win32') {
542
+ return { platform: process.platform, skipped: true };
543
+ }
544
+ const script = path.join(
545
+ ctx.agentRoot ?? path.join(ctx.projectRoot, '.agents'),
546
+ 'scripts',
547
+ 'check-windows-git-perf.js',
548
+ );
549
+ if (!fsImpl.existsSync(script)) {
550
+ return { platform: 'win32', skipped: true, reason: 'script-missing' };
551
+ }
552
+ const result = spawnImpl(process.execPath, [script], {
553
+ cwd: ctx.projectRoot,
554
+ encoding: 'utf8',
555
+ });
556
+ return {
557
+ platform: 'win32',
558
+ skipped: false,
559
+ ok: result.status === 0,
560
+ stdout: (result.stdout ?? '').trim(),
561
+ };
562
+ }
563
+
564
+ // ---------------------------------------------------------------------------
565
+ // BOOTSTRAP_PHASES (Story #2459 / Task #2473)
566
+ //
567
+ // The previous `applyProjectBootstrap` was an 11-step inline pipeline with
568
+ // three fatal-abort branches (`nodeCheck`, `validation`, `parity`). Each
569
+ // phase is now a declarative `{ name, run, isFatal?, formatError? }`
570
+ // entry. The single-pass driver `runPhases` reads the array, calls each
571
+ // `run(ctx, report)`, accumulates the result onto `report[phase.name]`,
572
+ // and routes fatal phases through `throwIfFatal` so the abort message
573
+ // remains operator-visible.
574
+ //
575
+ // `applyProjectBootstrap` collapses to two lines: instantiate an empty
576
+ // report, hand it to `runPhases`, return it.
577
+ // ---------------------------------------------------------------------------
578
+
579
+ /**
580
+ * @typedef {object} BootstrapPhase
581
+ * @property {string} name — key used to land the result on the report.
582
+ * @property {(ctx: object, report: object) => any|Promise<any>} run
583
+ * — executes the phase. May read prior
584
+ * phases via `report.<name>`.
585
+ * @property {boolean} [isFatal] — when `true`, the driver passes the
586
+ * result through `formatError`; if the
587
+ * formatter returns a non-empty string,
588
+ * the driver throws with that message.
589
+ * @property {(result: any) => string|null} [formatError]
590
+ * — produces the error message when the
591
+ * phase result indicates a fatal abort.
592
+ */
593
+
594
+ const fatalNodeCheck = (result) =>
595
+ result.ok
596
+ ? null
597
+ : `[bootstrap] Node ${result.version} is below required ${result.required}. Upgrade Node and re-run.`;
598
+
599
+ const fatalValidation = (result) =>
600
+ result.ok
601
+ ? null
602
+ : `[bootstrap] .agentrc.json failed schema validation: ${JSON.stringify(
603
+ result.errors,
604
+ null,
605
+ 2,
606
+ )}`;
607
+
608
+ const fatalParity = (result) =>
609
+ result.ok
610
+ ? null
611
+ : `[bootstrap] Parity check failed — workflows missing commands: ${
612
+ result.missingCommand.join(', ') || '(none)'
613
+ }; orphan commands: ${result.orphanCommand.join(', ') || '(none)'}`;
614
+
615
+ /**
616
+ * Pipeline definition — the order, the helpers, and the fatal-abort
617
+ * branches. Exported so tests can assert phase ordering, the fatal flag,
618
+ * and the report-shape parity guarantee without driving the whole
619
+ * bootstrap.
620
+ *
621
+ * Each project-side mutation phase carries a `phaseGroup` matching one of
622
+ * the consent-first {@link PHASE_GROUPS}. When a phased-approval gate is
623
+ * supplied via `ctx.approvedGroups`, a phase whose `phaseGroup` is not in
624
+ * the approved set is skipped (recorded as a `phase-group-declined` no-op)
625
+ * — declining one group never short-circuits the others (Story #3524).
626
+ * Phases with no `phaseGroup` (the Node-version precondition and the
627
+ * dependency install) are always-run infrastructure, never gated.
628
+ */
629
+ export const BOOTSTRAP_PHASES = Object.freeze([
630
+ {
631
+ name: 'nodeCheck',
632
+ run: () => checkNodeVersion(),
633
+ isFatal: true,
634
+ formatError: fatalNodeCheck,
635
+ },
636
+ {
637
+ name: 'pkg',
638
+ phaseGroup: PHASE_GROUPS.REPO_CONFIG,
639
+ run: (ctx) => ensurePackageJson(ctx),
640
+ },
641
+ {
642
+ name: 'install',
643
+ run: (ctx) => ensureDependenciesInstalled(ctx),
644
+ },
645
+ {
646
+ name: 'agentrc',
647
+ phaseGroup: PHASE_GROUPS.REPO_CONFIG,
648
+ run: (ctx) => ensureAgentrc(ctx),
649
+ },
650
+ {
651
+ name: 'validation',
652
+ phaseGroup: PHASE_GROUPS.REPO_CONFIG,
653
+ run: async (ctx) => validateAgentrc(ctx),
654
+ isFatal: true,
655
+ formatError: fatalValidation,
656
+ },
657
+ {
658
+ name: 'claudeSettings',
659
+ phaseGroup: PHASE_GROUPS.IDE_WIRING,
660
+ run: (ctx) => ensureClaudeSettings(ctx),
661
+ },
662
+ {
663
+ name: 'systemPromptWiring',
664
+ phaseGroup: PHASE_GROUPS.IDE_WIRING,
665
+ run: (ctx) => ensureSystemPromptWiring(ctx),
666
+ },
667
+ {
668
+ name: 'gitignore',
669
+ phaseGroup: PHASE_GROUPS.IDE_WIRING,
670
+ run: (ctx) => ensureGitignore(ctx),
671
+ },
672
+ {
673
+ name: 'sync',
674
+ phaseGroup: PHASE_GROUPS.IDE_WIRING,
675
+ run: (ctx) => runSyncCommands(ctx),
676
+ },
677
+ {
678
+ name: 'parity',
679
+ phaseGroup: PHASE_GROUPS.IDE_WIRING,
680
+ run: (ctx) => checkParity(ctx),
681
+ isFatal: true,
682
+ formatError: fatalParity,
683
+ },
684
+ {
685
+ name: 'quality',
686
+ phaseGroup: PHASE_GROUPS.QUALITY_GATES,
687
+ run: (ctx) =>
688
+ ctx.skipQuality
689
+ ? { skipped: true }
690
+ : applyQualityBootstrap({ projectRoot: ctx.projectRoot }),
691
+ },
692
+ {
693
+ name: 'winPerf',
694
+ run: (ctx) => checkWindowsGitPerf(ctx),
695
+ },
696
+ ]);
697
+
698
+ /**
699
+ * Decide whether a phase should run given the approved-phase-group gate.
700
+ * An always-run infrastructure phase (no `phaseGroup`) runs unconditionally.
701
+ * A grouped phase runs only when no gate is supplied (`approvedGroups`
702
+ * absent — the un-gated legacy path) or when its group is in the gate.
703
+ *
704
+ * Exported for unit testing.
705
+ *
706
+ * @param {BootstrapPhase} phase
707
+ * @param {Set<string>|undefined} approvedGroups
708
+ * @returns {boolean}
709
+ */
710
+ export function isPhaseApproved(phase, approvedGroups) {
711
+ if (!phase.phaseGroup) return true;
712
+ if (!approvedGroups) return true;
713
+ return approvedGroups.has(phase.phaseGroup);
714
+ }
715
+
716
+ /**
717
+ * Throw with the formatted message when the phase is marked fatal and
718
+ * the result indicates an abort. Pure helper so the driver stays a
719
+ * single-branch loop.
720
+ *
721
+ * Exported for tests.
722
+ *
723
+ * @param {BootstrapPhase} phase
724
+ * @param {any} result
725
+ */
726
+ export function throwIfFatal(phase, result) {
727
+ if (!phase.isFatal) return;
728
+ const msg = phase.formatError?.(result);
729
+ if (typeof msg === 'string' && msg.length > 0) throw new Error(msg);
730
+ }
731
+
732
+ /**
733
+ * Iterate `phases` in order; await each phase's `run(ctx, report)`, land
734
+ * the result on `report[phase.name]`, then route fatal phases through
735
+ * `throwIfFatal`. Returns the accumulated report.
736
+ *
737
+ * When `ctx.approvedGroups` is a `Set`, a grouped phase whose `phaseGroup`
738
+ * is not approved is skipped and recorded as
739
+ * `{ skipped: true, reason: 'phase-group-declined', phaseGroup }` — it never
740
+ * runs, never throws (so a declined `ide-wiring` group also skips its
741
+ * fatal `parity` check), and never short-circuits the remaining phases.
742
+ *
743
+ * Exported for tests so phase ordering and fatal behaviour can be
744
+ * asserted without spawning a full bootstrap.
745
+ *
746
+ * @param {ReadonlyArray<BootstrapPhase>} phases
747
+ * @param {object} ctx
748
+ * @returns {Promise<object>}
749
+ */
750
+ export async function runPhases(phases, ctx) {
751
+ const report = {};
752
+ for (const phase of phases) {
753
+ if (!isPhaseApproved(phase, ctx.approvedGroups)) {
754
+ report[phase.name] = {
755
+ skipped: true,
756
+ reason: 'phase-group-declined',
757
+ phaseGroup: phase.phaseGroup,
758
+ };
759
+ continue;
760
+ }
761
+ const result = await phase.run(ctx, report);
762
+ report[phase.name] = result;
763
+ throwIfFatal(phase, result);
764
+ }
765
+ return report;
766
+ }
767
+
768
+ /**
769
+ * Compose every step in order. Each returned key is the outcome of one
770
+ * step so the CLI can render a structured summary.
771
+ *
772
+ * When `ctx.preview` is truthy, the function performs **no writes and no
773
+ * network I/O**. Instead it derives the operator-facing change list from
774
+ * the single mutation-manifest source ({@link previewMutationManifest}) and
775
+ * returns `{ preview: true, groups, entries }` — the exact same source the
776
+ * consent-first install screen renders. Deriving the preview from
777
+ * `buildMutationManifest` (rather than from a parallel hand-maintained list)
778
+ * guarantees the preview the operator approves and the execution that
779
+ * follows enumerate one identical set of mutations (Story #3521).
780
+ *
781
+ * @param {object} ctx
782
+ * @param {string} ctx.projectRoot
783
+ * @param {string} [ctx.agentRoot]
784
+ * @param {{ owner: string, repo: string, baseBranch: string,
785
+ * operatorHandle: string|null }} ctx.answers
786
+ * @param {boolean} [ctx.preview] — no-write preview from the manifest.
787
+ * @param {Set<string>} [ctx.approvedGroups] — when present, only phases
788
+ * whose `phaseGroup` is in this set execute (the consent-first gate from
789
+ * Story #3524); always-run infrastructure phases ignore it.
790
+ * @param {boolean} [ctx.skipQuality]
791
+ * @param {boolean} [ctx.skipGithub]
792
+ * @param {boolean} [ctx.skipInstall]
793
+ * @param {boolean} [ctx.quiet]
794
+ * @param {typeof fs} [ctx.fsImpl] — injectable filesystem seam (test-seams.md).
795
+ * @param {typeof defaultSpawnSync} [ctx.spawnImpl] — injectable spawn seam (test-seams.md).
796
+ * @returns {Promise<object>}
797
+ */
798
+ export async function applyProjectBootstrap(ctx) {
799
+ if (ctx.preview) return previewMutationManifest(ctx);
800
+ return runPhases(BOOTSTRAP_PHASES, ctx);
801
+ }