cc-safe-setup 29.8.0 → 30.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +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-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 +1699 -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
@@ -1,40 +1,122 @@
1
1
  #!/bin/bash
2
2
  # ================================================================
3
- # memory-write-guard.sh — Log writes to ~/.claude/ directory
3
+ # memory-write-guard.sh — See, approve, or block silent memory writes
4
4
  # ================================================================
5
5
  # PURPOSE:
6
- # Claude auto-writes to ~/.claude/projects/*/memory/ without
7
- # user visibility. This hook logs all writes to ~/.claude/ paths
8
- # so users know what's being stored.
6
+ # Claude Code writes to its memory without asking: it edits CLAUDE.md
7
+ # and silently creates/updates/deletes files under
8
+ # ~/.claude/projects/*/memory/. Users report having to re-check those
9
+ # files after every session to find changes they never approved.
9
10
  #
10
- # TRIGGER: PreToolUse MATCHER: "Write|Edit"
11
+ # This hook gives the operator control over those writes. By default it
12
+ # only makes them VISIBLE (logs + a stderr note), which is non-intrusive
13
+ # and safe for automated runs. Opt in to an approval prompt — or a hard
14
+ # block — when you want every memory change to pass through you first.
11
15
  #
12
- # Born from: https://github.com/anthropics/claude-code/issues/38040
13
- # "No way to enforce approval on all file modifications"
16
+ # WHAT COUNTS AS A "MEMORY" WRITE (Write/Edit/MultiEdit on):
17
+ # - any CLAUDE.md / CLAUDE.local.md (project or user memory)
18
+ # - anything under a .claude/ directory, which includes the auto-memory
19
+ # store ~/.claude/projects/*/memory/ and ~/.claude/settings.json
20
+ #
21
+ # MODE (env var CC_MEMORY_WRITE_APPROVAL):
22
+ # off (default) — log + warn, never interrupt (backward compatible)
23
+ # ask — require interactive approval for each memory write
24
+ # block — refuse all memory writes
25
+ #
26
+ # WHY OPT-IN: existing installs and headless/CI runs must keep working
27
+ # unchanged, so the prompt is never on unless the operator asks for it.
28
+ #
29
+ # VERSION NOTE (measured 2026-08-13 on 2.1.228, corrects an earlier note here):
30
+ # #77212 reported that under bypassPermissions an "ask" decision is silently
31
+ # auto-approved and does not gate the write. This comment used to repeat that
32
+ # as current behaviour. It does not reproduce on 2.1.228: run interactively in
33
+ # an isolated HOME, the confirmation appears both under
34
+ # --dangerously-skip-permissions and under --permission-mode auto, carrying
35
+ # this hook's permissionDecisionReason. Control: with the hook removed, both
36
+ # modes ran the same command with no prompt at all, so the permissive mode was
37
+ # genuinely in effect. Non-interactively (claude -p) the call is refused
38
+ # rather than approved. Older builds may still match the report — verify on
39
+ # your own version with `--version` before relying on either behaviour.
40
+ # Independent of all this: an "ask" needs somebody present to answer, so for
41
+ # fully unattended runs use CC_MEMORY_WRITE_APPROVAL=block (exit 2), which is
42
+ # enforced regardless of permission mode.
43
+ #
44
+ # TRIGGER: PreToolUse MATCHER: "Write|Edit|MultiEdit"
45
+ #
46
+ # Born from:
47
+ # https://github.com/anthropics/claude-code/issues/38040
48
+ # "No way to enforce approval on all file modifications"
49
+ # https://github.com/anthropics/claude-code/issues/65064
50
+ # "claude code writes memory without asking for permission"
14
51
  # ================================================================
15
52
 
53
+ set -u
54
+
55
+ # Without jq, the parse below silently yields empty and this hook stops
56
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
57
+ # here: blocking would halt every tool call, and exiting 0 would change
58
+ # the behaviour of guards that do not depend on the parsed value.
59
+ if ! command -v jq >/dev/null 2>&1; then
60
+ _nojq_warned="/tmp/cc-nojq-warned-memory-write-guard-$PPID"
61
+ [ -f "$_nojq_warned" ] || {
62
+ echo "WARNING [memory-write-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
63
+ : > "$_nojq_warned"
64
+ }
65
+ fi
66
+
16
67
  INPUT=$(cat)
17
68
  FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
18
69
  [ -z "$FILE" ] && exit 0
19
70
 
20
- # Check if targeting ~/.claude/
71
+ # Is this a memory file? Match the auto-memory/.claude store and CLAUDE.md
72
+ # files anywhere (project ./CLAUDE.md as well as ~/.claude/CLAUDE.md).
73
+ BASENAME=$(basename "$FILE")
74
+ IS_MEMORY=0
21
75
  case "$FILE" in
