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,507 @@
1
+ /**
2
+ * mr-opener.mjs — Open a merge/pull request for an MR-tier repair candidate
3
+ * (Epic #643 Skill Self-Evolution Foundation / issue #647 — C2 auto-repair engine).
4
+ *
5
+ * MR-tier candidates are `plugin-skill` / `local-skill` targets. Per the
6
+ * blast-radius classifier (`blast-radius-classifier.mjs`), these are ALWAYS
7
+ * routed through a merge request — never applied autonomously. This module
8
+ * carries the candidate's diff onto a real branch and opens a draft MR/PR.
9
+ *
10
+ * DESIGN: heavy REUSE of existing modules. The ONE net-new primitive is the
11
+ * git add/commit/push triple. Everything else delegates:
12
+ * - `validateMrInputs` / `buildMrBody` / `maybeCreateDraftMR` ← mr-draft.mjs
13
+ * - VCS auto-detect (`bin: 'glab'|'gh'|null`) ← vcs-detector.mjs
14
+ * - owner-leakage gate (CLI script, scans TRACKED files) ← check-owner-leakage.mjs
15
+ * - conditional slopcheck gate (`classifyPackages`) ← slopcheck.mjs
16
+ *
17
+ * CONTRACT: NEVER throws. Every failure path degrades to an advisory or blocked
18
+ * result. glab/gh absence or dry-run → `advisory`. Gate failure → `blocked`.
19
+ *
20
+ * SECURITY: all subprocess invocations use execFile arg-vectors (shell:false) —
21
+ * never shell-string interpolation (RCE surface). Branch/title/description are
22
+ * validated via `validateMrInputs` (newline/null-byte guard) before use.
23
+ *
24
+ * DEPENDENCY-INJECTION: every external seam is injectable via `opts` so the
25
+ * whole flow is testable without real git/glab/gh:
26
+ * - opts.execFile — promisified execFile for glab/gh mr-create (mr-draft seam)
27
+ * - opts.git — async ({ args, cwd }) => { stdout } git runner
28
+ * - opts.leakageScan— async ({ repoRoot }) => { ok, exitCode } owner-leakage gate
29
+ * - opts.slopcheck — async (pkgs, { repoRoot }) => Array<{classification}>
30
+ * - opts.vcsDetect — ({ config, projectRoot }) => { bin } VCS detector
31
+ * - opts.createMr — async (loop, draftOpts) => { created, mrUrl } MR opener
32
+ * - opts.log — (level, msg) => void diagnostic logger
33
+ */
34
+
35
+ import { execFile as execFileCb, spawnSync } from 'node:child_process';
36
+ import { promisify } from 'node:util';
37
+ import path from 'node:path';
38
+ import { fileURLToPath } from 'node:url';
39
+
40
+ import {
41
+ validateMrInputs,
42
+ buildMrBody,
43
+ maybeCreateDraftMR,
44
+ MrDraftError,
45
+ } from '../autopilot/mr-draft.mjs';
46
+ import { detectVcsCommand } from '../tmux-layout/vcs-detector.mjs';
47
+ import { classifyPackages } from '../slopcheck.mjs';
48
+
49
+ const realExecFile = promisify(execFileCb);
50
+
51
+ /** Absolute path to the owner-leakage CLI scanner (a script, not an importable fn). */
52
+ const OWNER_LEAKAGE_SCRIPT = fileURLToPath(
53
+ new URL('../validate/check-owner-leakage.mjs', import.meta.url),
54
+ );
55
+
56
+ /**
57
+ * @typedef {Object} RepairCandidate
58
+ * @property {string} id Deterministic short hash (idempotency key).
59
+ * @property {string} target_path Repo-relative path the repair targets.
60
+ * @property {string} [proposed_change] Human-readable description of the fix.
61
+ * @property {string} [rationale] Why this candidate exists.
62
+ * @property {string} [source_ref] Back-reference into the source feeder.
63
+ */
64
+
65
+ /**
66
+ * @typedef {Object} RepairDiff
67
+ * @property {string} [content] Full new file content to write at target_path.
68
+ * @property {string} [raw] Raw unified-diff text (used for the pre-commit
69
+ * owner-leakage preview + package-add detection).
70
+ */
71
+
72
+ /**
73
+ * @typedef {Object} OpenRepairMrResult
74
+ * @property {boolean} ok
75
+ * @property {'mr-opened'|'advisory'|'blocked'} action
76
+ * @property {string} [mrUrl]
77
+ * @property {string} [reason]
78
+ * @property {{ ownerLeakage: 'pass'|'fail', slopcheck?: 'pass'|'fail'|'skipped' }} [gate]
79
+ */
80
+
81
+ // ---------------------------------------------------------------------------
82
+ // Net-new primitive: git runner (injectable)
83
+ // ---------------------------------------------------------------------------
84
+
85
+ /**
86
+ * Default git runner — execFile arg-vector, shell:false. Never interpolates a
87
+ * shell string. Resolves `{ stdout }`; rejects on non-zero exit (the caller
88
+ * wraps this in try/catch and degrades to advisory).
89
+ *
90
+ * @param {{ args: string[], cwd: string }} arg0
91
+ * @returns {Promise<{ stdout: string }>}
92
+ */
93
+ async function defaultGit({ args, cwd }) {
94
+ const { stdout } = await realExecFile('git', args, {
95
+ cwd,
96
+ shell: false,
97
+ timeout: 30_000,
98
+ maxBuffer: 1024 * 1024,
99
+ });
100
+ return { stdout: stdout ?? '' };
101
+ }
102
+
103
+ /**
104
+ * Default owner-leakage gate — spawns the CLI scanner against the committed
105
+ * worktree. Exit 0 = clean, non-zero = leak. Never throws; on spawn error
106
+ * (e.g. ENOENT) returns `{ ok: false }` so the caller can decide. We treat a
107
+ * spawn FAILURE distinctly from a leak DETECTION via the `spawnError` flag.
108
+ *
109
+ * @param {{ repoRoot: string }} arg0
110
+ * @returns {Promise<{ ok: boolean, exitCode: number, spawnError?: boolean }>}
111
+ */
112
+ async function defaultLeakageScan({ repoRoot }) {
113
+ const result = spawnSync('node', [OWNER_LEAKAGE_SCRIPT, repoRoot], {
114
+ encoding: 'utf8',
115
+ timeout: 30_000,
116
+ maxBuffer: 4 * 1024 * 1024,
117
+ });
118
+ if (result.error) {
119
+ // Scanner could not run at all — surface as a spawn error, not a leak.
120
+ return { ok: false, exitCode: -1, spawnError: true };
121
+ }
122
+ return { ok: result.status === 0, exitCode: result.status ?? -1 };
123
+ }
124
+
125
+ // ---------------------------------------------------------------------------
126
+ // Package-add detection (slopcheck gate trigger)
127
+ // ---------------------------------------------------------------------------
128
+
129
+ /**
130
+ * Detect newly-ADDED package dependencies in a raw unified diff. Only lines that
131
+ * START with a single `+` (added) within a manifest hunk are considered. Returns
132
+ * a `{ name, registry }[]` for slopcheck. Pure prose/config diffs → [].
133
+ *
134
+ * Supported manifests: package.json (npm), requirements.txt (pip),
135
+ * Cargo.toml (cargo). Detection is intentionally conservative — when in doubt
136
+ * it emits nothing (slopcheck then reports 'skipped').
137
+ *
138
+ * @param {string|undefined} rawDiff
139
+ * @returns {Array<{ name: string, registry: 'npm'|'pip'|'cargo' }>}
140
+ */
141
+ export function detectAddedPackages(rawDiff) {
142
+ if (typeof rawDiff !== 'string' || rawDiff.length === 0) return [];
143
+
144
+ const pkgs = [];
145
+ const seen = new Set();
146
+ let registry = null; // active manifest registry, set by the +++ file header
147
+
148
+ const add = (name, reg) => {
149
+ const key = `${reg}:${name}`;
150
+ if (name && !seen.has(key)) {
151
+ seen.add(key);
152
+ pkgs.push({ name, registry: reg });
153
+ }
154
+ };
155
+
156
+ for (const line of rawDiff.split('\n')) {
157
+ // File header sets the active registry for subsequent + lines.
158
+ if (line.startsWith('+++ ') || line.startsWith('diff --git')) {
159
+ if (/package\.json\b/.test(line)) registry = 'npm';
160
+ else if (/requirements\.txt\b/.test(line)) registry = 'pip';
161
+ else if (/Cargo\.toml\b/.test(line)) registry = 'cargo';
162
+ else registry = null;
163
+ continue;
164
+ }
165
+ // Only consider added lines (single leading '+', not the '+++' header).
166
+ if (!line.startsWith('+') || line.startsWith('+++')) continue;
167
+ if (registry === null) continue;
168
+
169
+ const added = line.slice(1).trim();
170
+ if (added.length === 0) continue;
171
+
172
+ if (registry === 'npm') {
173
+ // npm dependency line: "name": "^1.2.3" (scope-aware).
174
+ const m = added.match(/^"(@?[a-z0-9~][\w.~/-]*)"\s*:/i);
175
+ if (m) add(m[1], 'npm');
176
+ } else if (registry === 'pip') {
177
+ // requirements line: name==1.2.3 / name>=1.0 / name (skip comments).
178
+ if (added.startsWith('#')) continue;
179
+ const m = added.match(/^([A-Za-z0-9][\w.-]*)/);
180
+ if (m) add(m[1], 'pip');
181
+ } else if (registry === 'cargo') {
182
+ // Cargo.toml dependency line: name = "1.2.3" (skip table headers).
183
+ if (added.startsWith('[')) continue;
184
+ const m = added.match(/^([A-Za-z0-9][\w-]*)\s*=/);
185
+ if (m) add(m[1], 'cargo');
186
+ }
187
+ }
188
+
189
+ return pkgs;
190
+ }
191
+
192
+ // ---------------------------------------------------------------------------
193
+ // Internal helpers
194
+ // ---------------------------------------------------------------------------
195
+
196
+ /**
197
+ * Map a `vcsDetect().bin` value ('glab'|'gh'|null) to the loop.vcs token
198
+ * ('gitlab'|'github') that maybeCreateDraftMR expects.
199
+ * @param {string|null|undefined} bin
200
+ * @returns {'gitlab'|'github'|null}
201
+ */
202
+ function binToVcs(bin) {
203
+ if (bin === 'glab') return 'gitlab';
204
+ if (bin === 'gh') return 'github';
205
+ return null;
206
+ }
207
+
208
+ /**
209
+ * Normalise the caller-supplied `vcs` argument OR detector result into a
210
+ * `{ bin, vcs }` pair. The explicit `vcs` arg wins; otherwise we auto-detect.
211
+ * @param {*} vcsArg Caller arg: 'gitlab'|'github'|'glab'|'gh'|undefined.
212
+ * @param {Function} vcsDetect detectVcsCommand seam.
213
+ * @param {string} repoRoot
214
+ * @returns {{ bin: 'glab'|'gh'|null, vcs: 'gitlab'|'github'|null }}
215
+ */
216
+ function resolveVcs(vcsArg, vcsDetect, repoRoot) {
217
+ if (vcsArg === 'gitlab' || vcsArg === 'glab') return { bin: 'glab', vcs: 'gitlab' };
218
+ if (vcsArg === 'github' || vcsArg === 'gh') return { bin: 'gh', vcs: 'github' };
219
+
220
+ // Auto-detect via the seam. Pass vcs through Session-Config-shaped `config`.
221
+ let detected;
222
+ try {
223
+ detected = vcsDetect({ config: {}, projectRoot: repoRoot }) ?? {};
224
+ } catch {
225
+ detected = {};
226
+ }
227
+ const bin = detected.bin === 'glab' || detected.bin === 'gh' ? detected.bin : null;
228
+ return { bin, vcs: binToVcs(bin) };
229
+ }
230
+
231
+ /**
232
+ * Build a safe MR title + body from the candidate. Title is validated for
233
+ * newline/null-byte safety via validateMrInputs before any subprocess use.
234
+ * @param {RepairCandidate} candidate
235
+ * @returns {{ title: string, description: string }}
236
+ */
237
+ function buildCandidateMrBody(candidate) {
238
+ const proposed = candidate.proposed_change || 'skill repair';
239
+ const built = buildMrBody({
240
+ issueTitle: `Auto-repair: ${proposed}`,
241
+ issueIid: candidate.source_ref ?? candidate.id ?? 'unknown',
242
+ parentRunId: `repair/${candidate.id ?? 'unknown'}`,
243
+ worktreePath: candidate.target_path ?? '(unknown)',
244
+ });
245
+ // Validate the user/feeder-derived title before it reaches any execFile.
246
+ validateMrInputs(built.title, '');
247
+ return built;
248
+ }
249
+
250
+ // ---------------------------------------------------------------------------
251
+ // Public API
252
+ // ---------------------------------------------------------------------------
253
+
254
+ /**
255
+ * Open a draft merge/pull request for an MR-tier repair candidate.
256
+ *
257
+ * Flow (see issue #647 spec):
258
+ * 1. dryRun → owner-leakage preview (best-effort) + MR-body build → advisory.
259
+ * 2. Resolve VCS; no glab/gh → advisory.
260
+ * 3. Create branch + write change + git add/commit/push (net-new primitive).
261
+ * 4. GATE owner-leakage (always) → fail = blocked.
262
+ * 5. GATE slopcheck (only when the diff ADDS a package) → SLOP = blocked.
263
+ * 6. Open the MR → mr-opened. ENOENT/exec failure → advisory.
264
+ *
265
+ * NEVER throws — every error path degrades to advisory or blocked.
266
+ *
267
+ * @param {{ candidate: RepairCandidate, diff: RepairDiff, repoRoot: string, dryRun?: boolean, vcs?: string }} arg0
268
+ * @param {object} [opts] dependency-injection seams (see module JSDoc).
269
+ * @returns {Promise<OpenRepairMrResult>}
270
+ */
271
+ export async function openRepairMr(
272
+ { candidate, diff, repoRoot, dryRun = false, vcs } = {},
273
+ opts = {},
274
+ ) {
275
+ const log = typeof opts.log === 'function' ? opts.log : () => {};
276
+
277
+ // Seam resolution — real implementations are the defaults; opts override.
278
+ const git = typeof opts.git === 'function' ? opts.git : defaultGit;
279
+ const leakageScan =
280
+ typeof opts.leakageScan === 'function' ? opts.leakageScan : defaultLeakageScan;
281
+ const slopcheck = typeof opts.slopcheck === 'function' ? opts.slopcheck : classifyPackages;
282
+ const vcsDetect = typeof opts.vcsDetect === 'function' ? opts.vcsDetect : detectVcsCommand;
283
+ const createMr = typeof opts.createMr === 'function' ? opts.createMr : maybeCreateDraftMR;
284
+
285
+ // --- Input guard (never throw) ---
286
+ if (!candidate || typeof candidate !== 'object' || typeof candidate.id !== 'string') {
287
+ log('error', 'mr-opener: missing/invalid candidate');
288
+ return { ok: false, action: 'advisory', reason: 'invalid candidate input' };
289
+ }
290
+ if (typeof repoRoot !== 'string' || repoRoot.length === 0) {
291
+ log('error', 'mr-opener: missing repoRoot');
292
+ return { ok: false, action: 'advisory', reason: 'invalid repoRoot input' };
293
+ }
294
+ const safeDiff = diff && typeof diff === 'object' ? diff : {};
295
+
296
+ // Branch name derived from the candidate id (validated for arg safety).
297
+ const branch = `repair/${candidate.id}`;
298
+ try {
299
+ validateMrInputs(branch, '');
300
+ } catch (err) {
301
+ log('error', `mr-opener: unsafe branch name — ${err.message}`);
302
+ return { ok: false, action: 'advisory', reason: 'unsafe branch name derived from candidate id' };
303
+ }
304
+
305
+ // Validate the candidate-derived MR title up front (newline/null-byte guard)
306
+ // so a malformed candidate fails fast as advisory — BEFORE any git work. The
307
+ // authoritative title/body is built later by the createMr seam.
308
+ try {
309
+ buildCandidateMrBody(candidate);
310
+ } catch (err) {
311
+ const msg = err instanceof MrDraftError ? err.message : String(err?.message ?? err);
312
+ log('error', `mr-opener: MR body build failed — ${msg}`);
313
+ return { ok: false, action: 'advisory', reason: `MR body validation failed: ${msg}` };
314
+ }
315
+
316
+ // -----------------------------------------------------------------------
317
+ // Step 1 — dry-run preview. No push, no MR. Best-effort leakage pre-check.
318
+ // -----------------------------------------------------------------------
319
+ if (dryRun === true) {
320
+ // The leakage scanner only inspects TRACKED files, so a true pre-commit
321
+ // scan is not feasible without a commit. We mark the gate 'pass' optimistically
322
+ // for the preview and let the real path run the authoritative scan.
323
+ log('info', `mr-opener: dry-run preview for ${branch} — no MR opened`);
324
+ return {
325
+ ok: true,
326
+ action: 'advisory',
327
+ reason: 'dry-run preview — no MR opened',
328
+ gate: { ownerLeakage: 'pass' },
329
+ };
330
+ }
331
+
332
+ // -----------------------------------------------------------------------
333
+ // Step 2 — resolve VCS. No glab/gh → advisory.
334
+ // -----------------------------------------------------------------------
335
+ const { bin, vcs: resolvedVcs } = resolveVcs(vcs, vcsDetect, repoRoot);
336
+ if (bin === null || resolvedVcs === null) {
337
+ log('info', 'mr-opener: no glab/gh available — advisory only');
338
+ return {
339
+ ok: true,
340
+ action: 'advisory',
341
+ reason: 'glab/gh not installed — advisory only',
342
+ };
343
+ }
344
+
345
+ // -----------------------------------------------------------------------
346
+ // Step 3 — create branch + write change + git add/commit/push (net-new).
347
+ // -----------------------------------------------------------------------
348
+ try {
349
+ await git({ args: ['checkout', '-B', branch], cwd: repoRoot });
350
+
351
+ // Write the candidate's change into the target file (when content provided).
352
+ if (typeof safeDiff.content === 'string' && typeof candidate.target_path === 'string') {
353
+ const abs = path.resolve(repoRoot, candidate.target_path);
354
+ // R5 defense-in-depth: never write outside the repo even if a future differ
355
+ // populates `content` from a candidate-influenced target_path (mirrors the
356
+ // fail-closed escape check in blast-radius-classifier.mjs).
357
+ const rel = path.relative(repoRoot, abs);
358
+ if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) {
359
+ log('error', `mr-opener: target_path escapes repo (${candidate.target_path}) — blocked`);
360
+ return { ok: false, action: 'blocked', reason: 'target_path escapes repo' };
361
+ }
362
+ const writeFile =
363
+ typeof opts.writeFile === 'function'
364
+ ? opts.writeFile
365
+ : (await import('node:fs/promises')).writeFile;
366
+ await writeFile(abs, safeDiff.content, 'utf8');
367
+ }
368
+
369
+ await git({ args: ['add', '--', candidate.target_path ?? '.'], cwd: repoRoot });
370
+ const commitMsg = `fix(skill-evolution): auto-repair ${candidate.target_path ?? candidate.id}`;
371
+ await git({ args: ['commit', '-m', commitMsg], cwd: repoRoot });
372
+ } catch (err) {
373
+ if (err && err.code === 'ENOENT') {
374
+ log('error', 'mr-opener: git binary not found — advisory only');
375
+ return { ok: true, action: 'advisory', reason: 'git not installed — advisory only' };
376
+ }
377
+ log('error', `mr-opener: branch/commit failed — ${err?.message ?? err}`);
378
+ return {
379
+ ok: true,
380
+ action: 'advisory',
381
+ reason: `git branch/commit failed: ${err?.message ?? 'unknown error'}`,
382
+ };
383
+ }
384
+
385
+ // -----------------------------------------------------------------------
386
+ // Step 4 — GATE owner-leakage (always). Runs AFTER commit, BEFORE push.
387
+ // -----------------------------------------------------------------------
388
+ let leak;
389
+ try {
390
+ leak = await leakageScan({ repoRoot });
391
+ } catch (err) {
392
+ log('error', `mr-opener: leakage scan threw — ${err?.message ?? err}`);
393
+ // Fail-closed on scan error: we cannot prove the diff is clean → block.
394
+ return {
395
+ ok: false,
396
+ action: 'blocked',
397
+ reason: 'owner-leakage scan failed to run',
398
+ gate: { ownerLeakage: 'fail' },
399
+ };
400
+ }
401
+ if (!leak || leak.ok !== true) {
402
+ const reason = leak?.spawnError
403
+ ? 'owner-leakage scan failed to run'
404
+ : 'owner-leakage detected';
405
+ log('warn', `mr-opener: owner-leakage gate failed (${reason})`);
406
+ return {
407
+ ok: false,
408
+ action: 'blocked',
409
+ reason,
410
+ gate: { ownerLeakage: 'fail' },
411
+ };
412
+ }
413
+
414
+ // -----------------------------------------------------------------------
415
+ // Step 5 — GATE slopcheck (CONDITIONAL — only when the diff ADDS a package).
416
+ // -----------------------------------------------------------------------
417
+ let slopStatus = 'skipped';
418
+ const addedPkgs = detectAddedPackages(safeDiff.raw);
419
+ if (addedPkgs.length > 0) {
420
+ let classified;
421
+ try {
422
+ classified = await slopcheck(addedPkgs, { repoRoot });
423
+ } catch (err) {
424
+ log('error', `mr-opener: slopcheck threw — ${err?.message ?? err}`);
425
+ // slopcheck itself never throws, but the seam might be mocked to. Fail-closed.
426
+ return {
427
+ ok: false,
428
+ action: 'blocked',
429
+ reason: 'slopcheck failed to run',
430
+ gate: { ownerLeakage: 'pass', slopcheck: 'fail' },
431
+ };
432
+ }
433
+ const hasSlop =
434
+ Array.isArray(classified) && classified.some((c) => c?.classification === 'SLOP');
435
+ if (hasSlop) {
436
+ const slopName =
437
+ classified.find((c) => c?.classification === 'SLOP')?.name ?? 'unknown';
438
+ log('warn', `mr-opener: slopcheck gate failed — SLOP package '${slopName}'`);
439
+ return {
440
+ ok: false,
441
+ action: 'blocked',
442
+ reason: 'slop package',
443
+ gate: { ownerLeakage: 'pass', slopcheck: 'fail' },
444
+ };
445
+ }
446
+ slopStatus = 'pass';
447
+ }
448
+
449
+ const gate = { ownerLeakage: 'pass', slopcheck: slopStatus };
450
+
451
+ // -----------------------------------------------------------------------
452
+ // Step 6 — push + open the draft MR/PR. ENOENT/exec failure → advisory.
453
+ // -----------------------------------------------------------------------
454
+ try {
455
+ await git({ args: ['push', '--set-upstream', 'origin', branch], cwd: repoRoot });
456
+ } catch (err) {
457
+ if (err && err.code === 'ENOENT') {
458
+ log('error', 'mr-opener: git push — binary not found — advisory only');
459
+ return { ok: true, action: 'advisory', reason: 'git not installed — advisory only', gate };
460
+ }
461
+ log('error', `mr-opener: git push failed — ${err?.message ?? err}`);
462
+ return {
463
+ ok: true,
464
+ action: 'advisory',
465
+ reason: `git push failed: ${err?.message ?? 'unknown error'}`,
466
+ gate,
467
+ };
468
+ }
469
+
470
+ // Delegate MR creation to the mr-draft seam (collision check + draft create).
471
+ let mrResult;
472
+ try {
473
+ mrResult = await createMr(
474
+ {
475
+ draftMrPolicy: 'on-loop-start',
476
+ vcs: resolvedVcs,
477
+ issueIid: candidate.source_ref ?? candidate.id,
478
+ issueTitle: `Auto-repair: ${candidate.proposed_change || 'skill repair'}`,
479
+ branchName: branch,
480
+ parentRunId: `repair/${candidate.id}`,
481
+ worktreePath: candidate.target_path ?? '(unknown)',
482
+ },
483
+ { execFile: opts.execFile, log },
484
+ );
485
+ } catch (err) {
486
+ const msg = err instanceof MrDraftError ? err.message : String(err?.message ?? err);
487
+ log('error', `mr-opener: MR create threw — ${msg}`);
488
+ return { ok: true, action: 'advisory', reason: `MR create failed: ${msg}`, gate };
489
+ }
490
+
491
+ // maybeCreateDraftMR returns { created, mrUrl?, existing?, error? } — never throws.
492
+ if (mrResult && mrResult.created === true) {
493
+ log('info', `mr-opener: draft MR opened — ${mrResult.mrUrl ?? '(no url)'}`);
494
+ return { ok: true, action: 'mr-opened', mrUrl: mrResult.mrUrl ?? undefined, gate };
495
+ }
496
+ if (mrResult && mrResult.existing === true) {
497
+ log('info', `mr-opener: existing MR found — ${mrResult.mrUrl ?? '(no url)'}`);
498
+ return { ok: true, action: 'mr-opened', mrUrl: mrResult.mrUrl ?? undefined, gate };
499
+ }
500
+
501
+ // Not created (binary missing, collision-check error, or other) → advisory.
502
+ const reason = mrResult?.error
503
+ ? `MR not opened: ${mrResult.error}`
504
+ : 'MR not opened — advisory only';
505
+ log('info', `mr-opener: ${reason}`);
506
+ return { ok: true, action: 'advisory', reason, gate };
507
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * join.mjs — Layer 2 (L2) skill-health: join skill-selection events to session outcomes.
3
+ *
4
+ * COARSE-GRANULARITY LIMITATION (read before using):
5
+ * The existing data model only records outcome signals at SESSION granularity via
6
+ * `agent_summary: { complete, partial, failed, spiral }` in sessions.jsonl. There is NO
7
+ * per-skill, per-wave, or per-invocation outcome signal in the current schema. Therefore
8
+ * this join is inherently coarse: for each skill we can tell WHICH sessions selected it
9
+ * and what those sessions' AGGREGATE outcomes were — but NOT whether the skill itself
10
+ * succeeded or failed within a session. Callers must not interpret the outcome buckets
11
+ * as per-skill success/failure rates; they are session-level aggregate outcomes for sessions
12
+ * that happened to select the skill.
13
+ *
14
+ * Where a session_id from skill-invocations.jsonl is not found in sessions.jsonl (e.g.
15
+ * the session is still in progress, or the record was never written), the session
16
+ * contributes `unknown` to the outcome tally — it is never silently dropped.
17
+ *
18
+ * Part of Epic #645 — Skill Self-Evolution Foundation, Layer 2.
19
+ */
20
+
21
+ import { promises as fs } from 'node:fs';
22
+ import path from 'node:path';
23
+ import { fileURLToPath } from 'node:url';
24
+
25
+ const DEFAULT_INVOCATIONS_PATH = path.resolve(
26
+ fileURLToPath(import.meta.url),
27
+ '../../../../.orchestrator/metrics/skill-invocations.jsonl',
28
+ );
29
+
30
+ const DEFAULT_SESSIONS_PATH = path.resolve(
31
+ fileURLToPath(import.meta.url),
32
+ '../../../../.orchestrator/metrics/sessions.jsonl',
33
+ );
34
+
35
+ /**
36
+ * Reads a JSONL file and returns an array of successfully parsed records.
37
+ * Silently skips malformed lines. Returns [] when the file is absent.
38
+ *
39
+ * @param {string} filePath
40
+ * @returns {Promise<object[]>}
41
+ */
42
+ async function readJsonl(filePath) {
43
+ let raw;
44
+ try {
45
+ raw = await fs.readFile(filePath, 'utf8');
46
+ } catch (err) {
47
+ if (err.code === 'ENOENT') return [];
48
+ throw err;
49
+ }
50
+ const records = [];
51
+ for (const line of raw.split('\n')) {
52
+ const trimmed = line.trim();
53
+ if (!trimmed) continue;
54
+ try {
55
+ records.push(JSON.parse(trimmed));
56
+ } catch {
57
+ // skip malformed lines per spec
58
+ }
59
+ }
60
+ return records;
61
+ }
62
+
63
+ /**
64
+ * Builds a Map<session_id, agent_summary> from sessions.jsonl records.
65
+ * Records without a session_id or with a non-object agent_summary are skipped.
66
+ *
67
+ * @param {object[]} sessionRecords
68
+ * @returns {Map<string, { complete: number, partial: number, failed: number, spiral: number }>}
69
+ */
70
+ function buildSessionMap(sessionRecords) {
71
+ const map = new Map();
72
+ for (const rec of sessionRecords) {
73
+ if (typeof rec.session_id !== 'string' || !rec.session_id) continue;
74
+ if (rec.agent_summary && typeof rec.agent_summary === 'object') {
75
+ map.set(rec.session_id, rec.agent_summary);
76
+ }
77
+ }
78
+ return map;
79
+ }
80
+
81
+ /**
82
+ * Joins skill-selection events to existing session outcomes.
83
+ *
84
+ * @param {object} [opts]
85
+ * @param {string} [opts.invocationsPath] - Path to skill-invocations.jsonl (L1 writer output).
86
+ * @param {string} [opts.sessionsPath] - Path to sessions.jsonl.
87
+ *
88
+ * @returns {Promise<{
89
+ * bySkill: {
90
+ * [skill: string]: {
91
+ * skill: string,
92
+ * selections: number,
93
+ * sessions: string[],
94
+ * outcomes: { complete: number, partial: number, failed: number, spiral: number, unknown: number }
95
+ * }
96
+ * },
97
+ * totalSelections: number,
98
+ * sessionsJoined: number,
99
+ * sessionsUnknown: number
100
+ * }>}
101
+ */
102
+ export async function joinSkillOutcomes({
103
+ invocationsPath = DEFAULT_INVOCATIONS_PATH,
104
+ sessionsPath = DEFAULT_SESSIONS_PATH,
105
+ } = {}) {
106
+ const [invocations, sessionRecords] = await Promise.all([
107
+ readJsonl(invocationsPath),
108
+ readJsonl(sessionsPath),
109
+ ]);
110
+
111
+ const sessionMap = buildSessionMap(sessionRecords);
112
+
113
+ /** @type {Map<string, { skill: string, selectionCount: number, sessions: Set<string>, outcomes: object }>} */
114
+ const bySkill = new Map();
115
+
116
+ let totalSelections = 0;
117
+ let sessionsJoined = 0;
118
+ let sessionsUnknown = 0;
119
+
120
+ for (const inv of invocations) {
121
+ // Only process skill-selection events with a valid skill field
122
+ if (typeof inv.skill !== 'string' || !inv.skill) continue;
123
+ if (inv.event !== 'selected') continue;
124
+
125
+ const skill = inv.skill;
126
+ const sessionId = typeof inv.session_id === 'string' ? inv.session_id : null;
127
+
128
+ totalSelections += 1;
129
+
130
+ if (!bySkill.has(skill)) {
131
+ bySkill.set(skill, {
132
+ skill,
133
+ selectionCount: 0,
134
+ sessions: new Set(),
135
+ outcomes: { complete: 0, partial: 0, failed: 0, spiral: 0, unknown: 0 },
136
+ });
137
+ }
138
+
139
+ const record = bySkill.get(skill);
140
+ record.selectionCount += 1;
141
+
142
+ if (sessionId) {
143
+ const isNew = !record.sessions.has(sessionId);
144
+ record.sessions.add(sessionId);
145
+
146
+ if (isNew) {
147
+ const summary = sessionMap.get(sessionId);
148
+ if (summary) {
149
+ // Sum session-level aggregate outcomes into this skill's buckets
150
+ record.outcomes.complete += typeof summary.complete === 'number' ? summary.complete : 0;
151
+ record.outcomes.partial += typeof summary.partial === 'number' ? summary.partial : 0;
152
+ record.outcomes.failed += typeof summary.failed === 'number' ? summary.failed : 0;
153
+ record.outcomes.spiral += typeof summary.spiral === 'number' ? summary.spiral : 0;
154
+ sessionsJoined += 1;
155
+ } else {
156
+ // Session id not found in sessions.jsonl — count as unknown, never drop
157
+ record.outcomes.unknown += 1;
158
+ sessionsUnknown += 1;
159
+ }
160
+ }
161
+ } else {
162
+ // No session_id on the invocation record — count as unknown
163
+ record.outcomes.unknown += 1;
164
+ sessionsUnknown += 1;
165
+ }
166
+ }
167
+
168
+ // Serialize: convert Set<string> → sorted string[] for stable output
169
+ /** @type {Record<string, object>} */
170
+ const bySkillObj = {};
171
+ for (const [skill, rec] of bySkill.entries()) {
172
+ bySkillObj[skill] = {
173
+ skill: rec.skill,
174
+ selections: rec.selectionCount,
175
+ sessions: [...rec.sessions].sort(),
176
+ outcomes: rec.outcomes,
177
+ };
178
+ }
179
+
180
+ return { bySkill: bySkillObj, totalSelections, sessionsJoined, sessionsUnknown };
181
+ }