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.
Files changed (1017) hide show
  1. package/.claude-plugin/marketplace.json +72 -19
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CONTRIBUTING.md +7 -2
  4. package/COOKBOOK.md +50 -46
  5. package/LICENSE +21 -0
  6. package/MIGRATION.md +8 -8
  7. package/README.md +421 -512
  8. package/SAFETY_CHECKLIST.md +15 -7
  9. package/SERVICES.md +194 -0
  10. package/SETTINGS_REFERENCE.md +236 -17
  11. package/SKILL.md +5 -5
  12. package/TROUBLESHOOTING.md +35 -14
  13. package/action.yml +12 -4
  14. package/audit/README.md +84 -0
  15. package/audit/audit-checklist.md +152 -0
  16. package/audit/boundary-selftest.sh +85 -0
  17. package/audit/boundary.sh +123 -0
  18. package/audit/count-hooks.py +42 -0
  19. package/audit/find-dead-hooks.sh +82 -0
  20. package/audit/find-unfirable-rules.sh +142 -0
  21. package/audit/fire.sh +97 -0
  22. package/audit/selftest.sh +42 -0
  23. package/audit/unfirable-selftest.sh +81 -0
  24. package/audit-web/index.html +9 -9
  25. package/examples/README.md +54 -17
  26. package/examples/account-billing-log.sh +98 -0
  27. package/examples/account-routing-preflight.sh +123 -0
  28. package/examples/agent-sdk-credit-pool-monitor.sh +145 -0
  29. package/examples/agent-view-quota-decrement.sh +32 -0
  30. package/examples/agent-view-quota-warn.sh +94 -0
  31. package/examples/agents-md-edit-drift-warner.sh +223 -0
  32. package/examples/agents-md-loader.sh +160 -0
  33. package/examples/agents-md-sync-checker.sh +102 -0
  34. package/examples/ai-slop-punctuation-arrest.sh +210 -0
  35. package/examples/allowlist.sh +70 -10
  36. package/examples/always-allow-pattern-suggester.sh +125 -0
  37. package/examples/ansible-vault-guard.sh +2 -1
  38. package/examples/anthropic-base-url-guard.sh +76 -0
  39. package/examples/api-busyloop-guard.sh +123 -0
  40. package/examples/api-endpoint-guard.sh +12 -0
  41. package/examples/api-key-in-url-guard.sh +17 -1
  42. package/examples/api-rate-limit-guard.sh +36 -1
  43. package/examples/api-rate-limit-tracker.sh +12 -0
  44. package/examples/articulated-scope-capture.sh +101 -0
  45. package/examples/askuserquestion-autonomy-gate.sh +102 -0
  46. package/examples/attachment-traversal-guard.sh +118 -0
  47. package/examples/aup-block-pattern-logger.sh +161 -0
  48. package/examples/aup-false-positive-helper.sh +124 -0
  49. package/examples/aup-large-tool-output-warner.sh +282 -0
  50. package/examples/aup-retry-loop-guard.sh +229 -0
  51. package/examples/auth-expiry-reminder.sh +157 -0
  52. package/examples/auth-macos-sleep-detector.sh +185 -0
  53. package/examples/auth-path-detector.sh +171 -0
  54. package/examples/auth-status-checker.sh +157 -0
  55. package/examples/authorized-reconfirmation-detector.sh +195 -0
  56. package/examples/auto-approve-build.sh +39 -0
  57. package/examples/auto-approve-cargo.sh +31 -1
  58. package/examples/auto-approve-docker.sh +35 -0
  59. package/examples/auto-approve-git-read.sh +37 -14
  60. package/examples/auto-approve-go.sh +30 -1
  61. package/examples/auto-approve-gradle.sh +29 -1
  62. package/examples/auto-approve-make.sh +29 -1
  63. package/examples/auto-approve-maven.sh +29 -1
  64. package/examples/auto-approve-python.sh +41 -1
  65. package/examples/auto-approve-readonly-tools.sh +1 -0
  66. package/examples/auto-approve-readonly.sh +110 -33
  67. package/examples/auto-approve-ssh.sh +30 -1
  68. package/examples/auto-approve-test.sh +44 -0
  69. package/examples/auto-checkpoint.sh +1 -1
  70. package/examples/auto-compact-prep.sh +0 -0
  71. package/examples/auto-git-checkpoint.sh +0 -0
  72. package/examples/auto-mode-safe-commands.sh +53 -1
  73. package/examples/auto-mode-safety-enforcer.sh +151 -4
  74. package/examples/auto-push-session-branch.sh +22 -0
  75. package/examples/aws-production-guard.sh +13 -1
  76. package/examples/aws-region-guard.sh +1 -1
  77. package/examples/background-cost-launch-guard.sh +82 -0
  78. package/examples/background-task-guard.sh +12 -0
  79. package/examples/backup-before-refactor.sh +0 -0
  80. package/examples/banned-command-guard.sh +12 -0
  81. package/examples/bash-allowlist-secondary-check.sh +157 -0
  82. package/examples/bash-domain-allowlist.sh +12 -0
  83. package/examples/bash-fanout-bounded-rewriter.sh +191 -0
  84. package/examples/bash-heuristic-approver.sh +112 -10
  85. package/examples/bash-project-fence.sh +194 -0
  86. package/examples/bash-safety-auto-deny.sh +12 -0
  87. package/examples/bash-secret-output-detector.sh +44 -3
  88. package/examples/bash-trace-guard.sh +12 -0
  89. package/examples/bashrc-safety-check.sh +0 -0
  90. package/examples/bg-permission-prompt-warner.sh +182 -0
  91. package/examples/bg-task-cooldown-guard.sh +12 -0
  92. package/examples/binary-read-detector.sh +135 -0
  93. package/examples/binary-upload-guard.sh +12 -0
  94. package/examples/block-database-wipe.sh +35 -10
  95. package/examples/branch-name-check.sh +8 -3
  96. package/examples/branch-naming-convention.sh +0 -0
  97. package/examples/broad-find-guard.sh +12 -0
  98. package/examples/broad-prefix-session-trap-warner.sh +106 -0
  99. package/examples/bulk-file-delete-guard.sh +45 -0
  100. package/examples/bypass-mode-effective-verifier.sh +203 -0
  101. package/examples/cache-creation-drift-detector.sh +120 -0
  102. package/examples/cache-residue-detector.sh +195 -0
  103. package/examples/cache-tier-logger.sh +70 -0
  104. package/examples/cache-ttl-eviction-detector.sh +149 -0
  105. package/examples/cargo-publish-guard.sh +14 -1
  106. package/examples/case-insensitive-path-guard.sh +21 -2
  107. package/examples/case-sensitive-guard.sh +23 -2
  108. package/examples/cch-cache-guard.sh +0 -0
  109. package/examples/cch-sentinel-precommit-guard.sh +47 -0
  110. package/examples/check-abort-controller.sh +1 -1
  111. package/examples/check-accessibility.sh +0 -0
  112. package/examples/check-aria-labels.sh +0 -0
  113. package/examples/check-before-act-enforcer.sh +12 -0
  114. package/examples/check-charset-meta.sh +0 -0
  115. package/examples/check-cookie-flags.sh +0 -0
  116. package/examples/check-cors-config.sh +0 -0
  117. package/examples/check-csp-headers.sh +0 -0
  118. package/examples/check-csrf-protection.sh +0 -0
  119. package/examples/check-debounce.sh +1 -1
  120. package/examples/check-dependency-age.sh +0 -0
  121. package/examples/check-dependency-license.sh +0 -0
  122. package/examples/check-dockerfile-best-practice.sh +0 -0
  123. package/examples/check-error-boundaries.sh +0 -0
  124. package/examples/check-error-class.sh +1 -1
  125. package/examples/check-error-handling.sh +0 -0
  126. package/examples/check-error-logging.sh +1 -1
  127. package/examples/check-error-message.sh +0 -0
  128. package/examples/check-error-stack.sh +0 -0
  129. package/examples/check-favicon.sh +0 -0
  130. package/examples/check-git-hooks-compat.sh +0 -0
  131. package/examples/check-gitattributes.sh +0 -0
  132. package/examples/check-https-redirect.sh +0 -0
  133. package/examples/check-input-validation.sh +0 -0
  134. package/examples/check-lang-attribute.sh +0 -0
  135. package/examples/check-npm-scripts-exist.sh +0 -0
  136. package/examples/check-package-size.sh +0 -0
  137. package/examples/check-port-availability.sh +0 -0
  138. package/examples/check-promise-all.sh +1 -1
  139. package/examples/check-rate-limiting.sh +0 -0
  140. package/examples/check-return-types.sh +0 -0
  141. package/examples/check-semantic-versioning.sh +0 -0
  142. package/examples/check-suspense-fallback.sh +1 -1
  143. package/examples/check-test-exists.sh +0 -0
  144. package/examples/check-test-naming.sh +0 -0
  145. package/examples/check-timeout-cleanup.sh +1 -1
  146. package/examples/check-tls-version.sh +0 -0
  147. package/examples/check-unsubscribe.sh +1 -1
  148. package/examples/check-viewport-meta.sh +0 -0
  149. package/examples/check-worker-terminate.sh +1 -1
  150. package/examples/checkpoint-tamper-guard.sh +12 -0
  151. package/examples/chmod-guard.sh +12 -0
  152. package/examples/chown-guard.sh +24 -0
  153. package/examples/ci-workflow-guard.sh +6 -1
  154. package/examples/claim-verify-detector.sh +109 -0
  155. package/examples/claim-vs-caveat-checker.sh +77 -0
  156. package/examples/classifier-fallback-allow.sh +114 -40
  157. package/examples/claude-cache-gc.sh +1 -0
  158. package/examples/claude-code-version-pin-advisor.sh +183 -0
  159. package/examples/claude-md-reinjector.sh +129 -0
  160. package/examples/claude-md-size-monitor.sh +66 -0
  161. package/examples/claude-update-budget-guard.sh +123 -0
  162. package/examples/claude-update-smart.sh +113 -0
  163. package/examples/claudeignore-enforce-guard.sh +12 -0
  164. package/examples/claudemd-enforcer.sh +0 -0
  165. package/examples/claudemd-tool-prohibition.sh +128 -0
  166. package/examples/clear-command-confirm-guard.sh +32 -15
  167. package/examples/cli-config-pinning-detector.sh +162 -0
  168. package/examples/cliff-countdown-advisor.sh +96 -0
  169. package/examples/clipboard-secret-guard.sh +12 -0
  170. package/examples/closure-word-verify-gate.sh +150 -0
  171. package/examples/cloud-cli-guard.sh +39 -2
  172. package/examples/commit-all-scope-guard.sh +44 -0
  173. package/examples/commit-message-check.sh +1 -1
  174. package/examples/commit-message-quality.sh +6 -1
  175. package/examples/commitment-carry-forward-arrest.sh +361 -0
  176. package/examples/compact-alert-notification.sh +0 -0
  177. package/examples/compact-dispatch-watchdog.sh +149 -0
  178. package/examples/completion-claim-without-verification-detector.sh +207 -0
  179. package/examples/composer-guard.sh +12 -0
  180. package/examples/compound-bash-permission-resolver.sh +156 -0
  181. package/examples/compound-command-allow.sh +1 -1
  182. package/examples/compound-command-deny-enforcer.sh +183 -0
  183. package/examples/compound-inject-guard.sh +12 -0
  184. package/examples/concurrent-edit-lock.sh +12 -0
  185. package/examples/conflict-marker-guard.sh +12 -0
  186. package/examples/consecutive-error-breaker.sh +0 -0
  187. package/examples/console-log-count.sh +1 -0
  188. package/examples/context-compact-advisor.sh +29 -2
  189. package/examples/context-length-budget.sh +69 -0
  190. package/examples/context-threshold-alert.sh +12 -0
  191. package/examples/context-usage-drift-alert.sh +41 -13
  192. package/examples/conversation-history-guard.sh +12 -0
  193. package/examples/core-file-protect-guard.sh +12 -0
  194. package/examples/cors-star-warn.sh +0 -0
  195. package/examples/cost-incident-self-audit.sh +162 -0
  196. package/examples/cowork-claude-md-load-checker.sh +100 -0
  197. package/examples/cowork-fuse-staleness-watcher.sh +140 -0
  198. package/examples/cowork-hook-absence-warner.sh +167 -0
  199. package/examples/cowork-model-picker-advisor.sh +115 -0
  200. package/examples/credential-exfil-guard.sh +65 -4
  201. package/examples/credential-file-cat-guard.sh +17 -1
  202. package/examples/cron-create-receipt.sh +112 -0
  203. package/examples/cron-modification-guard.sh +12 -0
  204. package/examples/cross-product-mcp-spawn-detector.sh +178 -0
  205. package/examples/cwd-project-boundary-guard.sh +0 -0
  206. package/examples/daemon-zombie-worker-surfacer.sh +118 -0
  207. package/examples/daily-cost-guard.sh +164 -0
  208. package/examples/daily-usage-tracker.sh +0 -0
  209. package/examples/dangerous-pip-flag-guard.sh +12 -0
  210. package/examples/db-connect-guard.sh +13 -1
  211. package/examples/denied-action-retry-guard.sh +12 -0
  212. package/examples/deny-bypass-detector.sh +12 -0
  213. package/examples/deny-rule-integrity-verifier.sh +181 -0
  214. package/examples/dependency-install-guard.sh +12 -0
  215. package/examples/deploy-guard.sh +14 -2
  216. package/examples/deploy-path-verify-guard.sh +12 -0
  217. package/examples/deployment-readback-gate.sh +135 -0
  218. package/examples/deployment-readback-gh-adapter.sh +247 -0
  219. package/examples/deployment-verify-guard.sh +25 -2
  220. package/examples/destructive-db-script-write-guard.sh +166 -0
  221. package/examples/destructive-migration-write-guard.sh +163 -0
  222. package/examples/diff-size-guard.sh +12 -0
  223. package/examples/disabled-feature-toggle-advisor.sh +88 -0
  224. package/examples/disk-partition-guard.sh +12 -0
  225. package/examples/dispatch-allowlist-preflight.sh +301 -0
  226. package/examples/dispatch-liveness-watchdog.sh +216 -0
  227. package/examples/dispatch-receipt.sh +174 -0
  228. package/examples/django-migrate-guard.sh +12 -0
  229. package/examples/dns-config-guard.sh +12 -0
  230. package/examples/docker-dangerous-guard.sh +12 -0
  231. package/examples/docker-volume-guard.sh +0 -0
  232. package/examples/dockerfile-latest-guard.sh +1 -0
  233. package/examples/dotenv-anthropic-key-billing-guard.sh +99 -0
  234. package/examples/dotenv-commit-guard.sh +12 -0
  235. package/examples/dotenv-read-guard.sh +12 -0
  236. package/examples/dotfile-protection-guard.sh +12 -0
  237. package/examples/dotnet-build-on-edit.sh +1 -1
  238. package/examples/drizzle-migrate-guard.sh +27 -2
  239. package/examples/echo-probe-spam-detector.sh +176 -0
  240. package/examples/edit-counter-test-gate.sh +12 -0
  241. package/examples/edit-error-counter.sh +1 -1
  242. package/examples/edit-guard.sh +12 -0
  243. package/examples/edit-old-string-validator.sh +12 -0
  244. package/examples/edit-quote-ambiguity-guard.sh +97 -0
  245. package/examples/edit-retry-loop-guard.sh +0 -0
  246. package/examples/edit-verify.sh +0 -0
  247. package/examples/env-inline-secret-guard.sh +14 -2
  248. package/examples/env-naming-convention.sh +0 -0
  249. package/examples/env-prod-guard.sh +0 -0
  250. package/examples/env-required-check.sh +0 -0
  251. package/examples/env-source-guard.sh +12 -0
  252. package/examples/env-var-check.sh +24 -1
  253. package/examples/ephemeral-container-detector.sh +147 -0
  254. package/examples/error-memory-guard.sh +12 -0
  255. package/examples/evidence-claim-gate.sh +187 -0
  256. package/examples/exploration-budget-guard.sh +12 -0
  257. package/examples/expo-eject-guard.sh +13 -0
  258. package/examples/extended-thinking-loop-guard.sh +139 -0
  259. package/examples/extended-thinking-resume-warning.sh +119 -0
  260. package/examples/extended-thinking-tool-use-mismatch-detector.sh +212 -0
  261. package/examples/fabricated-command-detector.sh +145 -0
  262. package/examples/false-disk-full-guard.sh +63 -0
  263. package/examples/feature-deprecation-detector.sh +109 -0
  264. package/examples/file-change-tracker.sh +1 -1
  265. package/examples/file-change-undo-tracker.sh +0 -0
  266. package/examples/file-edit-backup.sh +63 -14
  267. package/examples/file-reference-check.sh +0 -0
  268. package/examples/file-size-limit.sh +12 -0
  269. package/examples/financial-operation-guard.sh +12 -0
  270. package/examples/firewall-guard.sh +12 -0
  271. package/examples/fish-shell-wrapper.sh +125 -7
  272. package/examples/five-hundred-milestone.sh +1 -0
  273. package/examples/flask-static-route-guard.sh +89 -0
  274. package/examples/forbidden-response-phrase-detector.sh +161 -0
  275. package/examples/gem-push-guard.sh +13 -0
  276. package/examples/gh-cli-destructive-guard.sh +13 -1
  277. package/examples/git-checkout-safety-guard.sh +12 -0
  278. package/examples/git-checkout-uncommitted-guard.sh +12 -0
  279. package/examples/git-config-guard.sh +12 -0
  280. package/examples/git-crypt-worktree-guard.sh +12 -0
  281. package/examples/git-filter-repo-guard.sh +56 -0
  282. package/examples/git-history-rewrite-guard.sh +12 -0
  283. package/examples/git-hook-bypass-guard.sh +0 -0
  284. package/examples/git-maintenance-guard.sh +83 -0
  285. package/examples/git-merge-conflict-prevent.sh +0 -0
  286. package/examples/git-message-length-check.sh +0 -0
  287. package/examples/git-message-length.sh +0 -0
  288. package/examples/git-operations-require-approval.sh +68 -14
  289. package/examples/git-pack-temp-cleanup-guard.sh +102 -0
  290. package/examples/git-push-blast-radius-guard.sh +218 -0
  291. package/examples/git-remote-guard.sh +24 -3
  292. package/examples/git-rm-orphan-wipe-guard.sh +85 -0
  293. package/examples/git-stash-before-checkout.sh +12 -0
  294. package/examples/git-stash-before-danger.sh +0 -0
  295. package/examples/git-submodule-guard.sh +69 -2
  296. package/examples/git-tag-guard.sh +12 -0
  297. package/examples/github-actions-secret-guard.sh +0 -0
  298. package/examples/gitignore-check.sh +0 -0
  299. package/examples/gitops-drift-guard.sh +12 -0
  300. package/examples/go-mod-tidy-warn.sh +1 -0
  301. package/examples/go-vet-after-edit.sh +12 -0
  302. package/examples/goal-iteration-limit-warner.sh +152 -0
  303. package/examples/grep-nul-false-negative-guard.sh +30 -0
  304. package/examples/growthbook-flag-monitor.sh +257 -0
  305. package/examples/hallucination-url-check.sh +1 -1
  306. package/examples/halt-signal-detector.sh +135 -0
  307. package/examples/handoff-on-clear.sh +65 -0
  308. package/examples/hardcoded-ip-guard.sh +1 -0
  309. package/examples/headless-empty-result-guard.sh +0 -0
  310. package/examples/headless-stop-guard.sh +0 -0
  311. package/examples/helm-install-guard.sh +2 -1
  312. package/examples/home-critical-bash-guard.sh +17 -1
  313. package/examples/hook-debug-wrapper.sh +6 -2
  314. package/examples/hook-permission-fixer.sh +0 -0
  315. package/examples/hook-self-disable-detector.sh +99 -0
  316. package/examples/hook-stdout-sanitizer.sh +6 -2
  317. package/examples/hook-tamper-guard.sh +12 -0
  318. package/examples/idle-session-cost-alert.sh +0 -0
  319. package/examples/image-dimension-guard.sh +109 -0
  320. package/examples/image-file-validator.sh +0 -0
  321. package/examples/iteration-quality-degradation-detector.sh +170 -0
  322. package/examples/java-compile-on-edit.sh +1 -1
  323. package/examples/json-syntax-check.sh +0 -0
  324. package/examples/k8s-production-guard.sh +13 -1
  325. package/examples/kill-process-guard.sh +12 -0
  326. package/examples/kubernetes-guard.sh +13 -1
  327. package/examples/laravel-artisan-guard.sh +13 -0
  328. package/examples/large-file-guard.sh +1 -1
  329. package/examples/log-level-guard.sh +0 -0
  330. package/examples/log-truncation-guard.sh +12 -0
  331. package/examples/long-session-malformed-tool-call-detector.sh +183 -0
  332. package/examples/loop-detector.sh +12 -0
  333. package/examples/magic-number-warn.sh +1 -0
  334. package/examples/main-branch-warn.sh +12 -0
  335. package/examples/markdown-link-check.sh +0 -0
  336. package/examples/max-concurrent-agents.sh +12 -0
  337. package/examples/max-edit-size-guard.sh +13 -0
  338. package/examples/max-file-count-guard.sh +0 -0
  339. package/examples/max-file-delete-count.sh +0 -0
  340. package/examples/max-function-length.sh +1 -0
  341. package/examples/max-import-count.sh +0 -0
  342. package/examples/max-subagent-count.sh +0 -0
  343. package/examples/mcp-config-freeze.sh +12 -0
  344. package/examples/mcp-config-poisoning-audit.sh +150 -0
  345. package/examples/mcp-data-boundary.sh +1 -1
  346. package/examples/mcp-misdiagnosis-arrest.sh +209 -0
  347. package/examples/mcp-orphan-leak-warner.sh +49 -0
  348. package/examples/mcp-permissions-ask-warner.sh +151 -0
  349. package/examples/mcp-routine-approval-detector.sh +154 -0
  350. package/examples/mcp-server-allowlist.sh +12 -0
  351. package/examples/mcp-server-guard.sh +12 -0
  352. package/examples/mcp-startup-bloat-detector.sh +87 -0
  353. package/examples/mcp-stdio-compatibility-test.sh +153 -0
  354. package/examples/mcp-tool-audit-log.sh +0 -0
  355. package/examples/mcp-tool-guard.sh +101 -1
  356. package/examples/mcp-warmup-wait.sh +0 -0
  357. package/examples/memory-chain-audit.sh +56 -0
  358. package/examples/memory-orphan-detector.sh +188 -0
  359. package/examples/memory-write-guard.sh +99 -17
  360. package/examples/migration-verify-guard.sh +12 -0
  361. package/examples/model-swap-suggester.sh +177 -0
  362. package/examples/model-version-alert.sh +5 -1
  363. package/examples/model-version-lock.sh +63 -0
  364. package/examples/move-delete-sequence-guard.sh +33 -2
  365. package/examples/multi-file-plan-routing-gate.sh +192 -0
  366. package/examples/multi-vendor-concurrent-warner.sh +108 -0
  367. package/examples/multi-window-auth-drift-detector.sh +183 -0
  368. package/examples/multiline-command-approver.sh +161 -23
  369. package/examples/nested-background-agent-guard.sh +109 -0
  370. package/examples/nested-spawn-inflight-guard.sh +178 -0
  371. package/examples/network-exfil-guard.sh +12 -0
  372. package/examples/network-guard.sh +12 -0
  373. package/examples/network-interface-guard.sh +12 -0
  374. package/examples/nextjs-env-guard.sh +1 -1
  375. package/examples/no-absolute-import.sh +0 -0
  376. package/examples/no-alert-confirm-prompt.sh +0 -0
  377. package/examples/no-anonymous-default-export.sh +0 -0
  378. package/examples/no-any-type.sh +0 -0
  379. package/examples/no-any-typescript.sh +1 -0
  380. package/examples/no-ask-human.sh +12 -0
  381. package/examples/no-assignment-in-condition.sh +0 -0
  382. package/examples/no-base64-exfil.sh +12 -0
  383. package/examples/no-callback-hell.sh +0 -0
  384. package/examples/no-circular-dependency.sh +0 -0
  385. package/examples/no-cleartext-storage.sh +0 -0
  386. package/examples/no-commented-code.sh +0 -0
  387. package/examples/no-commit-fixup.sh +0 -0
  388. package/examples/no-console-assert.sh +0 -0
  389. package/examples/no-console-error-swallow.sh +0 -0
  390. package/examples/no-console-in-prod.sh +0 -0
  391. package/examples/no-console-log-commit.sh +12 -0
  392. package/examples/no-console-log.sh +0 -0
  393. package/examples/no-console-time.sh +0 -0
  394. package/examples/no-cors-wildcard.sh +4 -1
  395. package/examples/no-curl-upload.sh +0 -0
  396. package/examples/no-dangerouslySetInnerHTML.sh +0 -0
  397. package/examples/no-dangling-await.sh +1 -0
  398. package/examples/no-debug-commit.sh +12 -0
  399. package/examples/no-debug-in-commit.sh +0 -0
  400. package/examples/no-deep-nesting.sh +0 -0
  401. package/examples/no-deep-relative-import.sh +1 -0
  402. package/examples/no-default-credentials.sh +0 -0
  403. package/examples/no-deploy-friday.sh +13 -1
  404. package/examples/no-disabled-test.sh +0 -0
  405. package/examples/no-document-write.sh +0 -0
  406. package/examples/no-empty-function.sh +0 -0
  407. package/examples/no-eval-in-template.sh +0 -0
  408. package/examples/no-eval-template.sh +3 -1
  409. package/examples/no-eval.sh +0 -0
  410. package/examples/no-exec-user-input.sh +0 -0
  411. package/examples/no-fixme-ship.sh +12 -0
  412. package/examples/no-floating-promises.sh +0 -0
  413. package/examples/no-force-flag.sh +22 -5
  414. package/examples/no-force-install.sh +0 -0
  415. package/examples/no-git-amend.sh +12 -0
  416. package/examples/no-git-rebase-public.sh +0 -0
  417. package/examples/no-global-install.sh +12 -0
  418. package/examples/no-global-state.sh +0 -0
  419. package/examples/no-hardcoded-port.sh +1 -0
  420. package/examples/no-hardcoded-url.sh +0 -0
  421. package/examples/no-helmet-missing.sh +0 -0
  422. package/examples/no-http-url.sh +1 -0
  423. package/examples/no-http-without-https.sh +0 -0
  424. package/examples/no-inline-style.sh +0 -0
  425. package/examples/no-inline-styles.sh +1 -0
  426. package/examples/no-innerhtml.sh +0 -0
  427. package/examples/no-install-global.sh +12 -0
  428. package/examples/no-jwt-in-url.sh +0 -0
  429. package/examples/no-large-commit.sh +0 -0
  430. package/examples/no-localhost-expose.sh +0 -0
  431. package/examples/no-magic-number.sh +0 -0
  432. package/examples/no-md5-sha1.sh +0 -0
  433. package/examples/no-mixed-line-endings.sh +8 -1
  434. package/examples/no-mutation-in-reducer.sh +0 -0
  435. package/examples/no-nested-ternary.sh +0 -0
  436. package/examples/no-network-exfil.sh +0 -0
  437. package/examples/no-open-redirect.sh +0 -0
  438. package/examples/no-output-truncation.sh +12 -0
  439. package/examples/no-package-downgrade.sh +0 -0
  440. package/examples/no-package-lock-edit.sh +12 -0
  441. package/examples/no-path-join-user-input.sh +0 -0
  442. package/examples/no-port-bind.sh +0 -0
  443. package/examples/no-process-exit.sh +0 -0
  444. package/examples/no-prototype-pollution.sh +0 -0
  445. package/examples/no-push-without-ci.sh +0 -0
  446. package/examples/no-push-without-tests.sh +12 -0
  447. package/examples/no-raw-password-in-url.sh +0 -0
  448. package/examples/no-root-user-docker.sh +1 -0
  449. package/examples/no-root-write.sh +12 -0
  450. package/examples/no-secrets-in-args.sh +4 -1
  451. package/examples/no-secrets-in-logs.sh +0 -0
  452. package/examples/no-sensitive-log.sh +0 -0
  453. package/examples/no-sleep-in-hooks.sh +0 -0
  454. package/examples/no-star-import-python.sh +1 -0
  455. package/examples/no-string-concat-sql.sh +0 -0
  456. package/examples/no-sudo-guard.sh +12 -0
  457. package/examples/no-sync-fs.sh +0 -0
  458. package/examples/no-todo-in-merge.sh +0 -0
  459. package/examples/no-todo-in-production.sh +1 -0
  460. package/examples/no-todo-without-issue.sh +0 -0
  461. package/examples/no-unused-import.sh +0 -0
  462. package/examples/no-var-keyword.sh +0 -0
  463. package/examples/no-verify-blocker.sh +12 -0
  464. package/examples/no-wget-piped-bash.sh +12 -0
  465. package/examples/no-wildcard-cors.sh +0 -0
  466. package/examples/no-wildcard-delete.sh +0 -0
  467. package/examples/no-wildcard-import.sh +0 -0
  468. package/examples/no-with-statement.sh +0 -0
  469. package/examples/no-write-outside-src.sh +0 -0
  470. package/examples/no-xml-external-entity.sh +0 -0
  471. package/examples/non-english-quality-warner.sh +156 -0
  472. package/examples/notify-waiting.sh +1 -1
  473. package/examples/npm-audit-warn.sh +0 -0
  474. package/examples/npm-global-install-guard.sh +12 -0
  475. package/examples/npm-publish-guard.sh +12 -0
  476. package/examples/npm-script-injection.sh +0 -0
  477. package/examples/npm-supply-chain-guard.sh +0 -0
  478. package/examples/nuxt-config-guard.sh +1 -0
  479. package/examples/oauth-refresh-monitor.sh +210 -0
  480. package/examples/opus-degradation-tracker.sh +187 -0
  481. package/examples/opus48-routine-task-warning.sh +196 -0
  482. package/examples/opus48-thinking-wedge-advisor.sh +143 -0
  483. package/examples/output-credential-scan.sh +1 -1
  484. package/examples/output-secret-mask.sh +31 -9
  485. package/examples/output-token-spike-detector.sh +145 -0
  486. package/examples/package-json-guard.sh +12 -0
  487. package/examples/package-lock-frozen.sh +12 -0
  488. package/examples/parallel-batch-size-limiter.sh +121 -0
  489. package/examples/parallel-cascade-detector.sh +116 -0
  490. package/examples/partial-view-claim-arrest.sh +174 -0
  491. package/examples/path-deny-bash-guard.sh +12 -0
  492. package/examples/path-traversal-guard.sh +12 -0
  493. package/examples/per-prompt-token-cap.sh +124 -0
  494. package/examples/permission-audit-log.sh +1 -1
  495. package/examples/permission-denial-enforcer.sh +12 -0
  496. package/examples/permission-entry-validator.sh +0 -0
  497. package/examples/persisted-1m-model-advisor.sh +88 -0
  498. package/examples/php-lint-on-edit.sh +1 -1
  499. package/examples/pii-upload-guard.sh +12 -0
  500. package/examples/pip-publish-guard.sh +13 -0
  501. package/examples/pip-requirements-guard.sh +12 -0
  502. package/examples/pip-venv-required.sh +12 -0
  503. package/examples/plan-mode-edit-guard.sh +12 -0
  504. package/examples/plan-mode-enforcer.sh +12 -0
  505. package/examples/plan-mode-strict-guard.sh +12 -0
  506. package/examples/plugin-hooks-json-bloat-detector.sh +169 -0
  507. package/examples/plugin-process-cleanup.sh +0 -0
  508. package/examples/polyglot-rm-guard.sh +12 -0
  509. package/examples/post-compact-safety.sh +12 -0
  510. package/examples/post-edit-disk-verify.sh +152 -0
  511. package/examples/powershell-remove-item-guard.sh +85 -0
  512. package/examples/pr-description-check.sh +0 -0
  513. package/examples/pr-duplicate-guard.sh +13 -0
  514. package/examples/pre-bash-sed-line-ending-windows.sh +87 -0
  515. package/examples/pre-compact-knowledge-save.sh +0 -0
  516. package/examples/pre-compact-transcript-backup.sh +0 -0
  517. package/examples/pre-execution-claim-detector.sh +179 -0
  518. package/examples/prefer-builtin-tools.sh +10 -1
  519. package/examples/prefer-const.sh +0 -0
  520. package/examples/prefer-dedicated-tools.sh +12 -0
  521. package/examples/prefer-optional-chaining.sh +0 -0
  522. package/examples/prisma-migrate-guard.sh +24 -7
  523. package/examples/production-port-kill-guard.sh +12 -0
  524. package/examples/prompt-injection-guard.sh +2 -1
  525. package/examples/prompt-usage-logger.sh +0 -0
  526. package/examples/protect-claudemd.sh +12 -0
  527. package/examples/protect-dotfiles.sh +12 -0
  528. package/examples/proxy-capture-suggester.sh +159 -0
  529. package/examples/public-artefact-socratic-narrowing.sh +232 -0
  530. package/examples/public-repo-push-guard.sh +12 -0
  531. package/examples/push-requires-test-pass-record.sh +0 -0
  532. package/examples/push-requires-test-pass.sh +12 -0
  533. package/examples/quota-anomaly-detector.sh +173 -0
  534. package/examples/quota-reset-audit.sh +58 -0
  535. package/examples/quoted-flag-approver.sh +99 -10
  536. package/examples/rails-migration-guard.sh +12 -0
  537. package/examples/rate-limit-guard.sh +0 -0
  538. package/examples/read-all-files-enforcer.sh +0 -0
  539. package/examples/read-budget-guard.sh +12 -0
  540. package/examples/read-loop-detector.sh +59 -0
  541. package/examples/read-once-guard.sh +96 -0
  542. package/examples/read-only-mode.sh +12 -0
  543. package/examples/readme-exists-check.sh +0 -0
  544. package/examples/record-read-coverage.sh +73 -0
  545. package/examples/redirect-fragment-warner.sh +149 -0
  546. package/examples/redis-flushall-guard.sh +13 -0
  547. package/examples/redundant-read-blocker.sh +132 -0
  548. package/examples/refusal-arrest-gate.sh +248 -0
  549. package/examples/registry-publish-guard.sh +13 -1
  550. package/examples/remote-control-billing-classifier.sh +135 -0
  551. package/examples/replace-all-guard.sh +12 -0
  552. package/examples/repo-visibility-guard.sh +12 -0
  553. package/examples/reroute-after-block-guard.sh +150 -0
  554. package/examples/response-budget-guard.sh +0 -0
  555. package/examples/resume-drift-watcher.sh +57 -0
  556. package/examples/rg-replace-flag-detector.sh +125 -0
  557. package/examples/rhetorical-verification-prompt-detector.sh +102 -0
  558. package/examples/ripgrep-permission-fix.sh +0 -0
  559. package/examples/rm-safety-net.sh +151 -8
  560. package/examples/role-tool-guard.sh +12 -0
  561. package/examples/route-handler-emptiness-gate.sh +324 -0
  562. package/examples/ruby-lint-on-edit.sh +1 -1
  563. package/examples/runtime-binary-change-detector.sh +102 -0
  564. package/examples/same-command-repeat-detector.sh +196 -0
  565. package/examples/same-correction-arrest.sh +169 -0
  566. package/examples/sandbox-denywrite-enforcer.sh +78 -0
  567. package/examples/sandbox-relative-path-audit.sh +83 -25
  568. package/examples/sandbox-write-verify.sh +12 -0
  569. package/examples/schema-migration-guard.sh +0 -0
  570. package/examples/scope-expansion-receipt.sh +178 -0
  571. package/examples/scope-guard.sh +88 -9
  572. package/examples/secret-file-read-guard.sh +12 -0
  573. package/examples/secret-file-write-guard.sh +150 -0
  574. package/examples/self-modify-bypass-guard.sh +0 -0
  575. package/examples/sensitive-file-read-guard.sh +23 -3
  576. package/examples/sensitive-log-guard.sh +1 -0
  577. package/examples/server-side-prompt-injection-detector.sh +69 -0
  578. package/examples/session-agent-cost-limiter.sh +12 -0
  579. package/examples/session-backup-on-start.sh +1 -1
  580. package/examples/session-cost-alert.sh +12 -0
  581. package/examples/session-drift-guard.sh +12 -0
  582. package/examples/session-duration-guard.sh +25 -2
  583. package/examples/session-end-logger.sh +0 -0
  584. package/examples/session-health-monitor.sh +0 -0
  585. package/examples/session-index-repair.sh +1 -1
  586. package/examples/session-memory-watchdog.sh +1 -0
  587. package/examples/session-permission-reset-guard.sh +12 -0
  588. package/examples/session-persistence-verifier.sh +93 -0
  589. package/examples/session-plugin-pin-watch.sh +68 -0
  590. package/examples/session-rate-monitor.sh +176 -0
  591. package/examples/session-resume-env-fix.sh +0 -0
  592. package/examples/session-start-quota-status.sh +193 -0
  593. package/examples/session-start-safety-check.sh +55 -3
  594. package/examples/session-state-saver.sh +0 -0
  595. package/examples/session-summary-stop.sh +1 -1
  596. package/examples/session-summary.sh +0 -0
  597. package/examples/session-token-counter.sh +1 -1
  598. package/examples/settings-hooks-key-restorer.sh +99 -0
  599. package/examples/settings-json-health-check.sh +57 -0
  600. package/examples/settings-json-model-guard.sh +0 -0
  601. package/examples/settings-regression-tester.sh +188 -0
  602. package/examples/shell-config-truncation-guard.sh +12 -0
  603. package/examples/shell-wrapper-guard.sh +12 -0
  604. package/examples/skill-cumulative-size-detector.sh +104 -0
  605. package/examples/skill-description-drop-detector.sh +148 -0
  606. package/examples/skill-gate.sh +0 -0
  607. package/examples/skill-truncation-detector.sh +154 -0
  608. package/examples/skills-context-recorder.sh +167 -0
  609. package/examples/skills-load-verifier.sh +96 -0
  610. package/examples/skills-settings-validator.sh +139 -0
  611. package/examples/sonnet-45-deprecation-helper.sh +85 -0
  612. package/examples/spec-file-scope-guard.sh +12 -0
  613. package/examples/spring-profile-guard.sh +1 -0
  614. package/examples/spurious-malformed-notice-detector.sh +247 -0
  615. package/examples/sql-bulk-delete-warn.sh +88 -0
  616. package/examples/sql-injection-detect.sh +0 -0
  617. package/examples/ssh-key-protect.sh +12 -0
  618. package/examples/staged-secret-scan.sh +22 -1
  619. package/examples/stale-temp-settings-detector.sh +86 -0
  620. package/examples/standing-rule-session-surfacer.sh +137 -0
  621. package/examples/stop-hook-sigterm-wrapper.sh +182 -0
  622. package/examples/stop-transcript-write-health.sh +64 -0
  623. package/examples/strict-allowlist.sh +57 -15
  624. package/examples/strip-coauthored-by.sh +50 -10
  625. package/examples/subagent-blast-radius-guard.sh +184 -0
  626. package/examples/subagent-boundary-precheck.sh +126 -0
  627. package/examples/subagent-budget-guard.sh +12 -0
  628. package/examples/subagent-claudemd-inject.sh +0 -0
  629. package/examples/subagent-closure-verify-gate.sh +164 -0
  630. package/examples/subagent-destructive-git-guard.sh +120 -0
  631. package/examples/subagent-error-detector.sh +0 -0
  632. package/examples/subagent-forged-system-reminder-guard.sh +156 -0
  633. package/examples/subagent-identity-leak-guard.sh +102 -0
  634. package/examples/subagent-identity-reassertion.sh +51 -0
  635. package/examples/subagent-inheritance-tester.sh +179 -0
  636. package/examples/subagent-permission-mode-guard.sh +110 -0
  637. package/examples/subagent-scope-guard.sh +12 -0
  638. package/examples/subagent-spawn-verification-enforcer.sh +102 -0
  639. package/examples/subagent-tool-allowlist-enforcer.sh +101 -0
  640. package/examples/subagent-tool-call-limiter.sh +87 -15
  641. package/examples/subcommand-chain-guard.sh +12 -0
  642. package/examples/subscription-api-billing-warner.sh +160 -0
  643. package/examples/subscription-bypass-detector.sh +152 -0
  644. package/examples/svelte-lint-on-edit.sh +1 -0
  645. package/examples/swift-build-on-edit.sh +1 -1
  646. package/examples/symlink-guard.sh +27 -2
  647. package/examples/symlink-protect.sh +1 -0
  648. package/examples/system-dir-protection-guard.sh +73 -8
  649. package/examples/system-message-workaround.sh +38 -13
  650. package/examples/system-package-guard.sh +12 -0
  651. package/examples/systemd-service-guard.sh +12 -0
  652. package/examples/task-integrity-guard.sh +12 -0
  653. package/examples/temp-file-cleanup.sh +1 -1
  654. package/examples/temporal-suggestion-detector.sh +135 -0
  655. package/examples/terraform-guard.sh +27 -6
  656. package/examples/test-after-edit.sh +1 -1
  657. package/examples/test-before-push.sh +12 -0
  658. package/examples/test-coverage-reminder.sh +24 -1
  659. package/examples/thinking-budget-effort-mismatch-detector.sh +149 -0
  660. package/examples/timezone-guard.sh +0 -0
  661. package/examples/tmp-output-size-guard.sh +0 -0
  662. package/examples/todo-check.sh +1 -1
  663. package/examples/token-budget-guard.sh +12 -0
  664. package/examples/token-budget-per-task.sh +12 -0
  665. package/examples/token-usage-tracker.sh +7 -1
  666. package/examples/tokenizer-ratio-alert-corpus.sh +90 -0
  667. package/examples/tokenizer-ratio-alert.sh +104 -0
  668. package/examples/tool-call-rate-limiter.sh +0 -0
  669. package/examples/tool-result-correlation-checker.sh +167 -0
  670. package/examples/tool-result-size-guard.sh +132 -0
  671. package/examples/tool-retry-budget-guard.sh +12 -0
  672. package/examples/transcript-contamination-detector.sh +138 -0
  673. package/examples/trustfall-mcp-injection-guard.sh +103 -0
  674. package/examples/ultrareview-large-diff-advisor.sh +184 -0
  675. package/examples/unbounded-output-guard.sh +94 -0
  676. package/examples/uncommitted-changes-stop.sh +1 -0
  677. package/examples/uncommitted-discard-guard.sh +23 -5
  678. package/examples/uncommitted-work-guard.sh +12 -0
  679. package/examples/usage-warn.sh +0 -0
  680. package/examples/user-account-guard.sh +12 -0
  681. package/examples/userprompt-submit-receipt.sh +123 -0
  682. package/examples/variable-expansion-guard.sh +12 -0
  683. package/examples/verify-after-publish-reminder.sh +93 -0
  684. package/examples/verify-before-commit.sh +12 -0
  685. package/examples/version-bump-detector.sh +156 -0
  686. package/examples/version-regression-warner.sh +144 -0
  687. package/examples/vue-lint-on-edit.sh +1 -0
  688. package/examples/warn-cron-cost-trap.sh +173 -0
  689. package/examples/webfetch-runaway-guard.sh +89 -0
  690. package/examples/wellness-break-reminder.sh +118 -0
  691. package/examples/windows-destructive-command-guard.sh +177 -0
  692. package/examples/windows-path-guard.sh +12 -0
  693. package/examples/windows-python-stub-detector.sh +63 -0
  694. package/examples/work-hours-guard.sh +12 -0
  695. package/examples/working-directory-fence.sh +12 -0
  696. package/examples/workspace-lease-guard.sh +205 -0
  697. package/examples/worktree-create-log.sh +1 -0
  698. package/examples/worktree-delete-guard.sh +12 -0
  699. package/examples/worktree-edit-boundary-guard.sh +127 -0
  700. package/examples/worktree-escape-write-guard.sh +114 -0
  701. package/examples/worktree-hook-linker.sh +0 -0
  702. package/examples/worktree-hooks-path-fix.sh +111 -0
  703. package/examples/worktree-parent-write-guard.sh +43 -0
  704. package/examples/worktree-project-unify.sh +2 -1
  705. package/examples/worktree-remove-uncommitted-guard.sh +13 -0
  706. package/examples/worktree-unmerged-guard.sh +7 -1
  707. package/examples/write-byte-integrity-verifier.sh +190 -0
  708. package/examples/write-empty-content-guard.sh +67 -0
  709. package/examples/write-nul-corruption-detector.sh +61 -0
  710. package/examples/write-overwrite-confirm.sh +160 -14
  711. package/examples/write-secret-guard.sh +27 -5
  712. package/examples/write-shrink-guard.sh +12 -0
  713. package/examples/write-test-ratio.sh +0 -0
  714. package/examples/wsl-host-disk-space-guard.sh +97 -0
  715. package/examples/xml-format-leak-detector.sh +266 -0
  716. package/examples/yaml-syntax-check.sh +12 -0
  717. package/hooks/hooks.json +6 -6
  718. package/index.mjs +1718 -183
  719. package/mission.md +2 -0
  720. package/package.json +4 -4
  721. package/plugins/credential-guard/.claude-plugin/plugin.json +9 -7
  722. package/plugins/git-protection/.claude-plugin/plugin.json +10 -8
  723. package/plugins/safety-essentials/.claude-plugin/plugin.json +9 -7
  724. package/plugins/token-guard/.claude-plugin/plugin.json +10 -8
  725. package/scripts/agents-md-sync-setup.sh +156 -0
  726. package/scripts/autonomy-blocked-summary.sh +148 -0
  727. package/scripts/build-search-index.py +43 -0
  728. package/scripts/build-sitemap.py +119 -0
  729. package/scripts/cc-doctor.sh +192 -0
  730. package/scripts/check-hook-event-names.py +127 -0
  731. package/scripts/check-misfire-instrument.sh +64 -0
  732. package/scripts/claim-verify-audit.sh +467 -0
  733. package/scripts/cowork-claudemd-helper.sh +136 -0
  734. package/scripts/june-15-deprecated-model-scan.sh +111 -0
  735. package/scripts/measure-heredoc-shapes.sh +67 -0
  736. package/scripts/measure-literal-match-misfire.sh +110 -0
  737. package/scripts/probe-scope-guard-branches.sh +48 -0
  738. package/scripts/probe-skip-line-both-ways.sh +65 -0
  739. package/scripts/receipts-aggregate.py +199 -0
  740. package/scripts/session-forensic-audit.py +360 -0
  741. package/scripts.json +9 -9
  742. package/scripts.json.bak-2026-07-27-find +13 -0
  743. package/skills/safety-setup/SKILL.md +5 -5
  744. package/tests/approve-side-remaining-two.test.sh +129 -0
  745. package/tests/approver-list-granularity.test.sh +145 -0
  746. package/tests/askuserquestion-autonomy-gate.test.sh +181 -0
  747. package/tests/audit-ci-gate.test.sh +87 -0
  748. package/tests/audit-cross-layer-claudemd.test.sh +170 -0
  749. package/tests/audit-fail-open-parse.test.sh +100 -0
  750. package/tests/auto-approve-compound-tail.test.sh +194 -0
  751. package/tests/auto-mode-path-invoked-commands.test.sh +89 -0
  752. package/tests/auto-mode-quoted-targets.test.sh +127 -0
  753. package/tests/auto-mode-unquoted-targets.test.sh +112 -0
  754. package/tests/bash-secret-output-detector-detects.test.sh +102 -0
  755. package/tests/blindspots-cross-layer.test.sh +177 -0
  756. package/tests/block-database-wipe.test.sh +64 -0
  757. package/tests/bundled-short-flags-bypass.test.sh +85 -0
  758. package/tests/cd-git-allow-compound-tail.test.sh +67 -0
  759. package/tests/chown-guard-filesystem-root.test.sh +64 -0
  760. package/tests/ci-workflow-guard-skip-rule.test.sh +115 -0
  761. package/tests/compound-deny-safe-rm-targets.test.sh +105 -0
  762. package/tests/core-scripts-parser-fallback.test.sh +140 -0
  763. package/tests/destructive-guard-bare-glob.test.sh +74 -0
  764. package/tests/destructive-guard-every-operand.test.sh +100 -0
  765. package/tests/destructive-guard-find-deletion.test.sh +114 -0
  766. package/tests/destructive-guard-flag-order.test.sh +106 -0
  767. package/tests/destructive-guard-mentions-vs-invocations.test.sh +107 -0
  768. package/tests/destructive-guard-quoted-target.test.sh +89 -0
  769. package/tests/destructive-guard-separators.test.sh +105 -0
  770. package/tests/destructive-guard-variable-target.test.sh +98 -0
  771. package/tests/destructive-guard-wrapped-command.test.sh +91 -0
  772. package/tests/doctor-hook-disabling-env.test.sh +92 -0
  773. package/tests/doctor-misspelled-settings-keys.test.sh +106 -0
  774. package/tests/example-guards-wrapped-command.test.sh +169 -0
  775. package/tests/file-edit-backup.test.sh +93 -0
  776. package/tests/git-filter-repo-guard.test.sh +60 -0
  777. package/tests/git-global-options-bypass.test.sh +141 -0
  778. package/tests/git-invocation-prefixes-all-guards.test.sh +114 -0
  779. package/tests/git-maintenance-guard.test.sh +83 -0
  780. package/tests/git-pack-temp-cleanup-guard.test.sh +133 -0
  781. package/tests/git-rm-orphan-wipe-guard.test.sh +66 -0
  782. package/tests/git-submodule-guard.test.sh +50 -0
  783. package/tests/grep-pcre-portability.test.sh +155 -0
  784. package/tests/hook-registration-matches-input.test.sh +73 -0
  785. package/tests/hook-trigger-matches-envelope.test.sh +178 -0
  786. package/tests/install-does-not-claim-protection.test.sh +110 -0
  787. package/tests/install-example-standalone-tools.test.sh +139 -0
  788. package/tests/line-continuation-bypass.test.sh +114 -0
  789. package/tests/mcp-config-poisoning-audit.test.sh +106 -0
  790. package/tests/nested-background-agent-guard.test.sh +58 -0
  791. package/tests/no-unqualified-safety-claims.test.sh +114 -0
  792. package/tests/option-eating-grep-patterns.test.sh +130 -0
  793. package/tests/outdated-core-guards.test.sh +134 -0
  794. package/tests/outdated-report.test.sh +155 -0
  795. package/tests/output-secret-mask-warns.test.sh +73 -0
  796. package/tests/plugin-hooks-fail-open-under-sh.test.sh +165 -0
  797. package/tests/plugins-word-order.test.sh +126 -0
  798. package/tests/powershell-remove-item-guard.test.sh +85 -0
  799. package/tests/project-dir-naming.test.sh +103 -0
  800. package/tests/quoted-safe-targets-and-mentions.test.sh +190 -0
  801. package/tests/reroute-after-block-guard.test.sh +104 -0
  802. package/tests/secret-guard-documented-promises.test.sh +97 -0
  803. package/tests/session-plugin-pin-watch.test.sh +45 -0
  804. package/tests/settings-unreadable-refuses-to-write.test.sh +95 -0
  805. package/tests/shield-no-silent-adoption.test.py +110 -0
  806. package/tests/shield-no-silent-adoption.test.sh +46 -0
  807. package/tests/stop-transcript-write-health.test.sh +46 -0
  808. package/tests/system-dir-guard-root-erased.test.sh +66 -0
  809. package/tests/test-account-billing-log.sh +100 -0
  810. package/tests/test-account-routing-preflight.sh +77 -0
  811. package/tests/test-agent-sdk-credit-pool-monitor.sh +157 -0
  812. package/tests/test-agent-view-quota-warn.sh +184 -0
  813. package/tests/test-agents-md-edit-drift-warner.sh +176 -0
  814. package/tests/test-agents-md-loader.sh +204 -0
  815. package/tests/test-agents-md-sync-checker.sh +125 -0
  816. package/tests/test-ai-slop-punctuation-arrest.sh +280 -0
  817. package/tests/test-allowlist.sh +60 -0
  818. package/tests/test-always-allow-pattern-suggester.sh +147 -0
  819. package/tests/test-anthropic-base-url-guard.sh +88 -0
  820. package/tests/test-articulated-scope-capture.sh +139 -0
  821. package/tests/test-attachment-traversal-guard.sh +168 -0
  822. package/tests/test-aup-block-pattern-logger.sh +315 -0
  823. package/tests/test-aup-false-positive-helper.sh +188 -0
  824. package/tests/test-aup-large-tool-output-warner.sh +370 -0
  825. package/tests/test-aup-retry-loop-guard.sh +341 -0
  826. package/tests/test-auth-expiry-reminder.sh +303 -0
  827. package/tests/test-auth-macos-sleep-detector.sh +254 -0
  828. package/tests/test-auth-path-detector.sh +232 -0
  829. package/tests/test-auth-status-checker.sh +233 -0
  830. package/tests/test-authorized-reconfirmation-detector.sh +280 -0
  831. package/tests/test-background-cost-launch-guard.sh +62 -0
  832. package/tests/test-bash-allowlist-secondary-check.sh +143 -0
  833. package/tests/test-bash-fanout-bounded-rewriter.sh +186 -0
  834. package/tests/test-bash-project-fence.sh +127 -0
  835. package/tests/test-bg-permission-prompt-warner.sh +221 -0
  836. package/tests/test-binary-read-detector.sh +173 -0
  837. package/tests/test-broad-prefix-session-trap-warner.sh +167 -0
  838. package/tests/test-bulk-delete-target-resolution.sh +49 -0
  839. package/tests/test-bypass-mode-effective-verifier.sh +179 -0
  840. package/tests/test-cache-creation-drift-detector.sh +244 -0
  841. package/tests/test-cache-residue-detector.sh +429 -0
  842. package/tests/test-cache-tier-logger.sh +59 -0
  843. package/tests/test-cache-ttl-eviction-detector.sh +282 -0
  844. package/tests/test-cch-sentinel-precommit-guard.sh +64 -0
  845. package/tests/test-claim-verify-detector.sh +222 -0
  846. package/tests/test-claim-vs-caveat-checker.sh +134 -0
  847. package/tests/test-claude-code-version-pin-advisor.sh +353 -0
  848. package/tests/test-claude-md-reinjector.sh +173 -0
  849. package/tests/test-claude-md-size-monitor.sh +107 -0
  850. package/tests/test-claude-update-budget-guard.sh +132 -0
  851. package/tests/test-claude-update-smart.sh +91 -0
  852. package/tests/test-claudemd-tool-prohibition.sh +239 -0
  853. package/tests/test-cli-config-pinning-detector.sh +233 -0
  854. package/tests/test-cliff-countdown-advisor.sh +138 -0
  855. package/tests/test-closure-word-verify-gate.sh +158 -0
  856. package/tests/test-commit-all-scope-guard.sh +73 -0
  857. package/tests/test-commitment-carry-forward-arrest.sh +250 -0
  858. package/tests/test-compact-dispatch-watchdog.sh +147 -0
  859. package/tests/test-completion-claim-without-verification-detector.sh +326 -0
  860. package/tests/test-compound-bash-permission-resolver.sh +264 -0
  861. package/tests/test-compound-command-deny-enforcer.sh +67 -0
  862. package/tests/test-context-length-budget.sh +68 -0
  863. package/tests/test-context-usage-drift-alert.sh +52 -22
  864. package/tests/test-cost-incident-self-audit.sh +94 -0
  865. package/tests/test-cowork-claude-md-load-checker.sh +257 -0
  866. package/tests/test-cowork-claudemd-helper.sh +141 -0
  867. package/tests/test-cowork-fuse-staleness-watcher.sh +287 -0
  868. package/tests/test-cowork-hook-absence-warner.sh +230 -0
  869. package/tests/test-cowork-model-picker-advisor.sh +317 -0
  870. package/tests/test-credential-exfil-guard.sh +62 -0
  871. package/tests/test-cron-create-receipt.sh +165 -0
  872. package/tests/test-cross-product-mcp-spawn-detector.sh +112 -0
  873. package/tests/test-daemon-zombie-worker-surfacer.sh +71 -0
  874. package/tests/test-daily-cost-guard.sh +131 -0
  875. package/tests/test-deny-rule-integrity-verifier.sh +288 -0
  876. package/tests/test-deployment-readback-gate.sh +92 -0
  877. package/tests/test-deployment-readback-gh-adapter.sh +163 -0
  878. package/tests/test-disabled-feature-toggle-advisor.sh +78 -0
  879. package/tests/test-dispatch-allowlist-preflight.sh +385 -0
  880. package/tests/test-dispatch-liveness-watchdog.sh +319 -0
  881. package/tests/test-dispatch-receipt.sh +314 -0
  882. package/tests/test-dotenv-anthropic-key-billing-guard.sh +160 -0
  883. package/tests/test-echo-probe-spam-detector.sh +143 -0
  884. package/tests/test-edit-quote-ambiguity-guard.sh +75 -0
  885. package/tests/test-ephemeral-container-detector.sh +251 -0
  886. package/tests/test-evidence-claim-gate.sh +291 -0
  887. package/tests/test-extended-thinking-loop-guard.sh +289 -0
  888. package/tests/test-extended-thinking-resume-warning.sh +240 -0
  889. package/tests/test-extended-thinking-tool-use-mismatch-detector.sh +236 -0
  890. package/tests/test-fabricated-command-detector.sh +296 -0
  891. package/tests/test-false-disk-full-guard.sh +36 -0
  892. package/tests/test-feature-deprecation-detector.sh +117 -0
  893. package/tests/test-forbidden-response-phrase-detector.sh +246 -0
  894. package/tests/test-git-operations-require-approval.sh +53 -0
  895. package/tests/test-git-push-blast-radius-guard.sh +115 -0
  896. package/tests/test-goal-iteration-limit-warner.sh +128 -0
  897. package/tests/test-growthbook-flag-monitor.sh +428 -0
  898. package/tests/test-halt-signal-detector.sh +120 -0
  899. package/tests/test-hook-self-disable-detector.sh +232 -0
  900. package/tests/test-iteration-quality-degradation-detector.sh +244 -0
  901. package/tests/test-long-session-malformed-tool-call-detector.sh +185 -0
  902. package/tests/test-marketplace-plugins.sh +193 -0
  903. package/tests/test-mcp-misdiagnosis-arrest.sh +235 -0
  904. package/tests/test-mcp-orphan-leak-warner.sh +71 -0
  905. package/tests/test-mcp-permissions-ask-warner.sh +207 -0
  906. package/tests/test-mcp-routine-approval-detector.sh +229 -0
  907. package/tests/test-mcp-startup-bloat-detector.sh +141 -0
  908. package/tests/test-mcp-stdio-compatibility-test.sh +112 -0
  909. package/tests/test-memory-chain-audit.sh +59 -0
  910. package/tests/test-memory-orphan-detector.sh +227 -0
  911. package/tests/test-model-swap-suggester.sh +368 -0
  912. package/tests/test-model-version-lock.sh +83 -0
  913. package/tests/test-multi-file-plan-routing-gate.sh +277 -0
  914. package/tests/test-multi-window-auth-drift-detector.sh +262 -0
  915. package/tests/test-nested-spawn-inflight-guard.sh +281 -0
  916. package/tests/test-no-force-flag.sh +49 -0
  917. package/tests/test-non-english-quality-warner.sh +229 -0
  918. package/tests/test-oauth-refresh-monitor.sh +311 -0
  919. package/tests/test-opus-degradation-tracker.sh +274 -0
  920. package/tests/test-opus48-routine-task-warning.sh +201 -0
  921. package/tests/test-opus48-thinking-wedge-advisor.sh +249 -0
  922. package/tests/test-output-token-spike-detector.sh +315 -0
  923. package/tests/test-parallel-batch-size-limiter.sh +228 -0
  924. package/tests/test-parallel-cascade-detector.sh +191 -0
  925. package/tests/test-partial-view-claim-arrest.sh +272 -0
  926. package/tests/test-per-prompt-token-cap.sh +136 -0
  927. package/tests/test-persisted-1m-model-advisor.sh +71 -0
  928. package/tests/test-plugin-hooks-json-bloat-detector.sh +267 -0
  929. package/tests/test-post-edit-disk-verify.sh +294 -0
  930. package/tests/test-pre-bash-sed-line-ending-windows.sh +108 -0
  931. package/tests/test-pre-execution-claim-detector.sh +366 -0
  932. package/tests/test-private-key-backup-and-git-credentials.sh +100 -0
  933. package/tests/test-proxy-capture-suggester.sh +214 -0
  934. package/tests/test-public-artefact-socratic-narrowing.sh +346 -0
  935. package/tests/test-quota-anomaly-detector.sh +321 -0
  936. package/tests/test-quota-reset-audit.sh +81 -0
  937. package/tests/test-read-loop-detector.sh +137 -0
  938. package/tests/test-read-once-guard.sh +85 -0
  939. package/tests/test-receipts-aggregate.sh +143 -0
  940. package/tests/test-redirect-fragment-warner.sh +130 -0
  941. package/tests/test-redundant-read-blocker.sh +155 -0
  942. package/tests/test-refusal-arrest-gate.sh +303 -0
  943. package/tests/test-remote-control-billing-classifier.sh +125 -0
  944. package/tests/test-resume-drift-watcher.sh +65 -0
  945. package/tests/test-rg-replace-flag-detector.sh +175 -0
  946. package/tests/test-rhetorical-verification-prompt-detector.sh +237 -0
  947. package/tests/test-rm-safety-net.sh +115 -0
  948. package/tests/test-route-handler-emptiness-gate.sh +300 -0
  949. package/tests/test-runtime-binary-change-detector.sh +196 -0
  950. package/tests/test-same-command-repeat-detector.sh +165 -0
  951. package/tests/test-same-correction-arrest.sh +165 -0
  952. package/tests/test-scope-expansion-receipt.sh +207 -0
  953. package/tests/test-server-side-prompt-injection-detector.sh +181 -0
  954. package/tests/test-session-persistence-verifier.sh +128 -0
  955. package/tests/test-session-rate-monitor.sh +284 -0
  956. package/tests/test-session-start-quota-status.sh +210 -0
  957. package/tests/test-session-start-safety-check.sh +138 -0
  958. package/tests/test-settings-hooks-key-restorer.sh +257 -0
  959. package/tests/test-settings-json-health-check.sh +70 -0
  960. package/tests/test-settings-regression-tester.sh +197 -0
  961. package/tests/test-skill-cumulative-size-detector.sh +198 -0
  962. package/tests/test-skill-description-drop-detector.sh +236 -0
  963. package/tests/test-skill-truncation-detector.sh +263 -0
  964. package/tests/test-skills-context-recorder.sh +329 -0
  965. package/tests/test-skills-load-verifier.sh +184 -0
  966. package/tests/test-skills-settings-validator.sh +242 -0
  967. package/tests/test-sonnet-45-deprecation-helper.sh +150 -0
  968. package/tests/test-spurious-malformed-notice-detector.sh +290 -0
  969. package/tests/test-sql-bulk-delete-warn.sh +123 -0
  970. package/tests/test-ssh-key-protect.sh +81 -0
  971. package/tests/test-stale-temp-settings-detector.sh +161 -0
  972. package/tests/test-standing-rule-session-surfacer.sh +215 -0
  973. package/tests/test-starter-hooks-manifest.sh +96 -0
  974. package/tests/test-stop-hook-sigterm-wrapper.sh +258 -0
  975. package/tests/test-strict-allowlist.sh +72 -0
  976. package/tests/test-subagent-boundary-precheck.sh +137 -0
  977. package/tests/test-subagent-closure-verify-gate.sh +193 -0
  978. package/tests/test-subagent-destructive-git-guard.sh +86 -0
  979. package/tests/test-subagent-identity-leak-guard.sh +62 -0
  980. package/tests/test-subagent-identity-reassertion.sh +61 -0
  981. package/tests/test-subagent-inheritance-tester.sh +319 -0
  982. package/tests/test-subagent-permission-mode-guard.sh +61 -0
  983. package/tests/test-subagent-spawn-verification-enforcer.sh +60 -0
  984. package/tests/test-subagent-tool-allowlist-enforcer.sh +62 -0
  985. package/tests/test-subagent-tool-call-limiter.sh +97 -0
  986. package/tests/test-subscription-api-billing-warner.sh +138 -0
  987. package/tests/test-subscription-bypass-detector.sh +255 -0
  988. package/tests/test-temporal-suggestion-detector.sh +183 -0
  989. package/tests/test-thinking-budget-effort-mismatch-detector.sh +327 -0
  990. package/tests/test-tokenizer-ratio-alert-corpus.sh +77 -0
  991. package/tests/test-tokenizer-ratio-alert.sh +93 -0
  992. package/tests/test-tool-result-correlation-checker.sh +264 -0
  993. package/tests/test-tool-result-size-guard.sh +121 -0
  994. package/tests/test-transcript-contamination-detector.sh +264 -0
  995. package/tests/test-trigger-header-parsing.sh +151 -0
  996. package/tests/test-ultrareview-large-diff-advisor.sh +192 -0
  997. package/tests/test-userprompt-submit-receipt.sh +181 -0
  998. package/tests/test-verify-after-publish-reminder.sh +184 -0
  999. package/tests/test-version-bump-detector.sh +212 -0
  1000. package/tests/test-version-regression-warner.sh +165 -0
  1001. package/tests/test-warn-cron-cost-trap.sh +82 -0
  1002. package/tests/test-webfetch-runaway-guard.sh +77 -0
  1003. package/tests/test-wellness-break-reminder.sh +138 -0
  1004. package/tests/test-windows-destructive-command-guard.sh +169 -0
  1005. package/tests/test-windows-python-stub-detector.sh +146 -0
  1006. package/tests/test-worktree-edit-boundary-guard.sh +219 -0
  1007. package/tests/test-write-byte-integrity-verifier.sh +192 -0
  1008. package/tests/test-xml-format-leak-detector.sh +299 -0
  1009. package/tests/trustfall-mcp-injection-guard.test.sh +183 -0
  1010. package/tests/workspace-lease-guard.test.sh +144 -0
  1011. package/tests/worktree-escape-write-guard.test.sh +68 -0
  1012. package/tests/worktree-hooks-path-fix.test.sh +181 -0
  1013. package/tests/worktree-parent-write-guard.test.sh +51 -0
  1014. package/tests/write-empty-content-guard.test.sh +39 -0
  1015. package/tests/write-nul-corruption-detector.test.sh +29 -0
  1016. package/tests/write-overwrite-unread-content.test.sh +178 -0
  1017. package/tests/wsl-host-disk-space-guard.test.sh +55 -0
