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.
- package/dist/bin/cli.js +192 -13
- package/dist/bin/cli.js.map +1 -1
- package/dist/server/index.js +107 -10
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -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.
|
|
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 +=
|
|
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) {
|