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,127 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# worktree-edit-boundary-guard.sh — Warn or block when Edit/Write/NotebookEdit
|
|
3
|
+
# targets a path outside the active git worktree boundary.
|
|
4
|
+
#
|
|
5
|
+
# Solves: anthropics/claude-code#59628 — Claude Code sessions launched inside
|
|
6
|
+
# a git worktree receive a system-prompt declaration ("you are operating in a
|
|
7
|
+
# git worktree") but the harness does NOT prevent Edit/Write/NotebookEdit calls
|
|
8
|
+
# whose resolved absolute path points into the parent main checkout. An agent
|
|
9
|
+
# using cd-style context or absolute paths can dirty the main branch's working
|
|
10
|
+
# tree without prompt, warning, or confirmation. The worktree boundary is a
|
|
11
|
+
# claim in the system prompt; it is not an enforced isolation at the tool layer.
|
|
12
|
+
#
|
|
13
|
+
# This hook closes that gap from the operator side: when the current working
|
|
14
|
+
# directory is inside a worktree (detected via `git rev-parse --git-common-dir`
|
|
15
|
+
# differing from `git rev-parse --git-dir`), and the target file_path resolves
|
|
16
|
+
# outside the worktree's working tree, emit a warning (default) or block (opt-in
|
|
17
|
+
# via env). Pass-through outside worktrees, outside repos, or when target path
|
|
18
|
+
# is inside the worktree.
|
|
19
|
+
#
|
|
20
|
+
# Configuration:
|
|
21
|
+
# CC_WORKTREE_BOUNDARY_MODE=warn (default) — emit stderr, exit 0 (advisory)
|
|
22
|
+
# CC_WORKTREE_BOUNDARY_MODE=block — emit stderr, exit 2 (block)
|
|
23
|
+
# CC_WORKTREE_BOUNDARY_QUIET=1 — suppress all output (still exits)
|
|
24
|
+
#
|
|
25
|
+
# Usage: settings.json PreToolUse hook with matcher "Edit|Write|NotebookEdit".
|
|
26
|
+
#
|
|
27
|
+
# TRIGGER: PreToolUse MATCHER: "Edit|Write|NotebookEdit"
|
|
28
|
+
|
|
29
|
+
set -u
|
|
30
|
+
|
|
31
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
32
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
33
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
34
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
35
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
36
|
+
_nojq_warned="/tmp/cc-nojq-warned-worktree-edit-boundary-guard-$PPID"
|
|
37
|
+
[ -f "$_nojq_warned" ] || {
|
|
38
|
+
echo "WARNING [worktree-edit-boundary-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
39
|
+
: > "$_nojq_warned"
|
|
40
|
+
}
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
INPUT=$(cat)
|
|
44
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
45
|
+
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
46
|
+
|
|
47
|
+
# Only edit-style tools
|
|
48
|
+
case "$TOOL" in
|
|
49
|
+
Edit|Write|NotebookEdit) ;;
|
|
50
|
+
*) exit 0 ;;
|
|
51
|
+
esac
|
|
52
|
+
|
|
53
|
+
[ -z "$FILE" ] && exit 0
|
|
54
|
+
|
|
55
|
+
# Detect worktree: git-dir vs git-common-dir
|
|
56
|
+
# In a worktree, git-dir points to .git/worktrees/<name>, git-common-dir to the main .git
|
|
57
|
+
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) || exit 0
|
|
58
|
+
GIT_COMMON=$(git rev-parse --git-common-dir 2>/dev/null) || exit 0
|
|
59
|
+
|
|
60
|
+
# Resolve both to absolute paths for comparison
|
|
61
|
+
GIT_DIR_ABS=$(cd "$GIT_DIR" 2>/dev/null && pwd -P) || exit 0
|
|
62
|
+
GIT_COMMON_ABS=$(cd "$GIT_COMMON" 2>/dev/null && pwd -P) || exit 0
|
|
63
|
+
|
|
64
|
+
# Not a worktree if git-dir == git-common-dir
|
|
65
|
+
[ "$GIT_DIR_ABS" = "$GIT_COMMON_ABS" ] && exit 0
|
|
66
|
+
|
|
67
|
+
# We are in a worktree. Determine the worktree boundary (top of working tree).
|
|
68
|
+
WORKTREE_TOP=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
|
|
69
|
+
WORKTREE_TOP_ABS=$(cd "$WORKTREE_TOP" 2>/dev/null && pwd -P) || exit 0
|
|
70
|
+
|
|
71
|
+
# Resolve target path. If relative, anchor to current working directory.
|
|
72
|
+
# We do NOT require the file to exist (Write may create new files).
|
|
73
|
+
if [[ "$FILE" = /* ]]; then
|
|
74
|
+
TARGET="$FILE"
|
|
75
|
+
else
|
|
76
|
+
TARGET="$PWD/$FILE"
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Normalize: resolve .. and . segments without requiring the path to exist.
|
|
80
|
+
# Use python if available for portability, otherwise fall back to readlink -m.
|
|
81
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
82
|
+
TARGET_ABS=$(python3 -c "import os,sys; print(os.path.normpath(sys.argv[1]))" "$TARGET" 2>/dev/null)
|
|
83
|
+
elif command -v readlink >/dev/null 2>&1 && readlink -m / >/dev/null 2>&1; then
|
|
84
|
+
TARGET_ABS=$(readlink -m "$TARGET" 2>/dev/null)
|
|
85
|
+
else
|
|
86
|
+
# Last resort: assume already absolute and unnormalized; let the prefix test handle it
|
|
87
|
+
TARGET_ABS="$TARGET"
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
[ -z "$TARGET_ABS" ] && exit 0
|
|
91
|
+
|
|
92
|
+
# Check if target is inside the worktree boundary
|
|
93
|
+
# Append slash to avoid prefix-collision (e.g., /repo-main being matched by /repo)
|
|
94
|
+
case "$TARGET_ABS/" in
|
|
95
|
+
"$WORKTREE_TOP_ABS"/*)
|
|
96
|
+
# Inside worktree — allowed
|
|
97
|
+
exit 0
|
|
98
|
+
;;
|
|
99
|
+
esac
|
|
100
|
+
|
|
101
|
+
# Target is outside worktree boundary
|
|
102
|
+
MODE="${CC_WORKTREE_BOUNDARY_MODE:-warn}"
|
|
103
|
+
QUIET="${CC_WORKTREE_BOUNDARY_QUIET:-0}"
|
|
104
|
+
|
|
105
|
+
if [ "$QUIET" != "1" ]; then
|
|
106
|
+
echo "WORKTREE BOUNDARY: target outside active worktree." >&2
|
|
107
|
+
echo "" >&2
|
|
108
|
+
echo " Worktree: $WORKTREE_TOP_ABS" >&2
|
|
109
|
+
echo " Target: $TARGET_ABS" >&2
|
|
110
|
+
echo " Tool: $TOOL" >&2
|
|
111
|
+
echo "" >&2
|
|
112
|
+
echo "This Edit/Write call would land outside the worktree boundary the" >&2
|
|
113
|
+
echo "system prompt declared. The parent main checkout (or another worktree)" >&2
|
|
114
|
+
echo "may be modified without further confirmation. See anthropics/claude-code#59628." >&2
|
|
115
|
+
echo "" >&2
|
|
116
|
+
if [ "$MODE" = "block" ]; then
|
|
117
|
+
echo "Mode: BLOCK (CC_WORKTREE_BOUNDARY_MODE=block). Edit refused." >&2
|
|
118
|
+
else
|
|
119
|
+
echo "Mode: WARN (advisory). To block instead, set CC_WORKTREE_BOUNDARY_MODE=block." >&2
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
if [ "$MODE" = "block" ]; then
|
|
124
|
+
exit 2
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
exit 0
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ================================================================
|
|
3
|
+
# worktree-escape-write-guard.sh — Block Edit/Write that escape the
|
|
4
|
+
# active worktree and silently land on the main checkout
|
|
5
|
+
# ================================================================
|
|
6
|
+
# PURPOSE:
|
|
7
|
+
# When a session runs in a git worktree under .claude/worktrees/<name>,
|
|
8
|
+
# the model can resolve a repo-root-relative reference (e.g. an
|
|
9
|
+
# auto-memory/notes line listing "packages/x/y.ts") against the
|
|
10
|
+
# canonical repo root instead of the worktree root. The absolute path
|
|
11
|
+
# "<repo>/packages/x/y.ts" is a valid, EXISTING file — just the wrong
|
|
12
|
+
# copy. Edits then succeed silently on the MAIN checkout while cwd and
|
|
13
|
+
# gitBranch keep reporting the worktree the whole time. The worktree
|
|
14
|
+
# branch stays empty; nearly all work lands on the main branch, with
|
|
15
|
+
# no warning. The author usually notices long after.
|
|
16
|
+
#
|
|
17
|
+
# This is a data-loss-class accident: work you believe is isolated in a
|
|
18
|
+
# worktree is written to (and committed on) the main checkout, and can
|
|
19
|
+
# be lost outright if that branch is later rebased or force-pushed.
|
|
20
|
+
#
|
|
21
|
+
# HOW IT WORKS: PreToolUse hook on Edit|Write|MultiEdit. If cwd is inside
|
|
22
|
+
# a worktree (.claude/worktrees/<name>), it derives the worktree root
|
|
23
|
+
# and the repo root from cwd alone, then blocks any ABSOLUTE file_path
|
|
24
|
+
# that is under the repo root but OUTSIDE the worktree root (i.e. the
|
|
25
|
+
# main checkout's copy). Relative paths resolve against cwd (the
|
|
26
|
+
# worktree) and are allowed. Absolute paths fully outside the repo are
|
|
27
|
+
# not this guard's concern (other guards cover that).
|
|
28
|
+
#
|
|
29
|
+
# See: https://github.com/anthropics/claude-code/issues/70069
|
|
30
|
+
#
|
|
31
|
+
# TRIGGER: PreToolUse MATCHER: "Edit|Write|MultiEdit"
|
|
32
|
+
#
|
|
33
|
+
# Configuration:
|
|
34
|
+
# CC_WORKTREE_DIR_MARKER — path segment identifying worktrees.
|
|
35
|
+
# Default: ".claude/worktrees"
|
|
36
|
+
# ================================================================
|
|
37
|
+
|
|
38
|
+
set -euo pipefail
|
|
39
|
+
|
|
40
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
41
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
42
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
43
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
44
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
45
|
+
_nojq_warned="/tmp/cc-nojq-warned-worktree-escape-write-guard-$PPID"
|
|
46
|
+
[ -f "$_nojq_warned" ] || {
|
|
47
|
+
echo "WARNING [worktree-escape-write-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
48
|
+
: > "$_nojq_warned"
|
|
49
|
+
}
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
INPUT=$(cat)
|
|
53
|
+
|
|
54
|
+
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
55
|
+
case "$TOOL" in
|
|
56
|
+
Edit|Write|MultiEdit) ;;
|
|
57
|
+
*) exit 0 ;;
|
|
58
|
+
esac
|
|
59
|
+
|
|
60
|
+
CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
|
|
61
|
+
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
62
|
+
[ -z "$CWD" ] && exit 0
|
|
63
|
+
[ -z "$FILE" ] && exit 0
|
|
64
|
+
|
|
65
|
+
MARKER="${CC_WORKTREE_DIR_MARKER:-.claude/worktrees}"
|
|
66
|
+
|
|
67
|
+
# Only act when the session is inside a worktree.
|
|
68
|
+
case "$CWD" in
|
|
69
|
+
*"/$MARKER/"*) ;;
|
|
70
|
+
*) exit 0 ;;
|
|
71
|
+
esac
|
|
72
|
+
|
|
73
|
+
# Derive repo root (prefix before the marker) and worktree root
|
|
74
|
+
# (prefix + marker + the first segment after it = the worktree name).
|
|
75
|
+
REPO_ROOT="${CWD%%/$MARKER/*}"
|
|
76
|
+
REST="${CWD#*/$MARKER/}" # "<name>" or "<name>/sub/dir"
|
|
77
|
+
WT_NAME="${REST%%/*}"
|
|
78
|
+
WT_ROOT="$REPO_ROOT/$MARKER/$WT_NAME"
|
|
79
|
+
|
|
80
|
+
# Relative file_path resolves against cwd (the worktree) — safe.
|
|
81
|
+
case "$FILE" in
|
|
82
|
+
/*) ;; # absolute — keep checking
|
|
83
|
+
*) exit 0 ;;
|
|
84
|
+
esac
|
|
85
|
+
|
|
86
|
+
# Absolute paths that stay within the worktree are fine.
|
|
87
|
+
case "$FILE" in
|
|
88
|
+
"$WT_ROOT"|"$WT_ROOT"/*) exit 0 ;;
|
|
89
|
+
esac
|
|
90
|
+
|
|
91
|
+
# Absolute path under the repo root but outside the worktree = the bug.
|
|
92
|
+
case "$FILE" in
|
|
93
|
+
"$REPO_ROOT"/*)
|
|
94
|
+
echo "BLOCKED: Edit/Write escapes the active worktree onto the main checkout." >&2
|
|
95
|
+
echo "" >&2
|
|
96
|
+
echo " Worktree (cwd): $WT_ROOT" >&2
|
|
97
|
+
echo " Target file: $FILE" >&2
|
|
98
|
+
echo "" >&2
|
|
99
|
+
echo "This path is under the repository root but OUTSIDE the worktree." >&2
|
|
100
|
+
echo "It points at the MAIN checkout's copy of the file, not the worktree's." >&2
|
|
101
|
+
echo "Writing here silently commits your work to the main branch while the" >&2
|
|
102
|
+
echo "worktree branch stays empty (Claude Code issue #70069)." >&2
|
|
103
|
+
echo "" >&2
|
|
104
|
+
echo "Fix: rewrite the path under the worktree root, e.g." >&2
|
|
105
|
+
echo " $WT_ROOT/<path-relative-to-repo>" >&2
|
|
106
|
+
echo "" >&2
|
|
107
|
+
echo "Override (only if you truly mean the main checkout): set" >&2
|
|
108
|
+
echo "CC_WORKTREE_DIR_MARKER to a non-matching value for this command." >&2
|
|
109
|
+
exit 2
|
|
110
|
+
;;
|
|
111
|
+
esac
|
|
112
|
+
|
|
113
|
+
# Absolute path entirely outside the repo — not this guard's concern.
|
|
114
|
+
exit 0
|
|
File without changes
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# worktree-hooks-path-fix.sh — Unset bogus per-worktree core.hooksPath that
|
|
3
|
+
# Claude Code's EnterWorktree harness writes, so Husky / lefthook / pre-commit
|
|
4
|
+
# hooks fire in worktrees the same way they do in the main checkout.
|
|
5
|
+
#
|
|
6
|
+
# Solves: #60620 — Claude Code's EnterWorktree harness writes an absolute
|
|
7
|
+
# `core.hooksPath` into the per-worktree `config.worktree` file. The absolute
|
|
8
|
+
# path points at the *main checkout's* hooks directory, not the worktree's,
|
|
9
|
+
# and because `extensions.worktreeConfig = true` is also enabled, the
|
|
10
|
+
# worktree-scoped value overrides any correct shared `core.hooksPath`
|
|
11
|
+
# (e.g. Husky's repo-relative `frontend/.husky/_`).
|
|
12
|
+
#
|
|
13
|
+
# Net effect: every Husky / lefthook / pre-commit hook the project author
|
|
14
|
+
# installed is dormant inside Claude-created worktrees. Git silently runs
|
|
15
|
+
# zero hooks (most common case) or runs the wrong directory's hooks against
|
|
16
|
+
# the worktree's index (less common but still a silent context drift).
|
|
17
|
+
#
|
|
18
|
+
# Operator-side fix: at SessionStart, detect that we're inside a
|
|
19
|
+
# Claude-created worktree (path matches `.claude/worktrees/`), read the
|
|
20
|
+
# worktree's `config.worktree` for `core.hooksPath`, and unset it if it is
|
|
21
|
+
# an absolute path that does not resolve relative to the worktree root.
|
|
22
|
+
# The shared config's repo-relative `core.hooksPath` (set by Husky's
|
|
23
|
+
# `prepare` script) then takes over and resolves correctly from any
|
|
24
|
+
# worktree.
|
|
25
|
+
#
|
|
26
|
+
# This is a harness-bug workaround, not a model-drift hook. The
|
|
27
|
+
# recognition-without-arrest family at #60226 is a different shape; this
|
|
28
|
+
# Issue's failure fires before any model interaction.
|
|
29
|
+
#
|
|
30
|
+
# Related Issues:
|
|
31
|
+
# #60620 — Claude Code agent harness writes broken per-worktree
|
|
32
|
+
# core.hooksPath (the direct origin of this hook)
|
|
33
|
+
# #27474 — earlier failure mode in the same family (writes corrupted
|
|
34
|
+
# shared .git/config; closed but related)
|
|
35
|
+
# #60475 — sibling-session git checkout clobber (workspace-lease-guard
|
|
36
|
+
# addresses a different worktree failure)
|
|
37
|
+
#
|
|
38
|
+
# CONFIG:
|
|
39
|
+
# CC_WORKTREE_HOOKS_FIX_DISABLE=1 set to disable the hook entirely
|
|
40
|
+
# CC_WORKTREE_HOOKS_FIX_VERBOSE=1 emit a NOTICE on every fix
|
|
41
|
+
#
|
|
42
|
+
# TRIGGER: SessionStart
|
|
43
|
+
# MATCHER: "*"
|
|
44
|
+
|
|
45
|
+
set -u
|
|
46
|
+
|
|
47
|
+
[ "${CC_WORKTREE_HOOKS_FIX_DISABLE:-0}" = "1" ] && exit 0
|
|
48
|
+
|
|
49
|
+
# Identify the working tree. Prefer CLAUDE_PROJECT_DIR, fall back to PWD.
|
|
50
|
+
WORKING_TREE="${CLAUDE_PROJECT_DIR:-${PWD:-}}"
|
|
51
|
+
[ -z "$WORKING_TREE" ] && exit 0
|
|
52
|
+
|
|
53
|
+
# Confirm we are inside a git worktree (not the main checkout, not non-git).
|
|
54
|
+
WORKTREE_ROOT=$(git -C "$WORKING_TREE" rev-parse --show-toplevel 2>/dev/null)
|
|
55
|
+
[ -z "$WORKTREE_ROOT" ] && exit 0
|
|
56
|
+
|
|
57
|
+
# Detect whether this is a worktree (vs the main checkout). git rev-parse
|
|
58
|
+
# --git-common-dir differs from --git-dir only inside a linked worktree.
|
|
59
|
+
GIT_COMMON_DIR=$(git -C "$WORKTREE_ROOT" rev-parse --git-common-dir 2>/dev/null)
|
|
60
|
+
GIT_DIR=$(git -C "$WORKTREE_ROOT" rev-parse --git-dir 2>/dev/null)
|
|
61
|
+
[ -z "$GIT_DIR" ] && exit 0
|
|
62
|
+
|
|
63
|
+
# Resolve both to absolute paths for comparison
|
|
64
|
+
GIT_COMMON_DIR_ABS=$(cd "$WORKTREE_ROOT" && readlink -f "$GIT_COMMON_DIR" 2>/dev/null || echo "$GIT_COMMON_DIR")
|
|
65
|
+
GIT_DIR_ABS=$(cd "$WORKTREE_ROOT" && readlink -f "$GIT_DIR" 2>/dev/null || echo "$GIT_DIR")
|
|
66
|
+
|
|
67
|
+
# Not a linked worktree — nothing to fix
|
|
68
|
+
[ "$GIT_COMMON_DIR_ABS" = "$GIT_DIR_ABS" ] && exit 0
|
|
69
|
+
|
|
70
|
+
# Only act on worktrees that look Claude-created. The path pattern
|
|
71
|
+
# `.claude/worktrees/` is the standard surface for `EnterWorktree`.
|
|
72
|
+
case "$WORKTREE_ROOT" in
|
|
73
|
+
*/.claude/worktrees/*) ;;
|
|
74
|
+
*) exit 0 ;;
|
|
75
|
+
esac
|
|
76
|
+
|
|
77
|
+
# Read the worktree-scoped core.hooksPath
|
|
78
|
+
WORKTREE_HOOKS_PATH=$(git -C "$WORKTREE_ROOT" config --worktree --get core.hooksPath 2>/dev/null || true)
|
|
79
|
+
[ -z "$WORKTREE_HOOKS_PATH" ] && exit 0
|
|
80
|
+
|
|
81
|
+
# If the value is already a relative path resolving inside the worktree,
|
|
82
|
+
# leave it alone. Only intervene when it is an absolute path. Both POSIX-
|
|
83
|
+
# style (/) and Windows-style (C:\, D:\, etc.) absolute paths qualify.
|
|
84
|
+
case "$WORKTREE_HOOKS_PATH" in
|
|
85
|
+
/*|[A-Za-z]:[\\/]*) ;; # absolute — proceed
|
|
86
|
+
*) exit 0 ;; # relative — already correct, leave alone
|
|
87
|
+
esac
|
|
88
|
+
|
|
89
|
+
# If the absolute path happens to resolve inside the worktree root, leave
|
|
90
|
+
# it alone — the harness wrote something that works for this case.
|
|
91
|
+
case "$WORKTREE_HOOKS_PATH" in
|
|
92
|
+
"$WORKTREE_ROOT"/*) exit 0 ;;
|
|
93
|
+
esac
|
|
94
|
+
|
|
95
|
+
# Otherwise: the worktree config has an absolute hooksPath pointing
|
|
96
|
+
# outside the worktree, which silently shadows the shared config's
|
|
97
|
+
# relative hooksPath. Unset it.
|
|
98
|
+
if git -C "$WORKTREE_ROOT" config --worktree --unset core.hooksPath 2>/dev/null; then
|
|
99
|
+
if [ "${CC_WORKTREE_HOOKS_FIX_VERBOSE:-0}" = "1" ] || [ -n "${CLAUDE_PROJECT_DIR:-}" ]; then
|
|
100
|
+
cat >&2 <<EOF
|
|
101
|
+
NOTICE: worktree-hooks-path-fix unset a bogus core.hooksPath in this worktree.
|
|
102
|
+
Worktree: ${WORKTREE_ROOT}
|
|
103
|
+
Was pointing: ${WORKTREE_HOOKS_PATH}
|
|
104
|
+
Effect: Husky / lefthook / pre-commit hooks installed via the
|
|
105
|
+
shared config will now fire correctly in this worktree
|
|
106
|
+
(Issue #60620 workaround).
|
|
107
|
+
EOF
|
|
108
|
+
fi
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
exit 0
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
3
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
4
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
5
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
6
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
7
|
+
_nojq_warned="/tmp/cc-nojq-warned-worktree-parent-write-guard-$PPID"
|
|
8
|
+
[ -f "$_nojq_warned" ] || {
|
|
9
|
+
echo "WARNING [worktree-parent-write-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
10
|
+
: > "$_nojq_warned"
|
|
11
|
+
}
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
INPUT=$(cat)
|
|
15
|
+
TARGET=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty' 2>/dev/null)
|
|
16
|
+
[[ -z "$TARGET" ]] && exit 0
|
|
17
|
+
CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null)
|
|
18
|
+
[[ -z "$CWD" ]] && CWD="$PWD"
|
|
19
|
+
case "$CWD" in
|
|
20
|
+
*"/.claude/worktrees/"*) ;;
|
|
21
|
+
*) exit 0 ;;
|
|
22
|
+
esac
|
|
23
|
+
PARENT="${CWD%%/.claude/worktrees/*}"
|
|
24
|
+
REST="${CWD#*/.claude/worktrees/}" # <name>/maybe/more
|
|
25
|
+
WTNAME="${REST%%/*}" # <name>
|
|
26
|
+
WT="$PARENT/.claude/worktrees/$WTNAME"
|
|
27
|
+
case "$TARGET" in
|
|
28
|
+
/*) ABS="$TARGET" ;;
|
|
29
|
+
*) ABS="$CWD/$TARGET" ;;
|
|
30
|
+
esac
|
|
31
|
+
case "$ABS" in
|
|
32
|
+
"$WT"/*|"$WT")
|
|
33
|
+
exit 0 ;; # correctly inside the worktree — OK
|
|
34
|
+
"$PARENT"/*|"$PARENT")
|
|
35
|
+
echo "BLOCKED: write target is in the PARENT repo, not the active worktree." >&2
|
|
36
|
+
echo " cwd (worktree): $CWD" >&2
|
|
37
|
+
echo " target: $ABS" >&2
|
|
38
|
+
echo " Expected under: $WT/" >&2
|
|
39
|
+
echo " This is the silent nested-worktree parent-write (#62547/#60679/#69026)." >&2
|
|
40
|
+
echo " Fix: write under the worktree path, or create worktrees OUTSIDE the repo." >&2
|
|
41
|
+
exit 2 ;;
|
|
42
|
+
esac
|
|
43
|
+
exit 0
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
#!/bin/bash
|
|
1
2
|
MAIN_TREE=$(git worktree list --porcelain 2>/dev/null | head -1 | sed 's/worktree //')
|
|
2
3
|
[ -z "$MAIN_TREE" ] && exit 0
|
|
3
4
|
CUR_DIR=$(pwd)
|
|
4
5
|
[ "$CUR_DIR" = "$MAIN_TREE" ] && exit 0
|
|
5
6
|
to_project_dir() {
|
|
6
|
-
echo "$HOME/.claude/projects/$(echo "$1" | sed 's|/|-|g
|
|
7
|
+
echo "$HOME/.claude/projects/$(echo "$1" | sed 's|/|-|g')"
|
|
7
8
|
}
|
|
8
9
|
MAIN_PROJECT=$(to_project_dir "$MAIN_TREE")
|
|
9
10
|
CUR_PROJECT=$(to_project_dir "$CUR_DIR")
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
3
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
4
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
5
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
6
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
7
|
+
_nojq_warned="/tmp/cc-nojq-warned-worktree-remove-uncommitted-guard-$PPID"
|
|
8
|
+
[ -f "$_nojq_warned" ] || {
|
|
9
|
+
echo "WARNING [worktree-remove-uncommitted-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
10
|
+
: > "$_nojq_warned"
|
|
11
|
+
}
|
|
12
|
+
fi
|
|
13
|
+
|
|
1
14
|
INFO=$(cat)
|
|
2
15
|
PATH_WT=$(echo "$INFO" | jq -r '.path // empty' 2>/dev/null)
|
|
3
16
|
[ -z "$PATH_WT" ] && exit 0
|
|
@@ -36,7 +36,13 @@ if ! echo "$COMMAND" | grep -qE 'git\s+worktree\s+(remove|prune)|rm\s+.*worktree
|
|
|
36
36
|
fi
|
|
37
37
|
|
|
38
38
|
# Extract worktree path
|
|
39
|
-
|
|
39
|
+
# -P は GNU 拡張で、macOS の BSD grep では grep がエラーになり WORKTREE_PATH が空になる。
|
|
40
|
+
# すぐ下の「空なら exit 0」で、未マージのコミットを持つ worktree でも素通しになる。
|
|
41
|
+
# 実測: 未マージのコミットを持つ worktree への git worktree remove で、-P ありは 2、無しは 0。
|
|
42
|
+
# \K に POSIX の等価物は無いので、コマンド語から一致させて前置きを sed で落とす。
|
|
43
|
+
WORKTREE_PATH=$(echo "$COMMAND" \
|
|
44
|
+
| grep -oE 'git[[:space:]]+worktree[[:space:]]+remove[[:space:]]+[^[:space:]]+' \
|
|
45
|
+
| sed -E 's/^git[[:space:]]+worktree[[:space:]]+remove[[:space:]]+//')
|
|
40
46
|
|
|
41
47
|
if [ -z "$WORKTREE_PATH" ]; then
|
|
42
48
|
# Maybe it's rm -rf on a worktree directory
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# write-byte-integrity-verifier.sh — Detect silent file truncation after Write/Edit
|
|
3
|
+
#
|
|
4
|
+
# Solves: github.com/anthropics/claude-code/issues/58551
|
|
5
|
+
# "Write and Edit tools truncate files on virtiofs mounts in Claude Code"
|
|
6
|
+
#
|
|
7
|
+
# Reporter (2026-05-13) found that on virtiofs-backed mounts (common in
|
|
8
|
+
# devcontainers and Claude Cowork sandboxes), Write and Edit tools
|
|
9
|
+
# silently truncate or null-pad files:
|
|
10
|
+
# - Shrink case: file of N bytes, Write shorter content M, result is
|
|
11
|
+
# new content from 0..M then \x00 from M..N (size unchanged, tail
|
|
12
|
+
# padded with NULs instead of file being truncated to M).
|
|
13
|
+
# - Grow case: Edit makes file longer, but file is silently chopped
|
|
14
|
+
# at some boundary K < intended length.
|
|
15
|
+
# Both modes leave the file in a corrupted state with no error returned
|
|
16
|
+
# to the tool caller, so the assistant believes the write succeeded.
|
|
17
|
+
#
|
|
18
|
+
# WHY THIS MATTERS:
|
|
19
|
+
# The assistant's belief ("Write returned success, file has the new content")
|
|
20
|
+
# diverges from filesystem reality ("file is null-padded or tail-chopped").
|
|
21
|
+
# This is the textbook claim-verify gap, and on virtiofs it is reproducible.
|
|
22
|
+
# When the assistant's next Read returns the old/corrupted content, the
|
|
23
|
+
# assistant may retry, overwrite further, or report nonsense to the user.
|
|
24
|
+
#
|
|
25
|
+
# TRIGGER: PostToolUse MATCHER: Write|Edit
|
|
26
|
+
#
|
|
27
|
+
# HOW IT WORKS:
|
|
28
|
+
# After a successful Write/Edit:
|
|
29
|
+
# 1. Find the target file path from tool_input.
|
|
30
|
+
# 2. Use `wc -c` to get the on-disk byte count.
|
|
31
|
+
# 3. For Write: compare against the byte count of tool_input.content.
|
|
32
|
+
# 4. For Edit: read the file once and confirm tool_input.new_string is
|
|
33
|
+
# present (substring check) and tool_input.old_string is absent.
|
|
34
|
+
# 5. Detect null-padding by checking if the last 4 bytes are all \x00
|
|
35
|
+
# while the rest of the file does not naturally end in nulls.
|
|
36
|
+
# On mismatch: emit a clear warning to stderr describing the divergence,
|
|
37
|
+
# the file path, the expected vs. actual byte counts, and the recommended
|
|
38
|
+
# next steps (re-read the file, re-write if confirmed corrupted, escalate
|
|
39
|
+
# if on virtiofs).
|
|
40
|
+
#
|
|
41
|
+
# CONFIGURATION:
|
|
42
|
+
# CC_WRITE_INTEGRITY_DISABLE=1 — disable the hook entirely
|
|
43
|
+
# CC_WRITE_INTEGRITY_ACTION — "warn" (default) or "block" (exit 2)
|
|
44
|
+
# CC_WRITE_INTEGRITY_LOG — log file path
|
|
45
|
+
# (default /tmp/cc-write-integrity.log)
|
|
46
|
+
# CC_WRITE_INTEGRITY_SKIP_GLOB — pipe-separated globs to skip
|
|
47
|
+
# (default: "*.log|*.lock|*.tmp")
|
|
48
|
+
#
|
|
49
|
+
# Usage:
|
|
50
|
+
# {
|
|
51
|
+
# "hooks": {
|
|
52
|
+
# "PostToolUse": [{
|
|
53
|
+
# "matcher": "Write|Edit",
|
|
54
|
+
# "hooks": [{ "type": "command", "command": "~/.claude/hooks/write-byte-integrity-verifier.sh" }]
|
|
55
|
+
# }]
|
|
56
|
+
# }
|
|
57
|
+
# }
|
|
58
|
+
|
|
59
|
+
# Allow opt-out
|
|
60
|
+
if [ "${CC_WRITE_INTEGRITY_DISABLE:-0}" = "1" ]; then
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
65
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
66
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
67
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
68
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
69
|
+
_nojq_warned="/tmp/cc-nojq-warned-write-byte-integrity-verifier-$PPID"
|
|
70
|
+
[ -f "$_nojq_warned" ] || {
|
|
71
|
+
echo "WARNING [write-byte-integrity-verifier]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
72
|
+
: > "$_nojq_warned"
|
|
73
|
+
}
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
INPUT=$(cat)
|
|
77
|
+
|
|
78
|
+
# Get tool name; only handle Write and Edit
|
|
79
|
+
TOOL=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
80
|
+
case "$TOOL" in
|
|
81
|
+
Write|Edit) ;;
|
|
82
|
+
*) exit 0 ;;
|
|
83
|
+
esac
|
|
84
|
+
|
|
85
|
+
# Pull file path
|
|
86
|
+
FILE_PATH=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
87
|
+
if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
|
|
88
|
+
exit 0
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# Skip files matching configured globs
|
|
92
|
+
SKIP="${CC_WRITE_INTEGRITY_SKIP_GLOB:-*.log|*.lock|*.tmp}"
|
|
93
|
+
IFS='|' read -ra PATTERNS <<< "$SKIP"
|
|
94
|
+
for pat in "${PATTERNS[@]}"; do
|
|
95
|
+
pat=$(echo "$pat" | xargs) # trim
|
|
96
|
+
[ -z "$pat" ] && continue
|
|
97
|
+
case "$FILE_PATH" in
|
|
98
|
+
$pat) exit 0 ;;
|
|
99
|
+
esac
|
|
100
|
+
done
|
|
101
|
+
|
|
102
|
+
ACTION="${CC_WRITE_INTEGRITY_ACTION:-warn}"
|
|
103
|
+
LOG_FILE="${CC_WRITE_INTEGRITY_LOG:-/tmp/cc-write-integrity.log}"
|
|
104
|
+
|
|
105
|
+
# Read disk size
|
|
106
|
+
DISK_SIZE=$(wc -c < "$FILE_PATH" 2>/dev/null || echo "")
|
|
107
|
+
if [ -z "$DISK_SIZE" ]; then
|
|
108
|
+
exit 0
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
WARNINGS=()
|
|
112
|
+
|
|
113
|
+
if [ "$TOOL" = "Write" ]; then
|
|
114
|
+
# Compare disk size vs intended content size
|
|
115
|
+
CONTENT_SIZE=$(printf '%s' "$INPUT" | jq -r '.tool_input.content // empty' 2>/dev/null | wc -c)
|
|
116
|
+
# jq's `-r` adds a trailing newline; subtract 1 if content was non-empty
|
|
117
|
+
HAS_CONTENT=$(printf '%s' "$INPUT" | jq -r '.tool_input.content // empty' 2>/dev/null)
|
|
118
|
+
if [ -n "$HAS_CONTENT" ] && [ "$CONTENT_SIZE" -gt 0 ]; then
|
|
119
|
+
EXPECTED=$((CONTENT_SIZE - 1))
|
|
120
|
+
else
|
|
121
|
+
EXPECTED=0
|
|
122
|
+
fi
|
|
123
|
+
if [ "$DISK_SIZE" -ne "$EXPECTED" ]; then
|
|
124
|
+
# Possible shrink-pad case: disk size larger than expected
|
|
125
|
+
if [ "$DISK_SIZE" -gt "$EXPECTED" ]; then
|
|
126
|
+
# Check trailing bytes for nulls
|
|
127
|
+
TAIL_BYTES=$(tail -c 4 "$FILE_PATH" 2>/dev/null | od -An -tx1 | tr -d ' \n')
|
|
128
|
+
if [ "$TAIL_BYTES" = "00000000" ]; then
|
|
129
|
+
WARNINGS+=("Write target appears null-padded: on-disk size $DISK_SIZE bytes exceeds intended $EXPECTED bytes, trailing 4 bytes are 0x00. Possible virtiofs shrink-pad bug (#58551).")
|
|
130
|
+
else
|
|
131
|
+
WARNINGS+=("Write target byte count mismatch: on-disk $DISK_SIZE vs intended $EXPECTED. Tail bytes are not null but size differs; investigate.")
|
|
132
|
+
fi
|
|
133
|
+
else
|
|
134
|
+
# Tail-chop case: disk size smaller than expected
|
|
135
|
+
WARNINGS+=("Write target appears tail-chopped: on-disk size $DISK_SIZE bytes is less than intended $EXPECTED bytes. Possible virtiofs grow-chop bug (#58551).")
|
|
136
|
+
fi
|
|
137
|
+
fi
|
|
138
|
+
elif [ "$TOOL" = "Edit" ]; then
|
|
139
|
+
# For Edit, confirm new_string is in file and old_string is gone
|
|
140
|
+
NEW_STRING=$(printf '%s' "$INPUT" | jq -r '.tool_input.new_string // empty' 2>/dev/null)
|
|
141
|
+
OLD_STRING=$(printf '%s' "$INPUT" | jq -r '.tool_input.old_string // empty' 2>/dev/null)
|
|
142
|
+
REPLACE_ALL=$(printf '%s' "$INPUT" | jq -r '.tool_input.replace_all // false' 2>/dev/null)
|
|
143
|
+
|
|
144
|
+
if [ -n "$NEW_STRING" ]; then
|
|
145
|
+
if ! grep -F -q -- "$NEW_STRING" "$FILE_PATH" 2>/dev/null; then
|
|
146
|
+
WARNINGS+=("Edit completed but new_string not found in $FILE_PATH. The Edit may have been silently truncated (#58551) or applied incorrectly.")
|
|
147
|
+
fi
|
|
148
|
+
fi
|
|
149
|
+
if [ -n "$OLD_STRING" ] && [ "$REPLACE_ALL" != "true" ]; then
|
|
150
|
+
# In a non-replace_all Edit, old_string MAY still appear if it was a partial
|
|
151
|
+
# of a unique substring; skip strict check to avoid false positives.
|
|
152
|
+
:
|
|
153
|
+
fi
|
|
154
|
+
# Check for null-padding regardless
|
|
155
|
+
TAIL_BYTES=$(tail -c 4 "$FILE_PATH" 2>/dev/null | od -An -tx1 | tr -d ' \n')
|
|
156
|
+
if [ "$TAIL_BYTES" = "00000000" ]; then
|
|
157
|
+
# Avoid false positive: skip binary files
|
|
158
|
+
if file "$FILE_PATH" 2>/dev/null | grep -q "text"; then
|
|
159
|
+
WARNINGS+=("Edit target ends with 4 null bytes ($FILE_PATH). Text files normally do not. Possible virtiofs null-pad bug (#58551).")
|
|
160
|
+
fi
|
|
161
|
+
fi
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# No warnings → silent pass
|
|
165
|
+
if [ ${#WARNINGS[@]} -eq 0 ]; then
|
|
166
|
+
exit 0
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
# Log + emit
|
|
170
|
+
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
|
171
|
+
for w in "${WARNINGS[@]}"; do
|
|
172
|
+
echo "[$TIMESTAMP] file=$FILE_PATH tool=$TOOL action=$ACTION reason=$w" >> "$LOG_FILE"
|
|
173
|
+
done
|
|
174
|
+
|
|
175
|
+
MSG="⚠️ write-byte-integrity-verifier: potential file corruption after $TOOL"
|
|
176
|
+
for w in "${WARNINGS[@]}"; do
|
|
177
|
+
MSG+=$'\n'" - $w"
|
|
178
|
+
done
|
|
179
|
+
MSG+=$'\n'" Recommended: re-Read this file, confirm the intended content is on disk;"
|
|
180
|
+
MSG+=$'\n'" if corrupted, re-Write from your in-memory copy. On virtiofs mounts"
|
|
181
|
+
MSG+=$'\n'" (Claude Cowork sandbox / some devcontainers), consider working in /tmp"
|
|
182
|
+
MSG+=$'\n'" or a non-virtiofs path. Reference: github.com/anthropics/claude-code/issues/58551"
|
|
183
|
+
|
|
184
|
+
if [ "$ACTION" = "block" ]; then
|
|
185
|
+
printf '%s\n' "$MSG" >&2
|
|
186
|
+
exit 2
|
|
187
|
+
else
|
|
188
|
+
printf '%s\n' "$MSG" >&2
|
|
189
|
+
exit 0
|
|
190
|
+
fi
|