@adhdev/daemon-core 0.9.82-rc.58 → 0.9.82-rc.59

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.
@@ -0,0 +1,48 @@
1
+ import type { MeshLedgerEntry } from './mesh-ledger.js';
2
+ import type { MeshWorkQueueEntry } from './mesh-work-queue.js';
3
+ export type MeshActiveWorkSource = 'queue' | 'direct';
4
+ export type MeshActiveWorkStatus = 'pending' | 'assigned' | 'generating' | 'idle' | 'failed' | 'awaiting_approval';
5
+ export interface MeshActiveWorkRecord {
6
+ taskId: string;
7
+ source: MeshActiveWorkSource;
8
+ status: MeshActiveWorkStatus;
9
+ nodeId?: string;
10
+ sessionId?: string;
11
+ providerType?: string;
12
+ taskTitle: string;
13
+ taskSummary: string;
14
+ message?: string;
15
+ taskMode?: string;
16
+ createdAt: string;
17
+ updatedAt: string;
18
+ dispatchedAt?: string;
19
+ elapsedMs: number;
20
+ terminal?: boolean;
21
+ terminalKind?: string;
22
+ terminalAt?: string;
23
+ }
24
+ export interface MeshActiveWorkSummary {
25
+ totalActiveCount: number;
26
+ queueActiveCount: number;
27
+ directActiveCount: number;
28
+ awaitingApprovalCount: number;
29
+ generatingCount: number;
30
+ failedCount: number;
31
+ idleCount: number;
32
+ sourceCounts: Record<MeshActiveWorkSource, number>;
33
+ statusCounts: Record<MeshActiveWorkStatus, number>;
34
+ }
35
+ export interface BuildMeshActiveWorkOptions {
36
+ meshId: string;
37
+ queue?: MeshWorkQueueEntry[];
38
+ ledgerEntries?: MeshLedgerEntry[];
39
+ nodes?: any[];
40
+ now?: number;
41
+ /** Include terminal direct rows (idle/failed) for handoff/recent-work surfaces. Defaults false. */
42
+ includeTerminalDirect?: boolean;
43
+ }
44
+ export declare function buildMeshActiveWorkSummary(activeWork: MeshActiveWorkRecord[]): MeshActiveWorkSummary;
45
+ export declare function buildMeshActiveWork(opts: BuildMeshActiveWorkOptions): {
46
+ activeWork: MeshActiveWorkRecord[];
47
+ summary: MeshActiveWorkSummary;
48
+ };
@@ -25,6 +25,40 @@ export interface MeshLedgerEntry {
25
25
  payload: Record<string, unknown>;
26
26
  }
27
27
  export declare function isIntentionalCleanupStopEntry(entry: Pick<MeshLedgerEntry, 'kind' | 'payload'>): boolean;
