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

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.31",
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,7 @@ 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;
275
309
  }
276
310
 
277
311
  function readInlineMeshNodeId(node: any): string {
@@ -415,6 +449,152 @@ function toIsoTimestamp(value: unknown): string | null {
415
449
  return stringValue || null;
416
450
  }
417
451
 
452
+ function synthesizeMeshNodeFreshnessFromConnection(status: Record<string, unknown>): void {
453
+ const connection = readObjectRecord(status.connection);
454
+ const connectionFreshAt = toIsoTimestamp(connection.lastCommandAt ?? connection.lastConnectedAt ?? connection.lastStateChangeAt);
455
+ const git = readObjectRecord(status.git);
456
+ const gitCheckedAt = toIsoTimestamp(git.lastCheckedAt);
457
+ if (!status.lastSeenAt && connectionFreshAt) status.lastSeenAt = connectionFreshAt;
458
+ if (!status.updatedAt && (gitCheckedAt || connectionFreshAt)) {
459
+ status.updatedAt = gitCheckedAt ?? connectionFreshAt;
460
+ }
461
+ }
462
+
463
+ function finalizeMeshNodeStatus(args: {
464
+ status: Record<string, unknown>;
465
+ node: any;
466
+ daemonId?: string;
467
+ isSelfNode: boolean;
468
+ }): void {
469
+ const { status, node, daemonId, isSelfNode } = args;
470
+ if (!readStringValue(status.machineStatus)) {
471
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
472
+ const machineStatus = readStringValue(cachedStatus.machineStatus, cachedStatus.machine_status, node?.machineStatus);
473
+ if (machineStatus) status.machineStatus = machineStatus;
474
+ }
475
+ synthesizeMeshNodeFreshnessFromConnection(status);
476
+ const connectionState = readStringValue(readObjectRecord(status.connection).state);
477
+ status.launchReady = !!daemonId && (
478
+ readStringValue(status.machineStatus) === 'online'
479
+ || connectionState === 'connected'
480
+ || isSelfNode
481
+ );
482
+ }
483
+
484
+ async function probeRemoteMeshGitStatus(args: {
485
+ dispatchMeshCommand?: (daemonId: string, cmd: string, args: Record<string, unknown>) => Promise<unknown>;
486
+ daemonId: string;
487
+ workspace: string;
488
+ timeoutMs: number;
489
+ }): Promise<Record<string, unknown> | null> {
490
+ if (!args.dispatchMeshCommand) return null;
491
+ const remoteResult = await Promise.race([
492
+ args.dispatchMeshCommand(args.daemonId, 'git_status', { workspace: args.workspace }),
493
+ new Promise<never>((_, reject) => setTimeout(() => reject(new Error('timeout')), args.timeoutMs)),
494
+ ]) as any;
495
+ const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
496
+ return remoteGit && typeof remoteGit === 'object' && typeof remoteGit.isGitRepo === 'boolean'
497
+ ? remoteGit as Record<string, unknown>
498
+ : null;
499
+ }
500
+
501
+ async function hydrateInlineMeshDirectTruth(args: {
502
+ mesh: any;
503
+ meshSource: 'inline_cache' | 'inline_bootstrap' | 'local_config';
504
+ dispatchMeshCommand?: (daemonId: string, cmd: string, args: Record<string, unknown>) => Promise<unknown>;
505
+ statusInstanceId?: string;
506
+ localMachineId?: string;
507
+ }): Promise<{
508
+ directEvidenceCount: number;
509
+ localConfirmedCount: number;
510
+ peerAttemptedCount: number;
511
+ peerConfirmedCount: number;
512
+ unavailableNodeIds: string[];
513
+ }> {
514
+ const nodes = Array.isArray(args.mesh?.nodes) ? args.mesh.nodes : [];
515
+ if (!nodes.length) {
516
+ return {
517
+ directEvidenceCount: 0,
518
+ localConfirmedCount: 0,
519
+ peerAttemptedCount: 0,
520
+ peerConfirmedCount: 0,
521
+ unavailableNodeIds: [],
522
+ };
523
+ }
524
+
525
+ const selectedCoordinatorNodeId = readStringValue(
526
+ args.mesh?.coordinator?.preferredNodeId,
527
+ nodes[0]?.id,
528
+ nodes[0]?.nodeId,
529
+ );
530
+
531
+ let localConfirmedCount = 0;
532
+ let peerAttemptedCount = 0;
533
+ let peerConfirmedCount = 0;
534
+ const unavailableNodeIds: string[] = [];
535
+
536
+ for (const [nodeIndex, node] of nodes.entries()) {
537
+ const nodeId = readStringValue(node?.id, node?.nodeId) || `node_${nodeIndex}`;
538
+ const workspace = readStringValue(node?.workspace);
539
+ const daemonId = readStringValue(node?.daemonId);
540
+ const isSelfNode = Boolean(
541
+ nodeId && selectedCoordinatorNodeId && nodeId === selectedCoordinatorNodeId,
542
+ ) || Boolean(
543
+ daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId),
544
+ ) || Boolean(args.meshSource !== 'local_config' && nodeIndex === 0);
545
+
546
+ if (!workspace) {
547
+ if (!isSelfNode && daemonId) unavailableNodeIds.push(nodeId);
548
+ continue;
549
+ }
550
+
551
+ if (isSelfNode && fs.existsSync(workspace)) {
552
+ try {
553
+ const localGit = await getGitRepoStatus(workspace, { timeoutMs: 10_000, refreshUpstream: true });
554
+ if (localGit?.isGitRepo) {
555
+ recordInlineMeshDirectGitTruth(node, localGit as unknown as Record<string, unknown>, 'selected_coordinator_local_git');
556
+ localConfirmedCount += 1;
557
+ continue;
558
+ }
559
+ } catch {
560
+ // Fall through to remote classification.
561
+ }
562
+ }
563
+
564
+ if (!daemonId || !args.dispatchMeshCommand) {
565
+ if (!isSelfNode) unavailableNodeIds.push(nodeId);
566
+ continue;
567
+ }
568
+
569
+ peerAttemptedCount += 1;
570
+ try {
571
+ const remoteGit = await probeRemoteMeshGitStatus({
572
+ dispatchMeshCommand: args.dispatchMeshCommand,
573
+ daemonId,
574
+ workspace,
575
+ timeoutMs: 8_000,
576
+ });
577
+ if (remoteGit) {
578
+ recordInlineMeshDirectGitTruth(node, remoteGit, 'selected_coordinator_mesh_p2p_git');
579
+ peerConfirmedCount += 1;
580
+ continue;
581
+ }
582
+ } catch {
583
+ // Strict direct-only path: do not fall back to persisted cloud truth here.
584
+ }
585
+
586
+ unavailableNodeIds.push(nodeId);
587
+ }
588
+
589
+ return {
590
+ directEvidenceCount: localConfirmedCount + peerConfirmedCount,
591
+ localConfirmedCount,
592
+ peerAttemptedCount,
593
+ peerConfirmedCount,
594
+ unavailableNodeIds,
595
+ };
596
+ }
597
+
418
598
  function summarizeMeshSessionRecord(record: any): Record<string, unknown> {
419
599
  return {
420
600
  sessionId: readStringValue(record?.sessionId) || 'unknown',
@@ -2285,8 +2465,43 @@ export class DaemonCommandRouter {
2285
2465
  const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
2286
2466
  if (!meshId) return { success: false, error: 'meshId required' };
2287
2467
  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' };
2468
+ if (!meshRecord?.mesh) return { success: false, error: 'Mesh not found' };
2469
+
2470
+ const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
2471
+ const directTruth = await hydrateInlineMeshDirectTruth({
2472
+ mesh: meshRecord.mesh,
2473
+ meshSource: meshRecord.source,
2474
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
2475
+ statusInstanceId: this.deps.statusInstanceId,
2476
+ localMachineId: loadConfig().machineId || '',
2477
+ });
2478
+ const directTruthSatisfied = meshRecord.source !== 'inline_bootstrap' || directTruth.directEvidenceCount > 0;
2479
+ const sourceOfTruth = {
2480
+ membership: meshRecord.source === 'inline_cache'
2481
+ ? 'coordinator_inline_mesh_cache'
2482
+ : meshRecord.source === 'local_config'
2483
+ ? 'local_mesh_config'
2484
+ : 'inline_bootstrap_snapshot',
2485
+ coordinatorOwnsLiveTruth: directTruthSatisfied,
2486
+ directPeerTruth: {
2487
+ required: requireDirectPeerTruth,
2488
+ satisfied: directTruthSatisfied,
2489
+ directEvidenceCount: directTruth.directEvidenceCount,
2490
+ localConfirmedCount: directTruth.localConfirmedCount,
2491
+ peerAttemptedCount: directTruth.peerAttemptedCount,
2492
+ peerConfirmedCount: directTruth.peerConfirmedCount,
2493
+ unavailableNodeIds: directTruth.unavailableNodeIds,
2494
+ },
2495
+ };
2496
+ if (requireDirectPeerTruth && !directTruthSatisfied) {
2497
+ return {
2498
+ success: false,
2499
+ code: 'mesh_direct_peer_truth_unavailable',
2500
+ error: 'Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct get_mesh probes succeed.',
2501
+ sourceOfTruth,
2502
+ };
2503
+ }
2504
+ return { success: true, mesh: meshRecord.mesh, sourceOfTruth };
2290
2505
  }
2291
2506
 
2292
2507
  case 'create_mesh': {
@@ -3335,29 +3550,59 @@ export class DaemonCommandRouter {
3335
3550
  }
3336
3551
  if (workspace) {
3337
3552
  if (!fs.existsSync(workspace)) {
3338
- // Workspace not local — attempt a P2P git probe for remote nodes.
3553
+ // Workspace not local — prefer direct live inline truth, then attempt a P2P git probe.
3554
+ const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
3339
3555
  let remoteProbeApplied = false;
3340
- if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand) {
3556
+ if (inlineTransitGit) {
3557
+ status.git = inlineTransitGit;
3558
+ status.health = inlineTransitGit.isGitRepo
3559
+ ? deriveMeshNodeHealthFromGit(inlineTransitGit as unknown as Record<string, unknown>)
3560
+ : 'degraded';
3561
+ remoteProbeApplied = true;
3562
+ } else if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand) {
3341
3563
  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') {
3564
+ const remoteGit = await probeRemoteMeshGitStatus({
3565
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
3566
+ daemonId,
3567
+ workspace,
3568
+ timeoutMs: 8000,
3569
+ });
3570
+ if (remoteGit) {
3348
3571
  status.git = remoteGit;
3349
3572
  status.health = remoteGit.isGitRepo
3350
3573
  ? deriveMeshNodeHealthFromGit(remoteGit as unknown as Record<string, unknown>)
3351
3574
  : 'degraded';
3575
+ recordInlineMeshDirectGitTruth(node, remoteGit, 'selected_coordinator_mesh_p2p_git');
3352
3576
  remoteProbeApplied = true;
3353
3577
  }
3354
3578
  } catch {
3355
- // Probe timed out or P2P unavailable — fall back to cached status
3579
+ const refreshedConnection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
3580
+ const refreshedConnectionState = readStringValue(refreshedConnection?.state);
3581
+ if (refreshedConnection && refreshedConnectionState === 'connected') {
3582
+ status.connection = refreshedConnection;
3583
+ try {
3584
+ const remoteGit = await probeRemoteMeshGitStatus({
3585
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
3586
+ daemonId,
3587
+ workspace,
3588
+ timeoutMs: 12000,
3589
+ });
3590
+ if (remoteGit) {
3591
+ status.git = remoteGit;
3592
+ status.health = remoteGit.isGitRepo
3593
+ ? deriveMeshNodeHealthFromGit(remoteGit as unknown as Record<string, unknown>)
3594
+ : 'degraded';
3595
+ recordInlineMeshDirectGitTruth(node, remoteGit, 'selected_coordinator_mesh_p2p_git');
3596
+ remoteProbeApplied = true;
3597
+ }
3598
+ } catch {
3599
+ // Probe timed out again or P2P unavailable — fall back to cached status
3600
+ }
3601
+ }
3356
3602
  }
3357
3603
  }
3358
3604
  if (!remoteProbeApplied) {
3359
3605
  const connectionState = readStringValue((status.connection as any)?.state);
3360
- const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
3361
3606
  const pendingPeerGitProbe = !inlineTransitGit
3362
3607
  && !isSelfNode
3363
3608
  && !!daemonId
@@ -3377,12 +3622,12 @@ export class DaemonCommandRouter {
3377
3622
  node,
3378
3623
  pendingPeerGitProbe ? { skipGit: true, skipError: true, skipHealth: true } : undefined,
3379
3624
  )) {
3380
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3625
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
3381
3626
  nodeStatuses.push(status);
3382
3627
  continue;
3383
3628
  }
3384
3629
  if (meshRecord?.source === 'inline_cache' && !isSelfNode) {
3385
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3630
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
3386
3631
  nodeStatuses.push(status);
3387
3632
  continue;
3388
3633
  }
@@ -3391,6 +3636,7 @@ export class DaemonCommandRouter {
3391
3636
  try {
3392
3637
  const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 10_000, refreshUpstream: true });
3393
3638
  status.git = gitStatus;
3639
+ recordInlineMeshDirectGitTruth(node, gitStatus as unknown as Record<string, unknown>, 'selected_coordinator_local_git');
3394
3640
  if (gitStatus.isGitRepo) {
3395
3641
  status.health = deriveMeshNodeHealthFromGit(gitStatus as unknown as Record<string, unknown>);
3396
3642
  } else {
@@ -3406,7 +3652,7 @@ export class DaemonCommandRouter {
3406
3652
  } else {
3407
3653
  applyCachedInlineMeshNodeStatus(status, node);
3408
3654
  }
3409
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === 'online' || isSelfNode);
3655
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
3410
3656
  nodeStatuses.push(status);
3411
3657
  }
3412
3658