bonzai-burn 1.0.43 → 1.0.47
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/dist/bconfig.js +224 -0
- package/dist/graph-templates/config.js +18 -0
- package/dist/graph-templates/ignore.txt +58 -0
- package/dist/graph-templates/loops/visualization/list.js +16 -0
- package/dist/graph-templates/loops/visualization/read.js +120 -0
- package/dist/graph-templates/loops/visualization/scan_code_quality.js +144 -0
- package/dist/graph-templates/receiver.js +66 -0
- package/dist/graph-templates/utils/fileList.js +96 -0
- package/dist/graph-templates/utils/ignore.js +53 -0
- package/dist/graph-templates/utils/parsers.js +720 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/bconfig.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { spawn, exec } from 'child_process';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { ENABLED_LOOPS } from './loops.config.js';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
// Template folder in the package
|
|
12
|
+
const TEMPLATE_DIR = path.join(__dirname, 'graph-templates');
|
|
13
|
+
|
|
14
|
+
// Helper function to recursively copy directory
|
|
15
|
+
function copyDirectory(src, dest) {
|
|
16
|
+
if (!fs.existsSync(dest)) {
|
|
17
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
20
|
+
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
const srcPath = path.join(src, entry.name);
|
|
23
|
+
const destPath = path.join(dest, entry.name);
|
|
24
|
+
|
|
25
|
+
if (entry.isDirectory()) {
|
|
26
|
+
copyDirectory(srcPath, destPath);
|
|
27
|
+
} else {
|
|
28
|
+
fs.copyFileSync(srcPath, destPath);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function main() {
|
|
34
|
+
const currentDir = process.cwd();
|
|
35
|
+
const bonzaiDir = path.join(currentDir, 'bonzai');
|
|
36
|
+
const receiverPath = path.join(bonzaiDir, 'receiver.js');
|
|
37
|
+
|
|
38
|
+
console.log('Setting up local file server...');
|
|
39
|
+
|
|
40
|
+
// Create bonzai directory
|
|
41
|
+
if (!fs.existsSync(bonzaiDir)) {
|
|
42
|
+
console.log('Creating bonzai directory...');
|
|
43
|
+
fs.mkdirSync(bonzaiDir);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Write receiver.js
|
|
47
|
+
console.log('Writing receiver.js...');
|
|
48
|
+
const receiverContent = fs.readFileSync(path.join(TEMPLATE_DIR, 'receiver.js'), 'utf8');
|
|
49
|
+
fs.writeFileSync(receiverPath, receiverContent);
|
|
50
|
+
fs.chmodSync(receiverPath, '755');
|
|
51
|
+
|
|
52
|
+
// Write config.js
|
|
53
|
+
console.log('Writing config.js...');
|
|
54
|
+
const configContent = fs.readFileSync(path.join(TEMPLATE_DIR, 'config.js'), 'utf8');
|
|
55
|
+
fs.writeFileSync(path.join(bonzaiDir, 'config.js'), configContent);
|
|
56
|
+
|
|
57
|
+
// Copy handlers from enabled loops
|
|
58
|
+
console.log('Copying handlers...');
|
|
59
|
+
const handlersDest = path.join(bonzaiDir, 'handlers');
|
|
60
|
+
if (!fs.existsSync(handlersDest)) {
|
|
61
|
+
fs.mkdirSync(handlersDest, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Copy visualization loop handlers
|
|
65
|
+
if (ENABLED_LOOPS.includes('visualization')) {
|
|
66
|
+
const vizSrc = path.join(TEMPLATE_DIR, 'loops', 'visualization');
|
|
67
|
+
if (fs.existsSync(vizSrc)) {
|
|
68
|
+
for (const file of fs.readdirSync(vizSrc)) {
|
|
69
|
+
fs.copyFileSync(path.join(vizSrc, file), path.join(handlersDest, file));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Copy backend loop handlers
|
|
75
|
+
if (ENABLED_LOOPS.includes('backend')) {
|
|
76
|
+
const backendSrc = path.join(TEMPLATE_DIR, 'loops', 'backend');
|
|
77
|
+
if (fs.existsSync(backendSrc)) {
|
|
78
|
+
for (const file of fs.readdirSync(backendSrc)) {
|
|
79
|
+
fs.copyFileSync(path.join(backendSrc, file), path.join(handlersDest, file));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Copy utils directory
|
|
85
|
+
console.log('Copying utils...');
|
|
86
|
+
const utilsSrc = path.join(TEMPLATE_DIR, 'utils');
|
|
87
|
+
const utilsDest = path.join(bonzaiDir, 'utils');
|
|
88
|
+
copyDirectory(utilsSrc, utilsDest);
|
|
89
|
+
|
|
90
|
+
// Write .ignore file in bonzai directory
|
|
91
|
+
const ignoreTargetPath = path.join(bonzaiDir, '.ignore');
|
|
92
|
+
if (!fs.existsSync(ignoreTargetPath)) {
|
|
93
|
+
console.log('Writing .ignore file...');
|
|
94
|
+
const ignoreContent = fs.readFileSync(path.join(TEMPLATE_DIR, 'ignore.txt'), 'utf8');
|
|
95
|
+
fs.writeFileSync(ignoreTargetPath, ignoreContent);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Setup package.json in bonzai directory
|
|
99
|
+
const packageJsonPath = path.join(bonzaiDir, 'package.json');
|
|
100
|
+
let packageJson = {};
|
|
101
|
+
|
|
102
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
103
|
+
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
104
|
+
} else {
|
|
105
|
+
packageJson = {
|
|
106
|
+
name: "bonzai-server",
|
|
107
|
+
version: "1.0.0",
|
|
108
|
+
description: "Dependencies for bonzai graph server",
|
|
109
|
+
main: "receiver.js",
|
|
110
|
+
scripts: {
|
|
111
|
+
test: "echo \"Error: no test specified\" && exit 1"
|
|
112
|
+
},
|
|
113
|
+
author: "",
|
|
114
|
+
license: "ISC"
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Add dependencies
|
|
119
|
+
if (!packageJson.dependencies) {
|
|
120
|
+
packageJson.dependencies = {};
|
|
121
|
+
}
|
|
122
|
+
packageJson.dependencies.express = "^4.18.2";
|
|
123
|
+
packageJson.dependencies.cors = "^2.8.5";
|
|
124
|
+
packageJson.dependencies["@babel/parser"] = "^7.23.0";
|
|
125
|
+
packageJson.dependencies.ws = "^8.14.2";
|
|
126
|
+
packageJson.dependencies["node-pty"] = "^1.0.0";
|
|
127
|
+
|
|
128
|
+
// Add script to run receiver
|
|
129
|
+
if (!packageJson.scripts) {
|
|
130
|
+
packageJson.scripts = {};
|
|
131
|
+
}
|
|
132
|
+
packageJson.scripts["file-server"] = "node receiver.js";
|
|
133
|
+
|
|
134
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
135
|
+
|
|
136
|
+
console.log('Installing dependencies...');
|
|
137
|
+
|
|
138
|
+
// Install dependencies in bonzai directory
|
|
139
|
+
return new Promise((resolve, reject) => {
|
|
140
|
+
const npm = spawn('npm', ['install'], {
|
|
141
|
+
stdio: 'inherit',
|
|
142
|
+
cwd: bonzaiDir
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
npm.on('close', (code) => {
|
|
146
|
+
if (code === 0) {
|
|
147
|
+
// Fix node-pty spawn-helper permissions (npm doesn't preserve execute bits)
|
|
148
|
+
const nodePtyPrebuilds = path.join(bonzaiDir, 'node_modules', 'node-pty', 'prebuilds');
|
|
149
|
+
if (fs.existsSync(nodePtyPrebuilds)) {
|
|
150
|
+
const archDirs = ['darwin-arm64', 'darwin-x64', 'linux-x64', 'linux-arm64'];
|
|
151
|
+
for (const arch of archDirs) {
|
|
152
|
+
const spawnHelperPath = path.join(nodePtyPrebuilds, arch, 'spawn-helper');
|
|
153
|
+
if (fs.existsSync(spawnHelperPath)) {
|
|
154
|
+
try {
|
|
155
|
+
fs.chmodSync(spawnHelperPath, '755');
|
|
156
|
+
console.log(`Fixed node-pty spawn-helper permissions (${arch})`);
|
|
157
|
+
} catch (e) {
|
|
158
|
+
console.warn(`Warning: Could not fix spawn-helper permissions for ${arch}:`, e.message);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
console.log('\nListener endpoints successfully deployed');
|
|
165
|
+
console.log('All code stays on your machine\n');
|
|
166
|
+
console.log('Relay server running on localhost:3001');
|
|
167
|
+
console.log('Terminal WebSocket available at ws://localhost:3001/terminal');
|
|
168
|
+
console.log('Diagram available at https://bonzai.dev/\n');
|
|
169
|
+
|
|
170
|
+
// Start the server automatically
|
|
171
|
+
const server = spawn('node', ['receiver.js'], {
|
|
172
|
+
stdio: 'inherit',
|
|
173
|
+
cwd: bonzaiDir,
|
|
174
|
+
env: {
|
|
175
|
+
...process.env,
|
|
176
|
+
BONZAI_REPO_DIR: currentDir
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Open browser automatically
|
|
181
|
+
exec('open https://bonzai.dev/');
|
|
182
|
+
|
|
183
|
+
// Handle server process
|
|
184
|
+
server.on('close', (serverCode) => {
|
|
185
|
+
console.log(`\nServer stopped with code ${serverCode}`);
|
|
186
|
+
process.exit(serverCode);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
server.on('error', (err) => {
|
|
190
|
+
console.error('Error starting server:', err.message);
|
|
191
|
+
process.exit(1);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Handle cleanup on exit
|
|
195
|
+
process.on('SIGINT', () => {
|
|
196
|
+
console.log('\nShutting down server...');
|
|
197
|
+
server.kill('SIGINT');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
process.on('SIGTERM', () => {
|
|
201
|
+
console.log('\nShutting down server...');
|
|
202
|
+
server.kill('SIGTERM');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
resolve();
|
|
206
|
+
} else {
|
|
207
|
+
reject(new Error('npm install failed with code ' + code));
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
npm.on('error', (err) => {
|
|
212
|
+
reject(err);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Export for use via index.js flags
|
|
218
|
+
export { main };
|
|
219
|
+
|
|
220
|
+
// Run directly if called as standalone command
|
|
221
|
+
const isDirectRun = process.argv[1]?.endsWith('bconfig.js');
|
|
222
|
+
if (isDirectRun) {
|
|
223
|
+
main().catch(console.error);
|
|
224
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
// Root directory (one level up from templates/)
|
|
4
|
+
const ROOT = path.join(__dirname, '..');
|
|
5
|
+
|
|
6
|
+
// Initialize babelParser (optional dependency)
|
|
7
|
+
let babelParser = null;
|
|
8
|
+
try {
|
|
9
|
+
babelParser = require('./node_modules/@babel/parser');
|
|
10
|
+
} catch (e) {
|
|
11
|
+
// Babel parser not available, will fall back gracefully
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
ROOT,
|
|
16
|
+
babelParser
|
|
17
|
+
};
|
|
18
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Ignore patterns for file listing
|
|
2
|
+
# Lines starting with # are comments
|
|
3
|
+
# Use * for wildcards and ** for recursive patterns
|
|
4
|
+
|
|
5
|
+
# Dependencies
|
|
6
|
+
node_modules/
|
|
7
|
+
package.json
|
|
8
|
+
package-lock.json
|
|
9
|
+
|
|
10
|
+
# IDE and editor files
|
|
11
|
+
.vscode/
|
|
12
|
+
.idea/
|
|
13
|
+
*.swp
|
|
14
|
+
*.swo
|
|
15
|
+
|
|
16
|
+
# OS generated files
|
|
17
|
+
.DS_Store
|
|
18
|
+
.DS_Store?
|
|
19
|
+
._*
|
|
20
|
+
.Spotlight-V100
|
|
21
|
+
.Trashes
|
|
22
|
+
ehthumbs.db
|
|
23
|
+
Thumbs.db
|
|
24
|
+
|
|
25
|
+
# Environment and config files
|
|
26
|
+
.env
|
|
27
|
+
.env.local
|
|
28
|
+
.env.production
|
|
29
|
+
.env.staging
|
|
30
|
+
|
|
31
|
+
# Version control
|
|
32
|
+
.git/
|
|
33
|
+
.gitignore
|
|
34
|
+
.ignore
|
|
35
|
+
|
|
36
|
+
# Logs
|
|
37
|
+
*.log
|
|
38
|
+
logs/
|
|
39
|
+
|
|
40
|
+
# Build outputs
|
|
41
|
+
dist/
|
|
42
|
+
build/
|
|
43
|
+
static/
|
|
44
|
+
out/
|
|
45
|
+
.next/
|
|
46
|
+
*.min.js
|
|
47
|
+
*.min.css
|
|
48
|
+
*.bundle.js
|
|
49
|
+
*.chunk.js
|
|
50
|
+
|
|
51
|
+
# Temporary files
|
|
52
|
+
*.tmp
|
|
53
|
+
*.temp
|
|
54
|
+
|
|
55
|
+
# Project-specific files
|
|
56
|
+
receiver.js
|
|
57
|
+
bonzai/
|
|
58
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { ROOT } = require('../config');
|
|
3
|
+
const { listAllFiles } = require('../utils/fileList');
|
|
4
|
+
|
|
5
|
+
function listHandler(req, res) {
|
|
6
|
+
try {
|
|
7
|
+
const rootName = path.basename(ROOT);
|
|
8
|
+
const files = listAllFiles(ROOT, rootName);
|
|
9
|
+
res.json({ files });
|
|
10
|
+
} catch (e) {
|
|
11
|
+
res.status(500).send(e.message);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = listHandler;
|
|
16
|
+
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { ROOT } = require('../config');
|
|
4
|
+
const { extractPythonFunctions, extractJavaScriptFunctions, extractVueFunctions } = require('../utils/parsers');
|
|
5
|
+
|
|
6
|
+
function readHandler(req, res) {
|
|
7
|
+
try {
|
|
8
|
+
const requestedPath = req.query.path || '';
|
|
9
|
+
const filePath = path.join(ROOT, requestedPath);
|
|
10
|
+
|
|
11
|
+
if (!filePath.startsWith(ROOT)) {
|
|
12
|
+
return res.status(400).send('Invalid path');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Helper function to find and return content from parse result
|
|
16
|
+
const findAndReturn = (parseResult, name, type) => {
|
|
17
|
+
if (type === 'function') {
|
|
18
|
+
const target = parseResult.functions.find(f => f.name === name);
|
|
19
|
+
if (target) return target.content;
|
|
20
|
+
} else if (type === 'method') {
|
|
21
|
+
// Method name format: ClassName.methodName
|
|
22
|
+
for (const cls of parseResult.classes) {
|
|
23
|
+
const method = cls.methods.find(m => m.name === name);
|
|
24
|
+
if (method) return method.content;
|
|
25
|
+
}
|
|
26
|
+
} else if (type === 'class') {
|
|
27
|
+
const target = parseResult.classes.find(c => c.name === name);
|
|
28
|
+
if (target) return target.content;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Check if this is a virtual file request (.function, .method, or .class)
|
|
34
|
+
if (requestedPath.endsWith('.function') || requestedPath.endsWith('.method') || requestedPath.endsWith('.class')) {
|
|
35
|
+
// Traverse up the path to find the actual source file
|
|
36
|
+
let currentPath = filePath;
|
|
37
|
+
let sourceFilePath = null;
|
|
38
|
+
let parser = null;
|
|
39
|
+
|
|
40
|
+
// Keep going up until we find a source file (.py, .js, .jsx, .ts, .tsx, .vue)
|
|
41
|
+
while (currentPath !== ROOT && currentPath !== path.dirname(currentPath)) {
|
|
42
|
+
const stat = fs.existsSync(currentPath) ? fs.statSync(currentPath) : null;
|
|
43
|
+
|
|
44
|
+
// Check if current path is a file with a supported extension
|
|
45
|
+
if (stat && stat.isFile()) {
|
|
46
|
+
if (currentPath.endsWith('.py')) {
|
|
47
|
+
parser = extractPythonFunctions;
|
|
48
|
+
sourceFilePath = currentPath;
|
|
49
|
+
break;
|
|
50
|
+
} else if (currentPath.endsWith('.js') || currentPath.endsWith('.jsx') ||
|
|
51
|
+
currentPath.endsWith('.ts') || currentPath.endsWith('.tsx')) {
|
|
52
|
+
parser = extractJavaScriptFunctions;
|
|
53
|
+
sourceFilePath = currentPath;
|
|
54
|
+
break;
|
|
55
|
+
} else if (currentPath.endsWith('.vue')) {
|
|
56
|
+
parser = extractVueFunctions;
|
|
57
|
+
sourceFilePath = currentPath;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Move up one level
|
|
63
|
+
const parentPath = path.dirname(currentPath);
|
|
64
|
+
if (parentPath === currentPath) break; // Reached root
|
|
65
|
+
currentPath = parentPath;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!sourceFilePath || !parser) {
|
|
69
|
+
return res.status(404).send('Source file not found for virtual file');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Extract the requested item name from the requested path
|
|
73
|
+
let itemName = '';
|
|
74
|
+
let itemType = '';
|
|
75
|
+
|
|
76
|
+
if (requestedPath.endsWith('.function')) {
|
|
77
|
+
itemName = path.basename(requestedPath, '.function');
|
|
78
|
+
itemType = 'function';
|
|
79
|
+
} else if (requestedPath.endsWith('.method')) {
|
|
80
|
+
itemName = path.basename(requestedPath, '.method');
|
|
81
|
+
itemType = 'method';
|
|
82
|
+
} else if (requestedPath.endsWith('.class')) {
|
|
83
|
+
itemName = path.basename(requestedPath, '.class');
|
|
84
|
+
itemType = 'class';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Check if the source file exists
|
|
88
|
+
try {
|
|
89
|
+
if (!fs.existsSync(sourceFilePath)) {
|
|
90
|
+
return res.status(404).send('Source file not found');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Parse the file
|
|
94
|
+
const parseResult = parser(sourceFilePath);
|
|
95
|
+
|
|
96
|
+
// Find and return the content
|
|
97
|
+
const content = findAndReturn(parseResult, itemName, itemType);
|
|
98
|
+
|
|
99
|
+
if (!content) {
|
|
100
|
+
return res.status(404).send(`${itemType} '${itemName}' not found in file`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return res.json({ content });
|
|
104
|
+
} catch (e) {
|
|
105
|
+
const errorType = requestedPath.endsWith('.function') ? 'function' :
|
|
106
|
+
requestedPath.endsWith('.method') ? 'method' : 'class';
|
|
107
|
+
return res.status(500).send('Error reading ' + errorType + ': ' + e.message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Regular file read
|
|
112
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
113
|
+
res.json({ content });
|
|
114
|
+
} catch (e) {
|
|
115
|
+
res.status(500).send(e.message);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = readHandler;
|
|
120
|
+
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { ROOT } = require('../config');
|
|
4
|
+
|
|
5
|
+
function scanCodeQualityHandler(req, res) {
|
|
6
|
+
try {
|
|
7
|
+
const { projectPath } = req.body;
|
|
8
|
+
|
|
9
|
+
if (!projectPath) {
|
|
10
|
+
return res.status(400).json({ error: 'projectPath is required' });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const targetPath = path.join(ROOT, projectPath);
|
|
14
|
+
|
|
15
|
+
if (!targetPath.startsWith(ROOT)) {
|
|
16
|
+
return res.status(400).json({ error: 'Invalid path' });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!fs.existsSync(targetPath)) {
|
|
20
|
+
return res.status(404).json({ error: 'Path not found' });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const issues = [];
|
|
24
|
+
|
|
25
|
+
// Basic code quality checks
|
|
26
|
+
function scanDirectory(dir) {
|
|
27
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
28
|
+
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
const fullPath = path.join(dir, entry.name);
|
|
31
|
+
const relativePath = path.relative(ROOT, fullPath);
|
|
32
|
+
|
|
33
|
+
// Skip node_modules and other ignored directories
|
|
34
|
+
if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'bonzai') {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (entry.isDirectory()) {
|
|
39
|
+
scanDirectory(fullPath);
|
|
40
|
+
} else if (entry.isFile()) {
|
|
41
|
+
// Check file size (warn if > 500KB)
|
|
42
|
+
const stats = fs.statSync(fullPath);
|
|
43
|
+
if (stats.size > 500 * 1024) {
|
|
44
|
+
issues.push({
|
|
45
|
+
file: relativePath,
|
|
46
|
+
severity: 'warning',
|
|
47
|
+
message: `Large file detected (${(stats.size / 1024).toFixed(2)}KB). Consider splitting into smaller modules.`,
|
|
48
|
+
type: 'file-size'
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check for common code quality issues in JS/TS files
|
|
53
|
+
if (entry.name.endsWith('.js') || entry.name.endsWith('.jsx') ||
|
|
54
|
+
entry.name.endsWith('.ts') || entry.name.endsWith('.tsx')) {
|
|
55
|
+
try {
|
|
56
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
57
|
+
const lines = content.split('\n');
|
|
58
|
+
|
|
59
|
+
// Check for very long lines
|
|
60
|
+
lines.forEach((line, index) => {
|
|
61
|
+
if (line.length > 200) {
|
|
62
|
+
issues.push({
|
|
63
|
+
file: relativePath,
|
|
64
|
+
line: index + 1,
|
|
65
|
+
severity: 'info',
|
|
66
|
+
message: `Long line detected (${line.length} characters). Consider breaking into multiple lines.`,
|
|
67
|
+
type: 'line-length'
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Check for TODO/FIXME comments
|
|
73
|
+
lines.forEach((line, index) => {
|
|
74
|
+
if (line.match(/TODO|FIXME|XXX|HACK/i)) {
|
|
75
|
+
issues.push({
|
|
76
|
+
file: relativePath,
|
|
77
|
+
line: index + 1,
|
|
78
|
+
severity: 'info',
|
|
79
|
+
message: `TODO/FIXME comment found: ${line.trim().substring(0, 100)}`,
|
|
80
|
+
type: 'todo-comment'
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Check for console.log statements (potential debug code)
|
|
86
|
+
lines.forEach((line, index) => {
|
|
87
|
+
if (line.match(/console\.(log|debug|info|warn|error)/) && !line.includes('//')) {
|
|
88
|
+
issues.push({
|
|
89
|
+
file: relativePath,
|
|
90
|
+
line: index + 1,
|
|
91
|
+
severity: 'warning',
|
|
92
|
+
message: `Console statement found. Consider removing or using a proper logging library.`,
|
|
93
|
+
type: 'console-statement'
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
} catch (e) {
|
|
99
|
+
// Skip files that can't be read
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const stat = fs.statSync(targetPath);
|
|
107
|
+
if (stat.isDirectory()) {
|
|
108
|
+
scanDirectory(targetPath);
|
|
109
|
+
} else {
|
|
110
|
+
// Single file scan
|
|
111
|
+
const relativePath = path.relative(ROOT, targetPath);
|
|
112
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
113
|
+
const lines = content.split('\n');
|
|
114
|
+
|
|
115
|
+
lines.forEach((line, index) => {
|
|
116
|
+
if (line.length > 200) {
|
|
117
|
+
issues.push({
|
|
118
|
+
file: relativePath,
|
|
119
|
+
line: index + 1,
|
|
120
|
+
severity: 'info',
|
|
121
|
+
message: `Long line detected (${line.length} characters)`,
|
|
122
|
+
type: 'line-length'
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
res.json({
|
|
129
|
+
success: true,
|
|
130
|
+
issues: issues,
|
|
131
|
+
totalIssues: issues.length,
|
|
132
|
+
summary: {
|
|
133
|
+
errors: issues.filter(i => i.severity === 'error').length,
|
|
134
|
+
warnings: issues.filter(i => i.severity === 'warning').length,
|
|
135
|
+
info: issues.filter(i => i.severity === 'info').length
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
} catch (e) {
|
|
140
|
+
res.status(500).json({ error: e.message });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = scanCodeQualityHandler;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const express = require('./node_modules/express');
|
|
4
|
+
const cors = require('./node_modules/cors');
|
|
5
|
+
const http = require('http');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
const app = express();
|
|
10
|
+
const server = http.createServer(app);
|
|
11
|
+
|
|
12
|
+
app.use(cors());
|
|
13
|
+
app.use(express.json());
|
|
14
|
+
|
|
15
|
+
// Root route
|
|
16
|
+
app.get('/', (req, res) => {
|
|
17
|
+
res.json({ message: 'Bonzai Server', status: 'running' });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Dynamically load handlers based on what exists
|
|
21
|
+
const handlersDir = path.join(__dirname, 'handlers');
|
|
22
|
+
|
|
23
|
+
function tryLoad(name) {
|
|
24
|
+
const filePath = path.join(handlersDir, name + '.js');
|
|
25
|
+
if (fs.existsSync(filePath)) {
|
|
26
|
+
return require(filePath);
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Visualization loop handlers
|
|
32
|
+
const listHandler = tryLoad('list');
|
|
33
|
+
const readHandler = tryLoad('read');
|
|
34
|
+
const scanCodeQualityHandler = tryLoad('scan_code_quality');
|
|
35
|
+
|
|
36
|
+
if (listHandler) app.get('/list', listHandler);
|
|
37
|
+
if (readHandler) app.get('/read', readHandler);
|
|
38
|
+
if (scanCodeQualityHandler) app.post('/scan_code_quality', scanCodeQualityHandler);
|
|
39
|
+
|
|
40
|
+
// Backend loop handlers
|
|
41
|
+
const deleteHandler = tryLoad('delete');
|
|
42
|
+
const openCursorHandler = tryLoad('open-cursor');
|
|
43
|
+
const writeHandler = tryLoad('write');
|
|
44
|
+
const shutdownHandler = tryLoad('shutdown');
|
|
45
|
+
const gitHandlers = tryLoad('git');
|
|
46
|
+
const terminalHandlers = tryLoad('terminal');
|
|
47
|
+
|
|
48
|
+
if (deleteHandler) app.post('/delete', deleteHandler);
|
|
49
|
+
if (openCursorHandler) app.post('/open-cursor', openCursorHandler);
|
|
50
|
+
if (writeHandler) app.post('/write', writeHandler);
|
|
51
|
+
if (shutdownHandler) app.post('/shutdown', shutdownHandler);
|
|
52
|
+
if (gitHandlers) {
|
|
53
|
+
app.get('/git/burns', gitHandlers.listBurns);
|
|
54
|
+
app.post('/git/checkout', gitHandlers.checkoutBranch);
|
|
55
|
+
}
|
|
56
|
+
if (terminalHandlers) {
|
|
57
|
+
const { WebSocketServer } = require('./node_modules/ws');
|
|
58
|
+
const wss = new WebSocketServer({ server, path: '/terminal' });
|
|
59
|
+
terminalHandlers.setupTerminalWebSocket(wss);
|
|
60
|
+
app.get('/terminal', terminalHandlers.terminalHandler);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const port = 3001;
|
|
64
|
+
server.listen(port, () => {
|
|
65
|
+
console.log('File server running on http://localhost:' + port);
|
|
66
|
+
});
|