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,29 @@
1
+ /**
2
+ * Wave-context helpers — single source of truth for the
3
+ * agent-context env-var contract documented in
4
+ * CLAUDE.md (or AGENTS.md on Codex CLI) "Critical Gotchas"
5
+ * + .claude/rules/parallel-sessions.md.
6
+ *
7
+ * The `SO_WAVE_AGENT` env-var is set to '1' by the wave-executor
8
+ * harness when dispatching subagents. Agents check this guard before
9
+ * calling memory.propose() — coordinator-thread invocations must NOT
10
+ * succeed (use /evolve instead). See #548 A4.
11
+ *
12
+ * Strict equality semantics (=== '1') are intentional: leading
13
+ * whitespace, trailing newline, '01', 'true', '0', undefined, and
14
+ * empty string all return false. This matches the documented contract
15
+ * in scripts/memory-propose.mjs Step 2b and the regression tests in
16
+ * tests/scripts/memory-propose.test.mjs Section E.
17
+ */
18
+
19
+ export const WAVE_AGENT_ENV_VAR = 'SO_WAVE_AGENT';
20
+ export const WAVE_AGENT_ENV_VALUE = '1';
21
+
22
+ /**
23
+ * @returns {boolean} true iff this process is running as a dispatched
24
+ * wave-agent (i.e., SO_WAVE_AGENT === '1', strict equality — leading
25
+ * whitespace, trailing newline, '01', etc. all return false).
26
+ */
27
+ export function isWaveAgentContext() {
28
+ return process.env[WAVE_AGENT_ENV_VAR] === WAVE_AGENT_ENV_VALUE;
29
+ }
@@ -0,0 +1,248 @@
1
+ /**
2
+ * pool.mjs — Bounded-concurrency worker-pool cursor for wave-executor dispatch.
3
+ *
4
+ * Provides a true cursor-based pull loop for agent dispatch, replacing the
5
+ * existing Promise.all() fan-out model when `worker-pool.enabled: true` in
6
+ * Session Config. Agents pull tasks from a shared cursor so at most
7
+ * `maxParallel` workers are active at any moment — forward-compatible with
8
+ * resource-gate decisions (#193).
9
+ *
10
+ * Issue: #415
11
+ *
12
+ * Exports:
13
+ * runWavePool(opts) → Promise<{results: Array, errors: Array}>
14
+ *
15
+ * AbortSignal behaviour:
16
+ * When the caller's abortSignal fires, each in-flight worker is sent a
17
+ * per-worker AbortController.abort(). No new tasks are pulled. The function
18
+ * drains for up to `drainTimeoutMs` before returning partial results.
19
+ *
20
+ * Error semantics:
21
+ * A single failing task never cascades — remaining workers continue pulling
22
+ * until the cursor is exhausted. Failed tasks accumulate in `errors`.
23
+ */
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Types (JSDoc only — no TypeScript at runtime)
27
+ // ---------------------------------------------------------------------------
28
+
29
+ /**
30
+ * @typedef {{ taskId: string, dispatch: () => Promise<*> }} PoolTask
31
+ *
32
+ * @typedef {{
33
+ * tasks: PoolTask[],
34
+ * maxParallel: number,
35
+ * abortSignal?: AbortSignal,
36
+ * drainTimeoutMs?: number,
37
+ * onTaskStart?: (taskId: string) => void,
38
+ * onTaskComplete?: (taskId: string, result: *, error: Error|null) => void,
39
+ * }} PoolOptions
40
+ *
41
+ * @typedef {{
42
+ * results: Array<{ taskId: string, result: * }>,
43
+ * errors: Array<{ taskId: string, error: Error }>,
44
+ * }} PoolResult
45
+ */
46
+
47
+ /** Default drain timeout (ms) when an abort signal fires mid-run. */
48
+ export const DEFAULT_DRAIN_TIMEOUT_MS = 10_000;
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // runWavePool
52
+ // ---------------------------------------------------------------------------
53
+
54
+ /**
55
+ * Execute `tasks` with at most `maxParallel` concurrent workers.
56
+ *
57
+ * Workers pull tasks from a shared cursor — this is a genuine cursor model,
58
+ * not Promise.all(tasks.map(...)). Each worker loop:
59
+ * 1. Picks up the next unstarted task (atomic cursor advance).
60
+ * 2. Awaits task.dispatch().
61
+ * 3. Records result/error.
62
+ * 4. Repeats until cursor is exhausted.
63
+ *
64
+ * When `abortSignal.aborted` is true (or fires during execution), the pool
65
+ * stops pulling new tasks and each in-flight worker receives its own
66
+ * AbortController abort. The pool then waits up to `drainTimeoutMs` for
67
+ * workers to settle before returning partial results.
68
+ *
69
+ * @param {PoolOptions} opts
70
+ * @returns {Promise<PoolResult>}
71
+ */
72
+ export async function runWavePool({
73
+ tasks,
74
+ maxParallel,
75
+ abortSignal,
76
+ drainTimeoutMs = DEFAULT_DRAIN_TIMEOUT_MS,
77
+ onTaskStart,
78
+ onTaskComplete,
79
+ }) {
80
+ // ── Input validation ──────────────────────────────────────────────────────
81
+
82
+ if (!Array.isArray(tasks)) {
83
+ throw new TypeError('runWavePool: tasks must be an array');
84
+ }
85
+ if (typeof maxParallel !== 'number' || !Number.isInteger(maxParallel) || maxParallel < 1) {
86
+ throw new TypeError('runWavePool: maxParallel must be a positive integer');
87
+ }
88
+ if (typeof drainTimeoutMs !== 'number' || drainTimeoutMs < 0) {
89
+ throw new TypeError('runWavePool: drainTimeoutMs must be a non-negative number');
90
+ }
91
+
92
+ // ── Duplicate taskId guard ─────────────────────────────────────────────────
93
+ // Two tasks with the same taskId would produce duplicate records in `results`,
94
+ // silently dropping one when a caller builds a Map<taskId, result>.
95
+ const seenIds = new Set();
96
+ for (const t of tasks) {
97
+ if (!t || typeof t.taskId !== 'string') continue; // caught by runtime dispatch
98
+ if (seenIds.has(t.taskId)) {
99
+ throw new TypeError(`runWavePool: duplicate taskId "${t.taskId}"`);
100
+ }
101
+ seenIds.add(t.taskId);
102
+ }
103
+
104
+ // ── Fast path: empty tasks ─────────────────────────────────────────────────
105
+
106
+ if (tasks.length === 0) {
107
+ return { results: [], errors: [] };
108
+ }
109
+
110
+ // ── Shared state (cursor + result accumulators) ───────────────────────────
111
+
112
+ let nextIndex = 0;
113
+ /** @type {Map<number, AbortController>} taskIndex → per-worker AbortController */
114
+ const inFlight = new Map();
115
+ /** @type {Array<{ taskId: string, result: * }>} */
116
+ const results = [];
117
+ /** @type {Array<{ taskId: string, error: Error }>} */
118
+ const errors = [];
119
+
120
+ // Cap effective concurrency at tasks.length to avoid over-spawn.
121
+ const effective = Math.min(maxParallel, tasks.length);
122
+
123
+ // ── Abort handling ─────────────────────────────────────────────────────────
124
+
125
+ /**
126
+ * Returns true when the pool should stop pulling new tasks.
127
+ * Checks the caller-supplied AbortSignal (if any).
128
+ */
129
+ function isAborted() {
130
+ return abortSignal !== null && abortSignal !== undefined && abortSignal.aborted;
131
+ }
132
+
133
+ /**
134
+ * Abort all currently in-flight workers by forwarding to their per-worker
135
+ * AbortControllers. Called when the caller's abortSignal fires.
136
+ *
137
+ * Only workers that are already executing `task.dispatch()` at the moment
138
+ * this function is called will receive the abort signal. Tasks that are
139
+ * still queued (not yet pulled by any worker) are simply never started —
140
+ * the `isAborted()` guard in the worker loop stops the cursor on the next
141
+ * pull attempt.
142
+ */
143
+ function abortInFlight() {
144
+ for (const controller of inFlight.values()) {
145
+ controller.abort();
146
+ }
147
+ }
148
+
149
+ // Register a one-shot listener on the caller's AbortSignal so we react
150
+ // immediately if it fires while workers are running.
151
+ let abortListener = null;
152
+ if (abortSignal !== null && abortSignal !== undefined) {
153
+ abortListener = () => abortInFlight();
154
+ abortSignal.addEventListener('abort', abortListener, { once: true });
155
+ }
156
+
157
+ // ── Worker function ───────────────────────────────────────────────────────
158
+
159
+ /**
160
+ * A single worker loop. Pulls tasks from the shared cursor until the
161
+ * cursor is exhausted or the pool is aborted.
162
+ */
163
+ async function worker() {
164
+ while (true) {
165
+ // Stop pulling when aborted.
166
+ if (isAborted()) break;
167
+
168
+ // Atomically claim the next task index.
169
+ const taskIndex = nextIndex;
170
+ if (taskIndex >= tasks.length) break; // cursor exhausted
171
+ nextIndex += 1;
172
+
173
+ const task = tasks[taskIndex];
174
+ const workerController = new AbortController();
175
+ inFlight.set(taskIndex, workerController);
176
+
177
+ // Notify caller that this task is starting.
178
+ if (typeof onTaskStart === 'function') {
179
+ onTaskStart(task.taskId);
180
+ }
181
+
182
+ try {
183
+ // Pass the worker's AbortSignal to the dispatch function so callers
184
+ // can propagate cancellation into their child processes.
185
+ const result = await task.dispatch(workerController.signal);
186
+ results.push({ taskId: task.taskId, result });
187
+ if (typeof onTaskComplete === 'function') {
188
+ onTaskComplete(task.taskId, result, null);
189
+ }
190
+ } catch (err) {
191
+ const error = err instanceof Error ? err : new Error(String(err));
192
+ errors.push({ taskId: task.taskId, error });
193
+ if (typeof onTaskComplete === 'function') {
194
+ onTaskComplete(task.taskId, null, error);
195
+ }
196
+ // Single failure: continue the cursor, do NOT cascade abort.
197
+ } finally {
198
+ inFlight.delete(taskIndex);
199
+ }
200
+ }
201
+ }
202
+
203
+ // ── Spawn workers ──────────────────────────────────────────────────────────
204
+
205
+ // Pre-abort: if the signal already fired before workers started, abort now.
206
+ if (isAborted()) {
207
+ abortInFlight();
208
+ }
209
+
210
+ // Worker errors are individual task failures already captured above; we
211
+ // use allSettled so the pool itself never rejects.
212
+ const workerSettle = Promise.allSettled(
213
+ Array.from({ length: effective }, () => worker()),
214
+ );
215
+
216
+ // ── Drain with abort-timeout ───────────────────────────────────────────────
217
+
218
+ // Normal path: await all workers.
219
+ // Abort path: the abortListener forwards abort to each worker's controller,
220
+ // then we race settle vs. drainTimeoutMs. Workers that honour their signal
221
+ // exit quickly; those that ignore it are abandoned after the timeout (the
222
+ // Promise is still in-flight but we return whatever results we have).
223
+
224
+ let drainTimeoutHandle;
225
+ const drainTimeoutPromise = new Promise((resolve) => {
226
+ drainTimeoutHandle = setTimeout(resolve, drainTimeoutMs);
227
+ });
228
+
229
+ if (abortSignal !== null && abortSignal !== undefined) {
230
+ // Race: workers settle OR drain timeout fires after abort.
231
+ // The abortListener (registered earlier) already handles aborting workers
232
+ // when the signal fires. We just need to bound the wait.
233
+ await Promise.race([workerSettle, drainTimeoutPromise]);
234
+ } else {
235
+ // No abort signal — just wait for all workers to finish.
236
+ await workerSettle;
237
+ }
238
+
239
+ clearTimeout(drainTimeoutHandle);
240
+
241
+ // ── Cleanup ───────────────────────────────────────────────────────────────
242
+
243
+ if (abortListener !== null && abortSignal !== null && abortSignal !== undefined) {
244
+ abortSignal.removeEventListener('abort', abortListener);
245
+ }
246
+
247
+ return { results, errors };
248
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * wave-resource-gate.mjs — Pre-dispatch resource gate for parallel agent waves.
3
+ *
4
+ * Evaluates RAM / CPU / concurrent-session pressure before dispatching agents
5
+ * and returns a decision: "proceed", "reduce", or "coordinator-direct".
6
+ *
7
+ * Part of v3.1.0 Epic #157, Sub-Epic resource-gate. Issue #193.
8
+ */
9
+
10
+ import { probe } from './resource-probe.mjs';
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // Public API
14
+ // ---------------------------------------------------------------------------
15
+
16
+ /**
17
+ * Extract resource measurements either from a test override or by calling
18
+ * the live resource probe. Returns either a measurements object or a sentinel
19
+ * `{ probeFailed: true }` indicating the caller should short-circuit with a
20
+ * "proceed" decision.
21
+ *
22
+ * @param {object} opts - Same opts shape as evaluateWaveResourceGate
23
+ * @returns {Promise<{ramFreeGb: number, ramAvailableGb: number|null, cpuLoadPct: number, concurrentSessions: number} | {probeFailed: true}>}
24
+ */
25
+ async function extractMeasurements(opts) {
26
+ const { probeOverride } = opts;
27
+
28
+ if (probeOverride !== undefined && probeOverride !== null) {
29
+ return {
30
+ ramFreeGb: probeOverride.ramFreeGb,
31
+ // Tests may supply ramAvailableGb to exercise the macOS path; absent → null.
32
+ ramAvailableGb: probeOverride.ramAvailableGb ?? null,
33
+ cpuLoadPct: probeOverride.cpuLoadPct,
34
+ concurrentSessions: probeOverride.concurrentSessions,
35
+ };
36
+ }
37
+
38
+ let snapshot;
39
+ try {
40
+ snapshot = await probe({ skipProcessCounts: false });
41
+ } catch {
42
+ return { probeFailed: true };
43
+ }
44
+ return {
45
+ ramFreeGb: snapshot.ram_free_gb,
46
+ // macOS: free + reclaimable (vm_stat). null on Linux/Windows where
47
+ // os.freemem() is already accurate. (#667)
48
+ ramAvailableGb: snapshot.ram_available_gb ?? null,
49
+ cpuLoadPct: snapshot.cpu_load_pct,
50
+ // concurrent sessions: number of claude processes found by the probe.
51
+ concurrentSessions: snapshot.claude_processes_count ?? 0,
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Apply the gate decision rule sequence (rules 3-8) given measurements and
57
+ * config. Returns the full gate result.
58
+ *
59
+ * @param {{ramFreeGb: number, cpuLoadPct: number, concurrentSessions: number}} measurements
60
+ * @param {object} opts - Same opts shape as evaluateWaveResourceGate
61
+ * @returns {{decision: string, agents: number, reasons: string[], measurements: object}}
62
+ */
63
+ function applyDecisionRules(measurements, opts) {
64
+ const { config, plannedAgents } = opts;
65
+ const { ramFreeGb, ramAvailableGb, cpuLoadPct, concurrentSessions } = measurements;
66
+ const T = config['resource-thresholds'];
67
+
68
+ // macOS fix (#667): os.freemem() reports only `Pages free`, which reads
69
+ // sub-1 GB even on a 128 GB host with 80+ GB reclaimable cache — a false
70
+ // RAM-critical that forced spurious coordinator-direct fallbacks. When the
71
+ // probe supplied a numeric `ramAvailableGb` (free + reclaimable, via vm_stat),
72
+ // judge RAM thresholds on AVAILABLE; otherwise fall back to FREE (Linux/Win,
73
+ // where os.freemem() is already accurate).
74
+ const hasAvailable = ramAvailableGb !== null && ramAvailableGb !== undefined;
75
+ const effectiveRamGb = hasAvailable ? ramAvailableGb : ramFreeGb;
76
+ const ramLabel = hasAvailable ? 'RAM available' : 'RAM free';
77
+
78
+ // Rule 3: resource-thresholds missing → degrade to proceed (defensive).
79
+ // Handles legacy pre-#166 configs and test fixtures that omit the key.
80
+ // The gate is considered "ran" — caller receives measurements but no enforcement.
81
+ if (!T || typeof T !== 'object') {
82
+ return {
83
+ decision: 'proceed',
84
+ agents: plannedAgents,
85
+ reasons: ['resource-thresholds missing from config — gate skipped'],
86
+ measurements,
87
+ };
88
+ }
89
+
90
+ // Rule 4: RAM below critical → coordinator-direct.
91
+ if (effectiveRamGb < T['ram-free-critical-gb']) {
92
+ return {
93
+ decision: 'coordinator-direct',
94
+ agents: 0,
95
+ reasons: [
96
+ `${ramLabel} ${effectiveRamGb}GB < critical ${T['ram-free-critical-gb']}GB — escalating to coordinator-direct`,
97
+ ],
98
+ measurements,
99
+ };
100
+ }
101
+
102
+ // Rule 5: RAM below min (but above critical) → reduce.
103
+ if (effectiveRamGb < T['ram-free-min-gb']) {
104
+ return {
105
+ decision: 'reduce',
106
+ agents: Math.max(1, Math.floor(plannedAgents / 2)),
107
+ reasons: [
108
+ `${ramLabel} ${effectiveRamGb}GB < min ${T['ram-free-min-gb']}GB — reducing agent count`,
109
+ ],
110
+ measurements,
111
+ };
112
+ }
113
+
114
+ // Rule 6: CPU overloaded → reduce.
115
+ if (cpuLoadPct > T['cpu-load-max-pct']) {
116
+ return {
117
+ decision: 'reduce',
118
+ agents: Math.max(1, Math.floor(plannedAgents / 2)),
119
+ reasons: [
120
+ `CPU load ${cpuLoadPct}% > max ${T['cpu-load-max-pct']}% — reducing agent count`,
121
+ ],
122
+ measurements,
123
+ };
124
+ }
125
+
126
+ // Rule 7: concurrent sessions above warn → proceed with warning.
127
+ if (concurrentSessions > T['concurrent-sessions-warn']) {
128
+ return {
129
+ decision: 'proceed',
130
+ agents: plannedAgents,
131
+ reasons: [`warn: ${concurrentSessions} concurrent sessions`],
132
+ measurements,
133
+ };
134
+ }
135
+
136
+ // Rule 8: all within bounds.
137
+ return {
138
+ decision: 'proceed',
139
+ agents: plannedAgents,
140
+ reasons: ['all thresholds within bounds'],
141
+ measurements,
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Evaluate whether the wave can be dispatched at the planned agent count.
147
+ * @param {object} opts
148
+ * @param {object} opts.config - Parsed Session Config (from parse-config.sh output)
149
+ * @param {number} opts.plannedAgents - Number of agents the session-plan wants to dispatch
150
+ * @param {string} opts.waveRole - e.g. "Impl-Core", "Quality"
151
+ * @param {object} [opts.probeOverride] - {ramFreeGb, cpuLoadPct, concurrentSessions} for
152
+ * testing; when omitted, calls resource-probe
153
+ * @returns {Promise<{decision: "proceed"|"reduce"|"coordinator-direct", agents: number, reasons: string[], measurements: object}>}
154
+ */
155
+ export async function evaluateWaveResourceGate(opts) {
156
+ const { config, plannedAgents } = opts;
157
+
158
+ // Rule 1: resource-awareness disabled — skip all probing.
159
+ if (config['resource-awareness'] === false) {
160
+ return {
161
+ decision: 'proceed',
162
+ agents: plannedAgents,
163
+ reasons: ['resource-awareness disabled in Session Config'],
164
+ measurements: {},
165
+ };
166
+ }
167
+
168
+ // Rule 2: probe the system (or use override for tests).
169
+ const measured = await extractMeasurements(opts);
170
+ if ('probeFailed' in measured) {
171
+ return {
172
+ decision: 'proceed',
173
+ agents: plannedAgents,
174
+ reasons: ['probe failed (ignored)'],
175
+ measurements: {},
176
+ };
177
+ }
178
+
179
+ // Rules 3-8: apply decision rule sequence.
180
+ return applyDecisionRules(measured, opts);
181
+ }
182
+
183
+ /**
184
+ * Format a gate result into a short multi-line coordinator progress string.
185
+ * @param {{decision: string, agents: number, reasons: string[], measurements: object}} result
186
+ * @returns {string}
187
+ */
188
+ export function formatGateReport(result) {
189
+ const { decision, agents, reasons, measurements } = result;
190
+ const lines = reasons.map((r) => ` - ${r}`);
191
+ const m = measurements;
192
+ // Prefer the macOS available-RAM figure in the banner when present (#667):
193
+ // "RAM free" alone is misleading on Darwin (Pages-free underreports).
194
+ const hasAvailable = m.ramAvailableGb !== null && m.ramAvailableGb !== undefined;
195
+ const ramStr = hasAvailable
196
+ ? `RAM ${m.ramAvailableGb}GB avail`
197
+ : `RAM ${m.ramFreeGb ?? '?'}GB free`;
198
+ const measStr =
199
+ Object.keys(m).length > 0
200
+ ? ` (${ramStr}, CPU ${m.cpuLoadPct ?? '?'}%, sessions ${m.concurrentSessions ?? '?'})`
201
+ : '';
202
+ lines.push(`Decision: ${decision} — agents: ${agents}${measStr}`);
203
+ return lines.join('\n');
204
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * wave-sizing.mjs — graduated isolation defaults (issue #194).
3
+ * Learning: coordinator-over-worktree-on-shared-files caused back-to-back regressions.
4
+ */
5
+
6
+ const VALID_SESSION_TYPES = ['housekeeping', 'feature', 'deep'];
7
+ const VALID_COLLISION_RISKS = ['low', 'medium', 'high'];
8
+ const VALID_CONFIG_ISOLATIONS = ['auto', 'worktree', 'none'];
9
+ const VALID_ENFORCEMENTS = ['strict', 'warn', 'off'];
10
+ const VALID_ISOLATIONS = ['worktree', 'none'];
11
+
12
+ /**
13
+ * Resolve isolation mode for an agent wave dispatch.
14
+ *
15
+ * @param {Object} opts
16
+ * @param {number} opts.agentCount positive integer
17
+ * @param {string} opts.sessionType 'housekeeping' | 'feature' | 'deep'
18
+ * @param {string} [opts.collisionRisk] 'low' | 'medium' | 'high' — default 'low'
19
+ * @param {string} [opts.configIsolation] 'auto' | 'worktree' | 'none' — default 'auto'
20
+ * @returns {'worktree'|'none'}
21
+ */
22
+ export function resolveIsolation({ agentCount, sessionType, collisionRisk = 'low', configIsolation = 'auto' } = {}) {
23
+ if (!Number.isInteger(agentCount) || agentCount < 1) {
24
+ throw new TypeError(`resolveIsolation: agentCount must be a positive integer, got ${agentCount}`);
25
+ }
26
+ if (!VALID_SESSION_TYPES.includes(sessionType)) {
27
+ throw new TypeError(`resolveIsolation: sessionType must be housekeeping|feature|deep, got '${sessionType}'`);
28
+ }
29
+ if (!VALID_COLLISION_RISKS.includes(collisionRisk)) {
30
+ throw new TypeError(`resolveIsolation: collisionRisk must be low|medium|high, got '${collisionRisk}'`);
31
+ }
32
+ if (!VALID_CONFIG_ISOLATIONS.includes(configIsolation)) {
33
+ throw new TypeError(`resolveIsolation: configIsolation must be auto|worktree|none, got '${configIsolation}'`);
34
+ }
35
+
36
+ // Hard user overrides — first-match wins
37
+ if (configIsolation === 'worktree') return 'worktree';
38
+ if (configIsolation === 'none') return 'none';
39
+
40
+ // Plan-level collision declaration forces isolation even at ≤2 agents
41
+ if (collisionRisk === 'high') return 'worktree';
42
+
43
+ // Decision table
44
+ if (agentCount <= 2) return 'none';
45
+ if (agentCount >= 5) return 'worktree';
46
+ // agentCount is 3 or 4
47
+ if (sessionType === 'housekeeping') return 'none';
48
+ return 'worktree'; // feature | deep
49
+ }
50
+
51
+ /**
52
+ * Resolve enforcement mode given isolation.
53
+ *
54
+ * When isolation is 'none', the scope-enforcement hook is the only barrier —
55
+ * auto-promote 'warn' to 'strict'. Explicit 'off' is respected as user opt-out.
56
+ *
57
+ * @param {Object} opts
58
+ * @param {string} opts.isolation 'worktree' | 'none'
59
+ * @param {string} [opts.configEnforcement] 'strict' | 'warn' | 'off' — default 'warn'
60
+ * @returns {'strict'|'warn'|'off'}
61
+ */
62
+ export function resolveEnforcement({ isolation, configEnforcement = 'warn' } = {}) {
63
+ if (!VALID_ISOLATIONS.includes(isolation)) {
64
+ throw new TypeError(`resolveEnforcement: isolation must be worktree|none, got '${isolation}'`);
65
+ }
66
+ if (!VALID_ENFORCEMENTS.includes(configEnforcement)) {
67
+ throw new TypeError(`resolveEnforcement: configEnforcement must be strict|warn|off, got '${configEnforcement}'`);
68
+ }
69
+
70
+ if (isolation === 'worktree') return configEnforcement;
71
+
72
+ // isolation === 'none': auto-promote warn → strict; respect strict and off as-is
73
+ if (configEnforcement === 'warn') return 'strict';
74
+ return configEnforcement;
75
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * webhook-url.mjs — Centralized webhook URL resolution for session-orchestrator.
3
+ *
4
+ * Replaces ad-hoc hardcoded personal-domain URL fallbacks with a single
5
+ * resolution function that reads from environment variables and Session Config.
6
+ * No personal-domain default exists — callers that need a URL must supply one
7
+ * explicitly via env or config.
8
+ *
9
+ * Resolution order (env wins over config):
10
+ * 1. Environment variable: SO_WEBHOOK_<KIND>_URL (e.g. SO_WEBHOOK_SLACK_URL)
11
+ * 2. Session Config field: webhooks.<kind>.url
12
+ * 3. Error: WebhookConfigError is thrown — no silent fallback to a personal domain.
13
+ *
14
+ * Supported kinds: 'slack' | 'discord' | 'generic' | 'gitlab-pipeline-status'
15
+ *
16
+ * Issue #228 — centralize webhook URL resolution + drop personal-domain default.
17
+ */
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Named error
21
+ // ---------------------------------------------------------------------------
22
+
23
+ /**
24
+ * Thrown by `resolveWebhookUrl` when no URL source (env or config) provides a
25
+ * webhook URL for the requested kind. Callers should catch this and surface an
26
+ * actionable message to the user.
27
+ */
28
+ export class WebhookConfigError extends Error {
29
+ /**
30
+ * @param {string} kind - The webhook kind that was requested.
31
+ * @param {string} [message] - Optional override; defaults to a descriptive message.
32
+ */
33
+ constructor(kind, message) {
34
+ super(
35
+ message ??
36
+ `No webhook URL configured for kind "${kind}". ` +
37
+ `Set SO_WEBHOOK_${kind.toUpperCase().replace(/-/g, '_')}_URL ` +
38
+ `or add webhooks.${kind}.url to Session Config.`,
39
+ );
40
+ this.name = 'WebhookConfigError';
41
+ this.kind = kind;
42
+ }
43
+ }
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Supported kinds
47
+ // ---------------------------------------------------------------------------
48
+
49
+ /** @type {ReadonlySet<string>} */
50
+ const SUPPORTED_KINDS = new Set([
51
+ 'slack',
52
+ 'discord',
53
+ 'generic',
54
+ 'gitlab-pipeline-status',
55
+ ]);
56
+
57
+ // ---------------------------------------------------------------------------
58
+ // Public API
59
+ // ---------------------------------------------------------------------------
60
+
61
+ /**
62
+ * Resolve a webhook URL for the given kind.
63
+ *
64
+ * Resolution order:
65
+ * 1. `SO_WEBHOOK_<KIND>_URL` environment variable (e.g. `SO_WEBHOOK_SLACK_URL`)
66
+ * — kind is upper-cased and hyphens become underscores.
67
+ * 2. `config.webhooks.<kind>.url` — when a Session Config object is provided.
68
+ * 3. Throws {@link WebhookConfigError} — no silent personal-domain fallback.
69
+ *
70
+ * @param {{ kind: string, config?: object }} options
71
+ * - `kind` — One of the supported webhook kinds (see SUPPORTED_KINDS).
72
+ * - `config` — Parsed Session Config object (optional). Must have a `webhooks`
73
+ * sub-object if a config-based URL is desired.
74
+ * @returns {string} The resolved webhook URL (guaranteed non-empty string).
75
+ * @throws {WebhookConfigError} When kind is unsupported or no URL is found.
76
+ * @throws {TypeError} When `kind` is not a string.
77
+ */
78
+ export function resolveWebhookUrl({ kind, config } = {}) {
79
+ if (typeof kind !== 'string' || kind.length === 0) {
80
+ throw new TypeError('resolveWebhookUrl: "kind" must be a non-empty string');
81
+ }
82
+
83
+ if (!SUPPORTED_KINDS.has(kind)) {
84
+ throw new WebhookConfigError(
85
+ kind,
86
+ `Unsupported webhook kind "${kind}". Supported kinds: ${[...SUPPORTED_KINDS].join(', ')}.`,
87
+ );
88
+ }
89
+
90
+ // 1. Environment variable: SO_WEBHOOK_<KIND>_URL
91
+ const envKey = `SO_WEBHOOK_${kind.toUpperCase().replace(/-/g, '_')}_URL`;
92
+ const envUrl = process.env[envKey];
93
+ if (typeof envUrl === 'string' && envUrl.length > 0) {
94
+ return envUrl;
95
+ }
96
+
97
+ // 2. Session Config: webhooks.<kind>.url
98
+ const configUrl = config?.webhooks?.[kind]?.url;
99
+ if (typeof configUrl === 'string' && configUrl.length > 0) {
100
+ return configUrl;
101
+ }
102
+
103
+ // 3. No source provided a URL — throw rather than fall back to a personal domain.
104
+ throw new WebhookConfigError(kind);
105
+ }