22
- */.claude/*|~/.claude/*)
23
- # Log the write
24
- LOG="$HOME/.claude/memory-writes.log"
25
- echo "[$(date -Iseconds)] Write to: $FILE" >> "$LOG" 2>/dev/null
76
+ */.claude/*|~/.claude/*) IS_MEMORY=1 ;;
77
+ esac
78
+ case "$BASENAME" in
79
+ CLAUDE.md|CLAUDE.local.md) IS_MEMORY=1 ;;
80
+ esac
81
+ [ "$IS_MEMORY" -eq 0 ] && exit 0
82
+
83
+ # Record every memory write so the operator can audit what was stored.
84
+ LOG="$HOME/.claude/memory-writes.log"
85
+ echo "[$(date -Iseconds)] Write to: $FILE" >> "$LOG" 2>/dev/null
26
86
 
27
- # Only warn (don't block) — memory writes are usually intentional
28
- echo "NOTE: Writing to Claude config directory: $FILE" >&2
87
+ MODE="${CC_MEMORY_WRITE_APPROVAL:-off}"
29
88
 
30
- # Block writes to settings.json unless explicitly allowed
89
+ case "$MODE" in
90
+ ask)
91
+ # Emit a PreToolUse permission decision. In an interactive session
92
+ # this surfaces an approve/deny prompt — including under
93
+ # bypassPermissions and auto mode, measured on 2.1.228 (see the
94
+ # VERSION NOTE at the top; #77212 reported otherwise on older builds).
95
+ # Use =block when nobody is present to answer the prompt.
96
+ jq -n --arg f "$FILE" '{
97
+ hookSpecificOutput: {
98
+ hookEventName: "PreToolUse",
99
+ permissionDecision: "ask",
100
+ permissionDecisionReason: ("Approve write to memory file: " + $f)
101
+ }
102
+ }'
103
+ exit 0
104
+ ;;
105
+ block)
106
+ echo "BLOCKED: memory write refused by memory-write-guard." >&2
107
+ echo "File: $FILE" >&2
108
+ echo "Set CC_MEMORY_WRITE_APPROVAL=ask to approve per-write, or =off to only log." >&2
109
+ exit 2
110
+ ;;
111
+ *)
112
+ # off (default): only make the write visible.
113
+ echo "NOTE: Writing to Claude memory: $FILE" >&2
31
114
  case "$FILE" in
32
115
  */settings.json|*/settings.local.json)
33
116
  echo "WARNING: Modifying Claude Code settings file." >&2
34
117
  echo "Verify this change is intentional." >&2
35
118
  ;;
36
119
  esac
120
+ exit 0
37
121
  ;;
38
122
  esac
39
-
40
- exit 0
@@ -14,6 +14,18 @@
14
14
 
15
15
  set -euo pipefail
16
16
 
17
+ # Without jq, the parse below silently yields empty and this hook stops
18
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
19
+ # here: blocking would halt every tool call, and exiting 0 would change
20
+ # the behaviour of guards that do not depend on the parsed value.
21
+ if ! command -v jq >/dev/null 2>&1; then
22
+ _nojq_warned="/tmp/cc-nojq-warned-migration-verify-guard-$PPID"
23
+ [ -f "$_nojq_warned" ] || {
24
+ echo "WARNING [migration-verify-guard]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
25
+ : > "$_nojq_warned"
26
+ }
27
+ fi
28
+
17
29
  INPUT=$(cat)
18
30
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
19
31
  [ -z "$COMMAND" ] && exit 0
