cc-safe-setup 7.3.0 → 7.4.0

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.
@@ -0,0 +1,28 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # disk-space-guard.sh — Warn when disk space is running low
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Long Claude Code sessions can generate large files, logs, and
7
+ # build artifacts. This hook warns before writes when disk space
8
+ # is below a threshold.
9
+ #
10
+ # TRIGGER: PreToolUse MATCHER: "Write|Bash"
11
+ #
12
+ # CONFIG:
13
+ # CC_DISK_WARN_PCT=90 (warn at this percentage used)
14
+ # ================================================================
15
+
16
+ WARN_PCT="${CC_DISK_WARN_PCT:-90}"
17
+
18
+ # Check disk usage (percentage used on the working directory's partition)
19
+ USAGE=$(df --output=pcent . 2>/dev/null | tail -1 | tr -d ' %')
20
+ [ -z "$USAGE" ] && exit 0
21
+
22
+ if [ "$USAGE" -ge "$WARN_PCT" ]; then
23
+ AVAIL=$(df -h --output=avail . 2>/dev/null | tail -1 | tr -d ' ')
24
+ echo "WARNING: Disk usage is ${USAGE}% (${AVAIL} available)." >&2
25
+ echo "Consider cleaning up build artifacts, logs, or /tmp files." >&2
26
+ fi
27
+
28
+ exit 0
@@ -0,0 +1,40 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # memory-write-guard.sh — Log writes to ~/.claude/ directory
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Claude auto-writes to ~/.claude/projects/*/memory/ without
7
+ # user visibility. This hook logs all writes to ~/.claude/ paths
8
+ # so users know what's being stored.
9
+ #
10
+ # TRIGGER: PreToolUse MATCHER: "Write|Edit"
11
+ #
12
+ # Born from: https://github.com/anthropics/claude-code/issues/38040
13
+ # "No way to enforce approval on all file modifications"
14
+ # ================================================================
15
+
16
+ INPUT=$(cat)
17
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
18
+ [ -z "$FILE" ] && exit 0
19
+
20
+ # Check if targeting ~/.claude/
21
+ case "$FILE" in
22
+ */.claude/*|~/.claude/*)
23
+ # Log the write
24
+ LOG="$HOME/.claude/memory-writes.log"
25
+ echo "[$(date -Iseconds)] Write to: $FILE" >> "$LOG" 2>/dev/null
26
+
27
+ # Only warn (don't block) — memory writes are usually intentional
28
+ echo "NOTE: Writing to Claude config directory: $FILE" >&2
29
+
30
+ # Block writes to settings.json unless explicitly allowed
31
+ case "$FILE" in
32
+ */settings.json|*/settings.local.json)
33
+ echo "WARNING: Modifying Claude Code settings file." >&2
34
+ echo "Verify this change is intentional." >&2
35
+ ;;
36
+ esac
37
+ ;;
38
+ esac
39
+
40
+ exit 0
@@ -0,0 +1,32 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # overwrite-guard.sh — Warn before overwriting existing files
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Claude's Write tool can silently overwrite files without
7
+ # confirmation. This hook warns when a Write targets a file
8
+ # that already exists, giving visibility into potential data loss.
9
+ #
10
+ # TRIGGER: PreToolUse MATCHER: "Write"
11
+ #
12
+ # Born from: https://github.com/anthropics/claude-code/issues/37595
13
+ # "/export overwrites existing files without warning"
14
+ # ================================================================
15
+
16
+ INPUT=$(cat)
17
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
18
+ [ -z "$FILE" ] && exit 0
19
+
20
+ # Expand ~ to home directory
21
+ FILE="${FILE/#\~/$HOME}"
22
+
23
+ if [ -f "$FILE" ]; then
24
+ SIZE=$(wc -c < "$FILE" 2>/dev/null || echo 0)
25
+ if [ "$SIZE" -gt 0 ]; then
26
+ LINES=$(wc -l < "$FILE" 2>/dev/null || echo 0)
27
+ echo "WARNING: Overwriting existing file: $FILE ($LINES lines, $SIZE bytes)" >&2
28
+ echo "Use Edit tool instead to make targeted changes." >&2
29
+ fi
30
+ fi
31
+
32
+ exit 0
@@ -0,0 +1,51 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # prompt-injection-guard.sh — Detect prompt injection in tool output
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # When Claude reads files or fetches web content, malicious
7
+ # instructions can be injected. This hook warns when tool output
8
+ # contains common prompt injection patterns.
9
+ #
10
+ # TRIGGER: PostToolUse MATCHER: ""
11
+ #
12
+ # Born from: https://github.com/anthropics/claude-code/issues/38046
13
+ # "Prompt Injection in /insights output"
14
+ # ================================================================
15
+
16
+ INPUT=$(cat)
17
+ OUTPUT=$(echo "$INPUT" | jq -r '.tool_result // empty' 2>/dev/null)
18
+ [ -z "$OUTPUT" ] && exit 0
19
+
20
+ # Check for common prompt injection patterns
21
+ SUSPICIOUS=0
22
+
23
+ # "Ignore previous instructions" pattern
24
+ if echo "$OUTPUT" | grep -qiE 'ignore\s+(all\s+)?previous\s+instructions'; then
25
+ echo "WARNING: Possible prompt injection detected: 'ignore previous instructions'" >&2
26
+ SUSPICIOUS=1
27
+ fi
28
+
29
+ # "You are now" role reassignment
30
+ if echo "$OUTPUT" | grep -qiE 'you\s+are\s+now\s+(a|an)\s+'; then
31
+ echo "WARNING: Possible prompt injection detected: role reassignment" >&2
32
+ SUSPICIOUS=1
33
+ fi
34
+
35
+ # "System prompt" manipulation
36
+ if echo "$OUTPUT" | grep -qiE '(new|updated|override)\s+system\s+prompt'; then
37
+ echo "WARNING: Possible prompt injection detected: system prompt override" >&2
38
+ SUSPICIOUS=1
39
+ fi
40
+
41
+ # Hidden instructions in HTML comments or zero-width chars
42
+ if echo "$OUTPUT" | grep -qP '<!--.*(?:execute|run|delete|remove).*-->'; then
43
+ echo "WARNING: Possible prompt injection in HTML comment" >&2
44
+ SUSPICIOUS=1
45
+ fi
46
+
47
+ if [ "$SUSPICIOUS" -eq 1 ]; then
48
+ echo "Review the output carefully before acting on it." >&2
49
+ fi
50
+
51
+ exit 0
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # test-deletion-guard.sh — Block deletion of test assertions
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Claude sometimes deletes or comments out failing tests instead
7
+ # of fixing the underlying code. This hook detects when an Edit
8
+ # to a test file removes test assertions.
9
+ #
10
+ # TRIGGER: PreToolUse MATCHER: "Edit"
11
+ #
12
+ # Born from: https://github.com/anthropics/claude-code/issues/38050
13
+ # "Claude skips/deletes tests instead of fixing them"
14
+ # ================================================================
15
+
16
+ INPUT=$(cat)
17
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
18
+ [ -z "$FILE" ] && exit 0
19
+
20
+ # Only check test files
21
+ case "$FILE" in
22
+ *test*|*spec*|*__tests__*|*_test.go|*_test.py|*Test.java|*Test.kt)
23
+ ;;
24
+ *)
25
+ exit 0
26
+ ;;
27
+ esac
28
+
29
+ OLD=$(echo "$INPUT" | jq -r '.tool_input.old_string // empty' 2>/dev/null)
30
+ NEW=$(echo "$INPUT" | jq -r '.tool_input.new_string // empty' 2>/dev/null)
31
+ [ -z "$OLD" ] && exit 0
32
+
33
+ # Count test assertions in old vs new
34
+ count_tests() {
35
+ echo "$1" | grep -cE '(it\(|test\(|describe\(|def test_|#\[test\]|@Test|assert|expect\(|should\b)' 2>/dev/null || echo 0
36
+ }
37
+
38
+ OLD_COUNT=$(count_tests "$OLD")
39
+ NEW_COUNT=$(count_tests "$NEW")
40
+
41
+ if [ "$OLD_COUNT" -gt 0 ] && [ "$NEW_COUNT" -lt "$OLD_COUNT" ]; then
42
+ REMOVED=$((OLD_COUNT - NEW_COUNT))
43
+ echo "WARNING: This edit removes $REMOVED test assertion(s) from $FILE." >&2
44
+ echo "If tests are failing, fix the code instead of deleting tests." >&2
45
+ echo "Old assertions: $OLD_COUNT → New assertions: $NEW_COUNT" >&2
46
+ fi
47
+
48
+ exit 0
@@ -0,0 +1,45 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # uncommitted-work-guard.sh — Block destructive git when dirty
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Claude sometimes runs git checkout --, git reset --hard, or
7
+ # git stash drop when there are uncommitted changes, destroying
8
+ # hours of work. This hook checks git status before allowing
9
+ # destructive git commands.
10
+ #
11
+ # TRIGGER: PreToolUse MATCHER: "Bash"
12
+ #
13
+ # Born from: https://github.com/anthropics/claude-code/issues/37888
14
+ # "Claude runs forbidden destructive git commands, destroys work twice"
15
+ # ================================================================
16
+
17
+ COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
18
+ [ -z "$COMMAND" ] && exit 0
19
+
20
+ # Only check destructive git commands
21
+ DESTRUCTIVE=0
22
+ echo "$COMMAND" | grep -qE '\bgit\s+checkout\s+--\s' && DESTRUCTIVE=1
23
+ echo "$COMMAND" | grep -qE '\bgit\s+checkout\s+\.\s*$' && DESTRUCTIVE=1
24
+ echo "$COMMAND" | grep -qE '\bgit\s+restore\s+--staged\s+\.' && DESTRUCTIVE=1
25
+ echo "$COMMAND" | grep -qE '\bgit\s+restore\s+\.\s*$' && DESTRUCTIVE=1
26
+ echo "$COMMAND" | grep -qE '\bgit\s+reset\s+--hard' && DESTRUCTIVE=1
27
+ echo "$COMMAND" | grep -qE '\bgit\s+clean\s+-[a-zA-Z]*f' && DESTRUCTIVE=1
28
+ echo "$COMMAND" | grep -qE '\bgit\s+stash\s+drop' && DESTRUCTIVE=1
29
+
30
+ [ "$DESTRUCTIVE" -eq 0 ] && exit 0
31
+
32
+ # Check for uncommitted changes
33
+ DIRTY=$(git status --porcelain 2>/dev/null | head -20)
34
+ if [ -n "$DIRTY" ]; then
35
+ COUNT=$(echo "$DIRTY" | wc -l)
36
+ echo "BLOCKED: Destructive git command with $COUNT uncommitted change(s)." >&2
37
+ echo "Changes that would be lost:" >&2
38
+ echo "$DIRTY" | head -10 | sed 's/^/ /' >&2
39
+ [ "$COUNT" -gt 10 ] && echo " ... and $((COUNT-10)) more" >&2
40
+ echo "" >&2
41
+ echo "Commit or stash your changes first, then retry." >&2
42
+ exit 2
43
+ fi
44
+
45
+ exit 0
@@ -0,0 +1,43 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # verify-before-done.sh — Warn when committing without running tests
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Claude Code often declares fixes "done" and commits without
7
+ # verifying the fix actually works. This hook warns when a commit
8
+ # is made in a project that has tests, but no test command was
9
+ # run recently in the session.
10
+ #
11
+ # TRIGGER: PreToolUse MATCHER: "Bash"
12
+ #
13
+ # Born from: https://github.com/anthropics/claude-code/issues/37818
14
+ # "Claude repeatedly declares fixes done without verification"
15
+ # ================================================================
16
+
17
+ COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
18
+ [ -z "$COMMAND" ] && exit 0
19
+
20
+ # Only check on git commit
21
+ echo "$COMMAND" | grep -qE '^\s*git\s+commit' || exit 0
22
+
23
+ # Track test execution via state file
24
+ STATE="/tmp/cc-tests-ran-$(pwd | md5sum | cut -c1-8)"
25
+
26
+ # Check if tests were run in this session
27
+ if [ ! -f "$STATE" ]; then
28
+ # Detect if project has tests
29
+ HAS_TESTS=0
30
+ [ -f "package.json" ] && grep -q '"test"' package.json 2>/dev/null && HAS_TESTS=1
31
+ [ -f "pytest.ini" ] || [ -f "setup.cfg" ] || [ -f "pyproject.toml" ] && HAS_TESTS=1
32
+ [ -f "Cargo.toml" ] && HAS_TESTS=1
33
+ [ -f "go.mod" ] && HAS_TESTS=1
34
+ [ -f "Makefile" ] && grep -q 'test:' Makefile 2>/dev/null && HAS_TESTS=1
35
+
36
+ if [ "$HAS_TESTS" -eq 1 ]; then
37
+ echo "WARNING: Committing without running tests first." >&2
38
+ echo "Run your test suite before committing to verify changes work." >&2
39
+ echo "To suppress: touch $STATE" >&2
40
+ fi
41
+ fi
42
+
43
+ exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-safe-setup",
3
- "version": "7.3.0",
3
+ "version": "7.4.0",
4
4
  "description": "One command to make Claude Code safe. 59 hooks (8 built-in + 51 examples). 26 CLI commands: dashboard, create, audit, lint, diff, migrate, compare, generate-ci. 284 tests.",
5
5
  "main": "index.mjs",
6
6
  "bin": {