cc-safe-setup 3.7.0 → 3.8.1

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,73 @@
1
+ # Contributing to cc-safe-setup
2
+
3
+ Thanks for considering a contribution. Here's how to add a new hook.
4
+
5
+ ## Adding an Example Hook
6
+
7
+ 1. Create `examples/your-hook-name.sh`
8
+ 2. Add the standard header comment:
9
+
10
+ ```bash
11
+ #!/bin/bash
12
+ # ================================================================
13
+ # your-hook-name.sh — Short description
14
+ # ================================================================
15
+ # PURPOSE: What it does and why
16
+ # TRIGGER: PreToolUse | PostToolUse | Stop
17
+ # MATCHER: "Bash" | "Edit|Write" | ""
18
+ # ================================================================
19
+ ```
20
+
21
+ 3. Handle empty input:
22
+
23
+ ```bash
24
+ INPUT=$(cat)
25
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
26
+ [ -z "$COMMAND" ] && exit 0
27
+ ```
28
+
29
+ 4. Use exit codes correctly:
30
+ - `exit 0` = allow
31
+ - `exit 2` = block
32
+ - Never use `exit 1` for blocking
33
+
34
+ 5. Add to `index.mjs` categories (search for `CATEGORIES`)
35
+ 6. Add to `README.md` examples list
36
+ 7. Run tests: `bash test.sh`
37
+
38
+ ## Testing Your Hook
39
+
40
+ ```bash
41
+ # Manual test
42
+ echo '{"tool_input":{"command":"your test command"}}' | bash examples/your-hook.sh
43
+ echo $?
44
+
45
+ # Auto-test
46
+ npx cc-hook-test examples/your-hook.sh
47
+ ```
48
+
49
+ ## Hook Quality Checklist
50
+
51
+ - [ ] Handles empty input (exits 0)
52
+ - [ ] Uses `exit 2` for blocking (not `exit 1`)
53
+ - [ ] Has descriptive stderr messages on block
54
+ - [ ] Passes `bash -n` syntax check
55
+ - [ ] Linked to a GitHub Issue if applicable
56
+ - [ ] Added to README.md and index.mjs categories
57
+
58
+ ## Pull Request Process
59
+
60
+ 1. Fork and create a branch
61
+ 2. Add your hook + update README + update categories
62
+ 3. Run `bash test.sh` (all must pass)
63
+ 4. Submit PR with:
64
+ - What the hook does
65
+ - Which GitHub Issue inspired it (if any)
66
+ - Test evidence (manual or cc-hook-test output)
67
+
68
+ ## Code Style
69
+
70
+ - Bash hooks (not Python/Node) for zero dependencies
71
+ - `jq` for JSON parsing
72
+ - Short variable names are fine (`CMD`, `FILE`, `INPUT`)
73
+ - Comments explain *why*, not *what*
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.**
7
+ **One command to make Claude Code safe for autonomous operation.** [日本語](docs/README.ja.md)
8
8
 