@@ -0,0 +1,177 @@
1
+ #!/bin/bash
2
+ # model-swap-suggester.sh — Evidence-driven swap recommendation for the AUP false-positive cluster
3
+ #
4
+ # Background:
5
+ # Cluster 9 (Usage Policy classifier over-trigger) accumulated 25+ open GitHub issues
6
+ # between 2026-05-18 and 2026-05-27, with Opus 4.7 / 4.6 / 1M variants over-triggering
7
+ # on benign Claude Code prompts (English, Russian, Polish, Spanish; kernel security,
8
+ # biomedical, FPGA, plain greetings — context-independent). Sonnet variants are reported
9
+ # unaffected.
10
+ #
11
+ # Two defense hooks ship today:
12
+ # - aup-false-positive-helper.sh (SessionStart, opt-in, generic awareness)
13
+ # - aup-block-pattern-logger.sh (PostToolUse, on-by-default, records each block)
14
+ #
15
+ # The gap they leave: the operator who is actively being blocked needs an evidence-driven
16
+ # recommendation at the right moment — "you have been blocked N times in the last hour
17
+ # on Opus, here is the exact swap command." The helper hook is generic and fires on every
18
+ # Opus session; the logger collects evidence but does not act on it.
19
+ #
20
+ # This hook closes that loop. On SessionStart, it reads the block log written by the
21
+ # logger, counts Opus blocks in a recent time window, and emits a concrete swap-to-Sonnet
22
+ # advisory only when the count crosses a threshold. Silent otherwise.
23
+ #
24
+ # Reference: https://gist.github.com/yurukusa/4fa4751044be45bd83345601ee79c2db
25
+ #
26
+ # What this hook does:
27
+ # On SessionStart, if ANTHROPIC_MODEL is pinned to an Opus variant AND the AUP block log
28
+ # shows N or more blocks on any Opus model in the last M minutes, emit a one-time advisory
29
+ # with the exact swap command for the current session. Silent in every other case.
30
+ #
31
+ # When this hook does NOT emit anything:
32
+ # - CC_MODEL_SWAP_SUGGESTER_DISABLE=1
33
+ # - CC_MODEL_SWAP_SUGGESTER_QUIET=1
34
+ # - ANTHROPIC_MODEL unset (default routing)
35
+ # - ANTHROPIC_MODEL pinned to a non-Opus variant (Sonnet / Haiku unaffected)
36
+ # - aup-block log missing, empty, or unreadable
37
+ # - Opus blocks in the configured window < threshold
38
+ #
39
+ # Hook config (settings.json):
40
+ # {
41
+ # "hooks": {
42
+ # "SessionStart": [{
43
+ # "matcher": "",
44
+ # "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/model-swap-suggester.sh" }]
45
+ # }]
46
+ # }
47
+ # }
48
+ #
49
+ # Env vars:
50
+ # CC_MODEL_SWAP_SUGGESTER_DISABLE=1 — never emit
51
+ # CC_MODEL_SWAP_SUGGESTER_QUIET=1 — silent (post-acknowledgment)
52
+ # CC_MODEL_SWAP_SUGGESTER_THRESHOLD=<n> — Opus block count threshold (default 3)
53
+ # CC_MODEL_SWAP_SUGGESTER_WINDOW_MIN=<n> — lookback window in minutes (default 60)
54
+ # CC_MODEL_SWAP_SUGGESTER_TARGET=<model> — target Sonnet model (default claude-sonnet-4-7)
55
+ # CC_AUP_BLOCK_LOG_PATH=<path> — log path (shared with logger; default ~/.claude/aup-block-history.log)
56
+ #
57
+ # Design notes:
58
+ # - Evidence-driven, not opt-in. The advisory only fires when real blocks have happened,
59
+ # so it never adds noise for users who haven't been affected.
60
+ # - Counts Opus blocks across all Opus variants in the log (not just the currently pinned
61
+ # model), because the cluster signature is Opus-family-wide. If you swapped from
62
+ # opus-4-7 to opus-4-6 mid-day and both blocked, both count toward the threshold.
63
+ # - Window is timestamp-based, not last-N-lines, so a quiet session with stale entries
64
+ # does not trigger the advisory.
65
+ # - Never blocks. All failure paths exit 0 so a corrupt log or missing date utility
66
+ # cannot break the session.
67
+
68
+ set -u
69
+
70
+ # Disable path
71
+ if [ "${CC_MODEL_SWAP_SUGGESTER_DISABLE:-0}" = "1" ]; then
72
+ exit 0
73
+ fi
74
+
75
+ # Quiet path
76
+ if [ "${CC_MODEL_SWAP_SUGGESTER_QUIET:-0}" = "1" ]; then
77
+ exit 0
78
+ fi
79
+
80
+ # Model unset → default routing, no specific advisory
81
+ if [ -z "${ANTHROPIC_MODEL:-}" ]; then
82
+ exit 0
83
+ fi
84
+
85
+ # Non-Opus model → unaffected by the cluster
86
+ case "$ANTHROPIC_MODEL" in
87
+ *opus*|*Opus*|*OPUS*) : ;;
88
+ *) exit 0 ;;
89
+ esac
90
+
91
+ LOG_PATH="${CC_AUP_BLOCK_LOG_PATH:-$HOME/.claude/aup-block-history.log}"
92
+ [ -f "$LOG_PATH" ] || exit 0
93
+ [ -r "$LOG_PATH" ] || exit 0
94
+ [ -s "$LOG_PATH" ] || exit 0
95
+
96
+ THRESHOLD="${CC_MODEL_SWAP_SUGGESTER_THRESHOLD:-3}"
97
+ WINDOW_MIN="${CC_MODEL_SWAP_SUGGESTER_WINDOW_MIN:-60}"
98
+ TARGET="${CC_MODEL_SWAP_SUGGESTER_TARGET:-claude-sonnet-4-7}"
99
+
100
+ # Validate numeric env vars; fall back to defaults on garbage input.
101
+ case "$THRESHOLD" in
102
+ ''|*[!0-9]*) THRESHOLD=3 ;;
103
+ esac
104
+ case "$WINDOW_MIN" in
105
+ ''|*[!0-9]*) WINDOW_MIN=60 ;;
106
+ esac
107
+
108
+ # Compute cutoff epoch (now - window_min * 60). Use GNU date first, then BSD date.
109
+ NOW=$(date -u '+%s' 2>/dev/null) || exit 0
110
+ CUTOFF=$((NOW - WINDOW_MIN * 60))
111
+
112
+ ts_to_epoch() {
113
+ local ts="$1"
114
+ date -u -d "$ts" '+%s' 2>/dev/null \
115
+ || date -j -u -f '%Y-%m-%dT%H:%M:%SZ' "$ts" '+%s' 2>/dev/null
116
+ }
117
+
118
+ # Count Opus blocks in the window. The log schema is:
119
+ # ISO8601_UTC | MODEL | TOOL | PATTERN_KIND | EXCERPT
120
+ # We only count rows whose model field matches an Opus variant and whose timestamp falls
121
+ # inside the cutoff window. Rows with unparseable timestamps are skipped silently.
122
+ COUNT=0
123
+ while IFS='|' read -r LOG_TS LOG_MODEL _LOG_TOOL _LOG_KIND _LOG_EXCERPT; do
124
+ [ -z "$LOG_TS" ] && continue
125
+ [ -z "$LOG_MODEL" ] && continue
126
+ case "$LOG_MODEL" in
127
+ *opus*|*Opus*|*OPUS*) : ;;
128
+ *) continue ;;
129
+ esac
130
+ LOG_EPOCH=$(ts_to_epoch "$LOG_TS")
131
+ [ -z "$LOG_EPOCH" ] && continue
132
+ case "$LOG_EPOCH" in
133
+ *[!0-9]*) continue ;;
134
+ esac
135
+ if [ "$LOG_EPOCH" -ge "$CUTOFF" ] 2>/dev/null; then
136
+ COUNT=$((COUNT + 1))
137
+ fi
138
+ done < "$LOG_PATH"
139
+
140
+ if [ "$COUNT" -lt "$THRESHOLD" ] 2>/dev/null; then
141
+ exit 0
142
+ fi
143
+
144
+ # Threshold crossed → emit one-time advisory. The advisory is deliberately concrete:
145
+ # exact swap command, exact env-var suppression command, and pointers to the partner hooks
146
+ # the operator can lean on after swapping.
147
+ cat >&2 <<EOF
148
+ [model-swap-suggester] $COUNT Usage Policy block(s) recorded on Opus models in the last $WINDOW_MIN minutes.
149
+
150
+ Current model: $ANTHROPIC_MODEL
151
+ Log file: $LOG_PATH
152
+
153
+ The Anthropic Usage Policy classifier has been over-triggering on benign prompts on Opus
154
+ variants since 2026-05-18. Sonnet variants are reportedly unaffected. Recommended swap
155
+ for this session:
156
+
157
+ export ANTHROPIC_MODEL=$TARGET
158
+
159
+ After swapping, the false-positive helper will go silent automatically (Sonnet is treated
160
+ as unaffected). Re-pin Opus once the upstream classifier stabilises.
161
+
162
+ Related hooks (already shipped):
163
+ aup-false-positive-helper.sh — generic awareness advisory (opt-in via CC_AUP_FALSE_POSITIVE_HELPER_REMIND=1)
164
+ aup-block-pattern-logger.sh — records each block to $LOG_PATH
165
+
166
+ To silence this advisory permanently for the current session, even when blocks continue:
167
+ export CC_MODEL_SWAP_SUGGESTER_QUIET=1
168
+
169
+ To raise the threshold instead of silencing:
170
+ export CC_MODEL_SWAP_SUGGESTER_THRESHOLD=10 # only suggest after 10 blocks in $WINDOW_MIN min
171
+
172
+ GitHub tracker (25+ independent reports, 2026-05-18 through 2026-05-27):
173
+ https://github.com/anthropics/claude-code/issues/60366
174
+ https://github.com/anthropics/claude-code/issues/62190
175
+ EOF
176
+
177
+ exit 0
@@ -1,3 +1,4 @@
1
+ #!/bin/bash
1
2
  INPUT=$(cat)
