@adhdev/daemon-core 0.9.82-rc.4 → 0.9.82-rc.40

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.
@@ -26,6 +26,8 @@ import { getSavedProviderSessions } from '../config/saved-sessions.js';
26
26
  import { listProviderHistorySessions } from '../config/chat-history.js';
27
27
  import { detectIDEs } from '../detection/ide-detector.js';
28
28
  import { detectCLI } from '../detection/cli-detector.js';
29
+ import { getGitRepoStatus } from '../git/git-status.js';
30
+ import type { GitSubmoduleStatus } from '../git/git-types.js';
29
31
  import { SessionRegistry } from '../sessions/registry.js';
30
32
  import { LOG } from '../logging/logger.js';
31
33
  import { logCommand } from '../logging/command-log.js';
@@ -112,58 +114,44 @@ function readBooleanValue(...values: unknown[]): boolean | undefined {
112
114
  return undefined;
113
115
  }
114
116
 
115
- function buildCachedInlineMeshGitStatus(node: any): Record<string, unknown> | undefined {
116
- const cachedStatus = readObjectRecord(node?.cachedStatus);
117
- const cachedGit = readObjectRecord(cachedStatus.git);
118
- if (Object.keys(cachedGit).length) {
119
- const conflictFiles = Array.isArray(cachedGit.conflictFiles)
120
- ? cachedGit.conflictFiles.filter((value: unknown): value is string => typeof value === 'string')
121
- : [];
122
- const conflictCount = readNumberValue(cachedGit.conflicts) ?? conflictFiles.length;
123
- const hasConflicts = readBooleanValue(cachedGit.hasConflicts) ?? conflictCount > 0;
124
- const isGitRepo = readBooleanValue(cachedGit.isGitRepo);
125
- if (isGitRepo !== 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 {
127
+ if (!Array.isArray(value)) return undefined;
128
+ const submodules = value
129
+ .map(entry => {
130
+ const submodule = readObjectRecord(entry);
131
+ const path = readStringValue(submodule.path);
132
+ const commit = readStringValue(submodule.commit);
133
+ const repoPath = readStringValue(submodule.repoPath, submodule.repo_root)
134
+ ?? joinRepoPath(parentRepoRoot, path);
135
+ if (!path || !commit || !repoPath) return null;
126
136
  return {
127
- workspace: readStringValue(cachedGit.workspace, node?.workspace) || '',
128
- repoRoot: readStringValue(cachedGit.repoRoot, node?.repoRoot, node?.workspace) || null,
129
- isGitRepo,
130
- branch: readStringValue(cachedGit.branch) ?? null,
131
- headCommit: readStringValue(cachedGit.headCommit) ?? null,
132
- headMessage: readStringValue(cachedGit.headMessage) ?? null,
133
- upstream: readStringValue(cachedGit.upstream) ?? null,
134
- ahead: readNumberValue(cachedGit.ahead) ?? 0,
135
- behind: readNumberValue(cachedGit.behind) ?? 0,
136
- staged: readNumberValue(cachedGit.staged) ?? 0,
137
- modified: readNumberValue(cachedGit.modified) ?? 0,
138
- untracked: readNumberValue(cachedGit.untracked) ?? 0,
139
- deleted: readNumberValue(cachedGit.deleted) ?? 0,
140
- renamed: readNumberValue(cachedGit.renamed) ?? 0,
141
- hasConflicts,
142
- conflictFiles,
143
- stashCount: readNumberValue(cachedGit.stashCount) ?? 0,
144
- lastCheckedAt: readNumberValue(cachedGit.lastCheckedAt) ?? Date.now(),
137
+ path,
138
+ commit,
139
+ repoPath,
140
+ dirty: readBooleanValue(submodule.dirty) ?? false,
141
+ outOfSync: readBooleanValue(submodule.outOfSync, submodule.out_of_sync) ?? false,
142
+ lastCheckedAt: readNumberValue(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now(),
143
+ ...(readStringValue(submodule.error) ? { error: readStringValue(submodule.error) } : {}),
145
144
  };
146
- }
147
- }
145
+ })
146
+ .filter((entry): entry is GitSubmoduleStatus => entry !== null);
147
+ return submodules.length > 0 ? submodules : undefined;
148
+ }
148
149
 
149
- const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
150
- const gitResult = readObjectRecord(rawGit.result);
151
- const directStatus = readObjectRecord(rawGit.status);
152
- const nestedStatus = readObjectRecord(gitResult.status);
153
- const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
154
- const probeGit = readObjectRecord(rawProbe.git);
155
- const probeGitResult = readObjectRecord(probeGit.result);
156
- const probeDirectStatus = readObjectRecord(probeGit.status);
157
- const probeNestedStatus = readObjectRecord(probeGitResult.status);
158
- const status = Object.keys(directStatus).length
159
- ? directStatus
160
- : Object.keys(nestedStatus).length
161
- ? nestedStatus
162
- : Object.keys(probeDirectStatus).length
163
- ? probeDirectStatus
164
- : Object.keys(probeNestedStatus).length
165
- ? probeNestedStatus
166
- : {};
150
+ function normalizeInlineMeshGitStatus(
151
+ status: Record<string, unknown>,
152
+ node: any,
153
+ options?: { lastCheckedAt?: number },
154
+ ): Record<string, unknown> | undefined {
167
155
  const isGitRepo = readBooleanValue(status.isGitRepo);
168
156
  if (!Object.keys(status).length || isGitRepo === undefined) return undefined;
169
157
  const conflictFiles = Array.isArray(status.conflictFiles)
@@ -171,9 +159,11 @@ function buildCachedInlineMeshGitStatus(node: any): Record<string, unknown> | un
171
159
  : [];
172
160
  const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
173
161
  const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
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);
174
164
  return {
175
165
  workspace: readStringValue(status.workspace, node?.workspace) || '',
176
- repoRoot: readStringValue(status.repoRoot, node?.repoRoot, node?.workspace) || null,
166
+ repoRoot: repoRoot ?? null,
177
167
  isGitRepo,
178
168
  branch: readStringValue(status.branch) ?? null,
179
169
  headCommit: readStringValue(status.headCommit) ?? null,
@@ -189,30 +179,544 @@ function buildCachedInlineMeshGitStatus(node: any): Record<string, unknown> | un
189
179
  hasConflicts,
190
180
  conflictFiles,
191
181
  stashCount: readNumberValue(status.stashCount) ?? 0,
192
- lastCheckedAt: Date.now(),
182
+ lastCheckedAt: options?.lastCheckedAt ?? readNumberValue(status.lastCheckedAt) ?? Date.now(),
183
+ ...(submodules ? { submodules } : {}),
184
+ };
185
+ }
186
+
187
+ function buildInlineMeshTransitGitStatus(node: any): Record<string, unknown> | undefined {
188
+ const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
189
+ const gitResult = readObjectRecord(rawGit.result);
190
+ const directStatus = readObjectRecord(rawGit.status);
191
+ const nestedStatus = readObjectRecord(gitResult.status);
192
+ const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
193
+ const probeGit = readObjectRecord(rawProbe.git);
194
+ const probeGitResult = readObjectRecord(probeGit.result);
195
+ const probeDirectStatus = readObjectRecord(probeGit.status);
196
+ 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() });
207
+ }
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,
193
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
+
234
+ function buildCachedInlineMeshGitStatus(node: any): Record<string, unknown> | undefined {
235
+ const liveGit = buildInlineMeshTransitGitStatus(node);
236
+ if (liveGit) return liveGit;
237
+
238
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
239
+ const cachedGit = readObjectRecord(cachedStatus.git);
240
+ if (!Object.keys(cachedGit).length) return undefined;
241
+ return normalizeInlineMeshGitStatus(cachedGit, node);
242
+ }
243
+
244
+ function shouldDiscardCachedInlineMeshStatus(node: any): boolean {
245
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
246
+ if (!Object.keys(cachedStatus).length) return false;
247
+ const cachedGit = readObjectRecord(cachedStatus.git);
248
+ const workspaceError = readStringValue(cachedStatus.error, node?.error);
249
+ if (workspaceError && /workspace must be an existing directory/i.test(workspaceError)) return true;
250
+ const isGitRepo = readBooleanValue(cachedGit.isGitRepo);
251
+ const branch = readStringValue(cachedGit.branch);
252
+ const headCommit = readStringValue(cachedGit.headCommit);
253
+ return isGitRepo === false && !branch && !headCommit;
254
+ }
255
+
256
+ function stripInlineMeshTransientNodeState(node: any): any {
257
+ if (!node || typeof node !== 'object' || Array.isArray(node)) return node;
258
+ const {
259
+ cachedStatus,
260
+ lastGit: _lastGit,
261
+ last_git: _lastGitLegacy,
262
+ lastProbe: _lastProbe,
263
+ last_probe: _lastProbeLegacy,
264
+ error: _error,
265
+ health: _health,
266
+ machineStatus: _machineStatus,
267
+ lastSeenAt: _lastSeenAt,
268
+ last_seen_at: _lastSeenAtLegacy,
269
+ updatedAt: _updatedAt,
270
+ updated_at: _updatedAtLegacy,
271
+ activeSession: _activeSession,
272
+ active_session: _activeSessionLegacy,
273
+ activeSessionId: _activeSessionId,
274
+ active_session_id: _activeSessionIdLegacy,
275
+ sessionId: _sessionId,
276
+ session_id: _sessionIdLegacy,
277
+ providerType: _providerType,
278
+ provider_type: _providerTypeLegacy,
279
+ ...rest
280
+ } = node as Record<string, unknown>;
281
+ if (cachedStatus && !shouldDiscardCachedInlineMeshStatus(node)) {
282
+ return { ...rest, cachedStatus };
283
+ }
284
+ return rest;
285
+ }
286
+
287
+ function hasInlineMeshTransientNodeState(node: any): boolean {
288
+ if (!node || typeof node !== 'object' || Array.isArray(node)) return false;
289
+ return 'cachedStatus' in node
290
+ || 'lastGit' in node
291
+ || 'last_git' in node
292
+ || 'lastProbe' in node
293
+ || 'last_probe' in node
294
+ || 'error' in node
295
+ || 'health' in node
296
+ || 'machineStatus' in node
297
+ || 'lastSeenAt' in node
298
+ || 'last_seen_at' in node
299
+ || 'updatedAt' in node
300
+ || 'updated_at' in node
301
+ || 'activeSession' in node
302
+ || 'active_session' in node
303
+ || 'activeSessionId' in node
304
+ || 'active_session_id' in node
305
+ || 'sessionId' in node
306
+ || 'session_id' in node
307
+ || 'providerType' 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));
315
+ }
316
+
317
+ function readInlineMeshNodeId(node: any): string {
318
+ return readStringValue(node?.id, node?.nodeId) || '';
319
+ }
320
+
321
+ function sanitizeInlineMesh(inlineMesh: any): any {
322
+ if (!inlineMesh || typeof inlineMesh !== 'object' || Array.isArray(inlineMesh)) return inlineMesh;
323
+ if (!Array.isArray(inlineMesh.nodes)) return inlineMesh;
324
+ let changed = false;
325
+ const nodes = inlineMesh.nodes.map((node: any) => {
326
+ if (!hasInlineMeshTransientNodeState(node)) return node;
327
+ changed = true;
328
+ return stripInlineMeshTransientNodeState(node);
329
+ });
330
+ if (!changed) return inlineMesh;
331
+ return {
332
+ ...inlineMesh,
333
+ nodes,
334
+ };
335
+ }
336
+
337
+ function reconcileInlineMeshCache(cached: any, incoming: any): any {
338
+ if (!cached || typeof cached !== 'object' || Array.isArray(cached)) return incoming;
339
+ if (!incoming || typeof incoming !== 'object' || Array.isArray(incoming)) return cached;
340
+ const cachedNodes = Array.isArray(cached.nodes) ? cached.nodes : [];
341
+ const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
342
+ if (!cachedNodes.length || !incomingNodes.length) return { ...cached, ...incoming };
343
+
344
+ const incomingById = new Map<string, any>();
345
+ for (const node of incomingNodes) {
346
+ const nodeId = readInlineMeshNodeId(node);
347
+ if (nodeId) incomingById.set(nodeId, node);
348
+ }
349
+
350
+ const nodes = cachedNodes.map((cachedNode: any) => {
351
+ const nodeId = readInlineMeshNodeId(cachedNode);
352
+ const incomingNode = nodeId ? incomingById.get(nodeId) : undefined;
353
+ if (!incomingNode) return cachedNode;
354
+ if (hasInlineMeshTransientNodeState(incomingNode)) {
355
+ return { ...cachedNode, ...incomingNode };
356
+ }
357
+ return { ...stripInlineMeshTransientNodeState(cachedNode), ...incomingNode };
358
+ });
359
+
360
+ return {
361
+ ...cached,
362
+ ...incoming,
363
+ nodes,
364
+ };
365
+ }
366
+
367
+ function hasGitWorktreeChanges(git: Record<string, unknown> | null | undefined): boolean {
368
+ if (!git) return false;
369
+ return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
370
+ }
371
+
372
+ function getGitSubmoduleDriftState(git: Record<string, unknown> | null | undefined): { dirty: boolean; outOfSync: boolean } {
373
+ const submodules = Array.isArray(git?.submodules) ? git.submodules : [];
374
+ let dirty = false;
375
+ let outOfSync = false;
376
+ for (const entry of submodules) {
377
+ const submodule = readObjectRecord(entry);
378
+ if (readBooleanValue(submodule.dirty) === true) dirty = true;
379
+ if (readBooleanValue(submodule.outOfSync) === true || !!readStringValue(submodule.error)) outOfSync = true;
380
+ }
381
+ return { dirty, outOfSync };
382
+ }
383
+
384
+ function deriveMeshNodeHealthFromGit(git: Record<string, unknown> | null | undefined): 'online' | 'dirty' | 'degraded' {
385
+ if (!git || readBooleanValue(git.isGitRepo) === false) return 'degraded';
386
+ const branch = readStringValue(git.branch);
387
+ if (!branch) return 'degraded';
388
+ const submoduleDrift = getGitSubmoduleDriftState(git);
389
+ if (submoduleDrift.outOfSync) return 'degraded';
390
+ if (submoduleDrift.dirty || hasGitWorktreeChanges(git)) return 'dirty';
391
+ return 'online';
392
+ }
393
+
394
+ function readCachedInlineMeshActiveSessions(node: any): string[] {
395
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
396
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
397
+ const fallbackSession = Object.keys(activeSession).length
398
+ ? activeSession
399
+ : readObjectRecord(node?.activeSession ?? node?.active_session);
400
+ const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
401
+ return sessionId ? [sessionId] : [];
402
+ }
403
+
404
+ function readCachedInlineMeshActiveSessionDetails(node: any): Array<Record<string, unknown>> {
405
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
406
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
407
+ const fallbackSession = Object.keys(activeSession).length
408
+ ? activeSession
409
+ : readObjectRecord(node?.activeSession ?? node?.active_session);
410
+ const sessionId = readStringValue(
411
+ fallbackSession.id,
412
+ fallbackSession.sessionId,
413
+ fallbackSession.session_id,
414
+ node?.activeSessionId,
415
+ node?.active_session_id,
416
+ node?.sessionId,
417
+ node?.session_id,
418
+ );
419
+ if (!sessionId) return [];
420
+ return [{
421
+ sessionId,
422
+ providerType: readStringValue(
423
+ fallbackSession.providerType,
424
+ fallbackSession.provider_type,
425
+ fallbackSession.cliType,
426
+ fallbackSession.cli_type,
427
+ fallbackSession.provider,
428
+ node?.providerType,
429
+ node?.provider_type,
430
+ ),
431
+ state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
432
+ lifecycle: readStringValue(fallbackSession.lifecycle),
433
+ title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
434
+ workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
435
+ lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
436
+ recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
437
+ isCached: true,
438
+ }];
439
+ }
440
+
441
+ function readLiveMeshSessionState(record: any): string | undefined {
442
+ return readStringValue(
443
+ record?.meta?.sessionStatus,
444
+ record?.meta?.status,
445
+ record?.meta?.providerStatus,
446
+ record?.status,
447
+ record?.state,
448
+ record?.lifecycle,
449
+ );
450
+ }
451
+
452
+ function toIsoTimestamp(value: unknown): string | null {
453
+ if (typeof value === 'number' && Number.isFinite(value)) return new Date(value).toISOString();
454
+ const stringValue = readStringValue(value);
455
+ return stringValue || null;
456
+ }
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
+
604
+ function summarizeMeshSessionRecord(record: any): Record<string, unknown> {
605
+ return {
606
+ sessionId: readStringValue(record?.sessionId) || 'unknown',
607
+ providerType: readStringValue(record?.providerType),
608
+ state: readLiveMeshSessionState(record),
609
+ lifecycle: readStringValue(record?.lifecycle),
610
+ surfaceKind: getSessionHostSurfaceKind(record as any),
611
+ recoveryState: readStringValue(record?.meta?.runtimeRecoveryState) ?? null,
612
+ workspace: readStringValue(record?.workspace) ?? null,
613
+ title: readStringValue(record?.displayName, record?.workspaceLabel) ?? null,
614
+ lastActivityAt: toIsoTimestamp(record?.updatedAt ?? record?.lastActivityAt ?? record?.last_activity_at),
615
+ isCached: false,
616
+ };
617
+ }
618
+
619
+ function liveSessionRecordMatchesMeshNode(record: any, meshId: string, nodeId: string): boolean {
620
+ const recordNodeId = readStringValue(record?.meta?.meshNodeId);
621
+ if (!recordNodeId || recordNodeId !== nodeId) return false;
622
+ const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
623
+ return !recordMeshId || recordMeshId === meshId;
194
624
  }
