session-orchestrator 3.23.0 → 4.0.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 (393) hide show
  1. package/.agents/skills/architecture/SKILL.md +18 -0
  2. package/.agents/skills/autopilot/SKILL.md +17 -0
  3. package/.agents/skills/bootstrap/SKILL.md +20 -0
  4. package/.agents/skills/brainstorm/SKILL.md +22 -0
  5. package/.agents/skills/claude-md-drift-check/SKILL.md +15 -0
  6. package/.agents/skills/convergence-monitoring/SKILL.md +22 -0
  7. package/.agents/skills/debug/SKILL.md +22 -0
  8. package/.agents/skills/discovery/SKILL.md +20 -0
  9. package/.agents/skills/dispatcher/SKILL.md +15 -0
  10. package/.agents/skills/docs-orchestrator/SKILL.md +18 -0
  11. package/.agents/skills/ecosystem-health/SKILL.md +20 -0
  12. package/.agents/skills/eli5/SKILL.md +20 -0
  13. package/.agents/skills/eval/SKILL.md +21 -0
  14. package/.agents/skills/evolve/SKILL.md +21 -0
  15. package/.agents/skills/frontmatter-guard/SKILL.md +15 -0
  16. package/.agents/skills/gitlab-ops/SKILL.md +20 -0
  17. package/.agents/skills/gitlab-portfolio/SKILL.md +15 -0
  18. package/.agents/skills/grill/SKILL.md +22 -0
  19. package/.agents/skills/hook-development/SKILL.md +15 -0
  20. package/.agents/skills/mcp-builder/SKILL.md +15 -0
  21. package/.agents/skills/memory-cleanup/SKILL.md +21 -0
  22. package/.agents/skills/mode-selector/SKILL.md +17 -0
  23. package/.agents/skills/npm-publish/SKILL.md +16 -0
  24. package/.agents/skills/peekaboo-driver/SKILL.md +18 -0
  25. package/.agents/skills/persona-panel/SKILL.md +17 -0
  26. package/.agents/skills/plan/SKILL.md +20 -0
  27. package/.agents/skills/playwright-driver/SKILL.md +20 -0
  28. package/.agents/skills/quality-gates/SKILL.md +20 -0
  29. package/.agents/skills/reconcile/SKILL.md +21 -0
  30. package/.agents/skills/remote-offload/SKILL.md +20 -0
  31. package/.agents/skills/repo-audit/SKILL.md +16 -0
  32. package/.agents/skills/session-end/SKILL.md +20 -0
  33. package/.agents/skills/session-plan/SKILL.md +20 -0
  34. package/.agents/skills/session-start/SKILL.md +20 -0
  35. package/.agents/skills/spinout/SKILL.md +16 -0
  36. package/.agents/skills/sunset-review/SKILL.md +16 -0
  37. package/.agents/skills/test-runner/SKILL.md +20 -0
  38. package/.agents/skills/tmux-layout/SKILL.md +21 -0
  39. package/.agents/skills/using-orchestrator/SKILL.md +17 -0
  40. package/.agents/skills/vault-mirror/SKILL.md +15 -0
  41. package/.agents/skills/vault-sync/SKILL.md +15 -0
  42. package/.agents/skills/wave-executor/SKILL.md +20 -0
  43. package/.agents/skills/write-executable-plan/SKILL.md +22 -0
  44. package/.claude-plugin/marketplace.json +1 -1
  45. package/.claude-plugin/plugin.json +1 -1
  46. package/.codex-plugin/plugin.json +1 -1
  47. package/.cursor/commands/autopilot.md +2 -2
  48. package/.cursor/commands/bootstrap.md +1 -1
  49. package/.cursor/commands/brainstorm.md +1 -1
  50. package/.cursor/commands/debug.md +1 -1
  51. package/.cursor/commands/discovery.md +1 -1
  52. package/.cursor/commands/dispatcher.md +2 -2
  53. package/.cursor/commands/eli5.md +2 -2
  54. package/.cursor/commands/eval.md +2 -2
  55. package/.cursor/commands/evolve.md +1 -1
  56. package/.cursor/commands/go.md +1 -1
  57. package/.cursor/commands/grill.md +2 -2
  58. package/.cursor/commands/memory-cleanup.md +2 -2
  59. package/.cursor/commands/persona-panel.md +1 -1
  60. package/.cursor/commands/plan.md +1 -1
  61. package/.cursor/commands/portfolio.md +1 -1
  62. package/.cursor/commands/reconcile.md +2 -2
  63. package/.cursor/commands/release.md +2 -2
  64. package/.cursor/commands/session.md +2 -2
  65. package/.cursor/commands/spinout.md +2 -2
  66. package/.cursor/commands/sunset-review.md +2 -2
  67. package/.cursor/commands/templates-ack.md +2 -2
  68. package/.cursor/commands/test.md +2 -2
  69. package/.cursor/skills/brainstorm/SKILL.md +1 -1
  70. package/.cursor/skills/eval/SKILL.md +1 -1
  71. package/.cursor/skills/quality-gates/SKILL.md +1 -1
  72. package/.cursor/skills/remote-offload/SKILL.md +13 -0
  73. package/.orchestrator/policy/blocked-commands.json +121 -0
  74. package/.orchestrator/policy/ecosystem.schema.json +66 -0
  75. package/.orchestrator/policy/quality-gates.example.json +16 -0
  76. package/.orchestrator/policy/quality-gates.schema.json +38 -0
  77. package/.orchestrator/policy/templates-policy.json +27 -0
  78. package/.orchestrator/policy/test-profiles.json +47 -0
  79. package/AGENTS.md +225 -0
  80. package/CHANGELOG.md +1401 -0
  81. package/NOTICE +11 -6
  82. package/README.md +127 -92
  83. package/agents/db-specialist.md +0 -1
  84. package/agents/eval-judge.md +1 -1
  85. package/agents/skill-applied-judge.md +1 -1
  86. package/assets/wave-lifecycle.svg +98 -0
  87. package/commands/release.md +6 -3
  88. package/commands/session.md +18 -3
  89. package/docs/README.md +4 -0
  90. package/{agents/AGENTS.md → docs/agent-authoring.md} +19 -26
  91. package/docs/baseline.md +67 -0
  92. package/docs/ci-setup.md +249 -48
  93. package/docs/codex-setup.md +66 -22
  94. package/docs/components.md +37 -16
  95. package/docs/cursor-setup.md +6 -2
  96. package/docs/events-schema.md +51 -10
  97. package/docs/instruction-delivery.md +62 -0
  98. package/{agents/memory-proposal-collector.md → docs/memory-proposal-flow.md} +1 -8
  99. package/docs/migration-v4.md +341 -0
  100. package/docs/pi-setup.md +6 -1
  101. package/docs/plugin-architecture-v3.md +1 -1
  102. package/docs/rule-authoring.md +85 -19
  103. package/docs/scope-collision-guard.md +8 -8
  104. package/docs/session-config-reference.md +120 -61
  105. package/docs/session-config-template.md +40 -33
  106. package/docs/telemetry/telemetry-claims.md +11 -10
  107. package/docs/telemetry.md +187 -4
  108. package/docs/vault-docs-architecture.md +50 -11
  109. package/hooks/_lib/atomic-json.mjs +111 -0
  110. package/hooks/_lib/hook-import-set.json +1487 -0
  111. package/hooks/_lib/subagent-paths.mjs +143 -0
  112. package/hooks/_lib/subagent-transcript.mjs +562 -0
  113. package/hooks/config-protection.mjs +2 -2
  114. package/hooks/cwd-change-restore.mjs +11 -31
  115. package/hooks/enforce-commands.mjs +69 -0
  116. package/hooks/enforce-scope.mjs +35 -6
  117. package/hooks/hooks-codex.json +1 -1
  118. package/hooks/hooks-cursor.json +10 -0
  119. package/hooks/hooks-pi.json +5 -0
  120. package/hooks/hooks.json +6 -1
  121. package/hooks/loop-guard.mjs +3 -3
  122. package/hooks/on-session-end.mjs +280 -14
  123. package/hooks/on-session-start.mjs +153 -4
  124. package/hooks/on-stop.mjs +371 -17
  125. package/hooks/operator-steer.mjs +2 -2
  126. package/hooks/post-bash-write-verify.mjs +189 -4
  127. package/hooks/post-edit-import-probe.mjs +344 -0
  128. package/hooks/post-subagent-discovery-validator.mjs +278 -392
  129. package/hooks/post-tool-batch-wave-signal.mjs +272 -44
  130. package/hooks/post-tool-failure-corrective-context.mjs +11 -34
  131. package/hooks/post-tooluse-frontend-slop.mjs +3 -3
  132. package/hooks/pre-bash-destructive-guard.mjs +39 -13
  133. package/hooks/pre-bash-memory-propose-audit.mjs +13 -7
  134. package/hooks/skill-invocation-telemetry.mjs +17 -5
  135. package/hooks/subagent-telemetry.mjs +24 -30
  136. package/monitors/monitors.json +3 -3
  137. package/package.json +9 -1
  138. package/pi/prompts/session.md +2 -2
  139. package/plugin.json +27 -0
  140. package/scripts/autopilot.mjs +26 -12
  141. package/scripts/backfill-abandoned-sessions.mjs +130 -15
  142. package/scripts/backfill-learnings-from-vault.mjs +9 -3
  143. package/scripts/dialectic-deriver.mjs +73 -8
  144. package/scripts/emit-event.mjs +10 -2
  145. package/scripts/export-hw-learnings.mjs +113 -1
  146. package/scripts/generate-agents-skills.mjs +378 -0
  147. package/scripts/generate-cursor-adapter.mjs +45 -8
  148. package/scripts/generate-hook-import-set.mjs +249 -0
  149. package/scripts/lib/agent-status.mjs +13 -2
  150. package/scripts/lib/auq/parse.mjs +5 -29
  151. package/scripts/lib/auto-dialectic.mjs +68 -0
  152. package/scripts/lib/auto-dream.mjs +38 -36
  153. package/scripts/lib/autonomy/suitability.mjs +6 -0
  154. package/scripts/lib/autopilot/loop.mjs +2 -2
  155. package/scripts/lib/autopilot/worktree-pipeline.mjs +82 -6
  156. package/scripts/lib/build-live-signals.mjs +25 -22
  157. package/scripts/lib/ci-status-banner.mjs +220 -75
  158. package/scripts/lib/codex/plugin-contract.mjs +82 -6
  159. package/scripts/lib/cold-start-detector.mjs +23 -14
  160. package/scripts/lib/config/auto-dream.mjs +2 -1
  161. package/scripts/lib/config/block-header.mjs +63 -0
  162. package/scripts/lib/config/block-preprocess.mjs +177 -0
  163. package/scripts/lib/config/broken-window.mjs +2 -1
  164. package/scripts/lib/config/cold-start.mjs +2 -1
  165. package/scripts/lib/config/config-protection.mjs +22 -2
  166. package/scripts/lib/config/context-coverage.mjs +2 -1
  167. package/scripts/lib/config/cross-repo.mjs +2 -1
  168. package/scripts/lib/config/custom-phases.mjs +2 -1
  169. package/scripts/lib/config/dialectic.mjs +2 -1
  170. package/scripts/lib/config/discovery-validator.mjs +9 -3
  171. package/scripts/lib/config/dispatcher-autonomy-capture.mjs +24 -1
  172. package/scripts/lib/config/dispatcher-autonomy.mjs +2 -1
  173. package/scripts/lib/config/docs-orchestrator.mjs +2 -1
  174. package/scripts/lib/config/docs-staleness.mjs +2 -1
  175. package/scripts/lib/config/drift-check.mjs +2 -1
  176. package/scripts/lib/config/eval.mjs +2 -1
  177. package/scripts/lib/config/events-rotation.mjs +2 -1
  178. package/scripts/lib/config/evolve.mjs +8 -2
  179. package/scripts/lib/config/frontend-slop-hook.mjs +7 -3
  180. package/scripts/lib/config/gitlab-portfolio.mjs +2 -1
  181. package/scripts/lib/config/handover-gate.mjs +2 -1
  182. package/scripts/lib/config/health-endpoints.mjs +388 -0
  183. package/scripts/lib/config/issue-budget.mjs +2 -1
  184. package/scripts/lib/config/loop-guard.mjs +2 -1
  185. package/scripts/lib/config/memory.mjs +2 -1
  186. package/scripts/lib/config/moc-staleness.mjs +2 -1
  187. package/scripts/lib/config/persona-gate-wave.mjs +2 -1
  188. package/scripts/lib/config/private-config-dir.mjs +67 -0
  189. package/scripts/lib/config/reconcile.mjs +2 -1
  190. package/scripts/lib/config/remote-hosts.mjs +234 -0
  191. package/scripts/lib/config/section-extractor.mjs +7 -1
  192. package/scripts/lib/config/skill-evolution.mjs +2 -1
  193. package/scripts/lib/config/slopcheck.mjs +2 -1
  194. package/scripts/lib/config/state-md-lock.mjs +2 -1
  195. package/scripts/lib/config/templates-first.mjs +2 -1
  196. package/scripts/lib/config/test.mjs +2 -1
  197. package/scripts/lib/config/vault-integration.mjs +7 -1
  198. package/scripts/lib/config/vault-mirror-quality.mjs +2 -1
  199. package/scripts/lib/config/vault-staleness.mjs +2 -1
  200. package/scripts/lib/config/vault-sync.mjs +2 -1
  201. package/scripts/lib/config/verification-auto-fix.mjs +2 -1
  202. package/scripts/lib/config/wave-reviewers.mjs +2 -1
  203. package/scripts/lib/config/worktree-orphans.mjs +2 -1
  204. package/scripts/lib/config.mjs +31 -3
  205. package/scripts/lib/convergence-monitor.mjs +82 -16
  206. package/scripts/lib/dispatcher/enumerate.mjs +2 -17
  207. package/scripts/lib/dispatcher/rank.mjs +124 -48
  208. package/scripts/lib/ecosystem-health.mjs +16 -2
  209. package/scripts/lib/eval/engine.mjs +9 -1
  210. package/scripts/lib/eval/session-resolve.mjs +23 -4
  211. package/scripts/lib/events-schema.mjs +48 -0
  212. package/scripts/lib/events.mjs +256 -7
  213. package/scripts/lib/evolve/autonomy-verdict.mjs +9 -4
  214. package/scripts/lib/evolve/autopilot-effectiveness.mjs +18 -1
  215. package/scripts/lib/frontmatter-guard.mjs +131 -13
  216. package/scripts/lib/gates/gate-full.mjs +26 -0
  217. package/scripts/lib/gates/gate-helpers.mjs +76 -0
  218. package/scripts/lib/gitlab-portfolio/cli.mjs +3 -15
  219. package/scripts/lib/hardware-pattern-detector.mjs +18 -1
  220. package/scripts/lib/harness-audit/categories/category1.mjs +17 -6
  221. package/scripts/lib/harness-audit/categories/category4.mjs +31 -11
  222. package/scripts/lib/host-identity.mjs +50 -11
  223. package/scripts/lib/instruction-budget-guard.mjs +171 -5
  224. package/scripts/lib/learnings/evolve-telemetry.mjs +178 -0
  225. package/scripts/lib/learnings/io.mjs +60 -6
  226. package/scripts/lib/memory-banner.mjs +20 -8
  227. package/scripts/lib/memory-proposals/store.mjs +30 -22
  228. package/scripts/lib/owner-config-banner.mjs +43 -6
  229. package/scripts/lib/owner-config-loader.mjs +21 -10
  230. package/scripts/lib/owner-interview.mjs +3 -3
  231. package/scripts/lib/owner-yaml.mjs +207 -14
  232. package/scripts/lib/peer-discovery.mjs +20 -2
  233. package/scripts/lib/platform.mjs +108 -15
  234. package/scripts/lib/plugin-update-banner.mjs +406 -0
  235. package/scripts/lib/project-hygiene.mjs +38 -2
  236. package/scripts/lib/qg-command-drift-banner.mjs +50 -12
  237. package/scripts/lib/quality-gate.mjs +133 -44
  238. package/scripts/lib/reconcile/emitter.mjs +68 -6
  239. package/scripts/lib/reconcile/engine.mjs +249 -9
  240. package/scripts/lib/reconcile/idempotency.mjs +37 -4
  241. package/scripts/lib/reconcile/writer.mjs +40 -18
  242. package/scripts/lib/scope-gate.mjs +36 -0
  243. package/scripts/lib/session-close-backfill.mjs +125 -18
  244. package/scripts/lib/session-discovery.mjs +57 -3
  245. package/scripts/lib/session-end/phase-skip.mjs +2 -2
  246. package/scripts/lib/session-id.mjs +12 -23
  247. package/scripts/lib/session-identity/own-session.mjs +187 -11
  248. package/scripts/lib/session-lock-shape.mjs +43 -0
  249. package/scripts/lib/session-lock.mjs +5 -10
  250. package/scripts/lib/session-registry.mjs +25 -9
  251. package/scripts/lib/session-schema/constants.mjs +36 -2
  252. package/scripts/lib/session-schema/validator.mjs +38 -4
  253. package/scripts/lib/session-start-probes.mjs +18 -1
  254. package/scripts/lib/session-transition.mjs +1 -1
  255. package/scripts/lib/sessions-canonical.mjs +446 -0
  256. package/scripts/lib/sessions-staleness-banner.mjs +18 -11
  257. package/scripts/lib/skill-health/join.mjs +17 -4
  258. package/scripts/lib/state-md.mjs +78 -0
  259. package/scripts/lib/sunset/walker.mjs +6 -0
  260. package/scripts/lib/telemetry/schema.mjs +255 -17
  261. package/scripts/lib/telemetry/sync.mjs +417 -24
  262. package/scripts/lib/tmux-layout/telemetry.mjs +14 -2
  263. package/scripts/lib/validate/check-agents-skills.mjs +327 -0
  264. package/scripts/lib/validate/check-agents.mjs +3 -3
  265. package/scripts/lib/validate/check-cursor-adapter.mjs +234 -72
  266. package/scripts/lib/validate/check-doc-cli-commands.mjs +9 -33
  267. package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +370 -0
  268. package/scripts/lib/validate/check-hooks-symmetry.mjs +45 -16
  269. package/scripts/lib/validate/check-owner-leakage.mjs +281 -20
  270. package/scripts/lib/validate/check-skill-links.mjs +163 -0
  271. package/scripts/lib/validate/check-skill-script-paths.mjs +455 -0
  272. package/scripts/lib/validate/check-untracked-test-deps.mjs +10 -0
  273. package/scripts/lib/validate/check-unwired-features.mjs +0 -9
  274. package/scripts/lib/validate/check-validator-registration.mjs +254 -0
  275. package/scripts/lib/validate/check-vcs-repo-flag.mjs +6 -28
  276. package/scripts/lib/validate/enumerate-repo-files.mjs +317 -0
  277. package/scripts/lib/validate/markdown-fences.mjs +196 -0
  278. package/scripts/lib/vault-backfill/template.mjs +63 -6
  279. package/scripts/lib/vault-mirror/process.mjs +165 -42
  280. package/scripts/lib/vault-mirror/telemetry.mjs +2 -2
  281. package/scripts/lib/vault-status/board-lock.mjs +185 -0
  282. package/scripts/lib/vault-status/board-writer.mjs +174 -135
  283. package/scripts/lib/vault-status/narrative-mirror.mjs +129 -37
  284. package/scripts/lib/wave-executor/dispatch-common.mjs +164 -0
  285. package/scripts/lib/wave-executor/foreign-dispatch.mjs +7 -142
  286. package/scripts/lib/wave-executor/remote-dispatch.mjs +502 -0
  287. package/scripts/lib/wave-resource-gate.mjs +133 -7
  288. package/scripts/lib/wave-sizing.mjs +4 -1
  289. package/scripts/lib/wave-transcript-tail.mjs +142 -8
  290. package/scripts/materialize-wave-scope.mjs +32 -9
  291. package/scripts/memory-propose.mjs +146 -8
  292. package/scripts/migrate-cold-start-seed.mjs +4 -1
  293. package/scripts/parse-config.mjs +60 -3
  294. package/scripts/promote-vault-strict.mjs +4 -15
  295. package/scripts/release.mjs +337 -29
  296. package/scripts/repair-invalid-sessions.mjs +3 -3
  297. package/scripts/run-quality-gate.mjs +128 -11
  298. package/scripts/site-numbers.mjs +36 -4
  299. package/scripts/sweep-expired-learnings.mjs +90 -0
  300. package/scripts/sync-vault-schema.mjs +3 -1
  301. package/scripts/telemetry.mjs +2 -2
  302. package/scripts/validate-plugin.mjs +187 -0
  303. package/scripts/validate-wave-scope.mjs +28 -8
  304. package/scripts/vault-consolidate.mjs +3 -11
  305. package/scripts/vault-integration-watcher.mjs +2 -4
  306. package/scripts/vault-mirror.mjs +111 -26
  307. package/scripts/wave-scope-binding.mjs +215 -0
  308. package/skills/_shared/instruction-file-resolution.md +10 -0
  309. package/skills/_shared/parallel-aware-auq.md +31 -2
  310. package/skills/_shared/parallel-aware-preamble.md +18 -4
  311. package/skills/_shared/platform-tools.md +1 -1
  312. package/skills/_shared/state-ownership.md +1 -1
  313. package/skills/architecture/SKILL.md +7 -5
  314. package/skills/{domain-model/SKILL.md → architecture/references/domain-model.md} +9 -9
  315. package/skills/autopilot/SKILL.md +4 -18
  316. package/skills/claude-md-drift-check/SKILL.md +5 -1
  317. package/skills/claude-md-drift-check/checker.mjs +62 -2
  318. package/skills/convergence-monitoring/SIGNALS.md +55 -0
  319. package/skills/discovery/probes/vault-staleness.mjs +37 -13
  320. package/skills/discovery/probes-arch.md +20 -18
  321. package/skills/dispatcher/SKILL.md +3 -2
  322. package/skills/ecosystem-health/SKILL.md +4 -1
  323. package/skills/ecosystem-health/wizard.md +5 -0
  324. package/skills/evolve/SKILL.md +87 -11
  325. package/skills/frontmatter-guard/SKILL.md +11 -5
  326. package/skills/npm-publish/SKILL.md +1 -1
  327. package/skills/reconcile/SKILL.md +38 -2
  328. package/skills/remote-offload/SKILL.md +89 -0
  329. package/skills/session-end/SKILL.md +18 -905
  330. package/skills/session-end/phase-3-6-tail.md +19 -9
  331. package/skills/session-end/plan-verification.md +221 -155
  332. package/skills/session-end/references/phase-2-quality-gate.md +93 -0
  333. package/skills/session-end/references/phase-3-documentation-updates.md +229 -0
  334. package/skills/session-end/references/phase-4a-worktree-cleanup.md +120 -0
  335. package/skills/session-end/references/phase-4b-worktree-orphan-sweep.md +58 -0
  336. package/skills/session-end/references/phase-5-issue-cleanup.md +104 -0
  337. package/skills/session-end/references/session-summary-template.md +62 -0
  338. package/skills/session-plan/SKILL.md +49 -0
  339. package/skills/session-start/SKILL.md +41 -900
  340. package/skills/session-start/phase-8-5-express-path.md +1 -1
  341. package/skills/session-start/references/phase-1-1-dispatcher-autonomy-capture.md +55 -0
  342. package/skills/session-start/references/phase-1-2-session-lock.md +140 -0
  343. package/skills/session-start/references/phase-1-5-session-continuity.md +254 -0
  344. package/skills/session-start/references/phase-1-7-vault-status-board.md +53 -0
  345. package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +75 -0
  346. package/skills/session-start/references/phase-4-ssot-environment-check.md +155 -0
  347. package/skills/session-start/references/phase-6-5-forced-reads.md +75 -0
  348. package/skills/session-start/references/phase-6-6-project-intelligence.md +81 -0
  349. package/skills/session-start/references/phase-6-7-memory-banner-telemetry-consent.md +103 -0
  350. package/skills/vault-sync/validator.mjs +21 -27
  351. package/skills/wave-executor/SKILL.md +16 -2
  352. package/skills/wave-executor/references/wave-loop-dispatch.md +612 -0
  353. package/skills/wave-executor/references/wave-loop-review.md +570 -0
  354. package/skills/wave-executor/references/wave-loop-scope-manifest.md +162 -0
  355. package/skills/wave-executor/wave-loop.md +14 -1271
  356. package/templates/_shared/journey-manifest.md +10 -6
  357. package/.cursor/commands/autopilot-multi.md +0 -14
  358. package/.cursor/commands/contract-version-bump.md +0 -14
  359. package/.cursor/commands/journey-audit.md +0 -14
  360. package/.cursor/skills/contract-version-bump/SKILL.md +0 -12
  361. package/.cursor/skills/daily/SKILL.md +0 -12
  362. package/.cursor/skills/domain-model/SKILL.md +0 -13
  363. package/.cursor/skills/journey-audit/SKILL.md +0 -13
  364. package/.cursor/skills/skill-creator/SKILL.md +0 -13
  365. package/.cursor/skills/ubiquitous-language/SKILL.md +0 -13
  366. package/commands/autopilot-multi.md +0 -74
  367. package/commands/contract-version-bump.md +0 -28
  368. package/commands/journey-audit.md +0 -43
  369. package/pi/prompts/autopilot-multi.md +0 -12
  370. package/pi/prompts/contract-version-bump.md +0 -12
  371. package/pi/prompts/journey-audit.md +0 -12
  372. package/scripts/autopilot-multi.mjs +0 -885
  373. package/scripts/backfill-learnings-expires.mjs +0 -196
  374. package/scripts/backfill-learnings.mjs +0 -203
  375. package/scripts/fleet-instruction-scan.mjs +0 -141
  376. package/scripts/lib/autopilot/dep-graph.mjs +0 -417
  377. package/scripts/lib/autopilot/multi-killswitch.mjs +0 -184
  378. package/scripts/lib/webhook-url.mjs +0 -105
  379. package/scripts/lifecycle-sim-v6.mjs +0 -347
  380. package/scripts/migrate-learnings-jsonl.mjs +0 -189
  381. package/scripts/migrate-subagents-jsonl.mjs +0 -196
  382. package/scripts/upload-social-preview.mjs +0 -316
  383. package/skills/_shared/model-selection.md +0 -64
  384. package/skills/contract-version-bump/SKILL.md +0 -219
  385. package/skills/daily/SKILL.md +0 -222
  386. package/skills/daily/generate.sh +0 -92
  387. package/skills/daily/templates/daily.md.tpl +0 -36
  388. package/skills/journey-audit/SKILL.md +0 -269
  389. package/skills/skill-creator/SKILL.md +0 -168
  390. package/skills/ubiquitous-language/SKILL.md +0 -97
  391. package/skills/vault-sync/package-lock.json +0 -40
  392. /package/skills/{domain-model → architecture/references}/ADR-FORMAT.md +0 -0
  393. /package/skills/{domain-model → architecture/references}/CONTEXT-FORMAT.md +0 -0
