cc-safe-setup 29.7.0 → 30.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1022) hide show
  1. package/.claude-plugin/marketplace.json +72 -19
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CONTRIBUTING.md +7 -2
  4. package/COOKBOOK.md +50 -46
  5. package/LICENSE +21 -0
  6. package/MIGRATION.md +8 -8
  7. package/README.md +419 -512
  8. package/SAFETY_CHECKLIST.md +15 -7
  9. package/SERVICES.md +194 -0
  10. package/SETTINGS_REFERENCE.md +236 -17
  11. package/SKILL.md +5 -5
  12. package/TROUBLESHOOTING.md +35 -14
  13. package/action.yml +12 -4
  14. package/audit/README.md +84 -0
  15. package/audit/audit-checklist.md +152 -0
  16. package/audit/boundary-selftest.sh +85 -0
  17. package/audit/boundary.sh +123 -0
  18. package/audit/count-hooks.py +42 -0
  19. package/audit/find-dead-hooks.sh +82 -0
  20. package/audit/find-unfirable-rules.sh +142 -0
  21. package/audit/fire.sh +97 -0
  22. package/audit/selftest.sh +42 -0
  23. package/audit/unfirable-selftest.sh +81 -0
  24. package/audit-web/index.html +9 -9
  25. package/examples/README.md +54 -17
  26. package/examples/account-billing-log.sh +98 -0
  27. package/examples/account-routing-preflight.sh +123 -0
  28. package/examples/agent-sdk-credit-pool-monitor.sh +145 -0
  29. package/examples/agent-view-quota-decrement.sh +32 -0
  30. package/examples/agent-view-quota-warn.sh +94 -0
  31. package/examples/agents-md-edit-drift-warner.sh +223 -0
  32. package/examples/agents-md-loader.sh +160 -0
  33. package/examples/agents-md-sync-checker.sh +102 -0
  34. package/examples/ai-slop-punctuation-arrest.sh +210 -0
  35. package/examples/allowlist.sh +70 -10
  36. package/examples/always-allow-pattern-suggester.sh +125 -0
  37. package/examples/ansible-vault-guard.sh +2 -1
  38. package/examples/anthropic-base-url-guard.sh +76 -0
  39. package/examples/api-busyloop-guard.sh +123 -0
  40. package/examples/api-endpoint-guard.sh +12 -0
  41. package/examples/api-key-in-url-guard.sh +17 -1
  42. package/examples/api-rate-limit-guard.sh +36 -1
  43. package/examples/api-rate-limit-tracker.sh +12 -0
  44. package/examples/articulated-scope-capture.sh +101 -0
  45. package/examples/askuserquestion-autonomy-gate.sh +102 -0
  46. package/examples/attachment-traversal-guard.sh +118 -0
  47. package/examples/aup-block-pattern-logger.sh +161 -0
  48. package/examples/aup-false-positive-helper.sh +124 -0
  49. package/examples/aup-large-tool-output-warner.sh +282 -0
  50. package/examples/aup-retry-loop-guard.sh +229 -0
  51. package/examples/auth-expiry-reminder.sh +157 -0
  52. package/examples/auth-macos-sleep-detector.sh +185 -0
  53. package/examples/auth-path-detector.sh +171 -0
  54. package/examples/auth-status-checker.sh +157 -0
  55. package/examples/authorized-reconfirmation-detector.sh +195 -0
  56. package/examples/auto-approve-build.sh +39 -0
  57. package/examples/auto-approve-cargo.sh +31 -1
  58. package/examples/auto-approve-docker.sh +35 -0
  59. package/examples/auto-approve-git-read.sh +37 -14
  60. package/examples/auto-approve-go.sh +30 -1
  61. package/examples/auto-approve-gradle.sh +29 -1
  62. package/examples/auto-approve-make.sh +29 -1
  63. package/examples/auto-approve-maven.sh +29 -1
  64. package/examples/auto-approve-python.sh +41 -1
  65. package/examples/auto-approve-readonly-tools.sh +1 -0
  66. package/examples/auto-approve-readonly.sh +110 -33
  67. package/examples/auto-approve-ssh.sh +30 -1
  68. package/examples/auto-approve-test.sh +44 -0
  69. package/examples/auto-checkpoint.sh +1 -1
  70. package/examples/auto-compact-prep.sh +0 -0
  71. package/examples/auto-git-checkpoint.sh +0 -0
  72. package/examples/auto-mode-safe-commands.sh +53 -1
  73. package/examples/auto-mode-safety-enforcer.sh +151 -4
  74. package/examples/auto-push-session-branch.sh +22 -0
  75. package/examples/aws-production-guard.sh +13 -1
  76. package/examples/aws-region-guard.sh +1 -1
  77. package/examples/background-cost-launch-guard.sh +82 -0
  78. package/examples/background-task-guard.sh +12 -0
  79. package/examples/backup-before-refactor.sh +0 -0
  80. package/examples/banned-command-guard.sh +12 -0
  81. package/examples/bash-allowlist-secondary-check.sh +157 -0
  82. package/examples/bash-domain-allowlist.sh +12 -0
  83. package/examples/bash-fanout-bounded-rewriter.sh +191 -0
  84. package/examples/bash-heuristic-approver.sh +112 -10
  85. package/examples/bash-project-fence.sh +194 -0
  86. package/examples/bash-safety-auto-deny.sh +12 -0
  87. package/examples/bash-secret-output-detector.sh +44 -3
  88. package/examples/bash-trace-guard.sh +12 -0
  89. package/examples/bashrc-safety-check.sh +0 -0
  90. package/examples/bg-permission-prompt-warner.sh +182 -0
  91. package/examples/bg-task-cooldown-guard.sh +12 -0
  92. package/examples/binary-read-detector.sh +135 -0
  93. package/examples/binary-upload-guard.sh +12 -0
  94. package/examples/block-database-wipe.sh +35 -10
  95. package/examples/branch-name-check.sh +8 -3
  96. package/examples/branch-naming-convention.sh +0 -0
  97. package/examples/broad-find-guard.sh +12 -0
  98. package/examples/broad-prefix-session-trap-warner.sh +106 -0
  99. package/examples/bulk-file-delete-guard.sh +45 -0
  100. package/examples/bypass-mode-effective-verifier.sh +203 -0
  101. package/examples/cache-creation-drift-detector.sh +120 -0
  102. package/examples/cache-residue-detector.sh +195 -0
  103. package/examples/cache-tier-logger.sh +70 -0
  104. package/examples/cache-ttl-eviction-detector.sh +149 -0
  105. package/examples/cargo-publish-guard.sh +14 -1
  106. package/examples/case-insensitive-path-guard.sh +21 -2
  107. package/examples/case-sensitive-guard.sh +23 -2
  108. package/examples/cch-cache-guard.sh +0 -0
  109. package/examples/cch-sentinel-precommit-guard.sh +47 -0
  110. package/examples/check-abort-controller.sh +1 -1
  111. package/examples/check-accessibility.sh +0 -0
  112. package/examples/check-aria-labels.sh +0 -0
  113. package/examples/check-before-act-enforcer.sh +12 -0
  114. package/examples/check-charset-meta.sh +0 -0
  115. package/examples/check-cookie-flags.sh +0 -0
  116. package/examples/check-cors-config.sh +0 -0
  117. package/examples/check-csp-headers.sh +0 -0
  118. package/examples/check-csrf-protection.sh +0 -0
  119. package/examples/check-debounce.sh +1 -1
  120. package/examples/check-dependency-age.sh +0 -0
  121. package/examples/check-dependency-license.sh +0 -0
  122. package/examples/check-dockerfile-best-practice.sh +0 -0
  123. package/examples/check-error-boundaries.sh +0 -0
  124. package/examples/check-error-class.sh +1 -1
  125. package/examples/check-error-handling.sh +0 -0
  126. package/examples/check-error-logging.sh +1 -1
  127. package/examples/check-error-message.sh +0 -0
  128. package/examples/check-error-stack.sh +0 -0
  129. package/examples/check-favicon.sh +0 -0
  130. package/examples/check-git-hooks-compat.sh +0 -0
  131. package/examples/check-gitattributes.sh +0 -0
  132. package/examples/check-https-redirect.sh +0 -0
  133. package/examples/check-input-validation.sh +0 -0
  134. package/examples/check-lang-attribute.sh +0 -0
  135. package/examples/check-npm-scripts-exist.sh +0 -0
  136. package/examples/check-package-size.sh +0 -0
  137. package/examples/check-port-availability.sh +0 -0
  138. package/examples/check-promise-all.sh +1 -1
  139. package/examples/check-rate-limiting.sh +0 -0
  140. package/examples/check-return-types.sh +0 -0
  141. package/examples/check-semantic-versioning.sh +0 -0
  142. package/examples/check-suspense-fallback.sh +1 -1
  143. package/examples/check-test-exists.sh +0 -0
  144. package/examples/check-test-naming.sh +0 -0
  145. package/examples/check-timeout-cleanup.sh +1 -1
  146. package/examples/check-tls-version.sh +0 -0
  147. package/examples/check-unsubscribe.sh +1 -1
  148. package/examples/check-viewport-meta.sh +0 -0
  149. package/examples/check-worker-terminate.sh +1 -1
  150. package/examples/checkpoint-tamper-guard.sh +12 -0
  151. package/examples/chmod-guard.sh +12 -0
  152. package/examples/chown-guard.sh +24 -0
  153. package/examples/ci-workflow-guard.sh +6 -1
  154. package/examples/claim-verify-detector.sh +109 -0
  155. package/examples/claim-vs-caveat-checker.sh +77 -0
  156. package/examples/classifier-fallback-allow.sh +114 -40
  157. package/examples/claude-cache-gc.sh +1 -0
  158. package/examples/claude-code-version-pin-advisor.sh +183 -0
  159. package/examples/claude-md-reinjector.sh +129 -0
  160. package/examples/claude-md-size-monitor.sh +66 -0
  161. package/examples/claude-update-budget-guard.sh +123 -0
  162. package/examples/claude-update-smart.sh +113 -0
  163. package/examples/claudeignore-enforce-guard.sh +12 -0
  164. package/examples/claudemd-enforcer.sh +0 -0
  165. package/examples/claudemd-tool-prohibition.sh +128 -0
  166. package/examples/clear-command-confirm-guard.sh +32 -15
  167. package/examples/cli-config-pinning-detector.sh +162 -0
  168. package/examples/cliff-countdown-advisor.sh +96 -0
  169. package/examples/clipboard-secret-guard.sh +12 -0
  170. package/examples/closure-word-verify-gate.sh +150 -0
  171. package/examples/cloud-cli-guard.sh +39 -2
  172. package/examples/commit-all-scope-guard.sh +44 -0
  173. package/examples/commit-message-check.sh +1 -1
  174. package/examples/commit-message-quality.sh +6 -1
  175. package/examples/commitment-carry-forward-arrest.sh +361 -0
  176. package/examples/compact-alert-notification.sh +0 -0
  177. package/examples/compact-circuit-breaker.sh +72 -0
  178. package/examples/compact-dispatch-watchdog.sh +149 -0
  179. package/examples/completion-claim-without-verification-detector.sh +207 -0
  180. package/examples/composer-guard.sh +12 -0
  181. package/examples/compound-bash-permission-resolver.sh +156 -0
  182. package/examples/compound-command-allow.sh +1 -1
  183. package/examples/compound-command-deny-enforcer.sh +183 -0
  184. package/examples/compound-inject-guard.sh +12 -0
  185. package/examples/concurrent-edit-lock.sh +12 -0
  186. package/examples/conflict-marker-guard.sh +12 -0
  187. package/examples/consecutive-error-breaker.sh +0 -0
  188. package/examples/console-log-count.sh +1 -0
  189. package/examples/context-compact-advisor.sh +29 -2
  190. package/examples/context-length-budget.sh +69 -0
  191. package/examples/context-threshold-alert.sh +12 -0
  192. package/examples/context-usage-drift-alert.sh +41 -13
  193. package/examples/conversation-history-guard.sh +12 -0
  194. package/examples/core-file-protect-guard.sh +12 -0
  195. package/examples/cors-star-warn.sh +0 -0
  196. package/examples/cost-incident-self-audit.sh +162 -0
  197. package/examples/cowork-claude-md-load-checker.sh +100 -0
  198. package/examples/cowork-fuse-staleness-watcher.sh +140 -0
  199. package/examples/cowork-hook-absence-warner.sh +167 -0
  200. package/examples/cowork-model-picker-advisor.sh +115 -0
  201. package/examples/credential-exfil-guard.sh +65 -4
  202. package/examples/credential-file-cat-guard.sh +17 -1
  203. package/examples/cron-create-receipt.sh +112 -0
  204. package/examples/cron-modification-guard.sh +12 -0
  205. package/examples/cross-product-mcp-spawn-detector.sh +178 -0
  206. package/examples/cwd-project-boundary-guard.sh +0 -0
  207. package/examples/daemon-zombie-worker-surfacer.sh +118 -0
  208. package/examples/daily-cost-guard.sh +164 -0
  209. package/examples/daily-usage-tracker.sh +0 -0
  210. package/examples/dangerous-pip-flag-guard.sh +12 -0
  211. package/examples/db-connect-guard.sh +13 -1
  212. package/examples/denied-action-retry-guard.sh +12 -0
  213. package/examples/deny-bypass-detector.sh +12 -0
  214. package/examples/deny-rule-integrity-verifier.sh +181 -0
  215. package/examples/dependency-install-guard.sh +12 -0
  216. package/examples/deploy-guard.sh +14 -2
  217. package/examples/deploy-path-verify-guard.sh +12 -0
  218. package/examples/deployment-readback-gate.sh +135 -0
  219. package/examples/deployment-readback-gh-adapter.sh +247 -0
  220. package/examples/deployment-verify-guard.sh +25 -2
  221. package/examples/destructive-db-script-write-guard.sh +166 -0
  222. package/examples/destructive-migration-write-guard.sh +163 -0
  223. package/examples/diff-size-guard.sh +12 -0
  224. package/examples/disabled-feature-toggle-advisor.sh +88 -0
  225. package/examples/disk-partition-guard.sh +12 -0
  226. package/examples/dispatch-allowlist-preflight.sh +301 -0
  227. package/examples/dispatch-liveness-watchdog.sh +216 -0
  228. package/examples/dispatch-receipt.sh +174 -0
  229. package/examples/django-migrate-guard.sh +12 -0
  230. package/examples/dns-config-guard.sh +12 -0
  231. package/examples/docker-dangerous-guard.sh +12 -0
  232. package/examples/docker-volume-guard.sh +0 -0
  233. package/examples/dockerfile-latest-guard.sh +1 -0
  234. package/examples/dotenv-anthropic-key-billing-guard.sh +99 -0
  235. package/examples/dotenv-commit-guard.sh +12 -0
  236. package/examples/dotenv-read-guard.sh +12 -0
  237. package/examples/dotfile-protection-guard.sh +12 -0
  238. package/examples/dotnet-build-on-edit.sh +1 -1
  239. package/examples/drizzle-migrate-guard.sh +27 -2
  240. package/examples/echo-probe-spam-detector.sh +176 -0
  241. package/examples/edit-counter-test-gate.sh +12 -0
  242. package/examples/edit-error-counter.sh +1 -1
  243. package/examples/edit-guard.sh +12 -0
  244. package/examples/edit-old-string-validator.sh +12 -0
  245. package/examples/edit-quote-ambiguity-guard.sh +97 -0
  246. package/examples/edit-retry-loop-guard.sh +0 -0
  247. package/examples/edit-verify.sh +0 -0
  248. package/examples/env-inline-secret-guard.sh +14 -2
  249. package/examples/env-naming-convention.sh +0 -0
  250. package/examples/env-prod-guard.sh +0 -0
  251. package/examples/env-required-check.sh +0 -0
  252. package/examples/env-source-guard.sh +12 -0
  253. package/examples/env-var-check.sh +24 -1
  254. package/examples/ephemeral-container-detector.sh +147 -0
  255. package/examples/error-memory-guard.sh +12 -0
  256. package/examples/evidence-claim-gate.sh +187 -0
  257. package/examples/exploration-budget-guard.sh +89 -0
  258. package/examples/expo-eject-guard.sh +13 -0
  259. package/examples/extended-thinking-loop-guard.sh +139 -0
  260. package/examples/extended-thinking-resume-warning.sh +119 -0
  261. package/examples/extended-thinking-tool-use-mismatch-detector.sh +212 -0
  262. package/examples/fabricated-command-detector.sh +145 -0
  263. package/examples/false-disk-full-guard.sh +63 -0
  264. package/examples/feature-deprecation-detector.sh +109 -0
  265. package/examples/file-change-tracker.sh +1 -1
  266. package/examples/file-change-undo-tracker.sh +0 -0
  267. package/examples/file-edit-backup.sh +63 -14
  268. package/examples/file-reference-check.sh +0 -0
  269. package/examples/file-size-limit.sh +12 -0
  270. package/examples/financial-operation-guard.sh +12 -0
  271. package/examples/firewall-guard.sh +12 -0
  272. package/examples/fish-shell-wrapper.sh +125 -7
  273. package/examples/five-hundred-milestone.sh +1 -0
  274. package/examples/flask-static-route-guard.sh +89 -0
  275. package/examples/forbidden-response-phrase-detector.sh +161 -0
  276. package/examples/gem-push-guard.sh +13 -0
  277. package/examples/gh-cli-destructive-guard.sh +13 -1
  278. package/examples/git-checkout-safety-guard.sh +12 -0
  279. package/examples/git-checkout-uncommitted-guard.sh +12 -0
  280. package/examples/git-config-guard.sh +12 -0
  281. package/examples/git-crypt-worktree-guard.sh +12 -0
  282. package/examples/git-filter-repo-guard.sh +56 -0
  283. package/examples/git-history-rewrite-guard.sh +12 -0
  284. package/examples/git-hook-bypass-guard.sh +0 -0
  285. package/examples/git-maintenance-guard.sh +83 -0
  286. package/examples/git-merge-conflict-prevent.sh +0 -0
  287. package/examples/git-message-length-check.sh +0 -0
  288. package/examples/git-message-length.sh +0 -0
  289. package/examples/git-operations-require-approval.sh +68 -14
  290. package/examples/git-pack-temp-cleanup-guard.sh +102 -0
  291. package/examples/git-push-blast-radius-guard.sh +218 -0
  292. package/examples/git-remote-guard.sh +24 -3
  293. package/examples/git-rm-orphan-wipe-guard.sh +85 -0
  294. package/examples/git-stash-before-checkout.sh +12 -0
  295. package/examples/git-stash-before-danger.sh +0 -0
  296. package/examples/git-submodule-guard.sh +69 -2
  297. package/examples/git-tag-guard.sh +12 -0
  298. package/examples/github-actions-secret-guard.sh +0 -0
  299. package/examples/gitignore-check.sh +0 -0
  300. package/examples/gitops-drift-guard.sh +12 -0
  301. package/examples/go-mod-tidy-warn.sh +1 -0
  302. package/examples/go-vet-after-edit.sh +12 -0
  303. package/examples/goal-iteration-limit-warner.sh +152 -0
  304. package/examples/grep-nul-false-negative-guard.sh +30 -0
  305. package/examples/growthbook-flag-monitor.sh +257 -0
  306. package/examples/hallucination-url-check.sh +1 -1
  307. package/examples/halt-signal-detector.sh +135 -0
  308. package/examples/handoff-on-clear.sh +65 -0
  309. package/examples/hardcoded-ip-guard.sh +1 -0
  310. package/examples/headless-empty-result-guard.sh +0 -0
  311. package/examples/headless-stop-guard.sh +0 -0
  312. package/examples/helm-install-guard.sh +2 -1
  313. package/examples/home-critical-bash-guard.sh +17 -1
  314. package/examples/hook-debug-wrapper.sh +6 -2
  315. package/examples/hook-permission-fixer.sh +0 -0
  316. package/examples/hook-self-disable-detector.sh +99 -0
  317. package/examples/hook-stdout-sanitizer.sh +6 -2
  318. package/examples/hook-tamper-guard.sh +12 -0
  319. package/examples/idle-session-cost-alert.sh +0 -0
  320. package/examples/image-dimension-guard.sh +109 -0
  321. package/examples/image-file-validator.sh +0 -0
  322. package/examples/iteration-quality-degradation-detector.sh +170 -0
  323. package/examples/java-compile-on-edit.sh +1 -1
  324. package/examples/json-syntax-check.sh +0 -0
  325. package/examples/k8s-production-guard.sh +13 -1
  326. package/examples/kill-process-guard.sh +12 -0
  327. package/examples/kubernetes-guard.sh +13 -1
  328. package/examples/laravel-artisan-guard.sh +13 -0
  329. package/examples/large-file-guard.sh +1 -1
  330. package/examples/log-level-guard.sh +0 -0
  331. package/examples/log-truncation-guard.sh +12 -0
  332. package/examples/long-session-malformed-tool-call-detector.sh +183 -0
  333. package/examples/loop-detector.sh +12 -0
  334. package/examples/magic-number-warn.sh +1 -0
  335. package/examples/main-branch-warn.sh +12 -0
  336. package/examples/markdown-link-check.sh +0 -0
  337. package/examples/max-concurrent-agents.sh +12 -0
  338. package/examples/max-edit-size-guard.sh +13 -0
  339. package/examples/max-file-count-guard.sh +0 -0
  340. package/examples/max-file-delete-count.sh +0 -0
  341. package/examples/max-function-length.sh +1 -0
  342. package/examples/max-import-count.sh +0 -0
  343. package/examples/max-subagent-count.sh +0 -0
  344. package/examples/mcp-config-freeze.sh +12 -0
  345. package/examples/mcp-config-poisoning-audit.sh +150 -0
  346. package/examples/mcp-data-boundary.sh +1 -1
  347. package/examples/mcp-misdiagnosis-arrest.sh +209 -0
  348. package/examples/mcp-orphan-leak-warner.sh +49 -0
  349. package/examples/mcp-permissions-ask-warner.sh +151 -0
  350. package/examples/mcp-routine-approval-detector.sh +154 -0
  351. package/examples/mcp-server-allowlist.sh +12 -0
  352. package/examples/mcp-server-guard.sh +12 -0
  353. package/examples/mcp-startup-bloat-detector.sh +87 -0
  354. package/examples/mcp-stdio-compatibility-test.sh +153 -0
  355. package/examples/mcp-tool-audit-log.sh +0 -0
  356. package/examples/mcp-tool-guard.sh +101 -1
  357. package/examples/mcp-warmup-wait.sh +0 -0
  358. package/examples/memory-chain-audit.sh +56 -0
  359. package/examples/memory-orphan-detector.sh +188 -0
  360. package/examples/memory-write-guard.sh +99 -17
  361. package/examples/migration-verify-guard.sh +12 -0
  362. package/examples/model-swap-suggester.sh +177 -0
  363. package/examples/model-version-alert.sh +5 -1
  364. package/examples/model-version-lock.sh +63 -0
  365. package/examples/move-delete-sequence-guard.sh +33 -2
  366. package/examples/multi-file-plan-routing-gate.sh +192 -0
  367. package/examples/multi-vendor-concurrent-warner.sh +108 -0
  368. package/examples/multi-window-auth-drift-detector.sh +183 -0
  369. package/examples/multiline-command-approver.sh +161 -23
  370. package/examples/nested-background-agent-guard.sh +109 -0
  371. package/examples/nested-spawn-inflight-guard.sh +178 -0
  372. package/examples/network-exfil-guard.sh +12 -0
  373. package/examples/network-guard.sh +12 -0
  374. package/examples/network-interface-guard.sh +12 -0
  375. package/examples/nextjs-env-guard.sh +1 -1
  376. package/examples/no-absolute-import.sh +0 -0
  377. package/examples/no-alert-confirm-prompt.sh +0 -0
  378. package/examples/no-anonymous-default-export.sh +0 -0
  379. package/examples/no-any-type.sh +0 -0
  380. package/examples/no-any-typescript.sh +1 -0
  381. package/examples/no-ask-human.sh +12 -0
  382. package/examples/no-assignment-in-condition.sh +0 -0
  383. package/examples/no-base64-exfil.sh +12 -0
  384. package/examples/no-callback-hell.sh +0 -0
  385. package/examples/no-circular-dependency.sh +0 -0
  386. package/examples/no-cleartext-storage.sh +0 -0
  387. package/examples/no-commented-code.sh +0 -0
  388. package/examples/no-commit-fixup.sh +0 -0
  389. package/examples/no-console-assert.sh +0 -0
  390. package/examples/no-console-error-swallow.sh +0 -0
  391. package/examples/no-console-in-prod.sh +0 -0
  392. package/examples/no-console-log-commit.sh +12 -0
  393. package/examples/no-console-log.sh +0 -0
  394. package/examples/no-console-time.sh +0 -0
  395. package/examples/no-cors-wildcard.sh +4 -1
  396. package/examples/no-curl-upload.sh +0 -0
  397. package/examples/no-dangerouslySetInnerHTML.sh +0 -0
  398. package/examples/no-dangling-await.sh +1 -0
  399. package/examples/no-debug-commit.sh +12 -0
  400. package/examples/no-debug-in-commit.sh +0 -0
  401. package/examples/no-deep-nesting.sh +0 -0
  402. package/examples/no-deep-relative-import.sh +1 -0
  403. package/examples/no-default-credentials.sh +0 -0
  404. package/examples/no-deploy-friday.sh +13 -1
  405. package/examples/no-disabled-test.sh +0 -0
  406. package/examples/no-document-write.sh +0 -0
  407. package/examples/no-empty-function.sh +0 -0
  408. package/examples/no-eval-in-template.sh +0 -0
  409. package/examples/no-eval-template.sh +3 -1
  410. package/examples/no-eval.sh +0 -0
  411. package/examples/no-exec-user-input.sh +0 -0
  412. package/examples/no-fixme-ship.sh +12 -0
  413. package/examples/no-floating-promises.sh +0 -0
  414. package/examples/no-force-flag.sh +22 -5
  415. package/examples/no-force-install.sh +0 -0
  416. package/examples/no-git-amend.sh +12 -0
  417. package/examples/no-git-rebase-public.sh +0 -0
  418. package/examples/no-global-install.sh +12 -0
  419. package/examples/no-global-state.sh +0 -0
  420. package/examples/no-hardcoded-port.sh +1 -0
  421. package/examples/no-hardcoded-url.sh +0 -0
  422. package/examples/no-helmet-missing.sh +0 -0
  423. package/examples/no-http-url.sh +1 -0
  424. package/examples/no-http-without-https.sh +0 -0
  425. package/examples/no-inline-style.sh +0 -0
  426. package/examples/no-inline-styles.sh +1 -0
  427. package/examples/no-innerhtml.sh +0 -0
  428. package/examples/no-install-global.sh +12 -0
  429. package/examples/no-jwt-in-url.sh +0 -0
  430. package/examples/no-large-commit.sh +0 -0
  431. package/examples/no-localhost-expose.sh +0 -0
  432. package/examples/no-magic-number.sh +0 -0
  433. package/examples/no-md5-sha1.sh +0 -0
  434. package/examples/no-mixed-line-endings.sh +8 -1
  435. package/examples/no-mutation-in-reducer.sh +0 -0
  436. package/examples/no-nested-ternary.sh +0 -0
  437. package/examples/no-network-exfil.sh +0 -0
  438. package/examples/no-open-redirect.sh +0 -0
  439. package/examples/no-output-truncation.sh +12 -0
  440. package/examples/no-package-downgrade.sh +0 -0
  441. package/examples/no-package-lock-edit.sh +12 -0
  442. package/examples/no-path-join-user-input.sh +0 -0
  443. package/examples/no-port-bind.sh +0 -0
  444. package/examples/no-process-exit.sh +0 -0
  445. package/examples/no-prototype-pollution.sh +0 -0
  446. package/examples/no-push-without-ci.sh +0 -0
  447. package/examples/no-push-without-tests.sh +12 -0
  448. package/examples/no-raw-password-in-url.sh +0 -0
  449. package/examples/no-root-user-docker.sh +1 -0
  450. package/examples/no-root-write.sh +12 -0
  451. package/examples/no-secrets-in-args.sh +4 -1
  452. package/examples/no-secrets-in-logs.sh +0 -0
  453. package/examples/no-sensitive-log.sh +0 -0
  454. package/examples/no-sleep-in-hooks.sh +0 -0
  455. package/examples/no-star-import-python.sh +1 -0
  456. package/examples/no-string-concat-sql.sh +0 -0
  457. package/examples/no-sudo-guard.sh +12 -0
  458. package/examples/no-sync-fs.sh +0 -0
  459. package/examples/no-todo-in-merge.sh +0 -0
  460. package/examples/no-todo-in-production.sh +1 -0
  461. package/examples/no-todo-without-issue.sh +0 -0
  462. package/examples/no-unused-import.sh +0 -0
  463. package/examples/no-var-keyword.sh +0 -0
  464. package/examples/no-verify-blocker.sh +12 -0
  465. package/examples/no-wget-piped-bash.sh +12 -0
  466. package/examples/no-wildcard-cors.sh +0 -0
  467. package/examples/no-wildcard-delete.sh +0 -0
  468. package/examples/no-wildcard-import.sh +0 -0
  469. package/examples/no-with-statement.sh +0 -0
  470. package/examples/no-write-outside-src.sh +0 -0
  471. package/examples/no-xml-external-entity.sh +0 -0
  472. package/examples/non-english-quality-warner.sh +156 -0
  473. package/examples/notify-waiting.sh +1 -1
  474. package/examples/npm-audit-warn.sh +0 -0
  475. package/examples/npm-global-install-guard.sh +12 -0
  476. package/examples/npm-publish-guard.sh +12 -0
  477. package/examples/npm-script-injection.sh +0 -0
  478. package/examples/npm-supply-chain-guard.sh +0 -0
  479. package/examples/nuxt-config-guard.sh +1 -0
  480. package/examples/oauth-refresh-monitor.sh +210 -0
  481. package/examples/opus-degradation-tracker.sh +187 -0
  482. package/examples/opus48-routine-task-warning.sh +196 -0
  483. package/examples/opus48-thinking-wedge-advisor.sh +143 -0
  484. package/examples/output-credential-scan.sh +1 -1
  485. package/examples/output-secret-mask.sh +31 -9
  486. package/examples/output-token-spike-detector.sh +145 -0
  487. package/examples/package-json-guard.sh +12 -0
  488. package/examples/package-lock-frozen.sh +12 -0
  489. package/examples/parallel-batch-size-limiter.sh +121 -0
  490. package/examples/parallel-cascade-detector.sh +116 -0
  491. package/examples/partial-view-claim-arrest.sh +174 -0
  492. package/examples/path-deny-bash-guard.sh +12 -0
  493. package/examples/path-traversal-guard.sh +12 -0
  494. package/examples/per-prompt-token-cap.sh +124 -0
  495. package/examples/permission-audit-log.sh +1 -1
  496. package/examples/permission-denial-enforcer.sh +12 -0
  497. package/examples/permission-entry-validator.sh +0 -0
  498. package/examples/persisted-1m-model-advisor.sh +88 -0
  499. package/examples/php-lint-on-edit.sh +1 -1
  500. package/examples/pii-upload-guard.sh +12 -0
  501. package/examples/pip-publish-guard.sh +13 -0
  502. package/examples/pip-requirements-guard.sh +12 -0
  503. package/examples/pip-venv-required.sh +12 -0
  504. package/examples/plan-mode-edit-guard.sh +12 -0
  505. package/examples/plan-mode-enforcer.sh +12 -0
  506. package/examples/plan-mode-strict-guard.sh +12 -0
  507. package/examples/plugin-hooks-json-bloat-detector.sh +169 -0
  508. package/examples/plugin-process-cleanup.sh +0 -0
  509. package/examples/polyglot-rm-guard.sh +12 -0
  510. package/examples/post-compact-safety.sh +12 -0
  511. package/examples/post-edit-disk-verify.sh +152 -0
  512. package/examples/powershell-remove-item-guard.sh +85 -0
  513. package/examples/pr-description-check.sh +0 -0
  514. package/examples/pr-duplicate-guard.sh +13 -0
  515. package/examples/pre-bash-sed-line-ending-windows.sh +87 -0
  516. package/examples/pre-compact-knowledge-save.sh +0 -0
  517. package/examples/pre-compact-transcript-backup.sh +0 -0
  518. package/examples/pre-execution-claim-detector.sh +179 -0
  519. package/examples/prefer-builtin-tools.sh +10 -1
  520. package/examples/prefer-const.sh +0 -0
  521. package/examples/prefer-dedicated-tools.sh +12 -0
  522. package/examples/prefer-optional-chaining.sh +0 -0
  523. package/examples/prisma-migrate-guard.sh +24 -7
  524. package/examples/production-port-kill-guard.sh +12 -0
  525. package/examples/prompt-injection-guard.sh +2 -1
  526. package/examples/prompt-usage-logger.sh +0 -0
  527. package/examples/protect-claudemd.sh +12 -0
  528. package/examples/protect-dotfiles.sh +12 -0
  529. package/examples/proxy-capture-suggester.sh +159 -0
  530. package/examples/public-artefact-socratic-narrowing.sh +232 -0
  531. package/examples/public-repo-push-guard.sh +12 -0
  532. package/examples/push-requires-test-pass-record.sh +0 -0
  533. package/examples/push-requires-test-pass.sh +12 -0
  534. package/examples/quota-anomaly-detector.sh +173 -0
  535. package/examples/quota-reset-audit.sh +58 -0
  536. package/examples/quoted-flag-approver.sh +99 -10
  537. package/examples/rails-migration-guard.sh +12 -0
  538. package/examples/rate-limit-guard.sh +0 -0
  539. package/examples/read-all-files-enforcer.sh +0 -0
  540. package/examples/read-budget-guard.sh +12 -0
  541. package/examples/read-loop-detector.sh +59 -0
  542. package/examples/read-once-guard.sh +96 -0
  543. package/examples/read-only-mode.sh +12 -0
  544. package/examples/readme-exists-check.sh +0 -0
  545. package/examples/record-read-coverage.sh +73 -0
  546. package/examples/redirect-fragment-warner.sh +149 -0
  547. package/examples/redis-flushall-guard.sh +13 -0
  548. package/examples/redundant-read-blocker.sh +132 -0
  549. package/examples/refusal-arrest-gate.sh +248 -0
  550. package/examples/registry-publish-guard.sh +13 -1
  551. package/examples/remote-control-billing-classifier.sh +135 -0
  552. package/examples/replace-all-guard.sh +12 -0
  553. package/examples/repo-visibility-guard.sh +12 -0
  554. package/examples/reroute-after-block-guard.sh +150 -0
  555. package/examples/response-budget-guard.sh +0 -0
  556. package/examples/resume-drift-watcher.sh +57 -0
  557. package/examples/rg-replace-flag-detector.sh +125 -0
  558. package/examples/rhetorical-verification-prompt-detector.sh +102 -0
  559. package/examples/ripgrep-permission-fix.sh +0 -0
  560. package/examples/rm-safety-net.sh +151 -8
  561. package/examples/role-tool-guard.sh +12 -0
  562. package/examples/route-handler-emptiness-gate.sh +324 -0
  563. package/examples/ruby-lint-on-edit.sh +1 -1
  564. package/examples/runtime-binary-change-detector.sh +102 -0
  565. package/examples/same-command-repeat-detector.sh +196 -0
  566. package/examples/same-correction-arrest.sh +169 -0
  567. package/examples/sandbox-denywrite-enforcer.sh +78 -0
  568. package/examples/sandbox-relative-path-audit.sh +83 -25
  569. package/examples/sandbox-write-verify.sh +12 -0
  570. package/examples/schema-migration-guard.sh +0 -0
  571. package/examples/scope-expansion-receipt.sh +178 -0
  572. package/examples/scope-guard.sh +88 -9
  573. package/examples/secret-file-read-guard.sh +12 -0
  574. package/examples/secret-file-write-guard.sh +150 -0
  575. package/examples/self-modify-bypass-guard.sh +0 -0
  576. package/examples/sensitive-file-read-guard.sh +23 -3
  577. package/examples/sensitive-log-guard.sh +1 -0
  578. package/examples/server-side-prompt-injection-detector.sh +69 -0
  579. package/examples/session-agent-cost-limiter.sh +12 -0
  580. package/examples/session-backup-on-start.sh +1 -1
  581. package/examples/session-cost-alert.sh +12 -0
  582. package/examples/session-drift-guard.sh +12 -0
  583. package/examples/session-duration-guard.sh +25 -2
  584. package/examples/session-end-logger.sh +0 -0
  585. package/examples/session-health-monitor.sh +0 -0
  586. package/examples/session-index-repair.sh +1 -1
  587. package/examples/session-memory-watchdog.sh +1 -0
  588. package/examples/session-permission-reset-guard.sh +12 -0
  589. package/examples/session-persistence-verifier.sh +93 -0
  590. package/examples/session-plugin-pin-watch.sh +68 -0
  591. package/examples/session-rate-monitor.sh +176 -0
  592. package/examples/session-resume-env-fix.sh +0 -0
  593. package/examples/session-start-quota-status.sh +193 -0
  594. package/examples/session-start-safety-check.sh +55 -3
  595. package/examples/session-state-saver.sh +0 -0
  596. package/examples/session-summary-stop.sh +1 -1
  597. package/examples/session-summary.sh +0 -0
  598. package/examples/session-token-counter.sh +1 -1
  599. package/examples/settings-hooks-key-restorer.sh +99 -0
  600. package/examples/settings-json-health-check.sh +57 -0
  601. package/examples/settings-json-model-guard.sh +0 -0
  602. package/examples/settings-regression-tester.sh +188 -0
  603. package/examples/shell-config-truncation-guard.sh +12 -0
  604. package/examples/shell-wrapper-guard.sh +12 -0
  605. package/examples/skill-cumulative-size-detector.sh +104 -0
  606. package/examples/skill-description-drop-detector.sh +148 -0
  607. package/examples/skill-gate.sh +0 -0
  608. package/examples/skill-truncation-detector.sh +154 -0
  609. package/examples/skills-context-recorder.sh +167 -0
  610. package/examples/skills-load-verifier.sh +96 -0
  611. package/examples/skills-settings-validator.sh +139 -0
  612. package/examples/sonnet-45-deprecation-helper.sh +85 -0
  613. package/examples/spec-file-scope-guard.sh +12 -0
  614. package/examples/spring-profile-guard.sh +1 -0
  615. package/examples/spurious-malformed-notice-detector.sh +247 -0
  616. package/examples/sql-bulk-delete-warn.sh +88 -0
  617. package/examples/sql-injection-detect.sh +0 -0
  618. package/examples/ssh-key-protect.sh +12 -0
  619. package/examples/staged-secret-scan.sh +22 -1
  620. package/examples/stale-temp-settings-detector.sh +86 -0
  621. package/examples/standing-rule-session-surfacer.sh +137 -0
  622. package/examples/stop-hook-sigterm-wrapper.sh +182 -0
  623. package/examples/stop-transcript-write-health.sh +64 -0
  624. package/examples/strict-allowlist.sh +57 -15
  625. package/examples/strip-coauthored-by.sh +50 -10
  626. package/examples/subagent-blast-radius-guard.sh +184 -0
  627. package/examples/subagent-boundary-precheck.sh +126 -0
  628. package/examples/subagent-budget-guard.sh +12 -0
  629. package/examples/subagent-claudemd-inject.sh +0 -0
  630. package/examples/subagent-closure-verify-gate.sh +164 -0
  631. package/examples/subagent-destructive-git-guard.sh +120 -0
  632. package/examples/subagent-error-detector.sh +0 -0
  633. package/examples/subagent-forged-system-reminder-guard.sh +156 -0
  634. package/examples/subagent-identity-leak-guard.sh +102 -0
  635. package/examples/subagent-identity-reassertion.sh +51 -0
  636. package/examples/subagent-inheritance-tester.sh +179 -0
  637. package/examples/subagent-permission-mode-guard.sh +110 -0
  638. package/examples/subagent-scope-guard.sh +12 -0
  639. package/examples/subagent-spawn-verification-enforcer.sh +102 -0
  640. package/examples/subagent-tool-allowlist-enforcer.sh +101 -0
  641. package/examples/subagent-tool-call-limiter.sh +87 -15
  642. package/examples/subcommand-chain-guard.sh +12 -0
  643. package/examples/subscription-api-billing-warner.sh +160 -0
  644. package/examples/subscription-bypass-detector.sh +152 -0
  645. package/examples/svelte-lint-on-edit.sh +1 -0
  646. package/examples/swift-build-on-edit.sh +1 -1
  647. package/examples/symlink-guard.sh +27 -2
  648. package/examples/symlink-protect.sh +1 -0
  649. package/examples/system-dir-protection-guard.sh +73 -8
  650. package/examples/system-message-workaround.sh +38 -13
  651. package/examples/system-package-guard.sh +12 -0
  652. package/examples/systemd-service-guard.sh +12 -0
  653. package/examples/task-integrity-guard.sh +12 -0
  654. package/examples/temp-file-cleanup.sh +1 -1
  655. package/examples/temporal-suggestion-detector.sh +135 -0
  656. package/examples/terraform-guard.sh +27 -6
  657. package/examples/test-after-edit.sh +1 -1
  658. package/examples/test-before-push.sh +12 -0
  659. package/examples/test-coverage-reminder.sh +24 -1
  660. package/examples/thinking-budget-effort-mismatch-detector.sh +149 -0
  661. package/examples/thinking-stall-detector.sh +61 -0
  662. package/examples/timezone-guard.sh +0 -0
  663. package/examples/tmp-output-size-guard.sh +0 -0
  664. package/examples/todo-check.sh +1 -1
  665. package/examples/token-budget-guard.sh +12 -0
  666. package/examples/token-budget-per-task.sh +12 -0
  667. package/examples/token-usage-tracker.sh +7 -1
  668. package/examples/tokenizer-ratio-alert-corpus.sh +90 -0
  669. package/examples/tokenizer-ratio-alert.sh +104 -0
  670. package/examples/tool-call-rate-limiter.sh +0 -0
  671. package/examples/tool-result-correlation-checker.sh +167 -0
  672. package/examples/tool-result-size-guard.sh +132 -0
  673. package/examples/tool-retry-budget-guard.sh +12 -0
  674. package/examples/transcript-contamination-detector.sh +138 -0
  675. package/examples/trustfall-mcp-injection-guard.sh +103 -0
  676. package/examples/ultrareview-large-diff-advisor.sh +184 -0
  677. package/examples/unbounded-output-guard.sh +94 -0
  678. package/examples/uncommitted-changes-stop.sh +1 -0
  679. package/examples/uncommitted-discard-guard.sh +23 -5
  680. package/examples/uncommitted-work-guard.sh +12 -0
  681. package/examples/usage-warn.sh +0 -0
  682. package/examples/user-account-guard.sh +12 -0
  683. package/examples/userprompt-submit-receipt.sh +123 -0
  684. package/examples/variable-expansion-guard.sh +12 -0
  685. package/examples/verify-after-publish-reminder.sh +93 -0
  686. package/examples/verify-before-commit.sh +12 -0
  687. package/examples/version-bump-detector.sh +156 -0
  688. package/examples/version-regression-warner.sh +144 -0
  689. package/examples/vue-lint-on-edit.sh +1 -0
  690. package/examples/warn-cron-cost-trap.sh +173 -0
  691. package/examples/webfetch-runaway-guard.sh +89 -0
  692. package/examples/wellness-break-reminder.sh +118 -0
  693. package/examples/windows-destructive-command-guard.sh +177 -0
  694. package/examples/windows-path-guard.sh +12 -0
  695. package/examples/windows-python-stub-detector.sh +63 -0
  696. package/examples/work-hours-guard.sh +12 -0
  697. package/examples/working-directory-fence.sh +12 -0
  698. package/examples/workspace-lease-guard.sh +205 -0
  699. package/examples/worktree-create-log.sh +1 -0
  700. package/examples/worktree-delete-guard.sh +12 -0
  701. package/examples/worktree-edit-boundary-guard.sh +127 -0
  702. package/examples/worktree-escape-write-guard.sh +114 -0
  703. package/examples/worktree-hook-linker.sh +0 -0
  704. package/examples/worktree-hooks-path-fix.sh +111 -0
  705. package/examples/worktree-parent-write-guard.sh +43 -0
  706. package/examples/worktree-project-unify.sh +2 -1
  707. package/examples/worktree-remove-uncommitted-guard.sh +13 -0
  708. package/examples/worktree-unmerged-guard.sh +7 -1
  709. package/examples/write-byte-integrity-verifier.sh +190 -0
  710. package/examples/write-empty-content-guard.sh +67 -0
  711. package/examples/write-nul-corruption-detector.sh +61 -0
  712. package/examples/write-overwrite-confirm.sh +160 -14
  713. package/examples/write-secret-guard.sh +27 -5
  714. package/examples/write-shrink-guard.sh +12 -0
  715. package/examples/write-test-ratio.sh +0 -0
  716. package/examples/wsl-host-disk-space-guard.sh +97 -0
  717. package/examples/xml-format-leak-detector.sh +266 -0
  718. package/examples/yaml-syntax-check.sh +12 -0
  719. package/hooks/hooks.json +6 -6
  720. package/index.mjs +1699 -183
  721. package/mission.md +2 -0
  722. package/package.json +4 -4
  723. package/plugins/credential-guard/.claude-plugin/plugin.json +9 -7
  724. package/plugins/git-protection/.claude-plugin/plugin.json +10 -8
  725. package/plugins/safety-essentials/.claude-plugin/plugin.json +9 -7
  726. package/plugins/token-guard/.claude-plugin/plugin.json +10 -8
  727. package/scripts/agents-md-sync-setup.sh +156 -0
  728. package/scripts/autonomy-blocked-summary.sh +148 -0
  729. package/scripts/build-search-index.py +43 -0
  730. package/scripts/build-sitemap.py +119 -0
  731. package/scripts/cc-doctor.sh +192 -0
  732. package/scripts/check-hook-event-names.py +127 -0
  733. package/scripts/check-misfire-instrument.sh +64 -0
  734. package/scripts/claim-verify-audit.sh +467 -0
  735. package/scripts/cowork-claudemd-helper.sh +136 -0
  736. package/scripts/june-15-deprecated-model-scan.sh +111 -0
  737. package/scripts/measure-heredoc-shapes.sh +67 -0
  738. package/scripts/measure-literal-match-misfire.sh +110 -0
  739. package/scripts/probe-scope-guard-branches.sh +48 -0
  740. package/scripts/probe-skip-line-both-ways.sh +65 -0
  741. package/scripts/receipts-aggregate.py +199 -0
  742. package/scripts/session-forensic-audit.py +360 -0
  743. package/scripts.json +9 -9
  744. package/scripts.json.bak-2026-07-27-find +13 -0
  745. package/skills/safety-setup/SKILL.md +5 -5
  746. package/tests/approve-side-remaining-two.test.sh +129 -0
  747. package/tests/approver-list-granularity.test.sh +145 -0
  748. package/tests/askuserquestion-autonomy-gate.test.sh +181 -0
  749. package/tests/audit-ci-gate.test.sh +87 -0
  750. package/tests/audit-cross-layer-claudemd.test.sh +170 -0
  751. package/tests/audit-fail-open-parse.test.sh +100 -0
  752. package/tests/auto-approve-compound-tail.test.sh +194 -0
  753. package/tests/auto-mode-path-invoked-commands.test.sh +89 -0
  754. package/tests/auto-mode-quoted-targets.test.sh +127 -0
  755. package/tests/auto-mode-unquoted-targets.test.sh +112 -0
  756. package/tests/bash-secret-output-detector-detects.test.sh +102 -0
  757. package/tests/blindspots-cross-layer.test.sh +177 -0
  758. package/tests/block-database-wipe.test.sh +64 -0
  759. package/tests/bundled-short-flags-bypass.test.sh +85 -0
  760. package/tests/cd-git-allow-compound-tail.test.sh +67 -0
  761. package/tests/chown-guard-filesystem-root.test.sh +64 -0
  762. package/tests/ci-workflow-guard-skip-rule.test.sh +115 -0
  763. package/tests/compound-deny-safe-rm-targets.test.sh +105 -0
  764. package/tests/core-scripts-parser-fallback.test.sh +140 -0
  765. package/tests/destructive-guard-bare-glob.test.sh +74 -0
  766. package/tests/destructive-guard-every-operand.test.sh +100 -0
  767. package/tests/destructive-guard-find-deletion.test.sh +114 -0
  768. package/tests/destructive-guard-flag-order.test.sh +106 -0
  769. package/tests/destructive-guard-mentions-vs-invocations.test.sh +107 -0
  770. package/tests/destructive-guard-quoted-target.test.sh +89 -0
  771. package/tests/destructive-guard-separators.test.sh +105 -0
  772. package/tests/destructive-guard-variable-target.test.sh +98 -0
  773. package/tests/destructive-guard-wrapped-command.test.sh +91 -0
  774. package/tests/doctor-hook-disabling-env.test.sh +92 -0
  775. package/tests/doctor-misspelled-settings-keys.test.sh +106 -0
  776. package/tests/example-guards-wrapped-command.test.sh +169 -0
  777. package/tests/file-edit-backup.test.sh +93 -0
  778. package/tests/git-filter-repo-guard.test.sh +60 -0
  779. package/tests/git-global-options-bypass.test.sh +141 -0
  780. package/tests/git-invocation-prefixes-all-guards.test.sh +114 -0
  781. package/tests/git-maintenance-guard.test.sh +83 -0
  782. package/tests/git-pack-temp-cleanup-guard.test.sh +133 -0
  783. package/tests/git-rm-orphan-wipe-guard.test.sh +66 -0
  784. package/tests/git-submodule-guard.test.sh +50 -0
  785. package/tests/grep-pcre-portability.test.sh +155 -0
  786. package/tests/hook-registration-matches-input.test.sh +73 -0
  787. package/tests/hook-trigger-matches-envelope.test.sh +178 -0
  788. package/tests/install-does-not-claim-protection.test.sh +110 -0
  789. package/tests/install-example-standalone-tools.test.sh +139 -0
  790. package/tests/line-continuation-bypass.test.sh +114 -0
  791. package/tests/mcp-config-poisoning-audit.test.sh +106 -0
  792. package/tests/nested-background-agent-guard.test.sh +58 -0
  793. package/tests/no-unqualified-safety-claims.test.sh +114 -0
  794. package/tests/option-eating-grep-patterns.test.sh +130 -0
  795. package/tests/outdated-core-guards.test.sh +134 -0
  796. package/tests/outdated-report.test.sh +155 -0
  797. package/tests/output-secret-mask-warns.test.sh +73 -0
  798. package/tests/plugin-hooks-fail-open-under-sh.test.sh +165 -0
  799. package/tests/plugins-word-order.test.sh +126 -0
  800. package/tests/powershell-remove-item-guard.test.sh +85 -0
  801. package/tests/project-dir-naming.test.sh +103 -0
  802. package/tests/quoted-safe-targets-and-mentions.test.sh +190 -0
  803. package/tests/reroute-after-block-guard.test.sh +104 -0
  804. package/tests/secret-guard-documented-promises.test.sh +97 -0
  805. package/tests/session-plugin-pin-watch.test.sh +45 -0
  806. package/tests/settings-unreadable-refuses-to-write.test.sh +95 -0
  807. package/tests/shield-no-silent-adoption.test.py +110 -0
  808. package/tests/shield-no-silent-adoption.test.sh +46 -0
  809. package/tests/stop-transcript-write-health.test.sh +46 -0
  810. package/tests/system-dir-guard-root-erased.test.sh +66 -0
  811. package/tests/test-account-billing-log.sh +100 -0
  812. package/tests/test-account-routing-preflight.sh +77 -0
  813. package/tests/test-agent-sdk-credit-pool-monitor.sh +157 -0
  814. package/tests/test-agent-view-quota-warn.sh +184 -0
  815. package/tests/test-agents-md-edit-drift-warner.sh +176 -0
  816. package/tests/test-agents-md-loader.sh +204 -0
  817. package/tests/test-agents-md-sync-checker.sh +125 -0
  818. package/tests/test-ai-slop-punctuation-arrest.sh +280 -0
  819. package/tests/test-allowlist.sh +60 -0
  820. package/tests/test-always-allow-pattern-suggester.sh +147 -0
  821. package/tests/test-anthropic-base-url-guard.sh +88 -0
  822. package/tests/test-articulated-scope-capture.sh +139 -0
  823. package/tests/test-attachment-traversal-guard.sh +168 -0
  824. package/tests/test-aup-block-pattern-logger.sh +315 -0
  825. package/tests/test-aup-false-positive-helper.sh +188 -0
  826. package/tests/test-aup-large-tool-output-warner.sh +370 -0
  827. package/tests/test-aup-retry-loop-guard.sh +341 -0
  828. package/tests/test-auth-expiry-reminder.sh +303 -0
  829. package/tests/test-auth-macos-sleep-detector.sh +254 -0
  830. package/tests/test-auth-path-detector.sh +232 -0
  831. package/tests/test-auth-status-checker.sh +233 -0
  832. package/tests/test-authorized-reconfirmation-detector.sh +280 -0
  833. package/tests/test-background-cost-launch-guard.sh +62 -0
  834. package/tests/test-bash-allowlist-secondary-check.sh +143 -0
  835. package/tests/test-bash-fanout-bounded-rewriter.sh +186 -0
  836. package/tests/test-bash-project-fence.sh +127 -0
  837. package/tests/test-bg-permission-prompt-warner.sh +221 -0
  838. package/tests/test-binary-read-detector.sh +173 -0
  839. package/tests/test-broad-prefix-session-trap-warner.sh +167 -0
  840. package/tests/test-bulk-delete-target-resolution.sh +49 -0
  841. package/tests/test-bypass-mode-effective-verifier.sh +179 -0
  842. package/tests/test-cache-creation-drift-detector.sh +244 -0
  843. package/tests/test-cache-residue-detector.sh +429 -0
  844. package/tests/test-cache-tier-logger.sh +59 -0
  845. package/tests/test-cache-ttl-eviction-detector.sh +282 -0
  846. package/tests/test-cch-sentinel-precommit-guard.sh +64 -0
  847. package/tests/test-claim-verify-detector.sh +222 -0
  848. package/tests/test-claim-vs-caveat-checker.sh +134 -0
  849. package/tests/test-claude-code-version-pin-advisor.sh +353 -0
  850. package/tests/test-claude-md-reinjector.sh +173 -0
  851. package/tests/test-claude-md-size-monitor.sh +107 -0
  852. package/tests/test-claude-update-budget-guard.sh +132 -0
  853. package/tests/test-claude-update-smart.sh +91 -0
  854. package/tests/test-claudemd-tool-prohibition.sh +239 -0
  855. package/tests/test-cli-config-pinning-detector.sh +233 -0
  856. package/tests/test-cliff-countdown-advisor.sh +138 -0
  857. package/tests/test-closure-word-verify-gate.sh +158 -0
  858. package/tests/test-commit-all-scope-guard.sh +73 -0
  859. package/tests/test-commitment-carry-forward-arrest.sh +250 -0
  860. package/tests/test-compact-circuit-breaker.sh +134 -0
  861. package/tests/test-compact-dispatch-watchdog.sh +147 -0
  862. package/tests/test-completion-claim-without-verification-detector.sh +326 -0
  863. package/tests/test-compound-bash-permission-resolver.sh +264 -0
  864. package/tests/test-compound-command-deny-enforcer.sh +67 -0
  865. package/tests/test-context-length-budget.sh +68 -0
  866. package/tests/test-context-usage-drift-alert.sh +52 -22
  867. package/tests/test-cost-incident-self-audit.sh +94 -0
  868. package/tests/test-cowork-claude-md-load-checker.sh +257 -0
  869. package/tests/test-cowork-claudemd-helper.sh +141 -0
  870. package/tests/test-cowork-fuse-staleness-watcher.sh +287 -0
  871. package/tests/test-cowork-hook-absence-warner.sh +230 -0
  872. package/tests/test-cowork-model-picker-advisor.sh +317 -0
  873. package/tests/test-credential-exfil-guard.sh +62 -0
  874. package/tests/test-cron-create-receipt.sh +165 -0
  875. package/tests/test-cross-product-mcp-spawn-detector.sh +112 -0
  876. package/tests/test-daemon-zombie-worker-surfacer.sh +71 -0
  877. package/tests/test-daily-cost-guard.sh +131 -0
  878. package/tests/test-deny-rule-integrity-verifier.sh +288 -0
  879. package/tests/test-deployment-readback-gate.sh +92 -0
  880. package/tests/test-deployment-readback-gh-adapter.sh +163 -0
  881. package/tests/test-disabled-feature-toggle-advisor.sh +78 -0
  882. package/tests/test-dispatch-allowlist-preflight.sh +385 -0
  883. package/tests/test-dispatch-liveness-watchdog.sh +319 -0
  884. package/tests/test-dispatch-receipt.sh +314 -0
  885. package/tests/test-dotenv-anthropic-key-billing-guard.sh +160 -0
  886. package/tests/test-echo-probe-spam-detector.sh +143 -0
  887. package/tests/test-edit-quote-ambiguity-guard.sh +75 -0
  888. package/tests/test-ephemeral-container-detector.sh +251 -0
  889. package/tests/test-evidence-claim-gate.sh +291 -0
  890. package/tests/test-exploration-budget-guard.sh +164 -0
  891. package/tests/test-extended-thinking-loop-guard.sh +289 -0
  892. package/tests/test-extended-thinking-resume-warning.sh +240 -0
  893. package/tests/test-extended-thinking-tool-use-mismatch-detector.sh +236 -0
  894. package/tests/test-fabricated-command-detector.sh +296 -0
  895. package/tests/test-false-disk-full-guard.sh +36 -0
  896. package/tests/test-feature-deprecation-detector.sh +117 -0
  897. package/tests/test-forbidden-response-phrase-detector.sh +246 -0
  898. package/tests/test-git-operations-require-approval.sh +53 -0
  899. package/tests/test-git-push-blast-radius-guard.sh +115 -0
  900. package/tests/test-goal-iteration-limit-warner.sh +128 -0
  901. package/tests/test-growthbook-flag-monitor.sh +428 -0
  902. package/tests/test-halt-signal-detector.sh +120 -0
  903. package/tests/test-hook-self-disable-detector.sh +232 -0
  904. package/tests/test-iteration-quality-degradation-detector.sh +244 -0
  905. package/tests/test-long-session-malformed-tool-call-detector.sh +185 -0
  906. package/tests/test-marketplace-plugins.sh +193 -0
  907. package/tests/test-mcp-misdiagnosis-arrest.sh +235 -0
  908. package/tests/test-mcp-orphan-leak-warner.sh +71 -0
  909. package/tests/test-mcp-permissions-ask-warner.sh +207 -0
  910. package/tests/test-mcp-routine-approval-detector.sh +229 -0
  911. package/tests/test-mcp-startup-bloat-detector.sh +141 -0
  912. package/tests/test-mcp-stdio-compatibility-test.sh +112 -0
  913. package/tests/test-memory-chain-audit.sh +59 -0
  914. package/tests/test-memory-orphan-detector.sh +227 -0
  915. package/tests/test-model-swap-suggester.sh +368 -0
  916. package/tests/test-model-version-lock.sh +83 -0
  917. package/tests/test-multi-file-plan-routing-gate.sh +277 -0
  918. package/tests/test-multi-window-auth-drift-detector.sh +262 -0
  919. package/tests/test-nested-spawn-inflight-guard.sh +281 -0
  920. package/tests/test-no-force-flag.sh +49 -0
  921. package/tests/test-non-english-quality-warner.sh +229 -0
  922. package/tests/test-oauth-refresh-monitor.sh +311 -0
  923. package/tests/test-opus-degradation-tracker.sh +274 -0
  924. package/tests/test-opus48-routine-task-warning.sh +201 -0
  925. package/tests/test-opus48-thinking-wedge-advisor.sh +249 -0
  926. package/tests/test-output-token-spike-detector.sh +315 -0
  927. package/tests/test-parallel-batch-size-limiter.sh +228 -0
  928. package/tests/test-parallel-cascade-detector.sh +191 -0
  929. package/tests/test-partial-view-claim-arrest.sh +272 -0
  930. package/tests/test-per-prompt-token-cap.sh +136 -0
  931. package/tests/test-persisted-1m-model-advisor.sh +71 -0
  932. package/tests/test-plugin-hooks-json-bloat-detector.sh +267 -0
  933. package/tests/test-post-edit-disk-verify.sh +294 -0
  934. package/tests/test-pre-bash-sed-line-ending-windows.sh +108 -0
  935. package/tests/test-pre-execution-claim-detector.sh +366 -0
  936. package/tests/test-private-key-backup-and-git-credentials.sh +100 -0
  937. package/tests/test-proxy-capture-suggester.sh +214 -0
  938. package/tests/test-public-artefact-socratic-narrowing.sh +346 -0
  939. package/tests/test-quota-anomaly-detector.sh +321 -0
  940. package/tests/test-quota-reset-audit.sh +81 -0
  941. package/tests/test-read-loop-detector.sh +137 -0
  942. package/tests/test-read-once-guard.sh +85 -0
  943. package/tests/test-receipts-aggregate.sh +143 -0
  944. package/tests/test-redirect-fragment-warner.sh +130 -0
  945. package/tests/test-redundant-read-blocker.sh +155 -0
  946. package/tests/test-refusal-arrest-gate.sh +303 -0
  947. package/tests/test-remote-control-billing-classifier.sh +125 -0
  948. package/tests/test-resume-drift-watcher.sh +65 -0
  949. package/tests/test-rg-replace-flag-detector.sh +175 -0
  950. package/tests/test-rhetorical-verification-prompt-detector.sh +237 -0
  951. package/tests/test-rm-safety-net.sh +115 -0
  952. package/tests/test-route-handler-emptiness-gate.sh +300 -0
  953. package/tests/test-runtime-binary-change-detector.sh +196 -0
  954. package/tests/test-same-command-repeat-detector.sh +165 -0
  955. package/tests/test-same-correction-arrest.sh +165 -0
  956. package/tests/test-scope-expansion-receipt.sh +207 -0
  957. package/tests/test-server-side-prompt-injection-detector.sh +181 -0
  958. package/tests/test-session-persistence-verifier.sh +128 -0
  959. package/tests/test-session-rate-monitor.sh +284 -0
  960. package/tests/test-session-start-quota-status.sh +210 -0
  961. package/tests/test-session-start-safety-check.sh +138 -0
  962. package/tests/test-settings-hooks-key-restorer.sh +257 -0
  963. package/tests/test-settings-json-health-check.sh +70 -0
  964. package/tests/test-settings-regression-tester.sh +197 -0
  965. package/tests/test-skill-cumulative-size-detector.sh +198 -0
  966. package/tests/test-skill-description-drop-detector.sh +236 -0
  967. package/tests/test-skill-truncation-detector.sh +263 -0
  968. package/tests/test-skills-context-recorder.sh +329 -0
  969. package/tests/test-skills-load-verifier.sh +184 -0
  970. package/tests/test-skills-settings-validator.sh +242 -0
  971. package/tests/test-sonnet-45-deprecation-helper.sh +150 -0
  972. package/tests/test-spurious-malformed-notice-detector.sh +290 -0
  973. package/tests/test-sql-bulk-delete-warn.sh +123 -0
  974. package/tests/test-ssh-key-protect.sh +81 -0
  975. package/tests/test-stale-temp-settings-detector.sh +161 -0
  976. package/tests/test-standing-rule-session-surfacer.sh +215 -0
  977. package/tests/test-starter-hooks-manifest.sh +96 -0
  978. package/tests/test-stop-hook-sigterm-wrapper.sh +258 -0
  979. package/tests/test-strict-allowlist.sh +72 -0
  980. package/tests/test-subagent-boundary-precheck.sh +137 -0
  981. package/tests/test-subagent-closure-verify-gate.sh +193 -0
  982. package/tests/test-subagent-destructive-git-guard.sh +86 -0
  983. package/tests/test-subagent-identity-leak-guard.sh +62 -0
  984. package/tests/test-subagent-identity-reassertion.sh +61 -0
  985. package/tests/test-subagent-inheritance-tester.sh +319 -0
  986. package/tests/test-subagent-permission-mode-guard.sh +61 -0
  987. package/tests/test-subagent-spawn-verification-enforcer.sh +60 -0
  988. package/tests/test-subagent-tool-allowlist-enforcer.sh +62 -0
  989. package/tests/test-subagent-tool-call-limiter.sh +97 -0
  990. package/tests/test-subscription-api-billing-warner.sh +138 -0
  991. package/tests/test-subscription-bypass-detector.sh +255 -0
  992. package/tests/test-temporal-suggestion-detector.sh +183 -0
  993. package/tests/test-thinking-budget-effort-mismatch-detector.sh +327 -0
  994. package/tests/test-thinking-stall-detector.sh +151 -0
  995. package/tests/test-tokenizer-ratio-alert-corpus.sh +77 -0
  996. package/tests/test-tokenizer-ratio-alert.sh +93 -0
  997. package/tests/test-tool-result-correlation-checker.sh +264 -0
  998. package/tests/test-tool-result-size-guard.sh +121 -0
  999. package/tests/test-transcript-contamination-detector.sh +264 -0
  1000. package/tests/test-trigger-header-parsing.sh +151 -0
  1001. package/tests/test-ultrareview-large-diff-advisor.sh +192 -0
  1002. package/tests/test-userprompt-submit-receipt.sh +181 -0
  1003. package/tests/test-verify-after-publish-reminder.sh +184 -0
  1004. package/tests/test-version-bump-detector.sh +212 -0
  1005. package/tests/test-version-regression-warner.sh +165 -0
  1006. package/tests/test-warn-cron-cost-trap.sh +82 -0
  1007. package/tests/test-webfetch-runaway-guard.sh +77 -0
  1008. package/tests/test-wellness-break-reminder.sh +138 -0
  1009. package/tests/test-windows-destructive-command-guard.sh +169 -0
  1010. package/tests/test-windows-python-stub-detector.sh +146 -0
  1011. package/tests/test-worktree-edit-boundary-guard.sh +219 -0
  1012. package/tests/test-write-byte-integrity-verifier.sh +192 -0
  1013. package/tests/test-xml-format-leak-detector.sh +299 -0
  1014. package/tests/trustfall-mcp-injection-guard.test.sh +183 -0
  1015. package/tests/workspace-lease-guard.test.sh +144 -0
  1016. package/tests/worktree-escape-write-guard.test.sh +68 -0
  1017. package/tests/worktree-hooks-path-fix.test.sh +181 -0
  1018. package/tests/worktree-parent-write-guard.test.sh +51 -0
  1019. package/tests/write-empty-content-guard.test.sh +39 -0
  1020. package/tests/write-nul-corruption-detector.test.sh +29 -0
  1021. package/tests/write-overwrite-unread-content.test.sh +178 -0
  1022. package/tests/wsl-host-disk-space-guard.test.sh +55 -0