2
3
  COUNTER_FILE="/tmp/.cc-model-check-counter"
3
4
  COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
@@ -6,7 +7,10 @@ echo "$COUNT" > "$COUNTER_FILE"
6
7
  if [ $((COUNT % 50)) -ne 0 ]; then
7
8
  exit 0
8
9
  fi
9
- SESSION_FILE=$(ls -t ~/.claude/projects/*/session.jsonl 2>/dev/null | head -1)
10
+ # 記録の場所を推測しない(旧: projects/*/session.jsonl は実在せず、
11
+ # glob が空のまま黙って一度も警告しなかった)。
12
+ SESSION_FILE=$(printf '%s' "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
13
+ [ -f "$SESSION_FILE" ] || SESSION_FILE=$(ls -t "$HOME"/.claude/projects/*/*.jsonl 2>/dev/null | head -1)
10
14
  if [ -n "$SESSION_FILE" ]; then
11
15
  MODEL=$(grep -o '"model":"[^"]*"' "$SESSION_FILE" 2>/dev/null | tail -1 | cut -d'"' -f4)
12
16
  if echo "$MODEL" | grep -qi "opus-4-7\|opus-4.7"; then
@@ -0,0 +1,63 @@
1
+ #!/bin/bash
2
+ # model-version-lock.sh — silent mid-session downgrade detector (Incident 4)
3
+ # Why: Opus 4.7 sessions sometimes migrate mid-session to a different model
4
+ # (for example the 1M-context automatic switch, #49541) with no client-
5
+ # visible announcement. The downgrade silently changes token accounting,
6
+ # context window, and quality. This hook writes a lock file containing
7
+ # the model id seen on the first turn of the session and emits a stderr
8
+ # banner whenever a later turn reports a different model id.
9
+ # Event: PostToolUse MATCHER: "*"
10
+ # Action: First per-session call creates
11
+ # ~/.claude/logs/model-locks/<session-id>.model. Subsequent calls read
12
+ # the lock and compare. Mismatch → banner. /model is the expected
13
+ # user path for intentional switches, so the banner says so.
14
+ #
15
+ # To reset: rm -rf ~/.claude/logs/model-locks/ (between sessions that
16
+ # deliberately switch models, otherwise locks accumulate)
17
+
18
+ set -u
19
+
20
+ LOG_DIR="${HOME}/.claude/logs"
21
+ LOCK_DIR="${LOG_DIR}/model-locks"
22
+ mkdir -p "$LOCK_DIR" 2>/dev/null
23
+
24
+ INPUT=$(cat)
25
+
26
+ SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // "unknown"' 2>/dev/null)
27
+ [ "$SESSION_ID" = "unknown" ] && exit 0
28
+
29
+ # Resolve the current model. PostToolUse payload rarely has it directly, so
30
+ # read the last assistant turn from the transcript for its "model" field.
31
+ MODEL=""
32
+ TRANSCRIPT=$(printf '%s' "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
33
+ if [ -n "$TRANSCRIPT" ] && [ -r "$TRANSCRIPT" ]; then
34
+ MODEL=$(tac "$TRANSCRIPT" 2>/dev/null \
35
+ | grep -m1 '"model"' \
36
+ | jq -r '.message.model // .model // empty' 2>/dev/null)
37
+ fi
38
+
39
+ # Fallback: environment variable (used by some wrappers and tests).
40
+ if [ -z "$MODEL" ] && [ -n "${CLAUDE_MODEL:-}" ]; then
41
+ MODEL="$CLAUDE_MODEL"
42
+ fi
43
+
44
+ # If we still do not know the model, do nothing — no false positives.
45
+ [ -z "$MODEL" ] && exit 0
46
+
47
+ LOCK_FILE="${LOCK_DIR}/${SESSION_ID}.model"
48
+
49
+ if [ ! -s "$LOCK_FILE" ]; then
50
+ printf '%s\n' "$MODEL" > "$LOCK_FILE"
51
+ exit 0
52
+ fi
53
+
54
+ LOCKED=$(cat "$LOCK_FILE" 2>/dev/null)
55
+ if [ -n "$LOCKED" ] && [ "$LOCKED" != "$MODEL" ]; then
56
+ echo "⚠ model-version-lock: $LOCKED → $MODEL (session $SESSION_ID)" >&2
57
+ echo " Use /model to switch intentionally. Silent migrations (#49541) change token accounting and quality." >&2
58
+ # Update the lock so we do not emit again for the same transition this
59
+ # session. Users who want to see every transition can remove this line.
60
+ printf '%s\n' "$MODEL" > "$LOCK_FILE"
61
+ fi
62
+
63
+ exit 0
@@ -20,6 +20,18 @@
20
20
 
21
21
  set -euo pipefail
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-move-delete-sequence-guard-$PPID"
29
+ [ -f "$_nojq_warned" ] || {
30
+ echo "WARNING [move-delete-sequence-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
  [ -z "$COMMAND" ] && exit 0
@@ -33,10 +45,29 @@ fi
33
45
  # Pattern: mv <src> <dst> [&&;||] rm [-rf] <target>
34
46
  # We check if the rm target is a parent of, or the same as, the mv source
35
47
 
48
+ # The extraction below used grep -oP, which is GNU-only. BSD grep (macOS)
49
+ # rejects -P outright, so both variables came back empty, and the two [ -z ]
50
+ # checks under this block read that as "nothing to compare" and exited 0 —
51
+ # the guard was off on macOS with no sign of it. Keep the GNU path exactly as
52
+ # it was and add an equivalent for platforms without PCRE.
53
+ if echo x | grep -qP x 2>/dev/null; then HAS_PCRE=1; else HAS_PCRE=0; fi
54
+
55
+ # Reads a command line on stdin, prints the first argument after $1 and its flags.
56
+ # \b and \K have no POSIX equivalent, so the fallback matches the command word
57
+ # with its leading boundary and strips that prefix afterwards.
58
+ extract_operand() {
59
+ if [ "$HAS_PCRE" = 1 ]; then
60
+ grep -oP "\\b$1\\s+(-[a-zA-Z]+\\s+)*\\K\\S+" 2>/dev/null || true
61
+ else
62
+ grep -oE "(^|[^a-zA-Z])$1[[:space:]]+(-[a-zA-Z]+[[:space:]]+)*[^[:space:]]+" 2>/dev/null \
63
+ | sed -E "s/^[^a-zA-Z]?$1[[:space:]]+(-[a-zA-Z]+[[:space:]]+)*//" || true
64
+ fi
65
+ }
66
+
36
67
  # Get all mv source paths (first arg after mv and optional flags)
37
- MV_SOURCES=$(echo "$COMMAND" | grep -oP '\bmv\s+(-[a-zA-Z]+\s+)*\K\S+' 2>/dev/null || true)
68
+ MV_SOURCES=$(echo "$COMMAND" | extract_operand mv)
38
69
  # Get all rm targets
39
- RM_TARGETS=$(echo "$COMMAND" | grep -oP '\brm\s+(-[a-zA-Z]+\s+)*\K\S+' 2>/dev/null || true)
70
+ RM_TARGETS=$(echo "$COMMAND" | extract_operand rm)
40
71
 
41
72
  [ -z "$MV_SOURCES" ] && exit 0
42
73
  [ -z "$RM_TARGETS" ] && exit 0
@@ -0,0 +1,192 @@
1
+ #!/bin/bash
2
+ # multi-file-plan-routing-gate.sh — Refuse Write/Edit when the current session
3
+ # has touched N or more distinct files without a written plan, route the
4
+ # work through plan-mode before further writes land.
5
+ #
6
+ # Solves: #60506 — supplier-side recommendation #7 in the model's first-person
7
+ # self-report:
8
+ #
9
+ # "Automatic routing of three-or-more-file changes into a plan-mode path.
10
+ # Currently I can sprawl across the codebase without writing a plan first.
11
+ # The hook should refuse the third file-touching Write until a plan exists,
12
+ # and then enforce the plan as the contract for the remaining touches."
13
+ #
14
+ # This is the seventh and final operator-side implementation of the seven
15
+ # recommendations Semih extracted from claude-opus-4-7's self-report. The
16
+ # preceding six are shipped or in PR:
17
+ #
18
+ # 1. Chain templates as architectural rules → CLAUDE.md hook frameworks
19
+ # 2. Drift detector (3-correction repeat) → same-correction-arrest.sh
20
+ # 3. Failure-mode re-injection at Write → claude-md-reinjector.sh
21
+ # 4. Closure-word verification gate → closure-word-verify-gate.sh
22
+ # 5. Evidence requirements for "tested" → evidence-claim-gate.sh (PR #256)
23
+ # 6. Apology weighting at training time → supplier-only
24
+ # 7. THIS HOOK — plan-mode routing for 3+ file changes
25
+ #
26
+ # HOW IT WORKS:
27
+ # 1. Tracks distinct file_path values per session in a small state file.
28
+ # 2. On each PreToolUse Write/Edit/MultiEdit, adds the file_path to the
29
+ # session's set.
30
+ # 3. When the count reaches CC_PLAN_GATE_THRESHOLD (default 3), checks
31
+ # for the presence of a plan file at $PLAN_DIR/<session>.md.
32
+ # 4. If no plan file exists, refuses the Write with exit 2 + system reminder
33
+ # asking the assistant to write the plan first.
34
+ # 5. Once the plan file appears, subsequent writes pass through silently.
35
+ # 6. Stale session state (older than 7 days) is purged automatically.
36
+ #
37
+ # DESIGN PRINCIPLE: don't block the work, route it. The hook does not
38
+ # prevent multi-file changes; it requires that they be planned before being
39
+ # executed. The plan file is the contract; the writes are the contract's
40
+ # fulfillment. The arrest happens at the *third* file (configurable), not
41
+ # the first — single-file and two-file changes are common and not the
42
+ # failure mode #60506 is describing.
43
+ #
44
+ # Related Issues:
45
+ # #60506 (@zean89, 2026-05-19) — original report, recommendation 7
46
+ # #60226 (@suwayama, 2026-05-18) — recognition-without-arrest framework
47
+ # #60177 (@mike-prokhorov) — twelve days, fifty-one commits, no plan
48
+ #
49
+ # TRIGGER: PreToolUse
50
+ # MATCHER: Write|Edit|MultiEdit
51
+ #
52
+ # CONFIGURATION (environment variables):
53
+ # CC_PLAN_GATE_THRESHOLD default 3 — file count that triggers the gate
54
+ # CC_PLAN_GATE_STATE_DIR default /tmp/cc-plan-gate
55
+ # CC_PLAN_GATE_PLAN_DIR default .claude/plans
56
+ # CC_PLAN_GATE_DISABLE set to "1" to disable the gate entirely
57
+ # CC_PLAN_GATE_STATE_TTL default 7 (days) — stale state cleanup window
58
+ #
59
+ # USAGE (settings.json):
60
+ # {
61
+ # "hooks": {
62
+ # "PreToolUse": [{
63
+ # "matcher": "Write|Edit|MultiEdit",
64
+ # "hooks": [{
65
+ # "type": "command",
66
+ # "command": "~/.claude/hooks/multi-file-plan-routing-gate.sh"
67
+ # }]
68
+ # }]
69
+ # }
70
+ # }
71
+
72
+ set -uo pipefail
73
+
74
+ # Without jq, the parse below silently yields empty and this hook stops
75
+ # guarding - with no error anywhere. Say so. We deliberately do not exit
76
+ # here: blocking would halt every tool call, and exiting 0 would change
77
+ # the behaviour of guards that do not depend on the parsed value.
78
+ if ! command -v jq >/dev/null 2>&1; then
79
+ _nojq_warned="/tmp/cc-nojq-warned-multi-file-plan-routing-gate-$PPID"
80
+ [ -f "$_nojq_warned" ] || {
81
+ echo "WARNING [multi-file-plan-routing-gate]: jq not found - this hook cannot inspect tool calls and is NOT protecting you. Install jq." >&2
82
+ : > "$_nojq_warned"
83
+ }
84
+ fi
85
+
86
+ [ "${CC_PLAN_GATE_DISABLE:-0}" = "1" ] && exit 0
87
+
88
+ # OPT-IN: this gate BLOCKS the 3rd+ file Write/Edit in a session when no plan
89
+ # file exists. Ordinary multi-file work (refactors, features touching 3+ files)
90
+ # would be arrested by default, so it is off unless explicitly enabled.
91
+ # Set CC_PLAN_GATE_ENABLE=1 to turn it on.
92
+ [ "${CC_PLAN_GATE_ENABLE:-0}" = "1" ] || exit 0
93
+
94
+ INPUT=$(cat 2>/dev/null || true)
95
+ [ -z "$INPUT" ] && exit 0
96
+
97
+ THRESHOLD="${CC_PLAN_GATE_THRESHOLD:-3}"
98
+ STATE_DIR="${CC_PLAN_GATE_STATE_DIR:-/tmp/cc-plan-gate}"
99
+ PLAN_DIR="${CC_PLAN_GATE_PLAN_DIR:-.claude/plans}"
100
+ TTL_DAYS="${CC_PLAN_GATE_STATE_TTL:-7}"
101
+
102
+ mkdir -p "$STATE_DIR" 2>/dev/null || true
103
+
104
+ # Stale state cleanup. Purge session files older than TTL_DAYS.
105
+ find "$STATE_DIR" -type f -mtime "+${TTL_DAYS}" -delete 2>/dev/null || true
106
+
107
+ # Extract session_id and file_path from input.
108
+ SESSION_ID=$(printf '%s' "$INPUT" | jq -r '
109
+ .session_id //
110
+ .stop_input.session_id //
111
+ .transcript[-1].session_id //
112
+ "default"
113
+ ' 2>/dev/null)
114
+ [ -z "$SESSION_ID" ] && SESSION_ID="default"
115
+
116
+ # Sanitize session_id for filename use
117
+ SAFE_SESSION=$(printf '%s' "$SESSION_ID" | tr -c '[:alnum:]_-' '_' | head -c 64)
118
+
119
+ FILE_PATH=$(printf '%s' "$INPUT" | jq -r '
120
+ .tool_input.file_path //
121
+ empty
122
+ ' 2>/dev/null)
123
+
124
+ # No file_path → nothing to track (e.g. MultiEdit without path, fall back
125
+ # to tool_input.file as a fallback)
126
+ [ -z "$FILE_PATH" ] && FILE_PATH=$(printf '%s' "$INPUT" | jq -r '.tool_input.file // empty' 2>/dev/null)
127
+ [ -z "$FILE_PATH" ] && exit 0
128
+
129
+ STATE_FILE="$STATE_DIR/${SAFE_SESSION}.files"
130
+
131
+ # Add file_path to the session's set (deduplicated).
132
+ touch "$STATE_FILE"
133
+ if ! grep -Fxq "$FILE_PATH" "$STATE_FILE" 2>/dev/null; then
134
+ echo "$FILE_PATH" >> "$STATE_FILE"
135
+ fi
136
+
137
+ # Count distinct files touched this session.
138
+ FILE_COUNT=$(wc -l < "$STATE_FILE" 2>/dev/null | tr -d ' ')
139
+ FILE_COUNT="${FILE_COUNT:-0}"
140
+
141
+ # Below threshold → nothing to gate.
142
+ if [ "$FILE_COUNT" -lt "$THRESHOLD" ]; then
143
+ exit 0
144
+ fi
145
+
146
+ # At-or-above threshold. Is there a plan file for this session?
147
+ PLAN_FILE="$PLAN_DIR/${SAFE_SESSION}.md"
148
+ PLAN_FILE_ALT="$PLAN_DIR/plan-${SAFE_SESSION}.md"
149
+ PLAN_FILE_GENERIC="$PLAN_DIR/plan.md"
150
+
151
+ if [ -f "$PLAN_FILE" ] || [ -f "$PLAN_FILE_ALT" ] || [ -f "$PLAN_FILE_GENERIC" ]; then
152
+ # Plan exists — work has been routed, allow.
153
+ exit 0
154
+ fi
155
+
156
+ # No plan. Refuse the Write/Edit and ask the assistant to write a plan.
157
+ cat >&2 <<EOF
158
+ <system-reminder>
159
+ MULTI-FILE CHANGE WITHOUT A PLAN — this session has now touched $FILE_COUNT
160
+ distinct files via Write/Edit/MultiEdit, and no plan file exists at
161
+ $PLAN_FILE.
162
+
163
+ This is the failure mode documented in #60506 (recommendation 7): the model
164
+ sprawls across the codebase without writing a plan first, and the resulting
165
+ changes are scattered, partially-wired, or contradict each other. The cost
166
+ of an unplanned multi-file change lands on the operator at review time.
167
+
168
+ The files touched so far in this session:
169
+ $(sed 's/^/ - /' "$STATE_FILE" 2>/dev/null | head -20)
170
+
171
+ Before the next Write/Edit lands, do one of the following:
172
+
173
+ 1. Write a plan to $PLAN_FILE that lists the goal, the files involved,
174
+ the order of changes, and the verification step for each file. Once
175
+ the plan file exists, this gate auto-clears and writes proceed silently.
176
+
177
+ 2. If the changes are unrelated and a unified plan is not appropriate,
178
+ split the work across separate sessions — one task per session, gate
179
+ resets at session end (TTL 7 days).
180
+
181
+ 3. If this is a refactor where multi-file scope was inherent from the
182
+ start, the plan can be one or two paragraphs — the gate's purpose
183
+ is to require explicit forethought, not extensive documentation.
184
+
185
+ To disable this gate for design discussions, retrospectives, or sessions
186
+ where multi-file scope is not the failure mode you are guarding against,
187
+ set CC_PLAN_GATE_DISABLE=1 in your environment. The threshold can be
188
+ raised via CC_PLAN_GATE_THRESHOLD (default 3).
189
+ </system-reminder>
190
+ EOF
191
+
192
+ exit 2