@@ -35,7 +35,7 @@
35
35
  * none and holds no mutable runtime state.
36
36
  */
37
37
 
38
- import { SO_PLATFORM, SO_PLUGIN_ROOT } from '../platform.mjs';
38
+ import { getPlatform, getPluginRoot } from '../platform.mjs';
39
39
  import { enumerateSurface } from '../sunset/walker.mjs';
40
40
  import { readPluginVersionFromPackageJson } from '../bootstrap-lock-freshness.mjs';
41
41
 
@@ -70,6 +70,52 @@ export const USAGE_PING_FIELDS = Object.freeze([
70
70
  'commands',
71
71
  ]);
72
72
 
73
+ /**
74
+ * ADDITIVE optional fields (schema v1, GitLab #1234). Deliberately a SECOND
75
+ * list rather than an extension of USAGE_PING_FIELDS above, for two reasons:
76
+ *
77
+ * 1. USAGE_PING_FIELDS is the REQUIRED v1 contract — `tests/telemetry/parity.mjs`
78
+ * asserts, field by field, that the server independently REQUIRES every
79
+ * member. An optional field is by definition not required, so putting it in
80
+ * that list would force the parity guard to be weakened for all 15 fields to
81
+ * accommodate one.
82
+ * 2. The frozen-list tripwire (`projectUsagePing` drops anything unlisted)
83
+ * stays intact: the projection whitelist is the UNION of both lists, so a
84
+ * leaky field still has to be added to a reviewed list before it can reach
85
+ * the wire.
86
+ *
87
+ * Server tolerance: `server/ingest/validate.mjs` accepts unknown top-level
88
+ * fields and preserves them verbatim in `raw_json` (see its module docblock), so
89
+ * every member here round-trips through a server that predates it.
90
+ */
91
+ export const USAGE_PING_OPTIONAL_FIELDS = Object.freeze([
92
+ 'fleet_self_declared',
93
+ 'session_record',
94
+ 'session_profile',
95
+ ]);
96
+
97
+ /**
98
+ * The full projection whitelist: required v1 fields + additive optional fields.
99
+ * `projectUsagePing` is driven from THIS, so neither list alone can leak a field.
100
+ */
101
+ const USAGE_PING_PROJECTED_FIELDS = Object.freeze([...USAGE_PING_FIELDS, ...USAGE_PING_OPTIONAL_FIELDS]);
102
+
103
+ /**
104
+ * `session_record` provenance tokens — WHICH source the session facts
105
+ * (`session_type`, `duration_bucket`) in this ping came from.
106
+ *
107
+ * - `ledger` — `.orchestrator/metrics/sessions.jsonl` had a matching record.
108
+ * - `derived` — no ledger record; the facts were reconstructed from
109
+ * `events.jsonl` (`orchestrator.session.started` + last event).
110
+ * - `absent` — neither source produced a session type. `session_type` is then
111
+ * `'unknown'` and `duration_bucket` is NOT a measurement.
112
+ *
113
+ * Measured 2026-09-06 (d8 audit): this repo has NO sessions.jsonl, so 100 % of
114
+ * its pings took the `absent` path and were indistinguishable on the wire from
115
+ * a genuinely-measured `other` / `<15m` session — 32 such pings on the server.
116
+ */
117
+ export const SESSION_RECORD_SOURCES = Object.freeze(['ledger', 'derived', 'absent']);
118
+
73
119
  /** Exact duration-bucket tokens (ASCII, stable wire values). */
