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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/rules/030-wave-execution.mdc +17 -1
- package/CHANGELOG.md +130 -412
- package/README.md +17 -12
- package/SECURITY.md +190 -27
- package/agents/AGENTS.md +20 -3
- package/agents/code-implementer.md +6 -6
- package/agents/db-specialist.md +1 -1
- package/agents/qa-strategist.md +31 -6
- package/agents/schemas/qa-strategist.schema.json +27 -0
- package/agents/schemas/test-writer.schema.json +60 -2
- package/agents/security-reviewer.md +1 -1
- package/agents/session-reviewer.md +1 -1
- package/agents/test-writer.md +29 -10
- package/agents/ui-developer.md +1 -1
- package/commands/contract-version-bump.md +28 -0
- package/commands/portfolio.md +1 -1
- package/docs/README.md +2 -1
- package/docs/USER-GUIDE.md +8 -3
- package/docs/ci-setup.md +121 -7
- package/docs/codex-setup.md +1 -1
- package/docs/components.md +7 -7
- package/docs/cursor-setup.md +22 -9
- package/docs/events-schema.md +5 -1
- package/docs/instruction-delivery.md +444 -0
- package/docs/pi-setup.md +1 -1
- package/docs/rule-authoring.md +58 -9
- package/docs/session-config-reference.md +306 -6
- package/docs/session-config-template.md +66 -3
- package/docs/telemetry/telemetry-claims.md +204 -0
- package/docs/telemetry.md +158 -0
- package/hooks/_lib/guard-source-loader.mjs +467 -0
- package/hooks/_lib/lock-bootstrap.mjs +21 -0
- package/hooks/_lib/vcs-create-matcher.mjs +119 -0
- package/hooks/config-protection.mjs +0 -0
- package/hooks/enforce-commands.mjs +10 -2
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +11 -2
- package/hooks/hooks-pi.json +10 -0
- package/hooks/hooks.json +21 -1
- package/hooks/on-session-end.mjs +178 -18
- package/hooks/on-session-start.mjs +23 -0
- package/hooks/post-bash-write-verify.mjs +977 -0
- package/hooks/post-subagent-discovery-validator.mjs +256 -41
- package/hooks/pre-bash-destructive-guard.mjs +525 -160
- package/hooks/pre-bash-issue-budget.mjs +167 -0
- package/hooks/pre-bash-sessions-ledger-guard.mjs +627 -0
- package/hooks/pre-bash-templates-first.mjs +96 -63
- package/hooks/skill-invocation-telemetry.mjs +109 -10
- package/hooks/subagent-telemetry.mjs +527 -37
- package/package.json +16 -3
- package/pi/prompts/contract-version-bump.md +12 -0
- package/rules/README.md +32 -0
- package/scripts/archive-closed-prds.mjs +12 -22
- package/scripts/autopilot-multi.mjs +103 -20
- package/scripts/backfill-abandoned-sessions.mjs +160 -4
- package/scripts/check-doc-consistency.sh +17 -1
- package/scripts/compute-grounding-injection.sh +18 -3
- package/scripts/dialectic-deriver.mjs +7 -2
- package/scripts/eval-session.mjs +50 -9
- package/scripts/fleet-instruction-scan.mjs +141 -0
- package/scripts/lib/auto-dialectic.mjs +11 -2
- package/scripts/lib/auto-dream.mjs +16 -5
- package/scripts/lib/autopilot/mr-draft.mjs +31 -1
- package/scripts/lib/autopilot/worktree-pipeline.mjs +113 -5
- package/scripts/lib/backlog-scan.mjs +39 -6
- package/scripts/lib/blocked-commands-policy.mjs +340 -0
- package/scripts/lib/build-live-signals.mjs +7 -4
- package/scripts/lib/ci-status-banner.mjs +75 -12
- package/scripts/lib/claude-md-budget-lint.mjs +283 -34
- package/scripts/lib/command-blocker.mjs +1013 -58
- package/scripts/lib/config/config-protection.mjs +2 -1
- package/scripts/lib/config/context-coverage.mjs +82 -0
- package/scripts/lib/config/drift-check.mjs +9 -1
- package/scripts/lib/config/gitlab-portfolio.mjs +1 -1
- package/scripts/lib/config/issue-budget.mjs +123 -0
- package/scripts/lib/config/moc-staleness.mjs +98 -0
- package/scripts/lib/config/reconcile.mjs +21 -0
- package/scripts/lib/config/section-extractor.mjs +121 -1
- package/scripts/lib/config/worktree-orphans.mjs +138 -0
- package/scripts/lib/config-schema.mjs +23 -3
- package/scripts/lib/config.mjs +32 -0
- package/scripts/lib/context-coverage-banner.mjs +223 -0
- package/scripts/lib/convergence-monitor.mjs +49 -3
- package/scripts/lib/description-surface.mjs +535 -0
- package/scripts/lib/dispatcher/enumerate.mjs +136 -30
- package/scripts/lib/dispatcher/rank.mjs +22 -8
- package/scripts/lib/ecosystem-wizard/config-writer.mjs +26 -24
- package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +1 -1
- package/scripts/lib/eval/engine.mjs +47 -5
- package/scripts/lib/events.mjs +59 -7
- package/scripts/lib/evolve/autonomy-verdict.mjs +5 -0
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +54 -7
- package/scripts/lib/gates/gate-full.mjs +15 -3
- package/scripts/lib/gates/gate-helpers.mjs +132 -6
- package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +28 -8
- package/scripts/lib/gitlab-portfolio/aggregator.mjs +8 -2
- package/scripts/lib/gitlab-portfolio/cli.mjs +1 -1
- package/scripts/lib/handover-gate.mjs +7 -3
- package/scripts/lib/harness-audit/categories/category4.mjs +22 -5
- package/scripts/lib/instruction-budget-guard.mjs +402 -51
- package/scripts/lib/io.mjs +345 -10
- package/scripts/lib/issue-budget.mjs +269 -0
- package/scripts/lib/issue-close-strip-labels.mjs +39 -9
- package/scripts/lib/label-scope.mjs +47 -0
- package/scripts/lib/learnings/schema.mjs +43 -3
- package/scripts/lib/lock-reaper.mjs +1 -2
- package/scripts/lib/memory-proposals/schema.mjs +36 -1
- package/scripts/lib/moc-staleness-banner.mjs +267 -0
- package/scripts/lib/peer-discovery.mjs +645 -0
- package/scripts/lib/pi-hook-bridge.mjs +146 -17
- package/scripts/lib/product-repo-detect.mjs +9 -8
- package/scripts/lib/project-hygiene.mjs +432 -0
- package/scripts/lib/quality-gate.mjs +167 -0
- package/scripts/lib/recommendations-v0.mjs +1 -1
- package/scripts/lib/reconcile/eligibility.mjs +1 -1
- package/scripts/lib/reconcile/emitter.mjs +23 -4
- package/scripts/lib/reconcile/engine.mjs +147 -39
- package/scripts/lib/reconcile/idempotency.mjs +114 -14
- package/scripts/lib/reconcile-nudge-banner.mjs +65 -9
- package/scripts/lib/resource-probe/evaluate.mjs +70 -4
- package/scripts/lib/resource-probe.mjs +19 -0
- package/scripts/lib/rule-loader.mjs +6 -0
- package/scripts/lib/scope-baseline.mjs +564 -0
- package/scripts/lib/scope-gate.mjs +399 -98
- package/scripts/lib/session-close-backfill.mjs +61 -6
- package/scripts/lib/session-end/phase-skip.mjs +1 -0
- package/scripts/lib/session-end/worktree-orphan-sweep.mjs +252 -0
- package/scripts/lib/session-id.mjs +221 -41
- package/scripts/lib/session-lock.mjs +304 -6
- package/scripts/lib/session-schema/constants.mjs +22 -3
- package/scripts/lib/session-schema/filters.mjs +88 -0
- package/scripts/lib/session-schema/validator.mjs +16 -0
- package/scripts/lib/session-schema.mjs +1 -0
- package/scripts/lib/sessions-integrity-banner.mjs +294 -0
- package/scripts/lib/sessions-staleness-banner.mjs +121 -12
- package/scripts/lib/skill-evolution/idempotency.mjs +135 -16
- package/scripts/lib/skill-evolution/mr-opener.mjs +9 -1
- package/scripts/lib/skill-health/join.mjs +35 -9
- package/scripts/lib/spiral-carryover.mjs +142 -30
- package/scripts/lib/state-md/mission-status.mjs +53 -3
- package/scripts/lib/subagents-schema.mjs +43 -9
- package/scripts/lib/telemetry/anon-id.mjs +141 -0
- package/scripts/lib/telemetry/consent.mjs +299 -0
- package/scripts/lib/telemetry/paths.mjs +27 -0
- package/scripts/lib/telemetry/queue.mjs +287 -0
- package/scripts/lib/telemetry/schema.mjs +384 -0
- package/scripts/lib/telemetry/sync.mjs +312 -0
- package/scripts/lib/test-runner/issue-reconcile.mjs +53 -13
- package/scripts/lib/tests-src-ratio.mjs +484 -0
- package/scripts/lib/validate/check-agents.mjs +56 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +244 -10
- package/scripts/lib/validate/check-rules.mjs +217 -35
- package/scripts/lib/validate/check-test-value-bans.mjs +782 -0
- package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
- package/scripts/lib/validate-vendored-rules.mjs +10 -2
- package/scripts/lib/vault-archive.mjs +17 -2
- package/scripts/lib/vault-backfill/glab.mjs +8 -0
- package/scripts/lib/vault-mirror/process.mjs +30 -0
- package/scripts/lib/vault-mirror/render-sessions.mjs +293 -36
- package/scripts/lib/vault-status/board-writer.mjs +63 -5
- package/scripts/lib/vault-status/narrative-mirror.mjs +13 -7
- package/scripts/lib/vcs-repo-spec.mjs +362 -0
- package/scripts/lib/wave-resource-gate.mjs +115 -11
- package/scripts/lib/worktree/listing.mjs +44 -7
- package/scripts/mcp-server.sh +32 -6
- package/scripts/measure-context-overhead.sh +151 -0
- package/scripts/memory-propose.mjs +72 -9
- package/scripts/print-applicable-rules.mjs +51 -12
- package/scripts/release.mjs +534 -0
- package/scripts/run-quality-gate.mjs +123 -5
- package/scripts/telemetry.mjs +250 -0
- package/scripts/validate-wave-scope.mjs +182 -17
- package/scripts/vault-integration-watcher.mjs +32 -10
- package/skills/_shared/config-reading.md +2 -2
- package/skills/bootstrap/fast-template.md +1 -1
- package/skills/claude-md-drift-check/checker.mjs +145 -28
- package/skills/contract-version-bump/SKILL.md +219 -0
- package/skills/discovery/SKILL.md +4 -4
- package/skills/discovery/issue-templates.md +11 -11
- package/skills/discovery/probes-audit.md +1 -1
- package/skills/discovery/probes-feature.md +1 -1
- package/skills/discovery/probes-session.md +26 -5
- package/skills/ecosystem-health/SKILL.md +1 -1
- package/skills/ecosystem-health/wizard.md +4 -4
- package/skills/evolve/SKILL.md +1 -0
- package/skills/gitlab-ops/SKILL.md +20 -12
- package/skills/gitlab-portfolio/SKILL.md +2 -2
- package/skills/hook-development/SKILL.md +1 -1
- package/skills/mode-selector/SKILL.md +1 -1
- package/skills/npm-publish/SKILL.md +97 -0
- package/skills/plan/SKILL.md +5 -5
- package/skills/plan/mode-feature.md +4 -4
- package/skills/plan/mode-new.md +10 -10
- package/skills/plan/mode-retro.md +1 -1
- package/skills/quality-gates/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +21 -4
- package/skills/session-end/SKILL.md +108 -14
- package/skills/session-end/discovery-scan.md +4 -2
- package/skills/session-end/drift-operations.md +4 -4
- package/skills/session-end/metrics-collection.md +13 -0
- package/skills/session-end/phase-3-2-docs-verification.md +1 -1
- package/skills/session-end/phase-3-6-tail.md +2 -1
- package/skills/session-end/plan-verification.md +5 -2
- package/skills/session-end/vault-operations.md +1 -1
- package/skills/session-end/verification-checklist.md +1 -1
- package/skills/session-plan/SKILL.md +6 -2
- package/skills/session-plan/wave-template.md +2 -0
- package/skills/session-start/SKILL.md +149 -7
- package/skills/session-start/phase-4-5-resource-health.md +15 -2
- package/skills/test-runner/SKILL.md +2 -2
- package/skills/vault-sync/SKILL.md +1 -1
- package/skills/vault-sync/package-lock.json +3 -3
- package/skills/vault-sync/validator.mjs +228 -40
- package/skills/wave-executor/SKILL.md +5 -2
- package/skills/wave-executor/circuit-breaker.md +2 -0
- package/skills/wave-executor/wave-loop.md +163 -10
- 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
|
+
});
|