bonzai-burn 1.0.6 ā 1.0.7
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/package.json +1 -1
- package/src/btrim.js +87 -12
package/package.json
CHANGED
package/src/btrim.js
CHANGED
|
@@ -2,24 +2,45 @@
|
|
|
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';
|
|
14
|
+
|
|
15
|
+
// Template folder in the package
|
|
16
|
+
const TEMPLATE_DIR = join(__dirname, '..', 'bonzai');
|
|
17
|
+
|
|
18
|
+
function getTemplate(filename) {
|
|
19
|
+
const templatePath = join(TEMPLATE_DIR, filename);
|
|
20
|
+
if (fs.existsSync(templatePath)) {
|
|
21
|
+
return fs.readFileSync(templatePath, 'utf-8');
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
9
25
|
|
|
10
26
|
const DEFAULT_SPECS = `# Bonzai Specs
|
|
11
27
|
|
|
12
28
|
Define your cleanup requirements below. btrim will follow these instructions.
|
|
13
29
|
|
|
14
|
-
##
|
|
30
|
+
## Requirements:
|
|
15
31
|
- Remove unused imports
|
|
16
32
|
- Delete files matching pattern "*.tmp"
|
|
17
33
|
- Clean up console.log statements
|
|
18
34
|
`;
|
|
19
35
|
|
|
36
|
+
const DEFAULT_CONFIG = {
|
|
37
|
+
headlessClaude: true
|
|
38
|
+
};
|
|
39
|
+
|
|
20
40
|
function initializeBonzai() {
|
|
21
41
|
const bonzaiPath = join(process.cwd(), BONZAI_DIR);
|
|
22
42
|
const specsPath = join(bonzaiPath, SPECS_FILE);
|
|
43
|
+
const configPath = join(bonzaiPath, CONFIG_FILE);
|
|
23
44
|
|
|
24
45
|
// Check if bonzai/ folder exists
|
|
25
46
|
if (!fs.existsSync(bonzaiPath)) {
|
|
@@ -28,10 +49,18 @@ function initializeBonzai() {
|
|
|
28
49
|
console.log(`š Created ${BONZAI_DIR}/ folder`);
|
|
29
50
|
}
|
|
30
51
|
|
|
31
|
-
// Generate bonzai/specs.md
|
|
52
|
+
// Generate bonzai/specs.md from package template
|
|
32
53
|
if (!fs.existsSync(specsPath)) {
|
|
33
|
-
|
|
54
|
+
const specsContent = getTemplate(SPECS_FILE) || DEFAULT_SPECS;
|
|
55
|
+
fs.writeFileSync(specsPath, specsContent);
|
|
34
56
|
console.log(`š Created ${BONZAI_DIR}/${SPECS_FILE}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Generate bonzai/config.json from package template
|
|
60
|
+
if (!fs.existsSync(configPath)) {
|
|
61
|
+
const configContent = getTemplate(CONFIG_FILE) || JSON.stringify(DEFAULT_CONFIG, null, 2) + '\n';
|
|
62
|
+
fs.writeFileSync(configPath, configContent);
|
|
63
|
+
console.log(`āļø Created ${BONZAI_DIR}/${CONFIG_FILE}`);
|
|
35
64
|
console.log(`\nā ļø Please edit ${BONZAI_DIR}/${SPECS_FILE} to define your cleanup rules before running btrim.\n`);
|
|
36
65
|
process.exit(0);
|
|
37
66
|
}
|
|
@@ -40,6 +69,7 @@ function initializeBonzai() {
|
|
|
40
69
|
function ensureBonzaiDir() {
|
|
41
70
|
const bonzaiPath = join(process.cwd(), BONZAI_DIR);
|
|
42
71
|
const specsPath = join(bonzaiPath, SPECS_FILE);
|
|
72
|
+
const configPath = join(bonzaiPath, CONFIG_FILE);
|
|
43
73
|
|
|
44
74
|
if (!fs.existsSync(bonzaiPath)) {
|
|
45
75
|
fs.mkdirSync(bonzaiPath, { recursive: true });
|
|
@@ -47,11 +77,27 @@ function ensureBonzaiDir() {
|
|
|
47
77
|
}
|
|
48
78
|
|
|
49
79
|
if (!fs.existsSync(specsPath)) {
|
|
50
|
-
|
|
80
|
+
const specsContent = getTemplate(SPECS_FILE) || DEFAULT_SPECS;
|
|
81
|
+
fs.writeFileSync(specsPath, specsContent);
|
|
51
82
|
console.log(`š Created ${BONZAI_DIR}/${SPECS_FILE} - edit this file to define your cleanup specs\n`);
|
|
52
83
|
}
|
|
53
84
|
|
|
54
|
-
|
|
85
|
+
if (!fs.existsSync(configPath)) {
|
|
86
|
+
const configContent = getTemplate(CONFIG_FILE) || JSON.stringify(DEFAULT_CONFIG, null, 2) + '\n';
|
|
87
|
+
fs.writeFileSync(configPath, configContent);
|
|
88
|
+
console.log(`āļø Created ${BONZAI_DIR}/${CONFIG_FILE}\n`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return { specsPath, configPath };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function loadConfig(configPath) {
|
|
95
|
+
try {
|
|
96
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
97
|
+
return { ...DEFAULT_CONFIG, ...JSON.parse(content) };
|
|
98
|
+
} catch {
|
|
99
|
+
return DEFAULT_CONFIG;
|
|
100
|
+
}
|
|
55
101
|
}
|
|
56
102
|
|
|
57
103
|
function loadSpecs(specsPath) {
|
|
@@ -67,7 +113,7 @@ function execVisible(command) {
|
|
|
67
113
|
execSync(command, { stdio: 'inherit' });
|
|
68
114
|
}
|
|
69
115
|
|
|
70
|
-
function executeClaude(requirements) {
|
|
116
|
+
function executeClaude(requirements, config) {
|
|
71
117
|
// Check if Claude CLI exists
|
|
72
118
|
try {
|
|
73
119
|
execSync('which claude', { encoding: 'utf-8', stdio: 'pipe' });
|
|
@@ -78,13 +124,40 @@ function executeClaude(requirements) {
|
|
|
78
124
|
);
|
|
79
125
|
}
|
|
80
126
|
|
|
81
|
-
|
|
127
|
+
const headless = config.headlessClaude !== false;
|
|
128
|
+
|
|
129
|
+
// Non-headless mode: run Claude interactively
|
|
130
|
+
if (!headless) {
|
|
131
|
+
console.log('š„ļø Running in interactive mode...\n');
|
|
132
|
+
return new Promise((resolve, reject) => {
|
|
133
|
+
const args = [
|
|
134
|
+
'--allowedTools', 'Read,Write,Edit,Bash',
|
|
135
|
+
'--permission-mode', 'dontAsk'
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
const claude = spawn('claude', args, {
|
|
139
|
+
stdio: 'inherit'
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
claude.on('close', (code) => {
|
|
143
|
+
if (code === 0) {
|
|
144
|
+
resolve();
|
|
145
|
+
} else {
|
|
146
|
+
reject(new Error(`Claude exited with code ${code}`));
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
claude.on('error', (err) => {
|
|
151
|
+
reject(new Error(`Failed to execute Claude: ${err.message}`));
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Headless mode with token tracking
|
|
82
157
|
let totalInputTokens = 0;
|
|
83
158
|
let totalOutputTokens = 0;
|
|
84
159
|
let lastToolName = '';
|
|
85
160
|
|
|
86
|
-
// Execute Claude with streaming JSON output
|
|
87
|
-
|
|
88
161
|
return new Promise((resolve, reject) => {
|
|
89
162
|
const args = [
|
|
90
163
|
'-p', requirements,
|
|
@@ -189,8 +262,9 @@ async function burn() {
|
|
|
189
262
|
initializeBonzai();
|
|
190
263
|
|
|
191
264
|
// Ensure bonzai directory and specs file exist
|
|
192
|
-
const specsPath = ensureBonzaiDir();
|
|
265
|
+
const { specsPath, configPath } = ensureBonzaiDir();
|
|
193
266
|
const specs = loadSpecs(specsPath);
|
|
267
|
+
const config = loadConfig(configPath);
|
|
194
268
|
|
|
195
269
|
// Check if Claude CLI exists and execute
|
|
196
270
|
console.log('š Checking for Claude Code CLI...');
|
|
@@ -235,12 +309,13 @@ async function burn() {
|
|
|
235
309
|
exec(`git config bonzai.madeWipCommit ${madeWipCommit}`);
|
|
236
310
|
|
|
237
311
|
console.log(`š Specs loaded from: ${BONZAI_DIR}/${SPECS_FILE}`);
|
|
312
|
+
console.log(`āļø Headless mode: ${config.headlessClaude !== false ? 'on' : 'off'}`);
|
|
238
313
|
console.log('š„ Running Bonzai burn...\n');
|
|
239
314
|
|
|
240
315
|
const startTime = Date.now();
|
|
241
316
|
|
|
242
317
|
// Execute Claude with specs from bonzai/specs.md
|
|
243
|
-
await executeClaude(specs);
|
|
318
|
+
await executeClaude(specs, config);
|
|
244
319
|
|
|
245
320
|
const duration = Math.round((Date.now() - startTime) / 1000);
|
|
246
321
|
|