cc-safe-setup 29.7.0 → 30.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1022) 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 +419 -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-circuit-breaker.sh +72 -0
  178. package/examples/compact-dispatch-watchdog.sh +149 -0
  179. package/examples/completion-claim-without-verification-detector.sh +207 -0
  180. package/examples/composer-guard.sh +12 -0
  181. package/examples/compound-bash-permission-resolver.sh +156 -0
  182. package/examples/compound-command-allow.sh +1 -1
  183. package/examples/compound-command-deny-enforcer.sh +183 -0
  184. package/examples/compound-inject-guard.sh +12 -0
  185. package/examples/concurrent-edit-lock.sh +12 -0
  186. package/examples/conflict-marker-guard.sh +12 -0
  187. package/examples/consecutive-error-breaker.sh +0 -0
  188. package/examples/console-log-count.sh +1 -0
  189. package/examples/context-compact-advisor.sh +29 -2
  190. package/examples/context-length-budget.sh +69 -0
  191. package/examples/context-threshold-alert.sh +12 -0
  192. package/examples/context-usage-drift-alert.sh +41 -13
  193. package/examples/conversation-history-guard.sh +12 -0
  194. package/examples/core-file-protect-guard.sh +12 -0
  195. package/examples/cors-star-warn.sh +0 -0
  196. package/examples/cost-incident-self-audit.sh +162 -0
  197. package/examples/cowork-claude-md-load-checker.sh +100 -0
  198. package/examples/cowork-fuse-staleness-watcher.sh +140 -0
  199. package/examples/cowork-hook-absence-warner.sh +167 -0
  200. package/examples/cowork-model-picker-advisor.sh +115 -0
  201. package/examples/credential-exfil-guard.sh +65 -4
  202. package/examples/credential-file-cat-guard.sh +17 -1
  203. package/examples/cron-create-receipt.sh +112 -0
  204. package/examples/cron-modification-guard.sh +12 -0
  205. package/examples/cross-product-mcp-spawn-detector.sh +178 -0
  206. package/examples/cwd-project-boundary-guard.sh +0 -0
  207. package/examples/daemon-zombie-worker-surfacer.sh +118 -0
  208. package/examples/daily-cost-guard.sh +164 -0
  209. package/examples/daily-usage-tracker.sh +0 -0
  210. package/examples/dangerous-pip-flag-guard.sh +12 -0
  211. package/examples/db-connect-guard.sh +13 -1
  212. package/examples/denied-action-retry-guard.sh +12 -0
  213. package/examples/deny-bypass-detector.sh +12 -0
  214. package/examples/deny-rule-integrity-verifier.sh +181 -0
  215. package/examples/dependency-install-guard.sh +12 -0
  216. package/examples/deploy-guard.sh +14 -2
  217. package/examples/deploy-path-verify-guard.sh +12 -0
  218. package/examples/deployment-readback-gate.sh +135 -0
  219. package/examples/deployment-readback-gh-adapter.sh +247 -0
  220. package/examples/deployment-verify-guard.sh +25 -2
  221. package/examples/destructive-db-script-write-guard.sh +166 -0
  222. package/examples/destructive-migration-write-guard.sh +163 -0
  223. package/examples/diff-size-guard.sh +12 -0
  224. package/examples/disabled-feature-toggle-advisor.sh +88 -0
  225. package/examples/disk-partition-guard.sh +12 -0
  226. package/examples/dispatch-allowlist-preflight.sh +301 -0
  227. package/examples/dispatch-liveness-watchdog.sh +216 -0
  228. package/examples/dispatch-receipt.sh +174 -0
  229. package/examples/django-migrate-guard.sh +12 -0
  230. package/examples/dns-config-guard.sh +12 -0
  231. package/examples/docker-dangerous-guard.sh +12 -0
  232. package/examples/docker-volume-guard.sh +0 -0
  233. package/examples/dockerfile-latest-guard.sh +1 -0
  234. package/examples/dotenv-anthropic-key-billing-guard.sh +99 -0
  235. package/examples/dotenv-commit-guard.sh +12 -0
  236. package/examples/dotenv-read-guard.sh +12 -0
  237. package/examples/dotfile-protection-guard.sh +12 -0
  238. package/examples/dotnet-build-on-edit.sh +1 -1
  239. package/examples/drizzle-migrate-guard.sh +27 -2
  240. package/examples/echo-probe-spam-detector.sh +176 -0
  241. package/examples/edit-counter-test-gate.sh +12 -0
  242. package/examples/edit-error-counter.sh +1 -1
  243. package/examples/edit-guard.sh +12 -0
  244. package/examples/edit-old-string-validator.sh +12 -0
  245. package/examples/edit-quote-ambiguity-guard.sh +97 -0
  246. package/examples/edit-retry-loop-guard.sh +0 -0
  247. package/examples/edit-verify.sh +0 -0
  248. package/examples/env-inline-secret-guard.sh +14 -2
  249. package/examples/env-naming-convention.sh +0 -0
  250. package/examples/env-prod-guard.sh +0 -0
  251. package/examples/env-required-check.sh +0 -0
  252. package/examples/env-source-guard.sh +12 -0
  253. package/examples/env-var-check.sh +24 -1
  254. package/examples/ephemeral-container-detector.sh +147 -0
  255. package/examples/error-memory-guard.sh +12 -0
  256. package/examples/evidence-claim-gate.sh +187 -0
  257. package/examples/exploration-budget-guard.sh +89 -0
  258. package/examples/expo-eject-guard.sh +13 -0
  259. package/examples/extended-thinking-loop-guard.sh +139 -0
  260. package/examples/extended-thinking-resume-warning.sh +119 -0
  261. package/examples/extended-thinking-tool-use-mismatch-detector.sh +212 -0
  262. package/examples/fabricated-command-detector.sh +145 -0
  263. package/examples/false-disk-full-guard.sh +63 -0
  264. package/examples/feature-deprecation-detector.sh +109 -0
  265. package/examples/file-change-tracker.sh +1 -1
  266. package/examples/file-change-undo-tracker.sh +0 -0
  267. package/examples/file-edit-backup.sh +63 -14
  268. package/examples/file-reference-check.sh +0 -0
  269. package/examples/file-size-limit.sh +12 -0
  270. package/examples/financial-operation-guard.sh +12 -0
  271. package/examples/firewall-guard.sh +12 -0
  272. package/examples/fish-shell-wrapper.sh +125 -7
  273. package/examples/five-hundred-milestone.sh +1 -0
  274. package/examples/flask-static-route-guard.sh +89 -0
  275. package/examples/forbidden-response-phrase-detector.sh +161 -0
  276. package/examples/gem-push-guard.sh +13 -0
  277. package/examples/gh-cli-destructive-guard.sh +13 -1
  278. package/examples/git-checkout-safety-guard.sh +12 -0
  279. package/examples/git-checkout-uncommitted-guard.sh +12 -0
  280. package/examples/git-config-guard.sh +12 -0
  281. package/examples/git-crypt-worktree-guard.sh +12 -0
  282. package/examples/git-filter-repo-guard.sh +56 -0
  283. package/examples/git-history-rewrite-guard.sh +12 -0
  284. package/examples/git-hook-bypass-guard.sh +0 -0
  285. package/examples/git-maintenance-guard.sh +83 -0
  286. package/examples/git-merge-conflict-prevent.sh +0 -0
  287. package/examples/git-message-length-check.sh +0 -0
  288. package/examples/git-message-length.sh +0 -0
  289. package/examples/git-operations-require-approval.sh +68 -14
  290. package/examples/git-pack-temp-cleanup-guard.sh +102 -0
  291. package/examples/git-push-blast-radius-guard.sh +218 -0
  292. package/examples/git-remote-guard.sh +24 -3
  293. package/examples/git-rm-orphan-wipe-guard.sh +85 -0
  294. package/examples/git-stash-before-checkout.sh +12 -0
  295. package/examples/git-stash-before-danger.sh +0 -0
  296. package/examples/git-submodule-guard.sh +69 -2
  297. package/examples/git-tag-guard.sh +12 -0
  298. package/examples/github-actions-secret-guard.sh +0 -0
  299. package/examples/gitignore-check.sh +0 -0
  300. package/examples/gitops-drift-guard.sh +12 -0
  301. package/examples/go-mod-tidy-warn.sh +1 -0
  302. package/examples/go-vet-after-edit.sh +12 -0
  303. package/examples/goal-iteration-limit-warner.sh +152 -0
  304. package/examples/grep-nul-false-negative-guard.sh +30 -0
  305. package/examples/growthbook-flag-monitor.sh +257 -0
  306. package/examples/hallucination-url-check.sh +1 -1
  307. package/examples/halt-signal-detector.sh +135 -0
  308. package/examples/handoff-on-clear.sh +65 -0
  309. package/examples/hardcoded-ip-guard.sh +1 -0
  310. package/examples/headless-empty-result-guard.sh +0 -0
  311. package/examples/headless-stop-guard.sh +0 -0
  312. package/examples/helm-install-guard.sh +2 -1
  313. package/examples/home-critical-bash-guard.sh +17 -1
  314. package/examples/hook-debug-wrapper.sh +6 -2
  315. package/examples/hook-permission-fixer.sh +0 -0
  316. package/examples/hook-self-disable-detector.sh +99 -0
  317. package/examples/hook-stdout-sanitizer.sh +6 -2
  318. package/examples/hook-tamper-guard.sh +12 -0
  319. package/examples/idle-session-cost-alert.sh +0 -0
  320. package/examples/image-dimension-guard.sh +109 -0
  321. package/examples/image-file-validator.sh +0 -0
  322. package/examples/iteration-quality-degradation-detector.sh +170 -0
  323. package/examples/java-compile-on-edit.sh +1 -1
  324. package/examples/json-syntax-check.sh +0 -0
  325. package/examples/k8s-production-guard.sh +13 -1
  326. package/examples/kill-process-guard.sh +12 -0
  327. package/examples/kubernetes-guard.sh +13 -1
  328. package/examples/laravel-artisan-guard.sh +13 -0
  329. package/examples/large-file-guard.sh +1 -1
  330. package/examples/log-level-guard.sh +0 -0
  331. package/examples/log-truncation-guard.sh +12 -0
  332. package/examples/long-session-malformed-tool-call-detector.sh +183 -0
  333. package/examples/loop-detector.sh +12 -0
  334. package/examples/magic-number-warn.sh +1 -0
  335. package/examples/main-branch-warn.sh +12 -0
  336. package/examples/markdown-link-check.sh +0 -0
  337. package/examples/max-concurrent-agents.sh +12 -0
  338. package/examples/max-edit-size-guard.sh +13 -0
  339. package/examples/max-file-count-guard.sh +0 -0
  340. package/examples/max-file-delete-count.sh +0 -0
  341. package/examples/max-function-length.sh +1 -0
  342. package/examples/max-import-count.sh +0 -0
  343. package/examples/max-subagent-count.sh +0 -0
  344. package/examples/mcp-config-freeze.sh +12 -0
  345. package/examples/mcp-config-poisoning-audit.sh +150 -0
  346. package/examples/mcp-data-boundary.sh +1 -1
  347. package/examples/mcp-misdiagnosis-arrest.sh +209 -0
  348. package/examples/mcp-orphan-leak-warner.sh +49 -0
  349. package/examples/mcp-permissions-ask-warner.sh +151 -0
  350. package/examples/mcp-routine-approval-detector.sh +154 -0
  351. package/examples/mcp-server-allowlist.sh +12 -0
  352. package/examples/mcp-server-guard.sh +12 -0
  353. package/examples/mcp-startup-bloat-detector.sh +87 -0
  354. package/examples/mcp-stdio-compatibility-test.sh +153 -0
  355. package/examples/mcp-tool-audit-log.sh +0 -0
  356. package/examples/mcp-tool-guard.sh +101 -1
  357. package/examples/mcp-warmup-wait.sh +0 -0
  358. package/examples/memory-chain-audit.sh +56 -0
  359. package/examples/memory-orphan-detector.sh +188 -0
  360. package/examples/memory-write-guard.sh +99 -17
  361. package/examples/migration-verify-guard.sh +12 -0
  362. package/examples/model-swap-suggester.sh +177 -0
  363. package/examples/model-version-alert.sh +5 -1
  364. package/examples/model-version-lock.sh +63 -0
  365. package/examples/move-delete-sequence-guard.sh +33 -2
  366. package/examples/multi-file-plan-routing-gate.sh +192 -0
  367. package/examples/multi-vendor-concurrent-warner.sh +108 -0
  368. package/examples/multi-window-auth-drift-detector.sh +183 -0
  369. package/examples/multiline-command-approver.sh +161 -23
  370. package/examples/nested-background-agent-guard.sh +109 -0
  371. package/examples/nested-spawn-inflight-guard.sh +178 -0
  372. package/examples/network-exfil-guard.sh +12 -0
  373. package/examples/network-guard.sh +12 -0
  374. package/examples/network-interface-guard.sh +12 -0
  375. package/examples/nextjs-env-guard.sh +1 -1
  376. package/examples/no-absolute-import.sh +0 -0
  377. package/examples/no-alert-confirm-prompt.sh +0 -0
  378. package/examples/no-anonymous-default-export.sh +0 -0
  379. package/examples/no-any-type.sh +0 -0
  380. package/examples/no-any-typescript.sh +1 -0
  381. package/examples/no-ask-human.sh +12 -0
  382. package/examples/no-assignment-in-condition.sh +0 -0
  383. package/examples/no-base64-exfil.sh +12 -0
  384. package/examples/no-callback-hell.sh +0 -0
  385. package/examples/no-circular-dependency.sh +0 -0
  386. package/examples/no-cleartext-storage.sh +0 -0
  387. package/examples/no-commented-code.sh +0 -0
  388. package/examples/no-commit-fixup.sh +0 -0
  389. package/examples/no-console-assert.sh +0 -0
  390. package/examples/no-console-error-swallow.sh +0 -0
  391. package/examples/no-console-in-prod.sh +0 -0
  392. package/examples/no-console-log-commit.sh +12 -0
  393. package/examples/no-console-log.sh +0 -0
  394. package/examples/no-console-time.sh +0 -0
  395. package/examples/no-cors-wildcard.sh +4 -1
  396. package/examples/no-curl-upload.sh +0 -0
  397. package/examples/no-dangerouslySetInnerHTML.sh +0 -0
  398. package/examples/no-dangling-await.sh +1 -0
  399. package/examples/no-debug-commit.sh +12 -0
  400. package/examples/no-debug-in-commit.sh +0 -0
  401. package/examples/no-deep-nesting.sh +0 -0
  402. package/examples/no-deep-relative-import.sh +1 -0
  403. package/examples/no-default-credentials.sh +0 -0
  404. package/examples/no-deploy-friday.sh +13 -1
  405. package/examples/no-disabled-test.sh +0 -0
  406. package/examples/no-document-write.sh +0 -0
  407. package/examples/no-empty-function.sh +0 -0
  408. package/examples/no-eval-in-template.sh +0 -0
  409. package/examples/no-eval-template.sh +3 -1
  410. package/examples/no-eval.sh +0 -0
  411. package/examples/no-exec-user-input.sh +0 -0
  412. package/examples/no-fixme-ship.sh +12 -0
  413. package/examples/no-floating-promises.sh +0 -0
  414. package/examples/no-force-flag.sh +22 -5
  415. package/examples/no-force-install.sh +0 -0
  416. package/examples/no-git-amend.sh +12 -0
  417. package/examples/no-git-rebase-public.sh +0 -0
  418. package/examples/no-global-install.sh +12 -0
  419. package/examples/no-global-state.sh +0 -0
  420. package/examples/no-hardcoded-port.sh +1 -0
  421. package/examples/no-hardcoded-url.sh +0 -0
  422. package/examples/no-helmet-missing.sh +0 -0
  423. package/examples/no-http-url.sh +1 -0
  424. package/examples/no-http-without-https.sh +0 -0
  425. package/examples/no-inline-style.sh +0 -0
  426. package/examples/no-inline-styles.sh +1 -0
  427. package/examples/no-innerhtml.sh +0 -0
  428. package/examples/no-install-global.sh +12 -0
  429. package/examples/no-jwt-in-url.sh +0 -0
  430. package/examples/no-large-commit.sh +0 -0
  431. package/examples/no-localhost-expose.sh +0 -0
  432. package/examples/no-magic-number.sh +0 -0
  433. package/examples/no-md5-sha1.sh +0 -0
  434. package/examples/no-mixed-line-endings.sh +8 -1
  435. package/examples/no-mutation-in-reducer.sh +0 -0
  436. package/examples/no-nested-ternary.sh +0 -0
  437. package/examples/no-network-exfil.sh +0 -0
  438. package/examples/no-open-redirect.sh +0 -0
  439. package/examples/no-output-truncation.sh +12 -0
  440. package/examples/no-package-downgrade.sh +0 -0
  441. package/examples/no-package-lock-edit.sh +12 -0
  442. package/examples/no-path-join-user-input.sh +0 -0
  443. package/examples/no-port-bind.sh +0 -0
  444. package/examples/no-process-exit.sh +0 -0
  445. package/examples/no-prototype-pollution.sh +0 -0
  446. package/examples/no-push-without-ci.sh +0 -0
  447. package/examples/no-push-without-tests.sh +12 -0
  448. package/examples/no-raw-password-in-url.sh +0 -0
  449. package/examples/no-root-user-docker.sh +1 -0
  450. package/examples/no-root-write.sh +12 -0
  451. package/examples/no-secrets-in-args.sh +4 -1
  452. package/examples/no-secrets-in-logs.sh +0 -0
  453. package/examples/no-sensitive-log.sh +0 -0
  454. package/examples/no-sleep-in-hooks.sh +0 -0
  455. package/examples/no-star-import-python.sh +1 -0
  456. package/examples/no-string-concat-sql.sh +0 -0
  457. package/examples/no-sudo-guard.sh +12 -0
  458. package/examples/no-sync-fs.sh +0 -0
  459. package/examples/no-todo-in-merge.sh +0 -0
  460. package/examples/no-todo-in-production.sh +1 -0
  461. package/examples/no-todo-without-issue.sh +0 -0
  462. package/examples/no-unused-import.sh +0 -0
  463. package/examples/no-var-keyword.sh +0 -0
  464. package/examples/no-verify-blocker.sh +12 -0
  465. package/examples/no-wget-piped-bash.sh +12 -0
  466. package/examples/no-wildcard-cors.sh +0 -0
  467. package/examples/no-wildcard-delete.sh +0 -0
  468. package/examples/no-wildcard-import.sh +0 -0
  469. package/examples/no-with-statement.sh +0 -0
  470. package/examples/no-write-outside-src.sh +0 -0
  471. package/examples/no-xml-external-entity.sh +0 -0
  472. package/examples/non-english-quality-warner.sh +156 -0
  473. package/examples/notify-waiting.sh +1 -1
  474. package/examples/npm-audit-warn.sh +0 -0
  475. package/examples/npm-global-install-guard.sh +12 -0
  476. package/examples/npm-publish-guard.sh +12 -0
  477. package/examples/npm-script-injection.sh +0 -0
  478. package/examples/npm-supply-chain-guard.sh +0 -0
  479. package/examples/nuxt-config-guard.sh +1 -0
  480. package/examples/oauth-refresh-monitor.sh +210 -0
  481. package/examples/opus-degradation-tracker.sh +187 -0
  482. package/examples/opus48-routine-task-warning.sh +196 -0
  483. package/examples/opus48-thinking-wedge-advisor.sh +143 -0
  484. package/examples/output-credential-scan.sh +1 -1
  485. package/examples/output-secret-mask.sh +31 -9
  486. package/examples/output-token-spike-detector.sh +145 -0
  487. package/examples/package-json-guard.sh +12 -0
  488. package/examples/package-lock-frozen.sh +12 -0
  489. package/examples/parallel-batch-size-limiter.sh +121 -0
  490. package/examples/parallel-cascade-detector.sh +116 -0
  491. package/examples/partial-view-claim-arrest.sh +174 -0
  492. package/examples/path-deny-bash-guard.sh +12 -0
  493. package/examples/path-traversal-guard.sh +12 -0
  494. package/examples/per-prompt-token-cap.sh +124 -0
  495. package/examples/permission-audit-log.sh +1 -1
  496. package/examples/permission-denial-enforcer.sh +12 -0
  497. package/examples/permission-entry-validator.sh +0 -0
  498. package/examples/persisted-1m-model-advisor.sh +88 -0
  499. package/examples/php-lint-on-edit.sh +1 -1
  500. package/examples/pii-upload-guard.sh +12 -0
  501. package/examples/pip-publish-guard.sh +13 -0
  502. package/examples/pip-requirements-guard.sh +12 -0
  503. package/examples/pip-venv-required.sh +12 -0
  504. package/examples/plan-mode-edit-guard.sh +12 -0
  505. package/examples/plan-mode-enforcer.sh +12 -0
  506. package/examples/plan-mode-strict-guard.sh +12 -0
  507. package/examples/plugin-hooks-json-bloat-detector.sh +169 -0
  508. package/examples/plugin-process-cleanup.sh +0 -0
  509. package/examples/polyglot-rm-guard.sh +12 -0
  510. package/examples/post-compact-safety.sh +12 -0
  511. package/examples/post-edit-disk-verify.sh +152 -0
  512. package/examples/powershell-remove-item-guard.sh +85 -0
  513. package/examples/pr-description-check.sh +0 -0
  514. package/examples/pr-duplicate-guard.sh +13 -0
  515. package/examples/pre-bash-sed-line-ending-windows.sh +87 -0
  516. package/examples/pre-compact-knowledge-save.sh +0 -0
  517. package/examples/pre-compact-transcript-backup.sh +0 -0
  518. package/examples/pre-execution-claim-detector.sh +179 -0
  519. package/examples/prefer-builtin-tools.sh +10 -1
  520. package/examples/prefer-const.sh +0 -0
  521. package/examples/prefer-dedicated-tools.sh +12 -0
  522. package/examples/prefer-optional-chaining.sh +0 -0
  523. package/examples/prisma-migrate-guard.sh +24 -7
  524. package/examples/production-port-kill-guard.sh +12 -0
  525. package/examples/prompt-injection-guard.sh +2 -1
  526. package/examples/prompt-usage-logger.sh +0 -0
  527. package/examples/protect-claudemd.sh +12 -0
  528. package/examples/protect-dotfiles.sh +12 -0
  529. package/examples/proxy-capture-suggester.sh +159 -0
  530. package/examples/public-artefact-socratic-narrowing.sh +232 -0
  531. package/examples/public-repo-push-guard.sh +12 -0
  532. package/examples/push-requires-test-pass-record.sh +0 -0
  533. package/examples/push-requires-test-pass.sh +12 -0
  534. package/examples/quota-anomaly-detector.sh +173 -0
  535. package/examples/quota-reset-audit.sh +58 -0
  536. package/examples/quoted-flag-approver.sh +99 -10
  537. package/examples/rails-migration-guard.sh +12 -0
  538. package/examples/rate-limit-guard.sh +0 -0
  539. package/examples/read-all-files-enforcer.sh +0 -0
  540. package/examples/read-budget-guard.sh +12 -0
  541. package/examples/read-loop-detector.sh +59 -0
  542. package/examples/read-once-guard.sh +96 -0
  543. package/examples/read-only-mode.sh +12 -0
  544. package/examples/readme-exists-check.sh +0 -0
  545. package/examples/record-read-coverage.sh +73 -0
  546. package/examples/redirect-fragment-warner.sh +149 -0
  547. package/examples/redis-flushall-guard.sh +13 -0
  548. package/examples/redundant-read-blocker.sh +132 -0
  549. package/examples/refusal-arrest-gate.sh +248 -0
  550. package/examples/registry-publish-guard.sh +13 -1
  551. package/examples/remote-control-billing-classifier.sh +135 -0
  552. package/examples/replace-all-guard.sh +12 -0
  553. package/examples/repo-visibility-guard.sh +12 -0
  554. package/examples/reroute-after-block-guard.sh +150 -0
  555. package/examples/response-budget-guard.sh +0 -0
  556. package/examples/resume-drift-watcher.sh +57 -0
  557. package/examples/rg-replace-flag-detector.sh +125 -0
  558. package/examples/rhetorical-verification-prompt-detector.sh +102 -0
  559. package/examples/ripgrep-permission-fix.sh +0 -0
  560. package/examples/rm-safety-net.sh +151 -8
  561. package/examples/role-tool-guard.sh +12 -0
  562. package/examples/route-handler-emptiness-gate.sh +324 -0
  563. package/examples/ruby-lint-on-edit.sh +1 -1
  564. package/examples/runtime-binary-change-detector.sh +102 -0
  565. package/examples/same-command-repeat-detector.sh +196 -0
  566. package/examples/same-correction-arrest.sh +169 -0
  567. package/examples/sandbox-denywrite-enforcer.sh +78 -0
  568. package/examples/sandbox-relative-path-audit.sh +83 -25
  569. package/examples/sandbox-write-verify.sh +12 -0
  570. package/examples/schema-migration-guard.sh +0 -0
  571. package/examples/scope-expansion-receipt.sh +178 -0
  572. package/examples/scope-guard.sh +88 -9
  573. package/examples/secret-file-read-guard.sh +12 -0
  574. package/examples/secret-file-write-guard.sh +150 -0
  575. package/examples/self-modify-bypass-guard.sh +0 -0
  576. package/examples/sensitive-file-read-guard.sh +23 -3
  577. package/examples/sensitive-log-guard.sh +1 -0
  578. package/examples/server-side-prompt-injection-detector.sh +69 -0
  579. package/examples/session-agent-cost-limiter.sh +12 -0
  580. package/examples/session-backup-on-start.sh +1 -1
  581. package/examples/session-cost-alert.sh +12 -0
  582. package/examples/session-drift-guard.sh +12 -0
  583. package/examples/session-duration-guard.sh +25 -2
  584. package/examples/session-end-logger.sh +0 -0
  585. package/examples/session-health-monitor.sh +0 -0
  586. package/examples/session-index-repair.sh +1 -1
  587. package/examples/session-memory-watchdog.sh +1 -0
  588. package/examples/session-permission-reset-guard.sh +12 -0
  589. package/examples/session-persistence-verifier.sh +93 -0
  590. package/examples/session-plugin-pin-watch.sh +68 -0
  591. package/examples/session-rate-monitor.sh +176 -0
  592. package/examples/session-resume-env-fix.sh +0 -0
  593. package/examples/session-start-quota-status.sh +193 -0
  594. package/examples/session-start-safety-check.sh +55 -3
  595. package/examples/session-state-saver.sh +0 -0
  596. package/examples/session-summary-stop.sh +1 -1
  597. package/examples/session-summary.sh +0 -0
  598. package/examples/session-token-counter.sh +1 -1
  599. package/examples/settings-hooks-key-restorer.sh +99 -0
  600. package/examples/settings-json-health-check.sh +57 -0
  601. package/examples/settings-json-model-guard.sh +0 -0
  602. package/examples/settings-regression-tester.sh +188 -0
  603. package/examples/shell-config-truncation-guard.sh +12 -0
  604. package/examples/shell-wrapper-guard.sh +12 -0
  605. package/examples/skill-cumulative-size-detector.sh +104 -0
  606. package/examples/skill-description-drop-detector.sh +148 -0
  607. package/examples/skill-gate.sh +0 -0
  608. package/examples/skill-truncation-detector.sh +154 -0
  609. package/examples/skills-context-recorder.sh +167 -0
  610. package/examples/skills-load-verifier.sh +96 -0
  611. package/examples/skills-settings-validator.sh +139 -0
  612. package/examples/sonnet-45-deprecation-helper.sh +85 -0
  613. package/examples/spec-file-scope-guard.sh +12 -0
  614. package/examples/spring-profile-guard.sh +1 -0
  615. package/examples/spurious-malformed-notice-detector.sh +247 -0
  616. package/examples/sql-bulk-delete-warn.sh +88 -0
  617. package/examples/sql-injection-detect.sh +0 -0
  618. package/examples/ssh-key-protect.sh +12 -0
  619. package/examples/staged-secret-scan.sh +22 -1
  620. package/examples/stale-temp-settings-detector.sh +86 -0
  621. package/examples/standing-rule-session-surfacer.sh +137 -0
  622. package/examples/stop-hook-sigterm-wrapper.sh +182 -0
  623. package/examples/stop-transcript-write-health.sh +64 -0
  624. package/examples/strict-allowlist.sh +57 -15
  625. package/examples/strip-coauthored-by.sh +50 -10
  626. package/examples/subagent-blast-radius-guard.sh +184 -0
  627. package/examples/subagent-boundary-precheck.sh +126 -0
  628. package/examples/subagent-budget-guard.sh +12 -0
  629. package/examples/subagent-claudemd-inject.sh +0 -0
  630. package/examples/subagent-closure-verify-gate.sh +164 -0
  631. package/examples/subagent-destructive-git-guard.sh +120 -0
  632. package/examples/subagent-error-detector.sh +0 -0
  633. package/examples/subagent-forged-system-reminder-guard.sh +156 -0
  634. package/examples/subagent-identity-leak-guard.sh +102 -0
  635. package/examples/subagent-identity-reassertion.sh +51 -0
  636. package/examples/subagent-inheritance-tester.sh +179 -0
  637. package/examples/subagent-permission-mode-guard.sh +110 -0
  638. package/examples/subagent-scope-guard.sh +12 -0
  639. package/examples/subagent-spawn-verification-enforcer.sh +102 -0
  640. package/examples/subagent-tool-allowlist-enforcer.sh +101 -0
  641. package/examples/subagent-tool-call-limiter.sh +87 -15
  642. package/examples/subcommand-chain-guard.sh +12 -0
  643. package/examples/subscription-api-billing-warner.sh +160 -0
  644. package/examples/subscription-bypass-detector.sh +152 -0
  645. package/examples/svelte-lint-on-edit.sh +1 -0
  646. package/examples/swift-build-on-edit.sh +1 -1
  647. package/examples/symlink-guard.sh +27 -2
  648. package/examples/symlink-protect.sh +1 -0
  649. package/examples/system-dir-protection-guard.sh +73 -8
  650. package/examples/system-message-workaround.sh +38 -13
  651. package/examples/system-package-guard.sh +12 -0
  652. package/examples/systemd-service-guard.sh +12 -0
  653. package/examples/task-integrity-guard.sh +12 -0
  654. package/examples/temp-file-cleanup.sh +1 -1
  655. package/examples/temporal-suggestion-detector.sh +135 -0
  656. package/examples/terraform-guard.sh +27 -6
  657. package/examples/test-after-edit.sh +1 -1
  658. package/examples/test-before-push.sh +12 -0
  659. package/examples/test-coverage-reminder.sh +24 -1
  660. package/examples/thinking-budget-effort-mismatch-detector.sh +149 -0
  661. package/examples/thinking-stall-detector.sh +61 -0
  662. package/examples/timezone-guard.sh +0 -0
  663. package/examples/tmp-output-size-guard.sh +0 -0
  664. package/examples/todo-check.sh +1 -1
  665. package/examples/token-budget-guard.sh +12 -0
  666. package/examples/token-budget-per-task.sh +12 -0
  667. package/examples/token-usage-tracker.sh +7 -1
  668. package/examples/tokenizer-ratio-alert-corpus.sh +90 -0
  669. package/examples/tokenizer-ratio-alert.sh +104 -0
  670. package/examples/tool-call-rate-limiter.sh +0 -0
  671. package/examples/tool-result-correlation-checker.sh +167 -0
  672. package/examples/tool-result-size-guard.sh +132 -0
  673. package/examples/tool-retry-budget-guard.sh +12 -0
  674. package/examples/transcript-contamination-detector.sh +138 -0
  675. package/examples/trustfall-mcp-injection-guard.sh +103 -0
  676. package/examples/ultrareview-large-diff-advisor.sh +184 -0
  677. package/examples/unbounded-output-guard.sh +94 -0
  678. package/examples/uncommitted-changes-stop.sh +1 -0
  679. package/examples/uncommitted-discard-guard.sh +23 -5
  680. package/examples/uncommitted-work-guard.sh +12 -0
  681. package/examples/usage-warn.sh +0 -0
  682. package/examples/user-account-guard.sh +12 -0
  683. package/examples/userprompt-submit-receipt.sh +123 -0
  684. package/examples/variable-expansion-guard.sh +12 -0
  685. package/examples/verify-after-publish-reminder.sh +93 -0
  686. package/examples/verify-before-commit.sh +12 -0
  687. package/examples/version-bump-detector.sh +156 -0
  688. package/examples/version-regression-warner.sh +144 -0
  689. package/examples/vue-lint-on-edit.sh +1 -0
  690. package/examples/warn-cron-cost-trap.sh +173 -0
  691. package/examples/webfetch-runaway-guard.sh +89 -0
  692. package/examples/wellness-break-reminder.sh +118 -0
  693. package/examples/windows-destructive-command-guard.sh +177 -0
  694. package/examples/windows-path-guard.sh +12 -0
  695. package/examples/windows-python-stub-detector.sh +63 -0
  696. package/examples/work-hours-guard.sh +12 -0
  697. package/examples/working-directory-fence.sh +12 -0
  698. package/examples/workspace-lease-guard.sh +205 -0
  699. package/examples/worktree-create-log.sh +1 -0
  700. package/examples/worktree-delete-guard.sh +12 -0
  701. package/examples/worktree-edit-boundary-guard.sh +127 -0
  702. package/examples/worktree-escape-write-guard.sh +114 -0
  703. package/examples/worktree-hook-linker.sh +0 -0
  704. package/examples/worktree-hooks-path-fix.sh +111 -0
  705. package/examples/worktree-parent-write-guard.sh +43 -0
  706. package/examples/worktree-project-unify.sh +2 -1
  707. package/examples/worktree-remove-uncommitted-guard.sh +13 -0
  708. package/examples/worktree-unmerged-guard.sh +7 -1
  709. package/examples/write-byte-integrity-verifier.sh +190 -0
  710. package/examples/write-empty-content-guard.sh +67 -0
  711. package/examples/write-nul-corruption-detector.sh +61 -0
  712. package/examples/write-overwrite-confirm.sh +160 -14
  713. package/examples/write-secret-guard.sh +27 -5
  714. package/examples/write-shrink-guard.sh +12 -0
  715. package/examples/write-test-ratio.sh +0 -0
  716. package/examples/wsl-host-disk-space-guard.sh +97 -0
  717. package/examples/xml-format-leak-detector.sh +266 -0
  718. package/examples/yaml-syntax-check.sh +12 -0
  719. package/hooks/hooks.json +6 -6
  720. package/index.mjs +1699 -183
  721. package/mission.md +2 -0
  722. package/package.json +4 -4
  723. package/plugins/credential-guard/.claude-plugin/plugin.json +9 -7
  724. package/plugins/git-protection/.claude-plugin/plugin.json +10 -8
  725. package/plugins/safety-essentials/.claude-plugin/plugin.json +9 -7
  726. package/plugins/token-guard/.claude-plugin/plugin.json +10 -8
  727. package/scripts/agents-md-sync-setup.sh +156 -0
  728. package/scripts/autonomy-blocked-summary.sh +148 -0
  729. package/scripts/build-search-index.py +43 -0
  730. package/scripts/build-sitemap.py +119 -0
  731. package/scripts/cc-doctor.sh +192 -0
  732. package/scripts/check-hook-event-names.py +127 -0
  733. package/scripts/check-misfire-instrument.sh +64 -0
  734. package/scripts/claim-verify-audit.sh +467 -0
  735. package/scripts/cowork-claudemd-helper.sh +136 -0
  736. package/scripts/june-15-deprecated-model-scan.sh +111 -0
  737. package/scripts/measure-heredoc-shapes.sh +67 -0
  738. package/scripts/measure-literal-match-misfire.sh +110 -0
  739. package/scripts/probe-scope-guard-branches.sh +48 -0
  740. package/scripts/probe-skip-line-both-ways.sh +65 -0
  741. package/scripts/receipts-aggregate.py +199 -0
  742. package/scripts/session-forensic-audit.py +360 -0
  743. package/scripts.json +9 -9
  744. package/scripts.json.bak-2026-07-27-find +13 -0
  745. package/skills/safety-setup/SKILL.md +5 -5
  746. package/tests/approve-side-remaining-two.test.sh +129 -0
  747. package/tests/approver-list-granularity.test.sh +145 -0
  748. package/tests/askuserquestion-autonomy-gate.test.sh +181 -0
  749. package/tests/audit-ci-gate.test.sh +87 -0
  750. package/tests/audit-cross-layer-claudemd.test.sh +170 -0
  751. package/tests/audit-fail-open-parse.test.sh +100 -0
  752. package/tests/auto-approve-compound-tail.test.sh +194 -0
  753. package/tests/auto-mode-path-invoked-commands.test.sh +89 -0
  754. package/tests/auto-mode-quoted-targets.test.sh +127 -0
  755. package/tests/auto-mode-unquoted-targets.test.sh +112 -0
  756. package/tests/bash-secret-output-detector-detects.test.sh +102 -0
  757. package/tests/blindspots-cross-layer.test.sh +177 -0
  758. package/tests/block-database-wipe.test.sh +64 -0
  759. package/tests/bundled-short-flags-bypass.test.sh +85 -0
  760. package/tests/cd-git-allow-compound-tail.test.sh +67 -0
  761. package/tests/chown-guard-filesystem-root.test.sh +64 -0
  762. package/tests/ci-workflow-guard-skip-rule.test.sh +115 -0
  763. package/tests/compound-deny-safe-rm-targets.test.sh +105 -0
  764. package/tests/core-scripts-parser-fallback.test.sh +140 -0
  765. package/tests/destructive-guard-bare-glob.test.sh +74 -0
  766. package/tests/destructive-guard-every-operand.test.sh +100 -0
  767. package/tests/destructive-guard-find-deletion.test.sh +114 -0
  768. package/tests/destructive-guard-flag-order.test.sh +106 -0
  769. package/tests/destructive-guard-mentions-vs-invocations.test.sh +107 -0
  770. package/tests/destructive-guard-quoted-target.test.sh +89 -0
  771. package/tests/destructive-guard-separators.test.sh +105 -0
  772. package/tests/destructive-guard-variable-target.test.sh +98 -0
  773. package/tests/destructive-guard-wrapped-command.test.sh +91 -0
  774. package/tests/doctor-hook-disabling-env.test.sh +92 -0
  775. package/tests/doctor-misspelled-settings-keys.test.sh +106 -0
  776. package/tests/example-guards-wrapped-command.test.sh +169 -0
  777. package/tests/file-edit-backup.test.sh +93 -0
  778. package/tests/git-filter-repo-guard.test.sh +60 -0
  779. package/tests/git-global-options-bypass.test.sh +141 -0
  780. package/tests/git-invocation-prefixes-all-guards.test.sh +114 -0
  781. package/tests/git-maintenance-guard.test.sh +83 -0
  782. package/tests/git-pack-temp-cleanup-guard.test.sh +133 -0
  783. package/tests/git-rm-orphan-wipe-guard.test.sh +66 -0
  784. package/tests/git-submodule-guard.test.sh +50 -0
  785. package/tests/grep-pcre-portability.test.sh +155 -0
  786. package/tests/hook-registration-matches-input.test.sh +73 -0
  787. package/tests/hook-trigger-matches-envelope.test.sh +178 -0
  788. package/tests/install-does-not-claim-protection.test.sh +110 -0
  789. package/tests/install-example-standalone-tools.test.sh +139 -0
  790. package/tests/line-continuation-bypass.test.sh +114 -0
  791. package/tests/mcp-config-poisoning-audit.test.sh +106 -0
  792. package/tests/nested-background-agent-guard.test.sh +58 -0
  793. package/tests/no-unqualified-safety-claims.test.sh +114 -0
  794. package/tests/option-eating-grep-patterns.test.sh +130 -0
  795. package/tests/outdated-core-guards.test.sh +134 -0
  796. package/tests/outdated-report.test.sh +155 -0
  797. package/tests/output-secret-mask-warns.test.sh +73 -0
  798. package/tests/plugin-hooks-fail-open-under-sh.test.sh +165 -0
  799. package/tests/plugins-word-order.test.sh +126 -0
  800. package/tests/powershell-remove-item-guard.test.sh +85 -0
  801. package/tests/project-dir-naming.test.sh +103 -0
  802. package/tests/quoted-safe-targets-and-mentions.test.sh +190 -0
  803. package/tests/reroute-after-block-guard.test.sh +104 -0
  804. package/tests/secret-guard-documented-promises.test.sh +97 -0
  805. package/tests/session-plugin-pin-watch.test.sh +45 -0
  806. package/tests/settings-unreadable-refuses-to-write.test.sh +95 -0
  807. package/tests/shield-no-silent-adoption.test.py +110 -0
  808. package/tests/shield-no-silent-adoption.test.sh +46 -0
  809. package/tests/stop-transcript-write-health.test.sh +46 -0
  810. package/tests/system-dir-guard-root-erased.test.sh +66 -0
  811. package/tests/test-account-billing-log.sh +100 -0
  812. package/tests/test-account-routing-preflight.sh +77 -0
  813. package/tests/test-agent-sdk-credit-pool-monitor.sh +157 -0
  814. package/tests/test-agent-view-quota-warn.sh +184 -0
  815. package/tests/test-agents-md-edit-drift-warner.sh +176 -0
  816. package/tests/test-agents-md-loader.sh +204 -0
  817. package/tests/test-agents-md-sync-checker.sh +125 -0
  818. package/tests/test-ai-slop-punctuation-arrest.sh +280 -0
  819. package/tests/test-allowlist.sh +60 -0
  820. package/tests/test-always-allow-pattern-suggester.sh +147 -0
  821. package/tests/test-anthropic-base-url-guard.sh +88 -0
  822. package/tests/test-articulated-scope-capture.sh +139 -0
  823. package/tests/test-attachment-traversal-guard.sh +168 -0
  824. package/tests/test-aup-block-pattern-logger.sh +315 -0
  825. package/tests/test-aup-false-positive-helper.sh +188 -0
  826. package/tests/test-aup-large-tool-output-warner.sh +370 -0
  827. package/tests/test-aup-retry-loop-guard.sh +341 -0
  828. package/tests/test-auth-expiry-reminder.sh +303 -0
  829. package/tests/test-auth-macos-sleep-detector.sh +254 -0
  830. package/tests/test-auth-path-detector.sh +232 -0
  831. package/tests/test-auth-status-checker.sh +233 -0
  832. package/tests/test-authorized-reconfirmation-detector.sh +280 -0
  833. package/tests/test-background-cost-launch-guard.sh +62 -0
  834. package/tests/test-bash-allowlist-secondary-check.sh +143 -0
  835. package/tests/test-bash-fanout-bounded-rewriter.sh +186 -0
  836. package/tests/test-bash-project-fence.sh +127 -0
  837. package/tests/test-bg-permission-prompt-warner.sh +221 -0
  838. package/tests/test-binary-read-detector.sh +173 -0
  839. package/tests/test-broad-prefix-session-trap-warner.sh +167 -0
  840. package/tests/test-bulk-delete-target-resolution.sh +49 -0
  841. package/tests/test-bypass-mode-effective-verifier.sh +179 -0
  842. package/tests/test-cache-creation-drift-detector.sh +244 -0
  843. package/tests/test-cache-residue-detector.sh +429 -0
  844. package/tests/test-cache-tier-logger.sh +59 -0
  845. package/tests/test-cache-ttl-eviction-detector.sh +282 -0
  846. package/tests/test-cch-sentinel-precommit-guard.sh +64 -0
  847. package/tests/test-claim-verify-detector.sh +222 -0
  848. package/tests/test-claim-vs-caveat-checker.sh +134 -0
  849. package/tests/test-claude-code-version-pin-advisor.sh +353 -0
  850. package/tests/test-claude-md-reinjector.sh +173 -0
  851. package/tests/test-claude-md-size-monitor.sh +107 -0
  852. package/tests/test-claude-update-budget-guard.sh +132 -0
  853. package/tests/test-claude-update-smart.sh +91 -0
  854. package/tests/test-claudemd-tool-prohibition.sh +239 -0
  855. package/tests/test-cli-config-pinning-detector.sh +233 -0
  856. package/tests/test-cliff-countdown-advisor.sh +138 -0
  857. package/tests/test-closure-word-verify-gate.sh +158 -0
  858. package/tests/test-commit-all-scope-guard.sh +73 -0
  859. package/tests/test-commitment-carry-forward-arrest.sh +250 -0
  860. package/tests/test-compact-circuit-breaker.sh +134 -0
  861. package/tests/test-compact-dispatch-watchdog.sh +147 -0
  862. package/tests/test-completion-claim-without-verification-detector.sh +326 -0
  863. package/tests/test-compound-bash-permission-resolver.sh +264 -0
  864. package/tests/test-compound-command-deny-enforcer.sh +67 -0
  865. package/tests/test-context-length-budget.sh +68 -0
  866. package/tests/test-context-usage-drift-alert.sh +52 -22
  867. package/tests/test-cost-incident-self-audit.sh +94 -0
  868. package/tests/test-cowork-claude-md-load-checker.sh +257 -0
  869. package/tests/test-cowork-claudemd-helper.sh +141 -0
  870. package/tests/test-cowork-fuse-staleness-watcher.sh +287 -0
  871. package/tests/test-cowork-hook-absence-warner.sh +230 -0
  872. package/tests/test-cowork-model-picker-advisor.sh +317 -0
  873. package/tests/test-credential-exfil-guard.sh +62 -0
  874. package/tests/test-cron-create-receipt.sh +165 -0
  875. package/tests/test-cross-product-mcp-spawn-detector.sh +112 -0
  876. package/tests/test-daemon-zombie-worker-surfacer.sh +71 -0
  877. package/tests/test-daily-cost-guard.sh +131 -0
  878. package/tests/test-deny-rule-integrity-verifier.sh +288 -0
  879. package/tests/test-deployment-readback-gate.sh +92 -0
  880. package/tests/test-deployment-readback-gh-adapter.sh +163 -0
  881. package/tests/test-disabled-feature-toggle-advisor.sh +78 -0
  882. package/tests/test-dispatch-allowlist-preflight.sh +385 -0
  883. package/tests/test-dispatch-liveness-watchdog.sh +319 -0
  884. package/tests/test-dispatch-receipt.sh +314 -0
  885. package/tests/test-dotenv-anthropic-key-billing-guard.sh +160 -0
  886. package/tests/test-echo-probe-spam-detector.sh +143 -0
  887. package/tests/test-edit-quote-ambiguity-guard.sh +75 -0
  888. package/tests/test-ephemeral-container-detector.sh +251 -0
  889. package/tests/test-evidence-claim-gate.sh +291 -0
  890. package/tests/test-exploration-budget-guard.sh +164 -0
  891. package/tests/test-extended-thinking-loop-guard.sh +289 -0
  892. package/tests/test-extended-thinking-resume-warning.sh +240 -0
  893. package/tests/test-extended-thinking-tool-use-mismatch-detector.sh +236 -0
  894. package/tests/test-fabricated-command-detector.sh +296 -0
  895. package/tests/test-false-disk-full-guard.sh +36 -0
  896. package/tests/test-feature-deprecation-detector.sh +117 -0
  897. package/tests/test-forbidden-response-phrase-detector.sh +246 -0
  898. package/tests/test-git-operations-require-approval.sh +53 -0
  899. package/tests/test-git-push-blast-radius-guard.sh +115 -0
  900. package/tests/test-goal-iteration-limit-warner.sh +128 -0
  901. package/tests/test-growthbook-flag-monitor.sh +428 -0
  902. package/tests/test-halt-signal-detector.sh +120 -0
  903. package/tests/test-hook-self-disable-detector.sh +232 -0
  904. package/tests/test-iteration-quality-degradation-detector.sh +244 -0
  905. package/tests/test-long-session-malformed-tool-call-detector.sh +185 -0
  906. package/tests/test-marketplace-plugins.sh +193 -0
  907. package/tests/test-mcp-misdiagnosis-arrest.sh +235 -0
  908. package/tests/test-mcp-orphan-leak-warner.sh +71 -0
  909. package/tests/test-mcp-permissions-ask-warner.sh +207 -0
  910. package/tests/test-mcp-routine-approval-detector.sh +229 -0
  911. package/tests/test-mcp-startup-bloat-detector.sh +141 -0
  912. package/tests/test-mcp-stdio-compatibility-test.sh +112 -0
  913. package/tests/test-memory-chain-audit.sh +59 -0
  914. package/tests/test-memory-orphan-detector.sh +227 -0
  915. package/tests/test-model-swap-suggester.sh +368 -0
  916. package/tests/test-model-version-lock.sh +83 -0
  917. package/tests/test-multi-file-plan-routing-gate.sh +277 -0
  918. package/tests/test-multi-window-auth-drift-detector.sh +262 -0
  919. package/tests/test-nested-spawn-inflight-guard.sh +281 -0
  920. package/tests/test-no-force-flag.sh +49 -0
  921. package/tests/test-non-english-quality-warner.sh +229 -0
  922. package/tests/test-oauth-refresh-monitor.sh +311 -0
  923. package/tests/test-opus-degradation-tracker.sh +274 -0
  924. package/tests/test-opus48-routine-task-warning.sh +201 -0
  925. package/tests/test-opus48-thinking-wedge-advisor.sh +249 -0
  926. package/tests/test-output-token-spike-detector.sh +315 -0
  927. package/tests/test-parallel-batch-size-limiter.sh +228 -0
  928. package/tests/test-parallel-cascade-detector.sh +191 -0
  929. package/tests/test-partial-view-claim-arrest.sh +272 -0
  930. package/tests/test-per-prompt-token-cap.sh +136 -0
  931. package/tests/test-persisted-1m-model-advisor.sh +71 -0
  932. package/tests/test-plugin-hooks-json-bloat-detector.sh +267 -0
  933. package/tests/test-post-edit-disk-verify.sh +294 -0
  934. package/tests/test-pre-bash-sed-line-ending-windows.sh +108 -0
  935. package/tests/test-pre-execution-claim-detector.sh +366 -0
  936. package/tests/test-private-key-backup-and-git-credentials.sh +100 -0
  937. package/tests/test-proxy-capture-suggester.sh +214 -0
  938. package/tests/test-public-artefact-socratic-narrowing.sh +346 -0
  939. package/tests/test-quota-anomaly-detector.sh +321 -0
  940. package/tests/test-quota-reset-audit.sh +81 -0
  941. package/tests/test-read-loop-detector.sh +137 -0
  942. package/tests/test-read-once-guard.sh +85 -0
  943. package/tests/test-receipts-aggregate.sh +143 -0
  944. package/tests/test-redirect-fragment-warner.sh +130 -0
  945. package/tests/test-redundant-read-blocker.sh +155 -0
  946. package/tests/test-refusal-arrest-gate.sh +303 -0
  947. package/tests/test-remote-control-billing-classifier.sh +125 -0
  948. package/tests/test-resume-drift-watcher.sh +65 -0
  949. package/tests/test-rg-replace-flag-detector.sh +175 -0
  950. package/tests/test-rhetorical-verification-prompt-detector.sh +237 -0
  951. package/tests/test-rm-safety-net.sh +115 -0
  952. package/tests/test-route-handler-emptiness-gate.sh +300 -0
  953. package/tests/test-runtime-binary-change-detector.sh +196 -0
  954. package/tests/test-same-command-repeat-detector.sh +165 -0
  955. package/tests/test-same-correction-arrest.sh +165 -0
  956. package/tests/test-scope-expansion-receipt.sh +207 -0
  957. package/tests/test-server-side-prompt-injection-detector.sh +181 -0
  958. package/tests/test-session-persistence-verifier.sh +128 -0
  959. package/tests/test-session-rate-monitor.sh +284 -0
  960. package/tests/test-session-start-quota-status.sh +210 -0
  961. package/tests/test-session-start-safety-check.sh +138 -0
  962. package/tests/test-settings-hooks-key-restorer.sh +257 -0
  963. package/tests/test-settings-json-health-check.sh +70 -0
  964. package/tests/test-settings-regression-tester.sh +197 -0
  965. package/tests/test-skill-cumulative-size-detector.sh +198 -0
  966. package/tests/test-skill-description-drop-detector.sh +236 -0
  967. package/tests/test-skill-truncation-detector.sh +263 -0
  968. package/tests/test-skills-context-recorder.sh +329 -0
  969. package/tests/test-skills-load-verifier.sh +184 -0
  970. package/tests/test-skills-settings-validator.sh +242 -0
  971. package/tests/test-sonnet-45-deprecation-helper.sh +150 -0
  972. package/tests/test-spurious-malformed-notice-detector.sh +290 -0
  973. package/tests/test-sql-bulk-delete-warn.sh +123 -0
  974. package/tests/test-ssh-key-protect.sh +81 -0
  975. package/tests/test-stale-temp-settings-detector.sh +161 -0
  976. package/tests/test-standing-rule-session-surfacer.sh +215 -0
  977. package/tests/test-starter-hooks-manifest.sh +96 -0
  978. package/tests/test-stop-hook-sigterm-wrapper.sh +258 -0
  979. package/tests/test-strict-allowlist.sh +72 -0
  980. package/tests/test-subagent-boundary-precheck.sh +137 -0
  981. package/tests/test-subagent-closure-verify-gate.sh +193 -0
  982. package/tests/test-subagent-destructive-git-guard.sh +86 -0
  983. package/tests/test-subagent-identity-leak-guard.sh +62 -0
  984. package/tests/test-subagent-identity-reassertion.sh +61 -0
  985. package/tests/test-subagent-inheritance-tester.sh +319 -0
  986. package/tests/test-subagent-permission-mode-guard.sh +61 -0
  987. package/tests/test-subagent-spawn-verification-enforcer.sh +60 -0
  988. package/tests/test-subagent-tool-allowlist-enforcer.sh +62 -0
  989. package/tests/test-subagent-tool-call-limiter.sh +97 -0
  990. package/tests/test-subscription-api-billing-warner.sh +138 -0
  991. package/tests/test-subscription-bypass-detector.sh +255 -0
  992. package/tests/test-temporal-suggestion-detector.sh +183 -0
  993. package/tests/test-thinking-budget-effort-mismatch-detector.sh +327 -0
  994. package/tests/test-thinking-stall-detector.sh +151 -0
  995. package/tests/test-tokenizer-ratio-alert-corpus.sh +77 -0
  996. package/tests/test-tokenizer-ratio-alert.sh +93 -0
  997. package/tests/test-tool-result-correlation-checker.sh +264 -0
  998. package/tests/test-tool-result-size-guard.sh +121 -0
  999. package/tests/test-transcript-contamination-detector.sh +264 -0
  1000. package/tests/test-trigger-header-parsing.sh +151 -0
  1001. package/tests/test-ultrareview-large-diff-advisor.sh +192 -0
  1002. package/tests/test-userprompt-submit-receipt.sh +181 -0
  1003. package/tests/test-verify-after-publish-reminder.sh +184 -0
  1004. package/tests/test-version-bump-detector.sh +212 -0
  1005. package/tests/test-version-regression-warner.sh +165 -0
  1006. package/tests/test-warn-cron-cost-trap.sh +82 -0
  1007. package/tests/test-webfetch-runaway-guard.sh +77 -0
  1008. package/tests/test-wellness-break-reminder.sh +138 -0
  1009. package/tests/test-windows-destructive-command-guard.sh +169 -0
  1010. package/tests/test-windows-python-stub-detector.sh +146 -0
  1011. package/tests/test-worktree-edit-boundary-guard.sh +219 -0
  1012. package/tests/test-write-byte-integrity-verifier.sh +192 -0
  1013. package/tests/test-xml-format-leak-detector.sh +299 -0
  1014. package/tests/trustfall-mcp-injection-guard.test.sh +183 -0
  1015. package/tests/workspace-lease-guard.test.sh +144 -0
  1016. package/tests/worktree-escape-write-guard.test.sh +68 -0
  1017. package/tests/worktree-hooks-path-fix.test.sh +181 -0
  1018. package/tests/worktree-parent-write-guard.test.sh +51 -0
  1019. package/tests/write-empty-content-guard.test.sh +39 -0
  1020. package/tests/write-nul-corruption-detector.test.sh +29 -0
  1021. package/tests/write-overwrite-unread-content.test.sh +178 -0
  1022. package/tests/wsl-host-disk-space-guard.test.sh +55 -0