@@ -11,38 +11,110 @@
11
11
  # TRIGGER: PreToolUse
12
12
  # MATCHER: ""
13
13
 
14
+ __CC_HOOK_INPUT=$(cat 2>/dev/null)
15
+ # --- セッション識別子でファイルを分ける (2026-08-09 修正) ---
16
+ # 旧実装は "$$" を使っていたが、$$ はこのスクリプト自身のPIDで呼び出しごとに変わるため、
17
+ # 状態が一度も持続しなかった(実測: 200回呼ぶとファイルが200個でき、中身は全部 1)。
18
+ __CC_SID=""
19
+ if [ -n "${__CC_HOOK_INPUT:-}" ]; then
20
+ if command -v jq >/dev/null 2>&1; then
21
+ __CC_SID=$(printf '%s' "$__CC_HOOK_INPUT" | jq -r '.session_id // .sessionId // empty' 2>/dev/null)
22
+ fi
23
+ if [ -z "$__CC_SID" ] && command -v python3 >/dev/null 2>&1; then
24
+ __CC_SID=$(printf '%s' "$__CC_HOOK_INPUT" | python3 -c 'import sys,json
25
+ try:
26
+ d=json.load(sys.stdin); print(d.get("session_id") or d.get("sessionId") or "")
27
+ except Exception: print("")' 2>/dev/null)
28
+ fi
29
+ fi
30
+ if [ -n "$__CC_SID" ]; then
31
+ __CC_KEY=$(printf '%s' "$__CC_SID" | tr -c 'A-Za-z0-9_-' '_' | cut -c1-64)
32
+ else
33
+ __CC_KEY="nosession-$(date +%Y%m%d)"
34
+ fi
35
+ # --- ここまで ---
36
+
14
37
  set -euo pipefail
15
38
 
16
39
  MAX_CALLS="${CC_MAX_TOOL_CALLS:-200}"
17
- COUNTER_FILE="/tmp/claude-tool-call-counter-$$"
40
+ COUNTER_FILE="/tmp/claude-tool-call-counter-$__CC_KEY"
18
41
 
19
- # Use session-based counter (PID of parent process)
20
- PPID_FILE="/tmp/claude-tool-call-counter-${PPID:-0}"
21
- [ -f "$PPID_FILE" ] && COUNTER_FILE="$PPID_FILE"
42
+ # 2026-08-09: $PPID を使う旧機構を削除した。
43
+ # 旧実装は $PPID(親プロセスのID)をセッションの識別子として使っていた。
44
+ # ★訂正: 最初これを「一度も遮断しない」と書いたが、それは計測の誤りだった。
45
+ # 親が安定していれば $PPID は持続するので、上限10で15回叩くと11回目から5回遮断する(実測)。
46
+ # 「200回で遮断0回」という最初の測定は、こちらが $( ) の中で呼んだせいで
47
+ # 呼び出しごとに別のサブシェルが親になっていたためで、仕掛けが作った結果だった。
48
+ # 実際に残る欠陥はこちら: $PPID はセッションの識別子ではない。
49
+ # 同じ親から複数のセッションが走ると**カウンターが混ざる**。
50
+ # 実測: 同じ親から session_id が sX と sY の呼び出しを6回ずつ交互に流すと、
51
+ # カウンターファイルは1個だけで値は12(=6+6)。片方のセッションが上限を使い切ると、
52
+ # もう片方が何もしていなくても遮断される。
53
+ # 修正: hookの入力JSONの session_id で分ける。
54
+ #
55
+ # ★2026-08-27 追記: session_id だけでは、このhookの名前が約束していることができない。
56
+ # PreToolUse の入力を丸ごと落として実測したところ、サブエージェントの呼び出しでも
57
+ # session_id は親と1バイトも違わない(transcript_path も同じ)。増えるのは agent_id と
58
+ # agent_type の2つだけ。つまり session_id を鍵にしたカウンターは、親と全サブエージェントの
59
+ # 合算になる。#36727 の「1体のサブエージェントが1.5時間で234回」を止めたくても、
60
+ # 合算のカウンターでは「誰が使ったか」が分からず、暴走した子が枠を焼き切ると
61
+ # 何もしていない親まで止まる。
62
+ # → セッション全体の上限はそのままに、agent_id ごとの上限を足した。
63
+ # どちらか先に達したほうで止める。合計の上限は変えていないので、緩くはならない。
22
64
 
23
- # Initialize or read counter
24
- if [ -f "$COUNTER_FILE" ]; then
25
- COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
26
- else
27
- COUNT=0
28
- COUNTER_FILE="$PPID_FILE"
65
+ MAX_SUBAGENT_CALLS="${CC_MAX_SUBAGENT_TOOL_CALLS:-100}"
66
+
67
+ # agent_id はサブエージェントの呼び出しにだけ入る(実測)。上位エージェントでは空。
68
+ __CC_AID=""
69
+ if [ -n "${__CC_HOOK_INPUT:-}" ] && command -v jq >/dev/null 2>&1; then
70
+ __CC_AID=$(printf '%s' "$__CC_HOOK_INPUT" | jq -r '.agent_id // empty' 2>/dev/null)
29
71
  fi
72
+ __CC_AKEY=$(printf '%s' "$__CC_AID" | tr -c 'A-Za-z0-9_-' '_' | cut -c1-64)
73
+ AGENT_COUNTER_FILE="/tmp/claude-tool-call-counter-$__CC_KEY-agent-$__CC_AKEY"
30
74
 
31
- COUNT=$((COUNT + 1))
32
- echo "$COUNT" > "$COUNTER_FILE"
75
+ read_counter() {
76
+ _v=0
77
+ if [ -f "$1" ]; then
78
+ _v=$(cat "$1" 2>/dev/null || echo 0)
79
+ case "$_v" in ''|*[!0-9]*) _v=0 ;; esac
80
+ fi
81
+ printf '%s' "$_v"
82
+ }
33
83
 
