cc-safe-setup 29.6.32 → 29.6.33

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 (384) 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/commit-message-check.sh +2 -0
  99. package/examples/compact-blocker.sh +25 -0
  100. package/examples/composer-guard.sh +2 -0
  101. package/examples/compound-command-allow.sh +2 -0
  102. package/examples/consecutive-failure-circuit-breaker.sh +49 -0
  103. package/examples/console-log-count.sh +2 -0
  104. package/examples/context-compact-advisor.sh +16 -0
  105. package/examples/cors-star-warn.sh +2 -0
  106. package/examples/credential-exfil-guard.sh +2 -0
  107. package/examples/credential-file-cat-guard.sh +2 -0
  108. package/examples/cron-modification-guard.sh +40 -0
  109. package/examples/cwd-project-boundary-guard.sh +50 -0
  110. package/examples/denied-action-retry-guard.sh +41 -0
  111. package/examples/dependency-install-guard.sh +2 -0
  112. package/examples/deploy-guard.sh +2 -0
  113. package/examples/deploy-path-verify-guard.sh +62 -0
  114. package/examples/django-migrate-guard.sh +2 -0
  115. package/examples/docker-volume-guard.sh +2 -0
  116. package/examples/dockerfile-latest-guard.sh +2 -0
  117. package/examples/dotenv-commit-guard.sh +44 -0
  118. package/examples/dotenv-example-sync.sh +55 -0
  119. package/examples/dotnet-build-on-edit.sh +2 -0
  120. package/examples/drizzle-migrate-guard.sh +2 -0
  121. package/examples/edit-counter-test-gate.sh +44 -0
  122. package/examples/edit-error-counter.sh +2 -0
  123. package/examples/edit-guard.sh +2 -0
  124. package/examples/edit-retry-loop-guard.sh +2 -0
  125. package/examples/edit-verify.sh +2 -0
  126. package/examples/enforce-tests.sh +2 -0
  127. package/examples/env-inherit-guard.sh +2 -0
  128. package/examples/env-inline-secret-guard.sh +36 -0
  129. package/examples/env-prod-guard.sh +2 -0
  130. package/examples/env-required-check.sh +2 -0
  131. package/examples/env-var-check.sh +2 -0
  132. package/examples/expo-eject-guard.sh +2 -0
  133. package/examples/export-overwrite-guard.sh +29 -0
  134. package/examples/file-change-tracker.sh +2 -0
  135. package/examples/file-change-undo-tracker.sh +46 -0
  136. package/examples/file-recycle-bin.sh +48 -0
  137. package/examples/file-size-limit.sh +2 -0
  138. package/examples/five-hundred-milestone.sh +2 -0
  139. package/examples/flask-debug-guard.sh +2 -0
  140. package/examples/gem-push-guard.sh +2 -0
  141. package/examples/git-checkout-safety-guard.sh +2 -0
  142. package/examples/git-config-guard.sh +2 -0
  143. package/examples/git-hook-bypass-guard.sh +2 -0
  144. package/examples/git-merge-conflict-prevent.sh +2 -0
  145. package/examples/git-message-length.sh +2 -0
  146. package/examples/git-show-flag-sanitizer.sh +41 -0
  147. package/examples/git-stash-before-danger.sh +2 -0
  148. package/examples/git-submodule-guard.sh +2 -0
  149. package/examples/git-tag-guard.sh +2 -0
  150. package/examples/github-actions-secret-guard.sh +59 -0
  151. package/examples/gitignore-check.sh +2 -0
  152. package/examples/gitops-drift-guard.sh +53 -0
  153. package/examples/go-mod-tidy-warn.sh +2 -0
  154. package/examples/hallucination-url-check.sh +2 -0
  155. package/examples/hardcoded-ip-guard.sh +2 -0
  156. package/examples/headless-empty-result-guard.sh +46 -0
  157. package/examples/headless-stop-guard.sh +43 -0
  158. package/examples/helm-install-guard.sh +2 -0
  159. package/examples/issue-draft-redact-guard.sh +45 -0
  160. package/examples/java-compile-on-edit.sh +2 -0
  161. package/examples/k8s-production-guard.sh +77 -0
  162. package/examples/laravel-artisan-guard.sh +2 -0
  163. package/examples/large-file-guard.sh +2 -0
  164. package/examples/log-level-guard.sh +2 -0
  165. package/examples/magic-number-warn.sh +2 -0
  166. package/examples/max-edit-size-guard.sh +2 -0
  167. package/examples/max-file-count-guard.sh +2 -0
  168. package/examples/max-file-delete-count.sh +2 -0
  169. package/examples/max-function-length.sh +2 -0
  170. package/examples/max-import-count.sh +2 -0
  171. package/examples/max-subagent-count.sh +2 -0
  172. package/examples/mcp-orphan-process-guard.sh +39 -0
  173. package/examples/mcp-server-allowlist.sh +45 -0
  174. package/examples/mcp-tool-audit-log.sh +41 -0
  175. package/examples/mcp-tool-guard.sh +2 -0
  176. package/examples/migration-verify-guard.sh +44 -0
  177. package/examples/monorepo-scope-guard.sh +2 -0
  178. package/examples/network-exfil-guard.sh +61 -0
  179. package/examples/network-guard.sh +2 -0
  180. package/examples/nextjs-env-guard.sh +2 -0
  181. package/examples/no-absolute-import.sh +2 -0
  182. package/examples/no-alert-confirm-prompt.sh +2 -0
  183. package/examples/no-any-type.sh +2 -0
  184. package/examples/no-any-typescript.sh +2 -0
  185. package/examples/no-assignment-in-condition.sh +2 -0
  186. package/examples/no-callback-hell.sh +2 -0
  187. package/examples/no-catch-all-route.sh +2 -0
  188. package/examples/no-circular-dependency.sh +2 -0
  189. package/examples/no-class-in-functional.sh +2 -0
  190. package/examples/no-cleartext-storage.sh +2 -0
  191. package/examples/no-commented-code.sh +2 -0
  192. package/examples/no-commit-fixup.sh +2 -0
  193. package/examples/no-console-assert.sh +2 -0
  194. package/examples/no-console-error-swallow.sh +2 -0
  195. package/examples/no-console-in-prod.sh +2 -0
  196. package/examples/no-console-log.sh +2 -0
  197. package/examples/no-console-time.sh +2 -0
  198. package/examples/no-cors-wildcard.sh +2 -0
  199. package/examples/no-curl-upload.sh +2 -0
  200. package/examples/no-dangerouslySetInnerHTML.sh +2 -0
  201. package/examples/no-dangling-await.sh +2 -0
  202. package/examples/no-debug-in-commit.sh +2 -0
  203. package/examples/no-deep-nesting.sh +2 -0
  204. package/examples/no-deep-relative-import.sh +2 -0
  205. package/examples/no-default-credentials.sh +2 -0
  206. package/examples/no-deprecated-api.sh +2 -0
  207. package/examples/no-direct-dom-manipulation.sh +2 -0
  208. package/examples/no-disabled-test.sh +2 -0
  209. package/examples/no-document-cookie.sh +2 -0
  210. package/examples/no-document-write.sh +2 -0
  211. package/examples/no-empty-function.sh +2 -0
  212. package/examples/no-eval-in-template.sh +2 -0
  213. package/examples/no-eval-template.sh +2 -0
  214. package/examples/no-eval.sh +2 -0
  215. package/examples/no-exec-user-input.sh +2 -0
  216. package/examples/no-expose-internal-ids.sh +2 -0
  217. package/examples/no-floating-promises.sh +2 -0
  218. package/examples/no-force-install.sh +2 -0
  219. package/examples/no-git-rebase-public.sh +2 -0
  220. package/examples/no-global-state.sh +2 -0
  221. package/examples/no-hardcoded-port.sh +2 -0
  222. package/examples/no-hardcoded-url.sh +2 -0
  223. package/examples/no-helmet-missing.sh +2 -0
  224. package/examples/no-http-url.sh +2 -0
  225. package/examples/no-http-without-https.sh +2 -0
  226. package/examples/no-index-as-key.sh +2 -0
  227. package/examples/no-infinite-scroll-mem.sh +2 -0
  228. package/examples/no-inline-event-handler.sh +2 -0
  229. package/examples/no-inline-handler.sh +2 -0
  230. package/examples/no-inline-style.sh +2 -0
  231. package/examples/no-inline-styles.sh +2 -0
  232. package/examples/no-innerhtml.sh +2 -0
  233. package/examples/no-install-global.sh +2 -0
  234. package/examples/no-jwt-in-url.sh +2 -0
  235. package/examples/no-large-commit.sh +2 -0
  236. package/examples/no-localhost-expose.sh +2 -0
  237. package/examples/no-long-switch.sh +2 -0
  238. package/examples/no-magic-number.sh +2 -0
  239. package/examples/no-md5-sha1.sh +2 -0
  240. package/examples/no-memory-leak-interval.sh +2 -0
  241. package/examples/no-mixed-line-endings.sh +2 -0
  242. package/examples/no-mutation-in-reducer.sh +2 -0
  243. package/examples/no-mutation-observer-leak.sh +2 -0
  244. package/examples/no-nested-subscribe.sh +2 -0
  245. package/examples/no-nested-ternary.sh +2 -0
  246. package/examples/no-network-exfil.sh +2 -0
  247. package/examples/no-new-array-fill.sh +2 -0
  248. package/examples/no-object-freeze-mutation.sh +2 -0
  249. package/examples/no-open-redirect.sh +2 -0
  250. package/examples/no-output-truncation.sh +44 -0
  251. package/examples/no-package-downgrade.sh +2 -0
  252. package/examples/no-package-lock-edit.sh +2 -0
  253. package/examples/no-path-join-user-input.sh +2 -0
  254. package/examples/no-port-bind.sh +2 -0
  255. package/examples/no-process-exit.sh +2 -0
  256. package/examples/no-prototype-pollution.sh +2 -0
  257. package/examples/no-push-without-ci.sh +2 -0
  258. package/examples/no-raw-ref.sh +2 -0
  259. package/examples/no-redundant-fragment.sh +2 -0
  260. package/examples/no-render-in-loop.sh +2 -0
  261. package/examples/no-root-user-docker.sh +2 -0
  262. package/examples/no-root-write.sh +2 -0
  263. package/examples/no-secrets-in-args.sh +2 -0
  264. package/examples/no-secrets-in-logs.sh +2 -0
  265. package/examples/no-sensitive-log.sh +2 -0
  266. package/examples/no-side-effects-in-render.sh +2 -0
  267. package/examples/no-sleep-in-hooks.sh +2 -0
  268. package/examples/no-star-import-python.sh +2 -0
  269. package/examples/no-string-concat-sql.sh +2 -0
  270. package/examples/no-sudo-guard.sh +2 -0
  271. package/examples/no-sync-external-call.sh +2 -0
  272. package/examples/no-sync-fs.sh +2 -0
  273. package/examples/no-table-layout.sh +2 -0
  274. package/examples/no-throw-string.sh +2 -0
  275. package/examples/no-todo-in-merge.sh +2 -0
  276. package/examples/no-todo-in-production.sh +2 -0
  277. package/examples/no-todo-without-issue.sh +2 -0
  278. package/examples/no-triple-slash-ref.sh +2 -0
  279. package/examples/no-unreachable-code.sh +2 -0
  280. package/examples/no-unused-import.sh +2 -0
  281. package/examples/no-unused-state.sh +2 -0
  282. package/examples/no-var-keyword.sh +2 -0
  283. package/examples/no-wildcard-cors.sh +2 -0
  284. package/examples/no-wildcard-import.sh +2 -0
  285. package/examples/no-window-location.sh +2 -0
  286. package/examples/no-with-statement.sh +2 -0
  287. package/examples/no-write-outside-src.sh +2 -0
  288. package/examples/no-xml-external-entity.sh +2 -0
  289. package/examples/notify-waiting.sh +2 -0
  290. package/examples/npm-audit-warn.sh +2 -0
  291. package/examples/npm-publish-guard.sh +2 -0
  292. package/examples/npm-script-injection.sh +2 -0
  293. package/examples/npm-supply-chain-guard.sh +92 -0
  294. package/examples/nuxt-config-guard.sh +2 -0
  295. package/examples/output-secret-mask.sh +2 -0
  296. package/examples/package-json-guard.sh +2 -0
  297. package/examples/parallel-session-guard.sh +2 -0
  298. package/examples/path-traversal-guard.sh +2 -0
  299. package/examples/permission-audit-log.sh +2 -0
  300. package/examples/permission-entry-validator.sh +48 -0
  301. package/examples/php-lint-on-edit.sh +2 -0
  302. package/examples/pip-publish-guard.sh +2 -0
  303. package/examples/plain-language-danger-warn.sh +37 -0
  304. package/examples/plan-mode-enforcer.sh +2 -0
  305. package/examples/plugin-process-cleanup.sh +50 -0
  306. package/examples/polyglot-rm-guard.sh +59 -0
  307. package/examples/pr-description-check.sh +2 -0
  308. package/examples/pre-compact-knowledge-save.sh +53 -0
  309. package/examples/pre-compact-transcript-export.sh +85 -0
  310. package/examples/prefer-builtin-tools.sh +2 -0
  311. package/examples/prefer-const.sh +2 -0
  312. package/examples/prefer-dedicated-tools.sh +55 -0
  313. package/examples/prefer-optional-chaining.sh +2 -0
  314. package/examples/prisma-migrate-guard.sh +2 -0
  315. package/examples/prompt-injection-detector.sh +2 -0
  316. package/examples/prompt-length-guard.sh +2 -0
  317. package/examples/protect-dotfiles.sh +2 -0
  318. package/examples/public-repo-push-guard.sh +58 -0
  319. package/examples/push-requires-test-pass-record.sh +2 -0
  320. package/examples/push-requires-test-pass.sh +2 -0
  321. package/examples/rails-migration-guard.sh +2 -0
  322. package/examples/rate-limit-guard.sh +2 -0
  323. package/examples/read-all-files-enforcer.sh +51 -0
  324. package/examples/readme-exists-check.sh +2 -0
  325. package/examples/redis-flushall-guard.sh +2 -0
  326. package/examples/rm-safety-net.sh +2 -0
  327. package/examples/role-tool-guard.sh +69 -0
  328. package/examples/ruby-lint-on-edit.sh +2 -0
  329. package/examples/schema-migration-guard.sh +57 -0
  330. package/examples/scope-guard.sh +2 -0
  331. package/examples/secret-file-read-guard.sh +74 -0
  332. package/examples/self-modify-bypass-guard.sh +54 -0
  333. package/examples/sensitive-log-guard.sh +2 -0
  334. package/examples/session-checkpoint.sh +2 -0
  335. package/examples/session-end-logger.sh +57 -0
  336. package/examples/session-error-rate-monitor.sh +65 -0
  337. package/examples/session-health-monitor.sh +61 -0
  338. package/examples/session-memory-watchdog.sh +17 -0
  339. package/examples/session-permission-reset-guard.sh +39 -0
  340. package/examples/session-resume-env-fix.sh +49 -0
  341. package/examples/session-state-saver.sh +2 -0
  342. package/examples/session-summary-stop.sh +2 -0
  343. package/examples/session-summary.sh +2 -0
  344. package/examples/session-token-counter.sh +2 -0
  345. package/examples/shell-wrapper-guard.sh +2 -0
  346. package/examples/skill-gate.sh +2 -0
  347. package/examples/skill-injection-detector.sh +41 -0
  348. package/examples/spec-file-scope-guard.sh +69 -0
  349. package/examples/spring-profile-guard.sh +2 -0
  350. package/examples/sql-injection-detect.sh +2 -0
  351. package/examples/subagent-budget-guard.sh +2 -0
  352. package/examples/subagent-claudemd-inject.sh +45 -0
  353. package/examples/subagent-tool-call-limiter.sh +48 -0
  354. package/examples/svelte-lint-on-edit.sh +2 -0
  355. package/examples/swift-build-on-edit.sh +2 -0
  356. package/examples/system-message-workaround.sh +44 -0
  357. package/examples/system-package-guard.sh +2 -0
  358. package/examples/temp-file-cleanup.sh +2 -0
  359. package/examples/terminal-state-restore.sh +23 -0
  360. package/examples/test-after-edit.sh +2 -0
  361. package/examples/test-before-commit.sh +2 -0
  362. package/examples/test-before-push.sh +2 -0
  363. package/examples/test-exit-code-verify.sh +2 -0
  364. package/examples/timeout-guard.sh +2 -0
  365. package/examples/timezone-guard.sh +2 -0
  366. package/examples/tmp-output-size-guard.sh +46 -0
  367. package/examples/todo-check.sh +2 -0
  368. package/examples/todo-deadline-warn.sh +48 -0
  369. package/examples/token-budget-per-task.sh +55 -0
  370. package/examples/token-usage-tracker.sh +14 -0
  371. package/examples/turbo-cache-guard.sh +2 -0
  372. package/examples/uncommitted-changes-stop.sh +2 -0
  373. package/examples/uncommitted-work-shield.sh +37 -0
  374. package/examples/usage-warn.sh +2 -0
  375. package/examples/verify-before-commit.sh +2 -0
  376. package/examples/vue-lint-on-edit.sh +2 -0
  377. package/examples/webfetch-domain-allow.sh +96 -0
  378. package/examples/worktree-memory-guard.sh +47 -0
  379. package/examples/worktree-project-unify.sh +19 -0
  380. package/examples/worktree-unmerged-guard.sh +2 -0
  381. package/examples/write-overwrite-confirm.sh +40 -0
  382. package/examples/write-secret-guard.sh +2 -0
  383. package/examples/write-test-ratio.sh +2 -0
  384. package/package.json +2 -2
