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
|
@@ -22,23 +22,32 @@
|
|
|
22
22
|
* "host": "string",
|
|
23
23
|
* "started_at": "2026-05-23T21:30:00.000Z",
|
|
24
24
|
* "staged_paths": [
|
|
25
|
-
* { "
|
|
25
|
+
* { "paths": ["src/foo.ts"], "command_hash": "a635c66ec7e7bf56",
|
|
26
|
+
* "timestamp": "2026-…" },
|
|
26
27
|
* ...
|
|
27
28
|
* ]
|
|
28
29
|
* }
|
|
29
30
|
*
|
|
30
|
-
* The
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
31
|
+
* The entry records the PATH OPERANDS, never the command text (#1404): a
|
|
32
|
+
* staging command can carry a secret (`GIT_TOKEN=… git add x`), and the raw
|
|
33
|
+
* string was persisted verbatim to disk — the same defect 8f15f77b removed
|
|
34
|
+
* from hooks/enforce-commands.mjs. Paths are what the only reader
|
|
35
|
+
* (hooks/wave-scope-commit-guard.mjs) actually needs; `command_hash` keeps
|
|
36
|
+
* the entry countable and groupable without the text.
|
|
37
|
+
*
|
|
38
|
+
* `paths: ["*"]` means "stages a set no operand names" (`git add -A`, `.`,
|
|
39
|
+
* `-u`) and overlaps EVERY staged path — the case the reader's old raw-text
|
|
40
|
+
* regex could not see at all, because `-A` contains no path to match.
|
|
35
41
|
*
|
|
36
42
|
* Decision flow (G1-G6 early-return ladder):
|
|
37
43
|
* G1 tool filter — Bash only
|
|
38
44
|
* G2 command must be a non-empty string
|
|
39
|
-
* G3 regex
|
|
45
|
+
* G3 cheap regex PRE-FILTER — skip the tokenizer for plainly unrelated
|
|
46
|
+
* commands (see GIT_ADD_REGEX; it does not decide the question)
|
|
40
47
|
* G4 context gate — isWaveAgentContext(); exit 0 immediately for
|
|
41
48
|
* coordinator/manual commits (AC5 safe-default no-op)
|
|
49
|
+
* G4b tokenize + extract path operands; exit 0 when no `git add` statement
|
|
50
|
+
* resolves (a pre-filter false positive writes nothing)
|
|
42
51
|
* G5 derive agent_id, build fence dir + path
|
|
43
52
|
* G6 read-modify-write the fence file (append the staging-intent entry).
|
|
44
53
|
* Errors are warned + swallowed — the hook NEVER blocks the Bash call.
|
|
@@ -64,29 +73,303 @@ import os from 'node:os';
|
|
|
64
73
|
import crypto from 'node:crypto';
|
|
65
74
|
|
|
66
75
|
import { shouldRunHook } from './_lib/profile-gate.mjs';
|
|
76
|
+
import { isMainModule } from '../scripts/lib/is-main-module.mjs';
|
|
67
77
|
import { stableHostname } from '../scripts/lib/host-identity.mjs';
|
|
68
|
-
if (!shouldRunHook('pre-bash-staging-fence')) process.exit(0);
|
|
69
78
|
|
|
70
79
|
// ---------------------------------------------------------------------------
|
|
71
80
|
// Constants
|
|
72
81
|
// ---------------------------------------------------------------------------
|
|
73
82
|
|
|
74
83
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
84
|
+
* Cheap PRE-FILTER for the staging-command gate (G3). It answers "is it worth
|
|
85
|
+
* loading the tokenizer for this command?", never "is this a staging
|
|
86
|
+
* command?" — since #1404 that verdict belongs to {@link extractStagedPaths},
|
|
87
|
+
* which resolves the verb and subcommand properly.
|
|
88
|
+
*
|
|
89
|
+
* `git` and `add` must sit in the same statement (the negated class stops at
|
|
90
|
+
* `;`, `&`, `|` and newline) within 120 characters of each other, so global
|
|
91
|
+
* flags between them are tolerated: `git -C sub add x` reaches the extractor,
|
|
92
|
+
* where `\bgit\s+add\b` used to drop it silently. `\badd\b` keeps
|
|
93
|
+
* `git addremote` out.
|
|
94
|
+
*
|
|
95
|
+
* False positives are cheap AND inert: `git commit -m "add x"` matches here,
|
|
96
|
+
* resolves to no `git add` statement, and writes nothing (G4b).
|
|
97
|
+
*/
|
|
98
|
+
const GIT_ADD_REGEX = /\bgit\b[^;&|\n]{0,120}\badd\b/;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Recorded in place of a path list when the staging command names NO explicit
|
|
102
|
+
* path operand but stages a set we cannot enumerate — `git add -A`,
|
|
103
|
+
* `git add .`, `git add -u`, `git add --pathspec-from-file=<f>`. The reader
|
|
104
|
+
* (hooks/wave-scope-commit-guard.mjs) treats it as "overlaps every staged
|
|
105
|
+
* path". This is the case the previous raw-command regex silently MISSED:
|
|
106
|
+
* `-A` contains no path text, so `pathRegex(ours).test('git add -A')` was
|
|
107
|
+
* always false and the widest staging command of all fenced nothing.
|
|
83
108
|
*/
|
|
84
|
-
const
|
|
109
|
+
const ALL_PATHS_MARKER = '*';
|
|
110
|
+
|
|
111
|
+
/** git GLOBAL flags (before the subcommand) that consume the NEXT token. */
|
|
112
|
+
const GIT_GLOBAL_VALUE_FLAGS = new Set([
|
|
113
|
+
'-C', '-c', '--git-dir', '--work-tree', '--namespace', '--exec-path', '--config-env',
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
/** `git add` flags that consume the NEXT token as their value. */
|
|
117
|
+
const GIT_ADD_VALUE_FLAGS = new Set(['--chmod']);
|
|
118
|
+
|
|
119
|
+
/** `git add` long flags that stage a set no path operand names. */
|
|
120
|
+
const GIT_ADD_ALL_FLAGS = new Set(['--all', '--no-ignore-removal', '--update']);
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Shells whose `-c <payload>` operand is a command line the shell EXECUTES, so
|
|
124
|
+
* a `git add` inside it stages this working copy for real.
|
|
125
|
+
*
|
|
126
|
+
* DELIBERATE DUPLICATE of `DASH_C_SHELLS` in scripts/lib/command-blocker.mjs —
|
|
127
|
+
* that module does not export it (nor its `dashCPayloads`), and #1404's own
|
|
128
|
+
* rule for this hook is to consume the tokenizer, not to edit it (5 other
|
|
129
|
+
* consumers). Change one, change both.
|
|
130
|
+
*/
|
|
131
|
+
const DASH_C_SHELLS = new Set(['bash', 'sh', 'zsh', 'dash', 'ksh', 'su']);
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Payload recursion depth for {@link scanForStagedPaths}. ONE level: it covers
|
|
135
|
+
* `bash -c "git add x"` and `xargs -I{} sh -c "git add x"`, which is the whole
|
|
136
|
+
* measured regression class (2026-09-20), and keeps a hook that runs on EVERY
|
|
137
|
+
* Bash call from re-tokenizing an arbitrarily nested string.
|
|
138
|
+
*
|
|
139
|
+
* NAMED CEILING (BV-004): `bash -c "bash -c 'git add x'"` is not recorded.
|
|
140
|
+
* REVISIT TRIGGER: raise to 2 if a doubly-nested staging command is ever
|
|
141
|
+
* observed in a wave transcript.
|
|
142
|
+
*/
|
|
143
|
+
const MAX_PAYLOAD_DEPTH = 1;
|
|
85
144
|
|
|
86
145
|
// ---------------------------------------------------------------------------
|
|
87
146
|
// Helpers
|
|
88
147
|
// ---------------------------------------------------------------------------
|
|
89
148
|
|
|
149
|
+
/**
|
|
150
|
+
* sha256(command) truncated to 16 hex chars.
|
|
151
|
+
*
|
|
152
|
+
* DELIBERATE DUPLICATE of hooks/enforce-commands.mjs (itself a copy of
|
|
153
|
+
* hooks/pre-bash-destructive-guard.mjs) — see the 8f15f77b commit message:
|
|
154
|
+
* the three guards stay import-free of each other on purpose, so a shared
|
|
155
|
+
* helper is NOT introduced. The hash keeps a fence entry COUNTABLE and
|
|
156
|
+
* GROUPABLE without persisting command text that may carry a secret
|
|
157
|
+
* (`GIT_TOKEN=… git add x`) — issue #1404.
|
|
158
|
+
*
|
|
159
|
+
* @param {string} command
|
|
160
|
+
* @returns {string}
|
|
161
|
+
*/
|
|
162
|
+
function hashCommand(command) {
|
|
163
|
+
return crypto.createHash('sha256').update(command).digest('hex').slice(0, 16);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Normalise a path token so writer and reader compare the same spelling.
|
|
168
|
+
*
|
|
169
|
+
* DELIBERATE DUPLICATE of the identically-named function in
|
|
170
|
+
* hooks/wave-scope-commit-guard.mjs — the reader is a husky pre-commit hook
|
|
171
|
+
* outside the Claude-Code hook import set, and the two must agree byte for
|
|
172
|
+
* byte. Change one, change both.
|
|
173
|
+
*
|
|
174
|
+
* @param {string} raw
|
|
175
|
+
* @returns {string}
|
|
176
|
+
*/
|
|
177
|
+
function normalizeStagedPath(raw) {
|
|
178
|
+
let p = String(raw).trim();
|
|
179
|
+
while (p.startsWith('./')) p = p.slice(2);
|
|
180
|
+
p = p.replace(/\/{2,}/g, '/');
|
|
181
|
+
while (p.length > 1 && p.endsWith('/')) p = p.slice(0, -1);
|
|
182
|
+
return p;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Extract the PATH OPERANDS of every `git add` statement in a Bash command.
|
|
187
|
+
*
|
|
188
|
+
* Reuses the repo's own shell tokenizer (scripts/lib/command-blocker.mjs) —
|
|
189
|
+
* no second shell grammar is invented here. The import is LAZY: this hook
|
|
190
|
+
* runs on every Bash call of every session, and only a `git add` command
|
|
191
|
+
* (G3) ever reaches this function, so the tokenizer's module graph must not
|
|
192
|
+
* be paid for by the other 99% of calls.
|
|
193
|
+
*
|
|
194
|
+
* Handled: `git add -- a b`, quoted operands with spaces, `git -C <dir> add x`
|
|
195
|
+
* (relative `-C` is prefixed onto the operand), chained statements
|
|
196
|
+
* (`cd x && git add y` — each statement is its own segment), leading env
|
|
197
|
+
* assignments, and the enumerate-nothing flags that yield ALL_PATHS_MARKER.
|
|
198
|
+
*
|
|
199
|
+
* NAMED CEILINGS (BV-004):
|
|
200
|
+
* - Operands are recorded as WRITTEN, relative to the invoking cwd. A
|
|
201
|
+
* `cd subdir && git add foo.ts` records `foo.ts` while the staged path is
|
|
202
|
+
* `subdir/foo.ts` → a miss. This is exactly the pre-#1404 behaviour (the
|
|
203
|
+
* raw-command regex missed it too), not a new gap; revisit if a wave agent
|
|
204
|
+
* is ever observed staging from a subdirectory.
|
|
205
|
+
* - An ABSOLUTE operand (or an absolute `-C`) is recorded verbatim and will
|
|
206
|
+
* not match a repo-relative staged path. Same ceiling, same trigger.
|
|
207
|
+
* - A command the tokenizer resolves to no `git add` statement (`echo "git
|
|
208
|
+
* add x"` — G3's documented, tolerated false positive) yields an EMPTY
|
|
209
|
+
* list, never the marker: over-reporting here would turn a log line into a
|
|
210
|
+
* blocked commit, which the hook's fail-safe posture forbids. This is also
|
|
211
|
+
* why a blanket "pre-filter hit but nothing resolved → `paths: ['*']`"
|
|
212
|
+
* floor was REJECTED at the 2026-09-20 fix: `git commit -m "add x"` matches
|
|
213
|
+
* {@link GIT_ADD_REGEX}, and the marker overlaps EVERY staged path, so that
|
|
214
|
+
* floor manufactures a collision for a command that stages nothing.
|
|
215
|
+
* - A staging command a shell never executes locally is not recorded, and
|
|
216
|
+
* should not be: `ssh host 'git add x'` stages a REMOTE index, and
|
|
217
|
+
* `git submodule foreach "git add x"` stages the SUBMODULE's — neither can
|
|
218
|
+
* collide with a sibling agent in this working copy.
|
|
219
|
+
* REVISIT TRIGGER: if the commit-guard ever reconciles submodule indexes.
|
|
220
|
+
*
|
|
221
|
+
* @param {string} command
|
|
222
|
+
* @returns {Promise<{ recognised: boolean, paths: string[] }>}
|
|
223
|
+
*/
|
|
224
|
+
async function extractStagedPaths(command) {
|
|
225
|
+
let lib;
|
|
226
|
+
try {
|
|
227
|
+
lib = await import('../scripts/lib/command-blocker.mjs');
|
|
228
|
+
} catch {
|
|
229
|
+
return { recognised: false, paths: [] };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const paths = new Set();
|
|
233
|
+
const state = { recognised: false };
|
|
234
|
+
scanForStagedPaths(command, lib, paths, state, 0);
|
|
235
|
+
return { recognised: state.recognised, paths: [...paths] };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Collect the command lines a shell nested in this segment will EXECUTE.
|
|
240
|
+
*
|
|
241
|
+
* Two sources, unioned:
|
|
242
|
+
* - wrapper payloads `resolveSegmentVerb` already reports (`env -S '…'`),
|
|
243
|
+
* across both readings of an ambiguous dual parse (#1000);
|
|
244
|
+
* - a `-c`-style operand following a {@link DASH_C_SHELLS} token ANYWHERE in
|
|
245
|
+
* the segment, not only in resolved-verb position. The wider scan is what
|
|
246
|
+
* covers `xargs -I{} sh -c "git add x"` and `find … -exec sh -c "…" \;`,
|
|
247
|
+
* whose resolved verb is `xargs`/`find`; keying on the shell TOKEN instead
|
|
248
|
+
* of the verb also keeps `grep -c <pattern>` out, because `grep` is not a
|
|
249
|
+
* shell name.
|
|
250
|
+
*
|
|
251
|
+
* @param {Array<{ text: string, quoted: boolean }>} segment
|
|
252
|
+
* @param {{ payloads: string[], alt?: { payloads: string[] } }} resolved
|
|
253
|
+
* @returns {string[]} distinct payload strings
|
|
254
|
+
*/
|
|
255
|
+
function nestedShellPayloads(segment, resolved) {
|
|
256
|
+
const out = new Set();
|
|
257
|
+
for (const reading of [resolved, resolved.alt]) {
|
|
258
|
+
if (!reading) continue;
|
|
259
|
+
for (const p of reading.payloads) out.add(p);
|
|
260
|
+
}
|
|
261
|
+
for (let i = 0; i < segment.length - 1; i++) {
|
|
262
|
+
const tok = segment[i];
|
|
263
|
+
if (tok.quoted || !DASH_C_SHELLS.has(path.basename(tok.text))) continue;
|
|
264
|
+
for (let j = i + 1; j < segment.length - 1; j++) {
|
|
265
|
+
if (/^-[A-Za-z]*c$/.test(segment[j].text)) {
|
|
266
|
+
out.add(segment[j + 1].text);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return [...out];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* One tokenize + per-segment pass of {@link extractStagedPaths}, re-entered
|
|
276
|
+
* once per nested shell payload (bounded by {@link MAX_PAYLOAD_DEPTH}).
|
|
277
|
+
*
|
|
278
|
+
* Accumulates into the caller's `paths` set and `state.recognised` flag rather
|
|
279
|
+
* than returning, so a nested hit and a top-level hit compose:
|
|
280
|
+
* `git add a && bash -c "git add b"` records BOTH.
|
|
281
|
+
*
|
|
282
|
+
* @param {string} command
|
|
283
|
+
* @param {{ tokenizeCommand: Function, splitChainSegments: Function,
|
|
284
|
+
* resolveSegmentVerb: Function }} lib
|
|
285
|
+
* @param {Set<string>} paths - OUT
|
|
286
|
+
* @param {{ recognised: boolean }} state - OUT
|
|
287
|
+
* @param {number} depth
|
|
288
|
+
* @returns {void}
|
|
289
|
+
*/
|
|
290
|
+
function scanForStagedPaths(command, lib, paths, state, depth) {
|
|
291
|
+
let segments;
|
|
292
|
+
try {
|
|
293
|
+
segments = lib.splitChainSegments(lib.tokenizeCommand(command));
|
|
294
|
+
} catch {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
for (const segment of segments) {
|
|
299
|
+
const resolved = lib.resolveSegmentVerb(segment);
|
|
300
|
+
|
|
301
|
+
// A staging command nested in `bash -c "…"` resolves to the verb `bash`,
|
|
302
|
+
// so the loop below never sees it. Before #1404 the raw-text regex matched
|
|
303
|
+
// it INSIDE the quotes and the reader's path regex found the collision;
|
|
304
|
+
// the tokenizer rewrite dropped the whole class silently (measured
|
|
305
|
+
// 2026-09-20: `bash -c "git add src/foo.ts"` → no fence file at all). The
|
|
306
|
+
// fence is cross-agent collision detection, so a miss is silent in BOTH
|
|
307
|
+
// directions — re-enter the same extraction on the payload.
|
|
308
|
+
if (depth < MAX_PAYLOAD_DEPTH) {
|
|
309
|
+
for (const payload of nestedShellPayloads(segment, resolved)) {
|
|
310
|
+
// The G3 pre-filter again, on the payload: same cheap question, same
|
|
311
|
+
// tolerated false positives, and it keeps an unrelated `-c` operand
|
|
312
|
+
// from paying for a second tokenize.
|
|
313
|
+
if (typeof payload === 'string' && GIT_ADD_REGEX.test(payload)) {
|
|
314
|
+
scanForStagedPaths(payload, lib, paths, state, depth + 1);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const { verb, index } = resolved;
|
|
320
|
+
if (verb !== 'git' || index < 0) continue;
|
|
321
|
+
|
|
322
|
+
let i = index + 1;
|
|
323
|
+
let chdir = null;
|
|
324
|
+
|
|
325
|
+
// git GLOBAL flags sit between `git` and the subcommand.
|
|
326
|
+
while (i < segment.length) {
|
|
327
|
+
const tok = segment[i];
|
|
328
|
+
if (tok.quoted || !tok.text.startsWith('-') || tok.text === '-') break;
|
|
329
|
+
if (GIT_GLOBAL_VALUE_FLAGS.has(tok.text)) {
|
|
330
|
+
if (tok.text === '-C' && i + 1 < segment.length) chdir = segment[i + 1].text;
|
|
331
|
+
i += 2;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
i += 1; // boolean global flag, or attached `--git-dir=<p>`
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (i >= segment.length || segment[i].quoted || segment[i].text !== 'add') continue;
|
|
338
|
+
state.recognised = true;
|
|
339
|
+
i += 1;
|
|
340
|
+
|
|
341
|
+
let endOfFlags = false;
|
|
342
|
+
let stagesAll = false;
|
|
343
|
+
|
|
344
|
+
for (; i < segment.length; i++) {
|
|
345
|
+
const tok = segment[i];
|
|
346
|
+
const text = tok.text;
|
|
347
|
+
|
|
348
|
+
if (!endOfFlags && !tok.quoted && text.startsWith('-') && text !== '-') {
|
|
349
|
+
if (text === '--') { endOfFlags = true; continue; }
|
|
350
|
+
if (GIT_ADD_VALUE_FLAGS.has(text)) { i += 1; continue; }
|
|
351
|
+
if (text === '--pathspec-from-file' || text.startsWith('--pathspec-from-file=')) {
|
|
352
|
+
stagesAll = true;
|
|
353
|
+
if (text === '--pathspec-from-file') i += 1;
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (GIT_ADD_ALL_FLAGS.has(text)) { stagesAll = true; continue; }
|
|
357
|
+
// Short-flag cluster: `-A`, `-u`, `-An`, `-vu` all stage a set no
|
|
358
|
+
// operand names.
|
|
359
|
+
if (!text.startsWith('--') && /[Au]/.test(text.slice(1))) stagesAll = true;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (text === '.' || text === './') { stagesAll = true; continue; }
|
|
364
|
+
const operand = chdir && !chdir.startsWith('/') ? `${chdir}/${text}` : text;
|
|
365
|
+
const normalised = normalizeStagedPath(operand);
|
|
366
|
+
if (normalised.length > 0) paths.add(normalised);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (stagesAll) paths.add(ALL_PATHS_MARKER);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
90
373
|
/**
|
|
91
374
|
* Derive a per-agent identifier for the fence filename.
|
|
92
375
|
*
|
|
@@ -136,10 +419,10 @@ function resolveProjectDir() {
|
|
|
136
419
|
* #558 M1). The first call for a given agent_id creates the file with a
|
|
137
420
|
* fresh body.
|
|
138
421
|
*
|
|
139
|
-
* @param {{ fenceFile: string, agentId: string, command: string }} args
|
|
422
|
+
* @param {{ fenceFile: string, agentId: string, command: string, paths: string[] }} args
|
|
140
423
|
* @returns {{ ok: true } | { ok: false, reason: 'fs-error', error: string }}
|
|
141
424
|
*/
|
|
142
|
-
function appendIntent({ fenceFile, agentId, command }) {
|
|
425
|
+
function appendIntent({ fenceFile, agentId, command, paths }) {
|
|
143
426
|
const timestamp = new Date().toISOString();
|
|
144
427
|
|
|
145
428
|
let body;
|
|
@@ -169,7 +452,14 @@ function appendIntent({ fenceFile, agentId, command }) {
|
|
|
169
452
|
};
|
|
170
453
|
}
|
|
171
454
|
|
|
172
|
-
|
|
455
|
+
// #1404 — persist what the READER needs (path operands), never the command
|
|
456
|
+
// text: a staging command can carry a secret in a leading env assignment.
|
|
457
|
+
// The hash keeps the entry countable/groupable, mirroring enforce-commands.
|
|
458
|
+
body.staged_paths.push({
|
|
459
|
+
paths,
|
|
460
|
+
command_hash: hashCommand(command),
|
|
461
|
+
timestamp,
|
|
462
|
+
});
|
|
173
463
|
|
|
174
464
|
return writeJsonAtomicSync(fenceFile, body, { tmpPrefix: '.fence.tmp' });
|
|
175
465
|
}
|
|
@@ -189,12 +479,20 @@ async function main() {
|
|
|
189
479
|
const command = input?.tool_input?.command;
|
|
190
480
|
if (typeof command !== 'string' || command.length === 0) return emitAllow();
|
|
191
481
|
|
|
192
|
-
// G3 — regex
|
|
482
|
+
// G3 — cheap regex PRE-FILTER. Commands that cannot possibly be a staging
|
|
483
|
+
// command pass through without loading the tokenizer.
|
|
193
484
|
if (!GIT_ADD_REGEX.test(command)) return emitAllow();
|
|
194
485
|
|
|
195
486
|
// G4 — context gate. Coordinator/manual commits are not fenced.
|
|
196
487
|
if (!isWaveAgentContext()) return emitAllow();
|
|
197
488
|
|
|
489
|
+
// G4b — the PRECISE gate (#1404). The tokenizer, not the regex, decides
|
|
490
|
+
// whether this command really stages anything: a pre-filter hit with no
|
|
491
|
+
// resolvable `git add` statement (`git commit -m "add x"`) writes NO fence
|
|
492
|
+
// file, where the pre-#1404 hook logged its raw text.
|
|
493
|
+
const { recognised, paths } = await extractStagedPaths(command);
|
|
494
|
+
if (!recognised) return emitAllow();
|
|
495
|
+
|
|
198
496
|
// G5 — derive paths.
|
|
199
497
|
const projectDir = resolveProjectDir();
|
|
200
498
|
const agentId = deriveAgentId();
|
|
@@ -206,7 +504,7 @@ async function main() {
|
|
|
206
504
|
);
|
|
207
505
|
|
|
208
506
|
// G6 — append intent. Never blocks the Bash call on failure.
|
|
209
|
-
const result = appendIntent({ fenceFile, agentId, command });
|
|
507
|
+
const result = appendIntent({ fenceFile, agentId, command, paths });
|
|
210
508
|
if (!result.ok) {
|
|
211
509
|
process.stderr.write(
|
|
212
510
|
`⚠ pre-bash-staging-fence: failed to write fence file — ${result.error}\n`,
|
|
@@ -216,12 +514,18 @@ async function main() {
|
|
|
216
514
|
return emitAllow();
|
|
217
515
|
}
|
|
218
516
|
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
517
|
+
// Entry guard (#1393): run only as the node script the harness execs — a bare
|
|
518
|
+
// `import()` must run no handler and must not exit the importing process.
|
|
519
|
+
if (isMainModule(import.meta.url)) {
|
|
520
|
+
if (!shouldRunHook('pre-bash-staging-fence')) process.exit(0);
|
|
521
|
+
|
|
522
|
+
// Top-level error handler — never let exit 1 leak. Fail-open on internal
|
|
523
|
+
// errors to avoid blocking legitimate work (mirrors the destructive-guard
|
|
524
|
+
// posture).
|
|
525
|
+
main().catch((e) => {
|
|
526
|
+
process.stderr.write(
|
|
527
|
+
`⚠ pre-bash-staging-fence: internal error — ${e?.message || e}\n`,
|
|
528
|
+
);
|
|
529
|
+
process.exit(0);
|
|
530
|
+
});
|
|
531
|
+
}
|
|
@@ -44,14 +44,10 @@ import { hasReadInSession } from './_lib/transcript-history.mjs';
|
|
|
44
44
|
import { resolveHost, matchesBypass } from './_lib/vcs-create-matcher.mjs';
|
|
45
45
|
|
|
46
46
|
import { shouldRunHook } from './_lib/profile-gate.mjs';
|
|
47
|
+
import { isMainModule } from '../scripts/lib/is-main-module.mjs';
|
|
47
48
|
import { existsSync, readdirSync, lstatSync } from 'node:fs';
|
|
48
49
|
import path from 'node:path';
|
|
49
50
|
|
|
50
|
-
// #519: opt-in via profile/env. Default profile "full" enables this hook;
|
|
51
|
-
// minimal/off disable. SO_DISABLED_HOOKS=pre-bash-templates-first opts out
|
|
52
|
-
// per session.
|
|
53
|
-
if (!shouldRunHook('pre-bash-templates-first')) process.exit(0);
|
|
54
|
-
|
|
55
51
|
// ---------------------------------------------------------------------------
|
|
56
52
|
// Constants
|
|
57
53
|
// ---------------------------------------------------------------------------
|
|
@@ -426,12 +422,21 @@ async function main() {
|
|
|
426
422
|
});
|
|
427
423
|
}
|
|
428
424
|
|
|
429
|
-
//
|
|
430
|
-
//
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
);
|
|
436
|
-
|
|
437
|
-
|
|
425
|
+
// Entry guard (#1393): run only as the node script the harness execs — a bare
|
|
426
|
+
// `import()` must run no handler and must not exit the importing process.
|
|
427
|
+
if (isMainModule(import.meta.url)) {
|
|
428
|
+
// #519: opt-in via profile/env. Default profile "full" enables this hook;
|
|
429
|
+
// minimal/off disable. SO_DISABLED_HOOKS=pre-bash-templates-first opts out
|
|
430
|
+
// per session.
|
|
431
|
+
if (!shouldRunHook('pre-bash-templates-first')) process.exit(0);
|
|
432
|
+
|
|
433
|
+
// Top-level error handler — never let exit 1 leak. Same posture as
|
|
434
|
+
// pre-bash-destructive-guard.mjs: fail-open on internal errors to avoid
|
|
435
|
+
// blocking legitimate work.
|
|
436
|
+
main().catch((e) => {
|
|
437
|
+
process.stderr.write(
|
|
438
|
+
`⚠ pre-bash-templates-first: internal error — ${e?.message || e}\n`,
|
|
439
|
+
);
|
|
440
|
+
process.exit(0);
|
|
441
|
+
});
|
|
442
|
+
}
|