bonzai-burn 1.0.38 → 1.0.40

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 (26) hide show
  1. package/README.md +10 -20
  2. package/{src → dist}/bconfig.js +26 -4
  3. package/dist/graph-templates/receiver.js +66 -0
  4. package/dist/index.js +893 -0
  5. package/package.json +19 -10
  6. package/graph-templates/handlers/index.js +0 -22
  7. package/graph-templates/receiver.js +0 -47
  8. package/src/index.js +0 -99
  9. /package/{src → dist}/analyzer.js +0 -0
  10. /package/{src → dist}/bburn.js +0 -0
  11. /package/{src → dist}/bhook.js +0 -0
  12. /package/{graph-templates → dist/graph-templates}/config.js +0 -0
  13. /package/{graph-templates → dist/graph-templates}/ignore.txt +0 -0
  14. /package/{graph-templates/handlers → dist/graph-templates/loops/backend}/delete.js +0 -0
  15. /package/{graph-templates/handlers → dist/graph-templates/loops/backend}/git.js +0 -0
  16. /package/{graph-templates/handlers → dist/graph-templates/loops/backend}/open-cursor.js +0 -0
  17. /package/{graph-templates/handlers → dist/graph-templates/loops/backend}/shutdown.js +0 -0
  18. /package/{graph-templates/handlers → dist/graph-templates/loops/backend}/terminal.js +0 -0
  19. /package/{graph-templates/handlers → dist/graph-templates/loops/backend}/write.js +0 -0
  20. /package/{graph-templates/handlers → dist/graph-templates/loops/visualization}/list.js +0 -0
  21. /package/{graph-templates/handlers → dist/graph-templates/loops/visualization}/read.js +0 -0
  22. /package/{graph-templates/handlers → dist/graph-templates/loops/visualization}/scan_code_quality.js +0 -0
  23. /package/{graph-templates → dist/graph-templates}/utils/fileList.js +0 -0
  24. /package/{graph-templates → dist/graph-templates}/utils/ignore.js +0 -0
  25. /package/{graph-templates → dist/graph-templates}/utils/parsers.js +0 -0
  26. /package/{payload-bonzai → dist/payload-bonzai}/config.json +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # bonzai-burn
2
2
 
3
- Automated code cleanup via Claude Code on a safe git branch.
3
+ Code analysis CLI for Claude Code.
4
4
 
5
5
  ## Install
6
6
 
@@ -8,30 +8,20 @@ Automated code cleanup via Claude Code on a safe git branch.
8
8
  npx bonzai-burn
9
9
  ```
10
10
 
11
- Requires: [Claude Code CLI](https://github.com/anthropics/claude-code)
12
-
13
11
  ## Usage
14
12
 
15
- ### 1. Run burn
16
-
17
13
  ```bash
18
- npx bburn
14
+ npx bonzai-burn # Initialize bonzai/ folder
15
+ npx bonzai-burn -b # Run code analysis
16
+ npx bonzai-burn -h # Install Claude Code hook
17
+ npx bonzai-burn -h -s # Check hook status
18
+ npx bonzai-burn -h -u # Uninstall hook
19
19
  ```
20
20
 
21
- Creates `bonzai/specs.md` on first run. Edit it to define your cleanup rules.
22
-
23
- ### 2. Review changes
24
-
25
- ```bash
26
- git diff main
27
- ```
21
+ ## Config
28
22
 
29
- ### 3. Accept or discard
23
+ Edit `bonzai/config.json` to customize burn rules.
30
24
 
31
- ```bash
32
- # Accept
33
- baccept
25
+ ---
34
26
 
