@adhdev/daemon-core 0.9.82-rc.4 → 0.9.82-rc.41
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 +2 -0
- package/dist/commands/router.d.ts +11 -0
- package/dist/git/git-commands.d.ts +1 -0
- package/dist/git/git-status.d.ts +5 -0
- package/dist/git/git-types.d.ts +10 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1363 -311
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1362 -311
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +17 -5
- package/dist/mesh/mesh-work-queue.d.ts +3 -1
- package/dist/providers/chat-message-normalization.d.ts +1 -0
- package/dist/repo-mesh-types.d.ts +128 -0
- package/package.json +1 -1
- package/src/boot/daemon-lifecycle.ts +3 -0
- package/src/commands/router.ts +1200 -169
- package/src/git/git-commands.ts +3 -3
- package/src/git/git-status.ts +97 -6
- package/src/git/git-summary.ts +3 -0
- package/src/git/git-types.ts +11 -0
- package/src/index.ts +9 -1
- package/src/mesh/mesh-events.ts +168 -30
- package/src/mesh/mesh-work-queue.ts +135 -119
- package/src/providers/chat-message-normalization.ts +3 -1
- package/src/repo-mesh-types.ts +138 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, writeFileSync, readFileSync } from 'fs';
|
|
1
|
+
import { existsSync, writeFileSync, readFileSync, openSync, closeSync, unlinkSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { randomUUID } from 'crypto';
|
|
4
4
|
import { getLedgerDir } from './mesh-ledger.js';
|
|
@@ -50,6 +50,31 @@ function getQueuePath(meshId: string): string {
|
|
|
50
50
|
return join(getLedgerDir(), `${safe}.queue.json`);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
function getLockPath(meshId: string): string {
|
|
54
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
55
|
+
return join(getLedgerDir(), `${safe}.queue.lock`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Simple advisory file lock using O_EXCL (atomic create) for queue mutations.
|
|
60
|
+
* Retries up to 10 times at 30 ms intervals; proceeds without lock on timeout
|
|
61
|
+
* to prevent deadlock (best-effort — far better than no locking at all).
|
|
62
|
+
*/
|
|
63
|
+
function withQueueLock<T>(meshId: string, fn: () => T): T {
|
|
64
|
+
const lockPath = getLockPath(meshId);
|
|
65
|
+
let fd = -1;
|
|
66
|
+
for (let i = 0; i < 10; i++) {
|
|
67
|
+
try { fd = openSync(lockPath, 'wx'); break; } catch {
|
|
68
|
+
const deadline = Date.now() + 30;
|
|
69
|
+
while (Date.now() < deadline) { /* spin */ }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
try { return fn(); } finally {
|
|
73
|
+
if (fd !== -1) try { closeSync(fd); } catch { /* noop */ }
|
|
74
|
+
try { unlinkSync(lockPath); } catch { /* already removed */ }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
53
78
|
function readQueue(meshId: string): MeshWorkQueueEntry[] {
|
|
54
79
|
const path = getQueuePath(meshId);
|
|
55
80
|
if (!existsSync(path)) return [];
|
|
@@ -74,20 +99,22 @@ export function enqueueTask(
|
|
|
74
99
|
message: string,
|
|
75
100
|
opts?: { targetNodeId?: string; targetSessionId?: string }
|
|
76
101
|
): MeshWorkQueueEntry {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
102
|
+
return withQueueLock(meshId, () => {
|
|
103
|
+
const queue = readQueue(meshId);
|
|
104
|
+
const entry: MeshWorkQueueEntry = {
|
|
105
|
+
id: randomUUID(),
|
|
106
|
+
meshId,
|
|
107
|
+
message,
|
|
108
|
+
status: 'pending',
|
|
109
|
+
targetNodeId: opts?.targetNodeId,
|
|
110
|
+
targetSessionId: opts?.targetSessionId,
|
|
111
|
+
createdAt: new Date().toISOString(),
|
|
112
|
+
updatedAt: new Date().toISOString(),
|
|
113
|
+
};
|
|
114
|
+
queue.push(entry);
|
|
115
|
+
writeQueue(meshId, queue);
|
|
116
|
+
return entry;
|
|
117
|
+
});
|
|
91
118
|
}
|
|
92
119
|
|
|
93
120
|
/**
|
|
@@ -106,39 +133,29 @@ export function getQueue(meshId: string, opts?: { status?: MeshTaskStatus[] }):
|
|
|
106
133
|
* Find the next pending task that this node is allowed to claim, and mark it as assigned.
|
|
107
134
|
*/
|
|
108
135
|
export function claimNextTask(meshId: string, nodeId: string, sessionId: string): MeshWorkQueueEntry | null {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
q.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const entry = queue[targetIdx];
|
|
134
|
-
entry.status = 'assigned';
|
|
135
|
-
entry.assignedNodeId = nodeId;
|
|
136
|
-
entry.assignedSessionId = sessionId;
|
|
137
|
-
entry.dispatchTimestamp = new Date().toISOString();
|
|
138
|
-
entry.updatedAt = new Date().toISOString();
|
|
139
|
-
|
|
140
|
-
writeQueue(meshId, queue);
|
|
141
|
-
return entry;
|
|
136
|
+
return withQueueLock(meshId, () => {
|
|
137
|
+
const queue = readQueue(meshId);
|
|
138
|
+
const hasActiveAssignment = queue.some(q => q.status === 'assigned' && (
|
|
139
|
+
q.assignedSessionId === sessionId || q.assignedNodeId === nodeId
|
|
140
|
+
));
|
|
141
|
+
if (hasActiveAssignment) return null;
|
|
142
|
+
let targetIdx = queue.findIndex(q => q.status === 'pending' && q.targetSessionId === sessionId);
|
|
143
|
+
if (targetIdx === -1) {
|
|
144
|
+
targetIdx = queue.findIndex(q => q.status === 'pending' && q.targetNodeId === nodeId && !q.targetSessionId);
|
|
145
|
+
}
|
|
146
|
+
if (targetIdx === -1) {
|
|
147
|
+
targetIdx = queue.findIndex(q => q.status === 'pending' && !q.targetNodeId && !q.targetSessionId);
|
|
148
|
+
}
|
|
149
|
+
if (targetIdx === -1) return null;
|
|
150
|
+
const entry = queue[targetIdx];
|
|
151
|
+
entry.status = 'assigned';
|
|
152
|
+
entry.assignedNodeId = nodeId;
|
|
153
|
+
entry.assignedSessionId = sessionId;
|
|
154
|
+
entry.dispatchTimestamp = new Date().toISOString();
|
|
155
|
+
entry.updatedAt = new Date().toISOString();
|
|
156
|
+
writeQueue(meshId, queue);
|
|
157
|
+
return entry;
|
|
158
|
+
});
|
|
142
159
|
}
|
|
143
160
|
|
|
144
161
|
/**
|
|
@@ -150,14 +167,15 @@ export function updateTaskStatus(
|
|
|
150
167
|
taskId: string,
|
|
151
168
|
status: MeshTaskStatus,
|
|
152
169
|
): MeshWorkQueueEntry | null {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
170
|
+
return withQueueLock(meshId, () => {
|
|
171
|
+
const queue = readQueue(meshId);
|
|
172
|
+
const idx = queue.findIndex(q => q.id === taskId);
|
|
173
|
+
if (idx === -1) return null;
|
|
174
|
+
queue[idx].status = status;
|
|
175
|
+
queue[idx].updatedAt = new Date().toISOString();
|
|
176
|
+
writeQueue(meshId, queue);
|
|
177
|
+
return queue[idx];
|
|
178
|
+
});
|
|
161
179
|
}
|
|
162
180
|
|
|
163
181
|
export function recordTaskAutoLaunch(
|
|
@@ -165,17 +183,16 @@ export function recordTaskAutoLaunch(
|
|
|
165
183
|
taskId: string,
|
|
166
184
|
autoLaunch: Omit<NonNullable<MeshWorkQueueEntry['autoLaunch']>, 'updatedAt'>,
|
|
167
185
|
): MeshWorkQueueEntry | null {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
...autoLaunch,
|
|
174
|
-
updatedAt
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return queue[idx];
|
|
186
|
+
return withQueueLock(meshId, () => {
|
|
187
|
+
const queue = readQueue(meshId);
|
|
188
|
+
const idx = queue.findIndex(q => q.id === taskId);
|
|
189
|
+
if (idx === -1) return null;
|
|
190
|
+
const now = new Date().toISOString();
|
|
191
|
+
queue[idx].autoLaunch = { ...autoLaunch, updatedAt: now };
|
|
192
|
+
queue[idx].updatedAt = now;
|
|
193
|
+
writeQueue(meshId, queue);
|
|
194
|
+
return queue[idx];
|
|
195
|
+
});
|
|
179
196
|
}
|
|
180
197
|
|
|
181
198
|
/**
|
|
@@ -186,17 +203,18 @@ export function cancelTask(
|
|
|
186
203
|
taskId: string,
|
|
187
204
|
opts?: { reason?: string },
|
|
188
205
|
): MeshWorkQueueEntry | null {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
206
|
+
return withQueueLock(meshId, () => {
|
|
207
|
+
const queue = readQueue(meshId);
|
|
208
|
+
const idx = queue.findIndex(q => q.id === taskId);
|
|
209
|
+
if (idx === -1) return null;
|
|
210
|
+
const now = new Date().toISOString();
|
|
211
|
+
queue[idx].status = 'cancelled';
|
|
212
|
+
queue[idx].updatedAt = now;
|
|
213
|
+
queue[idx].cancelledAt = now;
|
|
214
|
+
if (opts?.reason) queue[idx].cancelReason = opts.reason;
|
|
215
|
+
writeQueue(meshId, queue);
|
|
216
|
+
return queue[idx];
|
|
217
|
+
});
|
|
200
218
|
}
|
|
201
219
|
|
|
202
220
|
/**
|
|
@@ -214,27 +232,28 @@ export function requeueTask(
|
|
|
214
232
|
clearTargetSession?: boolean;
|
|
215
233
|
},
|
|
216
234
|
): MeshWorkQueueEntry | null {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
return withQueueLock(meshId, () => {
|
|
236
|
+
const queue = readQueue(meshId);
|
|
237
|
+
const idx = queue.findIndex(q => q.id === taskId);
|
|
238
|
+
if (idx === -1) return null;
|
|
239
|
+
const entry = queue[idx];
|
|
240
|
+
const now = new Date().toISOString();
|
|
241
|
+
entry.status = 'pending';
|
|
242
|
+
delete entry.assignedNodeId;
|
|
243
|
+
delete entry.assignedSessionId;
|
|
244
|
+
delete entry.cancelledAt;
|
|
245
|
+
delete entry.cancelReason;
|
|
246
|
+
if (opts?.clearTargetNode) delete entry.targetNodeId;
|
|
247
|
+
if (typeof opts?.targetNodeId === 'string') entry.targetNodeId = opts.targetNodeId;
|
|
248
|
+
if (opts?.clearTargetSession !== false) delete entry.targetSessionId;
|
|
249
|
+
if (typeof opts?.targetSessionId === 'string') entry.targetSessionId = opts.targetSessionId;
|
|
250
|
+
entry.updatedAt = now;
|
|
251
|
+
entry.requeuedAt = now;
|
|
252
|
+
entry.requeueCount = (entry.requeueCount || 0) + 1;
|
|
253
|
+
if (opts?.reason) entry.requeueReason = opts.reason;
|
|
254
|
+
writeQueue(meshId, queue);
|
|
255
|
+
return entry;
|
|
256
|
+
});
|
|
238
257
|
}
|
|
239
258
|
|
|
240
259
|
/**
|
|
@@ -244,29 +263,26 @@ export function updateSessionTaskStatus(
|
|
|
244
263
|
meshId: string,
|
|
245
264
|
sessionId: string,
|
|
246
265
|
status: MeshTaskStatus,
|
|
266
|
+
opts?: { occurredAt?: string },
|
|
247
267
|
): MeshWorkQueueEntry | null {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (queue[i].assignedSessionId === sessionId && queue[i].status === 'assigned') {
|
|
268
|
+
return withQueueLock(meshId, () => {
|
|
269
|
+
const queue = readQueue(meshId);
|
|
270
|
+
const occurredAtTime = opts?.occurredAt ? new Date(opts.occurredAt).getTime() : Number.NaN;
|
|
271
|
+
const hasOccurredAt = Number.isFinite(occurredAtTime);
|
|
272
|
+
let bestIdx = -1;
|
|
273
|
+
let bestTime = 0;
|
|
274
|
+
for (let i = queue.length - 1; i >= 0; i--) {
|
|
275
|
+
if (queue[i].assignedSessionId !== sessionId || queue[i].status !== 'assigned') continue;
|
|
257
276
|
const time = new Date(queue[i].dispatchTimestamp || queue[i].updatedAt).getTime();
|
|
258
|
-
if (time >
|
|
259
|
-
|
|
260
|
-
bestIdx = i;
|
|
261
|
-
}
|
|
277
|
+
if (hasOccurredAt && Number.isFinite(time) && time > occurredAtTime) continue;
|
|
278
|
+
if (time > bestTime) { bestTime = time; bestIdx = i; }
|
|
262
279
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
return queue[bestIdx];
|
|
280
|
+
if (bestIdx === -1) return null;
|
|
281
|
+
queue[bestIdx].status = status;
|
|
282
|
+
queue[bestIdx].updatedAt = new Date().toISOString();
|
|
283
|
+
writeQueue(meshId, queue);
|
|
284
|
+
return queue[bestIdx];
|
|
285
|
+
});
|
|
270
286
|
}
|
|
271
287
|
|
|
272
288
|
export interface MeshWorkQueueStats {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { ChatMessage } from '../types.js';
|
|
2
2
|
import { flattenContent } from './contracts.js';
|
|
3
3
|
|
|
4
|
+
export const DEFAULT_FINAL_SUMMARY_MAX_CHARS = 4_000;
|
|
5
|
+
|
|
4
6
|
export function extractFinalSummaryFromMessages(
|
|
5
7
|
messages: ChatMessage[] | null | undefined,
|
|
6
|
-
maxChars: number =
|
|
8
|
+
maxChars: number = DEFAULT_FINAL_SUMMARY_MAX_CHARS,
|
|
7
9
|
): string {
|
|
8
10
|
if (!Array.isArray(messages) || messages.length === 0) return '';
|
|
9
11
|
|
package/src/repo-mesh-types.ts
CHANGED
|
@@ -259,17 +259,155 @@ export interface RepoMeshStatus {
|
|
|
259
259
|
meshId: string;
|
|
260
260
|
meshName: string;
|
|
261
261
|
repoIdentity: string;
|
|
262
|
+
defaultBranch?: string;
|
|
262
263
|
refreshedAt: string;
|
|
263
264
|
nodes: RepoMeshNodeStatus[];
|
|
265
|
+
queue?: RepoMeshQueueStatus;
|
|
266
|
+
ledger?: RepoMeshLedgerStatus;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export interface RepoMeshSessionStatus {
|
|
270
|
+
sessionId: string;
|
|
271
|
+
providerType?: string;
|
|
272
|
+
state?: string;
|
|
273
|
+
lifecycle?: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted';
|
|
274
|
+
surfaceKind?: 'live_runtime' | 'recovery_snapshot' | 'inactive_record';
|
|
275
|
+
recoveryState?: string | null;
|
|
276
|
+
workspace?: string | null;
|
|
277
|
+
title?: string | null;
|
|
278
|
+
lastActivityAt?: string | null;
|
|
279
|
+
isCached?: boolean;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export type RepoMeshPeerConnectionState = 'self' | 'connected' | 'connecting' | 'disconnected' | 'failed' | 'closed' | 'unknown';
|
|
283
|
+
export type RepoMeshPeerConnectionTransport = 'local' | 'direct' | 'relay' | 'unknown';
|
|
284
|
+
|
|
285
|
+
export interface RepoMeshPeerConnectionStatus {
|
|
286
|
+
perspective: 'selected_coordinator';
|
|
287
|
+
source: 'mesh_peer_status' | 'not_reported';
|
|
288
|
+
state: RepoMeshPeerConnectionState;
|
|
289
|
+
transport: RepoMeshPeerConnectionTransport;
|
|
290
|
+
reported: boolean;
|
|
291
|
+
reason?: string;
|
|
292
|
+
lastStateChangeAt?: string;
|
|
293
|
+
lastConnectedAt?: string;
|
|
294
|
+
lastCommandAt?: string;
|
|
264
295
|
}
|
|
265
296
|
|
|
266
297
|
export interface RepoMeshNodeStatus {
|
|
267
298
|
nodeId: string;
|
|
268
299
|
machineLabel: string;
|
|
269
300
|
workspace: string;
|
|
301
|
+
repoRoot?: string;
|
|
302
|
+
daemonId?: string;
|
|
303
|
+
machineId?: string;
|
|
304
|
+
machineStatus?: string;
|
|
305
|
+
isLocalWorktree?: boolean;
|
|
306
|
+
worktreeBranch?: string;
|
|
270
307
|
health: RepoMeshNodeHealth;
|
|
271
308
|
git?: GitRepoStatus;
|
|
309
|
+
/**
|
|
310
|
+
* True when the selected coordinator has evidence that a peer git probe is still
|
|
311
|
+
* in flight or just timed out during initial mesh handshake, so callers should
|
|
312
|
+
* treat missing git data as pending instead of authoritative absence.
|
|
313
|
+
*/
|
|
314
|
+
gitProbePending?: boolean;
|
|
272
315
|
providers: string[];
|
|
273
316
|
activeSessions: string[];
|
|
317
|
+
activeSessionDetails?: RepoMeshSessionStatus[];
|
|
318
|
+
providerPriority?: string[];
|
|
319
|
+
launchReady?: boolean;
|
|
320
|
+
lastSeenAt?: string;
|
|
321
|
+
updatedAt?: string;
|
|
322
|
+
connection?: RepoMeshPeerConnectionStatus;
|
|
274
323
|
error?: string;
|
|
275
324
|
}
|
|
325
|
+
|
|
326
|
+
export type RepoMeshQueueTaskStatus = 'pending' | 'assigned' | 'completed' | 'failed' | 'cancelled';
|
|
327
|
+
|
|
328
|
+
export interface RepoMeshQueueTask {
|
|
329
|
+
id: string;
|
|
330
|
+
meshId: string;
|
|
331
|
+
message: string;
|
|
332
|
+
status: RepoMeshQueueTaskStatus;
|
|
333
|
+
targetNodeId?: string;
|
|
334
|
+
targetSessionId?: string;
|
|
335
|
+
assignedNodeId?: string;
|
|
336
|
+
assignedSessionId?: string;
|
|
337
|
+
cancelReason?: string;
|
|
338
|
+
cancelledAt?: string;
|
|
339
|
+
requeueReason?: string;
|
|
340
|
+
requeuedAt?: string;
|
|
341
|
+
requeueCount?: number;
|
|
342
|
+
autoLaunch?: {
|
|
343
|
+
status: 'skipped' | 'started' | 'failed' | 'completed';
|
|
344
|
+
reason?: string;
|
|
345
|
+
nodeId?: string;
|
|
346
|
+
providerType?: string;
|
|
347
|
+
sessionId?: string;
|
|
348
|
+
updatedAt: string;
|
|
349
|
+
};
|
|
350
|
+
dispatchTimestamp?: string;
|
|
351
|
+
createdAt: string;
|
|
352
|
+
updatedAt: string;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export interface RepoMeshQueueSummary {
|
|
356
|
+
total: number;
|
|
357
|
+
active: number;
|
|
358
|
+
historical: number;
|
|
359
|
+
pending: number;
|
|
360
|
+
assigned: number;
|
|
361
|
+
completed: number;
|
|
362
|
+
failed: number;
|
|
363
|
+
cancelled: number;
|
|
364
|
+
activeCounts: {
|
|
365
|
+
pending: number;
|
|
366
|
+
assigned: number;
|
|
367
|
+
};
|
|
368
|
+
historicalCounts: {
|
|
369
|
+
completed: number;
|
|
370
|
+
failed: number;
|
|
371
|
+
cancelled: number;
|
|
372
|
+
};
|
|
373
|
+
activeAssignments: Array<{
|
|
374
|
+
id: string;
|
|
375
|
+
nodeId?: string;
|
|
376
|
+
sessionId?: string;
|
|
377
|
+
message: string;
|
|
378
|
+
}>;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export interface RepoMeshQueueStatus {
|
|
382
|
+
tasks: RepoMeshQueueTask[];
|
|
383
|
+
summary: RepoMeshQueueSummary;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export interface RepoMeshLedgerEntryStatus {
|
|
387
|
+
id: string;
|
|
388
|
+
meshId: string;
|
|
389
|
+
timestamp: string;
|
|
390
|
+
kind: string;
|
|
391
|
+
nodeId?: string;
|
|
392
|
+
sessionId?: string;
|
|
393
|
+
providerType?: string;
|
|
394
|
+
payload: Record<string, unknown>;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export interface RepoMeshLedgerSummaryStatus {
|
|
398
|
+
meshId: string;
|
|
399
|
+
totalEntries: number;
|
|
400
|
+
taskDispatched: number;
|
|
401
|
+
taskCompleted: number;
|
|
402
|
+
taskFailed: number;
|
|
403
|
+
taskStalled: number;
|
|
404
|
+
sessionLaunched: number;
|
|
405
|
+
checkpointCreated: number;
|
|
406
|
+
lastActivityAt: string | null;
|
|
407
|
+
recentFailures: number;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export interface RepoMeshLedgerStatus {
|
|
411
|
+
entries: RepoMeshLedgerEntryStatus[];
|
|
412
|
+
summary: RepoMeshLedgerSummaryStatus;
|
|
413
|
+
}
|