cc-safe-setup 29.6.32 → 29.6.36

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 (415) hide show
  1. package/COOKBOOK.md +70 -0
  2. package/README.md +6 -2
  3. package/examples/absolute-rule-enforcer.sh +42 -0
  4. package/examples/allow-claude-settings.sh +2 -0
  5. package/examples/allow-git-hooks-dir.sh +2 -0
  6. package/examples/allow-protected-dirs.sh +2 -0
  7. package/examples/allowlist.sh +2 -0
  8. package/examples/ansible-vault-guard.sh +2 -0
  9. package/examples/auto-approve-build.sh +2 -0
  10. package/examples/auto-approve-compound-git.sh +2 -0
  11. package/examples/auto-approve-docker.sh +2 -0
  12. package/examples/auto-approve-git-read.sh +2 -0
  13. package/examples/auto-approve-python.sh +2 -0
  14. package/examples/auto-approve-readonly-tools.sh +2 -0
  15. package/examples/auto-approve-ssh.sh +2 -0
  16. package/examples/auto-approve-test.sh +2 -0
  17. package/examples/auto-checkpoint.sh +2 -0
  18. package/examples/auto-git-checkpoint.sh +2 -0
  19. package/examples/auto-mode-safe-commands.sh +2 -0
  20. package/examples/auto-snapshot.sh +2 -0
  21. package/examples/backup-before-refactor.sh +2 -0
  22. package/examples/banned-command-guard.sh +3 -3
  23. package/examples/bash-domain-allowlist.sh +72 -0
  24. package/examples/bash-safety-auto-deny.sh +56 -0
  25. package/examples/bash-secret-output-detector.sh +68 -0
  26. package/examples/bash-timeout-guard.sh +2 -0
  27. package/examples/bashrc-safety-check.sh +59 -0
  28. package/examples/bg-task-cooldown-guard.sh +46 -0
  29. package/examples/block-database-wipe.sh +2 -0
  30. package/examples/branch-name-check.sh +2 -0
  31. package/examples/branch-naming-convention.sh +2 -0
  32. package/examples/cargo-publish-guard.sh +2 -0
  33. package/examples/check-abort-controller.sh +2 -0
  34. package/examples/check-accessibility.sh +2 -0
  35. package/examples/check-aria-labels.sh +2 -0
  36. package/examples/check-async-await-consistency.sh +2 -0
  37. package/examples/check-before-act-enforcer.sh +47 -0
  38. package/examples/check-charset-meta.sh +2 -0
  39. package/examples/check-cleanup-effect.sh +2 -0
  40. package/examples/check-content-type.sh +2 -0
  41. package/examples/check-controlled-input.sh +2 -0
  42. package/examples/check-cookie-flags.sh +2 -0
  43. package/examples/check-cors-config.sh +2 -0
  44. package/examples/check-csp-headers.sh +2 -0
  45. package/examples/check-csrf-protection.sh +2 -0
  46. package/examples/check-debounce.sh +2 -0
  47. package/examples/check-dependency-age.sh +2 -0
  48. package/examples/check-dependency-license.sh +2 -0
  49. package/examples/check-dockerfile-best-practice.sh +2 -0
  50. package/examples/check-error-boundaries.sh +2 -0
  51. package/examples/check-error-class.sh +2 -0
  52. package/examples/check-error-handling.sh +2 -0
  53. package/examples/check-error-logging.sh +2 -0
  54. package/examples/check-error-message.sh +2 -0
  55. package/examples/check-error-page.sh +2 -0
  56. package/examples/check-error-stack.sh +2 -0
  57. package/examples/check-favicon.sh +2 -0
  58. package/examples/check-form-validation.sh +2 -0
  59. package/examples/check-git-hooks-compat.sh +2 -0
  60. package/examples/check-https-redirect.sh +2 -0
  61. package/examples/check-image-optimization.sh +2 -0
  62. package/examples/check-input-validation.sh +2 -0
  63. package/examples/check-key-prop.sh +2 -0
  64. package/examples/check-lang-attribute.sh +2 -0
  65. package/examples/check-lazy-loading.sh +2 -0
  66. package/examples/check-loading-state.sh +2 -0
  67. package/examples/check-memo-deps.sh +2 -0
  68. package/examples/check-meta-description.sh +2 -0
  69. package/examples/check-npm-scripts-exist.sh +2 -0
  70. package/examples/check-null-check.sh +2 -0
  71. package/examples/check-package-size.sh +2 -0
  72. package/examples/check-pagination.sh +2 -0
  73. package/examples/check-port-availability.sh +2 -0
  74. package/examples/check-promise-all.sh +2 -0
  75. package/examples/check-prop-types.sh +2 -0
  76. package/examples/check-rate-limiting.sh +2 -0
  77. package/examples/check-responsive-design.sh +2 -0
  78. package/examples/check-retry-logic.sh +2 -0
  79. package/examples/check-return-types.sh +2 -0
  80. package/examples/check-semantic-html.sh +2 -0
  81. package/examples/check-semantic-versioning.sh +2 -0
  82. package/examples/check-suspense-fallback.sh +2 -0
  83. package/examples/check-test-naming.sh +2 -0
  84. package/examples/check-timeout-cleanup.sh +2 -0
  85. package/examples/check-tls-version.sh +2 -0
  86. package/examples/check-type-coercion.sh +2 -0
  87. package/examples/check-unsubscribe.sh +2 -0
  88. package/examples/check-viewport-meta.sh +2 -0
  89. package/examples/check-worker-terminate.sh +2 -0
  90. package/examples/checkpoint-tamper-guard.sh +2 -0
  91. package/examples/chmod-guard.sh +2 -0
  92. package/examples/chown-guard.sh +2 -0
  93. package/examples/ci-workflow-guard.sh +59 -0
  94. package/examples/classifier-fallback-allow.sh +2 -0
  95. package/examples/claude-cache-gc.sh +15 -0
  96. package/examples/claudeignore-enforce-guard.sh +60 -0
  97. package/examples/claudemd-enforcer.sh +2 -0
  98. package/examples/claudemd-violation-detector.sh +36 -0
  99. package/examples/clear-command-confirm-guard.sh +21 -0
  100. package/examples/commit-message-check.sh +2 -0
  101. package/examples/compact-blocker.sh +25 -0
  102. package/examples/composer-guard.sh +2 -0
  103. package/examples/compound-command-allow.sh +2 -0
  104. package/examples/consecutive-failure-circuit-breaker.sh +49 -0
  105. package/examples/console-log-count.sh +2 -0
  106. package/examples/context-compact-advisor.sh +16 -0
  107. package/examples/core-file-protect-guard.sh +91 -0
  108. package/examples/cors-star-warn.sh +2 -0
  109. package/examples/credential-exfil-guard.sh +2 -0
  110. package/examples/credential-file-cat-guard.sh +2 -0
  111. package/examples/cron-modification-guard.sh +40 -0
  112. package/examples/cwd-drift-detector.sh +47 -0
  113. package/examples/cwd-project-boundary-guard.sh +50 -0
  114. package/examples/denied-action-retry-guard.sh +41 -0
  115. package/examples/dependency-install-guard.sh +2 -0
  116. package/examples/deploy-guard.sh +2 -0
  117. package/examples/deploy-path-verify-guard.sh +62 -0
  118. package/examples/deployment-verify-guard.sh +81 -0
  119. package/examples/django-migrate-guard.sh +2 -0
  120. package/examples/docker-volume-guard.sh +2 -0
  121. package/examples/dockerfile-latest-guard.sh +2 -0
  122. package/examples/dotenv-commit-guard.sh +44 -0
  123. package/examples/dotenv-example-sync.sh +55 -0
  124. package/examples/dotnet-build-on-edit.sh +2 -0
  125. package/examples/drizzle-migrate-guard.sh +2 -0
  126. package/examples/edit-counter-test-gate.sh +44 -0
  127. package/examples/edit-error-counter.sh +2 -0
  128. package/examples/edit-guard.sh +2 -0
  129. package/examples/edit-old-string-validator.sh +37 -0
  130. package/examples/edit-retry-loop-guard.sh +2 -0
  131. package/examples/edit-verify.sh +2 -0
  132. package/examples/encoding-preserve-guard.sh +34 -0
  133. package/examples/enforce-tests.sh +2 -0
  134. package/examples/env-inherit-guard.sh +2 -0
  135. package/examples/env-inline-secret-guard.sh +36 -0
  136. package/examples/env-prod-guard.sh +2 -0
  137. package/examples/env-required-check.sh +2 -0
  138. package/examples/env-var-check.sh +2 -0
  139. package/examples/expo-eject-guard.sh +2 -0
  140. package/examples/export-overwrite-guard.sh +29 -0
  141. package/examples/file-change-tracker.sh +2 -0
  142. package/examples/file-change-undo-tracker.sh +46 -0
  143. package/examples/file-recycle-bin.sh +48 -0
  144. package/examples/file-size-limit.sh +2 -0
  145. package/examples/five-hundred-milestone.sh +2 -0
  146. package/examples/flask-debug-guard.sh +2 -0
  147. package/examples/gem-push-guard.sh +2 -0
  148. package/examples/git-checkout-safety-guard.sh +2 -0
  149. package/examples/git-config-guard.sh +2 -0
  150. package/examples/git-crypt-worktree-guard.sh +36 -0
  151. package/examples/git-hook-bypass-guard.sh +2 -0
  152. package/examples/git-merge-conflict-prevent.sh +2 -0
  153. package/examples/git-message-length.sh +2 -0
  154. package/examples/git-operations-require-approval.sh +99 -0
  155. package/examples/git-show-flag-sanitizer.sh +41 -0
  156. package/examples/git-stash-before-danger.sh +2 -0
  157. package/examples/git-submodule-guard.sh +2 -0
  158. package/examples/git-tag-guard.sh +2 -0
  159. package/examples/github-actions-secret-guard.sh +59 -0
  160. package/examples/gitignore-check.sh +2 -0
  161. package/examples/gitops-drift-guard.sh +53 -0
  162. package/examples/go-mod-tidy-warn.sh +2 -0
  163. package/examples/hallucination-url-check.sh +2 -0
  164. package/examples/hardcoded-ip-guard.sh +2 -0
  165. package/examples/headless-empty-result-guard.sh +46 -0
  166. package/examples/headless-stop-guard.sh +43 -0
  167. package/examples/helm-install-guard.sh +2 -0
  168. package/examples/issue-draft-redact-guard.sh +45 -0
  169. package/examples/java-compile-on-edit.sh +2 -0
  170. package/examples/k8s-production-guard.sh +77 -0
  171. package/examples/laravel-artisan-guard.sh +2 -0
  172. package/examples/large-file-guard.sh +2 -0
  173. package/examples/line-ending-guard.sh +30 -0
  174. package/examples/log-level-guard.sh +2 -0
  175. package/examples/magic-number-warn.sh +2 -0
  176. package/examples/max-edit-size-guard.sh +2 -0
  177. package/examples/max-file-count-guard.sh +2 -0
  178. package/examples/max-file-delete-count.sh +2 -0
  179. package/examples/max-function-length.sh +2 -0
  180. package/examples/max-import-count.sh +2 -0
  181. package/examples/max-subagent-count.sh +2 -0
  182. package/examples/mcp-orphan-process-guard.sh +39 -0
  183. package/examples/mcp-server-allowlist.sh +45 -0
  184. package/examples/mcp-tool-audit-log.sh +41 -0
  185. package/examples/mcp-tool-guard.sh +2 -0
  186. package/examples/migration-verify-guard.sh +44 -0
  187. package/examples/monorepo-scope-guard.sh +2 -0
  188. package/examples/network-exfil-guard.sh +61 -0
  189. package/examples/network-guard.sh +2 -0
  190. package/examples/nextjs-env-guard.sh +2 -0
  191. package/examples/no-absolute-import.sh +2 -0
  192. package/examples/no-alert-confirm-prompt.sh +2 -0
  193. package/examples/no-any-type.sh +2 -0
  194. package/examples/no-any-typescript.sh +2 -0
  195. package/examples/no-assignment-in-condition.sh +2 -0
  196. package/examples/no-callback-hell.sh +2 -0
  197. package/examples/no-catch-all-route.sh +2 -0
  198. package/examples/no-circular-dependency.sh +2 -0
  199. package/examples/no-class-in-functional.sh +2 -0
  200. package/examples/no-cleartext-storage.sh +2 -0
  201. package/examples/no-commented-code.sh +2 -0
  202. package/examples/no-commit-fixup.sh +2 -0
  203. package/examples/no-console-assert.sh +2 -0
  204. package/examples/no-console-error-swallow.sh +2 -0
  205. package/examples/no-console-in-prod.sh +2 -0
  206. package/examples/no-console-log.sh +2 -0
  207. package/examples/no-console-time.sh +2 -0
  208. package/examples/no-cors-wildcard.sh +2 -0
  209. package/examples/no-curl-upload.sh +2 -0
  210. package/examples/no-dangerouslySetInnerHTML.sh +2 -0
  211. package/examples/no-dangling-await.sh +2 -0
  212. package/examples/no-debug-in-commit.sh +2 -0
  213. package/examples/no-deep-nesting.sh +2 -0
  214. package/examples/no-deep-relative-import.sh +2 -0
  215. package/examples/no-default-credentials.sh +2 -0
  216. package/examples/no-deprecated-api.sh +2 -0
  217. package/examples/no-direct-dom-manipulation.sh +2 -0
  218. package/examples/no-disabled-test.sh +2 -0
  219. package/examples/no-document-cookie.sh +2 -0
  220. package/examples/no-document-write.sh +2 -0
  221. package/examples/no-empty-function.sh +2 -0
  222. package/examples/no-eval-in-template.sh +2 -0
  223. package/examples/no-eval-template.sh +2 -0
  224. package/examples/no-eval.sh +2 -0
  225. package/examples/no-exec-user-input.sh +2 -0
  226. package/examples/no-expose-internal-ids.sh +2 -0
  227. package/examples/no-floating-promises.sh +2 -0
  228. package/examples/no-force-install.sh +2 -0
  229. package/examples/no-git-rebase-public.sh +2 -0
  230. package/examples/no-global-state.sh +2 -0
  231. package/examples/no-hardcoded-port.sh +2 -0
  232. package/examples/no-hardcoded-url.sh +2 -0
  233. package/examples/no-helmet-missing.sh +2 -0
  234. package/examples/no-http-url.sh +2 -0
  235. package/examples/no-http-without-https.sh +2 -0
  236. package/examples/no-index-as-key.sh +2 -0
  237. package/examples/no-infinite-scroll-mem.sh +2 -0
  238. package/examples/no-inline-event-handler.sh +2 -0
  239. package/examples/no-inline-handler.sh +2 -0
  240. package/examples/no-inline-style.sh +2 -0
  241. package/examples/no-inline-styles.sh +2 -0
  242. package/examples/no-innerhtml.sh +2 -0
  243. package/examples/no-install-global.sh +2 -0
  244. package/examples/no-jwt-in-url.sh +2 -0
  245. package/examples/no-large-commit.sh +2 -0
  246. package/examples/no-localhost-expose.sh +2 -0
  247. package/examples/no-long-switch.sh +2 -0
  248. package/examples/no-magic-number.sh +2 -0
  249. package/examples/no-md5-sha1.sh +2 -0
  250. package/examples/no-memory-leak-interval.sh +2 -0
  251. package/examples/no-mixed-line-endings.sh +2 -0
  252. package/examples/no-mutation-in-reducer.sh +2 -0
  253. package/examples/no-mutation-observer-leak.sh +2 -0
  254. package/examples/no-nested-subscribe.sh +2 -0
  255. package/examples/no-nested-ternary.sh +2 -0
  256. package/examples/no-network-exfil.sh +2 -0
  257. package/examples/no-new-array-fill.sh +2 -0
  258. package/examples/no-object-freeze-mutation.sh +2 -0
  259. package/examples/no-open-redirect.sh +2 -0
  260. package/examples/no-output-truncation.sh +44 -0
  261. package/examples/no-package-downgrade.sh +2 -0
  262. package/examples/no-package-lock-edit.sh +2 -0
  263. package/examples/no-path-join-user-input.sh +2 -0
  264. package/examples/no-port-bind.sh +2 -0
  265. package/examples/no-process-exit.sh +2 -0
  266. package/examples/no-prototype-pollution.sh +2 -0
  267. package/examples/no-push-without-ci.sh +2 -0
  268. package/examples/no-raw-ref.sh +2 -0
  269. package/examples/no-redundant-fragment.sh +2 -0
  270. package/examples/no-render-in-loop.sh +2 -0
  271. package/examples/no-root-user-docker.sh +2 -0
  272. package/examples/no-root-write.sh +2 -0
  273. package/examples/no-secrets-in-args.sh +2 -0
  274. package/examples/no-secrets-in-logs.sh +2 -0
  275. package/examples/no-sensitive-log.sh +2 -0
  276. package/examples/no-side-effects-in-render.sh +2 -0
  277. package/examples/no-sleep-in-hooks.sh +2 -0
  278. package/examples/no-star-import-python.sh +2 -0
  279. package/examples/no-string-concat-sql.sh +2 -0
  280. package/examples/no-sudo-guard.sh +2 -0
  281. package/examples/no-sync-external-call.sh +2 -0
  282. package/examples/no-sync-fs.sh +2 -0
  283. package/examples/no-table-layout.sh +2 -0
  284. package/examples/no-throw-string.sh +2 -0
  285. package/examples/no-todo-in-merge.sh +2 -0
  286. package/examples/no-todo-in-production.sh +2 -0
  287. package/examples/no-todo-without-issue.sh +2 -0
  288. package/examples/no-triple-slash-ref.sh +2 -0
  289. package/examples/no-unreachable-code.sh +2 -0
  290. package/examples/no-unused-import.sh +2 -0
  291. package/examples/no-unused-state.sh +2 -0
  292. package/examples/no-var-keyword.sh +2 -0
  293. package/examples/no-wildcard-cors.sh +2 -0
  294. package/examples/no-wildcard-import.sh +2 -0
  295. package/examples/no-window-location.sh +2 -0
  296. package/examples/no-with-statement.sh +2 -0
  297. package/examples/no-write-outside-src.sh +2 -0
  298. package/examples/no-xml-external-entity.sh +2 -0
  299. package/examples/notify-waiting.sh +2 -0
  300. package/examples/npm-audit-warn.sh +2 -0
  301. package/examples/npm-publish-guard.sh +2 -0
  302. package/examples/npm-script-injection.sh +2 -0
  303. package/examples/npm-supply-chain-guard.sh +92 -0
  304. package/examples/nuxt-config-guard.sh +2 -0
  305. package/examples/output-secret-mask.sh +2 -0
  306. package/examples/package-json-guard.sh +2 -0
  307. package/examples/parallel-session-guard.sh +2 -0
  308. package/examples/path-traversal-guard.sh +2 -0
  309. package/examples/permission-audit-log.sh +2 -0
  310. package/examples/permission-entry-validator.sh +48 -0
  311. package/examples/permission-pattern-auto-allow.sh +50 -0
  312. package/examples/php-lint-on-edit.sh +2 -0
  313. package/examples/pip-publish-guard.sh +2 -0
  314. package/examples/plain-language-danger-warn.sh +37 -0
  315. package/examples/plan-mode-enforcer.sh +2 -0
  316. package/examples/plugin-process-cleanup.sh +50 -0
  317. package/examples/polyglot-rm-guard.sh +59 -0
  318. package/examples/pr-description-check.sh +2 -0
  319. package/examples/pre-compact-knowledge-save.sh +53 -0
  320. package/examples/pre-compact-transcript-export.sh +85 -0
  321. package/examples/prefer-builtin-tools.sh +2 -0
  322. package/examples/prefer-const.sh +2 -0
  323. package/examples/prefer-dedicated-tools.sh +55 -0
  324. package/examples/prefer-optional-chaining.sh +2 -0
  325. package/examples/prisma-migrate-guard.sh +2 -0
  326. package/examples/prompt-injection-detector.sh +2 -0
  327. package/examples/prompt-length-guard.sh +2 -0
  328. package/examples/protect-dotfiles.sh +2 -0
  329. package/examples/public-repo-push-guard.sh +58 -0
  330. package/examples/push-requires-test-pass-record.sh +2 -0
  331. package/examples/push-requires-test-pass.sh +2 -0
  332. package/examples/rails-migration-guard.sh +2 -0
  333. package/examples/rate-limit-guard.sh +2 -0
  334. package/examples/read-all-files-enforcer.sh +51 -0
  335. package/examples/read-audit-log.sh +34 -0
  336. package/examples/readme-exists-check.sh +2 -0
  337. package/examples/redis-flushall-guard.sh +2 -0
  338. package/examples/rm-safety-net.sh +2 -0
  339. package/examples/role-tool-guard.sh +69 -0
  340. package/examples/ruby-lint-on-edit.sh +2 -0
  341. package/examples/schema-migration-guard.sh +57 -0
  342. package/examples/scope-guard.sh +2 -0
  343. package/examples/secret-file-read-guard.sh +74 -0
  344. package/examples/self-modify-bypass-guard.sh +54 -0
  345. package/examples/sensitive-log-guard.sh +2 -0
  346. package/examples/session-checkpoint.sh +2 -0
  347. package/examples/session-duration-guard.sh +51 -0
  348. package/examples/session-end-logger.sh +57 -0
  349. package/examples/session-error-rate-monitor.sh +65 -0
  350. package/examples/session-health-monitor.sh +61 -0
  351. package/examples/session-memory-watchdog.sh +17 -0
  352. package/examples/session-permission-reset-guard.sh +39 -0
  353. package/examples/session-resume-env-fix.sh +49 -0
  354. package/examples/session-state-saver.sh +2 -0
  355. package/examples/session-summary-stop.sh +2 -0
  356. package/examples/session-summary.sh +2 -0
  357. package/examples/session-token-counter.sh +2 -0
  358. package/examples/settings-auto-backup.sh +53 -0
  359. package/examples/settings-mutation-detector.sh +45 -0
  360. package/examples/shell-wrapper-guard.sh +2 -0
  361. package/examples/skill-gate.sh +2 -0
  362. package/examples/skill-injection-detector.sh +41 -0
  363. package/examples/spec-file-scope-guard.sh +69 -0
  364. package/examples/spring-profile-guard.sh +2 -0
  365. package/examples/sql-injection-detect.sh +2 -0
  366. package/examples/subagent-budget-guard.sh +2 -0
  367. package/examples/subagent-claudemd-inject.sh +45 -0
  368. package/examples/subagent-context-size-guard.sh +26 -0
  369. package/examples/subagent-tool-call-limiter.sh +48 -0
  370. package/examples/svelte-lint-on-edit.sh +2 -0
  371. package/examples/swift-build-on-edit.sh +2 -0
  372. package/examples/symlink-protect.sh +12 -0
  373. package/examples/system-message-workaround.sh +44 -0
  374. package/examples/system-package-guard.sh +2 -0
  375. package/examples/temp-file-cleanup-stop.sh +28 -0
  376. package/examples/temp-file-cleanup.sh +2 -0
  377. package/examples/terminal-state-restore.sh +23 -0
  378. package/examples/test-after-edit.sh +2 -0
  379. package/examples/test-before-commit.sh +13 -14
  380. package/examples/test-before-push.sh +2 -0
  381. package/examples/test-exit-code-verify.sh +2 -0
  382. package/examples/timeout-guard.sh +2 -0
  383. package/examples/timezone-guard.sh +2 -0
  384. package/examples/tmp-output-size-guard.sh +46 -0
  385. package/examples/todo-check.sh +2 -0
  386. package/examples/todo-deadline-warn.sh +48 -0
  387. package/examples/token-budget-per-task.sh +55 -0
  388. package/examples/token-spike-alert.sh +51 -0
  389. package/examples/token-usage-tracker.sh +14 -0
  390. package/examples/turbo-cache-guard.sh +2 -0
  391. package/examples/uncommitted-changes-stop.sh +2 -0
  392. package/examples/uncommitted-work-shield.sh +37 -0
  393. package/examples/usage-warn.sh +2 -0
  394. package/examples/verify-before-commit.sh +2 -0
  395. package/examples/virtual-cwd-helper.sh +40 -0
  396. package/examples/vue-lint-on-edit.sh +2 -0
  397. package/examples/webfetch-domain-allow.sh +96 -0
  398. package/examples/worktree-delete-guard.sh +43 -0
  399. package/examples/worktree-memory-guard.sh +47 -0
  400. package/examples/worktree-path-validator.sh +42 -0
  401. package/examples/worktree-project-unify.sh +19 -0
  402. package/examples/worktree-unmerged-guard.sh +2 -0
  403. package/examples/write-overwrite-confirm.sh +40 -0
  404. package/examples/write-secret-guard.sh +2 -0
  405. package/examples/write-shrink-guard.sh +46 -0
  406. package/examples/write-test-ratio.sh +2 -0
  407. package/index.mjs +631 -138
  408. package/package.json +2 -2
  409. package/scripts/generate-categories.mjs +206 -0
  410. package/scripts.json +4 -1
  411. package/test.sh.new_tests +0 -0
  412. package/test.sh.patch +0 -0
  413. package/tests/test-core-file-protect-guard.sh +73 -0
  414. package/tests/test-deployment-verify-guard.sh +74 -0
  415. package/tests/test-git-operations-require-approval.sh +65 -0
