session-orchestrator 3.16.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 (762) hide show
  1. package/.claude-plugin/marketplace.json +29 -0
  2. package/.claude-plugin/plugin.json +18 -0
  3. package/.codex-plugin/agents/explorer.toml +14 -0
  4. package/.codex-plugin/agents/session-reviewer.toml +23 -0
  5. package/.codex-plugin/agents/wave-worker.toml +15 -0
  6. package/.codex-plugin/config.toml +20 -0
  7. package/.codex-plugin/plugin.json +37 -0
  8. package/.cursor/rules/000-session-orchestrator.mdc +73 -0
  9. package/.cursor/rules/010-session-workflow.mdc +170 -0
  10. package/.cursor/rules/020-quality-gates.mdc +128 -0
  11. package/.cursor/rules/030-wave-execution.mdc +216 -0
  12. package/.cursor/rules/040-discovery.mdc +242 -0
  13. package/.cursor/rules/050-plan.mdc +235 -0
  14. package/.cursor/rules/060-evolve.mdc +232 -0
  15. package/.cursor/rules/070-gitlab-ops.mdc +246 -0
  16. package/.cursor/rules/080-ecosystem-health.mdc +145 -0
  17. package/.mcp.json +8 -0
  18. package/CHANGELOG.md +1544 -0
  19. package/LICENSE +21 -0
  20. package/NOTICE +64 -0
  21. package/README.md +242 -0
  22. package/SECURITY.md +90 -0
  23. package/agents/AGENTS.md +136 -0
  24. package/agents/analyst.md +99 -0
  25. package/agents/architect-reviewer.md +93 -0
  26. package/agents/code-implementer.md +106 -0
  27. package/agents/db-specialist.md +104 -0
  28. package/agents/dialectic-deriver.md +139 -0
  29. package/agents/docs-writer.md +113 -0
  30. package/agents/eval-judge.md +146 -0
  31. package/agents/memory-proposal-collector.md +297 -0
  32. package/agents/qa-strategist.md +102 -0
  33. package/agents/schemas/analyst.schema.json +46 -0
  34. package/agents/schemas/architect-reviewer.schema.json +50 -0
  35. package/agents/schemas/code-implementer.schema.json +61 -0
  36. package/agents/schemas/db-specialist.schema.json +80 -0
  37. package/agents/schemas/docs-writer.schema.json +56 -0
  38. package/agents/schemas/persona-panel-sidecar.schema.json +245 -0
  39. package/agents/schemas/qa-strategist.schema.json +46 -0
  40. package/agents/schemas/security-reviewer.schema.json +86 -0
  41. package/agents/schemas/session-reviewer.schema.json +69 -0
  42. package/agents/schemas/test-writer.schema.json +69 -0
  43. package/agents/schemas/ui-developer.schema.json +90 -0
  44. package/agents/schemas/ux-evaluator.schema.json +51 -0
  45. package/agents/security-reviewer.md +236 -0
  46. package/agents/session-reviewer.md +201 -0
  47. package/agents/skill-applied-judge.md +122 -0
  48. package/agents/test-writer.md +123 -0
  49. package/agents/ui-developer.md +109 -0
  50. package/agents/ux-evaluator.md +161 -0
  51. package/assets/icon.svg +11 -0
  52. package/assets/og-card.png +0 -0
  53. package/assets/og-card.svg +47 -0
  54. package/commands/autopilot-multi.md +74 -0
  55. package/commands/autopilot.md +80 -0
  56. package/commands/bootstrap.md +56 -0
  57. package/commands/brainstorm.md +48 -0
  58. package/commands/close.md +24 -0
  59. package/commands/debug.md +36 -0
  60. package/commands/discovery.md +32 -0
  61. package/commands/dispatcher.md +59 -0
  62. package/commands/eval.md +28 -0
  63. package/commands/evolve.md +10 -0
  64. package/commands/go.md +41 -0
  65. package/commands/grill.md +45 -0
  66. package/commands/harness-audit.md +26 -0
  67. package/commands/memory-cleanup.md +25 -0
  68. package/commands/persona-panel.md +121 -0
  69. package/commands/plan.md +15 -0
  70. package/commands/portfolio.md +97 -0
  71. package/commands/reconcile.md +23 -0
  72. package/commands/repo-audit.md +24 -0
  73. package/commands/session.md +30 -0
  74. package/commands/spinout.md +15 -0
  75. package/commands/sunset-review.md +27 -0
  76. package/commands/templates-ack.md +96 -0
  77. package/commands/test.md +97 -0
  78. package/docs/README.md +105 -0
  79. package/docs/USER-GUIDE.md +1403 -0
  80. package/docs/ci-setup.md +81 -0
  81. package/docs/codex-setup.md +142 -0
  82. package/docs/components.md +74 -0
  83. package/docs/cursor-setup.md +104 -0
  84. package/docs/events-schema.md +81 -0
  85. package/docs/migration-v3.md +148 -0
  86. package/docs/owner-config-schema.md +154 -0
  87. package/docs/persona-panel.md +433 -0
  88. package/docs/pi-setup.md +115 -0
  89. package/docs/plugin-architecture-v3.md +296 -0
  90. package/docs/pm-skills-marketplace.md +114 -0
  91. package/docs/policy-cache-validation-2026-04-28.md +118 -0
  92. package/docs/rule-authoring.md +316 -0
  93. package/docs/session-config-reference.md +1439 -0
  94. package/docs/session-config-template.md +961 -0
  95. package/docs/vault-docs-architecture.md +297 -0
  96. package/hooks/_lib/lock-bootstrap.mjs +272 -0
  97. package/hooks/_lib/lock-reconcile.mjs +93 -0
  98. package/hooks/_lib/profile-gate.mjs +95 -0
  99. package/hooks/_lib/transcript-history.mjs +211 -0
  100. package/hooks/agent-teams-h3-test.sh +362 -0
  101. package/hooks/config-protection.mjs +0 -0
  102. package/hooks/cwd-change-restore.mjs +131 -0
  103. package/hooks/enforce-commands.mjs +179 -0
  104. package/hooks/enforce-scope.mjs +273 -0
  105. package/hooks/hooks-codex.json +60 -0
  106. package/hooks/hooks-cursor.json +15 -0
  107. package/hooks/hooks-pi.json +115 -0
  108. package/hooks/hooks.json +215 -0
  109. package/hooks/loop-guard.mjs +260 -0
  110. package/hooks/on-session-end.mjs +217 -0
  111. package/hooks/on-session-start.mjs +660 -0
  112. package/hooks/on-stop.mjs +294 -0
  113. package/hooks/operator-steer.mjs +64 -0
  114. package/hooks/post-edit-validate.mjs +225 -0
  115. package/hooks/post-subagent-discovery-validator.mjs +398 -0
  116. package/hooks/post-tool-batch-wave-signal.mjs +328 -0
  117. package/hooks/post-tool-failure-corrective-context.mjs +248 -0
  118. package/hooks/post-tooluse-frontend-slop.mjs +184 -0
  119. package/hooks/pre-bash-destructive-guard.mjs +515 -0
  120. package/hooks/pre-bash-memory-propose-audit.mjs +206 -0
  121. package/hooks/pre-bash-staging-fence.mjs +223 -0
  122. package/hooks/pre-bash-templates-first.mjs +404 -0
  123. package/hooks/run-node.sh +72 -0
  124. package/hooks/skill-invocation-telemetry.mjs +99 -0
  125. package/hooks/subagent-telemetry.mjs +249 -0
  126. package/hooks/wave-scope-commit-guard.mjs +191 -0
  127. package/monitors/monitors.json +14 -0
  128. package/output-styles/finding-report.md +48 -0
  129. package/output-styles/session-report.md +53 -0
  130. package/output-styles/wave-summary.md +38 -0
  131. package/package.json +94 -0
  132. package/pi/extensions/session-orchestrator.ts +25 -0
  133. package/pi/prompts/autopilot-multi.md +12 -0
  134. package/pi/prompts/autopilot.md +12 -0
  135. package/pi/prompts/bootstrap.md +12 -0
  136. package/pi/prompts/brainstorm.md +12 -0
  137. package/pi/prompts/close.md +11 -0
  138. package/pi/prompts/debug.md +12 -0
  139. package/pi/prompts/discovery.md +12 -0
  140. package/pi/prompts/dispatcher.md +12 -0
  141. package/pi/prompts/eval.md +12 -0
  142. package/pi/prompts/evolve.md +12 -0
  143. package/pi/prompts/go.md +12 -0
  144. package/pi/prompts/grill.md +12 -0
  145. package/pi/prompts/harness-audit.md +12 -0
  146. package/pi/prompts/memory-cleanup.md +12 -0
  147. package/pi/prompts/persona-panel.md +12 -0
  148. package/pi/prompts/plan.md +12 -0
  149. package/pi/prompts/portfolio.md +12 -0
  150. package/pi/prompts/reconcile.md +12 -0
  151. package/pi/prompts/repo-audit.md +12 -0
  152. package/pi/prompts/session.md +12 -0
  153. package/pi/prompts/spinout.md +12 -0
  154. package/pi/prompts/sunset-review.md +12 -0
  155. package/pi/prompts/templates-ack.md +12 -0
  156. package/pi/prompts/test.md +12 -0
  157. package/rules/_index.md +51 -0
  158. package/rules/always-on/commit-discipline.md +26 -0
  159. package/rules/always-on/npm-quality-gates.md +26 -0
  160. package/rules/always-on/parallel-sessions.md +43 -0
  161. package/rules/opt-in-domain/prompt-caching.md +270 -0
  162. package/rules/opt-in-stack/backend-data.md +188 -0
  163. package/rules/opt-in-stack/backend.md +390 -0
  164. package/rules/opt-in-stack/frontend.md +98 -0
  165. package/rules/opt-in-stack/security-web.md +194 -0
  166. package/rules/opt-in-stack/swift.md +65 -0
  167. package/scripts/archive-closed-prds.mjs +416 -0
  168. package/scripts/autopilot-multi.mjs +802 -0
  169. package/scripts/autopilot.mjs +383 -0
  170. package/scripts/backfill-abandoned-sessions.mjs +265 -0
  171. package/scripts/backfill-learnings-expires.mjs +196 -0
  172. package/scripts/backfill-learnings.mjs +203 -0
  173. package/scripts/backfill-sessions.mjs +282 -0
  174. package/scripts/check-doc-consistency.sh +279 -0
  175. package/scripts/check-package-manager.mjs +445 -0
  176. package/scripts/ci/assert-vitest-green.mjs +267 -0
  177. package/scripts/codex-install.mjs +435 -0
  178. package/scripts/compute-grounding-injection.sh +186 -0
  179. package/scripts/cursor-install.mjs +113 -0
  180. package/scripts/dialectic-deriver.mjs +573 -0
  181. package/scripts/emit-event.mjs +160 -0
  182. package/scripts/emit-session.mjs +212 -0
  183. package/scripts/eval-session.mjs +262 -0
  184. package/scripts/export-hw-learnings.mjs +437 -0
  185. package/scripts/gc-stale-worktrees.mjs +666 -0
  186. package/scripts/generate-pi-prompts.mjs +127 -0
  187. package/scripts/harness-audit.mjs +287 -0
  188. package/scripts/lib/agent-frontmatter.mjs +266 -0
  189. package/scripts/lib/agent-output-schema.mjs +166 -0
  190. package/scripts/lib/agent-status.mjs +303 -0
  191. package/scripts/lib/ajv-loader.mjs +34 -0
  192. package/scripts/lib/auto-dialectic.mjs +382 -0
  193. package/scripts/lib/auto-dream.mjs +471 -0
  194. package/scripts/lib/autonomy/suitability.mjs +212 -0
  195. package/scripts/lib/autopilot/dep-graph.mjs +417 -0
  196. package/scripts/lib/autopilot/durable-telemetry.mjs +121 -0
  197. package/scripts/lib/autopilot/flags.mjs +104 -0
  198. package/scripts/lib/autopilot/kill-switches.mjs +174 -0
  199. package/scripts/lib/autopilot/loop.mjs +320 -0
  200. package/scripts/lib/autopilot/mr-draft.mjs +520 -0
  201. package/scripts/lib/autopilot/multi-killswitch.mjs +184 -0
  202. package/scripts/lib/autopilot/recent-runs.mjs +106 -0
  203. package/scripts/lib/autopilot/stall-sampler.mjs +97 -0
  204. package/scripts/lib/autopilot/telemetry.mjs +224 -0
  205. package/scripts/lib/autopilot/worktree-pipeline.mjs +605 -0
  206. package/scripts/lib/autopilot-telemetry.mjs +11 -0
  207. package/scripts/lib/autopilot.mjs +39 -0
  208. package/scripts/lib/backlog-scan.mjs +179 -0
  209. package/scripts/lib/bootstrap-lock-freshness.mjs +260 -0
  210. package/scripts/lib/bootstrap-lock-refresh.mjs +186 -0
  211. package/scripts/lib/build-live-signals.mjs +150 -0
  212. package/scripts/lib/ci-status-banner.mjs +425 -0
  213. package/scripts/lib/claude-md-budget-lint.mjs +246 -0
  214. package/scripts/lib/cli-flags.mjs +158 -0
  215. package/scripts/lib/codex/plugin-contract.mjs +610 -0
  216. package/scripts/lib/cold-start-detector.mjs +240 -0
  217. package/scripts/lib/command-blocker.mjs +458 -0
  218. package/scripts/lib/common.mjs +333 -0
  219. package/scripts/lib/config/auto-dream.mjs +77 -0
  220. package/scripts/lib/config/block-header.mjs +94 -0
  221. package/scripts/lib/config/broken-window.mjs +114 -0
  222. package/scripts/lib/config/coercers.mjs +248 -0
  223. package/scripts/lib/config/cold-start.mjs +92 -0
  224. package/scripts/lib/config/config-protection.mjs +120 -0
  225. package/scripts/lib/config/cross-repo.mjs +104 -0
  226. package/scripts/lib/config/custom-phases.mjs +213 -0
  227. package/scripts/lib/config/dialectic.mjs +92 -0
  228. package/scripts/lib/config/discovery-validator.mjs +75 -0
  229. package/scripts/lib/config/dispatcher-autonomy-capture.mjs +240 -0
  230. package/scripts/lib/config/dispatcher-autonomy.mjs +152 -0
  231. package/scripts/lib/config/docs-orchestrator.mjs +90 -0
  232. package/scripts/lib/config/docs-staleness.mjs +96 -0
  233. package/scripts/lib/config/drift-check.mjs +155 -0
  234. package/scripts/lib/config/eval.mjs +130 -0
  235. package/scripts/lib/config/events-rotation.mjs +74 -0
  236. package/scripts/lib/config/evolve.mjs +308 -0
  237. package/scripts/lib/config/frontend-slop-hook.mjs +104 -0
  238. package/scripts/lib/config/gitlab-portfolio.mjs +150 -0
  239. package/scripts/lib/config/handover-gate.mjs +106 -0
  240. package/scripts/lib/config/host-paths.mjs +76 -0
  241. package/scripts/lib/config/io.mjs +54 -0
  242. package/scripts/lib/config/loop-guard.mjs +117 -0
  243. package/scripts/lib/config/memory.mjs +150 -0
  244. package/scripts/lib/config/persona-gate-wave.mjs +258 -0
  245. package/scripts/lib/config/reconcile.mjs +205 -0
  246. package/scripts/lib/config/section-extractor.mjs +100 -0
  247. package/scripts/lib/config/skill-evolution.mjs +112 -0
  248. package/scripts/lib/config/slopcheck.mjs +99 -0
  249. package/scripts/lib/config/state-md-lock.mjs +83 -0
  250. package/scripts/lib/config/templates-first.mjs +94 -0
  251. package/scripts/lib/config/test.mjs +113 -0
  252. package/scripts/lib/config/vault-integration.mjs +201 -0
  253. package/scripts/lib/config/vault-mirror-quality.mjs +99 -0
  254. package/scripts/lib/config/vault-staleness.mjs +84 -0
  255. package/scripts/lib/config/vault-sync.mjs +96 -0
  256. package/scripts/lib/config/verification-auto-fix.mjs +84 -0
  257. package/scripts/lib/config/wave-reviewers.mjs +133 -0
  258. package/scripts/lib/config-schema.mjs +345 -0
  259. package/scripts/lib/config.mjs +474 -0
  260. package/scripts/lib/convergence-monitor.mjs +389 -0
  261. package/scripts/lib/coordinator-snapshot.mjs +371 -0
  262. package/scripts/lib/crypto-digest-utils.mjs +91 -0
  263. package/scripts/lib/discovery/helpers.mjs +127 -0
  264. package/scripts/lib/discovery/triage-state.mjs +279 -0
  265. package/scripts/lib/dispatcher/cli.mjs +257 -0
  266. package/scripts/lib/dispatcher/enumerate.mjs +243 -0
  267. package/scripts/lib/dispatcher/rank.mjs +363 -0
  268. package/scripts/lib/ecosystem-health.mjs +224 -0
  269. package/scripts/lib/ecosystem-wizard/ci-detector.mjs +18 -0
  270. package/scripts/lib/ecosystem-wizard/config-parser.mjs +54 -0
  271. package/scripts/lib/ecosystem-wizard/config-writer.mjs +287 -0
  272. package/scripts/lib/ecosystem-wizard/package-manager-detector.mjs +42 -0
  273. package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +246 -0
  274. package/scripts/lib/ecosystem-wizard.mjs +48 -0
  275. package/scripts/lib/env-check.mjs +89 -0
  276. package/scripts/lib/eval/engine.mjs +605 -0
  277. package/scripts/lib/eval/judge.mjs +433 -0
  278. package/scripts/lib/eval/report.mjs +367 -0
  279. package/scripts/lib/eval/schema.mjs +618 -0
  280. package/scripts/lib/eval/session-resolve.mjs +137 -0
  281. package/scripts/lib/eval/sink.mjs +77 -0
  282. package/scripts/lib/events-rotation.mjs +86 -0
  283. package/scripts/lib/events-schema.mjs +81 -0
  284. package/scripts/lib/events.mjs +80 -0
  285. package/scripts/lib/evolve/autonomy-verdict.mjs +461 -0
  286. package/scripts/lib/evolve/autopilot-effectiveness.mjs +293 -0
  287. package/scripts/lib/exclusivity-matrix.mjs +68 -0
  288. package/scripts/lib/fetch-baseline.mjs +311 -0
  289. package/scripts/lib/file-lock.mjs +512 -0
  290. package/scripts/lib/frontend-detect/detect.mjs +138 -0
  291. package/scripts/lib/frontend-detect/rules.mjs +295 -0
  292. package/scripts/lib/frontmatter-guard.mjs +241 -0
  293. package/scripts/lib/gates/echo-stub-detect.mjs +39 -0
  294. package/scripts/lib/gates/gate-baseline.mjs +42 -0
  295. package/scripts/lib/gates/gate-full.mjs +85 -0
  296. package/scripts/lib/gates/gate-helpers.mjs +231 -0
  297. package/scripts/lib/gates/gate-incremental.mjs +76 -0
  298. package/scripts/lib/gates/gate-per-file.mjs +55 -0
  299. package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +447 -0
  300. package/scripts/lib/gitlab-portfolio/aggregator.mjs +383 -0
  301. package/scripts/lib/gitlab-portfolio/cli.mjs +428 -0
  302. package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +289 -0
  303. package/scripts/lib/gitlab-portfolio/vcs-detect.mjs +182 -0
  304. package/scripts/lib/handover-gate.mjs +222 -0
  305. package/scripts/lib/hardening.mjs +43 -0
  306. package/scripts/lib/hardware-pattern-detector.mjs +238 -0
  307. package/scripts/lib/harness-audit/categories/category1.mjs +123 -0
  308. package/scripts/lib/harness-audit/categories/category2.mjs +145 -0
  309. package/scripts/lib/harness-audit/categories/category3.mjs +143 -0
  310. package/scripts/lib/harness-audit/categories/category4.mjs +202 -0
  311. package/scripts/lib/harness-audit/categories/category5.mjs +152 -0
  312. package/scripts/lib/harness-audit/categories/category6.mjs +211 -0
  313. package/scripts/lib/harness-audit/categories/category7.mjs +125 -0
  314. package/scripts/lib/harness-audit/categories/category8.mjs +328 -0
  315. package/scripts/lib/harness-audit/categories/category9.mjs +294 -0
  316. package/scripts/lib/harness-audit/categories/helpers.mjs +165 -0
  317. package/scripts/lib/harness-audit/categories.mjs +19 -0
  318. package/scripts/lib/historical-guard.mjs +15 -0
  319. package/scripts/lib/host-identity.mjs +262 -0
  320. package/scripts/lib/instruction-budget-guard.mjs +332 -0
  321. package/scripts/lib/io.mjs +304 -0
  322. package/scripts/lib/issue-close-strip-labels.mjs +161 -0
  323. package/scripts/lib/language-mappers/README.md +57 -0
  324. package/scripts/lib/language-mappers/index.mjs +165 -0
  325. package/scripts/lib/language-mappers/markdown.mjs +149 -0
  326. package/scripts/lib/language-mappers/python.mjs +249 -0
  327. package/scripts/lib/language-mappers/swift.mjs +201 -0
  328. package/scripts/lib/language-mappers/typescript.mjs +433 -0
  329. package/scripts/lib/learnings/expiry-sweep.mjs +164 -0
  330. package/scripts/lib/learnings/filters.mjs +43 -0
  331. package/scripts/lib/learnings/io.mjs +255 -0
  332. package/scripts/lib/learnings/schema.mjs +518 -0
  333. package/scripts/lib/learnings/surface.mjs +207 -0
  334. package/scripts/lib/learnings.mjs +42 -0
  335. package/scripts/lib/lock-reaper.mjs +648 -0
  336. package/scripts/lib/locks/index.mjs +31 -0
  337. package/scripts/lib/locks/lock-body.mjs +62 -0
  338. package/scripts/lib/locks/staging-fence-lock.mjs +267 -0
  339. package/scripts/lib/locks/state-md-lock.mjs +351 -0
  340. package/scripts/lib/loop-readiness-banner.mjs +144 -0
  341. package/scripts/lib/memory-banner.mjs +478 -0
  342. package/scripts/lib/memory-cleanup/worktree-sweep.mjs +108 -0
  343. package/scripts/lib/memory-cleanup-stamp.mjs +56 -0
  344. package/scripts/lib/memory-paths.mjs +31 -0
  345. package/scripts/lib/memory-proposals/collector.mjs +334 -0
  346. package/scripts/lib/memory-proposals/schema.mjs +289 -0
  347. package/scripts/lib/memory-proposals/sink.mjs +507 -0
  348. package/scripts/lib/memory-proposals/store.mjs +441 -0
  349. package/scripts/lib/mission-status-schema.mjs +114 -0
  350. package/scripts/lib/mode-selector/alternatives.mjs +64 -0
  351. package/scripts/lib/mode-selector/constants.mjs +29 -0
  352. package/scripts/lib/mode-selector/context-pressure.mjs +157 -0
  353. package/scripts/lib/mode-selector/rationale.mjs +55 -0
  354. package/scripts/lib/mode-selector/scoring.mjs +221 -0
  355. package/scripts/lib/mode-selector-accuracy.mjs +121 -0
  356. package/scripts/lib/mode-selector.mjs +160 -0
  357. package/scripts/lib/multi-provider-build/providers.mjs +64 -0
  358. package/scripts/lib/multi-provider-build/templating.mjs +130 -0
  359. package/scripts/lib/named-baseline-resolver.mjs +233 -0
  360. package/scripts/lib/named-vault-resolver.mjs +433 -0
  361. package/scripts/lib/owner-config/coerce.mjs +29 -0
  362. package/scripts/lib/owner-config/constants.mjs +21 -0
  363. package/scripts/lib/owner-config/defaults.mjs +50 -0
  364. package/scripts/lib/owner-config/error.mjs +19 -0
  365. package/scripts/lib/owner-config/index.mjs +13 -0
  366. package/scripts/lib/owner-config/merge.mjs +52 -0
  367. package/scripts/lib/owner-config/validate.mjs +259 -0
  368. package/scripts/lib/owner-config-banner.mjs +126 -0
  369. package/scripts/lib/owner-config-loader.mjs +159 -0
  370. package/scripts/lib/owner-config.example.yaml +72 -0
  371. package/scripts/lib/owner-config.mjs +28 -0
  372. package/scripts/lib/owner-interview.mjs +243 -0
  373. package/scripts/lib/owner-yaml.mjs +571 -0
  374. package/scripts/lib/package-manager.mjs +160 -0
  375. package/scripts/lib/path-utils.mjs +217 -0
  376. package/scripts/lib/peer-cards/merger.mjs +310 -0
  377. package/scripts/lib/peer-cards/reader.mjs +125 -0
  378. package/scripts/lib/peer-cards/schema.mjs +230 -0
  379. package/scripts/lib/peer-cards/staleness-banner.mjs +86 -0
  380. package/scripts/lib/peer-cards/writer.mjs +138 -0
  381. package/scripts/lib/peer-discovery.mjs +200 -0
  382. package/scripts/lib/persona-panel/catalog-loader.mjs +577 -0
  383. package/scripts/lib/persona-panel/consolidator.mjs +370 -0
  384. package/scripts/lib/persona-panel/persona-runner.mjs +375 -0
  385. package/scripts/lib/persona-panel/threshold.mjs +130 -0
  386. package/scripts/lib/pi-hook-bridge.mjs +328 -0
  387. package/scripts/lib/platform.mjs +266 -0
  388. package/scripts/lib/playwright-driver/runner.mjs +297 -0
  389. package/scripts/lib/plugin-root.mjs +210 -0
  390. package/scripts/lib/pre-dispatch-check.mjs +126 -0
  391. package/scripts/lib/product-repo-detect.mjs +121 -0
  392. package/scripts/lib/profiles/registry.mjs +176 -0
  393. package/scripts/lib/profiles/schema.mjs +209 -0
  394. package/scripts/lib/qg-command-drift-banner.mjs +88 -0
  395. package/scripts/lib/quality-gate/diagnostics.mjs +92 -0
  396. package/scripts/lib/quality-gate.mjs +536 -0
  397. package/scripts/lib/quality-gates-cache.mjs +228 -0
  398. package/scripts/lib/quality-gates-policy.mjs +95 -0
  399. package/scripts/lib/recommendations-v0.mjs +156 -0
  400. package/scripts/lib/reconcile/eligibility.mjs +203 -0
  401. package/scripts/lib/reconcile/emitter.mjs +244 -0
  402. package/scripts/lib/reconcile/engine.mjs +412 -0
  403. package/scripts/lib/reconcile/idempotency.mjs +239 -0
  404. package/scripts/lib/reconcile/renderer.mjs +211 -0
  405. package/scripts/lib/reconcile/writer.mjs +293 -0
  406. package/scripts/lib/reconcile-nudge-banner.mjs +284 -0
  407. package/scripts/lib/resource-probe/evaluate.mjs +190 -0
  408. package/scripts/lib/resource-probe/parsers.mjs +181 -0
  409. package/scripts/lib/resource-probe/probe-platform.mjs +300 -0
  410. package/scripts/lib/resource-probe.mjs +95 -0
  411. package/scripts/lib/rule-loader.mjs +552 -0
  412. package/scripts/lib/rules-sync.mjs +439 -0
  413. package/scripts/lib/scope-gate.mjs +496 -0
  414. package/scripts/lib/session-close-backfill.mjs +539 -0
  415. package/scripts/lib/session-discovery.mjs +256 -0
  416. package/scripts/lib/session-end/phase-skip.mjs +357 -0
  417. package/scripts/lib/session-end/worktree-cleanup.mjs +112 -0
  418. package/scripts/lib/session-id.mjs +362 -0
  419. package/scripts/lib/session-lock.mjs +703 -0
  420. package/scripts/lib/session-registry.mjs +355 -0
  421. package/scripts/lib/session-schema/aliases.mjs +71 -0
  422. package/scripts/lib/session-schema/constants.mjs +115 -0
  423. package/scripts/lib/session-schema/normalizer.mjs +66 -0
  424. package/scripts/lib/session-schema/timestamps.mjs +64 -0
  425. package/scripts/lib/session-schema/validator.mjs +453 -0
  426. package/scripts/lib/session-schema.mjs +71 -0
  427. package/scripts/lib/session-token-rollup.mjs +137 -0
  428. package/scripts/lib/sessions-staleness-banner.mjs +247 -0
  429. package/scripts/lib/skill-evolution/blast-radius-classifier.mjs +114 -0
  430. package/scripts/lib/skill-evolution/candidate-intake.mjs +270 -0
  431. package/scripts/lib/skill-evolution/config-validation-gate.mjs +279 -0
  432. package/scripts/lib/skill-evolution/engine.mjs +719 -0
  433. package/scripts/lib/skill-evolution/idempotency.mjs +279 -0
  434. package/scripts/lib/skill-evolution/mr-opener.mjs +507 -0
  435. package/scripts/lib/skill-health/join.mjs +181 -0
  436. package/scripts/lib/skill-health/score.mjs +123 -0
  437. package/scripts/lib/skill-invocations-schema.mjs +214 -0
  438. package/scripts/lib/skill-judge.mjs +348 -0
  439. package/scripts/lib/skill-judgments-schema.mjs +264 -0
  440. package/scripts/lib/slopcheck.mjs +501 -0
  441. package/scripts/lib/soul-resolve.mjs +118 -0
  442. package/scripts/lib/spiral-carryover.mjs +495 -0
  443. package/scripts/lib/state-md/body-sections.mjs +851 -0
  444. package/scripts/lib/state-md/frontmatter-mutators.mjs +453 -0
  445. package/scripts/lib/state-md/mission-status.mjs +247 -0
  446. package/scripts/lib/state-md/recommendations.mjs +57 -0
  447. package/scripts/lib/state-md/yaml-parser.mjs +234 -0
  448. package/scripts/lib/state-md-peer-guard.mjs +232 -0
  449. package/scripts/lib/state-md.mjs +53 -0
  450. package/scripts/lib/subagents-schema.mjs +309 -0
  451. package/scripts/lib/sunset/walker.mjs +1192 -0
  452. package/scripts/lib/test-runner/artifact-paths.mjs +94 -0
  453. package/scripts/lib/test-runner/fingerprint.mjs +33 -0
  454. package/scripts/lib/test-runner/issue-reconcile.mjs +770 -0
  455. package/scripts/lib/tmux-layout/layouts.mjs +224 -0
  456. package/scripts/lib/tmux-layout/telemetry-stats.mjs +100 -0
  457. package/scripts/lib/tmux-layout/telemetry.mjs +88 -0
  458. package/scripts/lib/tmux-layout/tmux-shell.mjs +82 -0
  459. package/scripts/lib/tmux-layout/vcs-detector.mjs +88 -0
  460. package/scripts/lib/validate/check-agents.mjs +457 -0
  461. package/scripts/lib/validate/check-codex-plugin.mjs +37 -0
  462. package/scripts/lib/validate/check-commands.mjs +148 -0
  463. package/scripts/lib/validate/check-component-paths.mjs +112 -0
  464. package/scripts/lib/validate/check-dead-bridge.mjs +180 -0
  465. package/scripts/lib/validate/check-hooks-symmetry.mjs +258 -0
  466. package/scripts/lib/validate/check-json-files.mjs +116 -0
  467. package/scripts/lib/validate/check-owner-leakage.mjs +1011 -0
  468. package/scripts/lib/validate/check-path-utils-canary.mjs +175 -0
  469. package/scripts/lib/validate/check-peekaboo-driver-canary.mjs +201 -0
  470. package/scripts/lib/validate/check-pi-package.mjs +110 -0
  471. package/scripts/lib/validate/check-pi-prompts.mjs +43 -0
  472. package/scripts/lib/validate/check-playwright-mcp-canary.mjs +154 -0
  473. package/scripts/lib/validate/check-plugin-json.mjs +96 -0
  474. package/scripts/lib/validate/check-plugin-monitors.mjs +206 -0
  475. package/scripts/lib/validate/check-plugin-schema.mjs +137 -0
  476. package/scripts/lib/validate/check-rules.mjs +143 -0
  477. package/scripts/lib/validate/check-session-plan-routing.mjs +154 -0
  478. package/scripts/lib/validate/check-test-fixture-shapes.mjs +280 -0
  479. package/scripts/lib/validate/check-unicode-safety.mjs +533 -0
  480. package/scripts/lib/validate/confidential-names.mjs +169 -0
  481. package/scripts/lib/validate/dead-bridge-corpus.mjs +141 -0
  482. package/scripts/lib/validate/dead-bridge-detectors.mjs +568 -0
  483. package/scripts/lib/validate/tier-inference.mjs +100 -0
  484. package/scripts/lib/validate-vendored-rules.mjs +519 -0
  485. package/scripts/lib/vault-archive.mjs +404 -0
  486. package/scripts/lib/vault-backfill/glab.mjs +164 -0
  487. package/scripts/lib/vault-backfill/manifest.mjs +75 -0
  488. package/scripts/lib/vault-backfill/template.mjs +130 -0
  489. package/scripts/lib/vault-consolidate-fs.mjs +331 -0
  490. package/scripts/lib/vault-migration-rules.mjs +155 -0
  491. package/scripts/lib/vault-mirror/auto-commit.mjs +203 -0
  492. package/scripts/lib/vault-mirror/namespace.mjs +152 -0
  493. package/scripts/lib/vault-mirror/process.mjs +567 -0
  494. package/scripts/lib/vault-mirror/pseudonym-map.mjs +164 -0
  495. package/scripts/lib/vault-mirror/render-learnings.mjs +201 -0
  496. package/scripts/lib/vault-mirror/render-sessions.mjs +367 -0
  497. package/scripts/lib/vault-mirror/render.mjs +8 -0
  498. package/scripts/lib/vault-mirror/utils.mjs +217 -0
  499. package/scripts/lib/vault-relocation-rules.mjs +555 -0
  500. package/scripts/lib/vault-repo-backfill.mjs +235 -0
  501. package/scripts/lib/vault-staleness-banner.mjs +142 -0
  502. package/scripts/lib/vault-status/board-writer.mjs +769 -0
  503. package/scripts/lib/vault-status/narrative-mirror.mjs +544 -0
  504. package/scripts/lib/vault-sync-baseline.mjs +152 -0
  505. package/scripts/lib/wave-context.mjs +29 -0
  506. package/scripts/lib/wave-executor/pool.mjs +248 -0
  507. package/scripts/lib/wave-resource-gate.mjs +204 -0
  508. package/scripts/lib/wave-sizing.mjs +75 -0
  509. package/scripts/lib/webhook-url.mjs +105 -0
  510. package/scripts/lib/workspace.mjs +198 -0
  511. package/scripts/lib/worktree/constants.mjs +35 -0
  512. package/scripts/lib/worktree/index.mjs +17 -0
  513. package/scripts/lib/worktree/lifecycle.mjs +287 -0
  514. package/scripts/lib/worktree/listing.mjs +118 -0
  515. package/scripts/lib/worktree/meta.mjs +64 -0
  516. package/scripts/lib/worktree-freshness.mjs +313 -0
  517. package/scripts/lib/worktree.mjs +15 -0
  518. package/scripts/lifecycle-sim-v6.mjs +347 -0
  519. package/scripts/lock-reaper.mjs +185 -0
  520. package/scripts/mcp-server.sh +241 -0
  521. package/scripts/measure-policy-cache-effectiveness.mjs +427 -0
  522. package/scripts/memory-propose.mjs +464 -0
  523. package/scripts/migrate-cold-start-seed.mjs +404 -0
  524. package/scripts/migrate-learnings-jsonl.mjs +189 -0
  525. package/scripts/migrate-legacy-learnings.sh +61 -0
  526. package/scripts/migrate-sessions-jsonl.mjs +448 -0
  527. package/scripts/migrate-subagents-jsonl.mjs +196 -0
  528. package/scripts/migrate-vault-paths.mjs +796 -0
  529. package/scripts/parse-config.mjs +149 -0
  530. package/scripts/pi-install.mjs +117 -0
  531. package/scripts/print-applicable-rules.mjs +247 -0
  532. package/scripts/promote-vault-strict.mjs +496 -0
  533. package/scripts/relocate-vault-corpus.mjs +1178 -0
  534. package/scripts/run-migrate-v2-cross-repo.mjs +385 -0
  535. package/scripts/run-quality-gate.mjs +216 -0
  536. package/scripts/spikes/h3-agent-teams/preflight.sh +53 -0
  537. package/scripts/spikes/h3-agent-teams/run-h3.sh +112 -0
  538. package/scripts/spikes/h3-agent-teams/setup.sh +137 -0
  539. package/scripts/spikes/h3-agent-teams/toggle.sh +38 -0
  540. package/scripts/sweep-expired-learnings.mjs +135 -0
  541. package/scripts/sync-vault-schema.mjs +376 -0
  542. package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +8 -0
  543. package/scripts/tmux-layout.mjs +245 -0
  544. package/scripts/token-audit.sh +191 -0
  545. package/scripts/typecheck.mjs +42 -0
  546. package/scripts/upload-social-preview.mjs +316 -0
  547. package/scripts/validate-config.mjs +46 -0
  548. package/scripts/validate-plugin-manifests.mjs +163 -0
  549. package/scripts/validate-plugin.mjs +264 -0
  550. package/scripts/validate-wave-scope.mjs +289 -0
  551. package/scripts/vault-backfill.mjs +404 -0
  552. package/scripts/vault-consolidate.mjs +596 -0
  553. package/scripts/vault-integration-watcher.mjs +394 -0
  554. package/scripts/vault-mirror.mjs +430 -0
  555. package/skills/_shared/bootstrap-gate.md +111 -0
  556. package/skills/_shared/config-reading.md +226 -0
  557. package/skills/_shared/instruction-file-resolution.md +79 -0
  558. package/skills/_shared/model-selection.md +64 -0
  559. package/skills/_shared/monitor-patterns.md +300 -0
  560. package/skills/_shared/parallel-aware-auq.md +121 -0
  561. package/skills/_shared/parallel-aware-preamble.md +185 -0
  562. package/skills/_shared/platform-tools.md +96 -0
  563. package/skills/_shared/state-ownership.md +221 -0
  564. package/skills/architecture/DEEPENING.md +37 -0
  565. package/skills/architecture/INTERFACE-DESIGN.md +44 -0
  566. package/skills/architecture/LANGUAGE.md +53 -0
  567. package/skills/architecture/SKILL.md +92 -0
  568. package/skills/autopilot/SKILL.md +419 -0
  569. package/skills/bootstrap/SKILL.md +592 -0
  570. package/skills/bootstrap/STATE.md.template +24 -0
  571. package/skills/bootstrap/_shared-template.md +243 -0
  572. package/skills/bootstrap/deep-template.md +659 -0
  573. package/skills/bootstrap/fast-template.md +251 -0
  574. package/skills/bootstrap/intensity-heuristic.md +80 -0
  575. package/skills/bootstrap/public-fallback.md +342 -0
  576. package/skills/bootstrap/standard-template.md +736 -0
  577. package/skills/bootstrap/templates/agents/project-code-review.md +18 -0
  578. package/skills/bootstrap/templates/agents/project-discovery.md +18 -0
  579. package/skills/bootstrap/templates/agents/project-quality-gate.md +18 -0
  580. package/skills/brainstorm/SKILL.md +268 -0
  581. package/skills/brainstorm/soul.md +49 -0
  582. package/skills/claude-md-drift-check/SKILL.md +186 -0
  583. package/skills/claude-md-drift-check/checker.mjs +1380 -0
  584. package/skills/claude-md-drift-check/checker.sh +37 -0
  585. package/skills/claude-md-drift-check/package.json +16 -0
  586. package/skills/convergence-monitoring/README.md +39 -0
  587. package/skills/convergence-monitoring/SIGNALS.md +246 -0
  588. package/skills/convergence-monitoring/SKILL.md +285 -0
  589. package/skills/daily/SKILL.md +222 -0
  590. package/skills/daily/generate.sh +92 -0
  591. package/skills/daily/templates/daily.md.tpl +36 -0
  592. package/skills/debug/SKILL.md +188 -0
  593. package/skills/debug/soul.md +35 -0
  594. package/skills/discovery/SKILL.md +567 -0
  595. package/skills/discovery/issue-templates.md +237 -0
  596. package/skills/discovery/probes/docs-staleness.mjs +195 -0
  597. package/skills/discovery/probes/frontend-slop.mjs +186 -0
  598. package/skills/discovery/probes/ssot-code-diff.mjs +310 -0
  599. package/skills/discovery/probes/supply-chain-slopcheck.mjs +440 -0
  600. package/skills/discovery/probes/vault-narrative-staleness.mjs +355 -0
  601. package/skills/discovery/probes/vault-staleness.mjs +272 -0
  602. package/skills/discovery/probes-arch.md +252 -0
  603. package/skills/discovery/probes-audit.md +95 -0
  604. package/skills/discovery/probes-code.md +329 -0
  605. package/skills/discovery/probes-docs.md +76 -0
  606. package/skills/discovery/probes-feature.md +150 -0
  607. package/skills/discovery/probes-infra.md +138 -0
  608. package/skills/discovery/probes-intro.md +25 -0
  609. package/skills/discovery/probes-session.md +495 -0
  610. package/skills/discovery/probes-supply-chain.md +94 -0
  611. package/skills/discovery/probes-ui.md +147 -0
  612. package/skills/discovery/probes-vault.md +64 -0
  613. package/skills/discovery/slop-patterns.md +115 -0
  614. package/skills/dispatcher/SKILL.md +173 -0
  615. package/skills/docs-orchestrator/SKILL.md +362 -0
  616. package/skills/docs-orchestrator/audience-mapping.md +140 -0
  617. package/skills/domain-model/ADR-FORMAT.md +47 -0
  618. package/skills/domain-model/CONTEXT-FORMAT.md +77 -0
  619. package/skills/domain-model/SKILL.md +85 -0
  620. package/skills/ecosystem-health/SKILL.md +119 -0
  621. package/skills/ecosystem-health/wizard.md +193 -0
  622. package/skills/eval/SKILL.md +293 -0
  623. package/skills/eval/rubric-v1.md +218 -0
  624. package/skills/evolve/SKILL.md +546 -0
  625. package/skills/frontmatter-guard/SKILL.md +126 -0
  626. package/skills/gitlab-ops/SKILL.md +368 -0
  627. package/skills/gitlab-portfolio/SKILL.md +196 -0
  628. package/skills/grill/SKILL.md +185 -0
  629. package/skills/grill/soul.md +55 -0
  630. package/skills/hook-development/SKILL.md +413 -0
  631. package/skills/mcp-builder/SKILL.md +260 -0
  632. package/skills/memory-cleanup/SKILL.md +310 -0
  633. package/skills/mode-selector/SKILL.md +226 -0
  634. package/skills/peekaboo-driver/SKILL.md +237 -0
  635. package/skills/peekaboo-driver/soul.md +32 -0
  636. package/skills/persona-panel/SKILL.md +365 -0
  637. package/skills/persona-panel/persona-format.md +205 -0
  638. package/skills/persona-panel/presets/designer-lens.md +87 -0
  639. package/skills/persona-panel/presets/engineer-lens.md +88 -0
  640. package/skills/persona-panel/presets/pm-lens.md +86 -0
  641. package/skills/plan/SKILL.md +496 -0
  642. package/skills/plan/mode-feature.md +141 -0
  643. package/skills/plan/mode-new.md +297 -0
  644. package/skills/plan/mode-retro.md +271 -0
  645. package/skills/plan/prd-feature-template.md +132 -0
  646. package/skills/plan/prd-full-template.md +151 -0
  647. package/skills/plan/prd-reviewer-prompt.md +103 -0
  648. package/skills/plan/retro-template.md +75 -0
  649. package/skills/plan/soul.md +62 -0
  650. package/skills/playwright-driver/SKILL.md +226 -0
  651. package/skills/playwright-driver/soul.md +30 -0
  652. package/skills/quality-gates/SKILL.md +212 -0
  653. package/skills/reconcile/SKILL.md +324 -0
  654. package/skills/repo-audit/SKILL.md +272 -0
  655. package/skills/session-end/SKILL.md +1044 -0
  656. package/skills/session-end/discovery-scan.md +37 -0
  657. package/skills/session-end/drift-operations.md +97 -0
  658. package/skills/session-end/learning-patterns.md +78 -0
  659. package/skills/session-end/metrics-collection.md +175 -0
  660. package/skills/session-end/phase-3-2-docs-verification.md +148 -0
  661. package/skills/session-end/phase-3-6-tail.md +344 -0
  662. package/skills/session-end/phase-3-7a-recommendations.md +86 -0
  663. package/skills/session-end/plan-verification.md +288 -0
  664. package/skills/session-end/session-metrics-write.md +223 -0
  665. package/skills/session-end/vault-operations.md +50 -0
  666. package/skills/session-end/verification-checklist.md +20 -0
  667. package/skills/session-plan/SKILL.md +554 -0
  668. package/skills/session-plan/wave-template.md +37 -0
  669. package/skills/session-start/SKILL.md +1043 -0
  670. package/skills/session-start/phase-2-5-docs-planning.md +119 -0
  671. package/skills/session-start/phase-4-5-resource-health.md +49 -0
  672. package/skills/session-start/phase-7-1-premise-check.md +47 -0
  673. package/skills/session-start/phase-7-5-mode-selector.md +237 -0
  674. package/skills/session-start/phase-8-5-express-path.md +61 -0
  675. package/skills/session-start/presentation-format.md +81 -0
  676. package/skills/session-start/soul.md +57 -0
  677. package/skills/skill-creator/SKILL.md +168 -0
  678. package/skills/spinout/SKILL.md +76 -0
  679. package/skills/sunset-review/SKILL.md +96 -0
  680. package/skills/test-runner/SKILL.md +362 -0
  681. package/skills/test-runner/rubric-v1.md +388 -0
  682. package/skills/test-runner/soul.md +46 -0
  683. package/skills/tmux-layout/SKILL.md +104 -0
  684. package/skills/ubiquitous-language/SKILL.md +97 -0
  685. package/skills/using-orchestrator/SKILL.md +144 -0
  686. package/skills/vault-mirror/SKILL.md +234 -0
  687. package/skills/vault-sync/SKILL.md +319 -0
  688. package/skills/vault-sync/package-lock.json +40 -0
  689. package/skills/vault-sync/package.json +11 -0
  690. package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +8 -0
  691. package/skills/vault-sync/tests/fixtures/archive-test-vault/_meta/.gitkeep +0 -0
  692. package/skills/vault-sync/tests/fixtures/archive-test-vault/live-note.md +8 -0
  693. package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/_meta/.gitkeep +0 -0
  694. package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/bad-type.md +8 -0
  695. package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +8 -0
  696. package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +8 -0
  697. package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +10 -0
  698. package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +8 -0
  699. package/skills/vault-sync/tests/fixtures/clean-vault/README.md +3 -0
  700. package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +11 -0
  701. package/skills/vault-sync/tests/fixtures/dangling-link-vault/_meta/.gitkeep +0 -0
  702. package/skills/vault-sync/tests/fixtures/dangling-link-vault/has-dangling.md +9 -0
  703. package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +8 -0
  704. package/skills/vault-sync/tests/fixtures/empty-vault/_meta/.gitkeep +0 -0
  705. package/skills/vault-sync/tests/fixtures/missing-field-vault/_meta/.gitkeep +0 -0
  706. package/skills/vault-sync/tests/fixtures/missing-field-vault/missing-id.md +7 -0
  707. package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +9 -0
  708. package/skills/vault-sync/tests/fixtures/nested-tag-vault/_meta/.gitkeep +0 -0
  709. package/skills/vault-sync/tests/fixtures/nested-tag-vault/nested-tags-note.md +11 -0
  710. package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +3 -0
  711. package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +3 -0
  712. package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
  713. package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +11 -0
  714. package/skills/vault-sync/tests/fixtures/with-moc-vault/_meta/.gitkeep +0 -0
  715. package/skills/vault-sync/tests/fixtures/with-moc-vault/hello-world.md +11 -0
  716. package/skills/vault-sync/tests/schema-drift.test.mjs +133 -0
  717. package/skills/vault-sync/validator.mjs +658 -0
  718. package/skills/vault-sync/validator.sh +55 -0
  719. package/skills/wave-executor/SKILL.md +496 -0
  720. package/skills/wave-executor/circuit-breaker.md +169 -0
  721. package/skills/wave-executor/wave-loop.md +1043 -0
  722. package/skills/write-executable-plan/SKILL.md +237 -0
  723. package/skills/write-executable-plan/plan-template.md +154 -0
  724. package/templates/_minimal/CLAUDE.md.tmpl +41 -0
  725. package/templates/_minimal/README.md.tmpl +15 -0
  726. package/templates/_minimal/gitignore.tmpl +47 -0
  727. package/templates/_shared/harte-regeln.md +16 -0
  728. package/templates/_shared/loop.md +90 -0
  729. package/templates/_shared/rules/parallel-sessions.md +77 -0
  730. package/templates/nextjs-minimal/README.md +30 -0
  731. package/templates/nextjs-minimal/app/layout.tsx +18 -0
  732. package/templates/nextjs-minimal/app/page.tsx +7 -0
  733. package/templates/nextjs-minimal/eslint.config.mjs +16 -0
  734. package/templates/nextjs-minimal/next.config.mjs +4 -0
  735. package/templates/nextjs-minimal/package.json +27 -0
  736. package/templates/nextjs-minimal/tsconfig.json +23 -0
  737. package/templates/node-minimal/README.md +33 -0
  738. package/templates/node-minimal/eslint.config.mjs +10 -0
  739. package/templates/node-minimal/package.json +21 -0
  740. package/templates/node-minimal/src/index.ts +1 -0
  741. package/templates/node-minimal/tests/sanity.test.ts +5 -0
  742. package/templates/node-minimal/tsconfig.json +17 -0
  743. package/templates/personas/README.md +150 -0
  744. package/templates/personas/accounting-compliance.v1.md +120 -0
  745. package/templates/personas/accounting-tax-advisor.v1.md +116 -0
  746. package/templates/personas/buyer-p1-cto.v1.md +125 -0
  747. package/templates/personas/buyer-p2-kanzlei.v1.md +134 -0
  748. package/templates/personas/buyer-p3-build.v1.md +130 -0
  749. package/templates/personas/buyer-p4-tech-veto.v1.md +130 -0
  750. package/templates/personas/buyer-p5-solo.v1.md +132 -0
  751. package/templates/personas/buyer-p6-ld.v1.md +130 -0
  752. package/templates/personas/klima-ai-expert.v1.md +114 -0
  753. package/templates/personas/klima-physicist.v1.md +117 -0
  754. package/templates/python-uv/README.md +28 -0
  755. package/templates/python-uv/pyproject.toml +32 -0
  756. package/templates/python-uv/src/__PROJECT_NAME__/__init__.py +0 -0
  757. package/templates/python-uv/src/__PROJECT_NAME__/main.py +6 -0
  758. package/templates/python-uv/tests/test_sanity.py +2 -0
  759. package/templates/static-html/README.md +19 -0
  760. package/templates/static-html/index.html +15 -0
  761. package/templates/static-html/script.js +1 -0
  762. package/templates/static-html/styles.css +26 -0
