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,568 @@
1
+ // dead-bridge-detectors.mjs — PURE detection functions for the dead-bridge
2
+ // validator (#671). These functions consolidate the dead-reference guards that
3
+ // previously lived as standalone scripts (check-subagent-types.mjs,
4
+ // check-rules-references.mjs, check-baseline-fetch-bridge.mjs) plus a NEW
5
+ // bridge-balance detector for the producer/consumer dead-bridge class.
6
+ //
7
+ // PURITY CONTRACT (load-bearing — do not violate):
8
+ // - NO node:fs import. All filesystem access is INJECTED via the RepoContext
9
+ // (`ctx.listMdFiles`, `ctx.listFiles`, `ctx.readText`, `ctx.exists`), so
10
+ // detectors are unit-testable with in-memory fakes.
11
+ // - NO console.* output. Detectors return Finding[] — the orchestrator
12
+ // (check-dead-bridge.mjs) is responsible for rendering and exit codes.
13
+ // - NO process.exit. Tool-error semantics are signalled via a Finding whose
14
+ // `rule` ends in `-tool-error` (see TOOL-ERROR CONVENTION below).
15
+ // - `path` from node:path IS allowed (pure, no IO).
16
+ //
17
+ // TOOL-ERROR CONVENTION:
18
+ // The original standalone guards exited 2 (tool-error) when a REQUIRED scan
19
+ // directory was missing/unreadable (rules dir for dangling-rule-reference,
20
+ // bootstrap dir for dangling-bootstrap-bridge). Because these detectors are
21
+ // pure (no process.exit), a tool-error is instead signalled by RETURNING a
22
+ // Finding with `rule: '<subrule>-tool-error'`. The orchestrator translates any
23
+ // `*-tool-error` rule into process exit code 2 (distinct from a normal exit-1
24
+ // validation failure). Detectors that find a missing dir which is a vacuous
25
+ // pass (e.g. skills/ for dangling-subagent-type) return NO finding instead.
26
+ //
27
+ // @typedef {Object} Finding
28
+ // @property {string} rule stable detector / sub-rule id (or `<id>-tool-error`)
29
+ // @property {'fail'} severity always 'fail' for this validator
30
+ // @property {string} file absolute path of the offending file ('' = N/A)
31
+ // @property {number} line 1-based line number (0 = file-level / no line)
32
+ // @property {string} message human-readable description
33
+ //
34
+ // @typedef {Object} RepoContext
35
+ // @property {string} pluginRoot absolute plugin root
36
+ // @property {(absDir: string) => string[]} listMdFiles recursive list of *.md under absDir (abs paths)
37
+ // @property {(absDir: string, exts: string[]) => string[]} listFiles recursive list of files with given exts under absDir (abs paths)
38
+ // @property {(absPath: string) => string} readText read file content as UTF-8
39
+ // @property {(absPath: string) => boolean} exists path-existence test
40
+
41
+ import { join, dirname, basename } from 'node:path';
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // Shared constants (ported verbatim from the three standalone guards).
45
+ // ---------------------------------------------------------------------------
46
+
47
+ // Any line carrying the consolidated dead-bridge ignore marker is skipped by
48
+ // EVERY sub-rule, in addition to each sub-rule's own historical marker — this
49
+ // preserves the original per-guard ignore behaviour while giving the merged
50
+ // validator a single uniform escape hatch.
51
+ const DEAD_BRIDGE_IGNORE = 'check-dead-bridge:ignore';
52
+
53
+ // --- dangling-subagent-type (port of check-subagent-types.mjs) -------------
54
+ const SUBAGENT_IGNORE_MARKER = 'check-subagent-types:ignore';
55
+ const SUBAGENT_REF_RE = /subagent_type:\s*["']session-orchestrator:([a-z0-9-]+)["']/g;
56
+
57
+ // --- dangling-rule-reference (port of check-rules-references.mjs) -----------
58
+ const RULES_IGNORE_MARKER = 'check-rules-references:ignore';
59
+ // Backtick-wrapped reference: `name.md`. Capture group = inner ref so
60
+ // path-qualified refs (containing `/`) can be excluded downstream.
61
+ const BACKTICK_REF_RE = /`([^`]+\.md)`/g;
62
+ // See-Also footer tokens — bare `[a-z0-9-]+\.md` basenames in a `· `-delimited
63
+ // list line.
64
+ const SEE_ALSO_TOKEN_RE = /([a-z0-9-]+\.md)/g;
65
+ // A rule-style basename is lowercase-kebab. Deliberately EXCLUDES uppercase doc
66
+ // names (CLAUDE.md, AGENTS.md, SECURITY.md, SKILL.md, MIGRATION-vN.md) and
67
+ // wildcard prose (`*.md`).
68
+ const RULE_BASENAME_RE = /^[a-z0-9-]+\.md$/;
69
+
70
+ // --- dangling-bootstrap-bridge (port of check-baseline-fetch-bridge.mjs) ---
71
+ const BOOTSTRAP_IGNORE_MARKER = 'check-baseline-fetch-bridge:ignore';
72
+ const BOOTSTRAP_FILES = [
73
+ '_shared-template.md',
74
+ 'SKILL.md',
75
+ 'standard-template.md',
76
+ 'deep-template.md',
77
+ ];
78
+ const STALE_BASENAME = 'fetch-baseline.sh';
79
+ const DEAD_FUNCTIONS = [
80
+ 'fetch_baseline_file',
81
+ 'fetch_baseline_files_batch',
82
+ 'write_baseline_fetch_lock',
83
+ ];
84
+ // A `-f "$PLUGIN_ROOT/scripts/lib/fetch-baseline.<ext>"` guard reference.
85
+ // Capture group = guarded path relative to the plugin root.
86
+ const GUARD_RE = /-f\s+["']?\$(?:\{)?PLUGIN_ROOT(?:\})?\/(scripts\/lib\/fetch-baseline\.[a-z]+)["']?/g;
87
+
88
+ // Default file extensions searched by detectBridgeBalance scope entries when a
89
+ // scope entry does not carry its own `exts`.
90
+ const DEFAULT_BRIDGE_EXTS = ['.mjs', '.md'];
91
+
92
+ // ---------------------------------------------------------------------------
93
+ // Small helpers (pure).
94
+ // ---------------------------------------------------------------------------
95
+
96
+ /**
97
+ * Split file content into lines, tolerant of CRLF.
98
+ * @param {string} text
99
+ * @returns {string[]}
100
+ */
101
+ function splitLines(text) {
102
+ return String(text).split(/\r?\n/);
103
+ }
104
+
105
+ /**
106
+ * True if a line should be skipped by a sub-rule: it carries either the
107
+ * sub-rule's own historical ignore marker or the consolidated dead-bridge
108
+ * marker.
109
+ * @param {string} text
110
+ * @param {string} ownMarker
111
+ * @returns {boolean}
112
+ */
113
+ function isIgnored(text, ownMarker) {
114
+ return text.includes(ownMarker) || text.includes(DEAD_BRIDGE_IGNORE);
115
+ }
116
+
117
+ /**
118
+ * Make a fail Finding.
119
+ * @param {string} rule
120
+ * @param {string} file
121
+ * @param {number} line
122
+ * @param {string} message
123
+ * @returns {Finding}
124
+ */
125
+ function fail(rule, file, line, message) {
126
+ return { rule, severity: 'fail', file: file || '', line: line ?? 0, message };
127
+ }
128
+
129
+ // ---------------------------------------------------------------------------
130
+ // Sub-rule 1 — dangling-subagent-type (port of check-subagent-types.mjs).
131
+ // ---------------------------------------------------------------------------
132
+
133
+ /**
134
+ * Scan recursive skills/**.md for `subagent_type: "session-orchestrator:<X>"`
135
+ * references and FAIL when no `agents/<X>.md` exists. Missing skills/ dir is a
136
+ * vacuous pass (no findings).
137
+ *
138
+ * @param {RepoContext} ctx
139
+ * @returns {Finding[]}
140
+ */
141
+ function detectDanglingSubagentTypes(ctx) {
142
+ /** @type {Finding[]} */
143
+ const findings = [];
144
+ const skillsDir = join(ctx.pluginRoot, 'skills');
145
+ const agentsDir = join(ctx.pluginRoot, 'agents');
146
+
147
+ // Missing skills/ dir → vacuously OK (no findings, NOT a tool-error).
148
+ if (!ctx.exists(skillsDir)) return findings;
149
+
150
+ for (const file of ctx.listMdFiles(skillsDir)) {
151
+ const lines = splitLines(ctx.readText(file));
152
+ lines.forEach((text, idx) => {
153
+ if (isIgnored(text, SUBAGENT_IGNORE_MARKER)) return;
154
+ SUBAGENT_REF_RE.lastIndex = 0;
155
+ let m;
156
+ while ((m = SUBAGENT_REF_RE.exec(text)) !== null) {
157
+ const agent = m[1];
158
+ const agentFile = join(agentsDir, `${agent}.md`);
159
+ if (!ctx.exists(agentFile)) {
160
+ findings.push(
161
+ fail(
162
+ 'dangling-subagent-type',
163
+ file,
164
+ idx + 1,
165
+ `subagent_type session-orchestrator:${agent} → agents/${agent}.md NOT FOUND`,
166
+ ),
167
+ );
168
+ }
169
+ }
170
+ });
171
+ }
172
+
173
+ return findings;
174
+ }
175
+
176
+ // ---------------------------------------------------------------------------
177
+ // Sub-rule 2 — dangling-rule-reference (port of check-rules-references.mjs).
178
+ // ---------------------------------------------------------------------------
179
+
180
+ /**
181
+ * Scan TOP-LEVEL `.claude/rules/*.md` (non-recursive) for bare-basename rule
182
+ * references — backtick refs and See-Also footer tokens — and FAIL when the
183
+ * referenced basename does not resolve to an existing sibling rule file.
184
+ *
185
+ * Tool-error: missing/unreadable rules dir → a `dangling-rule-reference-tool-error`
186
+ * Finding (orchestrator maps to exit 2).
187
+ *
188
+ * @param {RepoContext} ctx
189
+ * @returns {Finding[]}
190
+ */
191
+ function detectDanglingRuleReferences(ctx) {
192
+ /** @type {Finding[]} */
193
+ const findings = [];
194
+ const rulesDir = join(ctx.pluginRoot, '.claude', 'rules');
195
+
196
+ // Tool-error gate: the rules dir is REQUIRED for this sub-rule.
197
+ if (!ctx.exists(rulesDir)) {
198
+ return [
199
+ fail(
200
+ 'dangling-rule-reference-tool-error',
201
+ '',
202
+ 0,
203
+ `rules directory not found: ${rulesDir}`,
204
+ ),
205
+ ];
206
+ }
207
+
208
+ // listMdFiles is recursive; filter to DIRECT children of rulesDir only — the
209
+ // original guard scanned the top level of `.claude/rules/` exclusively.
210
+ const allMd = ctx.listMdFiles(rulesDir);
211
+ const topLevel = allMd.filter((f) => dirname(f) === rulesDir);
212
+
213
+ // The resolution universe: the set of existing top-level rule basenames.
214
+ const existing = new Set(topLevel.map((f) => basename(f)));
215
+
216
+ for (const full of topLevel) {
217
+ const name = basename(full);
218
+ const lines = splitLines(ctx.readText(full));
219
+
220
+ lines.forEach((text, idx) => {
221
+ if (isIgnored(text, RULES_IGNORE_MARKER)) return;
222
+ const lineNo = idx + 1;
223
+
224
+ // Locus (a): backtick refs `name.md` anywhere in the body.
225
+ BACKTICK_REF_RE.lastIndex = 0;
226
+ let m;
227
+ while ((m = BACKTICK_REF_RE.exec(text)) !== null) {
228
+ const inner = m[1];
229
+ if (inner.includes('/')) continue; // path-qualified — out of scope
230
+ if (!RULE_BASENAME_RE.test(inner)) continue; // not a rule-style basename
231
+ if (inner === name) continue; // self-reference
232
+ if (!existing.has(inner)) {
233
+ findings.push(
234
+ fail(
235
+ 'dangling-rule-reference',
236
+ full,
237
+ lineNo,
238
+ `rule reference ${inner} NOT FOUND in .claude/rules/`,
239
+ ),
240
+ );
241
+ }
242
+ }
243
+
244
+ // Locus (b): See-Also footer tokens — only on `· `-delimited list lines.
245
+ if (text.includes('· ') && /[a-z0-9-]+\.md/.test(text)) {
246
+ SEE_ALSO_TOKEN_RE.lastIndex = 0;
247
+ let s;
248
+ while ((s = SEE_ALSO_TOKEN_RE.exec(text)) !== null) {
249
+ const token = s[1];
250
+ // Skip tokens that are the tail of a path-qualified ref (e.g.
251
+ // `skills/_shared/state-ownership.md`): walk back to the nearest
252
+ // whitespace/backtick/`·` boundary and check for a slash.
253
+ const before = text.slice(0, s.index);
254
+ if (/[\w./-]$/.test(before.slice(-1)) && /\//.test(before.slice(-40))) {
255
+ const segMatch = before.match(/([^\s`·]+)$/);
256
+ if (segMatch && segMatch[1].includes('/')) continue;
257
+ }
258
+ if (token === name) continue; // self-reference
259
+ if (!existing.has(token)) {
260
+ findings.push(
261
+ fail(
262
+ 'dangling-rule-reference',
263
+ full,
264
+ lineNo,
265
+ `rule reference ${token} NOT FOUND in .claude/rules/`,
266
+ ),
267
+ );
268
+ }
269
+ }
270
+ }
271
+ });
272
+ }
273
+
274
+ return findings;
275
+ }
276
+
277
+ // ---------------------------------------------------------------------------
278
+ // Sub-rule 3 — dangling-bootstrap-bridge (port of check-baseline-fetch-bridge.mjs).
279
+ // ---------------------------------------------------------------------------
280
+
281
+ /**
282
+ * Scan the fixed bootstrap file set for the baseline-fetch bridge and FAIL on:
283
+ * - a `-f "$PLUGIN_ROOT/scripts/lib/fetch-baseline.<ext>"` guard whose target
284
+ * does not exist (the #618 always-false dead-bridge),
285
+ * - any reference to the stale `fetch-baseline.sh` basename,
286
+ * - any reference to a dead shell-function name,
287
+ * - ZERO guards found across the whole scanned set (requireAtLeastOne).
288
+ *
289
+ * Absent individual bootstrap files are skipped silently (informational, not a
290
+ * finding). Tool-error: missing bootstrap dir → a
291
+ * `dangling-bootstrap-bridge-tool-error` Finding (orchestrator maps to exit 2).
292
+ *
293
+ * @param {RepoContext} ctx
294
+ * @returns {Finding[]}
295
+ */
296
+ function detectDanglingBootstrapBridge(ctx) {
297
+ /** @type {Finding[]} */
298
+ const findings = [];
299
+ const bootstrapDir = join(ctx.pluginRoot, 'skills', 'bootstrap');
300
+
301
+ // Tool-error gate: the bootstrap dir is REQUIRED for this sub-rule.
302
+ if (!ctx.exists(bootstrapDir)) {
303
+ return [
304
+ fail(
305
+ 'dangling-bootstrap-bridge-tool-error',
306
+ '',
307
+ 0,
308
+ `bootstrap directory not found: ${bootstrapDir}`,
309
+ ),
310
+ ];
311
+ }
312
+
313
+ let guardCount = 0;
314
+
315
+ for (const name of BOOTSTRAP_FILES) {
316
+ const full = join(bootstrapDir, name);
317
+ // Absent bootstrap file → skip silently (informational, not a finding).
318
+ if (!ctx.exists(full)) continue;
319
+
320
+ const lines = splitLines(ctx.readText(full));
321
+ lines.forEach((text, idx) => {
322
+ if (isIgnored(text, BOOTSTRAP_IGNORE_MARKER)) return;
323
+ const lineNo = idx + 1;
324
+
325
+ // Guard refs — every guarded fetch-baseline path must resolve.
326
+ GUARD_RE.lastIndex = 0;
327
+ let m;
328
+ while ((m = GUARD_RE.exec(text)) !== null) {
329
+ guardCount++;
330
+ const guardedPath = m[1];
331
+ const target = join(ctx.pluginRoot, guardedPath);
332
+ if (!ctx.exists(target)) {
333
+ findings.push(
334
+ fail(
335
+ 'dangling-bootstrap-bridge',
336
+ full,
337
+ lineNo,
338
+ `guard "${guardedPath}" points at a non-existent file — dead always-false bridge (#618 regression class)`,
339
+ ),
340
+ );
341
+ }
342
+ }
343
+
344
+ // Forbidden-presence: stale `.sh` basename.
345
+ if (text.includes(STALE_BASENAME)) {
346
+ findings.push(
347
+ fail(
348
+ 'dangling-bootstrap-bridge',
349
+ full,
350
+ lineNo,
351
+ `stale "${STALE_BASENAME}" reference (the plugin ships .mjs only)`,
352
+ ),
353
+ );
354
+ }
355
+
356
+ // Forbidden-presence: dead shell-function names.
357
+ for (const fn of DEAD_FUNCTIONS) {
358
+ if (text.includes(fn)) {
359
+ findings.push(
360
+ fail(
361
+ 'dangling-bootstrap-bridge',
362
+ full,
363
+ lineNo,
364
+ `dead shell-function reference "${fn}" (removed shell-source bridge)`,
365
+ ),
366
+ );
367
+ }
368
+ }
369
+ });
370
+ }
371
+
372
+ // requireAtLeastOne: zero fetch-baseline guards anywhere is itself a dead
373
+ // bridge (the on-demand baseline-fetch step lost its guard entirely).
374
+ if (guardCount === 0) {
375
+ findings.push(
376
+ fail(
377
+ 'dangling-bootstrap-bridge',
378
+ '',
379
+ 0,
380
+ 'no fetch-baseline guard reference found in bootstrap files (expected the on-demand baseline-fetch bridge guard)',
381
+ ),
382
+ );
383
+ }
384
+
385
+ return findings;
386
+ }
387
+
388
+ // ---------------------------------------------------------------------------
389
+ // Public detector: detectDanglingReferences — composes the 3 sub-rules.
390
+ // ---------------------------------------------------------------------------
391
+
392
+ /**
393
+ * Run all three dangling-reference sub-rules and return their combined
394
+ * Finding[]. Tool-errors are surfaced as `*-tool-error` Findings (see the
395
+ * TOOL-ERROR CONVENTION at the top of this file).
396
+ *
397
+ * @param {RepoContext} ctx
398
+ * @returns {Finding[]}
399
+ */
400
+ export function detectDanglingReferences(ctx) {
401
+ return [
402
+ ...detectDanglingSubagentTypes(ctx),
403
+ ...detectDanglingRuleReferences(ctx),
404
+ ...detectDanglingBootstrapBridge(ctx),
405
+ ];
406
+ }
407
+
408
+ // ---------------------------------------------------------------------------
409
+ // Public detector: detectBridgeBalance — the NEW dead-bridge class.
410
+ // ---------------------------------------------------------------------------
411
+
412
+ /**
413
+ * Build a RegExp from a producer/consumer pattern. The pattern may be a string
414
+ * (treated as a literal substring) or a RegExp source string. We always compile
415
+ * with the 'g' flag so `match` counts every occurrence. A leading/trailing `/`
416
+ * pair is treated as a regex literal; otherwise the string is escaped to a
417
+ * literal match.
418
+ *
419
+ * @param {string} pattern
420
+ * @returns {RegExp}
421
+ */
422
+ function compilePattern(pattern) {
423
+ const src = String(pattern);
424
+ // `/.../flags` form → treat the inside as a regex source.
425
+ const literalRe = src.match(/^\/(.*)\/([a-z]*)$/s);
426
+ if (literalRe) {
427
+ const flags = literalRe[2].includes('g') ? literalRe[2] : `${literalRe[2]}g`;
428
+ return new RegExp(literalRe[1], flags);
429
+ }
430
+ // Plain string → escape regex metacharacters and match literally.
431
+ const escaped = src.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
432
+ return new RegExp(escaped, 'g');
433
+ }
434
+
435
+ /**
436
+ * Normalize an extension allow-list so every entry carries a leading dot. This
437
+ * lets the corpus declare exts either way (`'md'` or `'.md'`) while the
438
+ * underlying `ctx.listFiles` (which compares against `path.extname()`, e.g.
439
+ * `'.md'`) still matches. Idempotent: `'.md'` stays `'.md'`.
440
+ *
441
+ * @param {string[]|undefined} exts
442
+ * @param {string[]} defaultExts
443
+ * @returns {string[]}
444
+ */
445
+ function normalizeExts(exts, defaultExts) {
446
+ const list = exts && exts.length ? exts : defaultExts;
447
+ return list.map((e) => (String(e).startsWith('.') ? String(e) : `.${e}`));
448
+ }
449
+
450
+ /**
451
+ * Count total matches of `pattern` across every file in `scope`. Each scope
452
+ * entry is a repo-relative path that may be EITHER a single FILE or a DIRECTORY
453
+ * (optionally an object `{ dir, exts }`):
454
+ *
455
+ * - FILE entry → read it directly via ctx.readText and count matches. We
456
+ * detect "is a file" by ATTEMPTING ctx.readText first: detectors only have
457
+ * the injected ctx callbacks (no isDirectory), so a successful read of a
458
+ * string is the cheapest reliable file-signal. If the read throws (the path
459
+ * is a directory, or missing), we fall through to the directory branch.
460
+ * - DIRECTORY entry → enumerate via ctx.listFiles with the scope's `exts`
461
+ * (default `.mjs` + `.md`, leading dot normalized) and read each file.
462
+ *
463
+ * This file-or-dir handling lets the corpus declare scope as concrete file
464
+ * paths (e.g. `docs/session-config-template.md`) without a new ctx callback.
465
+ *
466
+ * @param {RepoContext} ctx
467
+ * @param {string} pattern
468
+ * @param {Array<string|{dir: string, exts?: string[]}>} scope
469
+ * @param {string[]} defaultExts
470
+ * @returns {number}
471
+ */
472
+ function countMatches(ctx, pattern, scope, defaultExts) {
473
+ let count = 0;
474
+ const countIn = (text) => {
475
+ const re = compilePattern(pattern);
476
+ const matches = String(text).match(re);
477
+ return matches ? matches.length : 0;
478
+ };
479
+ for (const entry of scope ?? []) {
480
+ const relPath = typeof entry === 'string' ? entry : entry.dir;
481
+ const exts = normalizeExts(typeof entry === 'object' ? entry.exts : undefined, defaultExts);
482
+ const abs = join(ctx.pluginRoot, relPath);
483
+ if (!ctx.exists(abs)) continue;
484
+
485
+ // FILE-first: try reading the entry directly. A successful read means it is
486
+ // a single file; a throw means it is a directory (or vanished) → fall back
487
+ // to the recursive directory walk.
488
+ let fileText;
489
+ try {
490
+ fileText = ctx.readText(abs);
491
+ } catch {
492
+ // Not a readable file (directory or vanished) → fall through to dir walk.
493
+ }
494
+ if (typeof fileText === 'string') {
495
+ count += countIn(fileText);
496
+ continue;
497
+ }
498
+ for (const file of ctx.listFiles(abs, exts)) {
499
+ count += countIn(ctx.readText(file));
500
+ }
501
+ }
502
+ return count;
503
+ }
504
+
505
+ /**
506
+ * The NEW dead-bridge class. For each declared bridge — a producer/consumer
507
+ * pair — FAIL when exactly one side has zero matches:
508
+ * - producerCount === 0 && consumerCount > 0 → "read but never set"
509
+ * - consumerCount === 0 && producerCount > 0 → "set but never read"
510
+ *
511
+ * A bridge where BOTH sides are zero, or BOTH are non-zero, is NOT a finding.
512
+ * `bridges` defaults to [] → no findings (zero false positives by construction;
513
+ * only declared bridges are checked).
514
+ *
515
+ * @param {RepoContext} ctx
516
+ * @param {Array<{id: string, description?: string, producer: {pattern: string, scope: Array<string|{dir:string,exts?:string[]}>, exts?: string[]}, consumer: {pattern: string, scope: Array<string|{dir:string,exts?:string[]}>, exts?: string[]}}>} bridges
517
+ * @returns {Finding[]}
518
+ */
519
+ export function detectBridgeBalance(ctx, bridges) {
520
+ /** @type {Finding[]} */
521
+ const findings = [];
522
+
523
+ for (const bridge of bridges ?? []) {
524
+ const id = bridge?.id ?? '<unnamed>';
525
+ const producer = bridge?.producer;
526
+ const consumer = bridge?.consumer;
527
+ if (!producer || !consumer) continue; // malformed bridge — nothing to check
528
+
529
+ const producerExts = producer.exts || DEFAULT_BRIDGE_EXTS;
530
+ const consumerExts = consumer.exts || DEFAULT_BRIDGE_EXTS;
531
+
532
+ const producerCount = countMatches(ctx, producer.pattern, producer.scope, producerExts);
533
+ const consumerCount = countMatches(ctx, consumer.pattern, consumer.scope, consumerExts);
534
+
535
+ if (producerCount === 0 && consumerCount > 0) {
536
+ findings.push(
537
+ fail(
538
+ 'bridge-balance',
539
+ '',
540
+ 0,
541
+ `bridge "${id}": consumer side matches (${consumerCount}) but producer side has ZERO matches — read but never set (dead bridge)`,
542
+ ),
543
+ );
544
+ } else if (consumerCount === 0 && producerCount > 0) {
545
+ findings.push(
546
+ fail(
547
+ 'bridge-balance',
548
+ '',
549
+ 0,
550
+ `bridge "${id}": producer side matches (${producerCount}) but consumer side has ZERO matches — set but never read (dead bridge)`,
551
+ ),
552
+ );
553
+ }
554
+ }
555
+
556
+ return findings;
557
+ }
558
+
559
+ // ---------------------------------------------------------------------------
560
+ // Detector registry — consumed by the orchestrator (check-dead-bridge.mjs).
561
+ // Each entry's `fn(ctx, corpus)` returns Finding[]. The corpus carries the
562
+ // declared BRIDGES list for the bridge-balance detector.
563
+ // ---------------------------------------------------------------------------
564
+
565
+ export const DETECTORS = [
566
+ { id: 'dangling-reference', fn: (ctx, _corpus) => detectDanglingReferences(ctx) },
567
+ { id: 'bridge-balance', fn: (ctx, corpus) => detectBridgeBalance(ctx, corpus.BRIDGES ?? []) },
568
+ ];
@@ -0,0 +1,100 @@
1
+ /**
2
+ * tier-inference.mjs — Sandbox-tier vocabulary + inference helpers (issue #418).
3
+ *
4
+ * Four tiers (ordered from most-restricted to most-permissive):
5
+ * read-only — only observes the repo; no writes, no network
6
+ * repo-write — may create or modify files (Edit, Write)
7
+ * network-allowed — may make outbound network calls (future use)
8
+ * dangerous — may run destructive shell commands (future use)
9
+ *
10
+ * Backward-compat: agents without a `sandbox-tier:` field in frontmatter
11
+ * infer their tier from their declared tools list. The validator emits
12
+ * WARN (not FAIL) when the field is absent, so existing agents continue
13
+ * to work during migration.
14
+ */
15
+
16
+ /**
17
+ * Canonical ordered tier enum.
18
+ *
19
+ * @type {string[]}
20
+ */
21
+ export const TIER_ENUM = ['read-only', 'repo-write', 'network-allowed', 'dangerous'];
22
+
23
+ // Tools that signal write capability.
24
+ const WRITE_TOOLS = new Set(['Edit', 'Write']);
25
+
26
+ // Tools that are acceptable in the read-only tier (Bash is fine — fine-grained
27
+ // Bash control lives in hooks/pre-bash-destructive-guard.mjs, NOT here).
28
+ const READ_ONLY_TOOLS = new Set(['Read', 'Grep', 'Glob', 'Bash', 'Skill']);
29
+
30
+ /**
31
+ * Infer the sandbox tier from a parsed tools array.
32
+ *
33
+ * The inference is intentionally conservative:
34
+ * - Any Edit or Write entry → repo-write
35
+ * - All entries are read-only-compatible → read-only
36
+ * - Anything else (unknown tool, empty array) → repo-write (safe default)
37
+ *
38
+ * Skill(...) entries (e.g. "Skill(session-orchestrator:*)") are normalised
39
+ * to "Skill" before lookup so they match READ_ONLY_TOOLS.
40
+ *
41
+ * @param {string[]} toolsArray - array of tool name strings from frontmatter
42
+ * @returns {string} one of the values in TIER_ENUM
43
+ */
44
+ export function inferTierFromTools(toolsArray) {
45
+ if (!Array.isArray(toolsArray) || toolsArray.length === 0) {
46
+ return 'repo-write'; // safe default
47
+ }
48
+
49
+ // Normalise "Skill(...)" → "Skill"
50
+ const normalised = toolsArray.map((t) => {
51
+ if (typeof t !== 'string') return String(t);
52
+ return t.startsWith('Skill(') ? 'Skill' : t.trim();
53
+ });
54
+
55
+ // Any write tool → repo-write
56
+ for (const t of normalised) {
57
+ if (WRITE_TOOLS.has(t)) return 'repo-write';
58
+ }
59
+
60
+ // If every tool is in the read-only-compatible set → read-only
61
+ const allReadOnly = normalised.every((t) => READ_ONLY_TOOLS.has(t));
62
+ if (allReadOnly) return 'read-only';
63
+
64
+ // Unknown tool encountered — safe default
65
+ return 'repo-write';
66
+ }
67
+
68
+ /**
69
+ * Validate that a declared sandbox-tier is consistent with the agent's tools.
70
+ *
71
+ * @param {{
72
+ * declared: string,
73
+ * inferred: string,
74
+ * tools?: string[]
75
+ * }} params
76
+ * @returns {{ ok: true } | { ok: false, error: string }}
77
+ */
78
+ export function validateTierConsistency({ declared, inferred, tools }) {
79
+ // 1. Declared value must be in the enum.
80
+ if (!TIER_ENUM.includes(declared)) {
81
+ return {
82
+ ok: false,
83
+ error: `sandbox-tier "${declared}" is not a valid tier; must be one of: ${TIER_ENUM.join(', ')}`,
84
+ };
85
+ }
86
+
87
+ // 2. Read-only agent must not have write tools.
88
+ if (declared === 'read-only' && inferred !== 'read-only') {
89
+ const writeToolsPresent = Array.isArray(tools)
90
+ ? tools.filter((t) => WRITE_TOOLS.has(t))
91
+ : [];
92
+ const detail = writeToolsPresent.length > 0 ? ` (tools include: ${writeToolsPresent.join(', ')})` : '';
93
+ return {
94
+ ok: false,
95
+ error: `agent declares sandbox-tier "read-only" but tools suggest "${inferred}"${detail}`,
96
+ };
97
+ }
98
+
99
+ return { ok: true };
100
+ }