claude-kanban 0.2.1 → 0.3.1
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 +110 -13
- package/dist/bin/cli.js.map +1 -1
- package/dist/server/index.js +25 -10
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -36,7 +36,39 @@ function detectPackageManager(projectPath) {
|
|
|
36
36
|
if (existsSync(join(projectPath, "bun.lockb"))) return "bun";
|
|
37
37
|
return "npm";
|
|
38
38
|
}
|
|
39
|
+
function detectProjectType(projectPath) {
|
|
40
|
+
if (existsSync(join(projectPath, "package.json"))) return "node";
|
|
41
|
+
if (existsSync(join(projectPath, "pyproject.toml")) || existsSync(join(projectPath, "requirements.txt")) || existsSync(join(projectPath, "setup.py"))) return "python";
|
|
42
|
+
if (existsSync(join(projectPath, "composer.json"))) return "php";
|
|
43
|
+
if (existsSync(join(projectPath, "Gemfile"))) return "ruby";
|
|
44
|
+
if (existsSync(join(projectPath, "go.mod"))) return "go";
|
|
45
|
+
if (existsSync(join(projectPath, "Cargo.toml"))) return "rust";
|
|
46
|
+
return "unknown";
|
|
47
|
+
}
|
|
39
48
|
function detectProjectCommands(projectPath) {
|
|
49
|
+
const projectType = detectProjectType(projectPath);
|
|
50
|
+
switch (projectType) {
|
|
51
|
+
case "node":
|
|
52
|
+
return detectNodeCommands(projectPath);
|
|
53
|
+
case "python":
|
|
54
|
+
return detectPythonCommands(projectPath);
|
|
55
|
+
case "php":
|
|
56
|
+
return detectPHPCommands(projectPath);
|
|
57
|
+
case "ruby":
|
|
58
|
+
return detectRubyCommands(projectPath);
|
|
59
|
+
case "go":
|
|
60
|
+
return detectGoCommands(projectPath);
|
|
61
|
+
case "rust":
|
|
62
|
+
return detectRustCommands(projectPath);
|
|
63
|
+
default:
|
|
64
|
+
return {
|
|
65
|
+
testCommand: "",
|
|
66
|
+
typecheckCommand: "",
|
|
67
|
+
buildCommand: ""
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function detectNodeCommands(projectPath) {
|
|
40
72
|
const pm = detectPackageManager(projectPath);
|
|
41
73
|
const run = pm === "npm" ? "npm run" : pm;
|
|
42
74
|
const packageJsonPath = join(projectPath, "package.json");
|
|
@@ -48,11 +80,61 @@ function detectProjectCommands(projectPath) {
|
|
|
48
80
|
} catch {
|
|
49
81
|
}
|
|
50
82
|
}
|
|
51
|
-
const testCommand = scripts.test ? `${run} test` :
|
|
52
|
-
const typecheckCommand = scripts.typecheck ? `${run} typecheck` : scripts["type-check"] ? `${run} type-check` : existsSync(join(projectPath, "tsconfig.json")) ? `${run === "npm run" ? "npx" : pm} tsc --noEmit` :
|
|
53
|
-
const buildCommand = scripts.build ? `${run} build` :
|
|
83
|
+
const testCommand = scripts.test ? `${run} test` : "";
|
|
84
|
+
const typecheckCommand = scripts.typecheck ? `${run} typecheck` : scripts["type-check"] ? `${run} type-check` : existsSync(join(projectPath, "tsconfig.json")) ? `${run === "npm run" ? "npx" : pm} tsc --noEmit` : "";
|
|
85
|
+
const buildCommand = scripts.build ? `${run} build` : "";
|
|
54
86
|
return { testCommand, typecheckCommand, buildCommand };
|
|
55
87
|
}
|
|
88
|
+
function detectPythonCommands(projectPath) {
|
|
89
|
+
const hasPytest = existsSync(join(projectPath, "pytest.ini")) || existsSync(join(projectPath, "pyproject.toml")) || existsSync(join(projectPath, "tests"));
|
|
90
|
+
const hasMypy = existsSync(join(projectPath, "mypy.ini")) || existsSync(join(projectPath, ".mypy.ini"));
|
|
91
|
+
return {
|
|
92
|
+
testCommand: hasPytest ? "pytest" : "",
|
|
93
|
+
typecheckCommand: hasMypy ? "mypy ." : "",
|
|
94
|
+
buildCommand: ""
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function detectPHPCommands(projectPath) {
|
|
98
|
+
const hasPhpunit = existsSync(join(projectPath, "phpunit.xml")) || existsSync(join(projectPath, "phpunit.xml.dist"));
|
|
99
|
+
const hasPest = existsSync(join(projectPath, "tests", "Pest.php"));
|
|
100
|
+
const hasPhpstan = existsSync(join(projectPath, "phpstan.neon")) || existsSync(join(projectPath, "phpstan.neon.dist"));
|
|
101
|
+
let testCommand = "";
|
|
102
|
+
if (hasPest) {
|
|
103
|
+
testCommand = "./vendor/bin/pest";
|
|
104
|
+
} else if (hasPhpunit) {
|
|
105
|
+
testCommand = "./vendor/bin/phpunit";
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
testCommand,
|
|
109
|
+
typecheckCommand: hasPhpstan ? "./vendor/bin/phpstan analyse" : "",
|
|
110
|
+
buildCommand: ""
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function detectRubyCommands(projectPath) {
|
|
114
|
+
const hasRspec = existsSync(join(projectPath, "spec")) || existsSync(join(projectPath, ".rspec"));
|
|
115
|
+
const hasMinitest = existsSync(join(projectPath, "test"));
|
|
116
|
+
return {
|
|
117
|
+
testCommand: hasRspec ? "bundle exec rspec" : hasMinitest ? "bundle exec rake test" : "",
|
|
118
|
+
typecheckCommand: "",
|
|
119
|
+
// Ruby doesn't have built-in typechecking (sorbet is optional)
|
|
120
|
+
buildCommand: ""
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function detectGoCommands(_projectPath) {
|
|
124
|
+
return {
|
|
125
|
+
testCommand: "go test ./...",
|
|
126
|
+
typecheckCommand: "go build ./...",
|
|
127
|
+
// Go's compiler is the typechecker
|
|
128
|
+
buildCommand: "go build"
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function detectRustCommands(_projectPath) {
|
|
132
|
+
return {
|
|
133
|
+
testCommand: "cargo test",
|
|
134
|
+
typecheckCommand: "cargo check",
|
|
135
|
+
buildCommand: "cargo build"
|
|
136
|
+
};
|
|
137
|
+
}
|
|
56
138
|
function createInitialPRD(projectName) {
|
|
57
139
|
return {
|
|
58
140
|
version: "1.0",
|
|
@@ -709,13 +791,30 @@ ${summary}
|
|
|
709
791
|
/**
|
|
710
792
|
* Build the prompt for a specific task
|
|
711
793
|
*/
|
|
712
|
-
buildTaskPrompt(task, config) {
|
|
794
|
+
buildTaskPrompt(task, config, worktreeInfo) {
|
|
713
795
|
const kanbanDir = join4(this.projectPath, KANBAN_DIR4);
|
|
714
796
|
const prdPath = join4(kanbanDir, "prd.json");
|
|
715
797
|
const progressPath = join4(kanbanDir, "progress.txt");
|
|
716
798
|
const stepsText = task.steps.length > 0 ? `
|
|
717
799
|
Verification steps:
|
|
718
800
|
${task.steps.map((s, i) => `${i + 1}. ${s}`).join("\n")}` : "";
|
|
801
|
+
const verifySteps = [];
|
|
802
|
+
if (config.project.typecheckCommand) {
|
|
803
|
+
verifySteps.push(`Run typecheck: ${config.project.typecheckCommand}`);
|
|
804
|
+
}
|
|
805
|
+
if (config.project.testCommand) {
|
|
806
|
+
verifySteps.push(`Run tests: ${config.project.testCommand}`);
|
|
807
|
+
}
|
|
808
|
+
const verifySection = verifySteps.length > 0 ? `3. Verify your work:
|
|
809
|
+
${verifySteps.map((s) => ` - ${s}`).join("\n")}
|
|
810
|
+
|
|
811
|
+
` : "";
|
|
812
|
+
const worktreeSection = worktreeInfo ? `## ENVIRONMENT
|
|
813
|
+
You are running in an isolated git worktree on branch "${worktreeInfo.branchName}".
|
|
814
|
+
This is a fresh checkout - dependencies (node_modules, vendor, etc.) are NOT installed.
|
|
815
|
+
Before running any build/test commands, install dependencies first (e.g., npm install, composer install, pip install).
|
|
816
|
+
|
|
817
|
+
` : "";
|
|
719
818
|
return `You are an AI coding agent. Complete the following task:
|
|
720
819
|
|
|
721
820
|
## TASK
|
|
@@ -726,26 +825,24 @@ Priority: ${task.priority}
|
|
|
726
825
|
${task.description}
|
|
727
826
|
${stepsText}
|
|
728
827
|
|
|
729
|
-
## INSTRUCTIONS
|
|
730
|
-
1.
|
|
828
|
+
${worktreeSection}## INSTRUCTIONS
|
|
829
|
+
1. If dependencies are not installed, install them first.
|
|
731
830
|
|
|
732
|
-
2.
|
|
733
|
-
- Run typecheck: ${config.project.typecheckCommand}
|
|
734
|
-
- Run tests: ${config.project.testCommand}
|
|
831
|
+
2. Implement this task as described above.
|
|
735
832
|
|
|
736
|
-
3. When complete, update the task in ${prdPath}:
|
|
833
|
+
${verifySection}${verifySteps.length > 0 ? "4" : "3"}. When complete, update the task in ${prdPath}:
|
|
737
834
|
- Find the task with id "${task.id}"
|
|
738
835
|
- Set "passes": true
|
|
739
836
|
- Set "status": "completed"
|
|
740
837
|
|
|
741
|
-
4. Document your work in ${progressPath}:
|
|
838
|
+
${verifySteps.length > 0 ? "5" : "4"}. Document your work in ${progressPath}:
|
|
742
839
|
- What you implemented and files changed
|
|
743
840
|
- Key decisions made and why
|
|
744
841
|
- Gotchas, edge cases, or tricky parts discovered
|
|
745
842
|
- Useful patterns or approaches that worked well
|
|
746
843
|
- Anything a future agent should know about this area of the codebase
|
|
747
844
|
|
|
748
|
-
5. Make a git commit with a descriptive message.
|
|
845
|
+
${verifySteps.length > 0 ? "6" : "5"}. Make a git commit with a descriptive message.
|
|
749
846
|
|
|
750
847
|
Focus only on this task. When successfully complete, output: <promise>COMPLETE</promise>`;
|
|
751
848
|
}
|
|
@@ -769,7 +866,7 @@ Focus only on this task. When successfully complete, output: <promise>COMPLETE</
|
|
|
769
866
|
const startedAt = /* @__PURE__ */ new Date();
|
|
770
867
|
const worktreeInfo = this.createWorktree(taskId);
|
|
771
868
|
const executionPath = worktreeInfo?.worktreePath || this.projectPath;
|
|
772
|
-
const prompt = this.buildTaskPrompt(task, config);
|
|
869
|
+
const prompt = this.buildTaskPrompt(task, config, worktreeInfo);
|
|
773
870
|
const kanbanDir = join4(this.projectPath, KANBAN_DIR4);
|
|
774
871
|
const promptFile = join4(kanbanDir, `prompt-${taskId}.txt`);
|
|
775
872
|
writeFileSync4(promptFile, prompt);
|