@adhdev/daemon-core 0.9.82-rc.21 → 0.9.82-rc.23

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.21",
3
+ "version": "0.9.82-rc.23",
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",
@@ -222,6 +222,125 @@ function buildCachedInlineMeshGitStatus(node: any): Record<string, unknown> | un
222
222
  };
223
223
  }
224
224
 
225
+ function shouldDiscardCachedInlineMeshStatus(node: any): boolean {
226
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
227
+ if (!Object.keys(cachedStatus).length) return false;
228
+ const cachedGit = readObjectRecord(cachedStatus.git);
229
+ const workspaceError = readStringValue(cachedStatus.error, node?.error);
230
+ if (workspaceError && /workspace must be an existing directory/i.test(workspaceError)) return true;
231
+ const isGitRepo = readBooleanValue(cachedGit.isGitRepo);
232
+ const branch = readStringValue(cachedGit.branch);
233
+ const headCommit = readStringValue(cachedGit.headCommit);
234
+ return isGitRepo === false && !branch && !headCommit;
235
+ }
236
+
237
+ function stripInlineMeshTransientNodeState(node: any): any {
238
+ if (!node || typeof node !== 'object' || Array.isArray(node)) return node;
239
+ const {
240
+ cachedStatus,
241
+ lastGit: _lastGit,
242
+ last_git: _lastGitLegacy,
243
+ lastProbe: _lastProbe,
244
+ last_probe: _lastProbeLegacy,
245
+ error: _error,
246
+ health: _health,
247
+ machineStatus: _machineStatus,
248
+ lastSeenAt: _lastSeenAt,
249
+ last_seen_at: _lastSeenAtLegacy,
250
+ updatedAt: _updatedAt,
251
+ updated_at: _updatedAtLegacy,
252
+ activeSession: _activeSession,
253
+ active_session: _activeSessionLegacy,
254
+ activeSessionId: _activeSessionId,
255
+ active_session_id: _activeSessionIdLegacy,
256
+ sessionId: _sessionId,
257
+ session_id: _sessionIdLegacy,
258
+ providerType: _providerType,
259
+ provider_type: _providerTypeLegacy,
260
+ providers: _providers,
261
+ ...rest
262
+ } = node as Record<string, unknown>;
263
+ if (cachedStatus && !shouldDiscardCachedInlineMeshStatus(node)) {
264
+ return { ...rest, cachedStatus };
265
+ }
266
+ return rest;
267
+ }
268
+
269
+ function hasInlineMeshTransientNodeState(node: any): boolean {
270
+ if (!node || typeof node !== 'object' || Array.isArray(node)) return false;
271
+ return 'cachedStatus' in node
272
+ || 'lastGit' in node
273
+ || 'last_git' in node
274
+ || 'lastProbe' in node
275
+ || 'last_probe' in node
276
+ || 'error' in node
277
+ || 'health' in node
278
+ || 'machineStatus' in node
279
+ || 'lastSeenAt' in node
280
+ || 'last_seen_at' in node
281
+ || 'updatedAt' in node
282
+ || 'updated_at' in node
283
+ || 'activeSession' in node
284
+ || 'active_session' in node
285
+ || 'activeSessionId' in node
286
+ || 'active_session_id' in node
287
+ || 'sessionId' in node
288
+ || 'session_id' in node
289
+ || 'providerType' in node
290
+ || 'provider_type' in node
291
+ || 'providers' in node;
292
+ }
293
+
294
+ function readInlineMeshNodeId(node: any): string {
295
+ return readStringValue(node?.id, node?.nodeId) || '';
296
+ }
297
+
298
+ function sanitizeInlineMesh(inlineMesh: any): any {
299
+ if (!inlineMesh || typeof inlineMesh !== 'object' || Array.isArray(inlineMesh)) return inlineMesh;
300
+ if (!Array.isArray(inlineMesh.nodes)) return inlineMesh;
301
+ let changed = false;
302
+ const nodes = inlineMesh.nodes.map((node: any) => {
303
+ if (!hasInlineMeshTransientNodeState(node)) return node;
304
+ changed = true;
305
+ return stripInlineMeshTransientNodeState(node);
306
+ });
307
+ if (!changed) return inlineMesh;
308
+ return {
309
+ ...inlineMesh,
310
+ nodes,
311
+ };
312
+ }
313
+
314
+ function reconcileInlineMeshCache(cached: any, incoming: any): any {
315
+ if (!cached || typeof cached !== 'object' || Array.isArray(cached)) return incoming;
316
+ if (!incoming || typeof incoming !== 'object' || Array.isArray(incoming)) return cached;
317
+ const cachedNodes = Array.isArray(cached.nodes) ? cached.nodes : [];
318
+ const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
319
+ if (!cachedNodes.length || !incomingNodes.length) return { ...cached, ...incoming };
320
+
321
+ const incomingById = new Map<string, any>();
322
+ for (const node of incomingNodes) {
323
+ const nodeId = readInlineMeshNodeId(node);
324
+ if (nodeId) incomingById.set(nodeId, node);
325
+ }
326
+
327
+ const nodes = cachedNodes.map((cachedNode: any) => {
328
+ const nodeId = readInlineMeshNodeId(cachedNode);
329
+ const incomingNode = nodeId ? incomingById.get(nodeId) : undefined;
330
+ if (!incomingNode) return cachedNode;
331
+ if (hasInlineMeshTransientNodeState(incomingNode)) {
332
+ return { ...cachedNode, ...incomingNode };
333
+ }
334
+ return { ...stripInlineMeshTransientNodeState(cachedNode), ...incomingNode };
335
+ });
336
+
337
+ return {
338
+ ...cached,
339
+ ...incoming,
340
+ nodes,
341
+ };
342
+ }
343
+
225
344
  function hasGitWorktreeChanges(git: Record<string, unknown> | null | undefined): boolean {
226
345
  if (!git) return false;
227
346
  return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
@@ -328,6 +447,23 @@ function summarizeMeshSessionRecord(record: any): Record<string, unknown> {
328
447
  };
329
448
  }
