claude-kanban 0.2.0 → 0.3.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.
@@ -9,7 +9,7 @@ import { existsSync as existsSync3 } from "fs";
9
9
  // src/server/services/executor.ts
10
10
  import { spawn, execSync } from "child_process";
11
11
  import { join as join4 } from "path";
12
- import { writeFileSync as writeFileSync4, unlinkSync, mkdirSync as mkdirSync2, existsSync as existsSync2, appendFileSync as appendFileSync2, readFileSync as readFileSync4, rmSync } from "fs";
12
+ import { writeFileSync as writeFileSync4, unlinkSync, mkdirSync as mkdirSync2, existsSync as existsSync2, appendFileSync as appendFileSync2, readFileSync as readFileSync4, rmSync, symlinkSync } from "fs";
13
13
  import { EventEmitter } from "events";
14
14
 
15
15
  // src/server/services/project.ts
@@ -256,6 +256,64 @@ var TaskExecutor = class extends EventEmitter {
256
256
  if (!existsSync2(logPath)) return null;
257
257
  return readFileSync4(logPath, "utf-8");
258
258
  }
259
+ /**
260
+ * Format tool use for display in logs
261
+ */
262
+ formatToolUse(toolName, input) {
263
+ const truncate = (str, maxLen = 80) => {
264
+ if (str.length <= maxLen) return str;
265
+ return str.slice(0, maxLen) + "...";
266
+ };
267
+ switch (toolName) {
268
+ case "Bash":
269
+ return `[Bash] $ ${truncate(String(input.command || ""))}
270
+ `;
271
+ case "Read":
272
+ return `[Read] ${input.file_path}
273
+ `;
274
+ case "Edit":
275
+ return `[Edit] ${input.file_path}
276
+ `;
277
+ case "Write":
278
+ return `[Write] ${input.file_path}
279
+ `;
280
+ case "Grep":
281
+ return `[Grep] "${truncate(String(input.pattern || ""))}" in ${input.path || "."}
282
+ `;
283
+ case "Glob":
284
+ return `[Glob] ${input.pattern} in ${input.path || "."}
285
+ `;
286
+ case "Task":
287
+ return `[Task] ${input.description || truncate(String(input.prompt || ""))}
288
+ `;
289
+ case "TodoWrite":
290
+ const todos = input.todos;
291
+ if (todos && Array.isArray(todos)) {
292
+ const summary = todos.map((t) => ` ${t.status === "completed" ? "\u2713" : t.status === "in_progress" ? "\u2192" : "\u25CB"} ${truncate(t.content, 60)}`).join("\n");
293
+ return `[TodoWrite]
294
+ ${summary}
295
+ `;
296
+ }
297
+ return `[TodoWrite]
298
+ `;
299
+ case "WebFetch":
300
+ return `[WebFetch] ${input.url}
301
+ `;
302
+ case "WebSearch":
303
+ return `[WebSearch] "${truncate(String(input.query || ""))}"
304
+ `;
305
+ default:
306
+ const meaningfulParams = ["file_path", "path", "command", "query", "url", "pattern", "target"];
307
+ for (const param of meaningfulParams) {
308
+ if (input[param]) {
309
+ return `[${toolName}] ${truncate(String(input[param]))}
310
+ `;
311
+ }
312
+ }
313
+ return `[${toolName}]
314
+ `;
315
+ }
316
+ }
259
317
  /**
260
318
  * Check if project is a git repository
261
319
  */
@@ -321,6 +379,7 @@ var TaskExecutor = class extends EventEmitter {
321
379
  cwd: this.projectPath,
322
380
  stdio: "pipe"
323
381
  });
382
+ this.symlinkDependencies(worktreePath);
324
383
  console.log(`[executor] Created worktree at ${worktreePath} on branch ${branchName}`);
325
384
  return { worktreePath, branchName };
326
385
  } catch (error) {
@@ -328,6 +387,38 @@ var TaskExecutor = class extends EventEmitter {
328
387
  return null;
329
388
  }
330
389
  }
