cc-safe-setup 8.7.0 → 8.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/index.mjs +89 -0
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -95,6 +95,7 @@ const ANALYZE = process.argv.includes('--analyze');
|
|
|
95
95
|
const TEAM = process.argv.includes('--team');
|
|
96
96
|
const MIGRATE_FROM_IDX = process.argv.findIndex(a => a === '--migrate-from');
|
|
97
97
|
const MIGRATE_FROM = MIGRATE_FROM_IDX !== -1 ? process.argv[MIGRATE_FROM_IDX + 1] : null;
|
|
98
|
+
const HEALTH = process.argv.includes('--health');
|
|
98
99
|
const PROFILE_IDX = process.argv.findIndex(a => a === '--profile');
|
|
99
100
|
const PROFILE = PROFILE_IDX !== -1 ? process.argv[PROFILE_IDX + 1] : null;
|
|
100
101
|
const COMPARE_IDX = process.argv.findIndex(a => a === '--compare');
|
|
@@ -132,6 +133,7 @@ if (HELP) {
|
|
|
132
133
|
npx cc-safe-setup --doctor Diagnose why hooks aren't working
|
|
133
134
|
npx cc-safe-setup --watch Live dashboard of blocked commands
|
|
134
135
|
npx cc-safe-setup --create "<desc>" Generate a custom hook from description
|
|
136
|
+
npx cc-safe-setup --health Hook health dashboard (size, permissions, age)
|
|
135
137
|
npx cc-safe-setup --migrate-from <tool> Migrate from safety-net/hooks-mastery/etc.
|
|
136
138
|
npx cc-safe-setup --team Set up project-level hooks (commit to repo for team)
|
|
137
139
|
npx cc-safe-setup --profile <level> Switch safety profile (strict/standard/minimal)
|
|
@@ -843,6 +845,92 @@ async function fullSetup() {
|
|
|
843
845
|
console.log();
|
|
844
846
|
}
|
|
845
847
|
|
|
848
|
+
async function health() {
|
|
849
|
+
const { readdirSync, statSync } = await import('fs');
|
|
850
|
+
console.log();
|
|
851
|
+
console.log(c.bold + ' Hook Health Dashboard' + c.reset);
|
|
852
|
+
console.log();
|
|
853
|
+
|
|
854
|
+
if (!existsSync(HOOKS_DIR)) {
|
|
855
|
+
console.log(c.red + ' No hooks directory found.' + c.reset);
|
|
856
|
+
console.log(c.dim + ' Run: npx cc-safe-setup --shield' + c.reset);
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const hooks = readdirSync(HOOKS_DIR).filter(f => f.endsWith('.sh') || f.endsWith('.py'));
|
|
861
|
+
if (hooks.length === 0) {
|
|
862
|
+
console.log(c.yellow + ' No hooks installed.' + c.reset);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// Table header
|
|
867
|
+
const pad = (s, n) => s.substring(0, n).padEnd(n);
|
|
868
|
+
console.log(c.dim + ' ' + pad('Hook', 30) + pad('Size', 8) + pad('Perms', 7) + pad('Age', 12) + 'Shebang' + c.reset);
|
|
869
|
+
console.log(c.dim + ' ' + '─'.repeat(70) + c.reset);
|
|
870
|
+
|
|
871
|
+
let healthy = 0, issues = 0;
|
|
872
|
+
const now = Date.now();
|
|
873
|
+
|
|
874
|
+
for (const h of hooks.sort()) {
|
|
875
|
+
const fullPath = join(HOOKS_DIR, h);
|
|
876
|
+
const st = statSync(fullPath);
|
|
877
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
878
|
+
const firstLine = content.split('\n')[0];
|
|
879
|
+
|
|
880
|
+
// Size
|
|
881
|
+
const size = st.size < 1024 ? st.size + 'B' : Math.round(st.size / 1024) + 'KB';
|
|
882
|
+
|
|
883
|
+
// Permissions
|
|
884
|
+
const isExec = !!(st.mode & 0o111);
|
|
885
|
+
const perms = isExec ? c.green + '✓ exec' + c.reset : c.red + '✗ exec' + c.reset;
|
|
886
|
+
|
|
887
|
+
// Age
|
|
888
|
+
const ageDays = Math.floor((now - st.mtimeMs) / 86400000);
|
|
889
|
+
const age = ageDays === 0 ? 'today' : ageDays === 1 ? '1 day' : ageDays + ' days';
|
|
890
|
+
|
|
891
|
+
// Shebang
|
|
892
|
+
const hasShebang = firstLine.startsWith('#!');
|
|
893
|
+
const shebang = hasShebang ? c.green + '✓' + c.reset : c.red + '✗' + c.reset;
|
|
894
|
+
|
|
895
|
+
// Status icon
|
|
896
|
+
const ok = isExec && hasShebang;
|
|
897
|
+
const icon = ok ? c.green + '●' + c.reset : c.red + '●' + c.reset;
|
|
898
|
+
if (ok) healthy++; else issues++;
|
|
899
|
+
|
|
900
|
+
console.log(' ' + icon + ' ' + pad(h, 29) + pad(size, 8) + pad(isExec ? '✓ exec' : '✗ exec', 7) + pad(age, 12) + (hasShebang ? '✓' : '✗'));
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
console.log(c.dim + ' ' + '─'.repeat(70) + c.reset);
|
|
904
|
+
console.log(` ${c.green}${healthy} healthy${c.reset} · ${issues > 0 ? c.red + issues + ' issues' + c.reset : c.dim + '0 issues' + c.reset} · ${hooks.length} total`);
|
|
905
|
+
|
|
906
|
+
if (issues > 0) {
|
|
907
|
+
console.log();
|
|
908
|
+
console.log(c.yellow + ' Fix issues: npx cc-safe-setup --quickfix' + c.reset);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// Settings.json hook count
|
|
912
|
+
console.log();
|
|
913
|
+
if (existsSync(SETTINGS_PATH)) {
|
|
914
|
+
try {
|
|
915
|
+
const s = JSON.parse(readFileSync(SETTINGS_PATH, 'utf-8'));
|
|
916
|
+
let configured = 0;
|
|
917
|
+
for (const groups of Object.values(s.hooks || {})) {
|
|
918
|
+
for (const g of groups) {
|
|
919
|
+
configured += (g.hooks || []).length;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
console.log(c.dim + ` ${configured} hooks configured in settings.json` + c.reset);
|
|
923
|
+
if (configured < hooks.length) {
|
|
924
|
+
console.log(c.yellow + ` ${hooks.length - configured} hooks installed but not configured.` + c.reset);
|
|
925
|
+
console.log(c.dim + ' Run --shield to auto-configure all hooks.' + c.reset);
|
|
926
|
+
}
|
|
927
|
+
} catch {
|
|
928
|
+
console.log(c.red + ' settings.json has syntax errors.' + c.reset);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
console.log();
|
|
932
|
+
}
|
|
933
|
+
|
|
846
934
|
async function migrateFrom(tool) {
|
|
847
935
|
console.log();
|
|
848
936
|
console.log(c.bold + ' cc-safe-setup --migrate-from ' + (tool || '?') + c.reset);
|
|
@@ -3519,6 +3607,7 @@ async function main() {
|
|
|
3519
3607
|
if (FULL) return fullSetup();
|
|
3520
3608
|
if (DOCTOR) return doctor();
|
|
3521
3609
|
if (WATCH) return watch();
|
|
3610
|
+
if (HEALTH) return health();
|
|
3522
3611
|
if (MIGRATE_FROM_IDX !== -1) return migrateFrom(MIGRATE_FROM);
|
|
3523
3612
|
if (TEAM) return team();
|
|
3524
3613
|
if (PROFILE_IDX !== -1) return profile(PROFILE);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cc-safe-setup",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.8.0",
|
|
4
4
|
"description": "One command to make Claude Code safe. 59 hooks (8 built-in + 51 examples). 26 CLI commands: dashboard, create, audit, lint, diff, migrate, compare, generate-ci. 284 tests.",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"bin": {
|