@@ -8,46 +8,123 @@
8
8
  # while letting destructive commands go through normal approval.
9
9
  #
10
10
  # TRIGGER: PreToolUse MATCHER: "Bash"
11
+ #
12
+ # Rewritten 2026-08-03. Two things were wrong, and they compounded.
13
+ #
14
+ # 1. The base command was taken from the FIRST word of the whole line, so
15
+ # `cat README.md && sudo rm -rf app` produced the base `cat` and the
16
+ # approval was handed to the entire line. Same defect as PR #937
17
+ # (allowlist.sh), #940 (cd-git-allow.sh) and #941/#942 (the other
18
+ # auto-approve hooks) — on the approving side, where the decision is an
19
+ # explicit approval rather than a missed block.
20
+ # 2. `find` sat in the read-only list with no look at its predicates, so
21
+ # `find . -name '*.log' -delete` was approved as a read-only command.
22
+ # Redirections had the same shape: `cat x > out` writes a file and was
23
+ # approved for reading one.
24
+ #
25
+ # Now every command position has to qualify on its own, and the forms that
26
+ # write are named. A line that does not qualify gets no decision, which leaves
27
+ # it to the normal permission flow — this hook only ever adds approval, it
28
+ # never blocks.
29
+ #
30
+ # Known limit: quotes are not parsed, so a separator inside a quoted string
31
+ # ends a segment early. That is the conservative direction here (fewer
32
+ # approvals, not more).
11
33
  # ================================================================
