claudeboard 2.15.4 → 3.1.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/README.md +89 -93
- package/bin/cli.js +198 -230
- package/bin/init-context.js +22 -0
- package/package.json +22 -43
- package/public/app.js +1411 -0
- package/public/index.html +250 -0
- package/public/style.css +1872 -0
- package/src/context-template.md +20 -0
- package/src/notifier.js +65 -0
- package/src/orchestrator.js +800 -0
- package/src/scanner.js +153 -0
- package/src/server.js +205 -0
- package/src/store.js +182 -0
- package/src/verifier.js +131 -0
- package/agents/architect.js +0 -141
- package/agents/board-client.js +0 -126
- package/agents/claude-api.js +0 -124
- package/agents/claude-resolver.js +0 -167
- package/agents/developer.js +0 -224
- package/agents/expo-health.js +0 -584
- package/agents/orchestrator.js +0 -303
- package/agents/qa.js +0 -336
- package/dashboard/index.html +0 -1980
- package/dashboard/server.js +0 -412
- package/sql/setup.sql +0 -57
- package/tools/filesystem.js +0 -95
- package/tools/screenshot.js +0 -74
- package/tools/supabase-reader.js +0 -74
- package/tools/terminal.js +0 -63
package/agents/developer.js
DELETED
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Developer Agent — powered by Claude Agent SDK
|
|
3
|
-
* Replaces the old API-based developer with Claude Code running directly
|
|
4
|
-
* in the project directory — full codebase access, real shell commands.
|
|
5
|
-
*
|
|
6
|
-
* Requires: npm install -g @anthropic-ai/claude-code
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
10
|
-
import { startTask, completeTask, failTask, addLog } from "./board-client.js";
|
|
11
|
-
import { resolveClaudePath, buildEnv, installHint } from "./claude-resolver.js";
|
|
12
|
-
|
|
13
|
-
const CLAUDE_PATH = resolveClaudePath();
|
|
14
|
-
|
|
15
|
-
// ── Tools Claude Code can use ─────────────────────────────────────────────────
|
|
16
|
-
const DEVELOPER_TOOLS = [
|
|
17
|
-
"Read", "Write", "Edit", "MultiEdit",
|
|
18
|
-
"Bash", "Glob", "Grep",
|
|
19
|
-
"TodoWrite", "TodoRead",
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
const DEV_RULES = `
|
|
23
|
-
You are a senior React Native / Expo developer in an autonomous engineering team.
|
|
24
|
-
|
|
25
|
-
RULES:
|
|
26
|
-
- Write complete, production-ready code — no placeholders, no TODOs
|
|
27
|
-
- Use TypeScript if the project uses it
|
|
28
|
-
- Read existing files first to follow the project's patterns
|
|
29
|
-
- Install packages with: npx expo install <package>
|
|
30
|
-
- If tsconfig.json exists, run: npx tsc --noEmit after writing files and fix any errors
|
|
31
|
-
- If you hit an error, read it carefully and fix it — iterate until it works
|
|
32
|
-
- Do NOT ask questions or ask for confirmation. Make your best judgment.
|
|
33
|
-
- Do NOT run npx expo run:ios or npx expo run:android — the orchestrator handles native builds
|
|
34
|
-
- When fully done, print EXACTLY this line: TASK_COMPLETE: <one sentence summary>
|
|
35
|
-
`;
|
|
36
|
-
|
|
37
|
-
// ── Main export ───────────────────────────────────────────────────────────────
|
|
38
|
-
export async function runDeveloperAgent(task, projectPath, techStack, allTasks = [], retryContext = null) {
|
|
39
|
-
console.log(` 🤖 Claude Code working on: ${task.title}`);
|
|
40
|
-
|
|
41
|
-
if (!CLAUDE_PATH) {
|
|
42
|
-
const hint = installHint();
|
|
43
|
-
await startTask(task.id, hint);
|
|
44
|
-
await failTask(task.id, hint);
|
|
45
|
-
console.error(`\n ✗ ${hint}\n`);
|
|
46
|
-
return { success: false, error: hint };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
console.log(` CLI: ${CLAUDE_PATH}`);
|
|
50
|
-
await startTask(task.id, `Claude Code starting: ${task.title}`);
|
|
51
|
-
|
|
52
|
-
const retryNote = retryContext
|
|
53
|
-
? `\n\n⚠️ RETRY — Previous attempt failed. Fix these issues:\n${retryContext}`
|
|
54
|
-
: "";
|
|
55
|
-
|
|
56
|
-
const techNote = techStack && Object.keys(techStack).length > 0
|
|
57
|
-
? `\nKnown tech stack: ${JSON.stringify(techStack)}`
|
|
58
|
-
: "";
|
|
59
|
-
|
|
60
|
-
// Build task context for mini-plan
|
|
61
|
-
const doneTasks = allTasks
|
|
62
|
-
.filter(t => t.status === "done")
|
|
63
|
-
.map(t => ` ✓ ${t.title}`)
|
|
64
|
-
.join("\n");
|
|
65
|
-
const upcomingTasks = allTasks
|
|
66
|
-
.filter(t => t.status === "todo" && t.id !== task.id)
|
|
67
|
-
.slice(0, 12)
|
|
68
|
-
.map(t => ` ○ ${t.title}`)
|
|
69
|
-
.join("\n");
|
|
70
|
-
|
|
71
|
-
const taskContextSection = (doneTasks || upcomingTasks) ? `
|
|
72
|
-
## Implementation Context
|
|
73
|
-
|
|
74
|
-
**Tasks already completed:**
|
|
75
|
-
${doneTasks || " None yet — this is the first task"}
|
|
76
|
-
|
|
77
|
-
**Upcoming tasks (do NOT implement these, just be aware to avoid conflicts):**
|
|
78
|
-
${upcomingTasks || " None"}
|
|
79
|
-
` : "";
|
|
80
|
-
|
|
81
|
-
const prompt = `## Task to implement
|
|
82
|
-
|
|
83
|
-
**Title:** ${task.title}
|
|
84
|
-
|
|
85
|
-
**Description:**
|
|
86
|
-
${task.description || "No additional description provided."}
|
|
87
|
-
${techNote}
|
|
88
|
-
${taskContextSection}
|
|
89
|
-
## Project Context
|
|
90
|
-
Read CLAUDEBOARD_CONTEXT.md first if it exists — it contains key architectural decisions and patterns from previous tasks.
|
|
91
|
-
After completing this task, UPDATE CLAUDEBOARD_CONTEXT.md with any new decisions, patterns, file structure changes, or naming conventions introduced.
|
|
92
|
-
${retryNote}
|
|
93
|
-
|
|
94
|
-
## Steps
|
|
95
|
-
0. Read CLAUDEBOARD_CONTEXT.md if it exists. Then write a brief implementation plan: which files you will create/modify and how this fits with the done/upcoming tasks above.
|
|
96
|
-
1. Explore the project structure to understand existing patterns
|
|
97
|
-
2. Implement the task completely — follow patterns already established
|
|
98
|
-
3. Install any missing dependencies with: npx expo install <pkg>
|
|
99
|
-
4. If tsconfig.json exists, run: npx tsc --noEmit and fix any errors
|
|
100
|
-
5. Update CLAUDEBOARD_CONTEXT.md with key decisions made
|
|
101
|
-
6. When done, print: TASK_COMPLETE: <summary>`;
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
let toolCallCount = 0;
|
|
105
|
-
let completed = false;
|
|
106
|
-
let summary = "";
|
|
107
|
-
|
|
108
|
-
for await (const message of query({
|
|
109
|
-
prompt,
|
|
110
|
-
options: {
|
|
111
|
-
cwd: projectPath,
|
|
112
|
-
model: "claude-sonnet-4-20250514",
|
|
113
|
-
permissionMode: "bypassPermissions",
|
|
114
|
-
allowedTools: DEVELOPER_TOOLS,
|
|
115
|
-
maxTurns: 80,
|
|
116
|
-
pathToClaudeCodeExecutable: CLAUDE_PATH,
|
|
117
|
-
systemPrompt: {
|
|
118
|
-
type: "preset",
|
|
119
|
-
preset: "claude_code",
|
|
120
|
-
append: DEV_RULES,
|
|
121
|
-
},
|
|
122
|
-
env: buildEnv(),
|
|
123
|
-
},
|
|
124
|
-
})) {
|
|
125
|
-
|
|
126
|
-
// Assistant messages — log tools and text
|
|
127
|
-
if (message.type === "assistant") {
|
|
128
|
-
for (const block of message.message.content) {
|
|
129
|
-
if (block.type === "text" && block.text?.trim()) {
|
|
130
|
-
const text = block.text.trim();
|
|
131
|
-
if (text.includes("TASK_COMPLETE:")) {
|
|
132
|
-
completed = true;
|
|
133
|
-
summary = text.split("TASK_COMPLETE:")[1]?.trim().split("\n")[0] || task.title;
|
|
134
|
-
}
|
|
135
|
-
if (text.length > 20) {
|
|
136
|
-
const preview = text.split("\n")[0].slice(0, 120);
|
|
137
|
-
await addLog(task.id, preview, "progress");
|
|
138
|
-
console.log(` ${preview}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
if (block.type === "tool_use") {
|
|
142
|
-
toolCallCount++;
|
|
143
|
-
const log = formatToolLog(block);
|
|
144
|
-
if (log) {
|
|
145
|
-
await addLog(task.id, log, "progress");
|
|
146
|
-
console.log(` 🔧 ${log}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Result — task finished or errored
|
|
153
|
-
if (message.type === "result") {
|
|
154
|
-
if (message.subtype === "success") {
|
|
155
|
-
if (!completed && message.result?.includes("TASK_COMPLETE:")) {
|
|
156
|
-
completed = true;
|
|
157
|
-
summary = message.result.split("TASK_COMPLETE:")[1]?.trim().split("\n")[0] || task.title;
|
|
158
|
-
}
|
|
159
|
-
const finalSummary = summary || `Implemented: ${task.title}`;
|
|
160
|
-
await completeTask(task.id, `✓ ${finalSummary} (${toolCallCount} tool calls)`);
|
|
161
|
-
console.log(` ✓ Done: ${task.title} — ${toolCallCount} tool calls`);
|
|
162
|
-
return { success: true, summary: finalSummary };
|
|
163
|
-
|
|
164
|
-
} else if (message.subtype === "error_max_turns") {
|
|
165
|
-
if (completed) {
|
|
166
|
-
await completeTask(task.id, `✓ ${summary} (hit turn limit)`);
|
|
167
|
-
return { success: true, summary };
|
|
168
|
-
}
|
|
169
|
-
const err = "Reached max turns (80) — consider breaking this task into smaller pieces";
|
|
170
|
-
await failTask(task.id, err);
|
|
171
|
-
return { success: false, error: err };
|
|
172
|
-
|
|
173
|
-
} else {
|
|
174
|
-
const err = message.result || "Claude Code returned an error";
|
|
175
|
-
await failTask(task.id, err.slice(0, 500));
|
|
176
|
-
return { success: false, error: err };
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// System init — log session info
|
|
181
|
-
if (message.type === "system" && message.subtype === "init") {
|
|
182
|
-
const s = message.session_id?.slice(0, 8) || "?";
|
|
183
|
-
console.log(` 📡 Session ${s} | ${message.tools?.length || 0} tools | ${message.model}`);
|
|
184
|
-
await addLog(task.id, `Session ${s} started`, "start");
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Generator ended without a result message
|
|
189
|
-
if (completed) {
|
|
190
|
-
await completeTask(task.id, `✓ ${summary}`);
|
|
191
|
-
return { success: true, summary };
|
|
192
|
-
}
|
|
193
|
-
const err = "Session ended without result";
|
|
194
|
-
await failTask(task.id, err);
|
|
195
|
-
return { success: false, error: err };
|
|
196
|
-
|
|
197
|
-
} catch (err) {
|
|
198
|
-
const msg = err.message || String(err);
|
|
199
|
-
console.error(` ✗ Error:`, msg.slice(0, 200));
|
|
200
|
-
if (msg.includes("CLINotFoundError") || msg.includes("ENOENT")) {
|
|
201
|
-
const hint = "Claude Code CLI not installed. Run: npm install -g @anthropic-ai/claude-code";
|
|
202
|
-
await failTask(task.id, hint);
|
|
203
|
-
return { success: false, error: hint };
|
|
204
|
-
}
|
|
205
|
-
await failTask(task.id, msg.slice(0, 500));
|
|
206
|
-
return { success: false, error: msg };
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function formatToolLog(block) {
|
|
211
|
-
const { name, input = {} } = block;
|
|
212
|
-
const p = input.file_path || input.path || "";
|
|
213
|
-
switch (name) {
|
|
214
|
-
case "Read": return `Read: ${p}`;
|
|
215
|
-
case "Write": return `Write: ${p}`;
|
|
216
|
-
case "Edit":
|
|
217
|
-
case "MultiEdit": return `Edit: ${p}`;
|
|
218
|
-
case "Bash": return `Run: ${(input.command || "").slice(0, 80)}`;
|
|
219
|
-
case "Glob": return `Glob: ${input.pattern || ""}`;
|
|
220
|
-
case "Grep": return `Grep: "${(input.pattern || "").slice(0, 40)}"`;
|
|
221
|
-
case "TodoWrite": return `Planning...`;
|
|
222
|
-
default: return null;
|
|
223
|
-
}
|
|
224
|
-
}
|