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,571 @@
1
+ /**
2
+ * owner-yaml.mjs — owner.yaml schema, validator, parser, writer (Issue #161, D1).
3
+ *
4
+ * Implements the public Owner Persona Layer API: schema validation, disk I/O,
5
+ * and sensible defaults. Intentionally separate from `owner-config.mjs` (which
6
+ * ships the richer D2-era schema with schema-version, metadata, and extended
7
+ * fields). This module targets the simpler D1 surface defined in the #161 epic.
8
+ *
9
+ * ── Schema (schema-version: 1) ───────────────────────────────────────────────
10
+ *
11
+ * owner:
12
+ * name: string (required, non-empty)
13
+ * language: 'de' | 'en' (required)
14
+ * tone:
15
+ * style: 'direct' | 'neutral' | 'friendly' (required)
16
+ * tonality: string (optional, free text)
17
+ * efficiency:
18
+ * output-level: 'lite' | 'full' | 'ultra' (required)
19
+ * preamble: 'minimal' | 'verbose' (required)
20
+ * hardware-sharing:
21
+ * enabled: boolean (required)
22
+ * hash-salt: string (required when enabled=true)
23
+ * paths: (optional; host-local path overrides — #653)
24
+ * vault-dir: string ('' = no override; mirrors Session Config vault-integration.vault-dir)
25
+ * baseline-path: string ('' = no override; maps to Session Config plan-baseline-path / projects-baseline)
26
+ * namespace-map-path: string ('' = no override; #725 D5 — points at a host-local JSON
27
+ * { "real-slug": "pseudonym-slug" } map that vault-mirror uses to
28
+ * give owner-leaky repos stable pseudonyms instead of collapsing
29
+ * them all to 'redacted-repo'. Never committed; env SO_NAMESPACE_MAP overrides.)
30
+ * confidential-names-file: string ('' = no override; #728a — points at a host-local FLAT JSON
31
+ * array-of-strings ["customer-name", "private-repo", …] the
32
+ * owner-leakage scanner's CP11 rule matches against tracked files.
33
+ * The names live in the referenced file ONLY — NEVER inline in
34
+ * owner.yaml. Never committed; env SO_CONFIDENTIAL_NAMES_FILE overrides.)
35
+ * dispatcher: (optional; host-local cross-repo dispatcher autonomy override — #679)
36
+ * autonomy: string ('' = no override; resolver enum off | advisory | autonomous-gated;
37
+ * precedence env SO_DISPATCHER_AUTONOMY > this > committed > off)
38
+ *
39
+ * ── Exports ───────────────────────────────────────────────────────────────────
40
+ *
41
+ * OWNER_YAML_PATH — default file path on disk
42
+ * validateOwnerSections(obj) — pure validation, no I/O; bucketed per section (#820)
43
+ * validateOwnerConfig(obj) — pure validation, no I/O; thin wrapper over validateOwnerSections
44
+ * loadOwnerConfig({path?}) — reads file; per-section tolerance for OPTIONAL
45
+ * sections (paths/dispatcher/vaults/baselines) — #820
46
+ * writeOwnerConfig(config, {path?}) — validates, writes YAML, creates dir
47
+ * getDefaults() — returns sensible default config object
48
+ */
49
+
50
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
51
+ import { join, dirname } from 'node:path';
52
+ import { homedir } from 'node:os';
53
+ import yaml from 'js-yaml';
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Constants
57
+ // ---------------------------------------------------------------------------
58
+
59
+ /** Default path for the owner persona config file. */
60
+ export const OWNER_YAML_PATH = join(homedir(), '.config', 'session-orchestrator', 'owner.yaml');
61
+
62
+ const VALID_LANGUAGES = /** @type {const} */ (['de', 'en']);
63
+ const VALID_TONE_STYLES = /** @type {const} */ (['direct', 'neutral', 'friendly']);
64
+ const VALID_OUTPUT_LEVELS = /** @type {const} */ (['lite', 'full', 'ultra']);
65
+ const VALID_PREAMBLE_LEVELS = /** @type {const} */ (['minimal', 'verbose']);
66
+
67
+ /**
68
+ * REQUIRED sections (#820) — an invalid entry here keeps the legacy
69
+ * whole-file-discard behaviour of `loadOwnerConfig` unchanged.
70
+ */
71
+ const REQUIRED_SECTIONS = /** @type {const} */ (['owner', 'tone', 'efficiency', 'hardware-sharing']);
72
+
73
+ /**
74
+ * OPTIONAL object sections (#820) — a malformed entry is replaced by its
75
+ * `getDefaults()` value and reported via `droppedSections` + a stderr WARN,
76
+ * but does NOT discard the rest of the file.
77
+ */
78
+ const OPTIONAL_OBJECT_SECTIONS = /** @type {const} */ (['paths', 'dispatcher']);
79
+
80
+ /**
81
+ * OPTIONAL list sections (#820) — malformed entries are passed through
82
+ * UNTOUCHED (their consumers run a lenient parse-at-point-of-use pass —
83
+ * `parseNamedVaults`/`parseBaselines` — that already drops bad entries with
84
+ * its own WARN). Surfaced here only via `sectionWarnings`, never dropped.
85
+ */
86
+ const OPTIONAL_LIST_SECTIONS = /** @type {const} */ (['vaults', 'baselines']);
87
+
88
+ /** Canonical validation-order — MUST match the pre-#820 inline validation order. */
89
+ const SECTION_ORDER = /** @type {const} */ ([
90
+ ...REQUIRED_SECTIONS,
91
+ ...OPTIONAL_OBJECT_SECTIONS,
92
+ ...OPTIONAL_LIST_SECTIONS,
93
+ ]);
94
+
95
+ // ---------------------------------------------------------------------------
96
+ // Helpers
97
+ // ---------------------------------------------------------------------------
98
+
99
+ function isPlainObject(v) {
100
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
101
+ }
102
+
103
+ // ---------------------------------------------------------------------------
104
+ // Defaults
105
+ // ---------------------------------------------------------------------------
106
+
107
+ /**
108
+ * Returns the sensible default owner config. `owner.name` is left as an empty
109
+ * string — callers (e.g. D2 bootstrap) must fill it in from user input.
110
+ *
111
+ * @returns {object}
112
+ */
113
+ export function getDefaults() {
114
+ return {
115
+ owner: {
116
+ name: '',
117
+ language: 'en',
118
+ },
119
+ tone: {
120
+ style: 'neutral',
121
+ tonality: '',
122
+ },
123
+ efficiency: {
124
+ 'output-level': 'full',
125
+ preamble: 'minimal',
126
+ },
127
+ 'hardware-sharing': {
128
+ enabled: false,
129
+ 'hash-salt': '',
130
+ },
131
+ paths: {
132
+ 'vault-dir': '',
133
+ 'baseline-path': '',
134
+ 'namespace-map-path': '',
135
+ 'confidential-names-file': '',
136
+ },
137
+ dispatcher: {
138
+ autonomy: '',
139
+ },
140
+ };
141
+ }
142
+
143
+ // ---------------------------------------------------------------------------
144
+ // Validation
145
+ // ---------------------------------------------------------------------------
146
+
147
+ /**
148
+ * Validate a raw owner config object, bucketed per top-level section (#820).
149
+ * Pure function — never throws, never reads or writes any file. Reuses the
150
+ * EXACT validation rules `validateOwnerConfig` has always applied; only the
151
+ * bucketing is new, so error message text and (within a section) ordering
152
+ * are unchanged.
153
+ *
154
+ * @param {unknown} obj
155
+ * @returns {{ sections: Record<string, { valid: boolean, errors: string[] }>, errors: string[] }}
156
+ */
157
+ export function validateOwnerSections(obj) {
158
+ if (!isPlainObject(obj)) {
159
+ return { sections: {}, errors: ['config must be a plain object'] };
160
+ }
161
+
162
+ const sections = {};
163
+
164
+ // ── owner ──────────────────────────────────────────────────────────────────
165
+ {
166
+ const errors = [];
167
+ const owner = obj.owner;
168
+ if (!isPlainObject(owner)) {
169
+ errors.push('owner must be an object');
170
+ } else {
171
+ if (typeof owner.name !== 'string' || owner.name.trim().length === 0) {
172
+ errors.push('owner.name is required and must be a non-empty string');
173
+ }
174
+ if (!VALID_LANGUAGES.includes(owner.language)) {
175
+ errors.push(
176
+ `owner.language must be one of ${VALID_LANGUAGES.join(', ')}, got: ${JSON.stringify(owner.language)}`,
177
+ );
178
+ }
179
+ }
180
+ sections.owner = { valid: errors.length === 0, errors };
181
+ }
182
+
183
+ // ── tone ───────────────────────────────────────────────────────────────────
184
+ {
185
+ const errors = [];
186
+ const tone = obj.tone;
187
+ if (!isPlainObject(tone)) {
188
+ errors.push('tone must be an object');
189
+ } else {
190
+ if (!VALID_TONE_STYLES.includes(tone.style)) {
191
+ errors.push(
192
+ `tone.style must be one of ${VALID_TONE_STYLES.join(', ')}, got: ${JSON.stringify(tone.style)}`,
193
+ );
194
+ }
195
+ // tonality is optional; if present must be a string
196
+ if (tone.tonality !== undefined && tone.tonality !== null && typeof tone.tonality !== 'string') {
197
+ errors.push('tone.tonality must be a string or absent');
198
+ }
199
+ }
200
+ sections.tone = { valid: errors.length === 0, errors };
201
+ }
202
+
203
+ // ── efficiency ─────────────────────────────────────────────────────────────
204
+ {
205
+ const errors = [];
206
+ const efficiency = obj.efficiency;
207
+ if (!isPlainObject(efficiency)) {
208
+ errors.push('efficiency must be an object');
209
+ } else {
210
+ if (!VALID_OUTPUT_LEVELS.includes(efficiency['output-level'])) {
211
+ errors.push(
212
+ `efficiency.output-level must be one of ${VALID_OUTPUT_LEVELS.join(', ')}, got: ${JSON.stringify(efficiency['output-level'])}`,
213
+ );
214
+ }
215
+ if (!VALID_PREAMBLE_LEVELS.includes(efficiency.preamble)) {
216
+ errors.push(
217
+ `efficiency.preamble must be one of ${VALID_PREAMBLE_LEVELS.join(', ')}, got: ${JSON.stringify(efficiency.preamble)}`,
218
+ );
219
+ }
220
+ }
221
+ sections.efficiency = { valid: errors.length === 0, errors };
222
+ }
223
+
224
+ // ── hardware-sharing ───────────────────────────────────────────────────────
225
+ {
226
+ const errors = [];
227
+ const hw = obj['hardware-sharing'];
228
+ if (!isPlainObject(hw)) {
229
+ errors.push('hardware-sharing must be an object');
230
+ } else {
231
+ if (typeof hw.enabled !== 'boolean') {
232
+ errors.push(`hardware-sharing.enabled must be a boolean, got: ${typeof hw.enabled}`);
233
+ }
234
+ // hash-salt is required when enabled=true
235
+ if (hw.enabled === true) {
236
+ if (typeof hw['hash-salt'] !== 'string' || hw['hash-salt'].length === 0) {
237
+ errors.push('hardware-sharing.hash-salt is required (non-empty string) when hardware-sharing.enabled is true');
238
+ }
239
+ }
240
+ // if present and non-empty, must be a string
241
+ if (
242
+ hw['hash-salt'] !== undefined &&
243
+ hw['hash-salt'] !== null &&
244
+ hw['hash-salt'] !== '' &&
245
+ typeof hw['hash-salt'] !== 'string'
246
+ ) {
247
+ errors.push('hardware-sharing.hash-salt must be a string');
248
+ }
249
+ }
250
+ sections['hardware-sharing'] = { valid: errors.length === 0, errors };
251
+ }
252
+
253
+ // ── paths (optional; host-local path overrides — #653) ───────────────────────
254
+ {
255
+ const errors = [];
256
+ const paths = obj.paths;
257
+ if (paths !== undefined && paths !== null) {
258
+ if (!isPlainObject(paths)) {
259
+ errors.push('paths must be an object when present');
260
+ } else {
261
+ for (const key of ['vault-dir', 'baseline-path', 'namespace-map-path', 'confidential-names-file']) {
262
+ const v = paths[key];
263
+ if (v !== undefined && v !== null && typeof v !== 'string') {
264
+ errors.push(`paths.${key} must be a string`);
265
+ }
266
+ }
267
+ }
268
+ }
269
+ sections.paths = { valid: errors.length === 0, errors };
270
+ }
271
+
272
+ // ── dispatcher (optional; host-local dispatcher autonomy override — #679) ─────
273
+ // Loose validation only (mirrors `paths`): the resolver enum-validates the
274
+ // value (resolveDispatcherAutonomy in config/dispatcher-autonomy.mjs), so an
275
+ // invalid string here falls through to the next precedence tier rather than
276
+ // failing the whole owner.yaml load.
277
+ {
278
+ const errors = [];
279
+ const dispatcher = obj.dispatcher;
280
+ if (dispatcher !== undefined && dispatcher !== null) {
281
+ if (!isPlainObject(dispatcher)) {
282
+ errors.push('dispatcher must be an object when present');
283
+ } else if (
284
+ dispatcher.autonomy !== undefined &&
285
+ dispatcher.autonomy !== null &&
286
+ typeof dispatcher.autonomy !== 'string'
287
+ ) {
288
+ errors.push('dispatcher.autonomy must be a string');
289
+ }
290
+ }
291
+ sections.dispatcher = { valid: errors.length === 0, errors };
292
+ }
293
+
294
+ // ── vaults (optional; N named vaults for walk-up resolution — #700) ──────────
295
+ // Drop-and-WARN on malformed entries is handled by parseNamedVaults() in
296
+ // named-vault-resolver.mjs. Here we only validate the container shape to
297
+ // prevent clearly invalid config from passing silently.
298
+ // Absent or null → backward-compat no-op (no validation errors).
299
+ {
300
+ const errors = [];
301
+ const vaults = obj.vaults;
302
+ if (vaults !== undefined && vaults !== null) {
303
+ if (!Array.isArray(vaults)) {
304
+ errors.push('vaults must be an array when present');
305
+ } else {
306
+ for (let i = 0; i < vaults.length; i++) {
307
+ const entry = vaults[i];
308
+ if (entry === null || entry === undefined) {
309
+ errors.push(`vaults[${i}] must not be null`);
310
+ continue;
311
+ }
312
+ if (!isPlainObject(entry)) {
313
+ errors.push(`vaults[${i}] must be an object`);
314
+ continue;
315
+ }
316
+ // Required string fields: name, suffix, root
317
+ for (const field of ['name', 'suffix', 'root']) {
318
+ if (typeof entry[field] !== 'string' || entry[field].trim() === '') {
319
+ errors.push(`vaults[${i}].${field} must be a non-empty string`);
320
+ }
321
+ }
322
+ // Optional match sub-object
323
+ if (entry.match !== undefined && entry.match !== null) {
324
+ if (!isPlainObject(entry.match)) {
325
+ errors.push(`vaults[${i}].match must be an object when present`);
326
+ } else if (
327
+ entry.match['org-prefix'] !== undefined &&
328
+ typeof entry.match['org-prefix'] !== 'string'
329
+ ) {
330
+ errors.push(`vaults[${i}].match.org-prefix must be a string`);
331
+ }
332
+ }
333
+ }
334
+ }
335
+ }
336
+ sections.vaults = { valid: errors.length === 0, errors };
337
+ }
338
+
339
+ // ── baselines (optional; N named plan-baselines for per-context resolution — #819) ──
340
+ // Cousin of vaults: above. Drop-and-WARN on malformed entries is handled by
341
+ // parseBaselines() in named-baseline-resolver.mjs; here we validate the container
342
+ // + entry shape to prevent clearly invalid config from passing silently.
343
+ // Divergences from vaults: the match key is `path-prefix` (a local FILESYSTEM
344
+ // directory tree, not a git-remote org slug), `path` replaces root+suffix, and
345
+ // `match` is REQUIRED (a baseline with no path-prefix can never be selected).
346
+ // Absent or null → backward-compat no-op (no validation errors).
347
+ {
348
+ const errors = [];
349
+ const baselines = obj.baselines;
350
+ if (baselines !== undefined && baselines !== null) {
351
+ if (!Array.isArray(baselines)) {
352
+ errors.push('baselines must be an array when present');
353
+ } else {
354
+ for (let i = 0; i < baselines.length; i++) {
355
+ const entry = baselines[i];
356
+ if (entry === null || entry === undefined) {
357
+ errors.push(`baselines[${i}] must not be null`);
358
+ continue;
359
+ }
360
+ if (!isPlainObject(entry)) {
361
+ errors.push(`baselines[${i}] must be an object`);
362
+ continue;
363
+ }
364
+ // Required string fields: name, path
365
+ for (const field of ['name', 'path']) {
366
+ if (typeof entry[field] !== 'string' || entry[field].trim() === '') {
367
+ errors.push(`baselines[${i}].${field} must be a non-empty string`);
368
+ }
369
+ }
370
+ // Required match sub-object with a non-empty path-prefix string.
371
+ if (!isPlainObject(entry.match)) {
372
+ errors.push(`baselines[${i}].match must be an object`);
373
+ } else if (
374
+ typeof entry.match['path-prefix'] !== 'string' ||
375
+ entry.match['path-prefix'].trim() === ''
376
+ ) {
377
+ errors.push(`baselines[${i}].match.path-prefix must be a non-empty string`);
378
+ }
379
+ }
380
+ }
381
+ }
382
+ sections.baselines = { valid: errors.length === 0, errors };
383
+ }
384
+
385
+ const errors = SECTION_ORDER.flatMap((name) => sections[name].errors);
386
+ return { sections, errors };
387
+ }
388
+
389
+ /**
390
+ * Validate a raw owner config object. Pure function — never throws, never reads
391
+ * or writes any file. Thin wrapper over `validateOwnerSections` (#820) —
392
+ * preserves the original `{ valid, errors }` contract unchanged.
393
+ *
394
+ * @param {unknown} obj
395
+ * @returns {{ valid: boolean, errors: string[] }}
396
+ */
397
+ export function validateOwnerConfig(obj) {
398
+ const { errors } = validateOwnerSections(obj);
399
+ return { valid: errors.length === 0, errors };
400
+ }
401
+
402
+ // ---------------------------------------------------------------------------
403
+ // Loader
404
+ // ---------------------------------------------------------------------------
405
+
406
+ /**
407
+ * Load owner.yaml from disk. Returns defaults when the file is absent or
408
+ * contains invalid content, populating `errors` in the latter case.
409
+ *
410
+ * Per-section tolerance (#820): an invalid REQUIRED section (owner, tone,
411
+ * efficiency, hardware-sharing) still discards the whole file (legacy
412
+ * behaviour, unchanged). An invalid OPTIONAL object section (paths,
413
+ * dispatcher) is instead replaced by its default value — the rest of the
414
+ * file survives, `source` becomes `'partial'`, and the drop is reported via
415
+ * `droppedSections` + a stderr WARN. OPTIONAL list sections (vaults,
416
+ * baselines) are passed through UNTOUCHED even when strict-invalid — their
417
+ * consumers already run a lenient parse-at-point-of-use pass — and are
418
+ * surfaced only via `sectionWarnings` (never dropped, never counted towards
419
+ * `'partial'`).
420
+ *
421
+ * Defensive — never throws.
422
+ *
423
+ * @param {{ path?: string }} [opts]
424
+ * @returns {{
425
+ * config: object,
426
+ * source: 'file'|'defaults'|'partial',
427
+ * errors: string[],
428
+ * droppedSections?: Array<{ section: string, errors: string[] }>,
429
+ * sectionWarnings?: Array<{ section: string, errors: string[] }>,
430
+ * }}
431
+ */
432
+ export function loadOwnerConfig(opts = {}) {
433
+ const filePath = opts.path ?? OWNER_YAML_PATH;
434
+
435
+ if (!existsSync(filePath)) {
436
+ return { config: getDefaults(), source: 'defaults', errors: [] };
437
+ }
438
+
439
+ let raw;
440
+ try {
441
+ raw = readFileSync(filePath, 'utf8');
442
+ } catch (err) {
443
+ return {
444
+ config: getDefaults(),
445
+ source: 'defaults',
446
+ errors: [`failed to read owner.yaml: ${err.message}`],
447
+ };
448
+ }
449
+
450
+ let parsed;
451
+ try {
452
+ parsed = yaml.load(raw);
453
+ } catch (err) {
454
+ return {
455
+ config: getDefaults(),
456
+ source: 'defaults',
457
+ errors: [`YAML parse error: ${err.message}`],
458
+ };
459
+ }
460
+
461
+ if (!isPlainObject(parsed)) {
462
+ return {
463
+ config: getDefaults(),
464
+ source: 'defaults',
465
+ errors: ['owner.yaml must contain a YAML mapping at the top level'],
466
+ };
467
+ }
468
+
469
+ const { sections, errors: allErrors } = validateOwnerSections(parsed);
470
+
471
+ // Any REQUIRED section invalid → legacy whole-file-discard, unchanged (#820).
472
+ const requiredInvalid = REQUIRED_SECTIONS.some((name) => !sections[name]?.valid);
473
+ if (requiredInvalid) {
474
+ return {
475
+ config: getDefaults(),
476
+ source: 'defaults',
477
+ errors: allErrors,
478
+ };
479
+ }
480
+
481
+ // All REQUIRED sections valid — tolerate malformed OPTIONAL sections instead
482
+ // of discarding the whole file (#820).
483
+ const defaults = getDefaults();
484
+ const config = { ...parsed };
485
+ const droppedSections = [];
486
+ const sectionWarnings = [];
487
+
488
+ for (const name of OPTIONAL_OBJECT_SECTIONS) {
489
+ const sec = sections[name];
490
+ if (sec && !sec.valid) {
491
+ config[name] = defaults[name];
492
+ droppedSections.push({ section: name, errors: sec.errors });
493
+ const firstError = sec.errors[0] ?? 'invalid section';
494
+ console.warn(
495
+ `WARN owner-yaml: dropping owner.yaml section "${name}" (${firstError}); using defaults`,
496
+ );
497
+ }
498
+ }
499
+
500
+ for (const name of OPTIONAL_LIST_SECTIONS) {
501
+ const sec = sections[name];
502
+ if (sec && !sec.valid) {
503
+ // Raw pass-through — deliberate defense-in-depth; parseNamedVaults()/
504
+ // parseBaselines() run their own lenient drop-and-WARN at point-of-use.
505
+ sectionWarnings.push({ section: name, errors: sec.errors });
506
+ const firstError = sec.errors[0] ?? 'invalid entries';
507
+ console.warn(
508
+ `WARN owner-yaml: owner.yaml section "${name}" has invalid entries (${firstError}); ` +
509
+ 'lenient consumers will drop bad entries at point-of-use',
510
+ );
511
+ }
512
+ }
513
+
514
+ const result = {
515
+ config,
516
+ source: droppedSections.length > 0 ? 'partial' : 'file',
517
+ errors: allErrors,
518
+ };
519
+ if (droppedSections.length > 0) result.droppedSections = droppedSections;
520
+ if (sectionWarnings.length > 0) result.sectionWarnings = sectionWarnings;
521
+ return result;
522
+ }
523
+
524
+ // ---------------------------------------------------------------------------
525
+ // Writer
526
+ // ---------------------------------------------------------------------------
527
+
528
+ /**
529
+ * Validate `config` and write it as YAML to disk. Creates parent directories
530
+ * if they do not exist. Validates before writing — returns errors without
531
+ * touching the filesystem when validation fails.
532
+ *
533
+ * Synchronous. Defensive — never throws.
534
+ *
535
+ * @param {object} config
536
+ * @param {{ path?: string }} [opts]
537
+ * @returns {{ written: boolean, errors: string[] }}
538
+ */
539
+ export function writeOwnerConfig(config, opts = {}) {
540
+ const filePath = opts.path ?? OWNER_YAML_PATH;
541
+
542
+ const validation = validateOwnerConfig(config);
543
+ if (!validation.valid) {
544
+ return { written: false, errors: validation.errors };
545
+ }
546
+
547
+ const dir = dirname(filePath);
548
+ try {
549
+ mkdirSync(dir, { recursive: true });
550
+ } catch (err) {
551
+ return {
552
+ written: false,
553
+ errors: [`failed to create directory ${dir}: ${err.message}`],
554
+ };
555
+ }
556
+
557
+ let yamlStr;
558
+ try {
559
+ yamlStr = yaml.dump(config, { lineWidth: 120, noRefs: true });
560
+ } catch (err) {
561
+ return { written: false, errors: [`failed to serialise config to YAML: ${err.message}`] };
562
+ }
563
+
564
+ try {
565
+ writeFileSync(filePath, yamlStr, 'utf8');
566
+ } catch (err) {
567
+ return { written: false, errors: [`failed to write owner.yaml: ${err.message}`] };
568
+ }
569
+
570
+ return { written: true, errors: [] };
571
+ }