@@ -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)
@@ -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,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
  echo "$COMMAND" | grep -qE '^\s*git\s+commit' || 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,14 @@
1
+ INPUT=$(cat)
2
+ TRANSCRIPT=$(ls -t ~/.claude/projects/*/sessions/*/transcript.jsonl 2>/dev/null | head -1)
3
+ [ -f "$TRANSCRIPT" ] || exit 0
4
+ USAGE=$(tail -20 "$TRANSCRIPT" | grep -o '"usage":{[^}]*}' | tail -1)
5
+ if [ -n "$USAGE" ]; then
6
+ IN=$(echo "$USAGE" | grep -o '"input_tokens":[0-9]*' | grep -o '[0-9]*')
7
+ OUT=$(echo "$USAGE" | grep -o '"output_tokens":[0-9]*' | grep -o '[0-9]*')
8
+ TOTAL=$((${IN:-0} + ${OUT:-0}))
9
+ echo "$(date -Iseconds) in=${IN:-0} out=${OUT:-0} total=$TOTAL" >> ~/.claude/token-usage.log
10
+ BUDGET="${CC_TOKEN_BUDGET:-500000}"
11
+ SUM=$(awk -F'total=' '{sum+=$2}END{print sum+0}' ~/.claude/token-usage.log 2>/dev/null)
12
+ [ "${SUM:-0}" -gt "$BUDGET" ] && echo "Token usage: ~$SUM (budget: $BUDGET)" >&2
13
+ fi
14
+ exit 0
@@ -16,6 +16,8 @@
16
16
  # }
