bonzai-burn 1.0.3 ā 1.0.4
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/brevert.js +0 -0
- package/src/btrim.js +150 -16
- package/src/index.js +0 -0
package/package.json
CHANGED
package/src/brevert.js
CHANGED
|
File without changes
|
package/src/btrim.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execSync } from 'child_process';
|
|
3
|
-
import
|
|
2
|
+
import { execSync, spawn } from 'child_process';
|
|
3
|
+
import fs from 'fs';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
|
|
6
6
|
const BONZAI_DIR = 'bonzai';
|
|
@@ -16,17 +16,37 @@ Define your cleanup requirements below. btrim will follow these instructions.
|
|
|
16
16
|
- Clean up console.log statements
|
|
17
17
|
`;
|
|
18
18
|
|
|
19
|
+
function initializeBonzai() {
|
|
20
|
+
const bonzaiPath = join(process.cwd(), BONZAI_DIR);
|
|
21
|
+
const specsPath = join(bonzaiPath, SPECS_FILE);
|
|
22
|
+
|
|
23
|
+
// Check if bonzai/ folder exists
|
|
24
|
+
if (!fs.existsSync(bonzaiPath)) {
|
|
25
|
+
// Create bonzai/ folder
|
|
26
|
+
fs.mkdirSync(bonzaiPath, { recursive: true });
|
|
27
|
+
console.log(`š Created ${BONZAI_DIR}/ folder`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Generate bonzai/specs.md with template
|
|
31
|
+
if (!fs.existsSync(specsPath)) {
|
|
32
|
+
fs.writeFileSync(specsPath, DEFAULT_SPECS);
|
|
33
|
+
console.log(`š Created ${BONZAI_DIR}/${SPECS_FILE}`);
|
|
34
|
+
console.log(`\nā ļø Please edit ${BONZAI_DIR}/${SPECS_FILE} to define your cleanup rules before running btrim.\n`);
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
19
39
|
function ensureBonzaiDir() {
|
|
20
40
|
const bonzaiPath = join(process.cwd(), BONZAI_DIR);
|
|
21
41
|
const specsPath = join(bonzaiPath, SPECS_FILE);
|
|
22
42
|
|
|
23
|
-
if (!existsSync(bonzaiPath)) {
|
|
24
|
-
mkdirSync(bonzaiPath, { recursive: true });
|
|
43
|
+
if (!fs.existsSync(bonzaiPath)) {
|
|
44
|
+
fs.mkdirSync(bonzaiPath, { recursive: true });
|
|
25
45
|
console.log(`š Created ${BONZAI_DIR}/ folder\n`);
|
|
26
46
|
}
|
|
27
47
|
|
|
28
|
-
if (!existsSync(specsPath)) {
|
|
29
|
-
writeFileSync(specsPath, DEFAULT_SPECS);
|
|
48
|
+
if (!fs.existsSync(specsPath)) {
|
|
49
|
+
fs.writeFileSync(specsPath, DEFAULT_SPECS);
|
|
30
50
|
console.log(`š Created ${BONZAI_DIR}/${SPECS_FILE} - edit this file to define your cleanup specs\n`);
|
|
31
51
|
}
|
|
32
52
|
|
|
@@ -34,7 +54,7 @@ function ensureBonzaiDir() {
|
|
|
34
54
|
}
|
|
35
55
|
|
|
36
56
|
function loadSpecs(specsPath) {
|
|
37
|
-
const content = readFileSync(specsPath, 'utf-8');
|
|
57
|
+
const content = fs.readFileSync(specsPath, 'utf-8');
|
|
38
58
|
return `You are a code cleanup assistant. Follow these specifications:\n\n${content}`;
|
|
39
59
|
}
|
|
40
60
|
|
|
@@ -46,21 +66,132 @@ function execVisible(command) {
|
|
|
46
66
|
execSync(command, { stdio: 'inherit' });
|
|
47
67
|
}
|
|
48
68
|
|
|
69
|
+
function executeClaude(requirements) {
|
|
70
|
+
// Check if Claude CLI exists
|
|
71
|
+
try {
|
|
72
|
+
execSync('which claude', { encoding: 'utf-8', stdio: 'pipe' });
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
'Claude Code CLI not found.\n' +
|
|
76
|
+
'Install it with: npm install -g @anthropic-ai/claude-code'
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Track token usage
|
|
81
|
+
let totalInputTokens = 0;
|
|
82
|
+
let totalOutputTokens = 0;
|
|
83
|
+
let lastToolName = '';
|
|
84
|
+
|
|
85
|
+
// Execute Claude with streaming JSON output
|
|
86
|
+
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
const args = [
|
|
89
|
+
'-p', requirements,
|
|
90
|
+
'--allowedTools', 'Read,Write,Edit,Bash',
|
|
91
|
+
'--permission-mode', 'dontAsk',
|
|
92
|
+
'--output-format', 'stream-json'
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const claude = spawn('claude', args, {
|
|
96
|
+
stdio: ['inherit', 'pipe', 'pipe']
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
let buffer = '';
|
|
100
|
+
|
|
101
|
+
claude.stdout.on('data', (data) => {
|
|
102
|
+
buffer += data.toString();
|
|
103
|
+
|
|
104
|
+
// Process complete JSON lines
|
|
105
|
+
const lines = buffer.split('\n');
|
|
106
|
+
buffer = lines.pop(); // Keep incomplete line in buffer
|
|
107
|
+
|
|
108
|
+
for (const line of lines) {
|
|
109
|
+
if (!line.trim()) continue;
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const event = JSON.parse(line);
|
|
113
|
+
|
|
114
|
+
// Track tokens from assistant messages
|
|
115
|
+
if (event.type === 'assistant' && event.message?.usage) {
|
|
116
|
+
const usage = event.message.usage;
|
|
117
|
+
if (usage.input_tokens) totalInputTokens += usage.input_tokens;
|
|
118
|
+
if (usage.output_tokens) totalOutputTokens += usage.output_tokens;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Show tool usage updates
|
|
122
|
+
if (event.type === 'content_block_start' && event.content_block?.type === 'tool_use') {
|
|
123
|
+
lastToolName = event.content_block.name || '';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (event.type === 'content_block_stop' && lastToolName) {
|
|
127
|
+
const icon = getToolIcon(lastToolName);
|
|
128
|
+
console.log(` ${icon} ${lastToolName}`);
|
|
129
|
+
lastToolName = '';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Show result events with file info
|
|
133
|
+
if (event.type === 'result') {
|
|
134
|
+
if (event.usage) {
|
|
135
|
+
// Final usage stats
|
|
136
|
+
totalInputTokens = event.usage.input_tokens || totalInputTokens;
|
|
137
|
+
totalOutputTokens = event.usage.output_tokens || totalOutputTokens;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
} catch (e) {
|
|
142
|
+
// Not valid JSON, skip
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
claude.stderr.on('data', (data) => {
|
|
148
|
+
// Show errors but don't clutter with minor stderr
|
|
149
|
+
const msg = data.toString().trim();
|
|
150
|
+
if (msg && !msg.includes('ExperimentalWarning')) {
|
|
151
|
+
console.error(msg);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
claude.on('close', (code) => {
|
|
156
|
+
// Print token summary
|
|
157
|
+
console.log(`\nš Tokens: ${totalInputTokens.toLocaleString()} in / ${totalOutputTokens.toLocaleString()} out`);
|
|
158
|
+
|
|
159
|
+
if (code === 0) {
|
|
160
|
+
resolve();
|
|
161
|
+
} else {
|
|
162
|
+
reject(new Error(`Claude exited with code ${code}`));
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
claude.on('error', (err) => {
|
|
167
|
+
reject(new Error(`Failed to execute Claude: ${err.message}`));
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function getToolIcon(toolName) {
|
|
173
|
+
const icons = {
|
|
174
|
+
'Read': 'š',
|
|
175
|
+
'Write': 'āļø',
|
|
176
|
+
'Edit': 'š§',
|
|
177
|
+
'Bash': 'š»',
|
|
178
|
+
'Glob': 'š',
|
|
179
|
+
'Grep': 'š'
|
|
180
|
+
};
|
|
181
|
+
return icons[toolName] || 'š¹';
|
|
182
|
+
}
|
|
183
|
+
|
|
49
184
|
async function burn() {
|
|
50
185
|
try {
|
|
186
|
+
// Initialize bonzai folder and specs.md on first execution
|
|
187
|
+
initializeBonzai();
|
|
188
|
+
|
|
51
189
|
// Ensure bonzai directory and specs file exist
|
|
52
190
|
const specsPath = ensureBonzaiDir();
|
|
53
191
|
const specs = loadSpecs(specsPath);
|
|
54
192
|
|
|
55
|
-
// Check if Claude CLI exists
|
|
193
|
+
// Check if Claude CLI exists and execute
|
|
56
194
|
console.log('š Checking for Claude Code CLI...');
|
|
57
|
-
try {
|
|
58
|
-
exec('which claude');
|
|
59
|
-
} catch {
|
|
60
|
-
console.error('ā Claude Code CLI not found');
|
|
61
|
-
console.error('Install: npm install -g @anthropic-ai/claude-code');
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
195
|
|
|
65
196
|
// Check if in git repo
|
|
66
197
|
try {
|
|
@@ -114,7 +245,7 @@ async function burn() {
|
|
|
114
245
|
const startTime = Date.now();
|
|
115
246
|
|
|
116
247
|
// Execute Claude with specs from bonzai/specs.md
|
|
117
|
-
|
|
248
|
+
await executeClaude(specs);
|
|
118
249
|
|
|
119
250
|
const duration = Math.round((Date.now() - startTime) / 1000);
|
|
120
251
|
|
|
@@ -135,6 +266,9 @@ async function burn() {
|
|
|
135
266
|
|
|
136
267
|
} catch (error) {
|
|
137
268
|
console.error('ā Burn failed:', error.message);
|
|
269
|
+
if (error.message.includes('Claude Code CLI not found')) {
|
|
270
|
+
console.error('\n' + error.message);
|
|
271
|
+
}
|
|
138
272
|
process.exit(1);
|
|
139
273
|
}
|
|
140
274
|
}
|
package/src/index.js
CHANGED
|
File without changes
|