@adhdev/daemon-core 0.9.82-rc.17 → 0.9.82-rc.19

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.17",
3
+ "version": "0.9.82-rc.19",
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",
@@ -328,6 +328,59 @@ function summarizeMeshSessionRecord(record: any): Record<string, unknown> {
328
328
  };
329
329
  }
330
330
 
331
+ function readLiveMeshNodeWorkspace(args: {
332
+ meshId: string;
333
+ nodeId: string;
334
+ liveSessionRecords: any[];
335
+ allowCoordinatorSession?: boolean;
336
+ }): string {
337
+ const directNodeWorkspace = args.liveSessionRecords.find((record) => (
338
+ readStringValue(record?.meta?.meshNodeId) === args.nodeId
339
+ && readStringValue(record?.workspace)
340
+ ));
341
+ if (directNodeWorkspace) {
342
+ return readStringValue(directNodeWorkspace.workspace) || '';
343
+ }
344
+
345
+ if (args.allowCoordinatorSession) {
346
+ const coordinatorWorkspace = args.liveSessionRecords.find((record) => (
347
+ readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId
348
+ && readStringValue(record?.workspace)
349
+ ));
350
+ if (coordinatorWorkspace) {
351
+ return readStringValue(coordinatorWorkspace.workspace) || '';
352
+ }
353
+ }
354
+
355
+ return '';
356
+ }
357
+
358
+ function collectLiveMeshSessionRecords(args: {
359
+ meshId: string;
360
+ node: any;
361
+ nodeId: string;
362
+ liveSessionRecords: any[];
363
+ allowCoordinatorSession?: boolean;
364
+ }): any[] {
365
+ const matches = args.liveSessionRecords.filter((record) => {
366
+ if (readStringValue(record?.meta?.meshNodeId) === args.nodeId) return true;
367
+ const recordWorkspace = readStringValue(record?.workspace);
368
+ const nodeWorkspace = readStringValue(args.node?.workspace);
369
+ return !!recordWorkspace && !!nodeWorkspace && recordWorkspace === nodeWorkspace;
370
+ });
371
+
372
+ if (args.allowCoordinatorSession) {
373
+ for (const record of args.liveSessionRecords) {
374
+ if (readStringValue(record?.meta?.meshCoordinatorFor) !== args.meshId) continue;
375
+ const sessionId = readStringValue(record?.sessionId);
376
+ if (sessionId && matches.some((entry) => readStringValue(entry?.sessionId) === sessionId)) continue;
377
+ matches.push(record);
378
+ }
379
+ }
380
+
381
+ return matches;
382
+ }
383
+
331
384
  function applyCachedInlineMeshNodeStatus(status: Record<string, unknown>, node: any): boolean {
332
385
  const cachedStatus = readObjectRecord(node?.cachedStatus);
333
386
  const git = buildCachedInlineMeshGitStatus(node);
@@ -900,29 +953,40 @@ export class DaemonCommandRouter {
900
953
 
901
954
  public getCachedInlineMesh(meshId: string, inlineMesh?: unknown): any | undefined {
902
955
  if (inlineMesh && typeof inlineMesh === 'object') {
903
- this.inlineMeshCache.set(meshId, inlineMesh as any);
904
- return inlineMesh as any;
956
+ return this.warmInlineMeshCache(meshId, inlineMesh);
905
957
  }
906
958
  return this.inlineMeshCache.get(meshId);
907
959
  }
908
960
 
961
+ private warmInlineMeshCache(meshId: string, inlineMesh?: unknown): any | undefined {
962
+ if (!inlineMesh || typeof inlineMesh !== 'object') return undefined;
963
+ const cached = this.inlineMeshCache.get(meshId);
964
+ if (cached) return cached;
965
+ this.inlineMeshCache.set(meshId, inlineMesh as any);
966
+ return inlineMesh as any;
967
+ }
968
+
909
969
  private async getMeshForCommand(
910
970
  meshId: string,
911
971
  inlineMesh?: unknown,
912
972
  options?: { preferInline?: boolean },
913
- ): Promise<{ mesh: any; inline: boolean } | null> {
973
+ ): Promise<{ mesh: any; inline: boolean; source: 'inline_cache' | 'inline_bootstrap' | 'local_config' } | null> {
914
974
  const preferInline = options?.preferInline === true;
915
975
  if (preferInline) {
916
- const cached = this.getCachedInlineMesh(meshId, inlineMesh);
917
- if (cached) return { mesh: cached, inline: true };
976
+ const cached = this.getCachedInlineMesh(meshId);
977
+ if (cached) return { mesh: cached, inline: true, source: 'inline_cache' };
978
+ const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
979
+ if (warmedInline) return { mesh: warmedInline, inline: true, source: 'inline_bootstrap' };
918
980
  }
919
981
  try {
920
982
  const { getMesh } = await import('../config/mesh-config.js');
921
983
  const mesh = getMesh(meshId);
922
- if (mesh) return { mesh, inline: false };
984
+ if (mesh) return { mesh, inline: false, source: 'local_config' };
923
985
  } catch { /* fall through to inline cache */ }
924
- const cached = this.getCachedInlineMesh(meshId, inlineMesh);
925
- return cached ? { mesh: cached, inline: true } : null;
986
+ const cached = this.getCachedInlineMesh(meshId);
987
+ if (cached) return { mesh: cached, inline: true, source: 'inline_cache' };
988
+ const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
989
+ return warmedInline ? { mesh: warmedInline, inline: true, source: 'inline_bootstrap' } : null;
926
990
  }
927
991
 
928
992
  private updateInlineMeshNode(meshId: string, mesh: any, node: any): void {
@@ -1219,6 +1283,7 @@ export class DaemonCommandRouter {
1219
1283
  const deletedSessionIds: string[] = [];
1220
1284
  const skippedSessionIds: string[] = [];
1221
1285
  const skippedLiveSessionIds: string[] = [];
1286
+ const skippedCoordinatorSessionIds: string[] = [];
1222
1287
  const deleteUnsupportedSessionIds: string[] = [];
1223
1288
  const recordsRemainSessionIds: string[] = [];
1224
1289
  const errors: Array<{ sessionId: string; error: string }> = [];
@@ -1253,6 +1318,12 @@ export class DaemonCommandRouter {
1253
1318
  const completed = this.isCompletedHostedSession(record);
1254
1319
  const surfaceKind = getSessionHostSurfaceKind(record);
1255
1320
  const liveRuntime = surfaceKind === 'live_runtime';
1321
+ const coordinatorSession = readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId;
1322
+ if (!hasExplicitSessionIds && coordinatorSession) {
1323
+ skippedSessionIds.push(sessionId);
1324
+ skippedCoordinatorSessionIds.push(sessionId);
1325
+ continue;
1326
+ }
1256
1327
  if (!hasExplicitSessionIds && liveRuntime) {
1257
1328
  skippedSessionIds.push(sessionId);
1258
1329
  skippedLiveSessionIds.push(sessionId);
@@ -1322,6 +1393,7 @@ export class DaemonCommandRouter {
1322
1393
  deletedSessionIds,
1323
1394
  skippedSessionIds,
1324
1395
  skippedLiveSessionIds,
1396
+ skippedCoordinatorSessionIds,
1325
1397
  ...(deleteUnsupported ? {
1326
1398
  deleteUnsupported: true,
1327
1399
  effectiveCleanup: args.mode === 'stop_and_delete'
@@ -2669,7 +2741,16 @@ export class DaemonCommandRouter {
2669
2741
  cliType,
2670
2742
  };
2671
2743
  }
2672
- const workspace = typeof coordinatorNode.workspace === 'string' ? coordinatorNode.workspace.trim() : '';
2744
+ const sessionHostRecords = this.deps.sessionHostControl?.listSessions
2745
+ ? await this.deps.sessionHostControl.listSessions().catch(() => [])
2746
+ : [];
2747
+ const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
2748
+ const workspace = readLiveMeshNodeWorkspace({
2749
+ meshId,
2750
+ nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || ''),
2751
+ liveSessionRecords: liveMeshSessions,
2752
+ allowCoordinatorSession: true,
2753
+ }) || (typeof coordinatorNode.workspace === 'string' ? coordinatorNode.workspace.trim() : '');
2673
2754
  if (!workspace) return { success: false, error: 'Coordinator node workspace required', meshId, cliType };
2674
2755
  if (!cliType) {
2675
2756
  const resolved = await resolveProviderTypeFromPriority({
@@ -3028,8 +3109,13 @@ export class DaemonCommandRouter {
3028
3109
  const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
3029
3110
 
3030
3111
  const localMachineId = loadConfig().machineId || '';
3112
+ const selectedCoordinatorNodeId = readStringValue(
3113
+ mesh.coordinator?.preferredNodeId,
3114
+ (mesh.nodes?.[0] as any)?.id,
3115
+ (mesh.nodes?.[0] as any)?.nodeId,
3116
+ );
3031
3117
  const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes)
3032
- ? readStringValue((mesh.nodes[0] as any)?.id, (mesh.nodes[0] as any)?.nodeId)
3118
+ ? selectedCoordinatorNodeId
3033
3119
  : undefined;
3034
3120
  const refreshedAt = new Date().toISOString();
3035
3121
  const nodeStatuses = [];
@@ -3089,8 +3175,20 @@ export class DaemonCommandRouter {
3089
3175
  reason: 'Node has no daemon id, so mesh transport cannot be reported from the selected coordinator.',
3090
3176
  };
3091
3177
  }
3092
- const matchedLiveSessionRecords = liveMeshSessions
3093
- .filter((record) => this.sessionMatchesMeshNode(record, node, nodeId));
3178
+ const matchedLiveSessionRecords = collectLiveMeshSessionRecords({
3179
+ meshId,
3180
+ node,
3181
+ nodeId,
3182
+ liveSessionRecords: liveMeshSessions,
3183
+ allowCoordinatorSession: nodeId === selectedCoordinatorNodeId,
3184
+ });
3185
+ const workspace = readLiveMeshNodeWorkspace({
3186
+ meshId,
3187
+ nodeId,
3188
+ liveSessionRecords: matchedLiveSessionRecords,
3189
+ allowCoordinatorSession: nodeId === selectedCoordinatorNodeId,
3190
+ }) || (typeof node.workspace === 'string' ? node.workspace : '');
3191
+ status.workspace = workspace || node.workspace;
3094
3192
  if (matchedLiveSessionRecords.length > 0) {
3095
3193
  const sessionIds = matchedLiveSessionRecords
3096
3194
  .map((record: any) => typeof record?.sessionId === 'string' ? record.sessionId : '')
@@ -3104,14 +3202,14 @@ export class DaemonCommandRouter {
3104
3202
  status.providers = Array.from(new Set([...(Array.isArray(status.providers) ? status.providers as string[] : []), ...providerTypes]));
3105
3203
  }
3106
3204
  }
3107
- if (node.workspace && typeof node.workspace === 'string') {
3108
- if (!fs.existsSync(node.workspace as string) && applyCachedInlineMeshNodeStatus(status, node)) {
3205
+ if (workspace) {
3206
+ if (!fs.existsSync(workspace) && applyCachedInlineMeshNodeStatus(status, node)) {
3109
3207
  status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3110
3208
  nodeStatuses.push(status);
3111
3209
  continue;
3112
3210
  }
3113
3211
  try {
3114
- const gitStatus = await getGitRepoStatus(node.workspace as string, { timeoutMs: 10_000, refreshUpstream: true });
3212
+ const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 10_000, refreshUpstream: true });
3115
3213
  status.git = gitStatus;
3116
3214
  if (gitStatus.isGitRepo) {
3117
3215
  status.health = deriveMeshNodeHealthFromGit(gitStatus as unknown as Record<string, unknown>);
@@ -3138,6 +3236,15 @@ export class DaemonCommandRouter {
3138
3236
  repoIdentity: mesh.repoIdentity,
3139
3237
  defaultBranch: mesh.defaultBranch,
3140
3238
  refreshedAt: new Date().toISOString(),
3239
+ sourceOfTruth: {
3240
+ membership: meshRecord?.source === 'inline_cache'
3241
+ ? 'coordinator_inline_mesh_cache'
3242
+ : meshRecord?.source === 'local_config'
3243
+ ? 'local_mesh_config'
3244
+ : 'inline_bootstrap_snapshot',
3245
+ coordinatorOwnsLiveTruth: meshRecord?.source !== 'inline_bootstrap',
3246
+ historicalEvidenceOnly: ['recoveryHints', 'ledger.summary', 'queue.summary'],
3247
+ },
3141
3248
  nodes: nodeStatuses,
3142
3249
  queue: { tasks: queue, summary: queueSummary },
3143
3250
  ledger: { entries: ledgerEntries, summary: ledgerSummary },