@merlean/analyzer 2.3.0 → 3.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.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # @merlean/analyzer
2
+
3
+ AI-powered codebase analyzer that generates site maps for the Merlean AI assistant widget.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @merlean/analyzer
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ # Analyze current directory
15
+ merleanalyze --name "My App"
16
+
17
+ # Analyze specific path
18
+ merleanalyze ./my-project --name "My App"
19
+
20
+ # Merge into existing site map
21
+ merleanalyze ./admin-panel --merge-with site_abc123
22
+ ```
23
+
24
+ Or use with npx (no installation required):
25
+
26
+ ```bash
27
+ npx @merlean/analyzer ./my-project --name "My App"
28
+ ```
29
+
30
+ ## Options
31
+
32
+ | Option | Description |
33
+ |--------|-------------|
34
+ | `--name, -n <name>` | Site name (required for new analysis) |
35
+ | `--merge-with, -m <siteId>` | Merge into existing site map |
36
+ | `--backend, -b <url>` | Custom backend URL |
37
+ | `--output, -o <file>` | Save site map locally |
38
+ | `--help, -h` | Show help |
39
+
40
+ ## Supported Frameworks
41
+
42
+ - **JavaScript/TypeScript**: Express, Fastify, NestJS, React, Vue, Angular
43
+ - **PHP**: CodeIgniter, Laravel, Symfony
44
+ - **Python**: Flask, FastAPI, Django
45
+ - **Ruby**: Rails, Sinatra
46
+ - **Go**: Gin, Echo, Chi
47
+ - **Java/Kotlin**: Spring Boot
48
+
49
+ ## How It Works
50
+
51
+ 1. Scans your codebase for API patterns
52
+ 2. Extracts route definitions and request schemas
53
+ 3. Uploads to Merlean backend for AI analysis
54
+ 4. Returns a site ID for widget integration
55
+
56
+ ## Integration
57
+
58
+ After analysis, add the widget to your site:
59
+
60
+ ```html
61
+ <script src="https://ai-bot-backend.fly.dev/bot.js" data-site-id="YOUR_SITE_ID"></script>
62
+ ```
63
+
64
+ ## Platform Support
65
+
66
+ Pre-compiled binaries are available for:
67
+ - macOS (Apple Silicon / ARM64)
68
+ - macOS (Intel / x64)
69
+ - Linux (x64)
70
+ - Windows (x64)
71
+
72
+ ## Links
73
+
74
+ - [Documentation](https://github.com/zmaren/merlean#readme)
75
+ - [Report Issues](https://github.com/zmaren/merlean/issues)
package/bin/cli.js CHANGED
@@ -1,187 +1,67 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Merlean Analyzer CLI
4
+ * Merlean Analyzer - Platform Binary Loader
5
5
  *
6
- * Scans your codebase and uploads to Merlean backend for AI analysis.
7
- * No API keys required - analysis happens on our servers.
8
- *
9
- * Usage:
10
- * npx @merlean/analyzer ./my-project --name "My App"
6
+ * This wrapper loads the platform-specific binary for your OS/architecture.
7
+ * The actual analysis logic is compiled into native binaries.
11
8
  */
12
9
 
13
- const { scanCodebase } = require('../lib/analyzer');
10
+ const { spawn } = require('child_process');
14
11
  const path = require('path');
15
12
  const fs = require('fs');
16
13
 
17
- const DEFAULT_BACKEND = 'https://ai-bot-backend.fly.dev';
18
-
19
- // Parse CLI arguments
20
- function parseArgs() {
21
- const args = process.argv.slice(2);
22
- const options = {
23
- path: null,
24
- name: null,
25
- backend: DEFAULT_BACKEND,
26
- output: null,
27
- mergeWith: null // Existing siteId to merge into
28
- };
29
-
30
- for (let i = 0; i < args.length; i++) {
31
- const arg = args[i];
32
-
33
- if (arg === '--name' || arg === '-n') {
34
- options.name = args[++i];
35
- } else if (arg === '--backend' || arg === '-b') {
36
- options.backend = args[++i];
37
- } else if (arg === '--output' || arg === '-o') {
38
- options.output = args[++i];
39
- } else if (arg === '--merge-with' || arg === '-m') {
40
- options.mergeWith = args[++i];
41
- } else if (arg === '--help' || arg === '-h') {
42
- printHelp();
43
- process.exit(0);
44
- } else if (!arg.startsWith('-') && !options.path) {
45
- options.path = arg;
46
- }
47
- }
48
-
49
- return options;
50
- }
51
-
52
- function printHelp() {
53
- console.log(`
54
- Merlean Analyzer - AI-powered codebase analysis
55
-
56
- Usage:
57
- npx @merlean/analyzer --name <name>
58
- npx @merlean/analyzer <path> --name <name>
59
-
60
- Arguments:
61
- <path> Path to codebase (default: current directory)
62
-
63
- Options:
64
- --name, -n <name> Site name (required for new analysis)
65
- --merge-with, -m <siteId> Merge into existing site map (appends routes/forms/actions)
66
- --backend, -b <url> Backend URL (default: ${DEFAULT_BACKEND})
67
- --output, -o <file> Save site map locally (optional)
68
- --help, -h Show this help
69
-
70
- Examples:
71
- # Analyze current directory
72
- npx @merlean/analyzer --name "My App"
73
-
74
- # Analyze specific path
75
- npx @merlean/analyzer ./my-app --name "My App"
76
-
77
- # Merge another frontend into existing site map
78
- npx @merlean/analyzer ./admin-panel --merge-with site_abc123
79
-
80
- # Use custom backend (for local dev)
81
- npx @merlean/analyzer --name "My App" --backend http://localhost:3004
82
- `);
14
+ const PLATFORMS = {
15
+ 'darwin-arm64': '@merlean/analyzer-darwin-arm64',
16
+ 'darwin-x64': '@merlean/analyzer-darwin-x64',
17
+ 'linux-x64': '@merlean/analyzer-linux-x64',
18
+ 'win32-x64': '@merlean/analyzer-win32-x64',
19
+ };
20
+
21
+ const platformKey = `${process.platform}-${process.arch}`;
22
+ const packageName = PLATFORMS[platformKey];
23
+
24
+ if (!packageName) {
25
+ console.error(`\nāŒ Unsupported platform: ${platformKey}`);
26
+ console.error(`\nSupported platforms:`);
27
+ Object.keys(PLATFORMS).forEach(p => console.error(` - ${p}`));
28
+ console.error(`\nPlease open an issue at https://github.com/zmaren/merlean/issues`);
29
+ process.exit(1);
83
30
  }