17
17
  # }
18
18
  # ================================================================
19
+ #
20
+ # TRIGGER: PreToolUse MATCHER: "Bash"
19
21
 
20
22
  INPUT=$(cat)
21
23
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -1,3 +1,5 @@
1
+ #
2
+ # TRIGGER: Stop MATCHER: ""
1
3
  INPUT=$(cat)
2
4
  if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
3
5
  exit 0
@@ -0,0 +1,37 @@
1
+ #!/bin/bash
2
+ # uncommitted-work-shield.sh — Auto-stash before destructive git operations
3
+ #
4
+ # Solves: Git operations destroying uncommitted work (#34327, #33850, #37150).
5
+ # Users lost days of work from git reset/checkout/clean.
6
+ # Unlike uncommitted-work-guard (which blocks), this hook SAVES work.
7
+ #
8
+ # How it works: PreToolUse hook on Bash that detects destructive git
9
+ # commands and auto-stashes uncommitted changes before allowing them.
10
+ #
11
+ # TRIGGER: PreToolUse
12
+ # MATCHER: "Bash"
13
+
14
+ set -euo pipefail
15
+
16
+ INPUT=$(cat)
17
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
18
+ [ -z "$COMMAND" ] && exit 0
19
+
20
+ # Only check destructive git commands
21
+ DESTRUCTIVE_GIT='git\s+(reset\s+--hard|checkout\s+--|clean\s+-[fd]|stash\s+drop|stash\s+clear)'
22
+
23
+ if ! echo "$COMMAND" | grep -qE "$DESTRUCTIVE_GIT"; then
24
+ exit 0
25
+ fi
26
+
27
+ # Check if there are uncommitted changes
28
+ if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then
29
+ # Auto-stash with timestamp
30
+ STASH_MSG="auto-shield-$(date +%Y%m%d-%H%M%S)"
31
+ git stash push -m "$STASH_MSG" 2>/dev/null || true
32
+ echo "SHIELDED: Uncommitted changes saved to stash '$STASH_MSG'." >&2
33
+ echo "Restore with: git stash pop" >&2
34
+ fi
35
+
36
+ # Allow the command to proceed (changes are saved)
37
+ exit 0
@@ -1,4 +1,6 @@
1
1
  #!/bin/bash
