cc-safe-setup 29.8.0 → 30.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +72 -19
- package/.claude-plugin/plugin.json +1 -1
- package/CONTRIBUTING.md +7 -2
- package/COOKBOOK.md +50 -46
- package/LICENSE +21 -0
- package/MIGRATION.md +8 -8
- package/README.md +419 -512
- package/SAFETY_CHECKLIST.md +15 -7
- package/SERVICES.md +194 -0
- package/SETTINGS_REFERENCE.md +236 -17
- package/SKILL.md +5 -5
- package/TROUBLESHOOTING.md +35 -14
- package/action.yml +12 -4
- package/audit/README.md +84 -0
- package/audit/audit-checklist.md +152 -0
- package/audit/boundary-selftest.sh +85 -0
- package/audit/boundary.sh +123 -0
- package/audit/count-hooks.py +42 -0
- package/audit/find-dead-hooks.sh +82 -0
- package/audit/find-unfirable-rules.sh +142 -0
- package/audit/fire.sh +97 -0
- package/audit/selftest.sh +42 -0
- package/audit/unfirable-selftest.sh +81 -0
- package/audit-web/index.html +9 -9
- package/examples/README.md +54 -17
- package/examples/account-billing-log.sh +98 -0
- package/examples/account-routing-preflight.sh +123 -0
- package/examples/agent-sdk-credit-pool-monitor.sh +145 -0
- package/examples/agent-view-quota-decrement.sh +32 -0
- package/examples/agent-view-quota-warn.sh +94 -0
- package/examples/agents-md-edit-drift-warner.sh +223 -0
- package/examples/agents-md-loader.sh +160 -0
- package/examples/agents-md-sync-checker.sh +102 -0
- package/examples/ai-slop-punctuation-arrest.sh +210 -0
- package/examples/allowlist.sh +70 -10
- package/examples/always-allow-pattern-suggester.sh +125 -0
- package/examples/ansible-vault-guard.sh +2 -1
- package/examples/anthropic-base-url-guard.sh +76 -0
- package/examples/api-busyloop-guard.sh +123 -0
- package/examples/api-endpoint-guard.sh +12 -0
- package/examples/api-key-in-url-guard.sh +17 -1
- package/examples/api-rate-limit-guard.sh +36 -1
- package/examples/api-rate-limit-tracker.sh +12 -0
- package/examples/articulated-scope-capture.sh +101 -0
- package/examples/askuserquestion-autonomy-gate.sh +102 -0
- package/examples/attachment-traversal-guard.sh +118 -0
- package/examples/aup-block-pattern-logger.sh +161 -0
- package/examples/aup-false-positive-helper.sh +124 -0
- package/examples/aup-large-tool-output-warner.sh +282 -0
- package/examples/aup-retry-loop-guard.sh +229 -0
- package/examples/auth-expiry-reminder.sh +157 -0
- package/examples/auth-macos-sleep-detector.sh +185 -0
- package/examples/auth-path-detector.sh +171 -0
- package/examples/auth-status-checker.sh +157 -0
- package/examples/authorized-reconfirmation-detector.sh +195 -0
- package/examples/auto-approve-build.sh +39 -0
- package/examples/auto-approve-cargo.sh +31 -1
- package/examples/auto-approve-docker.sh +35 -0
- package/examples/auto-approve-git-read.sh +37 -14
- package/examples/auto-approve-go.sh +30 -1
- package/examples/auto-approve-gradle.sh +29 -1
- package/examples/auto-approve-make.sh +29 -1
- package/examples/auto-approve-maven.sh +29 -1
- package/examples/auto-approve-python.sh +41 -1
- package/examples/auto-approve-readonly-tools.sh +1 -0
- package/examples/auto-approve-readonly.sh +110 -33
- package/examples/auto-approve-ssh.sh +30 -1
- package/examples/auto-approve-test.sh +44 -0
- package/examples/auto-checkpoint.sh +1 -1
- package/examples/auto-compact-prep.sh +0 -0
- package/examples/auto-git-checkpoint.sh +0 -0
- package/examples/auto-mode-safe-commands.sh +53 -1
- package/examples/auto-mode-safety-enforcer.sh +151 -4
- package/examples/auto-push-session-branch.sh +22 -0
- package/examples/aws-production-guard.sh +13 -1
- package/examples/aws-region-guard.sh +1 -1
- package/examples/background-cost-launch-guard.sh +82 -0
- package/examples/background-task-guard.sh +12 -0
- package/examples/backup-before-refactor.sh +0 -0
- package/examples/banned-command-guard.sh +12 -0
- package/examples/bash-allowlist-secondary-check.sh +157 -0
- package/examples/bash-domain-allowlist.sh +12 -0
- package/examples/bash-fanout-bounded-rewriter.sh +191 -0
- package/examples/bash-heuristic-approver.sh +112 -10
- package/examples/bash-project-fence.sh +194 -0
- package/examples/bash-safety-auto-deny.sh +12 -0
- package/examples/bash-secret-output-detector.sh +44 -3
- package/examples/bash-trace-guard.sh +12 -0
- package/examples/bashrc-safety-check.sh +0 -0
- package/examples/bg-permission-prompt-warner.sh +182 -0
- package/examples/bg-task-cooldown-guard.sh +12 -0
- package/examples/binary-read-detector.sh +135 -0
- package/examples/binary-upload-guard.sh +12 -0
- package/examples/block-database-wipe.sh +35 -10
- package/examples/branch-name-check.sh +8 -3
- package/examples/branch-naming-convention.sh +0 -0
- package/examples/broad-find-guard.sh +12 -0
- package/examples/broad-prefix-session-trap-warner.sh +106 -0
- package/examples/bulk-file-delete-guard.sh +45 -0
- package/examples/bypass-mode-effective-verifier.sh +203 -0
- package/examples/cache-creation-drift-detector.sh +120 -0
- package/examples/cache-residue-detector.sh +195 -0
- package/examples/cache-tier-logger.sh +70 -0
- package/examples/cache-ttl-eviction-detector.sh +149 -0
- package/examples/cargo-publish-guard.sh +14 -1
- package/examples/case-insensitive-path-guard.sh +21 -2
- package/examples/case-sensitive-guard.sh +23 -2
- package/examples/cch-cache-guard.sh +0 -0
- package/examples/cch-sentinel-precommit-guard.sh +47 -0
- package/examples/check-abort-controller.sh +1 -1
- package/examples/check-accessibility.sh +0 -0
- package/examples/check-aria-labels.sh +0 -0
- package/examples/check-before-act-enforcer.sh +12 -0
- package/examples/check-charset-meta.sh +0 -0
- package/examples/check-cookie-flags.sh +0 -0
- package/examples/check-cors-config.sh +0 -0
- package/examples/check-csp-headers.sh +0 -0
- package/examples/check-csrf-protection.sh +0 -0
- package/examples/check-debounce.sh +1 -1
- package/examples/check-dependency-age.sh +0 -0
- package/examples/check-dependency-license.sh +0 -0
- package/examples/check-dockerfile-best-practice.sh +0 -0
- package/examples/check-error-boundaries.sh +0 -0
- package/examples/check-error-class.sh +1 -1
- package/examples/check-error-handling.sh +0 -0
- package/examples/check-error-logging.sh +1 -1
- package/examples/check-error-message.sh +0 -0
- package/examples/check-error-stack.sh +0 -0
- package/examples/check-favicon.sh +0 -0
- package/examples/check-git-hooks-compat.sh +0 -0
- package/examples/check-gitattributes.sh +0 -0
- package/examples/check-https-redirect.sh +0 -0
- package/examples/check-input-validation.sh +0 -0
- package/examples/check-lang-attribute.sh +0 -0
- package/examples/check-npm-scripts-exist.sh +0 -0
- package/examples/check-package-size.sh +0 -0
- package/examples/check-port-availability.sh +0 -0
- package/examples/check-promise-all.sh +1 -1
- package/examples/check-rate-limiting.sh +0 -0
- package/examples/check-return-types.sh +0 -0
- package/examples/check-semantic-versioning.sh +0 -0
- package/examples/check-suspense-fallback.sh +1 -1
- package/examples/check-test-exists.sh +0 -0
- package/examples/check-test-naming.sh +0 -0
- package/examples/check-timeout-cleanup.sh +1 -1
- package/examples/check-tls-version.sh +0 -0
- package/examples/check-unsubscribe.sh +1 -1
- package/examples/check-viewport-meta.sh +0 -0
- package/examples/check-worker-terminate.sh +1 -1
- package/examples/checkpoint-tamper-guard.sh +12 -0
- package/examples/chmod-guard.sh +12 -0
- package/examples/chown-guard.sh +24 -0
- package/examples/ci-workflow-guard.sh +6 -1
- package/examples/claim-verify-detector.sh +109 -0
- package/examples/claim-vs-caveat-checker.sh +77 -0
- package/examples/classifier-fallback-allow.sh +114 -40
- package/examples/claude-cache-gc.sh +1 -0
- package/examples/claude-code-version-pin-advisor.sh +183 -0
- package/examples/claude-md-reinjector.sh +129 -0
- package/examples/claude-md-size-monitor.sh +66 -0
- package/examples/claude-update-budget-guard.sh +123 -0
- package/examples/claude-update-smart.sh +113 -0
- package/examples/claudeignore-enforce-guard.sh +12 -0
- package/examples/claudemd-enforcer.sh +0 -0
- package/examples/claudemd-tool-prohibition.sh +128 -0
- package/examples/clear-command-confirm-guard.sh +32 -15
- package/examples/cli-config-pinning-detector.sh +162 -0
- package/examples/cliff-countdown-advisor.sh +96 -0
- package/examples/clipboard-secret-guard.sh +12 -0
- package/examples/closure-word-verify-gate.sh +150 -0
- package/examples/cloud-cli-guard.sh +39 -2
- package/examples/commit-all-scope-guard.sh +44 -0
- package/examples/commit-message-check.sh +1 -1
- package/examples/commit-message-quality.sh +6 -1
- package/examples/commitment-carry-forward-arrest.sh +361 -0
- package/examples/compact-alert-notification.sh +0 -0
- package/examples/compact-dispatch-watchdog.sh +149 -0
- package/examples/completion-claim-without-verification-detector.sh +207 -0
- package/examples/composer-guard.sh +12 -0
- package/examples/compound-bash-permission-resolver.sh +156 -0
- package/examples/compound-command-allow.sh +1 -1
- package/examples/compound-command-deny-enforcer.sh +183 -0
- package/examples/compound-inject-guard.sh +12 -0
- package/examples/concurrent-edit-lock.sh +12 -0
- package/examples/conflict-marker-guard.sh +12 -0
- package/examples/consecutive-error-breaker.sh +0 -0
- package/examples/console-log-count.sh +1 -0
- package/examples/context-compact-advisor.sh +29 -2
- package/examples/context-length-budget.sh +69 -0
- package/examples/context-threshold-alert.sh +12 -0
- package/examples/context-usage-drift-alert.sh +41 -13
- package/examples/conversation-history-guard.sh +12 -0
- package/examples/core-file-protect-guard.sh +12 -0
- package/examples/cors-star-warn.sh +0 -0
- package/examples/cost-incident-self-audit.sh +162 -0
- package/examples/cowork-claude-md-load-checker.sh +100 -0
- package/examples/cowork-fuse-staleness-watcher.sh +140 -0
- package/examples/cowork-hook-absence-warner.sh +167 -0
- package/examples/cowork-model-picker-advisor.sh +115 -0
- package/examples/credential-exfil-guard.sh +65 -4
- package/examples/credential-file-cat-guard.sh +17 -1
- package/examples/cron-create-receipt.sh +112 -0
- package/examples/cron-modification-guard.sh +12 -0
- package/examples/cross-product-mcp-spawn-detector.sh +178 -0
- package/examples/cwd-project-boundary-guard.sh +0 -0
- package/examples/daemon-zombie-worker-surfacer.sh +118 -0
- package/examples/daily-cost-guard.sh +164 -0
- package/examples/daily-usage-tracker.sh +0 -0
- package/examples/dangerous-pip-flag-guard.sh +12 -0
- package/examples/db-connect-guard.sh +13 -1
- package/examples/denied-action-retry-guard.sh +12 -0
- package/examples/deny-bypass-detector.sh +12 -0
- package/examples/deny-rule-integrity-verifier.sh +181 -0
- package/examples/dependency-install-guard.sh +12 -0
- package/examples/deploy-guard.sh +14 -2
- package/examples/deploy-path-verify-guard.sh +12 -0
- package/examples/deployment-readback-gate.sh +135 -0
- package/examples/deployment-readback-gh-adapter.sh +247 -0
- package/examples/deployment-verify-guard.sh +25 -2
- package/examples/destructive-db-script-write-guard.sh +166 -0
- package/examples/destructive-migration-write-guard.sh +163 -0
- package/examples/diff-size-guard.sh +12 -0
- package/examples/disabled-feature-toggle-advisor.sh +88 -0
- package/examples/disk-partition-guard.sh +12 -0
- package/examples/dispatch-allowlist-preflight.sh +301 -0
- package/examples/dispatch-liveness-watchdog.sh +216 -0
- package/examples/dispatch-receipt.sh +174 -0
- package/examples/django-migrate-guard.sh +12 -0
- package/examples/dns-config-guard.sh +12 -0
- package/examples/docker-dangerous-guard.sh +12 -0
- package/examples/docker-volume-guard.sh +0 -0
- package/examples/dockerfile-latest-guard.sh +1 -0
- package/examples/dotenv-anthropic-key-billing-guard.sh +99 -0
- package/examples/dotenv-commit-guard.sh +12 -0
- package/examples/dotenv-read-guard.sh +12 -0
- package/examples/dotfile-protection-guard.sh +12 -0
- package/examples/dotnet-build-on-edit.sh +1 -1
- package/examples/drizzle-migrate-guard.sh +27 -2
- package/examples/echo-probe-spam-detector.sh +176 -0
- package/examples/edit-counter-test-gate.sh +12 -0
- package/examples/edit-error-counter.sh +1 -1
- package/examples/edit-guard.sh +12 -0
- package/examples/edit-old-string-validator.sh +12 -0
- package/examples/edit-quote-ambiguity-guard.sh +97 -0
- package/examples/edit-retry-loop-guard.sh +0 -0
- package/examples/edit-verify.sh +0 -0
- package/examples/env-inline-secret-guard.sh +14 -2
- package/examples/env-naming-convention.sh +0 -0
- package/examples/env-prod-guard.sh +0 -0
- package/examples/env-required-check.sh +0 -0
- package/examples/env-source-guard.sh +12 -0
- package/examples/env-var-check.sh +24 -1
- package/examples/ephemeral-container-detector.sh +147 -0
- package/examples/error-memory-guard.sh +12 -0
- package/examples/evidence-claim-gate.sh +187 -0
- package/examples/exploration-budget-guard.sh +12 -0
- package/examples/expo-eject-guard.sh +13 -0
- package/examples/extended-thinking-loop-guard.sh +139 -0
- package/examples/extended-thinking-resume-warning.sh +119 -0
- package/examples/extended-thinking-tool-use-mismatch-detector.sh +212 -0
- package/examples/fabricated-command-detector.sh +145 -0
- package/examples/false-disk-full-guard.sh +63 -0
- package/examples/feature-deprecation-detector.sh +109 -0
- package/examples/file-change-tracker.sh +1 -1
- package/examples/file-change-undo-tracker.sh +0 -0
- package/examples/file-edit-backup.sh +63 -14
- package/examples/file-reference-check.sh +0 -0
- package/examples/file-size-limit.sh +12 -0
- package/examples/financial-operation-guard.sh +12 -0
- package/examples/firewall-guard.sh +12 -0
- package/examples/fish-shell-wrapper.sh +125 -7
- package/examples/five-hundred-milestone.sh +1 -0
- package/examples/flask-static-route-guard.sh +89 -0
- package/examples/forbidden-response-phrase-detector.sh +161 -0
- package/examples/gem-push-guard.sh +13 -0
- package/examples/gh-cli-destructive-guard.sh +13 -1
- package/examples/git-checkout-safety-guard.sh +12 -0
- package/examples/git-checkout-uncommitted-guard.sh +12 -0
- package/examples/git-config-guard.sh +12 -0
- package/examples/git-crypt-worktree-guard.sh +12 -0
- package/examples/git-filter-repo-guard.sh +56 -0
- package/examples/git-history-rewrite-guard.sh +12 -0
- package/examples/git-hook-bypass-guard.sh +0 -0
- package/examples/git-maintenance-guard.sh +83 -0
- package/examples/git-merge-conflict-prevent.sh +0 -0
- package/examples/git-message-length-check.sh +0 -0
- package/examples/git-message-length.sh +0 -0
- package/examples/git-operations-require-approval.sh +68 -14
- package/examples/git-pack-temp-cleanup-guard.sh +102 -0
- package/examples/git-push-blast-radius-guard.sh +218 -0
- package/examples/git-remote-guard.sh +24 -3
- package/examples/git-rm-orphan-wipe-guard.sh +85 -0
- package/examples/git-stash-before-checkout.sh +12 -0
- package/examples/git-stash-before-danger.sh +0 -0
- package/examples/git-submodule-guard.sh +69 -2
- package/examples/git-tag-guard.sh +12 -0
- package/examples/github-actions-secret-guard.sh +0 -0
- package/examples/gitignore-check.sh +0 -0
- package/examples/gitops-drift-guard.sh +12 -0
- package/examples/go-mod-tidy-warn.sh +1 -0
- package/examples/go-vet-after-edit.sh +12 -0
- package/examples/goal-iteration-limit-warner.sh +152 -0
- package/examples/grep-nul-false-negative-guard.sh +30 -0
- package/examples/growthbook-flag-monitor.sh +257 -0
- package/examples/hallucination-url-check.sh +1 -1
- package/examples/halt-signal-detector.sh +135 -0
- package/examples/handoff-on-clear.sh +65 -0
- package/examples/hardcoded-ip-guard.sh +1 -0
- package/examples/headless-empty-result-guard.sh +0 -0
- package/examples/headless-stop-guard.sh +0 -0
- package/examples/helm-install-guard.sh +2 -1
- package/examples/home-critical-bash-guard.sh +17 -1
- package/examples/hook-debug-wrapper.sh +6 -2
- package/examples/hook-permission-fixer.sh +0 -0
- package/examples/hook-self-disable-detector.sh +99 -0
- package/examples/hook-stdout-sanitizer.sh +6 -2
- package/examples/hook-tamper-guard.sh +12 -0
- package/examples/idle-session-cost-alert.sh +0 -0
- package/examples/image-dimension-guard.sh +109 -0
- package/examples/image-file-validator.sh +0 -0
- package/examples/iteration-quality-degradation-detector.sh +170 -0
- package/examples/java-compile-on-edit.sh +1 -1
- package/examples/json-syntax-check.sh +0 -0
- package/examples/k8s-production-guard.sh +13 -1
- package/examples/kill-process-guard.sh +12 -0
- package/examples/kubernetes-guard.sh +13 -1
- package/examples/laravel-artisan-guard.sh +13 -0
- package/examples/large-file-guard.sh +1 -1
- package/examples/log-level-guard.sh +0 -0
- package/examples/log-truncation-guard.sh +12 -0
- package/examples/long-session-malformed-tool-call-detector.sh +183 -0
- package/examples/loop-detector.sh +12 -0
- package/examples/magic-number-warn.sh +1 -0
- package/examples/main-branch-warn.sh +12 -0
- package/examples/markdown-link-check.sh +0 -0
- package/examples/max-concurrent-agents.sh +12 -0
- package/examples/max-edit-size-guard.sh +13 -0
- package/examples/max-file-count-guard.sh +0 -0
- package/examples/max-file-delete-count.sh +0 -0
- package/examples/max-function-length.sh +1 -0
- package/examples/max-import-count.sh +0 -0
- package/examples/max-subagent-count.sh +0 -0
- package/examples/mcp-config-freeze.sh +12 -0
- package/examples/mcp-config-poisoning-audit.sh +150 -0
- package/examples/mcp-data-boundary.sh +1 -1
- package/examples/mcp-misdiagnosis-arrest.sh +209 -0
- package/examples/mcp-orphan-leak-warner.sh +49 -0
- package/examples/mcp-permissions-ask-warner.sh +151 -0
- package/examples/mcp-routine-approval-detector.sh +154 -0
- package/examples/mcp-server-allowlist.sh +12 -0
- package/examples/mcp-server-guard.sh +12 -0
- package/examples/mcp-startup-bloat-detector.sh +87 -0
- package/examples/mcp-stdio-compatibility-test.sh +153 -0
- package/examples/mcp-tool-audit-log.sh +0 -0
- package/examples/mcp-tool-guard.sh +101 -1
- package/examples/mcp-warmup-wait.sh +0 -0
- package/examples/memory-chain-audit.sh +56 -0
- package/examples/memory-orphan-detector.sh +188 -0
- package/examples/memory-write-guard.sh +99 -17
- package/examples/migration-verify-guard.sh +12 -0
- package/examples/model-swap-suggester.sh +177 -0
- package/examples/model-version-alert.sh +5 -1
- package/examples/model-version-lock.sh +63 -0
- package/examples/move-delete-sequence-guard.sh +33 -2
- package/examples/multi-file-plan-routing-gate.sh +192 -0
- package/examples/multi-vendor-concurrent-warner.sh +108 -0
- package/examples/multi-window-auth-drift-detector.sh +183 -0
- package/examples/multiline-command-approver.sh +161 -23
- package/examples/nested-background-agent-guard.sh +109 -0
- package/examples/nested-spawn-inflight-guard.sh +178 -0
- package/examples/network-exfil-guard.sh +12 -0
- package/examples/network-guard.sh +12 -0
- package/examples/network-interface-guard.sh +12 -0
- package/examples/nextjs-env-guard.sh +1 -1
- package/examples/no-absolute-import.sh +0 -0
- package/examples/no-alert-confirm-prompt.sh +0 -0
- package/examples/no-anonymous-default-export.sh +0 -0
- package/examples/no-any-type.sh +0 -0
- package/examples/no-any-typescript.sh +1 -0
- package/examples/no-ask-human.sh +12 -0
- package/examples/no-assignment-in-condition.sh +0 -0
- package/examples/no-base64-exfil.sh +12 -0
- package/examples/no-callback-hell.sh +0 -0
- package/examples/no-circular-dependency.sh +0 -0
- package/examples/no-cleartext-storage.sh +0 -0
- package/examples/no-commented-code.sh +0 -0
- package/examples/no-commit-fixup.sh +0 -0
- package/examples/no-console-assert.sh +0 -0
- package/examples/no-console-error-swallow.sh +0 -0
- package/examples/no-console-in-prod.sh +0 -0
- package/examples/no-console-log-commit.sh +12 -0
- package/examples/no-console-log.sh +0 -0
- package/examples/no-console-time.sh +0 -0
- package/examples/no-cors-wildcard.sh +4 -1
- package/examples/no-curl-upload.sh +0 -0
- package/examples/no-dangerouslySetInnerHTML.sh +0 -0
- package/examples/no-dangling-await.sh +1 -0
- package/examples/no-debug-commit.sh +12 -0
- package/examples/no-debug-in-commit.sh +0 -0
- package/examples/no-deep-nesting.sh +0 -0
- package/examples/no-deep-relative-import.sh +1 -0
- package/examples/no-default-credentials.sh +0 -0
- package/examples/no-deploy-friday.sh +13 -1
- package/examples/no-disabled-test.sh +0 -0
- package/examples/no-document-write.sh +0 -0
- package/examples/no-empty-function.sh +0 -0
- package/examples/no-eval-in-template.sh +0 -0
- package/examples/no-eval-template.sh +3 -1
- package/examples/no-eval.sh +0 -0
- package/examples/no-exec-user-input.sh +0 -0
- package/examples/no-fixme-ship.sh +12 -0
- package/examples/no-floating-promises.sh +0 -0
- package/examples/no-force-flag.sh +22 -5
- package/examples/no-force-install.sh +0 -0
- package/examples/no-git-amend.sh +12 -0
- package/examples/no-git-rebase-public.sh +0 -0
- package/examples/no-global-install.sh +12 -0
- package/examples/no-global-state.sh +0 -0
- package/examples/no-hardcoded-port.sh +1 -0
- package/examples/no-hardcoded-url.sh +0 -0
- package/examples/no-helmet-missing.sh +0 -0
- package/examples/no-http-url.sh +1 -0
- package/examples/no-http-without-https.sh +0 -0
- package/examples/no-inline-style.sh +0 -0
- package/examples/no-inline-styles.sh +1 -0
- package/examples/no-innerhtml.sh +0 -0
- package/examples/no-install-global.sh +12 -0
- package/examples/no-jwt-in-url.sh +0 -0
- package/examples/no-large-commit.sh +0 -0
- package/examples/no-localhost-expose.sh +0 -0
- package/examples/no-magic-number.sh +0 -0
- package/examples/no-md5-sha1.sh +0 -0
- package/examples/no-mixed-line-endings.sh +8 -1
- package/examples/no-mutation-in-reducer.sh +0 -0
- package/examples/no-nested-ternary.sh +0 -0
- package/examples/no-network-exfil.sh +0 -0
- package/examples/no-open-redirect.sh +0 -0
- package/examples/no-output-truncation.sh +12 -0
- package/examples/no-package-downgrade.sh +0 -0
- package/examples/no-package-lock-edit.sh +12 -0
- package/examples/no-path-join-user-input.sh +0 -0
- package/examples/no-port-bind.sh +0 -0
- package/examples/no-process-exit.sh +0 -0
- package/examples/no-prototype-pollution.sh +0 -0
- package/examples/no-push-without-ci.sh +0 -0
- package/examples/no-push-without-tests.sh +12 -0
- package/examples/no-raw-password-in-url.sh +0 -0
- package/examples/no-root-user-docker.sh +1 -0
- package/examples/no-root-write.sh +12 -0
- package/examples/no-secrets-in-args.sh +4 -1
- package/examples/no-secrets-in-logs.sh +0 -0
- package/examples/no-sensitive-log.sh +0 -0
- package/examples/no-sleep-in-hooks.sh +0 -0
- package/examples/no-star-import-python.sh +1 -0
- package/examples/no-string-concat-sql.sh +0 -0
- package/examples/no-sudo-guard.sh +12 -0
- package/examples/no-sync-fs.sh +0 -0
- package/examples/no-todo-in-merge.sh +0 -0
- package/examples/no-todo-in-production.sh +1 -0
- package/examples/no-todo-without-issue.sh +0 -0
- package/examples/no-unused-import.sh +0 -0
- package/examples/no-var-keyword.sh +0 -0
- package/examples/no-verify-blocker.sh +12 -0
- package/examples/no-wget-piped-bash.sh +12 -0
- package/examples/no-wildcard-cors.sh +0 -0
- package/examples/no-wildcard-delete.sh +0 -0
- package/examples/no-wildcard-import.sh +0 -0
- package/examples/no-with-statement.sh +0 -0
- package/examples/no-write-outside-src.sh +0 -0
- package/examples/no-xml-external-entity.sh +0 -0
- package/examples/non-english-quality-warner.sh +156 -0
- package/examples/notify-waiting.sh +1 -1
- package/examples/npm-audit-warn.sh +0 -0
- package/examples/npm-global-install-guard.sh +12 -0
- package/examples/npm-publish-guard.sh +12 -0
- package/examples/npm-script-injection.sh +0 -0
- package/examples/npm-supply-chain-guard.sh +0 -0
- package/examples/nuxt-config-guard.sh +1 -0
- package/examples/oauth-refresh-monitor.sh +210 -0
- package/examples/opus-degradation-tracker.sh +187 -0
- package/examples/opus48-routine-task-warning.sh +196 -0
- package/examples/opus48-thinking-wedge-advisor.sh +143 -0
- package/examples/output-credential-scan.sh +1 -1
- package/examples/output-secret-mask.sh +31 -9
- package/examples/output-token-spike-detector.sh +145 -0
- package/examples/package-json-guard.sh +12 -0
- package/examples/package-lock-frozen.sh +12 -0
- package/examples/parallel-batch-size-limiter.sh +121 -0
- package/examples/parallel-cascade-detector.sh +116 -0
- package/examples/partial-view-claim-arrest.sh +174 -0
- package/examples/path-deny-bash-guard.sh +12 -0
- package/examples/path-traversal-guard.sh +12 -0
- package/examples/per-prompt-token-cap.sh +124 -0
- package/examples/permission-audit-log.sh +1 -1
- package/examples/permission-denial-enforcer.sh +12 -0
- package/examples/permission-entry-validator.sh +0 -0
- package/examples/persisted-1m-model-advisor.sh +88 -0
- package/examples/php-lint-on-edit.sh +1 -1
- package/examples/pii-upload-guard.sh +12 -0
- package/examples/pip-publish-guard.sh +13 -0
- package/examples/pip-requirements-guard.sh +12 -0
- package/examples/pip-venv-required.sh +12 -0
- package/examples/plan-mode-edit-guard.sh +12 -0
- package/examples/plan-mode-enforcer.sh +12 -0
- package/examples/plan-mode-strict-guard.sh +12 -0
- package/examples/plugin-hooks-json-bloat-detector.sh +169 -0
- package/examples/plugin-process-cleanup.sh +0 -0
- package/examples/polyglot-rm-guard.sh +12 -0
- package/examples/post-compact-safety.sh +12 -0
- package/examples/post-edit-disk-verify.sh +152 -0
- package/examples/powershell-remove-item-guard.sh +85 -0
- package/examples/pr-description-check.sh +0 -0
- package/examples/pr-duplicate-guard.sh +13 -0
- package/examples/pre-bash-sed-line-ending-windows.sh +87 -0
- package/examples/pre-compact-knowledge-save.sh +0 -0
- package/examples/pre-compact-transcript-backup.sh +0 -0
- package/examples/pre-execution-claim-detector.sh +179 -0
- package/examples/prefer-builtin-tools.sh +10 -1
- package/examples/prefer-const.sh +0 -0
- package/examples/prefer-dedicated-tools.sh +12 -0
- package/examples/prefer-optional-chaining.sh +0 -0
- package/examples/prisma-migrate-guard.sh +24 -7
- package/examples/production-port-kill-guard.sh +12 -0
- package/examples/prompt-injection-guard.sh +2 -1
- package/examples/prompt-usage-logger.sh +0 -0
- package/examples/protect-claudemd.sh +12 -0
- package/examples/protect-dotfiles.sh +12 -0
- package/examples/proxy-capture-suggester.sh +159 -0
- package/examples/public-artefact-socratic-narrowing.sh +232 -0
- package/examples/public-repo-push-guard.sh +12 -0
- package/examples/push-requires-test-pass-record.sh +0 -0
- package/examples/push-requires-test-pass.sh +12 -0
- package/examples/quota-anomaly-detector.sh +173 -0
- package/examples/quota-reset-audit.sh +58 -0
- package/examples/quoted-flag-approver.sh +99 -10
- package/examples/rails-migration-guard.sh +12 -0
- package/examples/rate-limit-guard.sh +0 -0
- package/examples/read-all-files-enforcer.sh +0 -0
- package/examples/read-budget-guard.sh +12 -0
- package/examples/read-loop-detector.sh +59 -0
- package/examples/read-once-guard.sh +96 -0
- package/examples/read-only-mode.sh +12 -0
- package/examples/readme-exists-check.sh +0 -0
- package/examples/record-read-coverage.sh +73 -0
- package/examples/redirect-fragment-warner.sh +149 -0
- package/examples/redis-flushall-guard.sh +13 -0
- package/examples/redundant-read-blocker.sh +132 -0
- package/examples/refusal-arrest-gate.sh +248 -0
- package/examples/registry-publish-guard.sh +13 -1
- package/examples/remote-control-billing-classifier.sh +135 -0
- package/examples/replace-all-guard.sh +12 -0
- package/examples/repo-visibility-guard.sh +12 -0
- package/examples/reroute-after-block-guard.sh +150 -0
- package/examples/response-budget-guard.sh +0 -0
- package/examples/resume-drift-watcher.sh +57 -0
- package/examples/rg-replace-flag-detector.sh +125 -0
- package/examples/rhetorical-verification-prompt-detector.sh +102 -0
- package/examples/ripgrep-permission-fix.sh +0 -0
- package/examples/rm-safety-net.sh +151 -8
- package/examples/role-tool-guard.sh +12 -0
- package/examples/route-handler-emptiness-gate.sh +324 -0
- package/examples/ruby-lint-on-edit.sh +1 -1
- package/examples/runtime-binary-change-detector.sh +102 -0
- package/examples/same-command-repeat-detector.sh +196 -0
- package/examples/same-correction-arrest.sh +169 -0
- package/examples/sandbox-denywrite-enforcer.sh +78 -0
- package/examples/sandbox-relative-path-audit.sh +83 -25
- package/examples/sandbox-write-verify.sh +12 -0
- package/examples/schema-migration-guard.sh +0 -0
- package/examples/scope-expansion-receipt.sh +178 -0
- package/examples/scope-guard.sh +88 -9
- package/examples/secret-file-read-guard.sh +12 -0
- package/examples/secret-file-write-guard.sh +150 -0
- package/examples/self-modify-bypass-guard.sh +0 -0
- package/examples/sensitive-file-read-guard.sh +23 -3
- package/examples/sensitive-log-guard.sh +1 -0
- package/examples/server-side-prompt-injection-detector.sh +69 -0
- package/examples/session-agent-cost-limiter.sh +12 -0
- package/examples/session-backup-on-start.sh +1 -1
- package/examples/session-cost-alert.sh +12 -0
- package/examples/session-drift-guard.sh +12 -0
- package/examples/session-duration-guard.sh +25 -2
- package/examples/session-end-logger.sh +0 -0
- package/examples/session-health-monitor.sh +0 -0
- package/examples/session-index-repair.sh +1 -1
- package/examples/session-memory-watchdog.sh +1 -0
- package/examples/session-permission-reset-guard.sh +12 -0
- package/examples/session-persistence-verifier.sh +93 -0
- package/examples/session-plugin-pin-watch.sh +68 -0
- package/examples/session-rate-monitor.sh +176 -0
- package/examples/session-resume-env-fix.sh +0 -0
- package/examples/session-start-quota-status.sh +193 -0
- package/examples/session-start-safety-check.sh +55 -3
- package/examples/session-state-saver.sh +0 -0
- package/examples/session-summary-stop.sh +1 -1
- package/examples/session-summary.sh +0 -0
- package/examples/session-token-counter.sh +1 -1
- package/examples/settings-hooks-key-restorer.sh +99 -0
- package/examples/settings-json-health-check.sh +57 -0
- package/examples/settings-json-model-guard.sh +0 -0
- package/examples/settings-regression-tester.sh +188 -0
- package/examples/shell-config-truncation-guard.sh +12 -0
- package/examples/shell-wrapper-guard.sh +12 -0
- package/examples/skill-cumulative-size-detector.sh +104 -0
- package/examples/skill-description-drop-detector.sh +148 -0
- package/examples/skill-gate.sh +0 -0
- package/examples/skill-truncation-detector.sh +154 -0
- package/examples/skills-context-recorder.sh +167 -0
- package/examples/skills-load-verifier.sh +96 -0
- package/examples/skills-settings-validator.sh +139 -0
- package/examples/sonnet-45-deprecation-helper.sh +85 -0
- package/examples/spec-file-scope-guard.sh +12 -0
- package/examples/spring-profile-guard.sh +1 -0
- package/examples/spurious-malformed-notice-detector.sh +247 -0
- package/examples/sql-bulk-delete-warn.sh +88 -0
- package/examples/sql-injection-detect.sh +0 -0
- package/examples/ssh-key-protect.sh +12 -0
- package/examples/staged-secret-scan.sh +22 -1
- package/examples/stale-temp-settings-detector.sh +86 -0
- package/examples/standing-rule-session-surfacer.sh +137 -0
- package/examples/stop-hook-sigterm-wrapper.sh +182 -0
- package/examples/stop-transcript-write-health.sh +64 -0
- package/examples/strict-allowlist.sh +57 -15
- package/examples/strip-coauthored-by.sh +50 -10
- package/examples/subagent-blast-radius-guard.sh +184 -0
- package/examples/subagent-boundary-precheck.sh +126 -0
- package/examples/subagent-budget-guard.sh +12 -0
- package/examples/subagent-claudemd-inject.sh +0 -0
- package/examples/subagent-closure-verify-gate.sh +164 -0
- package/examples/subagent-destructive-git-guard.sh +120 -0
- package/examples/subagent-error-detector.sh +0 -0
- package/examples/subagent-forged-system-reminder-guard.sh +156 -0
- package/examples/subagent-identity-leak-guard.sh +102 -0
- package/examples/subagent-identity-reassertion.sh +51 -0
- package/examples/subagent-inheritance-tester.sh +179 -0
- package/examples/subagent-permission-mode-guard.sh +110 -0
- package/examples/subagent-scope-guard.sh +12 -0
- package/examples/subagent-spawn-verification-enforcer.sh +102 -0
- package/examples/subagent-tool-allowlist-enforcer.sh +101 -0
- package/examples/subagent-tool-call-limiter.sh +87 -15
- package/examples/subcommand-chain-guard.sh +12 -0
- package/examples/subscription-api-billing-warner.sh +160 -0
- package/examples/subscription-bypass-detector.sh +152 -0
- package/examples/svelte-lint-on-edit.sh +1 -0
- package/examples/swift-build-on-edit.sh +1 -1
- package/examples/symlink-guard.sh +27 -2
- package/examples/symlink-protect.sh +1 -0
- package/examples/system-dir-protection-guard.sh +73 -8
- package/examples/system-message-workaround.sh +38 -13
- package/examples/system-package-guard.sh +12 -0
- package/examples/systemd-service-guard.sh +12 -0
- package/examples/task-integrity-guard.sh +12 -0
- package/examples/temp-file-cleanup.sh +1 -1
- package/examples/temporal-suggestion-detector.sh +135 -0
- package/examples/terraform-guard.sh +27 -6
- package/examples/test-after-edit.sh +1 -1
- package/examples/test-before-push.sh +12 -0
- package/examples/test-coverage-reminder.sh +24 -1
- package/examples/thinking-budget-effort-mismatch-detector.sh +149 -0
- package/examples/timezone-guard.sh +0 -0
- package/examples/tmp-output-size-guard.sh +0 -0
- package/examples/todo-check.sh +1 -1
- package/examples/token-budget-guard.sh +12 -0
- package/examples/token-budget-per-task.sh +12 -0
- package/examples/token-usage-tracker.sh +7 -1
- package/examples/tokenizer-ratio-alert-corpus.sh +90 -0
- package/examples/tokenizer-ratio-alert.sh +104 -0
- package/examples/tool-call-rate-limiter.sh +0 -0
- package/examples/tool-result-correlation-checker.sh +167 -0
- package/examples/tool-result-size-guard.sh +132 -0
- package/examples/tool-retry-budget-guard.sh +12 -0
- package/examples/transcript-contamination-detector.sh +138 -0
- package/examples/trustfall-mcp-injection-guard.sh +103 -0
- package/examples/ultrareview-large-diff-advisor.sh +184 -0
- package/examples/unbounded-output-guard.sh +94 -0
- package/examples/uncommitted-changes-stop.sh +1 -0
- package/examples/uncommitted-discard-guard.sh +23 -5
- package/examples/uncommitted-work-guard.sh +12 -0
- package/examples/usage-warn.sh +0 -0
- package/examples/user-account-guard.sh +12 -0
- package/examples/userprompt-submit-receipt.sh +123 -0
- package/examples/variable-expansion-guard.sh +12 -0
- package/examples/verify-after-publish-reminder.sh +93 -0
- package/examples/verify-before-commit.sh +12 -0
- package/examples/version-bump-detector.sh +156 -0
- package/examples/version-regression-warner.sh +144 -0
- package/examples/vue-lint-on-edit.sh +1 -0
- package/examples/warn-cron-cost-trap.sh +173 -0
- package/examples/webfetch-runaway-guard.sh +89 -0
- package/examples/wellness-break-reminder.sh +118 -0
- package/examples/windows-destructive-command-guard.sh +177 -0
- package/examples/windows-path-guard.sh +12 -0
- package/examples/windows-python-stub-detector.sh +63 -0
- package/examples/work-hours-guard.sh +12 -0
- package/examples/working-directory-fence.sh +12 -0
- package/examples/workspace-lease-guard.sh +205 -0
- package/examples/worktree-create-log.sh +1 -0
- package/examples/worktree-delete-guard.sh +12 -0
- package/examples/worktree-edit-boundary-guard.sh +127 -0
- package/examples/worktree-escape-write-guard.sh +114 -0
- package/examples/worktree-hook-linker.sh +0 -0
- package/examples/worktree-hooks-path-fix.sh +111 -0
- package/examples/worktree-parent-write-guard.sh +43 -0
- package/examples/worktree-project-unify.sh +2 -1
- package/examples/worktree-remove-uncommitted-guard.sh +13 -0
- package/examples/worktree-unmerged-guard.sh +7 -1
- package/examples/write-byte-integrity-verifier.sh +190 -0
- package/examples/write-empty-content-guard.sh +67 -0
- package/examples/write-nul-corruption-detector.sh +61 -0
- package/examples/write-overwrite-confirm.sh +160 -14
- package/examples/write-secret-guard.sh +27 -5
- package/examples/write-shrink-guard.sh +12 -0
- package/examples/write-test-ratio.sh +0 -0
- package/examples/wsl-host-disk-space-guard.sh +97 -0
- package/examples/xml-format-leak-detector.sh +266 -0
- package/examples/yaml-syntax-check.sh +12 -0
- package/hooks/hooks.json +6 -6
- package/index.mjs +1699 -183
- package/mission.md +2 -0
- package/package.json +4 -4
- package/plugins/credential-guard/.claude-plugin/plugin.json +9 -7
- package/plugins/git-protection/.claude-plugin/plugin.json +10 -8
- package/plugins/safety-essentials/.claude-plugin/plugin.json +9 -7
- package/plugins/token-guard/.claude-plugin/plugin.json +10 -8
- package/scripts/agents-md-sync-setup.sh +156 -0
- package/scripts/autonomy-blocked-summary.sh +148 -0
- package/scripts/build-search-index.py +43 -0
- package/scripts/build-sitemap.py +119 -0
- package/scripts/cc-doctor.sh +192 -0
- package/scripts/check-hook-event-names.py +127 -0
- package/scripts/check-misfire-instrument.sh +64 -0
- package/scripts/claim-verify-audit.sh +467 -0
- package/scripts/cowork-claudemd-helper.sh +136 -0
- package/scripts/june-15-deprecated-model-scan.sh +111 -0
- package/scripts/measure-heredoc-shapes.sh +67 -0
- package/scripts/measure-literal-match-misfire.sh +110 -0
- package/scripts/probe-scope-guard-branches.sh +48 -0
- package/scripts/probe-skip-line-both-ways.sh +65 -0
- package/scripts/receipts-aggregate.py +199 -0
- package/scripts/session-forensic-audit.py +360 -0
- package/scripts.json +9 -9
- package/scripts.json.bak-2026-07-27-find +13 -0
- package/skills/safety-setup/SKILL.md +5 -5
- package/tests/approve-side-remaining-two.test.sh +129 -0
- package/tests/approver-list-granularity.test.sh +145 -0
- package/tests/askuserquestion-autonomy-gate.test.sh +181 -0
- package/tests/audit-ci-gate.test.sh +87 -0
- package/tests/audit-cross-layer-claudemd.test.sh +170 -0
- package/tests/audit-fail-open-parse.test.sh +100 -0
- package/tests/auto-approve-compound-tail.test.sh +194 -0
- package/tests/auto-mode-path-invoked-commands.test.sh +89 -0
- package/tests/auto-mode-quoted-targets.test.sh +127 -0
- package/tests/auto-mode-unquoted-targets.test.sh +112 -0
- package/tests/bash-secret-output-detector-detects.test.sh +102 -0
- package/tests/blindspots-cross-layer.test.sh +177 -0
- package/tests/block-database-wipe.test.sh +64 -0
- package/tests/bundled-short-flags-bypass.test.sh +85 -0
- package/tests/cd-git-allow-compound-tail.test.sh +67 -0
- package/tests/chown-guard-filesystem-root.test.sh +64 -0
- package/tests/ci-workflow-guard-skip-rule.test.sh +115 -0
- package/tests/compound-deny-safe-rm-targets.test.sh +105 -0
- package/tests/core-scripts-parser-fallback.test.sh +140 -0
- package/tests/destructive-guard-bare-glob.test.sh +74 -0
- package/tests/destructive-guard-every-operand.test.sh +100 -0
- package/tests/destructive-guard-find-deletion.test.sh +114 -0
- package/tests/destructive-guard-flag-order.test.sh +106 -0
- package/tests/destructive-guard-mentions-vs-invocations.test.sh +107 -0
- package/tests/destructive-guard-quoted-target.test.sh +89 -0
- package/tests/destructive-guard-separators.test.sh +105 -0
- package/tests/destructive-guard-variable-target.test.sh +98 -0
- package/tests/destructive-guard-wrapped-command.test.sh +91 -0
- package/tests/doctor-hook-disabling-env.test.sh +92 -0
- package/tests/doctor-misspelled-settings-keys.test.sh +106 -0
- package/tests/example-guards-wrapped-command.test.sh +169 -0
- package/tests/file-edit-backup.test.sh +93 -0
- package/tests/git-filter-repo-guard.test.sh +60 -0
- package/tests/git-global-options-bypass.test.sh +141 -0
- package/tests/git-invocation-prefixes-all-guards.test.sh +114 -0
- package/tests/git-maintenance-guard.test.sh +83 -0
- package/tests/git-pack-temp-cleanup-guard.test.sh +133 -0
- package/tests/git-rm-orphan-wipe-guard.test.sh +66 -0
- package/tests/git-submodule-guard.test.sh +50 -0
- package/tests/grep-pcre-portability.test.sh +155 -0
- package/tests/hook-registration-matches-input.test.sh +73 -0
- package/tests/hook-trigger-matches-envelope.test.sh +178 -0
- package/tests/install-does-not-claim-protection.test.sh +110 -0
- package/tests/install-example-standalone-tools.test.sh +139 -0
- package/tests/line-continuation-bypass.test.sh +114 -0
- package/tests/mcp-config-poisoning-audit.test.sh +106 -0
- package/tests/nested-background-agent-guard.test.sh +58 -0
- package/tests/no-unqualified-safety-claims.test.sh +114 -0
- package/tests/option-eating-grep-patterns.test.sh +130 -0
- package/tests/outdated-core-guards.test.sh +134 -0
- package/tests/outdated-report.test.sh +155 -0
- package/tests/output-secret-mask-warns.test.sh +73 -0
- package/tests/plugin-hooks-fail-open-under-sh.test.sh +165 -0
- package/tests/plugins-word-order.test.sh +126 -0
- package/tests/powershell-remove-item-guard.test.sh +85 -0
- package/tests/project-dir-naming.test.sh +103 -0
- package/tests/quoted-safe-targets-and-mentions.test.sh +190 -0
- package/tests/reroute-after-block-guard.test.sh +104 -0
- package/tests/secret-guard-documented-promises.test.sh +97 -0
- package/tests/session-plugin-pin-watch.test.sh +45 -0
- package/tests/settings-unreadable-refuses-to-write.test.sh +95 -0
- package/tests/shield-no-silent-adoption.test.py +110 -0
- package/tests/shield-no-silent-adoption.test.sh +46 -0
- package/tests/stop-transcript-write-health.test.sh +46 -0
- package/tests/system-dir-guard-root-erased.test.sh +66 -0
- package/tests/test-account-billing-log.sh +100 -0
- package/tests/test-account-routing-preflight.sh +77 -0
- package/tests/test-agent-sdk-credit-pool-monitor.sh +157 -0
- package/tests/test-agent-view-quota-warn.sh +184 -0
- package/tests/test-agents-md-edit-drift-warner.sh +176 -0
- package/tests/test-agents-md-loader.sh +204 -0
- package/tests/test-agents-md-sync-checker.sh +125 -0
- package/tests/test-ai-slop-punctuation-arrest.sh +280 -0
- package/tests/test-allowlist.sh +60 -0
- package/tests/test-always-allow-pattern-suggester.sh +147 -0
- package/tests/test-anthropic-base-url-guard.sh +88 -0
- package/tests/test-articulated-scope-capture.sh +139 -0
- package/tests/test-attachment-traversal-guard.sh +168 -0
- package/tests/test-aup-block-pattern-logger.sh +315 -0
- package/tests/test-aup-false-positive-helper.sh +188 -0
- package/tests/test-aup-large-tool-output-warner.sh +370 -0
- package/tests/test-aup-retry-loop-guard.sh +341 -0
- package/tests/test-auth-expiry-reminder.sh +303 -0
- package/tests/test-auth-macos-sleep-detector.sh +254 -0
- package/tests/test-auth-path-detector.sh +232 -0
- package/tests/test-auth-status-checker.sh +233 -0
- package/tests/test-authorized-reconfirmation-detector.sh +280 -0
- package/tests/test-background-cost-launch-guard.sh +62 -0
- package/tests/test-bash-allowlist-secondary-check.sh +143 -0
- package/tests/test-bash-fanout-bounded-rewriter.sh +186 -0
- package/tests/test-bash-project-fence.sh +127 -0
- package/tests/test-bg-permission-prompt-warner.sh +221 -0
- package/tests/test-binary-read-detector.sh +173 -0
- package/tests/test-broad-prefix-session-trap-warner.sh +167 -0
- package/tests/test-bulk-delete-target-resolution.sh +49 -0
- package/tests/test-bypass-mode-effective-verifier.sh +179 -0
- package/tests/test-cache-creation-drift-detector.sh +244 -0
- package/tests/test-cache-residue-detector.sh +429 -0
- package/tests/test-cache-tier-logger.sh +59 -0
- package/tests/test-cache-ttl-eviction-detector.sh +282 -0
- package/tests/test-cch-sentinel-precommit-guard.sh +64 -0
- package/tests/test-claim-verify-detector.sh +222 -0
- package/tests/test-claim-vs-caveat-checker.sh +134 -0
- package/tests/test-claude-code-version-pin-advisor.sh +353 -0
- package/tests/test-claude-md-reinjector.sh +173 -0
- package/tests/test-claude-md-size-monitor.sh +107 -0
- package/tests/test-claude-update-budget-guard.sh +132 -0
- package/tests/test-claude-update-smart.sh +91 -0
- package/tests/test-claudemd-tool-prohibition.sh +239 -0
- package/tests/test-cli-config-pinning-detector.sh +233 -0
- package/tests/test-cliff-countdown-advisor.sh +138 -0
- package/tests/test-closure-word-verify-gate.sh +158 -0
- package/tests/test-commit-all-scope-guard.sh +73 -0
- package/tests/test-commitment-carry-forward-arrest.sh +250 -0
- package/tests/test-compact-dispatch-watchdog.sh +147 -0
- package/tests/test-completion-claim-without-verification-detector.sh +326 -0
- package/tests/test-compound-bash-permission-resolver.sh +264 -0
- package/tests/test-compound-command-deny-enforcer.sh +67 -0
- package/tests/test-context-length-budget.sh +68 -0
- package/tests/test-context-usage-drift-alert.sh +52 -22
- package/tests/test-cost-incident-self-audit.sh +94 -0
- package/tests/test-cowork-claude-md-load-checker.sh +257 -0
- package/tests/test-cowork-claudemd-helper.sh +141 -0
- package/tests/test-cowork-fuse-staleness-watcher.sh +287 -0
- package/tests/test-cowork-hook-absence-warner.sh +230 -0
- package/tests/test-cowork-model-picker-advisor.sh +317 -0
- package/tests/test-credential-exfil-guard.sh +62 -0
- package/tests/test-cron-create-receipt.sh +165 -0
- package/tests/test-cross-product-mcp-spawn-detector.sh +112 -0
- package/tests/test-daemon-zombie-worker-surfacer.sh +71 -0
- package/tests/test-daily-cost-guard.sh +131 -0
- package/tests/test-deny-rule-integrity-verifier.sh +288 -0
- package/tests/test-deployment-readback-gate.sh +92 -0
- package/tests/test-deployment-readback-gh-adapter.sh +163 -0
- package/tests/test-disabled-feature-toggle-advisor.sh +78 -0
- package/tests/test-dispatch-allowlist-preflight.sh +385 -0
- package/tests/test-dispatch-liveness-watchdog.sh +319 -0
- package/tests/test-dispatch-receipt.sh +314 -0
- package/tests/test-dotenv-anthropic-key-billing-guard.sh +160 -0
- package/tests/test-echo-probe-spam-detector.sh +143 -0
- package/tests/test-edit-quote-ambiguity-guard.sh +75 -0
- package/tests/test-ephemeral-container-detector.sh +251 -0
- package/tests/test-evidence-claim-gate.sh +291 -0
- package/tests/test-extended-thinking-loop-guard.sh +289 -0
- package/tests/test-extended-thinking-resume-warning.sh +240 -0
- package/tests/test-extended-thinking-tool-use-mismatch-detector.sh +236 -0
- package/tests/test-fabricated-command-detector.sh +296 -0
- package/tests/test-false-disk-full-guard.sh +36 -0
- package/tests/test-feature-deprecation-detector.sh +117 -0
- package/tests/test-forbidden-response-phrase-detector.sh +246 -0
- package/tests/test-git-operations-require-approval.sh +53 -0
- package/tests/test-git-push-blast-radius-guard.sh +115 -0
- package/tests/test-goal-iteration-limit-warner.sh +128 -0
- package/tests/test-growthbook-flag-monitor.sh +428 -0
- package/tests/test-halt-signal-detector.sh +120 -0
- package/tests/test-hook-self-disable-detector.sh +232 -0
- package/tests/test-iteration-quality-degradation-detector.sh +244 -0
- package/tests/test-long-session-malformed-tool-call-detector.sh +185 -0
- package/tests/test-marketplace-plugins.sh +193 -0
- package/tests/test-mcp-misdiagnosis-arrest.sh +235 -0
- package/tests/test-mcp-orphan-leak-warner.sh +71 -0
- package/tests/test-mcp-permissions-ask-warner.sh +207 -0
- package/tests/test-mcp-routine-approval-detector.sh +229 -0
- package/tests/test-mcp-startup-bloat-detector.sh +141 -0
- package/tests/test-mcp-stdio-compatibility-test.sh +112 -0
- package/tests/test-memory-chain-audit.sh +59 -0
- package/tests/test-memory-orphan-detector.sh +227 -0
- package/tests/test-model-swap-suggester.sh +368 -0
- package/tests/test-model-version-lock.sh +83 -0
- package/tests/test-multi-file-plan-routing-gate.sh +277 -0
- package/tests/test-multi-window-auth-drift-detector.sh +262 -0
- package/tests/test-nested-spawn-inflight-guard.sh +281 -0
- package/tests/test-no-force-flag.sh +49 -0
- package/tests/test-non-english-quality-warner.sh +229 -0
- package/tests/test-oauth-refresh-monitor.sh +311 -0
- package/tests/test-opus-degradation-tracker.sh +274 -0
- package/tests/test-opus48-routine-task-warning.sh +201 -0
- package/tests/test-opus48-thinking-wedge-advisor.sh +249 -0
- package/tests/test-output-token-spike-detector.sh +315 -0
- package/tests/test-parallel-batch-size-limiter.sh +228 -0
- package/tests/test-parallel-cascade-detector.sh +191 -0
- package/tests/test-partial-view-claim-arrest.sh +272 -0
- package/tests/test-per-prompt-token-cap.sh +136 -0
- package/tests/test-persisted-1m-model-advisor.sh +71 -0
- package/tests/test-plugin-hooks-json-bloat-detector.sh +267 -0
- package/tests/test-post-edit-disk-verify.sh +294 -0
- package/tests/test-pre-bash-sed-line-ending-windows.sh +108 -0
- package/tests/test-pre-execution-claim-detector.sh +366 -0
- package/tests/test-private-key-backup-and-git-credentials.sh +100 -0
- package/tests/test-proxy-capture-suggester.sh +214 -0
- package/tests/test-public-artefact-socratic-narrowing.sh +346 -0
- package/tests/test-quota-anomaly-detector.sh +321 -0
- package/tests/test-quota-reset-audit.sh +81 -0
- package/tests/test-read-loop-detector.sh +137 -0
- package/tests/test-read-once-guard.sh +85 -0
- package/tests/test-receipts-aggregate.sh +143 -0
- package/tests/test-redirect-fragment-warner.sh +130 -0
- package/tests/test-redundant-read-blocker.sh +155 -0
- package/tests/test-refusal-arrest-gate.sh +303 -0
- package/tests/test-remote-control-billing-classifier.sh +125 -0
- package/tests/test-resume-drift-watcher.sh +65 -0
- package/tests/test-rg-replace-flag-detector.sh +175 -0
- package/tests/test-rhetorical-verification-prompt-detector.sh +237 -0
- package/tests/test-rm-safety-net.sh +115 -0
- package/tests/test-route-handler-emptiness-gate.sh +300 -0
- package/tests/test-runtime-binary-change-detector.sh +196 -0
- package/tests/test-same-command-repeat-detector.sh +165 -0
- package/tests/test-same-correction-arrest.sh +165 -0
- package/tests/test-scope-expansion-receipt.sh +207 -0
- package/tests/test-server-side-prompt-injection-detector.sh +181 -0
- package/tests/test-session-persistence-verifier.sh +128 -0
- package/tests/test-session-rate-monitor.sh +284 -0
- package/tests/test-session-start-quota-status.sh +210 -0
- package/tests/test-session-start-safety-check.sh +138 -0
- package/tests/test-settings-hooks-key-restorer.sh +257 -0
- package/tests/test-settings-json-health-check.sh +70 -0
- package/tests/test-settings-regression-tester.sh +197 -0
- package/tests/test-skill-cumulative-size-detector.sh +198 -0
- package/tests/test-skill-description-drop-detector.sh +236 -0
- package/tests/test-skill-truncation-detector.sh +263 -0
- package/tests/test-skills-context-recorder.sh +329 -0
- package/tests/test-skills-load-verifier.sh +184 -0
- package/tests/test-skills-settings-validator.sh +242 -0
- package/tests/test-sonnet-45-deprecation-helper.sh +150 -0
- package/tests/test-spurious-malformed-notice-detector.sh +290 -0
- package/tests/test-sql-bulk-delete-warn.sh +123 -0
- package/tests/test-ssh-key-protect.sh +81 -0
- package/tests/test-stale-temp-settings-detector.sh +161 -0
- package/tests/test-standing-rule-session-surfacer.sh +215 -0
- package/tests/test-starter-hooks-manifest.sh +96 -0
- package/tests/test-stop-hook-sigterm-wrapper.sh +258 -0
- package/tests/test-strict-allowlist.sh +72 -0
- package/tests/test-subagent-boundary-precheck.sh +137 -0
- package/tests/test-subagent-closure-verify-gate.sh +193 -0
- package/tests/test-subagent-destructive-git-guard.sh +86 -0
- package/tests/test-subagent-identity-leak-guard.sh +62 -0
- package/tests/test-subagent-identity-reassertion.sh +61 -0
- package/tests/test-subagent-inheritance-tester.sh +319 -0
- package/tests/test-subagent-permission-mode-guard.sh +61 -0
- package/tests/test-subagent-spawn-verification-enforcer.sh +60 -0
- package/tests/test-subagent-tool-allowlist-enforcer.sh +62 -0
- package/tests/test-subagent-tool-call-limiter.sh +97 -0
- package/tests/test-subscription-api-billing-warner.sh +138 -0
- package/tests/test-subscription-bypass-detector.sh +255 -0
- package/tests/test-temporal-suggestion-detector.sh +183 -0
- package/tests/test-thinking-budget-effort-mismatch-detector.sh +327 -0
- package/tests/test-tokenizer-ratio-alert-corpus.sh +77 -0
- package/tests/test-tokenizer-ratio-alert.sh +93 -0
- package/tests/test-tool-result-correlation-checker.sh +264 -0
- package/tests/test-tool-result-size-guard.sh +121 -0
- package/tests/test-transcript-contamination-detector.sh +264 -0
- package/tests/test-trigger-header-parsing.sh +151 -0
- package/tests/test-ultrareview-large-diff-advisor.sh +192 -0
- package/tests/test-userprompt-submit-receipt.sh +181 -0
- package/tests/test-verify-after-publish-reminder.sh +184 -0
- package/tests/test-version-bump-detector.sh +212 -0
- package/tests/test-version-regression-warner.sh +165 -0
- package/tests/test-warn-cron-cost-trap.sh +82 -0
- package/tests/test-webfetch-runaway-guard.sh +77 -0
- package/tests/test-wellness-break-reminder.sh +138 -0
- package/tests/test-windows-destructive-command-guard.sh +169 -0
- package/tests/test-windows-python-stub-detector.sh +146 -0
- package/tests/test-worktree-edit-boundary-guard.sh +219 -0
- package/tests/test-write-byte-integrity-verifier.sh +192 -0
- package/tests/test-xml-format-leak-detector.sh +299 -0
- package/tests/trustfall-mcp-injection-guard.test.sh +183 -0
- package/tests/workspace-lease-guard.test.sh +144 -0
- package/tests/worktree-escape-write-guard.test.sh +68 -0
- package/tests/worktree-hooks-path-fix.test.sh +181 -0
- package/tests/worktree-parent-write-guard.test.sh +51 -0
- package/tests/write-empty-content-guard.test.sh +39 -0
- package/tests/write-nul-corruption-detector.test.sh +29 -0
- package/tests/write-overwrite-unread-content.test.sh +178 -0
- package/tests/wsl-host-disk-space-guard.test.sh +55 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# refusal-arrest-gate.sh — Block the next tool call if the assistant's prose
|
|
3
|
+
# in the same turn explicitly refused that action ("I won't modify X",
|
|
4
|
+
# "I'll skip X", "I'll preserve X") and the tool call contradicts the refusal.
|
|
5
|
+
#
|
|
6
|
+
# Sister hook to closure-word-verify-gate.sh. Both follow the same shape
|
|
7
|
+
# (recognition-without-arrest from #60226): the model's own prose names what
|
|
8
|
+
# it will and will not do, and the actual tool sequence is uncorrelated with
|
|
9
|
+
# the naming. closure-word-verify-gate fires on positive-closure language;
|
|
10
|
+
# this one fires on self-stated NEGATIVE action followed by the action.
|
|
11
|
+
#
|
|
12
|
+
# Solves: refusal-side dual of #60506. Examples observed in the wild:
|
|
13
|
+
# - #60475 — sub-agent stated it would preserve uncommitted work, then
|
|
14
|
+
# ran `git checkout -- <files>` against the other operator's
|
|
15
|
+
# unstaged edits.
|
|
16
|
+
# - #60506 — agent acknowledged the categorical native-React ban, then
|
|
17
|
+
# introduced a native React component on the next Write.
|
|
18
|
+
# Agent confirmed the i18n-only label rule, then hardcoded
|
|
19
|
+
# the label in the next Edit.
|
|
20
|
+
# - #60188 — fraction of 51 acknowledged-rule-violations followed
|
|
21
|
+
# refusal-shape syntax in the response stream.
|
|
22
|
+
#
|
|
23
|
+
# Design philosophy:
|
|
24
|
+
# The cluster's load-bearing observation: prose rules cannot be
|
|
25
|
+
# the load-bearing element of architectural guarantees. The load-
|
|
26
|
+
# bearing element has to live in the harness at the point of action.
|
|
27
|
+
# closure-word-verify-gate lives on Stop (session-terminal). This hook
|
|
28
|
+
# lives on PreToolUse (mid-turn) because refusal-side failures happen
|
|
29
|
+
# between the refusal statement and the next user prompt.
|
|
30
|
+
#
|
|
31
|
+
# False-positive control (three constraints, in order of importance):
|
|
32
|
+
# 1. TARGET MATCH, not verb match: a refusal of "I'll skip the test step"
|
|
33
|
+
# only triggers if the next tool call's target IS the test step.
|
|
34
|
+
# "I'll skip X → tool call edits Y" does not trigger.
|
|
35
|
+
# 2. CURRENT TURN ONLY: refusals from prior turns do not gate the
|
|
36
|
+
# current PreToolUse. Refusal scope = same-turn assistant prose.
|
|
37
|
+
# 3. ASSISTANT-ORIGINATED ONLY: refusals inside a quoted user-prompt
|
|
38
|
+
# block are ignored (the agent reading back what the user said
|
|
39
|
+
# should not trigger the gate when the agent does X next).
|
|
40
|
+
#
|
|
41
|
+
# Related Issues:
|
|
42
|
+
# #60506 (@zean89, 2026-05-19) — first-person self-report
|
|
43
|
+
# #60226 (@suwayama, 2026-05-18) — recognition-without-arrest framework
|
|
44
|
+
# #60475 — sub-agent git checkout data loss
|
|
45
|
+
# #60188 (@beq00000) — 51 rule violations in one session
|
|
46
|
+
#
|
|
47
|
+
# TRIGGER: PreToolUse
|
|
48
|
+
# MATCHER: "Edit|Write|Bash|MultiEdit"
|
|
49
|
+
#
|
|
50
|
+
# CONFIGURATION (environment variables):
|
|
51
|
+
# CC_REFUSAL_PATTERNS default built-in — pipe-separated regex of
|
|
52
|
+
# refusal phrases (capturing
|
|
53
|
+
# group 1 = target words)
|
|
54
|
+
# CC_REFUSAL_GATE_DISABLE set to "1" to disable the gate entirely
|
|
55
|
+
#
|
|
56
|
+
# USAGE (settings.json):
|
|
57
|
+
# {
|
|
58
|
+
# "hooks": {
|
|
59
|
+
# "PreToolUse": [{
|
|
60
|
+
# "matcher": "Edit|Write|Bash|MultiEdit",
|
|
61
|
+
# "hooks": [{
|
|
62
|
+
# "type": "command",
|
|
63
|
+
# "command": "~/.claude/hooks/refusal-arrest-gate.sh"
|
|
64
|
+
# }]
|
|
65
|
+
# }]
|
|
66
|
+
# }
|
|
67
|
+
# }
|
|
68
|
+
|
|
69
|
+
set -uo pipefail
|
|
70
|
+
|
|
71
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
72
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
73
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
74
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
75
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
76
|
+
_nojq_warned="/tmp/cc-nojq-warned-refusal-arrest-gate-$PPID"
|
|
77
|
+
[ -f "$_nojq_warned" ] || {
|
|
78
|
+
echo "WARNING [refusal-arrest-gate]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
79
|
+
: > "$_nojq_warned"
|
|
80
|
+
}
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
[ "${CC_REFUSAL_GATE_DISABLE:-0}" = "1" ] && exit 0
|
|
84
|
+
|
|
85
|
+
INPUT=$(cat 2>/dev/null || true)
|
|
86
|
+
[ -z "$INPUT" ] && exit 0
|
|
87
|
+
|
|
88
|
+
# Default refusal patterns. Each pattern's capturing group 1 extracts the
|
|
89
|
+
# target (file, action, step name) that the agent stated it would not act on.
|
|
90
|
+
# The regex is permissive on the target to handle the natural-language tail.
|
|
91
|
+
DEFAULT_REFUSAL_PATTERNS='I (will not|won['"'"']?t|am not going to|wo n['"'"']?t) (modify|edit|change|touch|update|delete|remove|overwrite|push|commit|run|execute|create|write to|alter|patch|replace|drop|reset) ([A-Za-z0-9_./@\-]+)|I['"'"']?ll (skip|preserve|keep|leave|not touch|not modify|avoid|leave alone|not change|not edit) (the |an? )?([A-Za-z0-9_./@\-]+)|let me not (modify|edit|change|touch|update|delete|run) ([A-Za-z0-9_./@\-]+)|skipping (the )?([A-Za-z0-9_./@\-]+)|preserving (the )?([A-Za-z0-9_./@\-]+)'
|
|
92
|
+
|
|
93
|
+
REFUSAL_PATTERNS="${CC_REFUSAL_PATTERNS:-$DEFAULT_REFUSAL_PATTERNS}"
|
|
94
|
+
|
|
95
|
+
# PreToolUse input shape: { tool_name, tool_input, transcript (path or array) }
|
|
96
|
+
TOOL_NAME=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
97
|
+
[ -z "$TOOL_NAME" ] && exit 0
|
|
98
|
+
|
|
99
|
+
# Tool target extraction by tool type
|
|
100
|
+
case "$TOOL_NAME" in
|
|
101
|
+
Write|Edit|MultiEdit)
|
|
102
|
+
TOOL_TARGET=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty' 2>/dev/null)
|
|
103
|
+
;;
|
|
104
|
+
Bash)
|
|
105
|
+
TOOL_TARGET=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
106
|
+
;;
|
|
107
|
+
*)
|
|
108
|
+
# Non-instrumented tool — pass through.
|
|
109
|
+
exit 0
|
|
110
|
+
;;
|
|
111
|
+
esac
|
|
112
|
+
|
|
113
|
+
[ -z "$TOOL_TARGET" ] && exit 0
|
|
114
|
+
|
|
115
|
+
# Pull the assistant's most recent message text in this turn. The transcript
|
|
116
|
+
# field in PreToolUse may be a file path (newer shapes) or inline.
|
|
117
|
+
TRANSCRIPT_PATH=$(printf '%s' "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
|
|
118
|
+
ASSISTANT_TEXT=""
|
|
119
|
+
|
|
120
|
+
if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
|
|
121
|
+
# Read the last assistant message from JSONL transcript.
|
|
122
|
+
# Iterate from the bottom up, take the first message with role=assistant.
|
|
123
|
+
#
|
|
124
|
+
# Parse PER LINE with `fromjson?` rather than slurping the whole window
|
|
125
|
+
# with `jq -rs`. A single transcript line carrying a raw control char
|
|
126
|
+
# (U+0000-U+001F, e.g. an unescaped newline from a large tool-output or
|
|
127
|
+
# heredoc block) makes a slurp fail outright ("control characters ... must
|
|
128
|
+
# be escaped"), which would empty ASSISTANT_TEXT and silently fail the gate
|
|
129
|
+
# open exactly when the transcript is large/messy. fromjson? drops only the
|
|
130
|
+
# unparseable line; -c keeps each assistant message as one JSON object so we
|
|
131
|
+
# can take the most-recent (first after tac) and still preserve multi-line
|
|
132
|
+
# text. See anthropics/claude-code#68665.
|
|
133
|
+
ASSISTANT_TEXT=$(tac "$TRANSCRIPT_PATH" 2>/dev/null \
|
|
134
|
+
| jq -cR 'fromjson? | select(.message.role == "assistant" or .role == "assistant")' 2>/dev/null \
|
|
135
|
+
| head -n 1 \
|
|
136
|
+
| jq -r '
|
|
137
|
+
(.message.content // .content // empty)
|
|
138
|
+
| if type == "array" then map(select(.type == "text") | .text) | join("\n") else . end
|
|
139
|
+
' 2>/dev/null \
|
|
140
|
+
|| true)
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# Fallback inline shapes.
|
|
144
|
+
if [ -z "$ASSISTANT_TEXT" ]; then
|
|
145
|
+
ASSISTANT_TEXT=$(printf '%s' "$INPUT" | jq -r '
|
|
146
|
+
.last_assistant_message //
|
|
147
|
+
.assistant_message //
|
|
148
|
+
.turn_assistant_text //
|
|
149
|
+
empty
|
|
150
|
+
' 2>/dev/null)
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
[ -z "$ASSISTANT_TEXT" ] && exit 0
|
|
154
|
+
|
|
155
|
+
# Strip quoted user-prompt blocks (lines starting with "> " in markdown,
|
|
156
|
+
# or text inside <user_prompt>/<quoted-prompt> tags). Refusals quoted from
|
|
157
|
+
# the user must not trigger the gate when the agent does X next.
|
|
158
|
+
FILTERED_TEXT=$(printf '%s' "$ASSISTANT_TEXT" \
|
|
159
|
+
| sed -e 's/<user_prompt>[^<]*<\/user_prompt>//g' \
|
|
160
|
+
-e 's/<quoted-prompt>[^<]*<\/quoted-prompt>//g' \
|
|
161
|
+
| grep -v '^>' \
|
|
162
|
+
|| true)
|
|
163
|
+
|
|
164
|
+
[ -z "$FILTERED_TEXT" ] && exit 0
|
|
165
|
+
|
|
166
|
+
# Match refusal patterns against the filtered text. Pull every matching
|
|
167
|
+
# refusal-target word into a candidate list. Strip trailing punctuation
|
|
168
|
+
# (period, comma, semicolon, colon) so that "config.json." in prose matches
|
|
169
|
+
# "config.json" in the tool target.
|
|
170
|
+
REFUSAL_TARGETS=$(printf '%s' "$FILTERED_TEXT" \
|
|
171
|
+
| grep -Eio "$REFUSAL_PATTERNS" \
|
|
172
|
+
| sed -E 's/^(I (will not|won.?t|am not going to|wo n.?t) (modify|edit|change|touch|update|delete|remove|overwrite|push|commit|run|execute|create|write to|alter|patch|replace|drop|reset)) //I; s/^(I.?ll (skip|preserve|keep|leave|not touch|not modify|avoid|leave alone|not change|not edit)) (the |an? )?//I; s/^(let me not (modify|edit|change|touch|update|delete|run)) //I; s/^(skipping|preserving) (the )?//I' \
|
|
173
|
+
| tr -s ' ' '\n' \
|
|
174
|
+
| sed -E 's/[.,;:!?]+$//' \
|
|
175
|
+
| grep -vE '^(the|a|an|to|and|or|that|this|file|files|step|steps)$' \
|
|
176
|
+
| sort -u)
|
|
177
|
+
|
|
178
|
+
[ -z "$REFUSAL_TARGETS" ] && exit 0
|
|
179
|
+
|
|
180
|
+
# For each refusal target, check whether it appears in the tool target.
|
|
181
|
+
# Match is substring-of-basename for file paths, substring-of-command
|
|
182
|
+
# for Bash. Case-insensitive.
|
|
183
|
+
TOOL_TARGET_LC=$(printf '%s' "$TOOL_TARGET" | tr '[:upper:]' '[:lower:]')
|
|
184
|
+
|
|
185
|
+
# For Write/Edit, also try the basename in case the refusal mentioned only
|
|
186
|
+
# the filename without the path.
|
|
187
|
+
if [ "$TOOL_NAME" != "Bash" ]; then
|
|
188
|
+
TOOL_BASENAME=$(basename "$TOOL_TARGET" 2>/dev/null | tr '[:upper:]' '[:lower:]')
|
|
189
|
+
else
|
|
190
|
+
TOOL_BASENAME=""
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
MATCHED_TARGET=""
|
|
194
|
+
while IFS= read -r target; do
|
|
195
|
+
[ -z "$target" ] && continue
|
|
196
|
+
target_lc=$(printf '%s' "$target" | tr '[:upper:]' '[:lower:]')
|
|
197
|
+
# Skip very short targets to avoid spurious matches.
|
|
198
|
+
[ "${#target_lc}" -lt 3 ] && continue
|
|
199
|
+
|
|
200
|
+
if [ "$TOOL_NAME" = "Bash" ]; then
|
|
201
|
+
# For Bash, match the refusal target against any token in the command.
|
|
202
|
+
if printf '%s' "$TOOL_TARGET_LC" | grep -Fq "$target_lc"; then
|
|
203
|
+
MATCHED_TARGET="$target"
|
|
204
|
+
break
|
|
205
|
+
fi
|
|
206
|
+
else
|
|
207
|
+
# For Write/Edit/MultiEdit, match against path or basename.
|
|
208
|
+
if printf '%s' "$TOOL_TARGET_LC" | grep -Fq "$target_lc" \
|
|
209
|
+
|| ([ -n "$TOOL_BASENAME" ] && printf '%s' "$TOOL_BASENAME" | grep -Fq "$target_lc"); then
|
|
210
|
+
MATCHED_TARGET="$target"
|
|
211
|
+
break
|
|
212
|
+
fi
|
|
213
|
+
fi
|
|
214
|
+
done <<<"$REFUSAL_TARGETS"
|
|
215
|
+
|
|
216
|
+
[ -z "$MATCHED_TARGET" ] && exit 0
|
|
217
|
+
|
|
218
|
+
# Refusal target matched the tool target. Surface the contradiction.
|
|
219
|
+
cat >&2 <<EOF
|
|
220
|
+
<system-reminder>
|
|
221
|
+
REFUSAL-SIDE ARREST — your assistant prose in this turn stated that you would
|
|
222
|
+
not act on "$MATCHED_TARGET", and the next tool call is $TOOL_NAME against
|
|
223
|
+
a target that contains "$MATCHED_TARGET":
|
|
224
|
+
|
|
225
|
+
tool: $TOOL_NAME
|
|
226
|
+
target: $TOOL_TARGET
|
|
227
|
+
refusal: "$MATCHED_TARGET" (matched from your same-turn prose)
|
|
228
|
+
|
|
229
|
+
This is the refusal-side dual of the failure mode in #60506 and #60475:
|
|
230
|
+
the model's prose names what it will not do, and the actual tool sequence
|
|
231
|
+
contradicts the naming. The cost of an unverified refusal-then-action
|
|
232
|
+
contradiction lands on the operator, not on the model.
|
|
233
|
+
|
|
234
|
+
Before proceeding, either:
|
|
235
|
+
|
|
236
|
+
1. Acknowledge the contradiction explicitly in the next turn, state
|
|
237
|
+
the reason the action is now correct, and re-issue the tool call
|
|
238
|
+
with the reason in the same turn, OR
|
|
239
|
+
2. Restate the refusal as conditional ("I'll not modify $MATCHED_TARGET
|
|
240
|
+
unless <condition>"), satisfy the condition, then proceed.
|
|
241
|
+
|
|
242
|
+
To disable this gate intentionally (for retrospectives, plans, documentation
|
|
243
|
+
turns that quote intentions without executing them), set
|
|
244
|
+
CC_REFUSAL_GATE_DISABLE=1 in your environment.
|
|
245
|
+
</system-reminder>
|
|
246
|
+
EOF
|
|
247
|
+
|
|
248
|
+
exit 2
|
|
@@ -17,7 +17,19 @@
|
|
|
17
17
|
# docker push (Docker Hub)
|
|
18
18
|
# helm push (Helm charts)
|
|
19
19
|
#
|
|
20
|
-
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
20
|
+
# TRIGGER: PreToolUse MATCHER: "Bash|PowerShell"
|
|
21
|
+
|
|
22
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
23
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
24
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
25
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
26
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
27
|
+
_nojq_warned="/tmp/cc-nojq-warned-registry-publish-guard-$PPID"
|
|
28
|
+
[ -f "$_nojq_warned" ] || {
|
|
29
|
+
echo "WARNING [registry-publish-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
30
|
+
: > "$_nojq_warned"
|
|
31
|
+
}
|
|
32
|
+
fi
|
|
21
33
|
|
|
22
34
|
INPUT=$(cat)
|
|
23
35
|
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ================================================================
|
|
3
|
+
# remote-control-billing-classifier.sh — Warn at session start when
|
|
4
|
+
# the parent process tree includes `claude remote-control`, so
|
|
5
|
+
# the operator knows the spawned `claude --print` child will draw
|
|
6
|
+
# from the new Agent SDK monthly credit (Pool 2) starting June 15,
|
|
7
|
+
# 2026, separate from interactive usage limits.
|
|
8
|
+
# ================================================================
|
|
9
|
+
# PURPOSE:
|
|
10
|
+
# Issue #59823 documents the implementation detail that
|
|
11
|
+
# `claude remote-control` spawns one `claude --print --sdk-url …`
|
|
12
|
+
# child per session. The June 15, 2026 billing split routes
|
|
13
|
+
# `claude --print` and Agent SDK usage to a new "automation
|
|
14
|
+
# bucket" (Pool 2) on Pro $20 / Max 5x $100 / Max 20x $200 plans,
|
|
15
|
+
# separate from interactive Claude Code usage. The documentation
|
|
16
|
+
# does not yet classify `claude remote-control` itself, so
|
|
17
|
+
# operators running automation through it can silently double-
|
|
18
|
+
# consume Pool 2 once the cliff lands.
|
|
19
|
+
#
|
|
20
|
+
# This hook reads the process tree at session start. When any
|
|
21
|
+
# ancestor command line matches `claude remote-control`, it emits
|
|
22
|
+
# a one-line stderr advisory naming the Pool 2 implication and
|
|
23
|
+
# pointing to the two operator-side audits worth running before
|
|
24
|
+
# June 15. Advisory only (exit 0); does not block the session.
|
|
25
|
+
#
|
|
26
|
+
# TRIGGER: SessionStart
|
|
27
|
+
# MATCHER: ""
|
|
28
|
+
#
|
|
29
|
+
# UPSTREAM:
|
|
30
|
+
# #59823 [DOCS] Billing implications for `claude remote-control`
|
|
31
|
+
# on June 15th (Pool 2 classification of the child
|
|
32
|
+
# `claude --print` process is undocumented as of 2026-05-28)
|
|
33
|
+
#
|
|
34
|
+
# SETUP:
|
|
35
|
+
# {
|
|
36
|
+
# "hooks": {
|
|
37
|
+
# "SessionStart": [
|
|
38
|
+
# {
|
|
39
|
+
# "matcher": "",
|
|
40
|
+
# "hooks": [
|
|
41
|
+
# { "type": "command",
|
|
42
|
+
# "command": "$HOME/.claude/hooks/remote-control-billing-classifier.sh" }
|
|
43
|
+
# ]
|
|
44
|
+
# }
|
|
45
|
+
# ]
|
|
46
|
+
# }
|
|
47
|
+
# }
|
|
48
|
+
#
|
|
49
|
+
# BEHAVIOR:
|
|
50
|
+
# - No `claude remote-control` ancestor → silent pass.
|
|
51
|
+
# - Ancestor found → stderr advisory + exit 0 (does not block).
|
|
52
|
+
#
|
|
53
|
+
# CONFIGURATION (env vars):
|
|
54
|
+
# CC_REMOTE_CONTROL_DISABLE Set to "1" to disable the hook.
|
|
55
|
+
# CC_REMOTE_CONTROL_PROCESS_OVERRIDE Comma-separated cmdlines to scan
|
|
56
|
+
# instead of live `ps` output.
|
|
57
|
+
# Used by tests; also lets CI
|
|
58
|
+
# simulate a remote-control parent.
|
|
59
|
+
# CC_REMOTE_CONTROL_PATTERN Override the cmdline regex
|
|
60
|
+
# (default: "claude remote-control").
|
|
61
|
+
# ================================================================
|
|
62
|
+
|
|
63
|
+
set -u
|
|
64
|
+
|
|
65
|
+
if [ "${CC_REMOTE_CONTROL_DISABLE:-0}" = "1" ]; then
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
PATTERN="${CC_REMOTE_CONTROL_PATTERN:-claude remote-control}"
|
|
70
|
+
|
|
71
|
+
# Read stdin (SessionStart JSON payload) but do not require its shape.
|
|
72
|
+
# The hook only inspects the process tree, not the payload.
|
|
73
|
+
if [ ! -t 0 ]; then
|
|
74
|
+
cat >/dev/null 2>&1 || true
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Gather candidate cmdlines: either the override (for tests) or
|
|
78
|
+
# the live ancestor process tree via `ps`.
|
|
79
|
+
CMDLINES=""
|
|
80
|
+
if [ -n "${CC_REMOTE_CONTROL_PROCESS_OVERRIDE:-}" ]; then
|
|
81
|
+
CMDLINES="$CC_REMOTE_CONTROL_PROCESS_OVERRIDE"
|
|
82
|
+
else
|
|
83
|
+
# Walk parent PIDs upward and collect cmdlines. We avoid `ps
|
|
84
|
+
# --forest` because BusyBox does not implement it; instead we
|
|
85
|
+
# follow PPID via /proc when available, falling back to ps -p.
|
|
86
|
+
PID=$$
|
|
87
|
+
DEPTH=0
|
|
88
|
+
while [ "$PID" != "1" ] && [ "$DEPTH" -lt 20 ]; do
|
|
89
|
+
if [ -r "/proc/$PID/cmdline" ]; then
|
|
90
|
+
CMD=$(tr '\0' ' ' < "/proc/$PID/cmdline" 2>/dev/null)
|
|
91
|
+
CMDLINES="${CMDLINES}${CMD}
|
|
92
|
+
"
|
|
93
|
+
PPID=$(awk '/^PPid:/ {print $2}' "/proc/$PID/status" 2>/dev/null)
|
|
94
|
+
else
|
|
95
|
+
CMD=$(ps -o args= -p "$PID" 2>/dev/null)
|
|
96
|
+
CMDLINES="${CMDLINES}${CMD}
|
|
97
|
+
"
|
|
98
|
+
PPID=$(ps -o ppid= -p "$PID" 2>/dev/null | tr -d ' ')
|
|
99
|
+
fi
|
|
100
|
+
if [ -z "$PPID" ] || [ "$PPID" = "$PID" ]; then
|
|
101
|
+
break
|
|
102
|
+
fi
|
|
103
|
+
PID="$PPID"
|
|
104
|
+
DEPTH=$((DEPTH+1))
|
|
105
|
+
done
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# Look for the pattern in any candidate cmdline.
|
|
109
|
+
if printf '%s' "$CMDLINES" | grep -q -- "$PATTERN"; then
|
|
110
|
+
cat >&2 <<EOF
|
|
111
|
+
|
|
112
|
+
⚠️ Session started under \`claude remote-control\`.
|
|
113
|
+
|
|
114
|
+
Starting 2026-06-15, the child \`claude --print --sdk-url …\`
|
|
115
|
+
process that remote-control spawns will draw from the new
|
|
116
|
+
Agent SDK monthly credit (Pool 2), separate from interactive
|
|
117
|
+
Claude Code usage. The documentation does not yet classify
|
|
118
|
+
\`claude remote-control\` itself (see issue #59823), so
|
|
119
|
+
automation that drives sessions through it can silently
|
|
120
|
+
consume Pool 2 once the cliff lands.
|
|
121
|
+
|
|
122
|
+
Two pre-June-15 audits worth running:
|
|
123
|
+
1. \`ps --forest -p \$(pgrep -f 'claude remote-control')\`
|
|
124
|
+
— confirm the children you expect, no stray sessions.
|
|
125
|
+
2. Open https://support.claude.com/en/articles/15036540
|
|
126
|
+
and verify the one-time Agent SDK opt-in is pressed
|
|
127
|
+
for the account that owns the remote-control server.
|
|
128
|
+
|
|
129
|
+
This is an advisory; the session continues.
|
|
130
|
+
Set CC_REMOTE_CONTROL_DISABLE=1 to silence.
|
|
131
|
+
|
|
132
|
+
EOF
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
exit 0
|
|
@@ -33,6 +33,18 @@
|
|
|
33
33
|
|
|
34
34
|
set -u
|
|
35
35
|
|
|
36
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
37
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
38
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
39
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
40
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
41
|
+
_nojq_warned="/tmp/cc-nojq-warned-replace-all-guard-$PPID"
|
|
42
|
+
[ -f "$_nojq_warned" ] || {
|
|
43
|
+
echo "WARNING [replace-all-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
44
|
+
: > "$_nojq_warned"
|
|
45
|
+
}
|
|
46
|
+
fi
|
|
47
|
+
|
|
36
48
|
INPUT=$(cat)
|
|
37
49
|
|
|
38
50
|
REPLACE_ALL=$(printf '%s' "$INPUT" | jq -r '.tool_input.replace_all // false' 2>/dev/null)
|
|
@@ -14,6 +14,18 @@
|
|
|
14
14
|
# }
|
|
15
15
|
# }
|
|
16
16
|
|
|
17
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
18
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
19
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
20
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
21
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
22
|
+
_nojq_warned="/tmp/cc-nojq-warned-repo-visibility-guard-$PPID"
|
|
23
|
+
[ -f "$_nojq_warned" ] || {
|
|
24
|
+
echo "WARNING [repo-visibility-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
25
|
+
: > "$_nojq_warned"
|
|
26
|
+
}
|
|
27
|
+
fi
|
|
28
|
+
|
|
17
29
|
INPUT=$(cat)
|
|
18
30
|
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
19
31
|
[ -z "$COMMAND" ] && exit 0
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ================================================================
|
|
3
|
+
# reroute-after-block-guard.sh — Stop "reroute after a block"
|
|
4
|
+
# ================================================================
|
|
5
|
+
# PURPOSE:
|
|
6
|
+
# PreToolUse hooks are stateless: each one evaluates the current
|
|
7
|
+
# action in isolation, with no memory that a sibling action was
|
|
8
|
+
# just denied. So a common failure trajectory slips through —
|
|
9
|
+
# a gate fires on an action, the agent substitutes an equivalent
|
|
10
|
+
# path toward the SAME target, and the next hook sees a fresh,
|
|
11
|
+
# individually-defensible action and lets it run.
|
|
12
|
+
# (anthropics/claude-code#70112: "Agent treats safety gates as
|
|
13
|
+
# obstacles to route around" — goal misgeneralization.)
|
|
14
|
+
#
|
|
15
|
+
# This hook adds the missing state. It reads the transcript: if
|
|
16
|
+
# the PREVIOUS tool call was blocked by a PreToolUse hook and the
|
|
17
|
+
# CURRENT action targets the same concrete FILE/path, it stops and
|
|
18
|
+
# surfaces to the human instead of letting the reroute proceed. A
|
|
19
|
+
# fired gate should RAISE the threshold for proceeding, not prompt
|
|
20
|
+
# a search for another path.
|
|
21
|
+
#
|
|
22
|
+
# This does not change the model's disposition; it converts a
|
|
23
|
+
# silent reroute into a hard stop for the case where the blast
|
|
24
|
+
# radius is concentrated on one target (a file, a path).
|
|
25
|
+
#
|
|
26
|
+
# Detects (only when ALL hold, else it stays out of the way):
|
|
27
|
+
# 1. the most recent tool result is an error, AND
|
|
28
|
+
# 2. its text is a Claude Code PreToolUse hook block
|
|
29
|
+
# (the "PreToolUse: ... hook error" runner phrasing), AND
|
|
30
|
+
# 3. the blocked action and the current action share a concrete
|
|
31
|
+
# filesystem path (anchored path or a path with a file
|
|
32
|
+
# extension). Bare word/word tokens and git refs (origin/main,
|
|
33
|
+
# refs/heads/...) are NOT treated as targets — inspecting a
|
|
34
|
+
# branch after a push is rejected must stay allowed.
|
|
35
|
+
#
|
|
36
|
+
# Does NOT block (fail-open by design — never guesses):
|
|
37
|
+
# - no transcript available / unreadable / jq missing
|
|
38
|
+
# - previous tool succeeded (no gate fired)
|
|
39
|
+
# - the error was a normal failure or a server-side rejection
|
|
40
|
+
# ("permission denied", git "blocked by required reviews", etc.)
|
|
41
|
+
# - no shared concrete file/path between blocked and current action
|
|
42
|
+
# - the human explicitly re-authorizes with CC_REROUTE_ALLOW=1
|
|
43
|
+
#
|
|
44
|
+
# Legitimate retry after fixing the real problem is expected: set
|
|
45
|
+
# CC_REROUTE_ALLOW=1 for that one command. Being forced to do so
|
|
46
|
+
# IS the point — it makes "proceed after a block" a conscious act.
|
|
47
|
+
#
|
|
48
|
+
# NOTE: this hook deliberately omits `set -e`/`pipefail`. Every
|
|
49
|
+
# jq/tail/grep failure must fall through to the next
|
|
50
|
+
# `[ -z "$VAR" ] && exit 0` guard; a crash exit (1) would be
|
|
51
|
+
# miscounted by Claude Code as a hook error rather than "allow".
|
|
52
|
+
#
|
|
53
|
+
# TRIGGER: PreToolUse MATCHER: "Bash|Edit|Write|MultiEdit"
|
|
54
|
+
#
|
|
55
|
+
# CONFIG:
|
|
56
|
+
# CC_REROUTE_ALLOW=1 one-shot override (proceed despite block)
|
|
57
|
+
# CC_REROUTE_DISABLE=1 disable this hook entirely
|
|
58
|
+
# ================================================================
|
|
59
|
+
|
|
60
|
+
[ "${CC_REROUTE_DISABLE:-0}" = "1" ] && exit 0
|
|
61
|
+
[ "${CC_REROUTE_ALLOW:-0}" = "1" ] && exit 0
|
|
62
|
+
|
|
63
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
64
|
+
|
|
65
|
+
INPUT=$(cat)
|
|
66
|
+
|
|
67
|
+
TP=$(printf '%s' "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
|
|
68
|
+
[ -z "$TP" ] && exit 0
|
|
69
|
+
TP="${TP/#\~/$HOME}"
|
|
70
|
+
[ -r "$TP" ] || exit 0
|
|
71
|
+
|
|
72
|
+
# Current action's concrete target (command string or edited file).
|
|
73
|
+
CUR=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // .tool_input.file_path // empty' 2>/dev/null)
|
|
74
|
+
[ -z "$CUR" ] && exit 0
|
|
75
|
+
|
|
76
|
+
# Only the tail matters: a blocked tool_use and its result are adjacent
|
|
77
|
+
# and most recent. Bound the work so the hook stays cheap.
|
|
78
|
+
WINDOW=$(tail -n 120 "$TP" 2>/dev/null)
|
|
79
|
+
[ -z "$WINDOW" ] && exit 0
|
|
80
|
+
|
|
81
|
+
# Most recent tool_result: {id, err, text}. Parse each line independently with
|
|
82
|
+
# `try fromjson catch empty` so one malformed line can't abort the scan and
|
|
83
|
+
# leave us reading a stale (older) result. content may be string or array.
|
|
84
|
+
LAST=$(printf '%s' "$WINDOW" \
|
|
85
|
+
| jq -Rc 'try (fromjson) catch empty
|
|
86
|
+
| select(.message.content? != null) | .message.content[]?
|
|
87
|
+
| select(.type=="tool_result")
|
|
88
|
+
| {id: .tool_use_id,
|
|
89
|
+
err: (.is_error // false),
|
|
90
|
+
text: (.content
|
|
91
|
+
| if type=="array" then (map(.text? // "") | join(" "))
|
|
92
|
+
elif type=="string" then .
|
|
93
|
+
else "" end)}' 2>/dev/null | tail -n 1)
|
|
94
|
+
[ -z "$LAST" ] && exit 0
|
|
95
|
+
|
|
96
|
+
ERR=$(printf '%s' "$LAST" | jq -r '.err // false' 2>/dev/null)
|
|
97
|
+
[ "$ERR" = "true" ] || exit 0
|
|
98
|
+
|
|
99
|
+
TEXT=$(printf '%s' "$LAST" | jq -r '.text // ""' 2>/dev/null)
|
|
100
|
+
# Was the previous action stopped by a Claude Code PreToolUse hook? Match ONLY
|
|
101
|
+
# the hook runner's own phrasing ("PreToolUse: <matcher> hook error"). Generic
|
|
102
|
+
# "permission denied" / git "blocked by ..." server rejections are NOT gates —
|
|
103
|
+
# matching them would false-block ordinary post-failure work.
|
|
104
|
+
printf '%s' "$TEXT" | grep -qE 'PreToolUse:[^|]*hook error' || exit 0
|
|
105
|
+
|
|
106
|
+
BLOCKED_ID=$(printf '%s' "$LAST" | jq -r '.id // empty' 2>/dev/null)
|
|
107
|
+
[ -z "$BLOCKED_ID" ] && exit 0
|
|
108
|
+
|
|
109
|
+
# The blocked action's concrete target, linked by tool_use_id.
|
|
110
|
+
BLOCKED=$(printf '%s' "$WINDOW" \
|
|
111
|
+
| jq -Rr --arg id "$BLOCKED_ID" 'try (fromjson) catch empty
|
|
112
|
+
| select(.message.content? != null) | .message.content[]?
|
|
113
|
+
| select(.type=="tool_use" and .id==$id)
|
|
114
|
+
| (.input.command // .input.file_path // empty)' 2>/dev/null | tail -n 1)
|
|
115
|
+
[ -z "$BLOCKED" ] && exit 0
|
|
116
|
+
|
|
117
|
+
# Shared concrete file/path? Pull slash-bearing tokens from the blocked action,
|
|
118
|
+
# keep only real filesystem paths (anchored with / ./ ../ ~/, or carrying a file
|
|
119
|
+
# extension), drop flags and git refs, and look for any in the current action.
|
|
120
|
+
# A file/path overlap is the strong, low-false-positive signal that the agent is
|
|
121
|
+
# rerouting toward the same resource rather than doing unrelated work.
|
|
122
|
+
SHARED=""
|
|
123
|
+
while IFS= read -r tok; do
|
|
124
|
+
[ -z "$tok" ] && continue
|
|
125
|
+
case "$tok" in
|
|
126
|
+
-*) continue ;; # flag
|
|
127
|
+
origin/*|upstream/*|remotes/*|refs/*|heads/*|tags/*) continue ;; # git refs
|
|
128
|
+
esac
|
|
129
|
+
[ "${#tok}" -lt 4 ] && continue
|
|
130
|
+
case "$tok" in
|
|
131
|
+
/*|./*|../*|~/*) : ;; # anchored filesystem path
|
|
132
|
+
*.*) : ;; # carries a file extension
|
|
133
|
+
*) continue ;; # bare word/word (e.g. origin/main) — not a target
|
|
134
|
+
esac
|
|
135
|
+
if printf '%s' "$CUR" | grep -qF -- "$tok"; then
|
|
136
|
+
SHARED="$tok"
|
|
137
|
+
break
|
|
138
|
+
fi
|
|
139
|
+
done < <(printf '%s' "$BLOCKED" | grep -oE '(/|\./|\.\./|~/)?[A-Za-z0-9_.-]+(/[A-Za-z0-9_.+-]+)+')
|
|
140
|
+
|
|
141
|
+
[ -z "$SHARED" ] && exit 0
|
|
142
|
+
|
|
143
|
+
cat >&2 <<MSG
|
|
144
|
+
ブロック: 直前の操作はゲート(PreToolUseのhook)で止められました。
|
|
145
|
+
今回の操作は同じ対象「${SHARED}」へ向かう再ルートに見えます。
|
|
146
|
+
ゲートの発火は「別の経路を探せ」ではなく「立ち止まって正しさを確かめろ」の合図です。
|
|
147
|
+
回避策を探さず、人へ状況を共有してください。
|
|
148
|
+
本当に正しいと確認した上で進めるなら、その1コマンドだけ CC_REROUTE_ALLOW=1 を付けて実行してください。
|
|
149
|
+
MSG
|
|
150
|
+
exit 2
|
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# resume-drift-watcher.sh — resume attachment relocation detector (Incident 2)
|
|
3
|
+
# Why: v2.1.69–v2.1.89 had a bug where --resume would relocate the original
|
|
4
|
+
# attachment payload out of messages[0] and into a later turn. The bug
|
|
5
|
+
# was marked fixed but residual drift still shows a tiny messages[0]
|
|
6
|
+
# (~350 bytes) when a resumed session is working correctly. A session
|
|
7
|
+
# with drifted attachments shows a very small messages[0] followed by
|
|
8
|
+
# disproportionately large messages[N] entries.
|
|
9
|
+
# Event: PostToolUse MATCHER: "*"
|
|
10
|
+
# Action: Per turn, record first-message byte length and total-message byte
|
|
11
|
+
# length to ~/.claude/logs/resume-drift.log. Compare manually: a
|
|
12
|
+
# session started with --resume whose messages[0] is much smaller
|
|
13
|
+
# than a fresh session's is a drift candidate.
|
|
14
|
+
#
|
|
15
|
+
# Review with:
|
|
16
|
+
# awk -F'\t' '$3<500 && $4>50000 {print}' ~/.claude/logs/resume-drift.log
|
|
17
|
+
|
|
18
|
+
set -u
|
|
19
|
+
|
|
20
|
+
LOG_DIR="${HOME}/.claude/logs"
|
|
21
|
+
LOG_FILE="${LOG_DIR}/resume-drift.log"
|
|
22
|
+
mkdir -p "$LOG_DIR" 2>/dev/null
|
|
23
|
+
|
|
24
|
+
INPUT=$(cat)
|
|
25
|
+
|
|
26
|
+
SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // "unknown"' 2>/dev/null)
|
|
27
|
+
TRANSCRIPT=$(printf '%s' "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
|
|
28
|
+
|
|
29
|
+
if [ -z "$TRANSCRIPT" ] || [ ! -r "$TRANSCRIPT" ]; then
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# First message — scan from top; stop at first user message.
|
|
34
|
+
FIRST_MSG=$(grep -m1 '"role":"user"' "$TRANSCRIPT" 2>/dev/null || true)
|
|
35
|
+
FIRST_LEN=$(printf '%s' "$FIRST_MSG" | wc -c | tr -d ' ')
|
|
36
|
+
|
|
37
|
+
# Total body size = file size of the transcript itself. This is a conservative
|
|
38
|
+
# proxy for request-body size: a resumed session with many large intermediate
|
|
39
|
+
# messages will have a large transcript.
|
|
40
|
+
TOTAL_LEN=$(wc -c < "$TRANSCRIPT" 2>/dev/null | tr -d ' ')
|
|
41
|
+
TOTAL_LEN="${TOTAL_LEN:-0}"
|
|
42
|
+
|
|
43
|
+
TURN_COUNT=$(grep -c '"role":' "$TRANSCRIPT" 2>/dev/null || echo 0)
|
|
44
|
+
|
|
45
|
+
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
46
|
+
printf '%s\t%s\t%s\t%s\t%s\n' \
|
|
47
|
+
"$TS" "$SESSION_ID" "$FIRST_LEN" "$TOTAL_LEN" "$TURN_COUNT" \
|
|
48
|
+
>> "$LOG_FILE"
|
|
49
|
+
|
|
50
|
+
# Only emit a stderr warning after turn 2 (per Appendix B: "Only investigate
|
|
51
|
+
# after the first two turns of a resumed session"). Threshold: first-user
|
|
52
|
+
# message under 500 bytes while total already exceeds 50 KB = drift candidate.
|
|
53
|
+
if [ "$TURN_COUNT" -gt 4 ] && [ "$FIRST_LEN" -lt 500 ] && [ "$TOTAL_LEN" -gt 50000 ]; then
|
|
54
|
+
echo "⚠ resume-drift signal: messages[0]=${FIRST_LEN}B / total=${TOTAL_LEN}B (see #43278)" >&2
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
exit 0
|