@adhdev/daemon-core 0.9.77-rc.31 → 0.9.77-rc.32

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.77-rc.31",
3
+ "version": "0.9.77-rc.32",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1331,6 +1331,21 @@ export class DaemonCommandRouter {
1331
1331
  }
1332
1332
  }
1333
1333
 
1334
+ case 'get_mesh_queue': {
1335
+ const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
1336
+ if (!meshId) return { success: false, error: 'meshId required' };
1337
+ try {
1338
+ const { getQueue } = await import('../mesh/mesh-work-queue.js');
1339
+ const status = Array.isArray(args?.status)
1340
+ ? args.status.map((s: any) => typeof s === 'string' ? s.trim() : '').filter(Boolean)
1341
+ : undefined;
1342
+ const queue = getQueue(meshId, { status: status as any });
1343
+ return { success: true, queue };
1344
+ } catch (e: any) {
1345
+ return { success: false, error: e.message };
1346
+ }
1347
+ }
1348
+
1334
1349
  case 'add_mesh_node': {
1335
1350
  const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
1336
1351
  const workspace = typeof args?.workspace === 'string' ? args.workspace.trim() : '';
@@ -46,7 +46,15 @@ function readNonEmptyString(value: unknown): string {
46
46
  return typeof value === 'string' && value.trim() ? value.trim() : '';
47
47
  }
48
48
 
49
+ function resolveEventSessionId(event: Record<string, unknown>, fallback?: unknown): string {
50
+ return readNonEmptyString(event.targetSessionId)
51
+ || readNonEmptyString(event.sessionId)
52
+ || readNonEmptyString(event.instanceId)
53
+ || readNonEmptyString(fallback);
54
+ }
55
+
49
56
  const MESH_COORDINATOR_EVENTS = new Set([
57
+ 'agent:generating_started',
50
58
  'agent:generating_completed',
51
59
  'agent:waiting_approval',
52
60
  'agent:stopped',
@@ -229,7 +237,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
229
237
  }) {
230
238
  // ── Task Queue & Ledger ──
231
239
  if (args.event === 'agent:generating_completed') {
232
- const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
240
+ const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
233
241
  const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
234
242
  const providerType = readNonEmptyString(args.metadataEvent.providerType);
235
243
 
@@ -243,9 +251,31 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
243
251
  }
244
252
  }
245
253
  } else if (args.event === 'agent:ready') {
246
- const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
254
+ const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
247
255
  const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
248
256
  const providerType = readNonEmptyString(args.metadataEvent.providerType);
257
+ const completedTask = sessionId
258
+ ? updateSessionTaskStatus(args.meshId, sessionId, 'completed')
259
+ : null;
260
+ if (completedTask) {
261
+ try {
262
+ appendLedgerEntry(args.meshId, {
263
+ kind: 'task_completed',
264
+ nodeId: nodeId || undefined,
265
+ sessionId,
266
+ providerType: providerType || undefined,
267
+ payload: {
268
+ event: args.event,
269
+ nodeLabel: args.nodeLabel,
270
+ taskId: completedTask.id,
271
+ completedViaReady: true,
272
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
273
+ },
274
+ });
275
+ } catch (e: any) {
276
+ LOG.warn('MeshLedger', `Failed to record task_completed from ready: ${e?.message || e}`);
277
+ }
278
+ }
249
279
 
250
280
  if (sessionId && nodeId && providerType) {
251
281
  remoteIdleSessions.set(`${nodeId}:${sessionId}`, { nodeId, sessionId, providerType });
@@ -257,13 +287,13 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
257
287
  }, 500);
258
288
  }
259
289
  } else if (args.event === 'agent:generating_started') {
260
- const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
290
+ const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
261
291
  const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
262
292
  if (sessionId && nodeId) {
263
293
  remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
264
294
  }
265
295
  } else if (args.event === 'agent:stopped') {
266
- const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
296
+ const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
267
297
  const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
268
298
  if (sessionId && nodeId) {
269
299
  remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
@@ -279,7 +309,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
279
309
  appendLedgerEntry(args.meshId, {
280
310
  kind: ledgerKind,
281
311
  nodeId: readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || undefined,
282
- sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || undefined,
312
+ sessionId: resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || undefined,
283
313
  providerType: readNonEmptyString(args.metadataEvent.providerType) || undefined,
284
314
  payload: {
285
315
  event: args.event,
@@ -301,7 +331,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
301
331
  const maxRetries = mesh?.policy?.maxTaskRetries ?? 1;
302
332
 
303
333
  recoveryContext = getSessionRecoveryContext(args.meshId, {
304
- sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || undefined,
334
+ sessionId: resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || undefined,
305
335
  nodeId: readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || undefined,
306
336
  maxRetries,
307
337
  });
@@ -414,7 +444,7 @@ export function handleMeshForwardEvent(components: DaemonComponents, payload: Re
414
444
  nodeLabel,
415
445
  event: eventName,
416
446
  metadataEvent: {
417
- targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId),
447
+ targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId) || readNonEmptyString(payload.instanceId),
418
448
  providerType: readNonEmptyString(payload.providerType),
419
449
  providerSessionId: readNonEmptyString(payload.providerSessionId),
420
450
  },
@@ -84,6 +84,14 @@ export function getQueue(meshId: string, opts?: { status?: MeshTaskStatus[] }):
84
84
  */
85
85
  export function claimNextTask(meshId: string, nodeId: string, sessionId: string): MeshWorkQueueEntry | null {
86
86
  const queue = readQueue(meshId);
87
+
88
+ // A worker must finish or fail its current queued assignment before it can
89
+ // claim another one. maxParallelTasks limits total mesh concurrency; it is
90
+ // not permission for one node/session to accumulate multiple assigned items.
91
+ const hasActiveAssignment = queue.some(q => q.status === 'assigned' && (
92
+ q.assignedSessionId === sessionId || q.assignedNodeId === nodeId
93
+ ));
94
+ if (hasActiveAssignment) return null;
87
95
 
88
96
  // Find highest priority task:
89
97
  // 1. Pending tasks explicitly targeted at this runtime session