@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.39",
3
+ "version": "0.9.82-rc.40",
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",
@@ -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
- return {
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: new Date().toISOString(),
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
  }