@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 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 (sub-agent mode)
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
@@ -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
- console.log(`Agents: ${lite ? "lite (shared)" : "full (independent)"}\n`);
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 { parseLine } = createStreamParser({
229
- teamNames: teamSections.names,
230
- callbacks: {
231
- onPhaseChange({ phase }) {
232
- console.log(`\n━━━ ${phase} ━━━\n`);
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
- const rl = createInterface({ input: child.stdout });
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
- for await (const line of rl) {
278
- parseLine(line);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kendoo.agentdesk/agentdesk",
3
- "version": "0.8.5",
3
+ "version": "0.9.0",
4
4
  "description": "AI team orchestrator for Claude Code — run collaborative agent sessions from your terminal",
5
5
  "type": "module",
6
6
  "bin": {