330
449
 
450
+ function liveSessionRecordMatchesMeshNode(record: any, meshId: string, nodeId: string): boolean {
451
+ const recordNodeId = readStringValue(record?.meta?.meshNodeId);
452
+ if (!recordNodeId || recordNodeId !== nodeId) return false;
453
+ const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
454
+ return !recordMeshId || recordMeshId === meshId;
455
+ }
456
+
457
+ function liveSessionRecordMatchesMeshWorkspace(record: any, meshId: string, workspace: string): boolean {
458
+ const recordWorkspace = readStringValue(record?.workspace);
459
+ if (!recordWorkspace || !workspace || recordWorkspace !== workspace) return false;
460
+
461
+ const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
462
+ if (recordMeshId) return recordMeshId === meshId;
463
+
464
+ return record?.meta?.launchedByCoordinator === true || !!readStringValue(record?.meta?.meshNodeId);
465
+ }
466
+
331
467
  function readLiveMeshNodeWorkspace(args: {
332
468
  meshId: string;
333
469
  nodeId: string;
@@ -335,7 +471,7 @@ function readLiveMeshNodeWorkspace(args: {
335
471
  allowCoordinatorSession?: boolean;
336
472
  }): string {
337
473
  const directNodeWorkspace = args.liveSessionRecords.find((record) => (
338
- readStringValue(record?.meta?.meshNodeId) === args.nodeId
474
+ liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)
339
475
  && readStringValue(record?.workspace)
340
476
  ));
341
477
  if (directNodeWorkspace) {
@@ -363,10 +499,9 @@ function collectLiveMeshSessionRecords(args: {
363
499
  allowCoordinatorSession?: boolean;
364
500
  }): any[] {
365
501
  const matches = args.liveSessionRecords.filter((record) => {
366
- if (readStringValue(record?.meta?.meshNodeId) === args.nodeId) return true;
367
- const recordWorkspace = readStringValue(record?.workspace);
368
502
  const nodeWorkspace = readStringValue(args.node?.workspace);
369
- return !!recordWorkspace && !!nodeWorkspace && recordWorkspace === nodeWorkspace;
503
+ if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)) return true;
504
+ return !!nodeWorkspace && liveSessionRecordMatchesMeshWorkspace(record, args.meshId, nodeWorkspace);
370
505
  });
371
506
 
372
507
  if (args.allowCoordinatorSession) {
@@ -960,10 +1095,15 @@ export class DaemonCommandRouter {
960
1095
 
961
1096
  private warmInlineMeshCache(meshId: string, inlineMesh?: unknown): any | undefined {
962
1097
  if (!inlineMesh || typeof inlineMesh !== 'object') return undefined;
1098
+ const sanitizedInlineMesh = sanitizeInlineMesh(inlineMesh as any);
963
1099
  const cached = this.inlineMeshCache.get(meshId);
964
- if (cached) return cached;
965
- this.inlineMeshCache.set(meshId, inlineMesh as any);
966
- return inlineMesh as any;
1100
+ if (cached) {
1101
+ const merged = reconcileInlineMeshCache(cached, sanitizedInlineMesh);
1102
+ this.inlineMeshCache.set(meshId, merged);
1103
+ return merged;
1104
+ }
1105
+ this.inlineMeshCache.set(meshId, sanitizedInlineMesh as any);
1106
+ return sanitizedInlineMesh as any;
967
1107
  }
968
1108
 
969
1109
  private async getMeshForCommand(
@@ -3203,10 +3343,17 @@ export class DaemonCommandRouter {
3203
3343
  }
3204
3344
  }
3205
3345
  if (workspace) {
3206
- if (!fs.existsSync(workspace) && applyCachedInlineMeshNodeStatus(status, node)) {
3207
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3208
- nodeStatuses.push(status);
3209
- continue;
3346
+ if (!fs.existsSync(workspace)) {
3347
+ if (applyCachedInlineMeshNodeStatus(status, node)) {
3348
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3349
+ nodeStatuses.push(status);
3350
+ continue;
3351
+ }
3352
+ if (meshRecord?.source === 'inline_cache' && !isSelfNode) {
3353
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3354
+ nodeStatuses.push(status);
3355
+ continue;
3356
+ }
3210
3357
  }
3211
3358
  try {
3212
3359
  const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 10_000, refreshUpstream: true });