74
120
  export const DURATION_BUCKETS = Object.freeze(['<15m', '15-60m', '1-3h', '>3h']);
75
121
 
@@ -83,6 +129,43 @@ const VALID_PLATFORMS = Object.freeze(['claude', 'codex', 'cursor', 'pi']);
83
129
  const VALID_SESSION_TYPES = Object.freeze(['housekeeping', 'feature', 'deep']);
84
130
  const PLATFORM_OTHER = 'other';
85
131
  const SESSION_TYPE_OTHER = 'other';
132
+ /**
133
+ * The type was never measured — distinct from `'other'`, which means "measured,
134
+ * but not one of the three known modes". Conflating the two is the defect this
135
+ * token fixes: before it existed, a ping built with NO session record silently
136
+ * reported `'other'`, so "we could not tell" and "we looked and it was unusual"
137
+ * were the same wire value.
138
+ *
139
+ * NOT an enum widening server-side: `session_type` is validated as a bounded
140
+ * STRING (`server/ingest/validate.mjs` `requireString` + `MAX_SESSION_TYPE`),
141
+ * never against a closed set, so `'unknown'` is accepted by today's server.
142
+ */
143
+ const SESSION_TYPE_UNKNOWN = 'unknown';
144
+
145
+ /**
146
+ * CLOSED whitelist of PUBLIC session-profile names that may reach the wire.
147
+ *
148
+ * WHY A WHITELIST AND NOT A REGEX: `session_profile` is copied from the STATE.md
149
+ * frontmatter key `session-profile`, which is written per repo by whoever runs
150
+ * `/session <alias>` — i.e. it is the only field on the usage-ping whose VALUE is
151
+ * repo-authored free text. Two independent Wave-1 reviewers reproduced the leak
152
+ * end-to-end (2026-09-06): `session-profile: client-acme-private-repo` travelled
153
+ * verbatim through `buildUsagePing` → `projectUsagePing` → the ingest server's
154
+ * `raw_json` column. A shape regex does NOT close it — that example string is
155
+ * already lowercase-and-hyphens and passes any such pattern. Only an
156
+ * enumeration of names that are public BY CONSTRUCTION does.
157
+ *
158
+ * Today exactly one profile exists: `ultradeep`, the 7-wave variant of a `deep`
159
+ * session (writer: `commands/session.md` § "Argument alias: ultradeep" → STATE.md
160
+ * frontmatter `session-profile`; wave shape: `skills/session-plan/SKILL.md`).
161
+ * Adding a profile there means adding it HERE and in the server's mirror
162
+ * (`server/ingest/validate.mjs` `SESSION_PROFILES`) — a deliberate two-line,
163
+ * reviewed edit, the same contract `ACCEPTED_VERSIONS` already uses server-side.
164
+ *
165
+ * NOT a member of VALID_SESSION_TYPES: the profile is a SECOND axis. An
166
+ * ultradeep session is `session_type: "deep"` PLUS `session_profile: "ultradeep"`.
167
+ */
168
+ export const VALID_SESSION_PROFILES = Object.freeze(['ultradeep']);
86
169
 