@@ -0,0 +1,69 @@
1
+ #!/bin/bash
2
+ # spec-file-scope-guard.sh — Restrict edits to files mentioned in a spec document
3
+ #
4
+ # Solves: Agent ignoring specification across multiple sessions (#40383).
5
+ # Claude modifies files not mentioned in the spec, introduces
6
+ # fabricated data, and drifts from the stated objective.
7
+ #
8
+ # How it works: Reads a spec/requirements file, extracts file paths and
9
+ # directory names mentioned in it, then blocks Edit/Write to files
10
+ # outside that scope.
11
+ #
12
+ # Setup:
13
+ # echo "spec.md" > .claude/spec-file.txt
14
+ # # Or set CC_SPEC_FILE=spec.md
15
+ #
16
+ # TRIGGER: PreToolUse
17
+ # MATCHER: "Edit|Write"
18
+
19
+ set -euo pipefail
20
+
21
+ INPUT=$(cat)
22
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
23
+
24
+ case "$TOOL" in
25
+ Edit|Write) ;;
26
+ *) exit 0 ;;
27
+ esac
28
+
29
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
30
+ [ -z "$FILE" ] && exit 0
31
+
32
+ # Find spec file
33
+ SPEC_FILE="${CC_SPEC_FILE:-}"
34
+ if [ -z "$SPEC_FILE" ] && [ -f ".claude/spec-file.txt" ]; then
35
+ SPEC_FILE=$(head -1 ".claude/spec-file.txt" | tr -d '\n')
36
+ fi
37
+ [ -z "$SPEC_FILE" ] && exit 0
38
+ [ -f "$SPEC_FILE" ] || exit 0
39
+
40
+ # Extract paths/directories mentioned in spec
41
+ # Matches: path/to/file.ext, src/components/, ./config.ts, etc.
42
+ MENTIONED=$(grep -oE '(\.?/?[a-zA-Z0-9_-]+/)+[a-zA-Z0-9_.-]*' "$SPEC_FILE" | sort -u || true)
43
+
44
+ if [ -z "$MENTIONED" ]; then
45
+ # No paths found in spec — don't restrict
46
+ exit 0
47
+ fi
48
+
49
+ # Check if the target file matches any mentioned path
50
+ BASENAME=$(basename "$FILE")
51
+ DIRNAME=$(dirname "$FILE")
52
+
53
+ for path in $MENTIONED; do
54
+ # Match if file path contains the spec path
55
+ if echo "$FILE" | grep -qF "$path"; then
56
+ exit 0
57
+ fi
58
+ # Match if basename matches
59
+ if echo "$BASENAME" | grep -qF "$path"; then
60
+ exit 0
61
+ fi
62
+ done
63
+
64
+ echo "WARNING: Editing file not mentioned in spec ($SPEC_FILE):" >&2
65
+ echo " File: $FILE" >&2
66
+ echo " Spec mentions: $(echo "$MENTIONED" | head -5 | tr '\n' ', ')" >&2
67
+ echo " Stay focused on the specification." >&2
68
+ # Warning only — change to exit 2 to block
69
+ exit 0
@@ -1,3 +1,5 @@
1
+ #
2
+ # TRIGGER: PreToolUse MATCHER: "Edit|Write"
1
3
  INPUT=$(cat)
