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.
@@ -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
- }