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,830 @@
1
+ // lib/cli/registry.js
2
+ /**
3
+ * Doctor check + remedy registry for `mandrel doctor`.
4
+ *
5
+ * Exports an ordered array of check objects each shaped `{ name, run() }`.
6
+ * `run()` returns `{ ok, detail, remedy? }` — `remedy` is present and
7
+ * non-empty only when `ok` is false. The registry is the single source of
8
+ * truth for which checks the doctor command runs and in what order.
9
+ *
10
+ * Checks run sequentially in the doctor runner (not in parallel) because
11
+ * some checks are meaningless without a prerequisite having passed first
12
+ * (e.g. `gh-auth` requires `gh-available`).
13
+ *
14
+ * Design goals
15
+ * - Every check is injectable via optional seam parameters so tests can
16
+ * drive every branch without spawning real child processes.
17
+ * - The `github-token` check never echoes the token value in `detail` or
18
+ * `remedy` (security baseline §5 — Secrets Management).
19
+ * - Node built-ins only; no third-party imports so the module loads inside
20
+ * the preflight guard before any third-party package is present.
21
+ */
22
+
23
+ import { spawnSync } from 'node:child_process';
24
+ import fs from 'node:fs';
25
+ import { createRequire } from 'node:module';
26
+ import path from 'node:path';
27
+ import { fileURLToPath } from 'node:url';
28
+
29
+ import { readCache } from './version-check.js';
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Internal helpers
33
+ // ---------------------------------------------------------------------------
34
+
35
+ /**
36
+ * Synchronously spawn a binary and return `{ status, stdout, stderr, error }`.
37
+ *
38
+ * @param {string} cmd
39
+ * @param {string[]} args
40
+ * @returns {{ status: number|null, stdout: string, stderr: string, error?: NodeJS.ErrnoException }}
41
+ */
42
+ function spawn(cmd, args) {
43
+ const r = spawnSync(cmd, args, { encoding: 'utf8' });
44
+ return {
45
+ status: r.status,
46
+ stdout: typeof r.stdout === 'string' ? r.stdout : '',
47
+ stderr: typeof r.stderr === 'string' ? r.stderr : '',
48
+ error: r.error,
49
+ };
50
+ }
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // check: node-version
54
+ // ---------------------------------------------------------------------------
55
+
56
+ /**
57
+ * The minimum Node version the framework requires (`engines.node`).
58
+ * Mirrors `lib/bootstrap/project-bootstrap.js#REQUIRED_NODE_FLOOR`.
59
+ */
60
+ const REQUIRED_NODE_FLOOR = '22.22.1';
61
+ const REQUIRED_NODE_CEILING_MAJOR = 25;
62
+
63
+ /**
64
+ * Return true when `version` satisfies `>=22.22.1 <25`.
65
+ *
66
+ * @param {string} version
67
+ * @returns {boolean}
68
+ */
69
+ function satisfiesNodeEngine(version) {
70
+ const [majorRaw, minorRaw, patchRaw] = String(version).split('.');
71
+ const major = Number.parseInt(majorRaw, 10) || 0;
72
+ const minor = Number.parseInt(minorRaw, 10) || 0;
73
+ const patch = Number.parseInt(patchRaw, 10) || 0;
74
+ if (major >= REQUIRED_NODE_CEILING_MAJOR) return false;
75
+ if (major > 22) return true;
76
+ if (major < 22) return false;
77
+ if (minor > 22) return true;
78
+ if (minor < 22) return false;
79
+ return patch >= 1;
80
+ }
81
+
82
+ /**
83
+ * @param {{ nodeVersion?: string }} [opts]
84
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
85
+ */
86
+ function runNodeVersion({ nodeVersion = process.versions.node } = {}) {
87
+ const ok = satisfiesNodeEngine(nodeVersion);
88
+ const detail = `v${nodeVersion} (required >=${REQUIRED_NODE_FLOOR} <${REQUIRED_NODE_CEILING_MAJOR})`;
89
+ if (ok) return { ok: true, detail };
90
+ return {
91
+ ok: false,
92
+ detail,
93
+ remedy: `Upgrade Node to >=${REQUIRED_NODE_FLOOR} <${REQUIRED_NODE_CEILING_MAJOR}: https://nodejs.org/`,
94
+ };
95
+ }
96
+
97
+ // ---------------------------------------------------------------------------
98
+ // check: git-available
99
+ // ---------------------------------------------------------------------------
100
+
101
+ /**
102
+ * @param {{ runner?: (cmd: string, args: string[]) => { status: number|null, stdout: string, stderr: string, error?: NodeJS.ErrnoException } }} [opts]
103
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
104
+ */
105
+ function runGitAvailable({ runner = spawn } = {}) {
106
+ const r = runner('git', ['--version']);
107
+ if (r.error?.code === 'ENOENT' || r.status !== 0) {
108
+ const snippet = (r.stderr || r.stdout || '').trim().slice(0, 120);
109
+ return {
110
+ ok: false,
111
+ detail: snippet || 'git not found on PATH',
112
+ remedy: 'Install git: https://git-scm.com/downloads — then re-run.',
113
+ };
114
+ }
115
+ return { ok: true, detail: r.stdout.trim().split('\n')[0] };
116
+ }
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // check: gh-available
120
+ // ---------------------------------------------------------------------------
121
+
122
+ /**
123
+ * @param {{ runner?: (cmd: string, args: string[]) => { status: number|null, stdout: string, stderr: string, error?: NodeJS.ErrnoException } }} [opts]
124
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
125
+ */
126
+ function runGhAvailable({ runner = spawn } = {}) {
127
+ const r = runner('gh', ['--version']);
128
+ if (r.error?.code === 'ENOENT' || r.status !== 0) {
129
+ const snippet = (r.stderr || r.stdout || '').trim().slice(0, 120);
130
+ return {
131
+ ok: false,
132
+ detail: snippet || 'gh not found on PATH',
133
+ remedy: 'Install gh CLI: https://cli.github.com/ — then re-run.',
134
+ };
135
+ }
136
+ return { ok: true, detail: r.stdout.trim().split('\n')[0] };
137
+ }
138
+
139
+ // ---------------------------------------------------------------------------
140
+ // check: github-token
141
+ // ---------------------------------------------------------------------------
142
+
143
+ /**
144
+ * Verify a GitHub token is resolvable the way the runtime resolves it.
145
+ *
146
+ * Parity with `.agents/scripts/providers/github/auth.js#resolveToken`: a
147
+ * token counts as present when either `GITHUB_TOKEN` / `GH_TOKEN` is set in
148
+ * the environment **or** `gh auth token` returns a value. The `mandrel` CLI
149
+ * does not load `.env`, so the previous env-only check false-blocked
150
+ * operators who authenticate solely via `gh auth login` (Finding A.4) —
151
+ * the runtime never needed `GITHUB_TOKEN` in that case because it falls back
152
+ * to the `gh` CLI. Never echoes the token value in `detail` or `remedy`
153
+ * (security baseline §5 — Secrets Management).
154
+ *
155
+ * @param {{ env?: Record<string,string|undefined>,
156
+ * runner?: (cmd: string, args: string[]) => {
157
+ * status: number|null, stdout: string, stderr: string,
158
+ * error?: NodeJS.ErrnoException } }} [opts]
159
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
160
+ */
161
+ function runGithubToken({ env = process.env, runner = spawn } = {}) {
162
+ const envToken = env.GITHUB_TOKEN || env.GH_TOKEN;
163
+ if (envToken && envToken.length > 0) {
164
+ return { ok: true, detail: 'GITHUB_TOKEN set' };
165
+ }
166
+ const r = runner('gh', ['auth', 'token']);
167
+ const ghToken = !r.error && r.status === 0 ? (r.stdout || '').trim() : '';
168
+ if (ghToken.length > 0) {
169
+ return { ok: true, detail: 'token resolved via `gh auth token`' };
170
+ }
171
+ return {
172
+ ok: false,
173
+ detail: 'no GitHub token (env unset, `gh auth token` returned nothing)',
174
+ remedy:
175
+ 'Run `gh auth login` (the CLI resolves the token via `gh auth token`), or export GITHUB_TOKEN=<your-token>.',
176
+ };
177
+ }
178
+
179
+ // ---------------------------------------------------------------------------
180
+ // check: gh-auth
181
+ // ---------------------------------------------------------------------------
182
+
183
+ /**
184
+ * Verify the GitHub CLI can authenticate.
185
+ *
186
+ * `gh auth status` performs **live token validation** (it probes the API for
187
+ * the active token). A GitHub Actions installation token — and some
188
+ * fine-grained tokens — cannot pass that probe (`GET /user` returns 403
189
+ * "Resource not accessible by integration") even though the token works for
190
+ * every git/API operation mandrel actually performs. The non-interactive
191
+ * runtime never consults `gh auth status`: it resolves auth via the env token
192
+ * or `gh auth token` (`.agents/scripts/providers/github/auth.js#resolveToken`,
193
+ * mirrored by the `github-token` check above). So when `gh auth status` fails
194
+ * but a token is present in the environment, degrade to **warn-and-skip**
195
+ * (ok=true) rather than false-blocking the ready verdict — the same
196
+ * warn-and-skip resolution #3915 applied to the project-scope preflight.
197
+ * A genuine "no token anywhere and not logged in" condition still fails.
198
+ *
199
+ * @param {{ runner?: (cmd: string, args: string[]) => { status: number|null, stdout: string, stderr: string, error?: NodeJS.ErrnoException }, env?: Record<string,string|undefined> }} [opts]
200
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
201
+ */
202
+ function runGhAuth({ runner = spawn, env = process.env } = {}) {
203
+ const r = runner('gh', ['auth', 'status']);
204
+ if (r.error?.code === 'ENOENT') {
205
+ return {
206
+ ok: false,
207
+ detail: 'gh not found — auth check skipped',
208
+ remedy: 'Install the GitHub CLI: https://cli.github.com',
209
+ };
210
+ }
211
+ if (r.status !== 0) {
212
+ const envToken = env.GITHUB_TOKEN || env.GH_TOKEN;
213
+ if (envToken && envToken.length > 0) {
214
+ return {
215
+ ok: true,
216
+ detail:
217
+ '`gh auth status` could not validate the active token, but GITHUB_TOKEN/GH_TOKEN is set (the runtime authenticates non-interactively with it)',
218
+ };
219
+ }
220
+ return {
221
+ ok: false,
222
+ detail: 'not logged in',
223
+ remedy:
224
+ 'Run `gh auth login` (choose GitHub.com → HTTPS → login with a web browser), then re-run.',
225
+ };
226
+ }
227
+ // Extract "Logged in to github.com as <handle>" from stdout or stderr.
228
+ const output = (r.stdout + r.stderr).trim();
229
+ const match = /Logged in to \S+ as (\S+)/i.exec(output);
230
+ const detail = match ? `logged in as ${match[1]}` : 'logged in';
231
+ return { ok: true, detail };
232
+ }
233
+
234
+ // ---------------------------------------------------------------------------
235
+ // check: commands-in-sync
236
+ // ---------------------------------------------------------------------------
237
+
238
+ /**
239
+ * Resolve the project root — the directory that contains `.agents/` and
240
+ * `.claude/`. Walks up from this file's own location.
241
+ *
242
+ * @returns {string}
243
+ */
244
+ function resolveProjectRoot() {
245
+ // lib/cli/registry.js lives at <root>/lib/cli/registry.js, so walk up two
246
+ // levels from __dirname to reach the project root.
247
+ const here = path.dirname(fileURLToPath(import.meta.url));
248
+ return path.resolve(here, '..', '..');
249
+ }
250
+
251
+ /**
252
+ * Dry-run the sync-claude-commands logic: compare `.agents/workflows/*.md`
253
+ * sources to the generated flat command tree `.claude/commands/*.md`
254
+ * destinations and report parity (the projection is a flat `/<name>` command
255
+ * surface; the #3576 plugin projection was reverted).
256
+ *
257
+ * Resolution anchor (Story #3588): the root defaults to `process.cwd()` —
258
+ * the consumer project directory where `mandrel sync` materializes both
259
+ * `.agents/` and the command tree — mirroring the `agents-materialized`
260
+ * and `agents-drift` checks. It MUST NOT fall back to `resolveProjectRoot()`:
261
+ * that walks up from this module's own location and lands on the *package*
262
+ * directory in an npm-installed consumer
263
+ * (`node_modules/mandrel/`), where the generated command tree never
264
+ * exists — yielding a permanent `N not synced` false positive whose
265
+ * `npm run sync:commands` remedy can never clear it.
266
+ *
267
+ * Injectable seams (used by tests so no real filesystem is touched):
268
+ * - `cwd()` replaces `process.cwd` so tests can pin the consumer root.
269
+ * - `readDir` replaces `fs.readdirSync`.
270
+ *
271
+ * @param {{ projectRoot?: string, cwd?: () => string, readDir?: (dir: string) => string[] }} [opts]
272
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
273
+ */
274
+ function runCommandsInSync({ projectRoot, cwd, readDir } = {}) {
275
+ const getCwd = cwd ?? (() => process.cwd());
276
+ const root = projectRoot ?? getCwd();
277
+ const listDir =
278
+ readDir ??
279
+ ((dir) => {
280
+ try {
281
+ return fs.readdirSync(dir).filter((f) => f.endsWith('.md'));
282
+ } catch {
283
+ return [];
284
+ }
285
+ });
286
+
287
+ const srcDir = path.join(root, '.agents', 'workflows');
288
+ const destDir = path.join(root, '.claude', 'commands');
289
+
290
+ // Only top-level .md files are synced (helpers/ subdirectory excluded by
291
+ // the sync script — they are path-included modules, not slash commands).
292
+ const sources = listDir(srcDir)
293
+ .filter((f) => !f.startsWith('.'))
294
+ .sort();
295
+ const dests = listDir(destDir)
296
+ .filter((f) => !f.startsWith('.'))
297
+ .sort();
298
+
299
+ const srcSet = new Set(sources);
300
+ const dstSet = new Set(dests);
301
+ const missing = sources.filter((f) => !dstSet.has(f));
302
+ const extra = dests.filter((f) => !srcSet.has(f));
303
+
304
+ if (missing.length === 0 && extra.length === 0) {
305
+ return { ok: true, detail: `${sources.length} commands up to date` };
306
+ }
307
+
308
+ const parts = [];
309
+ if (missing.length > 0) parts.push(`${missing.length} not synced`);
310
+ if (extra.length > 0) parts.push(`${extra.length} stale`);
311
+ return {
312
+ ok: false,
313
+ detail: parts.join(', '),
314
+ remedy:
315
+ 'Run `npm run sync:commands` to regenerate the `.claude/commands/` tree.',
316
+ };
317
+ }
318
+
319
+ // ---------------------------------------------------------------------------
320
+ // check: runtime-deps
321
+ // ---------------------------------------------------------------------------
322
+
323
+ /**
324
+ * Verify that the framework's required runtime dependencies are resolvable
325
+ * from the project's node_modules.
326
+ *
327
+ * Injectable seams:
328
+ * - `resolve(dep)` — replaces the real `require.resolve`; throws when a dep
329
+ * is missing.
330
+ * - `manifestRequired` — array of required package names, skips the
331
+ * filesystem read of `runtime-deps.json`.
332
+ *
333
+ * @param {{ projectRoot?: string, resolve?: (dep: string) => string, manifestRequired?: string[] }} [opts]
334
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
335
+ */
336
+ function runRuntimeDeps({
337
+ projectRoot,
338
+ resolve: resolveSeam,
339
+ manifestRequired,
340
+ } = {}) {
341
+ let required = manifestRequired;
342
+ if (!required) {
343
+ try {
344
+ const root = projectRoot ?? resolveProjectRoot();
345
+ const manifestPath = path.join(root, '.agents', 'runtime-deps.json');
346
+ const raw = fs.readFileSync(manifestPath, 'utf8');
347
+ const parsed = JSON.parse(raw);
348
+ required = Object.keys(parsed.dependencies ?? {});
349
+ } catch {
350
+ required = [];
351
+ }
352
+ }
353
+
354
+ if (required.length === 0) {
355
+ return { ok: true, detail: 'all dependencies found' };
356
+ }
357
+
358
+ const missing = [];
359
+
360
+ if (resolveSeam) {
361
+ for (const dep of required) {
362
+ try {
363
+ resolveSeam(dep);
364
+ } catch {
365
+ missing.push(dep);
366
+ }
367
+ }
368
+ } else {
369
+ // Anchor resolution to the project root so it mirrors the context in which
370
+ // the framework scripts run (they free-ride on the consumer's node_modules).
371
+ const root = projectRoot ?? resolveProjectRoot();
372
+ const req = createRequire(path.join(root, 'package.json'));
373
+ for (const dep of required) {
374
+ try {
375
+ req.resolve(dep);
376
+ } catch {
377
+ missing.push(dep);
378
+ }
379
+ }
380
+ }
381
+
382
+ if (missing.length === 0) {
383
+ return { ok: true, detail: 'all dependencies found' };
384
+ }
385
+ return {
386
+ ok: false,
387
+ detail: `missing: ${missing.join(', ')}`,
388
+ remedy: `Run \`npm install\` in the repository root to install missing packages: ${missing.join(', ')}`,
389
+ };
390
+ }
391
+
392
+ // ---------------------------------------------------------------------------
393
+ // check: agents-materialized
394
+ // ---------------------------------------------------------------------------
395
+
396
+ /**
397
+ * Verify that the `.agents/` payload has been materialized into the consumer
398
+ * project (`./.agents/instructions.md` exists). When it is absent but the
399
+ * `mandrel` package *is* installed in node_modules, the project is in
400
+ * the "postinstall-skipped" state — the package was installed with scripts
401
+ * disabled (e.g. `npm ci --ignore-scripts`, a sandboxed CI, or a package
402
+ * manager that skips lifecycle scripts), so the materializer never ran. The
403
+ * remedy is to run `mandrel sync` (lib/cli/sync.js) by hand.
404
+ *
405
+ * Resolution anchors:
406
+ * - `./.agents/instructions.md` is resolved against `cwd` (the consumer
407
+ * project root), matching where `mandrel sync` writes the materialized tree.
408
+ * - `mandrel` is resolved from `cwd` so we detect *their* install, not
409
+ * a copy hoisted next to this CLI module — mirroring sync.js's resolver.
410
+ *
411
+ * Injectable seams (used by tests so no real filesystem or package is needed):
412
+ * - `cwd()` — replaces `process.cwd`.
413
+ * - `existsSync(p)` — replaces `fs.existsSync`.
414
+ * - `resolvePackage(fromDir)` — replaces `mandrel` resolution; throws
415
+ * when the package is not installed.
416
+ *
417
+ * @param {{
418
+ * cwd?: () => string,
419
+ * existsSync?: (p: string) => boolean,
420
+ * resolvePackage?: (fromDir: string) => string,
421
+ * }} [opts]
422
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
423
+ */
424
+ function runAgentsMaterialized({ cwd, existsSync, resolvePackage } = {}) {
425
+ const getCwd = cwd ?? (() => process.cwd());
426
+ const exists = existsSync ?? ((p) => fs.existsSync(p));
427
+ const root = getCwd();
428
+ const instructionsPath = path.join(root, '.agents', 'instructions.md');
429
+
430
+ if (exists(instructionsPath)) {
431
+ return { ok: true, detail: '.agents/ materialized' };
432
+ }
433
+
434
+ const resolvePkg =
435
+ resolvePackage ??
436
+ ((fromDir) => {
437
+ const requireFrom = createRequire(path.join(fromDir, 'noop.js'));
438
+ return requireFrom.resolve('mandrel/package.json');
439
+ });
440
+
441
+ let packageInstalled = false;
442
+ try {
443
+ resolvePkg(root);
444
+ packageInstalled = true;
445
+ } catch {
446
+ packageInstalled = false;
447
+ }
448
+
449
+ if (packageInstalled) {
450
+ return {
451
+ ok: false,
452
+ detail: 'mandrel installed but ./.agents/ not materialized',
453
+ remedy:
454
+ 'Run `mandrel sync` to materialize the .agents/ payload (postinstall was skipped).',
455
+ };
456
+ }
457
+
458
+ return {
459
+ ok: false,
460
+ detail: 'mandrel not installed and ./.agents/ absent',
461
+ remedy:
462
+ 'Install the framework (`npm install mandrel`), then run `mandrel sync`.',
463
+ };
464
+ }
465
+
466
+ // ---------------------------------------------------------------------------
467
+ // check: agents-drift
468
+ // ---------------------------------------------------------------------------
469
+
470
+ /**
471
+ * Package name whose `.agents/` payload is the drift baseline. Mirrors
472
+ * `lib/cli/sync.js#PACKAGE_NAME`.
473
+ */
474
+ const PACKAGE_NAME = 'mandrel';
475
+
476
+ /**
477
+ * Top-level directory name (relative to `.agents/`) reserved as the
478
+ * sync-exempt local-additions zone (Story #3498, f-drift-local-zone).
479
+ *
480
+ * `.agents/local/` is consumer-owned space that `mandrel sync` never
481
+ * materializes nor prunes, so it is excluded from the drift comparison —
482
+ * a hand-authored file under `.agents/local/` is sanctioned, not drift.
483
+ * Mirrors `lib/cli/sync.js#LOCAL_ZONE_DIR`.
484
+ */
485
+ const LOCAL_ZONE_DIR = 'local';
486
+
487
+ /**
488
+ * Default resolver: locate the installed `mandrel` package root by
489
+ * resolving its `package.json` and returning the directory that contains it.
490
+ * Mirrors `lib/cli/sync.js#defaultResolvePackageRoot` so the drift baseline
491
+ * is exactly the payload that `mandrel sync` would copy.
492
+ *
493
+ * @param {string} fromDir - Directory to resolve from (the consumer project).
494
+ * @returns {string} Absolute path to the package root.
495
+ */
496
+ function defaultResolvePackageRoot(fromDir) {
497
+ const requireFrom = createRequire(path.join(fromDir, 'noop.js'));
498
+ const pkgJsonPath = requireFrom.resolve(`${PACKAGE_NAME}/package.json`);
499
+ return path.dirname(pkgJsonPath);
500
+ }
501
+
502
+ /**
503
+ * Recursively enumerate every regular file under `dir`, returning paths
504
+ * relative to `dir` using OS separators. The top-level `local/` subtree is
505
+ * skipped entirely — it is the consumer-owned local-additions zone and is
506
+ * never part of the package payload (Story #3498). Mirrors
507
+ * `lib/cli/sync.js#listFiles` so source enumeration matches the materializer.
508
+ *
509
+ * @param {string} dir - Absolute directory to walk.
510
+ * @param {typeof fs} fsImpl
511
+ * @param {string} [prefix] - Accumulated relative prefix (internal).
512
+ * @returns {string[]} Relative file paths.
513
+ */
514
+ function listPayloadFiles(dir, fsImpl, prefix = '') {
515
+ const out = [];
516
+ for (const ent of fsImpl.readdirSync(dir, { withFileTypes: true })) {
517
+ // Scope the local-zone skip to the top-level `.agents/local/` only; a
518
+ // deeper directory that happens to be named `local` stays in scope.
519
+ if (prefix === '' && ent.name === LOCAL_ZONE_DIR && ent.isDirectory()) {
520
+ continue;
521
+ }
522
+ const rel = prefix ? path.join(prefix, ent.name) : ent.name;
523
+ const abs = path.join(dir, ent.name);
524
+ if (ent.isDirectory()) {
525
+ out.push(...listPayloadFiles(abs, fsImpl, rel));
526
+ } else {
527
+ out.push(rel);
528
+ }
529
+ }
530
+ return out;
531
+ }
532
+
533
+ /**
534
+ * Compare the consumer's materialized `./.agents/<f>` bytes against the
535
+ * installed package payload (`node_modules/mandrel/.agents/<f>`),
536
+ * excluding the `.agents/local/` zone. Reports the first drifted (or
537
+ * missing) materialized file so the operator can re-sync or move local edits
538
+ * into `.agents/local/`.
539
+ *
540
+ * Security: logs only paths and counts — file contents are read for a byte
541
+ * comparison but never placed into `detail` or `remedy` (security baseline
542
+ * §5 — Data Leakage & Logging). The comparison is short-circuiting and never
543
+ * accumulates file contents.
544
+ *
545
+ * Injectable seams (used by tests so no real filesystem or package is needed):
546
+ * - `cwd()` — replaces `process.cwd`.
547
+ * - `fsImpl` — replaces the `node:fs` surface (`existsSync`, `readdirSync`,
548
+ * `readFileSync`).
549
+ * - `resolvePackageRoot(fromDir)` — replaces `mandrel` resolution;
550
+ * throws when the package is not installed.
551
+ *
552
+ * @param {{
553
+ * cwd?: () => string,
554
+ * fsImpl?: { existsSync: (p: string) => boolean, readdirSync: Function, readFileSync: Function },
555
+ * resolvePackageRoot?: (fromDir: string) => string,
556
+ * }} [opts]
557
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
558
+ */
559
+ function runAgentsDrift({ cwd, fsImpl = fs, resolvePackageRoot } = {}) {
560
+ const getCwd = cwd ?? (() => process.cwd());
561
+ const resolveRoot = resolvePackageRoot ?? defaultResolvePackageRoot;
562
+ const projectRoot = getCwd();
563
+
564
+ let packageRoot;
565
+ try {
566
+ packageRoot = resolveRoot(projectRoot);
567
+ } catch {
568
+ // Without the package installed there is no baseline to compare against;
569
+ // agents-materialized owns the "not installed" remedy, so this check is
570
+ // a no-op success rather than a false drift signal.
571
+ return {
572
+ ok: true,
573
+ detail: 'mandrel not installed — drift skipped',
574
+ };
575
+ }
576
+
577
+ const sourceRoot = path.join(packageRoot, '.agents');
578
+ if (!fsImpl.existsSync(sourceRoot)) {
579
+ return {
580
+ ok: true,
581
+ detail: 'mandrel ships no .agents/ payload — drift skipped',
582
+ };
583
+ }
584
+
585
+ const destRoot = path.join(projectRoot, '.agents');
586
+ if (!fsImpl.existsSync(destRoot)) {
587
+ // Nothing materialized yet — agents-materialized owns that remedy.
588
+ return { ok: true, detail: './.agents/ not materialized — drift skipped' };
589
+ }
590
+
591
+ const files = listPayloadFiles(sourceRoot, fsImpl);
592
+ let comparedCount = 0;
593
+ let missingCount = 0;
594
+
595
+ for (const rel of files) {
596
+ const src = path.join(sourceRoot, rel);
597
+ const dest = path.join(destRoot, rel);
598
+ const relLabel = path.join('.agents', rel);
599
+
600
+ if (!fsImpl.existsSync(dest)) {
601
+ missingCount += 1;
602
+ return {
603
+ ok: false,
604
+ detail: `${relLabel} is missing from ./.agents/ (${missingCount} of ${files.length} payload files checked so far)`,
605
+ remedy:
606
+ 'Run `mandrel sync` to restore the materialized .agents/ payload.',
607
+ };
608
+ }
609
+
610
+ const srcBytes = fsImpl.readFileSync(src);
611
+ const destBytes = fsImpl.readFileSync(dest);
612
+ comparedCount += 1;
613
+ if (!srcBytes.equals(destBytes)) {
614
+ return {
615
+ ok: false,
616
+ detail: `${relLabel} differs from the installed package payload`,
617
+ remedy:
618
+ 'Run `mandrel sync` to overwrite local edits, or move intentional changes into the `.agents/local/` zone.',
619
+ };
620
+ }
621
+ }
622
+
623
+ return {
624
+ ok: true,
625
+ detail: `${comparedCount} materialized file(s) match the package payload`,
626
+ };
627
+ }
628
+
629
+ // ---------------------------------------------------------------------------
630
+ // check: version-current
631
+ // ---------------------------------------------------------------------------
632
+
633
+ /**
634
+ * Parse a dotted semver-ish string into a numeric tuple. Non-numeric or
635
+ * missing segments coerce to 0 so a partial version still compares sanely.
636
+ * Mirrors `lib/cli/update.js#parseVersion`.
637
+ *
638
+ * @param {string} version
639
+ * @returns {[number, number, number]}
640
+ */
641
+ function parseVersionTuple(version) {
642
+ const [major, minor, patch] = String(version).split('.');
643
+ return [
644
+ Number.parseInt(major, 10) || 0,
645
+ Number.parseInt(minor, 10) || 0,
646
+ Number.parseInt(patch, 10) || 0,
647
+ ];
648
+ }
649
+
650
+ /**
651
+ * Compare two version strings. Negative when `a < b`, zero when equal,
652
+ * positive when `a > b`. Mirrors `lib/cli/update.js#compareVersions`.
653
+ *
654
+ * @param {string} a
655
+ * @param {string} b
656
+ * @returns {number}
657
+ */
658
+ function compareSemver(a, b) {
659
+ const pa = parseVersionTuple(a);
660
+ const pb = parseVersionTuple(b);
661
+ for (let i = 0; i < 3; i += 1) {
662
+ if (pa[i] !== pb[i]) return pa[i] - pb[i];
663
+ }
664
+ return 0;
665
+ }
666
+
667
+ /**
668
+ * Resolve the installed `mandrel` version from this package's own
669
+ * `package.json`. This module lives at `<root>/lib/cli/registry.js`, so the
670
+ * manifest is two directories up. Mirrors `lib/cli/update.js#defaultCurrentVersion`.
671
+ *
672
+ * @param {typeof fs} fsImpl
673
+ * @returns {string}
674
+ */
675
+ function defaultInstalledVersion(fsImpl) {
676
+ const here = path.dirname(fileURLToPath(import.meta.url));
677
+ const manifestPath = path.resolve(here, '..', '..', 'package.json');
678
+ const parsed = JSON.parse(fsImpl.readFileSync(manifestPath, 'utf8'));
679
+ return String(parsed.version);
680
+ }
681
+
682
+ /**
683
+ * Default cache filename — mirrors `version-check.js#DEFAULT_CACHE_FILENAME`.
684
+ */
685
+ const DEFAULT_VERSION_CACHE_FILENAME = 'version-check.json';
686
+
687
+ /**
688
+ * Default cache path: `<projectRoot>/temp/version-check.json`, the same daily
689
+ * freshness cache that `lib/cli/version-check.js` reads and refreshes.
690
+ *
691
+ * @returns {string}
692
+ */
693
+ function defaultVersionCachePath() {
694
+ return path.join(
695
+ resolveProjectRoot(),
696
+ 'temp',
697
+ DEFAULT_VERSION_CACHE_FILENAME,
698
+ );
699
+ }
700
+
701
+ /**
702
+ * Cache-only stale-version advisory (Story #3507, Epic #3437 — f-notify-stale).
703
+ *
704
+ * Reads the daily freshness cache written by `lib/cli/version-check.js` and
705
+ * reports whether a newer version than the installed one is already known
706
+ * locally. This check is **cache-only**: it NEVER issues a network request
707
+ * (it calls `readCache`, not `isStale`, so the network `runner` seam is never
708
+ * reached) — the daily refresh is owned by `version-check.js`, invoked
709
+ * elsewhere on the normal command path.
710
+ *
711
+ * **Non-fatal advisory contract.** A stale install is informational, not a
712
+ * readiness failure, so this check ALWAYS returns `ok: true` and therefore can
713
+ * never flip `mandrel doctor`'s exit code or block CI. When a newer version is
714
+ * cached, the advisory is surfaced through `detail` ("a newer version is
715
+ * available") and an actionable `remedy` (`mandrel update`); when the cache is
716
+ * absent, malformed, or already current, the check reports the up-to-date /
717
+ * unknown state with no remedy. The registry entry carries `advisory: true` so
718
+ * downstream renderers can label it as informational.
719
+ *
720
+ * Security (security-baseline § 5 — Data Leakage & Logging): emits only version
721
+ * strings; never reads or echoes tokens, credentials, or raw cache bytes beyond
722
+ * the two version fields `readCache` already validates.
723
+ *
724
+ * Injectable seams (used by tests so no real filesystem is touched):
725
+ * - `cachePath` — absolute path to the freshness cache JSON.
726
+ * - `installedVersion` — the currently installed version string.
727
+ * - `fsImpl` — `node:fs` surface forwarded to `readCache`.
728
+ *
729
+ * @param {{
730
+ * cachePath?: string,
731
+ * installedVersion?: string,
732
+ * fsImpl?: typeof fs,
733
+ * }} [opts]
734
+ * @returns {{ ok: boolean, detail: string, remedy?: string }}
735
+ */
736
+ function runVersionCurrent({ cachePath, installedVersion, fsImpl = fs } = {}) {
737
+ const resolvedPath = cachePath ?? defaultVersionCachePath();
738
+
739
+ let current = installedVersion;
740
+ if (!current) {
741
+ try {
742
+ current = defaultInstalledVersion(fsImpl);
743
+ } catch {
744
+ // Without a readable manifest we cannot compare; stay non-fatal.
745
+ return {
746
+ ok: true,
747
+ detail: 'installed version unknown — advisory skipped',
748
+ };
749
+ }
750
+ }
751
+
752
+ const cached = readCache({ cachePath: resolvedPath, fs: fsImpl });
753
+ if (!cached) {
754
+ // Missing / malformed cache → nothing to advise on yet. Non-fatal.
755
+ return {
756
+ ok: true,
757
+ detail: `v${current} (no cached freshness check yet)`,
758
+ };
759
+ }
760
+
761
+ if (compareSemver(cached.latestVersion, current) > 0) {
762
+ return {
763
+ ok: true,
764
+ detail: `a newer version is available: v${current} → v${cached.latestVersion} (advisory)`,
765
+ remedy: 'Run `mandrel update` to upgrade to the latest version.',
766
+ };
767
+ }
768
+
769
+ return { ok: true, detail: `v${current} is up to date` };
770
+ }
771
+
772
+ // ---------------------------------------------------------------------------
773
+ // Registry
774
+ // ---------------------------------------------------------------------------
775
+
776
+ /**
777
+ * Ordered array of doctor checks. Each entry follows the
778
+ * `{ name: string, run(opts?): { ok: boolean, detail: string, remedy?: string } }` contract.
779
+ * The doctor runner iterates this array sequentially.
780
+ *
781
+ * The `run` functions return plain objects (not Promises) — the doctor runner
782
+ * may call them with `await` but they do not need to be async.
783
+ */
784
+ export const registry = [
785
+ {
786
+ name: 'node-version',
787
+ run: (opts) => runNodeVersion(opts),
788
+ },
789
+ {
790
+ name: 'git-available',
791
+ run: (opts) => runGitAvailable(opts),
792
+ },
793
+ {
794
+ name: 'gh-available',
795
+ run: (opts) => runGhAvailable(opts),
796
+ },
797
+ {
798
+ name: 'github-token',
799
+ run: (opts) => runGithubToken(opts),
800
+ },
801
+ {
802
+ name: 'gh-auth',
803
+ run: (opts) => runGhAuth(opts),
804
+ },
805
+ {
806
+ name: 'commands-in-sync',
807
+ run: (opts) => runCommandsInSync(opts),
808
+ },
809
+ {
810
+ name: 'runtime-deps',
811
+ run: (opts) => runRuntimeDeps(opts),
812
+ },
813
+ {
814
+ name: 'agents-materialized',
815
+ run: (opts) => runAgentsMaterialized(opts),
816
+ },
817
+ {
818
+ name: 'agents-drift',
819
+ run: (opts) => runAgentsDrift(opts),
820
+ },
821
+ {
822
+ name: 'version-current',
823
+ // Non-fatal: surfaces a cache-only stale-version advisory. `run()` always
824
+ // returns ok:true, so it never blocks `mandrel doctor`'s exit code or CI.
825
+ advisory: true,
826
+ run: (opts) => runVersionCurrent(opts),
827
+ },
828
+ ];
829
+
830
+ export default registry;