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,118 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# wellness-break-reminder.sh — Remind the user to take a body break
|
|
3
|
+
#
|
|
4
|
+
# What this is: a hook that watches your Claude Code session and, after
|
|
5
|
+
# you've been working without a noticed pause for ~90 minutes, prints a
|
|
6
|
+
# short reminder to your terminal: did you drink water, did you stand up,
|
|
7
|
+
# is your back okay?
|
|
8
|
+
#
|
|
9
|
+
# Why this exists: AI coding assistants make long sessions feel shorter
|
|
10
|
+
# than they are. Tokens flow, code gets written, time passes. The token
|
|
11
|
+
# usage warning (long-session-reminder.sh) handles the cost side. This
|
|
12
|
+
# hook handles the body side, which the existing wellness/posture
|
|
13
|
+
# literature suggests is the part that quietly accumulates harm.
|
|
14
|
+
#
|
|
15
|
+
# Tone: this is meant to feel like a colleague leaning over your desk,
|
|
16
|
+
# not a popup ad. It fires at most once per 30 minutes, even if the
|
|
17
|
+
# 90-minute threshold has been exceeded for hours, so it won't nag.
|
|
18
|
+
#
|
|
19
|
+
# TRIGGER: PostToolUse MATCHER: ""
|
|
20
|
+
# (empty matcher = fires on every tool use, but we throttle internally)
|
|
21
|
+
#
|
|
22
|
+
# CONFIG:
|
|
23
|
+
# CC_WELLNESS_FIRST_MIN=90 最初に出すまでの分数 (デフォルト 90 分)
|
|
24
|
+
# CC_WELLNESS_REPEAT_MIN=30 繰り返しの最短間隔 (デフォルト 30 分)
|
|
25
|
+
# CC_WELLNESS_OFF=1 完全に黙らせる (本人がいま集中したい時など)
|
|
26
|
+
|
|
27
|
+
# stdin を読んでも使わない (PostToolUse hook の入力 JSON は無視)
|
|
28
|
+
cat > /dev/null
|
|
29
|
+
|
|
30
|
+
[ "${CC_WELLNESS_OFF:-0}" = "1" ] && exit 0
|
|
31
|
+
|
|
32
|
+
FIRST_THRESHOLD_MIN="${CC_WELLNESS_FIRST_MIN:-90}"
|
|
33
|
+
REPEAT_INTERVAL_MIN="${CC_WELLNESS_REPEAT_MIN:-30}"
|
|
34
|
+
|
|
35
|
+
START_FLAG="$HOME/.claude/wellness-session-start"
|
|
36
|
+
LAST_REMIND="$HOME/.claude/wellness-last-reminder"
|
|
37
|
+
|
|
38
|
+
# 最初の作業でセッション開始時刻を記録
|
|
39
|
+
if [ ! -f "$START_FLAG" ]; then
|
|
40
|
+
date +%s > "$START_FLAG"
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Claude Code のセッションが終わった時に START_FLAG が残っていると、
|
|
45
|
+
# 次のセッションで誤った時刻が使われる。stop hook 等で消すのが本来だが、
|
|
46
|
+
# ここでは 12 時間以上経った flag は古すぎるとみて作り直す
|
|
47
|
+
START_EPOCH=$(cat "$START_FLAG" 2>/dev/null)
|
|
48
|
+
NOW_EPOCH=$(date +%s)
|
|
49
|
+
if [ -z "$START_EPOCH" ]; then
|
|
50
|
+
date +%s > "$START_FLAG"
|
|
51
|
+
exit 0
|
|
52
|
+
fi
|
|
53
|
+
ELAPSED_SEC=$(( NOW_EPOCH - START_EPOCH ))
|
|
54
|
+
if [ "$ELAPSED_SEC" -lt 0 ] || [ "$ELAPSED_SEC" -gt 43200 ]; then
|
|
55
|
+
# 12 時間 (43200 秒) を超えていたら stale flag、新しく作り直す
|
|
56
|
+
date +%s > "$START_FLAG"
|
|
57
|
+
: > "$LAST_REMIND"
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
ELAPSED_MIN=$(( ELAPSED_SEC / 60 ))
|
|
62
|
+
|
|
63
|
+
# まだ閾値に届いていない
|
|
64
|
+
if [ "$ELAPSED_MIN" -lt "$FIRST_THRESHOLD_MIN" ]; then
|
|
65
|
+
exit 0
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# 直近のリマインダー時刻を確認、繰り返し間隔を守る
|
|
69
|
+
# stale-reset path で `: > "$LAST_REMIND"` が空ファイルを残す経路があり、
|
|
70
|
+
# 空 / 非数値の内容を読むと後続の `[ -gt 0 ]` で integer error が出て
|
|
71
|
+
# throttle が bypass される。空 / 非数値は 0 扱いに正規化 (PR #137 Codex review fix)
|
|
72
|
+
LAST_EPOCH=0
|
|
73
|
+
if [ -f "$LAST_REMIND" ]; then
|
|
74
|
+
LAST_EPOCH_RAW=$(cat "$LAST_REMIND" 2>/dev/null)
|
|
75
|
+
case "$LAST_EPOCH_RAW" in
|
|
76
|
+
''|*[!0-9]*) LAST_EPOCH=0 ;;
|
|
77
|
+
*) LAST_EPOCH="$LAST_EPOCH_RAW" ;;
|
|
78
|
+
esac
|
|
79
|
+
fi
|
|
80
|
+
SINCE_LAST_MIN=$(( (NOW_EPOCH - LAST_EPOCH) / 60 ))
|
|
81
|
+
if [ "$LAST_EPOCH" -gt 0 ] && [ "$SINCE_LAST_MIN" -lt "$REPEAT_INTERVAL_MIN" ]; then
|
|
82
|
+
exit 0
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# メッセージを 1 つ選んで出す (作業時間で内容を変える)
|
|
86
|
+
HOURS=$(( ELAPSED_MIN / 60 ))
|
|
87
|
+
MINS=$(( ELAPSED_MIN % 60 ))
|
|
88
|
+
|
|
89
|
+
if [ "$HOURS" -lt 2 ]; then
|
|
90
|
+
cat >&2 <<EOF
|
|
91
|
+
|
|
92
|
+
🫖 セッション ${HOURS}時間${MINS}分続いています。
|
|
93
|
+
コーヒーが冷めていませんか?水を一杯どうですか。
|
|
94
|
+
3 分くらい立ち上がって肩を回すと、たぶん次の判断が少し変わります。
|
|
95
|
+
(このリマインダーを止めるなら CC_WELLNESS_OFF=1)
|
|
96
|
+
EOF
|
|
97
|
+
elif [ "$HOURS" -lt 4 ]; then
|
|
98
|
+
cat >&2 <<EOF
|
|
99
|
+
|
|
100
|
+
🪟 もう ${HOURS}時間${MINS}分経ちました。
|
|
101
|
+
画面から目を離して、3 メートル先のものを 30 秒見てください。
|
|
102
|
+
立って、コップに水を入れて、トイレに行く。コードはここで待っています。
|
|
103
|
+
AI の私には体がないけれど、あなたにはある。
|
|
104
|
+
EOF
|
|
105
|
+
else
|
|
106
|
+
cat >&2 <<EOF
|
|
107
|
+
|
|
108
|
+
🌙 ${HOURS}時間${MINS}分。長丁場です。
|
|
109
|
+
そろそろ続きは明日にしませんか。残りの判断の質は、いまの肩や首の痛みと
|
|
110
|
+
たぶん相関しています。git commit して、画面を閉じて、ベッドへ。
|
|
111
|
+
私はあなたが戻ってきた時、いつでも続きから出来ます。
|
|
112
|
+
EOF
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# 直近のリマインダー時刻を更新
|
|
116
|
+
date +%s > "$LAST_REMIND"
|
|
117
|
+
|
|
118
|
+
exit 0
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ================================================================
|
|
3
|
+
# windows-destructive-command-guard.sh — Block Windows-side
|
|
4
|
+
# destructive command
|
|
5
|
+
# escalation chains
|
|
6
|
+
# ================================================================
|
|
7
|
+
# PURPOSE:
|
|
8
|
+
# The May 2026 Issue #56603 documented a catastrophic data-loss
|
|
9
|
+
# incident: Claude Opus 4.7 escalated through five increasingly
|
|
10
|
+
# destructive commands during routine git worktree cleanup,
|
|
11
|
+
# ending at `cmd /c "rd /s /q \"<unicode-and-space-path>\""`
|
|
12
|
+
# invoked from the PowerShell tool. The PowerShell-cmd-shell
|
|
13
|
+
# quoting interaction parsed the argument differently than
|
|
14
|
+
# intended; rd /s /q traversed the entire D: drive root and
|
|
15
|
+
# silently deleted all unlocked files. SSD TRIM made the loss
|
|
16
|
+
# irreversible — professional data recovery confirmed
|
|
17
|
+
# unrecoverable.
|
|
18
|
+
#
|
|
19
|
+
# The cc-safe-setup hook collection has rm-rf coverage on the
|
|
20
|
+
# POSIX side but no equivalent for the Windows command surface.
|
|
21
|
+
# This hook closes that gap: it inspects shell-tool commands for
|
|
22
|
+
# Windows-side destructive command shapes and blocks the chain
|
|
23
|
+
# before the dangerous step executes.
|
|
24
|
+
#
|
|
25
|
+
# TRIGGER: PreToolUse MATCHER: "Bash|PowerShell"
|
|
26
|
+
#
|
|
27
|
+
# IMPORTANT: Claude Code's PowerShell tool is a SEPARATE tool from
|
|
28
|
+
# Bash (see https://code.claude.com/docs/en/tools). A hook matched
|
|
29
|
+
# only on "Bash" never fires when Claude runs a command through the
|
|
30
|
+
# native PowerShell tool — which is exactly how the destructive
|
|
31
|
+
# command slipped past with no permission prompt in #69397. This
|
|
32
|
+
# guard therefore accepts both tool names; register it with
|
|
33
|
+
# matcher "Bash|PowerShell" so it covers the PowerShell tool too.
|
|
34
|
+
#
|
|
35
|
+
# CONFIG:
|
|
36
|
+
# WINDOWS_DESTRUCTIVE_BLOCK=1 (1 = block, 0 = warn-only)
|
|
37
|
+
#
|
|
38
|
+
# Born from: https://github.com/anthropics/claude-code/issues/56603
|
|
39
|
+
# (May 6 2026 — Opus 4.7 cmd /c rd /s /q catastrophic data loss
|
|
40
|
+
# via PowerShell quoting interaction on Unicode/space path)
|
|
41
|
+
# and https://github.com/anthropics/claude-code/issues/69397
|
|
42
|
+
# (Jun 2026 — destructive command via the PowerShell tool ran with
|
|
43
|
+
# no permission prompt; Bash-only guards/matchers do not fire)
|
|
44
|
+
# ================================================================
|
|
45
|
+
|
|
46
|
+
set -euo pipefail
|
|
47
|
+
|
|
48
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
49
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
50
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
51
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
52
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
53
|
+
_nojq_warned="/tmp/cc-nojq-warned-windows-destructive-command-guard-$PPID"
|
|
54
|
+
[ -f "$_nojq_warned" ] || {
|
|
55
|
+
echo "WARNING [windows-destructive-command-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
56
|
+
: > "$_nojq_warned"
|
|
57
|
+
}
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
BLOCK_MODE="${WINDOWS_DESTRUCTIVE_BLOCK:-1}"
|
|
61
|
+
|
|
62
|
+
# Read JSON input from stdin
|
|
63
|
+
INPUT=$(cat)
|
|
64
|
+
|
|
65
|
+
# Act on either shell tool. The PowerShell tool is separate from Bash
|
|
66
|
+
# in Claude Code; the #56603 incident command ran through the PowerShell
|
|
67
|
+
# tool, and #69397 showed a Bash-only gate lets PowerShell-tool commands
|
|
68
|
+
# through. Both tools carry the command string in tool_input.command.
|
|
69
|
+
TOOL_NAME=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
70
|
+
case "$TOOL_NAME" in
|
|
71
|
+
Bash|PowerShell) ;;
|
|
72
|
+
*) exit 0 ;;
|
|
73
|
+
esac
|
|
74
|
+
|
|
75
|
+
# Extract the command
|
|
76
|
+
CMD=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
77
|
+
[ -z "$CMD" ] && exit 0
|
|
78
|
+
|
|
79
|
+
# Detect Windows-side destructive command shapes.
|
|
80
|
+
# We look for the dangerous primitive AND for the contextual
|
|
81
|
+
# signals (drive-root target, recursive force flags, suppressed
|
|
82
|
+
# confirmation) that distinguish a routine cleanup from a
|
|
83
|
+
# whole-drive sweep.
|
|
84
|
+
|
|
85
|
+
DETECTED_PATTERNS=""
|
|
86
|
+
|
|
87
|
+
# Pattern 1: rd /s /q (or RD /S /Q, or rmdir /s /q) — recursive
|
|
88
|
+
# directory removal with force-quiet. Combined with /q, no
|
|
89
|
+
# confirmation prompt. The #56603 incident's terminal command.
|
|
90
|
+
if printf '%s' "$CMD" | grep -qiE '\b(rd|rmdir)\b[[:space:]]+(/[a-z][[:space:]]+){1,3}'; then
|
|
91
|
+
if printf '%s' "$CMD" | grep -qiE '\b(rd|rmdir)\b[[:space:]]+(/s|/q)'; then
|
|
92
|
+
DETECTED_PATTERNS="${DETECTED_PATTERNS}rd_recursive_quiet "
|
|
93
|
+
fi
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Pattern 2: cmd /c invocation — the shell-jump that produced the
|
|
97
|
+
# quoting interaction in #56603. Combined with rd/rmdir, this is
|
|
98
|
+
# the highest-risk shape because the second-level cmd parser may
|
|
99
|
+
# split the argument differently than the PowerShell first-level.
|
|
100
|
+
if printf '%s' "$CMD" | grep -qiE '\bcmd\b[[:space:]]+/c[[:space:]]+'; then
|
|
101
|
+
if printf '%s' "$CMD" | grep -qiE '(rd|rmdir|del|erase)'; then
|
|
102
|
+
DETECTED_PATTERNS="${DETECTED_PATTERNS}cmd_c_destructive "
|
|
103
|
+
fi
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
# Pattern 3: Remove-Item -Recurse -Force — PowerShell's recursive
|
|
107
|
+
# force removal. Step 4 in the #56603 escalation chain.
|
|
108
|
+
if printf '%s' "$CMD" | grep -qiE 'Remove-Item\b'; then
|
|
109
|
+
if printf '%s' "$CMD" | grep -qiE '\-Recurse\b'; then
|
|
110
|
+
if printf '%s' "$CMD" | grep -qiE '\-Force\b'; then
|
|
111
|
+
DETECTED_PATTERNS="${DETECTED_PATTERNS}remove_item_recurse_force "
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Pattern 4: del /s /q or erase /s /q — recursive file deletion.
|
|
117
|
+
if printf '%s' "$CMD" | grep -qiE '\b(del|erase)\b[[:space:]]+(/[a-z][[:space:]]+){1,3}'; then
|
|
118
|
+
if printf '%s' "$CMD" | grep -qiE '\b(del|erase)\b[[:space:]]+(/s|/q)'; then
|
|
119
|
+
DETECTED_PATTERNS="${DETECTED_PATTERNS}del_recursive_quiet "
|
|
120
|
+
fi
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Pattern 5: Format-Volume / Clear-Disk / Remove-PartitionAccessPath
|
|
124
|
+
# — disk-level destructive PowerShell cmdlets.
|
|
125
|
+
if printf '%s' "$CMD" | grep -qiE '(Format-Volume|Clear-Disk|Remove-Partition)\b'; then
|
|
126
|
+
DETECTED_PATTERNS="${DETECTED_PATTERNS}disk_level_destructive "
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
# If no destructive pattern detected, exit silently
|
|
130
|
+
[ -z "$DETECTED_PATTERNS" ] && exit 0
|
|
131
|
+
DETECTED_PATTERNS="${DETECTED_PATTERNS% }"
|
|
132
|
+
|
|
133
|
+
# Risk-elevating context signals — drive-root targets, escape-prone paths
|
|
134
|
+
RISK_NOTES=""
|
|
135
|
+
|
|
136
|
+
# Drive-root signal: target looks like "D:\" alone, "C:\" alone,
|
|
137
|
+
# or a path shorter than 6 characters after the colon. These are
|
|
138
|
+
# the highest-risk targets because a parsing error truncating to
|
|
139
|
+
# the drive root sweeps the whole drive.
|
|
140
|
+
if printf '%s' "$CMD" | grep -qiE '[A-Z]:\\?(\s|"|$)'; then
|
|
141
|
+
RISK_NOTES="${RISK_NOTES}drive_root_target "
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
# Unicode/space path signal: target contains escaped spaces or
|
|
145
|
+
# non-ASCII characters within quotes. The #56603 quoting
|
|
146
|
+
# interaction surfaced specifically on Unicode-and-space paths.
|
|
147
|
+
if printf '%s' "$CMD" | grep -qE '\\"|"[^"]*[[:space:]]'; then
|
|
148
|
+
if printf '%s' "$CMD" | grep -qE '"[^"]*[^[:print:]]'; then
|
|
149
|
+
RISK_NOTES="${RISK_NOTES}unicode_in_quoted_path "
|
|
150
|
+
elif printf '%s' "$CMD" | grep -qE '"[^"]*[[:space:]]'; then
|
|
151
|
+
RISK_NOTES="${RISK_NOTES}space_in_quoted_path "
|
|
152
|
+
fi
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# Block path: emit the blocking message
|
|
156
|
+
if [ "$BLOCK_MODE" = "1" ]; then
|
|
157
|
+
echo "BLOCKED: windows-destructive-command-guard: detected destructive Windows-side command pattern(s): ${DETECTED_PATTERNS}" >&2
|
|
158
|
+
if [ -n "$RISK_NOTES" ]; then
|
|
159
|
+
echo " Risk-elevating context: ${RISK_NOTES% }" >&2
|
|
160
|
+
fi
|
|
161
|
+
echo " May 2026 Issue #56603 cluster mitigation: Opus 4.7's escalation chain on Windows ended at cmd /c rd /s /q with quoting interaction sweeping the entire D: drive (SSD TRIM made loss irreversible)." >&2
|
|
162
|
+
echo " Safer alternatives:" >&2
|
|
163
|
+
echo " - For locked git worktrees: stop and tell the operator the lock blocker (VS Code, etc.) before escalating force flags." >&2
|
|
164
|
+
echo " - For path-quoting on Windows: avoid cmd /c from PowerShell; use Remove-Item with -LiteralPath and explicit -ErrorAction Stop." >&2
|
|
165
|
+
echo " - For specific files: list them by absolute path, do not rely on recursive sweeps." >&2
|
|
166
|
+
echo " To bypass for legitimate cleanup: export WINDOWS_DESTRUCTIVE_BLOCK=0 (warn-only mode)." >&2
|
|
167
|
+
exit 2
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# Warn path
|
|
171
|
+
echo "WARNING: windows-destructive-command-guard: detected destructive Windows-side command pattern(s): ${DETECTED_PATTERNS}" >&2
|
|
172
|
+
if [ -n "$RISK_NOTES" ]; then
|
|
173
|
+
echo " Risk-elevating context: ${RISK_NOTES% }" >&2
|
|
174
|
+
fi
|
|
175
|
+
echo " May 2026 Issue #56603: this command shape produced catastrophic data loss when a quoting interaction swept a whole drive. Verify the target path is bounded before proceeding." >&2
|
|
176
|
+
|
|
177
|
+
exit 0
|
|
@@ -12,6 +12,18 @@
|
|
|
12
12
|
# TRIGGER: PreToolUse
|
|
13
13
|
# MATCHER: "Bash"
|
|
14
14
|
|
|
15
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
16
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
17
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
18
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
19
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
20
|
+
_nojq_warned="/tmp/cc-nojq-warned-windows-path-guard-$PPID"
|
|
21
|
+
[ -f "$_nojq_warned" ] || {
|
|
22
|
+
echo "WARNING [windows-path-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
23
|
+
: > "$_nojq_warned"
|
|
24
|
+
}
|
|
25
|
+
fi
|
|
26
|
+
|
|
15
27
|
INPUT=$(cat)
|
|
16
28
|
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
17
29
|
[ -z "$COMMAND" ] && exit 0
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# windows-python-stub-detector.sh — Detect Microsoft Store python3 stub at session start
|
|
3
|
+
#
|
|
4
|
+
# Solves: Issue #57946 — On Windows Git Bash, `python3` may resolve to the
|
|
5
|
+
# Microsoft Store stub rather than a real Python interpreter. The stub is
|
|
6
|
+
# on PATH and `which python3` succeeds, but invoking it as a subprocess
|
|
7
|
+
# exits 49 with no stdout and no stderr. Python-based PreToolUse and
|
|
8
|
+
# PostToolUse hooks then exit silently before they can inspect the tool
|
|
9
|
+
# call — the hook configuration is valid, the script file is present,
|
|
10
|
+
# and the agent proceeds as if the hook approved.
|
|
11
|
+
#
|
|
12
|
+
# How it works: At SessionStart, probes the python3 command (or whatever
|
|
13
|
+
# $CC_PYTHON_CMD points to) with a trivial Python statement. If exit code
|
|
14
|
+
# is 49 (Store redirect) or stderr matches Store-redirect markers, emits a
|
|
15
|
+
# warning via hookSpecificOutput.additionalContext. The model sees the
|
|
16
|
+
# warning and can alert the user.
|
|
17
|
+
#
|
|
18
|
+
# Why advisory (no exit 2): SessionStart hooks blocking would prevent the
|
|
19
|
+
# user from working at all. The user may have intentional fallback paths.
|
|
20
|
+
# This hook surfaces the problem; the user decides what to do.
|
|
21
|
+
#
|
|
22
|
+
# TRIGGER: SessionStart
|
|
23
|
+
# MATCHER: none required
|
|
24
|
+
|
|
25
|
+
INPUT=$(cat)
|
|
26
|
+
|
|
27
|
+
# Allow tests / explicit overrides to point at a different binary
|
|
28
|
+
PYTHON_CMD="${CC_PYTHON_CMD:-python3}"
|
|
29
|
+
|
|
30
|
+
# Probe with a minimal Python statement.
|
|
31
|
+
# Real Python: prints "ok", exits 0.
|
|
32
|
+
# Microsoft Store stub: exits 49 with no output (sometimes "Microsoft Store"
|
|
33
|
+
# markers in stderr depending on shell wrapper).
|
|
34
|
+
PROBE_OUTPUT=$("$PYTHON_CMD" -c 'import sys; sys.stdout.write("ok"); sys.exit(0)' 2>&1)
|
|
35
|
+
PROBE_EXIT=$?
|
|
36
|
+
|
|
37
|
+
# Detection conditions (any one trips the warning):
|
|
38
|
+
# - exit code 49: documented Store-redirect signal in Git Bash subprocess
|
|
39
|
+
# - stderr contains "Microsoft Store" or "install Python"
|
|
40
|
+
# - exit code 127 or "command not found" / "no such file" output: python3 missing
|
|
41
|
+
# - exit code 0 but no "ok" in output (stub may succeed silently in some shells)
|
|
42
|
+
TRIGGERED=0
|
|
43
|
+
if [ "$PROBE_EXIT" -eq 49 ]; then
|
|
44
|
+
TRIGGERED=1
|
|
45
|
+
REASON="python3 exited 49 (Microsoft Store redirect)"
|
|
46
|
+
elif echo "$PROBE_OUTPUT" | grep -qi 'microsoft store\|install python'; then
|
|
47
|
+
TRIGGERED=1
|
|
48
|
+
REASON="python3 stderr matched Store-redirect marker"
|
|
49
|
+
elif [ "$PROBE_EXIT" -eq 127 ] || echo "$PROBE_OUTPUT" | grep -qi 'command not found\|no such file'; then
|
|
50
|
+
TRIGGERED=1
|
|
51
|
+
REASON="python3 not found in PATH"
|
|
52
|
+
elif [ "$PROBE_EXIT" -eq 0 ] && ! echo "$PROBE_OUTPUT" | grep -q '^ok$'; then
|
|
53
|
+
TRIGGERED=1
|
|
54
|
+
REASON="python3 exited 0 but produced no output (suspected silent stub)"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
if [ "$TRIGGERED" -eq 1 ]; then
|
|
58
|
+
cat <<EOF
|
|
59
|
+
{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"⚠️ python3 stub detected ($REASON). Any Python-based PreToolUse/PostToolUse hooks will exit 49 silently on this system and be ineffective. The hook configuration looks valid but the hooks never run. Fix: install real Python (winget install Python.Python.3.12, or from python.org) and ensure it precedes the Store stub in PATH, or rewrite hooks in bash. Reference: claude-code#57946."}}
|
|
60
|
+
EOF
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
exit 0
|
|
@@ -15,6 +15,18 @@
|
|
|
15
15
|
# CC_WORK_DAYS=12345 (default: Mon-Fri, 1=Mon 7=Sun)
|
|
16
16
|
# ================================================================
|
|
17
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-work-hours-guard-$PPID"
|
|
24
|
+
[ -f "$_nojq_warned" ] || {
|
|
25
|
+
echo "WARNING [work-hours-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
26
|
+
: > "$_nojq_warned"
|
|
27
|
+
}
|
|
28
|
+
fi
|
|
29
|
+
|
|
18
30
|
INPUT=$(cat)
|
|
19
31
|
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
20
32
|
[ -z "$COMMAND" ] && exit 0
|
|
@@ -32,6 +32,18 @@
|
|
|
32
32
|
|
|
33
33
|
set -u
|
|
34
34
|
|
|
35
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
36
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
37
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
38
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
39
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
40
|
+
_nojq_warned="/tmp/cc-nojq-warned-working-directory-fence-$PPID"
|
|
41
|
+
[ -f "$_nojq_warned" ] || {
|
|
42
|
+
echo "WARNING [working-directory-fence]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
43
|
+
: > "$_nojq_warned"
|
|
44
|
+
}
|
|
45
|
+
fi
|
|
46
|
+
|
|
35
47
|
INPUT=$(cat)
|
|
36
48
|
|
|
37
49
|
FILE_PATH=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# workspace-lease-guard.sh — Out-of-process workspace ownership lease, with
|
|
3
|
+
# compare-and-delete release and heartbeat takeover for crashed siblings.
|
|
4
|
+
#
|
|
5
|
+
# Solves: #60475 — "Subagent ran `git checkout` and clobbered another active
|
|
6
|
+
# session's uncommitted edits in the same working tree." The destructive
|
|
7
|
+
# action succeeded because no in-process register state could enumerate
|
|
8
|
+
# "is there a sibling agent in this tree?" — and in-process state is exactly
|
|
9
|
+
# what was lost across the auto-compact boundary that produced the failure.
|
|
10
|
+
#
|
|
11
|
+
# In the words of @kcarriedo's pattern 4 in that Issue thread:
|
|
12
|
+
#
|
|
13
|
+
# "Workspace ownership needs to be an out-of-process invariant. Once
|
|
14
|
+
# 'this directory is being mutated by agent X' lives only in agent X's
|
|
15
|
+
# session, agent Y has no way to discover that and the orchestrator has
|
|
16
|
+
# no way to enforce it. A simple file-based lease ... with compare-and-
|
|
17
|
+
# delete release semantics would have caught this at the moment of the
|
|
18
|
+
# destructive checkout."
|
|
19
|
+
#
|
|
20
|
+
# This hook implements that lease. The lease file lives at
|
|
21
|
+
# ${CC_LEASE_DIR}/workspace-${REPO_HASH}.lease and encodes:
|
|
22
|
+
# <agent_id>|<acquired_ts>|<heartbeat_ts>
|
|
23
|
+
#
|
|
24
|
+
# Lifecycle:
|
|
25
|
+
# * SessionStart — attempt to acquire. If unheld or stale, claim.
|
|
26
|
+
# If held by another live agent, BLOCK the session start.
|
|
27
|
+
# * PreToolUse — refresh heartbeat on every tool call. If the lease was
|
|
28
|
+
# taken over by a different agent_id (we crashed and got
|
|
29
|
+
# replaced), BLOCK the tool call so the user is warned
|
|
30
|
+
# rather than silently competing.
|
|
31
|
+
# * Stop — compare-and-delete release. Only the lease holder removes
|
|
32
|
+
# the lease file; an out-of-band cleanup that finds a
|
|
33
|
+
# different agent_id leaves it alone.
|
|
34
|
+
#
|
|
35
|
+
# The matcher must be "*" so the hook fires on every tool call (to refresh
|
|
36
|
+
# the heartbeat and detect cross-agent contention at the earliest moment).
|
|
37
|
+
#
|
|
38
|
+
# CONFIG:
|
|
39
|
+
# CC_LEASE_DIR=$HOME/.claude/locks directory for lease files
|
|
40
|
+
# CC_LEASE_HEARTBEAT_TTL=180 seconds before an idle lease is stale
|
|
41
|
+
# CC_LEASE_DISABLE=1 set to disable the hook entirely
|
|
42
|
+
#
|
|
43
|
+
# This is distinct from concurrent-edit-lock.sh (per-file lock on Edit/Write,
|
|
44
|
+
# 60-second expiry) and max-concurrent-agents.sh (caps subagent fan-out).
|
|
45
|
+
# workspace-lease-guard.sh is repo-scoped, covers Bash (not just Edit/Write),
|
|
46
|
+
# and survives auto-compact because the lease lives on the filesystem.
|
|
47
|
+
#
|
|
48
|
+
# Related Issues:
|
|
49
|
+
# #60475 (@anonymous, 2026-05-19) — subagent git checkout clobbered sibling
|
|
50
|
+
# #60506 (@zean89, 2026-05-19) — six-day drift inside maximal in-process enforcement
|
|
51
|
+
# #60226 (@suwayama, 2026-05-18) — recognition-without-arrest framework
|
|
52
|
+
# #57463 — subagent destructive-recovery family
|
|
53
|
+
#
|
|
54
|
+
# TRIGGER: PreToolUse, SessionStart, Stop
|
|
55
|
+
# MATCHER: "*"
|
|
56
|
+
|
|
57
|
+
set -u
|
|
58
|
+
|
|
59
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
60
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
61
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
62
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
63
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
64
|
+
_nojq_warned="/tmp/cc-nojq-warned-workspace-lease-guard-$PPID"
|
|
65
|
+
[ -f "$_nojq_warned" ] || {
|
|
66
|
+
echo "WARNING [workspace-lease-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
67
|
+
: > "$_nojq_warned"
|
|
68
|
+
}
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
[ "${CC_LEASE_DISABLE:-0}" = "1" ] && exit 0
|
|
72
|
+
|
|
73
|
+
LEASE_DIR="${CC_LEASE_DIR:-$HOME/.claude/locks}"
|
|
74
|
+
HEARTBEAT_TTL="${CC_LEASE_HEARTBEAT_TTL:-180}"
|
|
75
|
+
NOW=$(date +%s)
|
|
76
|
+
|
|
77
|
+
INPUT=$(cat)
|
|
78
|
+
EVENT=$(printf '%s' "$INPUT" | jq -r '.hook_event_name // empty' 2>/dev/null)
|
|
79
|
+
TOOL=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
80
|
+
|
|
81
|
+
# Identify the workspace: prefer the git toplevel, fall back to CLAUDE_PROJECT_DIR
|
|
82
|
+
# or PWD. Anything outside a recognisable workspace is ignored.
|
|
83
|
+
WORKSPACE=$(git -C "${CLAUDE_PROJECT_DIR:-${PWD:-.}}" rev-parse --show-toplevel 2>/dev/null)
|
|
84
|
+
if [ -z "$WORKSPACE" ]; then
|
|
85
|
+
WORKSPACE="${CLAUDE_PROJECT_DIR:-${PWD:-}}"
|
|
86
|
+
fi
|
|
87
|
+
[ -z "$WORKSPACE" ] && exit 0
|
|
88
|
+
|
|
89
|
+
# Identify the agent: prefer the session id, fall back to PPID. Parent PID is
|
|
90
|
+
# stable across one Claude Code session and distinct between sibling sessions.
|
|
91
|
+
AGENT_ID="${CLAUDE_SESSION_ID:-pid-${PPID:-$$}}"
|
|
92
|
+
|
|
93
|
+
REPO_HASH=$(printf '%s' "$WORKSPACE" | sha256sum | cut -c1-16)
|
|
94
|
+
mkdir -p "$LEASE_DIR" 2>/dev/null || true
|
|
95
|
+
LEASE_FILE="${LEASE_DIR}/workspace-${REPO_HASH}.lease"
|
|
96
|
+
|
|
97
|
+
# Read current lease, if any
|
|
98
|
+
read_lease() {
|
|
99
|
+
[ -f "$LEASE_FILE" ] || { echo ""; return; }
|
|
100
|
+
cat "$LEASE_FILE" 2>/dev/null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
write_lease() {
|
|
104
|
+
# acquired_ts | heartbeat_ts
|
|
105
|
+
local acquired="${1:-$NOW}"
|
|
106
|
+
printf '%s|%s|%s\n' "$AGENT_ID" "$acquired" "$NOW" > "$LEASE_FILE"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
LEASE_CONTENT=$(read_lease)
|
|
110
|
+
|
|
111
|
+
if [ -n "$LEASE_CONTENT" ]; then
|
|
112
|
+
LEASE_AGENT=$(printf '%s' "$LEASE_CONTENT" | cut -d'|' -f1)
|
|
113
|
+
LEASE_ACQUIRED=$(printf '%s' "$LEASE_CONTENT" | cut -d'|' -f2)
|
|
114
|
+
LEASE_HEARTBEAT=$(printf '%s' "$LEASE_CONTENT" | cut -d'|' -f3)
|
|
115
|
+
LEASE_AGE=$((NOW - ${LEASE_HEARTBEAT:-0}))
|
|
116
|
+
else
|
|
117
|
+
LEASE_AGENT=""
|
|
118
|
+
LEASE_ACQUIRED=""
|
|
119
|
+
LEASE_HEARTBEAT=""
|
|
120
|
+
LEASE_AGE=0
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
case "$EVENT" in
|
|
124
|
+
SessionStart)
|
|
125
|
+
if [ -z "$LEASE_CONTENT" ] || [ "$LEASE_AGENT" = "$AGENT_ID" ]; then
|
|
126
|
+
write_lease "${LEASE_ACQUIRED:-$NOW}"
|
|
127
|
+
exit 0
|
|
128
|
+
fi
|
|
129
|
+
if [ "$LEASE_AGE" -gt "$HEARTBEAT_TTL" ]; then
|
|
130
|
+
# Previous holder went stale (likely crashed) — take over with notice
|
|
131
|
+
write_lease "$NOW"
|
|
132
|
+
cat >&2 <<EOF
|
|
133
|
+
NOTICE: workspace-lease-guard took over a stale lease for ${WORKSPACE}.
|
|
134
|
+
Previous agent: ${LEASE_AGENT} (idle ${LEASE_AGE}s, TTL ${HEARTBEAT_TTL}s)
|
|
135
|
+
New agent: ${AGENT_ID}
|
|
136
|
+
If the previous session is still active, both sessions are now competing
|
|
137
|
+
for the same working tree. Stop one before continuing.
|
|
138
|
+
EOF
|
|
139
|
+
exit 0
|
|
140
|
+
fi
|
|
141
|
+
cat >&2 <<EOF
|
|
142
|
+
BLOCKED: workspace ${WORKSPACE} is held by another Claude session.
|
|
143
|
+
Held by: ${LEASE_AGENT} (last heartbeat ${LEASE_AGE}s ago)
|
|
144
|
+
This session: ${AGENT_ID}
|
|
145
|
+
|
|
146
|
+
A sibling agent is actively mutating this working tree. Concurrent
|
|
147
|
+
sessions in the same repo can silently clobber each other's uncommitted
|
|
148
|
+
edits (see Issue #60475). Either:
|
|
149
|
+
1. Switch to a different worktree: git worktree add ../sibling-path
|
|
150
|
+
2. Stop the other session, then retry
|
|
151
|
+
3. If the other session is dead, wait ${HEARTBEAT_TTL}s for the lease
|
|
152
|
+
to expire, or manually remove: ${LEASE_FILE}
|
|
153
|
+
EOF
|
|
154
|
+
exit 2
|
|
155
|
+
;;
|
|
156
|
+
|
|
157
|
+
PreToolUse)
|
|
158
|
+
# Heartbeat refresh + cross-agent takeover detection
|
|
159
|
+
if [ -z "$LEASE_CONTENT" ]; then
|
|
160
|
+
# No lease — first tool call after SessionStart hook misfire, or
|
|
161
|
+
# SessionStart was not registered. Claim it implicitly.
|
|
162
|
+
write_lease "$NOW"
|
|
163
|
+
exit 0
|
|
164
|
+
fi
|
|
165
|
+
if [ "$LEASE_AGENT" = "$AGENT_ID" ]; then
|
|
166
|
+
# We hold the lease — refresh heartbeat
|
|
167
|
+
write_lease "$LEASE_ACQUIRED"
|
|
168
|
+
exit 0
|
|
169
|
+
fi
|
|
170
|
+
if [ "$LEASE_AGE" -gt "$HEARTBEAT_TTL" ]; then
|
|
171
|
+
# Other holder went stale — take over with notice
|
|
172
|
+
write_lease "$NOW"
|
|
173
|
+
cat >&2 <<EOF
|
|
174
|
+
NOTICE: workspace-lease-guard took over a stale lease mid-session.
|
|
175
|
+
Previous agent: ${LEASE_AGENT} (idle ${LEASE_AGE}s)
|
|
176
|
+
This session: ${AGENT_ID}
|
|
177
|
+
EOF
|
|
178
|
+
exit 0
|
|
179
|
+
fi
|
|
180
|
+
cat >&2 <<EOF
|
|
181
|
+
BLOCKED: workspace-lease-guard detected a sibling agent.
|
|
182
|
+
Workspace: ${WORKSPACE}
|
|
183
|
+
Held by: ${LEASE_AGENT} (last heartbeat ${LEASE_AGE}s ago)
|
|
184
|
+
This: ${AGENT_ID}, attempting ${TOOL:-tool call}
|
|
185
|
+
|
|
186
|
+
This is the failure shape of Issue #60475. A second Claude session
|
|
187
|
+
is mutating this working tree concurrently. Refusing the tool call
|
|
188
|
+
to prevent silent clobbering of the sibling's uncommitted edits.
|
|
189
|
+
Switch to a separate worktree before continuing.
|
|
190
|
+
EOF
|
|
191
|
+
exit 2
|
|
192
|
+
;;
|
|
193
|
+
|
|
194
|
+
Stop)
|
|
195
|
+
# Compare-and-delete release: only the holder removes the lease
|
|
196
|
+
if [ -n "$LEASE_CONTENT" ] && [ "$LEASE_AGENT" = "$AGENT_ID" ]; then
|
|
197
|
+
rm -f "$LEASE_FILE"
|
|
198
|
+
fi
|
|
199
|
+
exit 0
|
|
200
|
+
;;
|
|
201
|
+
|
|
202
|
+
*)
|
|
203
|
+
exit 0
|
|
204
|
+
;;
|
|
205
|
+
esac
|
|
@@ -17,6 +17,18 @@
|
|
|
17
17
|
# - rm -rf on worktree directories
|
|
18
18
|
# ================================================================
|
|
19
19
|
|
|
20
|
+
# Without jq, the parse below silently yields empty and this hook stops
|
|
21
|
+
# guarding - with no error anywhere. Say so. We deliberately do not exit
|
|
22
|
+
# here: blocking would halt every tool call, and exiting 0 would change
|
|
23
|
+
# the behaviour of guards that do not depend on the parsed value.
|
|
24
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
25
|
+
_nojq_warned="/tmp/cc-nojq-warned-worktree-delete-guard-$PPID"
|
|
26
|
+
[ -f "$_nojq_warned" ] || {
|
|
27
|
+
echo "WARNING [worktree-delete-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
|
|
28
|
+
: > "$_nojq_warned"
|
|
29
|
+
}
|
|
30
|
+
fi
|
|
31
|
+
|
|
20
32
|
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
21
33
|
[ -z "$COMMAND" ] && exit 0
|
|
22
34
|
|