2
+ #
3
+ # TRIGGER: PreToolUse MATCHER: "Bash"
2
4
  COUNTER="${HOME}/.claude/session-tool-count"
3
5
  COUNT=$(cat "$COUNTER" 2>/dev/null || echo 0)
4
6
  COUNT=$((COUNT + 1))
@@ -22,6 +22,8 @@
22
22
  # }]
23
23
  # }
24
24
  # }
25
+ #
26
+ # TRIGGER: PreToolUse MATCHER: "Bash"
25
27
 
26
28
  INPUT=$(cat)
27
29
  COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
@@ -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
@@ -0,0 +1,96 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # webfetch-domain-allow.sh — Auto-approve WebFetch for allowed domains
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # WebFetch(domain:*) in settings.json silently fails to match in
7
+ # many configurations (especially sandbox mode). This hook reads
8
+ # the requested URL, extracts the domain, and auto-approves if
9
+ # it matches a configurable allowlist.
10
+ #
11
+ # TRIGGER: PreToolUse
12
+ # MATCHER: "WebFetch"
13
+ #
14
+ # DECISION: exit 0 with permissionDecision "allow" = auto-approve
15
+ # exit 0 with empty JSON = passthrough (ask user)
16
+ #
17
+ # CONFIG: Set CC_WEBFETCH_ALLOW_DOMAINS env var (comma-separated)
18
+ # or edit the ALLOWED_DOMAINS array below.
19
+ # Use "*" to allow all domains.
20
+ #
21
+ # See: https://github.com/anthropics/claude-code/issues/9329
22
+ # ================================================================
23
+
24
+ INPUT=$(cat)
25
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
26
+
27
+ # Only handle WebFetch
28
+ [[ "$TOOL" != "WebFetch" ]] && exit 0
29
+
30
+ # Extract URL from tool input
31
+ URL=$(echo "$INPUT" | jq -r '.tool_input.url // empty' 2>/dev/null)
32
+ [ -z "$URL" ] && exit 0
33
+
34
+ # Extract domain from URL
35
+ DOMAIN=$(echo "$URL" | sed -E 's|^https?://||' | sed 's|/.*||' | sed 's|:.*||')
36
+ [ -z "$DOMAIN" ] && exit 0
37
+
38
+ # ========================================
39
+ # DOMAIN ALLOWLIST — edit to your needs
40
+ # ========================================
41
+ # Option 1: Environment variable (comma-separated)
42
+ # export CC_WEBFETCH_ALLOW_DOMAINS="docs.anthropic.com,github.com,*.example.com"
43
+ # Option 2: Edit this array directly
44
+ ALLOWED_DOMAINS=(
45
+ "*" # Allow all domains — change to specific domains for tighter control
46
+ # "docs.anthropic.com"
47
+ # "github.com"
48
+ # "*.github.io"
49
+ # "developer.mozilla.org"
50
+ )
51
+
52
+ # Override from env if set
53
+ if [ -n "$CC_WEBFETCH_ALLOW_DOMAINS" ]; then
54
+ IFS=',' read -ra ALLOWED_DOMAINS <<< "$CC_WEBFETCH_ALLOW_DOMAINS"
55
+ fi
56
+
57
+ # Check domain against allowlist
58
+ for pattern in "${ALLOWED_DOMAINS[@]}"; do
59
+ pattern=$(echo "$pattern" | xargs) # trim whitespace
60
+ # Wildcard: allow everything
61
+ if [ "$pattern" = "*" ]; then
62
+ jq -n '{
63
+ hookSpecificOutput: {
64
+ hookEventName: "PreToolUse",
65
+ permissionDecision: "allow"
66
+ }
67
+ }'
68
+ exit 0
69
+ fi
70
+ # Glob pattern: *.example.com matches sub.example.com
71
+ if [[ "$pattern" == \** ]]; then
72
+ suffix="${pattern#\*}"
73
+ if [[ "$DOMAIN" == *"$suffix" ]]; then
74
+ jq -n '{
75
+ hookSpecificOutput: {
76
+ hookEventName: "PreToolUse",
77
+ permissionDecision: "allow"
78
+ }
79
+ }'
80
+ exit 0
81
+ fi
82
+ fi
83
+ # Exact match
84
+ if [ "$DOMAIN" = "$pattern" ]; then
85
+ jq -n '{
86
+ hookSpecificOutput: {
87
+ hookEventName: "PreToolUse",
88
+ permissionDecision: "allow"
89
+ }
90
+ }'
91
+ exit 0
92
+ fi
93
+ done
94
+
95
+ # Not in allowlist — passthrough to normal permission flow
96
+ exit 0
@@ -0,0 +1,47 @@
1
+ #!/bin/bash
2
+ # worktree-memory-guard.sh — Warn when memory path resolves to main worktree
3
+ #
4
+ # Solves: Git worktrees resolving to main worktree's memory directory (#39920).
5
+ # In worktree isolation mode, Claude writes memory to the main repo's
6
+ # .claude/projects/ instead of the worktree's, causing cross-contamination.
7
+ #
8
+ # How it works: PreToolUse hook on Write/Edit that checks if the target
9
+ # path is a memory file (.claude/projects/*/memory/) and warns if
10
+ # the current working directory differs from the resolved path's repo root.
11
+ #
12
+ # TRIGGER: PreToolUse
13
+ # MATCHER: "Write|Edit"
14
+
15
+ set -euo pipefail
16
+
17
+ INPUT=$(cat)
18
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
19
+ [ -z "$FILE" ] && exit 0
20
+
21
+ # Only check memory files
22
+ if ! echo "$FILE" | grep -q '.claude/projects/.*/memory/'; then
23
+ exit 0
24
+ fi
25
+
26
+ # Check if we're in a worktree
27
+ GIT_DIR=$(git rev-parse --git-dir 2>/dev/null || echo "")
28
+ if [ -z "$GIT_DIR" ]; then
29
+ exit 0
30
+ fi
31
+
32
+ # Detect worktree by checking if .git is a file (worktree) vs directory (main)
33
+ if [ -f ".git" ]; then
34
+ # We're in a worktree — check if memory path points to main repo
35
+ MAIN_WORKTREE=$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null | sed 's|/.git$||')
36
+ CWD=$(pwd)
37
+
38
+ if [ "$MAIN_WORKTREE" != "$CWD" ] && echo "$FILE" | grep -q "$MAIN_WORKTREE"; then
39
+ echo "WARNING: Memory file resolves to main worktree, not current worktree." >&2
40
+ echo " File: $FILE" >&2
41
+ echo " Main: $MAIN_WORKTREE" >&2
42
+ echo " CWD: $CWD" >&2
43
+ echo " Consider writing to worktree-local memory instead." >&2
44
+ fi
45
+ fi
46
+
47
+ exit 0
@@ -0,0 +1,19 @@
1
+ MAIN_TREE=$(git worktree list --porcelain 2>/dev/null | head -1 | sed 's/worktree //')
2
+ [ -z "$MAIN_TREE" ] && exit 0
3
+ CUR_DIR=$(pwd)
4
+ [ "$CUR_DIR" = "$MAIN_TREE" ] && exit 0
5
+ to_project_dir() {
6
+ echo "$HOME/.claude/projects/$(echo "$1" | sed 's|/|-|g; s|^-||')"
7
+ }
8
+ MAIN_PROJECT=$(to_project_dir "$MAIN_TREE")
9
+ CUR_PROJECT=$(to_project_dir "$CUR_DIR")
10
+ if [ -d "$MAIN_PROJECT" ] && [ ! -L "$CUR_PROJECT" ]; then
11
+ if [ -d "$CUR_PROJECT" ] && [ -z "$(ls -A "$CUR_PROJECT" 2>/dev/null)" ]; then
12
+ rmdir "$CUR_PROJECT"
13
+ fi
14
+ if [ ! -e "$CUR_PROJECT" ]; then
15
+ ln -s "$MAIN_PROJECT" "$CUR_PROJECT"
16
+ echo "Linked worktree project dir → main repo" >&2
17
+ fi
18
+ fi
19
+ 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
  # jq with python3 fallback (macOS may not have jq)
