bueller-wheel 0.1.0 → 0.2.0

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 (3) hide show
  1. package/README.md +7 -9
  2. package/dist/index.js +37 -17
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Bueller Wheel
2
2
 
3
- A headless Claude Code issue processor that runs in a loop and resolves issues or tickets written in markdown
3
+ A headless Claude Code issue processor that runs in a loop and resolves issues or ticket files written in markdown
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -15,16 +15,14 @@ npx bueller-wheel
15
15
 
16
16
  ## Why?
17
17
 
18
- Claude Code agents work better when they focus on one thing at a time. Bueller Wheel helps defer context until it's needed through two mechanisms:
18
+ You want Claude Code to autonomously work on a large pile of issues while you eat lunch and watch a baseball game. Bueller Wheel helps tackle several issues you might encounter:
19
19
 
20
- **Issues as directory-based threads** - Each task becomes a reviewable conversation stored as markdown that gets moved along a file-based "kanban" board. This solves a few problems:
21
- - **Code review**: When Claude burns through multiple tasks, it's hard to know what happened. The issues structure creates discrete, reviewable units of work.
22
- - **Iteration without re-prompting**: Markdown files are structured as a back-and-forth between you and Claude, which lets you append follow-ups naturally without starting over.
23
- - **Human-editable prompts**: Storing issues as simple markdown (not JSON or a database) makes it easy to edit, append, or retroactively clean up conversations to improve prompting.
20
+ - **Claude stops processing after a few issues**: Claude Code tends to stop processing after completing a few tasks. Bueller Wheel keeps prompting Claude Code to work until all of the issues have been resolved.
21
+ - **Claude forgets what it's doing**: As Claude Code uses up its context window, it tends to forget what it was working on. Bueller Wheel runs Claude Code with a fresh context window and prompt for each issue.
22
+ - **You forget what Claude was doing**: If you successfully get Claude Code to work on a large number of tasks, you end up with a pile of code to review. Bueller Wheel structures each issue as a discrete reviewable chunk of work, in a format amenable to multiple iterations of feedback between you and Claude.
23
+ - **Claude keeps making the same mistakes**: A Claude that forgets its history is doomed to repeat it. Bueller Wheel sets up an FAQ directory for Claude to speed up resolution of frequent pitfalls.
24
24
 
25
- **FAQ system** - Common mistakes get documented once, then referenced automatically. Instead of repeating corrections or watching Claude make the same errors over and over, capture solutions in FAQ files that the agent checks when stuck.
26
-
27
- **Note:** Bueller Wheel is not a full-fledged task management system. It has no concept of assignment or dependency apart from linear file ordering. The sweet spot for this tool is **solo developers working on a single branch**, but you can make [parallel branches and agents](#working-with-multiple-branches) work.
25
+ **Note**: Bueller Wheel is not a full-fledged task management system. It has no concept of assignment or dependency apart from linear file ordering. The sweet spot for this tool is **solo developers working on a single branch**. That said, you can make [parallel branches and agents](#working-with-multiple-branches) work.
28
26
 
29
27
  ## How It Works
30
28
 
package/dist/index.js CHANGED
@@ -3,6 +3,15 @@ import { execSync } from 'node:child_process';
3
3
  import * as fs from 'node:fs/promises';
4
4
  import * as path from 'node:path';
5
5
  import { query } from '@anthropic-ai/claude-agent-sdk';
6
+ // Colors for output
7
+ const colors = {
8
+ red: '\x1b[0;31m',
9
+ green: '\x1b[0;32m',
10
+ yellow: '\x1b[1;33m',
11
+ blue: '\x1b[0;34m',
12
+ cyan: '\x1b[0;36m',
13
+ reset: '\x1b[0m',
14
+ };
6
15
  const ISSUE_DIR_OPEN = 'open';
7
16
  const ISSUE_DIR_REVIEW = 'review';
8
17
  const ISSUE_DIR_STUCK = 'stuck';
@@ -136,7 +145,7 @@ function gitCommit(issueFile, status) {
136
145
  encoding: 'utf-8',
137
146
  }).trim();
138
147
  if (!untrackedFiles) {
139
- console.log('No changes to commit');
148
+ console.log(`${colors.cyan}No changes to commit${colors.reset}`);
140
149
  return;
141
150
  }
142
151
  }
@@ -150,10 +159,10 @@ function gitCommit(issueFile, status) {
150
159
  execSync(`git commit -m "${commitMessage.replace(/"/g, '\\"')}"`, {
151
160
  stdio: 'inherit',
152
161
  });
153
- console.log(`\nGit commit created: ${commitMessage}`);
162
+ console.log(`${colors.green}\nGit commit created: ${commitMessage}${colors.reset}`);
154
163
  }
155
164
  catch (error) {
156
- console.error(`Failed to create git commit: ${String(error)}`);
165
+ console.error(`${colors.red}Failed to create git commit: ${String(error)}${colors.reset}`);
157
166
  }
158
167
  }