12
34
 
13
35
  COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
14
36
  [ -z "$COMMAND" ] && exit 0
15
37
 
16
- # Extract the base command (first word, ignoring env vars and cd prefixes)
17
- BASE=$(echo "$COMMAND" | sed 's/^[A-Z_]*=[^ ]* //g; s/^cd [^;]*[;&|]* //' | awk '{print $1}' | sed 's|.*/||')
18
-
19
- # Read-only commands that never modify anything
20
- case "$BASE" in
21
- cat|head|tail|less|more|wc|grep|rg|ag|ack|find|locate|\
22
- ls|ll|dir|tree|stat|file|which|whereis|type|realpath|\
23
- date|uptime|uname|hostname|whoami|id|groups|env|printenv|\
24
- pwd|df|du|free|top|ps|pgrep|lsof|netstat|ss|\
25
- git-log|git-diff|git-show|git-status|git-branch|git-remote|git-tag|\
26
- jq|yq|python3-c|node-e|ruby-e|\
27
- npm-ls|npm-list|npm-info|npm-view|npm-outdated|\
28
- pip-list|pip-show|pip-freeze|\
29
- cargo-tree|go-list|go-doc)
30
- echo '{"decision":"approve","reason":"Read-only command"}'
31
- exit 0
32
- ;;
38
+ # A substitution can carry a command that no string-level read sees.
39
+ case "$COMMAND" in
40
+ *'$('*|*'`'*) exit 0 ;;
41
+ esac
42
+
43
+ # Anything that writes to a file is not a read, whatever the command word says.
44
+ case "$COMMAND" in
45
+ *'>'*) exit 0 ;;
33
46
  esac