34
- # Check limit
84
+ COUNT=$(( $(read_counter "$COUNTER_FILE") + 1 ))
85
+ AGENT_COUNT=0
86
+ [ -n "$__CC_AID" ] && AGENT_COUNT=$(( $(read_counter "$AGENT_COUNTER_FILE") + 1 ))
87
+
88
+ # ★記録は遮断を決めた後に置く。先に書くと、案内を読んで再試行するたびに
89
+ # カウンターが増えて待ち時間が自分の再試行で延びる(2026-07-28 に別のhookで実害)。
35
90
  if [ "$COUNT" -gt "$MAX_CALLS" ]; then
36
- echo "BLOCKED: Tool call limit reached ($COUNT/$MAX_CALLS)." >&2
37
- echo "This session has made $COUNT tool calls (limit: $MAX_CALLS)." >&2
91
+ echo "BLOCKED: Tool call limit reached ($COUNT/$MAX_CALLS) for this session." >&2
92
+ echo "This session (parent and all subagents share one session_id) has made" >&2
93
+ echo "$COUNT tool calls (limit: $MAX_CALLS)." >&2
38
94
  echo "Consider starting a new session or increasing CC_MAX_TOOL_CALLS." >&2
39
95
  exit 2
40
96
  fi
41
97
 
98
+ if [ -n "$__CC_AID" ] && [ "$AGENT_COUNT" -gt "$MAX_SUBAGENT_CALLS" ]; then
99
+ echo "BLOCKED: Subagent tool call limit reached ($AGENT_COUNT/$MAX_SUBAGENT_CALLS)." >&2
100
+ echo "Subagent agent_id=$__CC_AID has made $AGENT_COUNT tool calls on its own." >&2
101
+ echo "The session as a whole is still at $COUNT/$MAX_CALLS, so the parent is not blocked." >&2
102
+ echo "Raise CC_MAX_SUBAGENT_TOOL_CALLS if this subagent legitimately needs more." >&2
103
+ exit 2
104
+ fi
105
+
106
+ echo "$COUNT" > "$COUNTER_FILE"
107
+ [ -n "$__CC_AID" ] && echo "$AGENT_COUNT" > "$AGENT_COUNTER_FILE"
108
+
42
109
  # Warn at 80%
