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,74 @@
1
+ import { matchBlockHeader } from './block-header.mjs';
2
+
3
+ /**
4
+ * events-rotation.mjs — Parser for the top-level `events-rotation:` YAML block.
5
+ *
6
+ * Bounds: max-size-mb 1..1024, max-backups 1..20. Out-of-range values fall
7
+ * back to defaults (silently; tolerant parser — hard errors would break
8
+ * session-start, which must never block).
9
+ */
10
+
11
+ /**
12
+ * Parse the top-level `events-rotation:` YAML block from markdown content.
13
+ * Defaults: enabled=true, max-size-mb=10, max-backups=5.
14
+ * @param {string} content — full file contents
15
+ * @returns {{enabled: boolean, "max-size-mb": number, "max-backups": number}}
16
+ */
17
+ export function _parseEventsRotation(content) {
18
+ const defaults = { enabled: true, 'max-size-mb': 10, 'max-backups': 5 };
19
+
20
+ const lines = content.split(/\r?\n/);
21
+ let inBlock = false;
22
+ const blockLines = [];
23
+
24
+ for (const rawLine of lines) {
25
+ const line = rawLine.replace(/\r$/, '');
26
+ if (!inBlock) {
27
+ if (matchBlockHeader(line, 'events-rotation')) inBlock = true;
28
+ continue;
29
+ }
30
+ if (line.length > 0 && !/^\s/.test(line)) break;
31
+ blockLines.push(line);
32
+ }
33
+
34
+ if (blockLines.length === 0) return defaults;
35
+
36
+ let erEnabled = true;
37
+ let erMaxSize = 10;
38
+ let erMaxBackups = 5;
39
+
40
+ for (const rawLine of blockLines) {
41
+ const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
42
+ if (!clean.trim()) continue;
43
+
44
+ const kvMatch = clean.match(/^\s+([a-zA-Z_-]+):\s*(.*)/);
45
+ if (!kvMatch) continue;
46
+
47
+ const k = kvMatch[1];
48
+ let v = kvMatch[2].trim();
49
+ if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
50
+ else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
51
+
52
+ switch (k) {
53
+ case 'enabled':
54
+ erEnabled = v.toLowerCase() !== 'false';
55
+ break;
56
+ case 'max-size-mb': {
57
+ if (/^\d+$/.test(v)) {
58
+ const n = parseInt(v, 10);
59
+ if (n >= 1 && n <= 1024) erMaxSize = n;
60
+ }
61
+ break;
62
+ }
63
+ case 'max-backups': {
64
+ if (/^\d+$/.test(v)) {
65
+ const n = parseInt(v, 10);
66
+ if (n >= 1 && n <= 20) erMaxBackups = n;
67
+ }
68
+ break;
69
+ }
70
+ }
71
+ }
72
+
73
+ return { enabled: erEnabled, 'max-size-mb': erMaxSize, 'max-backups': erMaxBackups };
74
+ }
@@ -0,0 +1,308 @@
1
+ /**
2
+ * evolve.mjs — Parser for the `evolve:` Session Config block (#638).
3
+ *
4
+ * Lets a repo declare opt-in EXTRA learning sources for /evolve: sidecar JSON
5
+ * files produced OUT-OF-BAND by a domain measurement (e.g. an eval-learn harness
6
+ * regression report). /evolve READS these sidecars and emits `domain-regression`
7
+ * learning candidates — it NEVER runs the measurement itself (read-only contract).
8
+ *
9
+ * Exports:
10
+ * _parseEvolve(content) — PURE, no side effects beyond a stderr WARN when an
11
+ * entry is dropped for failing schema validation.
12
+ * Returns [] when the block is absent/empty.
13
+ * _parseEvolveDecay(content) — PURE memory time-decay tuning parser (#670).
14
+ * Returns `{ enabled, half-life-days, floor-factor }`
15
+ * with conservative defaults; malformed values
16
+ * silently fall back to the default (tolerant).
17
+ *
18
+ * Block shape:
19
+ * evolve:
20
+ * extra-sources:
21
+ * - path: eval/learn/reports/latest.json # required; SAFE_PATH_RE-validated
22
+ * kind: regression-flags # enum: regression-flags (only value)
23
+ * learning-type: domain-regression # enum: domain-regression (only value)
24
+ * decay-enabled: true # #670 — gate the recency factor
25
+ * decay-half-life-days: 90 # #670 — half-life (conservative)
26
+ * decay-floor-factor: 0.1 # #670 — catastrophic-loss floor
27
+ *
28
+ * Modelled on cross-repo.mjs (column-0 block scan + nested list + per-entry
29
+ * SAFE_PATH_RE validation, drop-with-warn) and custom-phases.mjs (nested record
30
+ * list parse). Unknown `kind` / `learning-type` enum values DROP the entry with a
31
+ * stderr WARN (schema gate — never guess), mirroring custom-phases' security posture
32
+ * for security-relevant fields the consumer will read.
33
+ */
34
+
35
+ import pathModule from 'node:path';
36
+
37
+ import { matchBlockHeader } from './block-header.mjs';
38
+
39
+ /** Per-entry defaults (none beyond the required field-set; documented for symmetry). */
40
+ export const EVOLVE_EXTRA_SOURCE_DEFAULTS = Object.freeze({
41
+ kind: 'regression-flags',
42
+ 'learning-type': 'domain-regression',
43
+ });
44
+
45
+ // Enum allow-lists. Each currently has a single legal value; unknown values DROP
46
+ // the entry (schema gate) rather than silently defaulting — the consumer reads the
47
+ // `kind` to pick a sidecar schema and the `learning-type` to stamp the candidate,
48
+ // so a guessed value would produce a wrong-shaped learning.
49
+ const VALID_KIND = new Set(['regression-flags']);
50
+ const VALID_LEARNING_TYPE = new Set(['domain-regression']);
51
+
52
+ // Allowlist: a sidecar `path` is a repo-relative file path — no spaces, no shell
53
+ // metacharacters, and no `..` scope escape. Mirrors cross-repo.mjs /
54
+ // custom-phases.mjs SAFE_PATH_RE for shell-injection filtering, then adds
55
+ // evolve-specific confinement because /evolve resolves sidecars against repo root.
56
+ const SAFE_PATH_RE = /^[A-Za-z0-9._~/-]+$/;
57
+
58
+ /**
59
+ * Parse the top-level `evolve:` block and its nested `extra-sources:` YAML list.
60
+ *
61
+ * Each list item is a record `{path, kind, learning-type}`. Records are validated
62
+ * per-entry; a record missing a required `path`, carrying a shell-metacharacter in
63
+ * `path`, or carrying an unknown `kind`/`learning-type` enum value is DROPPED with a
64
+ * stderr WARN.
65
+ *
66
+ * @param {string} content — full CLAUDE.md / AGENTS.md file content
67
+ * @returns {Array<{path: string, kind: string, 'learning-type': string}>}
68
+ */
69
+ export function _parseEvolve(content) {
70
+ const lines = content.split(/\r?\n/);
71
+ let inEvolve = false;
72
+ let inExtraSources = false;
73
+ const blockLines = [];
74
+
75
+ for (const rawLine of lines) {
76
+ const line = rawLine.replace(/\r$/, '');
77
+
78
+ if (!inEvolve) {
79
+ // Detect `evolve:` at column 0 with optional trailing spaces.
80
+ if (matchBlockHeader(line, 'evolve')) inEvolve = true;
81
+ continue;
82
+ }
83
+
84
+ // The `evolve:` block terminates at the first non-indented, non-empty line
85
+ // (next top-level key).
86
+ if (line.length > 0 && !/^\s/.test(line)) break;
87
+
88
+ if (!inExtraSources) {
89
+ // Detect the `extra-sources:` sub-key (any indent depth ≥ 1).
90
+ if (/^\s+extra-sources:\s*$/.test(line)) inExtraSources = true;
91
+ continue;
92
+ }
93
+
94
+ // Within extra-sources: collect list-item lines. A sibling sub-key of evolve:
95
+ // at the SAME indent as extra-sources: (shallower than the list dash) ends the
96
+ // sub-block. We detect this by a non-dash key whose indent matches extra-sources'.
97
+ blockLines.push(line);
98
+ }
99
+
100
+ if (blockLines.length === 0) return [];
101
+
102
+ /** @type {Array<{path: string, kind: string, 'learning-type': string}>} */
103
+ const records = [];
104
+ /** @type {Record<string, string>|null} */
105
+ let current = null;
106
+
107
+ const flush = () => {
108
+ if (current === null) return;
109
+ const rec = _validateRecord(current);
110
+ if (rec !== null) records.push(rec);
111
+ current = null;
112
+ };
113
+
114
+ for (const rawLine of blockLines) {
115
+ // Strip inline comments + trailing whitespace, preserve leading indent.
116
+ const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
117
+ if (!clean.trim()) continue;
118
+
119
+ // A new list item starts with a dash. The first key may sit on the dash line:
120
+ // - path: foo.json
121
+ const dashMatch = clean.match(/^\s*-\s+(.*)$/);
122
+ if (dashMatch) {
123
+ flush();
124
+ current = {};
125
+ const inlineKv = dashMatch[1].match(/^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/);
126
+ if (inlineKv) {
127
+ _assignKv(current, inlineKv[1], inlineKv[2]);
128
+ }
129
+ continue;
130
+ }
131
+
132
+ // Continuation key for the current record (deeper indent, no dash).
133
+ const kvMatch = clean.match(/^\s+([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/);
134
+ if (kvMatch && current !== null) {
135
+ _assignKv(current, kvMatch[1], kvMatch[2]);
136
+ }
137
+ }
138
+
139
+ flush();
140
+
141
+ return records;
142
+ }
143
+
144
+ /**
145
+ * Assign a raw key/value onto a record being built, stripping surrounding quotes.
146
+ * Only known keys are stored; unknown keys are silently ignored (additive-friendly).
147
+ *
148
+ * @param {Record<string, string>} record
149
+ * @param {string} key
150
+ * @param {string} rawValue
151
+ */
152
+ function _assignKv(record, key, rawValue) {
153
+ let v = rawValue.trim();
154
+ if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
155
+ else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
156
+
157
+ switch (key) {
158
+ case 'path':
159
+ case 'kind':
160
+ case 'learning-type':
161
+ record[key] = v;
162
+ break;
163
+ default:
164
+ // Unknown keys are silently ignored — additive-friendly.
165
+ break;
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Validate + normalise a raw extra-source record. Returns the record, or null
171
+ * (with a stderr WARN) when `path` is missing / SAFE_PATH_RE-failing, or when
172
+ * `kind` / `learning-type` carries an unknown enum value.
173
+ *
174
+ * @param {Record<string, string>} raw
175
+ * @returns {{path: string, kind: string, 'learning-type': string}|null}
176
+ */
177
+ function _validateRecord(raw) {
178
+ const path = (raw.path ?? '').trim();
179
+ if (path === '') {
180
+ process.stderr.write('evolve: dropped extra-source missing required field: path\n');
181
+ return null;
182
+ }
183
+ if (!SAFE_PATH_RE.test(path)) {
184
+ process.stderr.write(
185
+ `evolve: dropped extra-source with shell metacharacter in path: ${JSON.stringify(path)}\n`,
186
+ );
187
+ return null;
188
+ }
189
+ if (pathModule.isAbsolute(path) || path.split('/').includes('..')) {
190
+ process.stderr.write(
191
+ `evolve: dropped extra-source outside repo-relative scope: ${JSON.stringify(path)}\n`,
192
+ );
193
+ return null;
194
+ }
195
+
196
+ // kind: enum gate — unknown value DROPS the record (never guess).
197
+ const kind = (raw.kind ?? EVOLVE_EXTRA_SOURCE_DEFAULTS.kind).trim();
198
+ if (!VALID_KIND.has(kind)) {
199
+ process.stderr.write(
200
+ `evolve: dropped extra-source '${path}' with unknown kind: ${JSON.stringify(kind)} ` +
201
+ `(allowed: ${[...VALID_KIND].join(', ')})\n`,
202
+ );
203
+ return null;
204
+ }
205
+
206
+ // learning-type: enum gate — unknown value DROPS the record (never guess).
207
+ const learningType = (raw['learning-type'] ?? EVOLVE_EXTRA_SOURCE_DEFAULTS['learning-type']).trim();
208
+ if (!VALID_LEARNING_TYPE.has(learningType)) {
209
+ process.stderr.write(
210
+ `evolve: dropped extra-source '${path}' with unknown learning-type: ${JSON.stringify(learningType)} ` +
211
+ `(allowed: ${[...VALID_LEARNING_TYPE].join(', ')})\n`,
212
+ );
213
+ return null;
214
+ }
215
+
216
+ return { path, kind, 'learning-type': learningType };
217
+ }
218
+
219
+ // ---------------------------------------------------------------------------
220
+ // Memory time-decay tuning (#670)
221
+ // ---------------------------------------------------------------------------
222
+
223
+ /**
224
+ * Conservative decay defaults — nested UNDER the existing `evolve:` block so they
225
+ * do NOT add a new top-level Session Config key (claude-md-drift-check Check 6
226
+ * parity is unaffected). Floor means nothing vanishes; long half-life means decay
227
+ * is a tiebreaker, not a cliff. See #670.
228
+ */
229
+ export const EVOLVE_DECAY_DEFAULTS = Object.freeze({
230
+ enabled: true,
231
+ 'half-life-days': 90,
232
+ 'floor-factor': 0.1,
233
+ });
234
+
235
+ /**
236
+ * Parse the memory time-decay tuning keys nested under the `evolve:` block.
237
+ *
238
+ * Scans the same column-0 `evolve:` block as `_parseEvolve` but reads three flat
239
+ * sub-keys (siblings of `extra-sources:`):
240
+ * - `decay-enabled` (boolean; default true)
241
+ * - `decay-half-life-days` (positive number; default 90)
242
+ * - `decay-floor-factor` (float in [0,1]; default 0.1)
243
+ *
244
+ * Tolerant: malformed/out-of-range values silently fall back to the default
245
+ * (mirrors auto-dream.mjs). Returns the defaults when the block is absent.
246
+ *
247
+ * @param {string} content — full CLAUDE.md / AGENTS.md file content
248
+ * @returns {{enabled: boolean, 'half-life-days': number, 'floor-factor': number}}
249
+ */
250
+ export function _parseEvolveDecay(content) {
251
+ const result = {
252
+ enabled: EVOLVE_DECAY_DEFAULTS.enabled,
253
+ 'half-life-days': EVOLVE_DECAY_DEFAULTS['half-life-days'],
254
+ 'floor-factor': EVOLVE_DECAY_DEFAULTS['floor-factor'],
255
+ };
256
+
257
+ const lines = content.split(/\r?\n/);
258
+ let inEvolve = false;
259
+ const blockLines = [];
260
+
261
+ for (const rawLine of lines) {
262
+ const line = rawLine.replace(/\r$/, '');
263
+ if (!inEvolve) {
264
+ if (matchBlockHeader(line, 'evolve')) inEvolve = true;
265
+ continue;
266
+ }
267
+ // Terminate at the first non-indented, non-empty line (next top-level key).
268
+ if (line.length > 0 && !/^\s/.test(line)) break;
269
+ blockLines.push(line);
270
+ }
271
+
272
+ if (blockLines.length === 0) return result;
273
+
274
+ for (const rawLine of blockLines) {
275
+ const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
276
+ if (!clean.trim()) continue;
277
+
278
+ // Flat ` key: value` sub-key (skip list-item dash lines under extra-sources:).
279
+ const kvMatch = clean.match(/^\s+([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/);
280
+ if (!kvMatch) continue;
281
+
282
+ const key = kvMatch[1];
283
+ let v = kvMatch[2].trim();
284
+ if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
285
+ else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
286
+
287
+ if (key === 'decay-enabled') {
288
+ const lower = v.toLowerCase();
289
+ if (lower === 'true') result.enabled = true;
290
+ else if (lower === 'false') result.enabled = false;
291
+ // any other value → keep default (tolerant)
292
+ } else if (key === 'decay-half-life-days') {
293
+ // Positive number; reject 0/negative/non-numeric → keep default.
294
+ if (/^\d+(\.\d+)?$/.test(v)) {
295
+ const f = parseFloat(v);
296
+ if (Number.isFinite(f) && f > 0) result['half-life-days'] = f;
297
+ }
298
+ } else if (key === 'decay-floor-factor') {
299
+ // Float in [0,1] → keep default otherwise.
300
+ if (/^\d+(\.\d+)?$/.test(v)) {
301
+ const f = parseFloat(v);
302
+ if (Number.isFinite(f) && f >= 0 && f <= 1) result['floor-factor'] = f;
303
+ }
304
+ }
305
+ }
306
+
307
+ return result;
308
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * frontend-slop-hook.mjs — Parser + loader for the top-level
3
+ * `frontend-slop-hook:` YAML block (#684, Track 2 / item B).
4
+ *
5
+ * Drives the OPT-IN, NON-BLOCKING PostToolUse hook that runs the deterministic
6
+ * frontend-slop detector (scripts/lib/frontend-detect/detect.mjs) on a UI file
7
+ * right after it is edited and surfaces findings as an `additionalContext`
8
+ * roll-up. Warn-only / never blocks; profile-gate also applies.
9
+ *
10
+ * Returns `{ enabled }`. DEFAULT OFF (`enabled: false`) — opt-in by design,
11
+ * unlike loop-guard which defaults on. The flag only flips to `true` on an
12
+ * explicit `enabled: true` line under a column-0 `frontend-slop-hook:` block.
13
+ * Tolerant parser: any other value (or an absent block) resolves to disabled.
14
+ *
15
+ * Consumer: `hooks/post-tooluse-frontend-slop.mjs`.
16
+ */
17
+
18
+ import { promises as fs } from 'node:fs';
19
+ import path from 'node:path';
20
+
21
+ import { SO_PROJECT_DIR } from '../platform.mjs';
22
+ import { matchBlockHeader } from './block-header.mjs';
23
+
24
+ /**
25
+ * Parse the top-level `frontend-slop-hook:` YAML block from markdown content.
26
+ * Independent of the `## Session Config` section boundary (mirrors
27
+ * `_parseLoopGuard`).
28
+ *
29
+ * Default:
30
+ * enabled: false (OPT-IN — only an explicit `enabled: true` enables it)
31
+ *
32
+ * @param {string} content — full file contents
33
+ * @returns {{ enabled: boolean }}
34
+ */
35
+ export function _parseFrontendSlopHook(content) {
36
+ const defaults = { enabled: false };
37
+
38
+ const lines = content.split(/\r?\n/);
39
+ let inBlock = false;
40
+ const blockLines = [];
41
+
42
+ for (const rawLine of lines) {
43
+ const line = rawLine.replace(/\r$/, '');
44
+ if (!inBlock) {
45
+ if (matchBlockHeader(line, 'frontend-slop-hook')) inBlock = true;
46
+ continue;
47
+ }
48
+ // A column-0 (non-indented) non-blank line ends the block.
49
+ if (line.length > 0 && !/^\s/.test(line)) break;
50
+ blockLines.push(line);
51
+ }
52
+
53
+ if (blockLines.length === 0) return defaults;
54
+
55
+ let fshEnabled = false;
56
+
57
+ for (const rawLine of blockLines) {
58
+ const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
59
+ if (!clean.trim()) continue;
60
+
61
+ const kvMatch = clean.match(/^\s+([a-zA-Z_-]+):\s*(.*)/);
62
+ if (!kvMatch) continue;
63
+
64
+ const k = kvMatch[1];
65
+ let v = kvMatch[2].trim();
66
+ if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
67
+ else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
68
+
69
+ if (k === 'enabled') {
70
+ // Default is false → only flip to true on explicit "true".
71
+ fshEnabled = v.toLowerCase() === 'true';
72
+ }
73
+ }
74
+
75
+ return { enabled: fshEnabled };
76
+ }
77
+
78
+ /**
79
+ * Load `frontend-slop-hook.*` from CLAUDE.md (or AGENTS.md) at the project root.
80
+ * Cheap inline read — avoids importing the full config orchestrator from a hot
81
+ * hook path. Default OFF: a read failure (no instruction file) resolves to the
82
+ * parser defaults (`enabled: false`). Mirrors `loadConfig()` in
83
+ * hooks/loop-guard.mjs.
84
+ *
85
+ * @param {{ repoRoot?: string }} [opts]
86
+ * @returns {Promise<{ enabled: boolean }>}
87
+ */
88
+ export async function loadFrontendSlopHookConfig(opts = {}) {
89
+ const root = opts.repoRoot || SO_PROJECT_DIR;
90
+ const candidates = [
91
+ path.join(root, 'CLAUDE.md'),
92
+ path.join(root, 'AGENTS.md'),
93
+ ];
94
+ for (const file of candidates) {
95
+ try {
96
+ const content = await fs.readFile(file, 'utf8');
97
+ return _parseFrontendSlopHook(content);
98
+ } catch {
99
+ // missing or unreadable — try next candidate
100
+ }
101
+ }
102
+ // No CLAUDE.md/AGENTS.md → parser defaults (enabled:false).
103
+ return _parseFrontendSlopHook('');
104
+ }
@@ -0,0 +1,150 @@
1
+ import { matchBlockHeader } from './block-header.mjs';
2
+
3
+ /**
4
+ * gitlab-portfolio.mjs — Parser for the top-level `gitlab-portfolio:` YAML block.
5
+ */
6
+
7
+ /** Default values for the gitlab-portfolio block. */
8
+ export const GITLAB_PORTFOLIO_DEFAULTS = {
9
+ enabled: false,
10
+ mode: 'warn',
11
+ 'stale-days': 30,
12
+ 'critical-labels': ['priority:critical', 'priority:high'],
13
+ };
14
+
15
+ const VALID_MODES = new Set(['warn', 'strict', 'off']);
16
+
17
+ /**
18
+ * Coerce a raw `gitlab-portfolio` block (already parsed as a plain object) into a
19
+ * normalized, fully-defaulted config object.
20
+ *
21
+ * Unknown keys are dropped silently. Invalid types fall back to defaults.
22
+ * Returns the defaults object when input is missing or not a plain object.
23
+ *
24
+ * @param {unknown} raw
25
+ * @returns {{ enabled: boolean, mode: 'warn'|'strict'|'off', 'stale-days': number, 'critical-labels': string[] }}
26
+ */
27
+ export function coerceGitlabPortfolio(raw) {
28
+ if (raw === null || raw === undefined || typeof raw !== 'object' || Array.isArray(raw)) {
29
+ return { ...GITLAB_PORTFOLIO_DEFAULTS, 'critical-labels': [...GITLAB_PORTFOLIO_DEFAULTS['critical-labels']] };
30
+ }
31
+
32
+ // enabled: only strict true is coerced to true
33
+ const enabled = raw['enabled'] === true;
34
+
35
+ // mode: must be one of warn | strict | off, otherwise default
36
+ const mode = VALID_MODES.has(raw['mode']) ? /** @type {'warn'|'strict'|'off'} */ (raw['mode']) : 'warn';
37
+
38
+ // stale-days: finite integer >= 1, otherwise default
39
+ const rawStaleDays = raw['stale-days'];
40
+ const staleDays =
41
+ typeof rawStaleDays === 'number' &&
42
+ Number.isFinite(rawStaleDays) &&
43
+ Number.isInteger(rawStaleDays) &&
44
+ rawStaleDays >= 1
45
+ ? rawStaleDays
46
+ : GITLAB_PORTFOLIO_DEFAULTS['stale-days'];
47
+
48
+ // critical-labels: array of non-empty strings; filter out invalid entries, fall back to defaults if result is empty or invalid
49
+ const rawLabels = raw['critical-labels'];
50
+ let criticalLabels;
51
+ if (Array.isArray(rawLabels)) {
52
+ const filtered = rawLabels.filter((l) => typeof l === 'string' && l.length > 0);
53
+ criticalLabels = filtered.length > 0 ? filtered : [...GITLAB_PORTFOLIO_DEFAULTS['critical-labels']];
54
+ } else {
55
+ criticalLabels = [...GITLAB_PORTFOLIO_DEFAULTS['critical-labels']];
56
+ }
57
+
58
+ return { enabled, mode, 'stale-days': staleDays, 'critical-labels': criticalLabels };
59
+ }
60
+
61
+ /**
62
+ * Parse the top-level `gitlab-portfolio:` YAML block from markdown content.
63
+ * Returns fully-defaulted values when the block is absent or malformed.
64
+ *
65
+ * @param {string} content — full file contents (CLAUDE.md or AGENTS.md)
66
+ * @returns {{ enabled: boolean, mode: 'warn'|'strict'|'off', 'stale-days': number, 'critical-labels': string[] }}
67
+ */
68
+ export function _parseGitlabPortfolio(content) {
69
+ const lines = content.split(/\r?\n/);
70
+ let inBlock = false;
71
+ const blockLines = [];
72
+
73
+ for (const rawLine of lines) {
74
+ const line = rawLine.replace(/\r$/, '');
75
+ if (!inBlock) {
76
+ if (matchBlockHeader(line, 'gitlab-portfolio')) inBlock = true;
77
+ continue;
78
+ }
79
+ // A non-empty line without leading whitespace signals end of block
80
+ if (line.length > 0 && !/^\s/.test(line)) break;
81
+ blockLines.push(line);
82
+ }
83
+
84
+ if (blockLines.length === 0) {
85
+ return { ...GITLAB_PORTFOLIO_DEFAULTS, 'critical-labels': [...GITLAB_PORTFOLIO_DEFAULTS['critical-labels']] };
86
+ }
87
+
88
+ let gpEnabled = false;
89
+ let gpMode = /** @type {'warn'|'strict'|'off'} */ ('warn');
90
+ let gpStaleDays = GITLAB_PORTFOLIO_DEFAULTS['stale-days'];
91
+ let gpCriticalLabels = /** @type {string[]|null} */ (null);
92
+ let inCriticalLabelsBlock = false;
93
+
94
+ for (const rawLine of blockLines) {
95
+ // Strip inline comments and trailing whitespace
96
+ const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
97
+ if (!clean.trim()) continue;
98
+
99
+ // List item under critical-labels (deeper indent with leading `- `)
100
+ if (inCriticalLabelsBlock) {
101
+ const listMatch = clean.match(/^\s{3,}-\s+(.*)/);
102
+ if (listMatch) {
103
+ let val = listMatch[1].trim();
104
+ if (val.startsWith('"') && val.endsWith('"') && val.length >= 2) val = val.slice(1, -1);
105
+ else if (val.startsWith("'") && val.endsWith("'") && val.length >= 2) val = val.slice(1, -1);
106
+ if (val.length > 0) {
107
+ if (gpCriticalLabels === null) gpCriticalLabels = [];
108
+ gpCriticalLabels.push(val);
109
+ }
110
+ continue;
111
+ }
112
+ }
113
+
114
+ // Top-level key under gitlab-portfolio (2-space indent)
115
+ const kvMatch = clean.match(/^\s+([a-zA-Z_-]+):\s*(.*)/);
116
+ if (!kvMatch) continue;
117
+
118
+ inCriticalLabelsBlock = false;
119
+
120
+ const k = kvMatch[1];
121
+ let v = kvMatch[2].trim();
122
+ if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
123
+ else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
124
+
125
+ switch (k) {
126
+ case 'enabled':
127
+ gpEnabled = v.toLowerCase() === 'true';
128
+ break;
129
+ case 'mode':
130
+ if (VALID_MODES.has(v)) gpMode = /** @type {'warn'|'strict'|'off'} */ (v);
131
+ break;
132
+ case 'stale-days': {
133
+ const n = parseFloat(v);
134
+ if (Number.isFinite(n) && Number.isInteger(n) && n >= 1) gpStaleDays = n;
135
+ break;
136
+ }
137
+ case 'critical-labels':
138
+ // Value is empty (block style) — switch to list-collection mode
139
+ inCriticalLabelsBlock = true;
140
+ break;
141
+ }
142
+ }
143
+
144
+ const criticalLabels =
145
+ gpCriticalLabels !== null && gpCriticalLabels.length > 0
146
+ ? gpCriticalLabels
147
+ : [...GITLAB_PORTFOLIO_DEFAULTS['critical-labels']];
148
+
149
+ return { enabled: gpEnabled, mode: gpMode, 'stale-days': gpStaleDays, 'critical-labels': criticalLabels };
150
+ }