@kendoo.agentdesk/agentdesk 0.9.2 → 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 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 ← serverlocal (local overrides server)
78
+ // Merge: DEFAULTS ← localserver (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
- // Generate task ID
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,7 +374,7 @@ export async function runDaemon() {
364
374
  const result = await runOrchestrator({
365
375
  taskId, taskLink,
366
376
  description: prompt || "",
367
- createTask: false,
377
+ createTask: !remoteTaskId && !!prompt && !!tracker,
368
378
  tracker, config,
369
379
  project: detected, team, teamSections,
370
380
  inboxUrl, sessionUrl,
@@ -373,8 +383,9 @@ export async function runDaemon() {
373
383
  apiKey,
374
384
  serverUrl: agentdeskServer,
375
385
  onEvent(event) {
386
+ // Skip events after cancellation to prevent double session:end
387
+ if (!activeSession || activeSession.sessionId !== sessionId) return;
376
388
  sendBuffered(sessionId, event);
377
- // Track file paths for metadata logging
378
389
  if (event.type === "tool:use" && event.description) {
379
390
  const pathMatch = event.description.match(/(?:Reading|Editing|Writing)\s+(.+)/);
380
391
  if (pathMatch) filePathsTouched.add(pathMatch[1]);
@@ -413,8 +424,12 @@ export async function runDaemon() {
413
424
  function handleCancelSession({ sessionId }) {
414
425
  if (activeSession?.sessionId === sessionId) {
415
426
  console.log(` ${yellow}Cancelling session${reset} ${dim}${sessionId}${reset}`);
427
+ const duration = `${((Date.now() - activeSession.startedAt) / 1000).toFixed(1)}s`;
416
428
  killChild(activeSession.child);
429
+ // Clear active session BEFORE sending session:end — this prevents
430
+ // the orchestrator's onEvent callback from sending a duplicate
417
431
  activeSession = null;
432
+ sendBuffered(sessionId, { type: "session:end", duration, steps: 0, inputTokens: 0, outputTokens: 0 });
418
433
  }
419
434
  }
420
435
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kendoo.agentdesk/agentdesk",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "AI team orchestrator for Claude Code — run collaborative agent sessions from your terminal",
5
5
  "type": "module",
6
6
  "bin": {