34
47
 
35
- # git subcommands that are read-only
36
- if echo "$COMMAND" | grep -qE '^\s*git\s+(status|log|diff|show|branch|remote|tag\s+-l|blame|shortlog|describe|rev-parse|ls-files|ls-tree)\b'; then
37
- echo '{"decision":"approve","reason":"Read-only git command"}'
38
- exit 0
39
- fi
40
-
41
- # Commands piped to read-only output (anything | head, | grep, etc.)
42
- if echo "$COMMAND" | grep -qE '\|\s*(head|tail|grep|wc|sort|uniq|tr|cut|awk|sed|less|more)\s'; then
43
- # Only approve if the source command is also read-only
44
- FIRST=$(echo "$COMMAND" | cut -d'|' -f1 | awk '{print $1}')
45
- case "$FIRST" in
46
- cat|head|tail|grep|find|ls|git|npm|pip|cargo|go)
47
- echo '{"decision":"approve","reason":"Read-only pipeline"}'
48
- exit 0
49
- ;;
48
+ # Commands that read and nothing else. `git` is handled separately below,
49
+ # because only some of its subcommands read.
50
+ cc_ro_base_ok() {
51
+ case "$1" in
52
+ cat|head|tail|less|more|wc|grep|rg|ag|ack|locate|\
53
+ ls|ll|dir|tree|stat|file|which|whereis|type|realpath|\
54
+ date|uptime|uname|hostname|whoami|id|groups|env|printenv|\
55
+ pwd|df|du|free|top|ps|pgrep|lsof|netstat|ss|\
56
+ jq|yq)
57
+ return 0 ;;
58
+ esac
59
+ return 1
60
+ }
61
+
62
+ # Filters that only make sense downstream of something else. They stay out of
63
+ # the first position so that `sed …` on its own is not read as a read.
64
+ cc_filter_base_ok() {
65
+ case "$1" in
66
+ head|tail|grep|wc|sort|uniq|tr|cut|awk|sed|less|more|column|nl|rev)
67
+ return 0 ;;
50
68
  esac
