session-orchestrator 3.16.0 → 3.19.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 (220) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.cursor/rules/030-wave-execution.mdc +17 -1
  5. package/CHANGELOG.md +130 -412
  6. package/README.md +17 -12
  7. package/SECURITY.md +190 -27
  8. package/agents/AGENTS.md +20 -3
  9. package/agents/code-implementer.md +6 -6
  10. package/agents/db-specialist.md +1 -1
  11. package/agents/qa-strategist.md +31 -6
  12. package/agents/schemas/qa-strategist.schema.json +27 -0
  13. package/agents/schemas/test-writer.schema.json +60 -2
  14. package/agents/security-reviewer.md +1 -1
  15. package/agents/session-reviewer.md +1 -1
  16. package/agents/test-writer.md +29 -10
  17. package/agents/ui-developer.md +1 -1
  18. package/commands/contract-version-bump.md +28 -0
  19. package/commands/portfolio.md +1 -1
  20. package/docs/README.md +2 -1
  21. package/docs/USER-GUIDE.md +8 -3
  22. package/docs/ci-setup.md +121 -7
  23. package/docs/codex-setup.md +1 -1
  24. package/docs/components.md +7 -7
  25. package/docs/cursor-setup.md +22 -9
  26. package/docs/events-schema.md +5 -1
  27. package/docs/instruction-delivery.md +444 -0
  28. package/docs/pi-setup.md +1 -1
  29. package/docs/rule-authoring.md +58 -9
  30. package/docs/session-config-reference.md +306 -6
  31. package/docs/session-config-template.md +66 -3
  32. package/docs/telemetry/telemetry-claims.md +204 -0
  33. package/docs/telemetry.md +158 -0
  34. package/hooks/_lib/guard-source-loader.mjs +467 -0
  35. package/hooks/_lib/lock-bootstrap.mjs +21 -0
  36. package/hooks/_lib/vcs-create-matcher.mjs +119 -0
  37. package/hooks/config-protection.mjs +0 -0
  38. package/hooks/enforce-commands.mjs +10 -2
  39. package/hooks/hooks-codex.json +1 -1
  40. package/hooks/hooks-cursor.json +11 -2
  41. package/hooks/hooks-pi.json +10 -0
  42. package/hooks/hooks.json +21 -1
  43. package/hooks/on-session-end.mjs +178 -18
  44. package/hooks/on-session-start.mjs +23 -0
  45. package/hooks/post-bash-write-verify.mjs +977 -0
  46. package/hooks/post-subagent-discovery-validator.mjs +256 -41
  47. package/hooks/pre-bash-destructive-guard.mjs +525 -160
  48. package/hooks/pre-bash-issue-budget.mjs +167 -0
  49. package/hooks/pre-bash-sessions-ledger-guard.mjs +627 -0
  50. package/hooks/pre-bash-templates-first.mjs +96 -63
  51. package/hooks/skill-invocation-telemetry.mjs +109 -10
  52. package/hooks/subagent-telemetry.mjs +527 -37
  53. package/package.json +16 -3
  54. package/pi/prompts/contract-version-bump.md +12 -0
  55. package/rules/README.md +32 -0
  56. package/scripts/archive-closed-prds.mjs +12 -22
  57. package/scripts/autopilot-multi.mjs +103 -20
  58. package/scripts/backfill-abandoned-sessions.mjs +160 -4
  59. package/scripts/check-doc-consistency.sh +17 -1
  60. package/scripts/compute-grounding-injection.sh +18 -3
  61. package/scripts/dialectic-deriver.mjs +7 -2
  62. package/scripts/eval-session.mjs +50 -9
  63. package/scripts/fleet-instruction-scan.mjs +141 -0
  64. package/scripts/lib/auto-dialectic.mjs +11 -2
  65. package/scripts/lib/auto-dream.mjs +16 -5
  66. package/scripts/lib/autopilot/mr-draft.mjs +31 -1
  67. package/scripts/lib/autopilot/worktree-pipeline.mjs +113 -5
  68. package/scripts/lib/backlog-scan.mjs +39 -6
  69. package/scripts/lib/blocked-commands-policy.mjs +340 -0
  70. package/scripts/lib/build-live-signals.mjs +7 -4
  71. package/scripts/lib/ci-status-banner.mjs +75 -12
  72. package/scripts/lib/claude-md-budget-lint.mjs +283 -34
  73. package/scripts/lib/command-blocker.mjs +1013 -58
  74. package/scripts/lib/config/config-protection.mjs +2 -1
  75. package/scripts/lib/config/context-coverage.mjs +82 -0
  76. package/scripts/lib/config/drift-check.mjs +9 -1
  77. package/scripts/lib/config/gitlab-portfolio.mjs +1 -1
  78. package/scripts/lib/config/issue-budget.mjs +123 -0
  79. package/scripts/lib/config/moc-staleness.mjs +98 -0
  80. package/scripts/lib/config/reconcile.mjs +21 -0
  81. package/scripts/lib/config/section-extractor.mjs +121 -1
  82. package/scripts/lib/config/worktree-orphans.mjs +138 -0
  83. package/scripts/lib/config-schema.mjs +23 -3
  84. package/scripts/lib/config.mjs +32 -0
  85. package/scripts/lib/context-coverage-banner.mjs +223 -0
  86. package/scripts/lib/convergence-monitor.mjs +49 -3
  87. package/scripts/lib/description-surface.mjs +535 -0
  88. package/scripts/lib/dispatcher/enumerate.mjs +136 -30
  89. package/scripts/lib/dispatcher/rank.mjs +22 -8
  90. package/scripts/lib/ecosystem-wizard/config-writer.mjs +26 -24
  91. package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +1 -1
  92. package/scripts/lib/eval/engine.mjs +47 -5
  93. package/scripts/lib/events.mjs +59 -7
  94. package/scripts/lib/evolve/autonomy-verdict.mjs +5 -0
  95. package/scripts/lib/evolve/autopilot-effectiveness.mjs +54 -7
  96. package/scripts/lib/gates/gate-full.mjs +15 -3
  97. package/scripts/lib/gates/gate-helpers.mjs +132 -6
  98. package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +28 -8
  99. package/scripts/lib/gitlab-portfolio/aggregator.mjs +8 -2
  100. package/scripts/lib/gitlab-portfolio/cli.mjs +1 -1
  101. package/scripts/lib/handover-gate.mjs +7 -3
  102. package/scripts/lib/harness-audit/categories/category4.mjs +22 -5
  103. package/scripts/lib/instruction-budget-guard.mjs +402 -51
  104. package/scripts/lib/io.mjs +345 -10
  105. package/scripts/lib/issue-budget.mjs +269 -0
  106. package/scripts/lib/issue-close-strip-labels.mjs +39 -9
  107. package/scripts/lib/label-scope.mjs +47 -0
  108. package/scripts/lib/learnings/schema.mjs +43 -3
  109. package/scripts/lib/lock-reaper.mjs +1 -2
  110. package/scripts/lib/memory-proposals/schema.mjs +36 -1
  111. package/scripts/lib/moc-staleness-banner.mjs +267 -0
  112. package/scripts/lib/peer-discovery.mjs +645 -0
  113. package/scripts/lib/pi-hook-bridge.mjs +146 -17
  114. package/scripts/lib/product-repo-detect.mjs +9 -8
  115. package/scripts/lib/project-hygiene.mjs +432 -0
  116. package/scripts/lib/quality-gate.mjs +167 -0
  117. package/scripts/lib/recommendations-v0.mjs +1 -1
  118. package/scripts/lib/reconcile/eligibility.mjs +1 -1
  119. package/scripts/lib/reconcile/emitter.mjs +23 -4
  120. package/scripts/lib/reconcile/engine.mjs +147 -39
  121. package/scripts/lib/reconcile/idempotency.mjs +114 -14
  122. package/scripts/lib/reconcile-nudge-banner.mjs +65 -9
  123. package/scripts/lib/resource-probe/evaluate.mjs +70 -4
  124. package/scripts/lib/resource-probe.mjs +19 -0
  125. package/scripts/lib/rule-loader.mjs +6 -0
  126. package/scripts/lib/scope-baseline.mjs +564 -0
  127. package/scripts/lib/scope-gate.mjs +399 -98
  128. package/scripts/lib/session-close-backfill.mjs +61 -6
  129. package/scripts/lib/session-end/phase-skip.mjs +1 -0
  130. package/scripts/lib/session-end/worktree-orphan-sweep.mjs +252 -0
  131. package/scripts/lib/session-id.mjs +221 -41
  132. package/scripts/lib/session-lock.mjs +304 -6
  133. package/scripts/lib/session-schema/constants.mjs +22 -3
  134. package/scripts/lib/session-schema/filters.mjs +88 -0
  135. package/scripts/lib/session-schema/validator.mjs +16 -0
  136. package/scripts/lib/session-schema.mjs +1 -0
  137. package/scripts/lib/sessions-integrity-banner.mjs +294 -0
  138. package/scripts/lib/sessions-staleness-banner.mjs +121 -12
  139. package/scripts/lib/skill-evolution/idempotency.mjs +135 -16
  140. package/scripts/lib/skill-evolution/mr-opener.mjs +9 -1
  141. package/scripts/lib/skill-health/join.mjs +35 -9
  142. package/scripts/lib/spiral-carryover.mjs +142 -30
  143. package/scripts/lib/state-md/mission-status.mjs +53 -3
  144. package/scripts/lib/subagents-schema.mjs +43 -9
  145. package/scripts/lib/telemetry/anon-id.mjs +141 -0
  146. package/scripts/lib/telemetry/consent.mjs +299 -0
  147. package/scripts/lib/telemetry/paths.mjs +27 -0
  148. package/scripts/lib/telemetry/queue.mjs +287 -0
  149. package/scripts/lib/telemetry/schema.mjs +384 -0
  150. package/scripts/lib/telemetry/sync.mjs +312 -0
  151. package/scripts/lib/test-runner/issue-reconcile.mjs +53 -13
  152. package/scripts/lib/tests-src-ratio.mjs +484 -0
  153. package/scripts/lib/validate/check-agents.mjs +56 -0
  154. package/scripts/lib/validate/check-hooks-symmetry.mjs +244 -10
  155. package/scripts/lib/validate/check-rules.mjs +217 -35
  156. package/scripts/lib/validate/check-test-value-bans.mjs +782 -0
  157. package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
  158. package/scripts/lib/validate-vendored-rules.mjs +10 -2
  159. package/scripts/lib/vault-archive.mjs +17 -2
  160. package/scripts/lib/vault-backfill/glab.mjs +8 -0
  161. package/scripts/lib/vault-mirror/process.mjs +30 -0
  162. package/scripts/lib/vault-mirror/render-sessions.mjs +293 -36
  163. package/scripts/lib/vault-status/board-writer.mjs +63 -5
  164. package/scripts/lib/vault-status/narrative-mirror.mjs +13 -7
  165. package/scripts/lib/vcs-repo-spec.mjs +362 -0
  166. package/scripts/lib/wave-resource-gate.mjs +115 -11
  167. package/scripts/lib/worktree/listing.mjs +44 -7
  168. package/scripts/mcp-server.sh +32 -6
  169. package/scripts/measure-context-overhead.sh +151 -0
  170. package/scripts/memory-propose.mjs +72 -9
  171. package/scripts/print-applicable-rules.mjs +51 -12
  172. package/scripts/release.mjs +534 -0
  173. package/scripts/run-quality-gate.mjs +123 -5
  174. package/scripts/telemetry.mjs +250 -0
  175. package/scripts/validate-wave-scope.mjs +182 -17
  176. package/scripts/vault-integration-watcher.mjs +32 -10
  177. package/skills/_shared/config-reading.md +2 -2
  178. package/skills/bootstrap/fast-template.md +1 -1
  179. package/skills/claude-md-drift-check/checker.mjs +145 -28
  180. package/skills/contract-version-bump/SKILL.md +219 -0
  181. package/skills/discovery/SKILL.md +4 -4
  182. package/skills/discovery/issue-templates.md +11 -11
  183. package/skills/discovery/probes-audit.md +1 -1
  184. package/skills/discovery/probes-feature.md +1 -1
  185. package/skills/discovery/probes-session.md +26 -5
  186. package/skills/ecosystem-health/SKILL.md +1 -1
  187. package/skills/ecosystem-health/wizard.md +4 -4
  188. package/skills/evolve/SKILL.md +1 -0
  189. package/skills/gitlab-ops/SKILL.md +20 -12
  190. package/skills/gitlab-portfolio/SKILL.md +2 -2
  191. package/skills/hook-development/SKILL.md +1 -1
  192. package/skills/mode-selector/SKILL.md +1 -1
  193. package/skills/npm-publish/SKILL.md +97 -0
  194. package/skills/plan/SKILL.md +5 -5
  195. package/skills/plan/mode-feature.md +4 -4
  196. package/skills/plan/mode-new.md +10 -10
  197. package/skills/plan/mode-retro.md +1 -1
  198. package/skills/quality-gates/SKILL.md +1 -1
  199. package/skills/reconcile/SKILL.md +21 -4
  200. package/skills/session-end/SKILL.md +108 -14
  201. package/skills/session-end/discovery-scan.md +4 -2
  202. package/skills/session-end/drift-operations.md +4 -4
  203. package/skills/session-end/metrics-collection.md +13 -0
  204. package/skills/session-end/phase-3-2-docs-verification.md +1 -1
  205. package/skills/session-end/phase-3-6-tail.md +2 -1
  206. package/skills/session-end/plan-verification.md +5 -2
  207. package/skills/session-end/vault-operations.md +1 -1
  208. package/skills/session-end/verification-checklist.md +1 -1
  209. package/skills/session-plan/SKILL.md +6 -2
  210. package/skills/session-plan/wave-template.md +2 -0
  211. package/skills/session-start/SKILL.md +149 -7
  212. package/skills/session-start/phase-4-5-resource-health.md +15 -2
  213. package/skills/test-runner/SKILL.md +2 -2
  214. package/skills/vault-sync/SKILL.md +1 -1
  215. package/skills/vault-sync/package-lock.json +3 -3
  216. package/skills/vault-sync/validator.mjs +228 -40
  217. package/skills/wave-executor/SKILL.md +5 -2
  218. package/skills/wave-executor/circuit-breaker.md +2 -0
  219. package/skills/wave-executor/wave-loop.md +163 -10
  220. package/templates/_shared/loop.md +4 -4
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * pre-bash-issue-budget.mjs — PreToolUse hook: caps how many issues one
4
+ * session may create via `gh|glab issue create|new`.
5
+ *
6
+ * Sibling of pre-bash-templates-first.mjs (#519); both share the PreToolUse
7
+ * Bash matcher and run sequentially. The create-command matcher is IMPORTED
8
+ * from hooks/_lib/vcs-create-matcher.mjs rather than duplicated, so the two
9
+ * hooks can never drift on what counts as an issue-create call.
10
+ *
11
+ * Where templates-first asks "did you read a template?" (a QUALITY gate), this
12
+ * hook asks "how many have you already filed?" (a QUANTITY gate). The existing
13
+ * `discovery-severity-threshold` / `discovery-confidence-threshold` config keys
14
+ * do not answer the second question — they are per-finding filters, their `low`
15
+ * default filters nothing, and the largest producers never read them.
16
+ *
17
+ * Decision flow:
18
+ * G1 tool filter — only Bash is gated.
19
+ * G2 command is a non-empty string.
20
+ * G3 matcher — `gh|glab … issue create|new` only. PR/MR creation passes.
21
+ * G4 config — `issue-budget` from CLAUDE.md/AGENTS.md. `mode: off` → allow.
22
+ * G5 exemption — priority::critical / carryover class / broken-window /
23
+ * the overflow collector itself bypass the cap unconditionally, keeping
24
+ * the session-end promises at SKILL.md:319 and :1113 intact.
25
+ * G6 charge the counter in .orchestrator/runtime/issue-budget.json.
26
+ * under cap → allow; over cap + `warn` → allow with stderr notice;
27
+ * over cap + `strict` → park in `overflow[]`, then deny via emitDeny.
28
+ *
29
+ * Fail-safe posture: any internal exception is swallowed in main().catch and
30
+ * the hook exits 0 (allow). Same rationale as pre-bash-templates-first.mjs —
31
+ * a budget gate that crashes must not wedge a session; the worst case is a
32
+ * missed enforcement.
33
+ *
34
+ * Exit codes:
35
+ * 0 — every path. Pass-through (G1-G5 short-circuits, under cap, warn mode,
36
+ * error) emits nothing; the strict over-cap path emits the deny envelope
37
+ * on stdout. Exit 2 is NEVER used: Claude Code discards stdout on exit 2,
38
+ * which would throw away the deny envelope entirely (#906).
39
+ */
40
+
41
+ import { readStdin, emitAllow, emitDeny } from '../scripts/lib/io.mjs';
42
+ import { resolveProjectDir } from '../scripts/lib/platform.mjs';
43
+ import { readJson } from '../scripts/lib/common.mjs';
44
+ import { isIssueCreate, extractTitle } from './_lib/vcs-create-matcher.mjs';
45
+ import {
46
+ loadIssueBudgetConfig,
47
+ chargeIssueBudget,
48
+ formatBlockReason,
49
+ } from '../scripts/lib/issue-budget.mjs';
50
+
51
+ import { shouldRunHook } from './_lib/profile-gate.mjs';
52
+ import { existsSync } from 'node:fs';
53
+ import path from 'node:path';
54
+
55
+ // Opt-out per session via SO_DISABLED_HOOKS=pre-bash-issue-budget; the
56
+ // "minimal"/"off" profiles disable it like every other non-core hook.
57
+ if (!shouldRunHook('pre-bash-issue-budget')) process.exit(0);
58
+
59
+ // ---------------------------------------------------------------------------
60
+ // Helpers
61
+ // ---------------------------------------------------------------------------
62
+
63
+ /**
64
+ * Pull the session_id from the hook stdin payload, with a single fallback to
65
+ * the persisted file written by on-session-start.mjs. Mirrors the resolution
66
+ * in pre-bash-templates-first.mjs. Returns null when neither source yields a
67
+ * string — the counter then degrades to a per-repo counter, which still caps.
68
+ *
69
+ * @param {object|null} input
70
+ * @param {string|null} projectDir
71
+ * @returns {Promise<string|null>}
72
+ */
73
+ async function resolveSessionId(input, projectDir) {
74
+ const fromStdin = input?.session_id ?? input?.sessionId ?? null;
75
+ if (typeof fromStdin === 'string' && fromStdin.length > 0) return fromStdin;
76
+
77
+ if (!projectDir) return null;
78
+ const persisted = path.join(projectDir, '.orchestrator', 'current-session.json');
79
+ if (!existsSync(persisted)) return null;
80
+ try {
81
+ const data = await readJson(persisted);
82
+ if (data && typeof data === 'object') {
83
+ const sid = data.session_id ?? data.sessionId ?? null;
84
+ if (typeof sid === 'string' && sid.length > 0) return sid;
85
+ }
86
+ } catch {
87
+ // ignore — null below
88
+ }
89
+ return null;
90
+ }
91
+
92
+ // ---------------------------------------------------------------------------
93
+ // Main
94
+ // ---------------------------------------------------------------------------
95
+
96
+ async function main() {
97
+ const input = await readStdin();
98
+ if (!input) return emitAllow();
99
+
100
+ // G1 — only Bash is gated.
101
+ if (input.tool_name !== 'Bash') return emitAllow();
102
+
103
+ // G2 — command must be a non-empty string.
104
+ const command = input?.tool_input?.command;
105
+ if (typeof command !== 'string' || command.length === 0) return emitAllow();
106
+
107
+ // G3 — shared matcher. Only ISSUE creation is capped; `pr`/`mr` create pass.
108
+ if (!isIssueCreate(command)) return emitAllow();
109
+
110
+ const projectDir = resolveProjectDir() || process.cwd();
111
+
112
+ // G4 — config.
113
+ const config = loadIssueBudgetConfig(projectDir);
114
+ if (config.mode === 'off') return emitAllow();
115
+
116
+ const sessionId = await resolveSessionId(input, projectDir);
117
+
118
+ // G5 + G6 — exemption check and counter charge live in the shared core so
119
+ // the programmatic path (scripts/lib/spiral-carryover.mjs runCli) decides
120
+ // identically.
121
+ const verdict = chargeIssueBudget({
122
+ repoRoot: projectDir,
123
+ sessionId,
124
+ command,
125
+ title: extractTitle(command),
126
+ config,
127
+ });
128
+
129
+ if (verdict.decision === 'exempt') {
130
+ process.stderr.write(
131
+ `ℹ pre-bash-issue-budget: exempt (${verdict.reason}) — cap not charged ` +
132
+ `(${verdict.count}/${verdict.max})\n`,
133
+ );
134
+ return emitAllow();
135
+ }
136
+
137
+ if (verdict.decision === 'warn') {
138
+ process.stderr.write(
139
+ `⚠ pre-bash-issue-budget: session cap exceeded — ${verdict.count}/${verdict.max} ` +
140
+ `issues created (mode: warn — allowing). Set \`issue-budget.mode: strict\` to enforce.\n`,
141
+ );
142
+ return emitAllow();
143
+ }
144
+
145
+ if (verdict.decision === 'block') {
146
+ // Single channel (#906). formatBlockReason's multi-line text — overflow
147
+ // store path, the [Backlog-Sammel] fold-in promise, the exemption list and
148
+ // the cap-raising hint — used to go to stderr AND to a duplicated `exit 2`
149
+ // stdout envelope, the mixed form the hook docs forbid. None of that
150
+ // guidance is lost: it now rides in permissionDecisionReason, which is fed
151
+ // to Claude (the actor that must re-file or defer the issue), while the
152
+ // operator gets the first line as the systemMessage headline. Under exit 0
153
+ // a stderr write would only reach the debug log — dead, but alive-looking.
154
+ emitDeny(formatBlockReason(verdict));
155
+ }
156
+
157
+ // 'allow' / 'off'
158
+ return emitAllow();
159
+ }
160
+
161
+ // Top-level error handler — fail open, same posture as the sibling hooks.
162
+ main().catch((e) => {
163
+ process.stderr.write(
164
+ `⚠ pre-bash-issue-budget: internal error — ${e?.message || e}\n`,
165
+ );
166
+ process.exit(0);
167
+ });