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,433 @@
1
+ /**
2
+ * language-mappers/typescript.mjs — Semantic slice extractor for TypeScript/JS.
3
+ *
4
+ * Uses @babel/parser (lazy import) to parse the file into an AST and walk
5
+ * top-level declarations. Emits SemanticSlice records for:
6
+ * function — FunctionDeclaration
7
+ * class — ClassDeclaration (+ nested method slices)
8
+ * interface — TSInterfaceDeclaration
9
+ * type — TSTypeAliasDeclaration
10
+ * export — ExportNamedDeclaration without an inner declaration
11
+ *
12
+ * Part of the Clawpatch Borrow Cluster (issue #416).
13
+ */
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Types (JSDoc only — no runtime overhead)
17
+ // ---------------------------------------------------------------------------
18
+
19
+ /**
20
+ * @typedef {{
21
+ * kind: 'function'|'class'|'interface'|'type'|'export'|'section';
22
+ * name: string;
23
+ * file: string;
24
+ * line: number;
25
+ * endLine: number;
26
+ * exported: boolean;
27
+ * isNested: boolean;
28
+ * fidelity: 'regex'|'ast';
29
+ * params?: string[];
30
+ * doc?: string;
31
+ * source?: string;
32
+ * }} SemanticSlice
33
+ */
34
+
35
+ // All slices produced by this mapper carry fidelity:'ast' (#474 MED-3) —
36
+ // they come from a real @babel/parser AST walk, not regex matching.
37
+ const FIDELITY = /** @type {'ast'} */ ('ast');
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Babel parser options
41
+ // ---------------------------------------------------------------------------
42
+
43
+ const BABEL_OPTIONS = {
44
+ sourceType: 'module',
45
+ strictMode: false,
46
+ plugins: [
47
+ 'typescript',
48
+ 'jsx',
49
+ 'decorators-legacy',
50
+ 'classProperties',
51
+ 'classStaticBlock',
52
+ 'exportDefaultFrom',
53
+ 'importMeta',
54
+ ],
55
+ };
56
+
57
+ // ---------------------------------------------------------------------------
58
+ // Helpers
59
+ // ---------------------------------------------------------------------------
60
+
61
+ /**
62
+ * Extract parameter names from a Babel FunctionDeclaration / FunctionExpression
63
+ * params array. Returns an array of identifier name strings (skips patterns).
64
+ *
65
+ * @param {Array<object>} params
66
+ * @returns {string[]}
67
+ */
68
+ function extractParamNames(params) {
69
+ return params.flatMap((p) => {
70
+ if (p.type === 'Identifier') return [p.name];
71
+ if (p.type === 'AssignmentPattern' && p.left?.type === 'Identifier') return [p.left.name];
72
+ if (p.type === 'RestElement' && p.argument?.type === 'Identifier')
73
+ return [`...${p.argument.name}`];
74
+ if (p.type === 'TSParameterProperty' && p.parameter?.type === 'Identifier')
75
+ return [p.parameter.name];
76
+ return [];
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Extract a leading comment string from the node's `leadingComments` if present.
82
+ *
83
+ * @param {object} node
84
+ * @returns {string|undefined}
85
+ */
86
+ function extractDoc(node) {
87
+ const comments = node.leadingComments;
88
+ if (!Array.isArray(comments) || comments.length === 0) return undefined;
89
+ const last = comments[comments.length - 1];
90
+ if (!last) return undefined;
91
+ const raw = last.value ?? '';
92
+ // Strip leading * characters (JSDoc style) and trim
93
+ return raw
94
+ .split('\n')
95
+ .map((l) => l.replace(/^\s*\*\s?/, '').trim())
96
+ .filter(Boolean)
97
+ .join(' ')
98
+ .trim() || undefined;
99
+ }
100
+
101
+ /**
102
+ * Safe node location accessor — returns {startLine, endLine} or {1, 1} on miss.
103
+ *
104
+ * @param {object} node
105
+ * @returns {{ startLine: number; endLine: number }}
106
+ */
107
+ function nodeLoc(node) {
108
+ const start = node?.loc?.start?.line ?? 1;
109
+ const end = node?.loc?.end?.line ?? start;
110
+ return { startLine: start, endLine: end };
111
+ }
112
+
113
+ // ---------------------------------------------------------------------------
114
+ // AST walker
115
+ // ---------------------------------------------------------------------------
116
+
117
+ /**
118
+ * Walk a single statement and emit SemanticSlice records into `out`.
119
+ *
120
+ * @param {object} stmt AST statement node
121
+ * @param {string} filePath Source file path
122
+ * @param {boolean} exported Whether this stmt is inside an ExportDeclaration
123
+ * @param {SemanticSlice[]} out
124
+ */
125
+ function walkStatement(stmt, filePath, exported, out) {
126
+ if (!stmt || typeof stmt !== 'object') return;
127
+
128
+ switch (stmt.type) {
129
+ case 'ExportNamedDeclaration': {
130
+ const inner = stmt.declaration;
131
+ if (inner) {
132
+ // Has a nested declaration — delegate but mark as exported
133
+ walkStatement(inner, filePath, true, out);
134
+ } else {
135
+ // Re-export or `export { foo }` without a declaration.
136
+ // Note: `export * as ns from 'x'` lands here too (ExportNamespaceSpecifier).
137
+ const { startLine, endLine } = nodeLoc(stmt);
138
+ const source = stmt.source?.value;
139
+ // Collect specifier names
140
+ const names = (stmt.specifiers ?? []).map((s) => s.exported?.name ?? s.local?.name ?? '?');
141
+ if (names.length > 0) {
142
+ for (const name of names) {
143
+ out.push({
144
+ kind: 'export',
145
+ name,
146
+ file: filePath,
147
+ line: startLine,
148
+ endLine,
149
+ exported: true,
150
+ isNested: false,
151
+ fidelity: FIDELITY,
152
+ ...(source !== undefined ? { source } : {}),
153
+ });
154
+ }
155
+ } else {
156
+ // Empty specifiers with a source (rare: `export {} from 'x'`)
157
+ out.push({
158
+ kind: 'export',
159
+ name: source ?? '<re-export>',
160
+ file: filePath,
161
+ line: startLine,
162
+ endLine,
163
+ exported: true,
164
+ isNested: false,
165
+ fidelity: FIDELITY,
166
+ ...(source !== undefined ? { source } : {}),
167
+ });
168
+ }
169
+ }
170
+ break;
171
+ }
172
+
173
+ case 'ExportAllDeclaration': {
174
+ // `export * from './x'` → stmt.exported = null, name '*'
175
+ // `export * as ns from './x'` → stmt.exported = { name: 'ns' }
176
+ const { startLine, endLine } = nodeLoc(stmt);
177
+ out.push({
178
+ kind: 'export',
179
+ name: stmt.exported?.name ?? '*',
180
+ file: filePath,
181
+ line: startLine,
182
+ endLine,
183
+ exported: true,
184
+ isNested: false,
185
+ fidelity: FIDELITY,
186
+ source: stmt.source?.value ?? '<unknown>',
187
+ });
188
+ break;
189
+ }
190
+
191
+ case 'ExportDefaultDeclaration': {
192
+ const inner = stmt.declaration;
193
+ const { startLine, endLine } = nodeLoc(stmt);
194
+ if (inner && (inner.type === 'FunctionDeclaration' || inner.type === 'FunctionExpression')) {
195
+ const name = inner.id?.name ?? '<default>';
196
+ out.push({
197
+ kind: 'function',
198
+ name,
199
+ file: filePath,
200
+ line: startLine,
201
+ endLine,
202
+ exported: true,
203
+ isNested: false,
204
+ fidelity: FIDELITY,
205
+ params: extractParamNames(inner.params ?? []),
206
+ doc: extractDoc(stmt),
207
+ });
208
+ } else if (inner && (inner.type === 'ClassDeclaration' || inner.type === 'ClassExpression')) {
209
+ const name = inner.id?.name ?? '<default>';
210
+ out.push({
211
+ kind: 'class',
212
+ name,
213
+ file: filePath,
214
+ line: startLine,
215
+ endLine,
216
+ exported: true,
217
+ isNested: false,
218
+ fidelity: FIDELITY,
219
+ params: extractClassMethods(inner),
220
+ doc: extractDoc(stmt),
221
+ });
222
+ walkClassMethods(inner, filePath, out);
223
+ } else {
224
+ // Arrow function, expression, etc.
225
+ const innerName =
226
+ inner?.id?.name ?? (inner?.type === 'ArrowFunctionExpression' ? '<arrow>' : '<default>');
227
+ out.push({
228
+ kind: 'export',
229
+ name: innerName,
230
+ file: filePath,
231
+ line: startLine,
232
+ endLine,
233
+ exported: true,
234
+ isNested: false,
235
+ fidelity: FIDELITY,
236
+ doc: extractDoc(stmt),
237
+ });
238
+ }
239
+ break;
240
+ }
241
+
242
+ case 'FunctionDeclaration': {
243
+ if (!stmt.id) break; // anonymous
244
+ const { startLine, endLine } = nodeLoc(stmt);
245
+ out.push({
246
+ kind: 'function',
247
+ name: stmt.id.name,
248
+ file: filePath,
249
+ line: startLine,
250
+ endLine,
251
+ exported,
252
+ isNested: false,
253
+ fidelity: FIDELITY,
254
+ params: extractParamNames(stmt.params ?? []),
255
+ doc: extractDoc(stmt),
256
+ });
257
+ break;
258
+ }
259
+
260
+ case 'ClassDeclaration': {
261
+ if (!stmt.id) break;
262
+ const { startLine, endLine } = nodeLoc(stmt);
263
+ out.push({
264
+ kind: 'class',
265
+ name: stmt.id.name,
266
+ file: filePath,
267
+ line: startLine,
268
+ endLine,
269
+ exported,
270
+ isNested: false,
271
+ fidelity: FIDELITY,
272
+ params: extractClassMethods(stmt),
273
+ doc: extractDoc(stmt),
274
+ });
275
+ walkClassMethods(stmt, filePath, out);
276
+ break;
277
+ }
278
+
279
+ case 'TSInterfaceDeclaration': {
280
+ const { startLine, endLine } = nodeLoc(stmt);
281
+ const name = stmt.id?.name ?? '<interface>';
282
+ out.push({
283
+ kind: 'interface',
284
+ name,
285
+ file: filePath,
286
+ line: startLine,
287
+ endLine,
288
+ exported,
289
+ isNested: false,
290
+ fidelity: FIDELITY,
291
+ doc: extractDoc(stmt),
292
+ });
293
+ break;
294
+ }
295
+
296
+ case 'TSTypeAliasDeclaration': {
297
+ const { startLine, endLine } = nodeLoc(stmt);
298
+ const name = stmt.id?.name ?? '<type>';
299
+ out.push({
300
+ kind: 'type',
301
+ name,
302
+ file: filePath,
303
+ line: startLine,
304
+ endLine,
305
+ exported,
306
+ isNested: false,
307
+ fidelity: FIDELITY,
308
+ doc: extractDoc(stmt),
309
+ });
310
+ break;
311
+ }
312
+
313
+ // Variable declarations: const foo = () => {} or const foo = function() {}
314
+ case 'VariableDeclaration': {
315
+ for (const decl of stmt.declarations ?? []) {
316
+ if (!decl.id || decl.id.type !== 'Identifier') continue;
317
+ const init = decl.init;
318
+ if (!init) continue;
319
+ if (
320
+ init.type === 'ArrowFunctionExpression' ||
321
+ init.type === 'FunctionExpression'
322
+ ) {
323
+ const { startLine, endLine } = nodeLoc(stmt);
324
+ out.push({
325
+ kind: 'function',
326
+ name: decl.id.name,
327
+ file: filePath,
328
+ line: startLine,
329
+ endLine,
330
+ exported,
331
+ isNested: false,
332
+ fidelity: FIDELITY,
333
+ params: extractParamNames(init.params ?? []),
334
+ doc: extractDoc(stmt),
335
+ });
336
+ }
337
+ }
338
+ break;
339
+ }
340
+
341
+ default:
342
+ break;
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Extract method names from a ClassDeclaration body.
348
+ *
349
+ * @param {object} classNode
350
+ * @returns {string[]}
351
+ */
352
+ function extractClassMethods(classNode) {
353
+ const body = classNode?.body?.body ?? [];
354
+ return body
355
+ .filter((m) => m.type === 'ClassMethod' || m.type === 'ClassPrivateMethod')
356
+ .map((m) => {
357
+ if (m.key?.type === 'Identifier') return m.key.name;
358
+ if (m.key?.type === 'StringLiteral') return m.key.value;
359
+ return '<method>';
360
+ });
361
+ }
362
+
363
+ /**
364
+ * Walk class body and emit nested method slices.
365
+ *
366
+ * @param {object} classNode
367
+ * @param {string} filePath
368
+ * @param {SemanticSlice[]} out
369
+ */
370
+ function walkClassMethods(classNode, filePath, out) {
371
+ const body = classNode?.body?.body ?? [];
372
+ for (const member of body) {
373
+ if (member.type !== 'ClassMethod' && member.type !== 'ClassPrivateMethod') continue;
374
+ const { startLine, endLine } = nodeLoc(member);
375
+ let name;
376
+ if (member.key?.type === 'Identifier') {
377
+ name = member.key.name;
378
+ } else if (member.key?.type === 'StringLiteral') {
379
+ name = member.key.value;
380
+ } else {
381
+ name = '<method>';
382
+ }
383
+ out.push({
384
+ kind: 'function',
385
+ name,
386
+ file: filePath,
387
+ line: startLine,
388
+ endLine,
389
+ exported: false,
390
+ isNested: true,
391
+ fidelity: FIDELITY,
392
+ params: extractParamNames(member.params ?? []),
393
+ doc: extractDoc(member),
394
+ });
395
+ }
396
+ }
397
+
398
+ // ---------------------------------------------------------------------------
399
+ // Public API
400
+ // ---------------------------------------------------------------------------
401
+
402
+ /**
403
+ * Extract semantic slices from TypeScript/JavaScript source.
404
+ *
405
+ * @param {string} filePath Source file path (used only for the slice `file` field).
406
+ * @param {string} content Raw source text.
407
+ * @returns {Promise<SemanticSlice[]>}
408
+ */
409
+ export async function extractTypeScriptSlices(filePath, content) {
410
+ if (!content.trim()) return [];
411
+
412
+ const { parse } = await import('@babel/parser');
413
+
414
+ let ast;
415
+ try {
416
+ ast = parse(content, BABEL_OPTIONS);
417
+ } catch (err) {
418
+ throw new Error(
419
+ `extractTypeScriptSlices: parse error in '${filePath}': ${err.message}`,
420
+ { cause: err },
421
+ );
422
+ }
423
+
424
+ const body = ast?.program?.body ?? [];
425
+ /** @type {SemanticSlice[]} */
426
+ const slices = [];
427
+
428
+ for (const stmt of body) {
429
+ walkStatement(stmt, filePath, false, slices);
430
+ }
431
+
432
+ return slices;
433
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * learnings/expiry-sweep.mjs — mechanical expiry/archive sweep for learnings.jsonl.
3
+ *
4
+ * Epic #723 B4. Fleet audit found expired-resident learnings accumulating in
5
+ * 6+ repos (Vault: 70% expired) because nothing MECHANICALLY moves expired
6
+ * entries out of the active store — `memory-cleanup-soft-limit` and the
7
+ * `evolve` confidence-decay pass both operate on the live store but never
8
+ * relocate anything. This module is the missing mechanical sweep: it
9
+ * partitions `learnings.jsonl` into KEEP (still active, or too-recently
10
+ * expired to move yet) and ARCHIVE (expired past the grace window), appends
11
+ * the archive candidates to an append-only sidecar, then rewrites the store
12
+ * with only the KEEP set.
13
+ *
14
+ * Design constraints (deliberate, do not "simplify" away):
15
+ * - NEVER deletes data. Archive is append-only; the store rewrite is the
16
+ * ONLY destructive step, and it reuses `rewriteLearnings()` from io.mjs
17
+ * (#721), which itself snapshots a `.bak-<ISO>` backup before the atomic
18
+ * rename — the same safety net that protects every other bulk rewrite.
19
+ * - Grace period (default 14 days): an entry that JUST expired stays in the
20
+ * active store for `graceDays` more days. This absorbs two things: (a)
21
+ * TTL edge-noise near the boundary, and (b) a window for /evolve's
22
+ * confidence-reinforcement pass to re-stamp `expires_at` before the entry
23
+ * is moved out from under it. Without the grace window, a recurring
24
+ * learning could ping-pong between store and archive on every sweep.
25
+ * - Crash-safe ordering: the archive APPEND happens before the store
26
+ * REWRITE. A crash between the two steps leaves the entry in BOTH places
27
+ * (harmless — the archive is append-only and never de-duplicated on
28
+ * read) rather than in NEITHER (data loss, if the rewrite completed but
29
+ * the archive append had not yet happened).
30
+ * - KEEP-batch validated BEFORE the archive append: a `rewriteLearnings(...,
31
+ * { dryRun: true })` probe validates the KEEP set (throws on an
32
+ * invalid-but-parseable record) with zero disk writes. Without this
33
+ * probe, an invalid KEEP record would survive `readLearnings()` only to
34
+ * blow up the REAL rewrite AFTER the archive append had already landed —
35
+ * on a repeated `--apply` run that duplicates the archive append every
36
+ * time while the store is never actually pruned.
37
+ * - Read/normalize is delegated to `readLearnings()`; the destructive
38
+ * rewrite is delegated to `rewriteLearnings()`. This file does not
39
+ * implement its own JSONL writer for the store — see io.mjs #721
40
+ * (the incident that destroyed 107 live learnings via a bespoke writer
41
+ * with no backup/dry-run safety net).
42
+ *
43
+ * Sibling-module import convention (learnings.mjs barrel doc): import
44
+ * directly from `./io.mjs`, never from `../learnings.mjs`, to preserve the
45
+ * acyclic dependency graph.
46
+ */
47
+
48
+ import { existsSync } from 'node:fs';
49
+ import { mkdir, appendFile } from 'node:fs/promises';
50
+ import path from 'node:path';
51
+ import { readLearnings, rewriteLearnings } from './io.mjs';
52
+
53
+ const MS_PER_DAY = 86_400_000;
54
+ const DEFAULT_GRACE_DAYS = 14;
55
+
56
+ /**
57
+ * Sweep expired learnings out of `filePath` into `archivePath`.
58
+ *
59
+ * Partition rule (relative to `now`):
60
+ * - KEEP: `expires_at` unparseable/absent, OR not yet expired, OR expired
61
+ * but within `graceDays` of expiry (grace window).
62
+ * - ARCHIVE: `expires_at` parseable AND expired AND
63
+ * `expiresMs + graceDays*86400000 < now` (grace window elapsed).
64
+ *
65
+ * @param {object} opts
66
+ * @param {string} opts.filePath - absolute/relative path to the active learnings.jsonl
67
+ * @param {string} opts.archivePath - absolute/relative path to the append-only archive sidecar
68
+ * @param {Date|number} [opts.now] - injectable clock; defaults to `Date.now()`
69
+ * @param {boolean} [opts.dryRun=true] - when true, computes counts but writes nothing
70
+ * @param {number} [opts.graceDays=14] - days past expiry before an entry is archived
71
+ * @returns {Promise<{scanned: number, kept: number, archived: number, dryRun: boolean, archivePath: string}>}
72
+ * Never throws on a missing store — returns the zeroed shape instead. Both
73
+ * `filePath` and `archivePath` are required; a missing/invalid `filePath`
74
+ * throws a plain `Error` (programmer error, not a runtime data condition).
75
+ */
76
+ export async function sweepExpiredLearnings({
77
+ filePath,
78
+ archivePath,
79
+ now,
80
+ dryRun = true,
81
+ graceDays = DEFAULT_GRACE_DAYS,
82
+ } = {}) {
83
+ if (typeof filePath !== 'string' || filePath.length === 0) {
84
+ throw new Error('sweepExpiredLearnings: filePath is required');
85
+ }
86
+ if (typeof archivePath !== 'string' || archivePath.length === 0) {
87
+ throw new Error('sweepExpiredLearnings: archivePath is required');
88
+ }
89
+
90
+ if (!existsSync(filePath)) {
91
+ return { scanned: 0, kept: 0, archived: 0, dryRun, archivePath };
92
+ }
93
+
94
+ const nowMs =
95
+ now instanceof Date ? now.getTime() : typeof now === 'number' ? now : Date.now();
96
+ const graceMs =
97
+ (Number.isFinite(graceDays) && graceDays >= 0 ? graceDays : DEFAULT_GRACE_DAYS) * MS_PER_DAY;
98
+
99
+ const { entries } = await readLearnings(filePath);
100
+
101
+ const keep = [];
102
+ const archiveCandidates = [];
103
+
104
+ for (const entry of entries) {
105
+ const expiresMs = typeof entry?.expires_at === 'string' ? Date.parse(entry.expires_at) : NaN;
106
+ const isExpired = Number.isFinite(expiresMs) && expiresMs <= nowMs;
107
+ if (!isExpired) {
108
+ keep.push(entry);
109
+ continue;
110
+ }
111
+ // Expired — but does it clear the grace window?
112
+ if (expiresMs + graceMs < nowMs) {
113
+ archiveCandidates.push(entry);
114
+ } else {
115
+ keep.push(entry);
116
+ }
117
+ }
118
+
119
+ if (dryRun) {
120
+ return {
121
+ scanned: entries.length,
122
+ kept: keep.length,
123
+ archived: archiveCandidates.length,
124
+ dryRun: true,
125
+ archivePath,
126
+ };
127
+ }
128
+
129
+ // Validate the KEEP batch BEFORE the archive append (dry-run rewrite: throws
130
+ // on a bad record, writes nothing). Without this, an invalid-but-parseable
131
+ // KEEP record survives readLearnings() but blows up rewriteLearnings() later
132
+ // — AFTER the archive append already landed. On a repeated --apply run that
133
+ // duplicates the archive append every time (never de-duplicated on read)
134
+ // while the store is never actually pruned. Validating first means a bad
135
+ // record throws here, before anything on disk has been touched.
136
+ await rewriteLearnings(filePath, keep, { dryRun: true });
137
+
138
+ // Crash-safe ordering: archive append FIRST. A duplicate re-append after a
139
+ // crash is harmless (append-only, never de-duplicated on read); the reverse
140
+ // order risks losing an archive-worthy entry if the process dies after the
141
+ // store rewrite but before the archive write.
142
+ if (archiveCandidates.length > 0) {
143
+ const nowIso = new Date(nowMs).toISOString();
144
+ const body =
145
+ archiveCandidates
146
+ .map((e) => JSON.stringify({ ...e, _archived_at: nowIso, _archive_reason: 'expired' }))
147
+ .join('\n') + '\n';
148
+ await mkdir(path.dirname(archivePath), { recursive: true });
149
+ await appendFile(archivePath, body, 'utf8');
150
+ }
151
+
152
+ // Re-validates (cheap, idempotent) and snapshots a `.bak-<ISO>` backup of
153
+ // the current store before the atomic rename (io.mjs #721). The KEEP batch
154
+ // already passed the dry-run probe above, so this call cannot throw here.
155
+ await rewriteLearnings(filePath, keep, { dryRun: false });
156
+
157
+ return {
158
+ scanned: entries.length,
159
+ kept: keep.length,
160
+ archived: archiveCandidates.length,
161
+ dryRun: false,
162
+ archivePath,
163
+ };
164
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * learnings/filters.mjs — filtering helpers for learnings entries.
3
+ *
4
+ * Extracted from scripts/lib/learnings.mjs (issue #358).
5
+ * Depends on normalizeLearning from the schema layer in the parent module.
6
+ */
7
+
8
+ import { normalizeLearning } from './schema.mjs';
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Filtering helpers (used by C3 export + /evolve hardware-pattern queries)
12
+ // ---------------------------------------------------------------------------
13
+
14
+ /**
15
+ * Filter learnings by scope. Returns a new array.
16
+ * @param {object[]} entries
17
+ * @param {string|string[]} scope
18
+ * @returns {object[]}
19
+ */
20
+ export function filterByScope(entries, scope) {
21
+ const scopes = Array.isArray(scope) ? scope : [scope];
22
+ return entries.filter((e) => scopes.includes(normalizeLearning(e).scope));
23
+ }
24
+
25
+ /**
26
+ * Filter learnings by host_class. Returns a new array.
27
+ * @param {object[]} entries
28
+ * @param {string} hostClass
29
+ * @returns {object[]}
30
+ */
31
+ export function filterByHostClass(entries, hostClass) {
32
+ return entries.filter((e) => normalizeLearning(e).host_class === hostClass);
33
+ }
34
+
35
+ /**
36
+ * Filter learnings by type.
37
+ * @param {object[]} entries
38
+ * @param {string} type
39
+ * @returns {object[]}
40
+ */
41
+ export function filterByType(entries, type) {
42
+ return entries.filter((e) => e.type === type);
43
+ }