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,247 @@
1
+ /**
2
+ * sessions-staleness-banner.mjs — #724
3
+ *
4
+ * Deterministic session-start nudge for the "close-through" gap: sessions
5
+ * that end (agents stop, work happens) without ever writing a
6
+ * `.orchestrator/metrics/sessions.jsonl` ledger record. W1-D4 fleet finding:
7
+ * 141 `orchestrator.session.started` events vs. 39 sessions.jsonl records in
8
+ * this repo (~27% close-through rate) — the ledger silently under-counts
9
+ * completed sessions with no signal to the operator.
10
+ *
11
+ * Mirrors the contract used by the sibling Phase 4 banners
12
+ * (`scripts/lib/reconcile-nudge-banner.mjs`, `scripts/lib/vault-staleness-banner.mjs`,
13
+ * `scripts/lib/loop-readiness-banner.mjs`): a single `checkXxx({repoRoot})`
14
+ * entry point that is COMPLETELY try/catch-wrapped (never throws) and returns
15
+ * either `null` (silent no-op) or `{severity:'warn'|'alert', message, ...extra}`.
16
+ *
17
+ * Design — self-exclusion over time, NOT lock-presence (load-bearing
18
+ * correction; see issue #724 discussion): Phase 4 always runs INSIDE an
19
+ * active session — Phase 1.2 has already acquired `.orchestrator/session.lock`
20
+ * by the time this probe fires. Gating on "no live lock" would make the
21
+ * banner structurally silent forever. Instead:
22
+ *
23
+ * - `lastLedgerAt` = `completed_at` of the last PARSEABLE
24
+ * `sessions.jsonl` record (scanned from EOF
25
+ * backward, skipping malformed lines).
26
+ * - `cutoff` = the CURRENT session's `session.lock`
27
+ * `started_at` (via `readLock()`); when no lock is
28
+ * readable, `cutoff = now` (all events count).
29
+ * - `lastForeignEventAt`= the NEWEST `events.jsonl` line whose `timestamp`
30
+ * is STRICTLY BEFORE `cutoff` — this structurally
31
+ * excludes the current session's own events without
32
+ * needing a `session_id` filter (most event lines
33
+ * don't carry one; see the mission-log sample in
34
+ * `.orchestrator/metrics/events.jsonl`).
35
+ * - `deltaHours` = (lastForeignEventAt − lastLedgerAt) / 1h, only
36
+ * meaningful when > 0 (foreign activity happened
37
+ * AFTER the last ledger entry).
38
+ *
39
+ * Severity: warn above `2 × DEFAULT_TTL_HOURS` (8h, imported from
40
+ * `session-lock.mjs` rather than duplicated), alert above 24h.
41
+ *
42
+ * Plain-JS — no Zod dependency. Never throws. Never mutates input. No
43
+ * `console.*` calls (repo ESLint `no-console` rule).
44
+ *
45
+ * Cross-references:
46
+ * - `.claude/rules/verification-before-completion.md` — evidence-before-claims.
47
+ * - `scripts/lib/session-lock.mjs` — `readLock()`, `DEFAULT_TTL_HOURS`.
48
+ * - `scripts/lib/reconcile-nudge-banner.mjs` / `vault-staleness-banner.mjs` /
49
+ * `loop-readiness-banner.mjs` — the banner-shape template.
50
+ * - `scripts/backfill-abandoned-sessions.mjs` — the CLI this banner's
51
+ * message recommends running (`--dry-run` is its default/safe mode).
52
+ * - `scripts/lib/session-close-backfill.mjs` — the backfill engine
53
+ * (`synthesizeRecord`) that produces the abandoned-session stubs seen in
54
+ * `sessions.jsonl` (e.g. `_backfill_source: "events-jsonl"`).
55
+ * - `skills/session-start/SKILL.md` Phase 4 — banner render site.
56
+ * - Issue #724.
57
+ */
58
+
59
+ import { existsSync, readFileSync } from 'node:fs';
60
+ import path from 'node:path';
61
+
62
+ import { readLock, DEFAULT_TTL_HOURS } from './session-lock.mjs';
63
+
64
+ /** Repo-relative path to the session ledger (one record per closed session). */
65
+ const SESSIONS_PATH = '.orchestrator/metrics/sessions.jsonl';
66
+
67
+ /** Repo-relative path to the generic telemetry stream (one line per event). */
68
+ const EVENTS_PATH = '.orchestrator/metrics/events.jsonl';
69
+
70
+ /** warn threshold: 2x the session-lock default TTL (8h) — imported, not duplicated. */
71
+ export const WARN_THRESHOLD_HOURS = DEFAULT_TTL_HOURS * 2;
72
+
73
+ /** alert threshold: a full day behind is a strong close-through signal. */
74
+ export const ALERT_THRESHOLD_HOURS = 24;
75
+
76
+ /**
77
+ * Read a JSONL file's non-empty lines. Returns `null` when the file is
78
+ * absent or unreadable, `[]` when it exists but has no non-empty lines.
79
+ * Never throws.
80
+ *
81
+ * @param {string} filePath
82
+ * @returns {string[]|null}
83
+ */
84
+ function readJsonlLines(filePath) {
85
+ if (!existsSync(filePath)) return null;
86
+ let raw;
87
+ try {
88
+ raw = readFileSync(filePath, 'utf8');
89
+ } catch {
90
+ return null;
91
+ }
92
+ return raw.split('\n').filter((line) => line.length > 0);
93
+ }
94
+
95
+ /**
96
+ * Scan `sessions.jsonl` lines from EOF backward and return the `completed_at`
97
+ * of the last PARSEABLE record that carries a valid ISO timestamp. Malformed
98
+ * or non-conforming lines (bad JSON, missing/invalid `completed_at`) are
99
+ * skipped, not treated as fatal.
100
+ *
101
+ * @param {string[]} lines
102
+ * @returns {{iso: string, ms: number}|null}
103
+ */
104
+ function lastLedgerEntry(lines) {
105
+ for (let i = lines.length - 1; i >= 0; i--) {
106
+ let record;
107
+ try {
108
+ record = JSON.parse(lines[i]);
109
+ } catch {
110
+ continue;
111
+ }
112
+ if (!record || typeof record !== 'object' || typeof record.completed_at !== 'string') continue;
113
+ const ms = Date.parse(record.completed_at);
114
+ if (!Number.isFinite(ms)) continue;
115
+ return { iso: record.completed_at, ms };
116
+ }
117
+ return null;
118
+ }
119
+
120
+ /**
121
+ * Scan ALL `events.jsonl` lines and return the newest one whose `timestamp`
122
+ * is strictly before `cutoffMs`. This is the self-exclusion mechanism: the
123
+ * current session's own events (all >= cutoff, since cutoff is this
124
+ * session's lock `started_at`) are structurally excluded without needing a
125
+ * `session_id` filter. Malformed lines and lines with a missing/invalid
126
+ * `timestamp` are skipped.
127
+ *
128
+ * @param {string[]} lines
129
+ * @param {number} cutoffMs
130
+ * @returns {{iso: string, ms: number}|null}
131
+ */
132
+ function newestForeignEvent(lines, cutoffMs) {
133
+ let best = null;
134
+ for (const line of lines) {
135
+ let record;
136
+ try {
137
+ record = JSON.parse(line);
138
+ } catch {
139
+ continue;
140
+ }
141
+ if (!record || typeof record !== 'object' || typeof record.timestamp !== 'string') continue;
142
+ const ms = Date.parse(record.timestamp);
143
+ if (!Number.isFinite(ms)) continue;
144
+ if (ms >= cutoffMs) continue; // not "foreign" — belongs to (or postdates) the current session
145
+ if (best === null || ms > best.ms) best = { iso: record.timestamp, ms };
146
+ }
147
+ return best;
148
+ }
149
+
150
+ /**
151
+ * Resolve the cutoff instant (in epoch ms) that separates "the current
152
+ * session's own events" from "foreign/pre-session events". Prefers the
153
+ * current session's `session.lock` `started_at`; falls back to `now` when no
154
+ * lock is readable (or its `started_at` is unparseable) — in that fallback
155
+ * case every events.jsonl line counts as a candidate "foreign" event.
156
+ *
157
+ * Known limitation: the cutoff uses `lock.started_at` as recorded at lock
158
+ * acquisition time — a `forceAcquire()` takeover (stale-lock override) or
159
+ * cross-machine clock skew can shift this value away from the wall-clock
160
+ * instant the CURRENT process actually started, which can widen or narrow
161
+ * the "foreign" window by the skew amount. This banner is advisory-only
162
+ * tolerance (a nudge, never a gate), so an imprecise cutoff only affects when
163
+ * the warn/alert nudge fires, never blocks anything.
164
+ *
165
+ * @param {string} repoRoot
166
+ * @param {number} nowMs
167
+ * @returns {number}
168
+ */
169
+ function resolveCutoffMs(repoRoot, nowMs) {
170
+ let lock;
171
+ try {
172
+ lock = readLock({ repoRoot });
173
+ } catch {
174
+ return nowMs;
175
+ }
176
+ if (!lock || typeof lock.started_at !== 'string') return nowMs;
177
+ const parsed = Date.parse(lock.started_at);
178
+ return Number.isFinite(parsed) ? parsed : nowMs;
179
+ }
180
+
181
+ /**
182
+ * Check sessions-ledger staleness and produce a session-start banner.
183
+ *
184
+ * Silent (`null`) when: `sessions.jsonl` is missing/empty/entirely
185
+ * unparseable, `events.jsonl` is missing/empty, no foreign (pre-cutoff)
186
+ * event exists, the foreign event is not after the last ledger entry, or the
187
+ * resulting gap is under the warn threshold. Never throws.
188
+ *
189
+ * @param {{repoRoot: string, now?: number}} opts
190
+ * - `repoRoot`: REQUIRED absolute path to the repo root.
191
+ * - `now`: optional injectable clock (epoch ms); defaults to `Date.now()`.
192
+ * Used only as the cutoff fallback when no session.lock is readable.
193
+ * @returns {null | {
194
+ * severity: 'warn'|'alert',
195
+ * message: string,
196
+ * lastLedgerAt: string,
197
+ * lastForeignEventAt: string,
198
+ * deltaHours: number,
199
+ * }}
200
+ */
201
+ export function checkSessionsStaleness({ repoRoot, now = Date.now() } = {}) {
202
+ try {
203
+ if (!repoRoot || typeof repoRoot !== 'string') return null;
204
+
205
+ const nowMs = typeof now === 'number' && Number.isFinite(now) ? now : Date.now();
206
+
207
+ const sessionLines = readJsonlLines(path.join(repoRoot, SESSIONS_PATH));
208
+ if (sessionLines === null || sessionLines.length === 0) return null;
209
+
210
+ const ledger = lastLedgerEntry(sessionLines);
211
+ if (ledger === null) return null;
212
+
213
+ const eventLines = readJsonlLines(path.join(repoRoot, EVENTS_PATH));
214
+ if (eventLines === null || eventLines.length === 0) return null;
215
+
216
+ const cutoffMs = resolveCutoffMs(repoRoot, nowMs);
217
+
218
+ const foreign = newestForeignEvent(eventLines, cutoffMs);
219
+ if (foreign === null) return null;
220
+
221
+ const deltaMs = foreign.ms - ledger.ms;
222
+ if (deltaMs <= 0) return null; // foreign activity is not AFTER the last ledger entry
223
+
224
+ const deltaHours = Math.round((deltaMs / 3600000) * 10) / 10;
225
+ if (deltaHours <= WARN_THRESHOLD_HOURS) return null;
226
+
227
+ const severity = deltaHours > ALERT_THRESHOLD_HOURS ? 'alert' : 'warn';
228
+
229
+ const base =
230
+ `sessions-staleness: last sessions.jsonl entry ${ledger.iso} is ${deltaHours}h behind ` +
231
+ `pre-session events.jsonl activity ${foreign.iso} — possible close-through gap ` +
232
+ `(sessions ended without a ledger record; run node scripts/backfill-abandoned-sessions.mjs --dry-run)`;
233
+
234
+ const message = severity === 'alert' ? `🚨 ${base} — gap exceeds 24h.` : `⚠ ${base}.`;
235
+
236
+ return {
237
+ severity,
238
+ message,
239
+ lastLedgerAt: ledger.iso,
240
+ lastForeignEventAt: foreign.iso,
241
+ deltaHours,
242
+ };
243
+ } catch {
244
+ // Defensive catch-all — banner must never throw.
245
+ return null;
246
+ }
247
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * blast-radius-classifier.mjs — R5 blast-radius classifier for the C2
3
+ * auto-repair engine (Epic #643 Skill Self-Evolution Foundation / issue #647).
4
+ *
5
+ * The heart of the gate-per-artifact-type design: maps a repair target's path
6
+ * to a `{ targetType, gate, posture }` triple that the auto-repair engine uses
7
+ * to decide whether a change may be applied autonomously (behind a gate) or
8
+ * must always go through a merge request.
9
+ *
10
+ * SECURITY (R5 traversal safety): the classifier is PATH-TRAVERSAL-SAFE and
11
+ * FAIL-CLOSED. `targetPath` is never trusted lexically — it is resolved against
12
+ * a canonicalised `repoRoot` and any path that escapes the repo (or is
13
+ * otherwise ambiguous) is classified as `unknown` with the safest posture
14
+ * (`always-mr`). The ONLY input that yields `autonomous-gated` is the repo's
15
+ * own ROOT `CLAUDE.md` / `AGENTS.md`.
16
+ *
17
+ * No throwing: every code path returns a valid classification triple.
18
+ *
19
+ * Consumers:
20
+ * - C2 auto-repair engine (issue #647) — decides apply-vs-MR per repair target.
21
+ */
22
+
23
+ import path from 'node:path';
24
+ import fs from 'node:fs';
25
+
26
+ /**
27
+ * @typedef {'plugin-skill' | 'local-skill' | 'local-config' | 'unknown'} TargetType
28
+ * @typedef {'none' | 'config-validation'} Gate
29
+ * @typedef {'always-mr' | 'autonomous-gated'} Posture
30
+ * @typedef {{ targetType: TargetType, gate: Gate, posture: Posture }} Classification
31
+ */
32
+
33
+ /**
34
+ * The fail-closed default: returned for any path that escapes the repo, is
35
+ * empty/ambiguous, or matches no known artifact type. Never silent-applies.
36
+ * @type {Classification}
37
+ */
38
+ const FAIL_CLOSED = Object.freeze({
39
+ targetType: 'unknown',
40
+ gate: 'none',
41
+ posture: 'always-mr',
42
+ });
43
+
44
+ /**
45
+ * Classify a repair target's path into its blast-radius triple.
46
+ *
47
+ * The path is resolved against a canonicalised `repoRoot` before any
48
+ * classification rule is applied; paths that resolve outside the repo are
49
+ * fail-closed to `unknown` / `always-mr`. Path rules are applied first-match-wins
50
+ * against the repo-relative POSIX path:
51
+ *
52
+ * 1. `.claude/skills` (or under it) → local-skill / none / always-mr
53
+ * 2. `skills` (or under it) → plugin-skill / none / always-mr
54
+ * 3. ROOT `CLAUDE.md` / `AGENTS.md` → local-config / config-validation / autonomous-gated
55
+ * 4. anything else → unknown / none / always-mr (fail-closed)
56
+ *
57
+ * @param {string} targetPath — repair target path (relative or absolute); not trusted lexically.
58
+ * @param {{ repoRoot: string }} options — `repoRoot` is the repository root to resolve against.
59
+ * @returns {Classification} the blast-radius triple; never throws.
60
+ */
61
+ export function classifyTarget(targetPath, { repoRoot } = {}) {
62
+ // Guard the inputs — fail-closed on anything we cannot work with.
63
+ if (typeof targetPath !== 'string' || typeof repoRoot !== 'string' || repoRoot.length === 0) {
64
+ return { ...FAIL_CLOSED };
65
+ }
66
+
67
+ // Canonicalise the repo root. realpathSync resolves symlinks so a symlinked
68
+ // repoRoot still anchors the escape check correctly. If it throws (e.g. the
69
+ // root does not exist yet), fall back to a lexical resolve.
70
+ let root;
71
+ try {
72
+ root = fs.realpathSync(path.resolve(repoRoot));
73
+ } catch {
74
+ root = path.resolve(repoRoot);
75
+ }
76
+
77
+ // Resolve the target against the canonical root, then compute the repo-relative
78
+ // path. We do NOT inspect `targetPath` lexically before this point.
79
+ const abs = path.resolve(root, targetPath);
80
+ let rel = path.relative(root, abs);
81
+
82
+ // ESCAPE CHECK (fail-closed): empty rel means the target IS the root itself;
83
+ // a `..` prefix or an absolute rel means the target escaped the repo. Either
84
+ // way → unknown / always-mr. Never throw.
85
+ if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) {
86
+ return { ...FAIL_CLOSED };
87
+ }
88
+
89
+ // Normalize separators to POSIX so the rules below are platform-independent.
90
+ rel = rel.split(path.sep).join('/');
91
+
92
+ // Rule 1 — local (project) skills under `.claude/skills`.
93
+ if (rel === '.claude/skills' || rel.startsWith('.claude/skills/')) {
94
+ return { targetType: 'local-skill', gate: 'none', posture: 'always-mr' };
95
+ }
96
+
97
+ // Rule 2 — plugin skills under `skills`.
98
+ if (rel === 'skills' || rel.startsWith('skills/')) {
99
+ return { targetType: 'plugin-skill', gate: 'none', posture: 'always-mr' };
100
+ }
101
+
102
+ // Rule 3 — ROOT instruction files ONLY (no path separator in rel). A nested
103
+ // `subdir/CLAUDE.md` falls through to the fail-closed default below.
104
+ if (rel === 'CLAUDE.md' || rel === 'AGENTS.md') {
105
+ return {
106
+ targetType: 'local-config',
107
+ gate: 'config-validation',
108
+ posture: 'autonomous-gated',
109
+ };
110
+ }
111
+
112
+ // Rule 4 — fail-closed default for everything else.
113
+ return { ...FAIL_CLOSED };
114
+ }
@@ -0,0 +1,270 @@
1
+ /**
2
+ * candidate-intake.mjs — Pure transform for the #647 C2 auto-repair engine.
3
+ *
4
+ * Ingests the two repair-candidate feeders and normalises them into a single
5
+ * `RepairCandidate[]` shape:
6
+ * 1. `/evolve` learnings (`.orchestrator/metrics/learnings.jsonl` records)
7
+ * 2. `claude-md-drift-check` output (`driftResult.errors[]`)
8
+ *
9
+ * This module is a PURE transform: it performs NO I/O. It never reads or writes
10
+ * any file. Persistence and the `processed_at` / `superseded_by` lifecycle are
11
+ * OWNED BY the sibling `idempotency.mjs` module — this module only emits the
12
+ * raw candidates with those fields nulled out.
13
+ *
14
+ * The `id` field is a deterministic short hash of (source, target_path,
15
+ * fingerprint), so the same input always yields the same id. That determinism
16
+ * is the idempotency key the sibling module relies on.
17
+ *
18
+ * Part of Epic #643 → issue #647 (C2 auto-repair engine).
19
+ */
20
+
21
+ import { createHash } from 'node:crypto';
22
+
23
+ /**
24
+ * @typedef {Object} RepairCandidate
25
+ * @property {string} id Deterministic short hash (idempotency key).
26
+ * @property {1} schema_version Schema version, always 1.
27
+ * @property {'evolve-learning'|'drift-check'} source Originating feeder.
28
+ * @property {string} source_ref Back-reference into the source feeder.
29
+ * @property {string} target_path Repo-relative path the repair targets.
30
+ * @property {number} evidence Numeric confidence/strength of the signal.
31
+ * @property {'confidence'|'filesystem-fact'} evidence_kind Interpretation of `evidence`.
32
+ * @property {string} proposed_change Short human-readable description of the fix.
33
+ * @property {string} rationale Why this candidate exists.
34
+ * @property {string} created_at ISO timestamp when the candidate was minted.
35
+ * @property {null} processed_at Always null (idempotency.mjs sets this later).
36
+ * @property {null} superseded_by Always null (idempotency.mjs sets this later).
37
+ */
38
+
39
+ /** Drift-check checks that map to error candidates → `proposed_change` template. */
40
+ const DRIFT_PROPOSED_CHANGE = {
41
+ 'path-resolver': () => 'Update/remove stale absolute path',
42
+ 'project-count-sync': () => 'Sync project count',
43
+ 'session-file-existence': () => 'Remove/repoint missing session-file ref',
44
+ 'issue-reference-freshness': () =>
45
+ 'Move/remove closed issue ref out of forward-looking section',
46
+ 'session-config-parity': () => 'Add missing Session Config key',
47
+ 'vault-dir-parity': () => 'Reconcile vault-dir between CLAUDE.md and AGENTS.md',
48
+ };
49
+
50
+ /** Path-extraction regex: repo-relative dir paths OR bare known-extension filenames. */
51
+ const PATH_RE =
52
+ /(scripts|skills|hooks|tests|docs)\/[\w./-]+|\b[\w-]+\.(mjs|md|json|js|ts)\b/;
53
+
54
+ /** Prescriptive-verb regex: the insight must propose an action, not merely describe. */
55
+ const PRESCRIPTIVE_RE =
56
+ /\b(fix|change|switch|default|pin|port|remove|add|update|replace|disable|enable|require)\b/i;
57
+
58
+ /** Drift-check statuses that mean "no candidates to emit". */
59
+ const DRIFT_INERT_STATUSES = new Set(['skipped', 'skipped-mode-off', undefined]);
60
+
61
+ /**
62
+ * Slugify a string for use inside the deterministic fingerprint. The exact form
63
+ * is internal (it only feeds the hash) — kebab-case, alnum-only, collapsed.
64
+ * @param {string} input
65
+ * @returns {string}
66
+ */
67
+ function slug(input) {
68
+ return String(input ?? '')
69
+ .toLowerCase()
70
+ .replace(/[^a-z0-9]+/g, '-')
71
+ .replace(/^-+|-+$/g, '');
72
+ }
73
+
74
+ /**
75
+ * Build the deterministic candidate id from its idempotency triple.
76
+ * @param {string} source
77
+ * @param {string} targetPath
78
+ * @param {string} fingerprint
79
+ * @returns {string}
80
+ */
81
+ function makeId(source, targetPath, fingerprint) {
82
+ const hash = createHash('sha256')
83
+ .update(source + '\0' + targetPath + '\0' + fingerprint)
84
+ .digest('hex')
85
+ .slice(0, 8);
86
+ return `rc-${hash}`;
87
+ }
88
+
89
+ /**
90
+ * Extract the first repo-relative path from a candidate's text fields.
91
+ * @param {string} text
92
+ * @returns {string|null}
93
+ */
94
+ function extractPath(text) {
95
+ const match = PATH_RE.exec(String(text ?? ''));
96
+ return match ? match[0] : null;
97
+ }
98
+
99
+ /**
100
+ * Map a single learning record to a RepairCandidate, or null when it fails any
101
+ * actionable filter. learnings.jsonl records are NOT uniform — only `confidence`
102
+ * and `created_at` are guaranteed — so id/subject/insight/evidence are handled
103
+ * defensively.
104
+ * @param {Record<string, unknown>} learning
105
+ * @param {number} evidenceFloor
106
+ * @param {string} nowIso
107
+ * @returns {RepairCandidate|null}
108
+ */
109
+ function learningToCandidate(learning, evidenceFloor, nowIso) {
110
+ if (!learning || typeof learning !== 'object') return null;
111
+
112
+ // Filter 1: confidence gate.
113
+ const confidence = /** @type {unknown} */ (learning.confidence);
114
+ if (typeof confidence !== 'number' || !Number.isFinite(confidence)) return null;
115
+ if (confidence < evidenceFloor) return null;
116
+
117
+ // Filter 4: not expired (missing expires_at ⇒ live).
118
+ const expiresAt = learning.expires_at;
119
+ if (typeof expiresAt === 'string' && expiresAt.length > 0 && expiresAt < nowIso) {
120
+ return null;
121
+ }
122
+
123
+ const subject = typeof learning.subject === 'string' ? learning.subject : '';
124
+ const insight = typeof learning.insight === 'string' ? learning.insight : '';
125
+
126
+ // Filter 2: resolvable target path from subject OR insight.
127
+ const targetPath = extractPath(subject) ?? extractPath(insight);
128
+ if (!targetPath) return null;
129
+
130
+ // Filter 3: insight must be prescriptive.
131
+ if (!PRESCRIPTIVE_RE.test(insight)) return null;
132
+
133
+ const source = 'evolve-learning';
134
+ const sourceRef = typeof learning.id === 'string' && learning.id.length > 0
135
+ ? learning.id
136
+ : null;
137
+ const fingerprint = slug(targetPath + '-' + insight.slice(0, 80));
138
+
139
+ return {
140
+ id: makeId(source, targetPath, fingerprint),
141
+ schema_version: 1,
142
+ source,
143
+ source_ref: sourceRef,
144
+ target_path: targetPath,
145
+ evidence: confidence,
146
+ evidence_kind: 'confidence',
147
+ proposed_change: insight,
148
+ rationale: `evolve learning (confidence ${confidence}): ${insight}`,
149
+ created_at: nowIso,
150
+ processed_at: null,
151
+ superseded_by: null,
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Map a single drift-check error to a RepairCandidate. Drift errors are
157
+ * filesystem facts (evidence 1.0). Unknown checks fall back to a generic
158
+ * proposed-change derived from the check name.
159
+ * @param {Record<string, unknown>} err
160
+ * @param {string} nowIso
161
+ * @returns {RepairCandidate|null}
162
+ */
163
+ function driftErrorToCandidate(err, nowIso) {
164
+ if (!err || typeof err !== 'object') return null;
165
+
166
+ const check = typeof err.check === 'string' ? err.check : '';
167
+ const file = typeof err.file === 'string' ? err.file : '';
168
+ const line = err.line ?? '';
169
+ const message = typeof err.message === 'string' ? err.message : '';
170
+
171
+ // target_path is required — drift errors carry a repo-relative file already.
172
+ if (!file) return null;
173
+
174
+ const source = 'drift-check';
175
+ const sourceRef = `${check}:${file}:${line}`;
176
+
177
+ // Per-check proposed-change templates; command-count needs the actual count.
178
+ let proposedChange;
179
+ if (check === 'command-count') {
180
+ // Prefer the STRUCTURED bare claimed number (checker.mjs:495 exposes
181
+ // `command_count: { actual, claimed }` where `claimed` is `parseInt(m[1])`).
182
+ // `err.extracted` is the FULL regex match (e.g. "8 commands"); using it here
183
+ // produced the malformed double-word `'8 commands commands'` that the engine
184
+ // whitelist regex (engine.mjs COMMAND_COUNT_SHAPE) correctly rejects — making
185
+ // autonomous-apply dead code for this shape (#651 FIX 1).
186
+ const claimed =
187
+ (err.command_count && typeof err.command_count === 'object' && err.command_count !== null
188
+ ? /** @type {Record<string, unknown>} */ (err.command_count).claimed
189
+ : undefined) ?? err.extracted ?? '?';
190
+ const actual =
191
+ err.command_count && typeof err.command_count === 'object' && err.command_count !== null
192
+ ? /** @type {Record<string, unknown>} */ (err.command_count).actual ?? '?'
193
+ : '?';
194
+ proposedChange = `Update narrative '${claimed} commands' to actual ${actual}`;
195
+ } else if (Object.prototype.hasOwnProperty.call(DRIFT_PROPOSED_CHANGE, check)) {
196
+ proposedChange = DRIFT_PROPOSED_CHANGE[check]();
197
+ } else {
198
+ proposedChange = `Resolve drift-check '${check}'`;
199
+ }
200
+
201
+ const fingerprint = slug(file + '-' + message.slice(0, 80));
202
+
203
+ return {
204
+ id: makeId(source, file, fingerprint),
205
+ schema_version: 1,
206
+ source,
207
+ source_ref: sourceRef,
208
+ target_path: file,
209
+ evidence: 1.0,
210
+ evidence_kind: 'filesystem-fact',
211
+ proposed_change: proposedChange,
212
+ rationale: message,
213
+ created_at: nowIso,
214
+ processed_at: null,
215
+ superseded_by: null,
216
+ };
217
+ }
218
+
219
+ /**
220
+ * Ingest the two repair-candidate feeders and return a normalised
221
+ * `RepairCandidate[]`. Pure transform — performs no I/O.
222
+ *
223
+ * @param {Object} params
224
+ * @param {Array<Record<string, unknown>>} [params.learnings] - `/evolve` learning records.
225
+ * @param {{ status?: string, errors?: Array<Record<string, unknown>>, warnings?: unknown[] }|null} [params.driftResult]
226
+ * claude-md-drift-check output. Only `errors[]` are mapped; `warnings[]`
227
+ * are skipped. A null result, or a status of `skipped`/`skipped-mode-off`/
228
+ * undefined, emits zero drift candidates.
229
+ * @param {string} [params.repoRoot] - repo root (accepted for caller symmetry; unused in the pure transform).
230
+ * @param {number} [params.evidenceFloor=0.5] - minimum learning confidence to qualify.
231
+ * @param {string} [params.now] - ISO timestamp for `created_at` + expiry checks (test determinism).
232
+ * @returns {RepairCandidate[]}
233
+ */
234
+ export function extractCandidates({
235
+ learnings,
236
+ driftResult,
237
+ // eslint-disable-next-line no-unused-vars -- accepted for caller symmetry; pure transform does no path resolution
238
+ repoRoot,
239
+ evidenceFloor = 0.5,
240
+ now,
241
+ } = {}) {
242
+ const nowIso = typeof now === 'string' && now.length > 0 ? now : new Date().toISOString();
243
+ const floor = Number.isFinite(evidenceFloor) ? evidenceFloor : 0.5;
244
+
245
+ /** @type {RepairCandidate[]} */
246
+ const candidates = [];
247
+
248
+ // Feeder 1: /evolve learnings.
249
+ if (Array.isArray(learnings)) {
250
+ for (const learning of learnings) {
251
+ const candidate = learningToCandidate(learning, floor, nowIso);
252
+ if (candidate) candidates.push(candidate);
253
+ }
254
+ }
255
+
256
+ // Feeder 2: drift-check errors (skip when inert).
257
+ if (
258
+ driftResult &&
259
+ typeof driftResult === 'object' &&
260
+ !DRIFT_INERT_STATUSES.has(driftResult.status) &&
261
+ Array.isArray(driftResult.errors)
262
+ ) {
263
+ for (const err of driftResult.errors) {
264
+ const candidate = driftErrorToCandidate(err, nowIso);
265
+ if (candidate) candidates.push(candidate);
266
+ }
267
+ }
268
+
269
+ return candidates;
270
+ }