@kendoo.agentdesk/agentdesk 0.8.5 → 0.9.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/bin/agentdesk.mjs +2 -0
- package/cli/daemon.mjs +3 -2
- package/cli/orchestrator.mjs +80 -1
- package/cli/team.mjs +15 -111
- package/package.json +1 -1
package/bin/agentdesk.mjs
CHANGED
|
@@ -115,6 +115,8 @@ else if (command === "team") {
|
|
|
115
115
|
cwd = remaining[++i];
|
|
116
116
|
} else if (remaining[i] === "--lite" || remaining[i] === "--legacy") {
|
|
117
117
|
lite = true;
|
|
118
|
+
} else if (remaining[i] === "--full") {
|
|
119
|
+
lite = false;
|
|
118
120
|
} else if (!taskId && !remaining[i].startsWith("-")) {
|
|
119
121
|
taskId = remaining[i];
|
|
120
122
|
}
|
package/cli/daemon.mjs
CHANGED
|
@@ -313,7 +313,7 @@ export async function runDaemon() {
|
|
|
313
313
|
|
|
314
314
|
// 4. Session handling
|
|
315
315
|
|
|
316
|
-
async function handleStartSession({ sessionId, projectId, prompt }) {
|
|
316
|
+
async function handleStartSession({ sessionId, projectId, prompt, mode }) {
|
|
317
317
|
// Validate project against local allowlist
|
|
318
318
|
const project = projects.find(p => p.id === projectId);
|
|
319
319
|
if (!project) {
|
|
@@ -360,7 +360,7 @@ export async function runDaemon() {
|
|
|
360
360
|
const inboxUrl = `${agentdeskServer}/api/sessions/${sessionId}/inbox`;
|
|
361
361
|
const sessionUrl = `${agentdeskServer}/sessions/${sessionId}`;
|
|
362
362
|
|
|
363
|
-
// Run orchestrator
|
|
363
|
+
// Run orchestrator
|
|
364
364
|
const result = await runOrchestrator({
|
|
365
365
|
taskId, taskLink,
|
|
366
366
|
description: prompt || "",
|
|
@@ -369,6 +369,7 @@ export async function runDaemon() {
|
|
|
369
369
|
project: detected, team, teamSections,
|
|
370
370
|
inboxUrl, sessionUrl,
|
|
371
371
|
cwd: project.path,
|
|
372
|
+
mode: mode || "full",
|
|
372
373
|
onEvent(event) {
|
|
373
374
|
sendBuffered(sessionId, event);
|
|
374
375
|
// Track file paths for metadata logging
|
package/cli/orchestrator.mjs
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
// Orchestrator — manages agent sub-sessions across phases
|
|
2
2
|
|
|
3
|
+
import { spawn } from "child_process";
|
|
3
4
|
import { existsSync, readFileSync } from "fs";
|
|
5
|
+
import { createInterface } from "readline";
|
|
4
6
|
import { join, dirname } from "path";
|
|
5
7
|
import { fileURLToPath } from "url";
|
|
6
8
|
import { runAgent } from "./agent-runner.mjs";
|
|
9
|
+
import { buildPrompt } from "./prompt.mjs";
|
|
10
|
+
import { createStreamParser } from "./stream-parser.mjs";
|
|
7
11
|
|
|
8
12
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
13
|
const CLI_VERSION = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8")).version;
|
|
@@ -33,8 +37,14 @@ function timestamp() {
|
|
|
33
37
|
export async function runOrchestrator({
|
|
34
38
|
taskId, taskLink, description, createTask, tracker, config,
|
|
35
39
|
project, team, teamSections, inboxUrl, sessionUrl, cwd,
|
|
36
|
-
onEvent,
|
|
40
|
+
onEvent, mode = "full",
|
|
37
41
|
}) {
|
|
42
|
+
// --- Lite mode: single process, legacy behavior ---
|
|
43
|
+
if (mode === "lite") {
|
|
44
|
+
return runLiteMode({ taskId, taskLink, description, createTask, tracker, config, project, teamSections, inboxUrl, sessionUrl, cwd, onEvent });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// --- Full mode: independent sub-agents ---
|
|
38
48
|
const state = {
|
|
39
49
|
task: { id: taskId, link: taskLink, description: description || "" },
|
|
40
50
|
conversationLog: [], // { type: "message"|"phase", agent?, tag?, message?, phase? }
|
|
@@ -290,3 +300,72 @@ export async function runOrchestrator({
|
|
|
290
300
|
outputTokens: state.totalOutputTokens,
|
|
291
301
|
};
|
|
292
302
|
}
|
|
303
|
+
|
|
304
|
+
// --- Lite mode: single Claude process with all agents as personas ---
|
|
305
|
+
|
|
306
|
+
async function runLiteMode({ taskId, taskLink, description, createTask, tracker, config, project, teamSections, inboxUrl, sessionUrl, cwd, onEvent }) {
|
|
307
|
+
const env = { ...process.env, ...loadDotEnv(cwd) };
|
|
308
|
+
const startTime = Date.now();
|
|
309
|
+
let totalInputTokens = 0;
|
|
310
|
+
let totalOutputTokens = 0;
|
|
311
|
+
let totalSteps = 0;
|
|
312
|
+
|
|
313
|
+
function emit(event) {
|
|
314
|
+
onEvent?.({ ...event, timestamp: timestamp() });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const fullPrompt = buildPrompt({
|
|
318
|
+
taskId, taskLink, description, createTask, tracker, config,
|
|
319
|
+
project, teamSections, inboxUrl, sessionUrl,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
emit({
|
|
323
|
+
type: "session:start",
|
|
324
|
+
taskId, taskLink,
|
|
325
|
+
title: description || taskId,
|
|
326
|
+
project: project?.name || null,
|
|
327
|
+
sessionNumber: 1,
|
|
328
|
+
agents: teamSections.names,
|
|
329
|
+
cliVersion: CLI_VERSION,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
emit({ type: "phase:change", phase: "INTAKE" });
|
|
333
|
+
|
|
334
|
+
const child = spawn(
|
|
335
|
+
"claude",
|
|
336
|
+
["-p", fullPrompt, "--allowedTools", "Bash,Read,Edit,Write,Glob,Grep", "--verbose", "--output-format", "stream-json"],
|
|
337
|
+
{ stdio: ["pipe", "pipe", "inherit"], shell: false, env, cwd }
|
|
338
|
+
);
|
|
339
|
+
child.stdin.end();
|
|
340
|
+
|
|
341
|
+
const { parseLine } = createStreamParser({
|
|
342
|
+
teamNames: teamSections.names,
|
|
343
|
+
callbacks: {
|
|
344
|
+
onPhaseChange({ phase }) { emit({ type: "phase:change", phase }); },
|
|
345
|
+
onAgentMessage({ agent, tag, message }) { emit({ type: "agent:message", agent, tag, message }); },
|
|
346
|
+
onToolUse({ agent, tool, description }) { totalSteps++; emit({ type: "tool:use", agent, tool, description }); },
|
|
347
|
+
onToolResult({ success, summary }) { emit({ type: "tool:result", success, summary }); },
|
|
348
|
+
onSessionUpdate({ taskId: newTaskId, title }) {
|
|
349
|
+
if (newTaskId) emit({ type: "session:update", taskId: newTaskId });
|
|
350
|
+
if (title) emit({ type: "session:update", title });
|
|
351
|
+
},
|
|
352
|
+
onSessionEnd({ duration, steps, inputTokens, outputTokens }) {
|
|
353
|
+
totalInputTokens = inputTokens;
|
|
354
|
+
totalOutputTokens = outputTokens;
|
|
355
|
+
totalSteps = steps;
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
const rl = createInterface({ input: child.stdout });
|
|
361
|
+
for await (const line of rl) {
|
|
362
|
+
parseLine(line);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
await new Promise(resolve => child.on("close", resolve));
|
|
366
|
+
|
|
367
|
+
const duration = `${((Date.now() - startTime) / 1000).toFixed(1)}s`;
|
|
368
|
+
emit({ type: "session:end", duration, steps: totalSteps, inputTokens: totalInputTokens, outputTokens: totalOutputTokens });
|
|
369
|
+
|
|
370
|
+
return { duration, steps: totalSteps, inputTokens: totalInputTokens, outputTokens: totalOutputTokens };
|
|
371
|
+
}
|
package/cli/team.mjs
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
// `agentdesk team <TASK-ID> [--description "..."]` — run a team session
|
|
2
2
|
|
|
3
|
-
import { spawn } from "child_process";
|
|
4
3
|
import { existsSync, readFileSync } from "fs";
|
|
5
|
-
import { createInterface } from "readline";
|
|
6
4
|
import { join, dirname } from "path";
|
|
7
5
|
import { randomUUID } from "crypto";
|
|
8
6
|
import { fileURLToPath } from "url";
|
|
9
|
-
|
|
10
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
const CLI_VERSION = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8")).version;
|
|
12
7
|
import WebSocket from "ws";
|
|
13
8
|
import { detectProject } from "./detect.mjs";
|
|
14
9
|
import { loadConfig } from "./config.mjs";
|
|
15
10
|
import { getStoredApiKey } from "./login.mjs";
|
|
16
11
|
import { resolveTeam, generateTeamPrompt } from "./agents.mjs";
|
|
17
|
-
import { buildPrompt } from "./prompt.mjs";
|
|
18
|
-
import { createStreamParser } from "./stream-parser.mjs";
|
|
19
12
|
import { runOrchestrator } from "./orchestrator.mjs";
|
|
20
13
|
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const CLI_VERSION = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8")).version;
|
|
16
|
+
|
|
21
17
|
function loadDotEnv(dir) {
|
|
22
18
|
const envPath = join(dir, ".env");
|
|
23
19
|
if (!existsSync(envPath)) return {};
|
|
@@ -173,112 +169,20 @@ export async function runTeam(taskId, opts = {}) {
|
|
|
173
169
|
|
|
174
170
|
connectWs();
|
|
175
171
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// --- Sub-agent mode (default) ---
|
|
179
|
-
if (!lite) {
|
|
180
|
-
const result = await runOrchestrator({
|
|
181
|
-
taskId, taskLink, description, createTask, tracker, config,
|
|
182
|
-
project, team, teamSections, inboxUrl, sessionUrl, cwd,
|
|
183
|
-
onEvent: vizSend,
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
console.log(`\n━━━ DONE ━━━`);
|
|
187
|
-
const totalTokens = result.inputTokens + result.outputTokens;
|
|
188
|
-
console.log(` ${result.duration} | ${result.steps} steps${totalTokens ? ` | ${totalTokens.toLocaleString()} tokens` : ""}\n`);
|
|
189
|
-
|
|
190
|
-
setTimeout(() => { try { vizWs?.close(); } catch {} }, 500);
|
|
191
|
-
return 0;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// --- Lite mode (shared conversation) ---
|
|
195
|
-
const fullPrompt = buildPrompt({
|
|
196
|
-
taskId, taskLink, description, createTask, tracker, config, project,
|
|
197
|
-
teamSections, inboxUrl, sessionUrl,
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
const child = spawn(
|
|
201
|
-
"claude",
|
|
202
|
-
[
|
|
203
|
-
"-p", fullPrompt,
|
|
204
|
-
"--allowedTools", "Bash,Read,Edit,Write,Glob,Grep",
|
|
205
|
-
"--verbose",
|
|
206
|
-
"--output-format", "stream-json",
|
|
207
|
-
],
|
|
208
|
-
{
|
|
209
|
-
stdio: ["inherit", "pipe", "inherit"],
|
|
210
|
-
shell: false,
|
|
211
|
-
env: { ...process.env, ...loadDotEnv(cwd) },
|
|
212
|
-
cwd,
|
|
213
|
-
}
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
process.on("SIGINT", () => { try { child.kill(); } catch {} process.exit(1); });
|
|
217
|
-
process.on("SIGTERM", () => { try { child.kill(); } catch {} process.exit(1); });
|
|
218
|
-
|
|
219
|
-
console.log("\n━━━ INTAKE ━━━\n");
|
|
220
|
-
vizSend({ type: "phase:change", phase: "INTAKE" });
|
|
221
|
-
|
|
222
|
-
function timestamp() {
|
|
223
|
-
const d = new Date();
|
|
224
|
-
return [d.getHours(), d.getMinutes(), d.getSeconds()]
|
|
225
|
-
.map(n => String(n).padStart(2, "0")).join(":");
|
|
226
|
-
}
|
|
172
|
+
const agentMode = lite ? "lite" : "full";
|
|
173
|
+
console.log(`Agents: ${agentMode === "lite" ? "lite (shared)" : "full (independent)"}\n`);
|
|
227
174
|
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
vizSend({ type: "phase:change", phase });
|
|
234
|
-
},
|
|
235
|
-
onAgentMessage({ agent, tag, message }) {
|
|
236
|
-
console.log(`${timestamp()} ${agent} [${tag}] ${message}\n`);
|
|
237
|
-
vizSend({ type: "agent:message", agent, tag, message });
|
|
238
|
-
},
|
|
239
|
-
onToolUse({ agent, tool, description }) {
|
|
240
|
-
console.log(` ${agent} [ACT] ${description}`);
|
|
241
|
-
vizSend({ type: "tool:use", agent, tool, description });
|
|
242
|
-
},
|
|
243
|
-
onToolResult({ success, summary }) {
|
|
244
|
-
console.log(` ${success ? "✓" : "✗"} ${summary}`);
|
|
245
|
-
vizSend({ type: "tool:result", success, summary });
|
|
246
|
-
},
|
|
247
|
-
onSessionUpdate({ taskId: newTaskId, title: newTitle }) {
|
|
248
|
-
if (newTitle) {
|
|
249
|
-
vizSend({ type: "session:update", title: newTitle });
|
|
250
|
-
}
|
|
251
|
-
if (newTaskId && createTask) {
|
|
252
|
-
taskId = newTaskId;
|
|
253
|
-
if (tracker === "linear" && config.linear?.workspace) {
|
|
254
|
-
taskLink = `https://linear.app/${config.linear.workspace}/issue/${newTaskId}`;
|
|
255
|
-
} else if (tracker === "jira" && config.jira?.baseUrl) {
|
|
256
|
-
taskLink = `${config.jira.baseUrl}/browse/${newTaskId}`;
|
|
257
|
-
} else if (tracker === "github") {
|
|
258
|
-
const repo = config.github?.repo || "";
|
|
259
|
-
if (repo) taskLink = `https://github.com/${repo}/issues/${newTaskId}`;
|
|
260
|
-
}
|
|
261
|
-
console.log(`\n # Task: ${newTaskId}${taskLink ? ` (${taskLink})` : ""}\n`);
|
|
262
|
-
vizSend({ type: "session:update", taskId: newTaskId, taskLink, title: newTitle || description || newTaskId });
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
onSessionEnd({ duration, steps, inputTokens, outputTokens }) {
|
|
266
|
-
const totalTokens = inputTokens + outputTokens;
|
|
267
|
-
console.log(`\n━━━ DONE ━━━`);
|
|
268
|
-
console.log(` ${duration} | ${steps} steps${totalTokens ? ` | ${totalTokens.toLocaleString()} tokens` : ""}\n`);
|
|
269
|
-
vizSend({ type: "session:end", duration, steps, inputTokens, outputTokens });
|
|
270
|
-
setTimeout(() => { try { vizWs?.close(); } catch {} }, 500);
|
|
271
|
-
},
|
|
272
|
-
},
|
|
175
|
+
const result = await runOrchestrator({
|
|
176
|
+
taskId, taskLink, description, createTask, tracker, config,
|
|
177
|
+
project, team, teamSections, inboxUrl, sessionUrl, cwd,
|
|
178
|
+
onEvent: vizSend,
|
|
179
|
+
mode: agentMode,
|
|
273
180
|
});
|
|
274
181
|
|
|
275
|
-
|
|
182
|
+
console.log(`\n━━━ DONE ━━━`);
|
|
183
|
+
const totalTokens = result.inputTokens + result.outputTokens;
|
|
184
|
+
console.log(` ${result.duration} | ${result.steps} steps${totalTokens ? ` | ${totalTokens.toLocaleString()} tokens` : ""}\n`);
|
|
276
185
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return new Promise(resolve => {
|
|
282
|
-
child.on("close", (code) => resolve(code || 0));
|
|
283
|
-
});
|
|
186
|
+
setTimeout(() => { try { vizWs?.close(); } catch {} }, 500);
|
|
187
|
+
return 0;
|
|
284
188
|
}
|