9
9
  8 built-in hooks + 32 installable examples. Audit, create, lint, diff, watch, and learn. [Cheat Sheet](https://yurukusa.github.io/cc-safe-setup/cheatsheet.html) · [Web Tool](https://yurukusa.github.io/cc-safe-setup/) · [Troubleshooting](TROUBLESHOOTING.md)
10
10
 
@@ -224,6 +224,8 @@ Or browse all available examples in [`examples/`](examples/):
224
224
  - **session-handoff.sh** — Auto-save git state and session info to `~/.claude/session-handoff.md` on session end
225
225
  - **diff-size-guard.sh** — Warn/block when committing too many files at once (default: warn at 10, block at 50)
226
226
  - **dependency-audit.sh** — Warn when installing packages not in manifest (npm/pip/cargo supply chain awareness)
227
+ - **cost-tracker.sh** — Estimate session token cost and warn at thresholds ($1, $5)
228
+ - **read-before-edit.sh** — Warn when editing files not recently read (prevents old_string mismatches)
227
229
 
228
230
  ## Safety Checklist
229
231
 
@@ -244,7 +246,7 @@ Or browse all available examples in [`examples/`](examples/):
244
246
  ## Learn More
245
247
 
246
248
  - [Official Hooks Reference](https://docs.anthropic.com/en/docs/claude-code/hooks) — Claude Code hooks documentation
247
- - [Hooks Cookbook](https://github.com/yurukusa/claude-code-hooks/blob/main/COOKBOOK.md) — 19 ready-to-use recipes from real GitHub Issues
249
+ - [Hooks Cookbook](https://github.com/yurukusa/claude-code-hooks/blob/main/COOKBOOK.md) — 25 recipes from real GitHub Issues ([interactive version](https://yurukusa.github.io/claude-code-hooks/))
248
250
  - [Japanese guide (Qiita)](https://qiita.com/yurukusa/items/a9714b33f5d974e8f1e8) — この記事の日本語解説
249
251
  - [Hook Test Runner](https://github.com/yurukusa/cc-hook-test) — `npx cc-hook-test <hook.sh>` to auto-test any hook
250
252
  - [Hooks Cheat Sheet](https://yurukusa.github.io/cc-safe-setup/cheatsheet.html) — printable A4 quick reference
@@ -88,6 +88,31 @@ a { color: #58a6ff; text-decoration: none; }
88
88
  <div class="tab-content" id="tab-fix"></div>
89
89
  <div class="tab-content" id="tab-manual"></div>
90
90
 
91
+ <h2 style="margin-top:2rem">Hook Builder</h2>
92
+ <p class="subtitle">Build a custom hook without writing code.</p>
93
+
94
+ <div style="display:flex;gap:1rem;flex-wrap:wrap;margin:.5rem 0">
95
+ <div style="flex:1;min-width:200px">
96
+ <label style="color:#8b949e;font-size:.8rem">What should the hook do?</label>
97
+ <select id="hb-action" style="width:100%;padding:.5rem;background:#161b22;border:1px solid #30363d;border-radius:4px;color:#c9d1d9;margin-top:.25rem">
98
+ <option value="block">Block a command</option>
99
+ <option value="warn">Warn about a command</option>
100
+ <option value="approve">Auto-approve a command</option>
101
+ </select>
102
+ </div>
103
+ <div style="flex:2;min-width:300px">
104
+ <label style="color:#8b949e;font-size:.8rem">Command pattern (regex)</label>
105
+ <input id="hb-pattern" placeholder="e.g. rm\s+-rf, git push --force, npm publish" style="width:100%;padding:.5rem;background:#161b22;border:1px solid #30363d;border-radius:4px;color:#c9d1d9;margin-top:.25rem;font-family:monospace;font-size:.85rem">
106
+ </div>
107
+ </div>
108
+ <div style="margin:.5rem 0">
109
+ <label style="color:#8b949e;font-size:.8rem">Message shown to Claude</label>
110
+ <input id="hb-message" placeholder="e.g. Run tests before publishing" style="width:100%;padding:.5rem;background:#161b22;border:1px solid #30363d;border-radius:4px;color:#c9d1d9;margin-top:.25rem">
111
+ </div>
112
+ <button class="btn" onclick="buildHook()">Generate Hook</button>
113
+
114
+ <div id="hb-result" style="margin-top:1rem"></div>
115
+
91
116
  <p class="privacy">100% client-side. Your settings never leave this page. <a href="https://github.com/yurukusa/cc-safe-setup">Source</a> · <a href="https://www.npmjs.com/package/cc-safe-setup">npm</a> · <a href="ecosystem.html">Compare all hook projects</a></p>
92
117
  </div>
93
118
 
@@ -599,6 +624,48 @@ exit 0`
599
624
  return scripts[id] || '#!/bin/bash\nexit 0';
600
625
  }
601
626
 
627
+ function buildHook() {
628
+ const action = document.getElementById('hb-action').value;
629
+ const pattern = document.getElementById('hb-pattern').value.trim();
630
+ const message = document.getElementById('hb-message').value.trim() || 'Blocked by hook';
631
+ const el = document.getElementById('hb-result');
632
+
633
+ if (!pattern) { el.innerHTML = '<p style="color:#f85149">Enter a command pattern.</p>'; return; }
634
+
635
+ let script = '#!/bin/bash\n';
636
+ script += 'INPUT=$(cat)\n';
637
+ script += 'COMMAND=$(echo "$INPUT" | jq -r \'.tool_input.command // empty\' 2>/dev/null)\n';
638
+ script += '[ -z "$COMMAND" ] && exit 0\n\n';
639
+
640
+ if (action === 'block') {
641
+ script += 'if echo "$COMMAND" | grep -qE \'' + pattern.replace(/'/g, "'\\''") + '\'; then\n';
642
+ script += ' echo "BLOCKED: ' + message.replace(/"/g, '\\"') + '" >&2\n';
643
+ script += ' echo "Command: $COMMAND" >&2\n';
644
+ script += ' exit 2\n';
645
+ script += 'fi\n';
646
+ } else if (action === 'warn') {
647
+ script += 'if echo "$COMMAND" | grep -qE \'' + pattern.replace(/'/g, "'\\''") + '\'; then\n';
648
+ script += ' echo "WARNING: ' + message.replace(/"/g, '\\"') + '" >&2\n';
649
+ script += ' echo "Command: $COMMAND" >&2\n';
650
+ script += 'fi\n';
651
+ } else if (action === 'approve') {
652
+ script += 'if echo "$COMMAND" | grep -qE \'' + pattern.replace(/'/g, "'\\''") + '\'; then\n';
653
+ script += ' jq -n \'{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"' + message.replace(/"/g, '\\"') + '"}}\'\n';
654
+ script += 'fi\n';
655
+ }
656
+ script += 'exit 0';
657
+
658
+ const settings = {
659
+ hooks: { PreToolUse: [{ matcher: 'Bash', hooks: [{ type: 'command', command: '~/.claude/hooks/custom-hook.sh' }] }] }
660
+ };
661
+
662
+ el.innerHTML = '<h3>Hook Script</h3>' +
663
+ '<div class="code-block"><button class="copy-btn" onclick="copyText(\'hb-script\')">Copy</button><pre id="hb-script">' + escHtml(script) + '</pre></div>' +
664
+ '<h3>settings.json entry</h3>' +
665
+ '<div class="code-block"><button class="copy-btn" onclick="copyText(\'hb-settings\')">Copy</button><pre id="hb-settings">' + escHtml(JSON.stringify(settings, null, 2)) + '</pre></div>' +
666
+ '<p style="color:#8b949e;font-size:.8rem;margin-top:.5rem">Save the script as <code>~/.claude/hooks/custom-hook.sh</code>, run <code>chmod +x</code>, and merge the settings entry.</p>';
667
+ }
668
+
602
669
  // Auto-load from URL parameter: ?config=base64encodedJSON
603
670
  (function() {
604
671
  const params = new URLSearchParams(window.location.search);
@@ -0,0 +1,64 @@
1
+ # cc-safe-setup
2
+
3
+ **Claude Codeを安全にするワンコマンドツール。**
4
+
5
+ 8個の安全フック + 36個のインストール可能なexample。destructive guard、branch protection、secret leak prevention、syntax check、context monitor、その他。
6
+
7
+ ```bash
8
+ npx cc-safe-setup
9
+ ```
10
+
11
+ ## 何ができるか
12
+
13
+ | コマンド | 機能 |
14
+ |---|---|
15
+ | `npx cc-safe-setup` | 8個の安全フックをインストール |
16
+ | `--create "説明"` | 自然言語でカスタムフック生成 |
17
+ | `--audit` | 安全スコア(0-100) |
18
+ | `--lint` | 設定の静的解析 |
19
+ | `--diff <file>` | 設定を比較 |
20
+ | `--benchmark` | フック実行速度を計測 |
21
+ | `--doctor` | 動かない原因を診断 |
22
+ | `--watch` | ブロックされたコマンドをリアルタイム表示 |
23
+ | `--stats` | ブロック統計レポート |
24
+ | `--share` | 共有URLを生成 |
25
+ | `--export / --import` | チームで設定を共有 |
26
+ | `--verify` | 各フックの動作確認 |
27
+ | `--install-example <name>` | 36個のexampleフック |
28
+
29
+ ## インストール
30
+
31
+ ```bash
32
+ npx cc-safe-setup
33
+ ```
34
+
35
+ Claude Codeを再起動。完了。
36
+
37
+ ## 何がブロックされるか
38
+
39
+ | 操作 | Before | After |
40
+ |---|---|---|
41
+ | `rm -rf /` | 実行される | ブロック |
42
+ | `git push --force` | 実行される | ブロック |
43
+ | `git push origin main` | 実行される | ブロック |
44
+ | `git add .env` | 実行される | ブロック |
45
+ | Python構文エラー | 気づかない | 自動検出 |
46
+ | コンテキスト枯渇 | 突然死 | 段階的警告 |
47
+
48
+ ## ドキュメント
49
+
50
+ - [settings.jsonリファレンス](../SETTINGS_REFERENCE.md) — 全設定の解説
51
+ - [移行ガイド](../MIGRATION.md) — permissionsからhooksへ
52
+ - [トラブルシューティング](../TROUBLESHOOTING.md) — 動かない時の対処法
53
+ - [チートシート](https://yurukusa.github.io/cc-safe-setup/cheatsheet.html) — 印刷用A4
54
+ - [エコシステム比較](https://yurukusa.github.io/cc-safe-setup/ecosystem.html) — 全hookプロジェクト比較
55
+ - [Web版](https://yurukusa.github.io/cc-safe-setup/) — ブラウザで診断+セットアップ生成
56
+
57
+ ## 必要なもの
58
+
59
+ - `jq`: `brew install jq` / `apt install jq`
60
+ - Claude Code 2.1以上
61
+
62
+ ## ライセンス
63
+
64
+ MIT
package/docs/index.html CHANGED
@@ -88,6 +88,31 @@ a { color: #58a6ff; text-decoration: none; }
88
88
  <div class="tab-content" id="tab-fix"></div>
89
89
  <div class="tab-content" id="tab-manual"></div>
90
90
 
91
+ <h2 style="margin-top:2rem">Hook Builder</h2>
92
+ <p class="subtitle">Build a custom hook without writing code.</p>
93
+
94
+ <div style="display:flex;gap:1rem;flex-wrap:wrap;margin:.5rem 0">
95
+ <div style="flex:1;min-width:200px">
96
+ <label style="color:#8b949e;font-size:.8rem">What should the hook do?</label>
97
+ <select id="hb-action" style="width:100%;padding:.5rem;background:#161b22;border:1px solid #30363d;border-radius:4px;color:#c9d1d9;margin-top:.25rem">
98
+ <option value="block">Block a command</option>
99
+ <option value="warn">Warn about a command</option>
100
+ <option value="approve">Auto-approve a command</option>
101
+ </select>
102
+ </div>
103
+ <div style="flex:2;min-width:300px">
104
+ <label style="color:#8b949e;font-size:.8rem">Command pattern (regex)</label>
105
+ <input id="hb-pattern" placeholder="e.g. rm\s+-rf, git push --force, npm publish" style="width:100%;padding:.5rem;background:#161b22;border:1px solid #30363d;border-radius:4px;color:#c9d1d9;margin-top:.25rem;font-family:monospace;font-size:.85rem">
106
+ </div>
107
+ </div>
108
+ <div style="margin:.5rem 0">
109
+ <label style="color:#8b949e;font-size:.8rem">Message shown to Claude</label>
110
+ <input id="hb-message" placeholder="e.g. Run tests before publishing" style="width:100%;padding:.5rem;background:#161b22;border:1px solid #30363d;border-radius:4px;color:#c9d1d9;margin-top:.25rem">
111
+ </div>
112
+ <button class="btn" onclick="buildHook()">Generate Hook</button>
113
+
114
+ <div id="hb-result" style="margin-top:1rem"></div>
115
+
91
116
  <p class="privacy">100% client-side. Your settings never leave this page. <a href="https://github.com/yurukusa/cc-safe-setup">Source</a> · <a href="https://www.npmjs.com/package/cc-safe-setup">npm</a> · <a href="ecosystem.html">Compare all hook projects</a></p>
92
117
  </div>
93
118
 
@@ -599,6 +624,48 @@ exit 0`
599
624
  return scripts[id] || '#!/bin/bash\nexit 0';
600
625
  }
601
626
 
627
+ function buildHook() {
628
+ const action = document.getElementById('hb-action').value;
629
+ const pattern = document.getElementById('hb-pattern').value.trim();
630
+ const message = document.getElementById('hb-message').value.trim() || 'Blocked by hook';
631
+ const el = document.getElementById('hb-result');
632
+
633
+ if (!pattern) { el.innerHTML = '<p style="color:#f85149">Enter a command pattern.</p>'; return; }
634
+
635
+ let script = '#!/bin/bash\n';
636
+ script += 'INPUT=$(cat)\n';
637
+ script += 'COMMAND=$(echo "$INPUT" | jq -r \'.tool_input.command // empty\' 2>/dev/null)\n';
638
+ script += '[ -z "$COMMAND" ] && exit 0\n\n';
639
+
640
+ if (action === 'block') {
641
+ script += 'if echo "$COMMAND" | grep -qE \'' + pattern.replace(/'/g, "'\\''") + '\'; then\n';
642
+ script += ' echo "BLOCKED: ' + message.replace(/"/g, '\\"') + '" >&2\n';
643
+ script += ' echo "Command: $COMMAND" >&2\n';
644
+ script += ' exit 2\n';
645
+ script += 'fi\n';
646
+ } else if (action === 'warn') {
647
+ script += 'if echo "$COMMAND" | grep -qE \'' + pattern.replace(/'/g, "'\\''") + '\'; then\n';
648
+ script += ' echo "WARNING: ' + message.replace(/"/g, '\\"') + '" >&2\n';
649
+ script += ' echo "Command: $COMMAND" >&2\n';
650
+ script += 'fi\n';
651
+ } else if (action === 'approve') {
652
+ script += 'if echo "$COMMAND" | grep -qE \'' + pattern.replace(/'/g, "'\\''") + '\'; then\n';
653
+ script += ' jq -n \'{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"' + message.replace(/"/g, '\\"') + '"}}\'\n';
654
+ script += 'fi\n';
655
+ }
656
+ script += 'exit 0';
657
+
658
+ const settings = {
659
+ hooks: { PreToolUse: [{ matcher: 'Bash', hooks: [{ type: 'command', command: '~/.claude/hooks/custom-hook.sh' }] }] }
660
+ };
661
+
662
+ el.innerHTML = '<h3>Hook Script</h3>' +
663
+ '<div class="code-block"><button class="copy-btn" onclick="copyText(\'hb-script\')">Copy</button><pre id="hb-script">' + escHtml(script) + '</pre></div>' +
664
+ '<h3>settings.json entry</h3>' +
665
+ '<div class="code-block"><button class="copy-btn" onclick="copyText(\'hb-settings\')">Copy</button><pre id="hb-settings">' + escHtml(JSON.stringify(settings, null, 2)) + '</pre></div>' +
666
+ '<p style="color:#8b949e;font-size:.8rem;margin-top:.5rem">Save the script as <code>~/.claude/hooks/custom-hook.sh</code>, run <code>chmod +x</code>, and merge the settings entry.</p>';
667
+ }
668
+
602
669
  // Auto-load from URL parameter: ?config=base64encodedJSON
603
670
  (function() {
604
671
  const params = new URLSearchParams(window.location.search);
@@ -0,0 +1,56 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # cost-tracker.sh — Estimate session token cost
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Claude Code doesn't show token costs. This hook tracks
7
+ # tool calls and estimates cumulative cost, warning at thresholds.
8
+ #
9
+ # TRIGGER: PostToolUse
10
+ # MATCHER: ""
11
+ #
12
+ # HOW IT WORKS:
13
+ # Counts tool calls as a proxy for token usage.
14
+ # Average tool call ≈ 2K tokens input + 1K output.
15
+ # Opus: $15/M input, $75/M output
16
+ # Sonnet: $3/M input, $15/M output
17
+ #
18
+ # CONFIGURATION:
19
+ # CC_COST_MODEL=opus (default) or sonnet
20
+ # CC_COST_WARN=1.00 warn at $1 (default)
21
+ # CC_COST_BLOCK=5.00 warn at $5 (default, doesn't block)
22
+ # ================================================================
23
+
24
+ COUNTER_FILE="/tmp/cc-cost-tracker-calls"
25
+ LAST_WARN="/tmp/cc-cost-tracker-warned"
26
+
27
+ COUNT=$(cat "$COUNTER_FILE" 2>/dev/null || echo 0)
28
+ COUNT=$((COUNT + 1))
29
+ echo "$COUNT" > "$COUNTER_FILE"
30
+
31
+ MODEL="${CC_COST_MODEL:-opus}"
32
+ WARN="${CC_COST_WARN:-1.00}"
33
+ BLOCK="${CC_COST_BLOCK:-5.00}"
34
+
35
+ # Estimate: ~2K input + ~1K output tokens per tool call
36
+ if [ "$MODEL" = "opus" ]; then
37
+ # Opus: $15/M in, $75/M out → ~$0.105 per tool call
38
+ COST=$(echo "scale=2; $COUNT * 0.105" | bc 2>/dev/null || echo "0")
39
+ else
40
+ # Sonnet: $3/M in, $15/M out → ~$0.021 per tool call
41
+ COST=$(echo "scale=2; $COUNT * 0.021" | bc 2>/dev/null || echo "0")
42
+ fi
43
+
44
+ # Graduated warnings (with cooldown)
45
+ WARNED=$(cat "$LAST_WARN" 2>/dev/null || echo "0")
46
+
47
+ if [ "$(echo "$COST >= $BLOCK" | bc 2>/dev/null)" = "1" ] && [ "$WARNED" != "block" ]; then
48
+ echo "COST: ~\$${COST} estimated ($COUNT tool calls, $MODEL)" >&2
49
+ echo "Consider finishing current task and compacting." >&2
50
+ echo "block" > "$LAST_WARN"
51
+ elif [ "$(echo "$COST >= $WARN" | bc 2>/dev/null)" = "1" ] && [ "$WARNED" = "0" ]; then
52
+ echo "COST: ~\$${COST} estimated ($COUNT tool calls, $MODEL)" >&2
53
+ echo "warn" > "$LAST_WARN"
54
+ fi
55
+
56
+ exit 0
@@ -0,0 +1,44 @@
1
+ #!/bin/bash
2
+ # ================================================================
3
+ # read-before-edit.sh — Warn when editing files not recently read
4
+ # ================================================================
5
+ # PURPOSE:
6
+ # Claude Code sometimes tries to Edit files it hasn't Read,
7
+ # leading to old_string mismatches. This hook tracks which
8
+ # files were recently Read and warns when Edit targets an
9
+ # unread file.
10
+ #
11
+ # TRIGGER: PreToolUse
12
+ # MATCHER: "Edit"
13
+ #
14
+ # HOW IT WORKS:
15
+ # - PostToolUse Read hook records file paths to /tmp/cc-read-files
16
+ # - This PreToolUse Edit hook checks if the target was read
17
+ # - Warns (doesn't block) if file wasn't read recently
18
+ #
19
+ # NOTE: Requires companion PostToolUse hook to record Read events.
20
+ # Or just install this and accept the warning.
21
+ # ================================================================
22
+
23
+ INPUT=$(cat)
24
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
25
+ FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
26
+
27
+ # Only check Edit tool
28
+ if [[ "$TOOL" != "Edit" ]] || [[ -z "$FILE" ]]; then
29
+ exit 0
30
+ fi
31
+
32
+ READ_LOG="/tmp/cc-read-files"
33
+
34
+ # Check if file was recently read
35
+ if [ -f "$READ_LOG" ]; then
36
+ if grep -qF "$FILE" "$READ_LOG" 2>/dev/null; then
37
+ exit 0 # File was read, safe to edit
38
+ fi
39
+ fi
40
+
41
+ echo "NOTE: Editing $FILE without reading it first." >&2
42
+ echo "Consider using Read before Edit to avoid old_string mismatches." >&2
43
+
44
+ exit 0
package/index.mjs CHANGED
@@ -356,6 +356,8 @@ function examples() {
356
356
  'commit-quality-gate.sh': 'Warn on vague or too-long commit messages',
357
357
  'diff-size-guard.sh': 'Warn/block on large diffs (10+ files warn, 50+ block)',
358
358
  'dependency-audit.sh': 'Warn on new package installs not in manifest',
359
+ 'cost-tracker.sh': 'Estimate session token cost ($1 warn, $5 alert)',
360
+ 'read-before-edit.sh': 'Warn when editing files not recently read',
359
361
  },
360
362
  };
361
363
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-safe-setup",
3
- "version": "3.7.0",
3
+ "version": "3.8.1",
4
4
  "description": "One command to make Claude Code safe for autonomous operation. 8 built-in + 36 examples. 21 commands: create, audit, lint, diff, share, benchmark, watch, learn. 2,500+ daily npm downloads.",
5
5
  "main": "index.mjs",
6
6
  "bin": {