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,795 @@
1
+ // lib/cli/uninstall.js
2
+ /**
3
+ * `mandrel uninstall` subcommand.
4
+ *
5
+ * Reverses a recorded install by consuming the install ledger written by the
6
+ * consent-first bootstrap (`.agents/.install-manifest.json`, Story #3524).
7
+ * Each ledger entry is a mutation-manifest record
8
+ * (`{ phaseGroup, target, action, reversible }`); uninstall walks the
9
+ * reversible entries and undoes exactly the mutation the install applied,
10
+ * keyed off the entry's `target` path.
11
+ *
12
+ * Design goals
13
+ * ------------
14
+ * - **Preserve pre-existing user content.** Reversal is marker-based, not
15
+ * blunt file deletion: the CLAUDE.md import block is stripped (not the file
16
+ * removed) so a CLAUDE.md the operator authored before install survives;
17
+ * the `.claude/settings.json` sync hook is spliced out without touching
18
+ * other hooks; the `.gitignore` entries are removed without disturbing the
19
+ * operator's own ignore rules; only the framework's own npm scripts are
20
+ * removed from `package.json`. A file is deleted outright only when
21
+ * stripping the framework block leaves it empty / framework-only (the
22
+ * install created it from nothing).
23
+ * - **GitHub-side state is never touched by default.** The `github-admin`
24
+ * ledger entries carry `reversible: false`; they are surfaced as a manual
25
+ * rollback checklist and are only acted on when the operator opts in with
26
+ * `--include-github` (which, for now, still only enumerates them — remote
27
+ * admin reversal is out of scope for this Story and would require the same
28
+ * `gh` plumbing the bootstrap uses).
29
+ * - **Idempotent.** Re-running after a successful uninstall is a no-op: the
30
+ * ledger is removed last, and every reversal step is a no-op when the
31
+ * marker is already absent.
32
+ *
33
+ * Output contract
34
+ * ---------------
35
+ * reversed file → "✔ reverted <target> <detail>"
36
+ * skipped → "• skipped <target> <reason>"
37
+ * manual (gh) → "! manual <target> <detail>"
38
+ * final → "✅ Uninstalled (<n> reversed, <m> manual follow-ups)"
39
+ * | "❌ No install ledger found — nothing to uninstall."
40
+ *
41
+ * All output goes to process.stdout (never console.log — the repo enforces a
42
+ * no-console rule). Exit code 0 on success (including the no-ledger case,
43
+ * which is a benign no-op), 1 only on an unrecoverable error.
44
+ *
45
+ * Injectable seams (used by tests so no real filesystem is touched):
46
+ * - `projectRoot` — overrides the resolved consumer root.
47
+ * - `fsImpl` — replaces the `node:fs` surface.
48
+ * - `write` — replaces process.stdout.write.
49
+ * - `exit` — replaces process.exit.
50
+ * - `includeGithub`— forces the --include-github behaviour.
51
+ *
52
+ * @module cli/uninstall
53
+ */
54
+
55
+ import fs from 'node:fs';
56
+ import path from 'node:path';
57
+ import { fileURLToPath } from 'node:url';
58
+
59
+ import {
60
+ LEDGER_SCHEMA_VERSION,
61
+ ledgerPath,
62
+ readInstallLedger,
63
+ } from '../../.agents/scripts/lib/bootstrap/install-ledger.js';
64
+ import {
65
+ BOOTSTRAP_COMMAND,
66
+ GITIGNORE_BLOCKS,
67
+ SYNC_COMMAND,
68
+ SYSTEM_PROMPT_BLOCK,
69
+ SYSTEM_PROMPT_CLAUDE_MD,
70
+ SYSTEM_PROMPT_IMPORT,
71
+ } from '../../.agents/scripts/lib/bootstrap/project-bootstrap.js';
72
+ import {
73
+ DOWNSTREAM_PRE_COMMIT,
74
+ PRE_COMMIT_MARKER,
75
+ QUALITY_NPM_SCRIPTS,
76
+ } from '../../.agents/scripts/lib/bootstrap/quality-bootstrap.js';
77
+
78
+ // ---------------------------------------------------------------------------
79
+ // Project-root resolution
80
+ // ---------------------------------------------------------------------------
81
+
82
+ /**
83
+ * Resolve the consumer project root — the directory that holds `.agents/`.
84
+ * `mandrel uninstall` runs from the consumer's checkout, so the install
85
+ * ledger and every target path are anchored at `process.cwd()`. This mirrors
86
+ * how `lib/cli/sync.js` and the doctor checks anchor consumer-facing paths.
87
+ *
88
+ * @param {() => string} [cwd=process.cwd]
89
+ * @returns {string}
90
+ */
91
+ function resolveProjectRoot(cwd = () => process.cwd()) {
92
+ return cwd();
93
+ }
94
+
95
+ // ---------------------------------------------------------------------------
96
+ // npm-script removal set
97
+ // ---------------------------------------------------------------------------
98
+
99
+ /**
100
+ * The exact `package.json` scripts the bootstrap seeds. Reversal removes a
101
+ * script key only when its value still equals the framework-seeded command —
102
+ * an operator who overwrote the value keeps their version. `prepare` is
103
+ * special: the bootstrap may *append* the sync command to an existing
104
+ * `prepare`, so reversal strips the framework fragment rather than deleting
105
+ * the whole key. Mirrors `ensurePackageJson` / `ensureQualityNpmScripts`.
106
+ *
107
+ * @type {Readonly<Record<string, string>>}
108
+ */
109
+ const FRAMEWORK_NPM_SCRIPTS = Object.freeze({
110
+ 'sync:commands': SYNC_COMMAND,
111
+ bootstrap: BOOTSTRAP_COMMAND,
112
+ ...QUALITY_NPM_SCRIPTS,
113
+ });
114
+
115
+ // ---------------------------------------------------------------------------
116
+ // Pure reversal helpers (filesystem effects via the injected fsImpl)
117
+ // ---------------------------------------------------------------------------
118
+
119
+ /**
120
+ * @typedef {object} ReversalOutcome
121
+ * @property {'reverted'|'skipped'|'manual'} kind
122
+ * @property {string} target
123
+ * @property {string} detail
124
+ */
125
+
126
+ /**
127
+ * Strip the framework system-prompt import block from a `CLAUDE.md`. The file
128
+ * is removed only when it is byte-identical to the install-authored template
129
+ * (`SYSTEM_PROMPT_CLAUDE_MD`). Any other file — including one whose only
130
+ * operator content is markdown headings — is preserved with just the framework
131
+ * block excised.
132
+ *
133
+ * Using a byte-equality check rather than a "non-`#` meaningful lines"
134
+ * heuristic prevents data loss when an operator's pre-install `CLAUDE.md`
135
+ * consists entirely of markdown headings (all lines start with `#`).
136
+ *
137
+ * @param {string} projectRoot
138
+ * @param {typeof fs} fsImpl
139
+ * @returns {ReversalOutcome}
140
+ */
141
+ function revertClaudeMd(projectRoot, fsImpl) {
142
+ const target = path.join(projectRoot, 'CLAUDE.md');
143
+ const rel = 'CLAUDE.md';
144
+ if (!fsImpl.existsSync(target)) {
145
+ return { kind: 'skipped', target: rel, detail: 'file absent' };
146
+ }
147
+ const original = fsImpl.readFileSync(target, 'utf8');
148
+ if (!original.includes(SYSTEM_PROMPT_IMPORT)) {
149
+ return { kind: 'skipped', target: rel, detail: 'import already absent' };
150
+ }
151
+ // Delete only when the file is exactly the install-authored template — i.e.
152
+ // the install created it from nothing. Operator-authored content (even an
153
+ // all-headings file) must survive.
154
+ if (original.trim() === SYSTEM_PROMPT_CLAUDE_MD.trim()) {
155
+ fsImpl.rmSync(target, { force: true });
156
+ return {
157
+ kind: 'reverted',
158
+ target: rel,
159
+ detail: 'removed install-created CLAUDE.md',
160
+ };
161
+ }
162
+ // Remove the full block first (heading + import), then fall back to the
163
+ // bare import line so a hand-edited block without the heading still clears.
164
+ let next = original.includes(SYSTEM_PROMPT_BLOCK)
165
+ ? original.replace(SYSTEM_PROMPT_BLOCK, '')
166
+ : original;
167
+ if (next.includes(SYSTEM_PROMPT_IMPORT)) {
168
+ next = next
169
+ .split('\n')
170
+ .filter((line) => line.trim() !== SYSTEM_PROMPT_IMPORT)
171
+ .join('\n');
172
+ }
173
+ // Collapse any run of 3+ blank lines the splice may have produced.
174
+ next = next.replace(/\n{3,}/g, '\n\n').replace(/^\n+/, '');
175
+ fsImpl.writeFileSync(
176
+ target,
177
+ next.endsWith('\n') ? next : `${next}\n`,
178
+ 'utf8',
179
+ );
180
+ return {
181
+ kind: 'reverted',
182
+ target: rel,
183
+ detail: 'stripped system-prompt import block',
184
+ };
185
+ }
186
+
187
+ /**
188
+ * Splice the framework UserPromptSubmit sync hook **and** the plugin
189
+ * enablement keys (Story #3576) out of `.claude/settings.json`, leaving every
190
+ * other hook and setting intact. When the settings file is left with no hooks
191
+ * and no other keys, it is removed.
192
+ *
193
+ * @param {string} projectRoot
194
+ * @param {typeof fs} fsImpl
195
+ * @returns {ReversalOutcome}
196
+ */
197
+ function revertClaudeSettings(projectRoot, fsImpl) {
198
+ const target = path.join(projectRoot, '.claude', 'settings.json');
199
+ const rel = '.claude/settings.json';
200
+ if (!fsImpl.existsSync(target)) {
201
+ return { kind: 'skipped', target: rel, detail: 'file absent' };
202
+ }
203
+ const settings = JSON.parse(fsImpl.readFileSync(target, 'utf8'));
204
+ const groups = settings?.hooks?.UserPromptSubmit;
205
+ const isFrameworkHook = (h) =>
206
+ typeof h?.command === 'string' &&
207
+ h.command.includes('sync-claude-commands.js');
208
+
209
+ let mutated = false;
210
+
211
+ // 1. Strip any legacy plugin-enablement keys (#3576). The flat-command
212
+ // projection no longer writes these, but a consumer upgraded from a
213
+ // #3576 install may still carry them — clean them up on uninstall.
214
+ if (
215
+ settings.enabledPlugins &&
216
+ settings.enabledPlugins['mandrel@mandrel'] !== undefined
217
+ ) {
218
+ delete settings.enabledPlugins['mandrel@mandrel'];
219
+ if (Object.keys(settings.enabledPlugins).length === 0) {
220
+ delete settings.enabledPlugins;
221
+ }
222
+ mutated = true;
223
+ }
224
+ if (settings.extraKnownMarketplaces?.mandrel !== undefined) {
225
+ delete settings.extraKnownMarketplaces.mandrel;
226
+ if (Object.keys(settings.extraKnownMarketplaces).length === 0) {
227
+ delete settings.extraKnownMarketplaces;
228
+ }
229
+ mutated = true;
230
+ }
231
+
232
+ // 2. Splice out the UserPromptSubmit sync hook.
233
+ if (Array.isArray(groups)) {
234
+ const kept = groups
235
+ .map((group) => ({
236
+ ...group,
237
+ hooks: (group?.hooks ?? []).filter((h) => !isFrameworkHook(h)),
238
+ }))
239
+ .filter((group) => (group.hooks ?? []).length > 0);
240
+ if (kept.length !== groups.length) {
241
+ if (kept.length === 0) {
242
+ delete settings.hooks.UserPromptSubmit;
243
+ } else {
244
+ settings.hooks.UserPromptSubmit = kept;
245
+ }
246
+ if (settings.hooks && Object.keys(settings.hooks).length === 0) {
247
+ delete settings.hooks;
248
+ }
249
+ mutated = true;
250
+ }
251
+ }
252
+
253
+ if (!mutated) {
254
+ return { kind: 'skipped', target: rel, detail: 'framework wiring absent' };
255
+ }
256
+ if (Object.keys(settings).length === 0) {
257
+ fsImpl.rmSync(target, { force: true });
258
+ return {
259
+ kind: 'reverted',
260
+ target: rel,
261
+ detail: 'removed install-created settings.json',
262
+ };
263
+ }
264
+ fsImpl.writeFileSync(
265
+ target,
266
+ `${JSON.stringify(settings, null, 2)}\n`,
267
+ 'utf8',
268
+ );
269
+ return {
270
+ kind: 'reverted',
271
+ target: rel,
272
+ detail: 'removed sync hook (and any legacy plugin enablement)',
273
+ };
274
+ }
275
+
276
+ /**
277
+ * Remove the generated Claude Code command projection: the flat
278
+ * `.claude/commands/` tree. The tree is generated from `.agents/workflows/`, so
279
+ * it is safe to remove wholesale (it is gitignored and never hand-edited). Any
280
+ * legacy #3576 plugin projection (`.claude/plugins/mandrel/` +
281
+ * `.claude/.claude-plugin/`) left by an older install is also removed.
282
+ *
283
+ * @param {string} projectRoot
284
+ * @param {typeof fs} fsImpl
285
+ * @returns {ReversalOutcome}
286
+ */
287
+ function revertClaudeCommands(projectRoot, fsImpl) {
288
+ const rel = '.claude/commands';
289
+ const targets = [
290
+ path.join(projectRoot, '.claude', 'commands'),
291
+ // Legacy #3576 plugin projection — clean it up too if present.
292
+ path.join(projectRoot, '.claude', 'plugins', 'mandrel'),
293
+ path.join(projectRoot, '.claude', '.claude-plugin'),
294
+ ];
295
+ const present = targets.filter((t) => fsImpl.existsSync(t));
296
+ if (present.length === 0) {
297
+ return {
298
+ kind: 'skipped',
299
+ target: rel,
300
+ detail: 'command projection absent',
301
+ };
302
+ }
303
+ for (const t of present) {
304
+ fsImpl.rmSync(t, { recursive: true, force: true });
305
+ }
306
+ return {
307
+ kind: 'reverted',
308
+ target: rel,
309
+ detail: 'removed generated .claude/commands/ projection',
310
+ };
311
+ }
312
+
313
+ /**
314
+ * Remove the two `.gitignore` blocks the install appended (the
315
+ * `.claude/commands/` and `.mcp.json` entries), preserving every other line
316
+ * the operator authored. When the file is left empty it is removed.
317
+ *
318
+ * The `.mcp.json` ignore block is intentionally retained when a real
319
+ * `.mcp.json` exists at the project root: that file may carry secrets and
320
+ * removing the ignore entry would expose it on the next `git add .`.
321
+ *
322
+ * @param {string} projectRoot
323
+ * @param {typeof fs} fsImpl
324
+ * @returns {ReversalOutcome}
325
+ */
326
+ function revertGitignore(projectRoot, fsImpl) {
327
+ const target = path.join(projectRoot, '.gitignore');
328
+ const rel = '.gitignore';
329
+ if (!fsImpl.existsSync(target)) {
330
+ return { kind: 'skipped', target: rel, detail: 'file absent' };
331
+ }
332
+ const original = fsImpl.readFileSync(target, 'utf8');
333
+ const mcpJsonExists = fsImpl.existsSync(path.join(projectRoot, '.mcp.json'));
334
+ let next = original;
335
+ for (const [key, def] of Object.entries(GITIGNORE_BLOCKS)) {
336
+ if (next.includes(def.block)) {
337
+ // Retain the .mcp.json ignore entry when a real .mcp.json is present —
338
+ // removing it would expose a potentially secret-bearing file to git.
339
+ if (key === 'mcp' && mcpJsonExists) {
340
+ continue;
341
+ }
342
+ next = next.replace(def.block, '');
343
+ }
344
+ }
345
+ if (next === original) {
346
+ return { kind: 'skipped', target: rel, detail: 'ignore entries absent' };
347
+ }
348
+ next = next.replace(/\n{3,}/g, '\n\n');
349
+ if (next.trim().length === 0) {
350
+ fsImpl.rmSync(target, { force: true });
351
+ return {
352
+ kind: 'reverted',
353
+ target: rel,
354
+ detail: 'removed install-created .gitignore',
355
+ };
356
+ }
357
+ fsImpl.writeFileSync(target, next, 'utf8');
358
+ const detail = mcpJsonExists
359
+ ? 'removed framework ignore entries; kept .mcp.json entry (.mcp.json exists)'
360
+ : 'removed framework ignore entries';
361
+ return { kind: 'reverted', target: rel, detail };
362
+ }
363
+
364
+ /**
365
+ * Remove the framework-seeded npm scripts (and the appended `prepare`
366
+ * fragment) from `package.json`, leaving every operator-authored script and
367
+ * field intact. A script whose value the operator overwrote is preserved.
368
+ *
369
+ * @param {string} projectRoot
370
+ * @param {typeof fs} fsImpl
371
+ * @returns {ReversalOutcome}
372
+ */
373
+ function revertPackageJson(projectRoot, fsImpl) {
374
+ const target = path.join(projectRoot, 'package.json');
375
+ const rel = 'package.json';
376
+ if (!fsImpl.existsSync(target)) {
377
+ return { kind: 'skipped', target: rel, detail: 'file absent' };
378
+ }
379
+ const pkg = JSON.parse(fsImpl.readFileSync(target, 'utf8'));
380
+ if (!pkg.scripts || typeof pkg.scripts !== 'object') {
381
+ return { kind: 'skipped', target: rel, detail: 'no framework scripts' };
382
+ }
383
+ const removed = [];
384
+ for (const [name, cmd] of Object.entries(FRAMEWORK_NPM_SCRIPTS)) {
385
+ if (pkg.scripts[name] === cmd) {
386
+ delete pkg.scripts[name];
387
+ removed.push(name);
388
+ }
389
+ }
390
+ // `prepare` may be the bare sync command (delete it) or an operator command
391
+ // with the sync fragment appended via ` && ` (strip just the fragment).
392
+ // When stripping leaves an empty string, delete the key rather than writing
393
+ // `"prepare": ""`. Only push 'prepare' onto `removed` when the value
394
+ // actually changed (i.e. the fragment was present and was stripped).
395
+ const prepare = pkg.scripts.prepare;
396
+ if (typeof prepare === 'string' && prepare.includes(SYNC_COMMAND)) {
397
+ if (prepare === SYNC_COMMAND) {
398
+ delete pkg.scripts.prepare;
399
+ removed.push('prepare');
400
+ } else {
401
+ const stripped = prepare
402
+ .replace(` && ${SYNC_COMMAND}`, '')
403
+ .replace(`${SYNC_COMMAND} && `, '')
404
+ .trim();
405
+ if (stripped !== prepare) {
406
+ if (stripped === '') {
407
+ delete pkg.scripts.prepare;
408
+ } else {
409
+ pkg.scripts.prepare = stripped;
410
+ }
411
+ removed.push('prepare');
412
+ }
413
+ }
414
+ }
415
+ if (removed.length === 0) {
416
+ return { kind: 'skipped', target: rel, detail: 'no framework scripts' };
417
+ }
418
+ if (Object.keys(pkg.scripts).length === 0) {
419
+ delete pkg.scripts;
420
+ }
421
+ fsImpl.writeFileSync(target, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8');
422
+ return {
423
+ kind: 'reverted',
424
+ target: rel,
425
+ detail: `removed npm scripts: ${removed.sort().join(', ')}`,
426
+ };
427
+ }
428
+
429
+ /**
430
+ * Remove an install-created `.agentrc.json` — but never one the install did
431
+ * not create (Story #3895, data-loss fix for `docs/install-bootstrap-review.md`
432
+ * Finding B.2).
433
+ *
434
+ * The ledger now records the **live** outcome of the `agentrc` bootstrap phase
435
+ * as `executedAction` (schema v2). `ensureAgentrc` returns `seeded` when it
436
+ * wrote the file from the starter and `already-present` when it left a
437
+ * pre-existing, operator-authored file untouched. Reversal is gated on that:
438
+ *
439
+ * - `executedAction === 'already-present'` → the operator owned this file
440
+ * before the install ran; the install created nothing, so deleting it would
441
+ * be data loss. Skip.
442
+ * - `executedAction === 'seeded'` (or any other create-class outcome) → the
443
+ * install authored the file from nothing; deleting it returns the project to
444
+ * the pre-install state.
445
+ * - `executedAction` absent (legacy v1 ledger / no hint) → cannot happen for a
446
+ * v2 ledger written by this framework, but if encountered we fail **safe**
447
+ * and skip rather than risk deleting operator content.
448
+ *
449
+ * @param {string} projectRoot
450
+ * @param {typeof fs} fsImpl
451
+ * @param {string} [executedAction] — the recorded `agentrc` phase outcome.
452
+ * @returns {ReversalOutcome}
453
+ */
454
+ function revertAgentrc(projectRoot, fsImpl, executedAction) {
455
+ const target = path.join(projectRoot, '.agentrc.json');
456
+ const rel = '.agentrc.json';
457
+ if (!fsImpl.existsSync(target)) {
458
+ return { kind: 'skipped', target: rel, detail: 'file absent' };
459
+ }
460
+ // Only delete a file the install actually created. Any non-`seeded` outcome
461
+ // (pre-existing `already-present`, a missing hint, or an unexpected value)
462
+ // is treated as "not install-created" → preserve the operator's file.
463
+ if (executedAction !== 'seeded') {
464
+ return {
465
+ kind: 'skipped',
466
+ target: rel,
467
+ detail: 'pre-existing .agentrc.json preserved (not install-created)',
468
+ };
469
+ }
470
+ fsImpl.rmSync(target, { force: true });
471
+ return {
472
+ kind: 'reverted',
473
+ target: rel,
474
+ detail: 'removed install-created .agentrc.json',
475
+ };
476
+ }
477
+
478
+ /**
479
+ * Reverse the `.husky/pre-commit` quality hook. The file is removed only when
480
+ * it is byte-identical to the install-authored template (`DOWNSTREAM_PRE_COMMIT`).
481
+ * Any other hook — including one whose only non-framework lines are a shebang
482
+ * or comments — is preserved with just the quality-preview line stripped.
483
+ *
484
+ * Using a byte-equality check rather than a "non-`#` meaningful lines"
485
+ * heuristic prevents data loss when an operator's pre-install hook consists
486
+ * entirely of a shebang line and/or comments (all lines start with `#`).
487
+ *
488
+ * @param {string} projectRoot
489
+ * @param {typeof fs} fsImpl
490
+ * @returns {ReversalOutcome}
491
+ */
492
+ function revertPreCommitHook(projectRoot, fsImpl) {
493
+ const target = path.join(projectRoot, '.husky', 'pre-commit');
494
+ const rel = '.husky/pre-commit';
495
+ if (!fsImpl.existsSync(target)) {
496
+ return { kind: 'skipped', target: rel, detail: 'hook absent' };
497
+ }
498
+ const original = fsImpl.readFileSync(target, 'utf8');
499
+ if (!original.includes(PRE_COMMIT_MARKER)) {
500
+ return { kind: 'skipped', target: rel, detail: 'quality line absent' };
501
+ }
502
+ // Delete only when the file is exactly the install-authored template — i.e.
503
+ // the install created it from nothing. Operator-authored content (even an
504
+ // all-comments hook) must survive.
505
+ if (original.trim() === DOWNSTREAM_PRE_COMMIT.trim()) {
506
+ fsImpl.rmSync(target, { force: true });
507
+ return {
508
+ kind: 'reverted',
509
+ target: rel,
510
+ detail: 'removed install-created pre-commit hook',
511
+ };
512
+ }
513
+ const kept = original
514
+ .split('\n')
515
+ .filter((line) => !line.includes(PRE_COMMIT_MARKER));
516
+ const remaining = kept.join('\n').trim();
517
+ fsImpl.writeFileSync(target, `${remaining}\n`, 'utf8');
518
+ return {
519
+ kind: 'reverted',
520
+ target: rel,
521
+ detail: 'stripped quality-preview line',
522
+ };
523
+ }
524
+
525
+ // ---------------------------------------------------------------------------
526
+ // Dispatch table — ledger target → reversal helper
527
+ // ---------------------------------------------------------------------------
528
+
529
+ /**
530
+ * Map a reversible ledger entry's `target` to the helper that undoes it.
531
+ * Targets that map to the same file (e.g. both `repo-config` and
532
+ * `quality-gates` touch `package.json`) are deduped by the caller so each
533
+ * file is reverted once.
534
+ *
535
+ * Handlers take `(root, fsImpl)`; `.agentrc.json` additionally takes the
536
+ * recorded `executedAction` (the third arg, ignored by the others) so it can
537
+ * preserve a pre-existing file the install did not create (Story #3895).
538
+ *
539
+ * @type {Readonly<Record<string, (root: string, fsImpl: typeof fs, executedAction?: string) => ReversalOutcome>>}
540
+ */
541
+ const REVERSAL_BY_TARGET = Object.freeze({
542
+ 'CLAUDE.md': revertClaudeMd,
543
+ '.claude/settings.json': revertClaudeSettings,
544
+ '.claude/plugins/mandrel': revertClaudeCommands,
545
+ '.gitignore': revertGitignore,
546
+ 'package.json': revertPackageJson,
547
+ '.agentrc.json': revertAgentrc,
548
+ '.husky/pre-commit': revertPreCommitHook,
549
+ });
550
+
551
+ // ---------------------------------------------------------------------------
552
+ // Planner (pure over the ledger; effects deferred to the helpers)
553
+ // ---------------------------------------------------------------------------
554
+
555
+ /**
556
+ * Partition a ledger's entries into the reversible local-file reversals to
557
+ * run, the remote (`github-admin`) entries to surface as manual follow-ups,
558
+ * and the set of unique file targets to revert (deduped).
559
+ *
560
+ * Pure — derives entirely from the ledger record, with no filesystem access.
561
+ *
562
+ * The returned `executedActionByTarget` map carries the per-target
563
+ * `executedAction` recorded in the ledger (schema v2, Story #3895). When more
564
+ * than one entry shares a target (e.g. the repo-config `create` and
565
+ * quality-gates `merge` entries for `.agentrc.json`), the first defined
566
+ * `executedAction` wins — they resolve to the same bootstrap phase outcome, so
567
+ * the choice is unambiguous.
568
+ *
569
+ * @param {{ entries: Array<import('../../.agents/scripts/lib/bootstrap/manifest.js').MutationManifestEntry & { executedAction?: string }> }} ledger
570
+ * @returns {{ fileTargets: string[], manual: import('../../.agents/scripts/lib/bootstrap/manifest.js').MutationManifestEntry[], executedActionByTarget: Record<string, string> }}
571
+ */
572
+ export function planUninstall(ledger) {
573
+ const fileTargets = [];
574
+ const seen = new Set();
575
+ const manual = [];
576
+ const executedActionByTarget = {};
577
+ for (const entry of ledger.entries ?? []) {
578
+ if (entry.reversible === false) {
579
+ manual.push(entry);
580
+ continue;
581
+ }
582
+ if (!REVERSAL_BY_TARGET[entry.target]) {
583
+ // A reversible entry with no known handler is surfaced as manual so the
584
+ // operator is never silently left with an un-reverted mutation.
585
+ manual.push(entry);
586
+ continue;
587
+ }
588
+ if (
589
+ typeof entry.executedAction === 'string' &&
590
+ executedActionByTarget[entry.target] === undefined
591
+ ) {
592
+ executedActionByTarget[entry.target] = entry.executedAction;
593
+ }
594
+ if (!seen.has(entry.target)) {
595
+ seen.add(entry.target);
596
+ fileTargets.push(entry.target);
597
+ }
598
+ }
599
+ return { fileTargets, manual, executedActionByTarget };
600
+ }
601
+
602
+ // ---------------------------------------------------------------------------
603
+ // Formatting
604
+ // ---------------------------------------------------------------------------
605
+
606
+ const TARGET_COL = 22;
607
+
608
+ function pad(value, width) {
609
+ const s = String(value);
610
+ return s.length >= width ? s : s + ' '.repeat(width - s.length);
611
+ }
612
+
613
+ /**
614
+ * @param {ReversalOutcome} outcome
615
+ * @returns {string}
616
+ */
617
+ function formatOutcome(outcome) {
618
+ const icon =
619
+ outcome.kind === 'reverted' ? '✔' : outcome.kind === 'manual' ? '!' : '•';
620
+ const label =
621
+ outcome.kind === 'reverted'
622
+ ? 'reverted'
623
+ : outcome.kind === 'manual'
624
+ ? 'manual '
625
+ : 'skipped ';
626
+ return `${icon} ${label} ${pad(outcome.target, TARGET_COL)} ${outcome.detail}\n`;
627
+ }
628
+
629
+ // ---------------------------------------------------------------------------
630
+ // Runner (exported for testing)
631
+ // ---------------------------------------------------------------------------
632
+
633
+ /**
634
+ * Execute the uninstall against a project root.
635
+ *
636
+ * @param {{
637
+ * projectRoot?: string,
638
+ * cwd?: () => string,
639
+ * fsImpl?: typeof fs,
640
+ * write?: (s: string) => void,
641
+ * exit?: (code: number) => void,
642
+ * includeGithub?: boolean,
643
+ * }} [opts]
644
+ * @returns {{ revertedCount: number, manualCount: number, ledgerFound: boolean, parseErrorCount: number }}
645
+ */
646
+ export function runUninstall({
647
+ projectRoot,
648
+ cwd,
649
+ fsImpl = fs,
650
+ write = (s) => process.stdout.write(s),
651
+ exit = (code) => process.exit(code),
652
+ includeGithub = false,
653
+ } = {}) {
654
+ const root = projectRoot ?? resolveProjectRoot(cwd);
655
+
656
+ let ledger;
657
+ try {
658
+ ledger = readInstallLedger(root);
659
+ } catch (err) {
660
+ write(`❌ Install ledger is unreadable: ${err.message}\n`);
661
+ exit(1);
662
+ return {
663
+ revertedCount: 0,
664
+ manualCount: 0,
665
+ ledgerFound: false,
666
+ parseErrorCount: 0,
667
+ };
668
+ }
669
+
670
+ if (!ledger) {
671
+ write('❌ No install ledger found — nothing to uninstall.\n');
672
+ // A missing ledger is a benign no-op (never installed, or already
673
+ // uninstalled), so this is success, not an error.
674
+ exit(0);
675
+ return {
676
+ revertedCount: 0,
677
+ manualCount: 0,
678
+ ledgerFound: false,
679
+ parseErrorCount: 0,
680
+ };
681
+ }
682
+
683
+ if (ledger.schemaVersion !== LEDGER_SCHEMA_VERSION) {
684
+ write(
685
+ `❌ Install ledger schema v${ledger.schemaVersion} is not supported by this mandrel (expected v${LEDGER_SCHEMA_VERSION}). Upgrade/downgrade mandrel to match, then re-run.\n`,
686
+ );
687
+ exit(1);
688
+ return {
689
+ revertedCount: 0,
690
+ manualCount: 0,
691
+ ledgerFound: true,
692
+ parseErrorCount: 0,
693
+ };
694
+ }
695
+
696
+ const { fileTargets, manual, executedActionByTarget } = planUninstall(ledger);
697
+
698
+ let revertedCount = 0;
699
+ let parseErrorCount = 0;
700
+ for (const target of fileTargets) {
701
+ let outcome;
702
+ try {
703
+ // The third arg carries the recorded `executedAction` for the target
704
+ // (schema v2). Only `revertAgentrc` consults it; the other handlers
705
+ // ignore extra arguments. This is how uninstall avoids deleting a
706
+ // pre-existing `.agentrc.json` the install did not create (Story #3895).
707
+ outcome = REVERSAL_BY_TARGET[target](
708
+ root,
709
+ fsImpl,
710
+ executedActionByTarget[target],
711
+ );
712
+ } catch (err) {
713
+ // An operator-edited file that contains invalid JSON (or any other
714
+ // unexpected throw from the reversal helper) must not abort the whole
715
+ // uninstall and leave earlier targets reverted while later ones are not.
716
+ // Emit a `skipped` outcome so the operator knows they must revert this
717
+ // target by hand, and leave the install ledger intact so a re-run after
718
+ // the file is fixed can resume cleanly.
719
+ outcome = {
720
+ kind: 'skipped',
721
+ target,
722
+ detail: `unparseable — revert manually (${err.message})`,
723
+ };
724
+ parseErrorCount += 1;
725
+ }
726
+ if (outcome.kind === 'reverted') revertedCount += 1;
727
+ write(formatOutcome(outcome));
728
+ }
729
+
730
+ // GitHub-admin (and any unhandled reversible) entries are manual follow-ups.
731
+ // They are NEVER acted on automatically; --include-github only annotates
732
+ // that the operator acknowledged them (remote reversal stays out of scope).
733
+ let manualCount = 0;
734
+ for (const entry of manual) {
735
+ manualCount += 1;
736
+ const note = includeGithub
737
+ ? `${entry.detail} (acknowledged — reverse manually via the GitHub UI/API)`
738
+ : `${entry.detail} (left untouched — pass --include-github to acknowledge)`;
739
+ write(
740
+ formatOutcome({ kind: 'manual', target: entry.target, detail: note }),
741
+ );
742
+ }
743
+
744
+ // Remove the ledger last so a re-run is a clean no-op and a partial failure
745
+ // mid-reversal still leaves the ledger for a resume. When any target was
746
+ // skipped due to a parse error, leave the ledger in place so the operator
747
+ // can fix the corrupt file and re-run to complete the uninstall.
748
+ const lp = ledgerPath(root);
749
+ if (fsImpl.existsSync(lp) && parseErrorCount === 0) {
750
+ fsImpl.rmSync(lp, { force: true });
751
+ write(
752
+ formatOutcome({
753
+ kind: 'reverted',
754
+ target: '.agents/.install-manifest.json',
755
+ detail: 'removed install ledger',
756
+ }),
757
+ );
758
+ revertedCount += 1;
759
+ } else if (parseErrorCount > 0 && fsImpl.existsSync(lp)) {
760
+ write(
761
+ formatOutcome({
762
+ kind: 'skipped',
763
+ target: '.agents/.install-manifest.json',
764
+ detail: 'ledger retained — re-run after fixing unparseable file(s)',
765
+ }),
766
+ );
767
+ }
768
+
769
+ write(
770
+ `✅ Uninstalled (${revertedCount} reversed, ${manualCount} manual follow-up${
771
+ manualCount === 1 ? '' : 's'
772
+ })\n`,
773
+ );
774
+ exit(0);
775
+ return { revertedCount, manualCount, ledgerFound: true, parseErrorCount };
776
+ }
777
+
778
+ // ---------------------------------------------------------------------------
779
+ // Subcommand entry point (called by bin/mandrel.js)
780
+ // ---------------------------------------------------------------------------
781
+
782
+ /**
783
+ * Default export consumed by `bin/mandrel.js`.
784
+ *
785
+ * @param {string[]} argv — supports the single `--include-github` flag.
786
+ * @returns {Promise<void>}
787
+ */
788
+ export default async function run(argv = []) {
789
+ const includeGithub = argv.includes('--include-github');
790
+ runUninstall({ includeGithub });
791
+ }
792
+
793
+ // Re-export so tests and callers can reference the resolved module path
794
+ // without re-deriving it.
795
+ export const __filenameForTests = fileURLToPath(import.meta.url);