cc-safe-setup 29.8.0 → 30.0.4

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