cc-safe-setup 3.8.1 → 4.0.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.
- package/docs/ROADMAP.md +83 -0
- package/index.mjs +71 -0
- package/package.json +2 -2
package/docs/ROADMAP.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# cc-safe-setup Roadmap
|
|
2
|
+
|
|
3
|
+
## Current: v3.8.1
|
|
4
|
+
|
|
5
|
+
- 8 built-in hooks + 38 examples
|
|
6
|
+
- 21 CLI commands
|
|
7
|
+
- 5 web tools (audit, cheatsheet, ecosystem, cookbook, hook builder)
|
|
8
|
+
- 173 tests, CI green
|
|
9
|
+
- 2,500+ daily npm downloads
|
|
10
|
+
|
|
11
|
+
## Next Major: v4.0 (planned)
|
|
12
|
+
|
|
13
|
+
### --dashboard: Real-Time Terminal Dashboard
|
|
14
|
+
|
|
15
|
+
A single screen showing everything about your Claude Code safety:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
┌─ cc-safe-setup dashboard ─────────────────────────┐
|
|
19
|
+
│ │
|
|
20
|
+
│ Hooks: 26 active (8 built-in + 18 examples) │
|
|
21
|
+
│ Score: 85/100 (Grade A) │
|
|
22
|
+
│ Context: ~60% remaining │
|
|
23
|
+
│ Cost: ~$1.47 (142 tool calls, Opus) │
|
|
24
|
+
│ │
|
|
25
|
+
│ ── Recent Blocks ──────────────────────────────── │
|
|
26
|
+
│ 14:23 rm -rf ~/projects (destructive-guard) │
|
|
27
|
+
│ 14:21 git push --force (branch-guard) │
|
|
28
|
+
│ 14:18 git add .env (secret-guard) │
|
|
29
|
+
│ │
|
|
30
|
+
│ ── Hook Performance ───────────────────────────── │
|
|
31
|
+
│ destructive-guard 15ms ████████ │
|
|
32
|
+
│ branch-guard 7ms ████ │
|
|
33
|
+
│ secret-guard 5ms ███ │
|
|
34
|
+
│ │
|
|
35
|
+
│ ── Today ──────────────────────────────────────── │
|
|
36
|
+
│ Blocks: 12 | Warns: 5 | Approves: 34 │
|
|
37
|
+
│ Top reason: rm on sensitive path (5) │
|
|
38
|
+
└─────────────────────────────────────────────────────┘
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Implementation notes:**
|
|
42
|
+
- ANSI escape codes only (no blessed/ink dependencies)
|
|
43
|
+
- Reads blocked-commands.log + context-monitor state + cost-tracker state
|
|
44
|
+
- Refreshes every 2 seconds
|
|
45
|
+
- Ctrl+C to exit
|
|
46
|
+
- Works in any terminal (iTerm, VS Code, Windows Terminal, WSL)
|
|
47
|
+
|
|
48
|
+
### Hook Marketplace (concept)
|
|
49
|
+
|
|
50
|
+
Community-contributed hooks discoverable from CLI:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx cc-safe-setup --search "database"
|
|
54
|
+
npx cc-safe-setup --install-remote user/hook-name
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Would require a registry (GitHub-based, no server). Defer to v5.0.
|
|
58
|
+
|
|
59
|
+
### Hook Composition
|
|
60
|
+
|
|
61
|
+
Chain hooks with conditions:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"hooks": [{
|
|
66
|
+
"if": "branch === 'main'",
|
|
67
|
+
"then": "block-all-writes.sh",
|
|
68
|
+
"else": "allow-all.sh"
|
|
69
|
+
}]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Requires Claude Code API changes. Not feasible with current hook system.
|
|
74
|
+
|
|
75
|
+
## Done (Session 39)
|
|
76
|
+
|
|
77
|
+
- --create, --lint, --diff, --share, --benchmark, --doctor, --watch, --stats
|
|
78
|
+
- --export/--import, --audit --json
|
|
79
|
+
- 38 examples including cost-tracker, loop-detector, session-handoff
|
|
80
|
+
- Hook Builder web tool
|
|
81
|
+
- Interactive COOKBOOK
|
|
82
|
+
- 6 documentation files + Japanese README
|
|
83
|
+
- CONTRIBUTING.md for external contributors
|
package/index.mjs
CHANGED
|
@@ -84,6 +84,7 @@ const DIFF_IDX = process.argv.findIndex(a => a === '--diff');
|
|
|
84
84
|
const DIFF_FILE = DIFF_IDX !== -1 ? process.argv[DIFF_IDX + 1] : null;
|
|
85
85
|
const SHARE = process.argv.includes('--share');
|
|
86
86
|
const BENCHMARK = process.argv.includes('--benchmark');
|
|
87
|
+
const DASHBOARD = process.argv.includes('--dashboard');
|
|
87
88
|
const CREATE_IDX = process.argv.findIndex(a => a === '--create');
|
|
88
89
|
const CREATE_DESC = CREATE_IDX !== -1 ? process.argv.slice(CREATE_IDX + 1).join(' ') : null;
|
|
89
90
|
|
|
@@ -105,6 +106,7 @@ if (HELP) {
|
|
|
105
106
|
npx cc-safe-setup --audit --json Machine-readable output for CI/CD
|
|
106
107
|
npx cc-safe-setup --scan Detect tech stack, recommend hooks
|
|
107
108
|
npx cc-safe-setup --learn Learn from your block history
|
|
109
|
+
npx cc-safe-setup --dashboard Real-time status dashboard
|
|
108
110
|
npx cc-safe-setup --benchmark Measure hook execution time
|
|
109
111
|
npx cc-safe-setup --share Generate shareable URL for your setup
|
|
110
112
|
npx cc-safe-setup --diff <file> Compare your settings with another file
|
|
@@ -788,6 +790,74 @@ async function fullSetup() {
|
|
|
788
790
|
console.log();
|
|
789
791
|
}
|
|
790
792
|
|
|
793
|
+
async function dashboard() {
|
|
794
|
+
const { createReadStream, watchFile } = await import('fs');
|
|
795
|
+
const { createInterface: createRL } = await import('readline');
|
|
796
|
+
|
|
797
|
+
const BLOCK_LOG = join(HOME, '.claude', 'blocked-commands.log');
|
|
798
|
+
const COST_FILE = '/tmp/cc-cost-tracker-calls';
|
|
799
|
+
const CONTEXT_FILE = '/tmp/cc-context-pct';
|
|
800
|
+
|
|
801
|
+
const clear = () => process.stdout.write('\x1b[2J\x1b[H');
|
|
802
|
+
|
|
803
|
+
// Count hooks
|
|
804
|
+
let hookCount = 0;
|
|
805
|
+
let exampleCount = 0;
|
|
806
|
+
if (existsSync(SETTINGS_PATH)) {
|
|
807
|
+
try {
|
|
808
|
+
const s = JSON.parse(readFileSync(SETTINGS_PATH, 'utf-8'));
|
|
809
|
+
for (const entries of Object.values(s.hooks || {})) {
|
|
810
|
+
hookCount += entries.reduce((n, e) => n + (e.hooks || []).length, 0);
|
|
811
|
+
}
|
|
812
|
+
} catch {}
|
|
813
|
+
}
|
|
814
|
+
exampleCount = existsSync(join(HOOKS_DIR)) ?
|
|
815
|
+
(await import('fs')).readdirSync(HOOKS_DIR).filter(f => f.endsWith('.sh')).length : 0;
|
|
816
|
+
|
|
817
|
+
function render() {
|
|
818
|
+
clear();
|
|
819
|
+
|
|
820
|
+
// Header
|
|
821
|
+
console.log(c.bold + ' cc-safe-setup --dashboard' + c.reset + ' ' + c.dim + new Date().toLocaleTimeString() + c.reset);
|
|
822
|
+
console.log(' ' + '─'.repeat(50));
|
|
823
|
+
|
|
824
|
+
// Status row
|
|
825
|
+
const context = existsSync(CONTEXT_FILE) ? readFileSync(CONTEXT_FILE, 'utf-8').trim() + '%' : '?';
|
|
826
|
+
const calls = existsSync(COST_FILE) ? readFileSync(COST_FILE, 'utf-8').trim() : '0';
|
|
827
|
+
const cost = (parseInt(calls) * 0.105).toFixed(2);
|
|
828
|
+
|
|
829
|
+
console.log(' Hooks: ' + c.green + hookCount + c.reset + ' registered | Scripts: ' + exampleCount);
|
|
830
|
+
console.log(' Context: ' + c.yellow + context + c.reset + ' | Cost: ~$' + cost + ' (' + calls + ' calls)');
|
|
831
|
+
console.log(' ' + '─'.repeat(50));
|
|
832
|
+
|
|
833
|
+
// Recent blocks
|
|
834
|
+
console.log(c.bold + ' Recent Blocks' + c.reset);
|
|
835
|
+
if (existsSync(BLOCK_LOG)) {
|
|
836
|
+
const lines = readFileSync(BLOCK_LOG, 'utf-8').split('\n').filter(l => l.trim());
|
|
837
|
+
const recent = lines.slice(-5);
|
|
838
|
+
for (const line of recent) {
|
|
839
|
+
const m = line.match(/^\[([^\]]+)\]\s*BLOCKED:\s*(.+?)\s*\|/);
|
|
840
|
+
if (m) {
|
|
841
|
+
const time = m[1].replace(/T/, ' ').replace(/\+.*/, '').slice(11, 16);
|
|
842
|
+
console.log(' ' + c.dim + time + c.reset + ' ' + c.red + m[2].trim() + c.reset);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
if (recent.length === 0) console.log(c.dim + ' (none)' + c.reset);
|
|
846
|
+
} else {
|
|
847
|
+
console.log(c.dim + ' (no log yet)' + c.reset);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
console.log(' ' + '─'.repeat(50));
|
|
851
|
+
console.log(c.dim + ' Refreshing every 3s. Ctrl+C to exit.' + c.reset);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
render();
|
|
855
|
+
setInterval(render, 3000);
|
|
856
|
+
|
|
857
|
+
// Keep alive
|
|
858
|
+
await new Promise(() => {});
|
|
859
|
+
}
|
|
860
|
+
|
|
791
861
|
async function benchmark() {
|
|
792
862
|
const { spawnSync } = await import('child_process');
|
|
793
863
|
|
|
@@ -2075,6 +2145,7 @@ async function main() {
|
|
|
2075
2145
|
if (FULL) return fullSetup();
|
|
2076
2146
|
if (DOCTOR) return doctor();
|
|
2077
2147
|
if (WATCH) return watch();
|
|
2148
|
+
if (DASHBOARD) return dashboard();
|
|
2078
2149
|
if (BENCHMARK) return benchmark();
|
|
2079
2150
|
if (SHARE) return share();
|
|
2080
2151
|
if (DIFF_FILE) return diff(DIFF_FILE);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cc-safe-setup",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "One command to make Claude Code safe for autonomous operation. 8 built-in +
|
|
3
|
+
"version": "4.0.1",
|
|
4
|
+
"description": "One command to make Claude Code safe for autonomous operation. 8 built-in + 38 examples. 22 commands including dashboard, create, audit, lint, diff, benchmark. 2,500+ daily npm downloads.",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cc-safe-setup": "index.mjs"
|