159
168
  function getDefaultPromptTemplate() {
@@ -256,12 +265,12 @@ async function loadOrCreatePromptTemplate(promptFile) {
256
265
  // If prompt file exists, load it
257
266
  try {
258
267
  await fs.access(promptFile);
259
- console.log(`Loading prompt template from: ${promptFile}`);
268
+ console.log(`${colors.cyan}Loading prompt template from: ${promptFile}${colors.reset}`);
260
269
  return await fs.readFile(promptFile, 'utf-8');
261
270
  }
262
271
  catch {
263
272
  // Otherwise, create the default prompt template
264
- console.log(`Prompt file not found. Creating default template at: ${promptFile}`);
273
+ console.log(`${colors.yellow}Prompt file not found. Creating default template at: ${promptFile}${colors.reset}`);
265
274
  const defaultTemplate = getDefaultPromptTemplate();
266
275
  // Ensure the directory exists
267
276
  const promptDir = path.dirname(promptFile);
@@ -289,7 +298,7 @@ function buildSystemPrompt(template, issuesDir, faqDir, issueFile) {
289
298
  }
290
299
  function logToolUse(block) {
291
300
  process.stdout.write('\n');
292
- process.stdout.write(`[${block.name}] `);
301
+ process.stdout.write(`${colors.cyan}[${block.name}]${colors.reset} `);
293
302
  switch (block.name.toLowerCase()) {
294
303
  case 'read':
295
304
  case 'write':
@@ -302,18 +311,29 @@ function logToolUse(block) {
302
311
  case 'glob':
303
312
  process.stdout.write(`${block.input?.pattern}`);
304
313
  break;
314
+ case 'grep': {
315
+ const pattern = block.input?.pattern;
316
+ const glob = block.input?.glob;
317
+ if (pattern) {
318
+ process.stdout.write(`${pattern}`);
319
+ }
320
+ if (glob) {
321
+ process.stdout.write(` (${glob})`);
322
+ }
323
+ break;
324
+ }
305
325
  case 'todowrite': {
306
326
  for (const todo of block.input?.todos ?? []) {
307
327
  process.stdout.write('\n');
308
328
  switch (todo.status) {
309
329
  case 'in_progress':
310
- process.stdout.write('⧖');
330
+ process.stdout.write(`${colors.yellow}⧖${colors.reset}`);
311
331
  break;
312
332
  case 'pending':
313
333
  process.stdout.write('☐');
314
334
  break;
315
335
  case 'completed':
316
- process.stdout.write('✓');
336
+ process.stdout.write(`${colors.green}✓${colors.reset}`);
317
337
  break;
318
338
  default:
319
339
  process.stdout.write(todo.status);
@@ -361,7 +381,7 @@ function logSDKMessage(item) {
361
381
  async function runAgent(options) {
362
382
  const { template, issuesDir, faqDir, issueFile, continueMode, continuePrompt } = options;
363
383
  const systemPrompt = buildSystemPrompt(template, issuesDir, faqDir, issueFile);
364
- console.log('\n--- Starting agent ---');
384
+ console.log(`${colors.blue}\n--- Starting agent ---${colors.reset}`);
365
385
  const stream = query({
366
386
  prompt: continueMode ? continuePrompt : systemPrompt,
367
387
  options: {
@@ -373,12 +393,12 @@ async function runAgent(options) {
373
393
  for await (const item of stream) {
374
394
  logSDKMessage(item);
375
395
  }
376
- console.log('\n--- Agent finished ---');
396
+ console.log(`${colors.blue}\n--- Agent finished ---${colors.reset}`);
377
397
  }
378
398
  async function main() {
379
399
  const config = parseArgs();
380
- console.log('Bueller? Bueller?');
381
- console.log('-----------------');
400
+ console.log(`${colors.cyan}Bueller? Bueller?${colors.reset}`);
401
+ console.log(`${colors.cyan}-----------------${colors.reset}`);
382
402
  console.log(`Issues directory: ${config.issuesDir}`);
383
403
  console.log(`FAQ directory: ${config.faqDir}`);
384
404
  console.log(`Max iterations: ${config.maxIterations}`);
@@ -393,10 +413,10 @@ async function main() {
393
413
  let iteration = 0;
394
414
  while (iteration < config.maxIterations) {
395
415
  iteration++;
396
- console.log(`\n### Iteration ${iteration} ###\n`);
416
+ console.log(`${colors.yellow}\n### Iteration ${iteration} ###${colors.reset}\n`);
397
417
  const openIssues = await getOpenIssues(config.issuesDir);
398
418
  if (openIssues.length === 0) {
399
- console.log('No more issues in open/. Exiting.');
419
+ console.log(`${colors.green}No more issues in open/. Exiting.${colors.reset}`);
400
420
  break;
401
421
  }
402
422
  console.log(`Found ${openIssues.length} open issue(s)`);
@@ -451,12 +471,12 @@ async function main() {
451
471
  }
452
472
  }
453
473
  if (iteration >= config.maxIterations) {
454
- console.log(`\nReached maximum iterations (${config.maxIterations}). Exiting.`);
474
+ console.log(`${colors.yellow}\nReached maximum iterations (${config.maxIterations}). Exiting.${colors.reset}`);
455
475
  }
456
- console.log('\nDone!');
476
+ console.log(`${colors.green}\nDone!${colors.reset}`);
457
477
  }
458
478
  main().catch((error) => {
459
- console.error('Error:', error);
479
+ console.error(`${colors.red}Error:${colors.reset}`, error);
460
480
  process.exit(1);
461
481
  });
462
482
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bueller-wheel",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Headless Claude Code issue processor - A wrapper that runs Claude Code in a loop to process issues from a directory queue",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",