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,121 @@
1
+ /**
2
+ * product-repo-detect.mjs — #190
3
+ * Detects product-repo signals in a repo root. Returns scored signal object.
4
+ *
5
+ * Stdlib-only, cross-platform, no zx, never throws.
6
+ */
7
+
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+
11
+ const FRAMEWORK_DEPS = [
12
+ 'next',
13
+ 'nuxt',
14
+ 'astro',
15
+ '@remix-run/react',
16
+ '@remix-run/node',
17
+ '@sveltejs/kit',
18
+ ];
19
+
20
+ const PRODUCT_ENV_PATTERNS = [
21
+ /^SUPABASE_URL=/m,
22
+ /^SUPABASE_ANON_KEY=/m,
23
+ /^STRIPE_[A-Z_]+=/m,
24
+ /^(NEXT_PUBLIC_)?AUTH0_[A-Z_]+=/m,
25
+ /^(NEXT_PUBLIC_)?CLERK_[A-Z_]+=/m,
26
+ /^(NEXT_PUBLIC_)?FIREBASE_[A-Z_]+=/m,
27
+ /^(NEXT_PUBLIC_)?POSTHOG_[A-Z_]+=/m,
28
+ /^SENTRY_DSN=/m,
29
+ ];
30
+
31
+ const CONTENT_DIRS = ['src/lib/personas', 'src/content', 'content', 'src/data/personas'];
32
+
33
+ /**
34
+ * @param {{ repoRoot: string }} opts
35
+ * @returns {{
36
+ * isProductRepo: boolean,
37
+ * framework: string | null,
38
+ * contentDirs: string[],
39
+ * productEnvMatches: string[],
40
+ * score: number,
41
+ * signals: { framework: boolean, contentDir: boolean, envVars: boolean }
42
+ * }}
43
+ */
44
+ export function detectProductRepo({ repoRoot } = {}) {
45
+ let framework = null;
46
+ const pkgPath = join(repoRoot, 'package.json');
47
+ if (existsSync(pkgPath)) {
48
+ try {
49
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
50
+ const deps = {
51
+ ...(pkg.dependencies || {}),
52
+ ...(pkg.devDependencies || {}),
53
+ ...(pkg.peerDependencies || {}),
54
+ };
55
+ for (const dep of FRAMEWORK_DEPS) {
56
+ if (dep in deps) {
57
+ framework = dep;
58
+ break;
59
+ }
60
+ }
61
+ } catch {
62
+ /* malformed package.json — no framework match */
63
+ }
64
+ }
65
+
66
+ const contentDirs = CONTENT_DIRS.filter((d) => existsSync(join(repoRoot, d)));
67
+
68
+ const productEnvMatches = [];
69
+ const envPath = join(repoRoot, '.env.local.example');
70
+ if (existsSync(envPath)) {
71
+ try {
72
+ const content = readFileSync(envPath, 'utf8');
73
+ for (const re of PRODUCT_ENV_PATTERNS) {
74
+ const m = content.match(re);
75
+ if (m) productEnvMatches.push(m[0].split('=')[0]);
76
+ }
77
+ } catch {
78
+ /* unreadable — ignore */
79
+ }
80
+ }
81
+
82
+ const signals = {
83
+ framework: framework !== null,
84
+ contentDir: contentDirs.length > 0,
85
+ envVars: productEnvMatches.length > 0,
86
+ };
87
+ const score =
88
+ (signals.framework ? 2 : 0) + (signals.contentDir ? 1 : 0) + (signals.envVars ? 2 : 0);
89
+ return {
90
+ isProductRepo: score >= 2,
91
+ framework,
92
+ contentDirs,
93
+ productEnvMatches,
94
+ score,
95
+ signals,
96
+ };
97
+ }
98
+
99
+ /**
100
+ * Check whether CLAUDE.md (or AGENTS.md) already has a `vault:` key in Session Config.
101
+ * @param {string} configFilePath
102
+ * @returns {boolean}
103
+ */
104
+ export function hasVaultConfig(configFilePath) {
105
+ if (!existsSync(configFilePath)) return false;
106
+ let text;
107
+ try {
108
+ text = readFileSync(configFilePath, 'utf8');
109
+ } catch {
110
+ return false;
111
+ }
112
+ // Scan only within the Session Config section (bounded by the next ## heading).
113
+ const startMatch = text.match(/^## Session Config[ \t]*(?:\r?\n|$)/m);
114
+ if (!startMatch || startMatch.index === undefined) return false;
115
+ const afterBlock = text.slice(startMatch.index + startMatch[0].length);
116
+ const nextHeadingMatch = afterBlock.match(/^## /m);
117
+ const blockContent = nextHeadingMatch
118
+ ? afterBlock.slice(0, nextHeadingMatch.index)
119
+ : afterBlock;
120
+ return /^\s*vault\s*:/m.test(blockContent);
121
+ }
@@ -0,0 +1,176 @@
1
+ /**
2
+ * profiles/registry.mjs — Pure loader for test profile registry.
3
+ *
4
+ * Reads `.orchestrator/policy/test-profiles.json`, validates each entry
5
+ * against profileRegistrySchema, and exposes pure helper accessors.
6
+ * DI-friendly: accepts an `fs` seam so callers can inject mock file systems.
7
+ *
8
+ * Issue: #383 (part 3) — /test command: profile registry schema + seed profiles
9
+ *
10
+ * Exports:
11
+ * loadProfiles({ profilesPath?, fs? }) → Promise<{ok, profiles?, error?}>
12
+ * listProfileNames(profiles) → string[]
13
+ * getProfile(profiles, name) → {ok, profile?, error?}
14
+ * validateProfile(entry) → {ok, value?, error?}
15
+ * ProfileRegistryError
16
+ */
17
+
18
+ import fsPromises from 'node:fs/promises';
19
+ import { profileEntrySchema, profileRegistrySchema } from './schema.mjs';
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Default path
23
+ // ---------------------------------------------------------------------------
24
+
25
+ const DEFAULT_PROFILES_PATH = '.orchestrator/policy/test-profiles.json';
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // ProfileRegistryError
29
+ // ---------------------------------------------------------------------------
30
+
31
+ /**
32
+ * Typed error for profile registry failures.
33
+ * Codes: 'FILE_NOT_FOUND' | 'PARSE_ERROR' | 'SCHEMA_INVALID' | 'UNKNOWN_PROFILE'
34
+ */
35
+ export class ProfileRegistryError extends Error {
36
+ /**
37
+ * @param {string} code
38
+ * @param {string} message
39
+ */
40
+ constructor(code, message) {
41
+ super(message);
42
+ this.name = 'ProfileRegistryError';
43
+ this.code = code;
44
+ }
45
+ }
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // loadProfiles
49
+ // ---------------------------------------------------------------------------
50
+
51
+ /**
52
+ * Load and validate the profiles registry from disk.
53
+ *
54
+ * @param {object} [opts]
55
+ * @param {string} [opts.profilesPath] - path to the JSON registry file;
56
+ * defaults to `.orchestrator/policy/test-profiles.json`
57
+ * @param {{ readFile: Function }} [opts.fs] - injected fs/promises (DI seam);
58
+ * defaults to the real `fs/promises`
59
+ * @returns {Promise<{ ok: true, profiles: Record<string, object> } | { ok: false, error: ProfileRegistryError }>}
60
+ */
61
+ export async function loadProfiles({ profilesPath, fs: fsImpl } = {}) {
62
+ const filePath = profilesPath ?? DEFAULT_PROFILES_PATH;
63
+ const fsRead = fsImpl ?? fsPromises;
64
+
65
+ let raw;
66
+ try {
67
+ raw = await fsRead.readFile(filePath, 'utf8');
68
+ } catch (err) {
69
+ const code = err && err.code === 'ENOENT' ? 'FILE_NOT_FOUND' : 'PARSE_ERROR';
70
+ return {
71
+ ok: false,
72
+ error: new ProfileRegistryError(code, `Cannot read profiles file '${filePath}': ${err.message}`),
73
+ };
74
+ }
75
+
76
+ let parsed;
77
+ try {
78
+ parsed = JSON.parse(raw);
79
+ } catch (err) {
80
+ return {
81
+ ok: false,
82
+ error: new ProfileRegistryError('PARSE_ERROR', `Invalid JSON in '${filePath}': ${err.message}`),
83
+ };
84
+ }
85
+
86
+ const result = profileRegistrySchema.safeParse(parsed);
87
+ if (!result.success) {
88
+ return {
89
+ ok: false,
90
+ error: new ProfileRegistryError(
91
+ 'SCHEMA_INVALID',
92
+ `Profile registry schema validation failed: ${result.error.message}`,
93
+ ),
94
+ };
95
+ }
96
+
97
+ return { ok: true, profiles: result.data };
98
+ }
99
+
100
+ // ---------------------------------------------------------------------------
101
+ // listProfileNames
102
+ // ---------------------------------------------------------------------------
103
+
104
+ /**
105
+ * Return the sorted list of profile names in the registry.
106
+ *
107
+ * @param {Record<string, object>} profiles
108
+ * @returns {string[]}
109
+ */
110
+ export function listProfileNames(profiles) {
111
+ if (profiles === null || typeof profiles !== 'object' || Array.isArray(profiles)) {
112
+ return [];
113
+ }
114
+ return Object.keys(profiles).sort();
115
+ }
116
+
117
+ // ---------------------------------------------------------------------------
118
+ // getProfile
119
+ // ---------------------------------------------------------------------------
120
+
121
+ /**
122
+ * Retrieve a single profile by name.
123
+ *
124
+ * @param {Record<string, object>} profiles
125
+ * @param {string} name
126
+ * @returns {{ ok: true, profile: object } | { ok: false, error: ProfileRegistryError }}
127
+ */
128
+ export function getProfile(profiles, name) {
129
+ if (profiles === null || typeof profiles !== 'object' || Array.isArray(profiles)) {
130
+ return {
131
+ ok: false,
132
+ error: new ProfileRegistryError('SCHEMA_INVALID', 'profiles must be a non-null object'),
133
+ };
134
+ }
135
+
136
+ if (typeof name !== 'string' || name.length === 0) {
137
+ return {
138
+ ok: false,
139
+ error: new ProfileRegistryError('UNKNOWN_PROFILE', 'profile name must be a non-empty string'),
140
+ };
141
+ }
142
+
143
+ if (!Object.prototype.hasOwnProperty.call(profiles, name)) {
144
+ const available = Object.keys(profiles).sort().join(', ') || '(none)';
145
+ return {
146
+ ok: false,
147
+ error: new ProfileRegistryError(
148
+ 'UNKNOWN_PROFILE',
149
+ `Profile '${name}' not found. Available: ${available}`,
150
+ ),
151
+ };
152
+ }
153
+
154
+ return { ok: true, profile: profiles[name] };
155
+ }
156
+
157
+ // ---------------------------------------------------------------------------
158
+ // validateProfile
159
+ // ---------------------------------------------------------------------------
160
+
161
+ /**
162
+ * Validate a raw profile entry object against the schema.
163
+ *
164
+ * @param {unknown} entry
165
+ * @returns {{ ok: true, value: object } | { ok: false, error: ProfileRegistryError }}
166
+ */
167
+ export function validateProfile(entry) {
168
+ const result = profileEntrySchema.safeParse(entry);
169
+ if (!result.success) {
170
+ return {
171
+ ok: false,
172
+ error: new ProfileRegistryError('SCHEMA_INVALID', result.error.message),
173
+ };
174
+ }
175
+ return { ok: true, value: result.data };
176
+ }
@@ -0,0 +1,209 @@
1
+ /**
2
+ * profiles/schema.mjs — Validation schemas for test profile entries.
3
+ *
4
+ * Zod was not available in this project's node_modules at implementation time
5
+ * (issue #383 part 3), so validation is implemented as a hand-rolled validator
6
+ * that mirrors the Zod schema contract specified in the task brief.
7
+ *
8
+ * Exports:
9
+ * profileEntrySchema — validator for a single profile entry
10
+ * profileRegistrySchema — validator for a full profiles record
11
+ *
12
+ * Both exports expose a `.safeParse(value)` method returning
13
+ * `{ success: true, data }` or `{ success: false, error: ZodLike }`.
14
+ */
15
+
16
+ import { validatePathInsideProject } from '../path-utils.mjs';
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Validation helpers
20
+ // ---------------------------------------------------------------------------
21
+
22
+ const VALID_DRIVERS = new Set(['playwright', 'peekaboo']);
23
+ const VALID_MODES = new Set(['headless', 'headed']);
24
+ const NAME_REGEX = /^[a-z0-9-]+$/;
25
+
26
+ /**
27
+ * Build a ZodLike error object matching Zod's safeParse error shape.
28
+ * @param {string} message
29
+ * @returns {{ issues: Array<{message: string}> }}
30
+ */
31
+ function makeError(message) {
32
+ return { issues: [{ message }], message };
33
+ }
34
+
35
+ /**
36
+ * Validate a single profile entry and return the parsed (defaulted) value.
37
+ * Mirrors the Zod schema:
38
+ *
39
+ * name: string, matches /^[a-z0-9-]+$/, min 1, max 50
40
+ * target: string | null | undefined
41
+ * driver: 'playwright' | 'peekaboo'
42
+ * mode: 'headless' | 'headed', default 'headless'
43
+ * rubric: string, default 'skills/test-runner/rubric-v1.md'
44
+ * checks: string[] | undefined
45
+ * tags: string[] | undefined
46
+ * rubric_features: string[] | undefined
47
+ * timeout_ms: positive integer, default 120000
48
+ * description: string | undefined
49
+ *
50
+ * @param {unknown} value
51
+ * @returns {{ success: true, data: object } | { success: false, error: object }}
52
+ */
53
+ function parseProfileEntry(value) {
54
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
55
+ return { success: false, error: makeError('profile entry must be a non-null object') };
56
+ }
57
+
58
+ const v = /** @type {Record<string, unknown>} */ (value);
59
+
60
+ // name
61
+ if (typeof v.name !== 'string') {
62
+ return { success: false, error: makeError('name must be a string') };
63
+ }
64
+ if (v.name.length < 1 || v.name.length > 50) {
65
+ return { success: false, error: makeError('name must be between 1 and 50 characters') };
66
+ }
67
+ if (!NAME_REGEX.test(v.name)) {
68
+ return { success: false, error: makeError('name must match /^[a-z0-9-]+$/') };
69
+ }
70
+
71
+ // target
72
+ if (v.target !== undefined && v.target !== null && typeof v.target !== 'string') {
73
+ return { success: false, error: makeError('target must be a string, null, or undefined') };
74
+ }
75
+
76
+ // driver
77
+ if (!VALID_DRIVERS.has(/** @type {string} */ (v.driver))) {
78
+ return {
79
+ success: false,
80
+ error: makeError(`driver must be one of: ${[...VALID_DRIVERS].join(', ')}`),
81
+ };
82
+ }
83
+
84
+ // mode (with default)
85
+ const mode = v.mode === undefined ? 'headless' : v.mode;
86
+ if (!VALID_MODES.has(/** @type {string} */ (mode))) {
87
+ return {
88
+ success: false,
89
+ error: makeError(`mode must be one of: ${[...VALID_MODES].join(', ')}`),
90
+ };
91
+ }
92
+
93
+ // rubric (with default)
94
+ const rubric = v.rubric === undefined ? 'skills/test-runner/rubric-v1.md' : v.rubric;
95
+ if (typeof rubric !== 'string') {
96
+ return { success: false, error: makeError('rubric must be a string') };
97
+ }
98
+ // SEC-IR-LOW-3 + SEC-Q2-LOW-1: rubric must stay within project root; also reject symlink-escape (CWE-23)
99
+ // Two-phase guard (Phase 1 lexical + Phase 2 realpath-when-exists) delegated to validatePathInsideProject.
100
+ const projectRoot = process.cwd();
101
+ const rubricGuard = validatePathInsideProject(rubric, projectRoot);
102
+ if (!rubricGuard.ok) {
103
+ return { success: false, error: makeError('rubric path escapes project root') };
104
+ }
105
+
106
+ // checks (optional array of strings)
107
+ if (v.checks !== undefined) {
108
+ if (!Array.isArray(v.checks) || v.checks.some((c) => typeof c !== 'string')) {
109
+ return { success: false, error: makeError('checks must be an array of strings') };
110
+ }
111
+ }
112
+
113
+ // tags (optional array of strings)
114
+ if (v.tags !== undefined) {
115
+ if (!Array.isArray(v.tags) || v.tags.some((t) => typeof t !== 'string')) {
116
+ return { success: false, error: makeError('tags must be an array of strings') };
117
+ }
118
+ }
119
+
120
+ // rubric_features (optional array of strings)
121
+ if (v.rubric_features !== undefined) {
122
+ if (!Array.isArray(v.rubric_features) || v.rubric_features.some((f) => typeof f !== 'string')) {
123
+ return { success: false, error: makeError('rubric_features must be an array of strings') };
124
+ }
125
+ }
126
+
127
+ // timeout_ms (positive integer, with default)
128
+ const timeout_ms = v.timeout_ms === undefined ? 120000 : v.timeout_ms;
129
+ if (
130
+ typeof timeout_ms !== 'number' ||
131
+ !Number.isInteger(timeout_ms) ||
132
+ timeout_ms <= 0
133
+ ) {
134
+ return { success: false, error: makeError('timeout_ms must be a positive integer') };
135
+ }
136
+ // SEC-PD-LOW-3: V8 setTimeout uses int32 — values > 2^31-1 silently overflow to immediate-fire.
137
+ // Practical ceiling is 1 hour for test profiles.
138
+ const MAX_TIMEOUT_MS = 3_600_000; // 1 hour
139
+ if (timeout_ms > MAX_TIMEOUT_MS) {
140
+ return { success: false, error: makeError(`timeout_ms must not exceed ${MAX_TIMEOUT_MS} (1 hour)`) };
141
+ }
142
+
143
+ // description (optional string)
144
+ if (v.description !== undefined && typeof v.description !== 'string') {
145
+ return { success: false, error: makeError('description must be a string') };
146
+ }
147
+
148
+ // SEC-Q2-LOW-2 (deep-5): store resolved rubric path (realPath when exists, else lexicalPath)
149
+ // to defeat post-validation symlink-swap TOCTOU. Mirrors the #405 pattern in config/test.mjs.
150
+ const resolvedRubric = rubricGuard.realPath ?? rubricGuard.lexicalPath;
151
+ /** @type {Record<string, unknown>} */
152
+ const data = {
153
+ name: v.name,
154
+ driver: v.driver,
155
+ mode,
156
+ rubric: resolvedRubric,
157
+ timeout_ms,
158
+ };
159
+
160
+ if (v.target !== undefined) data.target = v.target;
161
+ if (v.checks !== undefined) data.checks = v.checks;
162
+ if (v.tags !== undefined) data.tags = v.tags;
163
+ if (v.rubric_features !== undefined) data.rubric_features = v.rubric_features;
164
+ if (v.description !== undefined) data.description = v.description;
165
+
166
+ return { success: true, data };
167
+ }
168
+
169
+ /**
170
+ * Validate a full profiles registry (Record<string, profileEntry>).
171
+ *
172
+ * @param {unknown} value
173
+ * @returns {{ success: true, data: Record<string, object> } | { success: false, error: object }}
174
+ */
175
+ function parseProfileRegistry(value) {
176
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
177
+ return { success: false, error: makeError('profile registry must be a non-null object') };
178
+ }
179
+
180
+ /** @type {Record<string, object>} */
181
+ const data = {};
182
+
183
+ for (const [key, entry] of Object.entries(/** @type {Record<string, unknown>} */ (value))) {
184
+ const result = parseProfileEntry(entry);
185
+ if (!result.success) {
186
+ return {
187
+ success: false,
188
+ error: makeError(`profile '${key}': ${result.error.message}`),
189
+ };
190
+ }
191
+ data[key] = result.data;
192
+ }
193
+
194
+ return { success: true, data };
195
+ }
196
+
197
+ // ---------------------------------------------------------------------------
198
+ // Exports — Zod-compatible safeParse interface
199
+ // ---------------------------------------------------------------------------
200
+
201
+ export const profileEntrySchema = {
202
+ /** @param {unknown} value */
203
+ safeParse: (value) => parseProfileEntry(value),
204
+ };
205
+
206
+ export const profileRegistrySchema = {
207
+ /** @param {unknown} value */
208
+ safeParse: (value) => parseProfileRegistry(value),
209
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * qg-command-drift-banner.mjs — session-start banner probe for *-command drift detection.
3
+ *
4
+ * Detects when CLAUDE.md Session Config `lint-command` / `typecheck-command` /
5
+ * `test-command` values deviate from project defaults. Returns a structured
6
+ * banner object `{severity, message}` (or null for silent no-op), mirroring
7
+ * the contract used by `checkVaultStaleness` and other session-start probes.
8
+ *
9
+ * Used by session-start Phase 4 alongside other freshness/drift probes.
10
+ *
11
+ * Config-read path: this module reads Session Config exclusively via
12
+ * `loadCommandsFromSessionConfig` from `./quality-gate.mjs`. That helper
13
+ * returns a partial object (missing keys are absent — no default substitution),
14
+ * which means absent `*-command` keys cannot trigger spurious drift against
15
+ * `PROJECT_DEFAULTS`. Drift is only reported when a value is explicitly set
16
+ * AND differs from the corresponding `PROJECT_DEFAULTS` entry.
17
+ *
18
+ * Cross-references:
19
+ * - .claude/rules/quality-gates-autofix.md § Session Config Command Injection
20
+ * - scripts/lib/quality-gate.mjs `loadCommandsFromSessionConfig()`
21
+ *
22
+ * @see #525 (Pattern 4 Auto-Fix-Loop residuals)
23
+ * @see #526 (Pattern 4 banner ecosystem coherence)
24
+ */
25
+
26
+ import { loadCommandsFromSessionConfig } from './quality-gate.mjs';
27
+
28
+ /**
29
+ * Default *-command values for the session-orchestrator plugin.
30
+ * Source of truth: CLAUDE.md `## Session Config` block as shipped.
31
+ *
32
+ * Override this constant only when the canonical defaults change in CLAUDE.md.
33
+ */
34
+ export const PROJECT_DEFAULTS = Object.freeze({
35
+ lint: 'npm run lint',
36
+ typecheck: 'npm run typecheck',
37
+ test: 'npm test',
38
+ });
39
+
40
+ /**
41
+ * Check for *-command drift.
42
+ *
43
+ * Reads Session Config from CLAUDE.md (or AGENTS.md) in `repoRoot` via
44
+ * `loadCommandsFromSessionConfig` and compares any resolved `lint`,
45
+ * `typecheck`, and `test` values against PROJECT_DEFAULTS. Returns null
46
+ * when no drift is detected, or when the config-read returns no recognised
47
+ * `*-command` keys at all (graceful no-op).
48
+ *
49
+ * Important: missing keys do NOT trigger drift. Only explicit overrides
50
+ * that differ from PROJECT_DEFAULTS produce a banner.
51
+ *
52
+ * Marked `async` for backward compatibility with existing callers that
53
+ * `await` the result; internally the helper is synchronous.
54
+ *
55
+ * @param {object} [opts]
56
+ * @param {string} [opts.repoRoot] — project root (defaults to process.cwd()).
57
+ * @returns {Promise<null | {severity: 'warn', message: string}>}
58
+ */
59
+ export async function checkQgCommandDrift(opts = {}) {
60
+ const repoRoot = opts.repoRoot ?? process.cwd();
61
+
62
+ let cfg;
63
+ try {
64
+ cfg = loadCommandsFromSessionConfig(repoRoot);
65
+ } catch {
66
+ return null; // graceful no-op on config load failure
67
+ }
68
+ if (!cfg || typeof cfg !== 'object') return null;
69
+
70
+ const drifts = [];
71
+ for (const [key, defaultVal] of Object.entries(PROJECT_DEFAULTS)) {
72
+ const currentVal = cfg[key];
73
+ // Skip the comparison when the key is absent — missing keys cannot drift.
74
+ if (typeof currentVal !== 'string' || !currentVal.trim()) continue;
75
+ if (currentVal !== defaultVal) {
76
+ drifts.push(` ${key}-command: "${currentVal}" ← deviates from default "${defaultVal}"`);
77
+ }
78
+ }
79
+ if (drifts.length === 0) return null;
80
+
81
+ const message = [
82
+ '⚠ Session Config drift (*-command keys):',
83
+ ...drifts,
84
+ 'Verify the overrides are intentional. See .claude/rules/quality-gates-autofix.md § Session Config Command Injection for the RCE-equivalent trust-model.',
85
+ ].join('\n');
86
+
87
+ return { severity: 'warn', message };
88
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * scripts/lib/quality-gate/diagnostics.mjs
3
+ *
4
+ * Diagnostics-bundle redaction helpers for the auto-fix loop (#521 + #525).
5
+ * Strips token-shaped strings, secret env-var values, sensitive HTTP headers,
6
+ * and user-path identifiers before persisting the bundle to disk.
7
+ *
8
+ * Extracted from scripts/lib/quality-gate.mjs in #525 to give W4 tests a clean
9
+ * module surface and isolate redaction concerns from gate-runner concerns.
10
+ *
11
+ * @see .claude/rules/quality-gates-autofix.md § Session Config Command Injection
12
+ * @see scripts/lib/quality-gate.mjs (consumer — writes diagnostics bundle)
13
+ */
14
+
15
+ /**
16
+ * Token-shaped patterns that may appear in diagnostics output (gate command
17
+ * output lines, corrective_context entries, etc.). Replace each match with a
18
+ * placeholder so bundles are safe to attach to issue trackers or share with
19
+ * support.
20
+ *
21
+ * Ordering: more-specific patterns first (long prefixes before short ones) to
22
+ * prevent partial overlap.
23
+ */
24
+ const REDACTION_PATTERNS = [
25
+ [/ghp_[A-Za-z0-9]{36}/g, '***GITHUB_PAT***'],
26
+ [/glpat-[A-Za-z0-9_-]{20,}/g, '***GITLAB_PAT***'],
27
+ [/npm_[A-Za-z0-9]{36,}/g, '***NPM_TOKEN***'],
28
+ [/AKIA[0-9A-Z]{16}/g, '***AWS_ACCESS_KEY***'],
29
+ [/sk-ant-[A-Za-z0-9_-]{20,}/g, '***ANTHROPIC_KEY***'],
30
+ [/sbp_[A-Za-z0-9_-]{40,}/g, '***SUPABASE_TOKEN***'],
31
+ [/sk-[A-Za-z0-9]{40,}/g, '***OPENAI_KEY***'],
32
+ [/xox[bpae]-[A-Za-z0-9-]+/g, '***SLACK_TOKEN***'],
33
+ [/sk_(live|test)_[A-Za-z0-9]{24,}/g, '***STRIPE_KEY***'],
34
+ [/pk_(live|test)_[A-Za-z0-9]{24,}/g, '***STRIPE_PK***'],
35
+ [/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '***JWT***'],
36
+ [/https:\/\/(discord(app)?\.com|hooks\.slack\.com)\/[^\s"']+/g, '***WEBHOOK_URL***'],
37
+ [/Bearer\s+[A-Za-z0-9._-]+/gi, 'Bearer ***REDACTED***'],
38
+ [/Authorization:\s*Basic\s+[A-Za-z0-9+/=]+/gi, 'Authorization: Basic ***REDACTED***'],
39
+ [/Cookie:\s*[^\n\r]+/gi, 'Cookie: ***REDACTED***'],
40
+ [/\/Users\/[^/\s"']+\//g, '/Users/<redacted>/'],
41
+ [/\/home\/[^/\s"']+\//g, '/home/<redacted>/'],
42
+ ];
43
+
44
+ /**
45
+ * Matches env-var names that are semantically secret-bearing.
46
+ * Keys matching this pattern have their VALUES redacted (the key name is kept
47
+ * so operators can still audit which secret categories were present).
48
+ */
49
+ const SECRET_ENV_NAME_RE = /^([A-Z][A-Z0-9_]*(?:_TOKEN|_KEY|_SECRET|_PASSWORD|_CREDENTIAL[A-Z_]*))$/;
50
+
51
+ /**
52
+ * Redact secrets, env-var values, and user-specific paths from a diagnostics
53
+ * bundle before writing it to disk.
54
+ *
55
+ * Applies two passes:
56
+ * 1. Strip values of env-var keys that match SECRET_ENV_NAME_RE.
57
+ * 2. Serialize the bundle to JSON, apply REDACTION_PATTERNS against the full
58
+ * JSON string, then parse back. This catches token-shaped strings nested
59
+ * anywhere in the object graph (gate output lines, corrective_context
60
+ * entries, error messages) without requiring a recursive string-walker.
61
+ *
62
+ * Never throws — on any error the original bundle is returned so the write
63
+ * still completes (a partially-unredacted bundle is better than a lost bundle).
64
+ *
65
+ * @param {object} bundle
66
+ * @returns {object}
67
+ */
68
+ export function redactDiagnosticsBundle(bundle) {
69
+ try {
70
+ // Deep-clone via JSON round-trip so we never mutate the caller's object.
71
+ const copy = JSON.parse(JSON.stringify(bundle ?? {}));
72
+
73
+ // Pass 1 — redact secret-bearing env-var values.
74
+ if (copy.env && typeof copy.env === 'object') {
75
+ for (const key of Object.keys(copy.env)) {
76
+ if (SECRET_ENV_NAME_RE.test(key)) {
77
+ copy.env[key] = '***REDACTED***';
78
+ }
79
+ }
80
+ }
81
+
82
+ // Pass 2 — regex-replace token/path patterns over the full JSON string.
83
+ let serialized = JSON.stringify(copy);
84
+ for (const [re, replacement] of REDACTION_PATTERNS) {
85
+ serialized = serialized.replace(re, replacement);
86
+ }
87
+ return JSON.parse(serialized);
88
+ } catch {
89
+ // Return unredacted rather than losing the bundle entirely.
90
+ return bundle ?? {};
91
+ }
92
+ }