@adhdev/daemon-core 0.9.82-rc.39 → 0.9.82-rc.40
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/commands/router.d.ts +6 -0
- package/dist/index.js +64 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/commands/router.ts +75 -2
package/package.json
CHANGED
package/src/commands/router.ts
CHANGED
|
@@ -1364,11 +1364,67 @@ export class DaemonCommandRouter {
|
|
|
1364
1364
|
* Allows the MCP server to query mesh data via get_mesh even when
|
|
1365
1365
|
* the mesh doesn't exist in the local meshes.json file. */
|
|
1366
1366
|
private inlineMeshCache = new Map<string, any>();
|
|
1367
|
+
/** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default. */
|
|
1368
|
+
private aggregateMeshStatusCache = new Map<string, { builtAt: number; snapshot: any }>();
|
|
1367
1369
|
|
|
1368
1370
|
constructor(deps: CommandRouterDeps) {
|
|
1369
1371
|
this.deps = deps;
|
|
1370
1372
|
}
|
|
1371
1373
|
|
|
1374
|
+
private cloneJsonValue<T>(value: T): T {
|
|
1375
|
+
if (typeof structuredClone === 'function') return structuredClone(value);
|
|
1376
|
+
return JSON.parse(JSON.stringify(value)) as T;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
private getCachedAggregateMeshStatus(meshId: string): any | null {
|
|
1380
|
+
const cached = this.aggregateMeshStatusCache.get(meshId);
|
|
1381
|
+
if (!cached?.snapshot || cached.snapshot.success !== true || !Array.isArray(cached.snapshot.nodes)) return null;
|
|
1382
|
+
const snapshot = this.cloneJsonValue(cached.snapshot);
|
|
1383
|
+
const ageMs = Math.max(0, Date.now() - cached.builtAt);
|
|
1384
|
+
const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === 'object'
|
|
1385
|
+
? snapshot.sourceOfTruth
|
|
1386
|
+
: {};
|
|
1387
|
+
snapshot.sourceOfTruth = {
|
|
1388
|
+
...sourceOfTruth,
|
|
1389
|
+
aggregateSnapshot: {
|
|
1390
|
+
...(sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === 'object'
|
|
1391
|
+
? sourceOfTruth.aggregateSnapshot
|
|
1392
|
+
: {}),
|
|
1393
|
+
owner: 'coordinator_daemon_memory',
|
|
1394
|
+
cached: true,
|
|
1395
|
+
source: 'memory',
|
|
1396
|
+
refreshReason: 'memory_cache_hit',
|
|
1397
|
+
ageMs,
|
|
1398
|
+
cachedAt: new Date(cached.builtAt).toISOString(),
|
|
1399
|
+
returnedAt: new Date().toISOString(),
|
|
1400
|
+
},
|
|
1401
|
+
};
|
|
1402
|
+
return snapshot;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
private rememberAggregateMeshStatus(meshId: string, snapshot: any, refreshReason: string): any {
|
|
1406
|
+
if (!snapshot || typeof snapshot !== 'object' || snapshot.success !== true || !Array.isArray(snapshot.nodes)) return snapshot;
|
|
1407
|
+
const builtAt = Date.now();
|
|
1408
|
+
const next = this.cloneJsonValue(snapshot);
|
|
1409
|
+
const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === 'object'
|
|
1410
|
+
? next.sourceOfTruth
|
|
1411
|
+
: {};
|
|
1412
|
+
next.sourceOfTruth = {
|
|
1413
|
+
...sourceOfTruth,
|
|
1414
|
+
aggregateSnapshot: {
|
|
1415
|
+
owner: 'coordinator_daemon_memory',
|
|
1416
|
+
cached: false,
|
|
1417
|
+
source: 'live_refresh',
|
|
1418
|
+
refreshReason,
|
|
1419
|
+
ageMs: 0,
|
|
1420
|
+
cachedAt: new Date(builtAt).toISOString(),
|
|
1421
|
+
returnedAt: new Date(builtAt).toISOString(),
|
|
1422
|
+
},
|
|
1423
|
+
};
|
|
1424
|
+
this.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: this.cloneJsonValue(next) });
|
|
1425
|
+
return next;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1372
1428
|
public getCachedInlineMesh(meshId: string, inlineMesh?: unknown): any | undefined {
|
|
1373
1429
|
if (inlineMesh && typeof inlineMesh === 'object') {
|
|
1374
1430
|
return this.warmInlineMeshCache(meshId, inlineMesh);
|
|
@@ -1414,6 +1470,10 @@ export class DaemonCommandRouter {
|
|
|
1414
1470
|
return warmedInline ? { mesh: warmedInline, inline: true, source: 'inline_bootstrap' } : null;
|
|
1415
1471
|
}
|
|
1416
1472
|
|
|
1473
|
+
private invalidateAggregateMeshStatus(meshId: string): void {
|
|
1474
|
+
this.aggregateMeshStatusCache.delete(meshId);
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1417
1477
|
private updateInlineMeshNode(meshId: string, mesh: any, node: any): void {
|
|
1418
1478
|
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
1419
1479
|
const idx = mesh.nodes.findIndex((entry: any) => entry?.id === node.id || entry?.nodeId === node.id);
|
|
@@ -1421,6 +1481,7 @@ export class DaemonCommandRouter {
|
|
|
1421
1481
|
else mesh.nodes.push(node);
|
|
1422
1482
|
mesh.updatedAt = new Date().toISOString();
|
|
1423
1483
|
this.inlineMeshCache.set(meshId, mesh);
|
|
1484
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
1424
1485
|
}
|
|
1425
1486
|
|
|
1426
1487
|
private removeInlineMeshNode(meshId: string, mesh: any, nodeId: string): boolean {
|
|
@@ -1430,6 +1491,7 @@ export class DaemonCommandRouter {
|
|
|
1430
1491
|
mesh.nodes.splice(idx, 1);
|
|
1431
1492
|
mesh.updatedAt = new Date().toISOString();
|
|
1432
1493
|
this.inlineMeshCache.set(meshId, mesh);
|
|
1494
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
1433
1495
|
return true;
|
|
1434
1496
|
}
|
|
1435
1497
|
|
|
@@ -2648,6 +2710,7 @@ export class DaemonCommandRouter {
|
|
|
2648
2710
|
const mesh = updateMesh(meshId, patch as any);
|
|
2649
2711
|
if (!mesh) return { success: false, error: 'Mesh not found' };
|
|
2650
2712
|
this.inlineMeshCache.set(meshId, mesh);
|
|
2713
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
2651
2714
|
return { success: true, mesh };
|
|
2652
2715
|
} catch (e: any) {
|
|
2653
2716
|
return { success: false, error: e.message };
|
|
@@ -3127,6 +3190,7 @@ export class DaemonCommandRouter {
|
|
|
3127
3190
|
} else {
|
|
3128
3191
|
const { removeNode } = await import('../config/mesh-config.js');
|
|
3129
3192
|
removed = removeNode(meshId, nodeId);
|
|
3193
|
+
if (removed) this.invalidateAggregateMeshStatus(meshId);
|
|
3130
3194
|
}
|
|
3131
3195
|
|
|
3132
3196
|
// Record in task ledger
|
|
@@ -3212,6 +3276,7 @@ export class DaemonCommandRouter {
|
|
|
3212
3276
|
policy: { ...(sourceNode.policy || {}) },
|
|
3213
3277
|
});
|
|
3214
3278
|
if (!node) return { success: false, error: 'Failed to register worktree node' };
|
|
3279
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
3215
3280
|
}
|
|
3216
3281
|
|
|
3217
3282
|
// Initialize submodules if policy allows (default: true)
|
|
@@ -3658,6 +3723,13 @@ export class DaemonCommandRouter {
|
|
|
3658
3723
|
const mesh = meshRecord?.mesh;
|
|
3659
3724
|
if (!mesh) return { success: false, error: 'Mesh not found' };
|
|
3660
3725
|
|
|
3726
|
+
const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
|
|
3727
|
+
if (!refreshRequested) {
|
|
3728
|
+
const cachedStatus = this.getCachedAggregateMeshStatus(meshId);
|
|
3729
|
+
if (cachedStatus) return cachedStatus;
|
|
3730
|
+
}
|
|
3731
|
+
const refreshReason = refreshRequested ? 'explicit_refresh' : 'cold_cache_miss';
|
|
3732
|
+
|
|
3661
3733
|
const { getMeshQueueStats, getQueue } = await import('../mesh/mesh-work-queue.js');
|
|
3662
3734
|
const queue = getQueue(meshId);
|
|
3663
3735
|
const queueSummary = getMeshQueueStats(meshId);
|
|
@@ -3915,13 +3987,13 @@ export class DaemonCommandRouter {
|
|
|
3915
3987
|
nodeStatuses.push(status);
|
|
3916
3988
|
}
|
|
3917
3989
|
|
|
3918
|
-
|
|
3990
|
+
const statusResult = {
|
|
3919
3991
|
success: true,
|
|
3920
3992
|
meshId: mesh.id,
|
|
3921
3993
|
meshName: mesh.name,
|
|
3922
3994
|
repoIdentity: mesh.repoIdentity,
|
|
3923
3995
|
defaultBranch: mesh.defaultBranch,
|
|
3924
|
-
refreshedAt
|
|
3996
|
+
refreshedAt,
|
|
3925
3997
|
sourceOfTruth: {
|
|
3926
3998
|
membership: meshRecord?.source === 'inline_cache'
|
|
3927
3999
|
? 'coordinator_inline_mesh_cache'
|
|
@@ -3947,6 +4019,7 @@ export class DaemonCommandRouter {
|
|
|
3947
4019
|
queue: { tasks: queue, summary: queueSummary },
|
|
3948
4020
|
ledger: { entries: ledgerEntries, summary: ledgerSummary },
|
|
3949
4021
|
};
|
|
4022
|
+
return this.rememberAggregateMeshStatus(meshId, statusResult, refreshReason);
|
|
3950
4023
|
} catch (e: any) {
|
|
3951
4024
|
return { success: false, error: e.message };
|
|
3952
4025
|
}
|