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,805 @@
1
+ /**
2
+ * review-providers/native.js — Native (in-process) ReviewProvider adapter.
3
+ *
4
+ * Story #2833 (Epic #2815) — extracts the findings-collection logic that
5
+ * previously lived in the retired `.agents/scripts/epic-code-review` CLI into a
6
+ * `ReviewProvider`-shaped adapter. The adapter:
7
+ *
8
+ * 1. Diffs `headRef` against `baseRef` to enumerate changed files.
9
+ * 2. Runs scoped lint (biome + markdownlint) over the changed surface.
10
+ * 3. Computes per-file maintainability reports for changed JS files.
11
+ * 4. Maps each signal to a `Finding` with a `severity` ∈ {critical, high,
12
+ * medium, suggestion}.
13
+ *
14
+ * The adapter does NOT post to GitHub, does NOT render a markdown body,
15
+ * and does NOT consult the lifecycle bus. Those concerns belong to
16
+ * `runCodeReview()` (which calls the renderer + the structured-comment
17
+ * upserter) and the listener chain.
18
+ *
19
+ * Construction is intentionally zero-arg so the factory can instantiate
20
+ * it without threading config through every call. Per-invocation config
21
+ * (paths, runners, evidence store) is injected via the `runReview` arg or
22
+ * the `createNativeProvider({ deps })` overload used by tests.
23
+ *
24
+ * **Depth is deliberately ignored here (Story #3937).** The pluggable review
25
+ * contract threads a risk-derived `depth` lever (`light` / `standard` /
26
+ * `deep`) on `ReviewInput` so LLM-backed providers can dial their thoroughness
27
+ * up or down with the Epic's judged risk. This native adapter does not read
28
+ * `input.depth` and does not branch on it: its work is a *mechanical* lint +
29
+ * maintainability sweep whose cost already scales with the diff — every
30
+ * changed file is linted once and every changed JS file is scored once,
31
+ * regardless of risk tier. There is no "review harder" knob a deterministic
32
+ * scorer can turn: a high-risk diff and a low-risk diff of the same size do
33
+ * exactly the same amount of work. The contract is therefore explicit rather
34
+ * than silently dropping the field — `depth` is a no-op for this provider by
35
+ * design, and the LLM-backed providers (codex, security-review, ultrareview)
36
+ * are where the lever actually changes behaviour.
37
+ *
38
+ * @typedef {import('./types.js').Finding} Finding
39
+ * @typedef {import('./types.js').ReviewInput} ReviewInput
40
+ * @typedef {import('./types.js').ReviewProvider} ReviewProvider
41
+ */
42
+
43
+ import { spawnSync } from 'node:child_process';
44
+ import path from 'node:path';
45
+ import { PROJECT_ROOT } from '../../config-resolver.js';
46
+ import { runOnPool } from '../../cpu-pool.js';
47
+ import { gitSpawn } from '../../git-utils.js';
48
+ import {
49
+ calculateReport,
50
+ classifyReport,
51
+ } from '../../maintainability-engine.js';
52
+ import { transpileIfNeeded } from '../../maintainability-utils.js';
53
+ import {
54
+ hashCommandConfig,
55
+ recordPass,
56
+ shouldSkip,
57
+ } from '../../validation-evidence.js';
58
+
59
+ /** Worker entry that scores one file into a full maintainability report. */
60
+ const MAINTAINABILITY_REPORT_WORKER_URL = new URL(
61
+ '../../workers/maintainability-report-worker.js',
62
+ import.meta.url,
63
+ );
64
+
65
+ /**
66
+ * Below this JS-file count the worker pool's spawn overhead dominates, so
67
+ * `analyzeChangedFiles` scores in-process (the pre-pool serial path). At or
68
+ * above it, per-file `calculateReportForFile` scoring is offloaded to the
69
+ * shared worker pool so the event loop is not blocked during epic-scoped
70
+ * reviews (f-performance). Tuned to match the `SERIAL_THRESHOLD` used by the
71
+ * maintainability baseline scan in `maintainability-utils.js`.
72
+ */
73
+ export const SERIAL_THRESHOLD = 8;
74
+
75
+ const JS_MAINTAINABILITY_EXTS = new Set(['.js', '.mjs', '.cjs']);
76
+
77
+ /**
78
+ * Parse stdout/stderr from a lint runner to estimate error vs warning counts.
79
+ *
80
+ * Handles the two runners composing `npm run lint` in this project:
81
+ * - Biome: emits "Found N error(s)." and "Found N warning(s)." lines.
82
+ * - markdownlint: emits one diagnostic per issue, plus a trailing
83
+ * "Summary: N error(s)" line.
84
+ *
85
+ * Severity classification: when the runner exits non-zero but its output
86
+ * matches neither known reporter format, the result is "could not classify" —
87
+ * `executionFailed: true` so callers can degrade the gate to a suggestion +
88
+ * skipped marker rather than mislabelling an environment problem as high risk.
89
+ *
90
+ * Exported for testing.
91
+ *
92
+ * @param {{ status: number, stdout: string, stderr: string }} result
93
+ * @returns {{ errors: number, warnings: number, parsed: boolean, executionFailed: boolean }}
94
+ */
95
+ export function parseLintOutput(result) {
96
+ const combined = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
97
+
98
+ let errors = 0;
99
+ let warnings = 0;
100
+ let parsed = false;
101
+
102
+ const errMatches = combined.matchAll(/Found\s+(\d+)\s+error/gi);
103
+ for (const m of errMatches) {
104
+ errors += Number(m[1]);
105
+ parsed = true;
106
+ }
107
+ const warnMatches = combined.matchAll(/Found\s+(\d+)\s+warning/gi);
108
+ for (const m of warnMatches) {
109
+ warnings += Number(m[1]);
110
+ parsed = true;
111
+ }
112
+
113
+ const mdSummary = combined.match(/Summary:\s+(\d+)\s+error/i);
114
+ if (mdSummary) {
115
+ errors += Number(mdSummary[1]);
116
+ parsed = true;
117
+ }
118
+
119
+ const executionFailed = !parsed && result.status !== 0;
120
+
121
+ return { errors, warnings, parsed, executionFailed };
122
+ }
123
+
124
+ /**
125
+ * Pure: split changed paths into the file lists each lint runner consumes.
126
+ *
127
+ * Exported for testing.
128
+ *
129
+ * @param {string[]} changedFiles
130
+ * @returns {{ code: string[], md: string[] }}
131
+ */
132
+ export function partitionFilesForLint(changedFiles) {
133
+ const CODE = /\.(js|mjs|cjs|jsx|ts|tsx|json|jsonc)$/i;
134
+ const code = [];
135
+ const md = [];
136
+ for (const f of changedFiles) {
137
+ if (CODE.test(f)) code.push(f);
138
+ else if (/\.md$/i.test(f)) md.push(f);
139
+ }
140
+ return { code, md };
141
+ }
142
+
143
+ function resolveCurrentSha(cwd, gitSpawnFn = gitSpawn) {
144
+ const res = gitSpawnFn(cwd, 'rev-parse', 'HEAD');
145
+ if (res.status !== 0) return null;
146
+ const sha = (res.stdout || '').trim();
147
+ return sha.length > 0 ? sha : null;
148
+ }
149
+
150
+ /**
151
+ * Read a changed file's content as it exists at `headRef` via
152
+ * `git show <headRef>:<relPath>`, rather than reading the on-disk copy at
153
+ * `PROJECT_ROOT`.
154
+ *
155
+ * This is the fix for Story #3696: the native review previously scored the
156
+ * working-tree copy at `PROJECT_ROOT`, which — when the review runs from the
157
+ * main checkout (the common case for story/epic close) — is the **base**
158
+ * (pre-change) content, not the **head** (PR-branch) content the PR actually
159
+ * produces. Scoring the base copy made MI-*improving* refactors emit a
160
+ * false-positive "Size/Volume Warning" citing the very debt they removed.
161
+ * Sourcing from `headRef` makes the score reflect the PR branch regardless of
162
+ * which tree happens to be checked out on disk.
163
+ *
164
+ * Returns `null` when the file does not exist at `headRef` (deleted by the PR,
165
+ * a brand-new untracked path not yet committed, or a `git show` failure). A
166
+ * `null` source is dropped downstream exactly like a `reportFn` throw — the
167
+ * provider does not warn about a file it cannot read at head.
168
+ *
169
+ * @param {string} relPath Repo-relative path of the changed file.
170
+ * @param {string} headRef Git ref under review (e.g. 'story-3696', 'epic/42').
171
+ * @param {typeof gitSpawn} [gitSpawnFn] Injected git runner (test seam).
172
+ * @returns {string|null}
173
+ */
174
+ export function readHeadSource(relPath, headRef, gitSpawnFn = gitSpawn) {
175
+ const res = gitSpawnFn(PROJECT_ROOT, 'show', `${headRef}:${relPath}`);
176
+ if (res.status !== 0) return null;
177
+ return res.stdout ?? '';
178
+ }
179
+
180
+ /**
181
+ * Pure: score a raw source string into a maintainability report, applying the
182
+ * in-memory TS/TSX transpile shim first so a changed `.ts`/`.tsx` file scores
183
+ * the same as the JS the engine would otherwise see. Returns a parse-error
184
+ * report (never throws) when the source cannot be transpiled, matching the
185
+ * disk-based `calculateReportForFile` contract.
186
+ *
187
+ * Exported for testing.
188
+ *
189
+ * @param {string} source File content at head.
190
+ * @param {string} relPath Path (used only to pick the transpile mode).
191
+ * @returns {ReturnType<typeof calculateReport>}
192
+ */
193
+ export function scoreSourceReport(source, relPath) {
194
+ const prepared = transpileIfNeeded(relPath, source);
195
+ if (prepared === null) {
196
+ return {
197
+ moduleScore: 0,
198
+ methods: [],
199
+ worstMethod: null,
200
+ meanMethod: null,
201
+ parseError: true,
202
+ };
203
+ }
204
+ return calculateReport(prepared);
205
+ }
206
+
207
+ function spawnLintRunner(bin, args, cwd) {
208
+ const result = spawnSync('npx', ['--no', bin, ...args], {
209
+ cwd,
210
+ encoding: 'utf-8',
211
+ shell: process.platform === 'win32',
212
+ });
213
+ return {
214
+ status: result.status ?? 1,
215
+ stdout: result.stdout ?? '',
216
+ stderr: result.stderr ?? '',
217
+ };
218
+ }
219
+
220
+ /**
221
+ * Run lint scoped to the changed surface only. Returns a normalized summary
222
+ * compatible with `parseLintOutput` plus a `skipped` flag set when there is
223
+ * no JS or markdown file in the changed set (nothing to lint).
224
+ *
225
+ * @param {string[]} changedFiles
226
+ * @param {string} cwd
227
+ * @param {(bin: string, args: string[], cwd: string) => { status: number, stdout: string, stderr: string }} [runnerFn]
228
+ * @returns {{ errors: number, warnings: number, parsed: boolean, skipped: boolean, mode: 'changed-only', executionFailed?: boolean }}
229
+ */
230
+ export function runScopedLint(changedFiles, cwd, runnerFn = spawnLintRunner) {
231
+ const { code, md } = partitionFilesForLint(changedFiles);
232
+ if (code.length === 0 && md.length === 0) {
233
+ return {
234
+ errors: 0,
235
+ warnings: 0,
236
+ parsed: false,
237
+ skipped: true,
238
+ mode: 'changed-only',
239
+ };
240
+ }
241
+
242
+ const runs = [];
243
+ if (code.length > 0) runs.push(runnerFn('biome', ['lint', ...code], cwd));
244
+ if (md.length > 0) {
245
+ runs.push(
246
+ runnerFn('markdownlint', [...md, '--ignore', 'node_modules'], cwd),
247
+ );
248
+ }
249
+
250
+ let status = 0;
251
+ let stdout = '';
252
+ let stderr = '';
253
+ for (const r of runs) {
254
+ if ((r.status ?? 1) > status) status = r.status ?? 1;
255
+ stdout += r.stdout ?? '';
256
+ stderr += r.stderr ?? '';
257
+ }
258
+ const summary = parseLintOutput({ status, stdout, stderr });
259
+ return { ...summary, skipped: false, mode: 'changed-only' };
260
+ }
261
+
262
+ /**
263
+ * Compute the canonical command-config hash for the scoped-lint runner. The
264
+ * caller passes the partitioned biome + markdown lists so the hash captures
265
+ * the exact set of files; any change to that set invalidates the prior
266
+ * evidence and forces a re-lint.
267
+ *
268
+ * Exported for testing.
269
+ */
270
+ export function buildLintEvidenceConfig(changedFiles, cwd) {
271
+ const { code, md } = partitionFilesForLint(changedFiles);
272
+ const args = [];
273
+ if (code.length > 0) args.push('biome', 'lint', ...code);
274
+ if (md.length > 0) {
275
+ args.push('markdownlint', ...md, '--ignore', 'node_modules');
276
+ }
277
+ return hashCommandConfig({
278
+ cmd: 'epic-code-review/scoped-lint',
279
+ args,
280
+ cwd,
281
+ });
282
+ }
283
+
284
+ /**
285
+ * Pure: classify a single file's maintainability report into a row + optional
286
+ * Finding-shaped entries. `reportFn` is the thunk that produces the file's
287
+ * report (it closes over the file's head-ref source — see
288
+ * {@link analyzeChangedFiles}); a throw is treated as "drop this file".
289
+ *
290
+ * @returns {{ row: object|null, criticalFinding: Finding|null, mediumFinding: Finding|null }}
291
+ */
292
+ export function classifyChangedFile(relPath, { reportFn, classifier } = {}) {
293
+ let report;
294
+ try {
295
+ report = reportFn(relPath);
296
+ } catch (_err) {
297
+ return { row: null, criticalFinding: null, mediumFinding: null };
298
+ }
299
+ const tier = classifier(report);
300
+ const row = { file: relPath, report, tier };
301
+ if (tier === 'critical') {
302
+ const reason =
303
+ report.worstMethod !== null && report.worstMethod < 20
304
+ ? `worst method ${report.worstMethod.toFixed(1)}`
305
+ : `module score ${report.moduleScore.toFixed(1)}`;
306
+ return {
307
+ row,
308
+ criticalFinding: {
309
+ severity: 'critical',
310
+ title: 'Low Maintainability',
311
+ body:
312
+ `Module \`${relPath}\` reports a critical maintainability tier (${reason}).` +
313
+ '\n\nRefactor toward shorter methods and lower module size before merging.',
314
+ file: relPath,
315
+ category: 'maintainability',
316
+ },
317
+ mediumFinding: null,
318
+ };
319
+ }
320
+ if (tier === 'warning') {
321
+ const moduleScore = report.moduleScore.toFixed(1);
322
+ const worst =
323
+ report.worstMethod !== null
324
+ ? `, worst method ${report.worstMethod.toFixed(1)}`
325
+ : '';
326
+ return {
327
+ row,
328
+ criticalFinding: null,
329
+ mediumFinding: {
330
+ severity: 'medium',
331
+ title: 'Size/Volume Warning',
332
+ body:
333
+ `Module \`${relPath}\` reports a size/volume warning ` +
334
+ `(module ${moduleScore}${worst}).` +
335
+ '\n\nConsider breaking up the module or extracting helpers.',
336
+ file: relPath,
337
+ category: 'maintainability',
338
+ },
339
+ };
340
+ }
341
+ return { row, criticalFinding: null, mediumFinding: null };
342
+ }
343
+
344
+ /**
345
+ * Pure: fold one classified file into the running analysis tally. Shared by
346
+ * the serial and pooled scoring paths so both produce byte-for-byte identical
347
+ * `maintainability` rows and `critical`/`medium` findings.
348
+ *
349
+ * @param {{ totalFiles: number, jsFiles: number, maintainability: object[], criticalFindings: Finding[], mediumFindings: Finding[] }} results
350
+ * @param {{ row: object|null, criticalFinding: Finding|null, mediumFinding: Finding|null }} classified
351
+ */
352
+ function accumulateClassified(results, classified) {
353
+ const { row, criticalFinding, mediumFinding } = classified;
354
+ if (!row) return;
355
+ results.maintainability.push(row);
356
+ if (criticalFinding) results.criticalFindings.push(criticalFinding);
357
+ if (mediumFinding) results.mediumFindings.push(mediumFinding);
358
+ }
359
+
360
+ function isJsMaintainabilityFile(relPath) {
361
+ return JS_MAINTAINABILITY_EXTS.has(path.extname(relPath));
362
+ }
363
+
364
+ /**
365
+ * Walk every changed JS file and accumulate the analysis tally.
366
+ *
367
+ * For small JS-file sets (below {@link SERIAL_THRESHOLD}) scoring runs
368
+ * in-process — the worker pool's spawn overhead dominates at small sizes and
369
+ * the in-process path matches the pre-pool behaviour byte-for-byte. At or
370
+ * above the threshold, each file's `calculateReportForFile` call is offloaded
371
+ * to the shared worker pool (`maintainability-report-worker`) so the native
372
+ * provider no longer blocks the event loop during epic-scoped reviews
373
+ * (f-performance). Either way the pure classification core
374
+ * ({@link classifyChangedFile} + {@link classifyReport}) runs in-process, so
375
+ * the two paths emit identical rows and findings.
376
+ *
377
+ * **Head sourcing (Story #3696).** Each changed JS file is scored against the
378
+ * content it has at `headRef` — sourced via `git show <headRef>:<relPath>` —
379
+ * not the on-disk copy at `PROJECT_ROOT`. When the review runs from the main
380
+ * checkout (the common story/epic close case) the on-disk copy is the *base*
381
+ * (pre-change) content, so scoring it made MI-improving refactors emit a
382
+ * false-positive size/volume warning citing the debt they remove. Sourcing
383
+ * from head makes the score reflect the PR branch regardless of the checked-out
384
+ * tree. A file with no content at head (deleted by the PR, or unreadable) is
385
+ * dropped — the provider never warns about a file it cannot read at head.
386
+ *
387
+ * `classifier` is injected for testability. Tests may also inject `reportFn`
388
+ * to bypass head sourcing entirely (it receives the head source string and the
389
+ * relPath); production callers omit it and get the git-head scorer. Injecting
390
+ * `reportFn` forces the serial path (the injected scorer cannot cross the
391
+ * worker boundary).
392
+ *
393
+ * @param {string[]} changedFiles
394
+ * @param {{ reportFn?: Function, classifier?: Function, runOnPoolFn?: typeof runOnPool, headRef?: string|null, gitSpawnFn?: typeof gitSpawn, readHeadSourceFn?: typeof readHeadSource }} [deps]
395
+ * @returns {Promise<{ totalFiles: number, jsFiles: number, maintainability: object[], criticalFindings: Finding[], mediumFindings: Finding[] }>}
396
+ */
397
+ export async function analyzeChangedFiles(
398
+ changedFiles,
399
+ {
400
+ reportFn = null,
401
+ classifier = classifyReport,
402
+ runOnPoolFn = runOnPool,
403
+ headRef = null,
404
+ gitSpawnFn = gitSpawn,
405
+ readHeadSourceFn = readHeadSource,
406
+ } = {},
407
+ ) {
408
+ const results = {
409
+ totalFiles: changedFiles.length,
410
+ jsFiles: 0,
411
+ maintainability: [],
412
+ criticalFindings: [],
413
+ mediumFindings: [],
414
+ };
415
+
416
+ const jsFiles = changedFiles.filter(isJsMaintainabilityFile);
417
+ results.jsFiles = jsFiles.length;
418
+ if (jsFiles.length === 0) return results;
419
+
420
+ // Resolve each file's head-ref source up front. `null` source (deleted at
421
+ // head / unreadable) is dropped — it carries no head report to warn about.
422
+ const sources = jsFiles.map((relPath) =>
423
+ headRef == null ? '' : readHeadSourceFn(relPath, headRef, gitSpawnFn),
424
+ );
425
+
426
+ // Default scorer: score the head source string. A test-injected `reportFn`
427
+ // overrides it (receives the head source + relPath) and forces the serial
428
+ // path because the closure cannot be cloned into a worker thread.
429
+ const scoreReport =
430
+ reportFn ?? ((source, relPath) => scoreSourceReport(source, relPath));
431
+ const customReportFn = reportFn != null;
432
+
433
+ // Serial path: small batches, or whenever a caller injects its own scorer.
434
+ if (jsFiles.length < SERIAL_THRESHOLD || customReportFn) {
435
+ for (let i = 0; i < jsFiles.length; i += 1) {
436
+ const relPath = jsFiles[i];
437
+ const source = sources[i];
438
+ if (source == null) continue;
439
+ accumulateClassified(
440
+ results,
441
+ classifyChangedFile(relPath, {
442
+ reportFn: () => scoreReport(source, relPath),
443
+ classifier,
444
+ }),
445
+ );
446
+ }
447
+ return results;
448
+ }
449
+
450
+ // Pooled path: offload `scoreSourceReport` to the worker pool by sending the
451
+ // pre-sourced head content (not a disk path) so the worker scores the same
452
+ // head string the serial path does. Files with `null` head source are not
453
+ // sent to the pool; their slot is reconstructed by mapping pool results back
454
+ // onto the non-null subset in input order. The pure classification core runs
455
+ // in-process so both paths emit identical rows and findings.
456
+ const poolItems = [];
457
+ const poolIndex = []; // poolItems[k] corresponds to jsFiles[poolIndex[k]]
458
+ for (let i = 0; i < jsFiles.length; i += 1) {
459
+ if (sources[i] == null) continue;
460
+ poolItems.push({ source: sources[i], label: jsFiles[i] });
461
+ poolIndex.push(i);
462
+ }
463
+ if (poolItems.length === 0) return results;
464
+
465
+ const poolResults = await runOnPoolFn(
466
+ MAINTAINABILITY_REPORT_WORKER_URL,
467
+ poolItems,
468
+ );
469
+ for (let k = 0; k < poolIndex.length; k += 1) {
470
+ const relPath = jsFiles[poolIndex[k]];
471
+ const poolEntry = poolResults[k];
472
+ // A host-level pool error or a null report (the worker's parse/I/O
473
+ // sentinel) maps to the serial path's "reportFn threw" → dropped file.
474
+ if (!poolEntry || poolEntry.__cpuPoolError || poolEntry.report == null) {
475
+ continue;
476
+ }
477
+ accumulateClassified(
478
+ results,
479
+ classifyChangedFile(relPath, {
480
+ reportFn: () => poolEntry.report,
481
+ classifier,
482
+ }),
483
+ );
484
+ }
485
+ return results;
486
+ }
487
+
488
+ /**
489
+ * Pure: turn a lint summary into Finding(s). Lint errors collapse into a
490
+ * single high-risk finding (the structured comment shows the count); lint
491
+ * warnings collapse into a single suggestion. An `executionFailed` summary
492
+ * produces one suggestion finding describing the runner failure rather than
493
+ * a high-risk false positive.
494
+ *
495
+ * @param {{ errors: number, warnings: number, parsed?: boolean, skipped?: boolean, mode?: string, executionFailed?: boolean, evidenceSkipped?: boolean }} lintSummary
496
+ * @returns {Finding[]}
497
+ */
498
+ export function buildLintFindings(lintSummary) {
499
+ if (lintSummary.mode === 'off') return [];
500
+ if (lintSummary.evidenceSkipped) return [];
501
+ if (lintSummary.skipped) return [];
502
+ if (lintSummary.executionFailed) {
503
+ return [
504
+ {
505
+ severity: 'suggestion',
506
+ title: 'Lint runner could not execute',
507
+ body:
508
+ 'The scoped lint runner produced no parseable output (binary missing, ' +
509
+ 'parse failure, or environment issue). Verify with the canonical ' +
510
+ '`npm run lint` before merging — treating as a suggestion to avoid a ' +
511
+ 'false high-risk signal.',
512
+ category: 'lint',
513
+ },
514
+ ];
515
+ }
516
+ const findings = [];
517
+ if (lintSummary.errors > 0) {
518
+ findings.push({
519
+ severity: 'high',
520
+ title: `Lint check failed (${lintSummary.errors} error(s))`,
521
+ body:
522
+ `Scoped lint reported ${lintSummary.errors} error(s) and ` +
523
+ `${lintSummary.warnings} warning(s) on the changed surface. ` +
524
+ 'Fix errors before merging.',
525
+ category: 'lint',
526
+ });
527
+ } else if (lintSummary.warnings > 0) {
528
+ findings.push({
529
+ severity: 'suggestion',
530
+ title: `Lint check passed with ${lintSummary.warnings} warning(s)`,
531
+ body:
532
+ `Scoped lint reported ${lintSummary.warnings} warning(s) on the ` +
533
+ 'changed surface. Treat as suggestions.',
534
+ category: 'lint',
535
+ });
536
+ }
537
+ return findings;
538
+ }
539
+
540
+ function _emptyResults() {
541
+ return {
542
+ totalFiles: 0,
543
+ jsFiles: 0,
544
+ maintainability: [],
545
+ criticalFindings: [],
546
+ mediumFindings: [],
547
+ };
548
+ }
549
+
550
+ function tryEvidenceSkip({
551
+ storyId,
552
+ epicId,
553
+ useEvidence,
554
+ headSha,
555
+ evidenceCfg,
556
+ shouldSkipFn,
557
+ logger,
558
+ }) {
559
+ if (!(useEvidence && storyId && epicId && headSha)) return null;
560
+ const verdict = shouldSkipFn(
561
+ {
562
+ storyId,
563
+ gateName: 'epic-code-review/lint',
564
+ currentSha: headSha,
565
+ configHash: evidenceCfg,
566
+ },
567
+ { cwd: PROJECT_ROOT, epicId },
568
+ );
569
+ if (!verdict.skip) return null;
570
+ logger?.info?.(
571
+ `[native-review] Scoped lint skipped (evidence match: SHA=${headSha.slice(
572
+ 0,
573
+ 7,
574
+ )}, recorded ${verdict.record?.timestamp ?? 'n/a'}).`,
575
+ );
576
+ return {
577
+ errors: 0,
578
+ warnings: 0,
579
+ parsed: false,
580
+ skipped: true,
581
+ mode: 'changed-only',
582
+ evidenceSkipped: true,
583
+ };
584
+ }
585
+
586
+ function maybeRecordLintEvidence({
587
+ storyId,
588
+ epicId,
589
+ useEvidence,
590
+ headSha,
591
+ evidenceCfg,
592
+ lintSummary,
593
+ recordPassFn,
594
+ logger,
595
+ }) {
596
+ const eligible =
597
+ useEvidence &&
598
+ storyId &&
599
+ epicId &&
600
+ headSha &&
601
+ lintSummary.errors === 0 &&
602
+ !lintSummary.skipped;
603
+ if (!eligible) return;
604
+ try {
605
+ recordPassFn(
606
+ {
607
+ storyId,
608
+ gateName: 'epic-code-review/lint',
609
+ sha: headSha,
610
+ configHash: evidenceCfg,
611
+ exitCode: 0,
612
+ },
613
+ { cwd: PROJECT_ROOT, epicId },
614
+ );
615
+ } catch (err) {
616
+ logger?.warn?.(
617
+ `[native-review] Failed to record lint evidence: ${err?.message ?? err}`,
618
+ );
619
+ }
620
+ }
621
+
622
+ async function runLintPhase({
623
+ scopeLint,
624
+ changedFiles,
625
+ storyId,
626
+ epicId,
627
+ useEvidence,
628
+ gitSpawnFn,
629
+ shouldSkipFn,
630
+ recordPassFn,
631
+ runScopedLintFn,
632
+ logger,
633
+ }) {
634
+ if (scopeLint === 'off') {
635
+ logger?.info?.(
636
+ '[native-review] Lint scoped off (scopeLint=off); skipping.',
637
+ );
638
+ return {
639
+ errors: 0,
640
+ warnings: 0,
641
+ parsed: false,
642
+ skipped: true,
643
+ mode: 'off',
644
+ };
645
+ }
646
+ const evidenceCfg = buildLintEvidenceConfig(changedFiles, PROJECT_ROOT);
647
+ const headSha = resolveCurrentSha(PROJECT_ROOT, gitSpawnFn);
648
+ const skipSummary = tryEvidenceSkip({
649
+ storyId,
650
+ epicId,
651
+ useEvidence,
652
+ headSha,
653
+ evidenceCfg,
654
+ shouldSkipFn,
655
+ logger,
656
+ });
657
+ if (skipSummary) return skipSummary;
658
+
659
+ logger?.info?.(
660
+ '[native-review] Linting changed files only (biome + markdownlint, scoped to diff)...',
661
+ );
662
+ const lintSummary = runScopedLintFn(changedFiles, PROJECT_ROOT);
663
+ maybeRecordLintEvidence({
664
+ storyId,
665
+ epicId,
666
+ useEvidence,
667
+ headSha,
668
+ evidenceCfg,
669
+ lintSummary,
670
+ recordPassFn,
671
+ logger,
672
+ });
673
+ return lintSummary;
674
+ }
675
+
676
+ /**
677
+ * Build a `ReviewProvider` instance backed by the native in-process pipeline.
678
+ *
679
+ * The `deps` overload is the test seam — production callers (the factory)
680
+ * invoke `createNativeProvider()` with no arguments and get the default
681
+ * dependency chain (real git, real lint, real maintainability engine).
682
+ *
683
+ * @param {{
684
+ * gitSpawnFn?: typeof gitSpawn,
685
+ * runScopedLintFn?: typeof runScopedLint,
686
+ * analyzeChangedFilesFn?: typeof analyzeChangedFiles,
687
+ * buildLintFindingsFn?: typeof buildLintFindings,
688
+ * shouldSkipFn?: typeof shouldSkip,
689
+ * recordPassFn?: typeof recordPass,
690
+ * logger?: { info?: Function, warn?: Function, error?: Function },
691
+ * scopeLint?: 'changed-only'|'off',
692
+ * storyId?: number|null,
693
+ * useEvidence?: boolean,
694
+ * }} [deps]
695
+ * @returns {ReviewProvider}
696
+ */
697
+ export function createNativeProvider(deps = {}) {
698
+ const {
699
+ gitSpawnFn = gitSpawn,
700
+ runScopedLintFn = runScopedLint,
701
+ analyzeChangedFilesFn = analyzeChangedFiles,
702
+ buildLintFindingsFn = buildLintFindings,
703
+ shouldSkipFn = shouldSkip,
704
+ recordPassFn = recordPass,
705
+ logger,
706
+ scopeLint = 'changed-only',
707
+ storyId = null,
708
+ useEvidence = true,
709
+ } = deps;
710
+
711
+ return {
712
+ /**
713
+ * @param {ReviewInput} input
714
+ * @returns {Promise<Finding[]>}
715
+ */
716
+ async runReview(input) {
717
+ const { scope, ticketId, baseRef, headRef } = input ?? {};
718
+ if (!baseRef || !headRef) {
719
+ throw new TypeError(
720
+ '[native-review] runReview requires baseRef and headRef.',
721
+ );
722
+ }
723
+ if (!Number.isInteger(ticketId) || ticketId <= 0) {
724
+ throw new TypeError(
725
+ '[native-review] runReview requires a positive integer ticketId.',
726
+ );
727
+ }
728
+
729
+ logger?.info?.(
730
+ `[native-review] Comparing ${headRef} against ${baseRef} for ${scope} #${ticketId}...`,
731
+ );
732
+
733
+ const diffResult = gitSpawnFn(
734
+ PROJECT_ROOT,
735
+ 'diff',
736
+ `${baseRef}...${headRef}`,
737
+ '--name-only',
738
+ );
739
+ if (diffResult.status !== 0) {
740
+ throw new Error(
741
+ `[native-review] Failed to get diff ${baseRef}...${headRef}: ${diffResult.stderr}`,
742
+ );
743
+ }
744
+
745
+ const changedFiles = diffResult.stdout
746
+ .trim()
747
+ .split('\n')
748
+ .filter((f) => f.length > 0);
749
+
750
+ if (changedFiles.length === 0) {
751
+ logger?.info?.('[native-review] No changes detected.');
752
+ return [];
753
+ }
754
+
755
+ logger?.info?.(
756
+ `[native-review] Analyzing ${changedFiles.length} changed file(s)...`,
757
+ );
758
+ const results = await analyzeChangedFilesFn(changedFiles, {
759
+ headRef,
760
+ gitSpawnFn,
761
+ });
762
+
763
+ // Epic-scope reviews flow through validation-evidence; story-scope
764
+ // reviews currently share the same gate name, keyed on the storyId.
765
+ const epicId = scope === 'epic' ? ticketId : null;
766
+ const lintSummary = await runLintPhase({
767
+ scopeLint,
768
+ changedFiles,
769
+ storyId: storyId ?? (scope === 'story' ? ticketId : null),
770
+ epicId,
771
+ useEvidence,
772
+ gitSpawnFn,
773
+ shouldSkipFn,
774
+ recordPassFn,
775
+ runScopedLintFn,
776
+ logger,
777
+ });
778
+
779
+ const lintFindings = buildLintFindingsFn(lintSummary);
780
+
781
+ // Canonical ordering: critical (maintainability) first, then high
782
+ // (lint errors), then medium (size/volume warnings), then suggestion
783
+ // (lint warnings / executionFailed). The renderer re-bucketizes by
784
+ // severity tier, so this order only matters for stability of fixture
785
+ // outputs.
786
+ return [
787
+ ...results.criticalFindings,
788
+ ...lintFindings.filter((f) => f.severity === 'high'),
789
+ ...results.mediumFindings,
790
+ ...lintFindings.filter((f) => f.severity === 'suggestion'),
791
+ ];
792
+ },
793
+ };
794
+ }
795
+
796
+ /**
797
+ * Zero-arg factory entry point used by the `review-provider-factory`. Kept
798
+ * separate from `createNativeProvider({ deps })` so the registry signature
799
+ * stays `() => ReviewProvider`.
800
+ *
801
+ * @returns {ReviewProvider}
802
+ */
803
+ export function createNativeProviderForRegistry() {
804
+ return createNativeProvider();
805
+ }