35
- # Discard
36
- brevert
37
- ```
27
+ > **Note:** Release configuration (loops, channels) is managed outside this repo. See internal docs.
@@ -3,12 +3,13 @@ import fs from 'fs';
3
3
  import path from 'path';
4
4
  import { spawn, exec } from 'child_process';
5
5
  import { fileURLToPath } from 'url';
6
+ import { ENABLED_LOOPS } from './loops.config.js';
6
7
 
7
8
  const __filename = fileURLToPath(import.meta.url);
8
9
  const __dirname = path.dirname(__filename);
9
10
 
10
11
  // Template folder in the package
11
- const TEMPLATE_DIR = path.join(__dirname, '..', 'graph-templates');
12
+ const TEMPLATE_DIR = path.join(__dirname, 'graph-templates');
12
13
 
13
14
  // Helper function to recursively copy directory
14
15
  function copyDirectory(src, dest) {
@@ -53,11 +54,32 @@ async function main() {
53
54
  const configContent = fs.readFileSync(path.join(TEMPLATE_DIR, 'config.js'), 'utf8');
54
55
  fs.writeFileSync(path.join(bonzaiDir, 'config.js'), configContent);
55
56
 
56
- // Copy handlers directory
57
+ // Copy handlers from enabled loops
57
58
  console.log('Copying handlers...');
58
- const handlersSrc = path.join(TEMPLATE_DIR, 'handlers');
59
59
  const handlersDest = path.join(bonzaiDir, 'handlers');
60
- copyDirectory(handlersSrc, handlersDest);
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
+ }
61
83
 
62
84
  // Copy utils directory
63
85
  console.log('Copying utils...');
@@ -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
+ });
package/dist/index.js ADDED
@@ -0,0 +1,893 @@
1
+ #!/usr/bin/env node
2
+ import { spawn, exec, execSync } from 'child_process';
3
+ import fs4, { existsSync, mkdirSync, copyFileSync } from 'fs';
4
+ import path2, { dirname, join } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+
17
+ // src/loops.config.js
18
+ var CHANNELS, channel, ENABLED_LOOPS;
19
+ var init_loops_config = __esm({
20
+ "src/loops.config.js"() {
21
+ CHANNELS = {
22
+ dev: ["burn", "visualization", "backend"],
23
+ beta: ["burn", "visualization"],
24
+ stable: ["burn"]
25
+ };
26
+ channel = "dev";
27
+ ENABLED_LOOPS = CHANNELS[channel];
28
+ }
29
+ });
30
+ function commandExists(cmd) {
31
+ try {
32
+ execSync(`which ${cmd}`, { encoding: "utf-8", stdio: "pipe" });
33
+ return true;
34
+ } catch {
35
+ return false;
36
+ }
37
+ }
38
+ function isInstalledLocally(pkg, rootDir) {
39
+ return fs4.existsSync(path2.join(rootDir, "node_modules", pkg));
40
+ }
41
+ function installPackage(pkg, rootDir) {
42
+ try {
43
+ console.log(` Installing ${pkg}...`);
44
+ execSync(`cd "${rootDir}" && npm install --save-dev ${pkg}`, {
45
+ encoding: "utf-8",
46
+ stdio: "pipe"
47
+ });
48
+ return true;
49
+ } catch (e) {
50
+ return false;
51
+ }
52
+ }
53
+ function hasEslintConfig(rootDir) {
54
+ const configFiles = [
55
+ "eslint.config.js",
56
+ "eslint.config.mjs",
57
+ "eslint.config.cjs",
58
+ // Legacy configs (ESLint < 9)
59
+ ".eslintrc.js",
60
+ ".eslintrc.cjs",
61
+ ".eslintrc.json",
62
+ ".eslintrc.yml",
63
+ ".eslintrc.yaml",
64
+ ".eslintrc"
65
+ ];
66
+ return configFiles.some((file) => fs4.existsSync(path2.join(rootDir, file)));
67
+ }
68
+ function createEslintConfig(rootDir, config) {
69
+ var _a4;
70
+ const rules = ((_a4 = config.eslint) == null ? void 0 : _a4.rules) || ["no-unused-vars"];
71
+ const rulesObj = {};
72
+ for (const rule of rules) {
73
+ rulesObj[rule] = "error";
74
+ }
75
+ const rulesJson = JSON.stringify(rulesObj, null, 2).replace(/\n/g, "\n ");
76
+ const configContent = `// Auto-generated by bonzai-burn for ESLint v9+
77
+ export default [
78
+ {
79
+ files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx', '**/*.mjs', '**/*.cjs'],
80
+ languageOptions: {
81
+ ecmaVersion: 'latest',
82
+ sourceType: 'module',
83
+ parserOptions: {
84
+ ecmaFeatures: {
85
+ jsx: true
86
+ }
87
+ }
88
+ },
89
+ rules: ${rulesJson}
90
+ }
91
+ ];
92
+ `;
93
+ const configPath = path2.join(rootDir, "eslint.config.js");
94
+ try {
95
+ fs4.writeFileSync(configPath, configContent, "utf-8");
96
+ return true;
97
+ } catch (e) {
98
+ return false;
99
+ }
100
+ }
101
+ function ensureEslint(rootDir, config) {
102
+ const cfg = config.eslint || {};
103
+ if (!cfg.enabled) {
104
+ return { available: false, reason: "Disabled in config" };
105
+ }
106
+ let eslintInstalled = commandExists("eslint") || isInstalledLocally("eslint", rootDir);
107
+ let installed = false;
108
+ if (!eslintInstalled) {
109
+ console.log("\u{1F4E6} ESLint not found, installing...");
110
+ if (installPackage("eslint", rootDir)) {
111
+ eslintInstalled = true;
112
+ installed = true;
113
+ } else {
114
+ return { available: false, reason: "Failed to install ESLint" };
115
+ }
116
+ }
117
+ let configCreated = false;
118
+ if (!hasEslintConfig(rootDir)) {
119
+ console.log("\u{1F4C4} Creating eslint.config.js...");
120
+ if (createEslintConfig(rootDir, config)) {
121
+ configCreated = true;
122
+ } else {
123
+ return { available: false, reason: "Failed to create ESLint config" };
124
+ }
125
+ }
126
+ return { available: true, installed, configCreated };
127
+ }
128
+ function ensureTypeScript(rootDir, config) {
129
+ const cfg = config.typescript || {};
130
+ if (!cfg.enabled) {
131
+ return { available: false, reason: "Disabled in config" };
132
+ }
133
+ if (!fs4.existsSync(path2.join(rootDir, "tsconfig.json"))) {
134
+ return { available: false, reason: "No tsconfig.json found" };
135
+ }
136
+ if (commandExists("tsc") || isInstalledLocally("typescript", rootDir)) {
137
+ return { available: true };
138
+ }
139
+ console.log("\u{1F4E6} TypeScript not found, installing...");
140
+ if (installPackage("typescript", rootDir)) {
141
+ return { available: true, installed: true };
142
+ }
143
+ return { available: false, reason: "Failed to install TypeScript" };
144
+ }
145
+ function listAllFiles(dir, basePath = "") {
146
+ const ignorePatterns = ["node_modules", ".git", ".DS_Store", "dist", "build", "coverage", "bonzai"];
147
+ let results = [];
148
+ try {
149
+ const entries = fs4.readdirSync(dir, { withFileTypes: true });
150
+ for (const entry of entries) {
151
+ const fullPath = path2.join(dir, entry.name);
152
+ const relativePath = path2.join(basePath, entry.name);
153
+ if (ignorePatterns.some((p) => entry.name === p) || entry.name.startsWith(".")) {
154
+ continue;
155
+ }
156
+ if (entry.isDirectory()) {
157
+ results = results.concat(listAllFiles(fullPath, relativePath));
158
+ } else {
159
+ results.push({
160
+ path: relativePath,
161
+ fullPath
162
+ });
163
+ }
164
+ }
165
+ } catch (e) {
166
+ }
167
+ return results;
168
+ }
169
+ function runEslintAnalysis(rootDir, config) {
170
+ const issues = [];
171
+ const cfg = config.eslint || {};
172
+ if (!cfg.enabled) {
173
+ return { issues, skipped: true, reason: "Disabled in config" };
174
+ }
175
+ const rules = cfg.rules || ["no-unused-vars"];
176
+ const ruleArgs = rules.map((r) => `--rule "${r}: error"`).join(" ");
177
+ const eslintCmd = isInstalledLocally("eslint", rootDir) ? `"${path2.join(rootDir, "node_modules", ".bin", "eslint")}"` : "eslint";
178
+ try {
179
+ const result = execSync(
180
+ `${eslintCmd} "${rootDir}" --format json ${ruleArgs} --ignore-pattern node_modules --ignore-pattern bonzai 2>/dev/null || true`,
181
+ { encoding: "utf-8", stdio: "pipe", maxBuffer: 50 * 1024 * 1024 }
182
+ );
183
+ if (result.trim()) {
184
+ const eslintOutput = JSON.parse(result);
185
+ for (const file of eslintOutput) {
186
+ for (const msg of file.messages || []) {
187
+ if (msg.ruleId && rules.some((r) => msg.ruleId.includes(r.replace("no-", "")))) {
188
+ issues.push({
189
+ file: path2.relative(rootDir, file.filePath),
190
+ line: msg.line,
191
+ message: msg.message,
192
+ rule: msg.ruleId
193
+ });
194
+ }
195
+ }
196
+ }
197
+ }
198
+ } catch (e) {
199
+ return { issues, skipped: true, reason: "ESLint analysis failed" };
200
+ }
201
+ return { issues, skipped: false };
202
+ }
203
+ function runTypeScriptAnalysis(rootDir, config) {
204
+ const issues = [];
205
+ const cfg = config.typescript || {};
206
+ if (!cfg.enabled) {
207
+ return { issues, skipped: true, reason: "Disabled in config" };
208
+ }
209
+ const tsconfigPath = path2.join(rootDir, "tsconfig.json");
210
+ if (!fs4.existsSync(tsconfigPath)) {
211
+ return { issues, skipped: true, reason: "No tsconfig.json found" };
212
+ }
213
+ const tscCmd = isInstalledLocally("typescript", rootDir) ? `"${path2.join(rootDir, "node_modules", ".bin", "tsc")}"` : "tsc";
214
+ try {
215
+ const result = execSync(
216
+ `cd "${rootDir}" && ${tscCmd} --noEmit --noUnusedLocals --noUnusedParameters 2>&1 || true`,
217
+ { encoding: "utf-8", stdio: "pipe", maxBuffer: 50 * 1024 * 1024 }
218
+ );
219
+ const lines = result.split("\n");
220
+ const errorRegex = /^(.+)\((\d+),(\d+)\):\s*error\s+TS(\d+):\s*(.+)$/;
221
+ for (const line of lines) {
222
+ const match = line.match(errorRegex);
223
+ if (match) {
224
+ const [, filePath, lineNum, , errorCode, message] = match;
225
+ if (["6133", "6196", "6198"].includes(errorCode)) {
226
+ issues.push({
227
+ file: path2.relative(rootDir, filePath),
228
+ line: parseInt(lineNum, 10),
229
+ message,
230
+ rule: `TS${errorCode}`
231
+ });
232
+ }
233
+ }
234
+ }
235
+ } catch (e) {
236
+ return { issues, skipped: true, reason: "TypeScript analysis failed" };
237
+ }
238
+ return { issues, skipped: false };
239
+ }
240
+ function checkLineLimits(files, config) {
241
+ const issues = [];
242
+ const cfg = config.lineLimit || {};
243
+ if (!cfg.enabled) {
244
+ return { issues, skipped: true, reason: "Disabled in config" };
245
+ }
246
+ const maxLines = cfg.limit || 500;
247
+ for (const file of files) {
248
+ if (file.path.endsWith(".json") || file.path.endsWith(".lock") || file.path.endsWith(".css")) {
249
+ continue;
250
+ }
251
+ try {
252
+ const content = fs4.readFileSync(file.fullPath, "utf-8");
253
+ const lineCount = content.split("\n").length;
254
+ if (lineCount > maxLines) {
255
+ issues.push({
256
+ file: file.path,
257
+ count: lineCount,
258
+ limit: maxLines
259
+ });
260
+ }
261
+ } catch (e) {
262
+ }
263
+ }
264
+ issues.sort((a, b) => b.count - a.count);
265
+ return { issues, skipped: false, prompt: cfg.prompt };
266
+ }
267
+ function checkFolderLimits(files, config) {
268
+ const issues = [];
269
+ const cfg = config.folderLimit || {};
270
+ if (!cfg.enabled) {
271
+ return { issues, skipped: true, reason: "Disabled in config" };
272
+ }
273
+ const maxItems = cfg.limit || 20;
274
+ const folderCounts = {};
275
+ for (const file of files) {
276
+ const dir = path2.dirname(file.path);
277
+ if (!folderCounts[dir]) {
278
+ folderCounts[dir] = 0;
279
+ }
280
+ folderCounts[dir]++;
281
+ }
282
+ for (const [folder, count] of Object.entries(folderCounts)) {
283
+ if (count > maxItems) {
284
+ issues.push({
285
+ file: folder,
286
+ count,
287
+ limit: maxItems
288
+ });
289
+ }
290
+ }
291
+ issues.sort((a, b) => b.count - a.count);
292
+ return { issues, skipped: false, prompt: cfg.prompt };
293
+ }
294
+ function checkMissingTests(files, config) {
295
+ const issues = [];
296
+ const cfg = config.testCheck || {};
297
+ if (!cfg.enabled) {
298
+ return { issues, skipped: true, reason: "Disabled in config" };
299
+ }
300
+ const patterns = cfg.patterns || {
301
+ ".vue": ".test.js",
302
+ ".jsx": ".test.jsx",
303
+ ".tsx": ".test.tsx"
304
+ };
305
+ const testFiles = new Set(
306
+ files.filter((f) => f.path.includes(".test.") || f.path.includes(".spec.")).map((f) => f.path.toLowerCase())
307
+ );
308
+ for (const file of files) {
309
+ const ext = path2.extname(file.path);
310
+ const testExt = patterns[ext];
311
+ if (!testExt) continue;
312
+ if (file.path.includes(".test.") || file.path.includes(".spec.")) continue;
313
+ if (!file.path.startsWith("src/") && !file.path.startsWith("components/")) continue;
314
+ const baseName = path2.basename(file.path, ext);
315
+ const hasTest = [...testFiles].some((t) => t.includes(baseName.toLowerCase()) && t.includes(".test."));
316
+ if (!hasTest) {
317
+ issues.push({
318
+ file: file.path,
319
+ expectedTest: `${baseName}${testExt}`
320
+ });
321
+ }
322
+ }
323
+ return { issues, skipped: false, prompt: cfg.prompt };
324
+ }
325
+ async function analyze(rootDir = process.cwd(), config = {}) {
326
+ var _a4, _b, _c;
327
+ const startTime = Date.now();
328
+ const files = listAllFiles(rootDir);
329
+ const toolStatus = {};
330
+ console.log("\u{1F527} Checking tools...");
331
+ const eslintStatus = ensureEslint(rootDir, config);
332
+ toolStatus.eslint = eslintStatus;
333
+ if (eslintStatus.installed && eslintStatus.configCreated) {
334
+ console.log(" \u2713 ESLint installed + config created");
335
+ } else if (eslintStatus.installed) {
336
+ console.log(" \u2713 ESLint installed");
337
+ } else if (eslintStatus.configCreated) {
338
+ console.log(" \u2713 ESLint ready (config created)");
339
+ } else if (eslintStatus.available) {
340
+ console.log(" \u2713 ESLint ready");
341
+ } else if ((_a4 = config.eslint) == null ? void 0 : _a4.enabled) {
342
+ console.log(` \u2717 ESLint: ${eslintStatus.reason}`);
343
+ }
344
+ const tsStatus = ensureTypeScript(rootDir, config);
345
+ toolStatus.typescript = tsStatus;
346
+ if (tsStatus.installed) {
347
+ console.log(" \u2713 TypeScript installed");
348
+ } else if (tsStatus.available) {
349
+ console.log(" \u2713 TypeScript ready");
350
+ } else if ((_b = config.typescript) == null ? void 0 : _b.enabled) {
351
+ console.log(` \u2717 TypeScript: ${tsStatus.reason}`);
352
+ }
353
+ console.log("");
354
+ const eslint = eslintStatus.available ? runEslintAnalysis(rootDir, config) : { issues: [], skipped: true, reason: eslintStatus.reason };
355
+ const typescript = tsStatus.available ? runTypeScriptAnalysis(rootDir, config) : { issues: [], skipped: true, reason: tsStatus.reason };
356
+ const lineLimit = checkLineLimits(files, config);
357
+ const folderLimit = checkFolderLimits(files, config);
358
+ const missingTests = checkMissingTests(files, config);
359
+ const duration = Date.now() - startTime;
360
+ return {
361
+ eslint,
362
+ typescript,
363
+ lineLimit,
364
+ folderLimit,
365
+ missingTests,
366
+ customRequirements: ((_c = config.customChecks) == null ? void 0 : _c.requirements) || null,
367
+ filesScanned: files.length,
368
+ durationMs: duration,
369
+ toolStatus
370
+ };
371
+ }
372
+ function formatAnalysisResults(results) {
373
+ var _a4, _b;
374
+ let output = "";
375
+ let totalIssues = 0;
376
+ if (!results.eslint.skipped && results.eslint.issues.length > 0) {
377
+ output += `\u{1F5D1}\uFE0F UNUSED CODE (ESLint) - ${results.eslint.issues.length} issues
378
+ `;
379
+ for (const issue of results.eslint.issues.slice(0, 15)) {
380
+ output += ` ${issue.file}:${issue.line} - ${issue.message}
381
+ `;
382
+ }
383
+ if (results.eslint.issues.length > 15) {
384
+ output += ` ... and ${results.eslint.issues.length - 15} more
385
+ `;
386
+ }
387
+ output += "\n";
388
+ totalIssues += results.eslint.issues.length;
389
+ }
390
+ if (!results.typescript.skipped && results.typescript.issues.length > 0) {
391
+ output += `\u{1F537} UNUSED CODE (TypeScript) - ${results.typescript.issues.length} issues
392
+ `;
393
+ for (const issue of results.typescript.issues.slice(0, 15)) {
394
+ output += ` ${issue.file}:${issue.line} - ${issue.message}
395
+ `;
396
+ }
397
+ if (results.typescript.issues.length > 15) {
398
+ output += ` ... and ${results.typescript.issues.length - 15} more
399
+ `;
400
+ }
401
+ output += "\n";
402
+ totalIssues += results.typescript.issues.length;
403
+ }
404
+ if (!results.lineLimit.skipped && results.lineLimit.issues.length > 0) {
405
+ output += `\u{1F4CF} FILES OVER LINE LIMIT - ${results.lineLimit.issues.length} files
406
+ `;
407
+ for (const issue of results.lineLimit.issues) {
408
+ output += ` ${issue.file} - ${issue.count} lines (limit: ${issue.limit})
409
+ `;
410
+ }
411
+ if (results.lineLimit.prompt) {
412
+ output += `
413
+ \u2192 ${results.lineLimit.prompt.replace(/\{\{\s*linelimit\s*\}\}/gi, ((_a4 = results.lineLimit.issues[0]) == null ? void 0 : _a4.limit) || "")}
414
+ `;
415
+ }
416
+ output += "\n";
417
+ totalIssues += results.lineLimit.issues.length;
418
+ }
419
+ if (!results.folderLimit.skipped && results.folderLimit.issues.length > 0) {
420
+ output += `\u{1F4C1} FOLDERS OVER ITEM LIMIT - ${results.folderLimit.issues.length} folders
421
+ `;
422
+ for (const issue of results.folderLimit.issues) {
423
+ output += ` ${issue.file}/ - ${issue.count} items (limit: ${issue.limit})
424
+ `;
425
+ }
426
+ if (results.folderLimit.prompt) {
427
+ output += `
428
+ \u2192 ${results.folderLimit.prompt.replace(/\{\{\s*folderlimit\s*\}\}/gi, ((_b = results.folderLimit.issues[0]) == null ? void 0 : _b.limit) || "")}
429
+ `;
430
+ }
431
+ output += "\n";
432
+ totalIssues += results.folderLimit.issues.length;
433
+ }
434
+ if (!results.missingTests.skipped && results.missingTests.issues.length > 0) {
435
+ output += `\u{1F9EA} MISSING TESTS - ${results.missingTests.issues.length} files
436
+ `;
437
+ for (const issue of results.missingTests.issues.slice(0, 10)) {
438
+ output += ` ${issue.file} \u2192 needs ${issue.expectedTest}
439
+ `;
440
+ }
441
+ if (results.missingTests.issues.length > 10) {
442
+ output += ` ... and ${results.missingTests.issues.length - 10} more
443
+ `;
444
+ }
445
+ output += "\n";
446
+ totalIssues += results.missingTests.issues.length;
447
+ }
448
+ if (results.customRequirements) {
449
+ output += `\u{1F4CB} CUSTOM REQUIREMENTS
450
+ `;
451
+ output += ` ${results.customRequirements}
452
+
453
+ `;
454
+ }
455
+ return { output, totalIssues };
456
+ }
457
+ var init_analyzer = __esm({
458
+ "src/analyzer.js"() {
459
+ }
460
+ });
461
+
462
+ // src/bburn.js
463
+ var bburn_exports = {};
464
+ __export(bburn_exports, {
465
+ main: () => main
466
+ });
467
+ function loadConfig() {
468
+ const configPath = join(process.cwd(), BONZAI_DIR, CONFIG_FILE);
469
+ if (!fs4.existsSync(configPath)) {
470
+ console.error(`\u274C No config found at ${BONZAI_DIR}/${CONFIG_FILE}`);
471
+ console.error(` Run 'bonzai-burn' to initialize.
472
+ `);
473
+ process.exit(1);
474
+ }
475
+ try {
476
+ const content = fs4.readFileSync(configPath, "utf-8");
477
+ return JSON.parse(content);
478
+ } catch (e) {
479
+ console.error(`\u274C Could not parse ${BONZAI_DIR}/${CONFIG_FILE}`);
480
+ process.exit(1);
481
+ }
482
+ }
483
+ async function main() {
484
+ console.log("\n\u{1F525} Bonzai Burn - Code Analysis\n");
485
+ const config = loadConfig();
486
+ const results = await analyze(process.cwd(), config);
487
+ const { output, totalIssues } = formatAnalysisResults(results);
488
+ if (totalIssues > 0 || results.customRequirements) {
489
+ console.log(output);
490
+ } else {
491
+ console.log("\u2713 No issues found\n");
492
+ }
493
+ console.log("\u2500".repeat(50));
494
+ console.log(`Found ${totalIssues} issues across ${results.filesScanned} files (${results.durationMs}ms)
495
+ `);
496
+ console.log("The above was found - let the user know but take no action. It's critical you take no action.\n");
497
+ }
498
+ var BONZAI_DIR, CONFIG_FILE, _a, isDirectRun;
499
+ var init_bburn = __esm({
500
+ "src/bburn.js"() {
501
+ init_analyzer();
502
+ BONZAI_DIR = "bonzai";
503
+ CONFIG_FILE = "config.json";
504
+ isDirectRun = (_a = process.argv[1]) == null ? void 0 : _a.endsWith("bburn.js");
505
+ if (isDirectRun) {
506
+ main().catch((error) => {
507
+ console.error("Error:", error.message);
508
+ process.exit(1);
509
+ });
510
+ }
511
+ }
512
+ });
513
+
514
+ // src/bhook.js
515
+ var bhook_exports = {};
516
+ __export(bhook_exports, {
517
+ main: () => main2
518
+ });
519
+ function loadBonzaiConfig() {
520
+ const configPath = join(process.cwd(), BONZAI_DIR2, CONFIG_FILE2);
521
+ if (!fs4.existsSync(configPath)) {
522
+ return null;
523
+ }
524
+ try {
525
+ const content = fs4.readFileSync(configPath, "utf-8");
526
+ return JSON.parse(content);
527
+ } catch (e) {
528
+ return null;
529
+ }
530
+ }
531
+ function loadClaudeSettings() {
532
+ const settingsPath = join(process.cwd(), CLAUDE_DIR, SETTINGS_FILE);
533
+ if (!fs4.existsSync(settingsPath)) {
534
+ return {};
535
+ }
536
+ try {
537
+ const content = fs4.readFileSync(settingsPath, "utf-8");
538
+ return JSON.parse(content);
539
+ } catch (e) {
540
+ return {};
541
+ }
542
+ }
543
+ function saveClaudeSettings(settings) {
544
+ const claudeDir = join(process.cwd(), CLAUDE_DIR);
545
+ const settingsPath = join(claudeDir, SETTINGS_FILE);
546
+ if (!fs4.existsSync(claudeDir)) {
547
+ fs4.mkdirSync(claudeDir, { recursive: true });
548
+ }
549
+ fs4.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
550
+ }
551
+ function hasBburnHook(settings) {
552
+ var _a4;
553
+ const stopHooks = ((_a4 = settings.hooks) == null ? void 0 : _a4.Stop) || [];
554
+ return stopHooks.some(
555
+ (entry) => {
556
+ var _a5;
557
+ return (_a5 = entry.hooks) == null ? void 0 : _a5.some((hook) => hook.command === "bburn");
558
+ }
559
+ );
560
+ }
561
+ function installHook() {
562
+ const settings = loadClaudeSettings();
563
+ if (hasBburnHook(settings)) {
564
+ console.log("\u2713 bburn hook already installed\n");
565
+ return;
566
+ }
567
+ if (!settings.hooks) {
568
+ settings.hooks = {};
569
+ }
570
+ if (!settings.hooks.Stop) {
571
+ settings.hooks.Stop = [];
572
+ }
573
+ settings.hooks.Stop.push({
574
+ hooks: [
575
+ {
576
+ type: "command",
577
+ command: "bburn"
578
+ }
579
+ ]
580
+ });
581
+ saveClaudeSettings(settings);
582
+ console.log("\u2713 Installed bburn as Claude Code Stop hook");
583
+ console.log(" bburn will run after every Claude Code message\n");
584
+ }
585
+ function uninstallHook() {
586
+ const settings = loadClaudeSettings();
587
+ if (!hasBburnHook(settings)) {
588
+ console.log("\u2713 bburn hook not installed\n");
589
+ return;
590
+ }
591
+ settings.hooks.Stop = settings.hooks.Stop.filter(
592
+ (entry) => {
593
+ var _a4;
594
+ return !((_a4 = entry.hooks) == null ? void 0 : _a4.some((hook) => hook.command === "bburn"));
595
+ }
596
+ );
597
+ if (settings.hooks.Stop.length === 0) {
598
+ delete settings.hooks.Stop;
599
+ }
600
+ if (Object.keys(settings.hooks).length === 0) {
601
+ delete settings.hooks;
602
+ }
603
+ saveClaudeSettings(settings);
604
+ console.log("\u2713 Removed bburn hook from Claude Code\n");
605
+ }
606
+ function showStatus() {
607
+ var _a4;
608
+ const settings = loadClaudeSettings();
609
+ const config = loadBonzaiConfig();
610
+ console.log("\n\u{1F525} Bonzai Hook Status\n");
611
+ const autoBurnEnabled = ((_a4 = config == null ? void 0 : config.autoBurn) == null ? void 0 : _a4.enabled) ?? false;
612
+ console.log(`Config autoBurn: ${autoBurnEnabled ? "enabled" : "disabled"}`);
613
+ const hookInstalled = hasBburnHook(settings);
614
+ console.log(`Claude hook: ${hookInstalled ? "installed" : "not installed"}
615
+ `);
616
+ if (autoBurnEnabled && !hookInstalled) {
617
+ console.log('Run "bhook install" to install the hook\n');
618
+ }
619
+ }
620
+ async function main2(subArgs = []) {
621
+ const args = subArgs.length > 0 ? subArgs : process.argv.slice(2);
622
+ const command = args[0];
623
+ switch (command) {
624
+ case "uninstall":
625
+ case "remove":
626
+ case "-u":
627
+ uninstallHook();
628
+ break;
629
+ case "status":
630
+ case "-s":
631
+ showStatus();
632
+ break;
633
+ case "install":
634
+ case "-i":
635
+ default:
636
+ installHook();
637
+ break;
638
+ }
639
+ }
640
+ var BONZAI_DIR2, CONFIG_FILE2, CLAUDE_DIR, SETTINGS_FILE, _a2, isDirectRun2;
641
+ var init_bhook = __esm({
642
+ "src/bhook.js"() {
643
+ BONZAI_DIR2 = "bonzai";
644
+ CONFIG_FILE2 = "config.json";
645
+ CLAUDE_DIR = ".claude";
646
+ SETTINGS_FILE = "settings.local.json";
647
+ isDirectRun2 = (_a2 = process.argv[1]) == null ? void 0 : _a2.endsWith("bhook.js");
648
+ if (isDirectRun2) {
649
+ main2().catch((error) => {
650
+ console.error("Error:", error.message);
651
+ process.exit(1);
652
+ });
653
+ }
654
+ }
655
+ });
656
+
657
+ // src/bconfig.js
658
+ var bconfig_exports = {};
659
+ __export(bconfig_exports, {
660
+ main: () => main3
661
+ });
662
+ function copyDirectory(src, dest) {
663
+ if (!fs4.existsSync(dest)) {
664
+ fs4.mkdirSync(dest, { recursive: true });
665
+ }
666
+ const entries = fs4.readdirSync(src, { withFileTypes: true });
667
+ for (const entry of entries) {
668
+ const srcPath = path2.join(src, entry.name);
669
+ const destPath = path2.join(dest, entry.name);
670
+ if (entry.isDirectory()) {
671
+ copyDirectory(srcPath, destPath);
672
+ } else {
673
+ fs4.copyFileSync(srcPath, destPath);
674
+ }
675
+ }
676
+ }
677
+ async function main3() {
678
+ const currentDir = process.cwd();
679
+ const bonzaiDir = path2.join(currentDir, "bonzai");
680
+ const receiverPath = path2.join(bonzaiDir, "receiver.js");
681
+ console.log("Setting up local file server...");
682
+ if (!fs4.existsSync(bonzaiDir)) {
683
+ console.log("Creating bonzai directory...");
684
+ fs4.mkdirSync(bonzaiDir);
685
+ }
686
+ console.log("Writing receiver.js...");
687
+ const receiverContent = fs4.readFileSync(path2.join(TEMPLATE_DIR, "receiver.js"), "utf8");
688
+ fs4.writeFileSync(receiverPath, receiverContent);
689
+ fs4.chmodSync(receiverPath, "755");
690
+ console.log("Writing config.js...");
691
+ const configContent = fs4.readFileSync(path2.join(TEMPLATE_DIR, "config.js"), "utf8");
692
+ fs4.writeFileSync(path2.join(bonzaiDir, "config.js"), configContent);
693
+ console.log("Copying handlers...");
694
+ const handlersDest = path2.join(bonzaiDir, "handlers");
695
+ if (!fs4.existsSync(handlersDest)) {
696
+ fs4.mkdirSync(handlersDest, { recursive: true });
697
+ }
698
+ if (ENABLED_LOOPS.includes("visualization")) {
699
+ const vizSrc = path2.join(TEMPLATE_DIR, "loops", "visualization");
700
+ if (fs4.existsSync(vizSrc)) {
701
+ for (const file of fs4.readdirSync(vizSrc)) {
702
+ fs4.copyFileSync(path2.join(vizSrc, file), path2.join(handlersDest, file));
703
+ }
704
+ }
705
+ }
706
+ if (ENABLED_LOOPS.includes("backend")) {
707
+ const backendSrc = path2.join(TEMPLATE_DIR, "loops", "backend");
708
+ if (fs4.existsSync(backendSrc)) {
709
+ for (const file of fs4.readdirSync(backendSrc)) {
710
+ fs4.copyFileSync(path2.join(backendSrc, file), path2.join(handlersDest, file));
711
+ }
712
+ }
713
+ }
714
+ console.log("Copying utils...");
715
+ const utilsSrc = path2.join(TEMPLATE_DIR, "utils");
716
+ const utilsDest = path2.join(bonzaiDir, "utils");
717
+ copyDirectory(utilsSrc, utilsDest);
718
+ const ignoreTargetPath = path2.join(bonzaiDir, ".ignore");
719
+ if (!fs4.existsSync(ignoreTargetPath)) {
720
+ console.log("Writing .ignore file...");
721
+ const ignoreContent = fs4.readFileSync(path2.join(TEMPLATE_DIR, "ignore.txt"), "utf8");
722
+ fs4.writeFileSync(ignoreTargetPath, ignoreContent);
723
+ }
724
+ const packageJsonPath = path2.join(bonzaiDir, "package.json");
725
+ let packageJson = {};
726
+ if (fs4.existsSync(packageJsonPath)) {
727
+ packageJson = JSON.parse(fs4.readFileSync(packageJsonPath, "utf8"));
728
+ } else {
729
+ packageJson = {
730
+ name: "bonzai-server",
731
+ version: "1.0.0",
732
+ description: "Dependencies for bonzai graph server",
733
+ main: "receiver.js",
734
+ scripts: {
735
+ test: 'echo "Error: no test specified" && exit 1'
736
+ },
737
+ author: "",
738
+ license: "ISC"
739
+ };
740
+ }
741
+ if (!packageJson.dependencies) {
742
+ packageJson.dependencies = {};
743
+ }
744
+ packageJson.dependencies.express = "^4.18.2";
745
+ packageJson.dependencies.cors = "^2.8.5";
746
+ packageJson.dependencies["@babel/parser"] = "^7.23.0";
747
+ packageJson.dependencies.ws = "^8.14.2";
748
+ packageJson.dependencies["node-pty"] = "^1.0.0";
749
+ if (!packageJson.scripts) {
750
+ packageJson.scripts = {};
751
+ }
752
+ packageJson.scripts["file-server"] = "node receiver.js";
753
+ fs4.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
754
+ console.log("Installing dependencies...");
755
+ return new Promise((resolve, reject) => {
756
+ const npm = spawn("npm", ["install"], {
757
+ stdio: "inherit",
758
+ cwd: bonzaiDir
759
+ });
760
+ npm.on("close", (code) => {
761
+ if (code === 0) {
762
+ const nodePtyPrebuilds = path2.join(bonzaiDir, "node_modules", "node-pty", "prebuilds");
763
+ if (fs4.existsSync(nodePtyPrebuilds)) {
764
+ const archDirs = ["darwin-arm64", "darwin-x64", "linux-x64", "linux-arm64"];
765
+ for (const arch of archDirs) {
766
+ const spawnHelperPath = path2.join(nodePtyPrebuilds, arch, "spawn-helper");
767
+ if (fs4.existsSync(spawnHelperPath)) {
768
+ try {
769
+ fs4.chmodSync(spawnHelperPath, "755");
770
+ console.log(`Fixed node-pty spawn-helper permissions (${arch})`);
771
+ } catch (e) {
772
+ console.warn(`Warning: Could not fix spawn-helper permissions for ${arch}:`, e.message);
773
+ }
774
+ }
775
+ }
776
+ }
777
+ console.log("\nListener endpoints successfully deployed");
778
+ console.log("All code stays on your machine\n");
779
+ console.log("Relay server running on localhost:3001");
780
+ console.log("Terminal WebSocket available at ws://localhost:3001/terminal");
781
+ console.log("Diagram available at https://bonzai.dev/\n");
782
+ const server = spawn("node", ["receiver.js"], {
783
+ stdio: "inherit",
784
+ cwd: bonzaiDir,
785
+ env: {
786
+ ...process.env,
787
+ BONZAI_REPO_DIR: currentDir
788
+ }
789
+ });
790
+ exec("open https://bonzai.dev/");
791
+ server.on("close", (serverCode) => {
792
+ console.log(`
793
+ Server stopped with code ${serverCode}`);
794
+ process.exit(serverCode);
795
+ });
796
+ server.on("error", (err) => {
797
+ console.error("Error starting server:", err.message);
798
+ process.exit(1);
799
+ });
800
+ process.on("SIGINT", () => {
801
+ console.log("\nShutting down server...");
802
+ server.kill("SIGINT");
803
+ });
804
+ process.on("SIGTERM", () => {
805
+ console.log("\nShutting down server...");
806
+ server.kill("SIGTERM");
807
+ });
808
+ resolve();
809
+ } else {
810
+ reject(new Error("npm install failed with code " + code));
811
+ }
812
+ });
813
+ npm.on("error", (err) => {
814
+ reject(err);
815
+ });
816
+ });
817
+ }
818
+ var __filename$1, __dirname$1, TEMPLATE_DIR, _a3, isDirectRun3;
819
+ var init_bconfig = __esm({
820
+ "src/bconfig.js"() {
821
+ init_loops_config();
822
+ __filename$1 = fileURLToPath(import.meta.url);
823
+ __dirname$1 = path2.dirname(__filename$1);
824
+ TEMPLATE_DIR = path2.join(__dirname$1, "graph-templates");
825
+ isDirectRun3 = (_a3 = process.argv[1]) == null ? void 0 : _a3.endsWith("bconfig.js");
826
+ if (isDirectRun3) {
827
+ main3().catch(console.error);
828
+ }
829
+ }
830
+ });
831
+
832
+ // src/index.js
833
+ init_loops_config();
834
+ var __filename2 = fileURLToPath(import.meta.url);
835
+ var __dirname2 = dirname(__filename2);
836
+ var BONZAI_DIR3 = "bonzai";
837
+ var TEMPLATE_DIR2 = join(__dirname2, "payload-bonzai");
838
+ function showHelp() {
839
+ let help = `
840
+ Usage: npx bonzai-burn [option]
841
+
842
+ Options:
843
+ (no option) Initialize bonzai in current directory
844
+ -b, --burn Run code analysis
845
+ -h, --hook Manage Claude Code stop hook
846
+ --help Show this help message`;
847
+ if (ENABLED_LOOPS.includes("visualization") || ENABLED_LOOPS.includes("backend")) {
848
+ help = help.replace("--help", "-c, --config Launch visualization server\n --help");
849
+ }
850
+ console.log(help);
851
+ }
852
+ function init() {
853
+ const currentDir = process.cwd();
854
+ const bonzaiPath = join(currentDir, BONZAI_DIR3);
855
+ if (existsSync(bonzaiPath)) {
856
+ console.log(`${BONZAI_DIR3}/ already exists`);
857
+ return;
858
+ }
859
+ mkdirSync(bonzaiPath, { recursive: true });
860
+ copyFileSync(join(TEMPLATE_DIR2, "config.json"), join(bonzaiPath, "config.json"));
861
+ console.log(`Created ${BONZAI_DIR3}/ folder with config.json`);
862
+ console.log(`Edit ${BONZAI_DIR3}/config.json to configure your burn rules`);
863
+ console.log(`Run 'npx bonzai-burn -b' to analyze your codebase`);
864
+ }
865
+ async function main4() {
866
+ const args = process.argv.slice(2);
867
+ const flag = args[0];
868
+ if (ENABLED_LOOPS.includes("burn")) {
869
+ if (flag === "-b" || flag === "--burn") {
870
+ const { main: burnMain } = await Promise.resolve().then(() => (init_bburn(), bburn_exports));
871
+ return burnMain == null ? void 0 : burnMain();
872
+ }
873
+ if (flag === "-h" || flag === "--hook") {
874
+ const { main: hookMain } = await Promise.resolve().then(() => (init_bhook(), bhook_exports));
875
+ return hookMain == null ? void 0 : hookMain(args.slice(1));
876
+ }
877
+ }
878
+ if (ENABLED_LOOPS.includes("visualization") || ENABLED_LOOPS.includes("backend")) {
879
+ if (flag === "-c" || flag === "--config") {
880
+ const { main: configMain } = await Promise.resolve().then(() => (init_bconfig(), bconfig_exports));
881
+ return configMain == null ? void 0 : configMain();
882
+ }
883
+ }
884
+ if (flag === "--help") {
885
+ showHelp();
886
+ return;
887
+ }
888
+ init();
889
+ }
890
+ main4().catch((error) => {
891
+ console.error("Error:", error.message);
892
+ process.exit(1);
893
+ });
package/package.json CHANGED
@@ -1,14 +1,23 @@
1
1
  {
2
2
  "name": "bonzai-burn",
3
- "version": "1.0.38",
3
+ "version": "1.0.40",
4
4
  "description": "Git branch-based cleanup tool with bburn, baccept, and brevert commands",
5
5
  "type": "module",
6
- "main": "src/index.js",
6
+ "main": "dist/index.js",
7
7
  "bin": {
8
- "bonzai-burn": "./src/index.js",
9
- "bburn": "./src/bburn.js",
10
- "bconfig": "./src/bconfig.js",
11
- "bhook": "./src/bhook.js"
8
+ "bonzai-burn": "./dist/index.js",
9
+ "bburn": "./dist/bburn.js",
10
+ "bhook": "./dist/bhook.js"
11
+ },
12
+ "scripts": {
13
+ "dev": "RELEASE_CHANNEL=dev node src/index.js",
14
+ "build": "RELEASE_CHANNEL=stable tsup",
15
+ "build:beta": "RELEASE_CHANNEL=beta tsup",
16
+ "build:dev": "RELEASE_CHANNEL=dev tsup",
17
+ "prepublishOnly": "npm run build",
18
+ "release": "npm version patch && npm publish",
19
+ "release:beta": "npm run build:beta && npm publish --tag beta --ignore-scripts",
20
+ "release:dev": "npm run build:dev && npm publish --tag dev --ignore-scripts"
12
21
  },
13
22
  "keywords": [
14
23
  "git",
@@ -20,14 +29,14 @@
20
29
  "node": ">=16.0.0"
21
30
  },
22
31
  "files": [
23
- "src",
24
- "payload-bonzai",
25
- "graph-templates"
32
+ "dist"
26
33
  ],
27
34
  "dependencies": {
28
35
  "@modelcontextprotocol/sdk": "^1.25.3"
29
36
  },
30
37
  "devDependencies": {
31
- "eslint": "^9.39.2"
38
+ "eslint": "^9.39.2",
39
+ "tsup": "^8.5.1",
40
+ "typescript": "^5.9.3"
32
41
  }
33
42
  }
@@ -1,22 +0,0 @@
1
- // Root route - simple API documentation
2
- function indexHandler(req, res) {
3
- res.json({
4
- message: 'Local File Server API',
5
- endpoints: {
6
- 'GET /list': 'List all files in the directory',
7
- 'GET /read?path=<filepath>': 'Read file content',
8
- 'POST /delete': 'Delete file or directory (body: {path})',
9
- 'POST /open-cursor': 'Open Cursor (body: {path, line?})',
10
- 'POST /shutdown': 'Gracefully shutdown the server',
11
- 'POST /scan_code_quality': 'Scan code quality (body: {projectPath})',
12
- 'POST /write': 'Write file content (body: {path, content})',
13
- 'GET /git/burns': 'List all bonzai-burn branches',
14
- 'POST /git/checkout': 'Checkout a branch (body: {branchName})',
15
- 'WS /terminal': 'Interactive terminal via WebSocket'
16
- },
17
- example: 'Try: /list or /read?path=README.md'
18
- });
19
- }
20
-
21
- module.exports = indexHandler;
22
-
@@ -1,47 +0,0 @@
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 { WebSocketServer } = require('./node_modules/ws');
7
-
8
- // Import handlers
9
- const indexHandler = require('./handlers/index');
10
- const listHandler = require('./handlers/list');
11
- const readHandler = require('./handlers/read');
12
- const deleteHandler = require('./handlers/delete');
13
- const openCursorHandler = require('./handlers/open-cursor');
14
- const shutdownHandler = require('./handlers/shutdown');
15
- const scanCodeQualityHandler = require('./handlers/scan_code_quality');
16
- const writeHandler = require('./handlers/write');
17
- const { listBurns, checkoutBranch } = require('./handlers/git');
18
- const { terminalHandler, setupTerminalWebSocket } = require('./handlers/terminal');
19
-
20
- const app = express();
21
- const server = http.createServer(app);
22
-
23
- // WebSocket server for terminal
24
- const wss = new WebSocketServer({ server, path: '/terminal' });
25
- setupTerminalWebSocket(wss);
26
-
27
- app.use(cors());
28
- app.use(express.json());
29
-
30
- // Register routes
31
- app.get('/', indexHandler);
32
- app.get('/list', listHandler);
33
- app.get('/read', readHandler);
34
- app.post('/delete', deleteHandler);
35
- app.post('/open-cursor', openCursorHandler);
36
- app.post('/shutdown', shutdownHandler);
37
- app.post('/scan_code_quality', scanCodeQualityHandler);
38
- app.post('/write', writeHandler);
39
- app.get('/git/burns', listBurns);
40
- app.post('/git/checkout', checkoutBranch);
41
- app.get('/terminal', terminalHandler);
42
-
43
- const port = 3001;
44
- server.listen(port, () => {
45
- console.log('📂 File server running on http://localhost:' + port);
46
- console.log('🖥️ Terminal WebSocket available at ws://localhost:' + port + '/terminal');
47
- });
package/src/index.js DELETED
@@ -1,99 +0,0 @@
1
- #!/usr/bin/env node
2
- import { existsSync, mkdirSync, copyFileSync } from 'fs';
3
- import { join, dirname } from 'path';
4
- import { fileURLToPath } from 'url';
5
-
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = dirname(__filename);
8
-
9
- const BONZAI_DIR = 'bonzai';
10
- const TEMPLATE_DIR = join(__dirname, '..', 'payload-bonzai');
11
-
12
- function showHelp() {
13
- console.log(`
14
- 🌳 Bonzai Burn - Code Analysis Tool
15
-
16
- Usage: npx bonzai-burn [option]
17
-
18
- Options:
19
- (no option) Initialize bonzai in current directory
20
- -b, --burn Run code analysis (bburn)
21
- -c, --config Launch visualization server (bconfig)
22
- -h, --hook Manage Claude Code stop hook (bhook)
23
- --help Show this help message
24
-
25
- Hook subcommands (-h):
26
- -h Install hook (default)
27
- -h -i Install hook
28
- -h -s Show hook status
29
- -h -u Uninstall hook
30
-
31
- Examples:
32
- npx bonzai-burn # Initialize bonzai folder
33
- npx bonzai-burn -b # Run burn analysis
34
- npx bonzai-burn -c # Start graph server
35
- npx bonzai-burn -h # Install hook
36
- npx bonzai-burn -h -s # Check hook status
37
- `);
38
- }
39
-
40
- function init() {
41
- const currentDir = process.cwd();
42
- const bonzaiPath = join(currentDir, BONZAI_DIR);
43
-
44
- if (existsSync(bonzaiPath)) {
45
- console.log(`📁 ${BONZAI_DIR}/ already exists`);
46
- return;
47
- }
48
-
49
- mkdirSync(bonzaiPath, { recursive: true });
50
- copyFileSync(join(TEMPLATE_DIR, 'config.json'), join(bonzaiPath, 'config.json'));
51
- console.log(`📁 Created ${BONZAI_DIR}/ folder with config.json`);
52
- console.log(`📝 Edit ${BONZAI_DIR}/config.json to configure your burn rules`);
53
- console.log(`🔥 Run 'npx bonzai-burn -b' to analyze your codebase`);
54
- console.log('');
55
- console.log('┌─────────────────────────────────────────────────────────────────────┐');
56
- console.log('│ │');
57
- console.log('│ 🌳 Run `npx bonzai-burn -c` to configure your cleanup settings │');
58
- console.log('│ │');
59
- console.log('└─────────────────────────────────────────────────────────────────────┘');
60
- }
61
-
62
- async function main() {
63
- const args = process.argv.slice(2);
64
- const flag = args[0];
65
-
66
- switch (flag) {
67
- case '-b':
68
- case '--burn': {
69
- const { main: burnMain } = await import('./bburn.js');
70
- if (burnMain) await burnMain();
71
- break;
72
- }
73
- case '-c':
74
- case '--config': {
75
- const { main: configMain } = await import('./bconfig.js');
76
- if (configMain) await configMain();
77
- break;
78
- }
79
- case '-h':
80
- case '--hook': {
81
- const { main: hookMain } = await import('./bhook.js');
82
- // Pass remaining args as subcommands (e.g., -h -s → ['-s'])
83
- const subArgs = args.slice(1);
84
- if (hookMain) await hookMain(subArgs);
85
- break;
86
- }
87
- case '--help':
88
- showHelp();
89
- break;
90
- default:
91
- init();
92
- break;
93
- }
94
- }
95
-
96
- main().catch((error) => {
97
- console.error('Error:', error.message);
98
- process.exit(1);
99
- });
File without changes
File without changes
File without changes