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,289 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * validate-wave-scope.mjs — Validate .claude/wave-scope.json before enforcement hooks consume it.
4
+ *
5
+ * Part of v3.0 Bash→Node migration (Epic #124). Replaces validate-wave-scope.sh
6
+ * which depended on scripts/lib/common.sh → scripts/lib/platform.sh (removed).
7
+ *
8
+ * Usage:
9
+ * node scripts/validate-wave-scope.mjs <path-to-wave-scope.json>
10
+ * cat wave-scope.json | node scripts/validate-wave-scope.mjs
11
+ * node scripts/validate-wave-scope.mjs --assert-subset <agent-filescope.json> < wave-scope.json
12
+ *
13
+ * Flags:
14
+ * --assert-subset <path> After schema validation passes, read the agent
15
+ * fileScope file (a JSON array of strings) and assert
16
+ * it is a subset of wave-scope.allowedPaths (#796).
17
+ * Fails (exit 1) with "missing: [...]" on violation.
18
+ *
19
+ * Exit codes:
20
+ * 0 — valid (validated JSON echoed to stdout)
21
+ * 1 — invalid input / validation failure (error messages written to stderr)
22
+ * 2 — I/O error (file not found, unreadable stdin, unreadable --assert-subset file)
23
+ */
24
+
25
+ import { readFileSync, existsSync, statSync } from 'node:fs';
26
+ import { warn } from './lib/common.mjs';
27
+ import { assertFileScopeSubset } from './lib/scope-gate.mjs';
28
+
29
+ /**
30
+ * Write an error to stderr and exit with the given code.
31
+ * @param {string} msg
32
+ * @param {number} [code=1]
33
+ * @returns {never}
34
+ */
35
+ function die(msg, code = 1) {
36
+ process.stderr.write(`ERROR: ${msg}\n`);
37
+ process.exit(code);
38
+ }
39
+
40
+ /**
41
+ * Parse CLI flags out of argv, leaving positional args behind.
42
+ *
43
+ * Recognised: `--assert-subset <path>` (#796). Everything else is treated as a
44
+ * positional argument (the wave-scope.json file path), preserving legacy
45
+ * behaviour where argv[2] is the input file.
46
+ *
47
+ * @param {string[]} argv - full process.argv
48
+ * @returns {{ assertSubset: string|null, positionals: string[] }}
49
+ */
50
+ function parseArgs(argv) {
51
+ const positionals = [];
52
+ let assertSubset = null;
53
+ for (let i = 2; i < argv.length; i++) {
54
+ const a = argv[i];
55
+ if (a === '--assert-subset') {
56
+ assertSubset = argv[i + 1];
57
+ if (assertSubset === undefined) {
58
+ die('--assert-subset requires a file-path argument', 1);
59
+ }
60
+ i++; // consume the value
61
+ } else {
62
+ positionals.push(a);
63
+ }
64
+ }
65
+ return { assertSubset, positionals };
66
+ }
67
+
68
+ /**
69
+ * Read raw input: from a file path arg or from stdin (fd 0).
70
+ *
71
+ * Exit codes used here:
72
+ * 1 — bad argument (file path argument given but file not found)
73
+ * 2 — unexpected I/O error (file exists but cannot be read, stdin failure)
74
+ *
75
+ * @param {string|undefined} arg - the positional wave-scope.json file path (or undefined for stdin)
76
+ * @returns {string}
77
+ */
78
+ function readInput(arg) {
79
+ if (arg) {
80
+ // Exit 1: file not found is a user/argument error
81
+ if (!existsSync(arg) || !statSync(arg).isFile()) {
82
+ die(`File not found: ${arg}`, 1);
83
+ }
84
+ // Exit 2: file exists but cannot be read is an I/O error
85
+ try {
86
+ return readFileSync(arg, 'utf8');
87
+ } catch (err) {
88
+ die(`Cannot read file ${arg}: ${err.message}`, 2);
89
+ }
90
+ }
91
+ // Exit 2: stdin read failure is an I/O error
92
+ try {
93
+ return readFileSync(0, 'utf8');
94
+ } catch (err) {
95
+ die(`Cannot read stdin: ${err.message}`, 2);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Parse raw JSON input; exits 1 on parse failure.
101
+ * @param {string} input
102
+ * @returns {unknown}
103
+ */
104
+ function parseJson(input) {
105
+ try {
106
+ return JSON.parse(input);
107
+ } catch {
108
+ die('Input is not valid JSON');
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Validate required scalar fields: wave, role, enforcement.
114
+ * @param {Record<string, unknown>} obj
115
+ * @param {string[]} errors
116
+ */
117
+ function validateRequired(obj, errors) {
118
+ // wave — positive integer
119
+ if (!('wave' in obj) || obj.wave === null || obj.wave === undefined) {
120
+ errors.push('Missing required field: wave');
121
+ } else if (typeof obj.wave !== 'number' || !Number.isInteger(obj.wave) || obj.wave <= 0) {
122
+ errors.push(`wave must be a positive integer, got: ${JSON.stringify(obj.wave)}`);
123
+ }
124
+
125
+ // role — non-empty string
126
+ const roleType = obj.role === null ? 'null' : typeof obj.role;
127
+ if (!('role' in obj) || roleType !== 'string') {
128
+ errors.push(`role must be a string, got type: ${roleType}`);
129
+ } else if (obj.role.length === 0) {
130
+ errors.push('role must be a non-empty string');
131
+ }
132
+
133
+ // enforcement — one of strict|warn|off
134
+ const enfType = obj.enforcement === null ? 'null' : typeof obj.enforcement;
135
+ if (!('enforcement' in obj) || enfType !== 'string') {
136
+ errors.push(`enforcement must be a string, got type: ${enfType}`);
137
+ } else if (!['strict', 'warn', 'off'].includes(obj.enforcement)) {
138
+ errors.push(`enforcement must be one of: strict, warn, off — got: ${obj.enforcement}`);
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Validate allowedPaths array: must exist, be an array of non-empty strings,
144
+ * with no absolute paths and no path-traversal segments.
145
+ * @param {Record<string, unknown>} obj
146
+ * @param {string[]} errors
147
+ * @param {string[]} warnings
148
+ */
149
+ function validateAllowedPaths(obj, errors, warnings) {
150
+ if (!('allowedPaths' in obj)) {
151
+ errors.push('Missing required field: allowedPaths');
152
+ return;
153
+ }
154
+ const ap = obj.allowedPaths;
155
+ if (!Array.isArray(ap)) {
156
+ errors.push(`allowedPaths must be an array, got type: ${ap === null ? 'null' : typeof ap}`);
157
+ return;
158
+ }
159
+ for (const entry of ap) {
160
+ if (typeof entry !== 'string' || entry.length === 0) {
161
+ errors.push('allowedPaths contains empty string');
162
+ continue;
163
+ }
164
+ // Reject absolute paths (must be repo-relative)
165
+ if (entry.startsWith('/')) {
166
+ errors.push(`allowedPaths contains absolute path: ${entry}`);
167
+ }
168
+ // Reject path traversal: any `../` segment
169
+ if (entry.includes('../')) {
170
+ errors.push(`allowedPaths contains path traversal: ${entry}`);
171
+ }
172
+ // Warn on overly permissive glob patterns
173
+ if (entry === '**/*' || entry === '*') {
174
+ warnings.push(`allowedPaths contains overly permissive pattern: ${entry}`);
175
+ }
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Validate blockedCommands: must exist and be an array.
181
+ * @param {Record<string, unknown>} obj
182
+ * @param {string[]} errors
183
+ */
184
+ function validateBlockedCommands(obj, errors) {
185
+ if (!('blockedCommands' in obj)) {
186
+ errors.push('Missing required field: blockedCommands');
187
+ return;
188
+ }
189
+ if (!Array.isArray(obj.blockedCommands)) {
190
+ const t = obj.blockedCommands === null ? 'null' : typeof obj.blockedCommands;
191
+ errors.push(`blockedCommands must be an array, got type: ${t}`);
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Validate optional gates field: if present must be an object of string→boolean entries.
197
+ * @param {Record<string, unknown>} obj
198
+ * @param {string[]} errors
199
+ */
200
+ function validateGates(obj, errors) {
201
+ if (!('gates' in obj)) return;
202
+ const gates = obj.gates;
203
+ if (gates === null || typeof gates !== 'object' || Array.isArray(gates)) {
204
+ const t = gates === null ? 'null' : Array.isArray(gates) ? 'array' : typeof gates;
205
+ errors.push(`gates must be an object, got type: ${t}`);
206
+ return;
207
+ }
208
+ const bad = Object.entries(gates)
209
+ .filter(([, v]) => typeof v !== 'boolean')
210
+ .map(([k]) => k);
211
+ if (bad.length > 0) {
212
+ errors.push(`gates values must be booleans, invalid entries: ${bad.join(', ')}`);
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Read the agent fileScope sidecar file and assert it is a subset of the
218
+ * wave's allowedPaths union (#796). Exits on failure; returns on success.
219
+ *
220
+ * Exit codes:
221
+ * 1 — fileScope file is not valid JSON, is not an array of strings, or the
222
+ * subset assertion fails (validation error)
223
+ * 2 — fileScope file is missing / not a regular file / unreadable (I/O error)
224
+ *
225
+ * @param {Record<string, unknown>} obj - the already schema-validated wave-scope object
226
+ * @param {string} fileScopePath - path to the agent fileScope JSON file
227
+ */
228
+ function assertSubsetOrDie(obj, fileScopePath) {
229
+ if (!existsSync(fileScopePath) || !statSync(fileScopePath).isFile()) {
230
+ die(`Cannot read --assert-subset file: ${fileScopePath}`, 2);
231
+ }
232
+ let raw;
233
+ try {
234
+ raw = readFileSync(fileScopePath, 'utf8');
235
+ } catch (err) {
236
+ die(`Cannot read --assert-subset file ${fileScopePath}: ${err.message}`, 2);
237
+ }
238
+ let fileScope;
239
+ try {
240
+ fileScope = JSON.parse(raw);
241
+ } catch {
242
+ die(`--assert-subset file is not valid JSON: ${fileScopePath}`, 1);
243
+ }
244
+ if (!Array.isArray(fileScope) || !fileScope.every((e) => typeof e === 'string')) {
245
+ die('--assert-subset file must be a JSON array of strings', 1);
246
+ }
247
+ const { ok, missing } = assertFileScopeSubset(fileScope, obj.allowedPaths);
248
+ if (!ok) {
249
+ die(`agent fileScope not ⊆ allowedPaths — missing: [${missing.join(', ')}]`, 1);
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Main validation entry point. Reads input, validates, exits with appropriate code.
255
+ * @param {string} input - raw JSON string
256
+ * @param {string|null} [assertSubsetPath] - optional agent fileScope file for the #796 subset assertion
257
+ */
258
+ function validate(input, assertSubsetPath = null) {
259
+ const obj = parseJson(input);
260
+ const errors = [];
261
+ const warnings = [];
262
+
263
+ validateRequired(obj, errors);
264
+ validateAllowedPaths(obj, errors, warnings);
265
+ validateBlockedCommands(obj, errors);
266
+ validateGates(obj, errors);
267
+
268
+ for (const w of warnings) {
269
+ warn(w);
270
+ }
271
+
272
+ if (errors.length > 0) {
273
+ for (const e of errors) {
274
+ process.stderr.write(`ERROR: ${e}\n`);
275
+ }
276
+ process.exit(1);
277
+ }
278
+
279
+ // #796 — optional dispatch-time subset assertion (runs only after schema validation passes)
280
+ if (assertSubsetPath) {
281
+ assertSubsetOrDie(obj, assertSubsetPath);
282
+ }
283
+
284
+ // Echo validated JSON to stdout (trailing newline normalised)
285
+ process.stdout.write(input.endsWith('\n') ? input : input + '\n');
286
+ }
287
+
288
+ const { assertSubset, positionals } = parseArgs(process.argv);
289
+ validate(readInput(positionals[0]), assertSubset);
@@ -0,0 +1,404 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * vault-backfill.mjs — GitLab group scanner + .vault.yaml backfill CLI (Issue #241).
4
+ *
5
+ * Scans GitLab groups for repos missing .vault.yaml and either previews (dry-run,
6
+ * default) or renders the canonical template content (--apply).
7
+ *
8
+ * CLI usage:
9
+ * node scripts/vault-backfill.mjs [--groups <CSV>] [--dry-run] [--apply]
10
+ * [--out-dir <path>] [--yes <manifest.json>] [--vault-dir <path>] [--verbose]
11
+ *
12
+ * Exit codes:
13
+ * 0 — success (clean run, dry or apply, even if some repos skipped)
14
+ * 1 — validation error (bad CLI flags, missing --groups AND no Session Config
15
+ * gitlab-groups, malformed manifest, missing glab CLI)
16
+ * 2 — filesystem error (template missing, cannot write to out-dir)
17
+ * 3 — GitLab API error (auth failure, rate limit, group not found — when ALL
18
+ * groups fail to resolve OR all repo-probes fail and nothing was processed)
19
+ * 4 — dry-run found nothing to backfill (informational; not an error)
20
+ *
21
+ * All logging → stderr. Structured JSON actions → stdout (one object per line).
22
+ * No external dependencies — Node stdlib only.
23
+ *
24
+ * Part of Vault-Docs Sub-Epic C (Issue #241).
25
+ */
26
+
27
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
28
+ import { join, resolve, dirname } from 'node:path';
29
+ import { createInterface } from 'node:readline';
30
+
31
+ import {
32
+ assertGlabExists, setVerbose as setGlabVerbose,
33
+ listGroupRepos, checkVaultYaml, fetchRepoOwner,
34
+ } from './lib/vault-backfill/glab.mjs';
35
+
36
+ import {
37
+ loadTemplate, slugToHumanName, pathToSlug, renderTemplate,
38
+ } from './lib/vault-backfill/template.mjs';
39
+
40
+ import { validateManifest, SLUG_RE } from './lib/vault-backfill/manifest.mjs';
41
+
42
+ // ── CLI argument parsing ──────────────────────────────────────────────────────
43
+
44
+ const args = process.argv.slice(2);
45
+
46
+ function getArg(name) {
47
+ const idx = args.indexOf(name);
48
+ return idx !== -1 ? args[idx + 1] : undefined;
49
+ }
50
+
51
+ const flagGroups = getArg('--groups');
52
+ const flagDryRun = args.includes('--dry-run');
53
+ const flagApply = args.includes('--apply');
54
+ const flagYes = getArg('--yes');
55
+ const flagVaultDir = getArg('--vault-dir');
56
+ const flagOutDir = getArg('--out-dir');
57
+ const flagVerbose = args.includes('--verbose');
58
+
59
+ // ── Logging + output ──────────────────────────────────────────────────────────
60
+
61
+ function log(msg) {
62
+ process.stderr.write(`[vault-backfill] ${msg}\n`);
63
+ }
64
+
65
+ function emitAction(action, repoPath, extra = {}) {
66
+ process.stdout.write(JSON.stringify({ action, path: repoPath, ...extra }) + '\n');
67
+ }
68
+
69
+ function die(code, msg) {
70
+ process.stderr.write(`[vault-backfill] ERROR: ${msg}\n`);
71
+ process.exit(code);
72
+ }
73
+
74
+ // ── Validation ────────────────────────────────────────────────────────────────
75
+
76
+ if (flagDryRun && flagApply) die(1, '--dry-run and --apply are mutually exclusive');
77
+
78
+ const applyWrites = flagApply === true;
79
+
80
+ /** Resolved staging output directory (used when --apply is set). */
81
+ const outDir = resolve(flagOutDir ?? './.vault-backfill-staging');
82
+
83
+ /** Whether any file writes failed (contributes to exit 2). */
84
+ let hadWriteError = false;
85
+
86
+ if (flagVerbose) setGlabVerbose(true);
87
+
88
+ // ── Session Config reader (inline) ───────────────────────────────────────────
89
+
90
+ /** Read vault-integration.{gitlab-groups,vault-dir} from CLAUDE.md / AGENTS.md in CWD. */
91
+ function readVaultIntegrationConfig() {
92
+ const candidates = [join(process.cwd(), 'CLAUDE.md'), join(process.cwd(), 'AGENTS.md')];
93
+
94
+ let content = null;
95
+ for (const p of candidates) {
96
+ if (existsSync(p)) {
97
+ try { content = readFileSync(p, 'utf8'); break; } catch { /* try next */ }
98
+ }
99
+ }
100
+
101
+ if (!content) return { 'gitlab-groups': null, 'vault-dir': null };
102
+
103
+ let inBlock = false;
104
+ let gitlabGroups = null;
105
+ let vaultDir = null;
106
+
107
+ for (const rawLine of content.split(/\r?\n/)) {
108
+ const line = rawLine.replace(/\r$/, '');
109
+
110
+ if (!inBlock && /^vault-integration:\s*$/.test(line)) { inBlock = true; continue; }
111
+ if (inBlock) {
112
+ if (line.length > 0 && !/^\s/.test(line)) break;
113
+
114
+ const m = line.match(/^\s+([a-zA-Z_-]+):\s*(.*)/);
115
+ if (!m) continue;
116
+
117
+ const k = m[1].trim();
118
+ let v = m[2].trim().replace(/\s*#.*$/, '').trim();
119
+ if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) {
120
+ v = v.slice(1, -1);
121
+ }
122
+
123
+ if (k === 'gitlab-groups' && v) {
124
+ gitlabGroups = v.replace(/^\[/, '').replace(/\]$/, '').trim() || null;
125
+ }
126
+ if (k === 'vault-dir' && v && v !== 'none' && v !== 'null') {
127
+ vaultDir = v;
128
+ }
129
+ }
130
+ }
131
+
132
+ return { 'gitlab-groups': gitlabGroups, 'vault-dir': vaultDir };
133
+ }
134
+
135
+ // ── Vault-dir folder stub ─────────────────────────────────────────────────────
136
+
137
+ function createVaultFolderStub(vaultDir, slug) {
138
+ if (!vaultDir) return;
139
+ const stubDir = join(resolve(vaultDir), '01-projects', slug);
140
+ try {
141
+ if (!existsSync(stubDir)) {
142
+ if (applyWrites) {
143
+ mkdirSync(stubDir, { recursive: true });
144
+ log(`created vault folder stub: ${stubDir}`);
145
+ } else {
146
+ log(`[dry-run] would create vault folder stub: ${stubDir}`);
147
+ }
148
+ }
149
+ } catch (err) {
150
+ process.stderr.write(
151
+ `[vault-backfill] WARN: could not create vault stub for ${slug}: ${err.message}\n`,
152
+ );
153
+ }
154
+ }
155
+
156
+ // ── Process one repo ──────────────────────────────────────────────────────────
157
+
158
+ function processRepo(entry, vaultDir, templateContent) {
159
+ const { path: repoPath, slug, tier, visibility, group, id } = entry;
160
+ const humanName = slugToHumanName(slug);
161
+
162
+ const owner = applyWrites ? fetchRepoOwner(id) : 'unknown';
163
+
164
+ let renderedContent;
165
+ try {
166
+ renderedContent = renderTemplate(
167
+ { humanName, slug, tier, gitlabPath: repoPath, owner },
168
+ templateContent,
169
+ );
170
+ } catch (err) {
171
+ process.stderr.write(
172
+ `[vault-backfill] WARN: template render failed for ${repoPath}: ${err.message}\n`,
173
+ );
174
+ emitAction('skipped-render-error', repoPath, { slug, tier, visibility, error: err.message });
175
+ return;
176
+ }
177
+
178
+ if (!applyWrites) {
179
+ // Dry-run: emit preview action only (no disk write)
180
+ emitAction('vault-yaml-rendered', repoPath, { slug, tier, visibility, group, content: renderedContent });
181
+ log(`[dry-run] ${repoPath}: would write .vault.yaml (slug=${slug}, tier=${tier})`);
182
+ createVaultFolderStub(vaultDir, slug);
183
+ return;
184
+ }
185
+
186
+ // Apply: write to staging directory at <out-dir>/<group>/<repo>/.vault.yaml
187
+ const writePath = join(outDir, repoPath, '.vault.yaml');
188
+ try {
189
+ mkdirSync(dirname(writePath), { recursive: true });
190
+ writeFileSync(writePath, renderedContent, 'utf8');
191
+ emitAction('wrote', writePath, { slug, id, tier, visibility, group });
192
+ log(`${repoPath}: wrote .vault.yaml → ${writePath}`);
193
+ } catch (err) {
194
+ emitAction('write-failed', writePath, { error: err.message, slug, group });
195
+ process.stderr.write(
196
+ `[vault-backfill] ERROR: cannot write ${writePath}: ${err.message}\n`,
197
+ );
198
+ hadWriteError = true;
199
+ }
200
+
201
+ createVaultFolderStub(vaultDir, slug);
202
+ }
203
+
204
+ // ── Scan groups ───────────────────────────────────────────────────────────────
205
+
206
+ function scanGroups(groups) {
207
+ let failedGroups = 0;
208
+ const missing = [];
209
+
210
+ for (const group of groups) {
211
+ log(`scanning group: ${group}`);
212
+ const repos = listGroupRepos(group);
213
+ if (repos === null) { failedGroups++; continue; }
214
+
215
+ log(` found ${repos.length} repo(s) in ${group}`);
216
+ for (const repo of repos) {
217
+ if (!repo.path) continue;
218
+ const status = checkVaultYaml(repo.path);
219
+ if (status === 'present') {
220
+ log(` ${repo.path}: already has .vault.yaml — skipping`);
221
+ emitAction('skipped-has-vault-yaml', repo.path, { visibility: repo.visibility, createdAt: repo.createdAt });
222
+ continue;
223
+ }
224
+ missing.push({ ...repo, group });
225
+ }
226
+ }
227
+
228
+ const allGroupsFailed = failedGroups > 0 && failedGroups === groups.length;
229
+ return { repos: missing, apiError: failedGroups > 0, allGroupsFailed };
230
+ }
231
+
232
+ // ── Table printer ─────────────────────────────────────────────────────────────
233
+
234
+ function printTable(repos) {
235
+ if (repos.length === 0) { process.stderr.write('\n (no repos to backfill)\n'); return; }
236
+
237
+ const COL_REPO = Math.max(4, ...repos.map((r) => r.path.length));
238
+ const pad = (s, n) => String(s).padEnd(n);
239
+ const sep = ` ${'-'.repeat(COL_REPO + 26)}\n`;
240
+
241
+ process.stderr.write('\n');
242
+ process.stderr.write(` ${pad('Repo', COL_REPO)} ${pad('Date', 10)} Visibility\n`);
243
+ process.stderr.write(sep);
244
+ for (const r of repos) {
245
+ process.stderr.write(` ${pad(r.path, COL_REPO)} ${pad(r.createdAt, 10)} ${r.visibility}\n`);
246
+ }
247
+ process.stderr.write('\n');
248
+ }
249
+
250
+ // ── Interactive prompt ────────────────────────────────────────────────────────
251
+
252
+ async function promptForRepo(rl, repoPath, suggestedSlug) {
253
+ const ask = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
254
+
255
+ process.stderr.write(`\n Repo: ${repoPath}\n`);
256
+
257
+ let slug;
258
+ while (true) {
259
+ const input = await ask(` Slug [${suggestedSlug}]: `);
260
+ slug = input || suggestedSlug;
261
+ if (SLUG_RE.test(slug)) break;
262
+ process.stderr.write(` Invalid slug — must match [a-z0-9]+(-[a-z0-9]+)*\n`);
263
+ }
264
+
265
+ let tier;
266
+ while (true) {
267
+ const input = await ask(` Tier (top/active/archived) [active]: `);
268
+ tier = input || 'active';
269
+ if (['top', 'active', 'archived'].includes(tier)) break;
270
+ process.stderr.write(` Invalid tier — must be top|active|archived\n`);
271
+ }
272
+
273
+ const skip = await ask(` Skip this repo? [y/N]: `);
274
+ if (skip.toLowerCase() === 'y') return null;
275
+ return { slug, tier };
276
+ }
277
+
278
+ // ── Headless (--yes) path ─────────────────────────────────────────────────────
279
+
280
+ async function runHeadless(manifestPath, vaultDir) {
281
+ let raw;
282
+ try {
283
+ raw = JSON.parse(readFileSync(manifestPath, 'utf8'));
284
+ } catch (err) {
285
+ die(1, `cannot parse manifest '${manifestPath}': ${err.message}`);
286
+ }
287
+
288
+ const repos = validateManifest(raw, die);
289
+ const templateContent = loadTemplate(die);
290
+ const pending = repos.filter((r) => !r.skip);
291
+
292
+ log(`manifest: ${repos.length} entries, ${pending.length} to process`);
293
+ if (pending.length === 0) { log('nothing to backfill (all skip:true)'); process.exit(4); }
294
+
295
+ // When --yes manifest is provided, it is the authoritative scope — skip the
296
+ // GitLab API .vault.yaml presence check so the CLI works without live repo access.
297
+ for (const entry of pending) {
298
+ processRepo(
299
+ { ...entry, group: entry.path.split('/')[0] ?? '' },
300
+ vaultDir,
301
+ templateContent,
302
+ );
303
+ }
304
+ }
305
+
306
+ // ── Interactive path ──────────────────────────────────────────────────────────
307
+
308
+ async function runInteractive(groups, vaultDir) {
309
+ const templateContent = loadTemplate(die);
310
+
311
+ log('scanning groups for repos missing .vault.yaml …');
312
+ const { repos: missing, apiError, allGroupsFailed } = scanGroups(groups);
313
+
314
+ if (apiError) log('WARN: one or more groups had API errors; results may be incomplete');
315
+
316
+ // Exit 3 only when ALL groups failed and nothing was processed at all
317
+ if (allGroupsFailed) {
318
+ die(3, 'all GitLab group scans failed — check auth (GITLAB_TOKEN) and group paths');
319
+ }
320
+
321
+ if (missing.length === 0) { log('all scanned repos already have .vault.yaml — nothing to backfill'); process.exit(4); }
322
+
323
+ printTable(missing);
324
+ log(`found ${missing.length} repo(s) without .vault.yaml`);
325
+
326
+ if (!applyWrites) {
327
+ log('(dry-run mode — use --apply to write .vault.yaml files)');
328
+ for (const repo of missing) {
329
+ processRepo({ ...repo, slug: pathToSlug(repo.path), tier: 'active' }, vaultDir, templateContent);
330
+ }
331
+ return;
332
+ }
333
+
334
+ // Interactive prompts
335
+ const rl = createInterface({ input: process.stdin, output: process.stderr, terminal: true });
336
+ const decisions = [];
337
+
338
+ for (const repo of missing) {
339
+ const decision = await promptForRepo(rl, repo.path, pathToSlug(repo.path));
340
+ if (decision === null) {
341
+ log(`${repo.path}: skipped by user`);
342
+ emitAction('skipped-by-user', repo.path, { visibility: repo.visibility });
343
+ continue;
344
+ }
345
+ decisions.push({ repo, ...decision });
346
+ }
347
+
348
+ if (decisions.length === 0) {
349
+ rl.close();
350
+ log('no repos selected — nothing to apply');
351
+ process.exit(0);
352
+ }
353
+
354
+ process.stderr.write(`\n ${decisions.length} repo(s) will receive .vault.yaml. Apply? [y/N]: `);
355
+ const confirmed = await new Promise((resolve) => {
356
+ rl.question('', (a) => { rl.close(); resolve(a.trim().toLowerCase()); });
357
+ });
358
+
359
+ if (confirmed !== 'y') { log('aborted by user — no writes performed'); process.exit(0); }
360
+
361
+ for (const { repo, slug, tier } of decisions) {
362
+ processRepo({ ...repo, slug, tier }, vaultDir, templateContent);
363
+ }
364
+ }
365
+
366
+ // ── Main ──────────────────────────────────────────────────────────────────────
367
+
368
+ async function main() {
369
+ const cfgConfig = readVaultIntegrationConfig();
370
+
371
+ let groups;
372
+ if (flagGroups) {
373
+ groups = flagGroups.split(',').map((g) => g.trim()).filter(Boolean);
374
+ } else if (cfgConfig['gitlab-groups']) {
375
+ groups = cfgConfig['gitlab-groups'].split(',').map((g) => g.trim()).filter(Boolean);
376
+ }
377
+
378
+ const vaultDir = flagVaultDir ?? cfgConfig['vault-dir'] ?? null;
379
+
380
+ if (!flagYes && (!groups || groups.length === 0)) {
381
+ die(1, 'no GitLab groups specified — pass --groups <CSV> or set vault-integration.gitlab-groups in CLAUDE.md');
382
+ }
383
+
384
+ if (flagYes) {
385
+ // Headless path: manifest is authoritative. No glab required (CI / air-gapped).
386
+ await runHeadless(flagYes, vaultDir);
387
+ } else {
388
+ // Interactive path: glab is required for group scanning + per-repo presence checks.
389
+ assertGlabExists(die);
390
+ await runInteractive(groups, vaultDir);
391
+ }
392
+
393
+ // Propagate write failures (EACCES, ENOSPC, etc.) as exit code 2
394
+ if (hadWriteError) {
395
+ process.stderr.write('[vault-backfill] ERROR: one or more .vault.yaml writes failed (see above)\n');
396
+ process.exit(2);
397
+ }
398
+ }
399
+
400
+ main().catch((err) => {
401
+ process.stderr.write(`[vault-backfill] unexpected error: ${err.message}\n`);
402
+ if (flagVerbose && err.stack) process.stderr.write(err.stack + '\n');
403
+ process.exit(2);
404
+ });