@kendoo.agentdesk/agentdesk 0.9.1 → 0.9.3
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/cli/config.mjs +2 -2
- package/cli/daemon.mjs +23 -6
- package/cli/orchestrator.mjs +20 -5
- package/cli/team.mjs +2 -0
- package/package.json +1 -1
package/cli/config.mjs
CHANGED
|
@@ -75,10 +75,10 @@ export async function loadConfig(dir, opts = {}) {
|
|
|
75
75
|
// Fetch server settings
|
|
76
76
|
const serverConfig = await fetchServerConfig(projectName, apiKey, serverUrl);
|
|
77
77
|
|
|
78
|
-
// Merge: DEFAULTS ←
|
|
78
|
+
// Merge: DEFAULTS ← local ← server (UI is the single source of truth)
|
|
79
79
|
let config = { ...DEFAULTS };
|
|
80
|
-
if (serverConfig) config = deepMerge(config, serverConfig);
|
|
81
80
|
if (localConfig) config = deepMerge(config, localConfig);
|
|
81
|
+
if (serverConfig) config = deepMerge(config, serverConfig);
|
|
82
82
|
|
|
83
83
|
// Auto-sync: if local config exists but server is empty, push local to server
|
|
84
84
|
if (localConfig && !serverConfig && apiKey && serverUrl && projectName) {
|
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, mode }) {
|
|
316
|
+
async function handleStartSession({ sessionId, projectId, taskId: remoteTaskId, prompt, mode }) {
|
|
317
317
|
// Validate project against local allowlist
|
|
318
318
|
const project = projects.find(p => p.id === projectId);
|
|
319
319
|
if (!project) {
|
|
@@ -345,13 +345,23 @@ export async function runDaemon() {
|
|
|
345
345
|
const config = await loadConfig(project.path, { apiKey: projectApiKey, serverUrl: agentdeskServer, projectName: project.name });
|
|
346
346
|
const tracker = config.tracker || (detected.hasLinear ? "linear" : null);
|
|
347
347
|
|
|
348
|
-
//
|
|
349
|
-
const taskId = prompt
|
|
348
|
+
// Use provided task ID or generate from description
|
|
349
|
+
const taskId = remoteTaskId || (prompt
|
|
350
350
|
? prompt.toLowerCase().replace(/[^a-z0-9\s-]/g, "").trim().replace(/\s+/g, "-").slice(0, 40) || `task-${Date.now().toString(36)}`
|
|
351
|
-
: `daemon-${Date.now().toString(36)}
|
|
351
|
+
: `daemon-${Date.now().toString(36)}`);
|
|
352
352
|
|
|
353
353
|
// Build task link
|
|
354
354
|
let taskLink = null;
|
|
355
|
+
if (remoteTaskId) {
|
|
356
|
+
if (tracker === "linear" && config.linear?.workspace) {
|
|
357
|
+
taskLink = `https://linear.app/${config.linear.workspace}/issue/${remoteTaskId}`;
|
|
358
|
+
} else if (tracker === "jira" && config.jira?.baseUrl) {
|
|
359
|
+
taskLink = `${config.jira.baseUrl}/browse/${remoteTaskId}`;
|
|
360
|
+
} else if (tracker === "github") {
|
|
361
|
+
const repo = config.github?.repo || "";
|
|
362
|
+
if (repo) taskLink = `https://github.com/${repo}/issues/${remoteTaskId}`;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
355
365
|
|
|
356
366
|
// Resolve team
|
|
357
367
|
const team = resolveTeam(config);
|
|
@@ -364,15 +374,18 @@ export async function runDaemon() {
|
|
|
364
374
|
const result = await runOrchestrator({
|
|
365
375
|
taskId, taskLink,
|
|
366
376
|
description: prompt || "",
|
|
367
|
-
createTask:
|
|
377
|
+
createTask: !remoteTaskId && !!prompt && !!tracker,
|
|
368
378
|
tracker, config,
|
|
369
379
|
project: detected, team, teamSections,
|
|
370
380
|
inboxUrl, sessionUrl,
|
|
371
381
|
cwd: project.path,
|
|
372
382
|
mode: mode || "full",
|
|
383
|
+
apiKey,
|
|
384
|
+
serverUrl: agentdeskServer,
|
|
373
385
|
onEvent(event) {
|
|
386
|
+
// Skip events after cancellation to prevent double session:end
|
|
387
|
+
if (!activeSession || activeSession.sessionId !== sessionId) return;
|
|
374
388
|
sendBuffered(sessionId, event);
|
|
375
|
-
// Track file paths for metadata logging
|
|
376
389
|
if (event.type === "tool:use" && event.description) {
|
|
377
390
|
const pathMatch = event.description.match(/(?:Reading|Editing|Writing)\s+(.+)/);
|
|
378
391
|
if (pathMatch) filePathsTouched.add(pathMatch[1]);
|
|
@@ -411,8 +424,12 @@ export async function runDaemon() {
|
|
|
411
424
|
function handleCancelSession({ sessionId }) {
|
|
412
425
|
if (activeSession?.sessionId === sessionId) {
|
|
413
426
|
console.log(` ${yellow}Cancelling session${reset} ${dim}${sessionId}${reset}`);
|
|
427
|
+
const duration = `${((Date.now() - activeSession.startedAt) / 1000).toFixed(1)}s`;
|
|
414
428
|
killChild(activeSession.child);
|
|
429
|
+
// Clear active session BEFORE sending session:end — this prevents
|
|
430
|
+
// the orchestrator's onEvent callback from sending a duplicate
|
|
415
431
|
activeSession = null;
|
|
432
|
+
sendBuffered(sessionId, { type: "session:end", duration, steps: 0, inputTokens: 0, outputTokens: 0 });
|
|
416
433
|
}
|
|
417
434
|
}
|
|
418
435
|
|
package/cli/orchestrator.mjs
CHANGED
|
@@ -14,6 +14,19 @@ const CLI_VERSION = JSON.parse(readFileSync(join(__dirname, "../package.json"),
|
|
|
14
14
|
import { buildAgentPrompt, getAgentTools } from "./agent-prompts.mjs";
|
|
15
15
|
import { detectProject, generateContext } from "./detect.mjs";
|
|
16
16
|
|
|
17
|
+
// Fetch decrypted tracker credentials from server
|
|
18
|
+
async function fetchTrackerCredentials(projectName, apiKey, serverUrl) {
|
|
19
|
+
if (!apiKey || !serverUrl || !projectName) return {};
|
|
20
|
+
try {
|
|
21
|
+
const res = await fetch(`${serverUrl}/api/projects/${projectName}/settings/credentials`, {
|
|
22
|
+
headers: { "x-api-key": apiKey },
|
|
23
|
+
signal: AbortSignal.timeout(5000),
|
|
24
|
+
});
|
|
25
|
+
if (res.ok) return await res.json();
|
|
26
|
+
} catch {}
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
function loadDotEnv(dir) {
|
|
18
31
|
const envPath = join(dir, ".env");
|
|
19
32
|
if (!existsSync(envPath)) return {};
|
|
@@ -37,11 +50,11 @@ function timestamp() {
|
|
|
37
50
|
export async function runOrchestrator({
|
|
38
51
|
taskId, taskLink, description, createTask, tracker, config,
|
|
39
52
|
project, team, teamSections, inboxUrl, sessionUrl, cwd,
|
|
40
|
-
onEvent, mode = "full",
|
|
53
|
+
onEvent, mode = "full", apiKey, serverUrl,
|
|
41
54
|
}) {
|
|
42
55
|
// --- Lite mode: single process, legacy behavior ---
|
|
43
56
|
if (mode === "lite") {
|
|
44
|
-
return runLiteMode({ taskId, taskLink, description, createTask, tracker, config, project, teamSections, inboxUrl, sessionUrl, cwd, onEvent });
|
|
57
|
+
return runLiteMode({ taskId, taskLink, description, createTask, tracker, config, project, teamSections, inboxUrl, sessionUrl, cwd, onEvent, apiKey, serverUrl });
|
|
45
58
|
}
|
|
46
59
|
|
|
47
60
|
// --- Full mode: independent sub-agents ---
|
|
@@ -54,7 +67,8 @@ export async function runOrchestrator({
|
|
|
54
67
|
totalSteps: 0,
|
|
55
68
|
};
|
|
56
69
|
|
|
57
|
-
const
|
|
70
|
+
const trackerCreds = await fetchTrackerCredentials(project?.name, apiKey, serverUrl);
|
|
71
|
+
const env = { ...process.env, ...loadDotEnv(cwd), ...trackerCreds };
|
|
58
72
|
|
|
59
73
|
// Emit event to WebSocket (same protocol as single-process mode)
|
|
60
74
|
function emit(event) {
|
|
@@ -303,8 +317,9 @@ export async function runOrchestrator({
|
|
|
303
317
|
|
|
304
318
|
// --- Lite mode: single Claude process with all agents as personas ---
|
|
305
319
|
|
|
306
|
-
async function runLiteMode({ taskId, taskLink, description, createTask, tracker, config, project, teamSections, inboxUrl, sessionUrl, cwd, onEvent }) {
|
|
307
|
-
const
|
|
320
|
+
async function runLiteMode({ taskId, taskLink, description, createTask, tracker, config, project, teamSections, inboxUrl, sessionUrl, cwd, onEvent, apiKey, serverUrl }) {
|
|
321
|
+
const trackerCreds = await fetchTrackerCredentials(project?.name, apiKey, serverUrl);
|
|
322
|
+
const env = { ...process.env, ...loadDotEnv(cwd), ...trackerCreds };
|
|
308
323
|
const startTime = Date.now();
|
|
309
324
|
let totalInputTokens = 0;
|
|
310
325
|
let totalOutputTokens = 0;
|
package/cli/team.mjs
CHANGED