@@ -0,0 +1,155 @@
1
+ #!/bin/bash
2
+ # Tests for redundant-read-blocker.sh
3
+ set -uo pipefail
4
+
5
+ HOOK="$(dirname "$0")/../examples/redundant-read-blocker.sh"
6
+ PASS=0
7
+ FAIL=0
8
+ STATE_DIR="/tmp/cc-redundant-read-test-$$"
9
+ SESSION_ID="test-$$"
10
+ TMP_FILE="$STATE_DIR/sample.txt"
11
+
12
+ setup() {
13
+ rm -rf "$STATE_DIR" 2>/dev/null || true
14
+ mkdir -p "$STATE_DIR"
15
+ echo "sample content" > "$TMP_FILE"
16
+ }
17
+
18
+ run_hook() {
19
+ local file="$1"
20
+ local input
21
+ input=$(jq -nc \
22
+ --arg sid "$SESSION_ID" \
23
+ --arg fp "$file" \
24
+ '{tool_name: "Read", session_id: $sid, tool_input: {file_path: $fp}}')
25
+ printf '%s' "$input" \
26
+ | CC_REDUNDANT_READ_STATE_DIR="$STATE_DIR" \
27
+ CC_REDUNDANT_READ_THRESHOLD="${THRESHOLD:-1}" \
28
+ CC_REDUNDANT_READ_STRICT="${STRICT:-0}" \
29
+ bash "$HOOK" 2>&1
30
+ return $?
31
+ }
32
+
33
+ assert_pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
34
+ assert_fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
35
+
36
+ echo "=== redundant-read-blocker.sh tests ==="
37
+
38
+ # --- Test 1: First read is silent ---
39
+ setup
40
+ output=$(run_hook "$TMP_FILE")
41
+ rc=$?
42
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
43
+ assert_pass "first read is a silent no-op"
44
+ else
45
+ assert_fail "expected silent first read (rc=$rc output=$output)"
46
+ fi
47
+
48
+ # --- Test 2: Second read of same file (unchanged) hits threshold and warns ---
49
+ setup
50
+ run_hook "$TMP_FILE" >/dev/null
51
+ output=$(run_hook "$TMP_FILE")
52
+ rc=$?
53
+ if [ "$rc" -eq 0 ] && echo "$output" | grep -q "REDUNDANT READ"; then
54
+ assert_pass "second read of unchanged file emits warning (rc=0 by default)"
55
+ else
56
+ assert_fail "expected warning on 2nd read (rc=$rc output=$output)"
57
+ fi
58
+
59
+ # --- Test 3: Strict mode exits 2 on second read ---
60
+ setup
61
+ STRICT=1 run_hook "$TMP_FILE" >/dev/null
62
+ output=$(STRICT=1 run_hook "$TMP_FILE")
63
+ rc=$?
64
+ if [ "$rc" -eq 2 ] && echo "$output" | grep -q "REDUNDANT READ"; then
65
+ assert_pass "strict mode exits 2 with warning"
66
+ else
67
+ assert_fail "expected exit 2 in strict mode (rc=$rc)"
68
+ fi
69
+
70
+ # --- Test 4: Modified file is not redundant (mtime changed) ---
71
+ setup
72
+ run_hook "$TMP_FILE" >/dev/null
73
+ sleep 1
74
+ echo "modified" > "$TMP_FILE" # changes mtime
75
+ output=$(run_hook "$TMP_FILE")
76
+ rc=$?
77
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
78
+ assert_pass "modified file is not flagged as redundant"
79
+ else
80
+ assert_fail "modified file should pass (rc=$rc output=$output)"
81
+ fi
82
+
83
+ # --- Test 5: Different paths do not interfere ---
84
+ setup
85
+ OTHER="$STATE_DIR/other.txt"
86
+ echo "other content" > "$OTHER"
87
+ run_hook "$TMP_FILE" >/dev/null
88
+ output=$(run_hook "$OTHER")
89
+ rc=$?
90
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
91
+ assert_pass "different paths don't trigger each other"
92
+ else
93
+ assert_fail "different file should pass (rc=$rc output=$output)"
94
+ fi
95
+
96
+ # --- Test 6: Threshold raised to 3 lets two reads pass silently ---
97
+ setup
98
+ THRESHOLD=3 run_hook "$TMP_FILE" >/dev/null
99
+ output=$(THRESHOLD=3 run_hook "$TMP_FILE")
100
+ rc=$?
101
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
102
+ assert_pass "raising THRESHOLD lets extra reads through"
103
+ else
104
+ assert_fail "with THRESHOLD=3, 2 reads should be silent (rc=$rc output=$output)"
105
+ fi
106
+
107
+ # --- Test 7: Non-Read tool calls are ignored ---
108
+ setup
109
+ input=$(jq -nc --arg sid "$SESSION_ID" '{tool_name: "Edit", session_id: $sid, tool_input: {file_path: "x"}}')
110
+ output=$(printf '%s' "$input" | CC_REDUNDANT_READ_STATE_DIR="$STATE_DIR" bash "$HOOK" 2>&1)
111
+ rc=$?
112
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
113
+ assert_pass "non-Read tool calls are ignored"
114
+ else
115
+ assert_fail "expected silent for Edit (rc=$rc output=$output)"
116
+ fi
117
+
118
+ # --- Test 8: Missing file_path is a silent no-op ---
119
+ setup
120
+ input=$(jq -nc --arg sid "$SESSION_ID" '{tool_name: "Read", session_id: $sid, tool_input: {}}')
121
+ output=$(printf '%s' "$input" | CC_REDUNDANT_READ_STATE_DIR="$STATE_DIR" bash "$HOOK" 2>&1)
122
+ rc=$?
123
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
124
+ assert_pass "missing file_path is silent no-op"
125
+ else
126
+ assert_fail "expected silent (rc=$rc output=$output)"
127
+ fi
128
+
129
+ # --- Test 9: Warning references #60283 ---
130
+ setup
131
+ run_hook "$TMP_FILE" >/dev/null
132
+ output=$(run_hook "$TMP_FILE")
133
+ if echo "$output" | grep -q "#60283"; then
134
+ assert_pass "warning references #60283 for grounding"
135
+ else
136
+ assert_fail "expected reference to #60283 in warning"
137
+ fi
138
+
139
+ # --- Test 10: Reads log respects WINDOW size ---
140
+ setup
141
+ THRESHOLD=99 run_hook "$STATE_DIR/a.txt" >/dev/null 2>&1
142
+ THRESHOLD=99 run_hook "$STATE_DIR/b.txt" >/dev/null 2>&1
143
+ THRESHOLD=99 run_hook "$STATE_DIR/c.txt" >/dev/null 2>&1
144
+ THRESHOLD=99 run_hook "$STATE_DIR/d.txt" >/dev/null 2>&1
145
+ log_lines=$(wc -l < "$STATE_DIR/$SESSION_ID/reads.log" 2>/dev/null || echo 0)
146
+ if [ "$log_lines" -le 20 ]; then
147
+ assert_pass "reads log respects window size (lines: $log_lines <= 20)"
148
+ else
149
+ assert_fail "log grew unbounded (lines: $log_lines)"
150
+ fi
151
+
152
+ rm -rf "$STATE_DIR" 2>/dev/null || true
153
+ echo
154
+ echo "=== Results: $PASS passed, $FAIL failed ==="
155
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,303 @@
1
+ #!/bin/bash
2
+ # Tests for refusal-arrest-gate.sh
3
+ #
4
+ # Verifies the PreToolUse-hook behavior for the refusal-side dual of
5
+ # closure-word-verify-gate (#60506, #60475):
6
+ # - Refusal in same-turn prose + matching tool target → exit 2, feedback
7
+ # - Refusal in same-turn prose + non-matching target → exit 0 silent
8
+ # - No refusal in prose → exit 0 silent
9
+ # - Refusal inside quoted user prompt → exit 0 silent
10
+ # - Disable flag respected
11
+ # - Multiple refusal pattern variants
12
+ # - Bash command target matching
13
+ # - File path basename matching
14
+ # - Length threshold (very short targets ignored)
15
+ # - Non-instrumented tools pass through
16
+
17
+ set -uo pipefail
18
+
19
+ HOOK="$(dirname "$0")/../examples/refusal-arrest-gate.sh"
20
+ PASS=0
21
+ FAIL=0
22
+
23
+ assert_pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
24
+ assert_fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
25
+
26
+ # Helper: build PreToolUse input JSON from three params, then run hook.
27
+ # Args: tool_name, tool_input_json, assistant_text
28
+ make_input() {
29
+ local tn="$1" ti="$2" at="$3"
30
+ jq -nc \
31
+ --arg tn "$tn" \
32
+ --argjson ti "$ti" \
33
+ --arg at "$at" \
34
+ '{tool_name: $tn, tool_input: $ti, last_assistant_message: $at}'
35
+ }
36
+
37
+ run_hook() {
38
+ local input="$1"
39
+ local extra_env="${2:-}"
40
+ if [ -n "$extra_env" ]; then
41
+ env $extra_env bash "$HOOK" <<< "$input" 2>&1
42
+ else
43
+ printf '%s' "$input" | bash "$HOOK" 2>&1
44
+ fi
45
+ }
46
+
47
+ echo "=== refusal-arrest-gate.sh tests ==="
48
+
49
+ # --- Test 1: refusal + matching Edit target → blocks ---
50
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/src/config.json"}' \
51
+ "I will not modify config.json — the operator already finalized it.")
52
+ output=$(run_hook "$INPUT")
53
+ rc=$?
54
+ if [ "$rc" -eq 2 ] && echo "$output" | grep -q "REFUSAL-SIDE ARREST"; then
55
+ assert_pass "refusal + matching Edit target → exit 2 with feedback"
56
+ else
57
+ assert_fail "expected exit 2 + feedback, got rc=$rc output=$output"
58
+ fi
59
+
60
+ # --- Test 2: refusal + non-matching Edit target → silent pass ---
61
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/src/other.json"}' \
62
+ "I will not modify config.json — the operator already finalized it.")
63
+ output=$(run_hook "$INPUT")
64
+ rc=$?
65
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
66
+ assert_pass "refusal + non-matching target → silent pass"
67
+ else
68
+ assert_fail "expected silent exit 0, got rc=$rc output=$output"
69
+ fi
70
+
71
+ # --- Test 3: no refusal → silent pass ---
72
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/src/config.json"}' \
73
+ "Updating config.json with the new endpoint.")
74
+ output=$(run_hook "$INPUT")
75
+ rc=$?
76
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
77
+ assert_pass "no refusal in prose → silent pass"
78
+ else
79
+ assert_fail "expected silent exit 0, got rc=$rc output=$output"
80
+ fi
81
+
82
+ # --- Test 4: "I won't" variant + matching target → blocks ---
83
+ INPUT=$(make_input "Write" '{"file_path":"/repo/migrations/0042.sql"}' \
84
+ "I won't modify migrations until the lock is released.")
85
+ output=$(run_hook "$INPUT")
86
+ rc=$?
87
+ if [ "$rc" -eq 2 ]; then
88
+ assert_pass "I won't variant triggers refusal arrest"
89
+ else
90
+ assert_fail "expected exit 2, got rc=$rc output=$output"
91
+ fi
92
+
93
+ # --- Test 5: "I'll skip" variant + matching target → blocks ---
94
+ INPUT=$(make_input "Bash" '{"command":"pytest tests/integration/"}' \
95
+ "I'll skip integration since unit tests cover this path.")
96
+ output=$(run_hook "$INPUT")
97
+ rc=$?
98
+ if [ "$rc" -eq 2 ]; then
99
+ assert_pass "I'll skip variant triggers on Bash command"
100
+ else
101
+ assert_fail "expected exit 2, got rc=$rc output=$output"
102
+ fi
103
+
104
+ # --- Test 6: "I'll preserve" variant + matching target → blocks ---
105
+ INPUT=$(make_input "Write" '{"file_path":"/repo/data/customers.csv"}' \
106
+ "I'll preserve customers.csv as-is and write to a new file.")
107
+ output=$(run_hook "$INPUT")
108
+ rc=$?
109
+ if [ "$rc" -eq 2 ]; then
110
+ assert_pass "I'll preserve variant triggers when contradicted"
111
+ else
112
+ assert_fail "expected exit 2, got rc=$rc output=$output"
113
+ fi
114
+
115
+ # --- Test 7: "let me not" variant ---
116
+ INPUT=$(make_input "Edit" '{"file_path":"/etc/hosts"}' \
117
+ "Let me not touch hosts file — the operator owns DNS.")
118
+ output=$(run_hook "$INPUT")
119
+ rc=$?
120
+ if [ "$rc" -eq 2 ]; then
121
+ assert_pass "let me not variant triggers"
122
+ else
123
+ assert_fail "expected exit 2, got rc=$rc output=$output"
124
+ fi
125
+
126
+ # --- Test 8: refusal inside <user_prompt> tag → silent pass ---
127
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/src/config.json"}' \
128
+ "The user wrote: <user_prompt>I will not modify config.json</user_prompt> — I am now updating per the new request.")
129
+ output=$(run_hook "$INPUT")
130
+ rc=$?
131
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
132
+ assert_pass "refusal inside user_prompt tag → silent pass"
133
+ else
134
+ assert_fail "expected silent exit 0 (user-quote ignored), got rc=$rc output=$output"
135
+ fi
136
+
137
+ # --- Test 9: refusal in markdown blockquote → silent pass ---
138
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/src/config.json"}' \
139
+ "User said:
140
+ > I will not modify config.json without review
141
+ Proceeding with the requested change.")
142
+ output=$(run_hook "$INPUT")
143
+ rc=$?
144
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
145
+ assert_pass "refusal in markdown blockquote → silent pass"
146
+ else
147
+ assert_fail "expected silent exit 0 (blockquote ignored), got rc=$rc output=$output"
148
+ fi
149
+
150
+ # --- Test 10: disable flag respected ---
151
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/src/config.json"}' \
152
+ "I will not modify config.json.")
153
+ output=$(CC_REFUSAL_GATE_DISABLE=1 bash "$HOOK" <<< "$INPUT" 2>&1)
154
+ rc=$?
155
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
156
+ assert_pass "CC_REFUSAL_GATE_DISABLE=1 silences the gate"
157
+ else
158
+ assert_fail "expected silent disable, got rc=$rc output=$output"
159
+ fi
160
+
161
+ # --- Test 11: empty input → silent ---
162
+ output=$(printf '' | bash "$HOOK" 2>&1)
163
+ rc=$?
164
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
165
+ assert_pass "empty input → silent no-op"
166
+ else
167
+ assert_fail "expected silent exit 0, got rc=$rc output=$output"
168
+ fi
169
+
170
+ # --- Test 12: missing tool_name → silent ---
171
+ INPUT=$(jq -nc '{tool_input: {file_path: "/repo/src/config.json"}, last_assistant_message: "I will not modify config.json."}')
172
+ output=$(run_hook "$INPUT")
173
+ rc=$?
174
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
175
+ assert_pass "missing tool_name → silent pass"
176
+ else
177
+ assert_fail "expected silent exit 0, got rc=$rc output=$output"
178
+ fi
179
+
180
+ # --- Test 13: unknown tool type (WebFetch) → silent ---
181
+ INPUT=$(make_input "WebFetch" '{"url":"https://example.com"}' \
182
+ "I will not fetch example.com.")
183
+ output=$(run_hook "$INPUT")
184
+ rc=$?
185
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
186
+ assert_pass "non-instrumented tool (WebFetch) → silent pass"
187
+ else
188
+ assert_fail "expected silent exit 0, got rc=$rc output=$output"
189
+ fi
190
+
191
+ # --- Test 14: refusal with basename match (no path in refusal) → blocks ---
192
+ INPUT=$(make_input "Edit" '{"file_path":"/very/deep/nested/path/secrets.env"}' \
193
+ "I will not modify secrets.env — credentials are operator-managed.")
194
+ output=$(run_hook "$INPUT")
195
+ rc=$?
196
+ if [ "$rc" -eq 2 ]; then
197
+ assert_pass "basename match on deep path → blocks"
198
+ else
199
+ assert_fail "expected exit 2 (basename match), got rc=$rc output=$output"
200
+ fi
201
+
202
+ # --- Test 15: short target word filter (≤2 chars) → no match ---
203
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/x.txt"}' \
204
+ "I will not modify x — it is a test fixture.")
205
+ output=$(run_hook "$INPUT")
206
+ rc=$?
207
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
208
+ assert_pass "short target (≤2 chars) does not trigger (false-positive guard)"
209
+ else
210
+ assert_fail "expected silent exit 0 (length threshold), got rc=$rc output=$output"
211
+ fi
212
+
213
+ # --- Test 16: refusal target appears in Bash command → blocks ---
214
+ INPUT=$(make_input "Bash" '{"command":"rm -rf node_modules/"}' \
215
+ "I will not delete node_modules — the operator just ran npm install.")
216
+ output=$(run_hook "$INPUT")
217
+ rc=$?
218
+ if [ "$rc" -eq 2 ]; then
219
+ assert_pass "Bash command containing refusal target → blocks"
220
+ else
221
+ assert_fail "expected exit 2 (Bash target match), got rc=$rc output=$output"
222
+ fi
223
+
224
+ # --- Test 17: Bash command not matching refusal target → silent pass ---
225
+ INPUT=$(make_input "Bash" '{"command":"ls -la"}' \
226
+ "I will not delete node_modules.")
227
+ output=$(run_hook "$INPUT")
228
+ rc=$?
229
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
230
+ assert_pass "Bash command not matching refusal target → silent pass"
231
+ else
232
+ assert_fail "expected silent exit 0, got rc=$rc output=$output"
233
+ fi
234
+
235
+ # --- Test 18: missing assistant text → silent pass ---
236
+ INPUT=$(jq -nc '{tool_name: "Edit", tool_input: {file_path: "/repo/src/config.json"}}')
237
+ output=$(run_hook "$INPUT")
238
+ rc=$?
239
+ if [ "$rc" -eq 0 ] && [ -z "$output" ]; then
240
+ assert_pass "missing assistant text → silent pass (no false positive)"
241
+ else
242
+ assert_fail "expected silent exit 0, got rc=$rc output=$output"
243
+ fi
244
+
245
+ # --- Test 19: custom CC_REFUSAL_PATTERNS does not crash ---
246
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/src/config.json"}' \
247
+ "yapmayacağım config.json üzerinde değişiklik.")
248
+ output=$(CC_REFUSAL_PATTERNS='yapmayacağım [a-zA-Z0-9_./@\-]+' bash "$HOOK" <<< "$INPUT" 2>&1)
249
+ rc=$?
250
+ if [ "$rc" -eq 0 ] || [ "$rc" -eq 2 ]; then
251
+ assert_pass "custom CC_REFUSAL_PATTERNS does not crash hook"
252
+ else
253
+ assert_fail "custom pattern caused crash rc=$rc output=$output"
254
+ fi
255
+
256
+ # --- Test 20: feedback message cites #60506 / #60475 ---
257
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/src/config.json"}' \
258
+ "I will not modify config.json under any circumstance.")
259
+ output=$(run_hook "$INPUT")
260
+ if echo "$output" | grep -q "60506" && echo "$output" | grep -q "60475"; then
261
+ assert_pass "feedback message cites both #60506 and #60475"
262
+ else
263
+ assert_fail "expected references to #60506 and #60475 in feedback"
264
+ fi
265
+
266
+ # --- Test 21: feedback message names the disable escape ---
267
+ INPUT=$(make_input "Edit" '{"file_path":"/repo/src/config.json"}' \
268
+ "I will not modify config.json.")
269
+ output=$(run_hook "$INPUT")
270
+ if echo "$output" | grep -q "CC_REFUSAL_GATE_DISABLE=1"; then
271
+ assert_pass "feedback message names the disable escape"
272
+ else
273
+ assert_fail "expected CC_REFUSAL_GATE_DISABLE=1 mention in feedback"
274
+ fi
275
+
276
+ # --- Test 22: transcript with a raw control-char line still detects the refusal ---
277
+ # Regression for the jq-slurp failure (anthropics/claude-code#68665): a single
278
+ # transcript line carrying a raw U+0001 (e.g. a large tool-output block) used to
279
+ # make `jq -rs` fail over the whole window, emptying ASSISTANT_TEXT and failing
280
+ # the gate open. Per-line `fromjson?` parsing must skip the bad line and still
281
+ # surface the most-recent assistant refusal from the transcript_path branch.
282
+ TRANSCRIPT=$(mktemp)
283
+ {
284
+ printf '%s\n' '{"message":{"role":"user","content":"please finalize config.json"}}'
285
+ # bad line: raw control char inside a JSON string (strictly invalid JSON)
286
+ printf '{"message":{"role":"assistant","content":[{"type":"text","text":"big tool dump \x01 raw"}]}}\n'
287
+ # most-recent assistant message: an explicit refusal
288
+ printf '%s\n' '{"message":{"role":"assistant","content":[{"type":"text","text":"I will not modify config.json — operator finalized it."}]}}'
289
+ } > "$TRANSCRIPT"
290
+ INPUT=$(jq -nc --arg tp "$TRANSCRIPT" \
291
+ '{tool_name:"Edit", tool_input:{file_path:"/repo/src/config.json"}, transcript_path:$tp}')
292
+ output=$(printf '%s' "$INPUT" | bash "$HOOK" 2>&1)
293
+ rc=$?
294
+ if [ "$rc" -eq 2 ] && echo "$output" | grep -q "REFUSAL-SIDE ARREST"; then
295
+ assert_pass "control-char transcript line → gate still fires (no fail-open)"
296
+ else
297
+ assert_fail "expected exit 2 despite control-char line, got rc=$rc output=$output"
298
+ fi
299
+ rm -f "$TRANSCRIPT"
300
+
301
+ echo ""
302
+ echo "=== Results: $PASS passed, $FAIL failed ==="
303
+ [ "$FAIL" -eq 0 ] || exit 1
@@ -0,0 +1,125 @@
1
+ #!/bin/bash
2
+ # Tests for remote-control-billing-classifier.sh
3
+ HOOK="examples/remote-control-billing-classifier.sh"
4
+ PASS=0 FAIL=0
5
+
6
+ assert_contains() { if echo "$2" | grep -q "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected '$3')"; fi; }
7
+ assert_not_contains() { if ! echo "$2" | grep -q "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (unexpected '$3')"; fi; }
8
+ assert_exit() { if [ "$2" = "$3" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected exit $3, got $2)"; fi; }
9
+
10
+ HOOK_ABS="$PWD/$HOOK"
11
+
12
+ # Test 1: No remote-control ancestor (override empty) → silent pass
13
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="bash,login -p,init" \
14
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
15
+ assert_not_contains "no remote-control no warning" "$OUT" "remote-control"
16
+ assert_exit "no remote-control exit 0" "$RC" "0"
17
+
18
+ # Test 2: remote-control in ancestor cmdline → advisory + exit 0
19
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="bash,/home/user/.local/bin/claude remote-control,init" \
20
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
21
+ assert_contains "remote-control triggers advisory" "$OUT" "remote-control"
22
+ assert_contains "advisory names Pool 2" "$OUT" "Pool 2"
23
+ assert_contains "advisory cites issue" "$OUT" "#59823"
24
+ assert_contains "advisory cites June 15" "$OUT" "2026-06-15"
25
+ assert_exit "advisory does not block (exit 0)" "$RC" "0"
26
+
27
+ # Test 3: Disable env var skips even when remote-control is present
28
+ OUT=$(CC_REMOTE_CONTROL_DISABLE=1 \
29
+ CC_REMOTE_CONTROL_PROCESS_OVERRIDE="claude remote-control" \
30
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
31
+ assert_not_contains "disable suppresses advisory" "$OUT" "remote-control"
32
+ assert_exit "disable exit 0" "$RC" "0"
33
+
34
+ # Test 4: Pattern override matches custom string
35
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="my-automation-runner --headless" \
36
+ CC_REMOTE_CONTROL_PATTERN="my-automation-runner" \
37
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
38
+ assert_contains "custom pattern triggers advisory" "$OUT" "remote-control"
39
+ assert_exit "custom pattern exit 0" "$RC" "0"
40
+
41
+ # Test 5: Pattern does not match arbitrary "remote" string
42
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="git remote update,bash" \
43
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
44
+ assert_not_contains "git remote does not trigger" "$OUT" "remote-control"
45
+ assert_exit "git remote exit 0" "$RC" "0"
46
+
47
+ # Test 6: Advisory includes the two pre-June-15 audits
48
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="claude remote-control" \
49
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
50
+ assert_contains "advisory names ps audit" "$OUT" "pgrep"
51
+ assert_contains "advisory names opt-in audit" "$OUT" "opt-in"
52
+
53
+ # Test 7: Hook reads and ignores stdin payload (does not hang)
54
+ PAYLOAD='{"hook_event_name":"SessionStart","session_id":"abc"}'
55
+ OUT=$(echo "$PAYLOAD" | \
56
+ CC_REMOTE_CONTROL_PROCESS_OVERRIDE="claude remote-control" \
57
+ bash "$HOOK_ABS" 2>&1); RC=$?
58
+ assert_contains "stdin consumed without breakage" "$OUT" "Pool 2"
59
+ assert_exit "stdin path exit 0" "$RC" "0"
60
+
61
+ # Test 8: Empty override and no live remote-control → silent pass
62
+ # (live ps may or may not find remote-control on the test host; we
63
+ # only assert that an explicitly-empty override yields no advisory.)
64
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="bash" \
65
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
66
+ assert_not_contains "empty override no advisory" "$OUT" "remote-control"
67
+ assert_exit "empty override exit 0" "$RC" "0"
68
+
69
+ # Test 9: Multiple ancestors, only one matches → advisory
70
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="bash,sshd,claude remote-control --port 9999,init" \
71
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
72
+ assert_contains "matching ancestor triggers advisory" "$OUT" "Pool 2"
73
+ assert_exit "multi-ancestor exit 0" "$RC" "0"
74
+
75
+ # Test 10: Disable still consumes stdin (no broken pipe)
76
+ PAYLOAD='{"hook_event_name":"SessionStart"}'
77
+ OUT=$(echo "$PAYLOAD" | \
78
+ CC_REMOTE_CONTROL_DISABLE=1 \
79
+ CC_REMOTE_CONTROL_PROCESS_OVERRIDE="claude remote-control" \
80
+ bash "$HOOK_ABS" 2>&1); RC=$?
81
+ assert_not_contains "disable with stdin no output" "$OUT" "Pool 2"
82
+ assert_exit "disable with stdin exit 0" "$RC" "0"
83
+
84
+ # Test 11: Pattern is anchored substring (not full regex by default)
85
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="something-claude remote-control-something,bash" \
86
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
87
+ assert_contains "substring match triggers" "$OUT" "Pool 2"
88
+ assert_exit "substring match exit 0" "$RC" "0"
89
+
90
+ # Test 12: Advisory mentions cc-safe-setup setup hint indirectly
91
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="claude remote-control" \
92
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
93
+ assert_contains "advisory points at silence path" "$OUT" "CC_REMOTE_CONTROL_DISABLE"
94
+
95
+ # Test 13: Live ps path runs without error when override is unset
96
+ unset CC_REMOTE_CONTROL_PROCESS_OVERRIDE
97
+ OUT=$(bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
98
+ # Cannot assert advisory content (host-dependent); only that exit is 0.
99
+ assert_exit "live ps path exit 0" "$RC" "0"
100
+
101
+ # Test 14: Forest-style ancestor (real-shape) triggers advisory
102
+ ANCESTOR="bash,/home/user/.local/bin/claude remote-control,/home/user/.local/share/claude/versions/2.1.143 --print --sdk-url https://api.anthropic.com/v1/code/sessions/abc --session-id xyz"
103
+ OUT=$(CC_REMOTE_CONTROL_PROCESS_OVERRIDE="$ANCESTOR" \
104
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
105
+ assert_contains "real-shape ancestor triggers" "$OUT" "Pool 2"
106
+ assert_contains "real-shape advisory cites #59823" "$OUT" "#59823"
107
+ assert_exit "real-shape exit 0" "$RC" "0"
108
+
109
+ # Test 15: Disable env wins over presence
110
+ OUT=$(CC_REMOTE_CONTROL_DISABLE=1 \
111
+ CC_REMOTE_CONTROL_PROCESS_OVERRIDE="$ANCESTOR" \
112
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
113
+ assert_not_contains "disable over presence" "$OUT" "Pool 2"
114
+ assert_exit "disable over presence exit 0" "$RC" "0"
115
+
116
+ # Test 16: Pattern override + disable still silent
117
+ OUT=$(CC_REMOTE_CONTROL_DISABLE=1 \
118
+ CC_REMOTE_CONTROL_PATTERN="x-runner" \
119
+ CC_REMOTE_CONTROL_PROCESS_OVERRIDE="x-runner" \
120
+ bash "$HOOK_ABS" </dev/null 2>&1); RC=$?
121
+ assert_not_contains "disable beats custom pattern" "$OUT" "Pool 2"
122
+ assert_exit "disable beats custom pattern exit 0" "$RC" "0"
123
+
124
+ echo "Results: $PASS passed, $FAIL failed"
125
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,65 @@
1
+ #!/bin/bash
2
+ # Tests for resume-drift-watcher.sh
3
+ HOOK="examples/resume-drift-watcher.sh"
4
+ PASS=0 FAIL=0
5
+
6
+ assert_contains() { if echo "$2" | grep -q "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected '$3' in: $2)"; fi; }
7
+ assert_not_contains() { if ! echo "$2" | grep -q "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (unexpected '$3' in: $2)"; fi; }
8
+ assert_exit() { if [ "$2" -eq "$3" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (exit $2, expected $3)"; fi; }
9
+
10
+ LOG="${HOME}/.claude/logs/resume-drift.log"
11
+ mkdir -p "${HOME}/.claude/logs"
12
+ : > "$LOG"
13
+
14
+ # Test 1: No transcript — exit 0, no log line
15
+ OUT=$(printf '{"session_id":"s1","tool_name":"X"}' | bash "$HOOK" 2>&1)
16
+ RC=$?
17
+ assert_exit "no transcript exits 0" "$RC" 0
18
+
19
+ # Test 2: Healthy fresh session — first message large, no warning
20
+ TRANS=$(mktemp)
21
+ {
22
+ printf '{"role":"user","content":"This is a reasonably sized first message with enough bytes to be well above 500. Adding filler: %s"}\n' "$(printf 'x%.0s' {1..600})"
23
+ printf '{"role":"assistant","content":"reply"}\n'
24
+ printf '{"role":"user","content":"follow up"}\n'
25
+ printf '{"role":"assistant","content":"reply 2"}\n'
26
+ printf '{"role":"user","content":"turn 3"}\n'
27
+ printf '{"role":"assistant","content":"reply 3"}\n'
28
+ } >> "$TRANS"
29
+ : > "$LOG"
30
+ OUT=$(printf '{"session_id":"healthy","transcript_path":"%s"}' "$TRANS" | bash "$HOOK" 2>&1)
31
+ assert_not_contains "healthy session no warning" "$OUT" "resume-drift signal"
32
+ if grep -q "healthy" "$LOG"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: healthy session should log"; fi
33
+ rm -f "$TRANS"
34
+
35
+ # Test 3: Drift signal — tiny first message + large total + >4 turns
36
+ TRANS=$(mktemp)
37
+ printf '{"role":"user","content":"tiny"}\n' >> "$TRANS" # <500 bytes
38
+ # Pad total size above 50KB using large assistant messages
39
+ for i in 1 2 3 4 5; do
40
+ printf '{"role":"assistant","content":"%s"}\n' "$(printf 'A%.0s' {1..12000})" >> "$TRANS"
41
+ printf '{"role":"user","content":"t%d"}\n' "$i" >> "$TRANS"
42
+ done
43
+ : > "$LOG"
44
+ OUT=$(printf '{"session_id":"drifted","transcript_path":"%s"}' "$TRANS" | bash "$HOOK" 2>&1)
45
+ assert_contains "drift emits warning" "$OUT" "resume-drift signal"
46
+ assert_contains "warning references issue" "$OUT" "#43278"
47
+ rm -f "$TRANS"
48
+
49
+ # Test 4: Under turn-count threshold — no warning even if first small
50
+ TRANS=$(mktemp)
51
+ printf '{"role":"user","content":"tiny"}\n' >> "$TRANS"
52
+ printf '{"role":"assistant","content":"%s"}\n' "$(printf 'A%.0s' {1..60000})" >> "$TRANS"
53
+ : > "$LOG"
54
+ OUT=$(printf '{"session_id":"early","transcript_path":"%s"}' "$TRANS" | bash "$HOOK" 2>&1)
55
+ assert_not_contains "early turns no warning" "$OUT" "resume-drift signal"
56
+ rm -f "$TRANS"
57
+
58
+ # Test 5: TSV format — 5 fields
59
+ if [ -s "$LOG" ]; then
60
+ FIELDS=$(awk -F'\t' '{print NF}' "$LOG" | head -1)
61
+ if [ "$FIELDS" = "5" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: expected 5 TSV fields, got $FIELDS"; fi
62
+ fi
63
+
64
+ echo "PASS: $PASS FAIL: $FAIL"
65
+ [ "$FAIL" -eq 0 ]