43
110
  WARN_AT=$((MAX_CALLS * 80 / 100))
44
111
  if [ "$COUNT" -eq "$WARN_AT" ]; then
45
112
  echo "WARNING: $COUNT/$MAX_CALLS tool calls used (80%). Consider wrapping up." >&2
46
113
  fi
47
114
 
115
+ AGENT_WARN_AT=$((MAX_SUBAGENT_CALLS * 80 / 100))
116
+ if [ -n "$__CC_AID" ] && [ "$AGENT_COUNT" -eq "$AGENT_WARN_AT" ]; then
117
+ echo "WARNING: subagent $__CC_AID is at $AGENT_COUNT/$MAX_SUBAGENT_CALLS of its own budget." >&2
118
+ fi
119
+
48
120
  exit 0
@@ -15,6 +15,18 @@
15
15
 
16
16
  set -euo pipefail
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-subcommand-chain-guard-$PPID"
24
+ [ -f "$_nojq_warned" ] || {
25
+ echo "WARNING [subcommand-chain-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
  THRESHOLD=${CC_SUBCOMMAND_LIMIT:-20}
19
31
 
20
32
  INPUT=$(cat)
@@ -0,0 +1,160 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # subscription-api-billing-warner.sh — Warn at session start when the
4
+ # active configuration will silently bill API / purchased credits
5
+ # *above* a Claude Pro/Max subscription, so a subscriber does not
6
+ # keep draining pay-per-token credits while subscription quota sits
7
+ # unused.
8
+ # ================================================================
9
+ # PURPOSE:
10
+ # Claude Code's credential precedence puts API-key auth ABOVE an
11
+ # OAuth subscription: if ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN
12
+ # is set, or settings.json defines an apiKeyHelper, every request
13
+ # authenticates as a pay-per-token API call and bills the
14
+ # Console/purchased credits — even when the user has a Pro/Max
15
+ # subscription with quota to spare. Because nothing in the UI
16
+ # surfaces this, subscribers lose real money without knowing an
17
+ # API key is in play.
18
+ #
19
+ # This is a recurring, money-losing pain on the issue tracker:
20
+ # #64613 API requests consuming personal token quota when
21
+ # subscription tokens available
22
+ # #53638 Desktop silently uses project API keys for billing
23
+ # instead of the subscription
24
+ # #53728 Silent ANTHROPIC_API_KEY precedence shadows Max
25
+ # subscription auth
26
+ # #54677 [FR] Distinguish API key vs OAuth subscription billing
27
+ #
28
+ # The hook inspects, at session start, the three locally-detectable
29
+ # precedence sources (the two env vars and an apiKeyHelper in
30
+ # user/project settings.json). If any is present it emits a one-line
31
+ # stderr advisory naming the precedence rule and the one-command
32
+ # confirmation (/status), then continues. Advisory only (exit 0);
33
+ # it never blocks the session and never reads the key value.
34
+ #
35
+ # It is deliberately conservative about noise: someone who runs on
36
+ # API billing on purpose (no subscription, or multiple deliberate
37
+ # API-key accounts) can silence it permanently, and it auto-skips
38
+ # when ANTHROPIC_ACCOUNT_LABEL is set — the same signal the
39
+ # account-routing-preflight.sh hook uses to mark intentional
40
+ # multi-account API use.
41
+ #
42
+ # TRIGGER: SessionStart
43
+ # MATCHER: ""
44
+ #
45
+ # SETUP:
46
+ # {
47
+ # "hooks": {
48
+ # "SessionStart": [
49
+ # {
50
+ # "matcher": "",
51
+ # "hooks": [
52
+ # { "type": "command",
53
+ # "command": "$HOME/.claude/hooks/subscription-api-billing-warner.sh" }
54
+ # ]
55
+ # }
56
+ # ]
57
+ # }
58
+ # }
59
+ #
60
+ # BEHAVIOR:
61
+ # - No API-key env var and no apiKeyHelper → silent pass.
62
+ # - Any precedence source present → stderr advisory + exit 0.
63
+ # - Never blocks; never prints the key/token value.
64
+ #
65
+ # CONFIGURATION (env vars):
66
+ # CC_SUB_BILLING_DISABLE Set to "1" to disable the hook entirely.
67
+ # ANTHROPIC_ACCOUNT_LABEL If set (non-empty), the hook stays silent:
68
+ # an explicit account label signals the
69
+ # operator is managing API billing on
70
+ # purpose (mirrors account-routing-preflight).
71
+ # CC_SUB_BILLING_SETTINGS_OVERRIDE
72
+ # Colon-separated list of settings.json paths
73
+ # to scan for apiKeyHelper instead of the real
74
+ # ~/.claude/settings.json and ./.claude/
75
+ # settings.json. Used by tests/CI.
76
+ # ================================================================
77
+
78
+ set -u
79
+
80
+ if [ "${CC_SUB_BILLING_DISABLE:-0}" = "1" ]; then
81
+ exit 0
82
+ fi
83
+
84
+ # Read and discard the SessionStart JSON payload; the hook only
85
+ # inspects the environment and settings files, not the payload.
86
+ if [ ! -t 0 ]; then
87
+ cat >/dev/null 2>&1 || true
88
+ fi
89
+
90
+ # An explicit account label means the operator is managing API-key
91
+ # billing deliberately — stay silent to avoid nagging that case.
92
+ if [ -n "${ANTHROPIC_ACCOUNT_LABEL:-}" ]; then
93
+ exit 0
94
+ fi
95
+
96
+ REASONS=""
97
+
98
+ if [ -n "${ANTHROPIC_API_KEY:-}" ]; then
99
+ REASONS="${REASONS} • ANTHROPIC_API_KEY is set in this environment
100
+ "
101
+ fi
102
+
103
+ if [ -n "${ANTHROPIC_AUTH_TOKEN:-}" ]; then
104
+ REASONS="${REASONS} • ANTHROPIC_AUTH_TOKEN is set in this environment
105
+ "
106
+ fi
107
+
108
+ # Scan settings.json files for an apiKeyHelper, which injects a key on
109
+ # every request even when no env var is set.
110
+ if [ -n "${CC_SUB_BILLING_SETTINGS_OVERRIDE:-}" ]; then
111
+ SETTINGS_LIST="${CC_SUB_BILLING_SETTINGS_OVERRIDE//:/
112
+ }"
113
+ else
114
+ SETTINGS_LIST="${HOME:-/root}/.claude/settings.json
115
+ ./.claude/settings.json"
116
+ fi
117
+
118
+ while IFS= read -r SETTINGS_FILE; do
119
+ [ -z "$SETTINGS_FILE" ] && continue
120
+ [ -r "$SETTINGS_FILE" ] || continue
121
+ # Tolerant key-presence check (no jq dependency): a JSON object key
122
+ # "apiKeyHelper" with a non-empty string value.
123
+ if grep -Eq '"apiKeyHelper"[[:space:]]*:[[:space:]]*"[^"]+"' "$SETTINGS_FILE" 2>/dev/null; then
124
+ REASONS="${REASONS} • apiKeyHelper is configured in ${SETTINGS_FILE}
125
+ "
126
+ fi
127
+ done <<EOF
128
+ $SETTINGS_LIST
129
+ EOF
130
+
131
+ if [ -n "$REASONS" ]; then
132
+ cat >&2 <<EOF
133
+
134
+ ⚠️ This session may bill API / purchased credits instead of your subscription.
135
+
136
+ Claude Code's credential precedence puts API-key auth ABOVE an
137
+ OAuth subscription. Detected:
138
+ ${REASONS}
139
+ If you have a Claude Pro/Max subscription, requests are likely
140
+ spending pay-per-token (Console/purchased) credits even while your
141
+ subscription quota is unused — the cause of the "subscription at 0%
142
+ but my purchased balance is draining" reports (#64613, #53638, #53728).
143
+
144
+ Confirm and fix:
145
+ 1. Run /status — it names the active auth method (subscription vs API).
146
+ 2. To use the subscription: unset the variable(s) above, and check the
147
+ shell profile (.zshrc/.bashrc/.profile) and any .env / direnv .envrc
148
+ that re-export them; remove apiKeyHelper from settings.json; and in
149
+ /config turn off "Use custom API key".
150
+ 3. If money was already charged while a subscription was active, a
151
+ billing review at https://support.claude.com can refund a misroute.
152
+
153
+ This is an advisory; the session continues.
154
+ Set CC_SUB_BILLING_DISABLE=1 (or ANTHROPIC_ACCOUNT_LABEL for deliberate
155
+ API-key accounts) to silence it.
156
+
157
+ EOF
158
+ fi
159
+
160
+ exit 0
@@ -0,0 +1,152 @@
1
+ #!/bin/bash
2
+ # subscription-bypass-detector.sh — SessionStart hook
3
+ # Trigger: SessionStart
4
+ # Matcher: ""
5
+ #
6
+ # Solves: anthropics/claude-code#60093 — operator with an active Max/Pro
7
+ # subscription accumulated approximately USD 1,050 in API charges
8
+ # across nine auto-refills over three days (2026-05-05 to 2026-05-07)
9
+ # because a dotenv-loaded ANTHROPIC_API_KEY silently overrode the
10
+ # subscription path. The UI displayed "Sonnet" throughout while
11
+ # billing routed through API-key Opus pricing. The operator had no
12
+ # in-session signal that the billing path had switched.
13
+ #
14
+ # The official support response was that this behavior is
15
+ # "intentional functionality" (the env var taking precedence over
16
+ # the subscription credential is documented somewhere but not on
17
+ # the path operators read), making operator-side detection the only
18
+ # reliable prevention.
19
+ #
20
+ # Earlier related case: a separate operator lost USD 187 in May
21
+ # 2026 from the same structural pattern (dotenv ANTHROPIC_API_KEY
22
+ # silently bypassing the subscription). The pattern is recurring.
23
+ #
24
+ # Class of failure: claim-vs-reality divergence at the billing-routing layer.
25
+ # The operator's mental model ("I subscribed, therefore I pay the
26
+ # subscription rate") and the runtime behavior ("API key in env
27
+ # takes precedence, so charges flow through metered API pricing")
28
+ # have diverged silently. The status surface (UI showing the
29
+ # expected model) reinforces the wrong mental model.
30
+ #
31
+ # HOW IT WORKS:
32
+ # At session start, inspect the resolved environment for ANTHROPIC_API_KEY
33
+ # (or related vendor-key env vars). If any are present, emit a SessionStart
34
+ # warning that explicitly states: (1) the env var was detected, (2) this
35
+ # bypasses subscription billing on the affected path, (3) the operator's
36
+ # choices are to unset the env var (subscription billing) or to
37
+ # acknowledge the API-key billing path explicitly.
38
+ #
39
+ # The hook reads the dotenv-style files Claude Code is known to load
40
+ # (~/.claude/.env, project .env, $HOME/.env) and surfaces which file is
41
+ # the source of the key, so the operator can disable the right line.
42
+ #
43
+ # WHY THIS MATTERS:
44
+ # Issue #60093 is one of the largest single-incident dollar losses in the
45
+ # May 2026 claim-vs-reality cluster (USD 1,050 across 9 auto-refills before
46
+ # the operator noticed). The cost is concentrated and irreversible at the
47
+ # billing layer (charges already accrued cannot be reversed by adjusting
48
+ # settings). Pre-session detection is the only reliable defense; in-session
49
+ # detection happens too late.
50
+ #
51
+ # TRIGGER: SessionStart
52
+ # MATCHER: ""
53
+ #
54
+ # CONFIGURATION:
55
+ # CC_SUBSCRIPTION_BYPASS_DISABLE=1 disable this hook entirely
56
+ # CC_SUBSCRIPTION_BYPASS_ACK=1 acknowledge API-key billing is intended
57
+ # (suppresses the warning but keeps the
58
+ # detection log entry)
59
+ # CC_SUBSCRIPTION_BYPASS_LOG=path append detection events to this file
60
+ # (default off)
61
+ #
62
+ # SAFETY:
63
+ # - Read-only on the environment and on .env files.
64
+ # - Does not modify, unset, or interact with the keys themselves.
65
+ # - Emits a warning to stderr; does not block the session.
66
+ # - Exit 0 always.
67
+ #
68
+ # REFERENCES:
69
+ # - anthropics/claude-code#60093 (2026-05-18, USD 1,050 case)
70
+ # - Earlier May 2026 case: USD 187 dotenv-bypass incident (community report,
71
+ # surfaced via a Qiita writeup published 2026-05-15)
72
+ set -euo pipefail
73
+
74
+ [ "${CC_SUBSCRIPTION_BYPASS_DISABLE:-}" = "1" ] && exit 0
75
+
76
+ # Collect signal sources. Each signal is reported only if the value is
77
+ # non-empty after the env var resolves.
78
+ declare -a SOURCES=()
79
+
80
+ # Direct env var check
81
+ if [ -n "${ANTHROPIC_API_KEY:-}" ]; then
82
+ SOURCES+=("process environment (ANTHROPIC_API_KEY is set in the shell that launched this session)")
83
+ fi
84
+
85
+ # Look for the key in the standard dotenv search paths Claude Code is
86
+ # documented to consult.
87
+ check_dotenv_for_key() {
88
+ local path="$1"
89
+ local label="$2"
90
+ [ ! -f "$path" ] && return 0
91
+ if grep -qE '^[[:space:]]*ANTHROPIC_API_KEY[[:space:]]*=' "$path" 2>/dev/null; then
92
+ SOURCES+=("$label ($path)")
93
+ fi
94
+ }
95
+
96
+ check_dotenv_for_key "$HOME/.claude/.env" "Claude per-user dotenv"
97
+ check_dotenv_for_key "$HOME/.env" "user home dotenv"
98
+ check_dotenv_for_key "$PWD/.env" "project working-directory dotenv"
99
+
100
+ # Git-repo root dotenv (if we're inside a repo and it's different from cwd)
101
+ if command -v git >/dev/null 2>&1; then
102
+ GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
103
+ if [ -n "$GIT_ROOT" ] && [ "$GIT_ROOT" != "$PWD" ]; then
104
+ check_dotenv_for_key "$GIT_ROOT/.env" "git repository root dotenv"
105
+ fi
106
+ fi
107
+
108
+ # If no sources were found, exit silently.
109
+ if [ "${#SOURCES[@]}" -eq 0 ]; then
110
+ exit 0
111
+ fi
112
+
113
+ # Build the warning body
114
+ SOURCE_LIST=""
115
+ for src in "${SOURCES[@]}"; do
116
+ SOURCE_LIST="${SOURCE_LIST}\n - ${src}"
117
+ done
118
+
119
+ WARNING_BODY="ANTHROPIC_API_KEY detected at session start. Source(s):${SOURCE_LIST}
120
+
121
+ Implication: if an ANTHROPIC_API_KEY is resolved in the environment, Claude Code routes billing through metered API-key pricing rather than your Max/Pro subscription, on the affected codepath. This is intentional per Anthropic support but it is not surfaced in-session — the UI continues to display the selected model normally while charges accumulate against the API key.
122
+
123
+ Issue #60093 (2026-05-18) documents a single operator accumulating ~USD 1,050 across 9 auto-refills over 3 days (2026-05-05 to 2026-05-07) before the divergence was noticed. An earlier May 2026 case surfaced a ~USD 187 loss from the same pattern. The cost is incurred at billing time and cannot be reversed by adjusting settings after the fact.
124
+
125
+ To use subscription billing on this session: unset ANTHROPIC_API_KEY in the shell (or remove the matching line from the source file above) and restart Claude Code.
126
+
127
+ To acknowledge that API-key billing is intended for this session, set CC_SUBSCRIPTION_BYPASS_ACK=1; the warning will be suppressed for future sessions but a log entry will still record the detection if CC_SUBSCRIPTION_BYPASS_LOG is set."
128
+
129
+ # Optional logging
130
+ if [ -n "${CC_SUBSCRIPTION_BYPASS_LOG:-}" ]; then
131
+ {
132
+ printf '[%s] subscription-bypass-detected: sources=%d sources_list=%s\n' \
133
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${#SOURCES[@]}" "${SOURCES[*]}"
134
+ } >> "$CC_SUBSCRIPTION_BYPASS_LOG" 2>/dev/null || true
135
+ fi
136
+
137
+ # Suppress visible warning if acknowledged
138
+ if [ "${CC_SUBSCRIPTION_BYPASS_ACK:-}" = "1" ]; then
139
+ exit 0
140
+ fi
141
+
142
+ # Emit warning via SessionStart hookSpecificOutput
143
+ jq -n \
144
+ --arg ctx "$(printf '%b' "$WARNING_BODY")" \
145
+ '{
146
+ hookSpecificOutput: {
147
+ hookEventName: "SessionStart",
148
+ additionalContext: $ctx
149
+ }
150
+ }'
151
+
152
+ exit 0
@@ -1,3 +1,4 @@
1
+ #!/bin/bash
1
2
  #
