session-orchestrator 5.1.0 → 5.3.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/.agents/skills/architecture/SKILL.md +3 -1
- package/.agents/skills/autopilot/SKILL.md +6 -1
- package/.agents/skills/autopilot/agents/openai.yaml +5 -0
- package/.agents/skills/bootstrap/SKILL.md +7 -1
- package/.agents/skills/bootstrap/agents/openai.yaml +5 -0
- package/.agents/skills/brainstorm/SKILL.md +8 -1
- package/.agents/skills/brainstorm/agents/openai.yaml +5 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +3 -1
- package/.agents/skills/close/SKILL.md +21 -0
- package/.agents/skills/close/agents/openai.yaml +5 -0
- package/.agents/skills/convergence-monitoring/SKILL.md +4 -2
- package/.agents/skills/debug/SKILL.md +7 -1
- package/.agents/skills/debug/agents/openai.yaml +5 -0
- package/.agents/skills/discovery/SKILL.md +7 -2
- package/.agents/skills/discovery/agents/openai.yaml +5 -0
- package/.agents/skills/dispatcher/SKILL.md +7 -1
- package/.agents/skills/dispatcher/agents/openai.yaml +5 -0
- package/.agents/skills/docs-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ecosystem-health/SKILL.md +3 -1
- package/.agents/skills/eli5/SKILL.md +7 -1
- package/.agents/skills/eli5/agents/openai.yaml +5 -0
- package/.agents/skills/eval/SKILL.md +7 -2
- package/.agents/skills/eval/agents/openai.yaml +5 -0
- package/.agents/skills/evolve/SKILL.md +8 -3
- package/.agents/skills/evolve/agents/openai.yaml +5 -0
- package/.agents/skills/frontmatter-guard/SKILL.md +3 -1
- package/.agents/skills/gitlab-ops/SKILL.md +3 -1
- package/.agents/skills/gitlab-portfolio/SKILL.md +3 -1
- package/.agents/skills/go/SKILL.md +22 -0
- package/.agents/skills/go/agents/openai.yaml +5 -0
- package/.agents/skills/grill/SKILL.md +7 -1
- package/.agents/skills/grill/agents/openai.yaml +5 -0
- package/.agents/skills/harness-audit/SKILL.md +20 -0
- package/.agents/skills/harness-audit/agents/openai.yaml +5 -0
- package/.agents/skills/hook-development/SKILL.md +3 -1
- package/.agents/skills/mcp-builder/SKILL.md +3 -1
- package/.agents/skills/memory-cleanup/SKILL.md +6 -1
- package/.agents/skills/memory-cleanup/agents/openai.yaml +5 -0
- package/.agents/skills/mode-selector/SKILL.md +3 -1
- package/.agents/skills/npm-publish/SKILL.md +4 -2
- package/.agents/skills/peekaboo-driver/SKILL.md +3 -1
- package/.agents/skills/persona-panel/SKILL.md +6 -1
- package/.agents/skills/persona-panel/agents/openai.yaml +5 -0
- package/.agents/skills/plan/SKILL.md +8 -2
- package/.agents/skills/plan/agents/openai.yaml +5 -0
- package/.agents/skills/playwright-driver/SKILL.md +3 -1
- package/.agents/skills/portfolio/SKILL.md +21 -0
- package/.agents/skills/portfolio/agents/openai.yaml +5 -0
- package/.agents/skills/quality-gates/SKILL.md +3 -1
- package/.agents/skills/reconcile/SKILL.md +6 -1
- package/.agents/skills/reconcile/agents/openai.yaml +5 -0
- package/.agents/skills/release/SKILL.md +22 -0
- package/.agents/skills/release/agents/openai.yaml +5 -0
- package/.agents/skills/remote-offload/SKILL.md +3 -1
- package/.agents/skills/repo-audit/SKILL.md +6 -1
- package/.agents/skills/repo-audit/agents/openai.yaml +5 -0
- package/.agents/skills/session/SKILL.md +21 -0
- package/.agents/skills/session/agents/openai.yaml +5 -0
- package/.agents/skills/session-end/SKILL.md +3 -1
- package/.agents/skills/session-plan/SKILL.md +3 -1
- package/.agents/skills/session-start/SKILL.md +3 -1
- package/.agents/skills/spinout/SKILL.md +6 -1
- package/.agents/skills/spinout/agents/openai.yaml +5 -0
- package/.agents/skills/sunset-review/SKILL.md +7 -1
- package/.agents/skills/sunset-review/agents/openai.yaml +5 -0
- package/.agents/skills/templates-ack/SKILL.md +21 -0
- package/.agents/skills/templates-ack/agents/openai.yaml +5 -0
- package/.agents/skills/test/SKILL.md +21 -0
- package/.agents/skills/test/agents/openai.yaml +5 -0
- package/.agents/skills/test-runner/SKILL.md +3 -1
- package/.agents/skills/tmux-layout/SKILL.md +3 -1
- package/.agents/skills/using-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ux-grill/SKILL.md +7 -1
- package/.agents/skills/ux-grill/agents/openai.yaml +5 -0
- package/.agents/skills/vault-mirror/SKILL.md +3 -1
- package/.agents/skills/vault-sync/SKILL.md +3 -1
- package/.agents/skills/wave-executor/SKILL.md +3 -1
- package/.agents/skills/write-executable-plan/SKILL.md +3 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +4 -4
- package/.codex-plugin/skills/autopilot/SKILL.md +5 -4
- package/.codex-plugin/skills/bootstrap/SKILL.md +8 -4
- package/.codex-plugin/skills/brainstorm/SKILL.md +11 -4
- package/.codex-plugin/skills/close/SKILL.md +3 -3
- package/.codex-plugin/skills/convergence-monitoring/SKILL.md +1 -1
- package/.codex-plugin/skills/debug/SKILL.md +11 -4
- package/.codex-plugin/skills/discovery/SKILL.md +8 -4
- package/.codex-plugin/skills/dispatcher/SKILL.md +4 -4
- package/.codex-plugin/skills/eli5/SKILL.md +9 -4
- package/.codex-plugin/skills/eval/SKILL.md +9 -4
- package/.codex-plugin/skills/evolve/SKILL.md +9 -4
- package/.codex-plugin/skills/go/SKILL.md +3 -3
- package/.codex-plugin/skills/grill/SKILL.md +11 -4
- package/.codex-plugin/skills/harness-audit/SKILL.md +4 -3
- package/.codex-plugin/skills/memory-cleanup/SKILL.md +9 -4
- package/.codex-plugin/skills/npm-publish/SKILL.md +1 -1
- package/.codex-plugin/skills/persona-panel/SKILL.md +5 -5
- package/.codex-plugin/skills/plan/SKILL.md +8 -4
- package/.codex-plugin/skills/portfolio/SKILL.md +3 -3
- package/.codex-plugin/skills/reconcile/SKILL.md +9 -4
- package/.codex-plugin/skills/release/SKILL.md +3 -3
- package/.codex-plugin/skills/repo-audit/SKILL.md +6 -4
- package/.codex-plugin/skills/session/SKILL.md +1 -1
- package/.codex-plugin/skills/spinout/SKILL.md +4 -4
- package/.codex-plugin/skills/sunset-review/SKILL.md +5 -4
- package/.codex-plugin/skills/test/SKILL.md +3 -3
- package/.codex-plugin/skills/ux-grill/SKILL.md +11 -4
- package/.cursor/commands/autopilot.md +4 -4
- package/.cursor/commands/bootstrap.md +5 -4
- package/.cursor/commands/brainstorm.md +5 -4
- package/.cursor/commands/close.md +4 -3
- package/.cursor/commands/debug.md +4 -4
- package/.cursor/commands/discovery.md +4 -4
- package/.cursor/commands/dispatcher.md +4 -4
- package/.cursor/commands/eli5.md +4 -4
- package/.cursor/commands/eval.md +4 -4
- package/.cursor/commands/evolve.md +4 -4
- package/.cursor/commands/go.md +4 -3
- package/.cursor/commands/grill.md +4 -4
- package/.cursor/commands/harness-audit.md +3 -3
- package/.cursor/commands/memory-cleanup.md +4 -4
- package/.cursor/commands/persona-panel.md +4 -4
- package/.cursor/commands/plan.md +5 -4
- package/.cursor/commands/portfolio.md +3 -3
- package/.cursor/commands/reconcile.md +4 -4
- package/.cursor/commands/release.md +4 -3
- package/.cursor/commands/repo-audit.md +4 -4
- package/.cursor/commands/session.md +1 -1
- package/.cursor/commands/spinout.md +4 -4
- package/.cursor/commands/sunset-review.md +4 -4
- package/.cursor/commands/test.md +3 -3
- package/.cursor/commands/ux-grill.md +4 -4
- package/.cursor/rules/000-session-orchestrator.mdc +0 -2
- package/.cursor/rules/010-session-workflow.mdc +2 -2
- package/.cursor/rules/050-plan.mdc +1 -1
- package/.cursor/skills/bootstrap/SKILL.md +1 -0
- package/.cursor/skills/close/SKILL.md +13 -0
- package/.cursor/skills/convergence-monitoring/SKILL.md +1 -0
- package/.cursor/skills/debug/SKILL.md +0 -1
- package/.cursor/skills/discovery/SKILL.md +0 -1
- package/.cursor/skills/dispatcher/SKILL.md +0 -1
- package/.cursor/skills/eli5/SKILL.md +0 -1
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/evolve/SKILL.md +0 -1
- package/.cursor/skills/go/SKILL.md +13 -0
- package/.cursor/skills/grill/SKILL.md +0 -1
- package/.cursor/skills/harness-audit/SKILL.md +12 -0
- package/.cursor/skills/npm-publish/SKILL.md +1 -0
- package/.cursor/skills/portfolio/SKILL.md +12 -0
- package/.cursor/skills/release/SKILL.md +13 -0
- package/.cursor/skills/repo-audit/SKILL.md +0 -1
- package/.cursor/skills/sunset-review/SKILL.md +0 -1
- package/.cursor/skills/test/SKILL.md +12 -0
- package/.cursor/skills/ux-grill/SKILL.md +0 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/.orchestrator/policy/blocked-commands.json +13 -4
- package/AGENTS.md +3 -2
- package/CHANGELOG.md +197 -0
- package/README.md +11 -9
- package/SECURITY.md +12 -0
- package/agents/dialectic-deriver.md +13 -10
- package/agents/eval-judge.md +67 -45
- package/agents/skill-applied-judge.md +34 -19
- package/commands/session.md +17 -3
- package/docs/baseline.md +12 -6
- package/docs/ci-setup.md +53 -0
- package/docs/codex-setup.md +15 -3
- package/docs/components.md +13 -6
- package/docs/events-schema.md +59 -9
- package/docs/install.md +16 -0
- package/docs/persona-panel.md +1 -1
- package/docs/pi-setup.md +1 -1
- package/docs/rule-authoring.md +135 -14
- package/docs/scope-collision-guard.md +2 -0
- package/docs/session-config-reference.md +106 -11
- package/docs/session-config-template.md +31 -2
- package/docs/telemetry.md +2 -0
- package/hooks/_lib/hook-import-set.json +125 -8
- package/hooks/_lib/subagent-paths.mjs +15 -0
- package/hooks/_lib/subagent-transcript.mjs +582 -31
- package/hooks/_lib/vcs-create-matcher.mjs +217 -62
- package/hooks/config-protection.mjs +11 -3
- package/hooks/cwd-change-restore.mjs +11 -3
- package/hooks/enforce-commands.mjs +70 -23
- package/hooks/enforce-scope.mjs +143 -33
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks.json +1 -1
- package/hooks/loop-guard.mjs +11 -3
- package/hooks/on-session-end.mjs +72 -25
- package/hooks/on-session-start.mjs +48 -11
- package/hooks/on-stop.mjs +211 -23
- package/hooks/operator-steer.mjs +11 -3
- package/hooks/post-bash-issue-budget-refund.mjs +18 -8
- package/hooks/post-bash-write-verify.mjs +6 -2
- package/hooks/post-edit-import-probe.mjs +17 -9
- package/hooks/post-edit-validate.mjs +13 -5
- package/hooks/post-subagent-discovery-validator.mjs +98 -13
- package/hooks/post-tool-batch-wave-signal.mjs +200 -38
- package/hooks/post-tool-failure-corrective-context.mjs +11 -5
- package/hooks/post-tooluse-frontend-slop.mjs +10 -4
- package/hooks/pre-auq-clarity.mjs +18 -2
- package/hooks/pre-bash-destructive-guard.mjs +80 -9
- package/hooks/pre-bash-issue-budget.mjs +119 -28
- package/hooks/pre-bash-memory-propose-audit.mjs +86 -54
- package/hooks/pre-bash-sessions-ledger-guard.mjs +391 -20
- package/hooks/pre-bash-staging-fence.mjs +335 -31
- package/hooks/pre-bash-templates-first.mjs +19 -14
- package/hooks/pre-task-scope-disjoint.mjs +385 -5
- package/hooks/skill-invocation-telemetry.mjs +2 -1
- package/hooks/subagent-telemetry.mjs +15 -19
- package/hooks/wave-scope-commit-guard.mjs +197 -100
- package/monitors/monitors.json +1 -1
- package/output-styles/wave-summary.md +1 -1
- package/package.json +2 -1
- package/pi/prompts/autopilot.md +3 -3
- package/pi/prompts/bootstrap.md +3 -3
- package/pi/prompts/brainstorm.md +3 -3
- package/pi/prompts/close.md +2 -2
- package/pi/prompts/debug.md +3 -3
- package/pi/prompts/discovery.md +3 -3
- package/pi/prompts/dispatcher.md +3 -3
- package/pi/prompts/eli5.md +3 -3
- package/pi/prompts/eval.md +3 -3
- package/pi/prompts/evolve.md +3 -3
- package/pi/prompts/go.md +2 -2
- package/pi/prompts/grill.md +3 -3
- package/pi/prompts/harness-audit.md +2 -3
- package/pi/prompts/memory-cleanup.md +3 -3
- package/pi/prompts/persona-panel.md +3 -3
- package/pi/prompts/plan.md +3 -3
- package/pi/prompts/portfolio.md +2 -2
- package/pi/prompts/reconcile.md +3 -3
- package/pi/prompts/release.md +3 -3
- package/pi/prompts/repo-audit.md +3 -4
- package/pi/prompts/session.md +2 -2
- package/pi/prompts/spinout.md +3 -3
- package/pi/prompts/sunset-review.md +3 -3
- package/pi/prompts/templates-ack.md +1 -1
- package/pi/prompts/test.md +3 -3
- package/pi/prompts/ux-grill.md +3 -3
- package/rules/README.md +1 -1
- package/rules/opt-in-domain/prompt-caching.md +1 -1
- package/rules/opt-in-stack/backend-data.md +1 -1
- package/rules/opt-in-stack/backend.md +3 -3
- package/rules/opt-in-stack/frontend.md +1 -1
- package/rules/opt-in-stack/security-web.md +3 -3
- package/rules/opt-in-stack/swift.md +1 -1
- package/scripts/archive-closed-prds.mjs +2 -2
- package/scripts/auq-audit.mjs +2 -3
- package/scripts/autopilot.mjs +23 -2
- package/scripts/backfill-abandoned-sessions.mjs +171 -15
- package/scripts/backfill-evidence-digest.mjs +2 -1
- package/scripts/backfill-learnings-from-vault.mjs +2 -2
- package/scripts/check-package-manager.mjs +2 -2
- package/scripts/check-sessions-integrity.mjs +300 -0
- package/scripts/ci/assert-vitest-green.mjs +2 -1
- package/scripts/dialectic-deriver.mjs +50 -13
- package/scripts/emit-session.mjs +77 -32
- package/scripts/eval-session.mjs +65 -3
- package/scripts/export-hw-learnings.mjs +2 -1
- package/scripts/express-path.mjs +1 -1
- package/scripts/gc-stale-worktrees.mjs +2 -1
- package/scripts/generate-agents-skills.mjs +102 -29
- package/scripts/generate-codex-skills.mjs +48 -4
- package/scripts/generate-cursor-adapter.mjs +220 -11
- package/scripts/generate-hook-import-set.mjs +12 -27
- package/scripts/generate-pi-prompts.mjs +183 -13
- package/scripts/github-protection-audit.mjs +2 -3
- package/scripts/lib/agent-frontmatter.mjs +23 -1
- package/scripts/lib/agent-status.mjs +2 -31
- package/scripts/lib/auq/clarity.mjs +10 -2
- package/scripts/lib/auq/parse.mjs +12 -31
- package/scripts/lib/auq/schema.mjs +56 -41
- package/scripts/lib/auto-dialectic.mjs +304 -15
- package/scripts/lib/autopilot/flags.mjs +12 -1
- package/scripts/lib/autopilot/kill-switches.mjs +6 -3
- package/scripts/lib/autopilot/loop.mjs +14 -1
- package/scripts/lib/autopilot/stall-sampler.mjs +80 -23
- package/scripts/lib/ci-status-banner.mjs +376 -16
- package/scripts/lib/claude-md-budget-lint.mjs +2 -5
- package/scripts/lib/command-blocker.mjs +408 -33
- package/scripts/lib/config/dialectic.mjs +12 -3
- package/scripts/lib/config/drift-check.mjs +19 -0
- package/scripts/lib/config/gate.mjs +74 -0
- package/scripts/lib/config/reaper.mjs +162 -0
- package/scripts/lib/config.mjs +14 -0
- package/scripts/lib/convergence-monitor.mjs +76 -13
- package/scripts/lib/cursor-hook-bridge.mjs +2 -2
- package/scripts/lib/description-surface.mjs +2 -5
- package/scripts/lib/dispatcher/cli.mjs +2 -1
- package/scripts/lib/ecosystem-health.mjs +11 -0
- package/scripts/lib/ecosystem-wizard.mjs +2 -1
- package/scripts/lib/eval/engine.mjs +421 -53
- package/scripts/lib/eval/judge.mjs +463 -40
- package/scripts/lib/eval/schema.mjs +10 -1
- package/scripts/lib/events-rotation.mjs +221 -25
- package/scripts/lib/events-schema.mjs +114 -0
- package/scripts/lib/events.mjs +524 -5
- package/scripts/lib/fetch-baseline.mjs +3 -8
- package/scripts/lib/frontmatter-guard.mjs +21 -10
- package/scripts/lib/gates/gate-baseline.mjs +27 -2
- package/scripts/lib/gates/gate-full.mjs +28 -3
- package/scripts/lib/gates/gate-helpers.mjs +243 -21
- package/scripts/lib/gates/gate-incremental.mjs +28 -3
- package/scripts/lib/gates/gate-per-file.mjs +27 -2
- package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +2 -1
- package/scripts/lib/gitlab-portfolio/cli.mjs +2 -1
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +6 -1
- package/scripts/lib/instruction-budget-guard.mjs +332 -50
- package/scripts/lib/io.mjs +42 -8
- package/scripts/lib/is-main-module.mjs +82 -0
- package/scripts/lib/issue-close-strip-labels.mjs +207 -49
- package/scripts/lib/js-mask.mjs +197 -0
- package/scripts/lib/learnings/evolve-telemetry.mjs +11 -7
- package/scripts/lib/locks/index.mjs +32 -25
- package/scripts/lib/maintenance-due-banner.mjs +122 -91
- package/scripts/lib/orphan-reaper.mjs +1588 -0
- package/scripts/lib/peer-cards/merger.mjs +48 -10
- package/scripts/lib/peer-cards/reader.mjs +78 -2
- package/scripts/lib/peer-discovery.mjs +2 -5
- package/scripts/lib/playwright-driver/runner.mjs +2 -1
- package/scripts/lib/process-group.mjs +899 -0
- package/scripts/lib/quality-gate.mjs +107 -28
- package/scripts/lib/reconcile/backlog.mjs +368 -0
- package/scripts/lib/reconcile/engine.mjs +55 -188
- package/scripts/lib/reconcile/rule-expiry-sweep.mjs +884 -0
- package/scripts/lib/reconcile/sanitize.mjs +69 -3
- package/scripts/lib/reconcile-nudge-banner.mjs +138 -45
- package/scripts/lib/resource-probe/parsers.mjs +31 -0
- package/scripts/lib/rule-loader.mjs +41 -12
- package/scripts/lib/rules-sync.mjs +2 -5
- package/scripts/lib/scope-echo.mjs +429 -7
- package/scripts/lib/scope-gate.mjs +605 -1
- package/scripts/lib/session-close-backfill.mjs +91 -12
- package/scripts/lib/session-id.mjs +9 -20
- package/scripts/lib/session-invocation.mjs +20 -0
- package/scripts/lib/session-schema/constants.mjs +30 -2
- package/scripts/lib/session-schema/normalizer.mjs +56 -4
- package/scripts/lib/session-schema.mjs +8 -3
- package/scripts/lib/session-start-probes.mjs +95 -10
- package/scripts/lib/sessions-canonical.mjs +23 -0
- package/scripts/lib/sessions-integrity-banner.mjs +7 -1
- package/scripts/lib/sessions-staleness-banner.mjs +193 -51
- package/scripts/lib/skill-evidence-window.mjs +891 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +133 -12
- package/scripts/lib/skill-evolution/engine.mjs +18 -9
- package/scripts/lib/skill-judge.mjs +45 -3
- package/scripts/lib/state-md.mjs +84 -3
- package/scripts/lib/sunset/walker.mjs +31 -4
- package/scripts/lib/tail-window.mjs +56 -0
- package/scripts/lib/telemetry/schema.mjs +30 -0
- package/scripts/lib/telemetry/sync.mjs +61 -6
- package/scripts/lib/telemetry-flush-health-banner.mjs +4 -22
- package/scripts/lib/test-runner/issue-reconcile.mjs +48 -16
- package/scripts/lib/tests-src-ratio.mjs +2 -6
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +74 -14
- package/scripts/lib/user-invocable-skills.mjs +205 -0
- package/scripts/lib/ux-grill/reconcile.mjs +48 -22
- package/scripts/lib/validate/check-agents-skills.mjs +26 -15
- package/scripts/lib/validate/check-banner-parity.mjs +2 -2
- package/scripts/lib/validate/check-cursor-adapter.mjs +3 -2
- package/scripts/lib/validate/check-dead-bridge.mjs +2 -2
- package/scripts/lib/validate/check-doc-cli-commands.mjs +2 -2
- package/scripts/lib/validate/check-entry-guard.mjs +329 -0
- package/scripts/lib/validate/check-guard-requires-parity.mjs +2 -2
- package/scripts/lib/validate/check-hook-entry-guards.mjs +636 -0
- package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +2 -2
- package/scripts/lib/validate/check-learning-provenance.mjs +2 -2
- package/scripts/lib/validate/check-pi-prompts.mjs +1 -0
- package/scripts/lib/validate/check-rules.mjs +7 -5
- package/scripts/lib/validate/check-skill-links.mjs +35 -6
- package/scripts/lib/validate/check-skill-script-paths.mjs +241 -29
- package/scripts/lib/validate/check-test-git-config-target.mjs +26 -36
- package/scripts/lib/validate/check-unicode-safety.mjs +2 -2
- package/scripts/lib/validate/check-untracked-test-deps.mjs +9 -104
- package/scripts/lib/validate/check-unwired-features.mjs +220 -33
- package/scripts/lib/validate/check-validator-registration.mjs +36 -12
- package/scripts/lib/validate/check-vcs-repo-flag.mjs +2 -2
- package/scripts/lib/validate/confidential-names.mjs +10 -0
- package/scripts/lib/validate-vendored-rules.mjs +39 -12
- package/scripts/lib/vault-mirror/namespace.mjs +46 -8
- package/scripts/lib/vault-mirror/process.mjs +10 -3
- package/scripts/lib/vault-mirror/render-sessions.mjs +12 -2
- package/scripts/lib/vault-status/narrative-mirror.mjs +31 -7
- package/scripts/lib/vault-yaml.mjs +118 -0
- package/scripts/lib/wave-transcript-tail.mjs +2 -2
- package/scripts/lib/worktree/lifecycle.mjs +153 -1
- package/scripts/lock-reaper.mjs +2 -1
- package/scripts/materialize-wave-scope.mjs +87 -4
- package/scripts/migrate-sessions-jsonl.mjs +2 -1
- package/scripts/migrate-vault-paths.mjs +2 -3
- package/scripts/release-session-lock.mjs +305 -0
- package/scripts/release.mjs +109 -39
- package/scripts/relocate-vault-corpus.mjs +2 -3
- package/scripts/repair-invalid-sessions.mjs +2 -2
- package/scripts/resolve-session-invocation.mjs +59 -0
- package/scripts/run-quality-gate.mjs +156 -17
- package/scripts/session-shape.mjs +2 -2
- package/scripts/site-numbers.mjs +35 -11
- package/scripts/sweep-expired-rules.mjs +227 -0
- package/scripts/validate-plugin.mjs +21 -0
- package/scripts/validate-wave-scope.mjs +32 -105
- package/scripts/vault-consolidate.mjs +2 -2
- package/scripts/vault-mirror.mjs +11 -4
- package/scripts/wave-scope-binding.mjs +2 -3
- package/skills/_shared/bootstrap-gate.md +1 -1
- package/skills/_shared/monitor-patterns.md +1 -1
- package/skills/_shared/platform-tools.md +23 -11
- package/skills/_shared/research-evidence.md +53 -0
- package/skills/_shared/state-ownership.md +3 -0
- package/skills/autopilot/SKILL.md +80 -11
- package/skills/bootstrap/SKILL.md +51 -1
- package/skills/brainstorm/SKILL.md +16 -0
- package/skills/claude-md-drift-check/SKILL.md +1 -1
- package/skills/claude-md-drift-check/checker.mjs +49 -11
- package/{commands/close.md → skills/close/SKILL.md} +9 -3
- package/skills/convergence-monitoring/README.md +8 -1
- package/skills/convergence-monitoring/SIGNALS.md +50 -6
- package/skills/convergence-monitoring/SKILL.md +15 -6
- package/skills/debug/SKILL.md +10 -0
- package/skills/discovery/SKILL.md +24 -1
- package/skills/discovery/probes-session.md +2 -2
- package/skills/dispatcher/SKILL.md +38 -7
- package/skills/eli5/SKILL.md +11 -0
- package/skills/eval/SKILL.md +52 -23
- package/skills/eval/rubric-v1.md +1 -0
- package/skills/eval/rubric-v2.md +457 -0
- package/skills/evolve/SKILL.md +9 -2
- package/skills/evolve/references/evolve-dialectic-mode.md +46 -25
- package/skills/gitlab-ops/SKILL.md +3 -2
- package/{commands/go.md → skills/go/SKILL.md} +9 -1
- package/skills/grill/SKILL.md +19 -0
- package/{commands/harness-audit.md → skills/harness-audit/SKILL.md} +7 -2
- package/skills/hook-development/SKILL.md +46 -41
- package/skills/memory-cleanup/SKILL.md +7 -0
- package/skills/npm-publish/SKILL.md +2 -2
- package/skills/persona-panel/SKILL.md +56 -1
- package/skills/persona-panel/persona-format.md +1 -1
- package/skills/plan/SKILL.md +28 -1
- package/{commands/portfolio.md → skills/portfolio/SKILL.md} +8 -2
- package/skills/reconcile/SKILL.md +21 -0
- package/{commands/release.md → skills/release/SKILL.md} +16 -2
- package/skills/repo-audit/SKILL.md +7 -0
- package/skills/session-end/SKILL.md +13 -16
- package/skills/session-end/discovery-scan.md +1 -1
- package/skills/session-end/phase-3-6-tail.md +55 -9
- package/skills/session-end/plan-verification.md +2 -2
- package/skills/session-end/references/phase-5-issue-cleanup.md +9 -14
- package/skills/session-end/session-metrics-write.md +10 -0
- package/skills/session-plan/SKILL.md +18 -6
- package/skills/session-plan/references/session-plan-task-classification.md +2 -2
- package/skills/session-start/SKILL.md +5 -4
- package/skills/session-start/phase-8-5-express-path.md +6 -6
- package/skills/session-start/references/phase-1-5-session-continuity.md +1 -1
- package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +1 -1
- package/skills/session-start/references/phase-4-ssot-environment-check.md +6 -4
- package/skills/spinout/SKILL.md +12 -1
- package/skills/sunset-review/SKILL.md +13 -0
- package/{commands/test.md → skills/test/SKILL.md} +10 -4
- package/skills/ux-grill/SKILL.md +20 -2
- package/skills/wave-executor/SKILL.md +14 -7
- package/skills/wave-executor/circuit-breaker.md +2 -0
- package/skills/wave-executor/references/wave-executor-state-init.md +18 -4
- package/skills/wave-executor/references/wave-loop-dispatch.md +5 -2
- package/skills/wave-executor/references/wave-loop-review.md +17 -1
- package/commands/autopilot.md +0 -80
- package/commands/bootstrap.md +0 -56
- package/commands/brainstorm.md +0 -48
- package/commands/debug.md +0 -36
- package/commands/discovery.md +0 -32
- package/commands/dispatcher.md +0 -59
- package/commands/eli5.md +0 -33
- package/commands/eval.md +0 -28
- package/commands/evolve.md +0 -10
- package/commands/grill.md +0 -45
- package/commands/memory-cleanup.md +0 -26
- package/commands/persona-panel.md +0 -121
- package/commands/plan.md +0 -15
- package/commands/reconcile.md +0 -23
- package/commands/repo-audit.md +0 -24
- package/commands/spinout.md +0 -15
- package/commands/sunset-review.md +0 -27
- package/commands/ux-grill.md +0 -51
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
import { readStdin, emitAllow, emitDeny, emitWarn } from '../scripts/lib/io.mjs';
|
|
54
54
|
import { resolveProjectDir } from '../scripts/lib/platform.mjs';
|
|
55
55
|
import { readJson } from '../scripts/lib/common.mjs';
|
|
56
|
-
import { findIssueCreateStatements,
|
|
56
|
+
import { findIssueCreateStatements, findLoopedIssueCreates } from './_lib/vcs-create-matcher.mjs';
|
|
57
57
|
import {
|
|
58
58
|
loadIssueBudgetConfig,
|
|
59
59
|
resolveIssueBudgetSessionId,
|
|
@@ -67,13 +67,10 @@ import {
|
|
|
67
67
|
} from '../scripts/lib/issue-budget.mjs';
|
|
68
68
|
|
|
69
69
|
import { shouldRunHook } from './_lib/profile-gate.mjs';
|
|
70
|
+
import { isMainModule } from '../scripts/lib/is-main-module.mjs';
|
|
70
71
|
import { existsSync } from 'node:fs';
|
|
71
72
|
import path from 'node:path';
|
|
72
73
|
|
|
73
|
-
// Opt-out per session via SO_DISABLED_HOOKS=pre-bash-issue-budget; the
|
|
74
|
-
// "minimal"/"off" profiles disable it like every other non-core hook.
|
|
75
|
-
if (!shouldRunHook('pre-bash-issue-budget')) process.exit(0);
|
|
76
|
-
|
|
77
74
|
// ---------------------------------------------------------------------------
|
|
78
75
|
// Helpers
|
|
79
76
|
// ---------------------------------------------------------------------------
|
|
@@ -187,15 +184,39 @@ function resolveToolCallId(input) {
|
|
|
187
184
|
* entry #N … nothing is lost", which would be false here — an uncountable bulk
|
|
188
185
|
* request is not parked, it is handed back whole.
|
|
189
186
|
*
|
|
187
|
+
* ## Why the lane is a parameter (#1379)
|
|
188
|
+
*
|
|
189
|
+
* Until 2026-09-17 this text said "sits inside a shell loop body (`do … done`)"
|
|
190
|
+
* on BOTH lanes, so the `xargs` deny (`echo b | xargs -I% glab issue create
|
|
191
|
+
* --title junk%` — no loop anywhere) sent the operator looking for a loop the
|
|
192
|
+
* command does not have. Only the lane SENTENCE varies; every other line is
|
|
193
|
+
* byte-identical across lanes, and tests pin them.
|
|
194
|
+
*
|
|
190
195
|
* @param {{ "max-per-session": number }} config
|
|
196
|
+
* @param {{ lane?: "loop"|"xargs"|"mixed" }} [opts]
|
|
191
197
|
* @returns {string}
|
|
192
198
|
*/
|
|
193
|
-
function formatLoopDenyReason(config) {
|
|
199
|
+
function formatLoopDenyReason(config, { lane = 'loop' } = {}) {
|
|
200
|
+
const LANE_SENTENCES = {
|
|
201
|
+
loop: [
|
|
202
|
+
'The `issue create` call sits inside a shell loop body (`do … done`), so the cap cannot',
|
|
203
|
+
'charge it honestly: the word list is expanded by the shell AFTER this hook runs, so',
|
|
204
|
+
'`for i in $(seq 1 50)` would file 50 issues against a count of 1.',
|
|
205
|
+
],
|
|
206
|
+
xargs: [
|
|
207
|
+
'The `issue create` call is driven by `xargs`, so the cap cannot charge it honestly: the',
|
|
208
|
+
'word list arrives on stdin AFTER this hook runs, so `seq 1 50 | xargs` would file 50',
|
|
209
|
+
'issues against a count of 1.',
|
|
210
|
+
],
|
|
211
|
+
mixed: [
|
|
212
|
+
'The `issue create` calls are driven by a shell loop body (`do … done`) AND by `xargs`,',
|
|
213
|
+
'so the cap cannot charge them honestly: both word lists are produced AFTER this hook',
|
|
214
|
+
'runs, so `seq 1 50 | xargs` would file 50 issues against a count of 1.',
|
|
215
|
+
],
|
|
216
|
+
};
|
|
194
217
|
return [
|
|
195
218
|
'issue-budget: this command creates an UNKNOWN number of issues — refusing to guess.',
|
|
196
|
-
|
|
197
|
-
'charge it honestly: the word list is expanded by the shell AFTER this hook runs, so',
|
|
198
|
-
'`for i in $(seq 1 50)` would file 50 issues against a count of 1.',
|
|
219
|
+
...(LANE_SENTENCES[lane] ?? LANE_SENTENCES.loop),
|
|
199
220
|
'',
|
|
200
221
|
'Nothing was parked as overflow, because nothing is lost: re-issue the create calls as',
|
|
201
222
|
'SEPARATE commands and each one is counted normally against the cap',
|
|
@@ -302,18 +323,59 @@ async function main() {
|
|
|
302
323
|
const config = loadIssueBudgetConfig(projectDir);
|
|
303
324
|
if (config.mode === 'off') return emitAllow();
|
|
304
325
|
|
|
305
|
-
// G3b — bulk creation whose multiplicity is not computable (#1145).
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
|
|
312
|
-
|
|
326
|
+
// G3b — bulk creation whose multiplicity is not computable (#1145). Two
|
|
327
|
+
// sources, one policy: a LOOP BODY (#1145) and an `xargs`-driven create
|
|
328
|
+
// (#1289), where the word list arrives on stdin. Both file N issues for one
|
|
329
|
+
// statement, so both are denied rather than charged 1 — the fix had to land
|
|
330
|
+
// here and not only in `isLoopedIssueCreate`, because G3 above short-circuits
|
|
331
|
+
// on `statements.length === 0` and an xargs create used to produce zero
|
|
332
|
+
// statements, so no loop-side fix could ever run.
|
|
333
|
+
//
|
|
334
|
+
// THE INVARIANT (rewritten 2026-09-16): the exemption is classified on the
|
|
335
|
+
// statement that CAUSED the bulk classification — never on `statements[0]`,
|
|
336
|
+
// and never on the whole command. A `[Carryover]` create standing NEXT TO an
|
|
337
|
+
// uncountable one is an unrelated neighbour and must not lift the deny; a
|
|
338
|
+
// `[Carryover]` create that IS the bulk statement keeps its documented
|
|
339
|
+
// unconditional pass (session-end's "those are never deferred" promise, which
|
|
340
|
+
// holds inside a loop too). Measured 2026-09-16 against the previous
|
|
341
|
+
// `statements[0]` binding, both lanes ALLOW where they must DENY:
|
|
342
|
+
// glab issue create --title "[Carryover] real"; echo X | xargs -I% glab issue create --title %
|
|
343
|
+
// glab issue create --title "[Carryover] real"; for i in 1 2 3; do glab issue create --title junk$i; done
|
|
344
|
+
// Same class as the bypass-scoping regression on `matchesBypass` — a matcher
|
|
345
|
+
// widened per statement while its exemption stayed whole-command
|
|
346
|
+
// (`.claude/rules/guard-design.md` § "Widening a matcher without narrowing
|
|
347
|
+
// its bypass", #1106).
|
|
348
|
+
//
|
|
349
|
+
// Fail-CLOSED when a command carries SEVERAL bulk statements and only some are
|
|
350
|
+
// exempt: `some()` over the non-exempt ones denies, because the command as a
|
|
351
|
+
// whole still files an uncountable number of untemplated issues.
|
|
352
|
+
//
|
|
353
|
+
// EVERY loop, not the first (#1379): the loop lane used to contribute at most
|
|
354
|
+
// ONE entry here, so an exempt FIRST loop was the only loop classified and
|
|
355
|
+
// every later loop went unjudged. Reproduced 2026-09-17 @ `9e8146b4`:
|
|
356
|
+
// for i in 1 2 3; do glab issue create --label carryover --title x$i; done;
|
|
357
|
+
// for j in 1 2 3; do glab issue create --title junk$j; done → ALLOW (count=1)
|
|
358
|
+
const bulkEntries = [
|
|
359
|
+
...findLoopedIssueCreates(command).map((tokens) => ({
|
|
360
|
+
lane: 'loop',
|
|
361
|
+
text: tokens.map((t) => t.text).join(' '),
|
|
362
|
+
})),
|
|
363
|
+
...statements.filter((s) => s.bulk).map((s) => ({ lane: 'xargs', text: s.text })),
|
|
364
|
+
];
|
|
365
|
+
const uncountableEntries = bulkEntries.filter((e) => !classifyExemption(e.text).exempt);
|
|
366
|
+
const uncountableBulk = uncountableEntries.length > 0;
|
|
367
|
+
// ONE lane resolution for BOTH reports (#1379 follow-up). The deny already
|
|
368
|
+
// named the lane it fired on; the `warn` undercount notice at the bottom of
|
|
369
|
+
// main() said "inside a loop body" unconditionally, so the xargs lane — where
|
|
370
|
+
// no loop exists anywhere in the command — sent the operator looking for one.
|
|
371
|
+
// Resolved here rather than twice, so the two reports can never disagree.
|
|
372
|
+
const uncountableLanes = new Set(uncountableEntries.map((e) => e.lane));
|
|
373
|
+
const uncountableLane =
|
|
374
|
+
uncountableLanes.size > 1 ? 'mixed' : ([...uncountableLanes][0] ?? 'loop');
|
|
313
375
|
if (uncountableBulk && config.mode === 'strict') {
|
|
314
376
|
// Nothing is charged and nothing is parked — the command is handed back
|
|
315
377
|
// whole, which is what makes unrolling it the correct next action.
|
|
316
|
-
return emitDeny(formatLoopDenyReason(config));
|
|
378
|
+
return emitDeny(formatLoopDenyReason(config, { lane: uncountableLane }));
|
|
317
379
|
}
|
|
318
380
|
|
|
319
381
|
const sessionId = await resolveSessionId(input, projectDir);
|
|
@@ -401,11 +463,32 @@ async function main() {
|
|
|
401
463
|
// to name the undercount out loud — a silent 1-for-N is the exact failure the
|
|
402
464
|
// deny above exists to prevent, and `warn` must not reintroduce it quietly.
|
|
403
465
|
// emitWarn, not stderr: under exit 0 stderr reaches only the debug log (#916).
|
|
404
|
-
|
|
466
|
+
//
|
|
467
|
+
// GATED ON THE BULK STATEMENTS, NEVER ON THE LAST VERDICT (2026-09-17). The
|
|
468
|
+
// condition used to read `verdict.decision === 'allow'`, i.e. the verdict of
|
|
469
|
+
// the LAST statement of the chain — so one exempt statement written AFTER an
|
|
470
|
+
// uncountable one silenced the notice the two paragraphs above declare
|
|
471
|
+
// mandatory. Reproduced through this hook binary in `mode: warn`:
|
|
472
|
+
// for i in 1 2; do glab issue create --title j$i; done; \
|
|
473
|
+
// glab issue create --title "[Carryover] z"
|
|
474
|
+
// → stdout EMPTY, ledger count=1 exempt=1 (the trailing exempt statement is
|
|
475
|
+
// an unrelated neighbour, exactly as in G3b's own invariant); without it,
|
|
476
|
+
// the identical loop reported the UNDERCOUNT.
|
|
477
|
+
// Reaching this point already means no statement blocked and none warned
|
|
478
|
+
// (both branches above return), so the uncountable bulk statement — non-exempt
|
|
479
|
+
// by construction of `uncountableEntries` — was charged as 1. The two negated
|
|
480
|
+
// conditions are kept explicit so a future reordering of those branches cannot
|
|
481
|
+
// turn this back into a report about the wrong statement.
|
|
482
|
+
if (uncountableBulk && !blocked && !verdicts.some((v) => v.decision === 'warn')) {
|
|
483
|
+
const LANE_PHRASES = {
|
|
484
|
+
loop: 'inside a loop body',
|
|
485
|
+
xargs: 'driven by `xargs`',
|
|
486
|
+
mixed: 'inside a loop body and by `xargs`',
|
|
487
|
+
};
|
|
405
488
|
return emitWarn(
|
|
406
|
-
`pre-bash-issue-budget: bulk create
|
|
489
|
+
`pre-bash-issue-budget: bulk create ${LANE_PHRASES[uncountableLane]} charged as 1 ` +
|
|
407
490
|
`(${verdict.count}/${verdict.max}) — the real number of issues this files is not ` +
|
|
408
|
-
`knowable before the
|
|
491
|
+
`knowable before the word list is expanded, so the count is an UNDERCOUNT. ` +
|
|
409
492
|
`Set \`issue-budget.mode: strict\` to deny this shape instead.`,
|
|
410
493
|
);
|
|
411
494
|
}
|
|
@@ -414,10 +497,18 @@ async function main() {
|
|
|
414
497
|
return emitAllow();
|
|
415
498
|
}
|
|
416
499
|
|
|
417
|
-
//
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
process.exit(0);
|
|
423
|
-
|
|
500
|
+
// Entry guard (#1393): run only as the node script the harness execs — a bare
|
|
501
|
+
// `import()` must run no handler and must not exit the importing process.
|
|
502
|
+
if (isMainModule(import.meta.url)) {
|
|
503
|
+
// Opt-out per session via SO_DISABLED_HOOKS=pre-bash-issue-budget; the
|
|
504
|
+
// "minimal"/"off" profiles disable it like every other non-core hook.
|
|
505
|
+
if (!shouldRunHook('pre-bash-issue-budget')) process.exit(0);
|
|
506
|
+
|
|
507
|
+
// Top-level error handler — fail open, same posture as the sibling hooks.
|
|
508
|
+
main().catch((e) => {
|
|
509
|
+
process.stderr.write(
|
|
510
|
+
`⚠ pre-bash-issue-budget: internal error — ${e?.message || e}\n`,
|
|
511
|
+
);
|
|
512
|
+
process.exit(0);
|
|
513
|
+
});
|
|
514
|
+
}
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
* G3 — regex match /\bnode\b.*\bmemory-propose\.mjs\b/i (no match → exit 0)
|
|
14
14
|
* G4 — resolve session_id (from stdin payload or .orchestrator/current-session.json)
|
|
15
15
|
* G5 — resolve wave (from the active wave-scope.json `wave` field, default 0)
|
|
16
|
-
* G6 —
|
|
16
|
+
* G6 — derive a NON-REVERSIBLE argv summary: sha256 command_hash + known flag
|
|
17
|
+
* NAMES + raw length. The command text itself never leaves this process.
|
|
17
18
|
* G7 — append event JSON line to .orchestrator/metrics/events.jsonl
|
|
18
19
|
* Always: exit 0 (never block)
|
|
19
20
|
*
|
|
@@ -22,6 +23,7 @@
|
|
|
22
23
|
*/
|
|
23
24
|
|
|
24
25
|
import { readStdin, emitAllow } from '../scripts/lib/io.mjs';
|
|
26
|
+
import crypto from 'node:crypto';
|
|
25
27
|
import { existsSync } from 'node:fs';
|
|
26
28
|
import { readFile } from 'node:fs/promises';
|
|
27
29
|
import path from 'node:path';
|
|
@@ -29,8 +31,7 @@ import { emitEvent } from '../scripts/lib/events.mjs';
|
|
|
29
31
|
import { findScopeFile } from '../scripts/lib/hardening.mjs';
|
|
30
32
|
|
|
31
33
|
import { shouldRunHook } from './_lib/profile-gate.mjs';
|
|
32
|
-
|
|
33
|
-
if (!shouldRunHook('pre-bash-memory-propose-audit')) process.exit(0);
|
|
34
|
+
import { isMainModule } from '../scripts/lib/is-main-module.mjs';
|
|
34
35
|
|
|
35
36
|
// ---------------------------------------------------------------------------
|
|
36
37
|
// Constants
|
|
@@ -48,59 +49,78 @@ if (!shouldRunHook('pre-bash-memory-propose-audit')) process.exit(0);
|
|
|
48
49
|
const MEMORY_PROPOSE_REGEX = /\bnode\b.*\bmemory-propose\.mjs\b/i;
|
|
49
50
|
|
|
50
51
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
52
|
+
* The flag NAMES `scripts/memory-propose.mjs` accepts (its `parseArgs` options
|
|
53
|
+
* block, plus `--help`). CLOSED LIST BY DESIGN: `flags_present` is built by
|
|
54
|
+
* intersecting the command with this constant, never by scraping `--\S+` tokens
|
|
55
|
+
* out of the command. A scrape would re-open the leak this file just closed —
|
|
56
|
+
* `--insight --my-secret-value` would publish the value as if it were a flag.
|
|
53
57
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* --insight unquoted → --insight [REDACTED]
|
|
58
|
+
* A flag the CLI does not know is simply not reported. That is the correct
|
|
59
|
+
* trade: the field exists to say WHICH of the audited CLI's switches were used,
|
|
60
|
+
* not to mirror the command line.
|
|
58
61
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// Issue #546: `\S+` would match an opening quote `"` or `'` (non-whitespace),
|
|
70
|
-
// and on malformed inputs (e.g. unbalanced or shell-already-unescaped values)
|
|
71
|
-
// could partial-match the value, leaving the tail unredacted. The negative
|
|
72
|
-
// lookahead `(?!["'])` forces `\S+` to be tried only on values that do not
|
|
73
|
-
// start with a quote, preserving the quoted-alt as the sole path for quoted
|
|
74
|
-
// values and preventing tail-leaks on malformed inputs.
|
|
75
|
-
const SENSITIVE_FLAGS_REGEX = /--(?:insight|subject|evidence|content|reason)(?:=("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|(?!["'])\S+)|\s+("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|(?!["'])\S+))/g;
|
|
62
|
+
const KNOWN_FLAGS = Object.freeze([
|
|
63
|
+
'type',
|
|
64
|
+
'subject',
|
|
65
|
+
'insight',
|
|
66
|
+
'evidence',
|
|
67
|
+
'confidence',
|
|
68
|
+
'dry-run',
|
|
69
|
+
'file-paths',
|
|
70
|
+
'help',
|
|
71
|
+
]);
|
|
76
72
|
|
|
77
73
|
// ---------------------------------------------------------------------------
|
|
78
74
|
// Helpers
|
|
79
75
|
// ---------------------------------------------------------------------------
|
|
80
76
|
|
|
81
77
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
78
|
+
* sha256(command), truncated to 16 hex characters.
|
|
79
|
+
*
|
|
80
|
+
* WORD-FOR-WORD the `hashCommand()` of `hooks/enforce-commands.mjs:69` (itself
|
|
81
|
+
* taken from `hooks/pre-bash-destructive-guard.mjs:253`, which mirrors
|
|
82
|
+
* `loop-guard.mjs` `hashArgs()`). Deliberately duplicated rather than shared:
|
|
83
|
+
* a PreToolUse hook must not gain another loadable module that can fail at
|
|
84
|
+
* start — three lines are cheaper than a load error on the hot path. Verified
|
|
85
|
+
* before duplicating that no helper is EXPORTED at any of those sites.
|
|
86
|
+
*
|
|
87
|
+
* WHY THE HASH IS HERE (#1415, 2026-09-21): until today this hook wrote a
|
|
88
|
+
* merely flag-redacted `argv_truncated` (512 chars of command text) into
|
|
89
|
+
* `orchestrator.memory.propose_invoked` — a TRACKED `events.jsonl` line and,
|
|
90
|
+
* with the webhook configured, a network payload. Redaction covered only the
|
|
91
|
+
* five `--insight/--subject/--evidence/--content/--reason` values and said so
|
|
92
|
+
* in its own caveat: `$VAR`, `$(cat secret)` and any value written elsewhere
|
|
93
|
+
* on the line passed through. This was the THIRD and last open site of the
|
|
94
|
+
* class closed by `8f15f77b` (enforce-commands) and #1404 (staging-fence).
|
|
95
|
+
*
|
|
96
|
+
* The hash keeps the event COUNTABLE and GROUPABLE — repeat invocations of the
|
|
97
|
+
* same command still collapse to one key — which is the only property any
|
|
98
|
+
* consumer needed. Measured 2026-09-21 (`rg argv_truncated` over `scripts/
|
|
99
|
+
* hooks/ skills/ docs/`): ZERO production readers, the field's only consumers
|
|
100
|
+
* were this hook's own tests.
|
|
84
101
|
*
|
|
85
102
|
* @param {string} command
|
|
86
103
|
* @returns {string}
|
|
87
104
|
*/
|
|
88
|
-
function
|
|
89
|
-
return command.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
function hashCommand(command) {
|
|
106
|
+
return crypto.createHash('sha256').update(command).digest('hex').slice(0, 16);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The subset of KNOWN_FLAGS that appears in the command, in KNOWN_FLAGS order.
|
|
111
|
+
*
|
|
112
|
+
* Names only — a value can never reach this array, because the array is built
|
|
113
|
+
* from the constant above and the command is only ever TESTED against it. Both
|
|
114
|
+
* spellings count (`--insight=x` and `--insight x`); the trailing boundary
|
|
115
|
+
* `(?![\w-])` keeps `--insightful` from reporting `insight`.
|
|
116
|
+
*
|
|
117
|
+
* @param {string} command
|
|
118
|
+
* @returns {string[]}
|
|
119
|
+
*/
|
|
120
|
+
function flagsPresent(command) {
|
|
121
|
+
return KNOWN_FLAGS.filter((flag) =>
|
|
122
|
+
new RegExp(`--${flag}(?![\\w-])`).test(command),
|
|
123
|
+
);
|
|
104
124
|
}
|
|
105
125
|
|
|
106
126
|
/**
|
|
@@ -180,8 +200,11 @@ async function main() {
|
|
|
180
200
|
// G5 — resolve wave
|
|
181
201
|
const wave = await resolveWave(projectDir);
|
|
182
202
|
|
|
183
|
-
// G6 —
|
|
184
|
-
|
|
203
|
+
// G6 — derive the non-reversible argv summary (#1415). Nothing downstream
|
|
204
|
+
// ever sees the command text: hash for grouping, known flag NAMES for
|
|
205
|
+
// shape, raw length for size — no operands, no paths, no values.
|
|
206
|
+
const commandHash = hashCommand(command);
|
|
207
|
+
const flags = flagsPresent(command);
|
|
185
208
|
|
|
186
209
|
// G7 — emit canonical event via emitEvent (single emission path: schema + webhook,
|
|
187
210
|
// replacing the local hand-rolled appendFileSync bypass).
|
|
@@ -193,7 +216,9 @@ async function main() {
|
|
|
193
216
|
await emitEvent('orchestrator.memory.propose_invoked', {
|
|
194
217
|
session_id: sessionId,
|
|
195
218
|
wave,
|
|
196
|
-
|
|
219
|
+
command_hash: commandHash,
|
|
220
|
+
flags_present: flags,
|
|
221
|
+
argv_length: command.length,
|
|
197
222
|
cwd: process.cwd(),
|
|
198
223
|
exit_code: null,
|
|
199
224
|
});
|
|
@@ -203,10 +228,17 @@ async function main() {
|
|
|
203
228
|
return emitAllow();
|
|
204
229
|
}
|
|
205
230
|
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
|
|
231
|
+
// Entry guard (#1393): run only as the node script the harness execs — a bare
|
|
232
|
+
// `import()` must run no handler and must not exit the importing process.
|
|
233
|
+
if (isMainModule(import.meta.url)) {
|
|
234
|
+
// exit 0 immediately when this hook is disabled via profile/env
|
|
235
|
+
if (!shouldRunHook('pre-bash-memory-propose-audit')) process.exit(0);
|
|
236
|
+
|
|
237
|
+
// Top-level error handler — never let exit 1 leak
|
|
238
|
+
main().catch((e) => {
|
|
239
|
+
process.stderr.write(
|
|
240
|
+
`⚠ pre-bash-memory-propose-audit: internal error — ${e?.message || e}\n`,
|
|
241
|
+
);
|
|
242
|
+
process.exit(0); // fail-open on internal errors
|
|
243
|
+
});
|
|
244
|
+
}
|