390
+ /**
391
+ * Symlink dependency directories from main project to worktree
392
+ */
393
+ symlinkDependencies(worktreePath) {
394
+ const depDirs = [
395
+ "node_modules",
396
+ ".pnpm",
397
+ // pnpm store
398
+ ".yarn",
399
+ // yarn cache
400
+ "vendor",
401
+ // PHP/Ruby deps
402
+ "__pycache__",
403
+ // Python cache
404
+ ".venv",
405
+ // Python virtual env
406
+ "venv"
407
+ // Python virtual env
408
+ ];
409
+ for (const dir of depDirs) {
410
+ const sourcePath = join4(this.projectPath, dir);
411
+ const targetPath = join4(worktreePath, dir);
412
+ if (existsSync2(sourcePath) && !existsSync2(targetPath)) {
413
+ try {
414
+ symlinkSync(sourcePath, targetPath, "junction");
415
+ console.log(`[executor] Symlinked ${dir} to worktree`);
416
+ } catch (error) {
417
+ console.log(`[executor] Could not symlink ${dir}:`, error);
418
+ }
419
+ }
420
+ }
421
+ }
331
422
  /**
332
423
  * Remove a git worktree
333
424
  */
@@ -420,6 +511,17 @@ var TaskExecutor = class extends EventEmitter {
420
511
  const stepsText = task.steps.length > 0 ? `
421
512
  Verification steps:
422
513
  ${task.steps.map((s, i) => `${i + 1}. ${s}`).join("\n")}` : "";
514
+ const verifySteps = [];
515
+ if (config.project.typecheckCommand) {
516
+ verifySteps.push(`Run typecheck: ${config.project.typecheckCommand}`);
517
+ }
518
+ if (config.project.testCommand) {
519
+ verifySteps.push(`Run tests: ${config.project.testCommand}`);
520
+ }
521
+ const verifySection = verifySteps.length > 0 ? `2. Verify your work:
522
+ ${verifySteps.map((s) => ` - ${s}`).join("\n")}
523
+
524
+ ` : "";
423
525
  return `You are an AI coding agent. Complete the following task:
424
526
 
425
527
  ## TASK
@@ -433,23 +535,19 @@ ${stepsText}
433
535
  ## INSTRUCTIONS
434
536
  1. Implement this task as described above.
435
537
 
436
- 2. Verify your work:
437
- - Run typecheck: ${config.project.typecheckCommand}
438
- - Run tests: ${config.project.testCommand}
439
-
440
- 3. When complete, update the task in ${prdPath}:
538
+ ${verifySection}${verifySteps.length > 0 ? "3" : "2"}. When complete, update the task in ${prdPath}:
441
539
  - Find the task with id "${task.id}"
442
540
  - Set "passes": true
443
541
  - Set "status": "completed"
444
542
 
445
- 4. Document your work in ${progressPath}:
543
+ ${verifySteps.length > 0 ? "4" : "3"}. Document your work in ${progressPath}:
446
544
  - What you implemented and files changed
447
545
  - Key decisions made and why
448
546
  - Gotchas, edge cases, or tricky parts discovered
449
547
  - Useful patterns or approaches that worked well
450
548
  - Anything a future agent should know about this area of the codebase
451
549
 
452
- 5. Make a git commit with a descriptive message.
550
+ ${verifySteps.length > 0 ? "5" : "4"}. Make a git commit with a descriptive message.
453
551
 
454
552
  Focus only on this task. When successfully complete, output: <promise>COMPLETE</promise>`;
455
553
  }
@@ -550,8 +648,7 @@ Focus only on this task. When successfully complete, output: <promise>COMPLETE</
550
648
  if (block.type === "text") {
551
649
  text += block.text;
552
650
  } else if (block.type === "tool_use") {
553
- text += `[Tool: ${block.name}]
554
- `;
651
+ text += this.formatToolUse(block.name, block.input);
555
652
  }
556
653
  }
557
654
  } else if (json.type === "content_block_delta" && json.delta?.text) {