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,127 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * generate-pi-prompts.mjs — build Pi prompt-template wrappers for commands/*.md.
4
+ *
5
+ * Pi prompt templates expand `$@`; Session Orchestrator command files use the
6
+ * cross-harness `$ARGUMENTS` placeholder. The generated wrapper keeps one
7
+ * maintained command source while giving Pi a native prompt entry per command.
8
+ *
9
+ * Usage:
10
+ * node scripts/generate-pi-prompts.mjs
11
+ * node scripts/generate-pi-prompts.mjs --check
12
+ */
13
+
14
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
15
+ import path from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const SCRIPT_DIR = path.dirname(__filename);
20
+ const ROOT = path.dirname(SCRIPT_DIR);
21
+ const COMMANDS_DIR = path.join(ROOT, 'commands');
22
+ const PROMPTS_DIR = path.join(ROOT, 'pi', 'prompts');
23
+ const CHECK_ONLY = process.argv.includes('--check');
24
+
25
+ function commandFiles() {
26
+ return readdirSync(COMMANDS_DIR)
27
+ .filter((name) => name.endsWith('.md'))
28
+ .sort();
29
+ }
30
+
31
+ function parseFrontmatter(content) {
32
+ if (!content.startsWith('---\n')) return {};
33
+ const end = content.indexOf('\n---\n', 4);
34
+ if (end === -1) return {};
35
+
36
+ const fields = {};
37
+ const block = content.slice(4, end).split('\n');
38
+ for (const line of block) {
39
+ const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
40
+ if (!match) continue;
41
+ fields[match[1]] = match[2];
42
+ }
43
+ return fields;
44
+ }
45
+
46
+ function frontmatterLine(key, value) {
47
+ if (value === undefined || value === '') return null;
48
+ return `${key}: ${value}`;
49
+ }
50
+
51
+ function renderPrompt(commandFile) {
52
+ const commandPath = path.join(COMMANDS_DIR, commandFile);
53
+ const commandName = commandFile.replace(/\.md$/, '');
54
+ const fields = parseFrontmatter(readFileSync(commandPath, 'utf8'));
55
+ const frontmatter = [
56
+ '---',
57
+ frontmatterLine('description', fields.description),
58
+ frontmatterLine('argument-hint', fields['argument-hint']),
59
+ '---',
60
+ ].filter(Boolean).join('\n');
61
+
62
+ return `${frontmatter}
63
+
64
+ # /${commandName}
65
+
66
+ Use the Session Orchestrator command definition at \`commands/${commandFile}\`.
67
+
68
+ Arguments: $@
69
+
70
+ Read that command file and follow it exactly. When it references \`$ARGUMENTS\`, substitute the arguments above. Keep all Session Orchestrator platform fallbacks intact.
71
+ `;
72
+ }
73
+
74
+ function expectedPrompts() {
75
+ const prompts = new Map();
76
+ for (const commandFile of commandFiles()) {
77
+ prompts.set(commandFile, renderPrompt(commandFile));
78
+ }
79
+ return prompts;
80
+ }
81
+
82
+ function checkPrompts(expected) {
83
+ const failures = [];
84
+ for (const [name, content] of expected) {
85
+ const promptPath = path.join(PROMPTS_DIR, name);
86
+ if (!existsSync(promptPath)) {
87
+ failures.push(`${name}: missing`);
88
+ continue;
89
+ }
90
+ const actual = readFileSync(promptPath, 'utf8');
91
+ if (actual !== content) failures.push(`${name}: stale`);
92
+ }
93
+
94
+ const expectedNames = new Set(expected.keys());
95
+ const actualNames = existsSync(PROMPTS_DIR)
96
+ ? readdirSync(PROMPTS_DIR).filter((name) => name.endsWith('.md'))
97
+ : [];
98
+ for (const name of actualNames) {
99
+ if (!expectedNames.has(name)) failures.push(`${name}: orphan`);
100
+ }
101
+
102
+ if (failures.length > 0) {
103
+ for (const failure of failures) {
104
+ console.error(`FAIL: ${failure}`);
105
+ }
106
+ process.exit(1);
107
+ }
108
+
109
+ console.log(`pi prompts: ${expected.size} file(s) up to date`);
110
+ }
111
+
112
+ function writePrompts(expected) {
113
+ mkdirSync(PROMPTS_DIR, { recursive: true });
114
+ for (const name of readdirSync(PROMPTS_DIR)) {
115
+ if (name.endsWith('.md') && !expected.has(name)) {
116
+ rmSync(path.join(PROMPTS_DIR, name));
117
+ }
118
+ }
119
+ for (const [name, content] of expected) {
120
+ writeFileSync(path.join(PROMPTS_DIR, name), content, 'utf8');
121
+ }
122
+ console.log(`pi prompts: wrote ${expected.size} file(s)`);
123
+ }
124
+
125
+ const expected = expectedPrompts();
126
+ if (CHECK_ONLY) checkPrompts(expected);
127
+ else writePrompts(expected);
@@ -0,0 +1,287 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * harness-audit.mjs — Deterministic harness-audit scorecard script.
4
+ *
5
+ * Runs 36 checks across 9 categories against a target repo. Emits a single
6
+ * JSON record to stdout (schema defined in issue #210) and appends the same
7
+ * record (with session_id) to .orchestrator/metrics/audit.jsonl.
8
+ * Writes a human-readable summary to stderr.
9
+ * Always exits 0 — audit never blocks.
10
+ *
11
+ * Usage: node scripts/harness-audit.mjs
12
+ *
13
+ * Stdlib only: node:fs, node:path, node:child_process, node:url.
14
+ * Rubric version: 2026-06
15
+ */
16
+
17
+ import { existsSync, readFileSync, mkdirSync, appendFileSync } from 'node:fs';
18
+ import { join } from 'node:path';
19
+ import { execFileSync } from 'node:child_process';
20
+
21
+ import {
22
+ runCategory1,
23
+ runCategory2,
24
+ runCategory3,
25
+ runCategory4,
26
+ runCategory5,
27
+ runCategory6,
28
+ runCategory7,
29
+ runCategory8,
30
+ runCategory9,
31
+ } from './lib/harness-audit/categories.mjs';
32
+
33
+ const RUBRIC_VERSION = '2026-06';
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Audit root resolution
37
+ // ---------------------------------------------------------------------------
38
+
39
+ function resolveAuditRoot() {
40
+ const cwd = process.cwd();
41
+ if (existsSync(join(cwd, '.git')) || existsSync(join(cwd, 'CLAUDE.md')) || existsSync(join(cwd, 'AGENTS.md'))) {
42
+ return cwd;
43
+ }
44
+ try {
45
+ const result = execFileSync('git', ['rev-parse', '--show-toplevel'], {
46
+ timeout: 5000,
47
+ stdio: ['pipe', 'pipe', 'pipe'],
48
+ encoding: 'utf8',
49
+ });
50
+ const top = result.trim();
51
+ if (top) return top;
52
+ } catch { /* fall through */ }
53
+ return cwd;
54
+ }
55
+
56
+ // ---------------------------------------------------------------------------
57
+ // Git metadata
58
+ // ---------------------------------------------------------------------------
59
+
60
+ function getGitMeta(root) {
61
+ let branch = null;
62
+ let headSha = null;
63
+ try {
64
+ branch = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
65
+ cwd: root, timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], encoding: 'utf8',
66
+ }).trim();
67
+ } catch { /* ignore */ }
68
+ try {
69
+ headSha = execFileSync('git', ['rev-parse', '--short', 'HEAD'], {
70
+ cwd: root, timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], encoding: 'utf8',
71
+ }).trim();
72
+ } catch { /* ignore */ }
73
+ return { branch: branch || null, head_sha: headSha || null };
74
+ }
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Package version
78
+ // ---------------------------------------------------------------------------
79
+
80
+ function getHarnessVersion(root) {
81
+ try {
82
+ const text = readFileSync(join(root, 'package.json'), 'utf8');
83
+ const pkg = JSON.parse(text);
84
+ return typeof pkg.version === 'string' ? pkg.version : null;
85
+ } catch { return null; }
86
+ }
87
+
88
+ // ---------------------------------------------------------------------------
89
+ // Session ID derivation
90
+ // ---------------------------------------------------------------------------
91
+
92
+ function getSessionId(root, branch) {
93
+ const now = new Date();
94
+ const utcDate = now.toISOString().slice(0, 10); // YYYY-MM-DD
95
+ const utcHHmm = now.toISOString().slice(11, 16).replace(':', ''); // HHmm
96
+
97
+ // Try reading STATE.md for active session_id
98
+ const candidates = [
99
+ join(root, '.claude/STATE.md'),
100
+ join(root, '.codex/STATE.md'),
101
+ join(root, '.cursor/STATE.md'),
102
+ ];
103
+ for (const p of candidates) {
104
+ if (!existsSync(p)) continue;
105
+ try {
106
+ const text = readFileSync(p, 'utf8');
107
+ const fm = parseFrontmatter(text);
108
+ if (fm && fm['status'] === 'active' && fm['session_id']) {
109
+ return fm['session_id'];
110
+ }
111
+ // Build session-id from branch + date if status is active but no session_id key
112
+ if (fm && fm['status'] === 'active') {
113
+ const sessionBranch = fm['branch'] || branch || 'unknown';
114
+ return `${sessionBranch}-${utcDate}-${utcHHmm}`;
115
+ }
116
+ } catch { /* ignore */ }
117
+ }
118
+
119
+ return `standalone-${utcDate}-${utcHHmm}`;
120
+ }
121
+
122
+ // ---------------------------------------------------------------------------
123
+ // Minimal frontmatter parser (duplicated here to avoid lib dependency in main)
124
+ // ---------------------------------------------------------------------------
125
+
126
+ function parseFrontmatter(text) {
127
+ const lines = text.split(/\r?\n/);
128
+ let start = -1;
129
+ let end = -1;
130
+ for (let i = 0; i < lines.length; i++) {
131
+ if (lines[i].trim() === '---') {
132
+ if (start === -1) { start = i; }
133
+ else { end = i; break; }
134
+ }
135
+ }
136
+ if (start === -1 || end === -1) return null;
137
+ const fm = {};
138
+ for (let i = start + 1; i < end; i++) {
139
+ const line = lines[i];
140
+ if (!line.trim() || line.trimStart().startsWith('#')) continue;
141
+ const colon = line.indexOf(':');
142
+ if (colon === -1) continue;
143
+ const key = line.slice(0, colon).trim();
144
+ const val = line.slice(colon + 1).trim();
145
+ fm[key] = val;
146
+ }
147
+ return fm;
148
+ }
149
+
150
+ // ---------------------------------------------------------------------------
151
+ // Score a category from its checks
152
+ // ---------------------------------------------------------------------------
153
+
154
+ function scoreCategory(name, weight, checks) {
155
+ const maxPoints = checks.reduce((s, c) => s + c.max_points, 0);
156
+ const earnedPoints = checks.reduce((s, c) => s + c.points, 0);
157
+ const score010 = maxPoints > 0 ? parseFloat(((earnedPoints / maxPoints) * 10).toFixed(2)) : 0;
158
+ return { name, weight, score_0_10: score010, earned_points: earnedPoints, max_points: maxPoints, checks };
159
+ }
160
+
161
+ // ---------------------------------------------------------------------------
162
+ // Overall band
163
+ // ---------------------------------------------------------------------------
164
+
165
+ function computeBand(score) {
166
+ if (score >= 8.5) return 'healthy';
167
+ if (score >= 6.0) return 'warn';
168
+ return 'critical';
169
+ }
170
+
171
+ // ---------------------------------------------------------------------------
172
+ // stderr summary
173
+ // ---------------------------------------------------------------------------
174
+
175
+ function writeSummary(categories, summary) {
176
+ const bandSymbol = { healthy: '[OK]', warn: '[WARN]', critical: '[CRIT]' };
177
+ process.stderr.write('\n--- harness-audit summary ---\n');
178
+ for (const cat of categories) {
179
+ const band = computeBand(cat.score_0_10);
180
+ process.stderr.write(
181
+ ` ${cat.name.padEnd(32)} score=${cat.score_0_10.toFixed(2)}/10 ${bandSymbol[band]}\n`
182
+ );
183
+ }
184
+ process.stderr.write(
185
+ ` ${'OVERALL'.padEnd(32)} score=${summary.overall_mean_0_10.toFixed(2)}/10 ${bandSymbol[summary.overall_band]} ` +
186
+ `checks=${summary.checks_passed}/${summary.checks_total}\n`
187
+ );
188
+ process.stderr.write('-----------------------------\n\n');
189
+ }
190
+
191
+ // ---------------------------------------------------------------------------
192
+ // Append to audit.jsonl
193
+ // ---------------------------------------------------------------------------
194
+
195
+ function appendAuditRecord(root, record) {
196
+ const metricsDir = join(root, '.orchestrator/metrics');
197
+ try {
198
+ mkdirSync(metricsDir, { recursive: true });
199
+ const line = JSON.stringify(record) + '\n';
200
+ appendFileSync(join(metricsDir, 'audit.jsonl'), line, 'utf8');
201
+ } catch (err) {
202
+ process.stderr.write(`harness-audit: Failed to append audit.jsonl: ${err.message}\n`);
203
+ }
204
+ }
205
+
206
+ // ---------------------------------------------------------------------------
207
+ // Main
208
+ // ---------------------------------------------------------------------------
209
+
210
+ const startedAt = new Date().toISOString();
211
+ const startMs = Date.now();
212
+
213
+ const auditRoot = resolveAuditRoot();
214
+ const gitMeta = getGitMeta(auditRoot);
215
+ const harnessVersion = getHarnessVersion(auditRoot);
216
+ const sessionId = getSessionId(auditRoot, gitMeta.branch);
217
+
218
+ // Run all 9 categories
219
+ const categoryResults = [
220
+ scoreCategory('Session Discipline', 10, runCategory1(auditRoot)),
221
+ scoreCategory('Quality Gate Coverage', 10, runCategory2(auditRoot)),
222
+ scoreCategory('Hook Integrity', 10, runCategory3(auditRoot)),
223
+ scoreCategory('Persistence Health', 10, runCategory4(auditRoot)),
224
+ scoreCategory('Plugin-Root Resolution', 9, runCategory5(auditRoot)),
225
+ scoreCategory('Config Hygiene', 8, runCategory6(auditRoot)),
226
+ scoreCategory('Policy Freshness', 10, runCategory7(auditRoot)),
227
+ // Weight 8 mirrors Config Hygiene (cat 6): cat 8 is structural-hygiene rubric,
228
+ // not runtime-correctness. Weight 10 is reserved for production-impacting cats
229
+ // (Session Discipline / Quality Gate Coverage / Persistence Health / Policy Freshness).
230
+ scoreCategory('Large-Codebase Readiness', 8, runCategory8(auditRoot)),
231
+ // Weight 8 mirrors cat 6/8: skill-health surfacing is an advisory-hygiene
232
+ // rubric, not runtime-correctness. No-adoption scores full points by design
233
+ // (absent telemetry/module are HEALTHY states), so this never penalizes a
234
+ // repo that has not opted into the #648 per-skill health pipeline.
235
+ scoreCategory('Skill-Health Surfacing', 8, runCategory9(auditRoot)),
236
+ ];
237
+
238
+ const durationMs = Date.now() - startMs;
239
+
240
+ // Compute weighted mean
241
+ const totalWeight = categoryResults.reduce((s, c) => s + c.weight, 0);
242
+ const weightedSum = categoryResults.reduce((s, c) => s + c.weight * c.score_0_10, 0);
243
+ const overallMean = parseFloat((weightedSum / totalWeight).toFixed(2));
244
+
245
+ const checksPassed = categoryResults.reduce((s, c) => s + c.checks.filter((ch) => ch.status === 'pass').length, 0);
246
+ const checksTotal = categoryResults.reduce((s, c) => s + c.checks.length, 0);
247
+
248
+ const summary = {
249
+ overall_mean_0_10: overallMean,
250
+ overall_band: computeBand(overallMean),
251
+ checks_passed: checksPassed,
252
+ checks_total: checksTotal,
253
+ };
254
+
255
+ const output = {
256
+ rubric_version: RUBRIC_VERSION,
257
+ started_at: startedAt,
258
+ duration_ms: durationMs,
259
+ audit_root: auditRoot,
260
+ harness_version: harnessVersion,
261
+ categories: categoryResults,
262
+ summary,
263
+ repository: gitMeta,
264
+ };
265
+
266
+ // Write stdout (without session_id — session_id only in audit.jsonl).
267
+ // Use the write callback to ensure the stdout buffer has fully drained before
268
+ // running any subsequent I/O or exiting. On CI runners the process can exit
269
+ // before the pipe buffer flushes, truncating the JSON at the OS pipe boundary
270
+ // (8 KiB on many Linux kernels). Pattern A — drain-aware write (issue #356).
271
+ const jsonStr = JSON.stringify(output, null, 2) + '\n';
272
+ process.stdout.write(jsonStr, (err) => {
273
+ if (err) {
274
+ process.stderr.write(`harness-audit: stdout write error: ${err.message}\n`);
275
+ process.exit(2);
276
+ return; // prevent fall-through to success-path side effects on stdout failure (#356 Q1)
277
+ }
278
+
279
+ // Append to audit.jsonl (with session_id) — runs only after stdout drains
280
+ appendAuditRecord(auditRoot, { session_id: sessionId, ...output });
281
+
282
+ // Write stderr summary
283
+ writeSummary(categoryResults, summary);
284
+
285
+ // Always exit 0
286
+ process.exit(0);
287
+ });
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Agent frontmatter validator — plain-JS, no Zod (issue #189).
3
+ *
4
+ * Validates `.claude/agents/*.md` frontmatter against the project-instruction
5
+ * file's Agent Authoring Rules (CLAUDE.md, or AGENTS.md on Codex CLI — see
6
+ * skills/_shared/instruction-file-resolution.md). Catches the two most common
7
+ * silent-failure pitfalls:
8
+ * (a) `tools` as a JSON array instead of a comma-separated string
9
+ * (b) `description` as a YAML block scalar (`>` or `|`) instead of an
10
+ * inline string
11
+ *
12
+ * Modelled after scripts/lib/state-md.mjs (FRONTMATTER_RE, line-by-line
13
+ * key:value parsing) and scripts/lib/config-schema.mjs (error shape).
14
+ *
15
+ * Never throws. Returns structured result objects.
16
+ */
17
+
18
+ import { readFileSync } from 'node:fs';
19
+
20
+ const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
21
+
22
+ // Aliases per https://code.claude.com/docs/en/sub-agents § model resolution.
23
+ // Full model IDs (claude-{opus|sonnet|haiku|fable}-N[-N][-YYYYMMDD], e.g.
24
+ // "claude-opus-4-7", "claude-sonnet-5", "claude-fable-5-20260101") also
25
+ // accepted via MODEL_ID_RE. `fable` is a valid upstream model family
26
+ // alongside opus/sonnet/haiku (#768) — the trailing numeric group is
27
+ // optional so both the two-part ("claude-sonnet-5") and three-part
28
+ // ("claude-opus-4-7") ID shapes validate.
29
+ // Exported so persona-panel modules (catalog-loader.mjs, persona-gate-wave.mjs) can
30
+ // validate against the SSOT instead of re-declaring (W4 architect MED-1, 2026-05-19).
31
+ export const ALLOWED_MODEL_ALIASES = new Set(['inherit', 'sonnet', 'opus', 'haiku', 'fable']);
32
+ export const MODEL_ID_RE = /^claude-(opus|sonnet|haiku|fable)-\d+(-\d+)?(-\d{8})?$/;
33
+
34
+ // Canonical Anthropic palette (red|blue|green|yellow|purple|orange|pink|cyan)
35
+ // plus magenta from plugin-dev SKILL.md for backward-compat.
36
+ const ALLOWED_COLORS = new Set(['blue', 'cyan', 'green', 'yellow', 'magenta', 'red', 'purple', 'orange', 'pink']);
37
+
38
+ /**
39
+ * name must be 3–50 chars, lowercase letters, digits, hyphens only,
40
+ * starting with a lowercase letter.
41
+ */
42
+ const NAME_RE = /^[a-z][a-z0-9-]{2,49}$/;
43
+
44
+ /**
45
+ * Parses the YAML frontmatter block from an agent markdown file.
46
+ *
47
+ * Preserves raw string values so the validator can detect JSON-array tools
48
+ * and block-scalar descriptions without normalising them away.
49
+ *
50
+ * @returns {{ ok: true, frontmatter: Record<string,string>, body: string }
51
+ * |{ ok: false, errors: Array<{path: string, rule: string, message: string}> }}
52
+ */
53
+ export function parseAgentFrontmatter(contents) {
54
+ if (typeof contents !== 'string') {
55
+ return {
56
+ ok: false,
57
+ errors: [{ path: '$', rule: 'type', message: 'contents must be a string' }],
58
+ };
59
+ }
60
+
61
+ const match = FRONTMATTER_RE.exec(contents);
62
+ if (!match) {
63
+ return {
64
+ ok: false,
65
+ errors: [
66
+ {
67
+ path: '$',
68
+ rule: 'missing-frontmatter',
69
+ message: 'No YAML front-matter block (expected file to start with ---)',
70
+ },
71
+ ],
72
+ };
73
+ }
74
+
75
+ const [, fmText, body] = match;
76
+ const frontmatter = /** @type {Record<string,string>} */ ({});
77
+ const lines = fmText.split(/\r?\n/);
78
+
79
+ for (const rawLine of lines) {
80
+ const line = rawLine.replace(/\s+$/, '');
81
+ if (line === '' || /^\s*#/.test(line)) continue;
82
+
83
+ // Detect block-scalar indicators on a key line, e.g. `description: >` or `description: |`
84
+ // These are valid YAML but break Claude Code's parser.
85
+ const blockScalarMatch = /^(\w[\w-]*):\s*[>|]\s*$/.exec(line);
86
+ if (blockScalarMatch) {
87
+ // Store a sentinel so the validator can emit the correct rule.
88
+ frontmatter[blockScalarMatch[1]] = '__BLOCK_SCALAR__';
89
+ continue;
90
+ }
91
+
92
+ const idx = line.indexOf(':');
93
+ if (idx === -1) continue;
94
+ const key = line.slice(0, idx).trim();
95
+ if (key === '') continue;
96
+ const value = line.slice(idx + 1).trim();
97
+ frontmatter[key] = value;
98
+ }
99
+
100
+ return {
101
+ ok: true,
102
+ frontmatter,
103
+ body: body.startsWith('\n') ? body.slice(1) : body,
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Validates a parsed frontmatter object against CLAUDE.md Agent Authoring Rules.
109
+ *
110
+ * @param {Record<string,string>|null|undefined} frontmatter
111
+ * @returns {{ ok: true }|{ ok: false, errors: Array<{path: string, rule: string, message: string}> }}
112
+ */
113
+ export function validateAgentFrontmatter(frontmatter) {
114
+ if (frontmatter === null || frontmatter === undefined || typeof frontmatter !== 'object') {
115
+ return {
116
+ ok: false,
117
+ errors: [{ path: '$', rule: 'missing-frontmatter', message: 'No YAML front-matter block' }],
118
+ };
119
+ }
120
+
121
+ const errors = /** @type {Array<{path: string, rule: string, message: string}>} */ ([]);
122
+
123
+ // --- name ---
124
+ const name = frontmatter['name'];
125
+ if (name === undefined || name === '') {
126
+ errors.push({
127
+ path: 'name',
128
+ rule: 'required',
129
+ message: 'name is required',
130
+ });
131
+ } else if (!NAME_RE.test(name)) {
132
+ errors.push({
133
+ path: 'name',
134
+ rule: 'name-format',
135
+ message: `name must be 3–50 chars, lowercase letters/digits/hyphens, starting with a letter (got ${JSON.stringify(name)})`,
136
+ });
137
+ }
138
+
139
+ // --- description ---
140
+ const description = frontmatter['description'];
141
+ if (description === undefined || description === '') {
142
+ errors.push({
143
+ path: 'description',
144
+ rule: 'required',
145
+ message: 'description is required',
146
+ });
147
+ } else if (description === '__BLOCK_SCALAR__') {
148
+ errors.push({
149
+ path: 'description',
150
+ rule: 'no-block-scalar',
151
+ message:
152
+ 'description must be an inline single-line string, not a YAML block scalar (> or |). Put <example> blocks inline.',
153
+ });
154
+ }
155
+
156
+ // --- model ---
157
+ const model = frontmatter['model'];
158
+ if (model === undefined || model === '') {
159
+ errors.push({
160
+ path: 'model',
161
+ rule: 'required',
162
+ message: 'model is required',
163
+ });
164
+ } else if (!ALLOWED_MODEL_ALIASES.has(model) && !MODEL_ID_RE.test(model)) {
165
+ errors.push({
166
+ path: 'model',
167
+ rule: 'enum',
168
+ message: `model must be one of ${[...ALLOWED_MODEL_ALIASES].map((m) => JSON.stringify(m)).join('|')} or a full model ID like "claude-opus-4-7" or "claude-sonnet-5" (got ${JSON.stringify(model)})`,
169
+ });
170
+ }
171
+
172
+ // --- color ---
173
+ const color = frontmatter['color'];
174
+ if (color === undefined || color === '') {
175
+ errors.push({
176
+ path: 'color',
177
+ rule: 'required',
178
+ message: 'color is required',
179
+ });
180
+ } else if (!ALLOWED_COLORS.has(color)) {
181
+ errors.push({
182
+ path: 'color',
183
+ rule: 'enum',
184
+ message: `color must be one of ${[...ALLOWED_COLORS].map((c) => JSON.stringify(c)).join('|')} (got ${JSON.stringify(color)})`,
185
+ });
186
+ }
187
+
188
+ // --- tools (optional) ---
189
+ // Both forms accepted per Anthropic canonical:
190
+ // 1. Comma-separated string: "Read, Edit, Write"
191
+ // 2. JSON array: ["Read","Edit","Write"]
192
+ // Reject only malformed arrays (non-string elements, parse failures).
193
+ const tools = frontmatter['tools'];
194
+ if (tools !== undefined && tools !== '' && typeof tools === 'string') {
195
+ if (tools.startsWith('[')) {
196
+ let parsed;
197
+ try {
198
+ parsed = JSON.parse(tools);
199
+ } catch {
200
+ errors.push({
201
+ path: 'tools',
202
+ rule: 'malformed-array',
203
+ message: `tools is a malformed JSON array: ${tools}`,
204
+ });
205
+ parsed = null;
206
+ }
207
+ if (parsed !== null) {
208
+ if (!Array.isArray(parsed)) {
209
+ errors.push({
210
+ path: 'tools',
211
+ rule: 'array-expected',
212
+ message: `tools must be an array when using JSON form (got ${typeof parsed})`,
213
+ });
214
+ } else if (!parsed.every((t) => typeof t === 'string')) {
215
+ errors.push({
216
+ path: 'tools',
217
+ rule: 'array-strings-only',
218
+ message: 'tools array must contain only string elements',
219
+ });
220
+ }
221
+ }
222
+ }
223
+ }
224
+
225
+ return errors.length > 0 ? { ok: false, errors } : { ok: true };
226
+ }
227
+
228
+ /**
229
+ * Convenience function: reads a file, parses its frontmatter, and validates it.
230
+ *
231
+ * Never throws. Returns a result object with the file path attached.
232
+ *
233
+ * @param {string} filePath - absolute or relative path to the agent .md file
234
+ * @returns {{ ok: true, file: string }
235
+ * |{ ok: false, file: string, errors: Array<{path: string, rule: string, message: string}> }}
236
+ */
237
+ export function validateAgentFile(filePath) {
238
+ let contents;
239
+ try {
240
+ contents = readFileSync(filePath, 'utf8');
241
+ } catch (err) {
242
+ return {
243
+ ok: false,
244
+ file: filePath,
245
+ errors: [
246
+ {
247
+ path: '$',
248
+ rule: 'read-error',
249
+ message: `Could not read file: ${err.message}`,
250
+ },
251
+ ],
252
+ };
253
+ }
254
+
255
+ const parsed = parseAgentFrontmatter(contents);
256
+ if (!parsed.ok) {
257
+ return { ok: false, file: filePath, errors: parsed.errors };
258
+ }
259
+
260
+ const validation = validateAgentFrontmatter(parsed.frontmatter);
261
+ if (!validation.ok) {
262
+ return { ok: false, file: filePath, errors: validation.errors };
263
+ }
264
+
265
+ return { ok: true, file: filePath };
266
+ }