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,213 @@
1
+ import { matchBlockHeader } from './block-header.mjs';
2
+
3
+ /**
4
+ * custom-phases.mjs — Parser for the `custom-phases:` Session Config block (#637).
5
+ *
6
+ * Lets a repo declare opt-in deterministic phases that run during session close
7
+ * (and/or housekeeping) as a CONTRACT: each phase has a name, a `when` trigger,
8
+ * a shell `command`, a `mode` (warn|hard|off) that gates the close, and an
9
+ * optional `review` file the coordinator reads after the command.
10
+ *
11
+ * Exports:
12
+ * _parseCustomPhases(content) — PURE, no side effects beyond a stderr WARN when
13
+ * a record is dropped for failing validation.
14
+ * Returns [] when the block is absent/empty.
15
+ *
16
+ * Block shape:
17
+ * custom-phases:
18
+ * - name: eval-learn-aggregate # required, non-empty, SAFE slug
19
+ * when: housekeeping # housekeeping | session-end | both (default: session-end)
20
+ * command: npm run eval:aggregate # required; NO interpolation from records
21
+ * mode: hard # warn | hard | off (default: warn)
22
+ * review: docs/eval/last-run.md # optional; SAFE_PATH_RE-validated; default null
23
+ *
24
+ * Modelled on cross-repo.mjs (per-entry SAFE_PATH_RE validation, drop-with-warn)
25
+ * and gitlab-portfolio.mjs (nested list/column-0 block scan). Enum fallbacks are
26
+ * SILENT to the default per block-parser convention (vault-sync.mjs precedent).
27
+ *
28
+ * NOTE on the mode enum: it is ['warn','hard','off'] — `hard` is the correct
29
+ * blocking value for THIS new key. Do NOT copy vault-sync's ['strict','warn','off']
30
+ * (see #217 regression: `hard` was a silent-default bug THERE, intentional HERE).
31
+ */
32
+
33
+ /** Per-phase defaults. */
34
+ export const CUSTOM_PHASE_DEFAULTS = Object.freeze({
35
+ when: 'session-end',
36
+ mode: 'warn',
37
+ review: null,
38
+ });
39
+
40
+ const VALID_WHEN = new Set(['housekeeping', 'session-end', 'both']);
41
+ const VALID_MODE = new Set(['warn', 'hard', 'off']);
42
+
43
+ // Allowlist: a phase `name` is a SAFE slug — lowercase/uppercase letters, digits,
44
+ // hyphen, underscore, dot. No spaces, no shell metacharacters.
45
+ const SAFE_NAME_RE = /^[A-Za-z0-9._-]+$/;
46
+
47
+ // Allowlist for `command` and `review`: rejects shell metacharacters (; $ ` | & > <
48
+ // ( ) newline) that would break the exit-code-gated execution / file-read contract.
49
+ // `command` legitimately contains spaces, slashes, colons (e.g. "npm run eval:aggregate"),
50
+ // so the allowlist is broader than SAFE_NAME_RE but still excludes injection vectors.
51
+ const SAFE_COMMAND_RE = /^[A-Za-z0-9._\-/: =]+$/;
52
+
53
+ // `review` is a repo-relative or absolute file path — no spaces, no metacharacters.
54
+ const SAFE_PATH_RE = /^[A-Za-z0-9._~/-]+$/;
55
+
56
+ /**
57
+ * Parse the top-level `custom-phases:` YAML list block from markdown content.
58
+ *
59
+ * Each list item is a record. Records are validated per-entry; a record missing
60
+ * a required field (`name`, `command`) or carrying a shell-metacharacter in
61
+ * `command`/`review`/`name` is DROPPED with a stderr WARN. Invalid `when`/`mode`
62
+ * enum values fall back SILENTLY to their defaults.
63
+ *
64
+ * @param {string} content — full CLAUDE.md / AGENTS.md file content
65
+ * @returns {Array<{name: string, when: string, command: string, mode: string, review: string|null}>}
66
+ */
67
+ export function _parseCustomPhases(content) {
68
+ const lines = content.split(/\r?\n/);
69
+ let inBlock = false;
70
+ const blockLines = [];
71
+
72
+ for (const rawLine of lines) {
73
+ const line = rawLine.replace(/\r$/, '');
74
+
75
+ if (!inBlock) {
76
+ // Detect `custom-phases:` at column 0 with optional trailing spaces.
77
+ if (matchBlockHeader(line, 'custom-phases')) inBlock = true;
78
+ continue;
79
+ }
80
+
81
+ // Block terminates at the first non-indented, non-empty line (next top-level key).
82
+ if (line.length > 0 && !/^\s/.test(line)) break;
83
+
84
+ blockLines.push(line);
85
+ }
86
+
87
+ if (blockLines.length === 0) return [];
88
+
89
+ /** @type {Array<{name: string, when: string, command: string, mode: string, review: string|null}>} */
90
+ const records = [];
91
+ /** @type {Record<string, string>|null} */
92
+ let current = null;
93
+
94
+ const flush = () => {
95
+ if (current === null) return;
96
+ const rec = _validateRecord(current);
97
+ if (rec !== null) records.push(rec);
98
+ current = null;
99
+ };
100
+
101
+ for (const rawLine of blockLines) {
102
+ // Strip inline comments + trailing whitespace, preserve leading indent.
103
+ const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
104
+ if (!clean.trim()) continue;
105
+
106
+ // A new list item starts with a dash. The first key may sit on the dash line:
107
+ // - name: foo
108
+ const dashMatch = clean.match(/^\s*-\s+(.*)$/);
109
+ if (dashMatch) {
110
+ flush();
111
+ current = {};
112
+ const inlineKv = dashMatch[1].match(/^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/);
113
+ if (inlineKv) {
114
+ _assignKv(current, inlineKv[1], inlineKv[2]);
115
+ }
116
+ continue;
117
+ }
118
+
119
+ // Continuation key for the current record (deeper indent, no dash).
120
+ const kvMatch = clean.match(/^\s+([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)$/);
121
+ if (kvMatch && current !== null) {
122
+ _assignKv(current, kvMatch[1], kvMatch[2]);
123
+ }
124
+ }
125
+
126
+ flush();
127
+
128
+ return records;
129
+ }
130
+
131
+ /**
132
+ * Assign a raw key/value onto a record being built, stripping surrounding quotes.
133
+ * Only known keys are stored; unknown keys are silently ignored (additive-friendly).
134
+ *
135
+ * @param {Record<string, string>} record
136
+ * @param {string} key
137
+ * @param {string} rawValue
138
+ */
139
+ function _assignKv(record, key, rawValue) {
140
+ let v = rawValue.trim();
141
+ if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
142
+ else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
143
+
144
+ switch (key) {
145
+ case 'name':
146
+ case 'when':
147
+ case 'command':
148
+ case 'mode':
149
+ case 'review':
150
+ record[key] = v;
151
+ break;
152
+ default:
153
+ // Unknown keys are silently ignored — additive-friendly.
154
+ break;
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Validate + normalise a raw record. Returns the fully-defaulted record, or null
160
+ * (with a stderr WARN) when a required field is missing or a SAFE-regex fails.
161
+ *
162
+ * @param {Record<string, string>} raw
163
+ * @returns {{name: string, when: string, command: string, mode: string, review: string|null}|null}
164
+ */
165
+ function _validateRecord(raw) {
166
+ const name = (raw.name ?? '').trim();
167
+ if (name === '') {
168
+ process.stderr.write('custom-phases: dropped record missing required field: name\n');
169
+ return null;
170
+ }
171
+ if (!SAFE_NAME_RE.test(name)) {
172
+ process.stderr.write(
173
+ `custom-phases: dropped record with unsafe name: ${JSON.stringify(name)}\n`,
174
+ );
175
+ return null;
176
+ }
177
+
178
+ const command = (raw.command ?? '').trim();
179
+ if (command === '') {
180
+ process.stderr.write(
181
+ `custom-phases: dropped record '${name}' missing required field: command\n`,
182
+ );
183
+ return null;
184
+ }
185
+ if (!SAFE_COMMAND_RE.test(command)) {
186
+ process.stderr.write(
187
+ `custom-phases: dropped record '${name}' with shell metacharacter in command: ${JSON.stringify(command)}\n`,
188
+ );
189
+ return null;
190
+ }
191
+
192
+ // when: enum fallback SILENT to default.
193
+ const when = VALID_WHEN.has(raw.when) ? raw.when : CUSTOM_PHASE_DEFAULTS.when;
194
+
195
+ // mode: enum fallback SILENT to default.
196
+ const mode = VALID_MODE.has(raw.mode) ? raw.mode : CUSTOM_PHASE_DEFAULTS.mode;
197
+
198
+ // review: optional; validated against SAFE_PATH_RE. An unsafe path DROPS the
199
+ // whole record (it is a security-relevant field the coordinator will read).
200
+ let review = CUSTOM_PHASE_DEFAULTS.review;
201
+ const rawReview = (raw.review ?? '').trim();
202
+ if (rawReview !== '' && rawReview !== 'null' && rawReview !== 'none') {
203
+ if (!SAFE_PATH_RE.test(rawReview)) {
204
+ process.stderr.write(
205
+ `custom-phases: dropped record '${name}' with shell metacharacter in review path: ${JSON.stringify(rawReview)}\n`,
206
+ );
207
+ return null;
208
+ }
209
+ review = rawReview;
210
+ }
211
+
212
+ return { name, when, command, mode, review };
213
+ }
@@ -0,0 +1,92 @@
1
+ import { matchBlockHeader } from './block-header.mjs';
2
+
3
+ /**
4
+ * dialectic.mjs — Parser for top-level `dialectic:` YAML block (#506).
5
+ *
6
+ * Drives the Dialectic-Deriver via /evolve --dialectic and session-end Phase 3.6.7.
7
+ * Returns { cadence, model, "budget-tokens" }.
8
+ * Fail-fast on unknown model value (per #506 EARS unwanted-behaviour);
9
+ * silent fallback for out-of-range integers (matches cold-start.mjs precedent).
10
+ *
11
+ * Consumer: skills/evolve/SKILL.md Phase 6, skills/session-end/SKILL.md Phase 3.6.7.
12
+ */
13
+
14
+ const ALLOWED_MODELS = new Set(['haiku', 'sonnet', 'opus']);
15
+
16
+ /**
17
+ * Parse the top-level `dialectic:` YAML block from markdown content.
18
+ * Independent of the `## Session Config` section boundary.
19
+ *
20
+ * Defaults:
21
+ * cadence: 5 (integer ≥ 0 — session count between auto-runs; 0 = disabled)
22
+ * model: 'haiku'
23
+ * budget-tokens: 8000 (integer ≥ 0)
24
+ *
25
+ * Throws if `model` is present but not one of haiku|sonnet|opus.
26
+ *
27
+ * @param {string} content — full file contents
28
+ * @returns {{ cadence: number, model: string, "budget-tokens": number }}
29
+ */
30
+ export function _parseDialectic(content) {
31
+ const defaults = { cadence: 5, model: 'haiku', 'budget-tokens': 8000 };
32
+
33
+ const lines = content.split(/\r?\n/);
34
+ let inBlock = false;
35
+ const blockLines = [];
36
+
37
+ for (const rawLine of lines) {
38
+ const line = rawLine.replace(/\r$/, '');
39
+ if (!inBlock) {
40
+ if (matchBlockHeader(line, 'dialectic')) inBlock = true;
41
+ continue;
42
+ }
43
+ if (line.length > 0 && !/^\s/.test(line)) break;
44
+ blockLines.push(line);
45
+ }
46
+
47
+ if (blockLines.length === 0) return defaults;
48
+
49
+ let cadence = 5;
50
+ let model = 'haiku';
51
+ let budgetTokens = 8000;
52
+
53
+ for (const rawLine of blockLines) {
54
+ const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
55
+ if (!clean.trim()) continue;
56
+
57
+ const kvMatch = clean.match(/^\s+([a-zA-Z_-]+):\s*(.*)/);
58
+ if (!kvMatch) continue;
59
+
60
+ const k = kvMatch[1];
61
+ let v = kvMatch[2].trim();
62
+ if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
63
+ else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
64
+
65
+ switch (k) {
66
+ case 'cadence': {
67
+ if (/^\d+$/.test(v)) {
68
+ const n = parseInt(v, 10);
69
+ if (n >= 0) cadence = n;
70
+ }
71
+ break;
72
+ }
73
+ case 'model': {
74
+ const lower = v.toLowerCase();
75
+ if (!ALLOWED_MODELS.has(lower)) {
76
+ throw new Error(`dialectic.model must be haiku|sonnet|opus, got '${v}'`);
77
+ }
78
+ model = lower;
79
+ break;
80
+ }
81
+ case 'budget-tokens': {
82
+ if (/^\d+$/.test(v)) {
83
+ const n = parseInt(v, 10);
84
+ if (n >= 0) budgetTokens = n;
85
+ }
86
+ break;
87
+ }
88
+ }
89
+ }
90
+
91
+ return { cadence, model, 'budget-tokens': budgetTokens };
92
+ }
@@ -0,0 +1,75 @@
1
+ import { matchBlockHeader } from './block-header.mjs';
2
+
3
+ /**
4
+ * discovery-validator.mjs — Parser for the top-level `discovery-validator:`
5
+ * YAML block (PSA-006 mechanical enforcement / issue #567).
6
+ *
7
+ * Drives the non-blocking SubagentStop hook that flags distributional
8
+ * claims ("N of M", "100% of", "all N", "no remaining", "every X", "none of")
9
+ * in a subagent's transcript tail that lack an adjacent fenced grep/rg/find
10
+ * transcript. v1 is log+warn only (events.jsonl + stderr WARN); exit 2
11
+ * (blocking) is reserved for a future hard-gate.
12
+ *
13
+ * Returns `{ enabled }`.
14
+ * Tolerant parser: malformed values silently fall back to defaults.
15
+ *
16
+ * Consumer: `hooks/post-subagent-discovery-validator.mjs`.
17
+ */
18
+
19
+ /**
20
+ * Parse the top-level `discovery-validator:` YAML block from markdown content.
21
+ * Independent of the `## Session Config` section boundary.
22
+ *
23
+ * Defaults:
24
+ * enabled: true
25
+ *
26
+ * @param {string} content — full file contents
27
+ * @returns {{ enabled: boolean }}
28
+ */
29
+ export function _parseDiscoveryValidator(content) {
30
+ const defaults = {
31
+ enabled: true,
32
+ };
33
+
34
+ const lines = content.split(/\r?\n/);
35
+ let inBlock = false;
36
+ const blockLines = [];
37
+
38
+ for (const rawLine of lines) {
39
+ const line = rawLine.replace(/\r$/, '');
40
+ if (!inBlock) {
41
+ if (matchBlockHeader(line, 'discovery-validator')) inBlock = true;
42
+ continue;
43
+ }
44
+ if (line.length > 0 && !/^\s/.test(line)) break;
45
+ blockLines.push(line);
46
+ }
47
+
48
+ if (blockLines.length === 0) return defaults;
49
+
50
+ let dvEnabled = false;
51
+
52
+ for (const rawLine of blockLines) {
53
+ const clean = rawLine.replace(/\s*#.*$/, '').replace(/\s+$/, '');
54
+ if (!clean.trim()) continue;
55
+
56
+ const kvMatch = clean.match(/^\s+([a-zA-Z_-]+):\s*(.*)/);
57
+ if (!kvMatch) continue;
58
+
59
+ const k = kvMatch[1];
60
+ let v = kvMatch[2].trim();
61
+ if (v.startsWith('"') && v.endsWith('"') && v.length >= 2) v = v.slice(1, -1);
62
+ else if (v.startsWith("'") && v.endsWith("'") && v.length >= 2) v = v.slice(1, -1);
63
+
64
+ switch (k) {
65
+ case 'enabled':
66
+ // Only literal "true" (case-insensitive) flips enabled; any other value → false
67
+ dvEnabled = v.toLowerCase() === 'true';
68
+ break;
69
+ }
70
+ }
71
+
72
+ return {
73
+ enabled: dvEnabled,
74
+ };
75
+ }
@@ -0,0 +1,240 @@
1
+ /**
2
+ * dispatcher-autonomy-capture.mjs — One-time per-repo capture of the
3
+ * `dispatcher-autonomy:` preference (Epic #673 / issue #681).
4
+ *
5
+ * The committed `dispatcher-autonomy:` block is asked EXACTLY ONCE per repo at
6
+ * two triggers:
7
+ * (a) bootstrap — new project, block always absent → always asks.
8
+ * (b) migration — first session-start after this feature ships, when the
9
+ * committed block is still absent.
10
+ *
11
+ * The guard is the RAW PRESENCE of the committed block, not the RESOLVED value:
12
+ * `_parseDispatcherAutonomy()` returns `autonomy: 'off'` for BOTH "block absent"
13
+ * AND "block present with autonomy: off" — so the resolved value cannot
14
+ * distinguish first-run from a deliberate `off`. This module therefore detects
15
+ * presence via the shared bold-tolerant `hasBlockHeader()` helper
16
+ * (block-header.mjs) — the same matcher the parser now uses (#830).
17
+ * Block presence IS the never-re-ask marker — there is no separate state file.
18
+ *
19
+ * The committed instruction file is `CLAUDE.md` on Claude Code / Cursor IDE and
20
+ * `AGENTS.md` on Codex CLI — transparent aliases (see
21
+ * `skills/_shared/instruction-file-resolution.md`); every reference to `CLAUDE.md`
22
+ * below resolves to `AGENTS.md` on those platforms.
23
+ *
24
+ * The writer writes ONLY the committed default (autonomy enum + confidence-floor).
25
+ * Host-local overrides (env `SO_DISPATCHER_AUTONOMY`, owner.yaml
26
+ * `dispatcher.autonomy`) NEVER land in CLAUDE.md / AGENTS.md — they stay host-local
27
+ * so a machine may differ from the committed default. See
28
+ * `scripts/lib/config/dispatcher-autonomy.mjs` `resolveDispatcherAutonomy()`.
29
+ *
30
+ * Pure, no-throw, zero-coupling helpers. The coordinator drives the
31
+ * AskUserQuestion call; this module only provides the question definition,
32
+ * the presence guard, the block renderer, and the idempotent writer.
33
+ *
34
+ * Consumers:
35
+ * - `skills/bootstrap/SKILL.md` (Phase 3.5.1 — new-project capture)
36
+ * - `skills/session-start/SKILL.md` (Phase 1.1 — migration capture)
37
+ */
38
+
39
+ import { readFileSync, writeFileSync } from 'node:fs';
40
+
41
+ import { hasBlockHeader } from './block-header.mjs';
42
+
43
+ const ALLOWED_AUTONOMY = ['off', 'advisory', 'autonomous-gated'];
44
+ const DEFAULT_CONFIDENCE_FLOOR = 0.5;
45
+
46
+ /**
47
+ * Coordinator-facing AUQ question definition for the one-time capture.
48
+ * Mirrors the shape of `getInterviewQuestions()` entries in owner-interview.mjs:
49
+ * { question, header, options: [{ label, description }], multiSelect }
50
+ *
51
+ * Option labels match the ALLOWED_AUTONOMY enum so the selected label maps
52
+ * directly to the `autonomy` value passed to writeDispatcherAutonomyBlock().
53
+ * Option 1 (`off`) is the recommended, fail-closed default.
54
+ *
55
+ * @returns {{ question: string, header: string, options: Array<{ label: string, description: string }>, multiSelect: boolean }}
56
+ */
57
+ export function getDispatcherAutonomyQuestion() {
58
+ return {
59
+ question:
60
+ 'Cross-repo dispatcher autonomy: how should this repo participate when the free-repo dispatcher routes work to it?',
61
+ header: 'Dispatcher Autonomy (one-time)',
62
+ options: [
63
+ {
64
+ label: 'off',
65
+ description:
66
+ '(Recommended) Fail-closed. The dispatcher never routes work to this repo automatically. No behaviour change.',
67
+ },
68
+ {
69
+ label: 'advisory',
70
+ description:
71
+ 'The dispatcher surfaces ranked free-repo candidates for operator review — no automated dispatch.',
72
+ },
73
+ {
74
+ label: 'autonomous-gated',
75
+ description:
76
+ 'A deterministic confidence gate is checked first; only dispatches that clear the confidence-floor route automatically.',
77
+ },
78
+ ],
79
+ multiSelect: false,
80
+ };
81
+ }
82
+
83
+ /**
84
+ * Detect whether the committed `dispatcher-autonomy:` block is present in the
85
+ * given CLAUDE.md / AGENTS.md content. This is the one-time-capture guard:
86
+ * absent → ask, present → never re-ask.
87
+ *
88
+ * SOURCE-OF-TRUTH ALIGNMENT: this guard mirrors the block-header detection of
89
+ * `_parseDispatcherAutonomy()` in dispatcher-autonomy.mjs EXACTLY — both now call
90
+ * the shared `matchBlockHeader()` matcher (block-header.mjs). `hasBlockHeader()`
91
+ * splits on `/\r?\n/` and tests each line, so `\r` and trailing whitespace are
92
+ * eaten by the `\s*$` tail and the identical set of inputs matches.
93
+ * Verified-equivalent edge cases:
94
+ * - CRLF line endings (`dispatcher-autonomy:\r\n`) → PRESENT (`\s*$` eats the `\r`).
95
+ * - Trailing spaces / tabs on the header line → PRESENT (`\s*$`).
96
+ * - Header glued to a leading BOM (a U+FEFF byte-order-mark immediately
97
+ * preceding `dispatcher-autonomy:`) → ABSENT, because `^...` requires column-0
98
+ * and the BOM occupies it — IDENTICAL to the parser, which also rejects it.
99
+ * (A BOM at file START with the header on a
100
+ * LATER line is unaffected; the block is always appended to the end of an
101
+ * existing file, so the BOM never touches the header in practice.)
102
+ * - Header inside a ``` fenced code block → PRESENT. This is DELIBERATE: the
103
+ * parser does not track fences and would treat such a header as a real block,
104
+ * so the guard must agree. The never-re-ask marker is "the parser would see a
105
+ * block", not "a human would call it config". If the parser is ever taught to
106
+ * skip fences, update this guard in lock-step.
107
+ * - Header present but BODY malformed (garbage non-yaml lines) → PRESENT. A
108
+ * malformed block is the operator's to fix, never a re-prompt trigger — the
109
+ * parser tolerantly falls back to defaults, and capture must not re-ask.
110
+ *
111
+ * No-throw: null / non-string / empty → false.
112
+ *
113
+ * @param {unknown} claudeMdContent — full CLAUDE.md / AGENTS.md file contents
114
+ * @returns {boolean}
115
+ */
116
+ export function isDispatcherAutonomyBlockPresent(claudeMdContent) {
117
+ if (typeof claudeMdContent !== 'string' || claudeMdContent.length === 0) return false;
118
+ return hasBlockHeader(claudeMdContent, 'dispatcher-autonomy');
119
+ }
120
+
121
+ /**
122
+ * Coerce a candidate autonomy value to a valid lowercase enum, falling back to
123
+ * 'off' when unset/empty/whitespace/invalid (fail-closed). Mirrors the
124
+ * fail-closed posture of resolveDispatcherAutonomy().
125
+ *
126
+ * @param {unknown} value
127
+ * @returns {string} one of ALLOWED_AUTONOMY
128
+ */
129
+ function coerceAutonomy(value) {
130
+ if (value === null || value === undefined) return 'off';
131
+ const normalized = String(value).toLowerCase().trim();
132
+ return ALLOWED_AUTONOMY.includes(normalized) ? normalized : 'off';
133
+ }
134
+
135
+ /**
136
+ * Clamp a candidate confidence-floor to the closed interval [0.0, 1.0],
137
+ * falling back to the default when unset/non-finite.
138
+ *
139
+ * @param {unknown} value
140
+ * @returns {number} float in [0.0, 1.0]
141
+ */
142
+ function clampConfidenceFloor(value) {
143
+ if (value === null || value === undefined || value === '') return DEFAULT_CONFIDENCE_FLOOR;
144
+ const f = Number(value);
145
+ if (!Number.isFinite(f)) return DEFAULT_CONFIDENCE_FLOOR;
146
+ if (f < 0) return 0;
147
+ if (f > 1) return 1;
148
+ return f;
149
+ }
150
+
151
+ /**
152
+ * Render the canonical standalone `## Dispatcher Autonomy` H2 block + fenced
153
+ * yaml. The standalone-H2 placement is MANDATORY: it keeps
154
+ * claude-md-drift-check Check-6 (Session-Config-parity) green. Promoting the
155
+ * block into `## Session Config` would hard-fail drift-check on every repo
156
+ * lacking the key.
157
+ *
158
+ * Validates `autonomy` against the enum (fall back to 'off') and clamps
159
+ * `confidenceFloor` to [0, 1]. Writes ONLY the committed default — never the
160
+ * host-local override.
161
+ *
162
+ * @param {{ autonomy?: unknown, confidenceFloor?: unknown }} [opts]
163
+ * @returns {string} the rendered block (leading newline, trailing newline)
164
+ */
165
+ export function renderDispatcherAutonomyBlock({ autonomy, confidenceFloor = DEFAULT_CONFIDENCE_FLOOR } = {}) {
166
+ const safeAutonomy = coerceAutonomy(autonomy);
167
+ const safeFloor = clampConfidenceFloor(confidenceFloor);
168
+
169
+ return [
170
+ '',
171
+ '## Dispatcher Autonomy',
172
+ '',
173
+ '> **Parity-exempt section.** This H2 is intentionally placed outside the `## Session Config` block so that the `claude-md-drift-check` Check-6 parity scanner (which extracts only column-0 keys inside the `## Session Config` block) does not flag repos that have not yet adopted this feature. Issue #679 / #681.',
174
+ '',
175
+ 'Opt-in configuration for the cross-repo free-repo dispatcher autonomy gate (Epic #673). The default is `off` — fail-closed. The effective `autonomy` resolves with host-local precedence `SO_DISPATCHER_AUTONOMY` env > `owner.yaml` `dispatcher.autonomy` > committed > `off` (#653 pattern).',
176
+ '',
177
+ '```yaml',
178
+ 'dispatcher-autonomy:',
179
+ ` autonomy: ${safeAutonomy} # off | advisory | autonomous-gated — default off (fail-closed)`,
180
+ ` confidence-floor: ${safeFloor} # float 0.0..1.0`,
181
+ '```',
182
+ '',
183
+ 'Read by: `scripts/lib/config/dispatcher-autonomy.mjs` (parser + resolver), `skills/dispatcher/SKILL.md` (cross-repo dispatch flow). Issue: #681.',
184
+ '',
185
+ ].join('\n');
186
+ }
187
+
188
+ /**
189
+ * Idempotently append the committed `dispatcher-autonomy:` block to CLAUDE.md.
190
+ *
191
+ * Behaviour:
192
+ * - block ABSENT → append the rendered block → { written: true, path }.
193
+ * - block PRESENT → no-op → { written: false, reason: 'already-present' }.
194
+ * - IO failure → { written: false, error: <message> } (no-throw).
195
+ *
196
+ * Block presence IS the never-re-ask marker, so a second invocation after a
197
+ * successful write is a safe no-op. A defensive double-write guard re-checks
198
+ * absence against the freshly-read file content immediately before writing (the
199
+ * content read here is the source of truth, not a stale caller-supplied value).
200
+ * This guard fires for a PARTIAL/MALFORMED existing block too: if a (even
201
+ * garbage-bodied) `dispatcher-autonomy:` header already exists, the writer
202
+ * returns `already-present` and never appends a second block — a malformed block
203
+ * is the operator's to repair, not ours to duplicate. The no-op is therefore
204
+ * idempotent against concurrent sessions (parallel writers) AND against
205
+ * hand-edited malformed blocks.
206
+ *
207
+ * @param {{ claudeMdPath: string, autonomy?: unknown, confidenceFloor?: unknown }} opts
208
+ * @returns {{ written: boolean, path?: string, reason?: string, error?: string }}
209
+ */
210
+ export function writeDispatcherAutonomyBlock({ claudeMdPath, autonomy, confidenceFloor } = {}) {
211
+ if (typeof claudeMdPath !== 'string' || claudeMdPath.length === 0) {
212
+ return { written: false, error: 'writeDispatcherAutonomyBlock requires a claudeMdPath' };
213
+ }
214
+
215
+ let content;
216
+ try {
217
+ content = readFileSync(claudeMdPath, 'utf8');
218
+ } catch (err) {
219
+ return { written: false, error: `read failed: ${err && err.message ? err.message : String(err)}` };
220
+ }
221
+
222
+ // Defensive double-write guard: re-check absence against the freshly-read
223
+ // content before writing.
224
+ if (isDispatcherAutonomyBlockPresent(content)) {
225
+ return { written: false, reason: 'already-present' };
226
+ }
227
+
228
+ const block = renderDispatcherAutonomyBlock({ autonomy, confidenceFloor });
229
+ // Ensure exactly one separating newline between existing content and the block.
230
+ const separator = content.endsWith('\n') ? '' : '\n';
231
+ const next = `${content}${separator}${block}`;
232
+
233
+ try {
234
+ writeFileSync(claudeMdPath, next, 'utf8');
235
+ } catch (err) {
236
+ return { written: false, error: `write failed: ${err && err.message ? err.message : String(err)}` };
237
+ }
238
+
239
+ return { written: true, path: claudeMdPath };
240
+ }