@merlean/analyzer 1.1.0 → 1.2.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/bin/cli.js CHANGED
@@ -51,10 +51,11 @@ function printHelp() {
51
51
  Merlean Analyzer - AI-powered codebase analysis
52
52
 
53
53
  Usage:
54
+ npx @merlean/analyzer --name <name>
54
55
  npx @merlean/analyzer <path> --name <name>
55
56
 
56
57
  Arguments:
57
- <path> Path to codebase to analyze
58
+ <path> Path to codebase (default: current directory)
58
59
 
59
60
  Options:
60
61
  --name, -n <name> Site name (required)
@@ -63,14 +64,14 @@ Options:
63
64
  --help, -h Show this help
64
65
 
65
66
  Examples:
66
- # Analyze your project
67
- npx @merlean/analyzer ./my-app --name "My App"
67
+ # Analyze current directory
68
+ npx @merlean/analyzer --name "My App"
68
69
 
69
- # Use custom backend
70
- npx @merlean/analyzer ./my-app --name "My App" --backend http://localhost:3004
70
+ # Analyze specific path
71
+ npx @merlean/analyzer ./my-app --name "My App"
71
72
 
72
- # Also save map locally
73
- npx @merlean/analyzer ./my-app --name "My App" --output ./site-map.json
73
+ # Use custom backend (for local dev)
74
+ npx @merlean/analyzer --name "My App" --backend http://localhost:3004
74
75
  `);
75
76
  }
76
77
 
@@ -80,18 +81,14 @@ async function main() {
80
81
  const options = parseArgs();
81
82
 
82
83
  // Validate required args
83
- if (!options.path) {
84
- console.error('❌ Error: Path to codebase is required');
85
- console.log(' Run with --help for usage');
86
- process.exit(1);
87
- }
88
-
89
84
  if (!options.name) {
90
85
  console.error('❌ Error: --name is required');
86
+ console.log(' Run with --help for usage');
91
87
  process.exit(1);
92
88
  }
93
89
 
94
- const codebasePath = path.resolve(options.path);
90
+ // Default to current directory if no path provided
91
+ const codebasePath = path.resolve(options.path || '.');
95
92
 
96
93
  if (!fs.existsSync(codebasePath)) {
97
94
  console.error(`❌ Error: Path does not exist: ${codebasePath}`);
package/lib/analyzer.js CHANGED
@@ -67,12 +67,19 @@ async function scanCodebase(codebasePath) {
67
67
  const content = fs.readFileSync(file, 'utf-8');
68
68
  const relativePath = path.relative(codebasePath, file);
69
69
 
70
- // Limit content per file
71
- const truncatedContent = content.slice(0, 3000);
70
+ // Smart extraction: if file is large, extract route-like patterns
71
+ let extractedContent;
72
+ if (content.length > 8000) {
73
+ // For large files, extract route definitions and API patterns
74
+ extractedContent = extractRoutePatterns(content, relativePath);
75
+ } else {
76
+ // For smaller files, include more content
77
+ extractedContent = content.slice(0, 8000);
78
+ }
72
79
 
73
80
  fileContents.push({
74
81
  path: relativePath,
75
- content: truncatedContent
82
+ content: extractedContent
76
83
  });
77
84
  } catch (error) {
78
85
  // Skip files that can't be read
@@ -82,6 +89,73 @@ async function scanCodebase(codebasePath) {
82
89
  return fileContents;
83
90
  }
84
91
 
92
+ /**
93
+ * Extract route patterns from large files
94
+ */
95
+ function extractRoutePatterns(content, filePath) {
96
+ const lines = content.split('\n');
97
+ const relevantLines = [];
98
+
99
+ // Patterns that indicate API routes/endpoints
100
+ const routePatterns = [
101
+ /app\.(get|post|put|patch|delete|use)\s*\(/i,
102
+ /router\.(get|post|put|patch|delete|use)\s*\(/i,
103
+ /Route::(get|post|put|patch|delete)\s*\(/i,
104
+ /@(Get|Post|Put|Patch|Delete|RequestMapping)/i,
105
+ /def\s+(get|post|put|patch|delete|index|create|update|destroy)/i,
106
+ /function\s+\w+\s*\(\s*(req|request)/i,
107
+ /fetch\s*\(/i,
108
+ /axios\./i,
109
+ /api['"]\s*:/i,
110
+ /endpoint/i,
111
+ /\/api\//i
112
+ ];
113
+
114
+ let inRouteBlock = false;
115
+ let braceCount = 0;
116
+
117
+ for (let i = 0; i < lines.length; i++) {
118
+ const line = lines[i];
119
+
120
+ // Check if line matches any route pattern
121
+ const isRouteLine = routePatterns.some(pattern => pattern.test(line));
122
+
123
+ if (isRouteLine) {
124
+ // Include context: 2 lines before
125
+ for (let j = Math.max(0, i - 2); j < i; j++) {
126
+ if (!relevantLines.includes(lines[j])) {
127
+ relevantLines.push(`// Line ${j + 1}: ${lines[j]}`);
128
+ }
129
+ }
130
+ relevantLines.push(`// Line ${i + 1}: ${line}`);
131
+ inRouteBlock = true;
132
+ braceCount = (line.match(/{/g) || []).length - (line.match(/}/g) || []).length;
133
+ } else if (inRouteBlock) {
134
+ // Continue capturing the route handler
135
+ relevantLines.push(line);
136
+ braceCount += (line.match(/{/g) || []).length - (line.match(/}/g) || []).length;
137
+
138
+ // End of route block
139
+ if (braceCount <= 0) {
140
+ inRouteBlock = false;
141
+ relevantLines.push('// ---');
142
+ }
143
+
144
+ // Safety limit per block
145
+ if (relevantLines.length > 200) {
146
+ inRouteBlock = false;
147
+ }
148
+ }
149
+ }
150
+
151
+ // If we found relevant lines, return them; otherwise return truncated content
152
+ if (relevantLines.length > 10) {
153
+ return `// Extracted route patterns from ${filePath} (${lines.length} lines total)\n\n${relevantLines.join('\n')}`;
154
+ }
155
+
156
+ return content.slice(0, 8000);
157
+ }
158
+
85
159
  /**
86
160
  * Prioritize files based on keywords in path/name
87
161
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@merlean/analyzer",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "AI Bot codebase analyzer - generates site maps for AI assistant integration",
5
5
  "keywords": ["ai", "bot", "analyzer", "claude", "anthropic", "widget"],
6
6
  "author": "zmaren",