cc-hook-registry 4.1.0 → 5.0.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 +119 -0
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -113,6 +113,7 @@ if (!command || command === '--help' || command === '-h') {
|
|
|
113
113
|
install <id> Install a hook
|
|
114
114
|
info <id> Show hook details
|
|
115
115
|
recommend Recommend hooks for current project
|
|
116
|
+
init Interactive setup — install recommended hooks
|
|
116
117
|
list List all installed hooks with status
|
|
117
118
|
update [id] Update one or all installed hooks
|
|
118
119
|
uninstall <id> Remove an installed hook
|
|
@@ -371,6 +372,124 @@ else if (command === 'recommend') {
|
|
|
371
372
|
console.log();
|
|
372
373
|
}
|
|
373
374
|
|
|
375
|
+
else if (command === 'init') {
|
|
376
|
+
console.log();
|
|
377
|
+
console.log(c.bold + ' cc-hook-registry init' + c.reset);
|
|
378
|
+
console.log(c.dim + ' Quick setup — installing essential + project-specific hooks' + c.reset);
|
|
379
|
+
console.log();
|
|
380
|
+
|
|
381
|
+
const cwd = process.cwd();
|
|
382
|
+
const toInstall = [];
|
|
383
|
+
|
|
384
|
+
// Essential hooks (always install)
|
|
385
|
+
toInstall.push('destructive-guard', 'branch-guard', 'secret-guard');
|
|
386
|
+
|
|
387
|
+
// Detect project type
|
|
388
|
+
if (existsSync(join(cwd, 'package.json'))) {
|
|
389
|
+
console.log(' ' + c.blue + '⬡' + c.reset + ' Node.js detected');
|
|
390
|
+
toInstall.push('auto-approve-build');
|
|
391
|
+
try {
|
|
392
|
+
const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8'));
|
|
393
|
+
if (pkg.dependencies?.prisma || pkg.devDependencies?.prisma) {
|
|
394
|
+
console.log(' ' + c.blue + '⬡' + c.reset + ' Prisma detected');
|
|
395
|
+
toInstall.push('block-database-wipe');
|
|
396
|
+
}
|
|
397
|
+
} catch {}
|
|
398
|
+
}
|
|
399
|
+
if (existsSync(join(cwd, 'requirements.txt')) || existsSync(join(cwd, 'pyproject.toml'))) {
|
|
400
|
+
console.log(' ' + c.blue + '⬡' + c.reset + ' Python detected');
|
|
401
|
+
toInstall.push('auto-approve-python');
|
|
402
|
+
}
|
|
403
|
+
if (existsSync(join(cwd, 'Dockerfile'))) {
|
|
404
|
+
console.log(' ' + c.blue + '⬡' + c.reset + ' Docker detected');
|
|
405
|
+
toInstall.push('auto-approve-docker');
|
|
406
|
+
}
|
|
407
|
+
if (existsSync(join(cwd, '.env'))) {
|
|
408
|
+
console.log(' ' + c.blue + '⬡' + c.reset + ' .env file detected');
|
|
409
|
+
toInstall.push('env-source-guard');
|
|
410
|
+
}
|
|
411
|
+
if (existsSync(join(cwd, 'Gemfile')) || existsSync(join(cwd, 'artisan'))) {
|
|
412
|
+
console.log(' ' + c.blue + '⬡' + c.reset + ' Rails/Laravel detected');
|
|
413
|
+
toInstall.push('block-database-wipe');
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Always useful
|
|
417
|
+
toInstall.push('compound-command-approver', 'loop-detector', 'session-handoff');
|
|
418
|
+
|
|
419
|
+
// Deduplicate
|
|
420
|
+
const unique = [...new Set(toInstall)];
|
|
421
|
+
|
|
422
|
+
// Check what's already installed
|
|
423
|
+
const installed = new Set();
|
|
424
|
+
if (existsSync(HOOKS_DIR)) {
|
|
425
|
+
const { readdirSync } = await import('fs');
|
|
426
|
+
for (const f of readdirSync(HOOKS_DIR)) {
|
|
427
|
+
installed.add(f.replace('.sh', ''));
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const toActuallyInstall = unique.filter(id => !installed.has(id));
|
|
432
|
+
|
|
433
|
+
console.log();
|
|
434
|
+
if (toActuallyInstall.length === 0) {
|
|
435
|
+
console.log(c.green + ' All recommended hooks already installed!' + c.reset);
|
|
436
|
+
console.log();
|
|
437
|
+
process.exit(0);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
console.log(c.bold + ' Installing ' + toActuallyInstall.length + ' hooks:' + c.reset);
|
|
441
|
+
|
|
442
|
+
for (const id of toActuallyInstall) {
|
|
443
|
+
const hook = REGISTRY.find(h => h.id === id);
|
|
444
|
+
if (!hook) continue;
|
|
445
|
+
|
|
446
|
+
// Try direct download
|
|
447
|
+
const rawUrl = `https://raw.githubusercontent.com/yurukusa/cc-safe-setup/main/examples/${id}.sh`;
|
|
448
|
+
const hookPath = join(HOOKS_DIR, id + '.sh');
|
|
449
|
+
|
|
450
|
+
try {
|
|
451
|
+
mkdirSync(HOOKS_DIR, { recursive: true });
|
|
452
|
+
const script = execSync(`curl -sL "${rawUrl}"`, { encoding: 'utf-8', timeout: 5000 });
|
|
453
|
+
|
|
454
|
+
if (script.startsWith('#!/bin/bash')) {
|
|
455
|
+
writeFileSync(hookPath, script);
|
|
456
|
+
chmodSync(hookPath, 0o755);
|
|
457
|
+
|
|
458
|
+
// Register in settings
|
|
459
|
+
const trigger = script.includes('PreToolUse') ? 'PreToolUse' :
|
|
460
|
+
script.includes('PostToolUse') ? 'PostToolUse' :
|
|
461
|
+
script.includes('Stop') ? 'Stop' :
|
|
462
|
+
script.includes('SessionStart') ? 'SessionStart' : 'PreToolUse';
|
|
463
|
+
const matcher = script.includes('MATCHER: "Bash"') ? 'Bash' :
|
|
464
|
+
script.includes('MATCHER: "Edit|Write"') ? 'Edit|Write' : '';
|
|
465
|
+
|
|
466
|
+
let settings = {};
|
|
467
|
+
if (existsSync(SETTINGS_PATH)) {
|
|
468
|
+
try { settings = JSON.parse(readFileSync(SETTINGS_PATH, 'utf-8')); } catch {}
|
|
469
|
+
}
|
|
470
|
+
if (!settings.hooks) settings.hooks = {};
|
|
471
|
+
if (!settings.hooks[trigger]) settings.hooks[trigger] = [];
|
|
472
|
+
|
|
473
|
+
const existing = settings.hooks[trigger].flatMap(e => (e.hooks || []).map(h => h.command));
|
|
474
|
+
if (!existing.some(cmd => cmd.includes(id))) {
|
|
475
|
+
settings.hooks[trigger].push({ matcher, hooks: [{ type: 'command', command: hookPath }] });
|
|
476
|
+
mkdirSync(dirname(SETTINGS_PATH), { recursive: true });
|
|
477
|
+
writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
console.log(' ' + c.green + '✓' + c.reset + ' ' + id);
|
|
481
|
+
}
|
|
482
|
+
} catch {
|
|
483
|
+
console.log(' ' + c.yellow + '✗' + c.reset + ' ' + id + c.dim + ' (download failed)' + c.reset);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
console.log();
|
|
488
|
+
console.log(c.green + ' Done! Restart Claude Code to activate.' + c.reset);
|
|
489
|
+
console.log(c.dim + ' Run: npx cc-hook-registry list' + c.reset);
|
|
490
|
+
console.log();
|
|
491
|
+
}
|
|
492
|
+
|
|
374
493
|
else if (command === 'list') {
|
|
375
494
|
console.log();
|
|
376
495
|
console.log(c.bold + ' Installed Hooks' + c.reset);
|