2
4
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
3
5
  [[ -z "$COMMAND" ]] && exit 0
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Edit|Write"
2
4
  INPUT=$(cat)
3
5
  CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
4
6
  [ -z "$CONTENT" ] && exit 0
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Bash"
2
4
  INPUT=$(cat)
3
5
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
4
6
  [[ "$TOOL" != "Agent" ]] && exit 0
@@ -0,0 +1,45 @@
1
+ #!/bin/bash
2
+ # subagent-claudemd-inject.sh — Inject CLAUDE.md rules into subagent prompts
3
+ #
4
+ # Solves: Subagents lose CLAUDE.md context since v2.1.84 (#40459).
5
+ # omitClaudeMd:true strips project instructions from Explore/Plan agents,
6
+ # causing them to ignore language preferences, environment config, etc.
7
+ #
8
+ # How it works: PreToolUse hook on Agent that appends key CLAUDE.md rules
9
+ # to the subagent's prompt. Extracts critical rules (marked with SUBAGENT:
10
+ # prefix in CLAUDE.md) and injects them into the agent description/prompt.
11
+ #
12
+ # Setup: Mark critical rules in CLAUDE.md with "SUBAGENT:" prefix:
13
+ # ## SUBAGENT: Always respond in Japanese
14
+ # ## SUBAGENT: Use DEV environment for testing
15
+ #
16
+ # TRIGGER: PreToolUse
17
+ # MATCHER: "Agent"
18
+
19
+ set -euo pipefail
20
+
21
+ INPUT=$(cat)
22
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
23
+ [ "$TOOL" = "Agent" ] || exit 0
24
+
25
+ # Find CLAUDE.md
26
+ CLAUDEMD=""
27
+ for candidate in "CLAUDE.md" "../CLAUDE.md" "../../CLAUDE.md"; do
28
+ if [ -f "$candidate" ]; then
29
+ CLAUDEMD="$candidate"
30
+ break
31
+ fi
32
+ done
33
+ [ -n "$CLAUDEMD" ] || exit 0
34
+
35
+ # Extract SUBAGENT-tagged rules
36
+ RULES=$(grep -iE '^##?\s*SUBAGENT:' "$CLAUDEMD" 2>/dev/null | sed 's/^##\?\s*SUBAGENT:\s*//' | head -10 || true)
37
+ [ -z "$RULES" ] && exit 0
38
+
39
+ # Inject rules as a system message warning
40
+ echo "REMINDER: Project rules from CLAUDE.md (apply to all subagents):" >&2
41
+ echo "$RULES" | while IFS= read -r rule; do
42
+ echo " - $rule" >&2
43
+ done
44
+
45
+ exit 0
@@ -0,0 +1,26 @@
1
+ #!/bin/bash
2
+ # subagent-context-size-guard.sh — Warn on thin subagent prompts
3
+ #
4
+ # Solves: Subagents get spawned with minimal context, leading to
5
+ # poor results because they lack necessary background (#40929).
6
+ # The parent agent assumes shared context, but each subagent
7
+ # starts fresh.
8
+ #
9
+ # How it works: Checks Agent tool's prompt parameter length.
10
+ # If under 100 characters, warns that the prompt may be too thin
11
+ # for a standalone agent to work effectively.
12
+ #
13
+ # TRIGGER: PreToolUse
14
+ # MATCHER: "Agent"
15
+
16
+ set -euo pipefail
17
+ INPUT=$(cat)
18
+ PROMPT=$(echo "$INPUT" | jq -r '.tool_input.prompt // empty' 2>/dev/null)
19
+
20
+ [ -z "$PROMPT" ] && exit 0
21
+
22
+ LEN=${#PROMPT}
23
+ if [ "$LEN" -lt 100 ]; then
24
+ echo "WARNING: Agent prompt is only ${LEN} chars. Subagents start with zero context — include enough background for them to work independently." >&2
25
+ fi
26
+ exit 0
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # subagent-tool-call-limiter.sh — Limit total tool calls per session
3
+ #
4
+ # Solves: Subagents making unbounded tool calls (#36727).
5
+ # One user reported 234 tool calls in 1.5 hours from a single subagent.
6
+ # Existing rate limiters check frequency, not total count.
7
+ #
8
+ # How it works: PreToolUse hook (all tools) that increments a counter file.
9
+ # When CC_MAX_TOOL_CALLS (default 200) is reached, blocks further calls.
10
+ #
11
+ # TRIGGER: PreToolUse
12
+ # MATCHER: ""
13
+
14
+ set -euo pipefail
15
+
16
+ MAX_CALLS="${CC_MAX_TOOL_CALLS:-200}"
17
+ COUNTER_FILE="/tmp/claude-tool-call-counter-$$"
18
+
19
+ # Use session-based counter (PID of parent process)
20
+ PPID_FILE="/tmp/claude-tool-call-counter-${PPID:-0}"
21
+ [ -f "$PPID_FILE" ] && COUNTER_FILE="$PPID_FILE"
22
+
23
+ # Initialize or read counter
24
+ if [ -f "$COUNTER_FILE" ]; then
25
+ COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
26
+ else
27
+ COUNT=0
28
+ COUNTER_FILE="$PPID_FILE"
29
+ fi
30
+
31
+ COUNT=$((COUNT + 1))
32
+ echo "$COUNT" > "$COUNTER_FILE"
33
+
34
+ # Check limit
35
+ if [ "$COUNT" -gt "$MAX_CALLS" ]; then
36
+ echo "BLOCKED: Tool call limit reached ($COUNT/$MAX_CALLS)." >&2
37
+ echo "This session has made $COUNT tool calls (limit: $MAX_CALLS)." >&2
38
+ echo "Consider starting a new session or increasing CC_MAX_TOOL_CALLS." >&2
39
+ exit 2
40
+ fi
41
+
42
+ # Warn at 80%
43
+ WARN_AT=$((MAX_CALLS * 80 / 100))
44
+ if [ "$COUNT" -eq "$WARN_AT" ]; then
45
+ echo "WARNING: $COUNT/$MAX_CALLS tool calls used (80%). Consider wrapping up." >&2
46
+ fi
47
+
48
+ exit 0
@@ -1,3 +1,5 @@
1
+ #
2
+ # TRIGGER: PostToolUse MATCHER: "Edit|Write"
1
3
  INPUT=$(cat)
2
4
  FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
3
5
  [[ -z "$FILE" ]] && exit 0
@@ -17,6 +17,8 @@
17
17
  # }
18
18
  # }
19
19
  # ================================================================
20
+ #
21
+ # TRIGGER: PreToolUse MATCHER: "Bash"
20
22
 
21
23
  INPUT=$(cat)
22
24
  FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
@@ -0,0 +1,12 @@
1
+ INPUT=$(cat)
2
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
3
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
4
+ [ -z "$FILE" ] && exit 0
5
+ [[ "$TOOL" != "Write" && "$TOOL" != "Edit" ]] && exit 0
6
+ if [ -L "$FILE" ]; then
7
+ TARGET=$(readlink -f "$FILE")
8
+ echo "NOTE: Redirecting write from symlink $FILE → $TARGET" >&2
9
+ echo "{\"updatedInput\":{\"file_path\":\"$TARGET\"}}"
10
+ exit 1
11
+ fi
12
+ exit 0
@@ -0,0 +1,44 @@
1
+ #!/bin/bash
2
+ # system-message-workaround.sh — Ensure hook warnings reach both user and model
3
+ #
4
+ # Solves: PreToolUse/PostToolUse systemMessage silently dropped (#40380).
5
+ # When a hook returns only systemMessage (without hookSpecificOutput),
6
+ # the warning is invisible to both user and model.
7
+ #
8
+ # How it works: Template hook that demonstrates the correct pattern for
9
+ # sending warnings that are visible. Uses stderr for user visibility
10
+ # AND hookSpecificOutput.systemMessage for model context injection.
11
+ #
12
+ # Usage: Copy and adapt this pattern for your custom warn hooks.
13
+ #
14
+ # TRIGGER: PreToolUse
15
+ # MATCHER: "Bash"
16
+
17
+ set -euo pipefail
18
+
19
+ INPUT=$(cat)
20
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
21
+ [ -z "$COMMAND" ] && exit 0
22
+
23
+ # Example: warn on dangerous-looking but not blocked commands
24
+ WARNING=""
25
+
26
+ if echo "$COMMAND" | grep -qE 'DROP\s+TABLE|TRUNCATE\s+TABLE'; then
27
+ WARNING="Database destructive operation detected: $COMMAND"
28
+ elif echo "$COMMAND" | grep -qE 'curl.*-X\s*(DELETE|PUT|PATCH)'; then
29
+ WARNING="Destructive HTTP method detected: $COMMAND"
30
+ fi
31
+
32
+ if [ -n "$WARNING" ]; then
33
+ # Method 1: stderr — always visible to the user in terminal
34
+ echo "⚠ WARNING: $WARNING" >&2
35
+
36
+ # Method 2: hookSpecificOutput with systemMessage — visible to model
37
+ # This is the workaround for #40380: include hookSpecificOutput
38
+ # to ensure the systemMessage is actually processed
39
+ cat << ENDJSON
40
+ {"hookSpecificOutput":{"hookEventName":"PreToolUse","decision":"allow","systemMessage":"WARNING: $WARNING. Proceed with caution."}}
41
+ ENDJSON
42
+ fi
43
+
44
+ exit 0
@@ -21,6 +21,8 @@
21
21
  # }
22
22
  # }
23
23
  # ================================================================
24
+ #
25
+ # TRIGGER: PreToolUse MATCHER: "Bash"
24
26
 
25
27
  INPUT=$(cat)
26
28
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -0,0 +1,28 @@
1
+ #!/bin/bash
2
+ # temp-file-cleanup-stop.sh — Clean up tmpclaude-* files on session end
3
+ #
4
+ # Solves: Claude Code creates tmpclaude-{hash}-cwd temporary
5
+ # files in the working directory but doesn't clean them
6
+ # up after the session ends (#17720). These accumulate
7
+ # over time and clutter the project.
8
+ #
9
+ # How it works: On Stop event, finds and removes all
10
+ # tmpclaude-*-cwd files in the current directory and /tmp.
11
+ # Only removes files matching the exact pattern to avoid
12
+ # deleting user files.
13
+ #
14
+ # TRIGGER: Stop
15
+ # MATCHER: ""
16
+
17
+ set -euo pipefail
18
+
19
+ # Clean up tmpclaude-* files in current directory
20
+ find . -maxdepth 1 -name "tmpclaude-*-cwd" -type f -delete 2>/dev/null || true
21
+
22
+ # Also clean up in /tmp
23
+ find /tmp -maxdepth 1 -name "tmpclaude-*" -type f -mmin +60 -delete 2>/dev/null || true
24
+
25
+ # Clean up any .claude-tmp-* files too
26
+ find . -maxdepth 1 -name ".claude-tmp-*" -type f -delete 2>/dev/null || true
27
+
28
+ exit 0
@@ -21,6 +21,8 @@
21
21
  # }
22
22
 
23
23
  # Count before cleanup
24
+ #
25
+ # TRIGGER: PreToolUse MATCHER: "Bash"
24
26
  COUNT=$(find /tmp -maxdepth 1 -name "claude-*" -type f 2>/dev/null | wc -l)
25
27
 
26
28
  if [ "$COUNT" -eq 0 ]; then
@@ -0,0 +1,23 @@
1
+ #!/bin/bash
2
+ # terminal-state-restore — restore terminal to clean state on session exit
3
+ # Fixes: bracketed paste mode, application cursor keys, cursor visibility,
4
+ # line wrapping, Kitty keyboard protocol left enabled after exit.
5
+ # Event: Notification (matcher: "stop")
6
+ # Related: https://github.com/anthropics/claude-code/issues/39272
7
+
8
+ # Reset bracketed paste mode
9
+ printf '\e[?2004l'
10
+ # Reset application cursor keys to normal mode
11
+ printf '\e[?1l'
12
+ # Ensure cursor is visible
13
+ printf '\e[?25h'
14
+ # Re-enable line wrapping
15
+ printf '\e[?7h'
16
+ # Disable Kitty keyboard protocol (if enabled)
17
+ printf '\e[>0u' 2>/dev/null
18
+ # Reset character set to default
19
+ printf '\e(B'
20
+ # Restore default SGR (color/style reset)
21
+ printf '\e[0m'
22
+
23
+ exit 0
@@ -21,6 +21,8 @@
21
21
  # }
22
22
  # }
23
23
  # ================================================================
24
+ #
25
+ # TRIGGER: PreToolUse MATCHER: "Bash"
24
26
 
25
27
  INPUT=$(cat)
26
28
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
@@ -1,18 +1,17 @@
1
1
  #!/bin/bash
2
- COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
2
+ INPUT=$(cat)
3
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
3
4
  [ -z "$COMMAND" ] && exit 0
4
- echo "$COMMAND" | grep -qE '^\s*git\s+commit' || exit 0
5
- RECENT=0
6
- TIMEOUT=${CC_TEST_TIMEOUT:-600}
7
- NOW=$(date +%s)
8
- for marker in coverage/.last-run.json test-results .nyc_output junit.xml; do
9
- [ -e "$marker" ] || continue
10
- MTIME=$(stat -c %Y "$marker" 2>/dev/null || echo 0)
11
- [ $((NOW - MTIME)) -lt "$TIMEOUT" ] && RECENT=1 && break
12
- done
13
- if [ "$RECENT" -eq 0 ]; then
14
- echo "BLOCKED: No recent test results (within $((TIMEOUT/60)) min)" >&2
15
- echo "Run your test suite first, then commit." >&2
16
- exit 2
5
+ STATE="/tmp/cc-tests-ran-$$"
6
+ if echo "$COMMAND" | grep -qE '^\s*(npm\s+test|npx\s+jest|pytest|python\s+-m\s+pytest|cargo\s+test|go\s+test|make\s+test|bundle\s+exec\s+rspec|mix\s+test)'; then
7
+ echo "1" > "$STATE"
8
+ exit 0
9
+ fi
10
+ if echo "$COMMAND" | grep -qE '^\s*git\s+commit'; then
11
+ if [ ! -f "$STATE" ] || [ "$(cat "$STATE" 2>/dev/null)" != "1" ]; then
12
+ echo "WARNING: No test commands detected since last commit." >&2
13
+ echo " Run tests before committing to verify your changes." >&2
14
+ fi
15
+ rm -f "$STATE"
17
16
  fi
18
17
  exit 0
@@ -23,6 +23,8 @@
23
23
  #
24
24
  # The "if" field (v2.1.85+) eliminates process spawning for non-push commands.
25
25
  # Without "if", the hook still works — it checks internally and exits early.
26
+ #
27
+ # TRIGGER: PreToolUse MATCHER: "Bash"
26
28
 
27
29
  INPUT=$(cat)
28
30
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -17,6 +17,8 @@
17
17
  #
18
18
  # Why stderr: PostToolUse hook stderr is shown to Claude as feedback.
19
19
  # This forces Claude to acknowledge test failures instead of fabricating results.
20
+ #
21
+ # TRIGGER: PostToolUse MATCHER: "Bash"
20
22
 
21
23
  INPUT=$(cat)
22
24
 
@@ -15,6 +15,8 @@
15
15
  # }]
16
16
  # }
17
17
  # }
18
+ #
19
+ # TRIGGER: PreToolUse MATCHER: "Bash"
18
20
 
19
21
  INPUT=$(cat)
20
22
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Bash"
2
4
  COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
3
5
  [ -z "$COMMAND" ] && exit 0
4
6
  if echo "$COMMAND" | grep -qE "TZ=|--timezone" && ! echo "$COMMAND" | grep -q "UTC"; then echo "NOTE: Non-UTC timezone in command" >&2; fi
@@ -0,0 +1,46 @@
1
+ #!/bin/bash
2
+ # tmp-output-size-guard.sh — Monitor and warn about large tmp output files
3
+ #
4
+ # Solves: Task .output files in /tmp grow unbounded (95GB+) filling disk
5
+ # (#39909). Subagent output aggregation can create multi-GB files.
6
+ #
7
+ # How it works: Notification/SessionStart hook that checks /tmp for large
8
+ # Claude Code output files and warns if any exceed a threshold.
9
+ # Also provides a cleanup command suggestion.
10
+ #
11
+ # TRIGGER: SessionStart
12
+ # MATCHER: ""
13
+ #
14
+ # Usage:
15
+ # {
16
+ # "hooks": {
17
+ # "SessionStart": [{
18
+ # "hooks": [{ "type": "command", "command": "~/.claude/hooks/tmp-output-size-guard.sh" }]
19
+ # }]
20
+ # }
21
+ # }
22
+
23
+ # Configurable threshold in MB
24
+ THRESHOLD_MB="${CC_TMP_THRESHOLD_MB:-500}"
25
+
26
+ # Find Claude Code tmp directories
27
+ TMP_BASE="/tmp/claude-$(id -u)"
28
+ [ -d "/private/tmp/claude-$(id -u)" ] && TMP_BASE="/private/tmp/claude-$(id -u)"
29
+ [ ! -d "$TMP_BASE" ] && exit 0
30
+
31
+ # Find files over threshold
32
+ LARGE_FILES=$(find "$TMP_BASE" -name "*.output" -size "+${THRESHOLD_MB}M" 2>/dev/null)
33
+ [ -z "$LARGE_FILES" ] && exit 0
34
+
35
+ TOTAL_SIZE=$(echo "$LARGE_FILES" | xargs du -sh 2>/dev/null | awk '{sum+=$1} END {print sum}')
36
+ FILE_COUNT=$(echo "$LARGE_FILES" | wc -l | tr -d ' ')
37
+
38
+ echo "⚠ Found $FILE_COUNT large task output file(s) in $TMP_BASE (>${THRESHOLD_MB}MB each):" >&2
39
+ echo "$LARGE_FILES" | while read f; do
40
+ SIZE=$(du -sh "$f" 2>/dev/null | cut -f1)
41
+ echo " $SIZE $(basename "$f")" >&2
42
+ done
43
+ echo "" >&2
44
+ echo "To clean up: find $TMP_BASE -name '*.output' -size +${THRESHOLD_MB}M -delete" >&2
45
+
46
+ exit 0
@@ -14,6 +14,8 @@
14
14
  # }]
15
15
  # }
16
16
  # }
17
+ #
18
+ # TRIGGER: PreToolUse MATCHER: "Bash"
17
19
 
18
20
  INPUT=$(cat)
19
21
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # todo-deadline-warn.sh — Warn about expired TODO deadlines in edited files
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # TODOs with dates (e.g., "TODO(2026-03-01): fix this") are often
7
+ # forgotten. When Claude edits a file containing expired TODOs,
8
+ # this hook warns so they can be addressed while the file is open.
9
+ #
10
+ # TRIGGER: PostToolUse
11
+ # MATCHER: "Edit|Write"
12
+ #
13
+ # DECISION: Advisory only (exit 0). Warns via stderr.
14
+ # ================================================================
15
+
16
+ INPUT=$(cat)
17
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
18
+ [ -z "$FILE" ] && exit 0
19
+ [ ! -f "$FILE" ] && exit 0
20
+
21
+ # Skip non-code files
22
+ case "$FILE" in
23
+ *.md|*.txt|*.json|*.yaml|*.yml|*.toml|*.xml|*.html|*.css) exit 0 ;;
24
+ esac
25
+
26
+ TODAY=$(date +%Y-%m-%d)
27
+ EXPIRED=0
28
+
29
+ # Find TODO/FIXME/HACK with dates like TODO(2026-03-01) or TODO 2026-03-01
30
+ while IFS= read -r line; do
31
+ # Extract date from patterns like TODO(2026-01-15) or FIXME 2026-01-15
32
+ DATE=$(echo "$line" | grep -oE '(TODO|FIXME|HACK|XXX)\s*\(?\s*[0-9]{4}-[0-9]{2}-[0-9]{2}' | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}')
33
+ if [ -n "$DATE" ] && [[ "$DATE" < "$TODAY" ]]; then
34
+ if [ "$EXPIRED" -eq 0 ]; then
35
+ echo "⚠ Expired TODOs in $(basename "$FILE"):" >&2
36
+ fi
37
+ LINENUM=$(echo "$line" | cut -d: -f1)
38
+ CONTENT=$(echo "$line" | cut -d: -f2- | sed 's/^[[:space:]]*//')
39
+ echo " L${LINENUM}: $CONTENT (expired: $DATE)" >&2
40
+ EXPIRED=$((EXPIRED + 1))
41
+ fi
42
+ done < <(grep -n -E '(TODO|FIXME|HACK|XXX).*[0-9]{4}-[0-9]{2}-[0-9]{2}' "$FILE" 2>/dev/null)
43
+
44
+ if [ "$EXPIRED" -gt 0 ]; then
45
+ echo " $EXPIRED expired TODO(s) — consider resolving while editing this file." >&2
46
+ fi
47
+
48
+ exit 0
@@ -0,0 +1,55 @@
1
+ #!/bin/bash
2
+ # token-budget-per-task.sh — Track and warn on per-task token usage
3
+ #
4
+ # Solves: A single task consuming the entire daily token budget.
5
+ # Without visibility into per-task costs, users don't realize
6
+ # until they hit rate limits.
7
+ #
8
+ # How it works: PostToolUse hook that estimates tokens per tool call
9
+ # and tracks cumulative usage. Warns at configurable thresholds.
10
+ #
11
+ # CONFIG:
12
+ # CC_TOKEN_WARN_THRESHOLD=50000 (warn at this many tokens)
13
+ # CC_TOKEN_BLOCK_THRESHOLD=200000 (block at this many tokens)
14
+ #
15
+ # TRIGGER: PostToolUse
16
+ # MATCHER: ""
17
+
18
+ set -euo pipefail
19
+
20
+ INPUT=$(cat)
21
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
22
+ [ -z "$TOOL" ] && exit 0
23
+
24
+ COUNTER_FILE="/tmp/claude-token-budget-${PPID:-0}"
25
+ WARN="${CC_TOKEN_WARN_THRESHOLD:-50000}"
26
+ BLOCK="${CC_TOKEN_BLOCK_THRESHOLD:-200000}"
27
+
28
+ # Rough token estimates per tool call
29
+ case "$TOOL" in
30
+ Bash) TOKENS=500 ;;
31
+ Read) TOKENS=2000 ;;
32
+ Edit|Write) TOKENS=1000 ;;
33
+ Glob|Grep) TOKENS=300 ;;
34
+ Agent) TOKENS=5000 ;;
35
+ *) TOKENS=200 ;;
36
+ esac
37
+
38
+ # Add result size estimate
39
+ RESULT_LEN=$(echo "$INPUT" | jq -r '.tool_result // "" | length' 2>/dev/null || echo 0)
40
+ TOKENS=$((TOKENS + RESULT_LEN / 4)) # ~4 chars per token
41
+
42
+ # Update counter
43
+ TOTAL=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
44
+ TOTAL=$((TOTAL + TOKENS))
45
+ echo "$TOTAL" > "$COUNTER_FILE"
46
+
47
+ if [ "$TOTAL" -ge "$BLOCK" ]; then
48
+ echo "TOKEN BUDGET: ~${TOTAL} tokens used in this task (limit: ${BLOCK})." >&2
49
+ echo "Consider breaking this into smaller tasks." >&2
50
+ # Warning only — change to exit 2 to block
51
+ elif [ "$TOTAL" -ge "$WARN" ]; then
52
+ echo "TOKEN BUDGET: ~${TOTAL} tokens used (warning threshold: ${WARN})." >&2
53
+ fi
54
+
55
+ exit 0
@@ -0,0 +1,51 @@
1
+ #!/bin/bash
2
+ # token-spike-alert.sh — Alert on abnormal token consumption per turn
3
+ #
4
+ # Solves: Users report 10-20% of their 5-hour quota consumed by
5
+ # a single lightweight question (#40524, #38029, #40881).
6
+ # Cache invalidation causes full context re-processing,
7
+ # spiking token usage without user awareness.
8
+ #
9
+ # How it works: Tracks tool call count per session via a counter
10
+ # file. If more than MAX_TOOLS_PER_TURN tool calls happen in
11
+ # rapid succession (within 30 seconds), warns about possible
12
+ # runaway behavior that could spike token usage.
13
+ #
14
+ # TRIGGER: PostToolUse
15
+ # MATCHER: ""
16
+
17
+ set -euo pipefail
18
+
19
+ COUNTER_FILE="/tmp/claude-token-spike-$$"
20
+ MAX_TOOLS_PER_BURST="${MAX_TOOLS_PER_BURST:-15}"
21
+
22
+ # Get current timestamp
23
+ NOW=$(date +%s)
24
+
25
+ # Read last timestamp and count
26
+ if [ -f "$COUNTER_FILE" ]; then
27
+ LAST_TS=$(head -1 "$COUNTER_FILE" 2>/dev/null || echo "0")
28
+ COUNT=$(tail -1 "$COUNTER_FILE" 2>/dev/null || echo "0")
29
+ else
30
+ LAST_TS=0
31
+ COUNT=0
32
+ fi
33
+
34
+ # If within 30-second burst window
35
+ DELTA=$((NOW - LAST_TS))
36
+ if [ "$DELTA" -lt 30 ]; then
37
+ COUNT=$((COUNT + 1))
38
+ else
39
+ COUNT=1
40
+ fi
41
+
42
+ # Save state
43
+ echo "$NOW" > "$COUNTER_FILE"
44
+ echo "$COUNT" >> "$COUNTER_FILE"
45
+
46
+ # Alert if burst detected
47
+ if [ "$COUNT" -ge "$MAX_TOOLS_PER_BURST" ]; then
48
+ echo "WARNING: $COUNT tool calls in ${DELTA}s burst. Possible runaway behavior — check token consumption." >&2
49
+ fi
50
+
51
+ exit 0