adhdev 0.9.81 → 0.9.82-rc.10

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/dist/index.js CHANGED
@@ -264,8 +264,14 @@ async function getGitRepoStatus(workspace, options = {}) {
264
264
  const includeSubmodules = options.includeSubmodules !== false;
265
265
  try {
266
266
  const repo = await resolveGitRepository(workspace, options);
267
- const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
268
- const parsed = parsePorcelainV2Status(statusOutput.stdout);
267
+ let parsed = await readPorcelainStatus(repo, options);
268
+ let upstreamProbe = getInitialUpstreamProbe(parsed);
269
+ if (options.refreshUpstream) {
270
+ upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
271
+ if (upstreamProbe.upstreamStatus === "fresh") {
272
+ parsed = await readPorcelainStatus(repo, options);
273
+ }
274
+ }
269
275
  const head = await readHead(repo, options);
270
276
  const stashCount = await readStashCount(repo, options);
271
277
  let submodules;
@@ -280,6 +286,9 @@ async function getGitRepoStatus(workspace, options = {}) {
280
286
  headCommit: head.commit,
281
287
  headMessage: head.message,
282
288
  upstream: parsed.upstream,
289
+ upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
290
+ upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
291
+ upstreamFetchError: upstreamProbe.upstreamFetchError,
283
292
  ahead: parsed.ahead,
284
293
  behind: parsed.behind,
285
294
  staged: parsed.staged,
@@ -304,6 +313,60 @@ async function getGitRepoStatus(workspace, options = {}) {
304
313
  );
305
314
  }
306
315
  }
316
+ async function readPorcelainStatus(repo, options) {
317
+ const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
318
+ return parsePorcelainV2Status(statusOutput.stdout);
319
+ }
320
+ function getInitialUpstreamProbe(parsed) {
321
+ return {
322
+ upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
323
+ };
324
+ }
325
+ async function refreshTrackedUpstream(repo, parsed, options) {
326
+ if (!parsed.upstream || !parsed.branch) {
327
+ return { upstreamStatus: "no_upstream" };
328
+ }
329
+ const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
330
+ if (!remoteName) {
331
+ return {
332
+ upstreamStatus: "stale",
333
+ upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
334
+ };
335
+ }
336
+ try {
337
+ await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
338
+ return {
339
+ upstreamStatus: "fresh",
340
+ upstreamFetchedAt: Date.now()
341
+ };
342
+ } catch (error48) {
343
+ return {
344
+ upstreamStatus: "stale",
345
+ upstreamFetchError: formatGitError(error48)
346
+ };
347
+ }
348
+ }
349
+ async function readBranchRemote(repo, branch, options) {
350
+ try {
351
+ const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
352
+ return result.stdout.trim() || null;
353
+ } catch {
354
+ return null;
355
+ }
356
+ }
357
+ function inferRemoteName(upstream) {
358
+ const [remoteName] = upstream.split("/");
359
+ return remoteName?.trim() || null;
360
+ }
361
+ function formatGitError(error48) {
362
+ if (error48 instanceof GitCommandError) {
363
+ return error48.stderr || error48.message;
364
+ }
365
+ if (error48 instanceof Error) {
366
+ return error48.message;
367
+ }
368
+ return String(error48);
369
+ }
307
370
  function parsePorcelainV2Status(output) {
308
371
  const parsed = {
309
372
  branch: null,
@@ -398,6 +461,7 @@ function emptyStatus(workspace, lastCheckedAt, error48) {
398
461
  headCommit: null,
399
462
  headMessage: null,
400
463
  upstream: null,
464
+ upstreamStatus: "unavailable",
401
465
  ahead: 0,
402
466
  behind: 0,
403
467
  staged: 0,
@@ -690,6 +754,9 @@ function createGitCompactSummary(status, diffSummary) {
690
754
  isGitRepo: status.isGitRepo,
691
755
  repoRoot: status.repoRoot,
692
756
  branch: status.branch,
757
+ upstreamStatus: status.upstreamStatus,
758
+ upstreamFetchedAt: status.upstreamFetchedAt,
759
+ upstreamFetchError: status.upstreamFetchError,
693
760
  dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
694
761
  changedFiles,
695
762
  ahead: status.ahead,
@@ -1017,7 +1084,7 @@ function serviceNotImplemented(command) {
1017
1084
  }
1018
1085
  function createDefaultGitCommandServices() {
1019
1086
  return {
1020
- getStatus: ({ workspace }) => getGitRepoStatus(workspace),
1087
+ getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
1021
1088
  getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
1022
1089
  getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
1023
1090
  createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
@@ -1102,7 +1169,7 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
1102
1169
  switch (command) {
1103
1170
  case "git_status": {
1104
1171
  if (!services.getStatus) return serviceNotImplemented(command);
1105
- const status = await runService(() => services.getStatus({ workspace }));
1172
+ const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
1106
1173
  return "success" in status ? status : { success: true, status };
1107
1174
  }
1108
1175
  case "git_diff_summary": {
@@ -3759,10 +3826,18 @@ __export(mesh_events_exports, {
3759
3826
  drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
3760
3827
  getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
3761
3828
  handleMeshForwardEvent: () => handleMeshForwardEvent,
3829
+ queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
3762
3830
  setupMeshEventForwarding: () => setupMeshEventForwarding,
3763
3831
  triggerMeshQueue: () => triggerMeshQueue,
3764
3832
  tryAssignQueueTask: () => tryAssignQueueTask
3765
3833
  });
3834
+ function queuePendingMeshCoordinatorEvent(event) {
3835
+ if (pendingMeshCoordinatorEvents.length >= MAX_PENDING_EVENTS) {
3836
+ return false;
3837
+ }
3838
+ pendingMeshCoordinatorEvents.push(event);
3839
+ return true;
3840
+ }
3766
3841
  function drainPendingMeshCoordinatorEvents() {
3767
3842
  return pendingMeshCoordinatorEvents.splice(0);
3768
3843
  }
@@ -4334,17 +4409,18 @@ function injectMeshSystemMessage(components, args) {
4334
4409
  return true;
4335
4410
  });
4336
4411
  if (coordinatorInstances.length === 0) {
4337
- if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
4338
- pendingMeshCoordinatorEvents.push({
4339
- event: args.event,
4340
- meshId: args.meshId,
4341
- nodeLabel: args.nodeLabel,
4342
- metadataEvent: {
4343
- ...args.metadataEvent,
4344
- ...recoveryContext ? { recoveryContext } : {}
4345
- },
4346
- queuedAt: Date.now()
4347
- });
4412
+ if (queuePendingMeshCoordinatorEvent({
4413
+ event: args.event,
4414
+ meshId: args.meshId,
4415
+ nodeLabel: args.nodeLabel,
4416
+ nodeId: args.nodeId || void 0,
4417
+ workspace: readNonEmptyString(args.metadataEvent.workspace),
4418
+ metadataEvent: {
4419
+ ...args.metadataEvent,
4420
+ ...recoveryContext ? { recoveryContext } : {}
4421
+ },
4422
+ queuedAt: Date.now()
4423
+ })) {
4348
4424
  LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
4349
4425
  }
4350
4426
  return { success: true, forwarded: 0 };
@@ -45393,6 +45469,240 @@ function readProviderPriorityFromPolicy(policy) {
45393
45469
  return true;
45394
45470
  });
45395
45471
  }
45472
+ function readObjectRecord(value) {
45473
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
45474
+ }
45475
+ function readStringValue(...values) {
45476
+ for (const value of values) {
45477
+ if (typeof value === "string" && value.trim()) return value.trim();
45478
+ }
45479
+ return void 0;
45480
+ }
45481
+ function readNumberValue(...values) {
45482
+ for (const value of values) {
45483
+ if (typeof value === "number" && Number.isFinite(value)) return value;
45484
+ }
45485
+ return void 0;
45486
+ }
45487
+ function readBooleanValue(...values) {
45488
+ for (const value of values) {
45489
+ if (typeof value === "boolean") return value;
45490
+ }
45491
+ return void 0;
45492
+ }
45493
+ function readGitSubmodules(value) {
45494
+ if (!Array.isArray(value)) return void 0;
45495
+ const submodules = value.map((entry) => {
45496
+ const submodule = readObjectRecord(entry);
45497
+ const path35 = readStringValue(submodule.path);
45498
+ const commit = readStringValue(submodule.commit);
45499
+ const repoPath = readStringValue(submodule.repoPath, submodule.repo_root);
45500
+ if (!path35 || !commit || !repoPath) return null;
45501
+ return {
45502
+ path: path35,
45503
+ commit,
45504
+ repoPath,
45505
+ dirty: readBooleanValue(submodule.dirty) ?? false,
45506
+ outOfSync: readBooleanValue(submodule.outOfSync, submodule.out_of_sync) ?? false,
45507
+ lastCheckedAt: readNumberValue(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now(),
45508
+ ...readStringValue(submodule.error) ? { error: readStringValue(submodule.error) } : {}
45509
+ };
45510
+ }).filter((entry) => entry !== null);
45511
+ return submodules.length > 0 ? submodules : void 0;
45512
+ }
45513
+ function buildCachedInlineMeshGitStatus(node) {
45514
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
45515
+ const cachedGit = readObjectRecord(cachedStatus.git);
45516
+ if (Object.keys(cachedGit).length) {
45517
+ const conflictFiles2 = Array.isArray(cachedGit.conflictFiles) ? cachedGit.conflictFiles.filter((value) => typeof value === "string") : [];
45518
+ const conflictCount2 = readNumberValue(cachedGit.conflicts) ?? conflictFiles2.length;
45519
+ const hasConflicts2 = readBooleanValue(cachedGit.hasConflicts) ?? conflictCount2 > 0;
45520
+ const isGitRepo2 = readBooleanValue(cachedGit.isGitRepo);
45521
+ if (isGitRepo2 !== void 0) {
45522
+ const submodules2 = readGitSubmodules(cachedGit.submodules);
45523
+ return {
45524
+ workspace: readStringValue(cachedGit.workspace, node?.workspace) || "",
45525
+ repoRoot: readStringValue(cachedGit.repoRoot, node?.repoRoot, node?.workspace) || null,
45526
+ isGitRepo: isGitRepo2,
45527
+ branch: readStringValue(cachedGit.branch) ?? null,
45528
+ headCommit: readStringValue(cachedGit.headCommit) ?? null,
45529
+ headMessage: readStringValue(cachedGit.headMessage) ?? null,
45530
+ upstream: readStringValue(cachedGit.upstream) ?? null,
45531
+ ahead: readNumberValue(cachedGit.ahead) ?? 0,
45532
+ behind: readNumberValue(cachedGit.behind) ?? 0,
45533
+ staged: readNumberValue(cachedGit.staged) ?? 0,
45534
+ modified: readNumberValue(cachedGit.modified) ?? 0,
45535
+ untracked: readNumberValue(cachedGit.untracked) ?? 0,
45536
+ deleted: readNumberValue(cachedGit.deleted) ?? 0,
45537
+ renamed: readNumberValue(cachedGit.renamed) ?? 0,
45538
+ hasConflicts: hasConflicts2,
45539
+ conflictFiles: conflictFiles2,
45540
+ stashCount: readNumberValue(cachedGit.stashCount) ?? 0,
45541
+ lastCheckedAt: readNumberValue(cachedGit.lastCheckedAt) ?? Date.now(),
45542
+ ...submodules2 ? { submodules: submodules2 } : {}
45543
+ };
45544
+ }
45545
+ }
45546
+ const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
45547
+ const gitResult = readObjectRecord(rawGit.result);
45548
+ const directStatus = readObjectRecord(rawGit.status);
45549
+ const nestedStatus = readObjectRecord(gitResult.status);
45550
+ const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
45551
+ const probeGit = readObjectRecord(rawProbe.git);
45552
+ const probeGitResult = readObjectRecord(probeGit.result);
45553
+ const probeDirectStatus = readObjectRecord(probeGit.status);
45554
+ const probeNestedStatus = readObjectRecord(probeGitResult.status);
45555
+ const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
45556
+ const isGitRepo = readBooleanValue(status.isGitRepo);
45557
+ if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
45558
+ const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((value) => typeof value === "string") : [];
45559
+ const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
45560
+ const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
45561
+ const submodules = readGitSubmodules(status.submodules);
45562
+ return {
45563
+ workspace: readStringValue(status.workspace, node?.workspace) || "",
45564
+ repoRoot: readStringValue(status.repoRoot, node?.repoRoot, node?.workspace) || null,
45565
+ isGitRepo,
45566
+ branch: readStringValue(status.branch) ?? null,
45567
+ headCommit: readStringValue(status.headCommit) ?? null,
45568
+ headMessage: readStringValue(status.headMessage) ?? null,
45569
+ upstream: readStringValue(status.upstream) ?? null,
45570
+ ahead: readNumberValue(status.ahead) ?? 0,
45571
+ behind: readNumberValue(status.behind) ?? 0,
45572
+ staged: readNumberValue(status.staged) ?? 0,
45573
+ modified: readNumberValue(status.modified) ?? 0,
45574
+ untracked: readNumberValue(status.untracked) ?? 0,
45575
+ deleted: readNumberValue(status.deleted) ?? 0,
45576
+ renamed: readNumberValue(status.renamed) ?? 0,
45577
+ hasConflicts,
45578
+ conflictFiles,
45579
+ stashCount: readNumberValue(status.stashCount) ?? 0,
45580
+ lastCheckedAt: Date.now(),
45581
+ ...submodules ? { submodules } : {}
45582
+ };
45583
+ }
45584
+ function hasGitWorktreeChanges(git) {
45585
+ if (!git) return false;
45586
+ return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
45587
+ }
45588
+ function getGitSubmoduleDriftState(git) {
45589
+ const submodules = Array.isArray(git?.submodules) ? git.submodules : [];
45590
+ let dirty = false;
45591
+ let outOfSync = false;
45592
+ for (const entry of submodules) {
45593
+ const submodule = readObjectRecord(entry);
45594
+ if (readBooleanValue(submodule.dirty) === true) dirty = true;
45595
+ if (readBooleanValue(submodule.outOfSync) === true || !!readStringValue(submodule.error)) outOfSync = true;
45596
+ }
45597
+ return { dirty, outOfSync };
45598
+ }
45599
+ function deriveMeshNodeHealthFromGit(git) {
45600
+ if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
45601
+ const branch = readStringValue(git.branch);
45602
+ if (!branch) return "degraded";
45603
+ const submoduleDrift = getGitSubmoduleDriftState(git);
45604
+ if (submoduleDrift.outOfSync) return "degraded";
45605
+ if (submoduleDrift.dirty || hasGitWorktreeChanges(git)) return "dirty";
45606
+ return "online";
45607
+ }
45608
+ function readCachedInlineMeshActiveSessions(node) {
45609
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
45610
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
45611
+ const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
45612
+ const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
45613
+ return sessionId ? [sessionId] : [];
45614
+ }
45615
+ function readCachedInlineMeshActiveSessionDetails(node) {
45616
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
45617
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
45618
+ const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
45619
+ const sessionId = readStringValue(
45620
+ fallbackSession.id,
45621
+ fallbackSession.sessionId,
45622
+ fallbackSession.session_id,
45623
+ node?.activeSessionId,
45624
+ node?.active_session_id,
45625
+ node?.sessionId,
45626
+ node?.session_id
45627
+ );
45628
+ if (!sessionId) return [];
45629
+ return [{
45630
+ sessionId,
45631
+ providerType: readStringValue(
45632
+ fallbackSession.providerType,
45633
+ fallbackSession.provider_type,
45634
+ fallbackSession.cliType,
45635
+ fallbackSession.cli_type,
45636
+ fallbackSession.provider,
45637
+ node?.providerType,
45638
+ node?.provider_type
45639
+ ),
45640
+ state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
45641
+ lifecycle: readStringValue(fallbackSession.lifecycle),
45642
+ title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
45643
+ workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
45644
+ lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
45645
+ recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
45646
+ isCached: true
45647
+ }];
45648
+ }
45649
+ function readLiveMeshSessionState(record2) {
45650
+ return readStringValue(
45651
+ record2?.meta?.sessionStatus,
45652
+ record2?.meta?.status,
45653
+ record2?.meta?.providerStatus,
45654
+ record2?.status,
45655
+ record2?.state,
45656
+ record2?.lifecycle
45657
+ );
45658
+ }
45659
+ function toIsoTimestamp(value) {
45660
+ if (typeof value === "number" && Number.isFinite(value)) return new Date(value).toISOString();
45661
+ const stringValue = readStringValue(value);
45662
+ return stringValue || null;
45663
+ }
45664
+ function summarizeMeshSessionRecord(record2) {
45665
+ return {
45666
+ sessionId: readStringValue(record2?.sessionId) || "unknown",
45667
+ providerType: readStringValue(record2?.providerType),
45668
+ state: readLiveMeshSessionState(record2),
45669
+ lifecycle: readStringValue(record2?.lifecycle),
45670
+ surfaceKind: getSessionHostSurfaceKind(record2),
45671
+ recoveryState: readStringValue(record2?.meta?.runtimeRecoveryState) ?? null,
45672
+ workspace: readStringValue(record2?.workspace) ?? null,
45673
+ title: readStringValue(record2?.displayName, record2?.workspaceLabel) ?? null,
45674
+ lastActivityAt: toIsoTimestamp(record2?.updatedAt ?? record2?.lastActivityAt ?? record2?.last_activity_at),
45675
+ isCached: false
45676
+ };
45677
+ }
45678
+ function applyCachedInlineMeshNodeStatus(status, node) {
45679
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
45680
+ const git = buildCachedInlineMeshGitStatus(node);
45681
+ const error48 = readStringValue(cachedStatus.error, node?.error);
45682
+ const health = readStringValue(cachedStatus.health, node?.health);
45683
+ const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
45684
+ const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
45685
+ const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
45686
+ const activeSessions = readCachedInlineMeshActiveSessions(node);
45687
+ const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
45688
+ if (!git && !error48 && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
45689
+ if (git) status.git = git;
45690
+ if (error48) status.error = error48;
45691
+ if (machineStatus) status.machineStatus = machineStatus;
45692
+ if (lastSeenAt) status.lastSeenAt = lastSeenAt;
45693
+ if (updatedAt) status.updatedAt = updatedAt;
45694
+ if (activeSessions.length > 0) status.activeSessions = activeSessions;
45695
+ if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
45696
+ if (health) {
45697
+ status.health = health;
45698
+ return true;
45699
+ }
45700
+ if (git) {
45701
+ status.health = deriveMeshNodeHealthFromGit(git);
45702
+ return true;
45703
+ }
45704
+ return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
45705
+ }
45396
45706
  async function resolveProviderTypeFromPriority(args) {
45397
45707
  if (!args.providerPriority.length) {
45398
45708
  return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
@@ -45781,6 +46091,7 @@ var init_router = __esm({
45781
46091
  init_chat_history();
45782
46092
  init_ide_detector();
45783
46093
  init_cli_detector();
46094
+ init_git_status();
45784
46095
  init_logger();
45785
46096
  init_command_log();
45786
46097
  init_js_yaml();
@@ -45830,7 +46141,12 @@ var init_router = __esm({
45830
46141
  }
45831
46142
  return this.inlineMeshCache.get(meshId);
45832
46143
  }
45833
- async getMeshForCommand(meshId, inlineMesh) {
46144
+ async getMeshForCommand(meshId, inlineMesh, options) {
46145
+ const preferInline = options?.preferInline === true;
46146
+ if (preferInline) {
46147
+ const cached3 = this.getCachedInlineMesh(meshId, inlineMesh);
46148
+ if (cached3) return { mesh: cached3, inline: true };
46149
+ }
45834
46150
  try {
45835
46151
  const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
45836
46152
  const mesh = getMesh3(meshId);
@@ -47653,7 +47969,7 @@ ${block}`);
47653
47969
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
47654
47970
  if (!meshId) return { success: false, error: "meshId required" };
47655
47971
  try {
47656
- const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
47972
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
47657
47973
  const mesh = meshRecord?.mesh;
47658
47974
  if (!mesh) return { success: false, error: "Mesh not found" };
47659
47975
  const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
@@ -47662,84 +47978,102 @@ ${block}`);
47662
47978
  const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
47663
47979
  const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
47664
47980
  const ledgerSummary = getLedgerSummary2(meshId);
47981
+ const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
47982
+ const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
47983
+ const localMachineId = loadConfig().machineId || "";
47984
+ const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes) ? readStringValue(mesh.nodes[0]?.id, mesh.nodes[0]?.nodeId) : void 0;
47985
+ const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
47665
47986
  const nodeStatuses = [];
47666
- for (const node of mesh.nodes || []) {
47987
+ for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
47988
+ const nodeId = String(node.id || node.nodeId || "");
47989
+ const daemonId = readStringValue(node.daemonId);
47990
+ const providerPriority = readProviderPriorityFromPolicy(node.policy);
47991
+ const isSelfNode = Boolean(
47992
+ nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
47993
+ ) || Boolean(
47994
+ daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
47995
+ ) || Boolean(meshRecord?.inline && nodeIndex === 0);
47667
47996
  const status = {
47668
- nodeId: node.id || node.nodeId,
47997
+ nodeId,
47669
47998
  machineLabel: node.machineLabel || node.id || node.nodeId,
47670
47999
  workspace: node.workspace,
47671
48000
  repoRoot: node.repoRoot,
47672
48001
  isLocalWorktree: node.isLocalWorktree,
47673
48002
  worktreeBranch: node.worktreeBranch,
47674
- daemonId: node.daemonId,
48003
+ daemonId,
47675
48004
  machineId: node.machineId,
48005
+ machineStatus: node.machineStatus,
47676
48006
  health: "unknown",
47677
48007
  providers: node.providers || [],
47678
- activeSessions: []
48008
+ providerPriority,
48009
+ activeSessions: [],
48010
+ activeSessionDetails: [],
48011
+ launchReady: false
47679
48012
  };
48013
+ if (isSelfNode) {
48014
+ status.connection = {
48015
+ perspective: "selected_coordinator",
48016
+ source: "mesh_peer_status",
48017
+ state: "self",
48018
+ transport: "local",
48019
+ reported: true,
48020
+ reason: "Selected coordinator daemon",
48021
+ lastStateChangeAt: refreshedAt
48022
+ };
48023
+ } else if (daemonId) {
48024
+ const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
48025
+ status.connection = connection ?? {
48026
+ perspective: "selected_coordinator",
48027
+ source: "not_reported",
48028
+ state: "unknown",
48029
+ transport: "unknown",
48030
+ reported: false,
48031
+ reason: "No live mesh peer telemetry reported by the selected coordinator yet."
48032
+ };
48033
+ } else {
48034
+ status.connection = {
48035
+ perspective: "selected_coordinator",
48036
+ source: "not_reported",
48037
+ state: "unknown",
48038
+ transport: "unknown",
48039
+ reported: false,
48040
+ reason: "Node has no daemon id, so mesh transport cannot be reported from the selected coordinator."
48041
+ };
48042
+ }
48043
+ const matchedLiveSessionRecords = liveMeshSessions.filter((record2) => this.sessionMatchesMeshNode(record2, node, nodeId));
48044
+ if (matchedLiveSessionRecords.length > 0) {
48045
+ const sessionIds = matchedLiveSessionRecords.map((record2) => typeof record2?.sessionId === "string" ? record2.sessionId : "").filter(Boolean);
48046
+ const providerTypes = matchedLiveSessionRecords.map((record2) => readStringValue(record2?.providerType)).filter(Boolean);
48047
+ status.activeSessions = sessionIds;
48048
+ status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
48049
+ if (providerTypes.length > 0) {
48050
+ status.providers = Array.from(/* @__PURE__ */ new Set([...Array.isArray(status.providers) ? status.providers : [], ...providerTypes]));
48051
+ }
48052
+ }
47680
48053
  if (node.workspace && typeof node.workspace === "string") {
48054
+ if (!fs10.existsSync(node.workspace) && applyCachedInlineMeshNodeStatus(status, node)) {
48055
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
48056
+ nodeStatuses.push(status);
48057
+ continue;
48058
+ }
47681
48059
  try {
47682
- const { execFile: execFile3 } = await import("child_process");
47683
- const { promisify: promisify3 } = await import("util");
47684
- const execFileAsync3 = promisify3(execFile3);
47685
- const runGit2 = async (args2) => {
47686
- const result = await execFileAsync3("git", ["-C", node.workspace, ...args2], {
47687
- encoding: "utf8",
47688
- timeout: 1e4
47689
- });
47690
- return result.stdout.trim();
47691
- };
47692
- const branch = await runGit2(["branch", "--show-current"]).catch(() => "");
47693
- const porc = await runGit2(["status", "--porcelain"]).catch(() => "");
47694
- const headCommit = await runGit2(["rev-parse", "--short", "HEAD"]).catch(() => null);
47695
- const headMessage = await runGit2(["log", "-1", "--format=%s"]).catch(() => null);
47696
- const upstream = await runGit2(["rev-parse", "--abbrev-ref", "@{upstream}"]).catch(() => null);
47697
- const aheadBehind = await runGit2(["rev-list", "--left-right", "--count", "@{upstream}...HEAD"]).catch(() => "");
47698
- const stashCount = await runGit2(["stash", "list"]).catch(() => "");
47699
- let ahead = 0, behind = 0;
47700
- if (aheadBehind) {
47701
- const parts = aheadBehind.split(/\s+/);
47702
- if (parts.length >= 2) {
47703
- behind = parseInt(parts[0], 10) || 0;
47704
- ahead = parseInt(parts[1], 10) || 0;
47705
- }
47706
- }
47707
- const dirty = porc.length > 0;
47708
- const lines = porc ? porc.split("\n").filter(Boolean) : [];
47709
- let staged = 0, modified = 0, untracked = 0, deleted = 0, renamed2 = 0;
47710
- for (const line of lines) {
47711
- const xy = line.slice(0, 2);
47712
- if (xy[0] !== " " && xy[0] !== "?") staged++;
47713
- if (xy[1] === "M") modified++;
47714
- if (xy[1] === "D") deleted++;
47715
- if (xy[0] === "R" || xy[1] === "R") renamed2++;
47716
- if (xy === "??") untracked++;
48060
+ const gitStatus = await getGitRepoStatus(node.workspace, { timeoutMs: 1e4, refreshUpstream: true });
48061
+ status.git = gitStatus;
48062
+ if (gitStatus.isGitRepo) {
48063
+ status.health = deriveMeshNodeHealthFromGit(gitStatus);
48064
+ } else {
48065
+ status.health = "degraded";
48066
+ if (gitStatus.error && !status.error) status.error = gitStatus.error;
47717
48067
  }
47718
- status.git = {
47719
- workspace: node.workspace,
47720
- repoRoot: node.workspace,
47721
- isGitRepo: true,
47722
- branch: branch || null,
47723
- headCommit,
47724
- headMessage,
47725
- upstream,
47726
- ahead,
47727
- behind,
47728
- staged,
47729
- modified,
47730
- untracked,
47731
- deleted,
47732
- renamed: renamed2,
47733
- hasConflicts: false,
47734
- conflictFiles: [],
47735
- stashCount: stashCount ? stashCount.split("\n").filter(Boolean).length : 0,
47736
- lastCheckedAt: Date.now()
47737
- };
47738
- status.health = branch ? dirty ? "dirty" : "online" : "degraded";
47739
48068
  } catch {
47740
- status.health = "degraded";
48069
+ if (!applyCachedInlineMeshNodeStatus(status, node)) {
48070
+ status.health = "degraded";
48071
+ }
47741
48072
  }
48073
+ } else {
48074
+ applyCachedInlineMeshNodeStatus(status, node);
47742
48075
  }
48076
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
47743
48077
  nodeStatuses.push(status);
47744
48078
  }
47745
48079
  return {
@@ -47748,6 +48082,7 @@ ${block}`);
47748
48082
  meshName: mesh.name,
47749
48083
  repoIdentity: mesh.repoIdentity,
47750
48084
  defaultBranch: mesh.defaultBranch,
48085
+ refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
47751
48086
  nodes: nodeStatuses,
47752
48087
  queue: { tasks: queue, summary: queueSummary },
47753
48088
  ledger: { entries: ledgerEntries, summary: ledgerSummary }
@@ -55826,6 +56161,7 @@ async function initDaemonComponents(config2) {
55826
56161
  sessionHostControl: config2.sessionHostControl,
55827
56162
  statusInstanceId: config2.statusInstanceId,
55828
56163
  statusVersion: config2.statusVersion,
56164
+ getMeshPeerConnectionStatus: config2.getMeshPeerConnectionStatus,
55829
56165
  getCdpLogFn: config2.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
55830
56166
  });
55831
56167
  poller = new AgentStreamPoller({
@@ -56127,6 +56463,7 @@ __export(src_exports, {
56127
56463
  prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
56128
56464
  prepareSessionModalUpdate: () => prepareSessionModalUpdate,
56129
56465
  probeCdpPort: () => probeCdpPort,
56466
+ queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
56130
56467
  readChatHistory: () => readChatHistory,
56131
56468
  readLedgerEntries: () => readLedgerEntries,
56132
56469
  readLedgerSlice: () => readLedgerSlice,
@@ -65918,11 +66255,30 @@ var init_daemon_mesh_manager = __esm({
65918
66255
  nodeDatachannel = null;
65919
66256
  peers = /* @__PURE__ */ new Map();
65920
66257
  // Map<targetDaemonId, PeerEntry>
66258
+ peerSnapshots = /* @__PURE__ */ new Map();
65921
66259
  pendingRequests = /* @__PURE__ */ new Map();
65922
66260
  commandCallback;
65923
66261
  p2pFailure(message, command, targetDaemonId) {
65924
66262
  return new P2pRelayFailureError(message, { command, targetDaemonId });
65925
66263
  }
66264
+ updatePeerSnapshot(targetDaemonId, state, patch = {}) {
66265
+ const previous = this.peerSnapshots.get(targetDaemonId);
66266
+ const now = (/* @__PURE__ */ new Date()).toISOString();
66267
+ this.peerSnapshots.set(targetDaemonId, {
66268
+ perspective: "selected_coordinator",
66269
+ source: "mesh_peer_status",
66270
+ reported: true,
66271
+ state,
66272
+ transport: patch.transport ?? previous?.transport ?? "unknown",
66273
+ reason: patch.reason ?? previous?.reason,
66274
+ lastStateChangeAt: now,
66275
+ lastConnectedAt: patch.lastConnectedAt ?? previous?.lastConnectedAt,
66276
+ lastCommandAt: patch.lastCommandAt ?? previous?.lastCommandAt
66277
+ });
66278
+ }
66279
+ getPeerConnectionStatus(targetDaemonId) {
66280
+ return this.peerSnapshots.get(targetDaemonId) ?? null;
66281
+ }
65926
66282
  invalidatePeer(targetDaemonId, reason, options = {}) {
65927
66283
  const peer = this.peers.get(targetDaemonId);
65928
66284
  if (peer?.commandQueue) {
@@ -65937,6 +66293,11 @@ var init_daemon_mesh_manager = __esm({
65937
66293
  pending.reject(this.p2pFailure(reason, pending.command, targetDaemonId));
65938
66294
  }
65939
66295
  }
66296
+ const snapshotState = peer?.state === "closed" ? "closed" : peer?.state === "disconnected" ? "disconnected" : "failed";
66297
+ this.updatePeerSnapshot(targetDaemonId, snapshotState, {
66298
+ reason,
66299
+ transport: peer?.isRelay === true ? "relay" : peer?.isRelay === false ? "direct" : "unknown"
66300
+ });
65940
66301
  if (options.closeResources !== false && peer) {
65941
66302
  try {
65942
66303
  peer.dataChannel?.close?.();
@@ -65969,6 +66330,7 @@ var init_daemon_mesh_manager = __esm({
65969
66330
  "send_chat",
65970
66331
  "read_chat",
65971
66332
  "get_chat_debug_bundle",
66333
+ "get_pending_mesh_events",
65972
66334
  "git_status",
65973
66335
  "git_diff_summary",
65974
66336
  "launch_cli",
@@ -66056,6 +66418,20 @@ var init_daemon_mesh_manager = __esm({
66056
66418
  if (!peer) {
66057
66419
  throw this.p2pFailure("Failed to initiate P2P connection entry", command, targetDaemonId);
66058
66420
  }
66421
+ const lastCommandAt = (/* @__PURE__ */ new Date()).toISOString();
66422
+ if (peer.state === "connected") {
66423
+ this.updatePeerSnapshot(targetDaemonId, "connected", {
66424
+ transport: peer.isRelay === true ? "relay" : peer.isRelay === false ? "direct" : "unknown",
66425
+ lastConnectedAt: this.peerSnapshots.get(targetDaemonId)?.lastConnectedAt,
66426
+ lastCommandAt
66427
+ });
66428
+ } else {
66429
+ this.updatePeerSnapshot(targetDaemonId, "connecting", {
66430
+ transport: peer.isRelay === true ? "relay" : peer.isRelay === false ? "direct" : "unknown",
66431
+ reason: "Waiting for mesh DataChannel to open.",
66432
+ lastCommandAt
66433
+ });
66434
+ }
66059
66435
  return new Promise((resolve20, reject) => {
66060
66436
  const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
66061
66437
  const timer = setTimeout(() => {
@@ -66199,6 +66575,9 @@ var init_daemon_mesh_manager = __esm({
66199
66575
  remoteDescriptionSet: false
66200
66576
  };
66201
66577
  this.peers.set(targetDaemonId, entry);
66578
+ this.updatePeerSnapshot(targetDaemonId, "connecting", {
66579
+ reason: isInitiator ? "P2P mesh connection initiated by the selected coordinator." : "Waiting for the remote daemon to finish the mesh DataChannel handshake."
66580
+ });
66202
66581
  pc.onLocalDescription((sdp, type2) => {
66203
66582
  this.serverConn.sendMeshCommand(targetDaemonId, type2 === "offer" ? "mesh_p2p_offer" : "mesh_p2p_answer", { sdp, type: type2 });
66204
66583
  });
@@ -66209,7 +66588,26 @@ var init_daemon_mesh_manager = __esm({
66209
66588
  LOG.info("Mesh", `[Mesh] P2P state with ${targetDaemonId.slice(0, 12)}: ${state}`);
66210
66589
  if (state === "connected") {
66211
66590
  entry.state = "connected";
66591
+ let transport = "unknown";
66592
+ try {
66593
+ const pair = pc.getSelectedCandidatePair?.();
66594
+ if (pair) {
66595
+ const localType = pair.local?.type || "unknown";
66596
+ const remoteType = pair.remote?.type || "unknown";
66597
+ entry.isRelay = localType === "relay" || remoteType === "relay";
66598
+ transport = entry.isRelay ? "relay" : "direct";
66599
+ LOG.info("Mesh", `[Mesh] Candidate pair with ${targetDaemonId.slice(0, 12)}: local=${localType} remote=${remoteType} \u2192 ${transport}`);
66600
+ }
66601
+ } catch {
66602
+ transport = entry.isRelay === true ? "relay" : entry.isRelay === false ? "direct" : "unknown";
66603
+ }
66604
+ this.updatePeerSnapshot(targetDaemonId, "connected", {
66605
+ transport,
66606
+ reason: transport === "relay" ? "Connected over TURN relay." : transport === "direct" ? "Connected directly peer-to-peer." : "Connected, but selected candidate pair details are unavailable.",
66607
+ lastConnectedAt: (/* @__PURE__ */ new Date()).toISOString()
66608
+ });
66212
66609
  } else if (state === "failed" || state === "closed" || state === "disconnected") {
66610
+ entry.state = state;
66213
66611
  this.invalidatePeer(targetDaemonId, `P2P state changed to ${state}`, { rejectPending: true, closeResources: false });
66214
66612
  }
66215
66613
  });
@@ -66227,6 +66625,11 @@ var init_daemon_mesh_manager = __esm({
66227
66625
  dc.onOpen(() => {
66228
66626
  LOG.info("Mesh", `[Mesh] DataChannel OPEN with ${targetDaemonId.slice(0, 12)}`);
66229
66627
  entry.state = "connected";
66628
+ this.updatePeerSnapshot(targetDaemonId, "connected", {
66629
+ transport: entry.isRelay === true ? "relay" : entry.isRelay === false ? "direct" : "unknown",
66630
+ reason: entry.isRelay === true ? "Connected over TURN relay." : entry.isRelay === false ? "Connected directly peer-to-peer." : "DataChannel open; transport details not reported yet.",
66631
+ lastConnectedAt: (/* @__PURE__ */ new Date()).toISOString()
66632
+ });
66230
66633
  if (entry.commandQueue) {
66231
66634
  const queue = entry.commandQueue;
66232
66635
  entry.commandQueue = [];
@@ -66506,6 +66909,7 @@ var init_adhdev_daemon = __esm({
66506
66909
  "use strict";
66507
66910
  init_server_connection();
66508
66911
  init_src();
66912
+ init_mesh_events();
66509
66913
  init_daemon_p2p2();
66510
66914
  init_screenshot_controller();
66511
66915
  init_session_host();
@@ -66522,7 +66926,7 @@ var init_adhdev_daemon = __esm({
66522
66926
  init_version();
66523
66927
  init_src();
66524
66928
  init_runtime_defaults();
66525
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.81" });
66929
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.82-rc.10" });
66526
66930
  AdhdevDaemon = class _AdhdevDaemon {
66527
66931
  localHttpServer = null;
66528
66932
  localWss = null;
@@ -67046,6 +67450,7 @@ ${err?.stack || ""}`);
67046
67450
  if (!this.meshManager) throw new Error("Mesh manager not initialized");
67047
67451
  return this.meshManager.sendCommand(daemonId, command, args);
67048
67452
  },
67453
+ getMeshPeerConnectionStatus: (daemonId) => this.meshManager?.getPeerConnectionStatus(daemonId) ?? null,
67049
67454
  onStatusChange: () => {
67050
67455
  this.invalidateHotChatSnapshotCache();
67051
67456
  this.statusReporter?.onStatusChange();
@@ -67438,6 +67843,21 @@ ${err?.stack || ""}`);
67438
67843
  await this.meshManager.sendCommand(coordinatorDaemonId, "mesh_forward_event", payload);
67439
67844
  LOG.info("MeshEvents", `Relayed ${payload.event} for mesh ${meshId} to coordinator daemon ${coordinatorDaemonId.slice(0, 12)}\u2026`);
67440
67845
  } catch (error48) {
67846
+ queuePendingMeshCoordinatorEvent({
67847
+ event: payload.event,
67848
+ meshId,
67849
+ nodeLabel: payload.nodeId ? `Node '${payload.nodeId}'` : payload.workspace ? `Agent at ${payload.workspace}` : "Remote agent",
67850
+ nodeId: payload.nodeId || void 0,
67851
+ workspace: payload.workspace || void 0,
67852
+ metadataEvent: {
67853
+ targetSessionId: payload.targetSessionId,
67854
+ providerType: payload.providerType,
67855
+ providerSessionId: payload.providerSessionId,
67856
+ finalSummary: payload.finalSummary,
67857
+ workspace: payload.workspace
67858
+ },
67859
+ queuedAt: Date.now()
67860
+ });
67441
67861
  LOG.warn("MeshEvents", `Failed to relay ${payload.event} for mesh ${meshId}: ${error48?.message || error48}`);
67442
67862
  }
67443
67863
  }