cc-safe-setup 10.7.0 → 10.9.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/README.md +1 -1
- package/index.mjs +133 -0
- 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 + 104 examples = **118 hooks**.
|
|
9
|
+
8 built-in + 104 examples = **118 hooks**. 39 CLI commands. 531 tests. 5 languages. [**Hub**](https://yurukusa.github.io/cc-safe-setup/hub.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
|
@@ -108,6 +108,8 @@ const COMPARE = COMPARE_IDX !== -1 ? { a: process.argv[COMPARE_IDX + 1], b: proc
|
|
|
108
108
|
const REPLAY = process.argv.includes('--replay');
|
|
109
109
|
const CREATE_IDX = process.argv.findIndex(a => a === '--create');
|
|
110
110
|
const CREATE_DESC = CREATE_IDX !== -1 ? process.argv.slice(CREATE_IDX + 1).join(' ') : null;
|
|
111
|
+
const WHY_IDX = process.argv.findIndex(a => a === '--why');
|
|
112
|
+
const WHY_HOOK = WHY_IDX !== -1 ? process.argv[WHY_IDX + 1] : null;
|
|
111
113
|
|
|
112
114
|
if (HELP) {
|
|
113
115
|
console.log(`
|
|
@@ -139,6 +141,7 @@ if (HELP) {
|
|
|
139
141
|
npx cc-safe-setup --doctor Diagnose why hooks aren't working
|
|
140
142
|
npx cc-safe-setup --watch Live dashboard of blocked commands
|
|
141
143
|
npx cc-safe-setup --create "<desc>" Generate a custom hook from description
|
|
144
|
+
npx cc-safe-setup --why <hook> Why this hook exists (real incident + issue link)
|
|
142
145
|
npx cc-safe-setup --replay Replay blocked commands timeline (demo/review)
|
|
143
146
|
npx cc-safe-setup --guard "<rule>" Instantly enforce a rule (generate + install + activate)
|
|
144
147
|
npx cc-safe-setup --diff-hooks <path> Compare hooks between two settings files
|
|
@@ -365,6 +368,21 @@ function examples() {
|
|
|
365
368
|
'git-config-guard.sh': 'Block git config --global modifications',
|
|
366
369
|
'case-sensitive-guard.sh': 'Detect case-insensitive FS collisions (exFAT/NTFS/HFS+)',
|
|
367
370
|
'compound-command-approver.sh': 'Auto-approve safe compound commands (cd && git log)',
|
|
371
|
+
'uncommitted-work-guard.sh': 'Block destructive git with uncommitted changes',
|
|
372
|
+
'no-deploy-friday.sh': 'Block deploys on Fridays',
|
|
373
|
+
'work-hours-guard.sh': 'Restrict risky operations outside business hours',
|
|
374
|
+
'symlink-guard.sh': 'Detect symlink/junction traversal in rm targets',
|
|
375
|
+
'env-source-guard.sh': 'Block sourcing .env files into shell',
|
|
376
|
+
'strict-allowlist.sh': 'Only allow explicitly permitted commands',
|
|
377
|
+
'overwrite-guard.sh': 'Warn before overwriting existing files',
|
|
378
|
+
'memory-write-guard.sh': 'Log writes to ~/.claude/ directory',
|
|
379
|
+
'worktree-guard.sh': 'Warn on destructive git in worktrees',
|
|
380
|
+
'no-curl-upload.sh': 'Warn on curl POST/upload commands',
|
|
381
|
+
'no-port-bind.sh': 'Warn on network port binding',
|
|
382
|
+
'docker-prune-guard.sh': 'Warn before docker system prune',
|
|
383
|
+
'pip-venv-guard.sh': 'Warn on pip install outside venv',
|
|
384
|
+
'no-git-amend-push.sh': 'Warn on amending pushed commits',
|
|
385
|
+
'typosquat-guard.sh': 'Detect npm/pip typosquatting attacks',
|
|
368
386
|
},
|
|
369
387
|
'Auto-Approve': {
|
|
370
388
|
'auto-approve-build.sh': 'Auto-approve npm/yarn/cargo/go build, test, lint',
|
|
@@ -372,6 +390,12 @@ function examples() {
|
|
|
372
390
|
'auto-approve-git-read.sh': 'Auto-approve git status/log/diff even with -C flags',
|
|
373
391
|
'auto-approve-python.sh': 'Auto-approve pytest, mypy, ruff, black, isort',
|
|
374
392
|
'auto-approve-ssh.sh': 'Auto-approve safe SSH commands (uptime, whoami)',
|
|
393
|
+
'auto-approve-go.sh': 'Auto-approve go build/test/vet/fmt',
|
|
394
|
+
'auto-approve-cargo.sh': 'Auto-approve cargo build/test/clippy',
|
|
395
|
+
'auto-approve-make.sh': 'Auto-approve make build/test/lint',
|
|
396
|
+
'auto-approve-gradle.sh': 'Auto-approve gradle/gradlew build/test',
|
|
397
|
+
'auto-approve-maven.sh': 'Auto-approve mvn compile/test/verify',
|
|
398
|
+
'permission-cache.sh': 'Auto-approve previously approved commands in session',
|
|
375
399
|
},
|
|
376
400
|
'Quality': {
|
|
377
401
|
'branch-name-check.sh': 'Warn on non-conventional branch names',
|
|
@@ -381,6 +405,28 @@ function examples() {
|
|
|
381
405
|
'large-file-guard.sh': 'Warn when Write creates files over 500KB',
|
|
382
406
|
'todo-check.sh': 'Warn when committing files with TODO/FIXME markers',
|
|
383
407
|
'verify-before-commit.sh': 'Block commit unless tests passed recently',
|
|
408
|
+
'test-deletion-guard.sh': 'Warn when removing test assertions',
|
|
409
|
+
'fact-check-gate.sh': 'Warn when docs reference unread source files',
|
|
410
|
+
'conflict-marker-guard.sh': 'Block commits with merge conflict markers',
|
|
411
|
+
'commit-quality-gate.sh': 'Warn on vague commit messages',
|
|
412
|
+
'commit-scope-guard.sh': 'Warn when committing 15+ files at once',
|
|
413
|
+
'require-issue-ref.sh': 'Warn when commit lacks issue reference',
|
|
414
|
+
'no-console-log.sh': 'Warn on console.log in production code',
|
|
415
|
+
'no-eval.sh': 'Warn on eval() usage (security risk)',
|
|
416
|
+
'no-wildcard-import.sh': 'Warn on import * patterns',
|
|
417
|
+
'no-todo-ship.sh': 'Warn on TODO/FIXME in commits',
|
|
418
|
+
'test-coverage-guard.sh': 'Warn when code grows without tests',
|
|
419
|
+
'ci-skip-guard.sh': 'Warn on [skip ci] and --no-verify',
|
|
420
|
+
'debug-leftover-guard.sh': 'Detect debugger/pdb/binding.pry in staged code',
|
|
421
|
+
'typescript-strict-guard.sh': 'Warn when tsconfig strict mode disabled',
|
|
422
|
+
'sensitive-regex-guard.sh': 'Detect ReDoS-vulnerable regex patterns',
|
|
423
|
+
'git-author-guard.sh': 'Verify git author is configured',
|
|
424
|
+
'git-blame-context.sh': 'Show file ownership before major edits',
|
|
425
|
+
'import-cycle-warn.sh': 'Detect circular import patterns',
|
|
426
|
+
'env-drift-guard.sh': 'Detect .env vs .env.example mismatch',
|
|
427
|
+
'package-script-guard.sh': 'Warn when package.json scripts change',
|
|
428
|
+
'lockfile-guard.sh': 'Warn when lockfiles modified in commits',
|
|
429
|
+
'git-lfs-guard.sh': 'Suggest Git LFS for large files',
|
|
384
430
|
},
|
|
385
431
|
'Recovery': {
|
|
386
432
|
'auto-checkpoint.sh': 'Auto-commit after edits for rollback protection',
|
|
@@ -410,6 +456,28 @@ function examples() {
|
|
|
410
456
|
'max-file-count-guard.sh': 'Warn when 20+ files created per session',
|
|
411
457
|
'protect-claudemd.sh': 'Block edits to CLAUDE.md and settings files',
|
|
412
458
|
'reinject-claudemd.sh': 'Re-inject CLAUDE.md rules after compaction',
|
|
459
|
+
'token-budget-guard.sh': 'Block when estimated cost exceeds budget',
|
|
460
|
+
'output-length-guard.sh': 'Warn when tool output exceeds 50KB',
|
|
461
|
+
'error-memory-guard.sh': 'Block retries of already-failed commands',
|
|
462
|
+
'parallel-edit-guard.sh': 'Detect concurrent edits to same file',
|
|
463
|
+
'large-read-guard.sh': 'Warn before catting large files',
|
|
464
|
+
'context-snapshot.sh': 'Auto-save session state before context loss',
|
|
465
|
+
'compact-reminder.sh': 'Suggest /compact after N tool calls',
|
|
466
|
+
'revert-helper.sh': 'Show undo command when session ends',
|
|
467
|
+
'hardcoded-secret-detector.sh': 'Detect AWS keys, passwords, JWT in code',
|
|
468
|
+
'prompt-injection-guard.sh': 'Detect injection patterns in tool output',
|
|
469
|
+
'verify-before-done.sh': 'Warn when committing without running tests',
|
|
470
|
+
'disk-space-guard.sh': 'Warn when disk space is low',
|
|
471
|
+
'changelog-reminder.sh': 'Remind to update CHANGELOG on version bump',
|
|
472
|
+
'rate-limit-guard.sh': 'Detect rapid-fire tool calls',
|
|
473
|
+
'stale-env-guard.sh': 'Warn when .env is 90+ days old',
|
|
474
|
+
'node-version-guard.sh': 'Detect .nvmrc version mismatch',
|
|
475
|
+
'auto-stash-before-pull.sh': 'Warn before pull/merge with dirty tree',
|
|
476
|
+
'license-check.sh': 'Note missing license headers in source files',
|
|
477
|
+
'backup-before-refactor.sh': 'Auto-stash before large refactors',
|
|
478
|
+
'file-size-limit.sh': 'Block creating files over 1MB',
|
|
479
|
+
'branch-naming-convention.sh': 'Enforce feat/fix/chore branch prefixes',
|
|
480
|
+
'pr-description-check.sh': 'Ensure PRs have description body',
|
|
413
481
|
},
|
|
414
482
|
};
|
|
415
483
|
|
|
@@ -857,6 +925,70 @@ async function fullSetup() {
|
|
|
857
925
|
console.log();
|
|
858
926
|
}
|
|
859
927
|
|
|
928
|
+
async function why(hookName) {
|
|
929
|
+
const WHY_DATA = {
|
|
930
|
+
'destructive-guard': { issue: '#36339', incident: 'User lost entire C:\\Users directory — rm -rf followed NTFS junctions', url: 'https://github.com/anthropics/claude-code/issues/36339' },
|
|
931
|
+
'branch-guard': { issue: '#36640', incident: 'Autonomous Claude pushed untested code to main at 3am', url: 'https://github.com/anthropics/claude-code/issues/36640' },
|
|
932
|
+
'secret-guard': { issue: '#16561', incident: 'API keys committed to public repo via git add .', url: 'https://github.com/anthropics/claude-code/issues/16561' },
|
|
933
|
+
'block-database-wipe': { issue: '#37405', incident: 'Production database wiped by migrate:fresh', url: 'https://github.com/anthropics/claude-code/issues/37405' },
|
|
934
|
+
'uncommitted-work-guard': { issue: '#37888', incident: 'Claude destroyed uncommitted work twice in same session', url: 'https://github.com/anthropics/claude-code/issues/37888' },
|
|
935
|
+
'test-deletion-guard': { issue: '#38050', incident: 'Claude deleted failing tests instead of fixing code', url: 'https://github.com/anthropics/claude-code/issues/38050' },
|
|
936
|
+
'fact-check-gate': { issue: '#38057', incident: 'Claude wrote false claims in technical docs without reading source', url: 'https://github.com/anthropics/claude-code/issues/38057' },
|
|
937
|
+
'token-budget-guard': { issue: '#38029', incident: 'Session consumed $342 in tokens without user knowing', url: 'https://github.com/anthropics/claude-code/issues/38029' },
|
|
938
|
+
'protect-dotfiles': { issue: '#37478', incident: '.bashrc and environment files overwritten', url: 'https://github.com/anthropics/claude-code/issues/37478' },
|
|
939
|
+
'scope-guard': { issue: '#36233', incident: 'Entire Mac filesystem deleted by out-of-scope operation', url: 'https://github.com/anthropics/claude-code/issues/36233' },
|
|
940
|
+
'case-sensitive-guard': { issue: '#37875', incident: 'exFAT case collision caused data loss via rm -rf', url: 'https://github.com/anthropics/claude-code/issues/37875' },
|
|
941
|
+
'prompt-injection-guard': { issue: '#38046', incident: 'Prompt injection found in /insights output', url: 'https://github.com/anthropics/claude-code/issues/38046' },
|
|
942
|
+
'overwrite-guard': { issue: '#37595', incident: '/export overwrites existing files without warning', url: 'https://github.com/anthropics/claude-code/issues/37595' },
|
|
943
|
+
'memory-write-guard': { issue: '#38040', incident: 'No way to see what Claude writes to ~/.claude/', url: 'https://github.com/anthropics/claude-code/issues/38040' },
|
|
944
|
+
'context-monitor': { issue: '#6527', incident: 'Sessions silently lost all state after 150+ tool calls', url: 'https://github.com/anthropics/claude-code/issues/6527' },
|
|
945
|
+
'comment-strip': { issue: '#29582', incident: 'Bash comments in hook commands broke permission matching', url: 'https://github.com/anthropics/claude-code/issues/29582' },
|
|
946
|
+
'cd-git-allow': { issue: '#32985', incident: 'cd+git compounds spammed permission prompts endlessly', url: 'https://github.com/anthropics/claude-code/issues/32985' },
|
|
947
|
+
'strict-allowlist': { issue: '#37471', incident: 'Denylist model creates arms race — Claude finds bypasses', url: 'https://github.com/anthropics/claude-code/issues/37471' },
|
|
948
|
+
'error-memory-guard': { issue: 'common', incident: 'Claude retries the same failing command 10+ times' },
|
|
949
|
+
'typosquat-guard': { issue: 'supply-chain', incident: 'Misspelled package names can install malware' },
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
console.log();
|
|
953
|
+
if (!hookName) {
|
|
954
|
+
console.log(c.bold + ' cc-safe-setup --why <hook-name>' + c.reset);
|
|
955
|
+
console.log(c.dim + ' Show why a hook exists — the real incident that inspired it.' + c.reset);
|
|
956
|
+
console.log();
|
|
957
|
+
console.log(' Examples:');
|
|
958
|
+
console.log(c.dim + ' npx cc-safe-setup --why destructive-guard' + c.reset);
|
|
959
|
+
console.log(c.dim + ' npx cc-safe-setup --why token-budget-guard' + c.reset);
|
|
960
|
+
console.log();
|
|
961
|
+
console.log(` ${Object.keys(WHY_DATA).length} hooks have documented incidents.`);
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
const name = hookName.replace('.sh', '');
|
|
966
|
+
const data = WHY_DATA[name];
|
|
967
|
+
if (!data) {
|
|
968
|
+
console.log(c.yellow + ` No incident documented for "${name}".` + c.reset);
|
|
969
|
+
console.log(c.dim + ' This hook may have been created proactively.' + c.reset);
|
|
970
|
+
console.log();
|
|
971
|
+
console.log(c.dim + ` Hooks with documented incidents: ${Object.keys(WHY_DATA).join(', ')}` + c.reset);
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
console.log(c.bold + ` Why "${name}" exists` + c.reset);
|
|
976
|
+
console.log();
|
|
977
|
+
console.log(c.red + ' Incident:' + c.reset);
|
|
978
|
+
console.log(' ' + data.incident);
|
|
979
|
+
console.log();
|
|
980
|
+
if (data.url) {
|
|
981
|
+
console.log(c.blue + ' Source:' + c.reset);
|
|
982
|
+
console.log(' ' + data.url);
|
|
983
|
+
}
|
|
984
|
+
if (data.issue && data.issue !== 'common' && data.issue !== 'supply-chain') {
|
|
985
|
+
console.log(c.dim + ` GitHub Issue: ${data.issue}` + c.reset);
|
|
986
|
+
}
|
|
987
|
+
console.log();
|
|
988
|
+
console.log(c.dim + ' Install: npx cc-safe-setup --install-example ' + name + c.reset);
|
|
989
|
+
console.log();
|
|
990
|
+
}
|
|
991
|
+
|
|
860
992
|
async function replay() {
|
|
861
993
|
console.log();
|
|
862
994
|
console.log(c.bold + ' cc-safe-setup --replay' + c.reset);
|
|
@@ -3986,6 +4118,7 @@ async function main() {
|
|
|
3986
4118
|
if (FULL) return fullSetup();
|
|
3987
4119
|
if (DOCTOR) return doctor();
|
|
3988
4120
|
if (WATCH) return watch();
|
|
4121
|
+
if (WHY_IDX !== -1) return why(WHY_HOOK);
|
|
3989
4122
|
if (REPLAY) return replay();
|
|
3990
4123
|
if (GUARD_IDX !== -1) return guard(GUARD_DESC);
|
|
3991
4124
|
if (DIFF_HOOKS_IDX !== -1) return diffHooks(DIFF_HOOKS);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cc-safe-setup",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.9.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": {
|