51
- fi
69
+ return 1
70
+ }
71
+
72
+ cc_segment_base() {
73
+ # strip leading blanks, leading VAR=value assignments, then take the command
74
+ # word without its directory
75
+ printf '%s' "$1" \
76
+ | sed -E 's/^[[:space:]]+//; s/^([A-Za-z_][A-Za-z0-9_]*=[^[:space:]]*[[:space:]]+)*//' \
77
+ | awk '{print $1}' \
78
+ | sed 's|.*/||'
79
+ }
80
+
81
+ cc_segment_reads() {
82
+ local seg="$1" idx="$2" base
83
+ base=$(cc_segment_base "$seg")
84
+ [ -z "$base" ] && return 1
85
+
86
+ # moving between directories reads nothing and writes nothing
87
+ [ "$base" = "cd" ] && return 0
88
+
89
+ # find reads only while it carries no predicate that acts on what it finds
90
+ if [ "$base" = "find" ]; then
91
+ printf '%s' "$seg" \
92
+ | grep -qE '(^|[[:space:]])-(delete|exec|execdir|ok|okdir|fprintf?|fls|fprint0)([[:space:]]|$)' \
93
+ && return 1
94
+ return 0
95
+ fi
96
+
97
+ # sed rewrites the file in place with -i
98
+ if [ "$base" = "sed" ]; then
99
+ printf '%s' "$seg" | grep -qE '(^|[[:space:]])-[a-zA-Z]*i' && return 1
100
+ fi
101
+
102
+ cc_ro_base_ok "$base" && return 0
103
+
104
+ # git, only the subcommands that read
105
+ if printf '%s' "$seg" | grep -qE '^[[:space:]]*git[[:space:]]+(status|log|diff|show|branch|remote|tag[[:space:]]+-l|blame|shortlog|describe|rev-parse|ls-files|ls-tree)([[:space:]]|$)'; then
106
+ return 0
107
+ fi
108
+
109
+ # downstream positions may also be a plain filter
110
+ [ "$idx" -gt 0 ] && cc_filter_base_ok "$base" && return 0
111
+
112
+ return 1
113
+ }
114
+
115
+ IDX=0
116
+ while IFS= read -r SEG; do
117
+ SEG="${SEG#"${SEG%%[![:space:]]*}"}"
118
+ SEG="${SEG%"${SEG##*[![:space:]]}"}"
119
+ [ -z "$SEG" ] && continue
120
+ cc_segment_reads "$SEG" "$IDX" || exit 0
121
+ IDX=$((IDX + 1))
122
+ done <<EOF
123
+ $(printf '%s' "$COMMAND" | tr ';&|' '\n\n\n')
124
+ EOF
125
+
126
+ # nothing to approve if the line held no command at all
127
+ [ "$IDX" -eq 0 ] && exit 0
52
128
 
129
+ echo '{"decision":"approve","reason":"Read-only command"}'
53
130
  exit 0
@@ -21,7 +21,36 @@ fi
21
21
  # Safe remote commands (customize this list)
22
22
  SAFE_COMMANDS="uptime|w|whoami|hostname|uname|date|df|free|cat /etc/os-release"
23
23
 
24
- if echo "$COMMAND" | grep -qE "^\s*ssh\s+\S+\s+($SAFE_COMMANDS)(\s|$)"; then
24
+ # Approve only when EVERY command position qualifies.
25
+ #
26
+ # The pattern below was anchored at `^\s*` and matched against the whole command
27
+ # string, so only the first command position was examined and the approval was
28
+ # then handed to the entire line: `ssh host uptime && sudo rm -rf app` was
29
+ # approved on the strength of its first word. Measured 2026-08-03. Same defect
30
+ # as PR #937 / #940 / #941, on the approving side, where the decision is an
31
+ # explicit approval rather than a missed block.
32
+ #
33
+ # Splitting on the separator characters is approximate — quotes are not parsed —
34
+ # so a quoted remote payload that carries a separator (`ssh host "uptime; df"`)
35
+ # stops qualifying too. That is the conservative direction: it gets no decision
36
+ # and lands in the normal permission flow. Command substitution and backticks
37
+ # disqualify the line outright. This hook only ever adds approval; it never
38
+ # blocks.
39
+ cc_every_segment_matches() {
40
+ local pat="$1" cmd="$2" seg
41
+ case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
42
+ while IFS= read -r seg; do
43
+ seg="${seg#"${seg%%[![:space:]]*}"}"
44
+ seg="${seg%"${seg##*[![:space:]]}"}"
45
+ [ -z "$seg" ] && continue
46
+ printf '%s' "$seg" | grep -qE "$pat" || return 1
47
+ done <<EOF
48
+ $(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
49
+ EOF
50
+ return 0
51
+ }
52
+
53
+ if cc_every_segment_matches "^\s*ssh\s+\S+\s+($SAFE_COMMANDS)(\s|\$)" "$COMMAND"; then
25
54
  jq -n '{
26
55
  hookSpecificOutput: {
27
56
  hookEventName: "PreToolUse",
@@ -3,6 +3,50 @@
3
3
  # TRIGGER: PreToolUse MATCHER: "Bash"
4
4
  COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
5
5
  [ -z "$COMMAND" ] && exit 0
6
+
7
+ # Approve only when EVERY command position qualifies.
8
+ #
9
+ # The patterns below were anchored at `^\s*` and matched against the whole
10
+ # command string, so only the first command position was examined and the
11
+ # approval was then handed to the entire line: `pytest && sudo rm -rf app` was
12
+ # approved on the strength of its first word. Measured 2026-08-03. Same defect
13
+ # as PR #937 / #940 / #941, on the approving side, where the decision is an
14
+ # explicit approval rather than a missed block.
15
+ #
16
+ # Splitting on the separator characters is approximate — quotes are not parsed —
17
+ # so anything that can hide a command from a string-level read (command
18
+ # substitution, backticks) disqualifies the line outright. A line that does not
19
+ # qualify gets no decision, which leaves it to the normal permission flow. This
20
+ # hook only ever adds approval; it never blocks.
21
+ #
22
+ # The gate uses the union of all eight patterns, so a chain of test runners
23
+ # (`pytest && go test ./...`) still passes; the if-chain below only picks which
24
+ # reason to report.
25
+ cc_every_segment_matches() {
26
+ local pat="$1" cmd="$2" seg
27
+ case "$cmd" in *'$('*|*'`'*) return 1 ;; esac
28
+ while IFS= read -r seg; do
29
+ seg="${seg#"${seg%%[![:space:]]*}"}"
30
+ seg="${seg%"${seg##*[![:space:]]}"}"
31
+ [ -z "$seg" ] && continue
32
+ printf '%s' "$seg" | grep -qE "$pat" || return 1
33
+ done <<EOF
34
+ $(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
35
+ EOF
36
+ return 0
37
+ }
38
+
39
+ TEST_SAFE_RE='^\s*(npm\s+test|npm\s+run\s+test|npx\s+(jest|vitest|mocha|ava|tap|playwright\s+test|cypress\s+run)|yarn\s+test|pnpm\s+test|bun\s+test)\b'
40
+ TEST_SAFE_RE="$TEST_SAFE_RE"'|^\s*(pytest|python\s+-m\s+(pytest|unittest)|tox)\b'
41
+ TEST_SAFE_RE="$TEST_SAFE_RE"'|^\s*go\s+test\b'
42
+ TEST_SAFE_RE="$TEST_SAFE_RE"'|^\s*cargo\s+test\b'
43
+ TEST_SAFE_RE="$TEST_SAFE_RE"'|^\s*(phpunit|vendor/bin/phpunit|php\s+artisan\s+test)\b'
44
+ TEST_SAFE_RE="$TEST_SAFE_RE"'|^\s*(rspec|bundle\s+exec\s+rspec|rake\s+test|rails\s+test)\b'
45
+ TEST_SAFE_RE="$TEST_SAFE_RE"'|^\s*(mvn\s+test|gradle\s+test|./gradlew\s+test)\b'
46
+ TEST_SAFE_RE="$TEST_SAFE_RE"'|^\s*dotnet\s+test\b'
47
+
48
+ cc_every_segment_matches "$TEST_SAFE_RE" "$COMMAND" || exit 0
49
+
6
50
  if echo "$COMMAND" | grep -qE '^\s*(npm\s+test|npm\s+run\s+test|npx\s+(jest|vitest|mocha|ava|tap|playwright\s+test|cypress\s+run)|yarn\s+test|pnpm\s+test|bun\s+test)\b'; then
7
51
  echo '{"decision":"approve","reason":"Test runner command"}'
8
52
  exit 0
@@ -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
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
File without changes
File without changes
@@ -21,7 +21,7 @@
21
21
  # }
22
22
  # }
23
23
  #
24
- # TRIGGER: PermissionRequest MATCHER: ""
24
+ # TRIGGER: PreToolUse MATCHER: "Bash"
25
25
 
26
26
  INPUT=$(cat)
27
27
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -99,6 +99,58 @@ if echo "$COMMAND" | grep -qE '^\s*(node|python3?)\s+-e\s'; then
99
99
  fi
100
100
  fi
101
101
 
102
+ # --- Every command position has to qualify, not just the first one ---
103
+ #
104
+ # The comment at the top of this file says "We check each component of compound
105
+ # commands". It did not. Every pattern above is anchored at `^\s*` and matched
106
+ # against the whole command string, so only the first command position was ever
107
+ # examined, and the approval below was then handed to the entire line.
108
+ # `cat README.md && sudo rm -rf app` and `curl -s http://… | sh` were both
109
+ # approved. Measured 2026-08-03. Same defect as PR #937 / #940 / #941, on the
110
+ # approving side, where the decision is an explicit approval rather than a
111
+ # missed block. This hook matters more than most because it exists for auto
112
+ # mode, where nobody is watching the prompt.
113
+ #
114
+ # Splitting on the separator characters is approximate — quotes are not parsed —
115
+ # so a line that does not qualify gets no decision and lands in the normal
116
+ # permission flow. This hook only ever adds approval; it never blocks.
117
+ cc_every_segment_matches() {
118
+ local pat="$1" cmd="$2" seg
119
+ while IFS= read -r seg; do
120
+ seg="${seg#"${seg%%[![:space:]]*}"}"
121
+ seg="${seg%"${seg##*[![:space:]]}"}"
122
+ [ -z "$seg" ] && continue
123
+ printf '%s' "$seg" | grep -qE "$pat" || return 1
124
+ done <<EOF
125
+ $(printf '%s' "$cmd" | tr ';&|' '\n\n\n')
126
+ EOF
127
+ return 0
128
+ }
129
+
130
+ SAFE_RE='^\s*(cat|head|tail|less|more|wc|file|stat|du|df|ls|tree|find|which|whereis|type|realpath|readlink)\s'
131
+ SAFE_RE="$SAFE_RE"'|^\s*(grep|rg|ag|ack|sed\s+-n|awk)\s'
132
+ SAFE_RE="$SAFE_RE"'|^\s*git\s+(status|log|diff|show|branch|tag|remote|stash\s+list|ls-files|ls-tree|rev-parse|describe|shortlog|blame|config\s+--get)'
133
+ SAFE_RE="$SAFE_RE"'|^\s*(npm\s+(ls|list|info|view|outdated|audit)|pip\s+(list|show|freeze)|yarn\s+(list|info|why)|pnpm\s+(ls|list))\s*'
134
+ SAFE_RE="$SAFE_RE"'|^\s*(echo|printf|date|env|printenv|uname|hostname|whoami|id|pwd|tput)\s*'
135
+ SAFE_RE="$SAFE_RE"'|^\s*(jq|yq|python3?\s+-c\s|python3?\s+-m\s+json)\s'
136
+ SAFE_RE="$SAFE_RE"'|^\s*curl\s+-s'
137
+ SAFE_RE="$SAFE_RE"'|^\s*(node|python3?)\s+-e\s'
138
+ SAFE_RE="$SAFE_RE"'|^\s*(mkdir|touch|cp|mv)\s'
139
+
140
+ if [ "$APPROVE" = true ]; then
141
+ # A substitution can carry a command that no string-level read sees. The
142
+ # `$(date …)` branch above is the one this hook deliberately supports, so
143
+ # strip those and refuse if any other substitution is left.
144
+ if printf '%s' "$COMMAND" | grep -q '`'; then
145
+ exit 0
146
+ fi
147
+ SUBST_REST=$(printf '%s' "$COMMAND" | sed -E 's/\$\(date[^)]*\)//g')
148
+ if printf '%s' "$SUBST_REST" | grep -q '\$('; then
149
+ exit 0
150
+ fi
151
+ cc_every_segment_matches "$SAFE_RE" "$COMMAND" || exit 0
152
+ fi
153
+
102
154
  # --- Output the decision ---
103
155
  if [ "$APPROVE" = true ]; then
104
156
  jq -n --arg reason "$REASON" \
@@ -21,21 +21,168 @@
21
21
 
22
22
  set -euo pipefail
23
23
 
24
+ # Without jq, the parse below silently yields empty and this hook stops
25
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
26
+ # here: blocking would halt every tool call, and exiting 0 would change
27
+ # the behaviour of guards that do not depend on the parsed value.
28
+ if ! command -v jq >/dev/null 2>&1; then
29
+ _nojq_warned="/tmp/cc-nojq-warned-auto-mode-safety-enforcer-$PPID"
30
+ [ -f "$_nojq_warned" ] || {
31
+ echo "WARNING [auto-mode-safety-enforcer]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
32
+ : > "$_nojq_warned"
33
+ }
34
+ fi
35
+
24
36
  INPUT=$(cat)
25
37
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
38
+
39
+ # --- Mention vs invocation ----------------------------------------------------
40
+ # Every pattern below scans the command text, so a dangerous string written
41
+ # inside quotes reaches them exactly as an executed command would. Until now
42
+ # this hook lived with that by leaving quotes out of the terminator sets: the
43
+ # five quoted targets the header claims passed, and the mention controls in
44
+ # tests/auto-mode-unquoted-targets.test.sh passed for the same reason -- the
45
+ # target was invisible, not recognised.
46
+ #
47
+ # This is the quote-aware extraction destructive-guard grew in PR #960, ported
48
+ # here as the comment further down said it would have to be. Blank out
49
+ # everything inside quotes, then ask whether a destructive verb still starts a
50
+ # command in what is left. If none does, nothing destructive is being invoked
51
+ # and there is nothing for the rest of this file to judge.
52
+ if [ -z "${CC_AUTOMODE_UNWRAPPED:-}" ] && [ -n "$COMMAND" ]; then
53
+ _am_outside=$(printf '%s' "$COMMAND" | awk -v SQ="'" -v DQ='"' '
54
+ { line = $0; out = ""; q = 0
55
+ for (i = 1; i <= length(line); i++) {
56
+ c = substr(line, i, 1)
57
+ if (q == 0 && c == SQ) { q = 1; out = out " "; continue }
58
+ if (q == 1) { if (c == SQ) q = 0; out = out " "; continue }
59
+ if (q == 0 && c == DQ) { q = 2; out = out " "; continue }
60
+ if (q == 2) { if (c == DQ) q = 0; out = out " "; continue }
61
+ out = out c
62
+ }
63
+ print out }')
64
+ # The wrapper unwrapping further down only runs if this gate lets the call
65
+ # through, so the gate has to see a verb that sits inside a substitution or
66
+ # a subshell too. Replace the wrapping tokens with separators first -- the
67
+ # same substitution the unwrapping step uses. Measured 2026-08-11: without
68
+ # this, a deletion inside a substitution and one on the right of an
69
+ # assignment both exited 0 here and never reached the unwrapping.
70
+ _am_gate=$(printf '%s' "$_am_outside" | sed -E \
71
+ -e 's/\$\(/ ; /g' -e 's/`/ ; /g' \
72
+ -e 's/(^|[[:space:]])\(/\1 ; /g' -e 's/\)([[:space:]]|$)/ ; \1/g' \
73
+ -e 's/\)$/ ; /g' \
74
+ -e 's/(^|[[:space:]])(then|do|else|elif)([[:space:]])/\1 ; \3/g')
75
+ # A quoted string is only inert while nothing executes it. `sh -c` with a
76
+ # quoted argument, `eval`, and a pipe into a shell all run that text, so
77
+ # there the quoted string is a command and not a mention. Never let the
78
+ # gate pass those through.
79
+ if printf '%s' "$_am_outside" | grep -qE '(^|[;&|`(){}]|[[:space:]])((sh|bash|zsh|dash|ksh)[[:space:]]+(-[a-z]*[[:space:]]+)*-c([[:space:]]|$)|eval([[:space:]]|$))|\|[[:space:]]*(sudo[[:space:]]+)?(sh|bash|zsh|dash|ksh|python3?|perl|ruby|node)([[:space:]]|$)' 2>/dev/null; then
80
+ :
81
+ elif ! printf '%s' "$_am_gate" | grep -qE '(^|[;&|`(){}]|\$\(|[[:space:]](then|do|else|elif)[[:space:]])[[:space:]]*([A-Za-z_][A-Za-z0-9_]*=[^[:space:]]*[[:space:]]+|(env|nice|ionice|timeout|exec|command|builtin|stdbuf|nohup|sudo|time|xargs)([[:space:]]+-[^[:space:]]+)*([[:space:]]+[0-9]+)?([[:space:]]+-[^[:space:]]+)*[[:space:]]+)*([./]*[A-Za-z0-9_./-]*/)?(rm|rmdir|unlink|shred|dd|mkfs[.a-z0-9]*|fdisk|parted|chmod|kill|killall)([[:space:]]|$)' 2>/dev/null; then
82
+ exit 0
83
+ fi
84
+ fi
85
+
86
+ # --- Look inside wrappers -----------------------------------------------------
87
+ # The target patterns below require whitespace or end-of-line after the
88
+ # dangerous path, so a deletion wrapped in a substitution or a subshell ends
89
+ # with `)` and never matches. Measured 2026-08-04: the bare deletion was
90
+ # blocked and five of six wrappings passed. Claude Code 2.1.221 fixed the same
91
+ # shape in its own permission check.
92
+ #
93
+ # Replace the wrapping tokens with separators and run this same script once more
94
+ # against that text. Detection only: never executed; the message keeps the
95
+ # command the user actually sent.
96
+ if [ -n "${CC_AUTOMODE_UNWRAPPED:-}" ]; then
97
+ COMMAND="$CC_AUTOMODE_UNWRAPPED"
98
+ elif [ -n "$COMMAND" ]; then
99
+ _am_unwrapped=$(printf '%s' "$COMMAND" | sed -E \
100
+ -e 's/\$\(/ ; /g' -e 's/`/ ; /g' \
101
+ -e 's/(^|[[:space:]])\(/\1 ; /g' -e 's/\)([[:space:]]|$)/ ; \1/g' \
102
+ -e 's/\)$/ ; /g' \
103
+ -e 's/(^|[[:space:]])(then|do|else|elif)([[:space:]])/\1 ; \3/g')
104
+ if [ "$_am_unwrapped" != "$COMMAND" ]; then
105
+ CC_AUTOMODE_UNWRAPPED="$_am_unwrapped" bash "$0" </dev/null >/dev/null 2>&1
106
+ if [ "$?" = "2" ]; then
107
+ echo "BLOCKED: a destructive command is hidden inside a wrapper." >&2
108
+ echo "Command: $COMMAND" >&2
109
+ echo "A substitution, a subshell or a shell keyword does not make it safe." >&2
110
+ exit 2
111
+ fi
112
+ fi
113
+ fi
26
114
  [ -z "$COMMAND" ] && exit 0
27
115
 
116
+ # Quote characters are dropped for matching only. The gate above has already
117
+ # ruled out text that merely names a command, so a quote here is an ordinary
118
+ # way to write an argument and the target behind it has to be judged. Every
119
+ # message below still shows the command the user actually sent.
120
+ #
121
+ # This has to come after the unwrapping above, not before it: that step
122
+ # re-reads COMMAND from CC_AUTOMODE_UNWRAPPED in the recursive call, so a
123
+ # CMD_UNQ computed earlier would still hold the value from before the rewrite
124
+ # (empty, in the child) and every pattern below would match nothing.
125
+ CMD_UNQ=$(printf '%s' "$COMMAND" | tr -d "\"'")
126
+
127
+ # The gate at the top of this file counts a path, a sudo, an inline assignment
128
+ # and the usual wrappers as an invocation. The two checks below anchored on a
129
+ # separator or a bare space, so `/usr/bin/rm -rf /` reached them and matched
130
+ # nothing: measured 2026-09-14, nine invocation forms against six destructive
131
+ # commands, twelve of fifty-four cells passed and every one of the twelve was
132
+ # reached through a path.
133
+ #
134
+ # This is a superset of what was here before, not a replacement. The bare-space
135
+ # branch is load-bearing: the gate lets `echo "rm -rf /" | sh` through on the
136
+ # pipe-into-a-shell arm, and only the loose match below stops it. Narrowing this
137
+ # to command position alone reopened four cases in tests/auto-mode-quoted-
138
+ # targets.test.sh -- measured against the pre-change copy to be sure it was the
139
+ # change and not the instrument.
140
+ AM_CMDPOS='(^|[;&|`(){}]|\$\(|[[:space:]])[[:space:]]*([A-Za-z_][A-Za-z0-9_]*=[^[:space:]]*[[:space:]]+|(env|nice|ionice|timeout|exec|command|builtin|stdbuf|nohup|sudo|time|xargs)([[:space:]]+-[^[:space:]]+)*([[:space:]]+[0-9]+)?([[:space:]]+-[^[:space:]]+)*[[:space:]]+)*([./]*[A-Za-z0-9_./-]*/)?'
141
+
28
142
  # --- Critical rm operations ---
29
- if echo "$COMMAND" | grep -qE '(^|\s|;|&&|\|)(sudo\s+)?rm\s'; then
143
+ if echo "$CMD_UNQ" | grep -qE "${AM_CMDPOS}"'rm[[:space:]]'; then
30
144
  # Always block rm on root-level and home-level critical paths
31
- if echo "$COMMAND" | grep -qE 'rm\s.*(/\s|/;|/$|~\/?\s|~\/?$|~\/\.|/home\b|/etc\b|/usr\b|/var\b|/opt\b|/root\b)'; then
145
+ # The home terminators used to be whitespace or end-of-line only, so
146
+ # `rm -rf ~; echo done` passed while `rm -rf ~ ; echo done` was blocked --
147
+ # one space apart, opposite verdicts. Separators end a command just as much
148
+ # as a space does. Measured 2026-08-04.
149
+ if echo "$CMD_UNQ" | grep -qE 'rm\s.*(/[[:space:];&|]|/$|~\/?[[:space:];&|]|~\/?$|~\/\.|/home\b|/etc\b|/usr\b|/var\b|/opt\b|/root\b)'; then
32
150
  echo "BLOCKED: rm targeting critical system/home path" >&2
33
151
  echo "This operation would cause irreversible data loss." >&2
34
152
  echo "Command: $COMMAND" >&2
35
153
  exit 2
36
154
  fi
155
+ # The header above lists $HOME, a parent traversal and the git directory
156
+ # among the paths this hook blocks, but the pattern before this one has no
157
+ # case for any of them. Measured 2026-08-11 against the 19 targets the
158
+ # header claims: 11 passed, including
159
+ #
160
+ # rm -rf $HOME rm -rf ${HOME} rm -rf ..
161
+ # rm -rf ../.. rm -rf a/../.. rm -rf .git
162
+ #
163
+ # scripts.json grew the $HOME case in PR #962 and the quoted case in #961.
164
+ # Neither fix reached this example, so the same defect stayed here.
165
+ #
166
+ # Quoted forms ("/", "$HOME", ".git") are deliberately still not matched.
167
+ # This hook has no mention-vs-invocation pass, so putting a quote in a
168
+ # terminator set would also block `echo "rm -rf /"` and a commit message
169
+ # that names the command. Those pass today only because the target is
170
+ # invisible behind the quote. Telling a mention from a run needs the
171
+ # quote-aware extraction destructive-guard grew in PR #960; until that is
172
+ # ported here, rm-safety-net and compound-command-deny-enforcer are the
173
+ # layer that catches the quoted forms (measured: both deny them).
174
+ #
175
+ # Terminators are deliberate: `..` and `.git` must be a whole path
176
+ # component, so `my..cache`, `backup..`, `.gitignore` and `.github` are
177
+ # untouched, and `$HOMEBREW_PREFIX` does not look like `$HOME`.
178
+ if echo "$CMD_UNQ" | grep -qE 'rm\s.*(\$\{?HOME\}?([[:space:];&|/]|$)|(^|[[:space:]/])\.\.([[:space:];&|/]|$)|(^|[[:space:]/])\.git([[:space:];&|/]|$))'; then
179
+ echo "BLOCKED: rm targeting the home directory, a parent directory, or the git directory" >&2
180
+ echo "This operation would cause irreversible data loss." >&2
181
+ echo "Command: $COMMAND" >&2
182
+ exit 2
183
+ fi
37
184
  # Block rm on dotfiles in home directory
38
- if echo "$COMMAND" | grep -qE "rm\s.*(${HOME}|\~)/\."; then
185
+ if echo "$CMD_UNQ" | grep -qE "rm\s.*(${HOME}|\~)/\."; then
39
186
  echo "BLOCKED: rm targeting home dotfile" >&2
40
187
  echo "Command: $COMMAND" >&2
41
188
  exit 2
@@ -43,7 +190,7 @@ if echo "$COMMAND" | grep -qE '(^|\s|;|&&|\|)(sudo\s+)?rm\s'; then
43
190
  fi
44
191
 
45
192
  # --- Disk-level operations ---
46
- if echo "$COMMAND" | grep -qE '(^|\s)(sudo\s+)?(dd\s+.*of=/dev|mkfs\.|fdisk\s|parted\s)'; then
193
+ if echo "$CMD_UNQ" | grep -qE "${AM_CMDPOS}"'(dd[[:space:]]+.*of=/dev|mkfs\.|fdisk[[:space:]]|parted[[:space:]])'; then
47
194
  echo "BLOCKED: Disk-level operation (dd/mkfs/fdisk/parted)" >&2
48
195
  exit 2
49
196
  fi
@@ -0,0 +1,22 @@
1
+ #!/bin/bash
2
+ set -uo pipefail
3
+ git rev-parse --is-inside-work-tree >/dev/null 2>&1 || exit 0
4
+ branch=$(git symbolic-ref --quiet --short HEAD 2>/dev/null || echo "")
5
+ [ -z "$branch" ] && exit 0 # detached HEAD: do nothing
6
+ case "$branch" in
7
+ main|master|develop|release) exit 0 ;;
8
+ esac
9
+ push() { if "$@"; then return 0; else
10
+ echo "[auto-push] '$branch' not pushed (no remote / auth / rejected). Push manually." >&2
11
+ exit 0; fi; }
12
+ if git rev-parse --abbrev-ref --symbolic-full-name '@{u}' >/dev/null 2>&1; then
13
+ ahead=$(git rev-list --count '@{u}..HEAD' 2>/dev/null || echo 0)
14
+ [ "$ahead" -eq 0 ] && exit 0 # nothing unpushed
15
+ push git push --quiet
16
+ echo "[auto-push] pushed $ahead commit(s) on '$branch'." >&2
17
+ else
18
+ git rev-parse --verify --quiet HEAD >/dev/null 2>&1 || exit 0
19
+ push git push --quiet -u origin "$branch"
20
+ echo "[auto-push] set upstream and pushed '$branch' to origin." >&2
21
+ fi
22
+ exit 0
@@ -6,7 +6,19 @@
6
6
  # aws rds delete-db-instance, aws cloudformation delete-stack
7
7
  #
8
8
  # TRIGGER: PreToolUse
9
- # MATCHER: "Bash"
9
+ # MATCHER: "Bash|PowerShell"
10
+
11
+ # Without jq, the parse below silently yields empty and this hook stops
12
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
13
+ # here: blocking would halt every tool call, and exiting 0 would change
14
+ # the behaviour of guards that do not depend on the parsed value.
15
+ if ! command -v jq >/dev/null 2>&1; then
16
+ _nojq_warned="/tmp/cc-nojq-warned-aws-production-guard-$PPID"
17
+ [ -f "$_nojq_warned" ] || {
18
+ echo "WARNING [aws-production-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
19
+ : > "$_nojq_warned"
20
+ }
21
+ fi
10
22
 
11
23
  INPUT=$(cat)
12
24
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
  # aws-region-guard.sh — Warn when AWS commands target unexpected regions
3
- # TRIGGER: PreToolUse MATCHER: "Bash"
3
+ # TRIGGER: PreToolUse MATCHER: "Bash|PowerShell"
4
4
  COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
5
5
  [ -z "$COMMAND" ] && exit 0
6
6
  echo "$COMMAND" | grep -qE '^\s*aws\s' || exit 0
@@ -0,0 +1,82 @@
1
+ #!/bin/bash
2
+ # background-cost-launch-guard.sh — Block a *background* Bash launch that can
3
+ # incur ongoing API/compute cost and would
4
+ # keep running after the model says "Done".
5
+ #
6
+ # Solves (#68642): Claude Code launched a batch API script with
7
+ # run_in_background=true, announced completion ("Done."), and the user walked
8
+ # away — but three processes kept hammering the API for 6+ hours, racking up
9
+ # several hundred USD. The model signaled completion WITHOUT confirming the
10
+ # background processes had exited. A foreground run would have blocked (and been
11
+ # visible); a background run is fire-and-forget and silent.
12
+ #
13
+ # Why existing guards miss this exact shape:
14
+ # - timeout-guard.sh nudges you TO use run_in_background for forever-servers —
15
+ # the opposite direction; it never inspects the cost of a bg launch.
16
+ # - dangling-process-guard.sh is a Stop hook that lists leftover `&`/`nohup`
17
+ # processes; it does not read the Bash tool's `run_in_background` parameter
18
+ # and only fires at session end, after the money is already spent.
19
+ # - api-busyloop-guard.sh fires on no-op-body busy-poll loops; a batch API
20
+ # script is not a busy-poll, so it never trips.
21
+ #
22
+ # What this does: on PreToolUse for Bash, if run_in_background is true AND the
23
+ # command matches a cost-incurring signature (LLM API endpoints/SDKs, `claude -p`
24
+ # headless runs, or a loop that calls curl/python against an API), it BLOCKS
25
+ # (exit 2) and tells the model to (a) run it in the FOREGROUND so completion is
26
+ # actually observed, or (b) add an explicit budget/turn cap and a hard timeout.
27
+ # Background launches with no cost signature (dev servers, log tails) pass.
28
+ #
29
+ # TRIGGER: PreToolUse MATCHER: "Bash"
30
+ # settings.json:
31
+ # { "hooks": { "PreToolUse": [{ "matcher": "Bash",
32
+ # "hooks": [{ "type": "command",
33
+ # "command": "~/.claude/hooks/background-cost-launch-guard.sh" }] }] } }
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-background-cost-launch-guard-$PPID"
41
+ [ -f "$_nojq_warned" ] || {
42
+ echo "WARNING [background-cost-launch-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
43
+ : > "$_nojq_warned"
44
+ }
45
+ fi
46
+
47
+ INPUT=$(cat)
48
+
49
+ # Only act on background launches. Claude Code exposes run_in_background as a
50
+ # top-level field of the Bash tool input.
51
+ BG=$(printf '%s' "$INPUT" | jq -r '.tool_input.run_in_background // false' 2>/dev/null)
52
+ [[ "$BG" != "true" ]] && exit 0
53
+
54
+ CMD=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
55
+ [[ -z "$CMD" ]] && exit 0
56
+
57
+ # Cost-incurring signatures. Kept deliberately specific so ordinary background
58
+ # work (servers, builds, log tails) is never blocked.
59
+ COST_RE='api\.anthropic\.com|api\.openai\.com|generativelanguage\.googleapis\.com|/v1/(messages|complete|chat/completions|batches)|anthropic|openai|litellm|(^|[^a-z])claude[[:space:]]+-p([[:space:]]|$)|--print|messages\.batches|batch'
60
+ LOOP_RE='(while|until|for)[[:space:]].*(curl|wget|python|node|claude|gh[[:space:]]+api)'
61
+
62
+ if printf '%s' "$CMD" | grep -qiE "$COST_RE" || printf '%s' "$CMD" | grep -qiE "$LOOP_RE"; then
63
+ {
64
+ echo "BLOCKED: background launch that can incur ongoing API/compute cost."
65
+ echo ""
66
+ echo "This Bash call sets run_in_background=true on a command that looks"
67
+ echo "like it spends money or loops over an API. A background launch is"
68
+ echo "fire-and-forget: the session can report \"Done\" while it keeps"
69
+ echo "running for hours (see anthropics/claude-code#68642 — several"
70
+ echo "hundred USD burned this exact way)."
71
+ echo ""
72
+ echo "Do one of:"
73
+ echo " 1) Run it in the FOREGROUND (run_in_background=false) so its exit"
74
+ echo " is actually observed before any completion is claimed; or"
75
+ echo " 2) Bound it: add a hard timeout and an explicit budget/turn cap"
76
+ echo " (e.g. 'timeout 600 ...', a max-iteration counter), then verify"
77
+ echo " the process has exited before moving on."
78
+ } >&2
79
+ exit 2
80
+ fi
81
+
82
+ exit 0