cc-safe-setup 2.2.0 → 2.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 (2) hide show
  1. package/index.mjs +142 -0
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -70,6 +70,7 @@ const INSTALL_EXAMPLE_IDX = process.argv.findIndex(a => a === '--install-example
70
70
  const INSTALL_EXAMPLE = INSTALL_EXAMPLE_IDX !== -1 ? process.argv[INSTALL_EXAMPLE_IDX + 1] : null;
71
71
  const AUDIT = process.argv.includes('--audit');
72
72
  const LEARN = process.argv.includes('--learn');
73
+ const SCAN = process.argv.includes('--scan');
73
74
 
74
75
  if (HELP) {
75
76
  console.log(`
@@ -682,6 +683,146 @@ exit 0`;
682
683
  console.log();
683
684
  }
684
685
 
686
+ function scan() {
687
+ console.log();
688
+ console.log(c.bold + ' cc-safe-setup --scan' + c.reset);
689
+ console.log(c.dim + ' Scanning project to generate safety config...' + c.reset);
690
+ console.log();
691
+
692
+ const cwd = process.cwd();
693
+ const detected = { languages: [], frameworks: [], hasDb: false, hasDocker: false, isMonorepo: false };
694
+ const hooks = ['destructive-guard', 'branch-guard', 'secret-guard', 'syntax-check'];
695
+ const claudeMdRules = ['# Project Safety Rules\n', '## Generated by cc-safe-setup --scan\n'];
696
+
697
+ // Detect languages & frameworks
698
+ if (existsSync(join(cwd, 'package.json'))) {
699
+ detected.languages.push('JavaScript/TypeScript');
700
+ try {
701
+ const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8'));
702
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
703
+ if (allDeps.next) detected.frameworks.push('Next.js');
704
+ if (allDeps.react) detected.frameworks.push('React');
705
+ if (allDeps.express) detected.frameworks.push('Express');
706
+ if (allDeps.prisma || allDeps['@prisma/client']) { detected.frameworks.push('Prisma'); detected.hasDb = true; }
707
+ if (allDeps.sequelize) { detected.frameworks.push('Sequelize'); detected.hasDb = true; }
708
+ if (allDeps.typeorm) { detected.frameworks.push('TypeORM'); detected.hasDb = true; }
709
+ } catch(e) {}
710
+ }
711
+ if (existsSync(join(cwd, 'requirements.txt')) || existsSync(join(cwd, 'pyproject.toml'))) {
712
+ detected.languages.push('Python');
713
+ if (existsSync(join(cwd, 'manage.py'))) { detected.frameworks.push('Django'); detected.hasDb = true; }
714
+ if (existsSync(join(cwd, 'app.py')) || existsSync(join(cwd, 'wsgi.py'))) detected.frameworks.push('Flask');
715
+ }
716
+ if (existsSync(join(cwd, 'Gemfile'))) {
717
+ detected.languages.push('Ruby');
718
+ detected.frameworks.push('Rails');
719
+ detected.hasDb = true;
720
+ }
721
+ if (existsSync(join(cwd, 'composer.json'))) {
722
+ detected.languages.push('PHP');
723
+ try {
724
+ const composer = JSON.parse(readFileSync(join(cwd, 'composer.json'), 'utf-8'));
725
+ if (composer.require?.['laravel/framework']) { detected.frameworks.push('Laravel'); detected.hasDb = true; }
726
+ if (composer.require?.['symfony/framework-bundle']) { detected.frameworks.push('Symfony'); detected.hasDb = true; }
727
+ } catch(e) {}
728
+ }
729
+ if (existsSync(join(cwd, 'go.mod'))) detected.languages.push('Go');
730
+ if (existsSync(join(cwd, 'Cargo.toml'))) detected.languages.push('Rust');
731
+
732
+ // Docker
733
+ if (existsSync(join(cwd, 'Dockerfile')) || existsSync(join(cwd, 'docker-compose.yml')) || existsSync(join(cwd, 'compose.yaml'))) {
734
+ detected.hasDocker = true;
735
+ }
736
+
737
+ // Monorepo
738
+ if (existsSync(join(cwd, 'pnpm-workspace.yaml')) || existsSync(join(cwd, 'lerna.json')) || existsSync(join(cwd, 'nx.json'))) {
739
+ detected.isMonorepo = true;
740
+ }
741
+
742
+ // .env files
743
+ const hasEnv = existsSync(join(cwd, '.env')) || existsSync(join(cwd, '.env.local'));
744
+
745
+ // Display detection results
746
+ console.log(c.bold + ' Detected:' + c.reset);
747
+ if (detected.languages.length) console.log(' ' + c.green + '✓' + c.reset + ' Languages: ' + detected.languages.join(', '));
748
+ if (detected.frameworks.length) console.log(' ' + c.green + '✓' + c.reset + ' Frameworks: ' + detected.frameworks.join(', '));
749
+ if (detected.hasDb) console.log(' ' + c.green + '✓' + c.reset + ' Database detected');
750
+ if (detected.hasDocker) console.log(' ' + c.green + '✓' + c.reset + ' Docker detected');
751
+ if (detected.isMonorepo) console.log(' ' + c.green + '✓' + c.reset + ' Monorepo detected');
752
+ if (hasEnv) console.log(' ' + c.yellow + '⚠' + c.reset + ' .env file found (secret leak risk)');
753
+ console.log();
754
+
755
+ // Generate recommendations
756
+ const examples = [];
757
+
758
+ if (detected.hasDb) {
759
+ examples.push('block-database-wipe');
760
+ claudeMdRules.push('- Never run destructive database commands (migrate:fresh, DROP DATABASE, prisma migrate reset)');
761
+ claudeMdRules.push('- Always backup database before schema changes');
762
+ }
763
+
764
+ if (detected.hasDocker) {
765
+ examples.push('auto-approve-docker');
766
+ claudeMdRules.push('- Docker commands are auto-approved for build/compose/ps/logs');
767
+ }
768
+
769
+ if (hasEnv) {
770
+ claudeMdRules.push('- Never commit .env files. Use .env.example for templates');
771
+ claudeMdRules.push('- Never hardcode API keys or secrets in source files');
772
+ }
773
+
774
+ if (detected.languages.includes('Python')) {
775
+ examples.push('auto-approve-python');
776
+ claudeMdRules.push('- Run pytest after every code change');
777
+ }
778
+
779
+ if (detected.languages.includes('JavaScript/TypeScript')) {
780
+ examples.push('auto-approve-build');
781
+ claudeMdRules.push('- Run npm test after every code change');
782
+ }
783
+
784
+ // Always recommend
785
+ examples.push('scope-guard');
786
+ examples.push('protect-dotfiles');
787
+ claudeMdRules.push('- Always run tests before committing');
788
+ claudeMdRules.push('- Never force-push to main/master');
789
+ claudeMdRules.push('- Create a backup branch before large refactors');
790
+
791
+ // Display recommendations
792
+ console.log(c.bold + ' Recommended hooks:' + c.reset);
793
+ console.log(' ' + c.dim + 'npx cc-safe-setup' + c.reset + ' (8 built-in hooks)');
794
+ for (const ex of examples) {
795
+ console.log(' ' + c.dim + 'npx cc-safe-setup --install-example ' + ex + c.reset);
796
+ }
797
+
798
+ // Generate CLAUDE.md
799
+ console.log();
800
+ const claudeMdPath = join(cwd, 'CLAUDE.md');
801
+ if (existsSync(claudeMdPath)) {
802
+ console.log(c.yellow + ' CLAUDE.md already exists. Suggested rules to add:' + c.reset);
803
+ console.log();
804
+ for (const rule of claudeMdRules.slice(2)) {
805
+ console.log(' ' + c.dim + rule + c.reset);
806
+ }
807
+ } else {
808
+ const content = claudeMdRules.join('\n') + '\n';
809
+ if (process.argv.includes('--apply')) {
810
+ writeFileSync(claudeMdPath, content);
811
+ console.log(c.green + ' ✓ CLAUDE.md created with ' + (claudeMdRules.length - 2) + ' project-specific rules.' + c.reset);
812
+ } else {
813
+ console.log(c.bold + ' Suggested CLAUDE.md:' + c.reset);
814
+ console.log();
815
+ for (const rule of claudeMdRules) {
816
+ console.log(' ' + c.dim + rule + c.reset);
817
+ }
818
+ console.log();
819
+ console.log(c.dim + ' Run with --apply to create: npx cc-safe-setup --scan --apply' + c.reset);
820
+ }
821
+ }
822
+
823
+ console.log();
824
+ }
825
+
685
826
  async function main() {
686
827
  if (UNINSTALL) return uninstall();
687
828
  if (VERIFY) return verify();
@@ -690,6 +831,7 @@ async function main() {
690
831
  if (INSTALL_EXAMPLE) return installExample(INSTALL_EXAMPLE);
691
832
  if (AUDIT) return audit();
692
833
  if (LEARN) return learn();
834
+ if (SCAN) return scan();
693
835
 
694
836
  console.log();
695
837
  console.log(c.bold + ' cc-safe-setup' + c.reset);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-safe-setup",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "One command to make Claude Code safe for autonomous operation. 8 built-in hooks + 25 installable examples. Destructive blocker, branch guard, database wipe protection, dotfile guard, and more.",
5
5
  "main": "index.mjs",
6
6
  "bin": {