@adhdev/daemon-core 0.9.82-rc.30 → 0.9.82-rc.32

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.30",
3
+ "version": "0.9.82-rc.32",
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,14 +114,24 @@ function readBooleanValue(...values: unknown[]): boolean | undefined {
114
114
  return undefined;
115
115
  }
116
116
 
117
- function readGitSubmodules(value: unknown): GitSubmoduleStatus[] | undefined {
117
+ function joinRepoPath(root: string | undefined, relativePath: string | undefined): string | undefined {
118
+ const normalizedRoot = typeof root === 'string' ? root.trim().replace(/[\\/]+$/, '') : '';
119
+ const normalizedPath = typeof relativePath === 'string' ? relativePath.trim() : '';
120
+ if (!normalizedPath) return undefined;
121
+ if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
122
+ if (!normalizedRoot) return undefined;
123
+ return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, '')}`;
124
+ }
125
+
126
+ function readGitSubmodules(value: unknown, parentRepoRoot?: string): GitSubmoduleStatus[] | undefined {
118
127
  if (!Array.isArray(value)) return undefined;
119
128
  const submodules = value
120
129
  .map(entry => {
121
130
  const submodule = readObjectRecord(entry);
122
131
  const path = readStringValue(submodule.path);
123
132
  const commit = readStringValue(submodule.commit);
124
- const repoPath = readStringValue(submodule.repoPath, submodule.repo_root);
133
+ const repoPath = readStringValue(submodule.repoPath, submodule.repo_root)
134
+ ?? joinRepoPath(parentRepoRoot, path);
125
135
  if (!path || !commit || !repoPath) return null;
126
136
  return {
127
137
  path,
@@ -149,10 +159,11 @@ function normalizeInlineMeshGitStatus(
149
159
  : [];
150
160
  const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
151
161
  const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
152
- const submodules = readGitSubmodules(status.submodules);
162
+ const repoRoot = readStringValue(status.repoRoot, status.repo_root, node?.repoRoot, node?.repo_root, status.workspace, node?.workspace) || undefined;
163
+ const submodules = readGitSubmodules(status.submodules, repoRoot);
153
164
  return {
154
165
  workspace: readStringValue(status.workspace, node?.workspace) || '',
155
- repoRoot: readStringValue(status.repoRoot, node?.repoRoot, node?.workspace) || null,
166
+ repoRoot: repoRoot ?? null,
156
167
  isGitRepo,
157
168
  branch: readStringValue(status.branch) ?? null,
158
169
  headCommit: readStringValue(status.headCommit) ?? null,
@@ -195,6 +206,31 @@ function buildInlineMeshTransitGitStatus(node: any): Record<string, unknown> | u
195
206
  return normalizeInlineMeshGitStatus(status, node, { lastCheckedAt: Date.now() });
196
207
  }
197
208
 
209
+ function recordInlineMeshDirectGitTruth(
210
+ node: any,
211
+ git: Record<string, unknown>,
212
+ source: 'selected_coordinator_local_git' | 'selected_coordinator_mesh_p2p_git',
213
+ ): void {
214
+ if (!node || typeof node !== 'object' || Array.isArray(node)) return;
215
+ const checkedAt = readNumberValue(git.lastCheckedAt) ?? Date.now();
216
+ const updatedAt = new Date(checkedAt).toISOString();
217
+ const nextGit: Record<string, unknown> = {
218
+ ...git,
219
+ lastCheckedAt: checkedAt,
220
+ };
221
+ node.lastGit = {
222
+ source,
223
+ checkedAt,
224
+ status: nextGit,
225
+ };
226
+ node.last_git = node.lastGit;
227
+ node.machineStatus = 'online';
228
+ node.updatedAt = updatedAt;
229
+ node.lastSeenAt = updatedAt;
230
+ const repoRoot = readStringValue(nextGit.repoRoot);
231
+ if (repoRoot && !readStringValue(node.repoRoot)) node.repoRoot = repoRoot;
232
+ }
233
+
198
234
  function buildCachedInlineMeshGitStatus(node: any): Record<string, unknown> | undefined {
199
235
  const liveGit = buildInlineMeshTransitGitStatus(node);
200
236
  if (liveGit) return liveGit;
@@ -240,7 +276,6 @@ function stripInlineMeshTransientNodeState(node: any): any {
240
276
  session_id: _sessionIdLegacy,
241
277
  providerType: _providerType,
242
278
  provider_type: _providerTypeLegacy,
243
- providers: _providers,
244
279
  ...rest
245
280
  } = node as Record<string, unknown>;
246
281
  if (cachedStatus && !shouldDiscardCachedInlineMeshStatus(node)) {
@@ -270,8 +305,13 @@ function hasInlineMeshTransientNodeState(node: any): boolean {
270
305
  || 'sessionId' in node
271
306
  || 'session_id' in node
272
307
  || 'providerType' in node
273
- || 'provider_type' in node
274
- || 'providers' in node;
308
+ || 'provider_type' in node;
309
+ }
310
+
311
+ function inlineMeshCarriesTransientNodeTruth(inlineMesh: any): boolean {
312
+ if (!inlineMesh || typeof inlineMesh !== 'object' || Array.isArray(inlineMesh)) return false;
313
+ if (!Array.isArray(inlineMesh.nodes) || inlineMesh.nodes.length === 0) return false;
314
+ return inlineMesh.nodes.some((node: any) => hasInlineMeshTransientNodeState(node));
275
315
  }
276
316
 
277
317
  function readInlineMeshNodeId(node: any): string {
@@ -415,6 +455,152 @@ function toIsoTimestamp(value: unknown): string | null {
415
455
  return stringValue || null;
416
456
  }
417
457
 
458
+ function synthesizeMeshNodeFreshnessFromConnection(status: Record<string, unknown>): void {
459
+ const connection = readObjectRecord(status.connection);
460
+ const connectionFreshAt = toIsoTimestamp(connection.lastCommandAt ?? connection.lastConnectedAt ?? connection.lastStateChangeAt);
461
+ const git = readObjectRecord(status.git);
462
+ const gitCheckedAt = toIsoTimestamp(git.lastCheckedAt);
463
+ if (!status.lastSeenAt && connectionFreshAt) status.lastSeenAt = connectionFreshAt;
464
+ if (!status.updatedAt && (gitCheckedAt || connectionFreshAt)) {
465
+ status.updatedAt = gitCheckedAt ?? connectionFreshAt;
466
+ }
467
+ }
468
+
469
+ function finalizeMeshNodeStatus(args: {
470
+ status: Record<string, unknown>;
471
+ node: any;
472
+ daemonId?: string;
473
+ isSelfNode: boolean;
474
+ }): void {
475
+ const { status, node, daemonId, isSelfNode } = args;
476
+ if (!readStringValue(status.machineStatus)) {
477
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
478
+ const machineStatus = readStringValue(cachedStatus.machineStatus, cachedStatus.machine_status, node?.machineStatus);
479
+ if (machineStatus) status.machineStatus = machineStatus;
480
+ }
481
+ synthesizeMeshNodeFreshnessFromConnection(status);
482
+ const connectionState = readStringValue(readObjectRecord(status.connection).state);
483
+ status.launchReady = !!daemonId && (
484
+ readStringValue(status.machineStatus) === 'online'
485
+ || connectionState === 'connected'
486
+ || isSelfNode
487
+ );
488
+ }
489
+
490
+ async function probeRemoteMeshGitStatus(args: {
491
+ dispatchMeshCommand?: (daemonId: string, cmd: string, args: Record<string, unknown>) => Promise<unknown>;
492
+ daemonId: string;
493
+ workspace: string;
494
+ timeoutMs: number;
495
+ }): Promise<Record<string, unknown> | null> {
496
+ if (!args.dispatchMeshCommand) return null;
497
+ const remoteResult = await Promise.race([
498
+ args.dispatchMeshCommand(args.daemonId, 'git_status', { workspace: args.workspace }),
499
+ new Promise<never>((_, reject) => setTimeout(() => reject(new Error('timeout')), args.timeoutMs)),
500
+ ]) as any;
501
+ const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
502
+ return remoteGit && typeof remoteGit === 'object' && typeof remoteGit.isGitRepo === 'boolean'
503
+ ? remoteGit as Record<string, unknown>
504
+ : null;
505
+ }
506
+
507
+ async function hydrateInlineMeshDirectTruth(args: {
508
+ mesh: any;
509
+ meshSource: 'inline_cache' | 'inline_bootstrap' | 'local_config';
510
+ dispatchMeshCommand?: (daemonId: string, cmd: string, args: Record<string, unknown>) => Promise<unknown>;
511
+ statusInstanceId?: string;
512
+ localMachineId?: string;
513
+ }): Promise<{
514
+ directEvidenceCount: number;
515
+ localConfirmedCount: number;
516
+ peerAttemptedCount: number;
517
+ peerConfirmedCount: number;
518
+ unavailableNodeIds: string[];
519
+ }> {
520
+ const nodes = Array.isArray(args.mesh?.nodes) ? args.mesh.nodes : [];
521
+ if (!nodes.length) {
522
+ return {
523
+ directEvidenceCount: 0,
524
+ localConfirmedCount: 0,
525
+ peerAttemptedCount: 0,
526
+ peerConfirmedCount: 0,
527
+ unavailableNodeIds: [],
528
+ };
529
+ }
530
+
531
+ const selectedCoordinatorNodeId = readStringValue(
532
+ args.mesh?.coordinator?.preferredNodeId,
533
+ nodes[0]?.id,
534
+ nodes[0]?.nodeId,
535
+ );
536
+
537
+ let localConfirmedCount = 0;
538
+ let peerAttemptedCount = 0;
539
+ let peerConfirmedCount = 0;
540
+ const unavailableNodeIds: string[] = [];
541
+
542
+ for (const [nodeIndex, node] of nodes.entries()) {
543
+ const nodeId = readStringValue(node?.id, node?.nodeId) || `node_${nodeIndex}`;
544
+ const workspace = readStringValue(node?.workspace);
545
+ const daemonId = readStringValue(node?.daemonId);
546
+ const isSelfNode = Boolean(
547
+ nodeId && selectedCoordinatorNodeId && nodeId === selectedCoordinatorNodeId,
548
+ ) || Boolean(
549
+ daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId),
550
+ ) || Boolean(args.meshSource !== 'local_config' && nodeIndex === 0);
551
+
552
+ if (!workspace) {
553
+ if (!isSelfNode && daemonId) unavailableNodeIds.push(nodeId);
554
+ continue;
555
+ }
556
+
557
+ if (isSelfNode && fs.existsSync(workspace)) {
558
+ try {
559
+ const localGit = await getGitRepoStatus(workspace, { timeoutMs: 10_000, refreshUpstream: true });
560
+ if (localGit?.isGitRepo) {
561
+ recordInlineMeshDirectGitTruth(node, localGit as unknown as Record<string, unknown>, 'selected_coordinator_local_git');
562
+ localConfirmedCount += 1;
563
+ continue;
564
+ }
565
+ } catch {
566
+ // Fall through to remote classification.
567
+ }
568
+ }
569
+
570
+ if (!daemonId || !args.dispatchMeshCommand) {
571
+ if (!isSelfNode) unavailableNodeIds.push(nodeId);
572
+ continue;
573
+ }
574
+
575
+ peerAttemptedCount += 1;
576
+ try {
577
+ const remoteGit = await probeRemoteMeshGitStatus({
578
+ dispatchMeshCommand: args.dispatchMeshCommand,
579
+ daemonId,
580
+ workspace,
581
+ timeoutMs: 8_000,
582
+ });
583
+ if (remoteGit) {
584
+ recordInlineMeshDirectGitTruth(node, remoteGit, 'selected_coordinator_mesh_p2p_git');
585
+ peerConfirmedCount += 1;
586
+ continue;
587
+ }
588
+ } catch {
589
+ // Strict direct-only path: do not fall back to persisted cloud truth here.
590
+ }
591
+
592
+ unavailableNodeIds.push(nodeId);
593
+ }
594
+
595
+ return {
596
+ directEvidenceCount: localConfirmedCount + peerConfirmedCount,
597
+ localConfirmedCount,
598
+ peerAttemptedCount,
599
+ peerConfirmedCount,
600
+ unavailableNodeIds,
601
+ };
602
+ }
603
+
418
604
  function summarizeMeshSessionRecord(record: any): Record<string, unknown> {
419
605
  return {
420
606
  sessionId: readStringValue(record?.sessionId) || 'unknown',
@@ -1105,8 +1291,10 @@ export class DaemonCommandRouter {
1105
1291
  if (preferInline) {
1106
1292
  const cached = this.getCachedInlineMesh(meshId);
1107
1293
  if (cached) return { mesh: cached, inline: true, source: 'inline_cache' };
1108
- const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
1109
- if (warmedInline) return { mesh: warmedInline, inline: true, source: 'inline_bootstrap' };
1294
+ if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
1295
+ this.warmInlineMeshCache(meshId, inlineMesh);
1296
+ return { mesh: inlineMesh, inline: true, source: 'inline_bootstrap' };
1297
+ }
1110
1298
  }
1111
1299
  try {
1112
1300
  const { getMesh } = await import('../config/mesh-config.js');
@@ -2285,8 +2473,43 @@ export class DaemonCommandRouter {
2285
2473
  const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
2286
2474
  if (!meshId) return { success: false, error: 'meshId required' };
2287
2475
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
2288
- if (meshRecord?.mesh) return { success: true, mesh: meshRecord.mesh };
2289
- return { success: false, error: 'Mesh not found' };
2476
+ if (!meshRecord?.mesh) return { success: false, error: 'Mesh not found' };
2477
+
2478
+ const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
2479
+ const directTruth = await hydrateInlineMeshDirectTruth({
2480
+ mesh: meshRecord.mesh,
2481
+ meshSource: meshRecord.source,
2482
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
2483
+ statusInstanceId: this.deps.statusInstanceId,
2484
+ localMachineId: loadConfig().machineId || '',
2485
+ });
2486
+ const directTruthSatisfied = meshRecord.source !== 'inline_bootstrap' || directTruth.directEvidenceCount > 0;
2487
+ const sourceOfTruth = {
2488
+ membership: meshRecord.source === 'inline_cache'
2489
+ ? 'coordinator_inline_mesh_cache'
2490
+ : meshRecord.source === 'local_config'
2491
+ ? 'local_mesh_config'
2492
+ : 'inline_bootstrap_snapshot',
2493
+ coordinatorOwnsLiveTruth: directTruthSatisfied,
2494
+ directPeerTruth: {
2495
+ required: requireDirectPeerTruth,
2496
+ satisfied: directTruthSatisfied,
2497
+ directEvidenceCount: directTruth.directEvidenceCount,
2498
+ localConfirmedCount: directTruth.localConfirmedCount,
2499
+ peerAttemptedCount: directTruth.peerAttemptedCount,
2500
+ peerConfirmedCount: directTruth.peerConfirmedCount,
2501
+ unavailableNodeIds: directTruth.unavailableNodeIds,
2502
+ },
2503
+ };
2504
+ if (requireDirectPeerTruth && !directTruthSatisfied) {
2505
+ return {
2506
+ success: false,
2507
+ code: 'mesh_direct_peer_truth_unavailable',
2508
+ error: 'Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct get_mesh probes succeed.',
2509
+ sourceOfTruth,
2510
+ };
2511
+ }
2512
+ return { success: true, mesh: meshRecord.mesh, sourceOfTruth };
2290
2513
  }
2291
2514
 
2292
2515
  case 'create_mesh': {
@@ -3335,29 +3558,59 @@ export class DaemonCommandRouter {
3335
3558
  }
3336
3559
  if (workspace) {
3337
3560
  if (!fs.existsSync(workspace)) {
3338
- // Workspace not local — attempt a P2P git probe for remote nodes.
3561
+ // Workspace not local — prefer direct live inline truth, then attempt a P2P git probe.
3562
+ const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
3339
3563
  let remoteProbeApplied = false;
3340
- if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand) {
3564
+ if (inlineTransitGit) {
3565
+ status.git = inlineTransitGit;
3566
+ status.health = inlineTransitGit.isGitRepo
3567
+ ? deriveMeshNodeHealthFromGit(inlineTransitGit as unknown as Record<string, unknown>)
3568
+ : 'degraded';
3569
+ remoteProbeApplied = true;
3570
+ } else if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand) {
3341
3571
  try {
3342
- const remoteResult = await Promise.race([
3343
- this.deps.dispatchMeshCommand(daemonId, 'git_status', { workspace }),
3344
- new Promise<never>((_, reject) => setTimeout(() => reject(new Error('timeout')), 8000)),
3345
- ]) as any;
3346
- const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
3347
- if (remoteGit && typeof remoteGit === 'object' && typeof remoteGit.isGitRepo === 'boolean') {
3572
+ const remoteGit = await probeRemoteMeshGitStatus({
3573
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
3574
+ daemonId,
3575
+ workspace,
3576
+ timeoutMs: 8000,
3577
+ });
3578
+ if (remoteGit) {
3348
3579
  status.git = remoteGit;
3349
3580
  status.health = remoteGit.isGitRepo
3350
3581
  ? deriveMeshNodeHealthFromGit(remoteGit as unknown as Record<string, unknown>)
3351
3582
  : 'degraded';
3583
+ recordInlineMeshDirectGitTruth(node, remoteGit, 'selected_coordinator_mesh_p2p_git');
3352
3584
  remoteProbeApplied = true;
3353
3585
  }
3354
3586
  } catch {
3355
- // Probe timed out or P2P unavailable — fall back to cached status
3587
+ const refreshedConnection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
3588
+ const refreshedConnectionState = readStringValue(refreshedConnection?.state);
3589
+ if (refreshedConnection && refreshedConnectionState === 'connected') {
3590
+ status.connection = refreshedConnection;
3591
+ try {
3592
+ const remoteGit = await probeRemoteMeshGitStatus({
3593
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
3594
+ daemonId,
3595
+ workspace,
3596
+ timeoutMs: 12000,
3597
+ });
3598
+ if (remoteGit) {
3599
+ status.git = remoteGit;
3600
+ status.health = remoteGit.isGitRepo
3601
+ ? deriveMeshNodeHealthFromGit(remoteGit as unknown as Record<string, unknown>)
3602
+ : 'degraded';
3603
+ recordInlineMeshDirectGitTruth(node, remoteGit, 'selected_coordinator_mesh_p2p_git');
3604
+ remoteProbeApplied = true;
3605
+ }
3606
+ } catch {
3607
+ // Probe timed out again or P2P unavailable — fall back to cached status
3608
+ }
3609
+ }
3356
3610
  }
3357
3611
  }
3358
3612
  if (!remoteProbeApplied) {
3359
3613
  const connectionState = readStringValue((status.connection as any)?.state);
3360
- const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
3361
3614
  const pendingPeerGitProbe = !inlineTransitGit
3362
3615
  && !isSelfNode
3363
3616
  && !!daemonId
@@ -3377,12 +3630,12 @@ export class DaemonCommandRouter {
3377
3630
  node,
3378
3631
  pendingPeerGitProbe ? { skipGit: true, skipError: true, skipHealth: true } : undefined,
3379
3632
  )) {
3380
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3633
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
3381
3634
  nodeStatuses.push(status);
3382
3635
  continue;
3383
3636
  }
3384
3637
  if (meshRecord?.source === 'inline_cache' && !isSelfNode) {
3385
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3638
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
3386
3639
  nodeStatuses.push(status);
3387
3640
  continue;
3388
3641
  }
@@ -3391,6 +3644,7 @@ export class DaemonCommandRouter {
3391
3644
  try {
3392
3645
  const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 10_000, refreshUpstream: true });
3393
3646
  status.git = gitStatus;
3647
+ recordInlineMeshDirectGitTruth(node, gitStatus as unknown as Record<string, unknown>, 'selected_coordinator_local_git');
3394
3648
  if (gitStatus.isGitRepo) {
3395
3649
  status.health = deriveMeshNodeHealthFromGit(gitStatus as unknown as Record<string, unknown>);
3396
3650
  } else {
@@ -3406,7 +3660,7 @@ export class DaemonCommandRouter {
3406
3660
  } else {
3407
3661
  applyCachedInlineMeshNodeStatus(status, node);
3408
3662
  }
3409
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3663
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
3410
3664
  nodeStatuses.push(status);
3411
3665
  }
3412
3666