@adhdev/daemon-core 0.9.82-rc.43 → 0.9.82-rc.45

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.43",
3
+ "version": "0.9.82-rc.45",
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",
@@ -114,6 +114,75 @@ function readBooleanValue(...values: unknown[]): boolean | undefined {
114
114
  return undefined;
115
115
  }
116
116
 
117
+ function summarizeRepoMeshDebugGit(git: unknown): Record<string, unknown> | null {
118
+ const record = readObjectRecord(git);
119
+ if (!Object.keys(record).length) return null;
120
+ const submodules = Array.isArray(record.submodules)
121
+ ? record.submodules.map((entry: any) => ({
122
+ path: readStringValue(entry?.path) ?? null,
123
+ commit: readStringValue(entry?.commit)?.slice(0, 12) ?? null,
124
+ dirty: readBooleanValue(entry?.dirty) ?? false,
125
+ outOfSync: readBooleanValue(entry?.outOfSync, entry?.out_of_sync) ?? false,
126
+ }))
127
+ : [];
128
+ return {
129
+ isGitRepo: readBooleanValue(record.isGitRepo),
130
+ workspace: readStringValue(record.workspace) ?? null,
131
+ repoRoot: readStringValue(record.repoRoot, record.repo_root) ?? null,
132
+ branch: readStringValue(record.branch) ?? null,
133
+ upstream: readStringValue(record.upstream) ?? null,
134
+ upstreamStatus: readStringValue(record.upstreamStatus, record.upstream_status) ?? null,
135
+ headCommit: readStringValue(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
136
+ ahead: readNumberValue(record.ahead) ?? null,
137
+ behind: readNumberValue(record.behind) ?? null,
138
+ dirtyCounts: {
139
+ staged: readNumberValue(record.staged) ?? 0,
140
+ modified: readNumberValue(record.modified) ?? 0,
141
+ untracked: readNumberValue(record.untracked) ?? 0,
142
+ deleted: readNumberValue(record.deleted) ?? 0,
143
+ renamed: readNumberValue(record.renamed) ?? 0,
144
+ },
145
+ lastCheckedAt: readNumberValue(record.lastCheckedAt, record.last_checked_at) ?? null,
146
+ submoduleCount: submodules.length,
147
+ submodules,
148
+ };
149
+ }
150
+
151
+ function summarizeRepoMeshStatusDebug(status: any): Record<string, unknown> {
152
+ const nodes = Array.isArray(status?.nodes) ? status.nodes : [];
153
+ return {
154
+ success: status?.success,
155
+ meshId: readStringValue(status?.meshId, status?.mesh_id) ?? null,
156
+ refreshedAt: readStringValue(status?.refreshedAt, status?.refreshed_at) ?? null,
157
+ sourceOfTruth: status?.sourceOfTruth ?? null,
158
+ nodeCount: nodes.length,
159
+ nodes: nodes.map((node: any) => ({
160
+ nodeId: readStringValue(node?.nodeId, node?.id) ?? null,
161
+ daemonId: readStringValue(node?.daemonId, node?.daemon_id) ?? null,
162
+ workspace: readStringValue(node?.workspace, node?.git?.workspace) ?? null,
163
+ health: readStringValue(node?.health) ?? null,
164
+ machineStatus: readStringValue(node?.machineStatus, node?.machine_status) ?? null,
165
+ connection: node?.connection && typeof node.connection === 'object' ? {
166
+ state: readStringValue(node.connection.state) ?? null,
167
+ transport: readStringValue(node.connection.transport) ?? null,
168
+ source: readStringValue(node.connection.source) ?? null,
169
+ reported: readBooleanValue(node.connection.reported) ?? null,
170
+ } : null,
171
+ gitProbePending: node?.gitProbePending === true,
172
+ launchReady: node?.launchReady === true,
173
+ git: summarizeRepoMeshDebugGit(node?.git),
174
+ })),
175
+ };
176
+ }
177
+
178
+ function logRepoMeshStatusDebug(event: string, fields: Record<string, unknown>): void {
179
+ try {
180
+ LOG.info('MeshStatusDebug', `[RepoMeshStatusDebug] ${JSON.stringify({ event, ...fields })}`);
181
+ } catch {
182
+ LOG.info('MeshStatusDebug', `[RepoMeshStatusDebug] ${event}`);
183
+ }
184
+ }
185
+
117
186
  function joinRepoPath(root: string | undefined, relativePath: string | undefined): string | undefined {
118
187
  const normalizedRoot = typeof root === 'string' ? root.trim().replace(/[\\/]+$/, '') : '';
119
188
  const normalizedPath = typeof relativePath === 'string' ? relativePath.trim() : '';
@@ -194,16 +263,12 @@ function buildInlineMeshTransitGitStatus(node: any): Record<string, unknown> | u
194
263
  const probeGitResult = readObjectRecord(probeGit.result);
195
264
  const probeDirectStatus = readObjectRecord(probeGit.status);
196
265
  const probeNestedStatus = readObjectRecord(probeGitResult.status);
197
- const status = Object.keys(directStatus).length
198
- ? directStatus
199
- : Object.keys(nestedStatus).length
200
- ? nestedStatus
201
- : Object.keys(probeDirectStatus).length
202
- ? probeDirectStatus
203
- : Object.keys(probeNestedStatus).length
204
- ? probeNestedStatus
205
- : {};
206
- return normalizeInlineMeshGitStatus(status, node, { lastCheckedAt: Date.now() });
266
+ const candidates = [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus];
267
+ for (const status of candidates) {
268
+ const normalized = normalizeInlineMeshGitStatus(status, node, { lastCheckedAt: Date.now() });
269
+ if (normalized) return normalized;
270
+ }
271
+ return undefined;
207
272
  }
208
273
 
209
274
  function recordInlineMeshDirectGitTruth(
@@ -1376,10 +1441,73 @@ export class DaemonCommandRouter {
1376
1441
  return JSON.parse(JSON.stringify(value)) as T;
1377
1442
  }
1378
1443
 
1379
- private getCachedAggregateMeshStatus(meshId: string): any | null {
1444
+ private hydrateCachedAggregateMeshStatusFromInline(snapshot: any, mesh: any, options?: { requireDirectPeerTruth?: boolean }): any {
1445
+ if (!mesh || typeof mesh !== 'object' || !Array.isArray(mesh.nodes) || !Array.isArray(snapshot?.nodes)) return snapshot;
1446
+ const inlineNodesById = new Map<string, any>();
1447
+ for (const node of mesh.nodes) {
1448
+ const nodeId = readInlineMeshNodeId(node);
1449
+ if (nodeId) inlineNodesById.set(nodeId, node);
1450
+ }
1451
+ if (!inlineNodesById.size) return snapshot;
1452
+
1453
+ let changed = false;
1454
+ const unavailableNodeIds = new Set<string>();
1455
+ const sourceOfTruth = readObjectRecord(snapshot.sourceOfTruth);
1456
+ const directPeerTruth = readObjectRecord(sourceOfTruth.directPeerTruth);
1457
+ for (const entry of Array.isArray(directPeerTruth.unavailableNodeIds) ? directPeerTruth.unavailableNodeIds : []) {
1458
+ const nodeId = readStringValue(entry);
1459
+ if (nodeId) unavailableNodeIds.add(nodeId);
1460
+ }
1461
+
1462
+ const nodes = snapshot.nodes.map((statusNode: any) => {
1463
+ const nodeId = readStringValue(statusNode?.nodeId, statusNode?.id);
1464
+ const inlineNode = nodeId ? inlineNodesById.get(nodeId) : undefined;
1465
+ if (!inlineNode) return statusNode;
1466
+ const liveGit = buildInlineMeshTransitGitStatus(inlineNode);
1467
+ if (!liveGit) return statusNode;
1468
+ const nextStatus = { ...statusNode };
1469
+ nextStatus.git = liveGit;
1470
+ nextStatus.health = deriveMeshNodeHealthFromGit(liveGit);
1471
+ delete nextStatus.gitProbePending;
1472
+ if (readStringValue(nextStatus.error) === 'waiting for live peer git snapshot') delete nextStatus.error;
1473
+ if (!readStringValue(nextStatus.machineStatus)) nextStatus.machineStatus = 'online';
1474
+ if (nodeId) unavailableNodeIds.delete(nodeId);
1475
+ changed = true;
1476
+ return nextStatus;
1477
+ });
1478
+
1479
+ if (!changed && !(options?.requireDirectPeerTruth && unavailableNodeIds.size > 0)) return snapshot;
1480
+ const nextSourceOfTruth = {
1481
+ ...sourceOfTruth,
1482
+ ...(Object.keys(directPeerTruth).length ? {
1483
+ directPeerTruth: {
1484
+ ...directPeerTruth,
1485
+ satisfied: options?.requireDirectPeerTruth === true ? unavailableNodeIds.size === 0 : directPeerTruth.satisfied,
1486
+ unavailableNodeIds: [...unavailableNodeIds],
1487
+ },
1488
+ ...(options?.requireDirectPeerTruth === true ? {
1489
+ coordinatorOwnsLiveTruth: unavailableNodeIds.size === 0,
1490
+ currentStatus: unavailableNodeIds.size === 0 ? 'live_git_and_session_probes' : 'direct_peer_truth_unavailable',
1491
+ } : {}),
1492
+ } : {}),
1493
+ };
1494
+ return {
1495
+ ...snapshot,
1496
+ ...(options?.requireDirectPeerTruth === true && unavailableNodeIds.size > 0 ? {
1497
+ success: false,
1498
+ code: 'mesh_direct_peer_truth_unavailable',
1499
+ error: 'Selected coordinator could not confirm direct mesh truth for every remote node yet.',
1500
+ } : {}),
1501
+ sourceOfTruth: nextSourceOfTruth,
1502
+ nodes,
1503
+ };
1504
+ }
1505
+
1506
+ private getCachedAggregateMeshStatus(meshId: string, mesh?: any, options?: { requireDirectPeerTruth?: boolean }): any | null {
1380
1507
  const cached = this.aggregateMeshStatusCache.get(meshId);
1381
1508
  if (!cached?.snapshot || cached.snapshot.success !== true || !Array.isArray(cached.snapshot.nodes)) return null;
1382
- const snapshot = this.cloneJsonValue(cached.snapshot);
1509
+ let snapshot = this.cloneJsonValue(cached.snapshot);
1510
+ snapshot = this.hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options);
1383
1511
  const ageMs = Math.max(0, Date.now() - cached.builtAt);
1384
1512
  const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === 'object'
1385
1513
  ? snapshot.sourceOfTruth
@@ -1453,7 +1581,14 @@ export class DaemonCommandRouter {
1453
1581
  const preferInline = options?.preferInline === true;
1454
1582
  if (preferInline) {
1455
1583
  const cached = this.getCachedInlineMesh(meshId);
1456
- if (cached) return { mesh: cached, inline: true, source: 'inline_cache' };
1584
+ if (cached) {
1585
+ if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
1586
+ const merged = reconcileInlineMeshCache(cached, inlineMesh as any);
1587
+ this.inlineMeshCache.set(meshId, sanitizeInlineMesh(merged));
1588
+ return { mesh: merged, inline: true, source: 'inline_cache' };
1589
+ }
1590
+ return { mesh: cached, inline: true, source: 'inline_cache' };
1591
+ }
1457
1592
  if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
1458
1593
  this.warmInlineMeshCache(meshId, inlineMesh);
1459
1594
  return { mesh: inlineMesh, inline: true, source: 'inline_bootstrap' };
@@ -3725,8 +3860,16 @@ export class DaemonCommandRouter {
3725
3860
 
3726
3861
  const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
3727
3862
  if (!refreshRequested) {
3728
- const cachedStatus = this.getCachedAggregateMeshStatus(meshId);
3729
- if (cachedStatus) return cachedStatus;
3863
+ const cachedStatus = this.getCachedAggregateMeshStatus(meshId, mesh, { requireDirectPeerTruth: args?.requireDirectPeerTruth === true });
3864
+ if (cachedStatus) {
3865
+ logRepoMeshStatusDebug('return_cached', {
3866
+ meshId,
3867
+ command: 'mesh_status',
3868
+ refreshRequested,
3869
+ summary: summarizeRepoMeshStatusDebug(cachedStatus),
3870
+ });
3871
+ return cachedStatus;
3872
+ }
3730
3873
  }
3731
3874
  const refreshReason = refreshRequested ? 'explicit_refresh' : 'cold_cache_miss';
3732
3875
 
@@ -3759,9 +3902,10 @@ export class DaemonCommandRouter {
3759
3902
  peerConfirmedCount: 0,
3760
3903
  unavailableNodeIds: [] as string[],
3761
3904
  };
3762
- const directTruthSatisfied = meshRecord.source !== 'inline_bootstrap' || directTruth.directEvidenceCount > 0;
3905
+ const directTruthSatisfied = !requireDirectPeerTruth
3906
+ || (directTruth.directEvidenceCount > 0 && directTruth.unavailableNodeIds.length === 0);
3763
3907
  if (requireDirectPeerTruth && !directTruthSatisfied) {
3764
- return {
3908
+ const failureResult = {
3765
3909
  success: false,
3766
3910
  code: 'mesh_direct_peer_truth_unavailable',
3767
3911
  error: 'Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct mesh_status probes succeed.',
@@ -3784,6 +3928,14 @@ export class DaemonCommandRouter {
3784
3928
  },
3785
3929
  },
3786
3930
  };
3931
+ logRepoMeshStatusDebug('direct_truth_unavailable', {
3932
+ meshId,
3933
+ command: 'mesh_status',
3934
+ refreshRequested,
3935
+ meshSource: meshRecord.source,
3936
+ directTruth,
3937
+ });
3938
+ return failureResult;
3787
3939
  }
3788
3940
  const directTruthUnavailableNodeIds = new Set(directTruth.unavailableNodeIds);
3789
3941
  const selectedCoordinatorNodeId = readStringValue(
@@ -4019,7 +4171,17 @@ export class DaemonCommandRouter {
4019
4171
  queue: { tasks: queue, summary: queueSummary },
4020
4172
  ledger: { entries: ledgerEntries, summary: ledgerSummary },
4021
4173
  };
4022
- return this.rememberAggregateMeshStatus(meshId, statusResult, refreshReason);
4174
+ const rememberedStatus = this.rememberAggregateMeshStatus(meshId, statusResult, refreshReason);
4175
+ logRepoMeshStatusDebug('return_live', {
4176
+ meshId,
4177
+ command: 'mesh_status',
4178
+ refreshRequested,
4179
+ refreshReason,
4180
+ meshSource: meshRecord.source,
4181
+ directTruth,
4182
+ summary: summarizeRepoMeshStatusDebug(rememberedStatus),
4183
+ });
4184
+ return rememberedStatus;
4023
4185
  } catch (e: any) {
4024
4186
  return { success: false, error: e.message };
4025
4187
  }