cc-safe-setup 13.2.0 → 13.3.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/README.md +1 -1
  2. package/index.mjs +41 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  **One command to make Claude Code safe for autonomous operation.** [日本語](docs/README.ja.md)
8
8
 
9
- 8 built-in + 124 examples = **138 hooks**. 43 CLI commands. 561 tests. 5 languages. [**Hub**](https://yurukusa.github.io/cc-safe-setup/hub.html) · [Wizard](https://yurukusa.github.io/cc-safe-setup/wizard.html) · [Cheat Sheet](https://yurukusa.github.io/cc-safe-setup/hooks-cheatsheet.html) · [Builder](https://yurukusa.github.io/cc-safe-setup/builder.html) · [FAQ](https://yurukusa.github.io/cc-safe-setup/faq.html) · [Examples](https://yurukusa.github.io/cc-safe-setup/by-example.html) · [Matrix](https://yurukusa.github.io/cc-safe-setup/matrix.html) · [Playground](https://yurukusa.github.io/cc-hook-registry/playground.html)
9
+ 8 built-in + 124 examples = **138 hooks**. 44 CLI commands. 561 tests. 5 languages. [**Hub**](https://yurukusa.github.io/cc-safe-setup/hub.html) · [Wizard](https://yurukusa.github.io/cc-safe-setup/wizard.html) · [Cheat Sheet](https://yurukusa.github.io/cc-safe-setup/hooks-cheatsheet.html) · [Builder](https://yurukusa.github.io/cc-safe-setup/builder.html) · [FAQ](https://yurukusa.github.io/cc-safe-setup/faq.html) · [Examples](https://yurukusa.github.io/cc-safe-setup/by-example.html) · [Matrix](https://yurukusa.github.io/cc-safe-setup/matrix.html) · [Playground](https://yurukusa.github.io/cc-hook-registry/playground.html)
10
10
 
11
11
  ```bash
12
12
  npx cc-safe-setup
package/index.mjs CHANGED
@@ -112,6 +112,7 @@ const CREATE_IDX = process.argv.findIndex(a => a === '--create');
112
112
  const CREATE_DESC = CREATE_IDX !== -1 ? process.argv.slice(CREATE_IDX + 1).join(' ') : null;
113
113
  const SUGGEST = process.argv.includes('--suggest');
114
114
  const INIT_PROJECT = process.argv.includes('--init-project');
115
+ const SCORE_ONLY = process.argv.includes('--score');
115
116
  const TEST_HOOK_IDX = process.argv.findIndex(a => a === '--test-hook');
116
117
  const TEST_HOOK = TEST_HOOK_IDX !== -1 ? process.argv[TEST_HOOK_IDX + 1] : null;
117
118
  const WHY_IDX = process.argv.findIndex(a => a === '--why');
@@ -149,6 +150,7 @@ if (HELP) {
149
150
  npx cc-safe-setup --create "<desc>" Generate a custom hook from description
150
151
  npx cc-safe-setup --test-hook <name> Test a specific hook with sample inputs
151
152
  npx cc-safe-setup --save-profile <name> Save current hooks as a named profile
153
+ npx cc-safe-setup --score Print safety score (0-100) and exit
152
154
  npx cc-safe-setup --init-project Complete project setup (CLAUDE.md + hooks + CI + .gitignore)
153
155
  npx cc-safe-setup --suggest Analyze project and predict risks → suggest hooks
154
156
  npx cc-safe-setup --why <hook> Why this hook exists (real incident + issue link)
@@ -1072,6 +1074,44 @@ async function saveProfile(name) {
1072
1074
  console.log();
1073
1075
  }
1074
1076
 
1077
+ async function scoreOnly() {
1078
+ const { readdirSync } = await import('fs');
1079
+ let score = 0;
1080
+
1081
+ // Hooks installed (max 50 points)
1082
+ const hookDir = join(HOME, '.claude', 'hooks');
1083
+ const hookCount = existsSync(hookDir) ? readdirSync(hookDir).filter(f => f.endsWith('.sh') || f.endsWith('.py')).length : 0;
1084
+ score += Math.min(hookCount * 3, 50);
1085
+
1086
+ // Critical hooks (max 20 points)
1087
+ const critical = ['destructive-guard', 'branch-guard', 'secret-guard'];
1088
+ if (existsSync(SETTINGS_PATH)) {
1089
+ try {
1090
+ const s = JSON.parse(readFileSync(SETTINGS_PATH, 'utf-8'));
1091
+ const cmds = JSON.stringify(s.hooks || {});
1092
+ for (const h of critical) {
1093
+ if (cmds.includes(h)) score += 7;
1094
+ }
1095
+ } catch {}
1096
+ }
1097
+
1098
+ // CLAUDE.md exists (10 points)
1099
+ if (existsSync(join(process.cwd(), 'CLAUDE.md'))) score += 10;
1100
+
1101
+ // .gitignore has .env (10 points)
1102
+ const gi = existsSync(join(process.cwd(), '.gitignore')) ? readFileSync(join(process.cwd(), '.gitignore'), 'utf-8') : '';
1103
+ if (gi.includes('.env')) score += 10;
1104
+
1105
+ // CI workflow (10 points)
1106
+ if (existsSync(join(process.cwd(), '.github', 'workflows', 'claude-code-safety.yml'))) score += 10;
1107
+
1108
+ score = Math.min(score, 100);
1109
+
1110
+ // Output just the score for piping
1111
+ console.log(score);
1112
+ process.exit(score >= 70 ? 0 : 1);
1113
+ }
1114
+
1075
1115
  async function initProject() {
1076
1116
  console.log();
1077
1117
  console.log(c.bold + ' cc-safe-setup --init-project' + c.reset);
@@ -4498,6 +4538,7 @@ async function main() {
4498
4538
  if (WATCH) return watch();
4499
4539
  if (TEST_HOOK_IDX !== -1) return testHook(TEST_HOOK);
4500
4540
  if (SAVE_PROFILE_IDX !== -1) return saveProfile(SAVE_PROFILE);
4541
+ if (SCORE_ONLY) return scoreOnly();
4501
4542
  if (INIT_PROJECT) return initProject();
4502
4543
  if (SUGGEST) return suggest();
4503
4544
  if (WHY_IDX !== -1) return why(WHY_HOOK);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-safe-setup",
3
- "version": "13.2.0",
3
+ "version": "13.3.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": {