bonzai-burn 1.0.6 ā 1.0.8
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/bonzai/config.json +4 -0
- package/bonzai/specs.md +8 -0
- package/package.json +3 -2
- package/src/btrim.js +69 -21
package/bonzai/specs.md
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bonzai-burn",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Git branch-based cleanup tool with btrim and brevert commands",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"node": ">=16.0.0"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
|
-
"src"
|
|
22
|
+
"src",
|
|
23
|
+
"bonzai"
|
|
23
24
|
]
|
|
24
25
|
}
|
package/src/btrim.js
CHANGED
|
@@ -2,36 +2,40 @@
|
|
|
2
2
|
import { execSync, spawn } from 'child_process';
|
|
3
3
|
import crypto from 'crypto';
|
|
4
4
|
import fs from 'fs';
|
|
5
|
-
import { join } from 'path';
|
|
5
|
+
import { join, dirname } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
6
10
|
|
|
7
11
|
const BONZAI_DIR = 'bonzai';
|
|
8
12
|
const SPECS_FILE = 'specs.md';
|
|
13
|
+
const CONFIG_FILE = 'config.json';
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Define your cleanup requirements below. btrim will follow these instructions.
|
|
13
|
-
|
|
14
|
-
## Example:
|
|
15
|
-
- Remove unused imports
|
|
16
|
-
- Delete files matching pattern "*.tmp"
|
|
17
|
-
- Clean up console.log statements
|
|
18
|
-
`;
|
|
15
|
+
// Template folder in the package
|
|
16
|
+
const TEMPLATE_DIR = join(__dirname, '..', 'bonzai');
|
|
19
17
|
|
|
20
18
|
function initializeBonzai() {
|
|
21
19
|
const bonzaiPath = join(process.cwd(), BONZAI_DIR);
|
|
22
20
|
const specsPath = join(bonzaiPath, SPECS_FILE);
|
|
21
|
+
const configPath = join(bonzaiPath, CONFIG_FILE);
|
|
23
22
|
|
|
24
23
|
// Check if bonzai/ folder exists
|
|
25
24
|
if (!fs.existsSync(bonzaiPath)) {
|
|
26
|
-
// Create bonzai/ folder
|
|
27
25
|
fs.mkdirSync(bonzaiPath, { recursive: true });
|
|
28
26
|
console.log(`š Created ${BONZAI_DIR}/ folder`);
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
//
|
|
29
|
+
// Copy specs.md from package template
|
|
32
30
|
if (!fs.existsSync(specsPath)) {
|
|
33
|
-
fs.
|
|
31
|
+
fs.copyFileSync(join(TEMPLATE_DIR, SPECS_FILE), specsPath);
|
|
34
32
|
console.log(`š Created ${BONZAI_DIR}/${SPECS_FILE}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Copy config.json from package template
|
|
36
|
+
if (!fs.existsSync(configPath)) {
|
|
37
|
+
fs.copyFileSync(join(TEMPLATE_DIR, CONFIG_FILE), configPath);
|
|
38
|
+
console.log(`āļø Created ${BONZAI_DIR}/${CONFIG_FILE}`);
|
|
35
39
|
console.log(`\nā ļø Please edit ${BONZAI_DIR}/${SPECS_FILE} to define your cleanup rules before running btrim.\n`);
|
|
36
40
|
process.exit(0);
|
|
37
41
|
}
|
|
@@ -40,6 +44,7 @@ function initializeBonzai() {
|
|
|
40
44
|
function ensureBonzaiDir() {
|
|
41
45
|
const bonzaiPath = join(process.cwd(), BONZAI_DIR);
|
|
42
46
|
const specsPath = join(bonzaiPath, SPECS_FILE);
|
|
47
|
+
const configPath = join(bonzaiPath, CONFIG_FILE);
|
|
43
48
|
|
|
44
49
|
if (!fs.existsSync(bonzaiPath)) {
|
|
45
50
|
fs.mkdirSync(bonzaiPath, { recursive: true });
|
|
@@ -47,11 +52,25 @@ function ensureBonzaiDir() {
|
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
if (!fs.existsSync(specsPath)) {
|
|
50
|
-
fs.
|
|
55
|
+
fs.copyFileSync(join(TEMPLATE_DIR, SPECS_FILE), specsPath);
|
|
51
56
|
console.log(`š Created ${BONZAI_DIR}/${SPECS_FILE} - edit this file to define your cleanup specs\n`);
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
if (!fs.existsSync(configPath)) {
|
|
60
|
+
fs.copyFileSync(join(TEMPLATE_DIR, CONFIG_FILE), configPath);
|
|
61
|
+
console.log(`āļø Created ${BONZAI_DIR}/${CONFIG_FILE}\n`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { specsPath, configPath };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function loadConfig(configPath) {
|
|
68
|
+
try {
|
|
69
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
70
|
+
return JSON.parse(content);
|
|
71
|
+
} catch {
|
|
72
|
+
return { headlessClaude: true };
|
|
73
|
+
}
|
|
55
74
|
}
|
|
56
75
|
|
|
57
76
|
function loadSpecs(specsPath) {
|
|
@@ -67,7 +86,7 @@ function execVisible(command) {
|
|
|
67
86
|
execSync(command, { stdio: 'inherit' });
|
|
68
87
|
}
|
|
69
88
|
|
|
70
|
-
function executeClaude(requirements) {
|
|
89
|
+
function executeClaude(requirements, config) {
|
|
71
90
|
// Check if Claude CLI exists
|
|
72
91
|
try {
|
|
73
92
|
execSync('which claude', { encoding: 'utf-8', stdio: 'pipe' });
|
|
@@ -78,13 +97,40 @@ function executeClaude(requirements) {
|
|
|
78
97
|
);
|
|
79
98
|
}
|
|
80
99
|
|
|
81
|
-
|
|
100
|
+
const headless = config.headlessClaude !== false;
|
|
101
|
+
|
|
102
|
+
// Non-headless mode: run Claude interactively
|
|
103
|
+
if (!headless) {
|
|
104
|
+
console.log('š„ļø Running in interactive mode...\n');
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
const args = [
|
|
107
|
+
'--allowedTools', 'Read,Write,Edit,Bash',
|
|
108
|
+
'--permission-mode', 'dontAsk'
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
const claude = spawn('claude', args, {
|
|
112
|
+
stdio: 'inherit'
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
claude.on('close', (code) => {
|
|
116
|
+
if (code === 0) {
|
|
117
|
+
resolve();
|
|
118
|
+
} else {
|
|
119
|
+
reject(new Error(`Claude exited with code ${code}`));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
claude.on('error', (err) => {
|
|
124
|
+
reject(new Error(`Failed to execute Claude: ${err.message}`));
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Headless mode with token tracking
|
|
82
130
|
let totalInputTokens = 0;
|
|
83
131
|
let totalOutputTokens = 0;
|
|
84
132
|
let lastToolName = '';
|
|
85
133
|
|
|
86
|
-
// Execute Claude with streaming JSON output
|
|
87
|
-
|
|
88
134
|
return new Promise((resolve, reject) => {
|
|
89
135
|
const args = [
|
|
90
136
|
'-p', requirements,
|
|
@@ -189,8 +235,9 @@ async function burn() {
|
|
|
189
235
|
initializeBonzai();
|
|
190
236
|
|
|
191
237
|
// Ensure bonzai directory and specs file exist
|
|
192
|
-
const specsPath = ensureBonzaiDir();
|
|
238
|
+
const { specsPath, configPath } = ensureBonzaiDir();
|
|
193
239
|
const specs = loadSpecs(specsPath);
|
|
240
|
+
const config = loadConfig(configPath);
|
|
194
241
|
|
|
195
242
|
// Check if Claude CLI exists and execute
|
|
196
243
|
console.log('š Checking for Claude Code CLI...');
|
|
@@ -235,12 +282,13 @@ async function burn() {
|
|
|
235
282
|
exec(`git config bonzai.madeWipCommit ${madeWipCommit}`);
|
|
236
283
|
|
|
237
284
|
console.log(`š Specs loaded from: ${BONZAI_DIR}/${SPECS_FILE}`);
|
|
285
|
+
console.log(`āļø Headless mode: ${config.headlessClaude !== false ? 'on' : 'off'}`);
|
|
238
286
|
console.log('š„ Running Bonzai burn...\n');
|
|
239
287
|
|
|
240
288
|
const startTime = Date.now();
|
|
241
289
|
|
|
242
290
|
// Execute Claude with specs from bonzai/specs.md
|
|
243
|
-
await executeClaude(specs);
|
|
291
|
+
await executeClaude(specs, config);
|
|
244
292
|
|
|
245
293
|
const duration = Math.round((Date.now() - startTime) / 1000);
|
|
246
294
|
|