2
3
  # TRIGGER: PostToolUse MATCHER: "Edit|Write"
3
4
  INPUT=$(cat)
@@ -18,7 +18,7 @@
18
18
  # }
19
19
  # ================================================================
20
20
  #
21
- # TRIGGER: PreToolUse MATCHER: "Bash"
21
+ # TRIGGER: PostToolUse MATCHER: "Edit|Write"
22
22
 
23
23
  INPUT=$(cat)
24
24
  FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
@@ -20,6 +20,18 @@
20
20
  # GitHub Issues: #36339 (93r), #764 (63r), #24964 (135r)
21
21
  # ================================================================
22
22
 
23
+ # Without jq, the parse below silently yields empty and this hook stops
24
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
25
+ # here: blocking would halt every tool call, and exiting 0 would change
26
+ # the behaviour of guards that do not depend on the parsed value.
27
+ if ! command -v jq >/dev/null 2>&1; then
28
+ _nojq_warned="/tmp/cc-nojq-warned-symlink-guard-$PPID"
29
+ [ -f "$_nojq_warned" ] || {
30
+ echo "WARNING [symlink-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
31
+ : > "$_nojq_warned"
32
+ }
33
+ fi
34
+
23
35
  INPUT=$(cat)
24
36
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
25
37
 
@@ -32,8 +44,21 @@ if ! echo "$COMMAND" | grep -qE '^\s*rm\s+.*-[rf]'; then
32
44
  exit 0
