claudex-setup 1.0.0 → 1.0.1

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/package.json +1 -1
  2. package/src/setup.js +69 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudex-setup",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Audit and optimize any project for Claude Code. Powered by 1107 verified techniques.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/setup.js CHANGED
@@ -29,12 +29,20 @@ function detectScripts(ctx) {
29
29
  // Helper: detect main directories
30
30
  // ============================================================
31
31
  function detectMainDirs(ctx) {
32
- const candidates = ['src', 'lib', 'app', 'pages', 'components', 'api', 'routes', 'utils', 'helpers', 'services', 'models', 'controllers', 'views', 'public', 'assets', 'config', 'tests', 'test', '__tests__', 'spec', 'scripts', 'prisma', 'db', 'middleware'];
32
+ const candidates = ['src', 'lib', 'app', 'pages', 'components', 'api', 'routes', 'utils', 'helpers', 'services', 'models', 'controllers', 'views', 'public', 'assets', 'config', 'tests', 'test', '__tests__', 'spec', 'scripts', 'prisma', 'db', 'middleware', 'hooks'];
33
+ // Also check inside src/ for nested structure (common in Next.js, React)
34
+ const srcNested = ['src/components', 'src/app', 'src/pages', 'src/api', 'src/lib', 'src/hooks', 'src/utils', 'src/services', 'src/models', 'src/middleware', 'src/app/api', 'app/api'];
33
35
  const found = [];
34
- for (const dir of candidates) {
36
+ const seenNames = new Set();
37
+
38
+ for (const dir of [...candidates, ...srcNested]) {
35
39
  if (ctx.hasDir(dir)) {
36
40
  const files = ctx.dirFiles(dir);
37
- found.push({ name: dir, fileCount: files.length, files: files.slice(0, 10) });
41
+ const displayName = dir.includes('/') ? dir : dir;
42
+ if (!seenNames.has(displayName)) {
43
+ found.push({ name: displayName, fileCount: files.length, files: files.slice(0, 10) });
44
+ seenNames.add(displayName);
45
+ }
38
46
  }
39
47
  }
40
48
  return found;
@@ -61,31 +69,63 @@ function generateMermaid(dirs, stacks) {
61
69
  return ` ${id}[${label}]`;
62
70
  }
63
71
 
64
- // Entry point
65
- nodes.push(addNode('Entry Point', 'round'));
72
+ // Detect Next.js App Router specifically
73
+ const hasAppRouter = dirNames.includes('app') || dirNames.includes('src/app');
74
+ const hasPages = dirNames.includes('pages') || dirNames.includes('src/pages');
75
+ const hasAppApi = dirNames.includes('app/api') || dirNames.includes('src/app/api');
76
+ const hasSrcComponents = dirNames.includes('src/components') || dirNames.includes('components');
77
+ const hasSrcHooks = dirNames.includes('src/hooks') || dirNames.includes('hooks');
78
+ const hasSrcLib = dirNames.includes('src/lib') || dirNames.includes('lib');
79
+
80
+ // Smart entry point based on framework
81
+ const isNextJs = stackKeys.includes('nextjs');
82
+ const isDjango = stackKeys.includes('django');
83
+ const isFastApi = stackKeys.includes('fastapi');
84
+
85
+ if (isNextJs) {
86
+ nodes.push(addNode('Next.js', 'round'));
87
+ } else if (isDjango) {
88
+ nodes.push(addNode('Django', 'round'));
89
+ } else if (isFastApi) {
90
+ nodes.push(addNode('FastAPI', 'round'));
91
+ } else {
92
+ nodes.push(addNode('Entry Point', 'round'));
93
+ }
94
+
95
+ const root = ids['Next.js'] || ids['Django'] || ids['FastAPI'] || ids['Entry Point'];
66
96
 
67
97
  // Detect layers
68
- if (dirNames.includes('app') || dirNames.includes('pages')) {
69
- nodes.push(addNode('Pages / Routes', 'default'));
70
- edges.push(` ${ids['Entry Point']} --> ${ids['Pages / Routes']}`);
98
+ if (hasAppRouter || hasPages) {
99
+ const label = hasAppRouter ? 'App Router' : 'Pages';
100
+ nodes.push(addNode(label, 'default'));
101
+ edges.push(` ${root} --> ${ids[label]}`);
102
+ }
103
+
104
+ if (hasAppApi) {
105
+ nodes.push(addNode('API Routes', 'default'));
106
+ const parent = ids['App Router'] || ids['Pages'] || root;
107
+ edges.push(` ${parent} --> ${ids['API Routes']}`);
71
108
  }
72
109
 
73
- if (dirNames.includes('components')) {
110
+ if (hasSrcComponents) {
74
111
  nodes.push(addNode('Components', 'default'));
75
- const parent = ids['Pages / Routes'] || ids['Entry Point'];
112
+ const parent = ids['App Router'] || ids['Pages'] || root;
76
113
  edges.push(` ${parent} --> ${ids['Components']}`);
77
114
  }
78
115
 
79
- if (dirNames.includes('src')) {
80
- nodes.push(addNode('src/', 'default'));
81
- const parent = ids['Pages / Routes'] || ids['Entry Point'];
82
- edges.push(` ${parent} --> ${ids['src/']}`);
116
+ if (hasSrcHooks) {
117
+ nodes.push(addNode('Hooks', 'default'));
118
+ const parent = ids['Components'] || root;
119
+ edges.push(` ${parent} --> ${ids['Hooks']}`);
83
120
  }
84
121
 
85
- if (dirNames.includes('lib')) {
122
+ if (hasSrcLib) {
86
123
  nodes.push(addNode('lib/', 'default'));
87
- const parent = ids['src/'] || ids['Entry Point'];
124
+ const parent = ids['API Routes'] || ids['Hooks'] || ids['Components'] || root;
88
125
  edges.push(` ${parent} --> ${ids['lib/']}`);
126
+ } else if (dirNames.includes('src') && !hasAppRouter && !hasPages) {
127
+ nodes.push(addNode('src/', 'default'));
128
+ edges.push(` ${root} --> ${ids['src/']}`);
89
129
  }
90
130
 
91
131
  if (dirNames.includes('api') || dirNames.includes('routes') || dirNames.includes('controllers')) {
@@ -379,6 +419,9 @@ ${verificationSteps.join('\n')}
379
419
  - Use descriptive commit messages (why, not what)
380
420
  - Create focused PRs — one concern per PR
381
421
  - Document non-obvious decisions in code comments
422
+
423
+ ---
424
+ *Generated by [claudex-setup](https://github.com/DnaFin/claudex-setup) v${require('../package.json').version} on ${new Date().toISOString().split('T')[0]}. Customize this file for your project — a hand-crafted CLAUDE.md will always be better than a generated one.*
382
425
  `;
383
426
  },
384
427
 
@@ -413,8 +456,9 @@ echo '{"decision": "allow"}'
413
456
  # Appends to .claude/logs/file-changes.log
414
457
 
415
458
  INPUT=$(cat -)
416
- TOOL_NAME=$(echo "$INPUT" | grep -oP '"tool_name"\\s*:\\s*"\\K[^"]+' 2>/dev/null || echo "unknown")
417
- FILE_PATH=$(echo "$INPUT" | grep -oP '"file_path"\\s*:\\s*"\\K[^"]+' 2>/dev/null || echo "")
459
+ TOOL_NAME=$(echo "$INPUT" | sed -n 's/.*"tool_name"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p')
460
+ TOOL_NAME=\${TOOL_NAME:-unknown}
461
+ FILE_PATH=$(echo "$INPUT" | sed -n 's/.*"file_path"[[:space:]]*:[[:space:]]*"\\([^"]*\\)".*/\\1/p')
418
462
 
419
463
  if [ -z "$FILE_PATH" ]; then
420
464
  exit 0
@@ -590,7 +634,13 @@ async function setup(options) {
590
634
 
591
635
  if (typeof result === 'string') {
592
636
  // Single file template (like CLAUDE.md)
593
- const filePath = key === 'claudeMd' ? 'CLAUDE.md' : key;
637
+ // Map technique keys to actual file paths
638
+ const filePathMap = {
639
+ 'claudeMd': 'CLAUDE.md',
640
+ 'mermaidArchitecture': 'CLAUDE.md', // mermaid is part of CLAUDE.md, skip separate file
641
+ };
642
+ if (key === 'mermaidArchitecture') continue; // Mermaid is generated inside CLAUDE.md template
643
+ const filePath = filePathMap[key] || key;
594
644
  const fullPath = path.join(options.dir, filePath);
595
645
 
596
646
  if (!fs.existsSync(fullPath)) {