@adhdev/daemon-core 0.9.77-rc.21 → 0.9.77-rc.23
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/dist/boot/daemon-lifecycle.d.ts +3 -0
- package/dist/index.js +47 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +47 -4
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +2 -7
- package/package.json +1 -1
- package/src/boot/daemon-lifecycle.ts +5 -0
- package/src/mesh/mesh-events.ts +67 -5
|
@@ -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
|
@@ -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
|
package/src/mesh/mesh-events.ts
CHANGED
|
@@ -3,7 +3,20 @@ 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
|
+
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Remote Node Idle Session Tracking
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Tracks remote sessions that emitted 'agent:ready' so triggerMeshQueue
|
|
12
|
+
// can assign tasks to them.
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
interface RemoteIdleSession {
|
|
15
|
+
nodeId: string;
|
|
16
|
+
sessionId: string;
|
|
17
|
+
providerType: string;
|
|
18
|
+
}
|
|
19
|
+
const remoteIdleSessions = new Map<string, RemoteIdleSession>(); // key: `${nodeId}:${sessionId}`
|
|
7
20
|
|
|
8
21
|
// ---------------------------------------------------------------------------
|
|
9
22
|
// MCP coordinator pending-event queue
|
|
@@ -62,7 +75,7 @@ function formatCompletionMetadata(event: Record<string, unknown>): string {
|
|
|
62
75
|
}
|
|
63
76
|
|
|
64
77
|
export function tryAssignQueueTask(
|
|
65
|
-
components:
|
|
78
|
+
components: DaemonComponents,
|
|
66
79
|
meshId: string,
|
|
67
80
|
nodeId: string,
|
|
68
81
|
sessionId: string,
|
|
@@ -74,14 +87,37 @@ export function tryAssignQueueTask(
|
|
|
74
87
|
}
|
|
75
88
|
|
|
76
89
|
LOG.info('MeshQueue', `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
|
|
90
|
+
|
|
91
|
+
// Check if the node is remote
|
|
92
|
+
const mesh = getMesh(meshId);
|
|
93
|
+
const node = mesh?.nodes.find((n: any) => n.id === nodeId);
|
|
77
94
|
|
|
95
|
+
// If the node is explicitly remote and we have a dispatch mechanism, route via P2P
|
|
96
|
+
if (node?.daemonId && components.dispatchMeshCommand) {
|
|
97
|
+
const isLocalNode = components.cliManager.adapters.has(sessionId);
|
|
98
|
+
if (!isLocalNode) {
|
|
99
|
+
components.dispatchMeshCommand(node.daemonId, 'agent_command', {
|
|
100
|
+
targetSessionId: sessionId,
|
|
101
|
+
cliType: providerType,
|
|
102
|
+
action: 'send_chat',
|
|
103
|
+
message: task.message,
|
|
104
|
+
}).catch((e: any) => {
|
|
105
|
+
LOG.error('MeshQueue', `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
|
|
106
|
+
updateTaskStatus(meshId, task.id, 'failed');
|
|
107
|
+
});
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Local routing
|
|
78
113
|
components.cliManager.handleCliCommand('agent_command', {
|
|
79
114
|
targetSessionId: sessionId,
|
|
80
115
|
cliType: providerType,
|
|
81
116
|
action: 'send_chat',
|
|
82
117
|
message: task.message,
|
|
83
118
|
}).catch((e: any) => {
|
|
84
|
-
LOG.error('MeshQueue', `Failed to dispatch task to node ${nodeId}: ${e?.message}`);
|
|
119
|
+
LOG.error('MeshQueue', `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
|
|
120
|
+
updateTaskStatus(meshId, task.id, 'failed');
|
|
85
121
|
});
|
|
86
122
|
|
|
87
123
|
return true;
|
|
@@ -91,7 +127,7 @@ export function tryAssignQueueTask(
|
|
|
91
127
|
* Triggers a queue check for all nodes in the mesh.
|
|
92
128
|
* Called when a new task is enqueued, in case nodes are already idle.
|
|
93
129
|
*/
|
|
94
|
-
export function triggerMeshQueue(components:
|
|
130
|
+
export function triggerMeshQueue(components: DaemonComponents, meshId: string) {
|
|
95
131
|
const mesh = getMesh(meshId);
|
|
96
132
|
if (!mesh) return;
|
|
97
133
|
|
|
@@ -118,6 +154,18 @@ export function triggerMeshQueue(components: { instanceManager: any; cliManager:
|
|
|
118
154
|
tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType);
|
|
119
155
|
}
|
|
120
156
|
}
|
|
157
|
+
|
|
158
|
+
// Also check known idle remote sessions
|
|
159
|
+
for (const [key, idle] of remoteIdleSessions.entries()) {
|
|
160
|
+
// Find if this node is in the same mesh
|
|
161
|
+
const node = mesh.nodes.find((n: any) => n.id === idle.nodeId);
|
|
162
|
+
if (node) {
|
|
163
|
+
const assigned = tryAssignQueueTask(components, meshId, idle.nodeId, idle.sessionId, idle.providerType);
|
|
164
|
+
if (assigned) {
|
|
165
|
+
remoteIdleSessions.delete(key);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
121
169
|
}
|
|
122
170
|
|
|
123
171
|
function buildMeshSystemMessage(args: {
|
|
@@ -193,12 +241,26 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
|
|
|
193
241
|
const providerType = readNonEmptyString(args.metadataEvent.providerType);
|
|
194
242
|
|
|
195
243
|
if (sessionId && nodeId && providerType) {
|
|
244
|
+
remoteIdleSessions.set(`${nodeId}:${sessionId}`, { nodeId, sessionId, providerType });
|
|
196
245
|
setTimeout(() => {
|
|
197
|
-
tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
246
|
+
const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
247
|
+
if (assigned) {
|
|
248
|
+
remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
|
|
249
|
+
}
|
|
198
250
|
}, 500);
|
|
199
251
|
}
|
|
252
|
+
} else if (args.event === 'agent:generating_started') {
|
|
253
|
+
const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
|
|
254
|
+
const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
|
|
255
|
+
if (sessionId && nodeId) {
|
|
256
|
+
remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
|
|
257
|
+
}
|
|
200
258
|
} else if (args.event === 'agent:stopped') {
|
|
201
259
|
const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
|
|
260
|
+
const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
|
|
261
|
+
if (sessionId && nodeId) {
|
|
262
|
+
remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
|
|
263
|
+
}
|
|
202
264
|
if (sessionId) {
|
|
203
265
|
updateSessionTaskStatus(args.meshId, sessionId, 'failed');
|
|
204
266
|
}
|