cc-safe-setup 29.6.39 → 29.6.40

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dw/cc-safe-setup)](https://www.npmjs.com/package/cc-safe-setup)
5
5
  [![tests](https://github.com/yurukusa/cc-safe-setup/actions/workflows/test.yml/badge.svg)](https://github.com/yurukusa/cc-safe-setup/actions/workflows/test.yml)
6
6
 
7
- **One command to make Claude Code safe for autonomous operation.** 650 example hooks · 14,078 tests · 1,000+ installs/day · [日本語](docs/README.ja.md)
7
+ **One command to make Claude Code safe for autonomous operation.** 653 example hooks · 9,200+ tests · 1,200+ installs/week · [日本語](docs/README.ja.md)
8
8
 
9
9
  ```bash
10
10
  npx cc-safe-setup
@@ -14,7 +14,7 @@ Installs 8 safety hooks in ~10 seconds. Blocks `rm -rf /`, prevents pushes to ma
14
14
 
15
15
  > **What's a hook?** A checkpoint that runs before Claude executes a command. Like airport security — it inspects what's about to happen and blocks anything dangerous before it reaches the gate.
16
16
 
17
- [**Getting Started**](https://yurukusa.github.io/cc-safe-setup/getting-started.html) · [**All Tools**](https://yurukusa.github.io/cc-safe-setup/hub.html) · [**Recipes**](https://yurukusa.github.io/cc-safe-setup/recipes.html) · [Validate your settings.json](https://yurukusa.github.io/cc-safe-setup/validator.html) · [**Check your score**](https://yurukusa.github.io/cc-health-check/) (`npx cc-health-check`)
17
+ [**Getting Started**](https://yurukusa.github.io/cc-safe-setup/getting-started.html) · [**Hook Selector**](https://yurukusa.github.io/cc-safe-setup/hook-selector.html) · [**All Tools**](https://yurukusa.github.io/cc-safe-setup/hub.html) · [**Recipes**](https://yurukusa.github.io/cc-safe-setup/recipes.html) · [Validate your settings.json](https://yurukusa.github.io/cc-safe-setup/validator.html) · [**Check your score**](https://yurukusa.github.io/cc-health-check/) (`npx cc-health-check`)
18
18
 
19
19
  ```
20
20
  cc-safe-setup
@@ -29,6 +29,8 @@ Installs 8 safety hooks in ~10 seconds. Blocks `rm -rf /`, prevents pushes to ma
29
29
  ✗ API keys committed to public repos via git add .
30
30
  ✗ Syntax errors cascading through 30+ files
31
31
  ✗ Sessions losing all context with no warning
32
+ ✗ CLAUDE.md rules silently ignored after context compaction
33
+ ✗ Subagents ignoring all CLAUDE.md rules since v2.1.84 (#40459)
32
34
 
33
35
  Hooks to install:
34
36
 
@@ -47,12 +49,16 @@ Installs 8 safety hooks in ~10 seconds. Blocks `rm -rf /`, prevents pushes to ma
47
49
 
48
50
  ## Why This Exists
49
51
 
50
- A Claude Code user [lost their entire C:\Users directory](https://github.com/anthropics/claude-code/issues/36339) when `rm -rf` followed NTFS junctions. Another [lost all source code](https://github.com/anthropics/claude-code/issues/37331) when Claude ran `Remove-Item -Recurse -Force *` on a repo. Others had untested code pushed to main at 3am. API keys got committed via `git add .`. Syntax errors cascaded through 30+ files before anyone noticed.
52
+ A Claude Code user [lost their entire C:\Users directory](https://github.com/anthropics/claude-code/issues/36339) when `rm -rf` followed NTFS junctions. Another [lost all source code](https://github.com/anthropics/claude-code/issues/37331) when Claude ran `Remove-Item -Recurse -Force *` on a repo. Others had untested code pushed to main at 3am. API keys got committed via `git add .`. Syntax errors cascaded through 30+ files before anyone noticed. And [CLAUDE.md rules get silently dropped](https://github.com/anthropics/claude-code/issues/6354) after context compaction — your instructions vanish mid-session.
53
+
54
+ One user [analyzed 6,852 sessions](https://github.com/anthropics/claude-code/issues/42796) and found the Read:Edit ratio dropped from 6.6 to 2.0 — Claude editing files it never read jumped from 6% to 34%. That issue has over 1,000 reactions. The `read-before-edit` example hook catches this pattern before damage happens.
51
55
 
52
56
  Claude Code ships with no safety hooks by default. This tool fixes that.
53
57
 
54
58
  **Works with Auto Mode.** Claude Code's [Auto Mode sandboxing](https://www.anthropic.com/engineering/claude-code-sandboxing) provides container-level isolation. cc-safe-setup adds process-level hooks as defense-in-depth — catching destructive commands even outside sandboxed environments.
55
59
 
60
+ **Works with subagents.** Since v2.1.84, subagents and teammates [don't receive CLAUDE.md](https://github.com/anthropics/claude-code/issues/40459) — your project rules are silently skipped. Hooks operate at the process level, but [subagent tool calls may bypass PreToolUse hooks](https://github.com/anthropics/claude-code/issues/21460) in some configurations. As defense-in-depth, cc-safe-setup installs hooks at the user level (`~/.claude/settings.json`). The `subagent-claudemd-inject` example hook re-injects critical rules into subagent prompts.
61
+
56
62
  ## What Gets Installed
57
63
 
58
64
  | Hook | Prevents | Related Issues |
@@ -120,6 +126,7 @@ Guards against issues that corrupt sessions or waste tokens silently.
120
126
  | `mcp-warmup-wait` | Waits for MCP servers to initialize on session start (fixes first-turn tool errors) | [#41778](https://github.com/anthropics/claude-code/issues/41778) |
121
127
  | `pre-compact-transcript-backup` | Full JSONL backup before compaction (protects against rate-limit data loss) | [#40352](https://github.com/anthropics/claude-code/issues/40352) |
122
128
  | `conversation-history-guard` | Blocks access to session JSONL files (prevents 20x cache poisoning) | [#40524](https://github.com/anthropics/claude-code/issues/40524) |
129
+ | `read-before-edit` | Warns when Edit targets a file not recently Read (Read:Edit ratio dropped 70% — [#42796](https://github.com/anthropics/claude-code/issues/42796)) | [#42796](https://github.com/anthropics/claude-code/issues/42796) |
123
130
  | `replace-all-guard` | Warns/blocks Edit `replace_all:true` (prevents bulk data corruption) | [#41681](https://github.com/anthropics/claude-code/issues/41681) |
124
131
  | `ripgrep-permission-fix` | Auto-fixes vendored ripgrep +x permission on start (fixes broken commands/skills) | [#41933](https://github.com/anthropics/claude-code/issues/41933) |
125
132
 
@@ -146,7 +153,7 @@ Guards against issues that corrupt sessions or waste tokens silently.
146
153
  | `--scan [--apply]` | Tech stack detection |
147
154
  | `--export / --import` | Team config sharing |
148
155
  | `--verify` | Test each hook |
149
- | `--install-example <name>` | Install from 650 examples |
156
+ | `--install-example <name>` | Install from 653 examples |
150
157
  | `--examples [filter]` | Browse examples by keyword |
151
158
  | `--full` | All-in-one setup |
152
159
  | `--status` | Check installed hooks |
@@ -245,7 +252,10 @@ Safe to run multiple times. Existing settings are preserved. A backup is created
245
252
 
246
253
  **Note:** Hooks are skipped when Claude Code runs with `--bare` or `--dangerously-skip-permissions`. These modes bypass all safety hooks by design.
247
254
 
248
- **Known limitation:** In headless mode (`-p` / `--print`), hook exit code 2 may not block tool execution ([#36071](https://github.com/anthropics/claude-code/issues/36071)). For CI pipelines, use interactive mode with hooks rather than `-p` mode.
255
+ **Known limitations:**
256
+
257
+ - In headless mode (`-p` / `--print`), hook exit code 2 may not block tool execution ([#36071](https://github.com/anthropics/claude-code/issues/36071)). For CI pipelines, use interactive mode with hooks rather than `-p` mode.
258
+ - `FileChanged` notifications inject file contents into model context **before** hooks can intervene. If a sensitive file (`.env`, `credentials.json`) is modified externally during a session, its contents may appear in the conversation transcript regardless of hooks ([#44909](https://github.com/anthropics/claude-code/issues/44909)). Mitigation: use `dotenv-watch` to get alerted, and avoid editing sensitive files while Claude Code is running.
249
259
 
250
260
  ## Before / After
251
261
 
@@ -335,6 +335,32 @@ This prevents `ToolSearch` deferred loading and preserves the cache prefix acros
335
335
 
336
336
  **Related issues**: [#41249](https://github.com/anthropics/claude-code/issues/41249), [#41788](https://github.com/anthropics/claude-code/issues/41788), [#38335](https://github.com/anthropics/claude-code/issues/38335), [#40524](https://github.com/anthropics/claude-code/issues/40524), [#41617](https://github.com/anthropics/claude-code/issues/41617)
337
337
 
338
+ ## Multiple Hook Sources: stdin Race Condition
339
+
340
+ **Symptom**: Safety hooks appear installed but don't block dangerous commands. No errors, no warnings — hooks just silently allow everything.
341
+
342
+ **Root cause**: When multiple `PreToolUse` hooks match the same tool (e.g., two hooks both matching `Bash`), only the first hook receives stdin. The second hook gets empty input, all guard conditions fail, and it exits 0 (allow). This is an upstream Claude Code bug ([#42702](https://github.com/anthropics/claude-code/issues/42702)).
343
+
344
+ **When this happens**:
345
+ - cc-safe-setup hooks + another hook provider (e.g., project-level `.claude/settings.json` hooks)
346
+ - cc-safe-setup hooks + manually added hooks in `~/.claude/settings.json` that match the same trigger
347
+
348
+ **When this does NOT happen**:
349
+ - cc-safe-setup is the only hook source (default install)
350
+
351
+ **How to verify your hooks receive input**:
352
+
353
+ Add a temporary debug line to the top of a hook:
354
+
355
+ ```bash
356
+ INPUT=$(cat)
357
+ echo "DEBUG: input length = ${#INPUT}" >&2
358
+ ```
359
+
360
+ If you see `input length = 0`, that hook is not receiving stdin.
361
+
362
+ **Workaround**: Ensure only one hook source matches each trigger+matcher combination. If you need multiple hooks on the same trigger, combine them into a single script.
363
+
338
364
  ## Still Stuck?
339
365
 
340
366
  1. Wrap the hook with debug wrapper: `npx cc-safe-setup --install-example hook-debug-wrapper`
@@ -1,6 +1,6 @@
1
1
  # Example Hooks
2
2
 
3
- 518 installable hooks. Each solves a real problem from GitHub Issues or autonomous operation. 7,603 tests.
3
+ 658 installable hooks. Each solves a real problem from GitHub Issues or autonomous operation. 9,200+ tests.
4
4
 
5
5
  ```bash
6
6
  npx cc-safe-setup --install-example <name> # install one
@@ -0,0 +1,58 @@
1
+ #!/bin/bash
2
+ # activity-logger.sh — Log all tool uses to JSONL for audit and debugging
3
+ #
4
+ # Solves: "What did Claude do overnight?" — no activity trail after long sessions
5
+ # Also useful for: error tracking, cost analysis, compliance auditing
6
+ #
7
+ # Records every tool call with timestamp, tool name, and key metadata.
8
+ # Error patterns in Bash output are flagged for downstream guards.
9
+ #
10
+ # Usage: Add to settings.json as a PostToolUse hook
11
+ #
12
+ # {
13
+ # "hooks": {
14
+ # "PostToolUse": [{
15
+ # "matcher": "",
16
+ # "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/activity-logger.sh" }]
17
+ # }]
18
+ # }
19
+ # }
20
+ #
21
+ # Output: ~/.claude/activity-log.jsonl
22
+ # Each line is a JSON object with ts, tool, and tool-specific fields.
23
+
24
+ set -u
25
+
26
+ INPUT=$(cat)
27
+ TOOL=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
28
+ [ -z "$TOOL" ] && exit 0
29
+
30
+ LOG_FILE="${HOME}/.claude/activity-log.jsonl"
31
+ TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
32
+
33
+ case "$TOOL" in
34
+ Edit|Write)
35
+ FILE=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
36
+ printf '{"ts":"%s","tool":"%s","file":"%s"}\n' "$TS" "$TOOL" "$FILE" >> "$LOG_FILE"
37
+ ;;
38
+ Bash)
39
+ CMD=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null | head -c 200)
40
+ STDOUT=$(printf '%s' "$INPUT" | jq -r '.stdout // empty' 2>/dev/null | head -c 500)
41
+ EXIT_CODE=$(printf '%s' "$INPUT" | jq -r '.tool_result.exit_code // "0"' 2>/dev/null)
42
+ ERROR_PATTERN=""
43
+ if echo "$STDOUT" | grep -qiE '(error|ENOENT|EACCES|EPERM|fatal|panic|segfault)'; then
44
+ ERROR_PATTERN=$(echo "$STDOUT" | grep -oiE '(error|ENOENT|EACCES|EPERM|fatal|panic|segfault)' | head -1)
45
+ fi
46
+ printf '{"ts":"%s","tool":"%s","cmd":"%s","exit_code":%s,"error_pattern":"%s"}\n' \
47
+ "$TS" "$TOOL" "$(echo "$CMD" | tr '"' "'")" "$EXIT_CODE" "$ERROR_PATTERN" >> "$LOG_FILE"
48
+ ;;
49
+ Read)
50
+ FILE=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
51
+ printf '{"ts":"%s","tool":"%s","file":"%s"}\n' "$TS" "$TOOL" "$FILE" >> "$LOG_FILE"
52
+ ;;
53
+ *)
54
+ printf '{"ts":"%s","tool":"%s"}\n' "$TS" "$TOOL" >> "$LOG_FILE"
55
+ ;;
56
+ esac
57
+
58
+ exit 0
@@ -25,8 +25,9 @@ if echo "$FILE_PATH" | grep -qE '\.claude/'; then
25
25
  jq -n '{
26
26
  hookSpecificOutput: {
27
27
  hookEventName: "PermissionRequest",
28
- permissionDecision: "allow",
29
- permissionDecisionReason: "Allowed: .claude/ directory (isolated environment)"
28
+ decision: {
29
+ behavior: "allow"
30
+ }
30
31
  }
31
32
  }'
32
33
  exit 0
@@ -21,8 +21,9 @@ if echo "$FILE_PATH" | grep -qE '\.git/hooks/[^/]+$'; then
21
21
  jq -n '{
22
22
  hookSpecificOutput: {
23
23
  hookEventName: "PermissionRequest",
24
- permissionDecision: "allow",
25
- permissionDecisionReason: "Allowed: git hooks directory"
24
+ decision: {
25
+ behavior: "allow"
26
+ }
26
27
  }
27
28
  }'
28
29
  exit 0
@@ -24,8 +24,9 @@ if echo "$FILE_PATH" | grep -qE '\.(claude|git|vscode|idea)/'; then
24
24
  jq -n '{
25
25
  hookSpecificOutput: {
26
26
  hookEventName: "PermissionRequest",
27
- permissionDecision: "allow",
28
- permissionDecisionReason: "Allowed: protected directory (full bypass)"
27
+ decision: {
28
+ behavior: "allow"
29
+ }
29
30
  }
30
31
  }'
31
32
  exit 0
@@ -51,7 +51,7 @@ SAFE_COMMANDS="git|npm|npx|bun|yarn|pnpm|docker|make|cargo|go|pip|python3|node|t
51
51
  BASE_CMD=$(echo "$COMMAND" | tr '\n' ' ' | sed 's/^[[:space:]]*//' | sed 's/^[A-Z_]*=[^ ]* //' | sed 's/^cd [^&;]* *[&;]* *//' | awk '{print $1}' | sed 's|.*/||')
52
52
 
53
53
  if echo "$BASE_CMD" | grep -qE "^($SAFE_COMMANDS)$"; then
54
- echo '{"permissionDecision":"allow"}'
54
+ jq -n '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
55
55
  exit 0
56
56
  fi
57
57
 
@@ -0,0 +1,59 @@
1
+ #!/bin/bash
2
+ # decision-warn.sh — Warn and log irreversible operations
3
+ #
4
+ # Solves: "Why did Claude push to production?" — no decision trail for critical actions
5
+ # Detects dangerous operations (git push, rm -rf, database commands) and logs them
6
+ # to a decision log for post-incident analysis.
7
+ #
8
+ # Usage: Add to settings.json as a PostToolUse hook
9
+ #
10
+ # {
11
+ # "hooks": {
12
+ # "PostToolUse": [{
13
+ # "matcher": "Bash",
14
+ # "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/decision-warn.sh" }]
15
+ # }]
16
+ # }
17
+ # }
18
+ #
19
+ # Output: ~/.claude/decision-log.jsonl
20
+ # Each entry logs the command, timestamp, and detected risk category.
21
+
22
+ set -u
23
+
24
+ INPUT=$(cat)
25
+ TOOL=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
26
+ [ "$TOOL" = "Bash" ] || exit 0
27
+
28
+ CMD=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
29
+ [ -z "$CMD" ] && exit 0
30
+
31
+ LOG_FILE="${HOME}/.claude/decision-log.jsonl"
32
+ TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
33
+
34
+ RISK=""
35
+
36
+ # Detect irreversible operations
37
+ if echo "$CMD" | grep -qE 'git\s+push'; then
38
+ RISK="git-push"
39
+ elif echo "$CMD" | grep -qE 'git\s+reset\s+--hard'; then
40
+ RISK="git-reset-hard"
41
+ elif echo "$CMD" | grep -qE 'rm\s+(-rf|--recursive)'; then
42
+ RISK="destructive-delete"
43
+ elif echo "$CMD" | grep -qiE '(DROP\s+(TABLE|DATABASE)|TRUNCATE|DELETE\s+FROM)'; then
44
+ RISK="database-destructive"
45
+ elif echo "$CMD" | grep -qE 'npm\s+publish'; then
46
+ RISK="npm-publish"
47
+ elif echo "$CMD" | grep -qE 'curl\s+.*-X\s*(DELETE|PUT|POST)'; then
48
+ RISK="api-mutation"
49
+ fi
50
+
51
+ [ -z "$RISK" ] && exit 0
52
+
53
+ printf '{"ts":"%s","risk":"%s","cmd":"%s"}\n' \
54
+ "$TS" "$RISK" "$(echo "$CMD" | head -c 200 | tr '"' "'")" >> "$LOG_FILE"
55
+
56
+ echo "[DECISION] $RISK: $(echo "$CMD" | head -c 100)" >&2
57
+ echo " → Logged to: $LOG_FILE" >&2
58
+
59
+ exit 0
@@ -24,8 +24,15 @@ OLD_CWD=$(echo "$INPUT" | jq -r '.old_cwd // empty' 2>/dev/null)
24
24
  if [ -f "${NEW_CWD}/.envrc" ]; then
25
25
  echo "📂 Directory changed: found .envrc in ${NEW_CWD}" >&2
26
26
  if command -v direnv &>/dev/null; then
27
- echo " direnv: auto-allowing and loading" >&2
28
- cd "$NEW_CWD" && direnv allow . 2>/dev/null && eval "$(direnv export bash 2>/dev/null)"
27
+ # Write exports to CLAUDE_ENV_FILE so Claude Code picks them up
28
+ # (eval in a subshell would be lost CLAUDE_ENV_FILE persists to BashTool)
29
+ if [ -n "$CLAUDE_ENV_FILE" ]; then
30
+ echo " direnv: auto-allowing and writing to CLAUDE_ENV_FILE" >&2
31
+ cd "$NEW_CWD" && direnv allow . 2>/dev/null && \
32
+ direnv export bash > "$CLAUDE_ENV_FILE" 2>/dev/null
33
+ else
34
+ echo " ⚠ CLAUDE_ENV_FILE not set — direnv exports won't persist" >&2
35
+ fi
29
36
  else
30
37
  echo " ⚠ direnv not installed — .envrc found but not loaded" >&2
31
38
  fi
@@ -28,15 +28,21 @@ if echo "$COMMAND" | grep -qE 'git\s+add\s+.*\.env'; then
28
28
  exit 2
29
29
  fi
30
30
 
31
- # Check for git add -A/-f that might include .env
32
- if echo "$COMMAND" | grep -qE 'git\s+add\s+(-A|--all|-f|--force)\b'; then
33
- # Check if .env exists in the working directory
31
+ # Check for git add -f/--force (bypasses .gitignore can stage secrets)
32
+ # GitHub Issue anthropics/claude-code#44730: auto-mode used git add -f to
33
+ # force-add .gitignore'd secret files, exposing credentials in a commit.
34
+ if echo "$COMMAND" | grep -qE 'git\s+add\s+.*(-f|--force)\b'; then
35
+ echo "BLOCKED: 'git add --force' bypasses .gitignore and can stage secret files." >&2
36
+ echo " Use 'git add <specific-file>' without --force instead." >&2
37
+ exit 2
38
+ fi
39
+
40
+ # Check for git add -A/--all that might include .env
41
+ if echo "$COMMAND" | grep -qE 'git\s+add\s+(-A|--all)\b'; then
34
42
  if [ -f ".env" ] || [ -f ".env.local" ] || [ -f ".env.production" ]; then
35
- # Check if .gitignore excludes it
36
43
  if ! git check-ignore -q .env 2>/dev/null; then
37
44
  echo "WARNING: 'git add -A' with .env file not in .gitignore." >&2
38
45
  echo " Add .env to .gitignore before staging all files." >&2
39
- # Warning only for git add -A
40
46
  fi
41
47
  fi
42
48
  fi
@@ -0,0 +1,62 @@
1
+ #!/bin/bash
2
+ # proof-log-session.sh — Generate session summary on Stop event
3
+ #
4
+ # Solves: "What did the AI do last week?" — activity logs exist but are unreadable
5
+ # Creates a human-readable 5W1H summary from the activity log at session end.
6
+ #
7
+ # Usage: Add to settings.json as a Stop hook
8
+ #
9
+ # {
10
+ # "hooks": {
11
+ # "Stop": [{
12
+ # "matcher": "",
13
+ # "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/proof-log-session.sh" }]
14
+ # }]
15
+ # }
16
+ # }
17
+ #
18
+ # Output: ~/ops/proof-log/YYYY-MM-DD.md (appended)
19
+ # Requires: activity-logger.sh to be running as a PostToolUse hook
20
+
21
+ set -u
22
+
23
+ LOG_FILE="${HOME}/.claude/activity-log.jsonl"
24
+ DATE=$(date +"%Y-%m-%d")
25
+ PROOF_DIR="${HOME}/ops/proof-log"
26
+ PROOF_FILE="${PROOF_DIR}/${DATE}.md"
27
+
28
+ mkdir -p "$PROOF_DIR"
29
+
30
+ [ ! -f "$LOG_FILE" ] && exit 0
31
+
32
+ # Count today's activity
33
+ TODAY_START=$(date -u -d "today 00:00:00" +"%Y-%m-%dT" 2>/dev/null || date -u +"%Y-%m-%dT")
34
+ EDIT_COUNT=$(grep -c '"tool":"Edit"' "$LOG_FILE" 2>/dev/null) || EDIT_COUNT=0
35
+ WRITE_COUNT=$(grep -c '"tool":"Write"' "$LOG_FILE" 2>/dev/null) || WRITE_COUNT=0
36
+ BASH_COUNT=$(grep -c '"tool":"Bash"' "$LOG_FILE" 2>/dev/null) || BASH_COUNT=0
37
+ READ_COUNT=$(grep -c '"tool":"Read"' "$LOG_FILE" 2>/dev/null) || READ_COUNT=0
38
+ ERROR_COUNT=$(grep -c '"error_pattern":"[^"]*[a-zA-Z]' "$LOG_FILE" 2>/dev/null) || ERROR_COUNT=0
39
+
40
+ # Get edited files
41
+ FILES=$(grep '"tool":"Edit\|Write"' "$LOG_FILE" 2>/dev/null | jq -r '.file // empty' 2>/dev/null | sort -u | head -10)
42
+
43
+ {
44
+ echo ""
45
+ echo "## Session $(date +"%H:%M")"
46
+ echo "- Edit: ${EDIT_COUNT}, Write: ${WRITE_COUNT}, Bash: ${BASH_COUNT}, Read: ${READ_COUNT}"
47
+ [ "$ERROR_COUNT" -gt 0 ] && echo "- Errors detected: ${ERROR_COUNT}"
48
+ if [ -n "$FILES" ]; then
49
+ echo "- Files touched:"
50
+ echo "$FILES" | while read -r f; do
51
+ [ -n "$f" ] && echo " - $f"
52
+ done
53
+ fi
54
+ } >> "$PROOF_FILE"
55
+
56
+ # Rotate activity log (keep last 1000 lines)
57
+ LINE_COUNT=$(wc -l < "$LOG_FILE" 2>/dev/null) || LINE_COUNT=0
58
+ if [ "$LINE_COUNT" -gt 1000 ]; then
59
+ tail -1000 "$LOG_FILE" > "${LOG_FILE}.tmp" && mv "${LOG_FILE}.tmp" "$LOG_FILE"
60
+ fi
61
+
62
+ exit 0
package/index.mjs CHANGED
@@ -690,6 +690,14 @@ function examples() {
690
690
  'write-overwrite-confirm.sh': 'Warn when Write tool overwrites large files',
691
691
  'write-secret-guard.sh': 'Block secrets from being written to files',
692
692
  'write-shrink-guard.sh': 'Block writes that drastically shrink files',
693
+ 'cch-cache-guard.sh': 'Block reads of session files to prevent cache poisoning',
694
+ 'conversation-history-guard.sh': 'Block modifications to conversation history',
695
+ 'image-file-validator.sh': 'Block reads of fake image files that corrupt sessions',
696
+ 'permission-denial-enforcer.sh': 'Block alternative write methods after permission denial',
697
+ 'read-only-mode.sh': 'Block all file modifications and destructive commands',
698
+ 'replace-all-guard.sh': 'Warn when Edit uses replace_all: true',
699
+ 'task-integrity-guard.sh': 'Prevent Claude from deleting tasks to hide unfinished work',
700
+ 'working-directory-fence.sh': 'Block file operations outside current working directory',
693
701
  },
694
702
  'Auto-Approve': {
695
703
  'allow-claude-settings.sh': 'PermissionRequest hook',
@@ -927,6 +935,9 @@ function examples() {
927
935
  'tool-call-rate-limiter.sh': 'Prevent runaway tool calls',
928
936
  'tool-file-logger.sh': 'Log file paths from Read/Write/Edit to stderr',
929
937
  'usage-cache-local.sh': 'Cache usage info locally to avoid API calls',
938
+ 'compact-alert-notification.sh': 'Warn when context compaction is imminent',
939
+ 'prompt-usage-logger.sh': 'Log every prompt with timestamps',
940
+ 'subagent-error-detector.sh': 'Detect failed subagent results',
930
941
  },
931
942
  'Recovery': {
932
943
  'auto-checkpoint.sh': 'Auto-commit after every edit for rollback protection',
@@ -956,6 +967,10 @@ function examples() {
956
967
  'session-summary.sh': 'Session Summary',
957
968
  'settings-auto-backup.sh': 'Auto-backup settings on session start',
958
969
  'terminal-state-restore.sh': 'terminal-state-restore — restore terminal to clean state on session exit',
970
+ 'pre-compact-transcript-backup.sh': 'Backup transcript before compaction',
971
+ 'ripgrep-permission-fix.sh': 'Auto-fix ripgrep execute permission on session start',
972
+ 'session-backup-on-start.sh': 'Backup session JSONL files on start',
973
+ 'session-index-repair.sh': 'Rebuild sessions-index.json on exit',
959
974
  },
960
975
  'UX': {
961
976
  'auto-answer-question.sh': 'Auto-answer AskUserQuestion for headless/autonomous mode',
@@ -1028,6 +1043,7 @@ function examples() {
1028
1043
  },
1029
1044
  'Other': {
1030
1045
  'token-spike-alert.sh': 'Alert on abnormal token consumption per turn',
1046
+ 'mcp-warmup-wait.sh': 'Wait for MCP servers to be ready on session start',
1031
1047
  },
1032
1048
  };
1033
1049
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-safe-setup",
3
- "version": "29.6.39",
3
+ "version": "29.6.40",
4
4
  "description": "One command to make Claude Code safe. 650 example hooks + 8 built-in. 56 CLI commands. Token consumption diagnosis. Works with Auto Mode.",
5
5
  "main": "index.mjs",
6
6
  "bin": {