33
45
  fi
34
46
 
35
- # Extract target path
36
- TARGET=$(echo "$COMMAND" | grep -oP 'rm\s+(-[rf]+\s+)*\K\S+' | tail -1)
47
+ # Extract target path.
48
+ # grep -P is GNU-only; macOS ships BSD grep, which rejects -P and returns nothing.
49
+ # TARGET would then be empty and the "[[ -z ]] && exit 0" below would let every
50
+ # rm through — the guard would stop guarding without saying anything. Measured:
51
+ # with -P the hook exits 2 on a symlink pointing outside the project, without it
52
+ # it exits 0 on the same input. \K has no POSIX equivalent, so the fallback
53
+ # matches from the command word and strips that prefix afterwards.
54
+ if echo x | grep -qP x 2>/dev/null; then
55
+ TARGET=$(echo "$COMMAND" | grep -oP 'rm\s+(-[rf]+\s+)*\K\S+' | tail -1)
56
+ else
57
+ TARGET=$(echo "$COMMAND" \
58
+ | grep -oE 'rm[[:space:]]+(-[rf]+[[:space:]]+)*[^[:space:]]+' \
59
+ | tail -1 \
60
+ | sed -E 's/^rm[[:space:]]+(-[rf]+[[:space:]]+)*//')
61
+ fi
37
62
 