87
170
  /**
88
171
  * Closed sets for os/arch client-side normalization. A value outside the set —
@@ -121,7 +204,8 @@ function isNonEmptyString(v) {
121
204
  // ---------------------------------------------------------------------------
122
205
 
123
206
  /**
124
- * Project an arbitrary object onto the usage-ping whitelist (USAGE_PING_FIELDS).
207
+ * Project an arbitrary object onto the usage-ping whitelist (USAGE_PING_FIELDS
208
+ * PLUS USAGE_PING_OPTIONAL_FIELDS).
125
209
  * Fully data-driven: any key not on the whitelist — paths, repo names, prompts,
126
210
  * args, hostnames, rogue extras — is dropped. Array fields (skills, commands) are
127
211
  * copied as NEW arrays so no caller reference leaks into the projection.
@@ -132,7 +216,7 @@ function isNonEmptyString(v) {
132
216
  export function projectUsagePing(input) {
133
217
  if (!isPlainObject(input)) return {};
134
218
  const out = {};
135
- for (const key of USAGE_PING_FIELDS) {
219
+ for (const key of USAGE_PING_PROJECTED_FIELDS) {
136
220
  if (key in input) {
137
221
  const v = input[key];
138
222
  out[key] = Array.isArray(v) ? [...v] : v;
@@ -163,7 +247,7 @@ export function projectUsagePing(input) {
163
247
  export function loadRoster({ pluginRoot } = {}) {
164
248
  const root = (typeof pluginRoot === 'string' && pluginRoot.trim() !== '')
165
249
  ? pluginRoot
166
- : SO_PLUGIN_ROOT;
250
+ : getPluginRoot();
167
251
 
168
252
  if (!isNonEmptyString(root)) {
169
253
  process.stderr.write(
@@ -220,6 +304,54 @@ export function filterRosterNames(names, rosterSet) {
220
304
  return deduped.slice(0, MAX_NAMES);
221
305
  }
222
306
 
307
+ /**
308
+ * Classify a single raw invocation name into the skills or commands bucket.
309
+ *
310
+ * The Skill tool surfaces slash-commands that have NO backing `skills/` directory
311
+ * under the same plugin-prefixed name form as real skills (e.g.
312
+ * `session-orchestrator:session` for `commands/session.md`). `roster.skills` holds
313
+ * PREFIXED names, `roster.commands` holds BARE ones — so a prefixed command name
314
+ * matches neither set and used to be bucketed to 'other' (GitLab #1189: commands
315
+ * was `[]` in 345/345 usage pings).
316
+ *
317
+ * Decision order (skill roster wins on a spelling collision such as
318
+ * `memory-cleanup`, which is both a skill dir and a command file):
319
+ * 1. name in rosterSkills → {kind:'skill', name} (verbatim)
320
+ * 2. name is PREFIXED and its bare form is in rosterCommands
321
+ * → {kind:'command', bare}
322
+ * 3. otherwise → {kind:'skill', name} (verbatim)
323
+ *
324
+ * Case 2 REQUIRES the plugin prefix (session-reviewer W2 finding, 2026-09-02).
325
+ * Without that requirement, a BARE third-party or personal skill name that
326
+ * happens to collide with one of our shipped command names (`test`, `close`,
327
+ * `go`, `release`, `portfolio` are all plausible foreign skill names) would be
328
+ * recorded as OUR command — a data-integrity defect, and the same rule made
329
+ * `memory-cleanup` reach BOTH buckets in one ping (bare → commands, prefixed →
330
+ * skills), double-counting a single surface. Requiring the prefix removes both:
331
+ * a bare arrival can only ever be a skill-path name, so an unknown one becomes
332
+ * 'other'. Cost: the one genuine bare `memory-cleanup` record is recorded as
333
+ * 'other' rather than as the command.
334
+ *
335
+ * Case 3 keeps foreign/third-party names on the SKILLS path only, where
336
+ * filterRosterNames projects them to the opaque token 'other' — an unclassified
337
+ * name is never duplicated into `commands`, preserving the privacy invariant.
338
+ *
339
+ * @param {unknown} name raw invocation name
340
+ * @param {Set<string>} rosterSkills prefixed shipped-skill names
341
+ * @param {Set<string>} rosterCommands bare shipped-command names
342
+ * @returns {{kind: 'skill'|'command', name: unknown}}
343
+ */
344
+ export function classifyInvocationName(name, rosterSkills, rosterCommands) {
345
+ const skills = rosterSkills instanceof Set ? rosterSkills : new Set();
346
+ const commands = rosterCommands instanceof Set ? rosterCommands : new Set();
347
+ if (typeof name !== 'string') return { kind: 'skill', name };
348
+ if (skills.has(name)) return { kind: 'skill', name };
349
+ if (!name.startsWith(SKILL_PREFIX)) return { kind: 'skill', name };
350
+ const bare = name.slice(SKILL_PREFIX.length);
351
+ if (commands.has(bare)) return { kind: 'command', name: bare };
352
+ return { kind: 'skill', name };
353
+ }
354
+
223
355
  // ---------------------------------------------------------------------------
