cc-safe-setup 29.6.32 → 29.6.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COOKBOOK.md +70 -0
- package/README.md +6 -2
- package/examples/absolute-rule-enforcer.sh +42 -0
- package/examples/allow-claude-settings.sh +2 -0
- package/examples/allow-git-hooks-dir.sh +2 -0
- package/examples/allow-protected-dirs.sh +2 -0
- package/examples/allowlist.sh +2 -0
- package/examples/ansible-vault-guard.sh +2 -0
- package/examples/auto-approve-build.sh +2 -0
- package/examples/auto-approve-compound-git.sh +2 -0
- package/examples/auto-approve-docker.sh +2 -0
- package/examples/auto-approve-git-read.sh +2 -0
- package/examples/auto-approve-python.sh +2 -0
- package/examples/auto-approve-readonly-tools.sh +2 -0
- package/examples/auto-approve-ssh.sh +2 -0
- package/examples/auto-approve-test.sh +2 -0
- package/examples/auto-checkpoint.sh +2 -0
- package/examples/auto-git-checkpoint.sh +2 -0
- package/examples/auto-mode-safe-commands.sh +2 -0
- package/examples/auto-snapshot.sh +2 -0
- package/examples/backup-before-refactor.sh +2 -0
- package/examples/banned-command-guard.sh +3 -3
- package/examples/bash-domain-allowlist.sh +72 -0
- package/examples/bash-safety-auto-deny.sh +56 -0
- package/examples/bash-secret-output-detector.sh +68 -0
- package/examples/bash-timeout-guard.sh +2 -0
- package/examples/bashrc-safety-check.sh +59 -0
- package/examples/bg-task-cooldown-guard.sh +46 -0
- package/examples/block-database-wipe.sh +2 -0
- package/examples/branch-name-check.sh +2 -0
- package/examples/branch-naming-convention.sh +2 -0
- package/examples/cargo-publish-guard.sh +2 -0
- package/examples/check-abort-controller.sh +2 -0
- package/examples/check-accessibility.sh +2 -0
- package/examples/check-aria-labels.sh +2 -0
- package/examples/check-async-await-consistency.sh +2 -0
- package/examples/check-before-act-enforcer.sh +47 -0
- package/examples/check-charset-meta.sh +2 -0
- package/examples/check-cleanup-effect.sh +2 -0
- package/examples/check-content-type.sh +2 -0
- package/examples/check-controlled-input.sh +2 -0
- package/examples/check-cookie-flags.sh +2 -0
- package/examples/check-cors-config.sh +2 -0
- package/examples/check-csp-headers.sh +2 -0
- package/examples/check-csrf-protection.sh +2 -0
- package/examples/check-debounce.sh +2 -0
- package/examples/check-dependency-age.sh +2 -0
- package/examples/check-dependency-license.sh +2 -0
- package/examples/check-dockerfile-best-practice.sh +2 -0
- package/examples/check-error-boundaries.sh +2 -0
- package/examples/check-error-class.sh +2 -0
- package/examples/check-error-handling.sh +2 -0
- package/examples/check-error-logging.sh +2 -0
- package/examples/check-error-message.sh +2 -0
- package/examples/check-error-page.sh +2 -0
- package/examples/check-error-stack.sh +2 -0
- package/examples/check-favicon.sh +2 -0
- package/examples/check-form-validation.sh +2 -0
- package/examples/check-git-hooks-compat.sh +2 -0
- package/examples/check-https-redirect.sh +2 -0
- package/examples/check-image-optimization.sh +2 -0
- package/examples/check-input-validation.sh +2 -0
- package/examples/check-key-prop.sh +2 -0
- package/examples/check-lang-attribute.sh +2 -0
- package/examples/check-lazy-loading.sh +2 -0
- package/examples/check-loading-state.sh +2 -0
- package/examples/check-memo-deps.sh +2 -0
- package/examples/check-meta-description.sh +2 -0
- package/examples/check-npm-scripts-exist.sh +2 -0
- package/examples/check-null-check.sh +2 -0
- package/examples/check-package-size.sh +2 -0
- package/examples/check-pagination.sh +2 -0
- package/examples/check-port-availability.sh +2 -0
- package/examples/check-promise-all.sh +2 -0
- package/examples/check-prop-types.sh +2 -0
- package/examples/check-rate-limiting.sh +2 -0
- package/examples/check-responsive-design.sh +2 -0
- package/examples/check-retry-logic.sh +2 -0
- package/examples/check-return-types.sh +2 -0
- package/examples/check-semantic-html.sh +2 -0
- package/examples/check-semantic-versioning.sh +2 -0
- package/examples/check-suspense-fallback.sh +2 -0
- package/examples/check-test-naming.sh +2 -0
- package/examples/check-timeout-cleanup.sh +2 -0
- package/examples/check-tls-version.sh +2 -0
- package/examples/check-type-coercion.sh +2 -0
- package/examples/check-unsubscribe.sh +2 -0
- package/examples/check-viewport-meta.sh +2 -0
- package/examples/check-worker-terminate.sh +2 -0
- package/examples/checkpoint-tamper-guard.sh +2 -0
- package/examples/chmod-guard.sh +2 -0
- package/examples/chown-guard.sh +2 -0
- package/examples/ci-workflow-guard.sh +59 -0
- package/examples/classifier-fallback-allow.sh +2 -0
- package/examples/claude-cache-gc.sh +15 -0
- package/examples/claudeignore-enforce-guard.sh +60 -0
- package/examples/claudemd-enforcer.sh +2 -0
- package/examples/claudemd-violation-detector.sh +36 -0
- package/examples/clear-command-confirm-guard.sh +21 -0
- package/examples/commit-message-check.sh +2 -0
- package/examples/compact-blocker.sh +25 -0
- package/examples/composer-guard.sh +2 -0
- package/examples/compound-command-allow.sh +2 -0
- package/examples/consecutive-failure-circuit-breaker.sh +49 -0
- package/examples/console-log-count.sh +2 -0
- package/examples/context-compact-advisor.sh +16 -0
- package/examples/core-file-protect-guard.sh +91 -0
- package/examples/cors-star-warn.sh +2 -0
- package/examples/credential-exfil-guard.sh +2 -0
- package/examples/credential-file-cat-guard.sh +2 -0
- package/examples/cron-modification-guard.sh +40 -0
- package/examples/cwd-drift-detector.sh +47 -0
- package/examples/cwd-project-boundary-guard.sh +50 -0
- package/examples/denied-action-retry-guard.sh +41 -0
- package/examples/dependency-install-guard.sh +2 -0
- package/examples/deploy-guard.sh +2 -0
- package/examples/deploy-path-verify-guard.sh +62 -0
- package/examples/deployment-verify-guard.sh +81 -0
- package/examples/django-migrate-guard.sh +2 -0
- package/examples/docker-volume-guard.sh +2 -0
- package/examples/dockerfile-latest-guard.sh +2 -0
- package/examples/dotenv-commit-guard.sh +44 -0
- package/examples/dotenv-example-sync.sh +55 -0
- package/examples/dotnet-build-on-edit.sh +2 -0
- package/examples/drizzle-migrate-guard.sh +2 -0
- package/examples/edit-counter-test-gate.sh +44 -0
- package/examples/edit-error-counter.sh +2 -0
- package/examples/edit-guard.sh +2 -0
- package/examples/edit-old-string-validator.sh +37 -0
- package/examples/edit-retry-loop-guard.sh +2 -0
- package/examples/edit-verify.sh +2 -0
- package/examples/encoding-preserve-guard.sh +34 -0
- package/examples/enforce-tests.sh +2 -0
- package/examples/env-inherit-guard.sh +2 -0
- package/examples/env-inline-secret-guard.sh +36 -0
- package/examples/env-prod-guard.sh +2 -0
- package/examples/env-required-check.sh +2 -0
- package/examples/env-var-check.sh +2 -0
- package/examples/expo-eject-guard.sh +2 -0
- package/examples/export-overwrite-guard.sh +29 -0
- package/examples/file-change-tracker.sh +2 -0
- package/examples/file-change-undo-tracker.sh +46 -0
- package/examples/file-recycle-bin.sh +48 -0
- package/examples/file-size-limit.sh +2 -0
- package/examples/five-hundred-milestone.sh +2 -0
- package/examples/flask-debug-guard.sh +2 -0
- package/examples/gem-push-guard.sh +2 -0
- package/examples/git-checkout-safety-guard.sh +2 -0
- package/examples/git-config-guard.sh +2 -0
- package/examples/git-crypt-worktree-guard.sh +36 -0
- package/examples/git-hook-bypass-guard.sh +2 -0
- package/examples/git-merge-conflict-prevent.sh +2 -0
- package/examples/git-message-length.sh +2 -0
- package/examples/git-operations-require-approval.sh +99 -0
- package/examples/git-show-flag-sanitizer.sh +41 -0
- package/examples/git-stash-before-danger.sh +2 -0
- package/examples/git-submodule-guard.sh +2 -0
- package/examples/git-tag-guard.sh +2 -0
- package/examples/github-actions-secret-guard.sh +59 -0
- package/examples/gitignore-check.sh +2 -0
- package/examples/gitops-drift-guard.sh +53 -0
- package/examples/go-mod-tidy-warn.sh +2 -0
- package/examples/hallucination-url-check.sh +2 -0
- package/examples/hardcoded-ip-guard.sh +2 -0
- package/examples/headless-empty-result-guard.sh +46 -0
- package/examples/headless-stop-guard.sh +43 -0
- package/examples/helm-install-guard.sh +2 -0
- package/examples/issue-draft-redact-guard.sh +45 -0
- package/examples/java-compile-on-edit.sh +2 -0
- package/examples/k8s-production-guard.sh +77 -0
- package/examples/laravel-artisan-guard.sh +2 -0
- package/examples/large-file-guard.sh +2 -0
- package/examples/line-ending-guard.sh +30 -0
- package/examples/log-level-guard.sh +2 -0
- package/examples/magic-number-warn.sh +2 -0
- package/examples/max-edit-size-guard.sh +2 -0
- package/examples/max-file-count-guard.sh +2 -0
- package/examples/max-file-delete-count.sh +2 -0
- package/examples/max-function-length.sh +2 -0
- package/examples/max-import-count.sh +2 -0
- package/examples/max-subagent-count.sh +2 -0
- package/examples/mcp-orphan-process-guard.sh +39 -0
- package/examples/mcp-server-allowlist.sh +45 -0
- package/examples/mcp-tool-audit-log.sh +41 -0
- package/examples/mcp-tool-guard.sh +2 -0
- package/examples/migration-verify-guard.sh +44 -0
- package/examples/monorepo-scope-guard.sh +2 -0
- package/examples/network-exfil-guard.sh +61 -0
- package/examples/network-guard.sh +2 -0
- package/examples/nextjs-env-guard.sh +2 -0
- package/examples/no-absolute-import.sh +2 -0
- package/examples/no-alert-confirm-prompt.sh +2 -0
- package/examples/no-any-type.sh +2 -0
- package/examples/no-any-typescript.sh +2 -0
- package/examples/no-assignment-in-condition.sh +2 -0
- package/examples/no-callback-hell.sh +2 -0
- package/examples/no-catch-all-route.sh +2 -0
- package/examples/no-circular-dependency.sh +2 -0
- package/examples/no-class-in-functional.sh +2 -0
- package/examples/no-cleartext-storage.sh +2 -0
- package/examples/no-commented-code.sh +2 -0
- package/examples/no-commit-fixup.sh +2 -0
- package/examples/no-console-assert.sh +2 -0
- package/examples/no-console-error-swallow.sh +2 -0
- package/examples/no-console-in-prod.sh +2 -0
- package/examples/no-console-log.sh +2 -0
- package/examples/no-console-time.sh +2 -0
- package/examples/no-cors-wildcard.sh +2 -0
- package/examples/no-curl-upload.sh +2 -0
- package/examples/no-dangerouslySetInnerHTML.sh +2 -0
- package/examples/no-dangling-await.sh +2 -0
- package/examples/no-debug-in-commit.sh +2 -0
- package/examples/no-deep-nesting.sh +2 -0
- package/examples/no-deep-relative-import.sh +2 -0
- package/examples/no-default-credentials.sh +2 -0
- package/examples/no-deprecated-api.sh +2 -0
- package/examples/no-direct-dom-manipulation.sh +2 -0
- package/examples/no-disabled-test.sh +2 -0
- package/examples/no-document-cookie.sh +2 -0
- package/examples/no-document-write.sh +2 -0
- package/examples/no-empty-function.sh +2 -0
- package/examples/no-eval-in-template.sh +2 -0
- package/examples/no-eval-template.sh +2 -0
- package/examples/no-eval.sh +2 -0
- package/examples/no-exec-user-input.sh +2 -0
- package/examples/no-expose-internal-ids.sh +2 -0
- package/examples/no-floating-promises.sh +2 -0
- package/examples/no-force-install.sh +2 -0
- package/examples/no-git-rebase-public.sh +2 -0
- package/examples/no-global-state.sh +2 -0
- package/examples/no-hardcoded-port.sh +2 -0
- package/examples/no-hardcoded-url.sh +2 -0
- package/examples/no-helmet-missing.sh +2 -0
- package/examples/no-http-url.sh +2 -0
- package/examples/no-http-without-https.sh +2 -0
- package/examples/no-index-as-key.sh +2 -0
- package/examples/no-infinite-scroll-mem.sh +2 -0
- package/examples/no-inline-event-handler.sh +2 -0
- package/examples/no-inline-handler.sh +2 -0
- package/examples/no-inline-style.sh +2 -0
- package/examples/no-inline-styles.sh +2 -0
- package/examples/no-innerhtml.sh +2 -0
- package/examples/no-install-global.sh +2 -0
- package/examples/no-jwt-in-url.sh +2 -0
- package/examples/no-large-commit.sh +2 -0
- package/examples/no-localhost-expose.sh +2 -0
- package/examples/no-long-switch.sh +2 -0
- package/examples/no-magic-number.sh +2 -0
- package/examples/no-md5-sha1.sh +2 -0
- package/examples/no-memory-leak-interval.sh +2 -0
- package/examples/no-mixed-line-endings.sh +2 -0
- package/examples/no-mutation-in-reducer.sh +2 -0
- package/examples/no-mutation-observer-leak.sh +2 -0
- package/examples/no-nested-subscribe.sh +2 -0
- package/examples/no-nested-ternary.sh +2 -0
- package/examples/no-network-exfil.sh +2 -0
- package/examples/no-new-array-fill.sh +2 -0
- package/examples/no-object-freeze-mutation.sh +2 -0
- package/examples/no-open-redirect.sh +2 -0
- package/examples/no-output-truncation.sh +44 -0
- package/examples/no-package-downgrade.sh +2 -0
- package/examples/no-package-lock-edit.sh +2 -0
- package/examples/no-path-join-user-input.sh +2 -0
- package/examples/no-port-bind.sh +2 -0
- package/examples/no-process-exit.sh +2 -0
- package/examples/no-prototype-pollution.sh +2 -0
- package/examples/no-push-without-ci.sh +2 -0
- package/examples/no-raw-ref.sh +2 -0
- package/examples/no-redundant-fragment.sh +2 -0
- package/examples/no-render-in-loop.sh +2 -0
- package/examples/no-root-user-docker.sh +2 -0
- package/examples/no-root-write.sh +2 -0
- package/examples/no-secrets-in-args.sh +2 -0
- package/examples/no-secrets-in-logs.sh +2 -0
- package/examples/no-sensitive-log.sh +2 -0
- package/examples/no-side-effects-in-render.sh +2 -0
- package/examples/no-sleep-in-hooks.sh +2 -0
- package/examples/no-star-import-python.sh +2 -0
- package/examples/no-string-concat-sql.sh +2 -0
- package/examples/no-sudo-guard.sh +2 -0
- package/examples/no-sync-external-call.sh +2 -0
- package/examples/no-sync-fs.sh +2 -0
- package/examples/no-table-layout.sh +2 -0
- package/examples/no-throw-string.sh +2 -0
- package/examples/no-todo-in-merge.sh +2 -0
- package/examples/no-todo-in-production.sh +2 -0
- package/examples/no-todo-without-issue.sh +2 -0
- package/examples/no-triple-slash-ref.sh +2 -0
- package/examples/no-unreachable-code.sh +2 -0
- package/examples/no-unused-import.sh +2 -0
- package/examples/no-unused-state.sh +2 -0
- package/examples/no-var-keyword.sh +2 -0
- package/examples/no-wildcard-cors.sh +2 -0
- package/examples/no-wildcard-import.sh +2 -0
- package/examples/no-window-location.sh +2 -0
- package/examples/no-with-statement.sh +2 -0
- package/examples/no-write-outside-src.sh +2 -0
- package/examples/no-xml-external-entity.sh +2 -0
- package/examples/notify-waiting.sh +2 -0
- package/examples/npm-audit-warn.sh +2 -0
- package/examples/npm-publish-guard.sh +2 -0
- package/examples/npm-script-injection.sh +2 -0
- package/examples/npm-supply-chain-guard.sh +92 -0
- package/examples/nuxt-config-guard.sh +2 -0
- package/examples/output-secret-mask.sh +2 -0
- package/examples/package-json-guard.sh +2 -0
- package/examples/parallel-session-guard.sh +2 -0
- package/examples/path-traversal-guard.sh +2 -0
- package/examples/permission-audit-log.sh +2 -0
- package/examples/permission-entry-validator.sh +48 -0
- package/examples/permission-pattern-auto-allow.sh +50 -0
- package/examples/php-lint-on-edit.sh +2 -0
- package/examples/pip-publish-guard.sh +2 -0
- package/examples/plain-language-danger-warn.sh +37 -0
- package/examples/plan-mode-enforcer.sh +2 -0
- package/examples/plugin-process-cleanup.sh +50 -0
- package/examples/polyglot-rm-guard.sh +59 -0
- package/examples/pr-description-check.sh +2 -0
- package/examples/pre-compact-knowledge-save.sh +53 -0
- package/examples/pre-compact-transcript-export.sh +85 -0
- package/examples/prefer-builtin-tools.sh +2 -0
- package/examples/prefer-const.sh +2 -0
- package/examples/prefer-dedicated-tools.sh +55 -0
- package/examples/prefer-optional-chaining.sh +2 -0
- package/examples/prisma-migrate-guard.sh +2 -0
- package/examples/prompt-injection-detector.sh +2 -0
- package/examples/prompt-length-guard.sh +2 -0
- package/examples/protect-dotfiles.sh +2 -0
- package/examples/public-repo-push-guard.sh +58 -0
- package/examples/push-requires-test-pass-record.sh +2 -0
- package/examples/push-requires-test-pass.sh +2 -0
- package/examples/rails-migration-guard.sh +2 -0
- package/examples/rate-limit-guard.sh +2 -0
- package/examples/read-all-files-enforcer.sh +51 -0
- package/examples/read-audit-log.sh +34 -0
- package/examples/readme-exists-check.sh +2 -0
- package/examples/redis-flushall-guard.sh +2 -0
- package/examples/rm-safety-net.sh +2 -0
- package/examples/role-tool-guard.sh +69 -0
- package/examples/ruby-lint-on-edit.sh +2 -0
- package/examples/schema-migration-guard.sh +57 -0
- package/examples/scope-guard.sh +2 -0
- package/examples/secret-file-read-guard.sh +74 -0
- package/examples/self-modify-bypass-guard.sh +54 -0
- package/examples/sensitive-log-guard.sh +2 -0
- package/examples/session-checkpoint.sh +2 -0
- package/examples/session-duration-guard.sh +51 -0
- package/examples/session-end-logger.sh +57 -0
- package/examples/session-error-rate-monitor.sh +65 -0
- package/examples/session-health-monitor.sh +61 -0
- package/examples/session-memory-watchdog.sh +17 -0
- package/examples/session-permission-reset-guard.sh +39 -0
- package/examples/session-resume-env-fix.sh +49 -0
- package/examples/session-state-saver.sh +2 -0
- package/examples/session-summary-stop.sh +2 -0
- package/examples/session-summary.sh +2 -0
- package/examples/session-token-counter.sh +2 -0
- package/examples/settings-auto-backup.sh +53 -0
- package/examples/settings-mutation-detector.sh +45 -0
- package/examples/shell-wrapper-guard.sh +2 -0
- package/examples/skill-gate.sh +2 -0
- package/examples/skill-injection-detector.sh +41 -0
- package/examples/spec-file-scope-guard.sh +69 -0
- package/examples/spring-profile-guard.sh +2 -0
- package/examples/sql-injection-detect.sh +2 -0
- package/examples/subagent-budget-guard.sh +2 -0
- package/examples/subagent-claudemd-inject.sh +45 -0
- package/examples/subagent-context-size-guard.sh +26 -0
- package/examples/subagent-tool-call-limiter.sh +48 -0
- package/examples/svelte-lint-on-edit.sh +2 -0
- package/examples/swift-build-on-edit.sh +2 -0
- package/examples/symlink-protect.sh +12 -0
- package/examples/system-message-workaround.sh +44 -0
- package/examples/system-package-guard.sh +2 -0
- package/examples/temp-file-cleanup-stop.sh +28 -0
- package/examples/temp-file-cleanup.sh +2 -0
- package/examples/terminal-state-restore.sh +23 -0
- package/examples/test-after-edit.sh +2 -0
- package/examples/test-before-commit.sh +13 -14
- package/examples/test-before-push.sh +2 -0
- package/examples/test-exit-code-verify.sh +2 -0
- package/examples/timeout-guard.sh +2 -0
- package/examples/timezone-guard.sh +2 -0
- package/examples/tmp-output-size-guard.sh +46 -0
- package/examples/todo-check.sh +2 -0
- package/examples/todo-deadline-warn.sh +48 -0
- package/examples/token-budget-per-task.sh +55 -0
- package/examples/token-spike-alert.sh +51 -0
- package/examples/token-usage-tracker.sh +14 -0
- package/examples/turbo-cache-guard.sh +2 -0
- package/examples/uncommitted-changes-stop.sh +2 -0
- package/examples/uncommitted-work-shield.sh +37 -0
- package/examples/usage-warn.sh +2 -0
- package/examples/verify-before-commit.sh +2 -0
- package/examples/virtual-cwd-helper.sh +40 -0
- package/examples/vue-lint-on-edit.sh +2 -0
- package/examples/webfetch-domain-allow.sh +96 -0
- package/examples/worktree-delete-guard.sh +43 -0
- package/examples/worktree-memory-guard.sh +47 -0
- package/examples/worktree-path-validator.sh +42 -0
- package/examples/worktree-project-unify.sh +19 -0
- package/examples/worktree-unmerged-guard.sh +2 -0
- package/examples/write-overwrite-confirm.sh +40 -0
- package/examples/write-secret-guard.sh +2 -0
- package/examples/write-shrink-guard.sh +46 -0
- package/examples/write-test-ratio.sh +2 -0
- package/index.mjs +631 -138
- package/package.json +2 -2
- package/scripts/generate-categories.mjs +206 -0
- package/scripts.json +4 -1
- package/test.sh.new_tests +0 -0
- package/test.sh.patch +0 -0
- package/tests/test-core-file-protect-guard.sh +73 -0
- package/tests/test-deployment-verify-guard.sh +74 -0
- package/tests/test-git-operations-require-approval.sh +65 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
2
4
|
CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$CONTENT" ] && exit 0
|
|
4
6
|
COMMAND=$(cat | jq -r ".tool_input.command // empty" 2>/dev/null); echo "$COMMAND" | grep -qE "git\s+merge" && git diff --cached 2>/dev/null | grep -q "TODO" && echo "WARNING: TODO markers in merge target" >&2
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Edit|Write"
|
|
2
4
|
CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$CONTENT" ] && exit 0
|
|
4
6
|
echo "$CONTENT" | grep -qE "TODO[^(]|FIXME[^(]" && ! echo "$CONTENT" | grep -qE "TODO\(#|FIXME\(#" && echo "NOTE: TODO without issue reference" >&2
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Edit|Write"
|
|
2
4
|
CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$CONTENT" ] && exit 0
|
|
4
6
|
echo "$CONTENT" | grep -qE "^import.*from" && echo "$CONTENT" | grep -cE "^import" | xargs -I{} test {} -gt 10 && echo "NOTE: Many imports — check for unused ones" >&2
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Edit|Write"
|
|
2
4
|
CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$CONTENT" ] && exit 0
|
|
4
6
|
echo "$CONTENT" | grep -qE "^\s*var\s" && echo "NOTE: var keyword — use const/let" >&2
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Edit|Write"
|
|
2
4
|
CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$CONTENT" ] && exit 0
|
|
4
6
|
echo "$CONTENT" | grep -qE "Access-Control.*\*" && echo "WARNING: Wildcard CORS origin" >&2
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Edit|Write"
|
|
2
4
|
CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$CONTENT" ] && exit 0
|
|
4
6
|
echo "$CONTENT" | grep -qE "\bwith\s*\(" && echo "WARNING: with statement is deprecated" >&2
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Edit|Write"
|
|
2
4
|
CONTENT=$(cat | jq -r '.tool_input.new_string // .tool_input.content // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$CONTENT" ] && exit 0
|
|
4
6
|
echo "$CONTENT" | grep -qE "parseXML|xml2js|DOMParser|libxml" && echo "$CONTENT" | grep -q "ENTITY" && echo "WARNING: Possible XXE in XML parsing" >&2
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
# }
|
|
18
18
|
|
|
19
19
|
# Linux (notify-send) — skip on WSL2 where D-Bus may not be running
|
|
20
|
+
#
|
|
21
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
20
22
|
if command -v notify-send &>/dev/null && [ -z "$WSL_DISTRO_NAME" ]; then
|
|
21
23
|
notify-send "Claude Code" "Waiting for your input" --urgency=normal 2>/dev/null && exit 0
|
|
22
24
|
fi
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
2
4
|
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
3
5
|
[ -z "$COMMAND" ] && exit 0
|
|
4
6
|
if echo "$COMMAND" | grep -qE '^\s*(npm\s+publish|npx\s+npm\s+publish)' && ! echo "$COMMAND" | grep -qE '\-\-dry-run'; then
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# npm-supply-chain-guard.sh — Detect npm supply chain attack patterns
|
|
3
|
+
#
|
|
4
|
+
# Solves: npm install can execute arbitrary code via postinstall scripts.
|
|
5
|
+
# Claude Code may install malicious packages via typosquatting,
|
|
6
|
+
# dependency confusion, or compromised packages (#39421).
|
|
7
|
+
#
|
|
8
|
+
# How it works: PreToolUse hook on Bash that detects npm/yarn/pnpm
|
|
9
|
+
# install commands and checks for:
|
|
10
|
+
# 1. Typosquatting patterns (similar to popular packages)
|
|
11
|
+
# 2. Scoped packages from unknown registries
|
|
12
|
+
# 3. Packages with suspicious install scripts
|
|
13
|
+
# 4. Version pinning warnings
|
|
14
|
+
#
|
|
15
|
+
# TRIGGER: PreToolUse
|
|
16
|
+
# MATCHER: "Bash"
|
|
17
|
+
#
|
|
18
|
+
# Usage:
|
|
19
|
+
# {
|
|
20
|
+
# "hooks": {
|
|
21
|
+
# "PreToolUse": [{
|
|
22
|
+
# "matcher": "Bash",
|
|
23
|
+
# "hooks": [{ "type": "command", "command": "~/.claude/hooks/npm-supply-chain-guard.sh" }]
|
|
24
|
+
# }]
|
|
25
|
+
# }
|
|
26
|
+
# }
|
|
27
|
+
|
|
28
|
+
INPUT=$(cat)
|
|
29
|
+
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
30
|
+
[ -z "$CMD" ] && exit 0
|
|
31
|
+
|
|
32
|
+
# Only check npm/yarn/pnpm install commands
|
|
33
|
+
echo "$CMD" | grep -qE '\b(npm|yarn|pnpm)\s+(install|add|i)\b' || exit 0
|
|
34
|
+
|
|
35
|
+
# Extract package names from command
|
|
36
|
+
PACKAGES=$(echo "$CMD" | grep -oE '\b(npm|yarn|pnpm)\s+(install|add|i)\s+(.+)' | sed -E 's/^(npm|yarn|pnpm)\s+(install|add|i)\s+//' | tr ' ' '\n' | grep -v '^-')
|
|
37
|
+
|
|
38
|
+
WARNINGS=""
|
|
39
|
+
|
|
40
|
+
for pkg in $PACKAGES; do
|
|
41
|
+
# Skip flags
|
|
42
|
+
[[ "$pkg" == -* ]] && continue
|
|
43
|
+
|
|
44
|
+
# Check for known typosquatting patterns
|
|
45
|
+
# Common targets: lodash, express, react, axios, webpack, babel
|
|
46
|
+
POPULAR=("lodash" "express" "react" "axios" "webpack" "babel" "moment" "chalk" "commander" "inquirer")
|
|
47
|
+
for popular in "${POPULAR[@]}"; do
|
|
48
|
+
# Skip exact matches
|
|
49
|
+
[ "$pkg" = "$popular" ] && continue
|
|
50
|
+
# Check Levenshtein-like similarity (simple: 1 char difference)
|
|
51
|
+
if [ "${#pkg}" -ge 3 ] && [ "${#pkg}" -le $((${#popular} + 2)) ]; then
|
|
52
|
+
# Check if package name is very similar to a popular one
|
|
53
|
+
diff_count=$(python3 -c "
|
|
54
|
+
import sys
|
|
55
|
+
a, b = '$pkg', '$popular'
|
|
56
|
+
if abs(len(a)-len(b)) <= 2:
|
|
57
|
+
# Simple edit distance check
|
|
58
|
+
d = sum(1 for x,y in zip(a,b) if x!=y) + abs(len(a)-len(b))
|
|
59
|
+
print(d)
|
|
60
|
+
else:
|
|
61
|
+
print(99)
|
|
62
|
+
" 2>/dev/null)
|
|
63
|
+
if [ -n "$diff_count" ] && [ "$diff_count" -le 2 ] && [ "$diff_count" -gt 0 ]; then
|
|
64
|
+
WARNINGS="${WARNINGS}\n ⚠ '$pkg' looks similar to popular package '$popular' (possible typosquatting)"
|
|
65
|
+
fi
|
|
66
|
+
fi
|
|
67
|
+
done
|
|
68
|
+
|
|
69
|
+
# Check for internal/private scope packages being installed from public registry
|
|
70
|
+
if echo "$pkg" | grep -qE '^@[a-z]+-internal/|^@private-'; then
|
|
71
|
+
WARNINGS="${WARNINGS}\n ⚠ '$pkg' looks like an internal scoped package — verify it exists on the intended registry"
|
|
72
|
+
fi
|
|
73
|
+
done
|
|
74
|
+
|
|
75
|
+
# Check for --ignore-scripts bypass
|
|
76
|
+
if echo "$CMD" | grep -q '\-\-ignore-scripts'; then
|
|
77
|
+
# This is actually a safety measure, no warning needed
|
|
78
|
+
:
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Warn about not using --ignore-scripts
|
|
82
|
+
if [ -n "$PACKAGES" ] && ! echo "$CMD" | grep -qE '\-\-ignore-scripts|\-\-production'; then
|
|
83
|
+
WARNINGS="${WARNINGS}\n ℹ Consider using --ignore-scripts to prevent postinstall script execution"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
if [ -n "$WARNINGS" ]; then
|
|
87
|
+
echo "⚠ npm supply chain check:" >&2
|
|
88
|
+
echo -e "$WARNINGS" >&2
|
|
89
|
+
# Warn but don't block — exit 0
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
exit 0
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
# cat ~/.claude/tool-usage.jsonl | jq -s 'group_by(.tool) | map({tool: .[0].tool, count: length}) | sort_by(-.count)'
|
|
26
26
|
# # Top commands:
|
|
27
27
|
# cat ~/.claude/tool-usage.jsonl | jq -s '[.[] | select(.tool=="Bash")] | group_by(.command | split(" ")[0]) | map({cmd: .[0].command | split(" ")[0], count: length}) | sort_by(-.count) | .[:20]'
|
|
28
|
+
#
|
|
29
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
28
30
|
|
|
29
31
|
INPUT=$(cat)
|
|
30
32
|
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# permission-entry-validator.sh — Clean broken permission entries from settings
|
|
3
|
+
#
|
|
4
|
+
# Solves: Shell redirect targets saved as standalone permissions (#40382).
|
|
5
|
+
# Commands like `az ... > "filepath"` cause Claude Code to save
|
|
6
|
+
# `Bash("D:/path/file.json")` which is a bare filepath, not a command.
|
|
7
|
+
#
|
|
8
|
+
# How it works: Stop hook that reads settings.local.json and removes
|
|
9
|
+
# permission entries that are bare file paths (not valid command patterns).
|
|
10
|
+
# Identifies entries matching path patterns without a command prefix.
|
|
11
|
+
#
|
|
12
|
+
# TRIGGER: Stop
|
|
13
|
+
# MATCHER: ""
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
SETTINGS_FILE=".claude/settings.local.json"
|
|
18
|
+
[ -f "$SETTINGS_FILE" ] || exit 0
|
|
19
|
+
|
|
20
|
+
# Check for broken entries (bare file paths as Bash permissions)
|
|
21
|
+
BROKEN=$(jq -r '
|
|
22
|
+
.permissions.allow // [] | .[] |
|
|
23
|
+
select(
|
|
24
|
+
startswith("Bash(\"") and
|
|
25
|
+
(
|
|
26
|
+
# Windows paths
|
|
27
|
+
test("^Bash\\(\"[A-Z]:/") or
|
|
28
|
+
# Unix absolute paths without command
|
|
29
|
+
test("^Bash\\(\"/[^\"]*\"\\)$")
|
|
30
|
+
) and
|
|
31
|
+
# Must NOT contain a space (command + args have spaces)
|
|
32
|
+
(test("^Bash\\(\"[^\" ]*\"\\)$"))
|
|
33
|
+
)
|
|
34
|
+
' "$SETTINGS_FILE" 2>/dev/null || true)
|
|
35
|
+
|
|
36
|
+
if [ -n "$BROKEN" ]; then
|
|
37
|
+
COUNT=$(echo "$BROKEN" | wc -l)
|
|
38
|
+
echo "WARNING: Found $COUNT broken permission entries (bare file paths):" >&2
|
|
39
|
+
echo "$BROKEN" | head -5 | while IFS= read -r entry; do
|
|
40
|
+
echo " $entry" >&2
|
|
41
|
+
done
|
|
42
|
+
echo "" >&2
|
|
43
|
+
echo "These entries were likely created by 'Always allow' on commands with" >&2
|
|
44
|
+
echo "shell redirects (> filepath). They don't match any command pattern." >&2
|
|
45
|
+
echo "Consider removing them from $SETTINGS_FILE" >&2
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
exit 0
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# permission-pattern-auto-allow.sh — Auto-allow commands matching user-defined patterns
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude repeatedly asks for permission to run commands
|
|
5
|
+
# even after "Always Allow" — because the settings use
|
|
6
|
+
# exact argument matching, not pattern matching (#819).
|
|
7
|
+
#
|
|
8
|
+
# How it works: Maintains a list of regex patterns in an env var
|
|
9
|
+
# or config file. If the Bash command matches any pattern,
|
|
10
|
+
# returns allow decision. Bypasses the broken exact-match
|
|
11
|
+
# permission system entirely.
|
|
12
|
+
#
|
|
13
|
+
# Config: Set ALLOWED_PATTERNS env var or create ~/.claude/allowed-patterns.txt
|
|
14
|
+
# Example patterns (one per line):
|
|
15
|
+
# ^npm (test|run|install|ci)
|
|
16
|
+
# ^git (status|log|diff|add|commit|push|pull|fetch|branch|checkout)
|
|
17
|
+
# ^(ls|cat|pwd|echo|head|tail|wc|grep|find|which|env)
|
|
18
|
+
# ^python[23]?\s
|
|
19
|
+
# ^cargo (build|test|run|check)
|
|
20
|
+
#
|
|
21
|
+
# TRIGGER: PreToolUse
|
|
22
|
+
# MATCHER: "Bash"
|
|
23
|
+
|
|
24
|
+
set -euo pipefail
|
|
25
|
+
INPUT=$(cat)
|
|
26
|
+
|
|
27
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
28
|
+
[ -z "$COMMAND" ] && exit 0
|
|
29
|
+
|
|
30
|
+
# Load patterns from file or env
|
|
31
|
+
PATTERN_FILE="${HOME}/.claude/allowed-patterns.txt"
|
|
32
|
+
if [ -f "$PATTERN_FILE" ]; then
|
|
33
|
+
while IFS= read -r pattern || [ -n "$pattern" ]; do
|
|
34
|
+
# Skip empty lines and comments
|
|
35
|
+
[[ -z "$pattern" || "$pattern" == \#* ]] && continue
|
|
36
|
+
if echo "$COMMAND" | grep -qE "$pattern" 2>/dev/null; then
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
done < "$PATTERN_FILE"
|
|
40
|
+
elif [ -n "${ALLOWED_PATTERNS:-}" ]; then
|
|
41
|
+
# Fallback: pipe-separated patterns in env var
|
|
42
|
+
echo "$ALLOWED_PATTERNS" | tr '|' '\n' | while IFS= read -r pattern; do
|
|
43
|
+
[ -z "$pattern" ] && continue
|
|
44
|
+
if echo "$COMMAND" | grep -qE "$pattern" 2>/dev/null; then
|
|
45
|
+
exit 0
|
|
46
|
+
fi
|
|
47
|
+
done
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
exit 0
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# plain-language-danger-warn.sh — Add plain-language warnings to dangerous commands
|
|
3
|
+
#
|
|
4
|
+
# Solves: Users not understanding technical risk of commands (#30505).
|
|
5
|
+
# "git reset --hard" doesn't convey "this deletes all your unsaved work."
|
|
6
|
+
#
|
|
7
|
+
# How it works: PreToolUse hook on Bash that detects dangerous commands
|
|
8
|
+
# and injects plain-language explanations into stderr context.
|
|
9
|
+
#
|
|
10
|
+
# TRIGGER: PreToolUse
|
|
11
|
+
# MATCHER: "Bash"
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
INPUT=$(cat)
|
|
16
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
17
|
+
[ -z "$COMMAND" ] && exit 0
|
|
18
|
+
|
|
19
|
+
# Map dangerous commands to plain-language warnings
|
|
20
|
+
if echo "$COMMAND" | grep -qE 'git\s+reset\s+--hard'; then
|
|
21
|
+
echo "WARNING: This will DELETE all unsaved changes in your working directory." >&2
|
|
22
|
+
echo "Any uncommitted work will be permanently lost." >&2
|
|
23
|
+
elif echo "$COMMAND" | grep -qE 'git\s+clean\s+-[fd]'; then
|
|
24
|
+
echo "WARNING: This will DELETE all untracked files (files not in git)." >&2
|
|
25
|
+
elif echo "$COMMAND" | grep -qE 'git\s+push\s+.*--force'; then
|
|
26
|
+
echo "WARNING: This will OVERWRITE the remote branch history." >&2
|
|
27
|
+
echo "Other people's commits may be permanently lost." >&2
|
|
28
|
+
elif echo "$COMMAND" | grep -qE 'rm\s+-rf\s+/'; then
|
|
29
|
+
echo "WARNING: This will DELETE everything on the system. Unrecoverable." >&2
|
|
30
|
+
elif echo "$COMMAND" | grep -qE 'drop\s+(database|table|schema)'; then
|
|
31
|
+
echo "WARNING: This will DELETE the entire database/table. Data is unrecoverable." >&2
|
|
32
|
+
elif echo "$COMMAND" | grep -qE 'truncate\s+table'; then
|
|
33
|
+
echo "WARNING: This will DELETE all rows in the table." >&2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Always allow — this hook only warns, doesn't block
|
|
37
|
+
exit 0
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# plugin-process-cleanup.sh — Kill leaked plugin subprocesses on session end
|
|
3
|
+
#
|
|
4
|
+
# Solves: Channel plugin subprocesses (bun server.ts) leak across sessions,
|
|
5
|
+
# accumulating to 1000%+ CPU usage (#39137). Each session spawns
|
|
6
|
+
# new processes but never kills old ones.
|
|
7
|
+
#
|
|
8
|
+
# How it works: SessionEnd hook that finds and kills plugin server processes
|
|
9
|
+
# that are still running from the Claude plugins cache directory.
|
|
10
|
+
#
|
|
11
|
+
# TRIGGER: SessionEnd
|
|
12
|
+
# MATCHER: ""
|
|
13
|
+
#
|
|
14
|
+
# Usage:
|
|
15
|
+
# {
|
|
16
|
+
# "hooks": {
|
|
17
|
+
# "SessionEnd": [{
|
|
18
|
+
# "hooks": [{ "type": "command", "command": "~/.claude/hooks/plugin-process-cleanup.sh" }]
|
|
19
|
+
# }]
|
|
20
|
+
# }
|
|
21
|
+
# }
|
|
22
|
+
|
|
23
|
+
# Find plugin server processes from Claude's cache
|
|
24
|
+
PLUGIN_CACHE="$HOME/.claude/plugins/cache"
|
|
25
|
+
|
|
26
|
+
# Kill bun/node server processes from plugin directories
|
|
27
|
+
PIDS=$(pgrep -f "$PLUGIN_CACHE" 2>/dev/null)
|
|
28
|
+
|
|
29
|
+
if [ -n "$PIDS" ]; then
|
|
30
|
+
COUNT=$(echo "$PIDS" | wc -l | tr -d ' ')
|
|
31
|
+
echo "Cleaning up $COUNT leaked plugin process(es)..." >&2
|
|
32
|
+
|
|
33
|
+
for pid in $PIDS; do
|
|
34
|
+
# Try graceful shutdown first
|
|
35
|
+
kill "$pid" 2>/dev/null
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
# Wait briefly for graceful shutdown
|
|
39
|
+
sleep 1
|
|
40
|
+
|
|
41
|
+
# Force kill any remaining
|
|
42
|
+
for pid in $PIDS; do
|
|
43
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
44
|
+
kill -9 "$pid" 2>/dev/null
|
|
45
|
+
echo " Force-killed PID $pid" >&2
|
|
46
|
+
fi
|
|
47
|
+
done
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
exit 0
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# polyglot-rm-guard.sh — Block file deletion via any language, not just rm
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude circumvents Bash(rm) deny rules by using Python os.remove(),
|
|
5
|
+
# Node fs.unlinkSync(), or other languages to delete files (#39459).
|
|
6
|
+
# The permission system blocks the tool, not the goal.
|
|
7
|
+
#
|
|
8
|
+
# How it works: PreToolUse hook on Bash that detects file deletion attempts
|
|
9
|
+
# via Python, Node, Ruby, Perl, or any other interpreter — not just rm.
|
|
10
|
+
#
|
|
11
|
+
# TRIGGER: PreToolUse
|
|
12
|
+
# MATCHER: "Bash"
|
|
13
|
+
#
|
|
14
|
+
# Usage:
|
|
15
|
+
# {
|
|
16
|
+
# "hooks": {
|
|
17
|
+
# "PreToolUse": [{
|
|
18
|
+
# "matcher": "Bash",
|
|
19
|
+
# "hooks": [{ "type": "command", "command": "~/.claude/hooks/polyglot-rm-guard.sh" }]
|
|
20
|
+
# }]
|
|
21
|
+
# }
|
|
22
|
+
# }
|
|
23
|
+
|
|
24
|
+
INPUT=$(cat)
|
|
25
|
+
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
26
|
+
[ -z "$CMD" ] && exit 0
|
|
27
|
+
|
|
28
|
+
# Python file deletion
|
|
29
|
+
if echo "$CMD" | grep -qE 'python[23]?\s+-c\s.*\b(os\.remove|os\.unlink|shutil\.rmtree|pathlib.*unlink)\b'; then
|
|
30
|
+
echo "BLOCKED: File deletion via Python detected." >&2
|
|
31
|
+
echo "Blocked: os.remove/unlink/rmtree circumvents rm restrictions." >&2
|
|
32
|
+
exit 2
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Node.js file deletion
|
|
36
|
+
if echo "$CMD" | grep -qE 'node\s+-e\s.*\b(unlinkSync|rmdirSync|rmSync|fs\.rm)\b'; then
|
|
37
|
+
echo "BLOCKED: File deletion via Node.js detected." >&2
|
|
38
|
+
exit 2
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Ruby file deletion
|
|
42
|
+
if echo "$CMD" | grep -qE 'ruby\s+-e\s.*\b(File\.delete|FileUtils\.rm)\b'; then
|
|
43
|
+
echo "BLOCKED: File deletion via Ruby detected." >&2
|
|
44
|
+
exit 2
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Perl file deletion
|
|
48
|
+
if echo "$CMD" | grep -qE 'perl\s+-[eE]\s.*\bunlink\b'; then
|
|
49
|
+
echo "BLOCKED: File deletion via Perl detected." >&2
|
|
50
|
+
exit 2
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Generic: any interpreter with remove/delete/unlink in the command
|
|
54
|
+
if echo "$CMD" | grep -qE '(python|node|ruby|perl|php)\s+.*-[ceE]\s.*\b(remove|unlink|delete|rmtree|rmdir)\b'; then
|
|
55
|
+
echo "BLOCKED: File deletion via interpreter detected." >&2
|
|
56
|
+
exit 2
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
exit 0
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# pre-compact-knowledge-save.sh — Save critical context before compaction
|
|
3
|
+
#
|
|
4
|
+
# Solves: Context compaction losing important decisions, file locations,
|
|
5
|
+
# and progress state. After /compact, Claude forgets what it was
|
|
6
|
+
# doing and repeats work or contradicts earlier decisions.
|
|
7
|
+
#
|
|
8
|
+
# How it works: PreCompact hook that saves the current session state
|
|
9
|
+
# to a checkpoint file that survives compaction. The model can read
|
|
10
|
+
# this file after compaction to restore context.
|
|
11
|
+
#
|
|
12
|
+
# The checkpoint includes: current task, recent decisions, modified files.
|
|
13
|
+
#
|
|
14
|
+
# TRIGGER: PreCompact
|
|
15
|
+
# MATCHER: ""
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
INPUT=$(cat)
|
|
20
|
+
|
|
21
|
+
CHECKPOINT="${CC_COMPACT_CHECKPOINT:-.claude/pre-compact-checkpoint.md}"
|
|
22
|
+
mkdir -p "$(dirname "$CHECKPOINT")"
|
|
23
|
+
|
|
24
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
25
|
+
|
|
26
|
+
# Gather session state
|
|
27
|
+
GIT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
|
|
28
|
+
MODIFIED=$(git diff --name-only 2>/dev/null | head -10 || echo "none")
|
|
29
|
+
STAGED=$(git diff --cached --name-only 2>/dev/null | head -10 || echo "none")
|
|
30
|
+
RECENT_COMMITS=$(git log --oneline -3 2>/dev/null || echo "none")
|
|
31
|
+
|
|
32
|
+
cat > "$CHECKPOINT" << CHECKPOINT_EOF
|
|
33
|
+
# Pre-Compact Checkpoint
|
|
34
|
+
Generated: ${TIMESTAMP}
|
|
35
|
+
Branch: ${GIT_BRANCH}
|
|
36
|
+
|
|
37
|
+
## Modified files (not staged)
|
|
38
|
+
${MODIFIED}
|
|
39
|
+
|
|
40
|
+
## Staged files
|
|
41
|
+
${STAGED}
|
|
42
|
+
|
|
43
|
+
## Recent commits
|
|
44
|
+
${RECENT_COMMITS}
|
|
45
|
+
|
|
46
|
+
## Notes
|
|
47
|
+
Read this file after compaction to restore context.
|
|
48
|
+
Check tasks/todo.md for current task progress.
|
|
49
|
+
CHECKPOINT_EOF
|
|
50
|
+
|
|
51
|
+
echo "Pre-compact checkpoint saved to $CHECKPOINT" >&2
|
|
52
|
+
|
|
53
|
+
exit 0
|