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,190 @@
1
+ /**
2
+ * evaluate.mjs — verdict + threshold logic for resource snapshots.
3
+ *
4
+ * Evaluates a snapshot (output of probe()) against `resource-thresholds`
5
+ * from Session Config (#166) and returns a verdict used by session-start Phase 4.5.
6
+ *
7
+ * Part of v3.1.0 Epic #157 / Issue #163.
8
+ * Extended in v3.2 Phase C-2 (#296): swap + memory_pressure verdict rules.
9
+ * Zombie rule wired end-to-end in #178.
10
+ * Split from resource-probe.mjs in #287 (hotspot 2/2).
11
+ */
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Verdict precedence helper
15
+ // ---------------------------------------------------------------------------
16
+
17
+ const VERDICT_RANK = { green: 0, warn: 1, degraded: 2, critical: 3 };
18
+
19
+ /**
20
+ * Return the more restrictive of two verdicts.
21
+ * @param {string} current
22
+ * @param {string} target
23
+ * @returns {string}
24
+ */
25
+ function bumpVerdict(current, target) {
26
+ const currentRank = VERDICT_RANK[current] ?? 0;
27
+ const targetRank = VERDICT_RANK[target] ?? 0;
28
+ return targetRank > currentRank ? target : current;
29
+ }
30
+
31
+ /**
32
+ * macOS healthy-pressure threshold. When `memory_pressure_pct_free` ≥ this value,
33
+ * the OS reports that compressor + caches are doing their job, and `ram_free_gb`
34
+ * (which on macOS reflects only `Pages free`, not `inactive`) is misleading
35
+ * — the system has plenty of reclaimable memory. We suppress free-RAM-only
36
+ * verdict-bumps in that regime.
37
+ *
38
+ * Source: Apple Activity Monitor uses memory_pressure as the canonical health
39
+ * indicator since 10.9 Mavericks. See OSXDaily (2026-04) + Apple developer docs
40
+ * "Viewing Virtual Memory Usage". Threshold 30% matches the green/yellow
41
+ * boundary rendered by Activity Monitor (yellow at 30..50%, red at <30%).
42
+ */
43
+ const MACOS_HEALTHY_PRESSURE_PCT = 30;
44
+
45
+ /**
46
+ * Evaluate a snapshot against `resource-thresholds` (from Session Config #166)
47
+ * and return a verdict used by session-start Phase 4.5.
48
+ * @param {object} snapshot — output of probe()
49
+ * @param {object} thresholds — resource-thresholds block from parseSessionConfig
50
+ * @returns {{verdict: 'green'|'warn'|'degraded'|'critical', reasons: string[], recommended_agents_per_wave_cap: number|null}}
51
+ */
52
+ export function evaluate(snapshot, thresholds) {
53
+ const reasons = [];
54
+ let verdict = 'green';
55
+ let cap = null;
56
+
57
+ const { ram_free_gb, cpu_load_pct, claude_processes_count, memory_pressure_pct_free, ram_available_gb } = snapshot;
58
+ const {
59
+ 'ram-free-min-gb': ramMin,
60
+ 'ram-free-critical-gb': ramCrit,
61
+ 'cpu-load-max-pct': cpuMax,
62
+ 'concurrent-sessions-warn': concWarn,
63
+ } = thresholds;
64
+
65
+ // On macOS, `os.freemem()` reports only `Pages free` (excludes `inactive`),
66
+ // so `ram_free_gb` regularly reads sub-1 GB even when the system has 80+ GB
67
+ // reclaimable. The robust fix (#667): when `ram_available_gb` (free +
68
+ // inactive + speculative + purgeable, derived from vm_stat) is present, judge
69
+ // RAM-criticality on AVAILABLE rather than FREE. The `memory_pressure`
70
+ // healthy-suppression below is retained as a secondary guard for the case
71
+ // where vm_stat is unavailable but memory_pressure still reports.
72
+ const hasAvailable =
73
+ ram_available_gb !== null && ram_available_gb !== undefined;
74
+ const effectiveRamGb = hasAvailable ? ram_available_gb : ram_free_gb;
75
+ const ramLabel = hasAvailable ? 'RAM available' : 'RAM free';
76
+
77
+ const macosPressureHealthy =
78
+ memory_pressure_pct_free !== null &&
79
+ memory_pressure_pct_free !== undefined &&
80
+ memory_pressure_pct_free >= MACOS_HEALTHY_PRESSURE_PCT;
81
+
82
+ if (!macosPressureHealthy) {
83
+ if (effectiveRamGb < ramCrit) {
84
+ verdict = 'critical';
85
+ cap = 0;
86
+ reasons.push(`${ramLabel} ${effectiveRamGb.toFixed(1)} GB below critical threshold ${ramCrit} GB — recommend coordinator-direct (0 agents).`);
87
+ } else if (effectiveRamGb < ramMin) {
88
+ if (verdict === 'green') verdict = 'warn';
89
+ cap = cap === null ? 2 : Math.min(cap, 2);
90
+ reasons.push(`${ramLabel} ${effectiveRamGb.toFixed(1)} GB below threshold ${ramMin} GB — capping agents-per-wave at 2.`);
91
+ }
92
+ } else {
93
+ reasons.push(`macOS memory_pressure healthy (${memory_pressure_pct_free}% free ≥ ${MACOS_HEALTHY_PRESSURE_PCT}%) — free-RAM signal suppressed (Pages-free underreports on Darwin).`);
94
+ }
95
+
96
+ if (cpu_load_pct > cpuMax) {
97
+ if (verdict === 'green') verdict = 'warn';
98
+ cap = cap === null ? 2 : Math.min(cap, 2);
99
+ reasons.push(`CPU load ${cpu_load_pct}% above threshold ${cpuMax}% — capping agents-per-wave at 2.`);
100
+ }
101
+
102
+ if (claude_processes_count !== null && claude_processes_count !== undefined && claude_processes_count >= concWarn) {
103
+ if (verdict === 'green') verdict = 'warn';
104
+ reasons.push(`${claude_processes_count} Claude processes already running (threshold: ${concWarn}) — consider sequencing this session after others finish.`);
105
+ }
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // Zombie signal (#178): null = feature disabled (zombieThresholdMin absent) → no rule fires
109
+ // Escalates to warn only when BOTH zombie_processes_count >= 1 AND
110
+ // claude_processes_count is elevated (>= concWarn or > 0 with zombies).
111
+ // ---------------------------------------------------------------------------
112
+ const { zombie_processes_count } = snapshot;
113
+ if (zombie_processes_count !== null && zombie_processes_count !== undefined && zombie_processes_count >= 1) {
114
+ const claudeElevated =
115
+ claude_processes_count !== null &&
116
+ claude_processes_count !== undefined &&
117
+ claude_processes_count > 0;
118
+ if (claudeElevated) {
119
+ verdict = bumpVerdict(verdict, 'warn');
120
+ reasons.push(`${zombie_processes_count} zombie Claude/Node process(es) detected (age > ${thresholds['zombie-threshold-min'] ?? 30} min, idle CPU) with ${claude_processes_count} Claude process(es) running — consider sweeping stale sessions.`);
121
+ }
122
+ }
123
+
124
+ // ---------------------------------------------------------------------------
125
+ // Swap signal (macOS / Linux only; null = signal unavailable → no rule fires)
126
+ // On macOS, swap is accumulated over time and is not a real-time pressure
127
+ // indicator — Activity Monitor reports it under "Used" but classifies system
128
+ // health via memory_pressure, not swap volume. So when pressure is healthy,
129
+ // swap signal is treated as informational only (downgrades critical→warn).
130
+ // ---------------------------------------------------------------------------
131
+ const { swap_used_mb } = snapshot;
132
+ if (swap_used_mb !== null && swap_used_mb !== undefined) {
133
+ if (swap_used_mb > 3072 && !macosPressureHealthy) {
134
+ verdict = bumpVerdict(verdict, 'critical');
135
+ cap = 0;
136
+ reasons.push(`Swap usage ${swap_used_mb} MB above critical threshold 3072 MB — recommend coordinator-direct (0 agents).`);
137
+ } else if (swap_used_mb > 2048 && !macosPressureHealthy) {
138
+ const newVerdict = bumpVerdict(verdict, 'degraded');
139
+ if (newVerdict !== verdict) {
140
+ verdict = newVerdict;
141
+ cap = cap === null ? 2 : Math.min(cap, 2);
142
+ }
143
+ reasons.push(`Swap usage ${swap_used_mb} MB in degraded range (2048..3072 MB) — capping agents-per-wave at 2.`);
144
+ } else if (swap_used_mb > 1024 && !macosPressureHealthy) {
145
+ const newVerdict = bumpVerdict(verdict, 'warn');
146
+ if (newVerdict !== verdict) {
147
+ verdict = newVerdict;
148
+ cap = cap === null ? 2 : Math.min(cap, 2);
149
+ }
150
+ reasons.push(`Swap usage ${swap_used_mb} MB in warn range (1024..2048 MB) — capping agents-per-wave at 2.`);
151
+ } else if (swap_used_mb > 1024 && macosPressureHealthy) {
152
+ // Informational only: pressure says system is healthy, swap is historical.
153
+ reasons.push(`Swap usage ${swap_used_mb} MB present but macOS memory_pressure healthy — treating as informational (no cap).`);
154
+ }
155
+ }
156
+
157
+ // ---------------------------------------------------------------------------
158
+ // macOS memory_pressure signal (null = signal unavailable → no rule fires)
159
+ // (memory_pressure_pct_free already destructured at the top of this fn)
160
+ // ---------------------------------------------------------------------------
161
+ if (memory_pressure_pct_free !== null && memory_pressure_pct_free !== undefined) {
162
+ if (memory_pressure_pct_free < 5) {
163
+ verdict = bumpVerdict(verdict, 'critical');
164
+ cap = 0;
165
+ reasons.push(`macOS memory_pressure free ${memory_pressure_pct_free}% below critical threshold 5% — recommend coordinator-direct (0 agents).`);
166
+ } else if (memory_pressure_pct_free < 15) {
167
+ const newVerdict = bumpVerdict(verdict, 'degraded');
168
+ if (newVerdict !== verdict) {
169
+ verdict = newVerdict;
170
+ cap = cap === null ? 2 : Math.min(cap, 2);
171
+ }
172
+ reasons.push(`macOS memory_pressure free ${memory_pressure_pct_free}% in degraded range (5..15%) — capping agents-per-wave at 2.`);
173
+ } else if (memory_pressure_pct_free < 30) {
174
+ const newVerdict = bumpVerdict(verdict, 'warn');
175
+ if (newVerdict !== verdict) {
176
+ verdict = newVerdict;
177
+ cap = cap === null ? 2 : Math.min(cap, 2);
178
+ }
179
+ reasons.push(`macOS memory_pressure free ${memory_pressure_pct_free}% in warn range (15..30%) — capping agents-per-wave at 2.`);
180
+ }
181
+ }
182
+
183
+ // Ensure cap aligns with final verdict when critical was triggered by swap/memory_pressure
184
+ // (the bumpVerdict path sets cap=0 inline for critical, but re-affirm for safety)
185
+ if (verdict === 'critical') {
186
+ cap = 0;
187
+ }
188
+
189
+ return { verdict, reasons, recommended_agents_per_wave_cap: cap };
190
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * parsers.mjs — pure output-parser helpers for resource-probe signals.
3
+ *
4
+ * All functions are pure (no I/O) and exported for unit testability.
5
+ * Consumed by probe-platform.mjs and re-exported from resource-probe.mjs.
6
+ *
7
+ * Part of v3.1.0 Epic #157 / Issue #163.
8
+ * Extended in v3.2 Phase C-2 (#296): swap_used_mb + memory_pressure_pct_free parsers.
9
+ * Split from resource-probe.mjs in #287 (hotspot 2/2).
10
+ */
11
+
12
+ /**
13
+ * Parse a `ps` etime field (`[[DD-]HH:]MM:SS`) into whole minutes.
14
+ * Returns null when the format is unrecognised.
15
+ * Pure function for unit testability.
16
+ * @param {string} etime
17
+ * @returns {number|null}
18
+ */
19
+ export function parseEtimeToMinutes(etime) {
20
+ if (typeof etime !== 'string') return null;
21
+ const s = etime.trim();
22
+ // Regex: optional "DD-", optional "HH:", then "MM:SS"
23
+ const m = /^(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+)$/.exec(s);
24
+ if (!m) return null;
25
+ const days = parseInt(m[1] ?? '0', 10);
26
+ const hours = parseInt(m[2] ?? '0', 10);
27
+ const mins = parseInt(m[3], 10);
28
+ // seconds intentionally dropped (we only need minutes resolution)
29
+ if ([days, hours, mins].some(Number.isNaN)) return null;
30
+ return days * 24 * 60 + hours * 60 + mins;
31
+ }
32
+
33
+ /**
34
+ * Parse the detailed ps output and count Claude/Node zombie candidates.
35
+ * A zombie candidate is a process matching "claude" or "node" that:
36
+ * - has been running longer than `thresholdMin` minutes, AND
37
+ * - has CPU% at or below `maxCpuPct` (default 1.0 → idle).
38
+ * Pure function for unit testability.
39
+ * @param {string|null} psOutput — stdout from `ps -A -o pid,comm,etime,%cpu`
40
+ * @param {number} thresholdMin — age threshold in minutes
41
+ * @param {number} [maxCpuPct] — CPU% at-or-below which process is considered idle (default 1.0)
42
+ * @returns {number|null} count, or null when psOutput is null
43
+ */
44
+ export function countZombieProcesses(psOutput, thresholdMin, maxCpuPct = 1.0) {
45
+ if (psOutput === null || psOutput === undefined) return null;
46
+ const lines = String(psOutput).split(/\r?\n/);
47
+ let count = 0;
48
+ for (const raw of lines) {
49
+ const trimmed = raw.trim();
50
+ if (!trimmed || /^\s*PID/i.test(trimmed)) continue; // skip header
51
+ // Fields: PID COMM ELAPSED %CPU (ELAPSED may contain '-' and ':')
52
+ // Split on whitespace but preserve etime which has no spaces.
53
+ const parts = trimmed.split(/\s+/);
54
+ if (parts.length < 4) continue;
55
+ // parts[0]=PID, parts[1]=COMM, parts[2]=ETIME, parts[3]=%CPU
56
+ const comm = (parts[1] ?? '').toLowerCase();
57
+ const etimeStr = parts[2] ?? '';
58
+ const cpuStr = parts[3] ?? '';
59
+ const isClaudeOrNode =
60
+ /(^|[\s/])claude([\s]|$)/.test(comm) ||
61
+ comm === 'claude' ||
62
+ /(^|[\s/])node([\s]|$)/.test(comm) ||
63
+ comm === 'node';
64
+ if (!isClaudeOrNode) continue;
65
+ const ageMin = parseEtimeToMinutes(etimeStr);
66
+ if (ageMin === null || ageMin < thresholdMin) continue;
67
+ const cpu = parseFloat(cpuStr);
68
+ if (Number.isNaN(cpu) || cpu > maxCpuPct) continue;
69
+ count++;
70
+ }
71
+ return count;
72
+ }
73
+
74
+ /**
75
+ * Parse a raw process listing (ps or tasklist output) and count matches.
76
+ * Pure function for unit testability.
77
+ * @param {string|null} psOutput
78
+ * @param {Array<{key: string, match: (line: string) => boolean}>} patterns
79
+ * @returns {Record<string, number>|null}
80
+ */
81
+ export function countProcessMatches(psOutput, patterns) {
82
+ if (psOutput === null || psOutput === undefined) return null;
83
+ const lines = String(psOutput).split(/\r?\n/);
84
+ const counts = Object.fromEntries(patterns.map((p) => [p.key, 0]));
85
+ for (const raw of lines) {
86
+ const line = raw.toLowerCase();
87
+ for (const p of patterns) {
88
+ if (p.match(line)) counts[p.key] += 1;
89
+ }
90
+ }
91
+ return counts;
92
+ }
93
+
94
+ /**
95
+ * Parse `sysctl vm.swapusage` output (macOS) and return used MB as integer.
96
+ * Pure function for unit testability.
97
+ * @param {string} text
98
+ * @returns {number|null}
99
+ */
100
+ export function parseSwapUsageOutput(text) {
101
+ if (text === null || text === undefined) return null;
102
+ // Sample: "vm.swapusage: total = 4096.00M used = 1234.50M free = 2861.50M"
103
+ const match = /used\s*=\s*([\d.]+)M/i.exec(String(text));
104
+ if (!match) return null;
105
+ const mb = parseFloat(match[1]);
106
+ if (Number.isNaN(mb)) return null;
107
+ return Math.round(mb);
108
+ }
109
+
110
+ /**
111
+ * Parse `memory_pressure` output (macOS) and return the free percentage as integer.
112
+ * Pure function for unit testability.
113
+ * @param {string} text
114
+ * @returns {number|null}
115
+ */
116
+ export function parseMemoryPressureOutput(text) {
117
+ if (text === null || text === undefined) return null;
118
+ // Sample: "System-wide memory free percentage: 42%"
119
+ const match = /System-wide memory free percentage:\s*(\d+)%/i.exec(String(text));
120
+ if (!match) return null;
121
+ const pct = parseInt(match[1], 10);
122
+ if (Number.isNaN(pct)) return null;
123
+ return pct;
124
+ }
125
+
126
+ /**
127
+ * Parse `vm_stat` output (macOS) and compute AVAILABLE RAM in GB.
128
+ *
129
+ * macOS treats most physical RAM as reclaimable cache, so `os.freemem()` (which
130
+ * reflects only `Pages free`) regularly reads sub-1 GB on a machine with 100+ GB
131
+ * of genuinely reclaimable headroom. The correct "how much can a new process
132
+ * actually claim?" estimate is:
133
+ *
134
+ * available = (free + inactive + speculative + purgeable) × page_size
135
+ *
136
+ * - `Pages free` — immediately allocatable.
137
+ * - `Pages inactive` — clean/dirty pages on the inactive queue, reclaimable
138
+ * under pressure (the macOS file/anon cache).
139
+ * - `Pages speculative` — read-ahead pages, dropped first under pressure.
140
+ * - `Pages purgeable` — volatile pages the kernel may discard on demand.
141
+ *
142
+ * `File-backed pages` overlaps the inactive queue, so it is intentionally NOT
143
+ * added (would double-count). This mirrors how Activity Monitor derives "free"
144
+ * memory and matches the formula in the issue spec (#667).
145
+ *
146
+ * Pure function for unit testability.
147
+ * @param {string} text — stdout from `vm_stat`
148
+ * @returns {number|null} available GB rounded to 1 decimal, or null on parse failure
149
+ */
150
+ export function parseVmStatAvailableGb(text) {
151
+ if (text === null || text === undefined) return null;
152
+ const str = String(text);
153
+ // Page size is reported in the header: "page size of 16384 bytes".
154
+ const psMatch = /page size of (\d+) bytes/i.exec(str);
155
+ if (!psMatch) return null;
156
+ const pageSize = parseInt(psMatch[1], 10);
157
+ if (Number.isNaN(pageSize) || pageSize <= 0) return null;
158
+
159
+ // Each line looks like "Pages free: 10794." — value followed by a period.
160
+ const pagesFor = (label) => {
161
+ const re = new RegExp(`${label}:\\s+(\\d+)\\.`, 'i');
162
+ const m = re.exec(str);
163
+ if (!m) return null;
164
+ const n = parseInt(m[1], 10);
165
+ return Number.isNaN(n) ? null : n;
166
+ };
167
+
168
+ const free = pagesFor('Pages free');
169
+ const inactive = pagesFor('Pages inactive');
170
+ // `Pages free` and `Pages inactive` are the load-bearing terms; if either is
171
+ // absent the output is not recognisable vm_stat and we bail.
172
+ if (free === null || inactive === null) return null;
173
+
174
+ // speculative + purgeable are smaller reclaimable buckets; treat absent as 0.
175
+ const speculative = pagesFor('Pages speculative') ?? 0;
176
+ const purgeable = pagesFor('Pages purgeable') ?? 0;
177
+
178
+ const availablePages = free + inactive + speculative + purgeable;
179
+ const availableGb = (availablePages * pageSize) / 1024 ** 3;
180
+ return Math.round(availableGb * 10) / 10;
181
+ }
@@ -0,0 +1,300 @@
1
+ /**
2
+ * probe-platform.mjs — platform-specific resource sampling (RAM, CPU, processes, swap).
3
+ *
4
+ * Handles all async I/O: spawning `ps`/`tasklist`, reading `/proc/meminfo`,
5
+ * calling `sysctl`, `memory_pressure`. Pure parsing is delegated to parsers.mjs.
6
+ *
7
+ * Part of v3.1.0 Epic #157 / Issue #163.
8
+ * Extended in v3.2 Phase C-2 (#296): swap_used_mb + memory_pressure_pct_free signals.
9
+ * Split from resource-probe.mjs in #287 (hotspot 2/2).
10
+ */
11
+
12
+ import os from 'node:os';
13
+ import { spawn } from 'node:child_process';
14
+ import { SO_IS_WINDOWS } from '../platform.mjs';
15
+ import {
16
+ countProcessMatches,
17
+ countZombieProcesses,
18
+ parseSwapUsageOutput,
19
+ parseMemoryPressureOutput,
20
+ parseVmStatAvailableGb,
21
+ } from './parsers.mjs';
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // RAM / CPU primitives (synchronous, via Node os module)
25
+ // ---------------------------------------------------------------------------
26
+
27
+ /**
28
+ * @returns {{ ram_free_gb: number, ram_used_pct: number }}
29
+ */
30
+ export function ramSnapshot() {
31
+ const total = os.totalmem();
32
+ const free = os.freemem();
33
+ const usedPct = Math.round(((total - free) / total) * 100);
34
+ const freeGb = Math.round((free / (1024 * 1024 * 1024)) * 10) / 10;
35
+ return { ram_free_gb: freeGb, ram_used_pct: usedPct };
36
+ }
37
+
38
+ /**
39
+ * Derive CPU usage percentage from per-core times (used on Windows and when
40
+ * load-average is 0).
41
+ * @returns {number} 0-100
42
+ */
43
+ function cpuPctFromTimes() {
44
+ const cpus = os.cpus() || [];
45
+ if (cpus.length === 0) return 0;
46
+ let totalBusy = 0;
47
+ let total = 0;
48
+ for (const c of cpus) {
49
+ const t = c.times;
50
+ const busy = t.user + t.nice + t.sys + t.irq;
51
+ totalBusy += busy;
52
+ total += busy + t.idle;
53
+ }
54
+ if (total === 0) return 0;
55
+ return Math.min(100, Math.round((totalBusy / total) * 100));
56
+ }
57
+
58
+ /**
59
+ * @returns {{ cpu_load_1m: number, cpu_load_pct: number }}
60
+ */
61
+ export function cpuSnapshot() {
62
+ const load1m = os.loadavg()[0];
63
+ const cores = (os.cpus() || []).length || 1;
64
+ // load-average is a Unix concept and reports 0 on Windows. When zero, we
65
+ // fall back to per-core user+sys % derived from cpus() times (still rough,
66
+ // but non-zero on Windows so the threshold logic has a signal).
67
+ let loadPct;
68
+ if (SO_IS_WINDOWS || load1m === 0) {
69
+ loadPct = cpuPctFromTimes();
70
+ } else {
71
+ loadPct = Math.min(100, Math.round((load1m / cores) * 100));
72
+ }
73
+ return { cpu_load_1m: Math.round(load1m * 10) / 10, cpu_load_pct: loadPct };
74
+ }
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Process listing helpers (async, shell-based)
78
+ // ---------------------------------------------------------------------------
79
+
80
+ /**
81
+ * Run a command and collect stdout, with a timeout. Returns null on failure.
82
+ * @param {string} cmd
83
+ * @param {string[]} args
84
+ * @param {number} timeoutMs
85
+ * @returns {Promise<string|null>}
86
+ */
87
+ export function runCommand(cmd, args, timeoutMs = 1500) {
88
+ return new Promise((resolve) => {
89
+ let settled = false;
90
+ const finish = (value) => {
91
+ if (settled) return;
92
+ settled = true;
93
+ resolve(value);
94
+ };
95
+ try {
96
+ const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'ignore'] });
97
+ const chunks = [];
98
+ child.stdout.on('data', (c) => chunks.push(c));
99
+ child.on('error', () => finish(null));
100
+ child.on('close', (code) => {
101
+ if (code !== 0) return finish(null);
102
+ finish(Buffer.concat(chunks).toString('utf8'));
103
+ });
104
+ setTimeout(() => {
105
+ try { child.kill('SIGKILL'); } catch { /* ignore */ }
106
+ finish(null);
107
+ }, timeoutMs);
108
+ } catch {
109
+ finish(null);
110
+ }
111
+ });
112
+ }
113
+
114
+ /**
115
+ * Run `ps -A -o comm` (or `tasklist` on Windows) and return stdout, or null on failure.
116
+ * @param {number} [timeoutMs]
117
+ * @returns {Promise<string|null>}
118
+ */
119
+ function runPs(timeoutMs = 2000) {
120
+ return new Promise((resolve) => {
121
+ let settled = false;
122
+ const finish = (value) => {
123
+ if (settled) return;
124
+ settled = true;
125
+ resolve(value);
126
+ };
127
+ try {
128
+ const cmd = SO_IS_WINDOWS ? 'tasklist' : 'ps';
129
+ const args = SO_IS_WINDOWS
130
+ ? ['/FO', 'CSV', '/NH']
131
+ : ['-A', '-o', 'comm'];
132
+ const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'ignore'] });
133
+ const chunks = [];
134
+ child.stdout.on('data', (c) => chunks.push(c));
135
+ child.on('error', () => finish(null));
136
+ child.on('close', (code) => {
137
+ if (code !== 0) return finish(null);
138
+ finish(Buffer.concat(chunks).toString('utf8'));
139
+ });
140
+ setTimeout(() => {
141
+ try { child.kill('SIGKILL'); } catch { /* ignore */ }
142
+ finish(null);
143
+ }, timeoutMs);
144
+ } catch {
145
+ finish(null);
146
+ }
147
+ });
148
+ }
149
+
150
+ /**
151
+ * Run `ps` collecting PID, command name, elapsed time, and CPU% — used for zombie detection.
152
+ * Returns raw stdout string or null on failure.
153
+ * @param {number} [timeoutMs]
154
+ * @returns {Promise<string|null>}
155
+ */
156
+ function runPsDetailed(timeoutMs = 2000) {
157
+ return new Promise((resolve) => {
158
+ if (SO_IS_WINDOWS) { resolve(null); return; }
159
+ let settled = false;
160
+ const finish = (value) => {
161
+ if (settled) return;
162
+ settled = true;
163
+ resolve(value);
164
+ };
165
+ try {
166
+ // -A: all processes; output: pid, comm (basename), etime, %cpu
167
+ const child = spawn('ps', ['-A', '-o', 'pid,comm,etime,%cpu'], { stdio: ['ignore', 'pipe', 'ignore'] });
168
+ const chunks = [];
169
+ child.stdout.on('data', (c) => chunks.push(c));
170
+ child.on('error', () => finish(null));
171
+ child.on('close', (code) => {
172
+ if (code !== 0) return finish(null);
173
+ finish(Buffer.concat(chunks).toString('utf8'));
174
+ });
175
+ setTimeout(() => {
176
+ try { child.kill('SIGKILL'); } catch { /* ignore */ }
177
+ finish(null);
178
+ }, timeoutMs);
179
+ } catch {
180
+ finish(null);
181
+ }
182
+ });
183
+ }
184
+
185
+ // ---------------------------------------------------------------------------
186
+ // Process pattern matching defaults
187
+ // ---------------------------------------------------------------------------
188
+
189
+ export const DEFAULT_PATTERNS = [
190
+ {
191
+ key: 'claude',
192
+ // Matches the `claude` CLI process plus `Claude Code` macOS app names.
193
+ match: (l) => /(^|[\s/,"])claude([\s",]|$)/.test(l) || l.includes('claude code') || l.includes('claude.app'),
194
+ },
195
+ {
196
+ key: 'codex',
197
+ match: (l) => /(^|[\s/,"])codex([\s",]|$)/.test(l) || l.includes('codex cli'),
198
+ },
199
+ {
200
+ key: 'other_node',
201
+ // All node processes; caller subtracts claude/codex-related node procs.
202
+ match: (l) => /(^|[\s/,"])node([\s",]|$)/.test(l),
203
+ },
204
+ ];
205
+
206
+ /**
207
+ * Collect process counts (claude, codex, node) and optionally zombie count.
208
+ * @param {number|null} [zombieThresholdMin]
209
+ * @returns {Promise<{ claude_processes_count: number|null, codex_processes_count: number|null, other_node_processes: number|null, zombie_processes_count: number|null }>}
210
+ */
211
+ export async function processCounts(zombieThresholdMin = null) {
212
+ // Run simple ps (for counts) and detailed ps (for zombie detection) in parallel.
213
+ const [output, detailedOutput] = await Promise.all([
214
+ runPs(),
215
+ zombieThresholdMin !== null ? runPsDetailed() : Promise.resolve(null),
216
+ ]);
217
+ if (output === null || output === undefined) {
218
+ return {
219
+ claude_processes_count: null,
220
+ codex_processes_count: null,
221
+ other_node_processes: null,
222
+ zombie_processes_count: null,
223
+ };
224
+ }
225
+ const raw = countProcessMatches(output, DEFAULT_PATTERNS);
226
+ // Subtract self (the currently running probe process counts as 1 node).
227
+ const otherNode = Math.max(0, (raw.other_node ?? 0) - 1);
228
+ const zombie_processes_count =
229
+ zombieThresholdMin !== null
230
+ ? countZombieProcesses(detailedOutput, zombieThresholdMin)
231
+ : null;
232
+ return {
233
+ claude_processes_count: raw.claude ?? 0,
234
+ codex_processes_count: raw.codex ?? 0,
235
+ other_node_processes: otherNode,
236
+ zombie_processes_count,
237
+ };
238
+ }
239
+
240
+ // ---------------------------------------------------------------------------
241
+ // Swap usage (async, spawn-based) — macOS + Linux only
242
+ // ---------------------------------------------------------------------------
243
+
244
+ /**
245
+ * Probe swap usage. Returns used MB as integer, or null on unsupported/failure.
246
+ * @returns {Promise<number|null>}
247
+ */
248
+ export async function swapUsedMb() {
249
+ if (SO_IS_WINDOWS) return null;
250
+
251
+ if (process.platform === 'darwin') {
252
+ const output = await runCommand('sysctl', ['vm.swapusage']);
253
+ return parseSwapUsageOutput(output);
254
+ }
255
+
256
+ if (process.platform === 'linux') {
257
+ // Read /proc/meminfo and compute SwapTotal - SwapFree (values in kB)
258
+ const output = await runCommand('cat', ['/proc/meminfo']);
259
+ if (output === null) return null;
260
+ const totalMatch = /SwapTotal:\s*(\d+)\s*kB/i.exec(output);
261
+ const freeMatch = /SwapFree:\s*(\d+)\s*kB/i.exec(output);
262
+ if (!totalMatch || !freeMatch) return null;
263
+ const totalKb = parseInt(totalMatch[1], 10);
264
+ const freeKb = parseInt(freeMatch[1], 10);
265
+ if (Number.isNaN(totalKb) || Number.isNaN(freeKb)) return null;
266
+ return Math.round((totalKb - freeKb) / 1024);
267
+ }
268
+
269
+ return null;
270
+ }
271
+
272
+ /**
273
+ * Probe macOS memory_pressure free percentage. Returns integer 0..100, or null.
274
+ * @returns {Promise<number|null>}
275
+ */
276
+ export async function memoryPressurePctFree() {
277
+ if (process.platform !== 'darwin') return null;
278
+
279
+ const output = await runCommand('memory_pressure', []);
280
+ return parseMemoryPressureOutput(output);
281
+ }
282
+
283
+ /**
284
+ * Probe macOS AVAILABLE RAM (free + reclaimable) via `vm_stat`.
285
+ *
286
+ * On macOS, `os.freemem()` reflects only `Pages free` and routinely reads
287
+ * sub-1 GB even when 100+ GB is reclaimable cache. This derives the real
288
+ * headroom from vm_stat (see parseVmStatAvailableGb for the page-class formula).
289
+ *
290
+ * Darwin-only — returns null on Linux/Windows/unknown (those platforms already
291
+ * surface an accurate `os.freemem()`, so no override is needed) or on
292
+ * spawn/parse failure.
293
+ * @returns {Promise<number|null>} available GB rounded to 1 decimal, or null
294
+ */
295
+ export async function ramAvailableGb() {
296
+ if (process.platform !== 'darwin') return null;
297
+
298
+ const output = await runCommand('vm_stat', []);
299
+ return parseVmStatAvailableGb(output);
300
+ }