38
63
  if [[ -z "$TARGET" ]] || [[ ! -e "$TARGET" ]]; then
39
64
  exit 0
@@ -1,3 +1,4 @@
1
+ #!/bin/bash
1
2
  INPUT=$(cat)
2
3
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
3
4
  FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
@@ -16,15 +16,60 @@
16
16
 
17
17
  set -euo pipefail
18
18
 
19
+ # Without jq, the parse below silently yields empty and this hook stops
20
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
21
+ # here: blocking would halt every tool call, and exiting 0 would change
22
+ # the behaviour of guards that do not depend on the parsed value.
23
+ if ! command -v jq >/dev/null 2>&1; then
24
+ _nojq_warned="/tmp/cc-nojq-warned-system-dir-protection-guard-$PPID"
25
+ [ -f "$_nojq_warned" ] || {
26
+ echo "WARNING [system-dir-protection-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
27
+ : > "$_nojq_warned"
28
+ }
29
+ fi
30
+
19
31
  INPUT=$(cat)
20
32
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
33
+
34
+ # --- Look inside wrappers -----------------------------------------------------
35
+ # The three gates below open only when the command *starts* with rm / mv /
36
+ # chmod, so a command inside a substitution, a subshell, or after a shell
37
+ # keyword was never examined. Measured 2026-08-04: this hook blocked the bare
38
+ # deletion and passed all six wrappings of it. Claude Code 2.1.221 fixed the
39
+ # same shape in its own permission check.
40
+ #
41
+ # Replace the wrapping tokens with separators and run this same script once more
42
+ # against that text. Detection only: never executed, and the message keeps the
43
+ # command the user actually sent.
44
+ if [ -n "${CC_SYSDIR_UNWRAPPED:-}" ]; then
45
+ COMMAND="$CC_SYSDIR_UNWRAPPED"
46
+ elif [ -n "$COMMAND" ]; then
47
+ _sysdir_unwrapped=$(printf '%s' "$COMMAND" | sed -E \
48
+ -e 's/\$\(/ ; /g' -e 's/`/ ; /g' \
49
+ -e 's/(^|[[:space:]])\(/\1 ; /g' -e 's/\)([[:space:]]|$)/ ; \1/g' \
50
+ -e 's/(^|[[:space:]])(then|do|else|elif)([[:space:]])/\1 ; \3/g')
51
+ if [ "$_sysdir_unwrapped" != "$COMMAND" ]; then
52
+ CC_SYSDIR_UNWRAPPED="$_sysdir_unwrapped" bash "$0" </dev/null >/dev/null 2>&1
53
+ if [ "$?" = "2" ]; then
54
+ echo "BLOCKED: an operation on a system directory is hidden inside a wrapper." >&2
55
+ echo "Command: $COMMAND" >&2
56
+ echo "A substitution, a subshell or a shell keyword does not make it safe." >&2
57
+ exit 2
58
+ fi
59
+ fi
60
+ fi
21
61
  [ -z "$COMMAND" ] && exit 0