@@ -0,0 +1,719 @@
1
+ /**
2
+ * engine.mjs — C2 auto-repair ORCHESTRATOR for the Skill Self-Evolution
3
+ * Foundation (Epic #643 → issue #647).
4
+ *
5
+ * This is the HEART of #647: it composes the five W2 leaf modules into a single
6
+ * repair engine that implements the gate-per-artifact-type decision matrix
7
+ * (autonomy × posture × gate × evidence). R5 blast-radius enforcement lives here
8
+ * — the matrix is the load-bearing deliverable, not the file-write mechanics.
9
+ *
10
+ * COMPOSITION (the five siblings, all DI-injectable via `opts`):
11
+ * - candidate-intake.mjs → extractCandidates (pure transform)
12
+ * - idempotency.mjs → mergeCandidates / markProcessed / isProcessed
13
+ * / loadCandidates (store I/O + supersession)
14
+ * - blast-radius-classifier.mjs→ classifyTarget (R5 posture/gate triple)
15
+ * - config-validation-gate.mjs → runConfigValidationGate (deterministic gate)
16
+ * - mr-opener.mjs → openRepairMr (MR/PR for prose targets)
17
+ *
18
+ * PIPELINE:
19
+ * extractCandidates(learnings, driftResult)
20
+ * → mergeCandidates (persist + supersede)
21
+ * → for each NON-processed candidate:
22
+ * classify → decide per matrix → act
23
+ *
24
+ * DECISION MATRIX (implemented EXACTLY — see the gherkins / matrix rows):
25
+ * floor = config['skill-evolution']['evidence-floor'] (default 0.5)
26
+ * evidenceOk = Number.isFinite(c.evidence) && c.evidence >= floor (fail-closed)
27
+ * posture = classifyTarget(target).posture
28
+ *
29
+ * 1. autonomy 'off' → advisory-only (ALWAYS) [R4,R5,R13,R14,R16]
30
+ * 2. posture 'always-mr' (plugin/local/unknown):
31
+ * autonomy 'advisory' | 'autonomous-gated' → open-mr [R1,R2,R3,R15]
32
+ * 3. posture 'autonomous-gated' (local-config):
33
+ * autonomy 'advisory' → advisory-only [R11,R12]
34
+ * autonomy 'autonomous-gated':
35
+ * gateGreen && evidenceOk → autonomous-apply [R6 — the ONLY one]
36
+ * else → open-mr (carries failing-gate ctx) [R7..R10,R17]
37
+ *
38
+ * INVARIANTS (W4 asserts these):
39
+ * - autonomous-apply happens in EXACTLY the R6 condition. Nowhere else.
40
+ * - autonomy:off ⇒ every outcome advisory-only.
41
+ * - plugin-skill / local-skill ⇒ outcome ∈ {open-mr, advisory-only} ONLY.
42
+ * - gate not green ⇒ no autonomous-apply.
43
+ * - evidence < floor (or missing/NaN) ⇒ no autonomous-apply.
44
+ * - empty candidate set ⇒ outcomes:[], summary all-zero, touches no disk.
45
+ *
46
+ * CONTRACT: NEVER throws. Per-candidate logic is wrapped so one failure becomes a
47
+ * `no-op` outcome (with detail) and the loop continues.
48
+ *
49
+ * Part of Epic #643 → issue #647 (C2 auto-repair engine).
50
+ */
51
+
52
+ import { readFileSync, writeFileSync, renameSync } from 'node:fs';
53
+ import path from 'node:path';
54
+ import { randomBytes } from 'node:crypto';
55
+
56
+ import { extractCandidates as realExtractCandidates } from './candidate-intake.mjs';
57
+ import {
58
+ mergeCandidates as realMergeCandidates,
59
+ markProcessed as realMarkProcessed,
60
+ isProcessed as realIsProcessed,
61
+ } from './idempotency.mjs';
62
+ import { classifyTarget as realClassifyTarget } from './blast-radius-classifier.mjs';
63
+ import { runConfigValidationGate as realRunConfigValidationGate } from './config-validation-gate.mjs';
64
+ import { openRepairMr as realOpenRepairMr } from './mr-opener.mjs';
65
+
66
+ /**
67
+ * @typedef {import('./candidate-intake.mjs').RepairCandidate} RepairCandidate
68
+ */
69
+
70
+ /**
71
+ * @typedef {'autonomous-apply'|'open-mr'|'advisory-only'|'no-op'} RepairDecision
72
+ */
73
+
74
+ /**
75
+ * @typedef {Object} RepairOutcome
76
+ * @property {string} candidateId The candidate's idempotency id.
77
+ * @property {string} targetPath Repo-relative path the repair targets.
78
+ * @property {import('./blast-radius-classifier.mjs').TargetType} targetType
79
+ * The R5 blast-radius target type.
80
+ * @property {RepairDecision} decision The matrix decision applied.
81
+ * @property {string} detail Human-readable detail / reason for the decision.
82
+ */
83
+
84
+ /**
85
+ * @typedef {Object} RepairSummary
86
+ * @property {number} autonomousApplied Count of `autonomous-apply` outcomes.
87
+ * @property {number} mrsOpened Count of `open-mr` outcomes.
88
+ * @property {number} advisories Count of `advisory-only` outcomes.
89
+ * @property {number} blocked Count of `no-op` outcomes (errors/skips).
90
+ * @property {number} total Count of all outcomes emitted.
91
+ */
92
+
93
+ /**
94
+ * @typedef {Object} RepairEngineResult
95
+ * @property {RepairOutcome[]} outcomes
96
+ * @property {RepairSummary} summary
97
+ */
98
+
99
+ const DEFAULT_EVIDENCE_FLOOR = 0.5;
100
+ const VALID_AUTONOMY = new Set(['off', 'advisory', 'autonomous-gated']);
101
+
102
+ /**
103
+ * Default no-op logger. Replaced by `opts.log` when provided.
104
+ * @param {string} _level
105
+ * @param {string} _msg
106
+ * @returns {void}
107
+ */
108
+ function noopLog(_level, _msg) {
109
+ /* intentionally empty — diagnostics are opt-in via opts.log */
110
+ }
111
+
112
+ /**
113
+ * Read the `skill-evolution` sub-config from the parsed Session Config, applying
114
+ * conservative, fail-closed defaults. An absent / malformed block yields the
115
+ * safe default (`autonomy: 'off'`, floor 0.5, judge false).
116
+ *
117
+ * @param {Record<string, unknown>|null|undefined} config — full parsed Session Config.
118
+ * @returns {{ autonomy: 'off'|'advisory'|'autonomous-gated', evidenceFloor: number, judge: boolean }}
119
+ */
120
+ function readSkillEvolutionConfig(config) {
121
+ const block =
122
+ config && typeof config === 'object' && typeof config['skill-evolution'] === 'object'
123
+ ? /** @type {Record<string, unknown>} */ (config['skill-evolution'])
124
+ : {};
125
+
126
+ const rawAutonomy = block.autonomy;
127
+ const autonomy =
128
+ typeof rawAutonomy === 'string' && VALID_AUTONOMY.has(rawAutonomy)
129
+ ? /** @type {'off'|'advisory'|'autonomous-gated'} */ (rawAutonomy)
130
+ : 'off'; // fail-closed default
131
+
132
+ const rawFloor = block['evidence-floor'];
133
+ // Coerce a stringified floor (e.g. an unparsed `evidence-floor: "0.9"`) so an
134
+ // operator's intended stricter gate is honoured instead of silently reverting
135
+ // to the default. null/undefined/empty/object → NaN → default (never 0).
136
+ const coercedFloor =
137
+ typeof rawFloor === 'number'
138
+ ? rawFloor
139
+ : typeof rawFloor === 'string' && rawFloor.trim() !== ''
140
+ ? Number(rawFloor)
141
+ : NaN;
142
+ const evidenceFloor =
143
+ Number.isFinite(coercedFloor) && coercedFloor >= 0 && coercedFloor <= 1
144
+ ? coercedFloor
145
+ : DEFAULT_EVIDENCE_FLOOR;
146
+
147
+ const judge = block.judge === true;
148
+
149
+ return { autonomy, evidenceFloor, judge };
150
+ }
151
+
152
+ /**
153
+ * The ONE supported autonomous-apply shape (Option A — re-derive from prose).
154
+ * Anchored to the `command-count` `proposed_change` template emitted by
155
+ * candidate-intake.mjs (`Update narrative '<N> commands' to actual <M>`).
156
+ * Both numbers are embedded in the prose string; capturing them avoids a
157
+ * candidate-schema change. Anything that does not match is OUT OF WHITELIST.
158
+ * @type {RegExp}
159
+ */
160
+ const COMMAND_COUNT_SHAPE = /'(\d+)\s+commands'\s+to\s+actual\s+(\d+)/;
161
+
162
+ /**
163
+ * The string a not-yet-applied unsupported shape returns as its `reason`. The
164
+ * engine narrowly matches `/unsupported-shape/` against this to re-route to the
165
+ * MR path (rather than silently stamping a candidate it cannot apply).
166
+ */
167
+ const UNSUPPORTED_SHAPE_REASON = 'unsupported-shape — out of whitelist';
168
+
169
+ /**
170
+ * Parse the whitelisted command-count shape out of a candidate's PROSE
171
+ * `proposed_change`. Returns the claimed (narrative) and actual (filesystem)
172
+ * counts, or `null` when the prose is not the supported shape.
173
+ * @param {RepairCandidate} candidate
174
+ * @returns {{ claimedN: number, actualM: number } | null}
175
+ */
176
+ function parseCommandCountShape(candidate) {
177
+ const proposed =
178
+ candidate && typeof candidate.proposed_change === 'string' ? candidate.proposed_change : '';
179
+ const m = COMMAND_COUNT_SHAPE.exec(proposed);
180
+ if (!m) return null;
181
+ return { claimedN: Number(m[1]), actualM: Number(m[2]) };
182
+ }
183
+
184
+ /**
185
+ * Resolve a candidate's `target_path` against `repoRoot` with a fail-closed
186
+ * repo-escape guard (mirrors mr-opener.mjs Step 3 + blast-radius-classifier.mjs).
187
+ * Returns the absolute path when the target is genuinely inside the repo, or
188
+ * `null` when it escapes / is the root itself / inputs are unusable.
189
+ * @param {string} repoRoot
190
+ * @param {string} targetPath
191
+ * @returns {string|null}
192
+ */
193
+ function resolveInsideRepo(repoRoot, targetPath) {
194
+ if (typeof repoRoot !== 'string' || repoRoot.length === 0) return null;
195
+ if (typeof targetPath !== 'string' || targetPath.length === 0) return null;
196
+ const abs = path.resolve(repoRoot, targetPath);
197
+ const rel = path.relative(repoRoot, abs);
198
+ if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) return null;
199
+ return abs;
200
+ }
201
+
202
+ /**
203
+ * Apply the command-count number swap to file content. Finds the FIRST narrative
204
+ * occurrence of `<claimedN>` immediately preceding a `commands` token (tolerating
205
+ * the `/commands` and `slash commands` narrative variants the drift-check matches
206
+ * via `/\b(\d+)\s+(?:\/)?commands?\b/`, and an optional wrapping single-quote),
207
+ * and replaces ONLY that leading number with `actualM`. Every other byte — and
208
+ * the `commands` token itself — is preserved verbatim.
209
+ *
210
+ * Returns the rewritten content, or `null` when no occurrence is found OR the
211
+ * narrative number already equals `actualM` (idempotent no-op).
212
+ * @param {string} content
213
+ * @param {number} claimedN
214
+ * @param {number} actualM
215
+ * @returns {string|null}
216
+ */
217
+ function applyCommandCountSwap(content, claimedN, actualM) {
218
+ if (typeof content !== 'string' || content.length === 0) return null;
219
+ if (claimedN === actualM) return null; // already current — no-op
220
+ // Anchor on the claimed number followed by the (drift-check-shaped) commands
221
+ // token. \b before the number prevents matching a substring of a larger int
222
+ // (e.g. claimedN=8 must not match inside "18 commands"). The number group is
223
+ // the only segment we replace; the trailing token group is re-emitted as-is.
224
+ const swapRe = new RegExp(`\\b${claimedN}(\\s+(?:/|slash\\s+)?commands?\\b)`);
225
+ if (!swapRe.test(content)) return null; // claimed text not found — no-op
226
+ return content.replace(swapRe, `${actualM}$1`);
227
+ }
228
+
229
+ /**
230
+ * Default applyConfigRepair seam — the REAL autonomous mutator (issue #651).
231
+ *
232
+ * Implements the §C2-G2 contract for the whitelisted `command-count` drift
233
+ * shape ONLY. Every step is defense-in-depth + idempotent:
234
+ * 1. Repo-escape guard: resolve target inside `repoRoot`; escape ⇒ no-op.
235
+ * 2. Evidence-kind gate: only `filesystem-fact` (drift-check) candidates may
236
+ * auto-apply; `confidence` (learning) candidates carry attacker-influenceable
237
+ * prose and are routed to the MR path via `unsupported-shape`. (Security H1.)
238
+ * 3. Whitelist: parse the command-count shape from PROSE; miss ⇒
239
+ * `unsupported-shape` (the engine re-routes that to an MR — never stamps).
240
+ * 4. Mutation: swap the ONE narrative number, atomically (tmp + rename),
241
+ * content-level idempotent (already-current / text-absent ⇒ no write).
242
+ *
243
+ * NEVER throws — every error path degrades to `{ ok: true, applied: false }`.
244
+ * Does NOT stamp `processed_at`; the engine owns the G2 stamp.
245
+ *
246
+ * @param {RepairCandidate} candidate — the local-config candidate to apply.
247
+ * @param {string} [repoRoot] — repo root for path resolution (engine injects it).
248
+ * @returns {Promise<{ ok: boolean, applied: boolean, reason?: string }>}
249
+ */
250
+ async function defaultApplyConfigRepair(candidate, repoRoot) {
251
+ // Step 1 — repo-escape guard (fail-closed; mirrors mr-opener.mjs L353-361).
252
+ const abs = resolveInsideRepo(repoRoot, candidate?.target_path);
253
+ if (abs === null) {
254
+ return { ok: true, applied: false, reason: 'target escapes repo' };
255
+ }
256
+
257
+ // Step 2 — autonomous-apply is restricted to filesystem-fact candidates (drift-check origin).
258
+ // Learning-sourced candidates (evidence_kind: 'confidence') carry attacker-influenceable prose
259
+ // in proposed_change; route them to the MR path, never auto-apply. (Security review H1, session-3.)
260
+ if (candidate?.evidence_kind !== 'filesystem-fact') {
261
+ return { ok: true, applied: false, reason: UNSUPPORTED_SHAPE_REASON };
262
+ }
263
+
264
+ // Step 3 — whitelist gate. Only the command-count shape may auto-apply.
265
+ const parsed = parseCommandCountShape(candidate);
266
+ if (parsed === null) {
267
+ return { ok: true, applied: false, reason: UNSUPPORTED_SHAPE_REASON };
268
+ }
269
+ const { claimedN, actualM } = parsed;
270
+
271
+ // Step 4 — scoped, minimal, idempotent mutation (atomic write-back).
272
+ let content;
273
+ try {
274
+ content = readFileSync(abs, 'utf8');
275
+ } catch (err) {
276
+ return { ok: true, applied: false, reason: `read failed: ${err?.message ?? String(err)}` };
277
+ }
278
+
279
+ const next = applyCommandCountSwap(content, claimedN, actualM);
280
+ if (next === null || next === content) {
281
+ return { ok: true, applied: false, reason: 'already-current (no-op)' };
282
+ }
283
+
284
+ try {
285
+ const dir = path.dirname(abs);
286
+ const tmpFile = path.join(dir, `.${path.basename(abs)}.${randomBytes(6).toString('hex')}.tmp`);
287
+ writeFileSync(tmpFile, next, { encoding: 'utf8' });
288
+ renameSync(tmpFile, abs);
289
+ } catch (err) {
290
+ return { ok: true, applied: false, reason: `write failed: ${err?.message ?? String(err)}` };
291
+ }
292
+
293
+ return { ok: true, applied: true };
294
+ }
295
+
296
+ /**
297
+ * Default buildDiff seam — derive a {@link RepairDiff} from a candidate for the
298
+ * MR-opener (issue #651). For the whitelisted `command-count` shape on a config
299
+ * target it computes the FULL rewritten file content (same one-line swap as the
300
+ * apply seam) so the MR-opener can write the change; otherwise — unsupported
301
+ * prose shape, read error, or escape — it degrades to a `{ raw }`-only describe
302
+ * MR (the MR-opener opens a description-only MR when `content` is absent).
303
+ *
304
+ * Synchronous and NEVER throws.
305
+ *
306
+ * @param {RepairCandidate} candidate
307
+ * @param {string} [repoRoot] — repo root for path resolution (engine injects it).
308
+ * @returns {{ content?: string, raw?: string }}
309
+ */
310
+ function defaultBuildDiff(candidate, repoRoot) {
311
+ const proposed =
312
+ candidate && typeof candidate.proposed_change === 'string' ? candidate.proposed_change : '';
313
+
314
+ const abs = resolveInsideRepo(repoRoot, candidate?.target_path);
315
+ const parsed = parseCommandCountShape(candidate);
316
+ if (abs === null || parsed === null) {
317
+ return { raw: proposed };
318
+ }
319
+ const { claimedN, actualM } = parsed;
320
+
321
+ let content;
322
+ try {
323
+ content = readFileSync(abs, 'utf8');
324
+ } catch {
325
+ return { raw: proposed };
326
+ }
327
+
328
+ const next = applyCommandCountSwap(content, claimedN, actualM);
329
+ if (next === null || next === content) {
330
+ // Already current / claimed text absent → nothing to rewrite; describe only.
331
+ return { raw: proposed };
332
+ }
333
+
334
+ // Synthesise a minimal unified-diff preview of the one changed line. The
335
+ // describe path (`raw`) names the exact old/new narrative lines for the MR body.
336
+ const oldLine = `${claimedN} commands`;
337
+ const newLine = `${actualM} commands`;
338
+ const rel = path.relative(repoRoot, abs).split(path.sep).join('/');
339
+ return {
340
+ content: next,
341
+ raw: `--- a/${rel}\n+++ b/${rel}\n-${oldLine}\n+${newLine}\n`,
342
+ };
343
+ }
344
+
345
+ /**
346
+ * Decide the matrix outcome for a single classified candidate. Pure decision
347
+ * function over (autonomy, posture, gateGreen, evidenceOk) — no I/O. Returns the
348
+ * decision plus a short detail string. The CALLER performs the side effects
349
+ * (gate run, apply, MR open) — this only encodes the matrix branching for
350
+ * non-config postures. The config branch is handled in {@link decideAndAct}
351
+ * because it must run the gate before deciding.
352
+ *
353
+ * @param {'off'|'advisory'|'autonomous-gated'} autonomy
354
+ * @param {import('./blast-radius-classifier.mjs').Posture} posture
355
+ * @returns {{ decision: 'open-mr'|'advisory-only'|'config-branch', detail: string }}
356
+ */
357
+ function decideNonConfig(autonomy, posture) {
358
+ // Row group 1 — autonomy off ⇒ advisory-only ALWAYS (every target type).
359
+ if (autonomy === 'off') {
360
+ return { decision: 'advisory-only', detail: 'autonomy off — advisory only (safe default)' };
361
+ }
362
+
363
+ // Row group 2 — prose targets (plugin-skill / local-skill / unknown) ⇒
364
+ // always-mr posture. MR is the floor; never autonomous. [R1,R2,R3,R15]
365
+ if (posture === 'always-mr') {
366
+ return { decision: 'open-mr', detail: 'always-mr posture — prose target routed through MR' };
367
+ }
368
+
369
+ // Otherwise this is the autonomous-gated (local-config) posture — the caller
370
+ // must run the gate to decide. Signalled via the 'config-branch' sentinel.
371
+ return { decision: 'config-branch', detail: '' };
372
+ }
373
+
374
+ /**
375
+ * Run the matrix decision for one candidate and perform the corresponding side
376
+ * effect. NEVER throws — any failure degrades to a `no-op` outcome.
377
+ *
378
+ * @param {Object} ctx
379
+ * @param {RepairCandidate} ctx.candidate
380
+ * @param {string} ctx.repoRoot
381
+ * @param {{ autonomy: 'off'|'advisory'|'autonomous-gated', evidenceFloor: number }} ctx.se
382
+ * @param {boolean} ctx.dryRun
383
+ * @param {Object} ctx.seams — resolved DI seams.
384
+ * @returns {Promise<RepairOutcome>}
385
+ */
386
+ async function decideAndAct({ candidate, repoRoot, se, dryRun, seams }) {
387
+ const { autonomy, evidenceFloor: floor } = se;
388
+ const candidateId = candidate.id;
389
+ const targetPath = candidate.target_path;
390
+
391
+ // --- R5 blast-radius classification --------------------------------------
392
+ const classification = seams.classifyTarget(targetPath, { repoRoot });
393
+ const { targetType, posture } = classification;
394
+
395
+ // --- evidence gate (fail-closed: missing / NaN ⇒ false) ------------------
396
+ const evidenceOk = Number.isFinite(candidate.evidence) && candidate.evidence >= floor;
397
+
398
+ // --- matrix branch for off / always-mr -----------------------------------
399
+ const branch = decideNonConfig(autonomy, posture);
400
+ if (branch.decision === 'advisory-only') {
401
+ return finishAdvisory({ candidate, candidateId, targetPath, targetType, dryRun, seams, detail: branch.detail });
402
+ }
403
+ if (branch.decision === 'open-mr') {
404
+ return finishOpenMr({
405
+ candidate, candidateId, targetPath, targetType, repoRoot, dryRun, seams,
406
+ detail: branch.detail,
407
+ });
408
+ }
409
+
410
+ // --- config-branch: posture 'autonomous-gated' (local-config) ------------
411
+ // autonomy 'advisory' ⇒ advisory-only (never auto-applies/opens MR autonomously,
412
+ // even when gate+evidence would qualify). [R11,R12]
413
+ if (autonomy === 'advisory') {
414
+ return finishAdvisory({
415
+ candidate, candidateId, targetPath, targetType, dryRun, seams,
416
+ detail: 'advisory autonomy on local-config — advisory only (no autonomous action)',
417
+ });
418
+ }
419
+
420
+ // autonomy 'autonomous-gated' on local-config — run the gate, then decide.
421
+ // Both branches of the try/catch assign these, so no initializer is needed.
422
+ let gateGreen;
423
+ let gateDetail;
424
+ try {
425
+ const gate = await seams.runConfigValidationGate({ repoRoot });
426
+ gateGreen = gate && gate.ok === true;
427
+ gateDetail = gateGreen ? 'config-validation gate green' : 'config-validation gate not green';
428
+ } catch (err) {
429
+ // Gate threw (a real gate never throws, but a mocked seam might). Fail-closed.
430
+ gateGreen = false;
431
+ gateDetail = `config-validation gate errored: ${err?.message ?? String(err)}`;
432
+ }
433
+
434
+ // R6 — the ONLY autonomous-apply row: gate green AND evidence ≥ floor.
435
+ if (gateGreen && evidenceOk) {
436
+ if (dryRun === true) {
437
+ // Dry-run: preview only — do NOT mutate or stamp.
438
+ return {
439
+ candidateId,
440
+ targetPath,
441
+ targetType,
442
+ decision: 'autonomous-apply',
443
+ detail: 'dry-run preview',
444
+ };
445
+ }
446
+ // Real autonomous apply: applyConfigRepair → markProcessed.
447
+ try {
448
+ const applyResult = await seams.applyConfigRepair(candidate, repoRoot);
449
+ const applied = applyResult && applyResult.applied === true;
450
+ const applyReason = typeof applyResult?.reason === 'string' ? applyResult.reason : '';
451
+
452
+ // Re-route NARROWLY: only when the apply was declined because the shape is
453
+ // OUT OF WHITELIST do we open an MR (so the change is not silently
454
+ // stamped-and-dropped). Every OTHER non-applied reason that WON'T change on
455
+ // retry (already-current, target escapes repo) keeps the existing
456
+ // stamp-and-return behaviour — and existing engine.test.mjs mocks (generic
457
+ // results without an `unsupported-shape` reason) are unaffected.
458
+ if (!applied && /unsupported-shape/.test(applyReason)) {
459
+ return finishOpenMr({
460
+ candidate, candidateId, targetPath, targetType, repoRoot, dryRun, seams,
461
+ detail: `apply declined (${applyReason}) — routed to MR`,
462
+ });
463
+ }
464
+
465
+ // TRANSIENT I/O failure (read/write): do NOT stamp (so the drift retries on
466
+ // a future run once the FS issue clears) and do NOT count as an apply (so
467
+ // telemetry isn't inflated by a buried failure). Degrade to a `no-op` that
468
+ // surfaces the error reason. (#651 FIX 2 — silent-failure / telemetry-inflate)
469
+ if (!applied && /read failed|write failed/i.test(applyReason)) {
470
+ return {
471
+ candidateId,
472
+ targetPath,
473
+ targetType,
474
+ decision: 'no-op',
475
+ detail: `autonomous-apply aborted — ${applyReason} (not stamped; will retry)`,
476
+ };
477
+ }
478
+
479
+ const stamp = seams.markProcessed({ id: candidateId, repoRoot });
480
+ const stampOk = stamp && stamp.ok === true;
481
+ const detailParts = [
482
+ `gate green + evidence ${candidate.evidence} ≥ ${floor}`,
483
+ applied ? 'applied' : `apply deferred (${applyReason || 'seam stub'})`,
484
+ stampOk ? 'marked processed' : `markProcessed: ${stamp?.reason ?? 'unknown'}`,
485
+ ];
486
+ return {
487
+ candidateId,
488
+ targetPath,
489
+ targetType,
490
+ decision: 'autonomous-apply',
491
+ detail: detailParts.join('; '),
492
+ };
493
+ } catch (err) {
494
+ // Apply/stamp threw — degrade to no-op so the loop continues.
495
+ return {
496
+ candidateId,
497
+ targetPath,
498
+ targetType,
499
+ decision: 'no-op',
500
+ detail: `autonomous-apply errored: ${err?.message ?? String(err)}`,
501
+ };
502
+ }
503
+ }
504
+
505
+ // Else — gate fail OR evidence below floor OR gate un-evaluable ⇒ open-mr
506
+ // (fallback; the MR carries the failing-gate context). [R7,R8,R9,R10,R17]
507
+ const fallbackDetail = `fallback to MR — ${gateDetail}; evidence ${
508
+ evidenceOk ? `≥ ${floor}` : `below ${floor} (or missing)`
509
+ }`;
510
+ return finishOpenMr({
511
+ candidate, candidateId, targetPath, targetType, repoRoot, dryRun, seams,
512
+ detail: fallbackDetail,
513
+ });
514
+ }
515
+
516
+ /**
517
+ * Build an `advisory-only` outcome.
518
+ * @returns {RepairOutcome}
519
+ */
520
+ function finishAdvisory({ candidateId, targetPath, targetType, detail }) {
521
+ return { candidateId, targetPath, targetType, decision: 'advisory-only', detail };
522
+ }
523
+
524
+ /**
525
+ * Open an MR for the candidate via the mr-opener seam, mapping its result to a
526
+ * matrix outcome. NEVER throws (the seam itself never throws, but we guard the
527
+ * call anyway). An MR opener `advisory`/`blocked` action maps to `advisory-only`
528
+ * / `no-op` respectively, with the opener's reason carried into `detail`.
529
+ *
530
+ * @returns {Promise<RepairOutcome>}
531
+ */
532
+ async function finishOpenMr({ candidate, candidateId, targetPath, targetType, repoRoot, dryRun, seams, detail }) {
533
+ let diff;
534
+ try {
535
+ diff = seams.buildDiff(candidate, repoRoot);
536
+ } catch (err) {
537
+ return {
538
+ candidateId, targetPath, targetType,
539
+ decision: 'no-op',
540
+ detail: `buildDiff errored: ${err?.message ?? String(err)}`,
541
+ };
542
+ }
543
+
544
+ let result;
545
+ try {
546
+ result = await seams.openRepairMr(
547
+ { candidate, diff, repoRoot, dryRun },
548
+ { log: seams.log },
549
+ );
550
+ } catch (err) {
551
+ return {
552
+ candidateId, targetPath, targetType,
553
+ decision: 'no-op',
554
+ detail: `openRepairMr errored: ${err?.message ?? String(err)}`,
555
+ };
556
+ }
557
+
558
+ const action = result && typeof result.action === 'string' ? result.action : 'advisory';
559
+ const reason = result && typeof result.reason === 'string' ? result.reason : '';
560
+ const combined = reason ? `${detail} → ${reason}` : detail;
561
+
562
+ if (action === 'mr-opened') {
563
+ const url = result.mrUrl ? ` (${result.mrUrl})` : '';
564
+ return { candidateId, targetPath, targetType, decision: 'open-mr', detail: `${combined}${url}` };
565
+ }
566
+ if (action === 'advisory') {
567
+ return { candidateId, targetPath, targetType, decision: 'open-mr', detail: combined };
568
+ }
569
+ // action === 'blocked' (gate failure inside the opener) → no-op.
570
+ return { candidateId, targetPath, targetType, decision: 'no-op', detail: `blocked: ${combined}` };
571
+ }
572
+
573
+ /**
574
+ * Run the C2 auto-repair engine.
575
+ *
576
+ * Composes the five W2 leaf modules into the gate-per-artifact-type decision
577
+ * matrix. NEVER throws — per-candidate failures degrade to `no-op` outcomes.
578
+ *
579
+ * @param {Object} params
580
+ * @param {string} params.repoRoot — absolute path to the repo root.
581
+ * @param {Record<string, unknown>|null} [params.config] — full parsed Session Config
582
+ * (the engine reads `config['skill-evolution']`).
583
+ * @param {Array<Record<string, unknown>>} [params.learnings] — `/evolve` learning records.
584
+ * @param {{ status?: string, errors?: Array<Record<string, unknown>> }|null} [params.driftResult]
585
+ * claude-md-drift-check output.
586
+ * @param {boolean} [params.dryRun=false] — when true, no mutation/MR/stamp; previews only.
587
+ * @param {Object} [opts] — DI seams (all default to the real sibling functions).
588
+ * @param {typeof realExtractCandidates} [opts.extractCandidates]
589
+ * @param {typeof realMergeCandidates} [opts.mergeCandidates]
590
+ * @param {typeof realMarkProcessed} [opts.markProcessed]
591
+ * @param {typeof realIsProcessed} [opts.isProcessed]
592
+ * @param {typeof realClassifyTarget} [opts.classifyTarget]
593
+ * @param {typeof realRunConfigValidationGate} [opts.runConfigValidationGate]
594
+ * @param {typeof realOpenRepairMr} [opts.openRepairMr]
595
+ * @param {(candidate: RepairCandidate, repoRoot?: string) => Promise<{ok:boolean, applied:boolean, reason?:string}>} [opts.applyConfigRepair]
596
+ * @param {(candidate: RepairCandidate, repoRoot?: string) => { content?: string, raw?: string }} [opts.buildDiff]
597
+ * @param {(level: string, msg: string) => void} [opts.log]
598
+ * @returns {Promise<RepairEngineResult>}
599
+ */
600
+ export async function runRepairEngine(
601
+ { repoRoot, config, learnings = [], driftResult = null, dryRun = false } = {},
602
+ opts = {},
603
+ ) {
604
+ // --- Resolve DI seams (real siblings as defaults) ------------------------
605
+ const seams = {
606
+ extractCandidates:
607
+ typeof opts.extractCandidates === 'function' ? opts.extractCandidates : realExtractCandidates,
608
+ mergeCandidates:
609
+ typeof opts.mergeCandidates === 'function' ? opts.mergeCandidates : realMergeCandidates,
610
+ markProcessed:
611
+ typeof opts.markProcessed === 'function' ? opts.markProcessed : realMarkProcessed,
612
+ isProcessed: typeof opts.isProcessed === 'function' ? opts.isProcessed : realIsProcessed,
613
+ classifyTarget:
614
+ typeof opts.classifyTarget === 'function' ? opts.classifyTarget : realClassifyTarget,
615
+ runConfigValidationGate:
616
+ typeof opts.runConfigValidationGate === 'function'
617
+ ? opts.runConfigValidationGate
618
+ : realRunConfigValidationGate,
619
+ openRepairMr: typeof opts.openRepairMr === 'function' ? opts.openRepairMr : realOpenRepairMr,
620
+ applyConfigRepair:
621
+ typeof opts.applyConfigRepair === 'function' ? opts.applyConfigRepair : defaultApplyConfigRepair,
622
+ buildDiff: typeof opts.buildDiff === 'function' ? opts.buildDiff : defaultBuildDiff,
623
+ log: typeof opts.log === 'function' ? opts.log : noopLog,
624
+ };
625
+
626
+ const se = readSkillEvolutionConfig(config);
627
+
628
+ /** @type {RepairOutcome[]} */
629
+ const outcomes = [];
630
+ const summary = { autonomousApplied: 0, mrsOpened: 0, advisories: 0, blocked: 0, total: 0 };
631
+
632
+ // --- Pipeline step 1 — intake (pure transform) ---------------------------
633
+ let candidates;
634
+ try {
635
+ candidates = seams.extractCandidates({
636
+ learnings,
637
+ driftResult,
638
+ repoRoot,
639
+ evidenceFloor: se.evidenceFloor,
640
+ });
641
+ } catch (err) {
642
+ seams.log('error', `engine: extractCandidates threw — ${err?.message ?? err}`);
643
+ candidates = [];
644
+ }
645
+ if (!Array.isArray(candidates)) candidates = [];
646
+
647
+ // Empty candidate set ⇒ outcomes:[], summary all-zero, touches no disk.
648
+ if (candidates.length === 0) {
649
+ return { outcomes, summary };
650
+ }
651
+
652
+ // --- Pipeline step 2 — merge (persist + supersede) -----------------------
653
+ try {
654
+ seams.mergeCandidates({ candidates, repoRoot });
655
+ } catch (err) {
656
+ seams.log('error', `engine: mergeCandidates threw — ${err?.message ?? err}`);
657
+ // Persistence failure is non-fatal: continue with the in-memory candidates.
658
+ }
659
+
660
+ // --- Pipeline step 3 — per-candidate classify → decide → act -------------
661
+ for (const candidate of candidates) {
662
+ // Guard a malformed candidate (no id / target_path) → no-op.
663
+ if (!candidate || typeof candidate.id !== 'string' || typeof candidate.target_path !== 'string') {
664
+ outcomes.push({
665
+ candidateId: candidate?.id ?? '(unknown)',
666
+ targetPath: candidate?.target_path ?? '(unknown)',
667
+ targetType: 'unknown',
668
+ decision: 'no-op',
669
+ detail: 'malformed candidate (missing id/target_path)',
670
+ });
671
+ continue;
672
+ }
673
+
674
+ // Skip candidates already processed (idempotency). Both branches assign.
675
+ let processed;
676
+ try {
677
+ processed = seams.isProcessed({ id: candidate.id, repoRoot });
678
+ } catch (err) {
679
+ seams.log('error', `engine: isProcessed threw — ${err?.message ?? err}`);
680
+ processed = false;
681
+ }
682
+ if (processed) {
683
+ outcomes.push({
684
+ candidateId: candidate.id,
685
+ targetPath: candidate.target_path,
686
+ targetType: 'unknown',
687
+ decision: 'no-op',
688
+ detail: 'already processed (idempotent skip)',
689
+ });
690
+ continue;
691
+ }
692
+
693
+ // Decide + act (never throws — degrades to no-op internally).
694
+ let outcome;
695
+ try {
696
+ outcome = await decideAndAct({ candidate, repoRoot, se, dryRun, seams });
697
+ } catch (err) {
698
+ outcome = {
699
+ candidateId: candidate.id,
700
+ targetPath: candidate.target_path,
701
+ targetType: 'unknown',
702
+ decision: 'no-op',
703
+ detail: `engine: decideAndAct threw — ${err?.message ?? String(err)}`,
704
+ };
705
+ }
706
+ outcomes.push(outcome);
707
+ }
708
+
709
+ // --- Summary tally -------------------------------------------------------
710
+ for (const o of outcomes) {
711
+ summary.total += 1;
712
+ if (o.decision === 'autonomous-apply') summary.autonomousApplied += 1;
713
+ else if (o.decision === 'open-mr') summary.mrsOpened += 1;
714
+ else if (o.decision === 'advisory-only') summary.advisories += 1;
715
+ else summary.blocked += 1; // 'no-op'
716
+ }
717
+
718
+ return { outcomes, summary };
719
+ }