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,242 @@
1
+ #!/bin/bash
2
+ # Tests for skills-settings-validator.sh
3
+ # Hook addresses issue #62421 (fabricated Skills-related settings fields).
4
+ set -u
5
+
6
+ HOOK="$(dirname "$0")/../examples/skills-settings-validator.sh"
7
+ PASS=0
8
+ FAIL=0
9
+
10
+ TMP=$(mktemp -d /tmp/test-skills-validator.XXXXXX)
11
+ trap 'rm -rf "$TMP"' EXIT
12
+
13
+ # --- Test 1: no settings files produce no output ---
14
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/missing.json" bash "$HOOK")
15
+ if [ -z "$output" ]; then
16
+ echo " PASS: missing settings file produces no output"
17
+ PASS=$((PASS + 1))
18
+ else
19
+ echo " FAIL: missing file should produce no output: $output"
20
+ FAIL=$((FAIL + 1))
21
+ fi
22
+
23
+ # --- Test 2: empty JSON produces no output ---
24
+ echo '{}' > "$TMP/empty.json"
25
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/empty.json" bash "$HOOK")
26
+ if [ -z "$output" ]; then
27
+ echo " PASS: empty JSON produces no output"
28
+ PASS=$((PASS + 1))
29
+ else
30
+ echo " FAIL: empty JSON should produce no output: $output"
31
+ FAIL=$((FAIL + 1))
32
+ fi
33
+
34
+ # --- Test 3: valid schema fields produce no output ---
35
+ cat > "$TMP/valid.json" <<'EOF'
36
+ {
37
+ "permissions": {"allow": [], "deny": []},
38
+ "env": {"FOO": "bar"},
39
+ "hooks": {}
40
+ }
41
+ EOF
42
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/valid.json" bash "$HOOK")
43
+ if [ -z "$output" ]; then
44
+ echo " PASS: valid schema fields produce no output"
45
+ PASS=$((PASS + 1))
46
+ else
47
+ echo " FAIL: valid fields should produce no output: $output"
48
+ FAIL=$((FAIL + 1))
49
+ fi
50
+
51
+ # --- Test 4: disabledSkills (canonical fabrication) detected ---
52
+ cat > "$TMP/fab1.json" <<'EOF'
53
+ {
54
+ "permissions": {"allow": []},
55
+ "disabledSkills": ["mcp-builder", "pdf"]
56
+ }
57
+ EOF
58
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/fab1.json" bash "$HOOK")
59
+ if echo "$output" | grep -q "disabledSkills"; then
60
+ echo " PASS: disabledSkills is flagged"
61
+ PASS=$((PASS + 1))
62
+ else
63
+ echo " FAIL: disabledSkills should be flagged. Output: $output"
64
+ FAIL=$((FAIL + 1))
65
+ fi
66
+
67
+ # --- Test 5: output is valid JSON ---
68
+ if echo "$output" | jq empty 2>/dev/null; then
69
+ echo " PASS: output is valid JSON"
70
+ PASS=$((PASS + 1))
71
+ else
72
+ echo " FAIL: output is not valid JSON: $output"
73
+ FAIL=$((FAIL + 1))
74
+ fi
75
+
76
+ # --- Test 6: output references issue #62421 ---
77
+ if echo "$output" | grep -q "62421"; then
78
+ echo " PASS: output references issue #62421"
79
+ PASS=$((PASS + 1))
80
+ else
81
+ echo " FAIL: output should reference issue #62421"
82
+ FAIL=$((FAIL + 1))
83
+ fi
84
+
85
+ # --- Test 7: output has hookSpecificOutput.additionalContext ---
86
+ context=$(echo "$output" | jq -r '.hookSpecificOutput.additionalContext // empty' 2>/dev/null)
87
+ if [ -n "$context" ]; then
88
+ echo " PASS: output has hookSpecificOutput.additionalContext"
89
+ PASS=$((PASS + 1))
90
+ else
91
+ echo " FAIL: output missing hookSpecificOutput.additionalContext"
92
+ FAIL=$((FAIL + 1))
93
+ fi
94
+
95
+ # --- Test 8: enabledSkills also detected ---
96
+ cat > "$TMP/fab2.json" <<'EOF'
97
+ {"enabledSkills": ["only-this-one"]}
98
+ EOF
99
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/fab2.json" bash "$HOOK")
100
+ if echo "$output" | grep -q "enabledSkills"; then
101
+ echo " PASS: enabledSkills is flagged"
102
+ PASS=$((PASS + 1))
103
+ else
104
+ echo " FAIL: enabledSkills should be flagged"
105
+ FAIL=$((FAIL + 1))
106
+ fi
107
+
108
+ # --- Test 9: skillsConfig also detected ---
109
+ cat > "$TMP/fab3.json" <<'EOF'
110
+ {"skillsConfig": {"defaultEnabled": false}}
111
+ EOF
112
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/fab3.json" bash "$HOOK")
113
+ if echo "$output" | grep -q "skillsConfig"; then
114
+ echo " PASS: skillsConfig is flagged"
115
+ PASS=$((PASS + 1))
116
+ else
117
+ echo " FAIL: skillsConfig should be flagged"
118
+ FAIL=$((FAIL + 1))
119
+ fi
120
+
121
+ # --- Test 10: multiple fabricated fields all detected ---
122
+ cat > "$TMP/fab4.json" <<'EOF'
123
+ {
124
+ "disabledSkills": [],
125
+ "enabledSkills": [],
126
+ "skillRouting": {}
127
+ }
128
+ EOF
129
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/fab4.json" bash "$HOOK")
130
+ if echo "$output" | grep -q "disabledSkills" && \
131
+ echo "$output" | grep -q "enabledSkills" && \
132
+ echo "$output" | grep -q "skillRouting"; then
133
+ echo " PASS: multiple fabricated fields all flagged"
134
+ PASS=$((PASS + 1))
135
+ else
136
+ echo " FAIL: not all fabricated fields flagged. Output: $output"
137
+ FAIL=$((FAIL + 1))
138
+ fi
139
+
140
+ # --- Test 11: multiple files scanned ---
141
+ cat > "$TMP/fab5a.json" <<'EOF'
142
+ {"disabledSkills": []}
143
+ EOF
144
+ cat > "$TMP/fab5b.json" <<'EOF'
145
+ {"skillFilter": ""}
146
+ EOF
147
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/fab5a.json:$TMP/fab5b.json" bash "$HOOK")
148
+ if echo "$output" | grep -q "disabledSkills" && \
149
+ echo "$output" | grep -q "skillFilter"; then
150
+ echo " PASS: multiple files all scanned"
151
+ PASS=$((PASS + 1))
152
+ else
153
+ echo " FAIL: multiple files not all scanned. Output: $output"
154
+ FAIL=$((FAIL + 1))
155
+ fi
156
+
157
+ # --- Test 12: file path included in findings ---
158
+ if echo "$output" | grep -q "fab5a.json" && \
159
+ echo "$output" | grep -q "fab5b.json"; then
160
+ echo " PASS: file path included in findings"
161
+ PASS=$((PASS + 1))
162
+ else
163
+ echo " FAIL: file path missing from findings"
164
+ FAIL=$((FAIL + 1))
165
+ fi
166
+
167
+ # --- Test 13: invalid JSON file silently skipped ---
168
+ echo "not valid json" > "$TMP/broken.json"
169
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/broken.json" bash "$HOOK")
170
+ if [ -z "$output" ]; then
171
+ echo " PASS: invalid JSON silently skipped"
172
+ PASS=$((PASS + 1))
173
+ else
174
+ echo " FAIL: invalid JSON should be silently skipped: $output"
175
+ FAIL=$((FAIL + 1))
176
+ fi
177
+
178
+ # --- Test 14: invalid + valid mix only flags the valid ---
179
+ cat > "$TMP/fab6.json" <<'EOF'
180
+ {"disabledSkills": []}
181
+ EOF
182
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/broken.json:$TMP/fab6.json" bash "$HOOK")
183
+ if echo "$output" | grep -q "fab6.json: disabledSkills" && \
184
+ ! echo "$output" | grep -q "broken.json"; then
185
+ echo " PASS: invalid skipped, valid flagged"
186
+ PASS=$((PASS + 1))
187
+ else
188
+ echo " FAIL: mix handling incorrect. Output: $output"
189
+ FAIL=$((FAIL + 1))
190
+ fi
191
+
192
+ # --- Test 15: extra patterns via env var detected ---
193
+ cat > "$TMP/fab7.json" <<'EOF'
194
+ {"customSkillField": "x"}
195
+ EOF
196
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/fab7.json" CC_SKILLS_EXTRA_PATTERNS="customSkillField" bash "$HOOK")
197
+ if echo "$output" | grep -q "customSkillField"; then
198
+ echo " PASS: extra pattern via env var detected"
199
+ PASS=$((PASS + 1))
200
+ else
201
+ echo " FAIL: extra pattern not detected. Output: $output"
202
+ FAIL=$((FAIL + 1))
203
+ fi
204
+
205
+ # --- Test 16: extra patterns coexist with defaults ---
206
+ cat > "$TMP/fab8.json" <<'EOF'
207
+ {"disabledSkills": [], "myCustomField": "y"}
208
+ EOF
209
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/fab8.json" CC_SKILLS_EXTRA_PATTERNS="myCustomField" bash "$HOOK")
210
+ if echo "$output" | grep -q "disabledSkills" && \
211
+ echo "$output" | grep -q "myCustomField"; then
212
+ echo " PASS: extra patterns coexist with defaults"
213
+ PASS=$((PASS + 1))
214
+ else
215
+ echo " FAIL: extra+default coexist failed. Output: $output"
216
+ FAIL=$((FAIL + 1))
217
+ fi
218
+
219
+ # --- Test 17: nested non-top-level skills key not flagged ---
220
+ cat > "$TMP/nested.json" <<'EOF'
221
+ {
222
+ "permissions": {
223
+ "allow": ["Skill(foo)"],
224
+ "deny": []
225
+ },
226
+ "env": {"disabledSkills_unused": "1"}
227
+ }
228
+ EOF
229
+ output=$(echo '{}' | CC_SKILLS_SETTINGS_FILES="$TMP/nested.json" bash "$HOOK")
230
+ if [ -z "$output" ]; then
231
+ echo " PASS: nested skills mentions are not flagged"
232
+ PASS=$((PASS + 1))
233
+ else
234
+ echo " FAIL: nested skills mentions should not be flagged: $output"
235
+ FAIL=$((FAIL + 1))
236
+ fi
237
+
238
+ # --- Summary ---
239
+ echo ""
240
+ echo "Tests passed: $PASS"
241
+ echo "Tests failed: $FAIL"
242
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,150 @@
1
+ #!/bin/bash
2
+ # Tests for sonnet-45-deprecation-helper.sh
3
+ HOOK="$(dirname "$0")/../examples/sonnet-45-deprecation-helper.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
+ echo "Testing sonnet-45-deprecation-helper.sh"
20
+ echo "========================================"
21
+
22
+ # Test 1: QUIET=1 always silences, regardless of other state
23
+ OUT=$(CC_SONNET_45_HELPER_QUIET=1 CC_SONNET_45_HELPER_REMIND=1 \
24
+ bash "$HOOK" 2>&1)
25
+ EXIT=$?
26
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
27
+ run_test "QUIET=1 silences even with REMIND=1" pass
28
+ else
29
+ run_test "QUIET=1 silences even with REMIND=1 (exit=$EXIT, out_len=${#OUT})" fail
30
+ fi
31
+
32
+ # Test 2: ANTHROPIC_MODEL explicitly set to 4.5 → silent
33
+ OUT=$(unset CC_SONNET_45_HELPER_REMIND CC_SONNET_45_HELPER_QUIET; \
34
+ ANTHROPIC_MODEL=claude-sonnet-4-5-20250929 bash "$HOOK" 2>&1)
35
+ EXIT=$?
36
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
37
+ run_test "ANTHROPIC_MODEL=4.5 silences" pass
38
+ else
39
+ run_test "ANTHROPIC_MODEL=4.5 silences (exit=$EXIT, out_len=${#OUT})" fail
40
+ fi
41
+
42
+ # Test 3: ANTHROPIC_MODEL explicitly set to 4.6 → silent
43
+ OUT=$(unset CC_SONNET_45_HELPER_REMIND CC_SONNET_45_HELPER_QUIET; \
44
+ ANTHROPIC_MODEL=claude-sonnet-4-6 bash "$HOOK" 2>&1)
45
+ EXIT=$?
46
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
47
+ run_test "ANTHROPIC_MODEL=4.6 silences" pass
48
+ else
49
+ run_test "ANTHROPIC_MODEL=4.6 silences (exit=$EXIT, out_len=${#OUT})" fail
50
+ fi
51
+
52
+ # Test 4: ANTHROPIC_MODEL set to any non-empty value → silent (treated as deliberate)
53
+ OUT=$(unset CC_SONNET_45_HELPER_REMIND CC_SONNET_45_HELPER_QUIET; \
54
+ ANTHROPIC_MODEL=claude-opus-4-7 bash "$HOOK" 2>&1)
55
+ EXIT=$?
56
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
57
+ run_test "ANTHROPIC_MODEL=opus silences (any non-empty value)" pass
58
+ else
59
+ run_test "ANTHROPIC_MODEL=opus silences (exit=$EXIT, out_len=${#OUT})" fail
60
+ fi
61
+
62
+ # Test 5: ANTHROPIC_MODEL unset and REMIND unset → silent (opt-in only, default off)
63
+ OUT=$(unset ANTHROPIC_MODEL CC_SONNET_45_HELPER_REMIND CC_SONNET_45_HELPER_QUIET; \
64
+ bash "$HOOK" 2>&1)
65
+ EXIT=$?
66
+ if [ "$EXIT" = "0" ] && [ -z "$OUT" ]; then
67
+ run_test "ANTHROPIC_MODEL unset, REMIND unset → silent (opt-in default)" pass
68
+ else
69
+ run_test "ANTHROPIC_MODEL unset, REMIND unset → silent (exit=$EXIT, out_len=${#OUT})" fail
70
+ fi
71
+
72
+ # Test 6: ANTHROPIC_MODEL unset and REMIND=1 → emit reminder
73
+ OUT=$(unset ANTHROPIC_MODEL CC_SONNET_45_HELPER_QUIET; \
74
+ CC_SONNET_45_HELPER_REMIND=1 bash "$HOOK" 2>&1)
75
+ EXIT=$?
76
+ if [ "$EXIT" = "0" ] && echo "$OUT" | grep -q "ANTHROPIC_MODEL is unset"; then
77
+ run_test "ANTHROPIC_MODEL unset, REMIND=1 → reminder emitted" pass
78
+ else
79
+ run_test "ANTHROPIC_MODEL unset, REMIND=1 → reminder emitted (exit=$EXIT, out=$OUT)" fail
80
+ fi
81
+
82
+ # Test 7: Reminder includes the 4.5 model ID
83
+ OUT=$(unset ANTHROPIC_MODEL CC_SONNET_45_HELPER_QUIET; \
84
+ CC_SONNET_45_HELPER_REMIND=1 bash "$HOOK" 2>&1)
85
+ if echo "$OUT" | grep -q "claude-sonnet-4-5-20250929"; then
86
+ run_test "Reminder contains the 4.5 model ID for explicit pinning" pass
87
+ else
88
+ run_test "Reminder contains the 4.5 model ID" fail
89
+ fi
90
+
91
+ # Test 8: Reminder mentions the QUIET env var for suppression
92
+ OUT=$(unset ANTHROPIC_MODEL CC_SONNET_45_HELPER_QUIET; \
93
+ CC_SONNET_45_HELPER_REMIND=1 bash "$HOOK" 2>&1)
94
+ if echo "$OUT" | grep -q "CC_SONNET_45_HELPER_QUIET"; then
95
+ run_test "Reminder explains how to suppress" pass
96
+ else
97
+ run_test "Reminder explains how to suppress" fail
98
+ fi
99
+
100
+ # Test 9: Reminder references the operator-side paths Gist
101
+ OUT=$(unset ANTHROPIC_MODEL CC_SONNET_45_HELPER_QUIET; \
102
+ CC_SONNET_45_HELPER_REMIND=1 bash "$HOOK" 2>&1)
103
+ if echo "$OUT" | grep -q "gist.github.com/yurukusa/29d9c3ba62aa514450ba04fccc566161"; then
104
+ run_test "Reminder links to the 5-paths Gist" pass
105
+ else
106
+ run_test "Reminder links to the 5-paths Gist" fail
107
+ fi
108
+
109
+ # Test 10: ANTHROPIC_MODEL set to empty string is treated as unset (per [-n] semantics)
110
+ OUT=$(unset CC_SONNET_45_HELPER_QUIET; ANTHROPIC_MODEL="" CC_SONNET_45_HELPER_REMIND=1 bash "$HOOK" 2>&1)
111
+ EXIT=$?
112
+ if [ "$EXIT" = "0" ] && echo "$OUT" | grep -q "ANTHROPIC_MODEL is unset"; then
113
+ run_test "ANTHROPIC_MODEL='' (empty) → reminder emitted (treated as unset)" pass
114
+ else
115
+ run_test "ANTHROPIC_MODEL='' (empty) → reminder emitted (exit=$EXIT)" fail
116
+ fi
117
+
118
+ # Test 11: Multiple invocations are idempotent (no state leaked between runs)
119
+ OUT1=$(unset ANTHROPIC_MODEL CC_SONNET_45_HELPER_QUIET; \
120
+ CC_SONNET_45_HELPER_REMIND=1 bash "$HOOK" 2>&1)
121
+ OUT2=$(unset ANTHROPIC_MODEL CC_SONNET_45_HELPER_QUIET; \
122
+ CC_SONNET_45_HELPER_REMIND=1 bash "$HOOK" 2>&1)
123
+ if [ "$OUT1" = "$OUT2" ]; then
124
+ run_test "Idempotent: two invocations produce identical output" pass
125
+ else
126
+ run_test "Idempotent: two invocations produce identical output" fail
127
+ fi
128
+
129
+ # Test 12: Hook never blocks (always exits 0)
130
+ EXIT_CODES=""
131
+ for case in "QUIET=1" "ANTHROPIC_MODEL=4.5" "ANTHROPIC_MODEL=4.6" "all-unset" "REMIND=1"; do
132
+ case "$case" in
133
+ "QUIET=1") OUT=$(CC_SONNET_45_HELPER_QUIET=1 bash "$HOOK" 2>&1); EXIT=$? ;;
134
+ "ANTHROPIC_MODEL=4.5") OUT=$(unset CC_SONNET_45_HELPER_REMIND CC_SONNET_45_HELPER_QUIET; ANTHROPIC_MODEL=claude-sonnet-4-5-20250929 bash "$HOOK" 2>&1); EXIT=$? ;;
135
+ "ANTHROPIC_MODEL=4.6") OUT=$(unset CC_SONNET_45_HELPER_REMIND CC_SONNET_45_HELPER_QUIET; ANTHROPIC_MODEL=claude-sonnet-4-6 bash "$HOOK" 2>&1); EXIT=$? ;;
136
+ "all-unset") OUT=$(unset ANTHROPIC_MODEL CC_SONNET_45_HELPER_REMIND CC_SONNET_45_HELPER_QUIET; bash "$HOOK" 2>&1); EXIT=$? ;;
137
+ "REMIND=1") OUT=$(unset ANTHROPIC_MODEL CC_SONNET_45_HELPER_QUIET; CC_SONNET_45_HELPER_REMIND=1 bash "$HOOK" 2>&1); EXIT=$? ;;
138
+ esac
139
+ EXIT_CODES="$EXIT_CODES $EXIT"
140
+ done
141
+ NONZERO=$(echo "$EXIT_CODES" | tr ' ' '\n' | grep -v "^$" | grep -v "^0$" | head -1)
142
+ if [ -z "$NONZERO" ]; then
143
+ run_test "Hook never blocks (all paths exit 0)" pass
144
+ else
145
+ run_test "Hook never blocks (exit codes: $EXIT_CODES)" fail
146
+ fi
147
+
148
+ echo "========================================"
149
+ echo "Results: $PASS passed, $FAIL failed"
150
+ [ "$FAIL" = "0" ] && exit 0 || exit 1
@@ -0,0 +1,290 @@
1
+ #!/bin/bash
2
+ # Tests for spurious-malformed-notice-detector.sh
3
+ HOOK="examples/spurious-malformed-notice-detector.sh"
4
+ PASS=0 FAIL=0
5
+ TMPDIR=$(mktemp -d)
6
+ STATE_DIR="$TMPDIR/state"
7
+ trap "rm -rf $TMPDIR" EXIT
8
+
9
+ assert_contains() { if echo "$2" | grep -q "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected '$3' in output)"; fi; }
10
+ assert_not_contains() { if ! echo "$2" | grep -q "$3"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (unexpected '$3' in output)"; fi; }
11
+ assert_exit() { if [ "$2" = "$3" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $1 (expected exit $3, got $2)"; fi; }
12
+
13
+ HOOK_ABS="$PWD/$HOOK"
14
+
15
+ reset_state() { rm -rf "$STATE_DIR"; mkdir -p "$STATE_DIR"; }
16
+
17
+ mk_input() {
18
+ local transcript="$1" sid="${2:-test-session}"
19
+ printf '{"transcript_path":"%s","session_id":"%s"}' "$transcript" "$sid"
20
+ }
21
+
22
+ # A user-turn line carrying a successful tool_result block
23
+ # (no is_error, or is_error=false). This is the "tool actually
24
+ # succeeded" half of the 12C signature.
25
+ mk_success_result() {
26
+ printf '{"message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"t1","content":"ok"}]}}\n'
27
+ }
28
+
29
+ # A user-turn line carrying a tool_result with is_error=false
30
+ # explicitly set. Must still count as success.
31
+ mk_success_result_explicit() {
32
+ printf '{"message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"t1","content":"ok","is_error":false}]}}\n'
33
+ }
34
+
35
+ # A user-turn line carrying a tool_result with is_error=true.
36
+ # Must NOT count as success.
37
+ mk_failed_result() {
38
+ printf '{"message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"t1","content":"err","is_error":true}]}}\n'
39
+ }
40
+
41
+ # A top-level (non-.message) tool_result line — must be detected too.
42
+ mk_success_result_top() {
43
+ printf '{"role":"user","content":[{"type":"tool_result","tool_use_id":"t2","content":"ok"}]}\n'
44
+ }
45
+
46
+ # A system-style line carrying the spurious-malformed marker.
47
+ mk_marker() {
48
+ printf '{"role":"system","content":"Your tool call was malformed and could not be parsed. Please retry."}\n'
49
+ }
50
+
51
+ # An ordinary assistant turn with no marker.
52
+ mk_plain() {
53
+ printf '{"message":{"role":"assistant","content":"hello"}}\n'
54
+ }
55
+
56
+ # Test 1: No transcript path → silent pass
57
+ reset_state
58
+ OUT=$(echo '{}' | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
59
+ assert_not_contains "no transcript silent" "$OUT" "sub-pattern 12C"
60
+ assert_exit "no transcript exit 0" "$RC" "0"
61
+
62
+ # Test 2: Missing transcript file → silent pass
63
+ reset_state
64
+ OUT=$(mk_input "/nonexistent/transcript.jsonl" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
65
+ assert_not_contains "missing transcript silent" "$OUT" "sub-pattern 12C"
66
+ assert_exit "missing transcript exit 0" "$RC" "0"
67
+
68
+ # Test 3: No marker, only successes → silent pass
69
+ reset_state
70
+ TR="$TMPDIR/t3.jsonl"
71
+ mk_success_result > "$TR"
72
+ mk_success_result >> "$TR"
73
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
74
+ assert_not_contains "no marker silent" "$OUT" "sub-pattern 12C"
75
+ assert_exit "no marker exit 0" "$RC" "0"
76
+
77
+ # Test 4: Marker present but no successful tool_results → silent
78
+ # (this is the 12A-shaped state — let the 12A hook handle it)
79
+ reset_state
80
+ TR="$TMPDIR/t4.jsonl"
81
+ mk_marker > "$TR"
82
+ mk_marker >> "$TR"
83
+ mk_failed_result >> "$TR"
84
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
85
+ assert_not_contains "marker without success silent" "$OUT" "sub-pattern 12C"
86
+ assert_exit "marker without success exit 0" "$RC" "0"
87
+
88
+ # Test 5: One marker + one success → 12C advisory fires
89
+ reset_state
90
+ TR="$TMPDIR/t5.jsonl"
91
+ mk_marker > "$TR"
92
+ mk_success_result >> "$TR"
93
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
94
+ assert_contains "marker + success fires advisory" "$OUT" "sub-pattern 12C"
95
+ assert_contains "advisory cites #62700" "$OUT" "#62700"
96
+ assert_contains "advisory cites #62123" "$OUT" "#62123"
97
+ assert_contains "advisory differentiates from 12A" "$OUT" "12A"
98
+ assert_contains "advisory differentiates from 12B" "$OUT" "12B"
99
+ assert_contains "advisory warns not to /clear" "$OUT" "Do NOT /clear"
100
+ assert_contains "advisory cites cluster tracker" "$OUT" "cluster-tracker"
101
+ assert_exit "marker + success exit 0" "$RC" "0"
102
+
103
+ # Test 6: Multiple markers and at least as many successes → fires
104
+ reset_state
105
+ TR="$TMPDIR/t6.jsonl"
106
+ mk_marker > "$TR"
107
+ mk_success_result >> "$TR"
108
+ mk_marker >> "$TR"
109
+ mk_success_result >> "$TR"
110
+ mk_marker >> "$TR"
111
+ mk_success_result >> "$TR"
112
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
113
+ assert_contains "3 markers + 3 successes fires" "$OUT" "sub-pattern 12C"
114
+ assert_contains "advisory shows marker count" "$OUT" "3 \"malformed"
115
+ assert_contains "advisory shows success count" "$OUT" "3 successful"
116
+ assert_exit "3+3 exit 0" "$RC" "0"
117
+
118
+ # Test 7: Marker count > success count → silent (the 12A case)
119
+ reset_state
120
+ TR="$TMPDIR/t7.jsonl"
121
+ mk_marker > "$TR"
122
+ mk_marker >> "$TR"
123
+ mk_marker >> "$TR"
124
+ mk_success_result >> "$TR"
125
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
126
+ assert_not_contains "3 markers + 1 success silent" "$OUT" "sub-pattern 12C"
127
+ assert_exit "3+1 exit 0" "$RC" "0"
128
+
129
+ # Test 8: Equal marker and success counts → fires (boundary)
130
+ reset_state
131
+ TR="$TMPDIR/t8.jsonl"
132
+ mk_marker > "$TR"
133
+ mk_marker >> "$TR"
134
+ mk_success_result >> "$TR"
135
+ mk_success_result >> "$TR"
136
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
137
+ assert_contains "equal counts fires" "$OUT" "sub-pattern 12C"
138
+ assert_exit "equal counts exit 0" "$RC" "0"
139
+
140
+ # Test 9: Disabled via env → silent even with signature
141
+ reset_state
142
+ TR="$TMPDIR/t9.jsonl"
143
+ mk_marker > "$TR"
144
+ mk_success_result >> "$TR"
145
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_DISABLE=1 CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
146
+ assert_not_contains "disable env silences" "$OUT" "sub-pattern 12C"
147
+ assert_exit "disable env exit 0" "$RC" "0"
148
+
149
+ # Test 10: Threshold raised to 2 with only 1 marker → silent
150
+ reset_state
151
+ TR="$TMPDIR/t10.jsonl"
152
+ mk_marker > "$TR"
153
+ mk_success_result >> "$TR"
154
+ mk_success_result >> "$TR"
155
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_THRESHOLD=2 CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
156
+ assert_not_contains "threshold 2 with 1 marker silent" "$OUT" "sub-pattern 12C"
157
+ assert_exit "threshold 2 with 1 exit 0" "$RC" "0"
158
+
159
+ # Test 11: Explicit is_error=false counted as success
160
+ reset_state
161
+ TR="$TMPDIR/t11.jsonl"
162
+ mk_marker > "$TR"
163
+ mk_success_result_explicit >> "$TR"
164
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
165
+ assert_contains "explicit is_error=false counted" "$OUT" "sub-pattern 12C"
166
+ assert_exit "explicit is_error=false exit 0" "$RC" "0"
167
+
168
+ # Test 12: is_error=true does NOT count as success
169
+ reset_state
170
+ TR="$TMPDIR/t12.jsonl"
171
+ mk_marker > "$TR"
172
+ mk_failed_result >> "$TR"
173
+ mk_failed_result >> "$TR"
174
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
175
+ assert_not_contains "is_error=true not counted" "$OUT" "sub-pattern 12C"
176
+ assert_exit "is_error=true exit 0" "$RC" "0"
177
+
178
+ # Test 13: Top-level (non-.message) shape detected
179
+ reset_state
180
+ TR="$TMPDIR/t13.jsonl"
181
+ mk_marker > "$TR"
182
+ mk_success_result_top >> "$TR"
183
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
184
+ assert_contains "top-level shape detected" "$OUT" "sub-pattern 12C"
185
+ assert_exit "top-level shape exit 0" "$RC" "0"
186
+
187
+ # Test 14: Cooldown — second call within cooldown stays silent
188
+ reset_state
189
+ TR="$TMPDIR/t14.jsonl"
190
+ mk_marker > "$TR"
191
+ mk_success_result >> "$TR"
192
+ OUT1=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1)
193
+ OUT2=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1)
194
+ assert_contains "first call fires" "$OUT1" "sub-pattern 12C"
195
+ assert_not_contains "second call within cooldown silent" "$OUT2" "sub-pattern 12C"
196
+
197
+ # Test 15: Cooldown — past cooldown refires
198
+ reset_state
199
+ TR="$TMPDIR/t15.jsonl"
200
+ mk_marker > "$TR"
201
+ mk_success_result >> "$TR"
202
+ OUT1=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_COOLDOWN=2 CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1)
203
+ # Two no-op calls advance the counter (force silent via high threshold)
204
+ mk_input "$TR" | CC_SPURIOUS_MALFORMED_COOLDOWN=2 CC_SPURIOUS_MALFORMED_THRESHOLD=999 CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>/dev/null
205
+ mk_input "$TR" | CC_SPURIOUS_MALFORMED_COOLDOWN=2 CC_SPURIOUS_MALFORMED_THRESHOLD=999 CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>/dev/null
206
+ OUT2=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_COOLDOWN=2 CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1)
207
+ assert_contains "first call fires" "$OUT1" "sub-pattern 12C"
208
+ assert_contains "third call past cooldown refires" "$OUT2" "sub-pattern 12C"
209
+
210
+ # Test 16: Different sessions have independent state
211
+ reset_state
212
+ TR="$TMPDIR/t16.jsonl"
213
+ mk_marker > "$TR"
214
+ mk_success_result >> "$TR"
215
+ OUT_A=$(mk_input "$TR" "session-A" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1)
216
+ OUT_B=$(mk_input "$TR" "session-B" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1)
217
+ assert_contains "session A fires" "$OUT_A" "sub-pattern 12C"
218
+ assert_contains "session B fires independently" "$OUT_B" "sub-pattern 12C"
219
+
220
+ # Test 17: Lookback window excludes earlier markers
221
+ reset_state
222
+ TR="$TMPDIR/t17.jsonl"
223
+ mk_marker > "$TR"
224
+ mk_success_result >> "$TR"
225
+ for i in $(seq 1 50); do
226
+ mk_plain >> "$TR"
227
+ done
228
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_LOOKBACK=10 CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
229
+ assert_not_contains "lookback excludes old signature" "$OUT" "sub-pattern 12C"
230
+ assert_exit "lookback exclude exit 0" "$RC" "0"
231
+
232
+ # Test 18: Lookback window includes recent signature
233
+ reset_state
234
+ TR="$TMPDIR/t18.jsonl"
235
+ for i in $(seq 1 5); do
236
+ mk_plain >> "$TR"
237
+ done
238
+ mk_marker >> "$TR"
239
+ mk_success_result >> "$TR"
240
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_LOOKBACK=5 CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
241
+ assert_contains "lookback includes recent" "$OUT" "sub-pattern 12C"
242
+ assert_exit "lookback include exit 0" "$RC" "0"
243
+
244
+ # Test 19: Non-JSON lines tolerated; signature still detected
245
+ reset_state
246
+ TR="$TMPDIR/t19.jsonl"
247
+ echo "garbage line not json" > "$TR"
248
+ mk_marker >> "$TR"
249
+ echo "more garbage" >> "$TR"
250
+ mk_success_result >> "$TR"
251
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
252
+ assert_contains "non-json lines tolerated" "$OUT" "sub-pattern 12C"
253
+ assert_exit "non-json tolerated exit 0" "$RC" "0"
254
+
255
+ # Test 20: Mixed successful and failed results — only successes count
256
+ reset_state
257
+ TR="$TMPDIR/t20.jsonl"
258
+ mk_marker > "$TR"
259
+ mk_marker >> "$TR"
260
+ mk_success_result >> "$TR"
261
+ mk_failed_result >> "$TR"
262
+ mk_success_result >> "$TR"
263
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
264
+ assert_contains "mixed results fires (2 success >= 2 markers)" "$OUT" "sub-pattern 12C"
265
+ assert_contains "shows accurate success count" "$OUT" "2 successful"
266
+ assert_exit "mixed results exit 0" "$RC" "0"
267
+
268
+ # Test 21: Plain assistant turns without tool_result blocks ignored
269
+ reset_state
270
+ TR="$TMPDIR/t21.jsonl"
271
+ mk_marker > "$TR"
272
+ mk_plain >> "$TR"
273
+ mk_plain >> "$TR"
274
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1); RC=$?
275
+ assert_not_contains "marker + plain assistant silent" "$OUT" "sub-pattern 12C"
276
+ assert_exit "marker + plain assistant exit 0" "$RC" "0"
277
+
278
+ # Test 22: Advisory explains verification path
279
+ reset_state
280
+ TR="$TMPDIR/t22.jsonl"
281
+ mk_marker > "$TR"
282
+ mk_success_result >> "$TR"
283
+ OUT=$(mk_input "$TR" | CC_SPURIOUS_MALFORMED_STATE_DIR="$STATE_DIR" bash "$HOOK_ABS" 2>&1)
284
+ assert_contains "advisory mentions verification path" "$OUT" "Verify"
285
+ assert_contains "advisory mentions continue workaround" "$OUT" "continue"
286
+
287
+ echo ""
288
+ echo "PASSED: $PASS"
289
+ echo "FAILED: $FAIL"
290
+ [ "$FAIL" -eq 0 ]