22
62
 
23
63
  # Check if a path is a protected system directory
24
64
  is_system_dir() {
25
65
  local path="$1"
26
- # Remove trailing slash
27
- path="${path%/}"
66
+ # Remove a trailing slash -- but never on the root itself.
67
+ # `${path%/}` turns "/" into "", so the `/` branch in the case below (which
68
+ # the author did write) could never be reached, and `rm -rf /`, `mv / …`
69
+ # and `chmod -R 777 /` all walked through while `/etc` was blocked.
70
+ # Measured 2026-08-03: the root was the one directory this guard named and
71
+ # then erased one line before checking it.
72
+ [ "$path" != "/" ] && path="${path%/}"
28
73
 
29
74
  # Expand ~ to $HOME
30
75
  if [[ "$path" == "~"* ]]; then
@@ -55,10 +100,29 @@ is_system_dir() {
55
100
  return 1
56
101
  }
57
102
 
103
+ # The extractions below used grep -oP, which is GNU-only. BSD grep (macOS)
104
+ # rejects -P outright, so every target list came back empty, the loops below
105
+ # had nothing to iterate, and the guard exited 0 — `rm -rf /root` went through
106
+ # on macOS with no sign that the protection was off. The GNU path is unchanged;
107
+ # an equivalent is added for platforms without PCRE.
108
+ if echo x | grep -qP x 2>/dev/null; then HAS_PCRE=1; else HAS_PCRE=0; fi
109
+
110
+ # $1 = command alternation (e.g. "rm|unlink"), $2 = operand pattern.
111
+ # \K has no POSIX equivalent, so the fallback matches the whole thing and
112
+ # strips the command word and its flags afterwards.
113
+ extract_operand() {
114
+ if [ "$HAS_PCRE" = 1 ]; then
115
+ grep -oP "($1)\\s+(-[a-zA-Z]+\\s+)*\\K$2" 2>/dev/null || true
116
+ else
117
+ grep -oE "($1)[[:space:]]+(-[a-zA-Z]+[[:space:]]+)*$2" 2>/dev/null \
118
+ | sed -E "s/^($1)[[:space:]]+(-[a-zA-Z]+[[:space:]]+)*//" || true
119
+ fi
120
+ }
121
+
58
122
  # --- rm / unlink on system directories ---
59
- if echo "$COMMAND" | grep -qE '^\s*(sudo\s+)?(rm|unlink)\s'; then
123
+ if echo "$COMMAND" | grep -qE '(^|[;&|])[[:space:]]*(sudo[[:space:]]+)?(rm|unlink)[[:space:]]'; then
60
124
  # Extract targets after rm and flags
61
- TARGETS=$(echo "$COMMAND" | grep -oP '(rm|unlink)\s+(-[a-zA-Z]+\s+)*\K[^;|&]+' 2>/dev/null || true)
125
+ TARGETS=$(echo "$COMMAND" | extract_operand 'rm|unlink' '[^;|&]+')
62
126
  for target in $TARGETS; do
63
127
  if is_system_dir "$target"; then
64
128
  echo "BLOCKED: Destructive operation on system directory: $target" >&2
@@ -72,9 +136,9 @@ if echo "$COMMAND" | grep -qE '^\s*(sudo\s+)?(rm|unlink)\s'; then
72
136
  fi
73
137
 
74
138
  # --- mv (moving system directories) ---
75
- if echo "$COMMAND" | grep -qE '^\s*(sudo\s+)?mv\s'; then
139
+ if echo "$COMMAND" | grep -qE '(^|[;&|])[[:space:]]*(sudo[[:space:]]+)?mv[[:space:]]'; then
76
140
  # Get the source of the mv (first non-flag argument)
77
- MV_SOURCE=$(echo "$COMMAND" | grep -oP 'mv\s+(-[a-zA-Z]+\s+)*\K\S+' 2>/dev/null || true)
141
+ MV_SOURCE=$(echo "$COMMAND" | extract_operand 'mv' '[^[:space:]]+')
78
142
  if is_system_dir "$MV_SOURCE"; then
79
143
  echo "BLOCKED: Moving system directory: $MV_SOURCE" >&2
80
144
  echo "Command: $COMMAND" >&2
@@ -86,8 +150,9 @@ if echo "$COMMAND" | grep -qE '^\s*(sudo\s+)?mv\s'; then
86
150
  fi
87
151
 
88
152
  # --- chmod -R / chown -R on system directories ---
89
- if echo "$COMMAND" | grep -qE '^\s*(sudo\s+)?(chmod|chown)\s+.*-R'; then
90
- TARGETS=$(echo "$COMMAND" | grep -oP '(chmod|chown)\s+[^;|&]+' 2>/dev/null | awk '{print $NF}' || true)
153
+ if echo "$COMMAND" | grep -qE '(^|[;&|])[[:space:]]*(sudo[[:space:]]+)?(chmod|chown)[[:space:]]+.*-R'; then
154
+ # No \K here, so plain ERE is enough (POSIX classes instead of \s).
155
+ TARGETS=$(echo "$COMMAND" | grep -oE '(chmod|chown)[[:space:]]+[^;|&]+' 2>/dev/null | awk '{print $NF}' || true)
91
156
  for target in $TARGETS; do
92
157
  if is_system_dir "$target"; then
93
158
  echo "BLOCKED: Recursive permission change on system directory: $target" >&2