cc-hook-registry 3.2.0 → 4.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.
Files changed (3) hide show
  1. package/index.mjs +54 -0
  2. package/package.json +2 -2
  3. package/test.sh +34 -0
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
+ update [id] Update one or all installed hooks
116
117
  uninstall <id> Remove an installed hook
117
118
  outdated Check installed hooks for updates
118
119
  stats Registry statistics
@@ -369,6 +370,59 @@ else if (command === 'recommend') {
369
370
  console.log();
370
371
  }
371
372
 
373
+ else if (command === 'update') {
374
+ const targetId = args[1]; // Optional: update specific hook or all
375
+ console.log();
376
+ console.log(c.bold + ' Updating hooks...' + c.reset);
377
+ console.log();
378
+
379
+ if (!existsSync(HOOKS_DIR)) {
380
+ console.log(c.dim + ' No hooks installed.' + c.reset);
381
+ process.exit(0);
382
+ }
383
+
384
+ const { readdirSync } = await import('fs');
385
+ const installed = readdirSync(HOOKS_DIR).filter(f => f.endsWith('.sh'));
386
+ let updated = 0;
387
+ let skipped = 0;
388
+
389
+ for (const file of installed) {
390
+ const name = file.replace('.sh', '');
391
+ if (targetId && name !== targetId) continue;
392
+
393
+ const hook = REGISTRY.find(h => h.id === name);
394
+ if (!hook || !hook.install.includes('--install-example')) {
395
+ skipped++;
396
+ continue;
397
+ }
398
+
399
+ const rawUrl = `https://raw.githubusercontent.com/yurukusa/cc-safe-setup/main/examples/${name}.sh`;
400
+ try {
401
+ const remote = execSync(`curl -sL "${rawUrl}" 2>/dev/null`, { encoding: 'utf-8', timeout: 5000 });
402
+ const local = readFileSync(join(HOOKS_DIR, file), 'utf-8');
403
+
404
+ if (remote.trim() !== local.trim() && remote.startsWith('#!/bin/bash')) {
405
+ writeFileSync(join(HOOKS_DIR, file), remote);
406
+ chmodSync(join(HOOKS_DIR, file), 0o755);
407
+ console.log(' ' + c.green + '↑' + c.reset + ' Updated: ' + name);
408
+ updated++;
409
+ } else {
410
+ skipped++;
411
+ }
412
+ } catch {
413
+ skipped++;
414
+ }
415
+ }
416
+
417
+ if (updated === 0) {
418
+ console.log(c.green + ' All hooks are up to date.' + c.reset);
419
+ } else {
420
+ console.log();
421
+ console.log(c.green + ' Updated ' + updated + ' hook(s).' + c.reset + ' Restart Claude Code.');
422
+ }
423
+ console.log();
424
+ }
425
+
372
426
  else if (command === 'uninstall') {
373
427
  const id = args[1];
374
428
  if (!id) { console.log(c.red + ' Usage: cc-hook-registry uninstall <id>' + c.reset); process.exit(1); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-hook-registry",
3
- "version": "3.2.0",
3
+ "version": "4.0.0",
4
4
  "description": "Search, browse, and install Claude Code hooks from the community. GitHub-based registry, no server needed.",
5
5
  "main": "index.mjs",
6
6
  "bin": {
@@ -15,7 +15,7 @@
15
15
  "cli"
16
16
  ],
17
17
  "scripts": {
18
- "test": "node index.mjs --help"
18
+ "test": "bash test.sh"
19
19
  },
20
20
  "author": "yurukusa",
21
21
  "license": "MIT",
package/test.sh ADDED
@@ -0,0 +1,34 @@
1
+ #!/bin/bash
2
+ # cc-hook-registry tests
3
+ set -euo pipefail
4
+ PASS=0; FAIL=0
5
+ CLI="$(dirname "$0")/index.mjs"
6
+
7
+ test_cmd() {
8
+ local desc="$1" cmd="$2" expect="$3"
9
+ local out
10
+ out=$(eval "$cmd" 2>&1) || true
11
+ if echo "$out" | grep -q "$expect"; then
12
+ echo " PASS: $desc"; PASS=$((PASS+1))
13
+ else
14
+ echo " FAIL: $desc (expected '$expect')"; FAIL=$((FAIL+1))
15
+ fi
16
+ }
17
+
18
+ echo "--- cc-hook-registry tests ---"
19
+
20
+ test_cmd "--help" "node $CLI --help" "Commands"
21
+ test_cmd "search database" "node $CLI search database" "block-database-wipe"
22
+ test_cmd "search git" "node $CLI search git" "result"
23
+ test_cmd "search nonexistent" "node $CLI search zzzznotfound" "No hooks"
24
+ test_cmd "browse" "node $CLI browse" "hooks"
25
+ test_cmd "browse safety" "node $CLI browse safety" "Safety"
26
+ test_cmd "info destructive-guard" "node $CLI info destructive-guard" "Destructive"
27
+ test_cmd "info nonexistent" "node $CLI info notreal" "not found"
28
+ test_cmd "stats" "node $CLI stats" "Total hooks"
29
+ test_cmd "stats count" "node $CLI stats" "48"
30
+
31
+ echo ""
32
+ echo "Results: $PASS/$((PASS+FAIL)) passed"
33
+ [ "$FAIL" -gt 0 ] && exit 1
34
+ echo "All tests passed!"