cc-safe-setup 11.7.0 → 11.8.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.
package/docs/index.html DELETED
@@ -1,271 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>cc-safe-setup — Claude Code Safety Suite</title>
7
- <meta name="description" content="Audit, build, browse, and learn Claude Code hooks. All in one page, 100% client-side.">
8
- <style>
9
- *{box-sizing:border-box;margin:0;padding:0}
10
- body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0d1117;color:#c9d1d9;min-height:100vh}
11
- .nav{display:flex;background:#161b22;border-bottom:1px solid #30363d;overflow-x:auto}
12
- .nav a{padding:.75rem 1.2rem;color:#8b949e;text-decoration:none;font-size:.85rem;white-space:nowrap;border-bottom:2px solid transparent;cursor:pointer}
13
- .nav a.active{color:#f0f6fc;border-bottom-color:#f78166}
14
- .nav a:hover{color:#c9d1d9}
15
- .page{display:none;max-width:800px;margin:0 auto;padding:1.5rem}
16
- .page.active{display:block}
17
- h1{font-size:1.3rem;color:#f0f6fc;margin-bottom:.5rem}
18
- h2{font-size:1.1rem;color:#f0f6fc;margin:1.5rem 0 .5rem}
19
- h3{font-size:.95rem;color:#c9d1d9;margin:1rem 0 .3rem}
20
- p,.sub{color:#8b949e;font-size:.85rem;margin-bottom:.75rem}
21
- a{color:#58a6ff;text-decoration:none}
22
- textarea,input,select{width:100%;padding:.5rem;background:#161b22;border:1px solid #30363d;border-radius:4px;color:#c9d1d9;font-family:monospace;font-size:.8rem;margin:.25rem 0}
23
- textarea{height:150px;resize:vertical}
24
- button,.btn{background:#238636;color:#fff;border:none;padding:.5rem 1rem;border-radius:4px;cursor:pointer;font-size:.85rem;margin:.25rem .25rem .25rem 0}
25
- button:hover,.btn:hover{background:#2ea043}
26
- .btn-sm{padding:.25rem .5rem;font-size:.75rem}
27
- .btn-secondary{background:#30363d}
28
- pre{background:#161b22;border:1px solid #30363d;border-radius:4px;padding:.6rem;font-size:.75rem;overflow-x:auto;position:relative;margin:.3rem 0}
29
- .copy{position:absolute;top:.3rem;right:.3rem;background:#30363d;color:#c9d1d9;border:none;padding:.15rem .4rem;border-radius:3px;font-size:.65rem;cursor:pointer}
30
- .score{font-size:1.8rem;font-weight:bold;margin:.5rem 0}
31
- .score.good{color:#3fb950} .score.mid{color:#d29922} .score.bad{color:#f85149}
32
- .risk{background:#161b22;border:1px solid #30363d;border-radius:4px;padding:.75rem;margin:.3rem 0;font-size:.8rem}
33
- .good-item{color:#3fb950;margin:.2rem 0;font-size:.8rem}
34
- table{width:100%;border-collapse:collapse;font-size:.8rem;margin:.5rem 0}
35
- th,td{text-align:left;padding:.35rem .5rem;border-bottom:1px solid #21262d}
36
- th{font-weight:600;color:#f0f6fc}
37
- .recipe{background:#161b22;border:1px solid #30363d;border-radius:4px;margin:.3rem 0;overflow:hidden}
38
- .recipe summary{padding:.5rem .75rem;cursor:pointer;font-weight:600;color:#f0f6fc;font-size:.85rem}
39
- .recipe-body{padding:0 .75rem .5rem}
40
- .filter{padding:.2rem .5rem;border-radius:3px;border:1px solid #30363d;background:transparent;color:#8b949e;cursor:pointer;font-size:.7rem;margin:.15rem}
41
- .filter.active{background:#238636;border-color:#238636;color:#fff}
42
- .badge{display:inline-block;padding:.1rem .3rem;border-radius:3px;font-size:.65rem;font-weight:bold}
43
- .badge-bash{background:#1f6feb22;color:#58a6ff;border:1px solid #1f6feb44}
44
- .badge-js{background:#f0e68c22;color:#f0e68c;border:1px solid #f0e68c44}
45
- .badge-py{background:#3fb95022;color:#3fb950;border:1px solid #3fb95044}
46
- .badge-ts{background:#388bfd22;color:#388bfd;border:1px solid #388bfd44}
47
- .check{color:#3fb950} .cross{color:#484f58}
48
- .footer{text-align:center;color:#484f58;font-size:.7rem;padding:2rem 1rem}
49
- @media print{.nav{display:none} .page{display:block!important}}
50
- </style>
51
- </head>
52
- <body>
53
-
54
- <nav class="nav">
55
- <a onclick="go('audit')" id="nav-audit" class="active">Audit</a>
56
- <a onclick="go('builder')" id="nav-builder">Hook Builder</a>
57
- <a onclick="go('cookbook')" id="nav-cookbook">Cookbook</a>
58
- <a onclick="go('ecosystem')" id="nav-ecosystem">Ecosystem</a>
59
- <a onclick="go('cheatsheet')" id="nav-cheatsheet">Cheat Sheet</a>
60
- </nav>
61
-
62
- <!-- PAGE: AUDIT -->
63
- <div class="page active" id="page-audit">
64
- <h1>Safety Audit</h1>
65
- <p>Paste your <code>~/.claude/settings.json</code>. Nothing leaves your browser.</p>
66
- <textarea id="settings" placeholder='{"permissions":{"allow":["Bash(git:*)"]},"hooks":{"PreToolUse":[...]}}'></textarea>
67
- <button onclick="runAudit()">Run Audit</button>
68
- <button class="btn-secondary" onclick="generateFresh()">Generate Fresh Setup</button>
69
- <div id="audit-results"></div>
70
- </div>
71
-
72
- <!-- PAGE: HOOK BUILDER -->
73
- <div class="page" id="page-builder">
74
- <h1>Hook Builder</h1>
75
- <p>Build a custom hook without writing code.</p>
76
- <div style="display:flex;gap:.75rem;flex-wrap:wrap">
77
- <div style="flex:1;min-width:180px">
78
- <label style="font-size:.75rem;color:#8b949e">Action</label>
79
- <select id="hb-action"><option value="block">Block</option><option value="warn">Warn</option><option value="approve">Auto-approve</option></select>
80
- </div>
81
- <div style="flex:2;min-width:250px">
82
- <label style="font-size:.75rem;color:#8b949e">Pattern (regex)</label>
83
- <input id="hb-pattern" placeholder="e.g. rm\s+-rf, git push --force">
84
- </div>
85
- </div>
86
- <label style="font-size:.75rem;color:#8b949e">Message</label>
87
- <input id="hb-message" placeholder="e.g. Run tests before pushing">
88
- <button onclick="buildHook()">Generate</button>
89
- <div id="hb-result"></div>
90
- </div>
91
-
92
- <!-- PAGE: COOKBOOK -->
93
- <div class="page" id="page-cookbook">
94
- <h1>Hooks Cookbook</h1>
95
- <p>Copy-paste recipes from real GitHub Issues.</p>
96
- <input id="cb-search" placeholder="Search... (database, git, deploy)" oninput="filterRecipes()">
97
- <div style="margin:.3rem 0" id="cb-filters"></div>
98
- <div id="cb-count" style="color:#8b949e;font-size:.8rem"></div>
99
- <div id="cb-list"></div>
100
- </div>
101
-
102
- <!-- PAGE: ECOSYSTEM -->
103
- <div class="page" id="page-ecosystem">
104
- <h1>Ecosystem Comparison</h1>
105
- <p>All major Claude Code hook projects compared.</p>
106
- <table>
107
- <tr><th>Project</th><th>Lang</th><th>Hooks</th><th>Install</th></tr>
108
- <tr><td><a href="https://github.com/kenryu42/claude-code-safety-net">safety-net</a></td><td><span class="badge badge-ts">TS</span></td><td>5</td><td>npx</td></tr>
109
- <tr><td><a href="https://github.com/yurukusa/cc-safe-setup">cc-safe-setup</a></td><td><span class="badge badge-bash">Bash</span></td><td>8+39</td><td>npx</td></tr>
110
- <tr><td><a href="https://github.com/karanb192/claude-code-hooks">karanb192</a></td><td><span class="badge badge-js">JS</span></td><td>5+</td><td>copy</td></tr>
111
- <tr><td><a href="https://github.com/disler/claude-code-hooks-mastery">mastery</a></td><td><span class="badge badge-py">Python</span></td><td>12</td><td>copy</td></tr>
112
- <tr><td><a href="https://github.com/lasso-security/claude-hooks">lasso</a></td><td><span class="badge badge-py">Python</span></td><td>1</td><td>install.sh</td></tr>
113
- </table>
114
- <h2>Feature Matrix</h2>
115
- <table>
116
- <tr><th>Feature</th><th>safety-net</th><th>cc-safe-setup</th><th>karanb192</th><th>mastery</th></tr>
117
- <tr><td>rm -rf blocker</td><td class="check">✓</td><td class="check">✓</td><td class="check">✓</td><td class="check">✓</td></tr>
118
- <tr><td>Branch guard</td><td class="check">✓</td><td class="check">✓</td><td class="cross">-</td><td class="cross">-</td></tr>
119
- <tr><td>Secret guard</td><td class="cross">-</td><td class="check">✓</td><td class="check">✓</td><td class="cross">-</td></tr>
120
- <tr><td>Syntax check</td><td class="cross">-</td><td class="check">✓</td><td class="cross">-</td><td class="cross">-</td></tr>
121
- <tr><td>Context monitor</td><td class="cross">-</td><td class="check">✓</td><td class="cross">-</td><td class="cross">-</td></tr>
122
- <tr><td>Hook generator</td><td class="cross">-</td><td class="check">✓</td><td class="cross">-</td><td class="cross">-</td></tr>
123
- <tr><td>Dashboard</td><td class="cross">-</td><td class="check">✓</td><td class="cross">-</td><td class="cross">-</td></tr>
124
- <tr><td>GitHub Action</td><td class="cross">-</td><td class="check">✓</td><td class="cross">-</td><td class="cross">-</td></tr>
125
- </table>
126
- </div>
127
-
128
- <!-- PAGE: CHEAT SHEET -->
129
- <div class="page" id="page-cheatsheet">
130
- <h1>Hooks Cheat Sheet</h1>
131
- <p>Print this page (Ctrl+P) for a quick reference.</p>
132
-
133
- <h3>Lifecycle</h3>
134
- <pre>Prompt → PreToolUse → Tool → PostToolUse → Stop</pre>
135
-
136
- <h3>Exit Codes</h3>
137
- <table><tr><th>Code</th><th>Meaning</th></tr>
138
- <tr><td><code>0</code></td><td>Allow</td></tr>
139
- <tr><td><code>2</code></td><td><strong>Block</strong></td></tr></table>
140
-
141
- <h3>Minimal Block Hook</h3>
142
- <pre>#!/bin/bash
143
- CMD=$(cat | jq -r '.tool_input.command // empty')
144
- [ -z "$CMD" ] && exit 0
145
- echo "$CMD" | grep -qE 'PATTERN' && echo "BLOCKED" >&2 && exit 2
146
- exit 0</pre>
147
-
148
- <h3>Auto-Approve Hook</h3>
149
- <pre>#!/bin/bash
150
- CMD=$(cat | jq -r '.tool_input.command // empty')
151
- [ -z "$CMD" ] && exit 0
152
- echo "$CMD" | grep -qE '^git\s+(status|log|diff)' && \
153
- jq -n '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
154
- exit 0</pre>
155
-
156
- <h3>Quick Commands</h3>
157
- <table>
158
- <tr><td><code>npx cc-safe-setup</code></td><td>Install 8 hooks</td></tr>
159
- <tr><td><code>--create "desc"</code></td><td>Generate hook</td></tr>
160
- <tr><td><code>--audit</code></td><td>Score 0-100</td></tr>
161
- <tr><td><code>--dashboard</code></td><td>Live status</td></tr>
162
- <tr><td><code>--doctor</code></td><td>Diagnose</td></tr>
163
- <tr><td><code>--benchmark</code></td><td>Speed test</td></tr>
164
- </table>
165
- </div>
166
-
167
- <div class="footer">
168
- cc-safe-setup · 100% client-side · <a href="https://github.com/yurukusa/cc-safe-setup">GitHub</a> · <a href="https://www.npmjs.com/package/cc-safe-setup">npm</a>
169
- </div>
170
-
171
- <script>
172
- // Navigation
173
- function go(page) {
174
- document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
175
- document.querySelectorAll('.nav a').forEach(a => a.classList.remove('active'));
176
- document.getElementById('page-' + page).classList.add('active');
177
- document.getElementById('nav-' + page).classList.add('active');
178
- }
179
-
180
- // AUDIT
181
- function runAudit() {
182
- const raw = document.getElementById('settings').value.trim();
183
- const el = document.getElementById('audit-results');
184
- if (!raw) { generateFresh(); return; }
185
- let s; try { s = JSON.parse(raw); } catch { el.innerHTML='<p style="color:#f85149">Invalid JSON</p>'; return; }
186
- const {risks,good,score} = analyze(s);
187
- renderAudit(risks, good, score, el);
188
- }
189
- function generateFresh() {
190
- const {risks,good,score} = analyze({});
191
- renderAudit(risks, good, score, document.getElementById('audit-results'));
192
- }
193
- function analyze(s) {
194
- const risks=[], good=[];
195
- const pre=s.hooks?.PreToolUse||[], post=s.hooks?.PostToolUse||[];
196
- const all=JSON.stringify(pre).toLowerCase();
197
- if(!pre.length) risks.push({s:'CRITICAL',i:'No PreToolUse hooks',f:'npx cc-safe-setup'});
198
- else { good.push('PreToolUse ('+pre.length+')');
199
- if(!all.match(/destructive|guard|rm.*rf/)) risks.push({s:'HIGH',i:'No destructive guard',f:'npx cc-safe-setup'});
200
- else good.push('Destructive protection');
201
- if(!all.match(/branch|push|main/)) risks.push({s:'HIGH',i:'No branch guard',f:'npx cc-safe-setup'});
202
- else good.push('Branch protection');
203
- if(!all.match(/secret|env|credential/)) risks.push({s:'HIGH',i:'No secret guard',f:'npx cc-safe-setup'});
204
- else good.push('Secret protection');
205
- }
206
- if(!post.length) risks.push({s:'MEDIUM',i:'No PostToolUse hooks',f:'npx cc-safe-setup'});
207
- else good.push('PostToolUse ('+post.length+')');
208
- const score=Math.max(0,100-risks.reduce((n,r)=>n+(r.s==='CRITICAL'?30:r.s==='HIGH'?20:10),0));
209
- return {risks,good,score};
210
- }
211
- function renderAudit(risks,good,score,el) {
212
- const cls=score>=80?'good':score>=50?'mid':'bad';
213
- let h='<div class="score '+cls+'">'+score+'/100</div>';
214
- if(good.length) { h+='<h3 style="color:#3fb950">Working</h3>'; good.forEach(g=>h+='<div class="good-item">✓ '+g+'</div>'); }
215
- if(risks.length) { h+='<h3>Risks ('+risks.length+')</h3>'; risks.forEach(r=>h+='<div class="risk"><strong>['+r.s+']</strong> '+r.i+'<br><code>'+r.f+'</code></div>'); }
216
- if(!risks.length) h+='<p style="color:#3fb950">No risks detected.</p>';
217
- el.innerHTML=h;
218
- }
219
-
220
- // HOOK BUILDER
221
- function buildHook() {
222
- const action=document.getElementById('hb-action').value;
223
- const pattern=document.getElementById('hb-pattern').value.trim();
224
- const message=document.getElementById('hb-message').value.trim()||'Blocked';
225
- const el=document.getElementById('hb-result');
226
- if(!pattern){el.innerHTML='<p style="color:#f85149">Enter a pattern</p>';return;}
227
- let s='#!/bin/bash\nCMD=$(cat | jq -r \'.tool_input.command // empty\' 2>/dev/null)\n[ -z "$CMD" ] && exit 0\n';
228
- if(action==='block') s+='echo "$CMD" | grep -qE \''+pattern+'\' && echo "BLOCKED: '+message+'" >&2 && exit 2\n';
229
- else if(action==='warn') s+='echo "$CMD" | grep -qE \''+pattern+'\' && echo "WARNING: '+message+'" >&2\n';
230
- else s+='echo "$CMD" | grep -qE \''+pattern+'\' && jq -n \'{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}\'\n';
231
- s+='exit 0';
232
- el.innerHTML='<h3>Script</h3><pre>'+esc(s)+'</pre><p style="font-size:.75rem;color:#8b949e">Save as ~/.claude/hooks/custom.sh, chmod +x, add to settings.json</p>';
233
- }
234
-
235
- // COOKBOOK
236
- const RECIPES=[
237
- {cat:'block',t:'Block rm -rf',d:'Destructive commands (#36339)',code:'CMD=$(cat|jq -r \'.tool_input.command // empty\')\n[ -z "$CMD" ] && exit 0\necho "$CMD"|grep -qE \'rm\\s+(-[rf]+\\s+)*/\' && echo "BLOCKED" >&2 && exit 2\nexit 0',trigger:'PreToolUse'},
238
- {cat:'block',t:'Block force push',d:'Branch protection',code:'CMD=$(cat|jq -r \'.tool_input.command // empty\')\n[ -z "$CMD" ] && exit 0\necho "$CMD"|grep -qE \'git\\s+push.*--force\' && echo "BLOCKED" >&2 && exit 2\nexit 0',trigger:'PreToolUse'},
239
- {cat:'block',t:'Block .env staging',d:'Secret leak prevention (#6527)',code:'CMD=$(cat|jq -r \'.tool_input.command // empty\')\n[ -z "$CMD" ] && exit 0\necho "$CMD"|grep -qiE \'git\\s+add.*\\.env\' && echo "BLOCKED" >&2 && exit 2\nexit 0',trigger:'PreToolUse'},
240
- {cat:'block',t:'Block database wipe',d:'migrate:fresh, DROP DATABASE (#37405)',code:'CMD=$(cat|jq -r \'.tool_input.command // empty\')\n[ -z "$CMD" ] && exit 0\necho "$CMD"|grep -qiE \'migrate:fresh|DROP\\s+DATABASE|prisma\\s+migrate\\s+reset\' && echo "BLOCKED" >&2 && exit 2\nexit 0',trigger:'PreToolUse'},
241
- {cat:'approve',t:'Auto-approve git read',d:'git status/log/diff with -C flag (#36900)',code:'CMD=$(cat|jq -r \'.tool_input.command // empty\')\n[ -z "$CMD" ] && exit 0\necho "$CMD"|grep -qE \'^\\s*git\\s+(-C\\s+\\S+\\s+)?(status|log|diff|branch|show)\' && jq -n \'{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}\'\nexit 0',trigger:'PreToolUse'},
242
- {cat:'approve',t:'Compound commands',d:'cd && git log auto-approve (#30519)',code:'# Full: npx cc-safe-setup --install-example compound-command-approver',trigger:'PreToolUse'},
243
- {cat:'detect',t:'Loop detector',d:'Break command repetition (5+ times)',code:'CMD=$(cat|jq -r \'.tool_input.command // empty\')\n[ -z "$CMD" ] && exit 0\nSTATE=/tmp/cc-loop\necho "$CMD">>$STATE\ntail -n 10 $STATE>${STATE}.tmp&&mv ${STATE}.tmp $STATE\nCOUNT=$(grep -cF "$CMD" $STATE||echo 0)\n[ "$COUNT" -ge 5 ]&&echo "BLOCKED: repeated $COUNT times" >&2&&exit 2\nexit 0',trigger:'PreToolUse'},
244
- {cat:'utility',t:'Session handoff',d:'Save state for next session',code:'# npx cc-safe-setup --install-example session-handoff',trigger:'Stop'},
245
- {cat:'utility',t:'Cost tracker',d:'Estimate session token cost',code:'# npx cc-safe-setup --install-example cost-tracker',trigger:'PostToolUse'},
246
- {cat:'utility',t:'tmp cleanup',d:'/tmp/claude-*-cwd files (#8856)',code:'find /tmp -maxdepth 1 -name \'claude-*-cwd\' -type f -mmin +60 -delete 2>/dev/null\nexit 0',trigger:'Stop'},
247
- ];
248
-
249
- function initCookbook() {
250
- const cats=['all','block','approve','detect','utility'];
251
- document.getElementById('cb-filters').innerHTML=cats.map(c=>'<button class="filter'+(c==='all'?' active':'')+'" onclick="setCbFilter(\''+c+'\')">'+c+'</button>').join('');
252
- filterRecipes();
253
- }
254
- let cbFilter='all';
255
- function setCbFilter(f){cbFilter=f;document.querySelectorAll('#cb-filters .filter').forEach(b=>b.classList.toggle('active',b.textContent===f));filterRecipes();}
256
- function filterRecipes(){
257
- const q=(document.getElementById('cb-search')?.value||'').toLowerCase();
258
- const filtered=RECIPES.filter(r=>(cbFilter==='all'||r.cat===cbFilter)&&(!q||r.t.toLowerCase().includes(q)||r.d.toLowerCase().includes(q)||(r.code||'').toLowerCase().includes(q)));
259
- document.getElementById('cb-count').textContent=filtered.length+' recipe(s)';
260
- document.getElementById('cb-list').innerHTML=filtered.map(r=>'<details class="recipe"><summary>'+esc(r.t)+' <span style="color:#484f58;font-size:.7rem">['+r.trigger+']</span></summary><div class="recipe-body"><p style="color:#8b949e;font-size:.8rem">'+esc(r.d)+'</p>'+(r.code?'<pre>'+esc(r.code)+'</pre>':'')+'</div></details>').join('');
261
- }
262
-
263
- function esc(s){return(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');}
264
-
265
- // URL param
266
- (function(){const p=new URLSearchParams(location.search);const c=p.get('config');if(c){try{document.getElementById('settings').value=atob(c);runAudit();}catch{}}})();
267
-
268
- initCookbook();
269
- </script>
270
- </body>
271
- </html>
package/docs/matrix.html DELETED
@@ -1,139 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Claude Code Hooks Matrix — 112 Hooks at a Glance</title>
7
- <meta name="description" content="Interactive matrix of all 112 Claude Code hooks. Filter by trigger, category, and action type.">
8
- <style>
9
- *{box-sizing:border-box;margin:0;padding:0}
10
- body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0d1117;color:#c9d1d9;padding:1rem;font-size:.82rem}
11
- .c{max-width:1100px;margin:0 auto}
12
- h1{color:#f0f6fc;font-size:1.3rem;margin-bottom:.2rem}
13
- .sub{color:#8b949e;font-size:.8rem;margin-bottom:.8rem}
14
- a{color:#58a6ff;text-decoration:none}
15
- input{width:100%;padding:.5rem;background:#161b22;border:1px solid #30363d;border-radius:6px;color:#c9d1d9;font-size:.85rem;margin-bottom:.5rem}
16
- input::placeholder{color:#484f58}
17
- .filters{display:flex;gap:.3rem;flex-wrap:wrap;margin-bottom:.5rem}
18
- .f{padding:.2rem .5rem;border-radius:3px;border:1px solid #30363d;background:transparent;color:#8b949e;cursor:pointer;font-size:.7rem}
19
- .f.on{background:#238636;border-color:#238636;color:#fff}
20
- table{width:100%;border-collapse:collapse}
21
- th,td{padding:.3rem .4rem;border:1px solid #21262d;text-align:left;font-size:.75rem}
22
- th{background:#161b22;color:#f0f6fc;position:sticky;top:0;cursor:pointer}
23
- th:hover{background:#21262d}
24
- tr:hover td{background:#161b2288}
25
- .act-block{color:#f85149;font-weight:bold}
26
- .act-warn{color:#d29922}
27
- .act-approve{color:#3fb950}
28
- .act-monitor{color:#58a6ff}
29
- .count{color:#8b949e;font-size:.78rem;margin:.3rem 0}
30
- .footer{text-align:center;color:#484f58;font-size:.65rem;margin-top:1rem}
31
- td code{background:#21262d;padding:.1rem .2rem;border-radius:2px;font-size:.7rem;cursor:pointer}
32
- td code:hover{color:#58a6ff}
33
- </style>
34
- </head>
35
- <body>
36
- <div class="c">
37
- <h1>Hook Matrix</h1>
38
- <p class="sub">112 hooks. Click column headers to sort. Search to filter.</p>
39
-
40
- <input id="q" placeholder="Filter hooks..." oninput="render()">
41
- <div class="filters" id="filters"></div>
42
- <div class="count" id="count"></div>
43
- <div style="overflow-x:auto"><table id="tbl"><thead><tr>
44
- <th onclick="sortBy('name')">Hook</th>
45
- <th onclick="sortBy('cat')">Category</th>
46
- <th onclick="sortBy('trigger')">Trigger</th>
47
- <th onclick="sortBy('action')">Action</th>
48
- <th>Description</th>
49
- <th>Install</th>
50
- </tr></thead><tbody id="tbody"></tbody></table></div>
51
-
52
- <div class="footer">
53
- <a href="hooks-cheatsheet.html">Cheat Sheet</a> ·
54
- <a href="builder.html">Builder</a> ·
55
- <a href="troubleshooting.html">Troubleshoot</a> ·
56
- <a href="https://github.com/yurukusa/cc-safe-setup">GitHub</a>
57
- </div>
58
- </div>
59
-
60
- <script>
61
- const H=[
62
- {n:'destructive-guard',c:'safety',t:'Pre',a:'block',d:'rm -rf, git reset --hard, git clean',i:'npx cc-safe-setup'},
63
- {n:'branch-guard',c:'safety',t:'Pre',a:'block',d:'Push to main/master, force-push',i:'npx cc-safe-setup'},
64
- {n:'secret-guard',c:'safety',t:'Pre',a:'block',d:'git add .env, credential files',i:'npx cc-safe-setup'},
65
- {n:'syntax-check',c:'quality',t:'Post',a:'warn',d:'Python/Shell/JSON/JS syntax after edits',i:'npx cc-safe-setup'},
66
- {n:'context-monitor',c:'monitor',t:'Post',a:'warn',d:'Context warnings at 40/25/20/15%',i:'npx cc-safe-setup'},
67
- {n:'comment-strip',c:'utility',t:'Pre',a:'warn',d:'Fix bash comments breaking permissions',i:'npx cc-safe-setup'},
68
- {n:'cd-git-allow',c:'approve',t:'Pre',a:'approve',d:'Auto-approve cd && git compounds',i:'npx cc-safe-setup'},
69
- {n:'api-error-alert',c:'monitor',t:'Stop',a:'monitor',d:'Notify on session API errors',i:'npx cc-safe-setup'},
70
- {n:'scope-guard',c:'safety',t:'Pre',a:'block',d:'Block operations outside project',i:'--install-example scope-guard'},
71
- {n:'no-sudo-guard',c:'safety',t:'Pre',a:'block',d:'Block all sudo commands',i:'--install-example no-sudo-guard'},
72
- {n:'protect-claudemd',c:'safety',t:'Pre',a:'block',d:'Block edits to CLAUDE.md/settings',i:'--install-example protect-claudemd'},
73
- {n:'protect-dotfiles',c:'safety',t:'Pre',a:'block',d:'Block .bashrc, .aws/, .ssh/ changes',i:'--install-example protect-dotfiles'},
74
- {n:'block-database-wipe',c:'safety',t:'Pre',a:'block',d:'DROP DATABASE, migrate:fresh, prisma reset',i:'--install-example block-database-wipe'},
75
- {n:'deploy-guard',c:'deploy',t:'Pre',a:'warn',d:'Warn deploy with uncommitted changes',i:'--install-example deploy-guard'},
76
- {n:'no-deploy-friday',c:'deploy',t:'Pre',a:'block',d:'Block deploys on Fridays',i:'--install-example no-deploy-friday'},
77
- {n:'work-hours-guard',c:'deploy',t:'Pre',a:'warn',d:'Restrict risky ops outside hours',i:'--install-example work-hours-guard'},
78
- {n:'uncommitted-work-guard',c:'safety',t:'Pre',a:'block',d:'Block destructive git when dirty',i:'--install-example uncommitted-work-guard'},
79
- {n:'test-deletion-guard',c:'quality',t:'Pre',a:'warn',d:'Warn when removing test assertions',i:'--install-example test-deletion-guard'},
80
- {n:'overwrite-guard',c:'safety',t:'Pre',a:'warn',d:'Warn before overwriting files',i:'--install-example overwrite-guard'},
81
- {n:'memory-write-guard',c:'safety',t:'Pre',a:'warn',d:'Log writes to ~/.claude/',i:'--install-example memory-write-guard'},
82
- {n:'fact-check-gate',c:'quality',t:'Post',a:'warn',d:'Docs reference unread source files',i:'--install-example fact-check-gate'},
83
- {n:'token-budget-guard',c:'monitor',t:'Post',a:'block',d:'Block when cost exceeds budget',i:'--install-example token-budget-guard'},
84
- {n:'conflict-marker-guard',c:'quality',t:'Pre',a:'block',d:'Block commits with conflict markers',i:'--install-example conflict-marker-guard'},
85
- {n:'error-memory-guard',c:'safety',t:'Post',a:'block',d:'Block retries of failed commands',i:'--install-example error-memory-guard'},
86
- {n:'strict-allowlist',c:'safety',t:'Pre',a:'block',d:'Only allow permitted commands',i:'--install-example strict-allowlist'},
87
- {n:'hardcoded-secret-detector',c:'security',t:'Post',a:'warn',d:'Detect AWS keys, passwords, JWT',i:'--install-example hardcoded-secret-detector'},
88
- {n:'auto-approve-build',c:'approve',t:'Pre',a:'approve',d:'npm test, cargo build, go test',i:'--install-example auto-approve-build'},
89
- {n:'auto-approve-python',c:'approve',t:'Pre',a:'approve',d:'pytest, mypy, ruff, black',i:'--install-example auto-approve-python'},
90
- {n:'auto-approve-docker',c:'approve',t:'Pre',a:'approve',d:'docker build, compose, ps',i:'--install-example auto-approve-docker'},
91
- {n:'auto-approve-go',c:'approve',t:'Pre',a:'approve',d:'go build/test/vet/fmt',i:'--install-example auto-approve-go'},
92
- {n:'auto-approve-cargo',c:'approve',t:'Pre',a:'approve',d:'cargo build/test/clippy',i:'--install-example auto-approve-cargo'},
93
- {n:'auto-approve-make',c:'approve',t:'Pre',a:'approve',d:'make build/test/lint',i:'--install-example auto-approve-make'},
94
- {n:'auto-approve-gradle',c:'approve',t:'Pre',a:'approve',d:'gradle build/test',i:'--install-example auto-approve-gradle'},
95
- {n:'auto-approve-maven',c:'approve',t:'Pre',a:'approve',d:'mvn compile/test/verify',i:'--install-example auto-approve-maven'},
96
- {n:'loop-detector',c:'safety',t:'Pre',a:'block',d:'Break command repetition loops',i:'--install-example loop-detector'},
97
- {n:'cost-tracker',c:'monitor',t:'Post',a:'monitor',d:'Estimate session token cost',i:'--install-example cost-tracker'},
98
- {n:'session-handoff',c:'utility',t:'Stop',a:'monitor',d:'Save state for next session',i:'--install-example session-handoff'},
99
- {n:'revert-helper',c:'utility',t:'Stop',a:'monitor',d:'Show undo on session end',i:'--install-example revert-helper'},
100
- {n:'compact-reminder',c:'utility',t:'Stop',a:'warn',d:'Suggest /compact after N calls',i:'--install-example compact-reminder'},
101
- {n:'env-drift-guard',c:'quality',t:'Post',a:'warn',d:'.env vs .env.example mismatch',i:'--install-example env-drift-guard'},
102
- {n:'package-script-guard',c:'quality',t:'Pre',a:'warn',d:'Warn on package.json script changes',i:'--install-example package-script-guard'},
103
- {n:'git-blame-context',c:'quality',t:'Pre',a:'monitor',d:'Show file ownership before edits',i:'--install-example git-blame-context'},
104
- {n:'import-cycle-warn',c:'quality',t:'Post',a:'warn',d:'Detect circular imports',i:'--install-example import-cycle-warn'},
105
- {n:'lockfile-guard',c:'quality',t:'Pre',a:'warn',d:'Warn when lockfiles modified',i:'--install-example lockfile-guard'},
106
- {n:'context-snapshot',c:'utility',t:'Stop',a:'monitor',d:'Save branch/files/TODOs state',i:'--install-example context-snapshot'},
107
- {n:'prompt-injection-guard',c:'security',t:'Post',a:'warn',d:'Detect injection in output',i:'--install-example prompt-injection-guard'},
108
- {n:'no-eval',c:'security',t:'Post',a:'warn',d:'Warn on eval() usage',i:'--install-example no-eval'},
109
- {n:'no-console-log',c:'quality',t:'Post',a:'warn',d:'Warn on console.log in prod',i:'--install-example no-console-log'},
110
- {n:'no-wildcard-import',c:'quality',t:'Post',a:'warn',d:'Warn on import * patterns',i:'--install-example no-wildcard-import'},
111
- ];
112
-
113
- const cats=[...new Set(H.map(h=>h.c))].sort();
114
- const actClass={block:'act-block',warn:'act-warn',approve:'act-approve',monitor:'act-monitor'};
115
- let filter='all',sortKey='name',sortDir=1;
116
-
117
- document.getElementById('filters').innerHTML=['all',...cats].map(c=>`<button class="f${c==='all'?' on':''}" onclick="setF('${c}')">${c}</button>`).join('');
118
-
119
- function setF(f){filter=f;document.querySelectorAll('.f').forEach(b=>b.classList.toggle('on',b.textContent===f));render();}
120
- function sortBy(k){if(sortKey===k)sortDir*=-1;else{sortKey=k;sortDir=1;}render();}
121
-
122
- function render(){
123
- const q=document.getElementById('q').value.toLowerCase();
124
- let list=H.filter(h=>(filter==='all'||h.c===filter)&&(!q||h.n.includes(q)||h.d.toLowerCase().includes(q)||h.c.includes(q)));
125
- list.sort((a,b)=>{const av=a[sortKey]||'',bv=b[sortKey]||'';return av<bv?-sortDir:av>bv?sortDir:0;});
126
- document.getElementById('count').textContent=list.length+'/'+H.length+' hooks';
127
- document.getElementById('tbody').innerHTML=list.map(h=>`<tr>
128
- <td><strong>${h.n}</strong></td>
129
- <td>${h.c}</td>
130
- <td>${h.t}</td>
131
- <td class="${actClass[h.a]||''}">${h.a}</td>
132
- <td>${h.d}</td>
133
- <td><code onclick="navigator.clipboard.writeText('npx cc-safe-setup ${h.i}');this.textContent='✓'">${h.i.substring(0,25)}</code></td>
134
- </tr>`).join('');
135
- }
136
- render();
137
- </script>
138
- </body>
139
- </html>
@@ -1,198 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Claude Code Hooks — Migration Guide from Other AI Tools</title>
7
- <meta name="description" content="Moving from Cursor, Windsurf, Aider, or Copilot to Claude Code? Here's how to set up equivalent safety using hooks.">
8
- <style>
9
- *{box-sizing:border-box;margin:0;padding:0}
10
- body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0d1117;color:#c9d1d9;padding:1.5rem;line-height:1.6}
11
- .c{max-width:800px;margin:0 auto}
12
- h1{color:#f0f6fc;font-size:1.5rem;margin-bottom:.3rem}
13
- h2{color:#f0f6fc;font-size:1.1rem;margin:1.5rem 0 .5rem;padding-bottom:.3rem;border-bottom:1px solid #21262d}
14
- h3{color:#c9d1d9;font-size:.9rem;margin:.8rem 0 .3rem}
15
- .sub{color:#8b949e;font-size:.85rem;margin-bottom:1.5rem}
16
- a{color:#58a6ff;text-decoration:none}
17
- code{background:#161b22;padding:.15rem .3rem;border-radius:3px;font-size:.85rem}
18
- pre{background:#161b22;border:1px solid #30363d;border-radius:6px;padding:.7rem;font-size:.8rem;color:#e6edf3;overflow-x:auto;margin:.4rem 0}
19
- table{width:100%;border-collapse:collapse;margin:.5rem 0;font-size:.82rem}
20
- th,td{padding:.4rem .6rem;border:1px solid #21262d;text-align:left}
21
- th{background:#161b22;color:#f0f6fc}
22
- .note{background:#161b22;border-left:3px solid #58a6ff;padding:.5rem .8rem;margin:.5rem 0;font-size:.82rem;color:#8b949e}
23
- .tool{background:#161b22;border:1px solid #30363d;border-radius:6px;padding:.8rem;margin:.6rem 0}
24
- .tool-name{font-weight:600;color:#f0f6fc;font-size:.95rem}
25
- .tool-desc{color:#8b949e;font-size:.82rem;margin:.3rem 0}
26
- .footer{text-align:center;color:#484f58;font-size:.7rem;margin-top:2rem;padding-top:1rem;border-top:1px solid #21262d}
27
- .quick{background:#238636;color:#fff;padding:.5rem 1rem;border-radius:6px;font-family:monospace;font-size:.85rem;border:none;display:block;width:100%;text-align:center;margin:.5rem 0;cursor:pointer}
28
- </style>
29
- </head>
30
- <body>
31
- <div class="c">
32
-
33
- <h1>Migrating to Claude Code</h1>
34
- <p class="sub">Safety setup guide for developers coming from Cursor, Windsurf, Aider, or Copilot</p>
35
-
36
- <button class="quick" onclick="navigator.clipboard.writeText('npx cc-safe-setup --shield');this.textContent='Copied!';setTimeout(()=>this.textContent='npx cc-safe-setup --shield — one command to set up everything',1500)">npx cc-safe-setup --shield — one command to set up everything</button>
37
-
38
- <h2>Why Claude Code is Different</h2>
39
-
40
- <p>Unlike Cursor or Copilot, Claude Code has <strong>full terminal access</strong>. It can run any command, edit any file, push to any branch. This is powerful but requires safety hooks.</p>
41
-
42
- <table>
43
- <tr><th>Feature</th><th>Cursor/Copilot</th><th>Claude Code</th></tr>
44
- <tr><td>Terminal access</td><td>Limited/sandboxed</td><td><strong>Full access</strong></td></tr>
45
- <tr><td>File editing</td><td>IDE-controlled</td><td><strong>Direct filesystem</strong></td></tr>
46
- <tr><td>Git operations</td><td>Via IDE UI</td><td><strong>Direct git commands</strong></td></tr>
47
- <tr><td>Safety model</td><td>IDE sandbox</td><td><strong>Hooks (you configure)</strong></td></tr>
48
- <tr><td>Autonomous mode</td><td>No</td><td><strong>Yes (headless)</strong></td></tr>
49
- </table>
50
-
51
- <div class="note">
52
- <strong>Key difference:</strong> Cursor/Copilot run inside an IDE sandbox. Claude Code runs in your actual terminal. Hooks replace the sandbox.
53
- </div>
54
-
55
- <h2>From Cursor</h2>
56
-
57
- <div class="tool">
58
- <div class="tool-name">Cursor → Claude Code</div>
59
- <div class="tool-desc">Cursor Rules (.cursorrules) → CLAUDE.md + hooks</div>
60
- </div>
61
-
62
- <h3>What you had in Cursor</h3>
63
- <ul>
64
- <li><code>.cursorrules</code> — project-specific instructions</li>
65
- <li>IDE-level file protection</li>
66
- <li>Built-in git safety (can't force-push from UI)</li>
67
- </ul>
68
-
69
- <h3>What you need in Claude Code</h3>
70
- <pre><code># 1. Convert .cursorrules to CLAUDE.md
71
- cp .cursorrules CLAUDE.md # Then edit to Claude Code format
72
-
73
- # 2. Install safety hooks
74
- npx cc-safe-setup --shield
75
-
76
- # 3. Add auto-approve for your workflow
77
- npx cc-safe-setup --install-example auto-approve-build
78
- </code></pre>
79
-
80
- <h3>Key hooks for Cursor migrants</h3>
81
- <table>
82
- <tr><th>Cursor feature</th><th>Hook equivalent</th></tr>
83
- <tr><td>Can't delete system files</td><td><code>destructive-guard</code> + <code>scope-guard</code></td></tr>
84
- <tr><td>IDE confirms before push</td><td><code>branch-guard</code></td></tr>
85
- <tr><td>Lint on save</td><td><code>syntax-check</code></td></tr>
86
- <tr><td>.env excluded from commits</td><td><code>secret-guard</code></td></tr>
87
- </table>
88
-
89
- <h2>From Windsurf</h2>
90
-
91
- <div class="tool">
92
- <div class="tool-name">Windsurf → Claude Code</div>
93
- <div class="tool-desc">Windsurf Rules → CLAUDE.md + hooks</div>
94
- </div>
95
-
96
- <pre><code># Convert Windsurf cascade rules
97
- # Windsurf's "Flows" → Claude Code's autonomous mode + hooks
98
-
99
- npx cc-safe-setup --shield
100
- npx cc-safe-setup --install-example context-snapshot # Preserve state across sessions
101
- npx cc-safe-setup --install-example session-handoff # Hand off between sessions
102
- </code></pre>
103
-
104
- <h2>From Aider</h2>
105
-
106
- <div class="tool">
107
- <div class="tool-name">Aider → Claude Code</div>
108
- <div class="tool-desc">.aider.conf → CLAUDE.md, /lint → syntax-check hook</div>
109
- </div>
110
-
111
- <pre><code># Aider auto-commits → Claude Code needs explicit control
112
- npx cc-safe-setup --shield
113
- npx cc-safe-setup --install-example auto-checkpoint # Similar to Aider's auto-commit
114
- npx cc-safe-setup --install-example verify-before-done # Ensure tests pass before commit
115
-
116
- # Aider's /lint → already covered by syntax-check hook
117
- # Aider's /test → use auto-approve-build to skip prompts
118
- </code></pre>
119
-
120
- <h2>From GitHub Copilot Workspace</h2>
121
-
122
- <div class="tool">
123
- <div class="tool-name">Copilot Workspace → Claude Code</div>
124
- <div class="tool-desc">Copilot's plan-execute → Claude Code's plan mode + hooks</div>
125
- </div>
126
-
127
- <pre><code># Copilot Workspace creates PRs automatically
128
- # Claude Code needs branch protection
129
- npx cc-safe-setup --shield
130
- npx cc-safe-setup --install-example deploy-guard # Prevent accidental deploys
131
- npx cc-safe-setup --install-example diff-size-guard # Warn on large changes
132
- npx cc-safe-setup --install-example pr-description-check # Ensure PR quality
133
- </code></pre>
134
-
135
- <h2>Universal Setup (Any Tool)</h2>
136
-
137
- <pre><code># Step 1: Maximum safety
138
- npx cc-safe-setup --shield
139
-
140
- # Step 2: Check what's installed
141
- npx cc-safe-setup --status
142
-
143
- # Step 3: Verify everything works
144
- npx cc-safe-setup --verify
145
-
146
- # Step 4: View your safety score
147
- npx cc-safe-setup --audit
148
- </code></pre>
149
-
150
- <h2>CLAUDE.md Template</h2>
151
-
152
- <p>Create a <code>CLAUDE.md</code> in your project root:</p>
153
-
154
- <pre><code># Project Rules
155
-
156
- ## Safety
157
- - Do not push to main/master directly
158
- - Do not force-push
159
- - Do not delete files outside this project
160
- - Do not commit .env or credential files
161
- - Run tests before committing
162
-
163
- ## Code Style
164
- - Follow existing conventions in this codebase
165
- - Keep functions small and focused
166
-
167
- ## Git
168
- - Use descriptive commit messages
169
- - One logical change per commit
170
- - Create feature branches for new work
171
- </code></pre>
172
-
173
- <div class="note">
174
- <strong>CLAUDE.md vs .cursorrules:</strong> Same concept, but CLAUDE.md is also read by Claude in the API (not just the CLI). Hooks add enforcement — CLAUDE.md is advisory, hooks are mandatory.
175
- </div>
176
-
177
- <h2>Safety Profile Comparison</h2>
178
-
179
- <table>
180
- <tr><th>Profile</th><th>Hooks</th><th>Best for</th></tr>
181
- <tr><td><code>minimal</code></td><td>8</td><td>Experienced users, quick tasks</td></tr>
182
- <tr><td><code>standard</code></td><td>20</td><td>Daily development, balanced safety</td></tr>
183
- <tr><td><code>strict</code></td><td>33</td><td>Autonomous sessions, production repos</td></tr>
184
- </table>
185
-
186
- <pre><code>npx cc-safe-setup --profile strict # For autonomous/production use
187
- </code></pre>
188
-
189
- <div class="footer">
190
- <a href="hooks-cheatsheet.html">Cheat Sheet</a> ·
191
- <a href="builder.html">Hook Builder</a> ·
192
- <a href="faq.html">FAQ</a> ·
193
- <a href="https://yurukusa.github.io/cc-hook-registry/playground.html">Playground</a> ·
194
- <a href="https://github.com/yurukusa/cc-safe-setup">GitHub</a>
195
- </div>
196
- </div>
197
- </body>
198
- </html>