@adhdev/daemon-core 0.9.77-rc.20 → 0.9.77-rc.22

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.
@@ -8,17 +8,12 @@ export interface PendingMeshCoordinatorEvent {
8
8
  }
9
9
  /** Drain and return all pending coordinator events, clearing the queue. */
10
10
  export declare function drainPendingMeshCoordinatorEvents(): PendingMeshCoordinatorEvent[];
11
- export declare function tryAssignQueueTask(components: {
12
- cliManager: any;
13
- }, meshId: string, nodeId: string, sessionId: string, providerType: string): boolean;
11
+ export declare function tryAssignQueueTask(components: DaemonComponents, meshId: string, nodeId: string, sessionId: string, providerType: string): boolean;
14
12
  /**
15
13
  * Triggers a queue check for all nodes in the mesh.
16
14
  * Called when a new task is enqueued, in case nodes are already idle.
17
15
  */
18
- export declare function triggerMeshQueue(components: {
19
- instanceManager: any;
20
- cliManager: any;
21
- }, meshId: string): void;
16
+ export declare function triggerMeshQueue(components: DaemonComponents, meshId: string): void;
22
17
  export declare function handleMeshForwardEvent(components: DaemonComponents, payload: Record<string, unknown>): {
23
18
  success: boolean;
24
19
  forwarded: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.77-rc.20",
3
+ "version": "0.9.77-rc.22",
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",
@@ -83,6 +83,9 @@ export interface DaemonInitConfig {
83
83
 
84
84
  /** Fired before send_chat is dispatched — used for turn snapshot hooks */
85
85
  onBeforeSendChat?: (params: { workspace: string; sessionId: string }) => void;
86
+
87
+ /** Relays a command to a remote mesh node daemon */
88
+ dispatchMeshCommand?: (daemonId: string, command: string, args: Record<string, unknown>) => Promise<any>;
86
89
  }
87
90
 
88
91
  // ─── Result ───
@@ -100,6 +103,7 @@ export interface DaemonComponents {
100
103
  sessionRegistry: SessionRegistry;
101
104
  detectedIdes: { value: IDEInfo[] };
102
105
  refreshProviderAvailability: (providerType?: string) => Promise<void>;
106
+ dispatchMeshCommand?: (daemonId: string, command: string, args: Record<string, unknown>) => Promise<any>;
103
107
  }
104
108
 
105
109
  export interface DaemonDevSupportOptions {
@@ -331,6 +335,7 @@ export async function initDaemonComponents(config: DaemonInitConfig): Promise<Da
331
335
  sessionRegistry,
332
336
  detectedIdes: detectedIdesRef,
333
337
  refreshProviderAvailability,
338
+ dispatchMeshCommand: config.dispatchMeshCommand,
334
339
  };
335
340
 
336
341
  // 11. Setup Mesh Event Forwarding
@@ -3,7 +3,7 @@ import { getMesh, getMeshByRepo } from '../config/mesh-config.js';
3
3
  import { LOG } from '../logging/logger.js';
4
4
  import { appendLedgerEntry, getSessionRecoveryContext } from './mesh-ledger.js';
5
5
  import type { MeshLedgerKind, SessionRecoveryContext } from './mesh-ledger.js';
6
- import { claimNextTask, updateSessionTaskStatus, enqueueTask } from './mesh-work-queue.js';
6
+ import { claimNextTask, updateSessionTaskStatus, enqueueTask, updateTaskStatus } from './mesh-work-queue.js';
7
7
 
8
8
  // ---------------------------------------------------------------------------
9
9
  // MCP coordinator pending-event queue
@@ -62,24 +62,49 @@ function formatCompletionMetadata(event: Record<string, unknown>): string {
62
62
  }
63
63
 
64
64
  export function tryAssignQueueTask(
65
- components: { cliManager: any },
65
+ components: DaemonComponents,
66
66
  meshId: string,
67
67
  nodeId: string,
68
68
  sessionId: string,
69
69
  providerType: string
70
70
  ): boolean {
71
71
  const task = claimNextTask(meshId, nodeId, sessionId);
72
- if (!task) return false;
72
+ if (!task) {
73
+ return false;
74
+ }
73
75
 
74
76
  LOG.info('MeshQueue', `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
77
+
78
+ // Check if the node is remote
79
+ const mesh = getMesh(meshId);
80
+ const node = mesh?.nodes.find((n: any) => n.id === nodeId);
75
81
 
82
+ // If the node is explicitly remote and we have a dispatch mechanism, route via P2P
83
+ if (node?.daemonId && components.dispatchMeshCommand) {
84
+ const isLocalNode = components.cliManager.adapters.has(sessionId);
85
+ if (!isLocalNode) {
86
+ components.dispatchMeshCommand(node.daemonId, 'agent_command', {
87
+ targetSessionId: sessionId,
88
+ cliType: providerType,
89
+ action: 'send_chat',
90
+ message: task.message,
91
+ }).catch((e: any) => {
92
+ LOG.error('MeshQueue', `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
93
+ updateTaskStatus(meshId, task.id, 'failed');
94
+ });
95
+ return true;
96
+ }
97
+ }
98
+
99
+ // Local routing
76
100
  components.cliManager.handleCliCommand('agent_command', {
77
101
  targetSessionId: sessionId,
78
102
  cliType: providerType,
79
103
  action: 'send_chat',
80
104
  message: task.message,
81
105
  }).catch((e: any) => {
82
- LOG.error('MeshQueue', `Failed to dispatch task to node ${nodeId}: ${e?.message}`);
106
+ LOG.error('MeshQueue', `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
107
+ updateTaskStatus(meshId, task.id, 'failed');
83
108
  });
84
109
 
85
110
  return true;
@@ -89,7 +114,7 @@ export function tryAssignQueueTask(
89
114
  * Triggers a queue check for all nodes in the mesh.
90
115
  * Called when a new task is enqueued, in case nodes are already idle.
91
116
  */
92
- export function triggerMeshQueue(components: { instanceManager: any; cliManager: any }, meshId: string) {
117
+ export function triggerMeshQueue(components: DaemonComponents, meshId: string) {
93
118
  const mesh = getMesh(meshId);
94
119
  if (!mesh) return;
95
120
 
@@ -165,6 +190,7 @@ function buildMeshSystemMessage(args: {
165
190
  function injectMeshSystemMessage(components: DaemonComponents, args: {
166
191
  meshId: string;
167
192
  sourceInstanceId?: string;
193
+ nodeId?: string;
168
194
  nodeLabel: string;
169
195
  event: string;
170
196
  metadataEvent: Record<string, unknown>;
@@ -172,7 +198,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
172
198
  // ── Task Queue & Ledger ──
173
199
  if (args.event === 'agent:generating_completed') {
174
200
  const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
175
- const nodeId = readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
201
+ const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
176
202
  const providerType = readNonEmptyString(args.metadataEvent.providerType);
177
203
 
178
204
  if (sessionId) {
@@ -186,7 +212,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
186
212
  }
187
213
  } else if (args.event === 'agent:ready') {
188
214
  const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
189
- const nodeId = readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
215
+ const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
190
216
  const providerType = readNonEmptyString(args.metadataEvent.providerType);
191
217
 
192
218
  if (sessionId && nodeId && providerType) {
@@ -206,7 +232,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
206
232
  try {
207
233
  appendLedgerEntry(args.meshId, {
208
234
  kind: ledgerKind,
209
- nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || undefined,
235
+ nodeId: readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || undefined,
210
236
  sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || undefined,
211
237
  providerType: readNonEmptyString(args.metadataEvent.providerType) || undefined,
212
238
  payload: {
@@ -230,7 +256,7 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
230
256
 
231
257
  recoveryContext = getSessionRecoveryContext(args.meshId, {
232
258
  sessionId: readNonEmptyString(args.metadataEvent.targetSessionId) || undefined,
233
- nodeId: readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || undefined,
259
+ nodeId: readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || undefined,
234
260
  maxRetries,
235
261
  });
236
262
  recoveryContext.failedProviderType = readNonEmptyString(args.metadataEvent.providerType) || null;
@@ -338,6 +364,7 @@ export function handleMeshForwardEvent(components: DaemonComponents, payload: Re
338
364
  const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : 'Remote agent';
339
365
  return injectMeshSystemMessage(components, {
340
366
  meshId,
367
+ nodeId,
341
368
  nodeLabel,
342
369
  event: eventName,
343
370
  metadataEvent: {
@@ -385,6 +412,7 @@ export function setupMeshEventForwarding(components: DaemonComponents) {
385
412
  // Determine node label. Inline/cloud meshes may be unavailable here, so preserve runtime node id.
386
413
  const targetNode = mesh?.nodes?.find((n: any) => n.workspace === workspace);
387
414
  const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
415
+ const resolvedNodeId = targetNode?.id || runtimeNodeId;
388
416
  const nodeLabel = targetNode
389
417
  ? `Node '${targetNode.id}'`
390
418
  : runtimeNodeId
@@ -394,6 +422,7 @@ export function setupMeshEventForwarding(components: DaemonComponents) {
394
422
  injectMeshSystemMessage(components, {
395
423
  meshId,
396
424
  sourceInstanceId: instanceId,
425
+ nodeId: resolvedNodeId,
397
426
  nodeLabel,
398
427
  event: event.event,
399
428
  metadataEvent: event,