195
625
 
196
- function applyCachedInlineMeshNodeStatus(status: Record<string, unknown>, node: any): boolean {
626
+ function liveSessionRecordMatchesMeshWorkspace(record: any, meshId: string, workspace: string): boolean {
627
+ const recordWorkspace = readStringValue(record?.workspace);
628
+ if (!recordWorkspace || !workspace || recordWorkspace !== workspace) return false;
629
+
630
+ const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
631
+ if (recordMeshId) return recordMeshId === meshId;
632
+
633
+ return record?.meta?.launchedByCoordinator === true || !!readStringValue(record?.meta?.meshNodeId);
634
+ }
635
+
636
+ function readLiveMeshNodeWorkspace(args: {
637
+ meshId: string;
638
+ nodeId: string;
639
+ liveSessionRecords: any[];
640
+ allowCoordinatorSession?: boolean;
641
+ }): string {
642
+ const directNodeWorkspace = args.liveSessionRecords.find((record) => (
643
+ liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)
644
+ && readStringValue(record?.workspace)
645
+ ));
646
+ if (directNodeWorkspace) {
647
+ return readStringValue(directNodeWorkspace.workspace) || '';
648
+ }
649
+
650
+ if (args.allowCoordinatorSession) {
651
+ const coordinatorWorkspace = args.liveSessionRecords.find((record) => (
652
+ readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId
653
+ && readStringValue(record?.workspace)
654
+ ));
655
+ if (coordinatorWorkspace) {
656
+ return readStringValue(coordinatorWorkspace.workspace) || '';
657
+ }
658
+ }
659
+
660
+ return '';
661
+ }
662
+
663
+ function collectLiveMeshSessionRecords(args: {
664
+ meshId: string;
665
+ node: any;
666
+ nodeId: string;
667
+ liveSessionRecords: any[];
668
+ allowCoordinatorSession?: boolean;
669
+ }): any[] {
670
+ const matches = args.liveSessionRecords.filter((record) => {
671
+ const nodeWorkspace = readStringValue(args.node?.workspace);
672
+ if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)) return true;
673
+ return !!nodeWorkspace && liveSessionRecordMatchesMeshWorkspace(record, args.meshId, nodeWorkspace);
674
+ });
675
+
676
+ if (args.allowCoordinatorSession) {
677
+ for (const record of args.liveSessionRecords) {
678
+ if (readStringValue(record?.meta?.meshCoordinatorFor) !== args.meshId) continue;
679
+ const sessionId = readStringValue(record?.sessionId);
680
+ if (sessionId && matches.some((entry) => readStringValue(entry?.sessionId) === sessionId)) continue;
681
+ matches.push(record);
682
+ }
683
+ }
684
+
685
+ return matches;
686
+ }
687
+
688
+ function applyCachedInlineMeshNodeStatus(
689
+ status: Record<string, unknown>,
690
+ node: any,
691
+ options?: { skipGit?: boolean; skipError?: boolean; skipHealth?: boolean },
692
+ ): boolean {
197
693
  const cachedStatus = readObjectRecord(node?.cachedStatus);
198
- const git = buildCachedInlineMeshGitStatus(node);
199
- const error = readStringValue(cachedStatus.error, node?.error);
200
- const health = readStringValue(cachedStatus.health, node?.health);
694
+ const liveGit = buildInlineMeshTransitGitStatus(node);
695
+ const git = options?.skipGit ? undefined : (liveGit ?? buildCachedInlineMeshGitStatus(node));
696
+ const error = options?.skipError ? undefined : (liveGit ? undefined : readStringValue(cachedStatus.error, node?.error));
697
+ const health = options?.skipHealth ? undefined : (liveGit ? undefined : readStringValue(cachedStatus.health, node?.health));
201
698
  const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
202
- if (!git && !error && !health) return false;
203
- if (!machineStatus && !git && !error) return false;
699
+ const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
700
+ const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
701
+ const activeSessions = readCachedInlineMeshActiveSessions(node);
702
+ const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
703
+ if (!git && !error && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
204
704
  if (git) status.git = git;
205
705
  if (error) status.error = error;
706
+ if (machineStatus) status.machineStatus = machineStatus;
707
+ if (lastSeenAt) status.lastSeenAt = lastSeenAt;
708
+ if (updatedAt) status.updatedAt = updatedAt;
709
+ if (activeSessions.length > 0) status.activeSessions = activeSessions;
710
+ if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
206
711
  if (health) {
207
712
  status.health = health;
208
713
  return true;
209
714
  }
210
715
  if (git) {
211
- const dirty = Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
212
- status.health = git.isGitRepo === false ? 'degraded' : dirty ? 'dirty' : 'online';
716
+ status.health = deriveMeshNodeHealthFromGit(git);
213
717
  return true;
214
718
  }
215
- return false;
719
+ return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
216
720
  }
217
721
 
218
722
  async function resolveProviderTypeFromPriority(args: {
@@ -265,11 +769,29 @@ type MeshRefineValidationSummary = {
265
769
  outputLimitBytes: number;
266
770
  };
267
771
 
772
+ type MeshRefineStageStatus = 'passed' | 'failed' | 'skipped';
773
+
774
+ type MeshRefinePatchEquivalenceSummary = {
775
+ status: MeshRefineStageStatus;
776
+ equivalent: boolean;
777
+ baseHead: string;
778
+ branchHead: string;
779
+ mergeBase?: string;
780
+ mergedTree?: string;
781
+ expectedPatchId?: string;
782
+ actualPatchId?: string;
783
+ durationMs: number;
784
+ error?: string;
785
+ stdout?: string;
786
+ stderr?: string;
787
+ };
788
+
268
789
  const REFINE_VALIDATION_CATEGORIES = ['typecheck', 'test', 'lint', 'build'] as const;
269
790
  const REFINE_VALIDATION_TIMEOUT_MS = 120_000;
270
791
  const REFINE_VALIDATION_OUTPUT_LIMIT_BYTES = 128 * 1024;
271
792
  const REFINE_VALIDATION_SUMMARY_CHARS = 2_000;
272
793
  const REFINE_VALIDATION_MAX_COMMANDS = 4;
794
+ const REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
273
795
 
274
796
  function truncateValidationOutput(value: unknown): string {
275
797
  const text = typeof value === 'string' ? value : value == null ? '' : String(value);
@@ -277,6 +799,95 @@ function truncateValidationOutput(value: unknown): string {
277
799
  return `${text.slice(0, REFINE_VALIDATION_SUMMARY_CHARS)}\n[truncated ${text.length - REFINE_VALIDATION_SUMMARY_CHARS} chars]`;
278
800
  }
279
801
 
802
+ function recordMeshRefineStage(
803
+ stages: Array<Record<string, unknown>>,
804
+ stage: string,
805
+ status: MeshRefineStageStatus,
806
+ startedAt: number,
807
+ details?: Record<string, unknown>,
808
+ ): void {
809
+ stages.push({
810
+ stage,
811
+ status,
812
+ durationMs: Date.now() - startedAt,
813
+ ...(details || {}),
814
+ });
815
+ }
816
+
817
+ async function computeGitPatchId(cwd: string, fromRef: string, toRef: string): Promise<string> {
818
+ const { execFileSync } = await import('node:child_process');
819
+ const diff = execFileSync('git', ['diff', '--patch', '--full-index', fromRef, toRef], {
820
+ cwd,
821
+ encoding: 'utf8',
822
+ maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES,
823
+ });
824
+ if (!diff.trim()) return '';
825
+ const patchId = execFileSync('git', ['patch-id', '--stable'], {
826
+ cwd,
827
+ input: diff,
828
+ encoding: 'utf8',
829
+ maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES,
830
+ }).trim();
831
+ return patchId.split(/\s+/)[0] || '';
832
+ }
833
+
834
+ async function runMeshRefinePatchEquivalenceGate(
835
+ repoRoot: string,
836
+ baseHead: string,
837
+ branchHead: string,
838
+ ): Promise<MeshRefinePatchEquivalenceSummary> {
839
+ const startedAt = Date.now();
840
+ try {
841
+ const { execFileSync } = await import('node:child_process');
842
+ const git = (args: string[]) => execFileSync('git', args, {
843
+ cwd: repoRoot,
844
+ encoding: 'utf8',
845
+ maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES,
846
+ });
847
+ const mergeBase = git(['merge-base', baseHead, branchHead]).trim();
848
+ const mergeTreeStdout = git(['merge-tree', '--write-tree', baseHead, branchHead]);
849
+ const mergedTree = mergeTreeStdout.trim().split(/\s+/)[0] || '';
850
+ if (!mergeBase || !mergedTree) {
851
+ return {
852
+ status: 'failed',
853
+ equivalent: false,
854
+ baseHead,
855
+ branchHead,
856
+ mergeBase: mergeBase || undefined,
857
+ mergedTree: mergedTree || undefined,
858
+ durationMs: Date.now() - startedAt,
859
+ error: 'patch equivalence preflight could not resolve merge-base or synthetic merge tree',
860
+ stdout: truncateValidationOutput(mergeTreeStdout),
861
+ };
862
+ }
863
+ const expectedPatchId = await computeGitPatchId(repoRoot, mergeBase, branchHead);
864
+ const actualPatchId = await computeGitPatchId(repoRoot, baseHead, mergedTree);
865
+ const equivalent = expectedPatchId === actualPatchId;
866
+ return {
867
+ status: equivalent ? 'passed' : 'failed',
868
+ equivalent,
869
+ baseHead,
870
+ branchHead,
871
+ mergeBase,
872
+ mergedTree,
873
+ expectedPatchId,
874
+ actualPatchId,
875
+ durationMs: Date.now() - startedAt,
876
+ };
877
+ } catch (e: any) {
878
+ return {
879
+ status: 'failed',
880
+ equivalent: false,
881
+ baseHead,
882
+ branchHead,
883
+ durationMs: Date.now() - startedAt,
884
+ error: e?.message || String(e),
885
+ stdout: truncateValidationOutput(e?.stdout),
886
+ stderr: truncateValidationOutput(e?.stderr),
887
+ };
888
+ }
889
+ }
890
+
280
891
  function readPackageScripts(workspace: string): Record<string, string> {
281
892
  try {
282
893
  const packageJsonPath = pathJoin(workspace, 'package.json');
@@ -632,6 +1243,10 @@ export interface CommandRouterDeps {
632
1243
  statusVersion?: string;
633
1244
  /** Session host control plane */
634
1245
  sessionHostControl?: SessionHostControlPlane | null;
1246
+ /** Selected-coordinator mesh peer telemetry surface for target daemons, when supported by the runtime. */
1247
+ getMeshPeerConnectionStatus?: (daemonId: string) => Record<string, unknown> | null;
1248
+ /** Dispatch a command to a remote mesh node via P2P/relay. Injected by cloud runtime; absent in standalone. */
1249
+ dispatchMeshCommand?: (daemonId: string, cmd: string, args: Record<string, unknown>) => Promise<unknown>;
635
1250
  }
636
1251
 
637
1252
  export interface CommandRouterResult {
@@ -749,36 +1364,114 @@ export class DaemonCommandRouter {
749
1364
  * Allows the MCP server to query mesh data via get_mesh even when
750
1365
  * the mesh doesn't exist in the local meshes.json file. */
751
1366
  private inlineMeshCache = new Map<string, any>();
1367
+ /** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default. */
1368
+ private aggregateMeshStatusCache = new Map<string, { builtAt: number; snapshot: any }>();
752
1369
 
753
1370
  constructor(deps: CommandRouterDeps) {
754
1371
  this.deps = deps;
755
1372
  }
756
1373
 
1374
+ private cloneJsonValue<T>(value: T): T {
1375
+ if (typeof structuredClone === 'function') return structuredClone(value);
1376
+ return JSON.parse(JSON.stringify(value)) as T;
1377
+ }
1378
+
1379
+ private getCachedAggregateMeshStatus(meshId: string): any | null {
1380
+ const cached = this.aggregateMeshStatusCache.get(meshId);
1381
+ if (!cached?.snapshot || cached.snapshot.success !== true || !Array.isArray(cached.snapshot.nodes)) return null;
1382
+ const snapshot = this.cloneJsonValue(cached.snapshot);
1383
+ const ageMs = Math.max(0, Date.now() - cached.builtAt);
1384
+ const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === 'object'
1385
+ ? snapshot.sourceOfTruth
1386
+ : {};
1387
+ snapshot.sourceOfTruth = {
1388
+ ...sourceOfTruth,
1389
+ aggregateSnapshot: {
1390
+ ...(sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === 'object'
1391
+ ? sourceOfTruth.aggregateSnapshot
1392
+ : {}),
1393
+ owner: 'coordinator_daemon_memory',
1394
+ cached: true,
1395
+ source: 'memory',
1396
+ refreshReason: 'memory_cache_hit',
1397
+ ageMs,
1398
+ cachedAt: new Date(cached.builtAt).toISOString(),
1399
+ returnedAt: new Date().toISOString(),
1400
+ },
1401
+ };
1402
+ return snapshot;
1403
+ }
1404
+
1405
+ private rememberAggregateMeshStatus(meshId: string, snapshot: any, refreshReason: string): any {
1406
+ if (!snapshot || typeof snapshot !== 'object' || snapshot.success !== true || !Array.isArray(snapshot.nodes)) return snapshot;
1407
+ const builtAt = Date.now();
1408
+ const next = this.cloneJsonValue(snapshot);
1409
+ const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === 'object'
1410
+ ? next.sourceOfTruth
1411
+ : {};
1412
+ next.sourceOfTruth = {
1413
+ ...sourceOfTruth,
1414
+ aggregateSnapshot: {
1415
+ owner: 'coordinator_daemon_memory',
1416
+ cached: false,
1417
+ source: 'live_refresh',
1418
+ refreshReason,
1419
+ ageMs: 0,
1420
+ cachedAt: new Date(builtAt).toISOString(),
1421
+ returnedAt: new Date(builtAt).toISOString(),
1422
+ },
1423
+ };
1424
+ this.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: this.cloneJsonValue(next) });
1425
+ return next;
1426
+ }
1427
+
757
1428
  public getCachedInlineMesh(meshId: string, inlineMesh?: unknown): any | undefined {
758
1429
  if (inlineMesh && typeof inlineMesh === 'object') {
759
- this.inlineMeshCache.set(meshId, inlineMesh as any);
760
- return inlineMesh as any;
1430
+ return this.warmInlineMeshCache(meshId, inlineMesh);
761
1431
  }
762
1432
  return this.inlineMeshCache.get(meshId);
763
1433
  }
764
1434
 
1435
+ private warmInlineMeshCache(meshId: string, inlineMesh?: unknown): any | undefined {
1436
+ if (!inlineMesh || typeof inlineMesh !== 'object') return undefined;
1437
+ const sanitizedInlineMesh = sanitizeInlineMesh(inlineMesh as any);
1438
+ const cached = this.inlineMeshCache.get(meshId);
1439
+ if (cached) {
1440
+ const merged = reconcileInlineMeshCache(cached, sanitizedInlineMesh);
1441
+ this.inlineMeshCache.set(meshId, merged);
1442
+ return merged;
1443
+ }
1444
+ this.inlineMeshCache.set(meshId, sanitizedInlineMesh as any);
1445
+ return sanitizedInlineMesh as any;
1446
+ }
1447
+
765
1448
  private async getMeshForCommand(
766
1449
  meshId: string,
767
1450
  inlineMesh?: unknown,
768
1451
  options?: { preferInline?: boolean },
769
- ): Promise<{ mesh: any; inline: boolean } | null> {
1452
+ ): Promise<{ mesh: any; inline: boolean; source: 'inline_cache' | 'inline_bootstrap' | 'local_config' } | null> {
770
1453
  const preferInline = options?.preferInline === true;
771
1454
  if (preferInline) {
772
- const cached = this.getCachedInlineMesh(meshId, inlineMesh);
773
- if (cached) return { mesh: cached, inline: true };
1455
+ const cached = this.getCachedInlineMesh(meshId);
1456
+ if (cached) return { mesh: cached, inline: true, source: 'inline_cache' };
1457
+ if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
1458
+ this.warmInlineMeshCache(meshId, inlineMesh);
1459
+ return { mesh: inlineMesh, inline: true, source: 'inline_bootstrap' };
1460
+ }
774
1461
  }
775
1462
  try {
776
1463
  const { getMesh } = await import('../config/mesh-config.js');
777
1464
  const mesh = getMesh(meshId);
778
- if (mesh) return { mesh, inline: false };
1465
+ if (mesh) return { mesh, inline: false, source: 'local_config' };
779
1466
  } catch { /* fall through to inline cache */ }
780
- const cached = this.getCachedInlineMesh(meshId, inlineMesh);
781
- return cached ? { mesh: cached, inline: true } : null;
1467
+ const cached = this.getCachedInlineMesh(meshId);
1468
+ if (cached) return { mesh: cached, inline: true, source: 'inline_cache' };
1469
+ const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
1470
+ return warmedInline ? { mesh: warmedInline, inline: true, source: 'inline_bootstrap' } : null;
1471
+ }
1472
+
1473
+ private invalidateAggregateMeshStatus(meshId: string): void {
1474
+ this.aggregateMeshStatusCache.delete(meshId);
782
1475
  }
783
1476
 
784
1477
  private updateInlineMeshNode(meshId: string, mesh: any, node: any): void {
@@ -788,6 +1481,7 @@ export class DaemonCommandRouter {
788
1481
  else mesh.nodes.push(node);
789
1482
  mesh.updatedAt = new Date().toISOString();
790
1483
  this.inlineMeshCache.set(meshId, mesh);
1484
+ this.invalidateAggregateMeshStatus(meshId);
791
1485
  }
792
1486
 
793
1487
  private removeInlineMeshNode(meshId: string, mesh: any, nodeId: string): boolean {
@@ -797,6 +1491,7 @@ export class DaemonCommandRouter {
797
1491
  mesh.nodes.splice(idx, 1);
798
1492
  mesh.updatedAt = new Date().toISOString();
799
1493
  this.inlineMeshCache.set(meshId, mesh);
1494
+ this.invalidateAggregateMeshStatus(meshId);
800
1495
  return true;
801
1496
  }
802
1497
 
@@ -1075,6 +1770,7 @@ export class DaemonCommandRouter {
1075
1770
  const deletedSessionIds: string[] = [];
1076
1771
  const skippedSessionIds: string[] = [];
1077
1772
  const skippedLiveSessionIds: string[] = [];
1773
+ const skippedCoordinatorSessionIds: string[] = [];
1078
1774
  const deleteUnsupportedSessionIds: string[] = [];
1079
1775
  const recordsRemainSessionIds: string[] = [];
1080
1776
  const errors: Array<{ sessionId: string; error: string }> = [];
@@ -1109,6 +1805,12 @@ export class DaemonCommandRouter {
1109
1805
  const completed = this.isCompletedHostedSession(record);
1110
1806
  const surfaceKind = getSessionHostSurfaceKind(record);
1111
1807
  const liveRuntime = surfaceKind === 'live_runtime';
1808
+ const coordinatorSession = readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId;
1809
+ if (!hasExplicitSessionIds && coordinatorSession) {
1810
+ skippedSessionIds.push(sessionId);
1811
+ skippedCoordinatorSessionIds.push(sessionId);
1812
+ continue;
1813
+ }
1112
1814
  if (!hasExplicitSessionIds && liveRuntime) {
1113
1815
  skippedSessionIds.push(sessionId);
1114
1816
  skippedLiveSessionIds.push(sessionId);
@@ -1178,6 +1880,7 @@ export class DaemonCommandRouter {
1178
1880
  deletedSessionIds,
1179
1881
  skippedSessionIds,
1180
1882
  skippedLiveSessionIds,
1883
+ skippedCoordinatorSessionIds,
1181
1884
  ...(deleteUnsupported ? {
1182
1885
  deleteUnsupported: true,
1183
1886
  effectiveCleanup: args.mode === 'stop_and_delete'
@@ -1332,7 +2035,8 @@ export class DaemonCommandRouter {
1332
2035
  }
1333
2036
 
1334
2037
  case 'get_pending_mesh_events': {
1335
- const events = drainPendingMeshCoordinatorEvents();
2038
+ const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
2039
+ const events = drainPendingMeshCoordinatorEvents(meshId || undefined);
1336
2040
  return { success: true, events };
1337
2041
  }
1338
2042
 
@@ -1937,15 +2641,44 @@ export class DaemonCommandRouter {
1937
2641
  case 'get_mesh': {
1938
2642
  const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
1939
2643
  if (!meshId) return { success: false, error: 'meshId required' };
1940
- try {
1941
- const { getMesh } = await import('../config/mesh-config.js');
1942
- const mesh = getMesh(meshId);
1943
- if (mesh) return { success: true, mesh };
1944
- } catch { /* fall through to inline cache */ }
1945
- // Fallback: check in-memory cache for cloud-originating meshes
1946
- const cached = this.inlineMeshCache.get(meshId);
1947
- if (cached) return { success: true, mesh: cached };
1948
- return { success: false, error: 'Mesh not found' };
2644
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
2645
+ if (!meshRecord?.mesh) return { success: false, error: 'Mesh not found' };
2646
+
2647
+ const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
2648
+ const directTruth = await hydrateInlineMeshDirectTruth({
2649
+ mesh: meshRecord.mesh,
2650
+ meshSource: meshRecord.source,
2651
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
2652
+ statusInstanceId: this.deps.statusInstanceId,
2653
+ localMachineId: loadConfig().machineId || '',
2654
+ });
2655
+ const directTruthSatisfied = meshRecord.source !== 'inline_bootstrap' || directTruth.directEvidenceCount > 0;
2656
+ const sourceOfTruth = {
2657
+ membership: meshRecord.source === 'inline_cache'
2658
+ ? 'coordinator_inline_mesh_cache'
2659
+ : meshRecord.source === 'local_config'
2660
+ ? 'local_mesh_config'
2661
+ : 'inline_bootstrap_snapshot',
2662
+ coordinatorOwnsLiveTruth: directTruthSatisfied,
2663
+ directPeerTruth: {
2664
+ required: requireDirectPeerTruth,
2665
+ satisfied: directTruthSatisfied,
2666
+ directEvidenceCount: directTruth.directEvidenceCount,
2667
+ localConfirmedCount: directTruth.localConfirmedCount,
2668
+ peerAttemptedCount: directTruth.peerAttemptedCount,
2669
+ peerConfirmedCount: directTruth.peerConfirmedCount,
2670
+ unavailableNodeIds: directTruth.unavailableNodeIds,
2671
+ },
2672
+ };
2673
+ if (requireDirectPeerTruth && !directTruthSatisfied) {
2674
+ return {
2675
+ success: false,
2676
+ code: 'mesh_direct_peer_truth_unavailable',
2677
+ error: 'Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct get_mesh probes succeed.',
2678
+ sourceOfTruth,
2679
+ };
2680
+ }
2681
+ return { success: true, mesh: meshRecord.mesh, sourceOfTruth };
1949
2682
  }
1950
2683
 
1951
2684
  case 'create_mesh': {
@@ -1977,6 +2710,7 @@ export class DaemonCommandRouter {
1977
2710
  const mesh = updateMesh(meshId, patch as any);
1978
2711
  if (!mesh) return { success: false, error: 'Mesh not found' };
1979
2712
  this.inlineMeshCache.set(meshId, mesh);
2713
+ this.invalidateAggregateMeshStatus(meshId);
1980
2714
  return { success: true, mesh };
1981
2715
  } catch (e: any) {
1982
2716
  return { success: false, error: e.message };
@@ -2191,34 +2925,49 @@ export class DaemonCommandRouter {
2191
2925
  const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
2192
2926
  const nodeId = typeof args?.nodeId === 'string' ? args.nodeId.trim() : '';
2193
2927
  if (!meshId || !nodeId) return { success: false, error: 'meshId and nodeId required' };
2928
+ const refineStages: Array<Record<string, unknown>> = [];
2194
2929
  try {
2195
2930
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
2196
2931
  const mesh = meshRecord?.mesh;
2197
2932
  const node = mesh?.nodes?.find((n: any) => n.id === nodeId || n.nodeId === nodeId);
2198
- if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
2933
+ if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh`, refineStages };
2199
2934
 
2200
2935
  if (!node.isLocalWorktree || !node.workspace) {
2201
- return { success: false, error: `Refinery requires a local worktree node` };
2936
+ return { success: false, error: `Refinery requires a local worktree node`, refineStages };
2202
2937
  }
2203
2938
 
2204
2939
  const sourceNode = node.clonedFromNodeId
2205
2940
  ? mesh?.nodes.find((n: any) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId)
2206
2941
  : mesh?.nodes.find((n: any) => !n.isLocalWorktree);
2207
2942
  const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
2208
- if (!repoRoot) return { success: false, error: 'Source node repoRoot not found' };
2943
+ if (!repoRoot) return { success: false, error: 'Source node repoRoot not found', refineStages };
2209
2944
 
2210
2945
  const { execFile } = await import('node:child_process');
2211
2946
  const { promisify } = await import('node:util');
2212
2947
  const execFileAsync = promisify(execFile);
2213
2948
 
2949
+ const resolveStarted = Date.now();
2214
2950
  const { stdout: branchStdout } = await execFileAsync('git', ['branch', '--show-current'], { cwd: node.workspace, encoding: 'utf8' });
2215
2951
  const branch = branchStdout.trim();
2216
- if (!branch) return { success: false, error: 'Could not determine branch of the worktree node' };
2952
+ if (!branch) return { success: false, error: 'Could not determine branch of the worktree node', refineStages };
2217
2953
 
2218
2954
  const { stdout: baseBranchStdout } = await execFileAsync('git', ['branch', '--show-current'], { cwd: repoRoot, encoding: 'utf8' });
2219
2955
  const baseBranch = baseBranchStdout.trim();
2956
+ const { stdout: baseHeadStdout } = await execFileAsync('git', ['rev-parse', 'HEAD'], { cwd: repoRoot, encoding: 'utf8' });
2957
+ const { stdout: branchHeadStdout } = await execFileAsync('git', ['rev-parse', branch], { cwd: node.workspace, encoding: 'utf8' });
2958
+ const baseHead = baseHeadStdout.trim();
2959
+ const branchHead = branchHeadStdout.trim();
2960
+ recordMeshRefineStage(refineStages, 'resolve_refs', 'passed', resolveStarted, { branch, baseBranch, baseHead, branchHead });
2220
2961
 
2962
+ const validationStarted = Date.now();
2221
2963
  const validationSummary = await runMeshRefineValidationGate(mesh, node.workspace);
2964
+ recordMeshRefineStage(
2965
+ refineStages,
2966
+ 'validation',
2967
+ validationSummary.status === 'passed' ? 'passed' : validationSummary.status === 'failed' ? 'failed' : 'skipped',
2968
+ validationStarted,
2969
+ { validationStatus: validationSummary.status, commandsRun: validationSummary.commandsRun.length },
2970
+ );
2222
2971
  if (validationSummary.status === 'failed') {
2223
2972
  return {
2224
2973
  success: false,
@@ -2228,6 +2977,7 @@ export class DaemonCommandRouter {
2228
2977
  branch,
2229
2978
  into: baseBranch,
2230
2979
  validationSummary,
2980
+ refineStages,
2231
2981
  finalBranchConvergenceState: {
2232
2982
  branch,
2233
2983
  baseBranch,
@@ -2247,6 +2997,7 @@ export class DaemonCommandRouter {
2247
2997
  branch,
2248
2998
  into: baseBranch,
2249
2999
  validationSummary,
3000
+ refineStages,
2250
3001
  finalBranchConvergenceState: {
2251
3002
  branch,
2252
3003
  baseBranch,
@@ -2258,39 +3009,127 @@ export class DaemonCommandRouter {
2258
3009
  };
2259
3010
  }
2260
3011
 
3012
+ const patchEquivalenceStarted = Date.now();
3013
+ const patchEquivalence = await runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead);
3014
+ recordMeshRefineStage(refineStages, 'patch_equivalence', patchEquivalence.status, patchEquivalenceStarted, {
3015
+ equivalent: patchEquivalence.equivalent,
3016
+ expectedPatchId: patchEquivalence.expectedPatchId,
3017
+ actualPatchId: patchEquivalence.actualPatchId,
3018
+ error: patchEquivalence.error,
3019
+ });
3020
+ if (!patchEquivalence.equivalent) {
3021
+ return {
3022
+ success: false,
3023
+ code: 'patch_equivalence_failed',
3024
+ convergenceStatus: 'blocked_review',
3025
+ error: 'Refinery patch-equivalence preflight failed; merge/refine was not attempted.',
3026
+ branch,
3027
+ into: baseBranch,
3028
+ validationSummary,
3029
+ patchEquivalence,
3030
+ refineStages,
3031
+ finalBranchConvergenceState: {
3032
+ branch,
3033
+ baseBranch,
3034
+ merged: false,
3035
+ removed: false,
3036
+ validation: 'passed',
3037
+ patchEquivalence: 'failed',
3038
+ status: 'blocked_review',
3039
+ },
3040
+ };
3041
+ }
3042
+
3043
+ let mergeResult: Record<string, unknown> | undefined;
3044
+ const mergeStarted = Date.now();
2261
3045
  try {
2262
- await execFileAsync('git', ['merge', '--no-ff', branch, '-m', `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: 'utf8' });
3046
+ const result = await execFileAsync('git', ['merge', '--no-ff', branch, '-m', `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: 'utf8' });
3047
+ mergeResult = {
3048
+ stdout: truncateValidationOutput(result.stdout),
3049
+ stderr: truncateValidationOutput(result.stderr),
3050
+ durationMs: Date.now() - mergeStarted,
3051
+ };
3052
+ recordMeshRefineStage(refineStages, 'merge', 'passed', mergeStarted, mergeResult);
2263
3053
  } catch (e: any) {
3054
+ recordMeshRefineStage(refineStages, 'merge', 'failed', mergeStarted, {
3055
+ error: e?.message || String(e),
3056
+ stdout: truncateValidationOutput(e?.stdout),
3057
+ stderr: truncateValidationOutput(e?.stderr),
3058
+ });
2264
3059
  return {
2265
3060
  success: false,
2266
3061
  error: `Merge failed (conflicts?): ${e.message}`,
2267
3062
  validationSummary,
3063
+ patchEquivalence,
3064
+ refineStages,
2268
3065
  finalBranchConvergenceState: {
2269
3066
  branch,
2270
3067
  baseBranch,
2271
3068
  merged: false,
2272
3069
  removed: false,
2273
3070
  validation: 'passed',
3071
+ patchEquivalence: 'passed',
2274
3072
  status: 'not_mergeable',
2275
3073
  },
2276
3074
  };
2277
3075
  }
2278
3076
 
3077
+ const cleanupStarted = Date.now();
2279
3078
  const removeResult = await this.execute('remove_mesh_node', {
2280
3079
  meshId,
2281
3080
  nodeId,
2282
- sessionCleanupMode: 'kill',
3081
+ sessionCleanupMode: 'preserve',
2283
3082
  inlineMesh: args?.inlineMesh,
2284
3083
  });
3084
+ recordMeshRefineStage(refineStages, 'cleanup', removeResult?.success === false ? 'failed' : 'passed', cleanupStarted, {
3085
+ removed: removeResult?.removed,
3086
+ code: removeResult?.code,
3087
+ error: removeResult?.error,
3088
+ });
2285
3089
 
3090
+ let ledgerError: string | undefined;
3091
+ const ledgerStarted = Date.now();
2286
3092
  try {
2287
3093
  const { appendLedgerEntry } = await import('../mesh/mesh-ledger.js');
2288
3094
  appendLedgerEntry(meshId, {
2289
3095
  kind: 'node_removed',
2290
3096
  nodeId,
2291
- payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary },
3097
+ payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary, patchEquivalence },
2292
3098
  });
2293
- } catch {}
3099
+ recordMeshRefineStage(refineStages, 'ledger', 'passed', ledgerStarted);
3100
+ } catch (e: any) {
3101
+ ledgerError = e?.message || String(e);
3102
+ recordMeshRefineStage(refineStages, 'ledger', 'failed', ledgerStarted, { error: ledgerError });
3103
+ }
3104
+
3105
+ const finalBranchConvergenceState = {
3106
+ branch: baseBranch,
3107
+ mergedBranch: branch,
3108
+ baseBranch,
3109
+ merged: true,
3110
+ removed: removeResult?.success !== false,
3111
+ validation: 'passed',
3112
+ patchEquivalence: 'passed',
3113
+ status: removeResult?.success === false ? 'merged_cleanup_failed' : 'merged',
3114
+ };
3115
+
3116
+ if (removeResult?.success === false) {
3117
+ return {
3118
+ success: false,
3119
+ code: 'cleanup_failed',
3120
+ error: 'Refinery merge completed but worktree cleanup failed; manual cleanup/retry is required.',
3121
+ merged: true,
3122
+ branch,
3123
+ into: baseBranch,
3124
+ removeResult,
3125
+ validationSummary,
3126
+ patchEquivalence,
3127
+ mergeResult,
3128
+ refineStages,
3129
+ ...(ledgerError ? { ledgerError } : {}),
3130
+ finalBranchConvergenceState,
3131
+ };
3132
+ }
2294
3133
 
2295
3134
  return {
2296
3135
  success: true,
@@ -2299,18 +3138,14 @@ export class DaemonCommandRouter {
2299
3138
  into: baseBranch,
2300
3139
  removeResult,
2301
3140
  validationSummary,
2302
- finalBranchConvergenceState: {
2303
- branch: baseBranch,
2304
- mergedBranch: branch,
2305
- baseBranch,
2306
- merged: true,
2307
- removed: removeResult?.success !== false,
2308
- validation: 'passed',
2309
- status: removeResult?.success === false ? 'merged_cleanup_failed' : 'merged',
2310
- },
3141
+ patchEquivalence,
3142
+ mergeResult,
3143
+ refineStages,
3144
+ ...(ledgerError ? { ledgerError } : {}),
3145
+ finalBranchConvergenceState,
2311
3146
  };
2312
3147
  } catch (e: any) {
2313
- return { success: false, error: e.message };
3148
+ return { success: false, error: e.message, refineStages };
2314
3149
  }
2315
3150
  }
2316
3151
 
@@ -2355,6 +3190,7 @@ export class DaemonCommandRouter {
2355
3190
  } else {
2356
3191
  const { removeNode } = await import('../config/mesh-config.js');
2357
3192
  removed = removeNode(meshId, nodeId);
3193
+ if (removed) this.invalidateAggregateMeshStatus(meshId);
2358
3194
  }
2359
3195
 
2360
3196
  // Record in task ledger
@@ -2440,6 +3276,7 @@ export class DaemonCommandRouter {
2440
3276
  policy: { ...(sourceNode.policy || {}) },
2441
3277
  });
2442
3278
  if (!node) return { success: false, error: 'Failed to register worktree node' };
3279
+ this.invalidateAggregateMeshStatus(meshId);
2443
3280
  }
2444
3281
 
2445
3282
  // Initialize submodules if policy allows (default: true)
@@ -2531,7 +3368,16 @@ export class DaemonCommandRouter {
2531
3368
  cliType,
2532
3369
  };
2533
3370
  }
2534
- const workspace = typeof coordinatorNode.workspace === 'string' ? coordinatorNode.workspace.trim() : '';
3371
+ const sessionHostRecords = this.deps.sessionHostControl?.listSessions
3372
+ ? await this.deps.sessionHostControl.listSessions().catch(() => [])
3373
+ : [];
3374
+ const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
3375
+ const workspace = readLiveMeshNodeWorkspace({
3376
+ meshId,
3377
+ nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || ''),
3378
+ liveSessionRecords: liveMeshSessions,
3379
+ allowCoordinatorSession: true,
3380
+ }) || (typeof coordinatorNode.workspace === 'string' ? coordinatorNode.workspace.trim() : '');
2535
3381
  if (!workspace) return { success: false, error: 'Coordinator node workspace required', meshId, cliType };
2536
3382
  if (!cliType) {
2537
3383
  const resolved = await resolveProviderTypeFromPriority({
@@ -2877,6 +3723,13 @@ export class DaemonCommandRouter {
2877
3723
  const mesh = meshRecord?.mesh;
2878
3724
  if (!mesh) return { success: false, error: 'Mesh not found' };
2879
3725
 
3726
+ const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
3727
+ if (!refreshRequested) {
3728
+ const cachedStatus = this.getCachedAggregateMeshStatus(meshId);
3729
+ if (cachedStatus) return cachedStatus;
3730
+ }
3731
+ const refreshReason = refreshRequested ? 'explicit_refresh' : 'cold_cache_miss';
3732
+
2880
3733
  const { getMeshQueueStats, getQueue } = await import('../mesh/mesh-work-queue.js');
2881
3734
  const queue = getQueue(meshId);
2882
3735
  const queueSummary = getMeshQueueStats(meshId);
@@ -2884,111 +3737,289 @@ export class DaemonCommandRouter {
2884
3737
  const { readLedgerEntries, getLedgerSummary } = await import('../mesh/mesh-ledger.js');
2885
3738
  const ledgerEntries = readLedgerEntries(meshId, { tail: 20 });
2886
3739
  const ledgerSummary = getLedgerSummary(meshId);
2887
-
3740
+ const sessionHostRecords = this.deps.sessionHostControl?.listSessions
3741
+ ? await this.deps.sessionHostControl.listSessions().catch(() => [])
3742
+ : [];
3743
+ const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
3744
+
3745
+ const localMachineId = loadConfig().machineId || '';
3746
+ const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
3747
+ const directTruth = requireDirectPeerTruth
3748
+ ? await hydrateInlineMeshDirectTruth({
3749
+ mesh,
3750
+ meshSource: meshRecord.source,
3751
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
3752
+ statusInstanceId: this.deps.statusInstanceId,
3753
+ localMachineId,
3754
+ })
3755
+ : {
3756
+ directEvidenceCount: 0,
3757
+ localConfirmedCount: 0,
3758
+ peerAttemptedCount: 0,
3759
+ peerConfirmedCount: 0,
3760
+ unavailableNodeIds: [] as string[],
3761
+ };
3762
+ const directTruthSatisfied = meshRecord.source !== 'inline_bootstrap' || directTruth.directEvidenceCount > 0;
3763
+ if (requireDirectPeerTruth && !directTruthSatisfied) {
3764
+ return {
3765
+ success: false,
3766
+ code: 'mesh_direct_peer_truth_unavailable',
3767
+ error: 'Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct mesh_status probes succeed.',
3768
+ sourceOfTruth: {
3769
+ membership: meshRecord.source === 'inline_cache'
3770
+ ? 'coordinator_inline_mesh_cache'
3771
+ : meshRecord.source === 'local_config'
3772
+ ? 'local_mesh_config'
3773
+ : 'inline_bootstrap_snapshot',
3774
+ coordinatorOwnsLiveTruth: false,
3775
+ currentStatus: 'direct_peer_truth_unavailable',
3776
+ directPeerTruth: {
3777
+ required: true,
3778
+ satisfied: false,
3779
+ directEvidenceCount: directTruth.directEvidenceCount,
3780
+ localConfirmedCount: directTruth.localConfirmedCount,
3781
+ peerAttemptedCount: directTruth.peerAttemptedCount,
3782
+ peerConfirmedCount: directTruth.peerConfirmedCount,
3783
+ unavailableNodeIds: directTruth.unavailableNodeIds,
3784
+ },
3785
+ },
3786
+ };
3787
+ }
3788
+ const directTruthUnavailableNodeIds = new Set(directTruth.unavailableNodeIds);
3789
+ const selectedCoordinatorNodeId = readStringValue(
3790
+ mesh.coordinator?.preferredNodeId,
3791
+ (mesh.nodes?.[0] as any)?.id,
3792
+ (mesh.nodes?.[0] as any)?.nodeId,
3793
+ );
3794
+ const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes)
3795
+ ? selectedCoordinatorNodeId
3796
+ : undefined;
3797
+ const refreshedAt = new Date().toISOString();
2888
3798
  const nodeStatuses = [];
2889
- for (const node of mesh.nodes || []) {
3799
+ for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
3800
+ const nodeId = String(node.id || node.nodeId || '');
3801
+ const daemonId = readStringValue(node.daemonId);
3802
+ const providerPriority = readProviderPriorityFromPolicy(node.policy);
3803
+ const isSelfNode = Boolean(
3804
+ nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId,
3805
+ ) || Boolean(
3806
+ daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId),
3807
+ ) || Boolean(meshRecord?.inline && nodeIndex === 0);
2890
3808
  const status: Record<string, unknown> = {
2891
- nodeId: node.id || node.nodeId,
3809
+ nodeId,
2892
3810
  machineLabel: node.machineLabel || node.id || node.nodeId,
2893
3811
  workspace: node.workspace,
2894
3812
  repoRoot: node.repoRoot,
2895
3813
  isLocalWorktree: node.isLocalWorktree,
2896
3814
  worktreeBranch: node.worktreeBranch,
2897
- daemonId: node.daemonId,
3815
+ daemonId,
2898
3816
  machineId: node.machineId,
3817
+ machineStatus: node.machineStatus,
2899
3818
  health: 'unknown',
2900
3819
  providers: node.providers || [],
3820
+ providerPriority,
2901
3821
  activeSessions: [],
3822
+ activeSessionDetails: [],
3823
+ launchReady: false,
2902
3824
  };
2903
- if (node.workspace && typeof node.workspace === 'string') {
2904
- if (!fs.existsSync(node.workspace as string) && applyCachedInlineMeshNodeStatus(status, node)) {
2905
- nodeStatuses.push(status);
2906
- continue;
3825
+ if (isSelfNode) {
3826
+ status.connection = {
3827
+ perspective: 'selected_coordinator',
3828
+ source: 'mesh_peer_status',
3829
+ state: 'self',
3830
+ transport: 'local',
3831
+ reported: true,
3832
+ reason: 'Selected coordinator daemon',
3833
+ lastStateChangeAt: refreshedAt,
3834
+ };
3835
+ } else if (daemonId) {
3836
+ const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
3837
+ status.connection = connection ?? {
3838
+ perspective: 'selected_coordinator',
3839
+ source: 'not_reported',
3840
+ state: 'unknown',
3841
+ transport: 'unknown',
3842
+ reported: false,
3843
+ reason: 'No live mesh peer telemetry reported by the selected coordinator yet.',
3844
+ };
3845
+ } else {
3846
+ status.connection = {
3847
+ perspective: 'selected_coordinator',
3848
+ source: 'not_reported',
3849
+ state: 'unknown',
3850
+ transport: 'unknown',
3851
+ reported: false,
3852
+ reason: 'Node has no daemon id, so mesh transport cannot be reported from the selected coordinator.',
3853
+ };
3854
+ }
3855
+ const matchedLiveSessionRecords = collectLiveMeshSessionRecords({
3856
+ meshId,
3857
+ node,
3858
+ nodeId,
3859
+ liveSessionRecords: liveMeshSessions,
3860
+ allowCoordinatorSession: nodeId === selectedCoordinatorNodeId,
3861
+ });
3862
+ const workspace = readLiveMeshNodeWorkspace({
3863
+ meshId,
3864
+ nodeId,
3865
+ liveSessionRecords: matchedLiveSessionRecords,
3866
+ allowCoordinatorSession: nodeId === selectedCoordinatorNodeId,
3867
+ }) || (typeof node.workspace === 'string' ? node.workspace : '');
3868
+ status.workspace = workspace || node.workspace;
3869
+ if (matchedLiveSessionRecords.length > 0) {
3870
+ const sessionIds = matchedLiveSessionRecords
3871
+ .map((record: any) => typeof record?.sessionId === 'string' ? record.sessionId : '')
3872
+ .filter(Boolean);
3873
+ const providerTypes = matchedLiveSessionRecords
3874
+ .map((record: any) => readStringValue(record?.providerType))
3875
+ .filter(Boolean) as string[];
3876
+ status.activeSessions = sessionIds;
3877
+ status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
3878
+ if (providerTypes.length > 0) {
3879
+ status.providers = Array.from(new Set([...(Array.isArray(status.providers) ? status.providers as string[] : []), ...providerTypes]));
2907
3880
  }
2908
- try {
2909
- const { execFile } = await import('node:child_process');
2910
- const { promisify } = await import('node:util');
2911
- const execFileAsync = promisify(execFile);
2912
-
2913
- const runGit = async (args: string[]): Promise<string> => {
2914
- const result = await execFileAsync('git', ['-C', node.workspace as string, ...args], {
2915
- encoding: 'utf8',
2916
- timeout: 10_000,
2917
- });
2918
- return result.stdout.trim();
2919
- };
2920
-
2921
- const branch = await runGit(['branch', '--show-current']).catch(() => '');
2922
- const porc = await runGit(['status', '--porcelain']).catch(() => '');
2923
- const headCommit = await runGit(['rev-parse', '--short', 'HEAD']).catch(() => null);
2924
- const headMessage = await runGit(['log', '-1', '--format=%s']).catch(() => null);
2925
- const upstream = await runGit(['rev-parse', '--abbrev-ref', '@{upstream}']).catch(() => null);
2926
- const aheadBehind = await runGit(['rev-list', '--left-right', '--count', '@{upstream}...HEAD']).catch(() => '');
2927
- const stashCount = await runGit(['stash', 'list']).catch(() => '');
2928
-
2929
- let ahead = 0, behind = 0;
2930
- if (aheadBehind) {
2931
- const parts = aheadBehind.split(/\s+/);
2932
- if (parts.length >= 2) {
2933
- behind = parseInt(parts[0], 10) || 0;
2934
- ahead = parseInt(parts[1], 10) || 0;
3881
+ }
3882
+ if (workspace) {
3883
+ if (!fs.existsSync(workspace)) {
3884
+ // Workspace not local — prefer direct live inline truth, then attempt a P2P git probe.
3885
+ const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
3886
+ let remoteProbeApplied = false;
3887
+ if (inlineTransitGit) {
3888
+ status.git = inlineTransitGit;
3889
+ status.health = inlineTransitGit.isGitRepo
3890
+ ? deriveMeshNodeHealthFromGit(inlineTransitGit as unknown as Record<string, unknown>)
3891
+ : 'degraded';
3892
+ remoteProbeApplied = true;
3893
+ } else if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand && !directTruthUnavailableNodeIds.has(nodeId)) {
3894
+ try {
3895
+ const remoteGit = await probeRemoteMeshGitStatus({
3896
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
3897
+ daemonId,
3898
+ workspace,
3899
+ timeoutMs: 8000,
3900
+ });
3901
+ if (remoteGit) {
3902
+ status.git = remoteGit;
3903
+ status.health = remoteGit.isGitRepo
3904
+ ? deriveMeshNodeHealthFromGit(remoteGit as unknown as Record<string, unknown>)
3905
+ : 'degraded';
3906
+ recordInlineMeshDirectGitTruth(node, remoteGit, 'selected_coordinator_mesh_p2p_git');
3907
+ remoteProbeApplied = true;
3908
+ }
3909
+ } catch {
3910
+ const refreshedConnection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
3911
+ const refreshedConnectionState = readStringValue(refreshedConnection?.state);
3912
+ if (refreshedConnection && refreshedConnectionState === 'connected') {
3913
+ status.connection = refreshedConnection;
3914
+ try {
3915
+ const remoteGit = await probeRemoteMeshGitStatus({
3916
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
3917
+ daemonId,
3918
+ workspace,
3919
+ timeoutMs: 12000,
3920
+ });
3921
+ if (remoteGit) {
3922
+ status.git = remoteGit;
3923
+ status.health = remoteGit.isGitRepo
3924
+ ? deriveMeshNodeHealthFromGit(remoteGit as unknown as Record<string, unknown>)
3925
+ : 'degraded';
3926
+ recordInlineMeshDirectGitTruth(node, remoteGit, 'selected_coordinator_mesh_p2p_git');
3927
+ remoteProbeApplied = true;
3928
+ }
3929
+ } catch {
3930
+ // Probe timed out again or P2P unavailable — fall back to cached status
3931
+ }
3932
+ }
2935
3933
  }
2936
3934
  }
2937
-
2938
- const dirty = porc.length > 0;
2939
- const lines = porc ? porc.split('\n').filter(Boolean) : [];
2940
- let staged = 0, modified = 0, untracked = 0, deleted = 0, renamed = 0;
2941
- for (const line of lines) {
2942
- const xy = line.slice(0, 2);
2943
- if (xy[0] !== ' ' && xy[0] !== '?') staged++;
2944
- if (xy[1] === 'M') modified++;
2945
- if (xy[1] === 'D') deleted++;
2946
- if (xy[0] === 'R' || xy[1] === 'R') renamed++;
2947
- if (xy === '??') untracked++;
3935
+ if (!remoteProbeApplied) {
3936
+ const connectionState = readStringValue((status.connection as any)?.state);
3937
+ const pendingPeerGitProbe = !inlineTransitGit
3938
+ && !isSelfNode
3939
+ && !!daemonId
3940
+ && (
3941
+ readStringValue(status.machineStatus) === 'online'
3942
+ || readStringValue(status.health) === 'online'
3943
+ || connectionState === 'connecting'
3944
+ || connectionState === 'connected'
3945
+ || connectionState === 'unknown'
3946
+ );
3947
+ if (pendingPeerGitProbe) {
3948
+ status.gitProbePending = true;
3949
+ status.health = 'unknown';
3950
+ }
3951
+ if (applyCachedInlineMeshNodeStatus(
3952
+ status,
3953
+ node,
3954
+ pendingPeerGitProbe ? { skipGit: true, skipError: true, skipHealth: true } : undefined,
3955
+ )) {
3956
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
3957
+ nodeStatuses.push(status);
3958
+ continue;
3959
+ }
3960
+ if (meshRecord?.source === 'inline_cache' && !isSelfNode) {
3961
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
3962
+ nodeStatuses.push(status);
3963
+ continue;
3964
+ }
2948
3965
  }
2949
-
2950
- status.git = {
2951
- workspace: node.workspace,
2952
- repoRoot: node.workspace,
2953
- isGitRepo: true,
2954
- branch: branch || null,
2955
- headCommit,
2956
- headMessage,
2957
- upstream,
2958
- ahead,
2959
- behind,
2960
- staged,
2961
- modified,
2962
- untracked,
2963
- deleted,
2964
- renamed,
2965
- hasConflicts: false,
2966
- conflictFiles: [],
2967
- stashCount: stashCount ? stashCount.split('\n').filter(Boolean).length : 0,
2968
- lastCheckedAt: Date.now(),
2969
- };
2970
- status.health = branch ? (dirty ? 'dirty' : 'online') : 'degraded';
2971
- } catch {
2972
- if (!applyCachedInlineMeshNodeStatus(status, node)) {
2973
- status.health = 'degraded';
3966
+ } else {
3967
+ try {
3968
+ const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 10_000, refreshUpstream: true });
3969
+ status.git = gitStatus;
3970
+ recordInlineMeshDirectGitTruth(node, gitStatus as unknown as Record<string, unknown>, 'selected_coordinator_local_git');
3971
+ if (gitStatus.isGitRepo) {
3972
+ status.health = deriveMeshNodeHealthFromGit(gitStatus as unknown as Record<string, unknown>);
3973
+ } else {
3974
+ status.health = 'degraded';
3975
+ if (gitStatus.error && !status.error) status.error = gitStatus.error;
3976
+ }
3977
+ } catch {
3978
+ if (!applyCachedInlineMeshNodeStatus(status, node)) {
3979
+ status.health = 'degraded';
3980
+ }
2974
3981
  }
2975
3982
  }
2976
3983
  } else {
2977
3984
  applyCachedInlineMeshNodeStatus(status, node);
2978
3985
  }
3986
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
2979
3987
  nodeStatuses.push(status);
2980
3988
  }
2981
3989
 
2982
- return {
3990
+ const statusResult = {
2983
3991
  success: true,
2984
3992
  meshId: mesh.id,
2985
3993
  meshName: mesh.name,
2986
3994
  repoIdentity: mesh.repoIdentity,
2987
3995
  defaultBranch: mesh.defaultBranch,
3996
+ refreshedAt,
3997
+ sourceOfTruth: {
3998
+ membership: meshRecord?.source === 'inline_cache'
3999
+ ? 'coordinator_inline_mesh_cache'
4000
+ : meshRecord?.source === 'local_config'
4001
+ ? 'local_mesh_config'
4002
+ : 'inline_bootstrap_snapshot',
4003
+ coordinatorOwnsLiveTruth: directTruthSatisfied,
4004
+ ...(requireDirectPeerTruth ? {
4005
+ currentStatus: directTruthSatisfied ? 'live_git_and_session_probes' : 'direct_peer_truth_unavailable',
4006
+ directPeerTruth: {
4007
+ required: true,
4008
+ satisfied: directTruthSatisfied,
4009
+ directEvidenceCount: directTruth.directEvidenceCount,
4010
+ localConfirmedCount: directTruth.localConfirmedCount,
4011
+ peerAttemptedCount: directTruth.peerAttemptedCount,
4012
+ peerConfirmedCount: directTruth.peerConfirmedCount,
4013
+ unavailableNodeIds: directTruth.unavailableNodeIds,
4014
+ },
4015
+ } : {}),
4016
+ historicalEvidenceOnly: ['recoveryHints', 'ledger.summary', 'queue.summary'],
4017
+ },
2988
4018
  nodes: nodeStatuses,
2989
4019
  queue: { tasks: queue, summary: queueSummary },
2990
4020
  ledger: { entries: ledgerEntries, summary: ledgerSummary },
2991
4021
  };
4022
+ return this.rememberAggregateMeshStatus(meshId, statusResult, refreshReason);
2992
4023
  } catch (e: any) {
2993
4024
  return { success: false, error: e.message };
2994
4025
  }