84
31
 
85
- async function main() {
86
- console.log('\nšŸ” Merlean Analyzer\n');
87
-
88
- const options = parseArgs();
89
-
90
- // Validate required args
91
- if (!options.name && !options.mergeWith) {
92
- console.error('āŒ Error: --name is required (or use --merge-with to merge into existing site)');
93
- console.log(' Run with --help for usage');
94
- process.exit(1);
95
- }
96
-
97
- // Default to current directory if no path provided
98
- const codebasePath = path.resolve(options.path || '.');
32
+ let binaryPath;
33
+ try {
34
+ // Find the platform-specific package
35
+ const packagePath = require.resolve(`${packageName}/package.json`);
36
+ const packageDir = path.dirname(packagePath);
37
+ const binaryName = process.platform === 'win32' ? 'merleanalyze.exe' : 'merleanalyze';
38
+ binaryPath = path.join(packageDir, 'bin', binaryName);
99
39
 
100
- if (!fs.existsSync(codebasePath)) {
101
- console.error(`āŒ Error: Path does not exist: ${codebasePath}`);
102
- process.exit(1);
40
+ if (!fs.existsSync(binaryPath)) {
41
+ throw new Error('Binary not found in package');
103
42
  }
43
+ } catch (e) {
44
+ console.error(`\nāŒ Failed to find binary for ${platformKey}`);
45
+ console.error(`\nPackage: ${packageName}`);
46
+ console.error(`Error: ${e.message}`);
47
+ console.error(`\nTry reinstalling:`);
48
+ console.error(` npm install -g @merlean/analyzer`);
49
+ console.error(`\nOr with npx (downloads fresh):`);
50
+ console.error(` npx @merlean/analyzer@latest --help`);
51
+ process.exit(1);
52
+ }
104
53
 
105
- console.log(`šŸ“ Scanning: ${codebasePath}`);
106
- if (options.mergeWith) {
107
- console.log(`šŸ”— Merging into: ${options.mergeWith}`);
108
- if (options.name) {
109
- console.log(`šŸ“› Site name: ${options.name} (will update existing)`);
110
- }
111
- } else {
112
- console.log(`šŸ“› Site name: ${options.name}`);
113
- }
114
-
115
- try {
116
- // Scan codebase locally
117
- const scanResult = await scanCodebase(codebasePath);
118
- // Handle both old format (array) and new format (object with files + preExtractedRoutes)
119
- const fileContents = Array.isArray(scanResult) ? scanResult : scanResult.files;
120
- const preExtractedRoutes = Array.isArray(scanResult) ? [] : (scanResult.preExtractedRoutes || []);
121
-
122
- console.log(`\nšŸ“¤ Uploading to backend for analysis...`);
123
-
124
- // Build request body
125
- const requestBody = {
126
- siteName: options.name,
127
- files: fileContents,
128
- preExtractedRoutes // Include convention-based routes
129
- };
130
-
131
- // Add merge parameter if specified
132
- if (options.mergeWith) {
133
- requestBody.mergeWithSiteId = options.mergeWith;
134
- }
135
-
136
- // Send to backend for LLM analysis
137
- const response = await fetch(`${options.backend}/api/analyze`, {
138
- method: 'POST',
139
- headers: { 'Content-Type': 'application/json' },
140
- body: JSON.stringify(requestBody)
141
- });
142
-
143
- if (!response.ok) {
144
- const error = await response.text();
145
- throw new Error(`Backend error: ${response.status} ${error}`);
146
- }
147
-
148
- const result = await response.json();
149
-
150
- if (options.mergeWith) {
151
- console.log('\nāœ… Merge complete!');
152
- console.log('\nšŸ“Š Updated Summary:');
153
- } else {
154
- console.log('\nāœ… Analysis complete!');
155
- console.log('\nšŸ“Š Summary:');
156
- }
157
- console.log(` Site ID: ${result.siteId}`);
158
- console.log(` Framework: ${result.framework || 'Unknown'}`);
159
- console.log(` Routes: ${result.routes?.length || 0}`);
160
- console.log(` Forms: ${result.forms?.length || 0}`);
161
- console.log(` Actions: ${result.actions?.length || 0}`);
162
-
163
- if (result.merged) {
164
- console.log(`\n šŸ“Ž Merged from: ${result.merged.sourcesCount} source(s)`);
165
- }
166
-
167
- // Save locally if requested
168
- if (options.output) {
169
- const outputPath = path.resolve(options.output);
170
- fs.writeFileSync(outputPath, JSON.stringify(result, null, 2));
171
- console.log(`\nšŸ’¾ Saved to: ${outputPath}`);
172
- }
173
-
174
- // Show integration instructions
175
- console.log('\n' + '─'.repeat(50));
176
- console.log('\nšŸŽ‰ Integration Ready!\n');
177
- console.log('Add this to your website:\n');
178
- console.log(`<script src="${options.backend}/bot.js" data-site-id="${result.siteId}"></script>`);
179
- console.log('\n' + '─'.repeat(50) + '\n');
54
+ // Run the binary with all arguments
55
+ const child = spawn(binaryPath, process.argv.slice(2), {
56
+ stdio: 'inherit',
57
+ env: process.env
58
+ });
180
59
 
181
- } catch (error) {
182
- console.error(`\nāŒ Error: ${error.message}`);
183
- process.exit(1);
184
- }
185
- }
60
+ child.on('error', (err) => {
61
+ console.error(`\nāŒ Failed to execute binary: ${err.message}`);
62
+ process.exit(1);
63
+ });
186
64
 
187
- main();
65
+ child.on('exit', (code) => {
66
+ process.exit(code || 0);
67
+ });
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@merlean/analyzer",
3
- "version": "2.3.0",
4
- "description": "AI Bot codebase analyzer - generates site maps for AI assistant integration",
5
- "keywords": ["ai", "bot", "analyzer", "claude", "anthropic", "widget"],
3
+ "version": "3.0.1",
4
+ "description": "AI-powered codebase analyzer - generates site maps for AI assistant integration",
5
+ "keywords": ["ai", "bot", "analyzer", "claude", "anthropic", "widget", "merlean"],
6
6
  "author": "zmaren",
7
7
  "license": "MIT",
8
8
  "repository": {
@@ -15,32 +15,18 @@
15
15
  "access": "public"
16
16
  },
17
17
  "bin": {
18
- "ai-bot-analyze": "./bin/wrapper.js"
18
+ "merleanalyze": "./bin/cli.js"
19
19
  },
20
- "main": "lib/analyzer.js",
21
20
  "files": [
22
- "bin/",
23
- "lib/",
24
- "scripts/"
21
+ "bin/"
25
22
  ],
26
- "scripts": {
27
- "postinstall": "node scripts/postinstall.js",
28
- "build": "pkg . --targets node18-linux-x64,node18-macos-x64,node18-macos-arm64,node18-win-x64 --output dist/ai-bot-analyze",
29
- "build:local": "pkg bin/cli.js --targets node18-macos-arm64 --output dist/ai-bot-analyze-macos-arm64"
30
- },
31
- "pkg": {
32
- "scripts": ["lib/**/*.js", "bin/cli.js"],
33
- "assets": [],
34
- "targets": ["node18-linux-x64", "node18-macos-x64", "node18-macos-arm64", "node18-win-x64"],
35
- "outputPath": "dist"
23
+ "optionalDependencies": {
24
+ "@merlean/analyzer-darwin-arm64": "3.0.1",
25
+ "@merlean/analyzer-darwin-x64": "3.0.1",
26
+ "@merlean/analyzer-linux-x64": "3.0.1",
27
+ "@merlean/analyzer-win32-x64": "3.0.1"
36
28
  },
37
29
  "engines": {
38
30
  "node": ">=18.0.0"
39
- },
40
- "dependencies": {
41
- "glob": "^10.3.10"
42
- },
43
- "devDependencies": {
44
- "pkg": "^5.8.1"
45
31
  }
46
32
  }
package/bin/wrapper.js DELETED
@@ -1,51 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * AI Bot Analyzer - Wrapper Script
5
- *
6
- * Attempts to run the compiled binary, falls back to source if not available.
7
- * This allows the package to work even if binary download failed.
8
- */
9
-
10
- const { spawn, execFileSync } = require('child_process');
11
- const path = require('path');
12
- const fs = require('fs');
13
-
14
- const binDir = __dirname;
15
- const binaryName = process.platform === 'win32' ? 'ai-bot-analyze.exe' : 'ai-bot-analyze';
16
- const binaryPath = path.join(binDir, binaryName);
17
- const sourcePath = path.join(binDir, 'cli.js');
18
- const sourceModeFlagPath = path.join(binDir, '..', '.source-mode');
19
-
20
- // Check if we should use source mode
21
- const useSourceMode = fs.existsSync(sourceModeFlagPath) || !fs.existsSync(binaryPath);
22
-
23
- if (useSourceMode) {
24
- // Run source directly with Node.js
25
- require('./cli.js');
26
- } else {
27
- // Run compiled binary
28
- const args = process.argv.slice(2);
29
-
30
- try {
31
- const result = spawn(binaryPath, args, {
32
- stdio: 'inherit',
33
- env: process.env
34
- });
35
-
36
- result.on('error', (err) => {
37
- // If binary fails, fall back to source
38
- console.error('Binary execution failed, falling back to source mode...');
39
- require('./cli.js');
40
- });
41
-
42
- result.on('exit', (code) => {
43
- process.exit(code || 0);
44
- });
45
-
46
- } catch (err) {
47
- // Fall back to source mode
48
- require('./cli.js');
49
- }
50
- }
51
-