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/cli/index.js CHANGED
@@ -784,8 +784,14 @@ async function getGitRepoStatus(workspace, options = {}) {
784
784
  const includeSubmodules = options.includeSubmodules !== false;
785
785
  try {
786
786
  const repo = await resolveGitRepository(workspace, options);
787
- const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
788
- const parsed = parsePorcelainV2Status(statusOutput.stdout);
787
+ let parsed = await readPorcelainStatus(repo, options);
788
+ let upstreamProbe = getInitialUpstreamProbe(parsed);
789
+ if (options.refreshUpstream) {
790
+ upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
791
+ if (upstreamProbe.upstreamStatus === "fresh") {
792
+ parsed = await readPorcelainStatus(repo, options);
793
+ }
794
+ }
789
795
  const head = await readHead(repo, options);
790
796
  const stashCount = await readStashCount(repo, options);
791
797
  let submodules;
@@ -800,6 +806,9 @@ async function getGitRepoStatus(workspace, options = {}) {
800
806
  headCommit: head.commit,
801
807
  headMessage: head.message,
802
808
  upstream: parsed.upstream,
809
+ upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
810
+ upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
811
+ upstreamFetchError: upstreamProbe.upstreamFetchError,
803
812
  ahead: parsed.ahead,
804
813
  behind: parsed.behind,
805
814
  staged: parsed.staged,
@@ -824,6 +833,60 @@ async function getGitRepoStatus(workspace, options = {}) {
824
833
  );
825
834
  }
826
835
  }
836
+ async function readPorcelainStatus(repo, options) {
837
+ const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
838
+ return parsePorcelainV2Status(statusOutput.stdout);
839
+ }
840
+ function getInitialUpstreamProbe(parsed) {
841
+ return {
842
+ upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
843
+ };
844
+ }
845
+ async function refreshTrackedUpstream(repo, parsed, options) {
846
+ if (!parsed.upstream || !parsed.branch) {
847
+ return { upstreamStatus: "no_upstream" };
848
+ }
849
+ const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
850
+ if (!remoteName) {
851
+ return {
852
+ upstreamStatus: "stale",
853
+ upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
854
+ };
855
+ }
856
+ try {
857
+ await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
858
+ return {
859
+ upstreamStatus: "fresh",
860
+ upstreamFetchedAt: Date.now()
861
+ };
862
+ } catch (error48) {
863
+ return {
864
+ upstreamStatus: "stale",
865
+ upstreamFetchError: formatGitError(error48)
866
+ };
867
+ }
868
+ }
869
+ async function readBranchRemote(repo, branch, options) {
870
+ try {
871
+ const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
872
+ return result.stdout.trim() || null;
873
+ } catch {
874
+ return null;
875
+ }
876
+ }
877
+ function inferRemoteName(upstream) {
878
+ const [remoteName] = upstream.split("/");
879
+ return remoteName?.trim() || null;
880
+ }
881
+ function formatGitError(error48) {
882
+ if (error48 instanceof GitCommandError) {
883
+ return error48.stderr || error48.message;
884
+ }
885
+ if (error48 instanceof Error) {
886
+ return error48.message;
887
+ }
888
+ return String(error48);
889
+ }
827
890
  function parsePorcelainV2Status(output) {
828
891
  const parsed = {
829
892
  branch: null,
@@ -918,6 +981,7 @@ function emptyStatus(workspace, lastCheckedAt, error48) {
918
981
  headCommit: null,
919
982
  headMessage: null,
920
983
  upstream: null,
984
+ upstreamStatus: "unavailable",
921
985
  ahead: 0,
922
986
  behind: 0,
923
987
  staged: 0,
@@ -1210,6 +1274,9 @@ function createGitCompactSummary(status, diffSummary) {
1210
1274
  isGitRepo: status.isGitRepo,
1211
1275
  repoRoot: status.repoRoot,
1212
1276
  branch: status.branch,
1277
+ upstreamStatus: status.upstreamStatus,
1278
+ upstreamFetchedAt: status.upstreamFetchedAt,
1279
+ upstreamFetchError: status.upstreamFetchError,
1213
1280
  dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
1214
1281
  changedFiles,
1215
1282
  ahead: status.ahead,
@@ -1537,7 +1604,7 @@ function serviceNotImplemented(command) {
1537
1604
  }
1538
1605
  function createDefaultGitCommandServices() {
1539
1606
  return {
1540
- getStatus: ({ workspace }) => getGitRepoStatus(workspace),
1607
+ getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
1541
1608
  getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
1542
1609
  getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
1543
1610
  createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
@@ -1622,7 +1689,7 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
1622
1689
  switch (command) {
1623
1690
  case "git_status": {
1624
1691
  if (!services.getStatus) return serviceNotImplemented(command);
1625
- const status = await runService(() => services.getStatus({ workspace }));
1692
+ const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
1626
1693
  return "success" in status ? status : { success: true, status };
1627
1694
  }
1628
1695
  case "git_diff_summary": {
@@ -4279,10 +4346,18 @@ __export(mesh_events_exports, {
4279
4346
  drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
4280
4347
  getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
4281
4348
  handleMeshForwardEvent: () => handleMeshForwardEvent,
4349
+ queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
4282
4350
  setupMeshEventForwarding: () => setupMeshEventForwarding,
4283
4351
  triggerMeshQueue: () => triggerMeshQueue,
4284
4352
  tryAssignQueueTask: () => tryAssignQueueTask
4285
4353
  });
4354
+ function queuePendingMeshCoordinatorEvent(event) {
4355
+ if (pendingMeshCoordinatorEvents.length >= MAX_PENDING_EVENTS) {
4356
+ return false;
4357
+ }
4358
+ pendingMeshCoordinatorEvents.push(event);
4359
+ return true;
4360
+ }
4286
4361
  function drainPendingMeshCoordinatorEvents() {
4287
4362
  return pendingMeshCoordinatorEvents.splice(0);
4288
4363
  }
@@ -4854,17 +4929,18 @@ function injectMeshSystemMessage(components, args) {
4854
4929
  return true;
4855
4930
  });
4856
4931
  if (coordinatorInstances.length === 0) {
4857
- if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
4858
- pendingMeshCoordinatorEvents.push({
4859
- event: args.event,
4860
- meshId: args.meshId,
4861
- nodeLabel: args.nodeLabel,
4862
- metadataEvent: {
4863
- ...args.metadataEvent,
4864
- ...recoveryContext ? { recoveryContext } : {}
4865
- },
4866
- queuedAt: Date.now()
4867
- });
4932
+ if (queuePendingMeshCoordinatorEvent({
4933
+ event: args.event,
4934
+ meshId: args.meshId,
4935
+ nodeLabel: args.nodeLabel,
4936
+ nodeId: args.nodeId || void 0,
4937
+ workspace: readNonEmptyString(args.metadataEvent.workspace),
4938
+ metadataEvent: {
4939
+ ...args.metadataEvent,
4940
+ ...recoveryContext ? { recoveryContext } : {}
4941
+ },
4942
+ queuedAt: Date.now()
4943
+ })) {
4868
4944
  LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
4869
4945
  }
4870
4946
  return { success: true, forwarded: 0 };
@@ -46381,6 +46457,240 @@ function readProviderPriorityFromPolicy(policy) {
46381
46457
  return true;
46382
46458
  });
46383
46459
  }
46460
+ function readObjectRecord(value) {
46461
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
46462
+ }
46463
+ function readStringValue(...values) {
46464
+ for (const value of values) {
46465
+ if (typeof value === "string" && value.trim()) return value.trim();
46466
+ }
46467
+ return void 0;
46468
+ }
46469
+ function readNumberValue(...values) {
46470
+ for (const value of values) {
46471
+ if (typeof value === "number" && Number.isFinite(value)) return value;
46472
+ }
46473
+ return void 0;
46474
+ }
46475
+ function readBooleanValue(...values) {
46476
+ for (const value of values) {
46477
+ if (typeof value === "boolean") return value;
46478
+ }
46479
+ return void 0;
46480
+ }
46481
+ function readGitSubmodules(value) {
46482
+ if (!Array.isArray(value)) return void 0;
46483
+ const submodules = value.map((entry) => {
46484
+ const submodule = readObjectRecord(entry);
46485
+ const path42 = readStringValue(submodule.path);
46486
+ const commit = readStringValue(submodule.commit);
46487
+ const repoPath = readStringValue(submodule.repoPath, submodule.repo_root);
46488
+ if (!path42 || !commit || !repoPath) return null;
46489
+ return {
46490
+ path: path42,
46491
+ commit,
46492
+ repoPath,
46493
+ dirty: readBooleanValue(submodule.dirty) ?? false,
46494
+ outOfSync: readBooleanValue(submodule.outOfSync, submodule.out_of_sync) ?? false,
46495
+ lastCheckedAt: readNumberValue(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now(),
46496
+ ...readStringValue(submodule.error) ? { error: readStringValue(submodule.error) } : {}
46497
+ };
46498
+ }).filter((entry) => entry !== null);
46499
+ return submodules.length > 0 ? submodules : void 0;
46500
+ }
46501
+ function buildCachedInlineMeshGitStatus(node) {
46502
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
46503
+ const cachedGit = readObjectRecord(cachedStatus.git);
46504
+ if (Object.keys(cachedGit).length) {
46505
+ const conflictFiles2 = Array.isArray(cachedGit.conflictFiles) ? cachedGit.conflictFiles.filter((value) => typeof value === "string") : [];
46506
+ const conflictCount2 = readNumberValue(cachedGit.conflicts) ?? conflictFiles2.length;
46507
+ const hasConflicts2 = readBooleanValue(cachedGit.hasConflicts) ?? conflictCount2 > 0;
46508
+ const isGitRepo2 = readBooleanValue(cachedGit.isGitRepo);
46509
+ if (isGitRepo2 !== void 0) {
46510
+ const submodules2 = readGitSubmodules(cachedGit.submodules);
46511
+ return {
46512
+ workspace: readStringValue(cachedGit.workspace, node?.workspace) || "",
46513
+ repoRoot: readStringValue(cachedGit.repoRoot, node?.repoRoot, node?.workspace) || null,
46514
+ isGitRepo: isGitRepo2,
46515
+ branch: readStringValue(cachedGit.branch) ?? null,
46516
+ headCommit: readStringValue(cachedGit.headCommit) ?? null,
46517
+ headMessage: readStringValue(cachedGit.headMessage) ?? null,
46518
+ upstream: readStringValue(cachedGit.upstream) ?? null,
46519
+ ahead: readNumberValue(cachedGit.ahead) ?? 0,
46520
+ behind: readNumberValue(cachedGit.behind) ?? 0,
46521
+ staged: readNumberValue(cachedGit.staged) ?? 0,
46522
+ modified: readNumberValue(cachedGit.modified) ?? 0,
46523
+ untracked: readNumberValue(cachedGit.untracked) ?? 0,
46524
+ deleted: readNumberValue(cachedGit.deleted) ?? 0,
46525
+ renamed: readNumberValue(cachedGit.renamed) ?? 0,
46526
+ hasConflicts: hasConflicts2,
46527
+ conflictFiles: conflictFiles2,
46528
+ stashCount: readNumberValue(cachedGit.stashCount) ?? 0,
46529
+ lastCheckedAt: readNumberValue(cachedGit.lastCheckedAt) ?? Date.now(),
46530
+ ...submodules2 ? { submodules: submodules2 } : {}
46531
+ };
46532
+ }
46533
+ }
46534
+ const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
46535
+ const gitResult = readObjectRecord(rawGit.result);
46536
+ const directStatus = readObjectRecord(rawGit.status);
46537
+ const nestedStatus = readObjectRecord(gitResult.status);
46538
+ const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
46539
+ const probeGit = readObjectRecord(rawProbe.git);
46540
+ const probeGitResult = readObjectRecord(probeGit.result);
46541
+ const probeDirectStatus = readObjectRecord(probeGit.status);
46542
+ const probeNestedStatus = readObjectRecord(probeGitResult.status);
46543
+ const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
46544
+ const isGitRepo = readBooleanValue(status.isGitRepo);
46545
+ if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
46546
+ const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((value) => typeof value === "string") : [];
46547
+ const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
46548
+ const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
46549
+ const submodules = readGitSubmodules(status.submodules);
46550
+ return {
46551
+ workspace: readStringValue(status.workspace, node?.workspace) || "",
46552
+ repoRoot: readStringValue(status.repoRoot, node?.repoRoot, node?.workspace) || null,
46553
+ isGitRepo,
46554
+ branch: readStringValue(status.branch) ?? null,
46555
+ headCommit: readStringValue(status.headCommit) ?? null,
46556
+ headMessage: readStringValue(status.headMessage) ?? null,
46557
+ upstream: readStringValue(status.upstream) ?? null,
46558
+ ahead: readNumberValue(status.ahead) ?? 0,
46559
+ behind: readNumberValue(status.behind) ?? 0,
46560
+ staged: readNumberValue(status.staged) ?? 0,
46561
+ modified: readNumberValue(status.modified) ?? 0,
46562
+ untracked: readNumberValue(status.untracked) ?? 0,
46563
+ deleted: readNumberValue(status.deleted) ?? 0,
46564
+ renamed: readNumberValue(status.renamed) ?? 0,
46565
+ hasConflicts,
46566
+ conflictFiles,
46567
+ stashCount: readNumberValue(status.stashCount) ?? 0,
46568
+ lastCheckedAt: Date.now(),
46569
+ ...submodules ? { submodules } : {}
46570
+ };
46571
+ }
46572
+ function hasGitWorktreeChanges(git) {
46573
+ if (!git) return false;
46574
+ return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
46575
+ }
46576
+ function getGitSubmoduleDriftState(git) {
46577
+ const submodules = Array.isArray(git?.submodules) ? git.submodules : [];
46578
+ let dirty = false;
46579
+ let outOfSync = false;
46580
+ for (const entry of submodules) {
46581
+ const submodule = readObjectRecord(entry);
46582
+ if (readBooleanValue(submodule.dirty) === true) dirty = true;
46583
+ if (readBooleanValue(submodule.outOfSync) === true || !!readStringValue(submodule.error)) outOfSync = true;
46584
+ }
46585
+ return { dirty, outOfSync };
46586
+ }
46587
+ function deriveMeshNodeHealthFromGit(git) {
46588
+ if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
46589
+ const branch = readStringValue(git.branch);
46590
+ if (!branch) return "degraded";
46591
+ const submoduleDrift = getGitSubmoduleDriftState(git);
46592
+ if (submoduleDrift.outOfSync) return "degraded";
46593
+ if (submoduleDrift.dirty || hasGitWorktreeChanges(git)) return "dirty";
46594
+ return "online";
46595
+ }
46596
+ function readCachedInlineMeshActiveSessions(node) {
46597
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
46598
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
46599
+ const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
46600
+ const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
46601
+ return sessionId ? [sessionId] : [];
46602
+ }
46603
+ function readCachedInlineMeshActiveSessionDetails(node) {
46604
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
46605
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
46606
+ const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
46607
+ const sessionId = readStringValue(
46608
+ fallbackSession.id,
46609
+ fallbackSession.sessionId,
46610
+ fallbackSession.session_id,
46611
+ node?.activeSessionId,
46612
+ node?.active_session_id,
46613
+ node?.sessionId,
46614
+ node?.session_id
46615
+ );
46616
+ if (!sessionId) return [];
46617
+ return [{
46618
+ sessionId,
46619
+ providerType: readStringValue(
46620
+ fallbackSession.providerType,
46621
+ fallbackSession.provider_type,
46622
+ fallbackSession.cliType,
46623
+ fallbackSession.cli_type,
46624
+ fallbackSession.provider,
46625
+ node?.providerType,
46626
+ node?.provider_type
46627
+ ),
46628
+ state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
46629
+ lifecycle: readStringValue(fallbackSession.lifecycle),
46630
+ title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
46631
+ workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
46632
+ lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
46633
+ recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
46634
+ isCached: true
46635
+ }];
46636
+ }
46637
+ function readLiveMeshSessionState(record2) {
46638
+ return readStringValue(
46639
+ record2?.meta?.sessionStatus,
46640
+ record2?.meta?.status,
46641
+ record2?.meta?.providerStatus,
46642
+ record2?.status,
46643
+ record2?.state,
46644
+ record2?.lifecycle
46645
+ );
46646
+ }
46647
+ function toIsoTimestamp(value) {
46648
+ if (typeof value === "number" && Number.isFinite(value)) return new Date(value).toISOString();
46649
+ const stringValue = readStringValue(value);
46650
+ return stringValue || null;
46651
+ }
46652
+ function summarizeMeshSessionRecord(record2) {
46653
+ return {
46654
+ sessionId: readStringValue(record2?.sessionId) || "unknown",
46655
+ providerType: readStringValue(record2?.providerType),
46656
+ state: readLiveMeshSessionState(record2),
46657
+ lifecycle: readStringValue(record2?.lifecycle),
46658
+ surfaceKind: getSessionHostSurfaceKind(record2),
46659
+ recoveryState: readStringValue(record2?.meta?.runtimeRecoveryState) ?? null,
46660
+ workspace: readStringValue(record2?.workspace) ?? null,
46661
+ title: readStringValue(record2?.displayName, record2?.workspaceLabel) ?? null,
46662
+ lastActivityAt: toIsoTimestamp(record2?.updatedAt ?? record2?.lastActivityAt ?? record2?.last_activity_at),
46663
+ isCached: false
46664
+ };
46665
+ }
46666
+ function applyCachedInlineMeshNodeStatus(status, node) {
46667
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
46668
+ const git = buildCachedInlineMeshGitStatus(node);
46669
+ const error48 = readStringValue(cachedStatus.error, node?.error);
46670
+ const health = readStringValue(cachedStatus.health, node?.health);
46671
+ const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
46672
+ const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
46673
+ const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
46674
+ const activeSessions = readCachedInlineMeshActiveSessions(node);
46675
+ const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
46676
+ if (!git && !error48 && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
46677
+ if (git) status.git = git;
46678
+ if (error48) status.error = error48;
46679
+ if (machineStatus) status.machineStatus = machineStatus;
46680
+ if (lastSeenAt) status.lastSeenAt = lastSeenAt;
46681
+ if (updatedAt) status.updatedAt = updatedAt;
46682
+ if (activeSessions.length > 0) status.activeSessions = activeSessions;
46683
+ if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
46684
+ if (health) {
46685
+ status.health = health;
46686
+ return true;
46687
+ }
46688
+ if (git) {
46689
+ status.health = deriveMeshNodeHealthFromGit(git);
46690
+ return true;
46691
+ }
46692
+ return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
46693
+ }
46384
46694
  async function resolveProviderTypeFromPriority(args) {
46385
46695
  if (!args.providerPriority.length) {
46386
46696
  return { error: `Node '${args.nodeId}' has no providerPriority policy; pass cliType explicitly or configure node.policy.providerPriority` };
@@ -46769,6 +47079,7 @@ var init_router = __esm({
46769
47079
  init_chat_history();
46770
47080
  init_ide_detector();
46771
47081
  init_cli_detector();
47082
+ init_git_status();
46772
47083
  init_logger();
46773
47084
  init_command_log();
46774
47085
  init_js_yaml();
@@ -46818,7 +47129,12 @@ var init_router = __esm({
46818
47129
  }
46819
47130
  return this.inlineMeshCache.get(meshId);
46820
47131
  }
46821
- async getMeshForCommand(meshId, inlineMesh) {
47132
+ async getMeshForCommand(meshId, inlineMesh, options) {
47133
+ const preferInline = options?.preferInline === true;
47134
+ if (preferInline) {
47135
+ const cached3 = this.getCachedInlineMesh(meshId, inlineMesh);
47136
+ if (cached3) return { mesh: cached3, inline: true };
47137
+ }
46822
47138
  try {
46823
47139
  const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
46824
47140
  const mesh = getMesh3(meshId);
@@ -48641,7 +48957,7 @@ ${block}`);
48641
48957
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
48642
48958
  if (!meshId) return { success: false, error: "meshId required" };
48643
48959
  try {
48644
- const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
48960
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
48645
48961
  const mesh = meshRecord?.mesh;
48646
48962
  if (!mesh) return { success: false, error: "Mesh not found" };
48647
48963
  const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
@@ -48650,84 +48966,102 @@ ${block}`);
48650
48966
  const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
48651
48967
  const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
48652
48968
  const ledgerSummary = getLedgerSummary2(meshId);
48969
+ const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
48970
+ const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
48971
+ const localMachineId = loadConfig().machineId || "";
48972
+ const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes) ? readStringValue(mesh.nodes[0]?.id, mesh.nodes[0]?.nodeId) : void 0;
48973
+ const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
48653
48974
  const nodeStatuses = [];
48654
- for (const node of mesh.nodes || []) {
48975
+ for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
48976
+ const nodeId = String(node.id || node.nodeId || "");
48977
+ const daemonId = readStringValue(node.daemonId);
48978
+ const providerPriority = readProviderPriorityFromPolicy(node.policy);
48979
+ const isSelfNode = Boolean(
48980
+ nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
48981
+ ) || Boolean(
48982
+ daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
48983
+ ) || Boolean(meshRecord?.inline && nodeIndex === 0);
48655
48984
  const status = {
48656
- nodeId: node.id || node.nodeId,
48985
+ nodeId,
48657
48986
  machineLabel: node.machineLabel || node.id || node.nodeId,
48658
48987
  workspace: node.workspace,
48659
48988
  repoRoot: node.repoRoot,
48660
48989
  isLocalWorktree: node.isLocalWorktree,
48661
48990
  worktreeBranch: node.worktreeBranch,
48662
- daemonId: node.daemonId,
48991
+ daemonId,
48663
48992
  machineId: node.machineId,
48993
+ machineStatus: node.machineStatus,
48664
48994
  health: "unknown",
48665
48995
  providers: node.providers || [],
48666
- activeSessions: []
48996
+ providerPriority,
48997
+ activeSessions: [],
48998
+ activeSessionDetails: [],
48999
+ launchReady: false
48667
49000
  };
49001
+ if (isSelfNode) {
49002
+ status.connection = {
49003
+ perspective: "selected_coordinator",
49004
+ source: "mesh_peer_status",
49005
+ state: "self",
49006
+ transport: "local",
49007
+ reported: true,
49008
+ reason: "Selected coordinator daemon",
49009
+ lastStateChangeAt: refreshedAt
49010
+ };
49011
+ } else if (daemonId) {
49012
+ const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
49013
+ status.connection = connection ?? {
49014
+ perspective: "selected_coordinator",
49015
+ source: "not_reported",
49016
+ state: "unknown",
49017
+ transport: "unknown",
49018
+ reported: false,
49019
+ reason: "No live mesh peer telemetry reported by the selected coordinator yet."
49020
+ };
49021
+ } else {
49022
+ status.connection = {
49023
+ perspective: "selected_coordinator",
49024
+ source: "not_reported",
49025
+ state: "unknown",
49026
+ transport: "unknown",
49027
+ reported: false,
49028
+ reason: "Node has no daemon id, so mesh transport cannot be reported from the selected coordinator."
49029
+ };
49030
+ }
49031
+ const matchedLiveSessionRecords = liveMeshSessions.filter((record2) => this.sessionMatchesMeshNode(record2, node, nodeId));
49032
+ if (matchedLiveSessionRecords.length > 0) {
49033
+ const sessionIds = matchedLiveSessionRecords.map((record2) => typeof record2?.sessionId === "string" ? record2.sessionId : "").filter(Boolean);
49034
+ const providerTypes = matchedLiveSessionRecords.map((record2) => readStringValue(record2?.providerType)).filter(Boolean);
49035
+ status.activeSessions = sessionIds;
49036
+ status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
49037
+ if (providerTypes.length > 0) {
49038
+ status.providers = Array.from(/* @__PURE__ */ new Set([...Array.isArray(status.providers) ? status.providers : [], ...providerTypes]));
49039
+ }
49040
+ }
48668
49041
  if (node.workspace && typeof node.workspace === "string") {
49042
+ if (!fs10.existsSync(node.workspace) && applyCachedInlineMeshNodeStatus(status, node)) {
49043
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
49044
+ nodeStatuses.push(status);
49045
+ continue;
49046
+ }
48669
49047
  try {
48670
- const { execFile: execFile3 } = await import("child_process");
48671
- const { promisify: promisify3 } = await import("util");
48672
- const execFileAsync3 = promisify3(execFile3);
48673
- const runGit2 = async (args2) => {
48674
- const result = await execFileAsync3("git", ["-C", node.workspace, ...args2], {
48675
- encoding: "utf8",
48676
- timeout: 1e4
48677
- });
48678
- return result.stdout.trim();
48679
- };
48680
- const branch = await runGit2(["branch", "--show-current"]).catch(() => "");
48681
- const porc = await runGit2(["status", "--porcelain"]).catch(() => "");
48682
- const headCommit = await runGit2(["rev-parse", "--short", "HEAD"]).catch(() => null);
48683
- const headMessage = await runGit2(["log", "-1", "--format=%s"]).catch(() => null);
48684
- const upstream = await runGit2(["rev-parse", "--abbrev-ref", "@{upstream}"]).catch(() => null);
48685
- const aheadBehind = await runGit2(["rev-list", "--left-right", "--count", "@{upstream}...HEAD"]).catch(() => "");
48686
- const stashCount = await runGit2(["stash", "list"]).catch(() => "");
48687
- let ahead = 0, behind = 0;
48688
- if (aheadBehind) {
48689
- const parts = aheadBehind.split(/\s+/);
48690
- if (parts.length >= 2) {
48691
- behind = parseInt(parts[0], 10) || 0;
48692
- ahead = parseInt(parts[1], 10) || 0;
48693
- }
48694
- }
48695
- const dirty = porc.length > 0;
48696
- const lines = porc ? porc.split("\n").filter(Boolean) : [];
48697
- let staged = 0, modified = 0, untracked = 0, deleted = 0, renamed2 = 0;
48698
- for (const line of lines) {
48699
- const xy = line.slice(0, 2);
48700
- if (xy[0] !== " " && xy[0] !== "?") staged++;
48701
- if (xy[1] === "M") modified++;
48702
- if (xy[1] === "D") deleted++;
48703
- if (xy[0] === "R" || xy[1] === "R") renamed2++;
48704
- if (xy === "??") untracked++;
49048
+ const gitStatus = await getGitRepoStatus(node.workspace, { timeoutMs: 1e4, refreshUpstream: true });
49049
+ status.git = gitStatus;
49050
+ if (gitStatus.isGitRepo) {
49051
+ status.health = deriveMeshNodeHealthFromGit(gitStatus);
49052
+ } else {
49053
+ status.health = "degraded";
49054
+ if (gitStatus.error && !status.error) status.error = gitStatus.error;
48705
49055
  }
48706
- status.git = {
48707
- workspace: node.workspace,
48708
- repoRoot: node.workspace,
48709
- isGitRepo: true,
48710
- branch: branch || null,
48711
- headCommit,
48712
- headMessage,
48713
- upstream,
48714
- ahead,
48715
- behind,
48716
- staged,
48717
- modified,
48718
- untracked,
48719
- deleted,
48720
- renamed: renamed2,
48721
- hasConflicts: false,
48722
- conflictFiles: [],
48723
- stashCount: stashCount ? stashCount.split("\n").filter(Boolean).length : 0,
48724
- lastCheckedAt: Date.now()
48725
- };
48726
- status.health = branch ? dirty ? "dirty" : "online" : "degraded";
48727
49056
  } catch {
48728
- status.health = "degraded";
49057
+ if (!applyCachedInlineMeshNodeStatus(status, node)) {
49058
+ status.health = "degraded";
49059
+ }
48729
49060
  }
49061
+ } else {
49062
+ applyCachedInlineMeshNodeStatus(status, node);
48730
49063
  }
49064
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
48731
49065
  nodeStatuses.push(status);
48732
49066
  }
48733
49067
  return {
@@ -48736,6 +49070,7 @@ ${block}`);
48736
49070
  meshName: mesh.name,
48737
49071
  repoIdentity: mesh.repoIdentity,
48738
49072
  defaultBranch: mesh.defaultBranch,
49073
+ refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
48739
49074
  nodes: nodeStatuses,
48740
49075
  queue: { tasks: queue, summary: queueSummary },
48741
49076
  ledger: { entries: ledgerEntries, summary: ledgerSummary }
@@ -56814,6 +57149,7 @@ async function initDaemonComponents(config2) {
56814
57149
  sessionHostControl: config2.sessionHostControl,
56815
57150
  statusInstanceId: config2.statusInstanceId,
56816
57151
  statusVersion: config2.statusVersion,
57152
+ getMeshPeerConnectionStatus: config2.getMeshPeerConnectionStatus,
56817
57153
  getCdpLogFn: config2.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
56818
57154
  });
56819
57155
  poller = new AgentStreamPoller({
@@ -57115,6 +57451,7 @@ __export(src_exports, {
57115
57451
  prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
57116
57452
  prepareSessionModalUpdate: () => prepareSessionModalUpdate,
57117
57453
  probeCdpPort: () => probeCdpPort,
57454
+ queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
57118
57455
  readChatHistory: () => readChatHistory,
57119
57456
  readLedgerEntries: () => readLedgerEntries,
57120
57457
  readLedgerSlice: () => readLedgerSlice,
@@ -97091,11 +97428,30 @@ var init_daemon_mesh_manager = __esm({
97091
97428
  nodeDatachannel = null;
97092
97429
  peers = /* @__PURE__ */ new Map();
97093
97430
  // Map<targetDaemonId, PeerEntry>
97431
+ peerSnapshots = /* @__PURE__ */ new Map();
97094
97432
  pendingRequests = /* @__PURE__ */ new Map();
97095
97433
  commandCallback;
97096
97434
  p2pFailure(message, command, targetDaemonId) {
97097
97435
  return new P2pRelayFailureError(message, { command, targetDaemonId });
97098
97436
  }
97437
+ updatePeerSnapshot(targetDaemonId, state, patch = {}) {
97438
+ const previous = this.peerSnapshots.get(targetDaemonId);
97439
+ const now = (/* @__PURE__ */ new Date()).toISOString();
97440
+ this.peerSnapshots.set(targetDaemonId, {
97441
+ perspective: "selected_coordinator",
97442
+ source: "mesh_peer_status",
97443
+ reported: true,
97444
+ state,
97445
+ transport: patch.transport ?? previous?.transport ?? "unknown",
97446
+ reason: patch.reason ?? previous?.reason,
97447
+ lastStateChangeAt: now,
97448
+ lastConnectedAt: patch.lastConnectedAt ?? previous?.lastConnectedAt,
97449
+ lastCommandAt: patch.lastCommandAt ?? previous?.lastCommandAt
97450
+ });
97451
+ }
97452
+ getPeerConnectionStatus(targetDaemonId) {
97453
+ return this.peerSnapshots.get(targetDaemonId) ?? null;
97454
+ }
97099
97455
  invalidatePeer(targetDaemonId, reason, options = {}) {
97100
97456
  const peer = this.peers.get(targetDaemonId);
97101
97457
  if (peer?.commandQueue) {
@@ -97110,6 +97466,11 @@ var init_daemon_mesh_manager = __esm({
97110
97466
  pending.reject(this.p2pFailure(reason, pending.command, targetDaemonId));
97111
97467
  }
97112
97468
  }
97469
+ const snapshotState = peer?.state === "closed" ? "closed" : peer?.state === "disconnected" ? "disconnected" : "failed";
97470
+ this.updatePeerSnapshot(targetDaemonId, snapshotState, {
97471
+ reason,
97472
+ transport: peer?.isRelay === true ? "relay" : peer?.isRelay === false ? "direct" : "unknown"
97473
+ });
97113
97474
  if (options.closeResources !== false && peer) {
97114
97475
  try {
97115
97476
  peer.dataChannel?.close?.();
@@ -97142,6 +97503,7 @@ var init_daemon_mesh_manager = __esm({
97142
97503
  "send_chat",
97143
97504
  "read_chat",
97144
97505
  "get_chat_debug_bundle",
97506
+ "get_pending_mesh_events",
97145
97507
  "git_status",
97146
97508
  "git_diff_summary",
97147
97509
  "launch_cli",
@@ -97229,6 +97591,20 @@ var init_daemon_mesh_manager = __esm({
97229
97591
  if (!peer) {
97230
97592
  throw this.p2pFailure("Failed to initiate P2P connection entry", command, targetDaemonId);
97231
97593
  }
97594
+ const lastCommandAt = (/* @__PURE__ */ new Date()).toISOString();
97595
+ if (peer.state === "connected") {
97596
+ this.updatePeerSnapshot(targetDaemonId, "connected", {
97597
+ transport: peer.isRelay === true ? "relay" : peer.isRelay === false ? "direct" : "unknown",
97598
+ lastConnectedAt: this.peerSnapshots.get(targetDaemonId)?.lastConnectedAt,
97599
+ lastCommandAt
97600
+ });
97601
+ } else {
97602
+ this.updatePeerSnapshot(targetDaemonId, "connecting", {
97603
+ transport: peer.isRelay === true ? "relay" : peer.isRelay === false ? "direct" : "unknown",
97604
+ reason: "Waiting for mesh DataChannel to open.",
97605
+ lastCommandAt
97606
+ });
97607
+ }
97232
97608
  return new Promise((resolve23, reject) => {
97233
97609
  const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
97234
97610
  const timer = setTimeout(() => {
@@ -97372,6 +97748,9 @@ var init_daemon_mesh_manager = __esm({
97372
97748
  remoteDescriptionSet: false
97373
97749
  };
97374
97750
  this.peers.set(targetDaemonId, entry);
97751
+ this.updatePeerSnapshot(targetDaemonId, "connecting", {
97752
+ reason: isInitiator ? "P2P mesh connection initiated by the selected coordinator." : "Waiting for the remote daemon to finish the mesh DataChannel handshake."
97753
+ });
97375
97754
  pc.onLocalDescription((sdp, type2) => {
97376
97755
  this.serverConn.sendMeshCommand(targetDaemonId, type2 === "offer" ? "mesh_p2p_offer" : "mesh_p2p_answer", { sdp, type: type2 });
97377
97756
  });
@@ -97382,7 +97761,26 @@ var init_daemon_mesh_manager = __esm({
97382
97761
  LOG.info("Mesh", `[Mesh] P2P state with ${targetDaemonId.slice(0, 12)}: ${state}`);
97383
97762
  if (state === "connected") {
97384
97763
  entry.state = "connected";
97764
+ let transport = "unknown";
97765
+ try {
97766
+ const pair = pc.getSelectedCandidatePair?.();
97767
+ if (pair) {
97768
+ const localType = pair.local?.type || "unknown";
97769
+ const remoteType = pair.remote?.type || "unknown";
97770
+ entry.isRelay = localType === "relay" || remoteType === "relay";
97771
+ transport = entry.isRelay ? "relay" : "direct";
97772
+ LOG.info("Mesh", `[Mesh] Candidate pair with ${targetDaemonId.slice(0, 12)}: local=${localType} remote=${remoteType} \u2192 ${transport}`);
97773
+ }
97774
+ } catch {
97775
+ transport = entry.isRelay === true ? "relay" : entry.isRelay === false ? "direct" : "unknown";
97776
+ }
97777
+ this.updatePeerSnapshot(targetDaemonId, "connected", {
97778
+ transport,
97779
+ reason: transport === "relay" ? "Connected over TURN relay." : transport === "direct" ? "Connected directly peer-to-peer." : "Connected, but selected candidate pair details are unavailable.",
97780
+ lastConnectedAt: (/* @__PURE__ */ new Date()).toISOString()
97781
+ });
97385
97782
  } else if (state === "failed" || state === "closed" || state === "disconnected") {
97783
+ entry.state = state;
97386
97784
  this.invalidatePeer(targetDaemonId, `P2P state changed to ${state}`, { rejectPending: true, closeResources: false });
97387
97785
  }
97388
97786
  });
@@ -97400,6 +97798,11 @@ var init_daemon_mesh_manager = __esm({
97400
97798
  dc.onOpen(() => {
97401
97799
  LOG.info("Mesh", `[Mesh] DataChannel OPEN with ${targetDaemonId.slice(0, 12)}`);
97402
97800
  entry.state = "connected";
97801
+ this.updatePeerSnapshot(targetDaemonId, "connected", {
97802
+ transport: entry.isRelay === true ? "relay" : entry.isRelay === false ? "direct" : "unknown",
97803
+ reason: entry.isRelay === true ? "Connected over TURN relay." : entry.isRelay === false ? "Connected directly peer-to-peer." : "DataChannel open; transport details not reported yet.",
97804
+ lastConnectedAt: (/* @__PURE__ */ new Date()).toISOString()
97805
+ });
97403
97806
  if (entry.commandQueue) {
97404
97807
  const queue = entry.commandQueue;
97405
97808
  entry.commandQueue = [];
@@ -97679,6 +98082,7 @@ var init_adhdev_daemon = __esm({
97679
98082
  "use strict";
97680
98083
  init_server_connection();
97681
98084
  init_src();
98085
+ init_mesh_events();
97682
98086
  init_daemon_p2p2();
97683
98087
  init_screenshot_controller();
97684
98088
  init_session_host();
@@ -97695,7 +98099,7 @@ var init_adhdev_daemon = __esm({
97695
98099
  init_version();
97696
98100
  init_src();
97697
98101
  init_runtime_defaults();
97698
- pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.81" });
98102
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.82-rc.10" });
97699
98103
  AdhdevDaemon = class _AdhdevDaemon {
97700
98104
  localHttpServer = null;
97701
98105
  localWss = null;
@@ -98219,6 +98623,7 @@ ${err?.stack || ""}`);
98219
98623
  if (!this.meshManager) throw new Error("Mesh manager not initialized");
98220
98624
  return this.meshManager.sendCommand(daemonId, command, args);
98221
98625
  },
98626
+ getMeshPeerConnectionStatus: (daemonId) => this.meshManager?.getPeerConnectionStatus(daemonId) ?? null,
98222
98627
  onStatusChange: () => {
98223
98628
  this.invalidateHotChatSnapshotCache();
98224
98629
  this.statusReporter?.onStatusChange();
@@ -98611,6 +99016,21 @@ ${err?.stack || ""}`);
98611
99016
  await this.meshManager.sendCommand(coordinatorDaemonId, "mesh_forward_event", payload);
98612
99017
  LOG.info("MeshEvents", `Relayed ${payload.event} for mesh ${meshId} to coordinator daemon ${coordinatorDaemonId.slice(0, 12)}\u2026`);
98613
99018
  } catch (error48) {
99019
+ queuePendingMeshCoordinatorEvent({
99020
+ event: payload.event,
99021
+ meshId,
99022
+ nodeLabel: payload.nodeId ? `Node '${payload.nodeId}'` : payload.workspace ? `Agent at ${payload.workspace}` : "Remote agent",
99023
+ nodeId: payload.nodeId || void 0,
99024
+ workspace: payload.workspace || void 0,
99025
+ metadataEvent: {
99026
+ targetSessionId: payload.targetSessionId,
99027
+ providerType: payload.providerType,
99028
+ providerSessionId: payload.providerSessionId,
99029
+ finalSummary: payload.finalSummary,
99030
+ workspace: payload.workspace
99031
+ },
99032
+ queuedAt: Date.now()
99033
+ });
98614
99034
  LOG.warn("MeshEvents", `Failed to relay ${payload.event} for mesh ${meshId}: ${error48?.message || error48}`);
98615
99035
  }
98616
99036
  }
@@ -102745,11 +103165,36 @@ function rotateLogs() {
102745
103165
  rotateLogIfNeeded(LOG_OUT);
102746
103166
  rotateLogIfNeeded(LOG_ERR);
102747
103167
  }
102748
- function buildPlist(nodeExe, cliExe) {
103168
+ function normalizeLaunchdPathEntry(entry) {
103169
+ const trimmed = String(entry || "").trim();
103170
+ if (!trimmed) return null;
103171
+ if (trimmed.startsWith("~")) {
103172
+ return import_node_path5.default.join(import_node_os4.default.homedir(), trimmed.slice(1));
103173
+ }
103174
+ return import_node_path5.default.isAbsolute(trimmed) ? trimmed : null;
103175
+ }
103176
+ function buildLaunchdPath(nodeExe, currentPath = process.env.PATH || "") {
102749
103177
  const brewPrefix = import_node_fs4.default.existsSync("/opt/homebrew/bin") ? "/opt/homebrew/bin" : "/usr/local/bin";
102750
- const nodeDir = import_node_path5.default.dirname(nodeExe);
102751
- const pathEntries = /* @__PURE__ */ new Set([nodeDir, brewPrefix, "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"]);
102752
- const pathValue = Array.from(pathEntries).join(":");
103178
+ const entries = [];
103179
+ const seen = /* @__PURE__ */ new Set();
103180
+ const addEntry = (value) => {
103181
+ if (!value) return;
103182
+ const normalized = normalizeLaunchdPathEntry(value);
103183
+ if (!normalized || seen.has(normalized)) return;
103184
+ seen.add(normalized);
103185
+ entries.push(normalized);
103186
+ };
103187
+ addEntry(import_node_path5.default.dirname(nodeExe));
103188
+ for (const entry of String(currentPath || "").split(import_node_path5.default.delimiter)) {
103189
+ addEntry(entry);
103190
+ }
103191
+ for (const entry of [brewPrefix, "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"]) {
103192
+ addEntry(entry);
103193
+ }
103194
+ return entries.join(":");
103195
+ }
103196
+ function buildPlist(nodeExe, cliExe, currentPath = process.env.PATH || "") {
103197
+ const pathValue = buildLaunchdPath(nodeExe, currentPath);
102753
103198
  return `<?xml version="1.0" encoding="UTF-8"?>
102754
103199
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
102755
103200
  <plist version="1.0">