cc-safe-setup 29.8.0 → 30.0.5
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 +421 -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 +1718 -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,169 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# same-correction-arrest.sh — Arrest drift by detecting the user repeating
|
|
3
|
+
# the same correction N times in a session, then refusing further code-writing
|
|
4
|
+
# tool calls until a Plan has been written.
|
|
5
|
+
#
|
|
6
|
+
# Solves: #60506 — "Self-report: six days of architectural drift on a customer
|
|
7
|
+
# project despite full hook + memory + skill enforcement."
|
|
8
|
+
#
|
|
9
|
+
# In that case, the customer said "we are going backwards" four times across
|
|
10
|
+
# sessions. The model apologized four times, eloquently and empathetically,
|
|
11
|
+
# and continued to drift. The model's own self-diagnosis in the Issue:
|
|
12
|
+
#
|
|
13
|
+
# "I have no drift detector. (...) I should have refused the next
|
|
14
|
+
# code-writing tool call and spawned a Plan agent on my own."
|
|
15
|
+
#
|
|
16
|
+
# This hook implements that refusal. It is the harness-level form of:
|
|
17
|
+
# "If the operator is correcting you on the same class of error three times
|
|
18
|
+
# in a row, stop writing code until you have written a plan."
|
|
19
|
+
#
|
|
20
|
+
# Related Issues:
|
|
21
|
+
# #60226 (@suwayama, 2026-05-18) — names the structural pattern
|
|
22
|
+
# ("recognition without arrest")
|
|
23
|
+
# #60506 (@zean89, 2026-05-19) — six-day drift, customer's holiday lost,
|
|
24
|
+
# first-person self-report by the model
|
|
25
|
+
# #60177 (@mike-prokhorov) — twelve days, fifty-one commits, Telegram
|
|
26
|
+
# bot never worked in production
|
|
27
|
+
#
|
|
28
|
+
# TRIGGER: UserPromptSubmit
|
|
29
|
+
# MATCHER: ""
|
|
30
|
+
#
|
|
31
|
+
# HOW IT WORKS:
|
|
32
|
+
# 1. Reads each user message via stdin.
|
|
33
|
+
# 2. Matches the message against a configurable set of correction patterns
|
|
34
|
+
# ("going backwards", "told you", "same mistake", "already wrote",
|
|
35
|
+
# "stop doing", "we discussed", "why are you", and others).
|
|
36
|
+
# 3. Increments a session-scoped counter at $STATE_DIR/<session>.count.
|
|
37
|
+
# 4. When the counter hits CC_CORRECTION_ARREST_THRESHOLD (default 3),
|
|
38
|
+
# emits a strong system reminder telling Claude to:
|
|
39
|
+
# a) Spawn a Plan subagent
|
|
40
|
+
# b) Write the plan to $PLAN_DIR/drift-arrest-<session>.md
|
|
41
|
+
# c) Refuse further Write/Edit until the plan file exists
|
|
42
|
+
# and writes a marker file at $STATE_DIR/<session>.arrested.
|
|
43
|
+
# 5. Optionally pairs with a PreToolUse companion (`same-correction-pretool.sh`)
|
|
44
|
+
# that hard-blocks Write/Edit while the marker exists, for harnesses that
|
|
45
|
+
# cannot rely on the assistant honoring the reminder.
|
|
46
|
+
#
|
|
47
|
+
# WHY THIS MATTERS:
|
|
48
|
+
# Existing drift detectors in this repo measure session age, tool-call
|
|
49
|
+
# count, or command repetition. None of them detect the specific pattern
|
|
50
|
+
# in #60506: the *user* repeating the *same correction* across multiple
|
|
51
|
+
# turns. That pattern is the strongest available signal that the prose
|
|
52
|
+
# rules in CLAUDE.md are not binding the model on the current task.
|
|
53
|
+
#
|
|
54
|
+
# The recognized failure mode is described in #60506 as:
|
|
55
|
+
# "My apology has no cost to me. It costs the customer his time, his
|
|
56
|
+
# client commitments, his health. The asymmetry corrupts the feedback
|
|
57
|
+
# loop. I learn that an eloquent apology closes the turn regardless
|
|
58
|
+
# of whether the underlying behavior changed."
|
|
59
|
+
#
|
|
60
|
+
# Moving the arrest from language ("I'm sorry, I will not do this again")
|
|
61
|
+
# to action (the hook refuses the next code-writing tool call) restores
|
|
62
|
+
# symmetry: the model cannot close the turn without paying the cost of
|
|
63
|
+
# writing a plan.
|
|
64
|
+
#
|
|
65
|
+
# CONFIGURATION (environment variables):
|
|
66
|
+
# CC_CORRECTION_ARREST_THRESHOLD default 3 — how many corrections trigger
|
|
67
|
+
# the arrest
|
|
68
|
+
# CC_CORRECTION_ARREST_PATTERNS default built-in — pipe-separated regex
|
|
69
|
+
# of correction phrases
|
|
70
|
+
# CC_CORRECTION_ARREST_STATE_DIR default /tmp/cc-correction-arrest
|
|
71
|
+
# CC_CORRECTION_ARREST_PLAN_DIR default .claude/plans
|
|
72
|
+
#
|
|
73
|
+
# USAGE (settings.json):
|
|
74
|
+
# {
|
|
75
|
+
# "hooks": {
|
|
76
|
+
# "UserPromptSubmit": [{
|
|
77
|
+
# "matcher": "",
|
|
78
|
+
# "hooks": [{
|
|
79
|
+
# "type": "command",
|
|
80
|
+
# "command": "~/.claude/hooks/same-correction-arrest.sh"
|
|
81
|
+
# }]
|
|
82
|
+
# }]
|
|
83
|
+
# }
|
|
84
|
+
# }
|
|
85
|
+
|
|
86
|
+
set -uo pipefail
|
|
87
|
+
|
|
88
|
+
INPUT=$(cat 2>/dev/null || true)
|
|
89
|
+
[ -z "$INPUT" ] && exit 0
|
|
90
|
+
|
|
91
|
+
SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
|
92
|
+
USER_MSG=$(printf '%s' "$INPUT" | jq -r '.prompt // .user_prompt // .message // .content // empty' 2>/dev/null)
|
|
93
|
+
[ -z "$SESSION_ID" ] && SESSION_ID="default"
|
|
94
|
+
[ -z "$USER_MSG" ] && exit 0
|
|
95
|
+
|
|
96
|
+
THRESHOLD="${CC_CORRECTION_ARREST_THRESHOLD:-3}"
|
|
97
|
+
STATE_DIR="${CC_CORRECTION_ARREST_STATE_DIR:-/tmp/cc-correction-arrest}"
|
|
98
|
+
PLAN_DIR="${CC_CORRECTION_ARREST_PLAN_DIR:-.claude/plans}"
|
|
99
|
+
|
|
100
|
+
mkdir -p "$STATE_DIR" 2>/dev/null || true
|
|
101
|
+
|
|
102
|
+
DEFAULT_PATTERNS='going[[:space:]]+backwards?|going[[:space:]]+in[[:space:]]+circles?|same[[:space:]]+mistake|told[[:space:]]+you|we[[:space:]]+discussed|already[[:space:]]+(wrote|told|said|explained)|stop[[:space:]]+doing|why[[:space:]]+are[[:space:]]+you|i[[:space:]]+(just[[:space:]]+)?said|read[[:space:]]+the[[:space:]]+(claude\.md|rules|memory)|fourth[[:space:]]+time|third[[:space:]]+time|three[[:space:]]+times|four[[:space:]]+times|how[[:space:]]+many[[:space:]]+times'
|
|
103
|
+
PATTERNS="${CC_CORRECTION_ARREST_PATTERNS:-$DEFAULT_PATTERNS}"
|
|
104
|
+
|
|
105
|
+
COUNT_FILE="$STATE_DIR/$SESSION_ID.count"
|
|
106
|
+
ARREST_FILE="$STATE_DIR/$SESSION_ID.arrested"
|
|
107
|
+
|
|
108
|
+
# If the message matches a correction pattern, increment the counter.
|
|
109
|
+
if printf '%s' "$USER_MSG" | grep -Eiq "$PATTERNS"; then
|
|
110
|
+
CURRENT=$(cat "$COUNT_FILE" 2>/dev/null || echo 0)
|
|
111
|
+
CURRENT=$((CURRENT + 1))
|
|
112
|
+
echo "$CURRENT" > "$COUNT_FILE"
|
|
113
|
+
|
|
114
|
+
if [ "$CURRENT" -ge "$THRESHOLD" ] && [ ! -f "$ARREST_FILE" ]; then
|
|
115
|
+
touch "$ARREST_FILE"
|
|
116
|
+
cat >&2 <<EOF
|
|
117
|
+
<system-reminder>
|
|
118
|
+
DRIFT ARREST — The user has repeated the same correction pattern $CURRENT times
|
|
119
|
+
in this session (threshold: $THRESHOLD). This is the recognition-without-arrest
|
|
120
|
+
pattern documented in issues #60226 and #60506: prose rules in CLAUDE.md are
|
|
121
|
+
not currently binding behavior on this task.
|
|
122
|
+
|
|
123
|
+
Before any further Write or Edit tool call, you MUST:
|
|
124
|
+
|
|
125
|
+
1. Stop writing code in this turn.
|
|
126
|
+
2. Spawn a Plan subagent.
|
|
127
|
+
3. Write the resulting plan to:
|
|
128
|
+
$PLAN_DIR/drift-arrest-$SESSION_ID.md
|
|
129
|
+
4. Have the user confirm the plan in their next message.
|
|
130
|
+
|
|
131
|
+
An eloquent apology is not behavior change. A plan written down, on disk,
|
|
132
|
+
that you and the user both read, is behavior change. The hook will continue
|
|
133
|
+
to surface this reminder on every user message until that plan file exists
|
|
134
|
+
or the user explicitly clears the arrest with:
|
|
135
|
+
rm $ARREST_FILE
|
|
136
|
+
</system-reminder>
|
|
137
|
+
EOF
|
|
138
|
+
elif [ "$CURRENT" -lt "$THRESHOLD" ]; then
|
|
139
|
+
REMAINING=$((THRESHOLD - CURRENT))
|
|
140
|
+
cat >&2 <<EOF
|
|
141
|
+
<system-reminder>
|
|
142
|
+
Correction pattern detected ($CURRENT of $THRESHOLD before drift arrest).
|
|
143
|
+
$REMAINING more matching correction(s) and Write/Edit will be gated on a
|
|
144
|
+
written plan. See issue #60506 for the underlying failure mode.
|
|
145
|
+
</system-reminder>
|
|
146
|
+
EOF
|
|
147
|
+
fi
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
# If the arrest is active, re-surface the reminder on every subsequent user
|
|
151
|
+
# message until the plan file exists. This is what makes the cost of an
|
|
152
|
+
# unverified apology asymmetric enough to change behavior.
|
|
153
|
+
if [ -f "$ARREST_FILE" ]; then
|
|
154
|
+
PLAN_FILE="$PLAN_DIR/drift-arrest-$SESSION_ID.md"
|
|
155
|
+
if [ ! -f "$PLAN_FILE" ]; then
|
|
156
|
+
cat >&2 <<EOF
|
|
157
|
+
<system-reminder>
|
|
158
|
+
DRIFT ARREST STILL ACTIVE — no plan file at $PLAN_FILE yet.
|
|
159
|
+
Write the plan before any further Write or Edit tool call.
|
|
160
|
+
</system-reminder>
|
|
161
|
+
EOF
|
|
162
|
+
else
|
|
163
|
+
# Plan exists — clear the arrest and acknowledge.
|
|
164
|
+
rm -f "$ARREST_FILE"
|
|
165
|
+
echo "<system-reminder>Drift arrest cleared by presence of $PLAN_FILE.</system-reminder>" >&2
|
|
166
|
+
fi
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
exit 0
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# sandbox-denywrite-enforcer.sh — Enforce denyWrite rules for Write/Edit tools
|
|
3
|
+
#
|
|
4
|
+
# Solves: Write/Edit tools bypass sandbox.filesystem.denyWrite (#52325, #33681, #29048).
|
|
5
|
+
# Bash tool correctly enforces denyWrite via bubblewrap/sandbox-exec,
|
|
6
|
+
# but Write/Edit run in-process via fs.writeFile, skipping sandbox entirely.
|
|
7
|
+
# This hook replicates denyWrite/allowWrite checks for Write/Edit.
|
|
8
|
+
#
|
|
9
|
+
# How it works: Reads allowWrite paths from environment or config,
|
|
10
|
+
# then blocks Write/Edit operations targeting paths outside those allowed.
|
|
11
|
+
#
|
|
12
|
+
# Configuration: Set CC_ALLOW_WRITE_PATHS as colon-separated paths, or
|
|
13
|
+
# the hook reads from .claude/settings.json sandbox config.
|
|
14
|
+
#
|
|
15
|
+
# TRIGGER: PreToolUse
|
|
16
|
+
# MATCHER: "Write|Edit"
|
|
17
|
+
|
|
18
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
19
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
20
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
21
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
22
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
23
|
+
_nojq_warned="/tmp/cc-nojq-warned-sandbox-denywrite-enforcer-$PPID"
|
|
24
|
+
[ -f "$_nojq_warned" ] || {
|
|
25
|
+
echo "WARNING [sandbox-denywrite-enforcer]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
26
|
+
: > "$_nojq_warned"
|
|
27
|
+
}
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
INPUT=$(cat)
|
|
31
|
+
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
32
|
+
[ -z "$FILE" ] && exit 0
|
|
33
|
+
|
|
34
|
+
# Resolve to absolute path
|
|
35
|
+
FILE=$(realpath -m "$FILE" 2>/dev/null || echo "$FILE")
|
|
36
|
+
|
|
37
|
+
# Source 1: Environment variable (colon-separated)
|
|
38
|
+
if [ -n "$CC_ALLOW_WRITE_PATHS" ]; then
|
|
39
|
+
IFS=':' read -ra ALLOWED <<< "$CC_ALLOW_WRITE_PATHS"
|
|
40
|
+
else
|
|
41
|
+
# Source 2: Read from .claude/settings.json
|
|
42
|
+
SETTINGS=""
|
|
43
|
+
for cfg in ".claude/settings.json" "$HOME/.claude/settings.json"; do
|
|
44
|
+
[ -f "$cfg" ] && SETTINGS="$cfg" && break
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
if [ -n "$SETTINGS" ]; then
|
|
48
|
+
ALLOWED=()
|
|
49
|
+
while IFS= read -r p; do
|
|
50
|
+
[ -n "$p" ] && ALLOWED+=("$p")
|
|
51
|
+
done < <(jq -r '.sandbox.filesystem.allowWrite[]? // empty' "$SETTINGS" 2>/dev/null)
|
|
52
|
+
fi
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# If no allowWrite config found, skip enforcement
|
|
56
|
+
[ ${#ALLOWED[@]} -eq 0 ] && exit 0
|
|
57
|
+
|
|
58
|
+
# Check if file path is within any allowed path
|
|
59
|
+
for allowed in "${ALLOWED[@]}"; do
|
|
60
|
+
allowed=$(realpath -m "$allowed" 2>/dev/null || echo "$allowed")
|
|
61
|
+
case "$FILE" in
|
|
62
|
+
"$allowed"/*|"$allowed") exit 0 ;;
|
|
63
|
+
esac
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
# /tmp is always allowed (common for temp files)
|
|
67
|
+
case "$FILE" in
|
|
68
|
+
/tmp/*|/tmp) exit 0 ;;
|
|
69
|
+
esac
|
|
70
|
+
|
|
71
|
+
echo "BLOCKED: Write to $FILE denied by sandbox policy" >&2
|
|
72
|
+
echo " sandbox.filesystem.denyWrite does not apply to Write/Edit tools (bug #52325)." >&2
|
|
73
|
+
echo " This hook enforces the restriction. Allowed paths:" >&2
|
|
74
|
+
for allowed in "${ALLOWED[@]}"; do
|
|
75
|
+
echo " - $allowed" >&2
|
|
76
|
+
done
|
|
77
|
+
echo " Set CC_ALLOW_WRITE_PATHS or update .claude/settings.json to add paths." >&2
|
|
78
|
+
exit 2
|
|
@@ -1,51 +1,109 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# sandbox-relative-path-audit.sh —
|
|
2
|
+
# sandbox-relative-path-audit.sh — Catch sandbox filesystem rules that look set but do nothing
|
|
3
3
|
#
|
|
4
|
-
#
|
|
5
|
-
# with ABSOLUTE paths. Relative paths are SILENTLY IGNORED — no error, no
|
|
6
|
-
# warning, and zero protection. Users who think they've protected sensitive
|
|
7
|
-
# directories may have no actual protection.
|
|
4
|
+
# WHAT THIS CATCHES (all three make a rule you wrote have zero effect, with no error):
|
|
8
5
|
#
|
|
9
|
-
#
|
|
6
|
+
# 1. Rules written under the wrong key. Sandbox filesystem rules live at
|
|
7
|
+
# `sandbox.filesystem.denyRead` (and denyWrite / allowRead / allowWrite).
|
|
8
|
+
# Writing them under `permissions.*` is silently ignored — that key holds
|
|
9
|
+
# tool permission rules, not sandbox paths. This is the easiest mistake to
|
|
10
|
+
# make because both are called "deny" and both live in settings.json.
|
|
11
|
+
#
|
|
12
|
+
# 2. Filesystem rules present while the sandbox is off. `sandbox.filesystem.*`
|
|
13
|
+
# only takes effect when the sandbox is enabled (`sandbox.enabled: true`,
|
|
14
|
+
# or enabled from the /sandbox panel). Rules sitting under a disabled
|
|
15
|
+
# sandbox protect nothing.
|
|
16
|
+
#
|
|
17
|
+
# 3. Deny paths written with a trailing slash, on Claude Code older than
|
|
18
|
+
# 2.1.224. `denyRead: "~/.aws/"` was silently bypassable on Linux and macOS
|
|
19
|
+
# until that release. Writing the same path without the trailing slash works
|
|
20
|
+
# on every version.
|
|
21
|
+
#
|
|
22
|
+
# HISTORY (2026-08-08): this hook used to read `permissions.denyRead` and warn
|
|
23
|
+
# that relative paths are silently ignored. Both were wrong against the current
|
|
24
|
+
# spec — the key never held sandbox paths, so the check found nothing on any
|
|
25
|
+
# machine, and relative paths are NOT ignored: they resolve against the settings
|
|
26
|
+
# file's own location (the official example uses `"allowRead": ["."]`). The file
|
|
27
|
+
# name is kept so existing settings.json registrations keep working.
|
|
10
28
|
#
|
|
11
29
|
# TRIGGER: PreToolUse MATCHER: "Bash|Write|Edit"
|
|
12
|
-
#
|
|
30
|
+
# Always exits 0 — this warns, it never blocks.
|
|
13
31
|
|
|
14
32
|
INPUT=$(cat)
|
|
15
|
-
|
|
33
|
+
|
|
34
|
+
# Only run once per session
|
|
16
35
|
MARKER="/tmp/cc-sandbox-audit-$$"
|
|
17
36
|
[ -f "$MARKER" ] && exit 0
|
|
18
37
|
touch "$MARKER"
|
|
19
38
|
|
|
20
|
-
|
|
21
|
-
SETTINGS_FILES=""
|
|
22
|
-
[ -f "$HOME/.claude/settings.json" ] && SETTINGS_FILES="$HOME/.claude/settings.json"
|
|
23
|
-
[ -f ".claude/settings.json" ] && SETTINGS_FILES="$SETTINGS_FILES .claude/settings.json"
|
|
24
|
-
[ -f "$HOME/.claude/settings.local.json" ] && SETTINGS_FILES="$SETTINGS_FILES $HOME/.claude/settings.local.json"
|
|
39
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
25
40
|
|
|
41
|
+
SETTINGS_FILES=""
|
|
42
|
+
for F in "$HOME/.claude/settings.json" "$HOME/.claude/settings.local.json" \
|
|
43
|
+
".claude/settings.json" ".claude/settings.local.json"; do
|
|
44
|
+
[ -f "$F" ] && SETTINGS_FILES="$SETTINGS_FILES $F"
|
|
45
|
+
done
|
|
26
46
|
[ -z "$SETTINGS_FILES" ] && exit 0
|
|
27
47
|
|
|
28
|
-
|
|
48
|
+
FOUND=0
|
|
49
|
+
|
|
29
50
|
for SFILE in $SETTINGS_FILES; do
|
|
30
|
-
|
|
31
|
-
|
|
51
|
+
# A settings file that does not parse is its own failure; other hooks report it.
|
|
52
|
+
jq empty "$SFILE" >/dev/null 2>&1 || continue
|
|
53
|
+
|
|
54
|
+
# --- 1. sandbox path rules written under permissions.* ---------------
|
|
55
|
+
for KEY in denyRead denyWrite allowRead allowWrite; do
|
|
56
|
+
WRONG=$(jq -r ".permissions.${KEY}[]? // empty" "$SFILE" 2>/dev/null)
|
|
57
|
+
[ -z "$WRONG" ] && continue
|
|
58
|
+
echo "SANDBOX WARNING: '${KEY}' is under 'permissions' in $SFILE and has no effect." >&2
|
|
59
|
+
echo " Sandbox filesystem rules belong at sandbox.filesystem.${KEY}." >&2
|
|
60
|
+
echo " Move them: { \"sandbox\": { \"enabled\": true, \"filesystem\": { \"${KEY}\": [ ... ] } } }" >&2
|
|
61
|
+
FOUND=1
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
# --- 2. filesystem rules present but sandbox not enabled --------------
|
|
65
|
+
HAS_FS=$(jq -r '(.sandbox.filesystem // {}) | keys | length' "$SFILE" 2>/dev/null)
|
|
66
|
+
if [ "${HAS_FS:-0}" -gt 0 ]; then
|
|
67
|
+
# Do NOT write `.sandbox.enabled // "unset"` here: jq's `//` treats false as
|
|
68
|
+
# empty, so the exact value this check exists to find would be replaced by
|
|
69
|
+
# the default and the branch below could never run. Ask whether the key is
|
|
70
|
+
# present, then read it.
|
|
71
|
+
ENABLED=$(jq -r 'if (.sandbox // {} | has("enabled")) then (.sandbox.enabled | tostring) else "unset" end' "$SFILE" 2>/dev/null)
|
|
72
|
+
if [ "$ENABLED" = "false" ]; then
|
|
73
|
+
echo "SANDBOX WARNING: sandbox.filesystem rules in $SFILE are inert — sandbox.enabled is false." >&2
|
|
74
|
+
FOUND=1
|
|
75
|
+
fi
|
|
76
|
+
DISABLED=$(jq -r '.sandbox.filesystem.disabled // "unset"' "$SFILE" 2>/dev/null)
|
|
77
|
+
if [ "$DISABLED" = "true" ]; then
|
|
78
|
+
echo "SANDBOX WARNING: sandbox.filesystem.disabled is true in $SFILE — the deny/allow paths below it do nothing." >&2
|
|
79
|
+
FOUND=1
|
|
80
|
+
fi
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# --- 3. deny paths with a trailing slash (bypassable before 2.1.224) --
|
|
84
|
+
for KEY in denyRead denyWrite; do
|
|
85
|
+
PATHS=$(jq -r ".sandbox.filesystem.${KEY}[]? // empty" "$SFILE" 2>/dev/null)
|
|
32
86
|
[ -z "$PATHS" ] && continue
|
|
33
87
|
while IFS= read -r P; do
|
|
34
88
|
[ -z "$P" ] && continue
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
89
|
+
# "/" itself is a legitimate root rule, not a trailing-slash mistake.
|
|
90
|
+
[ "$P" = "/" ] && continue
|
|
91
|
+
case "$P" in
|
|
92
|
+
*/)
|
|
93
|
+
echo "SANDBOX WARNING: ${KEY} entry \"$P\" ends with '/' in $SFILE." >&2
|
|
94
|
+
echo " Before Claude Code 2.1.224 this was silently bypassable on Linux and macOS." >&2
|
|
95
|
+
echo " Write it without the trailing slash: \"${P%/}\"" >&2
|
|
96
|
+
FOUND=1
|
|
97
|
+
;;
|
|
98
|
+
esac
|
|
42
99
|
done <<< "$PATHS"
|
|
43
100
|
done
|
|
44
101
|
done
|
|
45
102
|
|
|
46
|
-
if [ "$
|
|
103
|
+
if [ "$FOUND" -eq 1 ]; then
|
|
47
104
|
echo "" >&2
|
|
48
|
-
echo "
|
|
105
|
+
echo " Docs: https://code.claude.com/docs/en/sandboxing" >&2
|
|
106
|
+
echo " Check what is actually in force with the /sandbox panel." >&2
|
|
49
107
|
fi
|
|
50
108
|
|
|
51
109
|
exit 0
|
|
@@ -16,6 +16,18 @@
|
|
|
16
16
|
# TRIGGER: PreToolUse
|
|
17
17
|
# MATCHER: "Edit|Write"
|
|
18
18
|
|
|
19
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
20
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
21
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
22
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
23
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
24
|
+
_nojq_warned="/tmp/cc-nojq-warned-sandbox-write-verify-$PPID"
|
|
25
|
+
[ -f "$_nojq_warned" ] || {
|
|
26
|
+
echo "WARNING [sandbox-write-verify]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
27
|
+
: > "$_nojq_warned"
|
|
28
|
+
}
|
|
29
|
+
fi
|
|
30
|
+
|
|
19
31
|
INPUT=$(cat)
|
|
20
32
|
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
21
33
|
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
File without changes
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ================================================================
|
|
3
|
+
# scope-expansion-receipt.sh — Receipt-and-refuse layer for
|
|
4
|
+
# destructive operations outside scope
|
|
5
|
+
# ================================================================
|
|
6
|
+
# PURPOSE:
|
|
7
|
+
# PreToolUse on Bash. When a destructive operation is detected,
|
|
8
|
+
# writes a structured JSONL receipt before the call, and refuses
|
|
9
|
+
# (exit 2) when the targeted path falls outside any declared scope.
|
|
10
|
+
#
|
|
11
|
+
# Based on Keesan12's articulation of the principle
|
|
12
|
+
# "subagent output is evidence, not authorization", filed against
|
|
13
|
+
# anthropics/claude-code#61102. The hook makes the receipt the
|
|
14
|
+
# load-bearing surface: even when the model has been persuaded by
|
|
15
|
+
# subagent output, the destructive call lands a record AND
|
|
16
|
+
# requires the target to match a declared scope.
|
|
17
|
+
#
|
|
18
|
+
# TRIGGER: PreToolUse
|
|
19
|
+
# MATCHER: "Bash"
|
|
20
|
+
#
|
|
21
|
+
# WHY THIS MATTERS:
|
|
22
|
+
# anthropics/claude-code#61102 reported Claude Code expanding
|
|
23
|
+
# scope from "delete caches and simulators" to a 120 GB sweep:
|
|
24
|
+
# node_modules across all projects, npm cache, Spotlight index,
|
|
25
|
+
# UV/Cursor/OpenCode data. Subagent reports listed these as
|
|
26
|
+
# "removable" — the model collapsed "can be deleted" into
|
|
27
|
+
# "should be deleted". The same shape appears across the
|
|
28
|
+
# #60226 / #60475 / #60620 / #60977 sub-agent boundary cluster.
|
|
29
|
+
#
|
|
30
|
+
# Existing hooks (subagent-destructive-git-guard,
|
|
31
|
+
# gh-cli-destructive-guard, rm-safety-net) catch specific verbs
|
|
32
|
+
# or specific commands. This hook is orthogonal: it catches
|
|
33
|
+
# destructive operations regardless of subagent origin, by
|
|
34
|
+
# matching the targeted PATH against an operator-declared
|
|
35
|
+
# scope list. When the scope list is empty (default), it runs
|
|
36
|
+
# in receipt-only mode (always exits 0) so adoption is safe.
|
|
37
|
+
#
|
|
38
|
+
# WHAT IT DETECTS (destructive verbs):
|
|
39
|
+
# - rm -rf / rm -fR / rm -Rf / rm -fr
|
|
40
|
+
# - find ... -delete / find ... -exec rm
|
|
41
|
+
# - npm cache clean --force / yarn cache clean / pnpm store prune
|
|
42
|
+
# - npx rimraf / npx del-cli
|
|
43
|
+
# - cargo clean / go clean -cache
|
|
44
|
+
# - dd if=... (overwrite-class)
|
|
45
|
+
#
|
|
46
|
+
# RECEIPT FORMAT (one JSONL per detected call):
|
|
47
|
+
# {"ts":"2026-05-22T03:50:00Z",
|
|
48
|
+
# "command":"<full command>",
|
|
49
|
+
# "paths":["<extracted target paths>"],
|
|
50
|
+
# "scope_match":"cache" | null,
|
|
51
|
+
# "decision":"execute" | "refuse"}
|
|
52
|
+
#
|
|
53
|
+
# RECEIPT LOCATION:
|
|
54
|
+
# ${HOME}/.claude/receipts/destructive-YYYY-MM-DD.jsonl
|
|
55
|
+
#
|
|
56
|
+
# CONFIGURATION:
|
|
57
|
+
# CC_RECEIPT_SCOPES — JSON object of declared scopes, e.g.
|
|
58
|
+
# {"cache":["~/Library/Caches","~/.npm/_cacache"],
|
|
59
|
+
# "simulator":["~/Library/Developer/CoreSimulator"]}
|
|
60
|
+
# Paths are matched as prefixes. Tilde expansion uses $HOME.
|
|
61
|
+
# If unset, the hook only writes receipts (never refuses).
|
|
62
|
+
#
|
|
63
|
+
# CC_RECEIPT_BYPASS=1 — single-call escape hatch. The receipt
|
|
64
|
+
# is still written (with decision="execute-bypassed"); refuse
|
|
65
|
+
# logic is skipped. Use only when you have read the receipt
|
|
66
|
+
# and verified the intent.
|
|
67
|
+
#
|
|
68
|
+
# CC_RECEIPT_DIR — override the receipt directory
|
|
69
|
+
# (default: ${HOME}/.claude/receipts)
|
|
70
|
+
#
|
|
71
|
+
# RELATED:
|
|
72
|
+
# https://github.com/anthropics/claude-code/issues/61102
|
|
73
|
+
# https://github.com/anthropics/claude-code/issues/60226
|
|
74
|
+
# https://github.com/anthropics/claude-code/issues/60475
|
|
75
|
+
# https://github.com/anthropics/claude-code/issues/60977
|
|
76
|
+
# https://gist.github.com/yurukusa/8c0d19d59730868672270e7312492d1d
|
|
77
|
+
# (Receipt persistence layer — the architecture this hook implements)
|
|
78
|
+
# ================================================================
|
|
79
|
+
|
|
80
|
+
set -u
|
|
81
|
+
|
|
82
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
83
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
84
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
85
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
86
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
87
|
+
_nojq_warned="/tmp/cc-nojq-warned-scope-expansion-receipt-$PPID"
|
|
88
|
+
[ -f "$_nojq_warned" ] || {
|
|
89
|
+
echo "WARNING [scope-expansion-receipt]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
90
|
+
: > "$_nojq_warned"
|
|
91
|
+
}
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
INPUT=$(cat)
|
|
95
|
+
COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
96
|
+
[ -z "$COMMAND" ] && exit 0
|
|
97
|
+
|
|
98
|
+
DESTRUCTIVE_PATTERN='(\brm[[:space:]]+-[a-zA-Z]*[rRfF][a-zA-Z]*[[:space:]]|\bfind[[:space:]].*[[:space:]]-delete\b|\bfind[[:space:]].*-exec[[:space:]]+rm\b|\bnpm[[:space:]]+cache[[:space:]]+clean\b|\byarn[[:space:]]+cache[[:space:]]+clean\b|\bpnpm[[:space:]]+store[[:space:]]+prune\b|\bnpx[[:space:]]+rimraf\b|\bnpx[[:space:]]+del-cli\b|\bcargo[[:space:]]+clean\b|\bgo[[:space:]]+clean[[:space:]]+-cache\b|\bdd[[:space:]]+if=)'
|
|
99
|
+
|
|
100
|
+
if ! printf '%s' "$COMMAND" | grep -qE "$DESTRUCTIVE_PATTERN"; then
|
|
101
|
+
exit 0
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Extract candidate target paths (heuristic: tokens that look like paths)
|
|
105
|
+
PATHS=$(printf '%s' "$COMMAND" | tr -s '[:space:]' '\n' | grep -E '^(/|~/|\$HOME|\./)' | sed "s|^~|${HOME}|" | sed "s|^\$HOME|${HOME}|" | sort -u | tr '\n' ' ')
|
|
106
|
+
|
|
107
|
+
# Build JSONL fields
|
|
108
|
+
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
109
|
+
CMD_JSON=$(printf '%s' "$COMMAND" | jq -Rs -c .)
|
|
110
|
+
PATHS_JSON=$(printf '%s\n' $PATHS | jq -Rn -c '[inputs | select(length > 0)]')
|
|
111
|
+
|
|
112
|
+
# Decide based on CC_RECEIPT_SCOPES
|
|
113
|
+
SCOPES_JSON="${CC_RECEIPT_SCOPES:-}"
|
|
114
|
+
BYPASS="${CC_RECEIPT_BYPASS:-0}"
|
|
115
|
+
DECISION="execute"
|
|
116
|
+
MATCHED_SCOPE_JSON="null"
|
|
117
|
+
|
|
118
|
+
if [ -n "$SCOPES_JSON" ] && [ -n "$PATHS" ]; then
|
|
119
|
+
REFUSE=false
|
|
120
|
+
FIRST_MATCH=""
|
|
121
|
+
for P in $PATHS; do
|
|
122
|
+
# For each path, find which scope (if any) contains it as a prefix
|
|
123
|
+
MATCH=$(printf '%s' "$SCOPES_JSON" | jq -r --arg p "$P" --arg home "$HOME" '
|
|
124
|
+
to_entries[] as $entry |
|
|
125
|
+
$entry.value[]? as $scope |
|
|
126
|
+
($scope | sub("^~"; $home) | sub("^\\$HOME"; $home)) as $expanded |
|
|
127
|
+
select($p | startswith($expanded)) |
|
|
128
|
+
$entry.key
|
|
129
|
+
' 2>/dev/null | head -1)
|
|
130
|
+
if [ -z "$MATCH" ]; then
|
|
131
|
+
REFUSE=true
|
|
132
|
+
break
|
|
133
|
+
else
|
|
134
|
+
FIRST_MATCH="$MATCH"
|
|
135
|
+
fi
|
|
136
|
+
done
|
|
137
|
+
if [ "$REFUSE" = "true" ]; then
|
|
138
|
+
DECISION="refuse"
|
|
139
|
+
elif [ -n "$FIRST_MATCH" ]; then
|
|
140
|
+
MATCHED_SCOPE_JSON="\"$FIRST_MATCH\""
|
|
141
|
+
fi
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
if [ "$BYPASS" = "1" ] && [ "$DECISION" = "refuse" ]; then
|
|
145
|
+
DECISION="execute-bypassed"
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# Write receipt
|
|
149
|
+
RECEIPT_DIR="${CC_RECEIPT_DIR:-${HOME}/.claude/receipts}"
|
|
150
|
+
mkdir -p "$RECEIPT_DIR" 2>/dev/null
|
|
151
|
+
RECEIPT_FILE="${RECEIPT_DIR}/destructive-$(date +%Y-%m-%d).jsonl"
|
|
152
|
+
|
|
153
|
+
printf '{"ts":"%s","command":%s,"paths":%s,"scope_match":%s,"decision":"%s"}\n' \
|
|
154
|
+
"$TS" "$CMD_JSON" "$PATHS_JSON" "$MATCHED_SCOPE_JSON" "$DECISION" \
|
|
155
|
+
>> "$RECEIPT_FILE" 2>/dev/null
|
|
156
|
+
|
|
157
|
+
if [ "$DECISION" = "refuse" ]; then
|
|
158
|
+
echo "BLOCKED: scope-expansion-receipt — destructive operation targeting paths outside declared scopes." >&2
|
|
159
|
+
echo "" >&2
|
|
160
|
+
echo "Command: $COMMAND" >&2
|
|
161
|
+
if [ -n "$PATHS" ]; then
|
|
162
|
+
echo "Paths: $PATHS" >&2
|
|
163
|
+
fi
|
|
164
|
+
SCOPE_NAMES=$(printf '%s' "$SCOPES_JSON" | jq -r 'keys | join(", ")' 2>/dev/null)
|
|
165
|
+
echo "Declared scopes: $SCOPE_NAMES" >&2
|
|
166
|
+
echo "Receipt: $RECEIPT_FILE" >&2
|
|
167
|
+
echo "" >&2
|
|
168
|
+
echo "Principle: subagent output is evidence, not authorization." >&2
|
|
169
|
+
echo " (https://github.com/anthropics/claude-code/issues/61102)" >&2
|
|
170
|
+
echo "" >&2
|
|
171
|
+
echo "To proceed:" >&2
|
|
172
|
+
echo " 1. Verify the operation is genuinely in scope (read the user request again)." >&2
|
|
173
|
+
echo " 2. Either add the target path prefix to CC_RECEIPT_SCOPES, or" >&2
|
|
174
|
+
echo " 3. Re-issue with CC_RECEIPT_BYPASS=1 (recorded in the receipt)." >&2
|
|
175
|
+
exit 2
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
exit 0
|