@@ -0,0 +1,40 @@
1
+ #!/bin/bash
2
+ # write-overwrite-confirm.sh — Warn when Write tool overwrites large files
3
+ #
4
+ # Solves: Write tool silently replacing large files with new content (#34597).
5
+ # A 500-line file can be overwritten with 10 lines without warning.
6
+ #
7
+ # How it works: PreToolUse hook on Write that compares the new content
8
+ # size against the existing file. If the new content is significantly
9
+ # smaller, warns about potential data loss.
10
+ #
11
+ # TRIGGER: PreToolUse
12
+ # MATCHER: "Write"
13
+
14
+ set -euo pipefail
15
+
16
+ INPUT=$(cat)
17
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
18
+ [ -z "$FILE" ] && exit 0
19
+
20
+ # Skip if file doesn't exist (new file creation)
21
+ [ ! -f "$FILE" ] && exit 0
22
+
23
+ # Get current file size (lines)
24
+ CURRENT_LINES=$(wc -l < "$FILE" 2>/dev/null || echo 0)
25
+
26
+ # Get new content size (approximate from JSON length)
27
+ NEW_CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // empty' 2>/dev/null)
28
+ NEW_LINES=$(echo "$NEW_CONTENT" | wc -l 2>/dev/null || echo 0)
29
+
30
+ # Warn if shrinking by more than 50% and file is > 50 lines
31
+ if [ "$CURRENT_LINES" -gt 50 ] && [ "$NEW_LINES" -gt 0 ]; then
32
+ RATIO=$((NEW_LINES * 100 / CURRENT_LINES))
33
+ if [ "$RATIO" -lt 50 ]; then
34
+ echo "WARNING: File shrinking from $CURRENT_LINES to ~$NEW_LINES lines ($RATIO%)." >&2
35
+ echo "File: $FILE" >&2
36
+ echo "Consider using Edit tool for targeted changes instead of full rewrite." >&2
37
+ fi
38
+ fi
39
+
40
+ exit 0
@@ -24,6 +24,8 @@
24
24
  # }]
25
25
  # }
26
26
  # }
27
+ #
28
+ # TRIGGER: PreToolUse MATCHER: "Edit|Write"
27
29
 
28
30
  INPUT=$(cat)
29
31
  TOOL=$(echo "$INPUT" | jq -r '.tool_name // 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
  echo "$COMMAND" | grep -qE "^\s*git\s+commit" || exit 0; S=$(git diff --cached --name-only 2>/dev/null | grep -cvE "test|spec" || echo 0); T=$(git diff --cached --name-only 2>/dev/null | grep -cE "test|spec" || echo 0); [ "$S" -gt 5 ] && [ "$T" -eq 0 ] && echo "WARNING: $S source files, 0 test files" >&2
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cc-safe-setup",
3
- "version": "29.6.32",
4
- "description": "One command to make Claude Code safe. 539 example hooks + 8 built-in. 56 CLI commands. 7789 tests. Works with Auto Mode.",
3
+ "version": "29.6.33",
4
+ "description": "One command to make Claude Code safe. 611 example hooks + 8 built-in. 56 CLI commands. 10411 tests. Works with Auto Mode.",
5
5
  "main": "index.mjs",
6
6
  "bin": {
7
7
  "cc-safe-setup": "index.mjs"