28
+ export type MeshWorkerResultStatus = 'completed' | 'failed' | 'blocked' | 'partial' | 'unknown';
29
+ export type MeshProcessArtifactKind = 'process' | 'log' | 'port' | 'window' | 'session' | 'file' | 'url' | 'other';
30
+ export interface MeshValidationResultArtifact {
31
+ command?: string;
32
+ status: 'passed' | 'failed' | 'skipped' | 'unknown';
33
+ durationMs?: number;
34
+ outputPath?: string;
35
+ summary?: string;
36
+ }
37
+ export interface MeshProcessArtifact {
38
+ kind: MeshProcessArtifactKind;
39
+ id?: string;
40
+ label?: string;
41
+ locator?: string;
42
+ pid?: number;
43
+ port?: number;
44
+ url?: string;
45
+ path?: string;
46
+ sessionId?: string;
47
+ keepRunning?: boolean;
48
+ metadata?: Record<string, unknown>;
49
+ }
50
+ export interface MeshWorkerResultArtifact {
51
+ status: MeshWorkerResultStatus;
52
+ classification?: string;
53
+ changedFiles: string[];
54
+ validationResults: MeshValidationResultArtifact[];
55
+ gitStatus?: Record<string, unknown>;
56
+ processArtifacts: MeshProcessArtifact[];
57
+ errors: string[];
58
+ nextAction?: string;
59
+ requiresUserAction: boolean;
60
+ source: 'explicit_metadata' | 'final_summary_json' | 'default';
61
+ }
28
62
  export interface MeshTaskCompletionEvidence {
29
63
  source: 'agent_status_event';
30
64
  event: 'agent:generating_completed' | 'agent:ready';
@@ -38,6 +72,7 @@ export interface MeshTaskCompletionEvidence {
38
72
  providerSessionId?: string;
39
73
  finalSummaryAvailable: boolean;
40
74
  };
75
+ workerResult: MeshWorkerResultArtifact;
41
76
  git: {
42
77
  status: 'deferred';
43
78
  reason: string;
@@ -59,6 +94,7 @@ export interface BuildTaskCompletionEvidenceOptions {
59
94
  providerType?: string;
60
95
  providerSessionId?: string;
61
96
  finalSummary?: string;
97
+ workerResult?: Record<string, unknown>;
62
98
  completedAt?: string;
63
99
  }
64
100
  export interface MeshLedgerSummary {
@@ -115,6 +151,7 @@ export interface AppendRemoteLedgerResult {
115
151
  }
116
152
  export declare const MAX_LEDGER_SLICE_LIMIT = 500;
117
153
  export declare function getLedgerDir(): string;
154
+ export declare function normalizeMeshWorkerResult(input?: Record<string, unknown>, source?: MeshWorkerResultArtifact['source']): MeshWorkerResultArtifact;
118
155
  export declare function buildTaskCompletionEvidence(opts: BuildTaskCompletionEvidenceOptions): MeshTaskCompletionEvidence;
119
156
  /**
120
157
  * Append a new entry to the mesh ledger.
@@ -2,13 +2,24 @@ import type { RepoMeshDaemonRole } from '../repo-mesh-types.js';
2
2
  export type MeshTaskStatus = 'pending' | 'assigned' | 'completed' | 'failed' | 'cancelled';
3
3
  export type MeshActiveTaskStatus = Extract<MeshTaskStatus, 'pending' | 'assigned'>;
4
4
  export type MeshHistoricalTaskStatus = Extract<MeshTaskStatus, 'completed' | 'failed' | 'cancelled'>;
5
+ export type MeshTaskMode = 'code_change' | 'validation' | 'live_debug_readonly' | 'launch_app' | 'convergence';
5
6
  export declare const ACTIVE_MESH_QUEUE_STATUSES: MeshActiveTaskStatus[];
6
7
  export declare const HISTORICAL_MESH_QUEUE_STATUSES: MeshHistoricalTaskStatus[];
8
+ export declare const MESH_TASK_MODES: MeshTaskMode[];
9
+ export interface MeshTaskModeValidationResult {
10
+ valid: boolean;
11
+ taskMode?: MeshTaskMode;
12
+ violations: string[];
13
+ allowedOperations?: string[];
14
+ }
15
+ export declare function normalizeMeshTaskMode(value: unknown): MeshTaskMode | undefined;
16
+ export declare function validateMeshTaskModeRequest(mode: unknown, message: string): MeshTaskModeValidationResult;
7
17
  export interface MeshWorkQueueEntry {
8
18
  id: string;
9
19
  meshId: string;
10
20
  message: string;
11
21
  status: MeshTaskStatus;
22
+ taskMode?: MeshTaskMode;
12
23
  /** If specified, only this node can claim the task (used by legacy mesh_send_task) */
13
24
  targetNodeId?: string;
14
25
  /** If specified, only this runtime session can claim the task */
@@ -47,6 +58,7 @@ export interface MeshQueueMutationOptions {
47
58
  export declare function enqueueTask(meshId: string, message: string, opts?: {
48
59
  targetNodeId?: string;
49
60
  targetSessionId?: string;
61
+ taskMode?: MeshTaskMode | string;
50
62
  } & MeshQueueMutationOptions): MeshWorkQueueEntry;
51
63
  /**
52
64
  * Get all tasks in the queue, optionally filtered by status.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.58",
3
+ "version": "0.9.82-rc.59",
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",
@@ -460,6 +460,11 @@ function reconcileInlineMeshCache(cached: any, incoming: any): any {
460
460
  const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
461
461
  if (!cachedNodes.length || !incomingNodes.length) return { ...cached, ...incoming };
462
462
 
463
+ const cachedUpdatedAt = Date.parse(readStringValue(cached.updatedAt, cached.updated_at) || '');
464
+ const incomingUpdatedAt = Date.parse(readStringValue(incoming.updatedAt, incoming.updated_at) || '');
465
+ const preserveCachedMembership = Number.isFinite(cachedUpdatedAt)
466
+ && (!Number.isFinite(incomingUpdatedAt) || cachedUpdatedAt > incomingUpdatedAt);
467
+
463
468
  const cachedById = new Map<string, any>();
464
469
  for (const node of cachedNodes) {
465
470
  const nodeId = readInlineMeshNodeId(node);
@@ -469,12 +474,13 @@ function reconcileInlineMeshCache(cached: any, incoming: any): any {
469
474
  const nodes = incomingNodes.map((incomingNode: any) => {
470
475
  const nodeId = readInlineMeshNodeId(incomingNode);
471
476
  const cachedNode = nodeId ? cachedById.get(nodeId) : undefined;
477
+ if (!cachedNode && preserveCachedMembership) return null;
472
478
  if (!cachedNode) return incomingNode;
473
479
  if (hasInlineMeshTransientNodeState(incomingNode)) {
474
480
  return { ...cachedNode, ...incomingNode };
475
481
  }
476
482
  return { ...stripInlineMeshTransientNodeState(cachedNode), ...incomingNode };
477
- });
483
+ }).filter(Boolean);
478
484
 
479
485
  return {
480
486
  ...cached,
package/src/index.ts CHANGED
@@ -178,16 +178,18 @@ export { syncMeshes } from './mesh/mesh-sync.js';
178
178
  export type { MeshSyncTransport, MeshSyncResult, RemoteMeshRecord } from './mesh/mesh-sync.js';
179
179
 
180
180
  // ── Mesh Task Ledger ──
181
- export { appendLedgerEntry, appendRemoteLedgerEntries, readLedgerEntries, readLedgerSlice, getLedgerSummary, getLedgerDir, getSessionRecoveryContext, MAX_LEDGER_SLICE_LIMIT } from './mesh/mesh-ledger.js';
182
- export type { AppendRemoteLedgerResult, MeshLedgerEntry, MeshLedgerKind, MeshLedgerSlice, MeshLedgerSummary, ReadLedgerOptions, ReadLedgerSliceOptions, SessionRecoveryContext } from './mesh/mesh-ledger.js';
181
+ export { appendLedgerEntry, appendRemoteLedgerEntries, buildTaskCompletionEvidence, normalizeMeshWorkerResult, readLedgerEntries, readLedgerSlice, getLedgerSummary, getLedgerDir, getSessionRecoveryContext, MAX_LEDGER_SLICE_LIMIT } from './mesh/mesh-ledger.js';
182
+ export type { AppendRemoteLedgerResult, MeshLedgerEntry, MeshLedgerKind, MeshLedgerSlice, MeshLedgerSummary, ReadLedgerOptions, ReadLedgerSliceOptions, SessionRecoveryContext, MeshTaskCompletionEvidence, MeshWorkerResultArtifact, MeshProcessArtifact, MeshValidationResultArtifact } from './mesh/mesh-ledger.js';
183
183
  export { fastForwardMeshNode } from './mesh/mesh-fast-forward.js';
184
184
  export type { MeshFastForwardNodeArgs, MeshFastForwardPlannedStep, MeshFastForwardResult } from './mesh/mesh-fast-forward.js';
185
185
  export { buildMeshLedgerReconciliationEvidence, buildMeshLedgerReplicaEvidence } from './mesh/mesh-ledger-reconciliation.js';
186
186
  export type { MeshLedgerReconciliationEvidence, MeshLedgerReplicaEvidence, MeshLedgerReplicaStatus } from './mesh/mesh-ledger-reconciliation.js';
187
187
 
188
188
  // ── Mesh Work Queue (GUPP) ──
189
- export { enqueueTask, getQueue, claimNextTask, updateTaskStatus, updateSessionTaskStatus, cancelTask, requeueTask, getMeshQueueStats } from './mesh/mesh-work-queue.js';
190
- export type { MeshWorkQueueEntry, MeshTaskStatus, MeshWorkQueueStats, MeshQueueMutationOptions } from './mesh/mesh-work-queue.js';
189
+ export { enqueueTask, getQueue, claimNextTask, updateTaskStatus, updateSessionTaskStatus, cancelTask, requeueTask, getMeshQueueStats, normalizeMeshTaskMode, validateMeshTaskModeRequest } from './mesh/mesh-work-queue.js';
190
+ export type { MeshWorkQueueEntry, MeshTaskStatus, MeshTaskMode, MeshWorkQueueStats, MeshQueueMutationOptions, MeshTaskModeValidationResult } from './mesh/mesh-work-queue.js';
191
+ export { buildMeshActiveWork, buildMeshActiveWorkSummary } from './mesh/mesh-active-work.js';
192
+ export type { MeshActiveWorkRecord, MeshActiveWorkStatus, MeshActiveWorkSummary, MeshActiveWorkSource } from './mesh/mesh-active-work.js';
191
193
 
192
194
  // ── Mesh Host Ownership ──
193
195
  export { buildMeshHostRequiredFailure, createDefaultMeshHostMetadata, isMeshHostOwner, normalizeMeshDaemonRole, requireMeshHostQueueOwner, resolveMeshHostStatus } from './mesh/mesh-host-ownership.js';
@@ -0,0 +1,205 @@
1
+ import type { MeshLedgerEntry } from './mesh-ledger.js';
2
+ import type { MeshWorkQueueEntry } from './mesh-work-queue.js';
3
+
4
+ export type MeshActiveWorkSource = 'queue' | 'direct';
5
+ export type MeshActiveWorkStatus = 'pending' | 'assigned' | 'generating' | 'idle' | 'failed' | 'awaiting_approval';
6
+
7
+ export interface MeshActiveWorkRecord {
8
+ taskId: string;
9
+ source: MeshActiveWorkSource;
10
+ status: MeshActiveWorkStatus;
11
+ nodeId?: string;
12
+ sessionId?: string;
13
+ providerType?: string;
14
+ taskTitle: string;
15
+ taskSummary: string;
16
+ message?: string;
17
+ taskMode?: string;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ dispatchedAt?: string;
21
+ elapsedMs: number;
22
+ terminal?: boolean;
23
+ terminalKind?: string;
24
+ terminalAt?: string;
25
+ }
26
+
27
+ export interface MeshActiveWorkSummary {
28
+ totalActiveCount: number;
29
+ queueActiveCount: number;
30
+ directActiveCount: number;
31
+ awaitingApprovalCount: number;
32
+ generatingCount: number;
33
+ failedCount: number;
34
+ idleCount: number;
35
+ sourceCounts: Record<MeshActiveWorkSource, number>;
36
+ statusCounts: Record<MeshActiveWorkStatus, number>;
37
+ }
38
+
39
+ export interface BuildMeshActiveWorkOptions {
40
+ meshId: string;
41
+ queue?: MeshWorkQueueEntry[];
42
+ ledgerEntries?: MeshLedgerEntry[];
43
+ nodes?: any[];
44
+ now?: number;
45
+ /** Include terminal direct rows (idle/failed) for handoff/recent-work surfaces. Defaults false. */
46
+ includeTerminalDirect?: boolean;
47
+ }
48
+
49
+ const DIRECT_DISPATCH_VIA = new Set(['p2p_direct', 'local_direct', 'mesh_send_task']);
50
+ const TERMINAL_LEDGER_KINDS = new Set(['task_completed', 'task_failed', 'task_stalled']);
51
+
52
+ function readString(value: unknown): string | undefined {
53
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
54
+ }
55
+
56
+ function summarizeMessage(message: string): { title: string; summary: string } {
57
+ const oneLine = message.replace(/\s+/g, ' ').trim();
58
+ const title = oneLine.length > 96 ? `${oneLine.slice(0, 93)}...` : oneLine;
59
+ return { title: title || '(untitled task)', summary: oneLine };
60
+ }
61
+
62
+ function elapsedSince(value: string | undefined, now: number): number {
63
+ const started = value ? new Date(value).getTime() : Number.NaN;
64
+ return Number.isFinite(started) ? Math.max(0, now - started) : 0;
65
+ }
66
+
67
+ function sessionStatusFromNodes(nodes: any[] | undefined, nodeId?: string, sessionId?: string): MeshActiveWorkStatus | undefined {
68
+ if (!nodeId || !sessionId || !Array.isArray(nodes)) return undefined;
69
+ const node = nodes.find(item => readString(item?.id) === nodeId || readString(item?.nodeId) === nodeId || readString(item?.node_id) === nodeId);
70
+ if (!node) return undefined;
71
+ const candidates: any[] = [];
72
+ for (const value of [node.sessions, node.activeSessions, node.active_sessions, node.lastProbe?.sessions, node.last_probe?.sessions, node.lastProbe?.status?.sessions, node.last_probe?.status?.sessions]) {
73
+ if (Array.isArray(value)) candidates.push(...value);
74
+ }
75
+ for (const value of [node.activeSession, node.active_session, node.currentSession, node.current_session, node.runtimeSession, node.runtime_session, node.session]) {
76
+ if (value && typeof value === 'object') candidates.push(value);
77
+ }
78
+ const session = candidates.find(item => {
79
+ const id = readString(item?.id) || readString(item?.sessionId) || readString(item?.session_id) || readString(item?.runtimeSessionId) || readString(item?.instanceId);
80
+ return id === sessionId;
81
+ });
82
+ if (!session) return undefined;
83
+ const raw = `${readString(session.status) || ''} ${readString(session.lifecycle) || ''} ${readString(session.state) || ''} ${readString(session.activeChat?.status) || ''}`.toLowerCase();
84
+ if (raw.includes('approval')) return 'awaiting_approval';
85
+ if (raw.includes('generating') || raw.includes('running') || raw.includes('busy')) return 'generating';
86
+ if (raw.includes('failed') || raw.includes('stopped') || raw.includes('terminated') || raw.includes('exited')) return 'failed';
87
+ if (raw.includes('idle') || raw.includes('waiting_input') || raw.includes('ready')) return 'idle';
88
+ return undefined;
89
+ }
90
+
91
+ function isDirectDispatch(entry: MeshLedgerEntry): boolean {
92
+ if (entry.kind !== 'task_dispatched') return false;
93
+ const payload = entry.payload || {};
94
+ if (payload.source === 'direct') return true;
95
+ const via = readString(payload.via);
96
+ return Boolean(via && DIRECT_DISPATCH_VIA.has(via) && payload.source !== 'queue');
97
+ }
98
+
99
+ function directDispatchTaskId(entry: MeshLedgerEntry): string {
100
+ return readString(entry.payload?.taskId) || entry.id;
101
+ }
102
+
103
+ function terminalMatchesDispatch(terminal: MeshLedgerEntry, dispatch: MeshLedgerEntry, taskId: string): boolean {
104
+ const terminalTaskId = readString(terminal.payload?.taskId);
105
+ if (terminalTaskId && terminalTaskId === taskId) return true;
106
+ if (terminalTaskId && terminalTaskId !== taskId) return false;
107
+ if (dispatch.sessionId && terminal.sessionId === dispatch.sessionId) return true;
108
+ return Boolean(dispatch.nodeId && terminal.nodeId === dispatch.nodeId && !dispatch.sessionId);
109
+ }
110
+
111
+ function statusFromTerminal(entry: MeshLedgerEntry): MeshActiveWorkStatus {
112
+ if (entry.kind === 'task_approval_needed') return 'awaiting_approval';
113
+ if (entry.kind === 'task_completed') return 'idle';
114
+ return 'failed';
115
+ }
116
+
117
+ export function buildMeshActiveWorkSummary(activeWork: MeshActiveWorkRecord[]): MeshActiveWorkSummary {
118
+ const statusCounts: Record<MeshActiveWorkStatus, number> = {
119
+ pending: 0,
120
+ assigned: 0,
121
+ generating: 0,
122
+ idle: 0,
123
+ failed: 0,
124
+ awaiting_approval: 0,
125
+ };
126
+ const sourceCounts: Record<MeshActiveWorkSource, number> = { queue: 0, direct: 0 };
127
+ for (const item of activeWork) {
128
+ sourceCounts[item.source] += 1;
129
+ statusCounts[item.status] += 1;
130
+ }
131
+ return {
132
+ totalActiveCount: activeWork.length,
133
+ queueActiveCount: sourceCounts.queue,
134
+ directActiveCount: sourceCounts.direct,
135
+ awaitingApprovalCount: statusCounts.awaiting_approval,
136
+ generatingCount: statusCounts.generating,
137
+ failedCount: statusCounts.failed,
138
+ idleCount: statusCounts.idle,
139
+ sourceCounts,
140
+ statusCounts,
141
+ };
142
+ }
143
+
144
+ export function buildMeshActiveWork(opts: BuildMeshActiveWorkOptions): { activeWork: MeshActiveWorkRecord[]; summary: MeshActiveWorkSummary } {
145
+ const now = opts.now ?? Date.now();
146
+ const records: MeshActiveWorkRecord[] = [];
147
+
148
+ for (const task of opts.queue || []) {
149
+ if (task.status !== 'pending' && task.status !== 'assigned') continue;
150
+ const { title, summary } = summarizeMessage(task.message || '');
151
+ records.push({
152
+ taskId: task.id,
153
+ source: 'queue',
154
+ status: task.status,
155
+ nodeId: task.assignedNodeId || task.targetNodeId,
156
+ sessionId: task.assignedSessionId || task.targetSessionId,
157
+ taskTitle: title,
158
+ taskSummary: summary,
159
+ message: task.message,
160
+ taskMode: task.taskMode,
161
+ createdAt: task.createdAt,
162
+ updatedAt: task.updatedAt,
163
+ dispatchedAt: task.dispatchTimestamp,
164
+ elapsedMs: elapsedSince(task.dispatchTimestamp || task.createdAt, now),
165
+ });
166
+ }
167
+
168
+ const ledgerEntries = (opts.ledgerEntries || []).slice().sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
169
+ const terminals = ledgerEntries.filter(entry => TERMINAL_LEDGER_KINDS.has(entry.kind) || entry.kind === 'task_approval_needed');
170
+ for (const dispatch of ledgerEntries.filter(isDirectDispatch)) {
171
+ const taskId = directDispatchTaskId(dispatch);
172
+ const terminal = terminals
173
+ .filter(entry => new Date(entry.timestamp).getTime() >= new Date(dispatch.timestamp).getTime())
174
+ .find(entry => terminalMatchesDispatch(entry, dispatch, taskId));
175
+ const terminalStatus = terminal ? statusFromTerminal(terminal) : undefined;
176
+ const liveStatus = sessionStatusFromNodes(opts.nodes, dispatch.nodeId, dispatch.sessionId);
177
+ const status = terminalStatus || liveStatus || 'assigned';
178
+ const terminalRow = Boolean(terminal && terminal.kind !== 'task_approval_needed');
179
+ if (terminalRow && opts.includeTerminalDirect !== true) continue;
180
+ const message = readString(dispatch.payload?.message) || readString(dispatch.payload?.summary) || '';
181
+ const { title, summary } = summarizeMessage(message);
182
+ records.push({
183
+ taskId,
184
+ source: 'direct',
185
+ status,
186
+ nodeId: dispatch.nodeId,
187
+ sessionId: dispatch.sessionId,
188
+ providerType: dispatch.providerType || readString(dispatch.payload?.providerType),
189
+ taskTitle: readString(dispatch.payload?.taskTitle) || title,
190
+ taskSummary: readString(dispatch.payload?.taskSummary) || summary,
191
+ message,
192
+ taskMode: readString(dispatch.payload?.taskMode),
193
+ createdAt: dispatch.timestamp,
194
+ updatedAt: terminal?.timestamp || dispatch.timestamp,
195
+ dispatchedAt: dispatch.timestamp,
196
+ elapsedMs: elapsedSince(dispatch.timestamp, now),
197
+ terminal: terminalRow,
198
+ terminalKind: terminal?.kind,
199
+ terminalAt: terminal?.timestamp,
200
+ });
201
+ }
202
+
203
+ records.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
204
+ return { activeWork: records, summary: buildMeshActiveWorkSummary(records) };
205
+ }
@@ -25,6 +25,10 @@ interface RemoteIdleSession {
25
25
  const REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1000; // 5 minutes
26
26
  const remoteIdleSessions = new Map<string, RemoteIdleSession>(); // key: `${nodeId}:${sessionId}`
27
27
 
28
+ function readWorkerResultMetadata(event: Record<string, unknown>): Record<string, unknown> | undefined {
29
+ return readRecord(event.workerResult) || readRecord(event.meshWorkerResult) || readRecord(event.structuredResult);
30
+ }
31
+
28
32
  function sweepExpiredRemoteIdleSessions(): void {
29
33
  const now = Date.now();
30
34
  for (const [key, session] of remoteIdleSessions) {
@@ -107,6 +111,12 @@ function readNonEmptyString(value: unknown): string {
107
111
  return typeof value === 'string' && value.trim() ? value.trim() : '';
108
112
  }
109
113
 
114
+ function readRecord(value: unknown): Record<string, unknown> | undefined {
115
+ return value && typeof value === 'object' && !Array.isArray(value)
116
+ ? value as Record<string, unknown>
117
+ : undefined;
118
+ }
119
+
110
120
  function resolveEventSessionId(event: Record<string, unknown>, fallback?: unknown): string {
111
121
  return readNonEmptyString(event.targetSessionId)
112
122
  || readNonEmptyString(event.sessionId)
@@ -759,6 +769,9 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
759
769
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
760
770
  const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
761
771
  const providerType = readNonEmptyString(args.metadataEvent.providerType);
772
+ const providerSessionId = readNonEmptyString(args.metadataEvent.providerSessionId) || undefined;
773
+ const finalSummary = readNonEmptyString(args.metadataEvent.finalSummary) || undefined;
774
+ const workerResult = readWorkerResultMetadata(args.metadataEvent);
762
775
  const completedTask = sessionId
763
776
  ? updateSessionTaskStatus(args.meshId, sessionId, 'completed')
764
777
  : null;
@@ -775,15 +788,17 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
775
788
  nodeLabel: args.nodeLabel,
776
789
  taskId: completedTask.id,
777
790
  completedViaReady: true,
778
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
779
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
791
+ providerSessionId,
792
+ finalSummary,
793
+ workerResult,
780
794
  evidence: buildTaskCompletionEvidence({
781
795
  event: 'agent:ready',
782
796
  nodeId,
783
797
  sessionId,
784
798
  providerType: providerType || undefined,
785
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
786
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
799
+ providerSessionId,
800
+ finalSummary,
801
+ workerResult,
787
802
  }),
788
803
  },
789
804
  });
@@ -826,14 +841,18 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
826
841
  const ledgerNodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || undefined;
827
842
  const ledgerSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || undefined;
828
843
  const ledgerProviderType = readNonEmptyString(args.metadataEvent.providerType) || undefined;
844
+ const providerSessionId = readNonEmptyString(args.metadataEvent.providerSessionId) || undefined;
845
+ const finalSummary = readNonEmptyString(args.metadataEvent.finalSummary) || undefined;
846
+ const workerResult = readWorkerResultMetadata(args.metadataEvent);
829
847
  const completionEvidence = ledgerKind === 'task_completed' && ledgerNodeId && ledgerSessionId
830
848
  ? buildTaskCompletionEvidence({
831
849
  event: 'agent:generating_completed',
832
850
  nodeId: ledgerNodeId,
833
851
  sessionId: ledgerSessionId,
834
852
  providerType: ledgerProviderType,
835
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
836
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
853
+ providerSessionId,
854
+ finalSummary,
855
+ workerResult,
837
856
  })
838
857
  : undefined;
839
858
  appendLedgerEntry(args.meshId, {
@@ -845,8 +864,9 @@ function injectMeshSystemMessage(components: DaemonComponents, args: {
845
864
  event: args.event,
846
865
  nodeLabel: args.nodeLabel,
847
866
  taskId: completedTaskForLedger?.id || undefined,
848
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
849
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
867
+ providerSessionId,
868
+ finalSummary,
869
+ workerResult,
850
870
  completionDiagnostic: args.metadataEvent.completionDiagnostic && typeof args.metadataEvent.completionDiagnostic === 'object'
851
871
  ? args.metadataEvent.completionDiagnostic
852
872
  : undefined,