224
356
  // Duration bucketing
225
357
  // ---------------------------------------------------------------------------
@@ -261,8 +393,9 @@ export function deriveDurationBucket(startedAtISO, completedAtISO) {
261
393
  * whose null return (missing/unparseable package.json or non-string version) maps to 'unknown'.
262
394
  */
263
395
  function resolvePluginVersion() {
264
- if (!isNonEmptyString(SO_PLUGIN_ROOT)) return 'unknown';
265
- return readPluginVersionFromPackageJson(SO_PLUGIN_ROOT) ?? 'unknown';
396
+ const root = getPluginRoot();
397
+ if (!isNonEmptyString(root)) return 'unknown';
398
+ return readPluginVersionFromPackageJson(root) ?? 'unknown';
266
399
  }
267
400
 
268
401
  /** Normalize the detected platform to the closed enum (+ 'other' fallback). */
@@ -272,7 +405,36 @@ function normalizePlatform(platform) {
272
405
 
273
406
  /** Normalize the session type to the closed enum (+ 'other' fallback). */
274
407
  function normalizeSessionType(sessionType) {
275
- return VALID_SESSION_TYPES.includes(sessionType) ? sessionType : SESSION_TYPE_OTHER;
408
+ if (VALID_SESSION_TYPES.includes(sessionType)) return sessionType;
409
+ // ABSENT ≠ UNRECOGNISED. A missing/blank value means nothing was measured
410
+ // (`unknown`); a present-but-unlisted value means something WAS measured and
411
+ // is not one of the three modes (`other`). The old single-branch version
412
+ // returned `other` for both, which is how 394 pings from a host with no
413
+ // sessions.jsonl arrived looking like measured `other` sessions (d8, 2026-09-06).
414
+ return isNonEmptyString(sessionType) ? SESSION_TYPE_OTHER : SESSION_TYPE_UNKNOWN;
415
+ }
416
+
417
+ /**
418
+ * Normalize a session PROFILE against the closed VALID_SESSION_PROFILES
419
+ * whitelist. Anything else — absent, blank, or an unlisted repo-authored value —
420
+ * returns `null`, and the caller OMITS the field.
421
+ *
422
+ * DELIBERATELY NOT MIRRORING normalizeSessionType's two-token report. That helper
423
+ * can distinguish ABSENT (`'unknown'`) from UNRECOGNISED (`'other'`) because both
424
+ * of its answers are public constants. Here the unrecognised VALUE is precisely
425
+ * what must not travel, and there is no third token that carries the distinction
426
+ * without carrying the string: an `'other'` profile would say "this host ran a
427
+ * profile we do not ship" — a fact of no product use, bought with a new wire
428
+ * value. So both cases collapse to omission, and the wire cannot tell them apart
429
+ * BY DESIGN. The local `session-profile` key is untouched either way.
430
+ *
431
+ * @param {unknown} profile
432
+ * @returns {string|null} a whitelisted profile name, or null (⇒ field omitted).
433
+ */
434
+ export function normalizeSessionProfile(profile) {
435
+ if (!isNonEmptyString(profile)) return null;
436
+ const trimmed = profile.trim();
437
+ return VALID_SESSION_PROFILES.includes(trimmed) ? trimmed : null;
276
438
  }
277
439
 
278
440
  /**
@@ -331,12 +493,12 @@ function distinctField(records, field) {
331
493
  * whitelist-clean but does NOT carry `anon_id` — the caller sets it via
332
494
  * ensureAnonId (anon-id.mjs), keeping ID rotation isolated there.
333
495
  *
334
- * skills are the distinct `.skill` values of `skillInvocations`; commands are the
335
- * distinct `.command` values of the same records (none in v1 skill-invocations
336
- * telemetry []; the field is honored so a future command-telemetry stream feeds
337
- * in without a signature change). Both are roster-filtered — off-roster names
338
- * become "other" — deduped, sorted, and capped. No frequencies are recorded (v1
339
- * decision).
496
+ * The distinct `.skill` and `.command` values of `skillInvocations` go through a
497
+ * single classifyInvocationName pass that routes each name to skills or commands
498
+ * (the `.command` field carries nothing today; it is honored so a future direct
499
+ * command-telemetry stream feeds in without a signature change). Both buckets are
500
+ * then roster-filtered — off-roster names become "other" — deduped, sorted, and
501
+ * capped. No frequencies are recorded (v1 decision).
340
502
  *
341
503
  * @param {{
342
504
  * sessionRecord: object,
@@ -355,6 +517,9 @@ export function buildUsagePing({
355
517
  env = process.env,
356
518
  now = new Date().toISOString(),
357
519
  roster,
520
+ consentState,
521
+ sessionRecordSource,
522
+ sessionProfile,
358
523
  } = {}) {
359
524
  const session = isPlainObject(sessionRecord) ? sessionRecord : {};
360
525
  const invocations = Array.isArray(skillInvocations) ? skillInvocations : [];
@@ -362,22 +527,95 @@ export function buildUsagePing({
362
527
  const rosterSkills = rst?.skills instanceof Set ? rst.skills : new Set();
363
528
  const rosterCommands = rst?.commands instanceof Set ? rst.commands : new Set();
364
529
 
365
- const skillNames = distinctField(invocations, 'skill');
366
- const commandNames = distinctField(invocations, 'command');
530
+ // ONE classification pass over the union of both producer fields: today only
531
+ // `.skill` is written by hooks/skill-invocation-telemetry.mjs, `.command` is
532
+ // kept for the forward-compat producer documented above.
533
+ //
534
+ // `.command` records carry the BARE name, and classifyInvocationName requires
535
+ // the plugin prefix before it will route anything to the commands bucket (see
536
+ // its doc comment). So a `.command` name is normalized to the prefixed form
537
+ // first — the field itself is the "this is one of ours" signal that a bare
538
+ // `.skill` arrival lacks. Without this the forward-compat producer would be
539
+ // wired but dead: every record it writes would silently become 'other'.
540
+ const skillNames = [];
541
+ const commandNames = [];
542
+ const rawNames = [
543
+ ...distinctField(invocations, 'skill'),
544
+ ...distinctField(invocations, 'command').map((n) => (n.startsWith(SKILL_PREFIX) ? n : `${SKILL_PREFIX}${n}`)),
545
+ ];
546
+ for (const raw of rawNames) {
547
+ const { kind, name } = classifyInvocationName(raw, rosterSkills, rosterCommands);
548
+ (kind === 'command' ? commandNames : skillNames).push(name);
549
+ }
550
+
551
+ // ── fleet: a statement about the OPERATOR, derived from the RESOLVED consent
552
+ // state, not from a raw owner.yaml read ────────────────────────────────────
553
+ // The old expression was `ownerConfig?.telemetry?.enabled === true` — a
554
+ // statement about a FILE. Measured 2026-09-06 (d8): the operator's second Mac
555
+ // has consent granted but no `telemetry:` block in owner.yaml, so 394 of 490
556
+ // server records (80,4 %) counted the operator as an external user and every
557
+ // week's `fleet_vs_external` was wrong.
558
+ //
559
+ // `resolveConsent()` already answers this question correctly: it returns
560
+ // `enabled-fleet` for the owner.yaml opt-in AND `enabled-env` for
561
+ // `SO_TELEMETRY=1`, both of which are operator-side postures. Callers that
562
+ // pass `consentState` get that answer; the ownerConfig fallback below keeps
563
+ // the two-argument callers (and the CLI preview) behaviourally identical.
564
+ //
565
+ // CEILING, named because the client cannot close it: this is still
566
+ // SELF-DECLARED — a sandbox or a host whose owner.yaml is unreachable declares
567
+ // `false` however honest it is. The authoritative classification is
568
+ // server-side (`SO_INGEST_FLEET_ANON_IDS`, server/ingest/config.mjs).
569
+ // `session_profile` (STATE.md frontmatter `session-profile`) is bounded by the
570
+ // CLOSED VALID_SESSION_PROFILES whitelist — it was the one free-text value on
571
+ // the wire until 2026-09-06, and a repo-authored one at that (see the
572
+ // whitelist's own docblock for the reproduced leak). It is still deliberately
573
+ // NOT routed through normalizeSessionType: that helper degrades anything
574
+ // outside ['housekeeping','feature','deep'] to 'other', which is exactly the
575
+ // silent loss the profile exists to prevent. The contract is
576
+ // `session_type: "deep"` PLUS `session_profile: "ultradeep"` — never
577
+ // `session_type: "ultradeep"`, and never a profile flattened to 'other'.
578
+ //
579
+ // ABSENT IS NOT EMPTY: with no profile — and with an UNLISTED one — the KEY IS
580
+ // OMITTED, matching every other optional ping field. `projectUsagePing` copies
581
+ // only keys that are `in` the input, so an omitted key never reaches the wire
582
+ // as `null`, and an unlisted profile never reaches it at all.
583
+ //
584
+ // SOURCE PRECEDENCE is resolved BEFORE normalization (explicit argument beats
585
+ // the session record), so an unlisted explicit profile is dropped rather than
586
+ // silently replaced by the record's value.
587
+ const rawProfile =
588
+ isNonEmptyString(sessionProfile) ? sessionProfile
589
+ : isNonEmptyString(session.session_profile) ? session.session_profile
590
+ : null;
591
+ const profile = normalizeSessionProfile(rawProfile);
592
+
593
+ const fleetSelfDeclared =
594
+ consentState === undefined || consentState === null
595
+ ? ownerConfig?.telemetry?.enabled === true
596
+ : consentState === 'enabled-fleet' || consentState === 'enabled-env';
367
597
 
368
598
  return {
369
599
  record_kind: 'usage-ping',
370
600
  schema_version: USAGE_PING_SCHEMA_VERSION,
371
601
  sent_at: now,
372
602
  plugin_version: resolvePluginVersion(),
373
- platform: normalizePlatform(SO_PLATFORM),
603
+ platform: normalizePlatform(getPlatform()),
374
604
  os: normalizeOs(process.platform),
375
605
  arch: normalizeArch(process.arch),
376
606
  node_major: parseInt(process.versions.node, 10),
377
607
  ci: deriveCi(env),
378
- fleet: ownerConfig?.telemetry?.enabled === true,
608
+ fleet: fleetSelfDeclared,
609
+ // DEPRECATED alias of `fleet_self_declared`, kept for one schema generation
610
+ // (removal: 2027-03-06 — see docs/telemetry.md § Schema evolution) so the
611
+ // server's existing `fleet` column stays comparable across the rename.
612
+ fleet_self_declared: fleetSelfDeclared,
379
613
  session_type: normalizeSessionType(session.session_type),
614
+ ...(profile !== null ? { session_profile: profile } : {}),
380
615
  duration_bucket: deriveDurationBucket(session.started_at, session.completed_at),
616
+ session_record: SESSION_RECORD_SOURCES.includes(sessionRecordSource)
617
+ ? sessionRecordSource
618
+ : 'absent',
381
619
  skills: filterRosterNames(skillNames, rosterSkills),
382
620
  commands: filterRosterNames(commandNames, rosterCommands),
383
621
  };