@adhdev/daemon-core 0.9.82-rc.5 → 0.9.82-rc.50

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
@@ -662,17 +662,91 @@ var init_config = __esm({
662
662
  }
663
663
  });
664
664
 
665
+ // src/mesh/mesh-host-ownership.ts
666
+ function readObject(value) {
667
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
668
+ }
669
+ function readString(value) {
670
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
671
+ }
672
+ function normalizeMeshDaemonRole(value) {
673
+ return value === "host" || value === "member" ? value : void 0;
674
+ }
675
+ function resolveMeshHostStatus(mesh) {
676
+ const meshRecord = readObject(mesh);
677
+ const raw = readObject(meshRecord?.meshHost);
678
+ const role = normalizeMeshDaemonRole(raw?.role) ?? "host";
679
+ const pairing = readObject(raw?.pairing);
680
+ const normalized = {
681
+ role,
682
+ canOwnCoordinator: role === "host",
683
+ canOwnQueue: role === "host",
684
+ defaulted: !raw
685
+ };
686
+ const hostDaemonId = readString(raw?.hostDaemonId);
687
+ const hostNodeId = readString(raw?.hostNodeId);
688
+ const hostAddress = readString(raw?.hostAddress);
689
+ if (hostDaemonId) normalized.hostDaemonId = hostDaemonId;
690
+ if (hostNodeId) normalized.hostNodeId = hostNodeId;
691
+ if (hostAddress) normalized.hostAddress = hostAddress;
692
+ if (pairing) {
693
+ const status = pairing.status === "pairing" || pairing.status === "paired" || pairing.status === "rejected" || pairing.status === "revoked" ? pairing.status : "not_configured";
694
+ normalized.pairing = {
695
+ status,
696
+ ...readString(pairing.tokenId) ? { tokenId: readString(pairing.tokenId) } : {},
697
+ ...readString(pairing.joinedAt) ? { joinedAt: readString(pairing.joinedAt) } : {},
698
+ ...readString(pairing.lastPairedAt) ? { lastPairedAt: readString(pairing.lastPairedAt) } : {},
699
+ ...readString(pairing.lastRejectedAt) ? { lastRejectedAt: readString(pairing.lastRejectedAt) } : {},
700
+ ...readString(pairing.expiresAt) ? { expiresAt: readString(pairing.expiresAt) } : {}
701
+ };
702
+ }
703
+ return normalized;
704
+ }
705
+ function isMeshHostOwner(mesh) {
706
+ return resolveMeshHostStatus(mesh).role === "host";
707
+ }
708
+ function buildMeshHostRequiredFailure(mesh, operation) {
709
+ const meshHost = resolveMeshHostStatus(mesh);
710
+ return {
711
+ success: false,
712
+ code: "mesh_host_required",
713
+ error: `Mesh Host daemon required for ${operation}; member daemons must pair with the host and cannot own coordinator/queue mutations.`,
714
+ meshHost
715
+ };
716
+ }
717
+ function requireMeshHostQueueOwner(opts) {
718
+ if (opts?.ownerRole === "member") {
719
+ throw new Error("Mesh Host daemon required to mutate mesh queue; member daemons must use the host-owned queue.");
720
+ }
721
+ }
722
+ function createDefaultMeshHostMetadata() {
723
+ return {
724
+ role: "host",
725
+ pairing: { status: "not_configured" }
726
+ };
727
+ }
728
+ var init_mesh_host_ownership = __esm({
729
+ "src/mesh/mesh-host-ownership.ts"() {
730
+ "use strict";
731
+ }
732
+ });
733
+
665
734
  // src/config/mesh-config.ts
666
735
  var mesh_config_exports = {};
667
736
  __export(mesh_config_exports, {
668
737
  addNode: () => addNode,
738
+ applyMeshHostJoinRequest: () => applyMeshHostJoinRequest,
739
+ configureMeshHostPairing: () => configureMeshHostPairing,
669
740
  createMesh: () => createMesh,
741
+ createMeshHostPairingToken: () => createMeshHostPairingToken,
670
742
  deleteMesh: () => deleteMesh,
671
743
  getMesh: () => getMesh,
672
744
  getMeshByRepo: () => getMeshByRepo,
673
745
  listMeshes: () => listMeshes,
746
+ markMeshHostPairingJoined: () => markMeshHostPairingJoined,
674
747
  normalizeRepoIdentity: () => normalizeRepoIdentity,
675
748
  removeNode: () => removeNode,
749
+ tokenIdForManualPairing: () => tokenIdForManualPairing,
676
750
  updateMesh: () => updateMesh,
677
751
  updateNode: () => updateNode
678
752
  });
@@ -748,6 +822,7 @@ function createMesh(opts) {
748
822
  defaultBranch: opts.defaultBranch,
749
823
  policy: mergeMeshPolicy(void 0, opts.policy),
750
824
  coordinator: opts.coordinator || {},
825
+ meshHost: opts.meshHost || createDefaultMeshHostMetadata(),
751
826
  nodes: [],
752
827
  createdAt: now,
753
828
  updatedAt: now
@@ -764,6 +839,7 @@ function updateMesh(meshId, opts) {
764
839
  if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
765
840
  if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
766
841
  if (opts.coordinator) mesh.coordinator = opts.coordinator;
842
+ if (opts.meshHost) mesh.meshHost = opts.meshHost;
767
843
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
768
844
  saveMeshConfig(config);
769
845
  return mesh;
@@ -776,6 +852,186 @@ function deleteMesh(meshId) {
776
852
  saveMeshConfig(config);
777
853
  return true;
778
854
  }
855
+ function normalizeManualHostAddress(hostAddress) {
856
+ const normalized = hostAddress.trim().replace(/\/+$/, "");
857
+ if (!normalized) throw new Error("hostAddress required");
858
+ let parsed;
859
+ try {
860
+ parsed = new URL(normalized);
861
+ } catch {
862
+ throw new Error("hostAddress must be a valid http(s) or ws(s) URL");
863
+ }
864
+ if (!["http:", "https:", "ws:", "wss:"].includes(parsed.protocol)) {
865
+ throw new Error("hostAddress must use http, https, ws, or wss");
866
+ }
867
+ return normalized;
868
+ }
869
+ function tokenIdForManualPairing(token) {
870
+ return `tok_${(0, import_crypto3.createHash)("sha256").update(token).digest("hex").slice(0, 16)}`;
871
+ }
872
+ function normalizeTokenExpiry(value) {
873
+ if (typeof value !== "string" || !value.trim()) return void 0;
874
+ const date = new Date(value);
875
+ if (Number.isNaN(date.getTime())) throw new Error("expiresAt must be a valid ISO date");
876
+ return date.toISOString();
877
+ }
878
+ function assertPairingTokenValid(pairing, rawToken, nowIso) {
879
+ const token = rawToken.trim();
880
+ if (!token) return { ok: false, reason: "token required" };
881
+ const presentedTokenId = tokenIdForManualPairing(token);
882
+ const expectedTokenId = pairing?.tokenId;
883
+ if (!expectedTokenId || pairing?.status === "not_configured" || pairing?.status === "revoked") {
884
+ return { ok: false, reason: "host pairing token is not configured", presentedTokenId };
885
+ }
886
+ if (pairing.expiresAt && new Date(pairing.expiresAt).getTime() <= new Date(nowIso).getTime()) {
887
+ return { ok: false, reason: "host pairing token expired", expectedTokenId, presentedTokenId };
888
+ }
889
+ if (presentedTokenId !== expectedTokenId) {
890
+ return { ok: false, reason: "invalid pairing token", expectedTokenId, presentedTokenId };
891
+ }
892
+ return { ok: true, tokenId: presentedTokenId };
893
+ }
894
+ function configureMeshHostPairing(meshId, opts) {
895
+ const hostAddress = normalizeManualHostAddress(opts.hostAddress);
896
+ const token = opts.token.trim();
897
+ if (!token) throw new Error("token required");
898
+ const config = loadMeshConfig();
899
+ const mesh = config.meshes.find((m) => m.id === meshId);
900
+ if (!mesh) return void 0;
901
+ const now = opts.now || (/* @__PURE__ */ new Date()).toISOString();
902
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
903
+ const meshHost = {
904
+ ...previous,
905
+ role: "member",
906
+ hostAddress,
907
+ pairing: {
908
+ status: "pairing",
909
+ tokenId: tokenIdForManualPairing(token),
910
+ lastPairedAt: now
911
+ }
912
+ };
913
+ mesh.meshHost = meshHost;
914
+ mesh.updatedAt = now;
915
+ saveMeshConfig(config);
916
+ return { mesh, meshHost, hostAddress };
917
+ }
918
+ function createMeshHostPairingToken(meshId, opts = {}) {
919
+ const config = loadMeshConfig();
920
+ const mesh = config.meshes.find((m) => m.id === meshId);
921
+ if (!mesh) return void 0;
922
+ const now = opts.now || (/* @__PURE__ */ new Date()).toISOString();
923
+ const token = (opts.token || `mhj_${(0, import_crypto3.randomBytes)(24).toString("base64url")}`).trim();
924
+ if (!token) throw new Error("token required");
925
+ const tokenId = tokenIdForManualPairing(token);
926
+ const expiresAt = normalizeTokenExpiry(opts.expiresAt);
927
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
928
+ if (previous.role === "member") {
929
+ throw new Error("Mesh Host daemon required to create host pairing tokens; member daemons cannot mint host join tokens.");
930
+ }
931
+ const meshHost = {
932
+ ...previous,
933
+ role: "host",
934
+ pairing: {
935
+ status: "pairing",
936
+ tokenId,
937
+ lastPairedAt: now,
938
+ ...expiresAt ? { expiresAt } : {}
939
+ }
940
+ };
941
+ mesh.meshHost = meshHost;
942
+ mesh.updatedAt = now;
943
+ saveMeshConfig(config);
944
+ return { mesh, meshHost, token, tokenId, ...expiresAt ? { expiresAt } : {} };
945
+ }
946
+ function applyMeshHostJoinRequest(meshId, opts) {
947
+ const config = loadMeshConfig();
948
+ const mesh = config.meshes.find((m) => m.id === meshId);
949
+ if (!mesh) return void 0;
950
+ const now = opts.now || (/* @__PURE__ */ new Date()).toISOString();
951
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
952
+ if (previous.role === "member") {
953
+ return { accepted: false, mesh, meshHost: previous, reason: "Mesh Host daemon required to accept join requests" };
954
+ }
955
+ const meshHost = { ...previous, role: "host" };
956
+ const validation = assertPairingTokenValid(meshHost.pairing, opts.token, now);
957
+ if (!validation.ok) {
958
+ mesh.meshHost = {
959
+ ...meshHost,
960
+ pairing: {
961
+ ...meshHost.pairing || { status: "not_configured" },
962
+ status: "rejected",
963
+ lastRejectedAt: now
964
+ }
965
+ };
966
+ mesh.updatedAt = now;
967
+ saveMeshConfig(config);
968
+ return { accepted: false, mesh, meshHost: mesh.meshHost, tokenId: validation.presentedTokenId, reason: validation.reason };
969
+ }
970
+ const workspace = opts.memberNode.workspace.trim();
971
+ if (!workspace) throw new Error("memberNode.workspace required");
972
+ const memberId = opts.memberNode.id?.trim();
973
+ let node = mesh.nodes.find((n) => memberId && n.id === memberId || n.workspace === workspace);
974
+ if (node) {
975
+ node.workspace = workspace;
976
+ node.repoRoot = opts.memberNode.repoRoot;
977
+ node.daemonId = opts.memberNode.daemonId;
978
+ node.machineId = opts.memberNode.machineId;
979
+ node.userOverrides = opts.memberNode.userOverrides || node.userOverrides || {};
980
+ node.policy = { ...node.policy || {}, ...opts.memberNode.policy || {} };
981
+ node.role = "member";
982
+ } else {
983
+ if (mesh.nodes.length >= 10) throw new Error("Maximum 10 nodes per mesh");
984
+ node = {
985
+ id: memberId || `node_${(0, import_crypto3.randomUUID)().replace(/-/g, "")}`,
986
+ workspace,
987
+ repoRoot: opts.memberNode.repoRoot,
988
+ daemonId: opts.memberNode.daemonId,
989
+ machineId: opts.memberNode.machineId,
990
+ userOverrides: opts.memberNode.userOverrides || {},
991
+ policy: opts.memberNode.policy || {},
992
+ role: "member"
993
+ };
994
+ mesh.nodes.push(node);
995
+ }
996
+ mesh.meshHost = {
997
+ ...meshHost,
998
+ pairing: {
999
+ ...meshHost.pairing || {},
1000
+ status: "paired",
1001
+ tokenId: validation.tokenId,
1002
+ joinedAt: now,
1003
+ lastPairedAt: meshHost.pairing?.lastPairedAt || now,
1004
+ ...meshHost.pairing?.expiresAt ? { expiresAt: meshHost.pairing.expiresAt } : {}
1005
+ }
1006
+ };
1007
+ mesh.updatedAt = now;
1008
+ saveMeshConfig(config);
1009
+ return { accepted: true, mesh, meshHost: mesh.meshHost, node, tokenId: validation.tokenId };
1010
+ }
1011
+ function markMeshHostPairingJoined(meshId, opts) {
1012
+ const config = loadMeshConfig();
1013
+ const mesh = config.meshes.find((m) => m.id === meshId);
1014
+ if (!mesh) return void 0;
1015
+ const now = opts.joinedAt || (/* @__PURE__ */ new Date()).toISOString();
1016
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
1017
+ const tokenId = opts.tokenId || (opts.token ? tokenIdForManualPairing(opts.token) : previous.pairing?.tokenId);
1018
+ mesh.meshHost = {
1019
+ ...previous,
1020
+ role: "member",
1021
+ ...opts.hostDaemonId ? { hostDaemonId: opts.hostDaemonId } : {},
1022
+ ...opts.hostNodeId ? { hostNodeId: opts.hostNodeId } : {},
1023
+ pairing: {
1024
+ ...previous.pairing || {},
1025
+ status: "paired",
1026
+ ...tokenId ? { tokenId } : {},
1027
+ joinedAt: now,
1028
+ lastPairedAt: previous.pairing?.lastPairedAt || now
1029
+ }
1030
+ };
1031
+ mesh.updatedAt = now;
1032
+ saveMeshConfig(config);
1033
+ return { mesh, meshHost: mesh.meshHost };
1034
+ }
779
1035
  function addNode(meshId, opts) {
780
1036
  const config = loadMeshConfig();
781
1037
  const mesh = config.meshes.find((m) => m.id === meshId);
@@ -796,7 +1052,8 @@ function addNode(meshId, opts) {
796
1052
  policy: opts.policy || {},
797
1053
  isLocalWorktree: opts.isLocalWorktree,
798
1054
  worktreeBranch: opts.worktreeBranch,
799
- clonedFromNodeId: opts.clonedFromNodeId
1055
+ clonedFromNodeId: opts.clonedFromNodeId,
1056
+ role: opts.role
800
1057
  };
801
1058
  mesh.nodes.push(node);
802
1059
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -835,6 +1092,7 @@ var init_mesh_config = __esm({
835
1092
  import_crypto3 = require("crypto");
836
1093
  init_config();
837
1094
  init_repo_mesh_types();
1095
+ init_mesh_host_ownership();
838
1096
  SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
839
1097
  SPAWNED_SESSION_VISIBILITY_MODES = /* @__PURE__ */ new Set(["visible", "hidden"]);
840
1098
  }
@@ -1018,19 +1276,19 @@ function isIntentionalCleanupStopEntry(entry) {
1018
1276
  return payload.intentional === true && (payload.reason === "operator_cleanup" || payload.intentionalStopReason === "operator_cleanup" || payload.source === "mesh_cleanup_sessions" || payload.source === "mesh_remove_node");
1019
1277
  }
1020
1278
  function getLedgerDir() {
1021
- const dir = (0, import_path3.join)(getConfigDir(), LEDGER_DIR_NAME);
1022
- if (!(0, import_fs3.existsSync)(dir)) {
1023
- (0, import_fs3.mkdirSync)(dir, { recursive: true, mode: 448 });
1279
+ const dir = (0, import_path4.join)(getConfigDir(), LEDGER_DIR_NAME);
1280
+ if (!(0, import_fs4.existsSync)(dir)) {
1281
+ (0, import_fs4.mkdirSync)(dir, { recursive: true, mode: 448 });
1024
1282
  }
1025
1283
  return dir;
1026
1284
  }
1027
1285
  function getLedgerPath(meshId) {
1028
1286
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1029
- return (0, import_path3.join)(getLedgerDir(), `${safe}.jsonl`);
1287
+ return (0, import_path4.join)(getLedgerDir(), `${safe}.jsonl`);
1030
1288
  }
1031
1289
  function getRotatedPath(meshId, index) {
1032
1290
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1033
- return (0, import_path3.join)(getLedgerDir(), `${safe}.${index}.jsonl`);
1291
+ return (0, import_path4.join)(getLedgerDir(), `${safe}.${index}.jsonl`);
1034
1292
  }
1035
1293
  function buildTaskCompletionEvidence(opts) {
1036
1294
  const providerSessionId = opts.providerSessionId?.trim() || void 0;
@@ -1071,9 +1329,9 @@ function appendLedgerEntry(meshId, partial) {
1071
1329
  ...partial
1072
1330
  };
1073
1331
  const filePath = getLedgerPath(meshId);
1074
- if ((0, import_fs3.existsSync)(filePath)) {
1332
+ if ((0, import_fs4.existsSync)(filePath)) {
1075
1333
  try {
1076
- const stat2 = (0, import_fs3.statSync)(filePath);
1334
+ const stat2 = (0, import_fs4.statSync)(filePath);
1077
1335
  if (stat2.size >= MAX_FILE_SIZE_BYTES) {
1078
1336
  rotateLedgerFile(meshId, filePath);
1079
1337
  }
@@ -1082,7 +1340,7 @@ function appendLedgerEntry(meshId, partial) {
1082
1340
  }
1083
1341
  try {
1084
1342
  const line = JSON.stringify(entry) + "\n";
1085
- (0, import_fs3.appendFileSync)(filePath, line, { encoding: "utf-8", mode: 384 });
1343
+ (0, import_fs4.appendFileSync)(filePath, line, { encoding: "utf-8", mode: 384 });
1086
1344
  meshLedgerEvents.emit("append", meshId, entry);
1087
1345
  return entry;
1088
1346
  } catch (e) {
@@ -1127,7 +1385,7 @@ function appendRemoteLedgerEntries(meshId, entries) {
1127
1385
  }
1128
1386
  try {
1129
1387
  const lines = validEntries.map((e) => JSON.stringify(e)).join("\n") + "\n";
1130
- (0, import_fs3.appendFileSync)(ledgerPath, lines, { encoding: "utf-8", mode: 384 });
1388
+ (0, import_fs4.appendFileSync)(ledgerPath, lines, { encoding: "utf-8", mode: 384 });
1131
1389
  for (const entry of validEntries) {
1132
1390
  meshLedgerEvents.emit("append", meshId, entry);
1133
1391
  }
@@ -1138,10 +1396,10 @@ function appendRemoteLedgerEntries(meshId, entries) {
1138
1396
  }
1139
1397
  function readLedgerEntries(meshId, opts) {
1140
1398
  const filePath = getLedgerPath(meshId);
1141
- if (!(0, import_fs3.existsSync)(filePath)) return [];
1399
+ if (!(0, import_fs4.existsSync)(filePath)) return [];
1142
1400
  let content;
1143
1401
  try {
1144
- content = (0, import_fs3.readFileSync)(filePath, "utf-8");
1402
+ content = (0, import_fs4.readFileSync)(filePath, "utf-8");
1145
1403
  } catch {
1146
1404
  return [];
1147
1405
  }
@@ -1313,22 +1571,22 @@ function getSessionRecoveryContext(meshId, opts) {
1313
1571
  }
1314
1572
  function rotateLedgerFile(meshId, currentPath) {
1315
1573
  let index = 1;
1316
- while ((0, import_fs3.existsSync)(getRotatedPath(meshId, index))) {
1574
+ while ((0, import_fs4.existsSync)(getRotatedPath(meshId, index))) {
1317
1575
  index++;
1318
1576
  if (index > 10) break;
1319
1577
  }
1320
1578
  if (index > 10) index = 10;
1321
1579
  try {
1322
- (0, import_fs3.renameSync)(currentPath, getRotatedPath(meshId, index));
1580
+ (0, import_fs4.renameSync)(currentPath, getRotatedPath(meshId, index));
1323
1581
  } catch {
1324
1582
  }
1325
1583
  }
1326
- var import_fs3, import_path3, import_crypto4, import_events, LEDGER_DIR_NAME, MAX_FILE_SIZE_BYTES, RECENT_FAILURE_WINDOW_MS, DEFAULT_LEDGER_SLICE_LIMIT, MAX_LEDGER_SLICE_LIMIT, meshLedgerEvents;
1584
+ var import_fs4, import_path4, import_crypto4, import_events, LEDGER_DIR_NAME, MAX_FILE_SIZE_BYTES, RECENT_FAILURE_WINDOW_MS, DEFAULT_LEDGER_SLICE_LIMIT, MAX_LEDGER_SLICE_LIMIT, meshLedgerEvents;
1327
1585
  var init_mesh_ledger = __esm({
1328
1586
  "src/mesh/mesh-ledger.ts"() {
1329
1587
  "use strict";
1330
- import_fs3 = require("fs");
1331
- import_path3 = require("path");
1588
+ import_fs4 = require("fs");
1589
+ import_path4 = require("path");
1332
1590
  import_crypto4 = require("crypto");
1333
1591
  init_config();
1334
1592
  import_events = require("events");
@@ -1358,13 +1616,43 @@ __export(mesh_work_queue_exports, {
1358
1616
  });
1359
1617
  function getQueuePath(meshId) {
1360
1618
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1361
- return (0, import_path4.join)(getLedgerDir(), `${safe}.queue.json`);
1619
+ return (0, import_path5.join)(getLedgerDir(), `${safe}.queue.json`);
1620
+ }
1621
+ function getLockPath(meshId) {
1622
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1623
+ return (0, import_path5.join)(getLedgerDir(), `${safe}.queue.lock`);
1624
+ }
1625
+ function withQueueLock(meshId, fn) {
1626
+ const lockPath = getLockPath(meshId);
1627
+ let fd = -1;
1628
+ for (let i = 0; i < 10; i++) {
1629
+ try {
1630
+ fd = (0, import_fs5.openSync)(lockPath, "wx");
1631
+ break;
1632
+ } catch {
1633
+ const deadline = Date.now() + 30;
1634
+ while (Date.now() < deadline) {
1635
+ }
1636
+ }
1637
+ }
1638
+ try {
1639
+ return fn();
1640
+ } finally {
1641
+ if (fd !== -1) try {
1642
+ (0, import_fs5.closeSync)(fd);
1643
+ } catch {
1644
+ }
1645
+ try {
1646
+ (0, import_fs5.unlinkSync)(lockPath);
1647
+ } catch {
1648
+ }
1649
+ }
1362
1650
  }
1363
1651
  function readQueue(meshId) {
1364
1652
  const path28 = getQueuePath(meshId);
1365
- if (!(0, import_fs4.existsSync)(path28)) return [];
1653
+ if (!(0, import_fs5.existsSync)(path28)) return [];
1366
1654
  try {
1367
- const content = (0, import_fs4.readFileSync)(path28, "utf-8");
1655
+ const content = (0, import_fs5.readFileSync)(path28, "utf-8");
1368
1656
  return JSON.parse(content);
1369
1657
  } catch {
1370
1658
  return [];
@@ -1372,23 +1660,26 @@ function readQueue(meshId) {
1372
1660
  }
1373
1661
  function writeQueue(meshId, queue) {
1374
1662
  const path28 = getQueuePath(meshId);
1375
- (0, import_fs4.writeFileSync)(path28, JSON.stringify(queue, null, 2), "utf-8");
1663
+ (0, import_fs5.writeFileSync)(path28, JSON.stringify(queue, null, 2), "utf-8");
1376
1664
  }
1377
1665
  function enqueueTask(meshId, message, opts) {
1378
- const queue = readQueue(meshId);
1379
- const entry = {
1380
- id: (0, import_crypto5.randomUUID)(),
1381
- meshId,
1382
- message,
1383
- status: "pending",
1384
- targetNodeId: opts?.targetNodeId,
1385
- targetSessionId: opts?.targetSessionId,
1386
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1387
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1388
- };
1389
- queue.push(entry);
1390
- writeQueue(meshId, queue);
1391
- return entry;
1666
+ requireMeshHostQueueOwner(opts);
1667
+ return withQueueLock(meshId, () => {
1668
+ const queue = readQueue(meshId);
1669
+ const entry = {
1670
+ id: (0, import_crypto5.randomUUID)(),
1671
+ meshId,
1672
+ message,
1673
+ status: "pending",
1674
+ targetNodeId: opts?.targetNodeId,
1675
+ targetSessionId: opts?.targetSessionId,
1676
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1677
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1678
+ };
1679
+ queue.push(entry);
1680
+ writeQueue(meshId, queue);
1681
+ return entry;
1682
+ });
1392
1683
  }
1393
1684
  function getQueue(meshId, opts) {
1394
1685
  let queue = readQueue(meshId);
@@ -1399,100 +1690,114 @@ function getQueue(meshId, opts) {
1399
1690
  return queue;
1400
1691
  }
1401
1692
  function claimNextTask(meshId, nodeId, sessionId) {
1402
- const queue = readQueue(meshId);
1403
- const hasActiveAssignment = queue.some((q) => q.status === "assigned" && (q.assignedSessionId === sessionId || q.assignedNodeId === nodeId));
1404
- if (hasActiveAssignment) return null;
1405
- let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetSessionId === sessionId);
1406
- if (targetIdx === -1) {
1407
- targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId && !q.targetSessionId);
1408
- }
1409
- if (targetIdx === -1) {
1410
- targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId && !q.targetSessionId);
1411
- }
1412
- if (targetIdx === -1) return null;
1413
- const entry = queue[targetIdx];
1414
- entry.status = "assigned";
1415
- entry.assignedNodeId = nodeId;
1416
- entry.assignedSessionId = sessionId;
1417
- entry.dispatchTimestamp = (/* @__PURE__ */ new Date()).toISOString();
1418
- entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1419
- writeQueue(meshId, queue);
1420
- return entry;
1421
- }
1422
- function updateTaskStatus(meshId, taskId, status) {
1423
- const queue = readQueue(meshId);
1424
- const idx = queue.findIndex((q) => q.id === taskId);
1425
- if (idx === -1) return null;
1426
- queue[idx].status = status;
1427
- queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1428
- writeQueue(meshId, queue);
1429
- return queue[idx];
1693
+ return withQueueLock(meshId, () => {
1694
+ const queue = readQueue(meshId);
1695
+ const hasActiveAssignment = queue.some((q) => q.status === "assigned" && (q.assignedSessionId === sessionId || q.assignedNodeId === nodeId));
1696
+ if (hasActiveAssignment) return null;
1697
+ let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetSessionId === sessionId);
1698
+ if (targetIdx === -1) {
1699
+ targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId && !q.targetSessionId);
1700
+ }
1701
+ if (targetIdx === -1) {
1702
+ targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId && !q.targetSessionId);
1703
+ }
1704
+ if (targetIdx === -1) return null;
1705
+ const entry = queue[targetIdx];
1706
+ entry.status = "assigned";
1707
+ entry.assignedNodeId = nodeId;
1708
+ entry.assignedSessionId = sessionId;
1709
+ entry.dispatchTimestamp = (/* @__PURE__ */ new Date()).toISOString();
1710
+ entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1711
+ writeQueue(meshId, queue);
1712
+ return entry;
1713
+ });
1714
+ }
1715
+ function updateTaskStatus(meshId, taskId, status, opts) {
1716
+ requireMeshHostQueueOwner(opts);
1717
+ return withQueueLock(meshId, () => {
1718
+ const queue = readQueue(meshId);
1719
+ const idx = queue.findIndex((q) => q.id === taskId);
1720
+ if (idx === -1) return null;
1721
+ queue[idx].status = status;
1722
+ queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1723
+ writeQueue(meshId, queue);
1724
+ return queue[idx];
1725
+ });
1430
1726
  }
1431
1727
  function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
1432
- const queue = readQueue(meshId);
1433
- const idx = queue.findIndex((q) => q.id === taskId);
1434
- if (idx === -1) return null;
1435
- const now = (/* @__PURE__ */ new Date()).toISOString();
1436
- queue[idx].autoLaunch = {
1437
- ...autoLaunch,
1438
- updatedAt: now
1439
- };
1440
- queue[idx].updatedAt = now;
1441
- writeQueue(meshId, queue);
1442
- return queue[idx];
1728
+ return withQueueLock(meshId, () => {
1729
+ const queue = readQueue(meshId);
1730
+ const idx = queue.findIndex((q) => q.id === taskId);
1731
+ if (idx === -1) return null;
1732
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1733
+ queue[idx].autoLaunch = { ...autoLaunch, updatedAt: now };
1734
+ queue[idx].updatedAt = now;
1735
+ writeQueue(meshId, queue);
1736
+ return queue[idx];
1737
+ });
1443
1738
  }
1444
1739
  function cancelTask(meshId, taskId, opts) {
1445
- const queue = readQueue(meshId);
1446
- const idx = queue.findIndex((q) => q.id === taskId);
1447
- if (idx === -1) return null;
1448
- const now = (/* @__PURE__ */ new Date()).toISOString();
1449
- queue[idx].status = "cancelled";
1450
- queue[idx].updatedAt = now;
1451
- queue[idx].cancelledAt = now;
1452
- if (opts?.reason) queue[idx].cancelReason = opts.reason;
1453
- writeQueue(meshId, queue);
1454
- return queue[idx];
1740
+ requireMeshHostQueueOwner(opts);
1741
+ return withQueueLock(meshId, () => {
1742
+ const queue = readQueue(meshId);
1743
+ const idx = queue.findIndex((q) => q.id === taskId);
1744
+ if (idx === -1) return null;
1745
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1746
+ queue[idx].status = "cancelled";
1747
+ queue[idx].updatedAt = now;
1748
+ queue[idx].cancelledAt = now;
1749
+ if (opts?.reason) queue[idx].cancelReason = opts.reason;
1750
+ writeQueue(meshId, queue);
1751
+ return queue[idx];
1752
+ });
1455
1753
  }
1456
1754
  function requeueTask(meshId, taskId, opts) {
1457
- const queue = readQueue(meshId);
1458
- const idx = queue.findIndex((q) => q.id === taskId);
1459
- if (idx === -1) return null;
1460
- const entry = queue[idx];
1461
- const now = (/* @__PURE__ */ new Date()).toISOString();
1462
- entry.status = "pending";
1463
- delete entry.assignedNodeId;
1464
- delete entry.assignedSessionId;
1465
- delete entry.cancelledAt;
1466
- delete entry.cancelReason;
1467
- if (opts?.clearTargetNode) delete entry.targetNodeId;
1468
- if (typeof opts?.targetNodeId === "string") entry.targetNodeId = opts.targetNodeId;
1469
- if (opts?.clearTargetSession !== false) delete entry.targetSessionId;
1470
- if (typeof opts?.targetSessionId === "string") entry.targetSessionId = opts.targetSessionId;
1471
- entry.updatedAt = now;
1472
- entry.requeuedAt = now;
1473
- entry.requeueCount = (entry.requeueCount || 0) + 1;
1474
- if (opts?.reason) entry.requeueReason = opts.reason;
1475
- writeQueue(meshId, queue);
1476
- return entry;
1477
- }
1478
- function updateSessionTaskStatus(meshId, sessionId, status) {
1479
- const queue = readQueue(meshId);
1480
- let bestIdx = -1;
1481
- let bestTime = 0;
1482
- for (let i = queue.length - 1; i >= 0; i--) {
1483
- if (queue[i].assignedSessionId === sessionId && queue[i].status === "assigned") {
1755
+ requireMeshHostQueueOwner(opts);
1756
+ return withQueueLock(meshId, () => {
1757
+ const queue = readQueue(meshId);
1758
+ const idx = queue.findIndex((q) => q.id === taskId);
1759
+ if (idx === -1) return null;
1760
+ const entry = queue[idx];
1761
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1762
+ entry.status = "pending";
1763
+ delete entry.assignedNodeId;
1764
+ delete entry.assignedSessionId;
1765
+ delete entry.cancelledAt;
1766
+ delete entry.cancelReason;
1767
+ if (opts?.clearTargetNode) delete entry.targetNodeId;
1768
+ if (typeof opts?.targetNodeId === "string") entry.targetNodeId = opts.targetNodeId;
1769
+ if (opts?.clearTargetSession !== false) delete entry.targetSessionId;
1770
+ if (typeof opts?.targetSessionId === "string") entry.targetSessionId = opts.targetSessionId;
1771
+ entry.updatedAt = now;
1772
+ entry.requeuedAt = now;
1773
+ entry.requeueCount = (entry.requeueCount || 0) + 1;
1774
+ if (opts?.reason) entry.requeueReason = opts.reason;
1775
+ writeQueue(meshId, queue);
1776
+ return entry;
1777
+ });
1778
+ }
1779
+ function updateSessionTaskStatus(meshId, sessionId, status, opts) {
1780
+ return withQueueLock(meshId, () => {
1781
+ const queue = readQueue(meshId);
1782
+ const occurredAtTime = opts?.occurredAt ? new Date(opts.occurredAt).getTime() : Number.NaN;
1783
+ const hasOccurredAt = Number.isFinite(occurredAtTime);
1784
+ let bestIdx = -1;
1785
+ let bestTime = 0;
1786
+ for (let i = queue.length - 1; i >= 0; i--) {
1787
+ if (queue[i].assignedSessionId !== sessionId || queue[i].status !== "assigned") continue;
1484
1788
  const time = new Date(queue[i].dispatchTimestamp || queue[i].updatedAt).getTime();
1789
+ if (hasOccurredAt && Number.isFinite(time) && time > occurredAtTime) continue;
1485
1790
  if (time > bestTime) {
1486
1791
  bestTime = time;
1487
1792
  bestIdx = i;
1488
1793
  }
1489
1794
  }
1490
- }
1491
- if (bestIdx === -1) return null;
1492
- queue[bestIdx].status = status;
1493
- queue[bestIdx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1494
- writeQueue(meshId, queue);
1495
- return queue[bestIdx];
1795
+ if (bestIdx === -1) return null;
1796
+ queue[bestIdx].status = status;
1797
+ queue[bestIdx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1798
+ writeQueue(meshId, queue);
1799
+ return queue[bestIdx];
1800
+ });
1496
1801
  }
1497
1802
  function getMeshQueueStats(meshId) {
1498
1803
  const queue = readQueue(meshId);
@@ -1527,14 +1832,15 @@ function getMeshQueueStats(meshId) {
1527
1832
  }))
1528
1833
  };
1529
1834
  }
1530
- var import_fs4, import_path4, import_crypto5, ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES;
1835
+ var import_fs5, import_path5, import_crypto5, ACTIVE_MESH_QUEUE_STATUSES, HISTORICAL_MESH_QUEUE_STATUSES;
1531
1836
  var init_mesh_work_queue = __esm({
1532
1837
  "src/mesh/mesh-work-queue.ts"() {
1533
1838
  "use strict";
1534
- import_fs4 = require("fs");
1535
- import_path4 = require("path");
1839
+ import_fs5 = require("fs");
1840
+ import_path5 = require("path");
1536
1841
  import_crypto5 = require("crypto");
1537
1842
  init_mesh_ledger();
1843
+ init_mesh_host_ownership();
1538
1844
  ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
1539
1845
  HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
1540
1846
  }
@@ -1564,7 +1870,7 @@ function resolveCommandPath(command) {
1564
1870
  if (isExplicitCommandPath(trimmed)) {
1565
1871
  const expanded = expandHome(trimmed);
1566
1872
  const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
1567
- return (0, import_fs5.existsSync)(candidate) ? candidate : null;
1873
+ return (0, import_fs6.existsSync)(candidate) ? candidate : null;
1568
1874
  }
1569
1875
  return null;
1570
1876
  }
@@ -1664,14 +1970,14 @@ async function detectCLI(cliId, providerLoader, options) {
1664
1970
  const all = await detectCLIs(providerLoader, options);
1665
1971
  return all.find((c) => c.id === resolvedId && c.installed) || null;
1666
1972
  }
1667
- var import_child_process, os2, path8, import_fs5;
1973
+ var import_child_process, os2, path8, import_fs6;
1668
1974
  var init_cli_detector = __esm({
1669
1975
  "src/detection/cli-detector.ts"() {
1670
1976
  "use strict";
1671
1977
  import_child_process = require("child_process");
1672
1978
  os2 = __toESM(require("os"));
1673
1979
  path8 = __toESM(require("path"));
1674
- import_fs5 = require("fs");
1980
+ import_fs6 = require("fs");
1675
1981
  }
1676
1982
  });
1677
1983
 
@@ -1896,18 +2202,75 @@ __export(mesh_events_exports, {
1896
2202
  drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
1897
2203
  getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
1898
2204
  handleMeshForwardEvent: () => handleMeshForwardEvent,
2205
+ queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
1899
2206
  setupMeshEventForwarding: () => setupMeshEventForwarding,
1900
2207
  triggerMeshQueue: () => triggerMeshQueue,
1901
2208
  tryAssignQueueTask: () => tryAssignQueueTask
1902
2209
  });
1903
- function drainPendingMeshCoordinatorEvents() {
1904
- return pendingMeshCoordinatorEvents.splice(0);
2210
+ function sweepExpiredRemoteIdleSessions() {
2211
+ const now = Date.now();
2212
+ for (const [key, session] of remoteIdleSessions) {
2213
+ if (session.expiresAt <= now) remoteIdleSessions.delete(key);
2214
+ }
1905
2215
  }
1906
- function getPendingMeshCoordinatorEvents() {
1907
- return pendingMeshCoordinatorEvents.slice();
2216
+ function getPendingEventsPath(meshId) {
2217
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
2218
+ return (0, import_path6.join)(getLedgerDir(), `${safe}.pending-events.jsonl`);
1908
2219
  }
1909
- function clearPendingMeshCoordinatorEvents() {
1910
- pendingMeshCoordinatorEvents.splice(0);
2220
+ function queuePendingMeshCoordinatorEvent(event) {
2221
+ try {
2222
+ (0, import_fs7.appendFileSync)(getPendingEventsPath(event.meshId), JSON.stringify(event) + "\n", "utf-8");
2223
+ return true;
2224
+ } catch (e) {
2225
+ LOG.warn("MeshEvents", `Failed to persist pending coordinator event: ${e?.message || e}`);
2226
+ return false;
2227
+ }
2228
+ }
2229
+ function drainPendingMeshCoordinatorEvents(meshId) {
2230
+ if (!meshId) return [];
2231
+ const path28 = getPendingEventsPath(meshId);
2232
+ if (!(0, import_fs7.existsSync)(path28)) return [];
2233
+ try {
2234
+ const raw = (0, import_fs7.readFileSync)(path28, "utf-8");
2235
+ try {
2236
+ (0, import_fs7.unlinkSync)(path28);
2237
+ } catch {
2238
+ }
2239
+ return raw.split("\n").filter(Boolean).flatMap((line) => {
2240
+ try {
2241
+ return [JSON.parse(line)];
2242
+ } catch {
2243
+ return [];
2244
+ }
2245
+ });
2246
+ } catch {
2247
+ return [];
2248
+ }
2249
+ }
2250
+ function getPendingMeshCoordinatorEvents(meshId) {
2251
+ if (!meshId) return [];
2252
+ const path28 = getPendingEventsPath(meshId);
2253
+ if (!(0, import_fs7.existsSync)(path28)) return [];
2254
+ try {
2255
+ const raw = (0, import_fs7.readFileSync)(path28, "utf-8");
2256
+ return raw.split("\n").filter(Boolean).flatMap((line) => {
2257
+ try {
2258
+ return [JSON.parse(line)];
2259
+ } catch {
2260
+ return [];
2261
+ }
2262
+ });
2263
+ } catch {
2264
+ return [];
2265
+ }
2266
+ }
2267
+ function clearPendingMeshCoordinatorEvents(meshId) {
2268
+ if (!meshId) return;
2269
+ const path28 = getPendingEventsPath(meshId);
2270
+ if ((0, import_fs7.existsSync)(path28)) try {
2271
+ (0, import_fs7.unlinkSync)(path28);
2272
+ } catch {
2273
+ }
1911
2274
  }
1912
2275
  function readNonEmptyString(value) {
1913
2276
  return typeof value === "string" && value.trim() ? value.trim() : "";
@@ -1953,6 +2316,38 @@ function shouldSuppressIntentionalCleanupStop(args) {
1953
2316
  if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
1954
2317
  return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
1955
2318
  }
2319
+ function readEventTimestamp(value) {
2320
+ if (typeof value === "number" && Number.isFinite(value)) return value;
2321
+ if (typeof value === "string" && value.trim()) {
2322
+ const numeric = Number(value);
2323
+ if (Number.isFinite(numeric)) return numeric;
2324
+ const parsed = Date.parse(value);
2325
+ if (Number.isFinite(parsed)) return parsed;
2326
+ }
2327
+ return null;
2328
+ }
2329
+ function buildMeshCompletionFingerprint(args) {
2330
+ const timestampPart = Number.isFinite(args.timestamp) ? String(args.timestamp) : readNonEmptyString(args.finalSummary).slice(0, 200);
2331
+ return [
2332
+ args.meshId,
2333
+ args.event,
2334
+ args.sessionId,
2335
+ args.providerType || "",
2336
+ args.providerSessionId || "",
2337
+ timestampPart
2338
+ ].join("::");
2339
+ }
2340
+ function isDuplicateMeshCompletionEvent(args) {
2341
+ const fingerprint = buildMeshCompletionFingerprint(args);
2342
+ if (!fingerprint) return false;
2343
+ const now = Date.now();
2344
+ for (const [key, seenAt] of recentCompletionFingerprints.entries()) {
2345
+ if (now - seenAt > RECENT_COMPLETION_FINGERPRINT_TTL_MS) recentCompletionFingerprints.delete(key);
2346
+ }
2347
+ if (recentCompletionFingerprints.has(fingerprint)) return true;
2348
+ recentCompletionFingerprints.set(fingerprint, now);
2349
+ return false;
2350
+ }
1956
2351
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
1957
2352
  const task = claimNextTask(meshId, nodeId, sessionId);
1958
2353
  if (!task) {
@@ -1971,7 +2366,16 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
1971
2366
  message: task.message
1972
2367
  }).catch((e) => {
1973
2368
  LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
1974
- updateTaskStatus(meshId, task.id, "failed");
2369
+ updateTaskStatus(meshId, task.id, "pending");
2370
+ try {
2371
+ appendLedgerEntry(meshId, {
2372
+ kind: "dispatch_failed",
2373
+ nodeId,
2374
+ sessionId,
2375
+ payload: { taskId: task.id, error: e?.message, retryable: true }
2376
+ });
2377
+ } catch {
2378
+ }
1975
2379
  });
1976
2380
  return true;
1977
2381
  }
@@ -2305,18 +2709,36 @@ function injectMeshSystemMessage(components, args) {
2305
2709
  LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
2306
2710
  return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
2307
2711
  }
2712
+ const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
2713
+ if (args.event === "agent:generating_completed" && eventSessionId) {
2714
+ const duplicateCompletion = isDuplicateMeshCompletionEvent({
2715
+ meshId: args.meshId,
2716
+ event: args.event,
2717
+ sessionId: eventSessionId,
2718
+ providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
2719
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2720
+ timestamp: eventTimestamp,
2721
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2722
+ });
2723
+ if (duplicateCompletion) {
2724
+ LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
2725
+ return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
2726
+ }
2727
+ }
2308
2728
  let completedTaskForLedger = null;
2309
2729
  if (args.event === "agent:generating_completed") {
2310
2730
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
2311
2731
  const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
2312
2732
  const providerType = readNonEmptyString(args.metadataEvent.providerType);
2313
2733
  if (sessionId) {
2314
- const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed");
2734
+ const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed", {
2735
+ occurredAt: eventTimestamp !== null ? new Date(eventTimestamp).toISOString() : void 0
2736
+ });
2315
2737
  completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
2316
2738
  if (nodeId && providerType) {
2317
- setTimeout(() => {
2739
+ setImmediate(() => {
2318
2740
  tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
2319
- }, 500);
2741
+ });
2320
2742
  }
2321
2743
  }
2322
2744
  } else if (args.event === "agent:ready") {
@@ -2354,13 +2776,17 @@ function injectMeshSystemMessage(components, args) {
2354
2776
  }
2355
2777
  }
2356
2778
  if (sessionId && nodeId && providerType) {
2357
- remoteIdleSessions.set(`${nodeId}:${sessionId}`, { nodeId, sessionId, providerType });
2358
- setTimeout(() => {
2779
+ sweepExpiredRemoteIdleSessions();
2780
+ remoteIdleSessions.set(`${nodeId}:${sessionId}`, {
2781
+ nodeId,
2782
+ sessionId,
2783
+ providerType,
2784
+ expiresAt: Date.now() + REMOTE_IDLE_SESSION_TTL_MS
2785
+ });
2786
+ setImmediate(() => {
2359
2787
  const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
2360
- if (assigned) {
2361
- remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
2362
- }
2363
- }, 500);
2788
+ if (assigned) remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
2789
+ });
2364
2790
  }
2365
2791
  } else if (args.event === "agent:generating_started") {
2366
2792
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
@@ -2471,17 +2897,18 @@ function injectMeshSystemMessage(components, args) {
2471
2897
  return true;
2472
2898
  });
2473
2899
  if (coordinatorInstances.length === 0) {
2474
- if (pendingMeshCoordinatorEvents.length < MAX_PENDING_EVENTS) {
2475
- pendingMeshCoordinatorEvents.push({
2476
- event: args.event,
2477
- meshId: args.meshId,
2478
- nodeLabel: args.nodeLabel,
2479
- metadataEvent: {
2480
- ...args.metadataEvent,
2481
- ...recoveryContext ? { recoveryContext } : {}
2482
- },
2483
- queuedAt: Date.now()
2484
- });
2900
+ if (queuePendingMeshCoordinatorEvent({
2901
+ event: args.event,
2902
+ meshId: args.meshId,
2903
+ nodeLabel: args.nodeLabel,
2904
+ nodeId: args.nodeId || void 0,
2905
+ workspace: readNonEmptyString(args.metadataEvent.workspace),
2906
+ metadataEvent: {
2907
+ ...args.metadataEvent,
2908
+ ...recoveryContext ? { recoveryContext } : {}
2909
+ },
2910
+ queuedAt: Date.now()
2911
+ })) {
2485
2912
  LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
2486
2913
  }
2487
2914
  return { success: true, forwarded: 0 };
@@ -2520,6 +2947,7 @@ function handleMeshForwardEvent(components, payload) {
2520
2947
  providerType: readNonEmptyString(payload.providerType),
2521
2948
  providerSessionId: readNonEmptyString(payload.providerSessionId),
2522
2949
  finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
2950
+ ...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
2523
2951
  intentional: payload.intentional === true,
2524
2952
  intentionalStop: payload.intentionalStop === true,
2525
2953
  operatorCleanup: payload.operatorCleanup === true,
@@ -2562,19 +2990,20 @@ function setupMeshEventForwarding(components) {
2562
2990
  });
2563
2991
  });
2564
2992
  }
2565
- var remoteIdleSessions, MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2993
+ var import_fs7, import_path6, REMOTE_IDLE_SESSION_TTL_MS, remoteIdleSessions, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, recentCompletionFingerprints, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2566
2994
  var init_mesh_events = __esm({
2567
2995
  "src/mesh/mesh-events.ts"() {
2568
2996
  "use strict";
2997
+ import_fs7 = require("fs");
2998
+ import_path6 = require("path");
2569
2999
  init_config();
2570
3000
  init_mesh_config();
2571
3001
  init_cli_detector();
2572
3002
  init_logger();
2573
3003
  init_mesh_ledger();
2574
3004
  init_mesh_work_queue();
3005
+ REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
2575
3006
  remoteIdleSessions = /* @__PURE__ */ new Map();
2576
- MAX_PENDING_EVENTS = 50;
2577
- pendingMeshCoordinatorEvents = [];
2578
3007
  MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
2579
3008
  "agent:generating_started",
2580
3009
  "agent:generating_completed",
@@ -2590,6 +3019,8 @@ var init_mesh_events = __esm({
2590
3019
  "monitor:long_generating": "task_stalled"
2591
3020
  };
2592
3021
  INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
3022
+ RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
3023
+ recentCompletionFingerprints = /* @__PURE__ */ new Map();
2593
3024
  autoLaunchInProgress = /* @__PURE__ */ new Set();
2594
3025
  autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
2595
3026
  AUTO_LAUNCH_COOLDOWN_MS = 5e3;
@@ -5713,6 +6144,8 @@ __export(index_exports, {
5713
6144
  InMemoryGitSnapshotStore: () => InMemoryGitSnapshotStore,
5714
6145
  LOG: () => LOG,
5715
6146
  MAX_LEDGER_SLICE_LIMIT: () => MAX_LEDGER_SLICE_LIMIT,
6147
+ MESH_REFINE_CONFIG_LOCATIONS: () => MESH_REFINE_CONFIG_LOCATIONS,
6148
+ MESH_REFINE_CONFIG_SCHEMA: () => MESH_REFINE_CONFIG_SCHEMA,
5716
6149
  MIN_GIT_WORKSPACE_POLL_INTERVAL_MS: () => MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
5717
6150
  MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
5718
6151
  MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
@@ -5735,6 +6168,7 @@ __export(index_exports, {
5735
6168
  buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
5736
6169
  buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt,
5737
6170
  buildMachineInfo: () => buildMachineInfo,
6171
+ buildMeshHostRequiredFailure: () => buildMeshHostRequiredFailure,
5738
6172
  buildMeshLedgerReconciliationEvidence: () => buildMeshLedgerReconciliationEvidence,
5739
6173
  buildMeshLedgerReplicaEvidence: () => buildMeshLedgerReplicaEvidence,
5740
6174
  buildP2pRelayFailurePayload: () => buildP2pRelayFailurePayload,
@@ -5760,6 +6194,7 @@ __export(index_exports, {
5760
6194
  connectCdpManager: () => connectCdpManager,
5761
6195
  createDebugTraceStore: () => createDebugTraceStore,
5762
6196
  createDefaultGitCommandServices: () => createDefaultGitCommandServices,
6197
+ createDefaultMeshHostMetadata: () => createDefaultMeshHostMetadata,
5763
6198
  createGitCompactSummary: () => createGitCompactSummary,
5764
6199
  createGitSnapshotStore: () => createGitSnapshotStore,
5765
6200
  createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
@@ -5823,6 +6258,7 @@ __export(index_exports, {
5823
6258
  isInternalChatMessage: () => isInternalChatMessage,
5824
6259
  isManagedStatusWaiting: () => isManagedStatusWaiting,
5825
6260
  isManagedStatusWorking: () => isManagedStatusWorking,
6261
+ isMeshHostOwner: () => isMeshHostOwner,
5826
6262
  isP2pRelayTransportFailure: () => isP2pRelayTransportFailure,
5827
6263
  isPathInside: () => isPathInside,
5828
6264
  isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
@@ -5836,6 +6272,7 @@ __export(index_exports, {
5836
6272
  listMeshes: () => listMeshes,
5837
6273
  listWorktrees: () => listWorktrees,
5838
6274
  loadConfig: () => loadConfig,
6275
+ loadMeshRefineConfig: () => loadMeshRefineConfig,
5839
6276
  loadState: () => loadState,
5840
6277
  logCommand: () => logCommand,
5841
6278
  markSetupComplete: () => markSetupComplete,
@@ -5849,6 +6286,7 @@ __export(index_exports, {
5849
6286
  normalizeGitWorkspaceSubscriptionParams: () => normalizeGitWorkspaceSubscriptionParams,
5850
6287
  normalizeInputEnvelope: () => normalizeInputEnvelope,
5851
6288
  normalizeManagedStatus: () => normalizeManagedStatus,
6289
+ normalizeMeshDaemonRole: () => normalizeMeshDaemonRole,
5852
6290
  normalizeMessageParts: () => normalizeMessageParts,
5853
6291
  normalizeRepoIdentity: () => normalizeRepoIdentity,
5854
6292
  normalizeSessionModalFields: () => normalizeSessionModalFields,
@@ -5860,6 +6298,7 @@ __export(index_exports, {
5860
6298
  prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
5861
6299
  prepareSessionModalUpdate: () => prepareSessionModalUpdate,
5862
6300
  probeCdpPort: () => probeCdpPort,
6301
+ queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
5863
6302
  readChatHistory: () => readChatHistory,
5864
6303
  readLedgerEntries: () => readLedgerEntries,
5865
6304
  readLedgerSlice: () => readLedgerSlice,
@@ -5868,6 +6307,7 @@ __export(index_exports, {
5868
6307
  removeNode: () => removeNode,
5869
6308
  removeWorktree: () => removeWorktree,
5870
6309
  requeueTask: () => requeueTask,
6310
+ requireMeshHostQueueOwner: () => requireMeshHostQueueOwner,
5871
6311
  resetConfig: () => resetConfig,
5872
6312
  resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
5873
6313
  resetState: () => resetState,
@@ -5875,6 +6315,8 @@ __export(index_exports, {
5875
6315
  resolveCurrentGlobalInstallSurface: () => resolveCurrentGlobalInstallSurface,
5876
6316
  resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
5877
6317
  resolveGitRepository: () => resolveGitRepository,
6318
+ resolveMeshHostStatus: () => resolveMeshHostStatus,
6319
+ resolveMeshRefineValidationPlan: () => resolveMeshRefineValidationPlan,
5878
6320
  resolveSessionHostAppName: () => resolveSessionHostAppName,
5879
6321
  resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
5880
6322
  resolveWorktreePath: () => resolveWorktreePath,
@@ -5890,6 +6332,7 @@ __export(index_exports, {
5890
6332
  shutdownDaemonComponents: () => shutdownDaemonComponents,
5891
6333
  spawnDetachedDaemonUpgradeHelper: () => spawnDetachedDaemonUpgradeHelper,
5892
6334
  startDaemonDevSupport: () => startDaemonDevSupport,
6335
+ suggestMeshRefineConfig: () => suggestMeshRefineConfig,
5893
6336
  summarizeGitStatus: () => summarizeGitStatus,
5894
6337
  syncMeshes: () => syncMeshes,
5895
6338
  triggerMeshQueue: () => triggerMeshQueue,
@@ -5898,7 +6341,8 @@ __export(index_exports, {
5898
6341
  updateNode: () => updateNode,
5899
6342
  updateSessionTaskStatus: () => updateSessionTaskStatus,
5900
6343
  updateTaskStatus: () => updateTaskStatus,
5901
- upsertSavedProviderSession: () => upsertSavedProviderSession
6344
+ upsertSavedProviderSession: () => upsertSavedProviderSession,
6345
+ validateMeshRefineConfig: () => validateMeshRefineConfig
5902
6346
  });
5903
6347
  module.exports = __toCommonJS(index_exports);
5904
6348
  init_repo_mesh_types();
@@ -5913,8 +6357,14 @@ async function getGitRepoStatus(workspace, options = {}) {
5913
6357
  const includeSubmodules = options.includeSubmodules !== false;
5914
6358
  try {
5915
6359
  const repo = await resolveGitRepository(workspace, options);
5916
- const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
5917
- const parsed = parsePorcelainV2Status(statusOutput.stdout);
6360
+ let parsed = await readPorcelainStatus(repo, options);
6361
+ let upstreamProbe = getInitialUpstreamProbe(parsed);
6362
+ if (options.refreshUpstream) {
6363
+ upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
6364
+ if (upstreamProbe.upstreamStatus === "fresh") {
6365
+ parsed = await readPorcelainStatus(repo, options);
6366
+ }
6367
+ }
5918
6368
  const head = await readHead(repo, options);
5919
6369
  const stashCount = await readStashCount(repo, options);
5920
6370
  let submodules;
@@ -5929,6 +6379,9 @@ async function getGitRepoStatus(workspace, options = {}) {
5929
6379
  headCommit: head.commit,
5930
6380
  headMessage: head.message,
5931
6381
  upstream: parsed.upstream,
6382
+ upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
6383
+ upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
6384
+ upstreamFetchError: upstreamProbe.upstreamFetchError,
5932
6385
  ahead: parsed.ahead,
5933
6386
  behind: parsed.behind,
5934
6387
  staged: parsed.staged,
@@ -5953,6 +6406,60 @@ async function getGitRepoStatus(workspace, options = {}) {
5953
6406
  );
5954
6407
  }
5955
6408
  }
6409
+ async function readPorcelainStatus(repo, options) {
6410
+ const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
6411
+ return parsePorcelainV2Status(statusOutput.stdout);
6412
+ }
6413
+ function getInitialUpstreamProbe(parsed) {
6414
+ return {
6415
+ upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
6416
+ };
6417
+ }
6418
+ async function refreshTrackedUpstream(repo, parsed, options) {
6419
+ if (!parsed.upstream || !parsed.branch) {
6420
+ return { upstreamStatus: "no_upstream" };
6421
+ }
6422
+ const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
6423
+ if (!remoteName) {
6424
+ return {
6425
+ upstreamStatus: "stale",
6426
+ upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
6427
+ };
6428
+ }
6429
+ try {
6430
+ await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
6431
+ return {
6432
+ upstreamStatus: "fresh",
6433
+ upstreamFetchedAt: Date.now()
6434
+ };
6435
+ } catch (error) {
6436
+ return {
6437
+ upstreamStatus: "stale",
6438
+ upstreamFetchError: formatGitError(error)
6439
+ };
6440
+ }
6441
+ }
6442
+ async function readBranchRemote(repo, branch, options) {
6443
+ try {
6444
+ const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
6445
+ return result.stdout.trim() || null;
6446
+ } catch {
6447
+ return null;
6448
+ }
6449
+ }
6450
+ function inferRemoteName(upstream) {
6451
+ const [remoteName] = upstream.split("/");
6452
+ return remoteName?.trim() || null;
6453
+ }
6454
+ function formatGitError(error) {
6455
+ if (error instanceof GitCommandError) {
6456
+ return error.stderr || error.message;
6457
+ }
6458
+ if (error instanceof Error) {
6459
+ return error.message;
6460
+ }
6461
+ return String(error);
6462
+ }
5956
6463
  function parsePorcelainV2Status(output) {
5957
6464
  const parsed = {
5958
6465
  branch: null,
@@ -6047,6 +6554,7 @@ function emptyStatus(workspace, lastCheckedAt, error) {
6047
6554
  headCommit: null,
6048
6555
  headMessage: null,
6049
6556
  upstream: null,
6557
+ upstreamStatus: "unavailable",
6050
6558
  ahead: 0,
6051
6559
  behind: 0,
6052
6560
  staged: 0,
@@ -6327,6 +6835,9 @@ function createGitCompactSummary(status, diffSummary) {
6327
6835
  isGitRepo: status.isGitRepo,
6328
6836
  repoRoot: status.repoRoot,
6329
6837
  branch: status.branch,
6838
+ upstreamStatus: status.upstreamStatus,
6839
+ upstreamFetchedAt: status.upstreamFetchedAt,
6840
+ upstreamFetchError: status.upstreamFetchError,
6330
6841
  dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
6331
6842
  changedFiles,
6332
6843
  ahead: status.ahead,
@@ -6671,7 +7182,7 @@ var defaultSnapshotStore = createGitSnapshotStore({
6671
7182
  });
6672
7183
  function createDefaultGitCommandServices() {
6673
7184
  return {
6674
- getStatus: ({ workspace }) => getGitRepoStatus(workspace),
7185
+ getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
6675
7186
  getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
6676
7187
  getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
6677
7188
  createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
@@ -6757,7 +7268,7 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
6757
7268
  switch (command) {
6758
7269
  case "git_status": {
6759
7270
  if (!services.getStatus) return serviceNotImplemented(command);
6760
- const status = await runService(() => services.getStatus({ workspace }));
7271
+ const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
6761
7272
  return "success" in status ? status : { success: true, status };
6762
7273
  }
6763
7274
  case "git_diff_summary": {
@@ -7563,6 +8074,238 @@ function getSavedProviderSessions(state, filters) {
7563
8074
  init_mesh_config();
7564
8075
  init_coordinator_prompt();
7565
8076
 
8077
+ // src/mesh/refine-config.ts
8078
+ var import_fs3 = require("fs");
8079
+ var import_path3 = require("path");
8080
+ var yaml = __toESM(require("js-yaml"));
8081
+ var MESH_REFINE_VALIDATION_CATEGORIES = ["typecheck", "test", "lint", "build"];
8082
+ var MESH_REFINE_CONFIG_LOCATIONS = [
8083
+ ".adhdev/refine.json",
8084
+ ".adhdev/refine.yaml",
8085
+ ".adhdev/refine.yml",
8086
+ ".adhdev/repo-mesh-refine.json",
8087
+ ".adhdev/repo-mesh-refine.yaml",
8088
+ ".adhdev/repo-mesh-refine.yml",
8089
+ "repo-mesh.refine.json",
8090
+ "repo-mesh.refine.yaml",
8091
+ "repo-mesh.refine.yml"
8092
+ ];
8093
+ var MESH_REFINE_CONFIG_SCHEMA = {
8094
+ $schema: "https://json-schema.org/draft/2020-12/schema",
8095
+ title: "ADHDev Repo Mesh Refinery Config",
8096
+ type: "object",
8097
+ additionalProperties: false,
8098
+ required: ["version"],
8099
+ properties: {
8100
+ version: { const: 1 },
8101
+ validation: {
8102
+ type: "object",
8103
+ additionalProperties: false,
8104
+ properties: {
8105
+ required: { type: "boolean", default: true },
8106
+ commands: {
8107
+ type: "array",
8108
+ minItems: 1,
8109
+ maxItems: 8,
8110
+ items: {
8111
+ type: "object",
8112
+ additionalProperties: false,
8113
+ required: ["command"],
8114
+ properties: {
8115
+ command: { type: "string", minLength: 1 },
8116
+ args: { type: "array", items: { type: "string" } },
8117
+ category: { enum: [...MESH_REFINE_VALIDATION_CATEGORIES, "custom"] },
8118
+ cwd: { type: "string" },
8119
+ timeoutMs: { type: "number", minimum: 1e3, maximum: 6e5 },
8120
+ env: { type: "object", additionalProperties: { type: "string" } }
8121
+ }
8122
+ }
8123
+ }
8124
+ }
8125
+ }
8126
+ }
8127
+ };
8128
+ function isRecord(value) {
8129
+ return !!value && typeof value === "object" && !Array.isArray(value);
8130
+ }
8131
+ function tokenizeCommandString(command) {
8132
+ const trimmed = command.trim();
8133
+ if (!trimmed) return null;
8134
+ if (/[;&|<>`$\\\n\r'\"]/.test(trimmed)) return null;
8135
+ const tokens = trimmed.split(/\s+/).filter(Boolean);
8136
+ if (!tokens.length) return null;
8137
+ if (tokens.some((token) => !/^[A-Za-z0-9_@./:=+-]+$/.test(token))) return null;
8138
+ return tokens;
8139
+ }
8140
+ function validateCategory(value) {
8141
+ return typeof value === "string" && [...MESH_REFINE_VALIDATION_CATEGORIES, "custom"].includes(value) ? value : "custom";
8142
+ }
8143
+ function normalizeCommandConfig(entry, source) {
8144
+ if (!isRecord(entry) || typeof entry.command !== "string") {
8145
+ return { rejected: { source, reason: "validation command must be an object with a command string" } };
8146
+ }
8147
+ const commandText = entry.command.trim();
8148
+ const explicitArgs = Array.isArray(entry.args) ? entry.args : void 0;
8149
+ if (explicitArgs && !explicitArgs.every((arg) => typeof arg === "string")) {
8150
+ return { rejected: { source, command: commandText, reason: "args must be an array of strings" } };
8151
+ }
8152
+ let command = commandText;
8153
+ let args = explicitArgs ? [...explicitArgs] : [];
8154
+ if (!explicitArgs) {
8155
+ const tokens = tokenizeCommandString(commandText);
8156
+ if (!tokens) return { rejected: { source, command: commandText, reason: "unsafe command string is not allowlisted" } };
8157
+ command = tokens[0];
8158
+ args = tokens.slice(1);
8159
+ } else if (!tokenizeCommandString(command)) {
8160
+ return { rejected: { source, command: commandText, reason: "unsafe executable name is not allowlisted" } };
8161
+ }
8162
+ if (args.some((arg) => /[\n\r\0]/.test(arg))) {
8163
+ return { rejected: { source, command: commandText, reason: "args cannot contain control characters" } };
8164
+ }
8165
+ if (entry.cwd !== void 0 && typeof entry.cwd !== "string") {
8166
+ return { rejected: { source, command: commandText, reason: "cwd must be a string when provided" } };
8167
+ }
8168
+ if (entry.timeoutMs !== void 0 && (typeof entry.timeoutMs !== "number" || !Number.isFinite(entry.timeoutMs) || entry.timeoutMs < 1e3 || entry.timeoutMs > 6e5)) {
8169
+ return { rejected: { source, command: commandText, reason: "timeoutMs must be between 1000 and 600000" } };
8170
+ }
8171
+ if (entry.env !== void 0 && (!isRecord(entry.env) || !Object.values(entry.env).every((value) => typeof value === "string"))) {
8172
+ return { rejected: { source, command: commandText, reason: "env must be an object of string values" } };
8173
+ }
8174
+ return {
8175
+ command: {
8176
+ command,
8177
+ args,
8178
+ displayCommand: [command, ...args].join(" "),
8179
+ category: validateCategory(entry.category),
8180
+ source,
8181
+ ...typeof entry.cwd === "string" && entry.cwd.trim() ? { cwd: entry.cwd.trim() } : {},
8182
+ ...typeof entry.timeoutMs === "number" ? { timeoutMs: entry.timeoutMs } : {},
8183
+ ...isRecord(entry.env) ? { env: entry.env } : {}
8184
+ }
8185
+ };
8186
+ }
8187
+ function validateMeshRefineConfig(config, source = "inline") {
8188
+ const errors = [];
8189
+ const commands = [];
8190
+ const rejectedCommands = [];
8191
+ if (!isRecord(config)) return { valid: false, errors: ["config must be an object"], commands, rejectedCommands };
8192
+ if (config.version !== 1) errors.push("version must be 1");
8193
+ const validation = config.validation;
8194
+ if (validation !== void 0 && !isRecord(validation)) errors.push("validation must be an object");
8195
+ const rawCommands = isRecord(validation) ? validation.commands : void 0;
8196
+ if (rawCommands !== void 0 && !Array.isArray(rawCommands)) errors.push("validation.commands must be an array");
8197
+ if (Array.isArray(rawCommands)) {
8198
+ rawCommands.forEach((entry, index) => {
8199
+ const normalized = normalizeCommandConfig(entry, `${source}:validation.commands[${index}]`);
8200
+ if (normalized.command) commands.push(normalized.command);
8201
+ if (normalized.rejected) rejectedCommands.push(normalized.rejected);
8202
+ });
8203
+ }
8204
+ if (rejectedCommands.length) errors.push("one or more validation commands are invalid");
8205
+ return { valid: errors.length === 0, errors, commands, rejectedCommands };
8206
+ }
8207
+ function parseConfigText(path28, text) {
8208
+ if (/\.json$/i.test(path28)) return JSON.parse(text);
8209
+ return yaml.load(text);
8210
+ }
8211
+ function loadMeshRefineConfig(mesh, workspace) {
8212
+ const policy = mesh?.policy && typeof mesh.policy === "object" && !Array.isArray(mesh.policy) ? mesh.policy : {};
8213
+ const inline = mesh?.refineConfig || policy.refineConfig || policy.refine;
8214
+ if (inline !== void 0) {
8215
+ const validation = validateMeshRefineConfig(inline, "mesh.policy.refineConfig");
8216
+ if (!validation.valid) return { source: "mesh.policy.refineConfig", sourceType: "invalid", error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
8217
+ return { config: inline, source: "mesh.policy.refineConfig", sourceType: "mesh_policy" };
8218
+ }
8219
+ for (const relative3 of MESH_REFINE_CONFIG_LOCATIONS) {
8220
+ const configPath = (0, import_path3.join)(workspace, relative3);
8221
+ if (!(0, import_fs3.existsSync)(configPath)) continue;
8222
+ try {
8223
+ const parsed = parseConfigText(configPath, (0, import_fs3.readFileSync)(configPath, "utf-8"));
8224
+ const validation = validateMeshRefineConfig(parsed, relative3);
8225
+ if (!validation.valid) return { source: relative3, sourceType: "invalid", path: configPath, error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
8226
+ return { config: parsed, source: relative3, sourceType: "repo_file", path: configPath };
8227
+ } catch (error) {
8228
+ return { source: relative3, sourceType: "invalid", path: configPath, error: error?.message || String(error) };
8229
+ }
8230
+ }
8231
+ return {
8232
+ source: "unavailable",
8233
+ sourceType: "unavailable",
8234
+ error: `No repo mesh/refine config found. Checked: ${MESH_REFINE_CONFIG_LOCATIONS.join(", ")}`
8235
+ };
8236
+ }
8237
+ function readPackageScripts(workspace) {
8238
+ try {
8239
+ const parsed = JSON.parse((0, import_fs3.readFileSync)((0, import_path3.join)(workspace, "package.json"), "utf-8"));
8240
+ return isRecord(parsed?.scripts) ? parsed.scripts : {};
8241
+ } catch {
8242
+ return {};
8243
+ }
8244
+ }
8245
+ function collectProjectContextSuggestions(mesh) {
8246
+ const commands = mesh?.projectContext?.commands;
8247
+ if (!isRecord(commands)) return [];
8248
+ const suggestions = [];
8249
+ for (const category of MESH_REFINE_VALIDATION_CATEGORIES) {
8250
+ const entries = Array.isArray(commands[category]) ? commands[category] : [];
8251
+ for (const entry of entries) {
8252
+ if (isRecord(entry) && typeof entry.command === "string") suggestions.push({ command: entry.command, category });
8253
+ }
8254
+ }
8255
+ return suggestions;
8256
+ }
8257
+ function collectPackageScriptSuggestions(workspace) {
8258
+ const scripts = readPackageScripts(workspace);
8259
+ const suggestions = [];
8260
+ for (const category of MESH_REFINE_VALIDATION_CATEGORIES) {
8261
+ for (const scriptName of Object.keys(scripts)) {
8262
+ if (scriptName === category || scriptName.startsWith(`${category}:`)) {
8263
+ suggestions.push({ command: "npm", args: ["run", scriptName], category });
8264
+ }
8265
+ }
8266
+ }
8267
+ return suggestions;
8268
+ }
8269
+ function suggestMeshRefineConfig(mesh, workspace) {
8270
+ const seen = /* @__PURE__ */ new Set();
8271
+ const suggestions = [];
8272
+ for (const entry of [...collectProjectContextSuggestions(mesh), ...collectPackageScriptSuggestions(workspace)]) {
8273
+ const key = `${entry.command} ${(entry.args || []).join(" ")}`.trim();
8274
+ if (seen.has(key)) continue;
8275
+ seen.add(key);
8276
+ suggestions.push(entry);
8277
+ }
8278
+ return {
8279
+ suggestions,
8280
+ suggestedConfig: suggestions.length ? { version: 1, validation: { required: true, commands: suggestions.slice(0, 4) } } : void 0
8281
+ };
8282
+ }
8283
+ function resolveMeshRefineValidationPlan(mesh, workspace) {
8284
+ const loaded = loadMeshRefineConfig(mesh, workspace);
8285
+ const suggestion = suggestMeshRefineConfig(mesh, workspace);
8286
+ if (!loaded.config) {
8287
+ return {
8288
+ source: loaded.source,
8289
+ sourceType: loaded.sourceType,
8290
+ commands: [],
8291
+ rejectedCommands: loaded.error ? [{ source: loaded.source, reason: loaded.error }] : [],
8292
+ suggestions: suggestion.suggestions,
8293
+ suggestedConfig: suggestion.suggestedConfig,
8294
+ unavailableReason: loaded.error || "validation_unavailable: repo mesh/refine config missing"
8295
+ };
8296
+ }
8297
+ const validation = validateMeshRefineConfig(loaded.config, loaded.source);
8298
+ return {
8299
+ source: loaded.path || loaded.source,
8300
+ sourceType: loaded.sourceType,
8301
+ commands: validation.commands,
8302
+ rejectedCommands: validation.rejectedCommands,
8303
+ suggestions: suggestion.suggestions,
8304
+ suggestedConfig: suggestion.suggestedConfig,
8305
+ unavailableReason: validation.commands.length ? void 0 : "validation_unavailable: repo mesh/refine config has no validation.commands"
8306
+ };
8307
+ }
8308
+
7566
8309
  // src/mesh/mesh-sync.ts
7567
8310
  init_mesh_config();
7568
8311
  async function syncMeshes(transport) {
@@ -7682,6 +8425,7 @@ function buildMeshLedgerReconciliationEvidence(meshId, replicas) {
7682
8425
 
7683
8426
  // src/index.ts
7684
8427
  init_mesh_work_queue();
8428
+ init_mesh_host_ownership();
7685
8429
  init_mesh_events();
7686
8430
 
7687
8431
  // src/mesh/p2p-relay-failure.ts
@@ -7795,8 +8539,8 @@ var P2pRelayFailureError = class extends Error {
7795
8539
  };
7796
8540
 
7797
8541
  // src/config/state-store.ts
7798
- var import_fs6 = require("fs");
7799
- var import_path5 = require("path");
8542
+ var import_fs8 = require("fs");
8543
+ var import_path7 = require("path");
7800
8544
  init_config();
7801
8545
  var DEFAULT_STATE = {
7802
8546
  recentActivity: [],
@@ -7810,7 +8554,7 @@ function isPlainObject2(value) {
7810
8554
  return !!value && typeof value === "object" && !Array.isArray(value);
7811
8555
  }
7812
8556
  function getStatePath() {
7813
- return (0, import_path5.join)(getConfigDir(), "state.json");
8557
+ return (0, import_path7.join)(getConfigDir(), "state.json");
7814
8558
  }
7815
8559
  function normalizeState(raw) {
7816
8560
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -7846,11 +8590,11 @@ function normalizeState(raw) {
7846
8590
  }
7847
8591
  function loadState() {
7848
8592
  const statePath = getStatePath();
7849
- if (!(0, import_fs6.existsSync)(statePath)) {
8593
+ if (!(0, import_fs8.existsSync)(statePath)) {
7850
8594
  return { ...DEFAULT_STATE };
7851
8595
  }
7852
8596
  try {
7853
- const raw = (0, import_fs6.readFileSync)(statePath, "utf-8");
8597
+ const raw = (0, import_fs8.readFileSync)(statePath, "utf-8");
7854
8598
  return normalizeState(JSON.parse(raw));
7855
8599
  } catch {
7856
8600
  return { ...DEFAULT_STATE };
@@ -7859,7 +8603,7 @@ function loadState() {
7859
8603
  function saveState(state) {
7860
8604
  const statePath = getStatePath();
7861
8605
  const normalized = normalizeState(state);
7862
- (0, import_fs6.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
8606
+ (0, import_fs8.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
7863
8607
  }
7864
8608
  function resetState() {
7865
8609
  saveState({ ...DEFAULT_STATE });
@@ -7867,7 +8611,7 @@ function resetState() {
7867
8611
 
7868
8612
  // src/detection/ide-detector.ts
7869
8613
  var import_child_process2 = require("child_process");
7870
- var import_fs7 = require("fs");
8614
+ var import_fs9 = require("fs");
7871
8615
  var import_os2 = require("os");
7872
8616
  var path10 = __toESM(require("path"));
7873
8617
  var BUILTIN_IDE_DEFINITIONS = [];
@@ -7891,7 +8635,7 @@ function findCliCommand(command) {
7891
8635
  if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
7892
8636
  const candidate = trimmed.startsWith("~") ? path10.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
7893
8637
  const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
7894
- return (0, import_fs7.existsSync)(resolved) ? resolved : null;
8638
+ return (0, import_fs9.existsSync)(resolved) ? resolved : null;
7895
8639
  }
7896
8640
  try {
7897
8641
  const result = (0, import_child_process2.execSync)(
@@ -7922,9 +8666,9 @@ function checkPathExists(paths) {
7922
8666
  if (normalized.includes("*")) {
7923
8667
  const username = home.split(/[\\/]/).pop() || "";
7924
8668
  const resolved = normalized.replace("*", username);
7925
- if ((0, import_fs7.existsSync)(resolved)) return resolved;
8669
+ if ((0, import_fs9.existsSync)(resolved)) return resolved;
7926
8670
  } else {
7927
- if ((0, import_fs7.existsSync)(normalized)) return normalized;
8671
+ if ((0, import_fs9.existsSync)(normalized)) return normalized;
7928
8672
  }
7929
8673
  }
7930
8674
  return null;
@@ -7938,7 +8682,7 @@ async function detectIDEs(providerLoader) {
7938
8682
  let resolvedCli = cliPath;
7939
8683
  if (!resolvedCli && appPath && os22 === "darwin") {
7940
8684
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
7941
- if ((0, import_fs7.existsSync)(bundledCli)) resolvedCli = bundledCli;
8685
+ if ((0, import_fs9.existsSync)(bundledCli)) resolvedCli = bundledCli;
7942
8686
  }
7943
8687
  if (!resolvedCli && appPath && os22 === "win32") {
7944
8688
  const { dirname: dirname9 } = await import("path");
@@ -7951,7 +8695,7 @@ async function detectIDEs(providerLoader) {
7951
8695
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
7952
8696
  ];
7953
8697
  for (const c of candidates) {
7954
- if ((0, import_fs7.existsSync)(c)) {
8698
+ if ((0, import_fs9.existsSync)(c)) {
7955
8699
  resolvedCli = c;
7956
8700
  break;
7957
8701
  }
@@ -9843,7 +10587,8 @@ var StatusMonitor = class {
9843
10587
  };
9844
10588
 
9845
10589
  // src/providers/chat-message-normalization.ts
9846
- function extractFinalSummaryFromMessages(messages, maxChars = 500) {
10590
+ var DEFAULT_FINAL_SUMMARY_MAX_CHARS = 4e3;
10591
+ function extractFinalSummaryFromMessages(messages, maxChars = DEFAULT_FINAL_SUMMARY_MAX_CHARS) {
9847
10592
  if (!Array.isArray(messages) || messages.length === 0) return "";
9848
10593
  for (let i = messages.length - 1; i >= 0; i--) {
9849
10594
  const msg = messages[i];
@@ -17103,7 +17848,7 @@ var DaemonCommandHandler = class {
17103
17848
  var os13 = __toESM(require("os"));
17104
17849
  var path18 = __toESM(require("path"));
17105
17850
  var crypto4 = __toESM(require("crypto"));
17106
- var import_fs8 = require("fs");
17851
+ var import_fs10 = require("fs");
17107
17852
  var import_child_process6 = require("child_process");
17108
17853
  var import_chalk = __toESM(require("chalk"));
17109
17854
  init_provider_cli_adapter();
@@ -19575,7 +20320,7 @@ function commandExists(command) {
19575
20320
  const trimmed = command.trim();
19576
20321
  if (!trimmed) return false;
19577
20322
  if (isExplicitCommand(trimmed)) {
19578
- return (0, import_fs8.existsSync)(expandExecutable(trimmed));
20323
+ return (0, import_fs10.existsSync)(expandExecutable(trimmed));
19579
20324
  }
19580
20325
  try {
19581
20326
  (0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -19604,10 +20349,10 @@ function hasCliArg(args, flag) {
19604
20349
  }
19605
20350
  function ensureEmptyDelegatedMcpConfig(workspace) {
19606
20351
  const baseDir = path18.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
19607
- (0, import_fs8.mkdirSync)(baseDir, { recursive: true });
20352
+ (0, import_fs10.mkdirSync)(baseDir, { recursive: true });
19608
20353
  const workspaceHash = crypto4.createHash("sha256").update(path18.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
19609
20354
  const filePath = path18.join(baseDir, `${workspaceHash}.json`);
19610
- (0, import_fs8.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
20355
+ (0, import_fs10.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
19611
20356
  return filePath;
19612
20357
  }
19613
20358
  function buildCoordinatorDelegatedCliLaunchOptions(input) {
@@ -22838,7 +23583,7 @@ function getRecentCommands(count = 50) {
22838
23583
  cleanOldFiles();
22839
23584
 
22840
23585
  // src/commands/router.ts
22841
- var yaml = __toESM(require("js-yaml"));
23586
+ var yaml2 = __toESM(require("js-yaml"));
22842
23587
  init_logger();
22843
23588
 
22844
23589
  // src/commands/mesh-coordinator.ts
@@ -23132,6 +23877,7 @@ function normalizeExistingPath(filePath) {
23132
23877
 
23133
23878
  // src/commands/router.ts
23134
23879
  init_mesh_events();
23880
+ init_mesh_host_ownership();
23135
23881
 
23136
23882
  // src/status/snapshot.ts
23137
23883
  var os18 = __toESM(require("os"));
@@ -23786,7 +24532,7 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
23786
24532
 
23787
24533
  // src/commands/router.ts
23788
24534
  var import_os3 = require("os");
23789
- var import_path6 = require("path");
24535
+ var import_path8 = require("path");
23790
24536
  var fs10 = __toESM(require("fs"));
23791
24537
  var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
23792
24538
  var CHANNEL_SERVER_URL = {
@@ -23835,13 +24581,85 @@ function readBooleanValue(...values) {
23835
24581
  }
23836
24582
  return void 0;
23837
24583
  }
23838
- function readGitSubmodules(value) {
24584
+ function summarizeRepoMeshDebugGit(git) {
24585
+ const record = readObjectRecord(git);
24586
+ if (!Object.keys(record).length) return null;
24587
+ const submodules = Array.isArray(record.submodules) ? record.submodules.map((entry) => ({
24588
+ path: readStringValue(entry?.path) ?? null,
24589
+ commit: readStringValue(entry?.commit)?.slice(0, 12) ?? null,
24590
+ dirty: readBooleanValue(entry?.dirty) ?? false,
24591
+ outOfSync: readBooleanValue(entry?.outOfSync, entry?.out_of_sync) ?? false
24592
+ })) : [];
24593
+ return {
24594
+ isGitRepo: readBooleanValue(record.isGitRepo),
24595
+ workspace: readStringValue(record.workspace) ?? null,
24596
+ repoRoot: readStringValue(record.repoRoot, record.repo_root) ?? null,
24597
+ branch: readStringValue(record.branch) ?? null,
24598
+ upstream: readStringValue(record.upstream) ?? null,
24599
+ upstreamStatus: readStringValue(record.upstreamStatus, record.upstream_status) ?? null,
24600
+ headCommit: readStringValue(record.headCommit, record.head_commit)?.slice(0, 12) ?? null,
24601
+ ahead: readNumberValue(record.ahead) ?? null,
24602
+ behind: readNumberValue(record.behind) ?? null,
24603
+ dirtyCounts: {
24604
+ staged: readNumberValue(record.staged) ?? 0,
24605
+ modified: readNumberValue(record.modified) ?? 0,
24606
+ untracked: readNumberValue(record.untracked) ?? 0,
24607
+ deleted: readNumberValue(record.deleted) ?? 0,
24608
+ renamed: readNumberValue(record.renamed) ?? 0
24609
+ },
24610
+ lastCheckedAt: readNumberValue(record.lastCheckedAt, record.last_checked_at) ?? null,
24611
+ submoduleCount: submodules.length,
24612
+ submodules
24613
+ };
24614
+ }
24615
+ function summarizeRepoMeshStatusDebug(status) {
24616
+ const nodes = Array.isArray(status?.nodes) ? status.nodes : [];
24617
+ return {
24618
+ success: status?.success,
24619
+ meshId: readStringValue(status?.meshId, status?.mesh_id) ?? null,
24620
+ refreshedAt: readStringValue(status?.refreshedAt, status?.refreshed_at) ?? null,
24621
+ sourceOfTruth: status?.sourceOfTruth ?? null,
24622
+ nodeCount: nodes.length,
24623
+ nodes: nodes.map((node) => ({
24624
+ nodeId: readStringValue(node?.nodeId, node?.id) ?? null,
24625
+ daemonId: readStringValue(node?.daemonId, node?.daemon_id) ?? null,
24626
+ workspace: readStringValue(node?.workspace, node?.git?.workspace) ?? null,
24627
+ health: readStringValue(node?.health) ?? null,
24628
+ machineStatus: readStringValue(node?.machineStatus, node?.machine_status) ?? null,
24629
+ connection: node?.connection && typeof node.connection === "object" ? {
24630
+ state: readStringValue(node.connection.state) ?? null,
24631
+ transport: readStringValue(node.connection.transport) ?? null,
24632
+ source: readStringValue(node.connection.source) ?? null,
24633
+ reported: readBooleanValue(node.connection.reported) ?? null
24634
+ } : null,
24635
+ gitProbePending: node?.gitProbePending === true,
24636
+ launchReady: node?.launchReady === true,
24637
+ git: summarizeRepoMeshDebugGit(node?.git)
24638
+ }))
24639
+ };
24640
+ }
24641
+ function logRepoMeshStatusDebug(event, fields) {
24642
+ try {
24643
+ LOG.info("MeshStatusDebug", `[RepoMeshStatusDebug] ${JSON.stringify({ event, ...fields })}`);
24644
+ } catch {
24645
+ LOG.info("MeshStatusDebug", `[RepoMeshStatusDebug] ${event}`);
24646
+ }
24647
+ }
24648
+ function joinRepoPath(root, relativePath) {
24649
+ const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
24650
+ const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
24651
+ if (!normalizedPath) return void 0;
24652
+ if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
24653
+ if (!normalizedRoot) return void 0;
24654
+ return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
24655
+ }
24656
+ function readGitSubmodules(value, parentRepoRoot) {
23839
24657
  if (!Array.isArray(value)) return void 0;
23840
24658
  const submodules = value.map((entry) => {
23841
24659
  const submodule = readObjectRecord(entry);
23842
24660
  const path28 = readStringValue(submodule.path);
23843
24661
  const commit = readStringValue(submodule.commit);
23844
- const repoPath = readStringValue(submodule.repoPath, submodule.repo_root);
24662
+ const repoPath = readStringValue(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path28);
23845
24663
  if (!path28 || !commit || !repoPath) return null;
23846
24664
  return {
23847
24665
  path: path28,
@@ -23855,58 +24673,17 @@ function readGitSubmodules(value) {
23855
24673
  }).filter((entry) => entry !== null);
23856
24674
  return submodules.length > 0 ? submodules : void 0;
23857
24675
  }
23858
- function buildCachedInlineMeshGitStatus(node) {
23859
- const cachedStatus = readObjectRecord(node?.cachedStatus);
23860
- const cachedGit = readObjectRecord(cachedStatus.git);
23861
- if (Object.keys(cachedGit).length) {
23862
- const conflictFiles2 = Array.isArray(cachedGit.conflictFiles) ? cachedGit.conflictFiles.filter((value) => typeof value === "string") : [];
23863
- const conflictCount2 = readNumberValue(cachedGit.conflicts) ?? conflictFiles2.length;
23864
- const hasConflicts2 = readBooleanValue(cachedGit.hasConflicts) ?? conflictCount2 > 0;
23865
- const isGitRepo2 = readBooleanValue(cachedGit.isGitRepo);
23866
- if (isGitRepo2 !== void 0) {
23867
- const submodules2 = readGitSubmodules(cachedGit.submodules);
23868
- return {
23869
- workspace: readStringValue(cachedGit.workspace, node?.workspace) || "",
23870
- repoRoot: readStringValue(cachedGit.repoRoot, node?.repoRoot, node?.workspace) || null,
23871
- isGitRepo: isGitRepo2,
23872
- branch: readStringValue(cachedGit.branch) ?? null,
23873
- headCommit: readStringValue(cachedGit.headCommit) ?? null,
23874
- headMessage: readStringValue(cachedGit.headMessage) ?? null,
23875
- upstream: readStringValue(cachedGit.upstream) ?? null,
23876
- ahead: readNumberValue(cachedGit.ahead) ?? 0,
23877
- behind: readNumberValue(cachedGit.behind) ?? 0,
23878
- staged: readNumberValue(cachedGit.staged) ?? 0,
23879
- modified: readNumberValue(cachedGit.modified) ?? 0,
23880
- untracked: readNumberValue(cachedGit.untracked) ?? 0,
23881
- deleted: readNumberValue(cachedGit.deleted) ?? 0,
23882
- renamed: readNumberValue(cachedGit.renamed) ?? 0,
23883
- hasConflicts: hasConflicts2,
23884
- conflictFiles: conflictFiles2,
23885
- stashCount: readNumberValue(cachedGit.stashCount) ?? 0,
23886
- lastCheckedAt: readNumberValue(cachedGit.lastCheckedAt) ?? Date.now(),
23887
- ...submodules2 ? { submodules: submodules2 } : {}
23888
- };
23889
- }
23890
- }
23891
- const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
23892
- const gitResult = readObjectRecord(rawGit.result);
23893
- const directStatus = readObjectRecord(rawGit.status);
23894
- const nestedStatus = readObjectRecord(gitResult.status);
23895
- const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
23896
- const probeGit = readObjectRecord(rawProbe.git);
23897
- const probeGitResult = readObjectRecord(probeGit.result);
23898
- const probeDirectStatus = readObjectRecord(probeGit.status);
23899
- const probeNestedStatus = readObjectRecord(probeGitResult.status);
23900
- const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
24676
+ function normalizeInlineMeshGitStatus(status, node, options) {
23901
24677
  const isGitRepo = readBooleanValue(status.isGitRepo);
23902
24678
  if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
23903
24679
  const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((value) => typeof value === "string") : [];
23904
24680
  const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
23905
24681
  const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
23906
- const submodules = readGitSubmodules(status.submodules);
24682
+ const repoRoot = readStringValue(status.repoRoot, status.repo_root, node?.repoRoot, node?.repo_root, status.workspace, node?.workspace) || void 0;
24683
+ const submodules = readGitSubmodules(status.submodules, repoRoot);
23907
24684
  return {
23908
24685
  workspace: readStringValue(status.workspace, node?.workspace) || "",
23909
- repoRoot: readStringValue(status.repoRoot, node?.repoRoot, node?.workspace) || null,
24686
+ repoRoot: repoRoot ?? null,
23910
24687
  isGitRepo,
23911
24688
  branch: readStringValue(status.branch) ?? null,
23912
24689
  headCommit: readStringValue(status.headCommit) ?? null,
@@ -23922,30 +24699,456 @@ function buildCachedInlineMeshGitStatus(node) {
23922
24699
  hasConflicts,
23923
24700
  conflictFiles,
23924
24701
  stashCount: readNumberValue(status.stashCount) ?? 0,
23925
- lastCheckedAt: Date.now(),
24702
+ lastCheckedAt: options?.lastCheckedAt ?? readNumberValue(status.lastCheckedAt) ?? Date.now(),
23926
24703
  ...submodules ? { submodules } : {}
23927
24704
  };
23928
24705
  }
23929
- function applyCachedInlineMeshNodeStatus(status, node) {
24706
+ function scoreInlineMeshGitStatus(git) {
24707
+ if (!git) return Number.NEGATIVE_INFINITY;
24708
+ let score = 0;
24709
+ if (readBooleanValue(git.isGitRepo) === true) score += 50;
24710
+ if (readBooleanValue(git.isGitRepo) === false) score -= 10;
24711
+ if (readStringValue(git.branch)) score += 20;
24712
+ if (readStringValue(git.headCommit)) score += 20;
24713
+ if (readStringValue(git.upstream)) score += 10;
24714
+ if (readStringValue(git.upstreamStatus)) score += 5;
24715
+ if (readNumberValue(git.ahead) !== void 0) score += 2;
24716
+ if (readNumberValue(git.behind) !== void 0) score += 2;
24717
+ if (Array.isArray(git.submodules) && git.submodules.length > 0) score += 4 + git.submodules.length;
24718
+ if (readStringValue(git.error)) score -= 20;
24719
+ return score;
24720
+ }
24721
+ function buildInlineMeshTransitGitStatus(node) {
24722
+ const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
24723
+ const gitResult = readObjectRecord(rawGit.result);
24724
+ const directStatus = readObjectRecord(rawGit.status);
24725
+ const nestedStatus = readObjectRecord(gitResult.status);
24726
+ const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
24727
+ const probeGit = readObjectRecord(rawProbe.git);
24728
+ const probeGitResult = readObjectRecord(probeGit.result);
24729
+ const probeDirectStatus = readObjectRecord(probeGit.status);
24730
+ const probeNestedStatus = readObjectRecord(probeGitResult.status);
24731
+ const candidates = [directStatus, nestedStatus, probeDirectStatus, probeNestedStatus];
24732
+ let best = null;
24733
+ for (const status of candidates) {
24734
+ const normalized = normalizeInlineMeshGitStatus(status, node, { lastCheckedAt: Date.now() });
24735
+ if (!normalized) continue;
24736
+ const score = scoreInlineMeshGitStatus(normalized);
24737
+ if (!best || score > best.score) best = { git: normalized, score };
24738
+ }
24739
+ return best?.git;
24740
+ }
24741
+ function shouldRefreshStalePendingAggregate(snapshot, options) {
24742
+ if (options?.requireDirectPeerTruth !== true || !Array.isArray(snapshot?.nodes)) return false;
24743
+ return snapshot.nodes.some((node) => {
24744
+ if (node?.gitProbePending !== true) return false;
24745
+ const git = readObjectRecord(node?.git);
24746
+ return !readBooleanValue(git.isGitRepo) && !readStringValue(git.branch, git.headCommit, git.upstream);
24747
+ });
24748
+ }
24749
+ function buildLivePeerGitConnection(connection, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
24750
+ const source = readStringValue(connection.source);
24751
+ const transport = readStringValue(connection.transport);
24752
+ return {
24753
+ ...connection,
24754
+ perspective: readStringValue(connection.perspective) ?? "selected_coordinator",
24755
+ source: source && source !== "not_reported" ? source : "mesh_peer_status",
24756
+ state: "connected",
24757
+ transport: transport && transport !== "unknown" ? transport : "direct",
24758
+ reported: true,
24759
+ reason: "Live peer git snapshot reported by the selected coordinator.",
24760
+ lastStateChangeAt: readStringValue(connection.lastStateChangeAt) ?? timestamp
24761
+ };
24762
+ }
24763
+ function recordInlineMeshDirectGitTruth(node, git, source) {
24764
+ if (!node || typeof node !== "object" || Array.isArray(node)) return;
24765
+ const checkedAt = readNumberValue(git.lastCheckedAt) ?? Date.now();
24766
+ const updatedAt = new Date(checkedAt).toISOString();
24767
+ const nextGit = {
24768
+ ...git,
24769
+ lastCheckedAt: checkedAt
24770
+ };
24771
+ node.lastGit = {
24772
+ source,
24773
+ checkedAt,
24774
+ status: nextGit
24775
+ };
24776
+ node.last_git = node.lastGit;
24777
+ node.machineStatus = "online";
24778
+ node.updatedAt = updatedAt;
24779
+ node.lastSeenAt = updatedAt;
24780
+ const repoRoot = readStringValue(nextGit.repoRoot);
24781
+ if (repoRoot && !readStringValue(node.repoRoot)) node.repoRoot = repoRoot;
24782
+ }
24783
+ function buildCachedInlineMeshGitStatus(node) {
24784
+ const liveGit = buildInlineMeshTransitGitStatus(node);
24785
+ if (liveGit) return liveGit;
23930
24786
  const cachedStatus = readObjectRecord(node?.cachedStatus);
23931
- const git = buildCachedInlineMeshGitStatus(node);
23932
- const error = readStringValue(cachedStatus.error, node?.error);
23933
- const health = readStringValue(cachedStatus.health, node?.health);
24787
+ const cachedGit = readObjectRecord(cachedStatus.git);
24788
+ if (!Object.keys(cachedGit).length) return void 0;
24789
+ return normalizeInlineMeshGitStatus(cachedGit, node);
24790
+ }
24791
+ function shouldDiscardCachedInlineMeshStatus(node) {
24792
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
24793
+ if (!Object.keys(cachedStatus).length) return false;
24794
+ const cachedGit = readObjectRecord(cachedStatus.git);
24795
+ const workspaceError = readStringValue(cachedStatus.error, node?.error);
24796
+ if (workspaceError && /workspace must be an existing directory/i.test(workspaceError)) return true;
24797
+ const isGitRepo = readBooleanValue(cachedGit.isGitRepo);
24798
+ const branch = readStringValue(cachedGit.branch);
24799
+ const headCommit = readStringValue(cachedGit.headCommit);
24800
+ return isGitRepo === false && !branch && !headCommit;
24801
+ }
24802
+ function stripInlineMeshTransientNodeState(node) {
24803
+ if (!node || typeof node !== "object" || Array.isArray(node)) return node;
24804
+ const {
24805
+ cachedStatus,
24806
+ lastGit: _lastGit,
24807
+ last_git: _lastGitLegacy,
24808
+ lastProbe: _lastProbe,
24809
+ last_probe: _lastProbeLegacy,
24810
+ error: _error,
24811
+ health: _health,
24812
+ machineStatus: _machineStatus,
24813
+ lastSeenAt: _lastSeenAt,
24814
+ last_seen_at: _lastSeenAtLegacy,
24815
+ updatedAt: _updatedAt,
24816
+ updated_at: _updatedAtLegacy,
24817
+ activeSession: _activeSession,
24818
+ active_session: _activeSessionLegacy,
24819
+ activeSessionId: _activeSessionId,
24820
+ active_session_id: _activeSessionIdLegacy,
24821
+ sessionId: _sessionId,
24822
+ session_id: _sessionIdLegacy,
24823
+ providerType: _providerType,
24824
+ provider_type: _providerTypeLegacy,
24825
+ ...rest
24826
+ } = node;
24827
+ if (cachedStatus && !shouldDiscardCachedInlineMeshStatus(node)) {
24828
+ return { ...rest, cachedStatus };
24829
+ }
24830
+ return rest;
24831
+ }
24832
+ function hasInlineMeshTransientNodeState(node) {
24833
+ if (!node || typeof node !== "object" || Array.isArray(node)) return false;
24834
+ return "cachedStatus" in node || "lastGit" in node || "last_git" in node || "lastProbe" in node || "last_probe" in node || "error" in node || "health" in node || "machineStatus" in node || "lastSeenAt" in node || "last_seen_at" in node || "updatedAt" in node || "updated_at" in node || "activeSession" in node || "active_session" in node || "activeSessionId" in node || "active_session_id" in node || "sessionId" in node || "session_id" in node || "providerType" in node || "provider_type" in node;
24835
+ }
24836
+ function inlineMeshCarriesTransientNodeTruth(inlineMesh) {
24837
+ if (!inlineMesh || typeof inlineMesh !== "object" || Array.isArray(inlineMesh)) return false;
24838
+ if (!Array.isArray(inlineMesh.nodes) || inlineMesh.nodes.length === 0) return false;
24839
+ return inlineMesh.nodes.some((node) => hasInlineMeshTransientNodeState(node));
24840
+ }
24841
+ function readInlineMeshNodeId(node) {
24842
+ return readStringValue(node?.id, node?.nodeId) || "";
24843
+ }
24844
+ function sanitizeInlineMesh(inlineMesh) {
24845
+ if (!inlineMesh || typeof inlineMesh !== "object" || Array.isArray(inlineMesh)) return inlineMesh;
24846
+ if (!Array.isArray(inlineMesh.nodes)) return inlineMesh;
24847
+ let changed = false;
24848
+ const nodes = inlineMesh.nodes.map((node) => {
24849
+ if (!hasInlineMeshTransientNodeState(node)) return node;
24850
+ changed = true;
24851
+ return stripInlineMeshTransientNodeState(node);
24852
+ });
24853
+ if (!changed) return inlineMesh;
24854
+ return {
24855
+ ...inlineMesh,
24856
+ nodes
24857
+ };
24858
+ }
24859
+ function reconcileInlineMeshCache(cached, incoming) {
24860
+ if (!cached || typeof cached !== "object" || Array.isArray(cached)) return incoming;
24861
+ if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return cached;
24862
+ const cachedNodes = Array.isArray(cached.nodes) ? cached.nodes : [];
24863
+ const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
24864
+ if (!cachedNodes.length || !incomingNodes.length) return { ...cached, ...incoming };
24865
+ const incomingById = /* @__PURE__ */ new Map();
24866
+ for (const node of incomingNodes) {
24867
+ const nodeId = readInlineMeshNodeId(node);
24868
+ if (nodeId) incomingById.set(nodeId, node);
24869
+ }
24870
+ const nodes = cachedNodes.map((cachedNode) => {
24871
+ const nodeId = readInlineMeshNodeId(cachedNode);
24872
+ const incomingNode = nodeId ? incomingById.get(nodeId) : void 0;
24873
+ if (!incomingNode) return cachedNode;
24874
+ if (hasInlineMeshTransientNodeState(incomingNode)) {
24875
+ return { ...cachedNode, ...incomingNode };
24876
+ }
24877
+ return { ...stripInlineMeshTransientNodeState(cachedNode), ...incomingNode };
24878
+ });
24879
+ return {
24880
+ ...cached,
24881
+ ...incoming,
24882
+ nodes
24883
+ };
24884
+ }
24885
+ function hasGitWorktreeChanges(git) {
24886
+ if (!git) return false;
24887
+ return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
24888
+ }
24889
+ function getGitSubmoduleDriftState(git) {
24890
+ const submodules = Array.isArray(git?.submodules) ? git.submodules : [];
24891
+ let dirty = false;
24892
+ let outOfSync = false;
24893
+ for (const entry of submodules) {
24894
+ const submodule = readObjectRecord(entry);
24895
+ if (readBooleanValue(submodule.dirty) === true) dirty = true;
24896
+ if (readBooleanValue(submodule.outOfSync) === true || !!readStringValue(submodule.error)) outOfSync = true;
24897
+ }
24898
+ return { dirty, outOfSync };
24899
+ }
24900
+ function deriveMeshNodeHealthFromGit(git) {
24901
+ if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
24902
+ const branch = readStringValue(git.branch);
24903
+ if (!branch) return "degraded";
24904
+ const submoduleDrift = getGitSubmoduleDriftState(git);
24905
+ if (submoduleDrift.outOfSync) return "degraded";
24906
+ if (submoduleDrift.dirty || hasGitWorktreeChanges(git)) return "dirty";
24907
+ return "online";
24908
+ }
24909
+ function readCachedInlineMeshActiveSessions(node) {
24910
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
24911
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
24912
+ const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
24913
+ const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
24914
+ return sessionId ? [sessionId] : [];
24915
+ }
24916
+ function readCachedInlineMeshActiveSessionDetails(node) {
24917
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
24918
+ const activeSession = readObjectRecord(cachedStatus.activeSession);
24919
+ const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
24920
+ const sessionId = readStringValue(
24921
+ fallbackSession.id,
24922
+ fallbackSession.sessionId,
24923
+ fallbackSession.session_id,
24924
+ node?.activeSessionId,
24925
+ node?.active_session_id,
24926
+ node?.sessionId,
24927
+ node?.session_id
24928
+ );
24929
+ if (!sessionId) return [];
24930
+ return [{
24931
+ sessionId,
24932
+ providerType: readStringValue(
24933
+ fallbackSession.providerType,
24934
+ fallbackSession.provider_type,
24935
+ fallbackSession.cliType,
24936
+ fallbackSession.cli_type,
24937
+ fallbackSession.provider,
24938
+ node?.providerType,
24939
+ node?.provider_type
24940
+ ),
24941
+ state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
24942
+ lifecycle: readStringValue(fallbackSession.lifecycle),
24943
+ title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
24944
+ workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
24945
+ lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
24946
+ recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
24947
+ isCached: true
24948
+ }];
24949
+ }
24950
+ function readLiveMeshSessionState(record) {
24951
+ return readStringValue(
24952
+ record?.meta?.sessionStatus,
24953
+ record?.meta?.status,
24954
+ record?.meta?.providerStatus,
24955
+ record?.status,
24956
+ record?.state,
24957
+ record?.lifecycle
24958
+ );
24959
+ }
24960
+ function toIsoTimestamp(value) {
24961
+ if (typeof value === "number" && Number.isFinite(value)) return new Date(value).toISOString();
24962
+ const stringValue = readStringValue(value);
24963
+ return stringValue || null;
24964
+ }
24965
+ function synthesizeMeshNodeFreshnessFromConnection(status) {
24966
+ const connection = readObjectRecord(status.connection);
24967
+ const connectionFreshAt = toIsoTimestamp(connection.lastCommandAt ?? connection.lastConnectedAt ?? connection.lastStateChangeAt);
24968
+ const git = readObjectRecord(status.git);
24969
+ const gitCheckedAt = toIsoTimestamp(git.lastCheckedAt);
24970
+ if (!status.lastSeenAt && connectionFreshAt) status.lastSeenAt = connectionFreshAt;
24971
+ if (!status.updatedAt && (gitCheckedAt || connectionFreshAt)) {
24972
+ status.updatedAt = gitCheckedAt ?? connectionFreshAt;
24973
+ }
24974
+ }
24975
+ function finalizeMeshNodeStatus(args) {
24976
+ const { status, node, daemonId, isSelfNode } = args;
24977
+ if (!readStringValue(status.machineStatus)) {
24978
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
24979
+ const machineStatus = readStringValue(cachedStatus.machineStatus, cachedStatus.machine_status, node?.machineStatus);
24980
+ if (machineStatus) status.machineStatus = machineStatus;
24981
+ }
24982
+ synthesizeMeshNodeFreshnessFromConnection(status);
24983
+ const connectionState = readStringValue(readObjectRecord(status.connection).state);
24984
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || connectionState === "connected" || isSelfNode);
24985
+ }
24986
+ async function probeRemoteMeshGitStatus(args) {
24987
+ if (!args.dispatchMeshCommand) return null;
24988
+ const remoteResult = await Promise.race([
24989
+ args.dispatchMeshCommand(args.daemonId, "git_status", { workspace: args.workspace }),
24990
+ new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), args.timeoutMs))
24991
+ ]);
24992
+ const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
24993
+ return remoteGit && typeof remoteGit === "object" && typeof remoteGit.isGitRepo === "boolean" ? remoteGit : null;
24994
+ }
24995
+ async function hydrateInlineMeshDirectTruth(args) {
24996
+ const nodes = Array.isArray(args.mesh?.nodes) ? args.mesh.nodes : [];
24997
+ if (!nodes.length) {
24998
+ return {
24999
+ directEvidenceCount: 0,
25000
+ localConfirmedCount: 0,
25001
+ peerAttemptedCount: 0,
25002
+ peerConfirmedCount: 0,
25003
+ unavailableNodeIds: []
25004
+ };
25005
+ }
25006
+ const selectedCoordinatorNodeId = readStringValue(
25007
+ args.mesh?.coordinator?.preferredNodeId,
25008
+ nodes[0]?.id,
25009
+ nodes[0]?.nodeId
25010
+ );
25011
+ let localConfirmedCount = 0;
25012
+ let peerAttemptedCount = 0;
25013
+ let peerConfirmedCount = 0;
25014
+ const unavailableNodeIds = [];
25015
+ for (const [nodeIndex, node] of nodes.entries()) {
25016
+ const nodeId = readStringValue(node?.id, node?.nodeId) || `node_${nodeIndex}`;
25017
+ const workspace = readStringValue(node?.workspace);
25018
+ const daemonId = readStringValue(node?.daemonId);
25019
+ const isSelfNode = Boolean(
25020
+ nodeId && selectedCoordinatorNodeId && nodeId === selectedCoordinatorNodeId
25021
+ ) || Boolean(
25022
+ daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId)
25023
+ ) || Boolean(args.meshSource !== "local_config" && nodeIndex === 0);
25024
+ if (!workspace) {
25025
+ if (!isSelfNode && daemonId) unavailableNodeIds.push(nodeId);
25026
+ continue;
25027
+ }
25028
+ if (isSelfNode && fs10.existsSync(workspace)) {
25029
+ try {
25030
+ const localGit = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
25031
+ if (localGit?.isGitRepo) {
25032
+ recordInlineMeshDirectGitTruth(node, localGit, "selected_coordinator_local_git");
25033
+ localConfirmedCount += 1;
25034
+ continue;
25035
+ }
25036
+ } catch {
25037
+ }
25038
+ }
25039
+ if (!daemonId || !args.dispatchMeshCommand) {
25040
+ if (!isSelfNode) unavailableNodeIds.push(nodeId);
25041
+ continue;
25042
+ }
25043
+ peerAttemptedCount += 1;
25044
+ try {
25045
+ const remoteGit = await probeRemoteMeshGitStatus({
25046
+ dispatchMeshCommand: args.dispatchMeshCommand,
25047
+ daemonId,
25048
+ workspace,
25049
+ timeoutMs: 8e3
25050
+ });
25051
+ if (remoteGit) {
25052
+ recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
25053
+ peerConfirmedCount += 1;
25054
+ continue;
25055
+ }
25056
+ } catch {
25057
+ }
25058
+ unavailableNodeIds.push(nodeId);
25059
+ }
25060
+ return {
25061
+ directEvidenceCount: localConfirmedCount + peerConfirmedCount,
25062
+ localConfirmedCount,
25063
+ peerAttemptedCount,
25064
+ peerConfirmedCount,
25065
+ unavailableNodeIds
25066
+ };
25067
+ }
25068
+ function summarizeMeshSessionRecord(record) {
25069
+ return {
25070
+ sessionId: readStringValue(record?.sessionId) || "unknown",
25071
+ providerType: readStringValue(record?.providerType),
25072
+ state: readLiveMeshSessionState(record),
25073
+ lifecycle: readStringValue(record?.lifecycle),
25074
+ surfaceKind: getSessionHostSurfaceKind(record),
25075
+ recoveryState: readStringValue(record?.meta?.runtimeRecoveryState) ?? null,
25076
+ workspace: readStringValue(record?.workspace) ?? null,
25077
+ title: readStringValue(record?.displayName, record?.workspaceLabel) ?? null,
25078
+ lastActivityAt: toIsoTimestamp(record?.updatedAt ?? record?.lastActivityAt ?? record?.last_activity_at),
25079
+ isCached: false
25080
+ };
25081
+ }
25082
+ function liveSessionRecordMatchesMeshNode(record, meshId, nodeId) {
25083
+ const recordNodeId = readStringValue(record?.meta?.meshNodeId);
25084
+ if (!recordNodeId || recordNodeId !== nodeId) return false;
25085
+ const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
25086
+ return !recordMeshId || recordMeshId === meshId;
25087
+ }
25088
+ function liveSessionRecordMatchesMeshWorkspace(record, meshId, workspace) {
25089
+ const recordWorkspace = readStringValue(record?.workspace);
25090
+ if (!recordWorkspace || !workspace || recordWorkspace !== workspace) return false;
25091
+ const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
25092
+ if (recordMeshId) return recordMeshId === meshId;
25093
+ return record?.meta?.launchedByCoordinator === true || !!readStringValue(record?.meta?.meshNodeId);
25094
+ }
25095
+ function readLiveMeshNodeWorkspace(args) {
25096
+ const directNodeWorkspace = args.liveSessionRecords.find((record) => liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId) && readStringValue(record?.workspace));
25097
+ if (directNodeWorkspace) {
25098
+ return readStringValue(directNodeWorkspace.workspace) || "";
25099
+ }
25100
+ if (args.allowCoordinatorSession) {
25101
+ const coordinatorWorkspace = args.liveSessionRecords.find((record) => readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId && readStringValue(record?.workspace));
25102
+ if (coordinatorWorkspace) {
25103
+ return readStringValue(coordinatorWorkspace.workspace) || "";
25104
+ }
25105
+ }
25106
+ return "";
25107
+ }
25108
+ function collectLiveMeshSessionRecords(args) {
25109
+ const matches = args.liveSessionRecords.filter((record) => {
25110
+ const nodeWorkspace = readStringValue(args.node?.workspace);
25111
+ if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)) return true;
25112
+ return !!nodeWorkspace && liveSessionRecordMatchesMeshWorkspace(record, args.meshId, nodeWorkspace);
25113
+ });
25114
+ if (args.allowCoordinatorSession) {
25115
+ for (const record of args.liveSessionRecords) {
25116
+ if (readStringValue(record?.meta?.meshCoordinatorFor) !== args.meshId) continue;
25117
+ const sessionId = readStringValue(record?.sessionId);
25118
+ if (sessionId && matches.some((entry) => readStringValue(entry?.sessionId) === sessionId)) continue;
25119
+ matches.push(record);
25120
+ }
25121
+ }
25122
+ return matches;
25123
+ }
25124
+ function applyCachedInlineMeshNodeStatus(status, node, options) {
25125
+ const cachedStatus = readObjectRecord(node?.cachedStatus);
25126
+ const liveGit = buildInlineMeshTransitGitStatus(node);
25127
+ const git = options?.skipGit ? void 0 : liveGit ?? buildCachedInlineMeshGitStatus(node);
25128
+ const error = options?.skipError ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.error, node?.error);
25129
+ const health = options?.skipHealth ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.health, node?.health);
23934
25130
  const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
23935
- if (!git && !error && !health) return false;
23936
- if (!machineStatus && !git && !error) return false;
25131
+ const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
25132
+ const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
25133
+ const activeSessions = readCachedInlineMeshActiveSessions(node);
25134
+ const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
25135
+ if (!git && !error && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
23937
25136
  if (git) status.git = git;
23938
25137
  if (error) status.error = error;
25138
+ if (machineStatus) status.machineStatus = machineStatus;
25139
+ if (lastSeenAt) status.lastSeenAt = lastSeenAt;
25140
+ if (updatedAt) status.updatedAt = updatedAt;
25141
+ if (activeSessions.length > 0) status.activeSessions = activeSessions;
25142
+ if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
23939
25143
  if (health) {
23940
25144
  status.health = health;
23941
25145
  return true;
23942
25146
  }
23943
25147
  if (git) {
23944
- const dirty = Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
23945
- status.health = git.isGitRepo === false ? "degraded" : dirty ? "dirty" : "online";
25148
+ status.health = deriveMeshNodeHealthFromGit(git);
23946
25149
  return true;
23947
25150
  }
23948
- return false;
25151
+ return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
23949
25152
  }
23950
25153
  async function resolveProviderTypeFromPriority(args) {
23951
25154
  if (!args.providerPriority.length) {
@@ -23970,152 +25173,116 @@ async function resolveProviderTypeFromPriority(args) {
23970
25173
  }
23971
25174
  return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
23972
25175
  }
23973
- var REFINE_VALIDATION_CATEGORIES = ["typecheck", "test", "lint", "build"];
23974
25176
  var REFINE_VALIDATION_TIMEOUT_MS = 12e4;
23975
25177
  var REFINE_VALIDATION_OUTPUT_LIMIT_BYTES = 128 * 1024;
23976
25178
  var REFINE_VALIDATION_SUMMARY_CHARS = 2e3;
23977
- var REFINE_VALIDATION_MAX_COMMANDS = 4;
25179
+ var REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
23978
25180
  function truncateValidationOutput(value) {
23979
25181
  const text = typeof value === "string" ? value : value == null ? "" : String(value);
23980
25182
  if (text.length <= REFINE_VALIDATION_SUMMARY_CHARS) return text;
23981
25183
  return `${text.slice(0, REFINE_VALIDATION_SUMMARY_CHARS)}
23982
25184
  [truncated ${text.length - REFINE_VALIDATION_SUMMARY_CHARS} chars]`;
23983
25185
  }
23984
- function readPackageScripts(workspace) {
23985
- try {
23986
- const packageJsonPath = (0, import_path6.join)(workspace, "package.json");
23987
- const parsed = JSON.parse(fs10.readFileSync(packageJsonPath, "utf-8"));
23988
- return parsed?.scripts && typeof parsed.scripts === "object" && !Array.isArray(parsed.scripts) ? parsed.scripts : {};
23989
- } catch {
23990
- return {};
23991
- }
23992
- }
23993
- function tokenizeValidationCommand(command) {
23994
- const trimmed = command.trim();
23995
- if (!trimmed) return null;
23996
- if (/[;&|<>`$\\\n\r'\"]/.test(trimmed)) return null;
23997
- const tokens = trimmed.split(/\s+/).filter(Boolean);
23998
- if (!tokens.length) return null;
23999
- if (tokens.some((token) => !/^[A-Za-z0-9_@./:=+-]+$/.test(token))) return null;
24000
- return tokens;
24001
- }
24002
- function scriptMatchesValidationCategory(scriptName, category) {
24003
- return scriptName === category || scriptName.startsWith(`${category}:`);
24004
- }
24005
- function parsePackageManagerValidationCommand(rawCommand, category, scripts, source) {
24006
- const tokens = tokenizeValidationCommand(rawCommand);
24007
- if (!tokens) {
24008
- return { rejected: { command: rawCommand, category, source, reason: "unsafe command string is not allowlisted" } };
24009
- }
24010
- const [binary, second, third, ...rest] = tokens;
24011
- let scriptName = "";
24012
- let command = binary;
24013
- let args = [];
24014
- if ((binary === "npm" || binary === "pnpm" || binary === "bun") && second === "run" && third) {
24015
- scriptName = third;
24016
- args = ["run", scriptName, ...rest];
24017
- } else if (binary === "npm" && second === "test" && !third) {
24018
- scriptName = "test";
24019
- args = ["test"];
24020
- } else if (binary === "yarn" && second === "run" && third) {
24021
- scriptName = third;
24022
- args = ["run", scriptName, ...rest];
24023
- } else if (binary === "yarn" && second && !third) {
24024
- scriptName = second;
24025
- args = [scriptName];
24026
- } else {
24027
- return { rejected: { command: rawCommand, category, source, reason: "command is not a supported package-manager script invocation" } };
24028
- }
24029
- if (!scriptName || !Object.prototype.hasOwnProperty.call(scripts, scriptName)) {
24030
- return { rejected: { command: rawCommand, category, source, script: scriptName, reason: "script is not declared in package.json" } };
24031
- }
24032
- if (!scriptMatchesValidationCategory(scriptName, category)) {
24033
- return { rejected: { command: rawCommand, category, source, script: scriptName, reason: "script name is outside the validation category allowlist" } };
24034
- }
24035
- return {
24036
- command: {
24037
- command,
24038
- args,
24039
- displayCommand: [command, ...args].join(" "),
24040
- category,
24041
- source
24042
- }
24043
- };
25186
+ function recordMeshRefineStage(stages, stage, status, startedAt, details) {
25187
+ stages.push({
25188
+ stage,
25189
+ status,
25190
+ durationMs: Date.now() - startedAt,
25191
+ ...details || {}
25192
+ });
24044
25193
  }
24045
- function collectProjectContextValidationCandidates(mesh) {
24046
- const commands = mesh?.projectContext?.commands;
24047
- if (!commands || typeof commands !== "object" || Array.isArray(commands)) return [];
24048
- const candidates = [];
24049
- for (const category of REFINE_VALIDATION_CATEGORIES) {
24050
- const entries = Array.isArray(commands[category]) ? commands[category] : [];
24051
- for (const entry of entries) {
24052
- if (typeof entry?.command !== "string") continue;
24053
- candidates.push({
24054
- command: entry.command,
24055
- category,
24056
- source: typeof entry.sourcePath === "string" ? entry.sourcePath : "projectContext.commands",
24057
- confidence: typeof entry.confidence === "string" ? entry.confidence : void 0
24058
- });
24059
- }
24060
- }
24061
- return candidates.sort((a, b) => {
24062
- const rank = (value) => value === "high" ? 0 : value === "medium" ? 1 : 2;
24063
- return rank(a.confidence) - rank(b.confidence);
25194
+ async function computeGitPatchId(cwd, fromRef, toRef) {
25195
+ const { execFileSync: execFileSync4 } = await import("child_process");
25196
+ const diff = execFileSync4("git", ["diff", "--patch", "--full-index", fromRef, toRef], {
25197
+ cwd,
25198
+ encoding: "utf8",
25199
+ maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
24064
25200
  });
25201
+ if (!diff.trim()) return "";
25202
+ const patchId = execFileSync4("git", ["patch-id", "--stable"], {
25203
+ cwd,
25204
+ input: diff,
25205
+ encoding: "utf8",
25206
+ maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
25207
+ }).trim();
25208
+ return patchId.split(/\s+/)[0] || "";
24065
25209
  }
24066
- function collectPolicyValidationCandidates(mesh) {
24067
- const policy = mesh?.policy && typeof mesh.policy === "object" && !Array.isArray(mesh.policy) ? mesh.policy : {};
24068
- const configured = Array.isArray(policy.validationCommands) ? policy.validationCommands : Array.isArray(policy.validationGate?.commands) ? policy.validationGate.commands : [];
24069
- return configured.map((entry) => typeof entry === "string" ? { command: entry, category: "", source: "mesh.policy.validationCommands" } : entry).filter((entry) => entry && typeof entry.command === "string").map((entry) => {
24070
- const commandText = entry.command.trim();
24071
- const category = REFINE_VALIDATION_CATEGORIES.find((cat) => commandText.includes(` ${cat}`)) ?? "";
24072
- return { command: commandText, category, source: "mesh.policy.validationCommands" };
24073
- }).filter((entry) => !!entry.category);
24074
- }
24075
- function selectMeshRefineValidationCommands(mesh, workspace) {
24076
- const scripts = readPackageScripts(workspace);
24077
- const rejectedCommands = [];
24078
- const selected = [];
24079
- const seen = /* @__PURE__ */ new Set();
24080
- const candidates = [
24081
- ...collectPolicyValidationCandidates(mesh),
24082
- ...collectProjectContextValidationCandidates(mesh)
24083
- ];
24084
- for (const candidate of candidates) {
24085
- const parsed = parsePackageManagerValidationCommand(candidate.command, candidate.category, scripts, candidate.source);
24086
- if (parsed.rejected) {
24087
- rejectedCommands.push(parsed.rejected);
24088
- continue;
24089
- }
24090
- if (!parsed.command || seen.has(parsed.command.displayCommand)) continue;
24091
- selected.push(parsed.command);
24092
- seen.add(parsed.command.displayCommand);
24093
- if (selected.length >= REFINE_VALIDATION_MAX_COMMANDS) break;
24094
- }
24095
- if (!selected.length && candidates.length === 0) {
24096
- for (const category of REFINE_VALIDATION_CATEGORIES) {
24097
- if (!Object.prototype.hasOwnProperty.call(scripts, category)) continue;
24098
- const fallback = parsePackageManagerValidationCommand(`npm run ${category}`, category, scripts, "package.json:scripts");
24099
- if (fallback.command && !seen.has(fallback.command.displayCommand)) {
24100
- selected.push(fallback.command);
24101
- seen.add(fallback.command.displayCommand);
24102
- } else if (fallback.rejected) {
24103
- rejectedCommands.push(fallback.rejected);
24104
- }
24105
- if (selected.length >= 2) break;
25210
+ async function runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead) {
25211
+ const startedAt = Date.now();
25212
+ try {
25213
+ const { execFileSync: execFileSync4 } = await import("child_process");
25214
+ const git = (args) => execFileSync4("git", args, {
25215
+ cwd: repoRoot,
25216
+ encoding: "utf8",
25217
+ maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
25218
+ });
25219
+ const mergeBase = git(["merge-base", baseHead, branchHead]).trim();
25220
+ const mergeTreeStdout = git(["merge-tree", "--write-tree", baseHead, branchHead]);
25221
+ const mergedTree = mergeTreeStdout.trim().split(/\s+/)[0] || "";
25222
+ if (!mergeBase || !mergedTree) {
25223
+ return {
25224
+ status: "failed",
25225
+ equivalent: false,
25226
+ baseHead,
25227
+ branchHead,
25228
+ mergeBase: mergeBase || void 0,
25229
+ mergedTree: mergedTree || void 0,
25230
+ durationMs: Date.now() - startedAt,
25231
+ error: "patch equivalence preflight could not resolve merge-base or synthetic merge tree",
25232
+ stdout: truncateValidationOutput(mergeTreeStdout)
25233
+ };
24106
25234
  }
25235
+ const expectedPatchId = await computeGitPatchId(repoRoot, mergeBase, branchHead);
25236
+ const actualPatchId = await computeGitPatchId(repoRoot, baseHead, mergedTree);
25237
+ const equivalent = expectedPatchId === actualPatchId;
25238
+ return {
25239
+ status: equivalent ? "passed" : "failed",
25240
+ equivalent,
25241
+ baseHead,
25242
+ branchHead,
25243
+ mergeBase,
25244
+ mergedTree,
25245
+ expectedPatchId,
25246
+ actualPatchId,
25247
+ durationMs: Date.now() - startedAt
25248
+ };
25249
+ } catch (e) {
25250
+ return {
25251
+ status: "failed",
25252
+ equivalent: false,
25253
+ baseHead,
25254
+ branchHead,
25255
+ durationMs: Date.now() - startedAt,
25256
+ error: e?.message || String(e),
25257
+ stdout: truncateValidationOutput(e?.stdout),
25258
+ stderr: truncateValidationOutput(e?.stderr)
25259
+ };
24107
25260
  }
25261
+ }
25262
+ function buildMeshRefineValidationPlan(mesh, workspace) {
25263
+ const plan = resolveMeshRefineValidationPlan(mesh, workspace);
24108
25264
  return {
24109
- commands: selected,
24110
- rejectedCommands,
24111
- source: selected.some((command) => command.source === "mesh.policy.validationCommands") ? "mesh_policy" : selected.some((command) => command.source !== "package.json:scripts") ? "project_context" : selected.length ? "package_json_scripts" : "unavailable"
25265
+ source: plan.source,
25266
+ sourceType: plan.sourceType,
25267
+ commands: plan.commands.map((command) => ({
25268
+ displayCommand: command.displayCommand,
25269
+ category: command.category,
25270
+ source: command.source,
25271
+ cwd: command.cwd,
25272
+ timeoutMs: command.timeoutMs
25273
+ })),
25274
+ unavailableReason: plan.unavailableReason,
25275
+ rejectedCommands: plan.rejectedCommands,
25276
+ suggestions: plan.suggestions,
25277
+ suggestedConfig: plan.suggestedConfig,
25278
+ note: plan.sourceType === "unavailable" ? "No validation command will be executed until a repo mesh/refine config is provided. Heuristics are suggestions only." : "Validation commands are resolved from repo mesh/refine config; heuristics are suggestions only."
24112
25279
  };
24113
25280
  }
24114
25281
  async function runMeshRefineValidationGate(mesh, workspace) {
24115
25282
  const { execFile: execFile3 } = await import("child_process");
24116
25283
  const { promisify: promisify3 } = await import("util");
24117
25284
  const execFileAsync3 = promisify3(execFile3);
24118
- const selection = selectMeshRefineValidationCommands(mesh, workspace);
25285
+ const selection = resolveMeshRefineValidationPlan(mesh, workspace);
24119
25286
  const summary = {
24120
25287
  status: "skipped",
24121
25288
  required: true,
@@ -24123,21 +25290,27 @@ async function runMeshRefineValidationGate(mesh, workspace) {
24123
25290
  rejectedCommands: selection.rejectedCommands,
24124
25291
  skippedReason: void 0,
24125
25292
  timeoutMs: REFINE_VALIDATION_TIMEOUT_MS,
24126
- outputLimitBytes: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES
25293
+ outputLimitBytes: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES,
25294
+ configSource: selection.source,
25295
+ configSourceType: selection.sourceType,
25296
+ suggestions: selection.suggestions,
25297
+ suggestedConfig: selection.suggestedConfig
24127
25298
  };
24128
25299
  if (!selection.commands.length) {
24129
- summary.skippedReason = "validation_unavailable: no allowlisted projectContext, mesh policy, or package.json build/test/typecheck/lint command was available";
25300
+ summary.skippedReason = selection.unavailableReason || "validation_unavailable: repo mesh/refine config did not provide executable validation.commands";
24130
25301
  return summary;
24131
25302
  }
24132
25303
  for (const candidate of selection.commands) {
24133
25304
  const startedAt = Date.now();
25305
+ const cwd = candidate.cwd ? (0, import_path8.resolve)(workspace, candidate.cwd) : workspace;
25306
+ const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
24134
25307
  try {
24135
25308
  const result = await execFileAsync3(candidate.command, candidate.args, {
24136
- cwd: workspace,
25309
+ cwd,
24137
25310
  encoding: "utf8",
24138
- timeout: REFINE_VALIDATION_TIMEOUT_MS,
25311
+ timeout,
24139
25312
  maxBuffer: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES,
24140
- env: { ...process.env, CI: process.env.CI || "1" }
25313
+ env: { ...process.env, CI: process.env.CI || "1", ...candidate.env || {} }
24141
25314
  });
24142
25315
  summary.commandsRun.push({
24143
25316
  command: candidate.command,
@@ -24145,6 +25318,7 @@ async function runMeshRefineValidationGate(mesh, workspace) {
24145
25318
  displayCommand: candidate.displayCommand,
24146
25319
  category: candidate.category,
24147
25320
  source: candidate.source,
25321
+ cwd,
24148
25322
  passed: true,
24149
25323
  exitCode: 0,
24150
25324
  durationMs: Date.now() - startedAt,
@@ -24158,6 +25332,7 @@ async function runMeshRefineValidationGate(mesh, workspace) {
24158
25332
  displayCommand: candidate.displayCommand,
24159
25333
  category: candidate.category,
24160
25334
  source: candidate.source,
25335
+ cwd,
24161
25336
  passed: false,
24162
25337
  exitCode: typeof error?.code === "number" ? error.code : null,
24163
25338
  signal: typeof error?.signal === "string" ? error.signal : null,
@@ -24174,7 +25349,7 @@ async function runMeshRefineValidationGate(mesh, workspace) {
24174
25349
  return summary;
24175
25350
  }
24176
25351
  function loadYamlModule() {
24177
- return yaml;
25352
+ return yaml2;
24178
25353
  }
24179
25354
  function getMcpServersKey(format) {
24180
25355
  return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
@@ -24191,13 +25366,13 @@ function serializeMeshCoordinatorMcpConfig(config, format) {
24191
25366
  }
24192
25367
  function resolveHermesUserHome() {
24193
25368
  const explicitHome = process.env.HERMES_HOME?.trim();
24194
- return explicitHome || (0, import_path6.join)((0, import_os3.homedir)(), ".hermes");
25369
+ return explicitHome || (0, import_path8.join)((0, import_os3.homedir)(), ".hermes");
24195
25370
  }
24196
25371
  function loadHermesCoordinatorBaseConfig(targetConfigPath) {
24197
25372
  const sourceHome = resolveHermesUserHome();
24198
- const sourceConfigPath = (0, import_path6.join)(sourceHome, "config.yaml");
25373
+ const sourceConfigPath = (0, import_path8.join)(sourceHome, "config.yaml");
24199
25374
  if (!fs10.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
24200
- if ((0, import_path6.resolve)(sourceConfigPath) === (0, import_path6.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
25375
+ if ((0, import_path8.resolve)(sourceConfigPath) === (0, import_path8.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
24201
25376
  const parsed = parseMeshCoordinatorMcpConfig(fs10.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
24202
25377
  const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
24203
25378
  return { config: baseConfig, sourceHome, sourceConfigPath };
@@ -24231,10 +25406,10 @@ function stripHermesCoordinatorTempModelProviderOverrides(config) {
24231
25406
  return sanitized;
24232
25407
  }
24233
25408
  function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
24234
- if ((0, import_path6.resolve)(sourceHome) === (0, import_path6.resolve)(targetHome)) return;
25409
+ if ((0, import_path8.resolve)(sourceHome) === (0, import_path8.resolve)(targetHome)) return;
24235
25410
  for (const fileName of [".env", "auth.json"]) {
24236
- const sourcePath = (0, import_path6.join)(sourceHome, fileName);
24237
- const targetPath = (0, import_path6.join)(targetHome, fileName);
25411
+ const sourcePath = (0, import_path8.join)(sourceHome, fileName);
25412
+ const targetPath = (0, import_path8.join)(targetHome, fileName);
24238
25413
  if (!fs10.existsSync(sourcePath)) continue;
24239
25414
  try {
24240
25415
  fs10.copyFileSync(sourcePath, targetPath);
@@ -24332,36 +25507,216 @@ function summarizeSessionHostPruneResult(result) {
24332
25507
  keptCount: Array.isArray(value.keptSessionIds) ? value.keptSessionIds.length : void 0
24333
25508
  };
24334
25509
  }
25510
+ function normalizeStandaloneHostCommandUrl(hostAddress) {
25511
+ const raw = hostAddress.trim();
25512
+ if (!raw) throw new Error("hostAddress required");
25513
+ const url = new URL(raw.replace(/^ws:/, "http:").replace(/^wss:/, "https:"));
25514
+ url.pathname = "/api/v1/command";
25515
+ url.search = "";
25516
+ url.hash = "";
25517
+ return url.toString();
25518
+ }
25519
+ function buildMemberJoinNode(mesh, args, fallbackDaemonId) {
25520
+ const requestedNodeId = typeof args?.memberNodeId === "string" ? args.memberNodeId.trim() : "";
25521
+ const explicit = args?.memberNode && typeof args.memberNode === "object" && !Array.isArray(args.memberNode) ? args.memberNode : null;
25522
+ const configured = Array.isArray(mesh?.nodes) ? requestedNodeId ? mesh.nodes.find((node) => node?.id === requestedNodeId || node?.nodeId === requestedNodeId) : mesh.nodes[0] : null;
25523
+ const source = explicit || configured;
25524
+ const workspace = typeof source?.workspace === "string" && source.workspace.trim() ? source.workspace.trim() : typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : process.cwd();
25525
+ if (!workspace) return null;
25526
+ const nodeId = typeof source?.id === "string" && source.id.trim() ? source.id.trim() : typeof source?.nodeId === "string" && source.nodeId.trim() ? source.nodeId.trim() : void 0;
25527
+ return {
25528
+ ...nodeId ? { id: nodeId } : {},
25529
+ workspace,
25530
+ ...typeof source?.repoRoot === "string" && source.repoRoot.trim() ? { repoRoot: source.repoRoot.trim() } : {},
25531
+ ...typeof source?.daemonId === "string" && source.daemonId.trim() ? { daemonId: source.daemonId.trim() } : fallbackDaemonId ? { daemonId: fallbackDaemonId } : {},
25532
+ ...typeof source?.machineId === "string" && source.machineId.trim() ? { machineId: source.machineId.trim() } : {},
25533
+ userOverrides: source?.userOverrides && typeof source.userOverrides === "object" && !Array.isArray(source.userOverrides) ? source.userOverrides : {},
25534
+ policy: source?.policy && typeof source.policy === "object" && !Array.isArray(source.policy) ? source.policy : {},
25535
+ role: "member"
25536
+ };
25537
+ }
24335
25538
  var DaemonCommandRouter = class {
24336
25539
  deps;
24337
25540
  /** In-memory cache for cloud-originating meshes passed via inlineMesh.
24338
25541
  * Allows the MCP server to query mesh data via get_mesh even when
24339
25542
  * the mesh doesn't exist in the local meshes.json file. */
24340
25543
  inlineMeshCache = /* @__PURE__ */ new Map();
25544
+ /** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default. */
25545
+ aggregateMeshStatusCache = /* @__PURE__ */ new Map();
24341
25546
  constructor(deps) {
24342
25547
  this.deps = deps;
24343
25548
  }
25549
+ cloneJsonValue(value) {
25550
+ if (typeof structuredClone === "function") return structuredClone(value);
25551
+ return JSON.parse(JSON.stringify(value));
25552
+ }
25553
+ hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options) {
25554
+ if (!mesh || typeof mesh !== "object" || !Array.isArray(mesh.nodes) || !Array.isArray(snapshot?.nodes)) return snapshot;
25555
+ const inlineNodesById = /* @__PURE__ */ new Map();
25556
+ for (const node of mesh.nodes) {
25557
+ const nodeId = readInlineMeshNodeId(node);
25558
+ if (nodeId) inlineNodesById.set(nodeId, node);
25559
+ }
25560
+ if (!inlineNodesById.size) return snapshot;
25561
+ let changed = false;
25562
+ const unavailableNodeIds = /* @__PURE__ */ new Set();
25563
+ const sourceOfTruth = readObjectRecord(snapshot.sourceOfTruth);
25564
+ const directPeerTruth = readObjectRecord(sourceOfTruth.directPeerTruth);
25565
+ for (const entry of Array.isArray(directPeerTruth.unavailableNodeIds) ? directPeerTruth.unavailableNodeIds : []) {
25566
+ const nodeId = readStringValue(entry);
25567
+ if (nodeId) unavailableNodeIds.add(nodeId);
25568
+ }
25569
+ const nodes = snapshot.nodes.map((statusNode) => {
25570
+ const nodeId = readStringValue(statusNode?.nodeId, statusNode?.id);
25571
+ const inlineNode = nodeId ? inlineNodesById.get(nodeId) : void 0;
25572
+ if (!inlineNode) return statusNode;
25573
+ const liveGit = buildInlineMeshTransitGitStatus(inlineNode);
25574
+ if (!liveGit) return statusNode;
25575
+ const nextStatus = { ...statusNode };
25576
+ nextStatus.git = liveGit;
25577
+ nextStatus.health = deriveMeshNodeHealthFromGit(liveGit);
25578
+ nextStatus.launchReady = readBooleanValue(nextStatus.launchReady) ?? true;
25579
+ const connection = readObjectRecord(nextStatus.connection);
25580
+ const connectionState = readStringValue(connection.state);
25581
+ const connectionReported = readBooleanValue(connection.reported) ?? false;
25582
+ if (!connectionReported || connectionState === "unknown") {
25583
+ nextStatus.connection = buildLivePeerGitConnection(connection);
25584
+ }
25585
+ delete nextStatus.gitProbePending;
25586
+ const error = readStringValue(nextStatus.error);
25587
+ if (error && /pending_git|git probe|live peer git snapshot|no peer git snapshot/i.test(error)) delete nextStatus.error;
25588
+ if (!readStringValue(nextStatus.machineStatus)) nextStatus.machineStatus = "online";
25589
+ if (nodeId) unavailableNodeIds.delete(nodeId);
25590
+ changed = true;
25591
+ return nextStatus;
25592
+ });
25593
+ if (!changed && !(options?.requireDirectPeerTruth && unavailableNodeIds.size > 0)) return snapshot;
25594
+ const nextSourceOfTruth = {
25595
+ ...sourceOfTruth,
25596
+ ...Object.keys(directPeerTruth).length ? {
25597
+ directPeerTruth: {
25598
+ ...directPeerTruth,
25599
+ satisfied: options?.requireDirectPeerTruth === true ? unavailableNodeIds.size === 0 : directPeerTruth.satisfied,
25600
+ unavailableNodeIds: [...unavailableNodeIds]
25601
+ },
25602
+ ...options?.requireDirectPeerTruth === true ? {
25603
+ coordinatorOwnsLiveTruth: unavailableNodeIds.size === 0,
25604
+ currentStatus: unavailableNodeIds.size === 0 ? "live_git_and_session_probes" : "direct_peer_truth_unavailable"
25605
+ } : {}
25606
+ } : {}
25607
+ };
25608
+ return {
25609
+ ...snapshot,
25610
+ ...options?.requireDirectPeerTruth === true && unavailableNodeIds.size > 0 ? {
25611
+ success: false,
25612
+ code: "mesh_direct_peer_truth_unavailable",
25613
+ error: "Selected coordinator could not confirm direct mesh truth for every remote node yet."
25614
+ } : {},
25615
+ sourceOfTruth: nextSourceOfTruth,
25616
+ nodes
25617
+ };
25618
+ }
25619
+ getCachedAggregateMeshStatus(meshId, mesh, options) {
25620
+ const cached = this.aggregateMeshStatusCache.get(meshId);
25621
+ if (!cached?.snapshot || cached.snapshot.success !== true || !Array.isArray(cached.snapshot.nodes)) return null;
25622
+ let snapshot = this.cloneJsonValue(cached.snapshot);
25623
+ snapshot = this.hydrateCachedAggregateMeshStatusFromInline(snapshot, mesh, options);
25624
+ if (shouldRefreshStalePendingAggregate(snapshot, options)) return null;
25625
+ const ageMs = Math.max(0, Date.now() - cached.builtAt);
25626
+ const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
25627
+ snapshot.sourceOfTruth = {
25628
+ ...sourceOfTruth,
25629
+ aggregateSnapshot: {
25630
+ ...sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === "object" ? sourceOfTruth.aggregateSnapshot : {},
25631
+ owner: "coordinator_daemon_memory",
25632
+ cached: true,
25633
+ source: "memory",
25634
+ refreshReason: "memory_cache_hit",
25635
+ ageMs,
25636
+ cachedAt: new Date(cached.builtAt).toISOString(),
25637
+ returnedAt: (/* @__PURE__ */ new Date()).toISOString()
25638
+ }
25639
+ };
25640
+ return snapshot;
25641
+ }
25642
+ rememberAggregateMeshStatus(meshId, snapshot, refreshReason) {
25643
+ if (!snapshot || typeof snapshot !== "object" || snapshot.success !== true || !Array.isArray(snapshot.nodes)) return snapshot;
25644
+ const builtAt = Date.now();
25645
+ const next = this.cloneJsonValue(snapshot);
25646
+ const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === "object" ? next.sourceOfTruth : {};
25647
+ next.sourceOfTruth = {
25648
+ ...sourceOfTruth,
25649
+ aggregateSnapshot: {
25650
+ owner: "coordinator_daemon_memory",
25651
+ cached: false,
25652
+ source: "live_refresh",
25653
+ refreshReason,
25654
+ ageMs: 0,
25655
+ cachedAt: new Date(builtAt).toISOString(),
25656
+ returnedAt: new Date(builtAt).toISOString()
25657
+ }
25658
+ };
25659
+ this.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: this.cloneJsonValue(next) });
25660
+ return next;
25661
+ }
24344
25662
  getCachedInlineMesh(meshId, inlineMesh) {
24345
25663
  if (inlineMesh && typeof inlineMesh === "object") {
24346
- this.inlineMeshCache.set(meshId, inlineMesh);
24347
- return inlineMesh;
25664
+ return this.warmInlineMeshCache(meshId, inlineMesh);
24348
25665
  }
24349
25666
  return this.inlineMeshCache.get(meshId);
24350
25667
  }
25668
+ warmInlineMeshCache(meshId, inlineMesh) {
25669
+ if (!inlineMesh || typeof inlineMesh !== "object") return void 0;
25670
+ const sanitizedInlineMesh = sanitizeInlineMesh(inlineMesh);
25671
+ const cached = this.inlineMeshCache.get(meshId);
25672
+ if (cached) {
25673
+ const merged = reconcileInlineMeshCache(cached, sanitizedInlineMesh);
25674
+ this.inlineMeshCache.set(meshId, merged);
25675
+ return merged;
25676
+ }
25677
+ this.inlineMeshCache.set(meshId, sanitizedInlineMesh);
25678
+ return sanitizedInlineMesh;
25679
+ }
24351
25680
  async getMeshForCommand(meshId, inlineMesh, options) {
24352
25681
  const preferInline = options?.preferInline === true;
24353
25682
  if (preferInline) {
24354
- const cached2 = this.getCachedInlineMesh(meshId, inlineMesh);
24355
- if (cached2) return { mesh: cached2, inline: true };
25683
+ const cached2 = this.getCachedInlineMesh(meshId);
25684
+ if (cached2) {
25685
+ if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
25686
+ const merged = reconcileInlineMeshCache(cached2, inlineMesh);
25687
+ this.inlineMeshCache.set(meshId, sanitizeInlineMesh(merged));
25688
+ return { mesh: merged, inline: true, source: "inline_cache" };
25689
+ }
25690
+ return { mesh: cached2, inline: true, source: "inline_cache" };
25691
+ }
25692
+ if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
25693
+ this.warmInlineMeshCache(meshId, inlineMesh);
25694
+ return { mesh: inlineMesh, inline: true, source: "inline_bootstrap" };
25695
+ }
24356
25696
  }
24357
25697
  try {
24358
25698
  const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
24359
25699
  const mesh = getMesh3(meshId);
24360
- if (mesh) return { mesh, inline: false };
25700
+ if (mesh) return { mesh, inline: false, source: "local_config" };
24361
25701
  } catch {
24362
25702
  }
24363
- const cached = this.getCachedInlineMesh(meshId, inlineMesh);
24364
- return cached ? { mesh: cached, inline: true } : null;
25703
+ const cached = this.getCachedInlineMesh(meshId);
25704
+ if (cached) return { mesh: cached, inline: true, source: "inline_cache" };
25705
+ const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
25706
+ return warmedInline ? { mesh: warmedInline, inline: true, source: "inline_bootstrap" } : null;
25707
+ }
25708
+ invalidateAggregateMeshStatus(meshId) {
25709
+ this.aggregateMeshStatusCache.delete(meshId);
25710
+ }
25711
+ async requireMeshHostMutationOwner(meshId, inlineMesh, operation) {
25712
+ const meshRecord = await this.getMeshForCommand(meshId, inlineMesh, { preferInline: true });
25713
+ const mesh = meshRecord?.mesh;
25714
+ if (!mesh) return { success: false, error: "Mesh not found" };
25715
+ const meshHost = resolveMeshHostStatus(mesh);
25716
+ if (!meshHost.canOwnCoordinator || !meshHost.canOwnQueue) {
25717
+ return { ...buildMeshHostRequiredFailure(mesh, operation), success: false, meshId };
25718
+ }
25719
+ return null;
24365
25720
  }
24366
25721
  updateInlineMeshNode(meshId, mesh, node) {
24367
25722
  if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
@@ -24370,6 +25725,7 @@ var DaemonCommandRouter = class {
24370
25725
  else mesh.nodes.push(node);
24371
25726
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
24372
25727
  this.inlineMeshCache.set(meshId, mesh);
25728
+ this.invalidateAggregateMeshStatus(meshId);
24373
25729
  }
24374
25730
  removeInlineMeshNode(meshId, mesh, nodeId) {
24375
25731
  if (!mesh || !Array.isArray(mesh.nodes)) return false;
@@ -24378,6 +25734,7 @@ var DaemonCommandRouter = class {
24378
25734
  mesh.nodes.splice(idx, 1);
24379
25735
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
24380
25736
  this.inlineMeshCache.set(meshId, mesh);
25737
+ this.invalidateAggregateMeshStatus(meshId);
24381
25738
  return true;
24382
25739
  }
24383
25740
  normalizeMeshSessionCleanupMode(value) {
@@ -24426,7 +25783,7 @@ var DaemonCommandRouter = class {
24426
25783
  }
24427
25784
  const { resolveWorktreePath: resolveWorktreePath2, listWorktrees: listWorktrees2, removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
24428
25785
  const normalizePath = (value) => {
24429
- const resolved = (0, import_path6.resolve)(value);
25786
+ const resolved = (0, import_path8.resolve)(value);
24430
25787
  try {
24431
25788
  return fs10.realpathSync(resolved);
24432
25789
  } catch {
@@ -24590,6 +25947,7 @@ var DaemonCommandRouter = class {
24590
25947
  const deletedSessionIds = [];
24591
25948
  const skippedSessionIds = [];
24592
25949
  const skippedLiveSessionIds = [];
25950
+ const skippedCoordinatorSessionIds = [];
24593
25951
  const deleteUnsupportedSessionIds = [];
24594
25952
  const recordsRemainSessionIds = [];
24595
25953
  const errors = [];
@@ -24622,6 +25980,12 @@ var DaemonCommandRouter = class {
24622
25980
  const completed = this.isCompletedHostedSession(record);
24623
25981
  const surfaceKind = getSessionHostSurfaceKind(record);
24624
25982
  const liveRuntime = surfaceKind === "live_runtime";
25983
+ const coordinatorSession = readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId;
25984
+ if (!hasExplicitSessionIds && coordinatorSession) {
25985
+ skippedSessionIds.push(sessionId);
25986
+ skippedCoordinatorSessionIds.push(sessionId);
25987
+ continue;
25988
+ }
24625
25989
  if (!hasExplicitSessionIds && liveRuntime) {
24626
25990
  skippedSessionIds.push(sessionId);
24627
25991
  skippedLiveSessionIds.push(sessionId);
@@ -24687,6 +26051,7 @@ var DaemonCommandRouter = class {
24687
26051
  deletedSessionIds,
24688
26052
  skippedSessionIds,
24689
26053
  skippedLiveSessionIds,
26054
+ skippedCoordinatorSessionIds,
24690
26055
  ...deleteUnsupported ? {
24691
26056
  deleteUnsupported: true,
24692
26057
  effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
@@ -24819,7 +26184,8 @@ var DaemonCommandRouter = class {
24819
26184
  return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
24820
26185
  }
24821
26186
  case "get_pending_mesh_events": {
24822
- const events = drainPendingMeshCoordinatorEvents();
26187
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26188
+ const events = drainPendingMeshCoordinatorEvents(meshId || void 0);
24823
26189
  return { success: true, events };
24824
26190
  }
24825
26191
  case "launch_cli":
@@ -25348,15 +26714,39 @@ var DaemonCommandRouter = class {
25348
26714
  case "get_mesh": {
25349
26715
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25350
26716
  if (!meshId) return { success: false, error: "meshId required" };
25351
- try {
25352
- const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
25353
- const mesh = getMesh3(meshId);
25354
- if (mesh) return { success: true, mesh };
25355
- } catch {
26717
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
26718
+ if (!meshRecord?.mesh) return { success: false, error: "Mesh not found" };
26719
+ const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
26720
+ const directTruth = await hydrateInlineMeshDirectTruth({
26721
+ mesh: meshRecord.mesh,
26722
+ meshSource: meshRecord.source,
26723
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
26724
+ statusInstanceId: this.deps.statusInstanceId,
26725
+ localMachineId: loadConfig().machineId || ""
26726
+ });
26727
+ const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
26728
+ const sourceOfTruth = {
26729
+ membership: meshRecord.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
26730
+ coordinatorOwnsLiveTruth: directTruthSatisfied,
26731
+ directPeerTruth: {
26732
+ required: requireDirectPeerTruth,
26733
+ satisfied: directTruthSatisfied,
26734
+ directEvidenceCount: directTruth.directEvidenceCount,
26735
+ localConfirmedCount: directTruth.localConfirmedCount,
26736
+ peerAttemptedCount: directTruth.peerAttemptedCount,
26737
+ peerConfirmedCount: directTruth.peerConfirmedCount,
26738
+ unavailableNodeIds: directTruth.unavailableNodeIds
26739
+ }
26740
+ };
26741
+ if (requireDirectPeerTruth && !directTruthSatisfied) {
26742
+ return {
26743
+ success: false,
26744
+ code: "mesh_direct_peer_truth_unavailable",
26745
+ error: "Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct get_mesh probes succeed.",
26746
+ sourceOfTruth
26747
+ };
25356
26748
  }
25357
- const cached = this.inlineMeshCache.get(meshId);
25358
- if (cached) return { success: true, mesh: cached };
25359
- return { success: false, error: "Mesh not found" };
26749
+ return { success: true, mesh: meshRecord.mesh, sourceOfTruth };
25360
26750
  }
25361
26751
  case "create_mesh": {
25362
26752
  const name = typeof args?.name === "string" ? args.name.trim() : "";
@@ -25366,7 +26756,8 @@ var DaemonCommandRouter = class {
25366
26756
  if (!name) return { success: false, error: "name required" };
25367
26757
  try {
25368
26758
  const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
25369
- const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
26759
+ const meshHost = args?.meshHost && typeof args.meshHost === "object" && !Array.isArray(args.meshHost) ? args.meshHost : void 0;
26760
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy, meshHost });
25370
26761
  return { success: true, mesh };
25371
26762
  } catch (e) {
25372
26763
  return { success: false, error: e.message };
@@ -25382,15 +26773,226 @@ var DaemonCommandRouter = class {
25382
26773
  if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
25383
26774
  if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
25384
26775
  if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
26776
+ if (args?.meshHost && typeof args.meshHost === "object" && !Array.isArray(args.meshHost)) patch.meshHost = args.meshHost;
25385
26777
  if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
25386
26778
  const mesh = updateMesh2(meshId, patch);
25387
26779
  if (!mesh) return { success: false, error: "Mesh not found" };
25388
26780
  this.inlineMeshCache.set(meshId, mesh);
26781
+ this.invalidateAggregateMeshStatus(meshId);
25389
26782
  return { success: true, mesh };
25390
26783
  } catch (e) {
25391
26784
  return { success: false, error: e.message };
25392
26785
  }
25393
26786
  }
26787
+ case "get_mesh_host_pairing": {
26788
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26789
+ if (!meshId) return { success: false, error: "meshId required" };
26790
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
26791
+ const mesh = meshRecord?.mesh;
26792
+ if (!mesh) return { success: false, error: "Mesh not found" };
26793
+ const meshHost = resolveMeshHostStatus(mesh);
26794
+ const pairingStatus = meshHost.pairing?.status || "not_configured";
26795
+ return {
26796
+ success: true,
26797
+ code: pairingStatus === "not_configured" ? "mesh_host_pairing_not_configured" : "mesh_host_pairing_pending",
26798
+ meshId,
26799
+ hostAddress: meshHost.hostAddress,
26800
+ meshHost,
26801
+ manualPairing: {
26802
+ status: pairingStatus,
26803
+ joinImplemented: true,
26804
+ protocol: "standalone_command_direct_v1",
26805
+ description: "Standalone manual pairing can save address/token metadata, apply a host join over direct standalone command HTTP or injected mesh command dispatch, and check persisted status. P2P signaling remains outside this slice."
26806
+ }
26807
+ };
26808
+ }
26809
+ case "configure_mesh_host_pairing": {
26810
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26811
+ const hostAddress = typeof args?.hostAddress === "string" ? args.hostAddress.trim() : "";
26812
+ const token = typeof args?.token === "string" ? args.token.trim() : "";
26813
+ if (!meshId) return { success: false, error: "meshId required" };
26814
+ if (!hostAddress || !token) return { success: false, error: "hostAddress and token required" };
26815
+ try {
26816
+ const { configureMeshHostPairing: configureMeshHostPairing2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26817
+ const configured = configureMeshHostPairing2(meshId, { hostAddress, token });
26818
+ if (!configured) return { success: false, error: "Mesh not found" };
26819
+ this.inlineMeshCache.set(meshId, configured.mesh);
26820
+ const meshHost = resolveMeshHostStatus(configured.mesh);
26821
+ return {
26822
+ success: true,
26823
+ code: "mesh_host_pairing_pending",
26824
+ meshId,
26825
+ hostAddress: configured.hostAddress,
26826
+ meshHost,
26827
+ manualPairing: {
26828
+ status: meshHost.pairing?.status || "pairing",
26829
+ joinImplemented: true,
26830
+ protocol: "standalone_command_direct_v1",
26831
+ description: "Manual Mesh Host pairing config was saved locally. Use join_mesh_host_pairing to apply it to the host. Raw token was not persisted."
26832
+ }
26833
+ };
26834
+ } catch (e) {
26835
+ return { success: false, code: "mesh_host_pairing_invalid", meshId, hostAddress, error: e.message };
26836
+ }
26837
+ }
26838
+ case "create_mesh_host_pairing_token": {
26839
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26840
+ if (!meshId) return { success: false, error: "meshId required" };
26841
+ try {
26842
+ const { createMeshHostPairingToken: createMeshHostPairingToken2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26843
+ const created = createMeshHostPairingToken2(meshId, {
26844
+ token: typeof args?.token === "string" ? args.token : void 0,
26845
+ expiresAt: typeof args?.expiresAt === "string" ? args.expiresAt : void 0
26846
+ });
26847
+ if (!created) return { success: false, error: "Mesh not found" };
26848
+ this.inlineMeshCache.set(meshId, created.mesh);
26849
+ this.invalidateAggregateMeshStatus(meshId);
26850
+ return {
26851
+ success: true,
26852
+ code: "mesh_host_pairing_token_created",
26853
+ meshId,
26854
+ token: created.token,
26855
+ tokenId: created.tokenId,
26856
+ expiresAt: created.expiresAt,
26857
+ meshHost: resolveMeshHostStatus(created.mesh),
26858
+ warning: "Raw token is returned once and is not persisted; share it with member daemons over a trusted channel."
26859
+ };
26860
+ } catch (e) {
26861
+ return { success: false, code: "mesh_host_pairing_token_invalid", meshId, error: e.message };
26862
+ }
26863
+ }
26864
+ case "apply_mesh_host_join": {
26865
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26866
+ const token = typeof args?.token === "string" ? args.token.trim() : "";
26867
+ const memberNode = args?.memberNode && typeof args.memberNode === "object" && !Array.isArray(args.memberNode) ? args.memberNode : null;
26868
+ if (!meshId) return { success: false, error: "meshId required" };
26869
+ if (!token || !memberNode) return { success: false, error: "token and memberNode required" };
26870
+ try {
26871
+ const { applyMeshHostJoinRequest: applyMeshHostJoinRequest2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26872
+ const applied = applyMeshHostJoinRequest2(meshId, {
26873
+ token,
26874
+ memberNode,
26875
+ memberMeshId: typeof args?.memberMeshId === "string" ? args.memberMeshId : void 0
26876
+ });
26877
+ if (!applied) return { success: false, error: "Mesh not found" };
26878
+ if (!applied.accepted) {
26879
+ return {
26880
+ success: false,
26881
+ code: "mesh_host_join_rejected",
26882
+ meshId,
26883
+ tokenId: applied.tokenId,
26884
+ meshHost: applied.meshHost ? resolveMeshHostStatus({ meshHost: applied.meshHost }) : void 0,
26885
+ error: applied.reason
26886
+ };
26887
+ }
26888
+ this.inlineMeshCache.set(meshId, applied.mesh);
26889
+ this.invalidateAggregateMeshStatus(meshId);
26890
+ try {
26891
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
26892
+ appendLedgerEntry2(meshId, {
26893
+ kind: "node_joined",
26894
+ nodeId: applied.node.id,
26895
+ payload: { role: "member", tokenId: applied.tokenId, workspace: applied.node.workspace }
26896
+ });
26897
+ } catch {
26898
+ }
26899
+ return {
26900
+ success: true,
26901
+ code: "mesh_host_join_accepted",
26902
+ meshId,
26903
+ node: applied.node,
26904
+ tokenId: applied.tokenId,
26905
+ meshHost: resolveMeshHostStatus(applied.mesh)
26906
+ };
26907
+ } catch (e) {
26908
+ return { success: false, code: "mesh_host_join_failed", meshId, error: e.message };
26909
+ }
26910
+ }
26911
+ case "join_mesh_host_pairing": {
26912
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26913
+ const token = typeof args?.token === "string" ? args.token.trim() : "";
26914
+ if (!meshId) return { success: false, error: "meshId required" };
26915
+ if (!token) return { success: false, error: "token required because raw pairing tokens are not persisted" };
26916
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
26917
+ const mesh = meshRecord?.mesh;
26918
+ if (!mesh) return { success: false, error: "Mesh not found" };
26919
+ const meshHost = resolveMeshHostStatus(mesh);
26920
+ if (meshHost.role !== "member") {
26921
+ return { success: false, code: "mesh_host_join_not_member", meshId, meshHost, error: "join_mesh_host_pairing must run from a member daemon configured with a Mesh Host address/token." };
26922
+ }
26923
+ try {
26924
+ const { tokenIdForManualPairing: tokenIdForManualPairing2, markMeshHostPairingJoined: markMeshHostPairingJoined2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26925
+ const tokenId = tokenIdForManualPairing2(token);
26926
+ if (meshHost.pairing?.tokenId && meshHost.pairing.tokenId !== tokenId) {
26927
+ return { success: false, code: "mesh_host_join_rejected", meshId, tokenId, meshHost, error: "invalid pairing token" };
26928
+ }
26929
+ const memberNode = buildMemberJoinNode(mesh, args, this.deps.statusInstanceId);
26930
+ if (!memberNode) return { success: false, error: "member node metadata unavailable" };
26931
+ const hostMeshId = typeof args?.hostMeshId === "string" && args.hostMeshId.trim() ? args.hostMeshId.trim() : meshId;
26932
+ const hostDaemonId = typeof args?.hostDaemonId === "string" && args.hostDaemonId.trim() ? args.hostDaemonId.trim() : meshHost.hostDaemonId;
26933
+ let hostResult;
26934
+ let transport;
26935
+ if (hostDaemonId && this.deps.dispatchMeshCommand) {
26936
+ transport = "mesh_command_dispatch";
26937
+ hostResult = await this.deps.dispatchMeshCommand(hostDaemonId, "apply_mesh_host_join", {
26938
+ meshId: hostMeshId,
26939
+ token,
26940
+ memberMeshId: meshId,
26941
+ memberNode
26942
+ });
26943
+ } else if (meshHost.hostAddress) {
26944
+ transport = "standalone_http_command";
26945
+ const commandUrl = normalizeStandaloneHostCommandUrl(meshHost.hostAddress);
26946
+ const response = await fetch(commandUrl, {
26947
+ method: "POST",
26948
+ headers: { "Content-Type": "application/json" },
26949
+ body: JSON.stringify({ type: "apply_mesh_host_join", payload: { meshId: hostMeshId, token, memberMeshId: meshId, memberNode } })
26950
+ });
26951
+ hostResult = await response.json().catch(() => ({ success: false, error: `Host returned HTTP ${response.status}` }));
26952
+ if (!response.ok && hostResult?.success !== false) hostResult = { success: false, error: `Host returned HTTP ${response.status}` };
26953
+ } else {
26954
+ return {
26955
+ success: false,
26956
+ code: "mesh_host_join_transport_unavailable",
26957
+ meshId,
26958
+ meshHost,
26959
+ error: "No hostDaemonId dispatch path or hostAddress HTTP command path is available. P2P signaling join is not implemented in this slice."
26960
+ };
26961
+ }
26962
+ if (!hostResult?.success) {
26963
+ return { success: false, code: hostResult?.code || "mesh_host_join_rejected", meshId, meshHost, transport, error: hostResult?.error || "Mesh Host rejected join request", hostResult };
26964
+ }
26965
+ const joined = meshRecord.inline ? null : markMeshHostPairingJoined2(meshId, {
26966
+ tokenId: hostResult.tokenId || tokenId,
26967
+ hostDaemonId: hostResult.meshHost?.hostDaemonId || hostDaemonId,
26968
+ hostNodeId: hostResult.meshHost?.hostNodeId,
26969
+ joinedAt: hostResult.meshHost?.pairing?.joinedAt
26970
+ });
26971
+ if (joined) {
26972
+ this.inlineMeshCache.set(meshId, joined.mesh);
26973
+ this.invalidateAggregateMeshStatus(meshId);
26974
+ }
26975
+ return {
26976
+ success: true,
26977
+ code: "mesh_host_join_applied",
26978
+ meshId,
26979
+ hostMeshId,
26980
+ transport,
26981
+ node: hostResult.node,
26982
+ tokenId: hostResult.tokenId || tokenId,
26983
+ meshHost: joined ? resolveMeshHostStatus(joined.mesh) : { ...meshHost, pairing: { ...meshHost.pairing || {}, status: "paired", tokenId: hostResult.tokenId || tokenId } },
26984
+ hostResult,
26985
+ manualPairing: {
26986
+ status: "paired",
26987
+ joinImplemented: true,
26988
+ protocol: "standalone_command_direct_v1",
26989
+ description: "Mesh Host accepted the join and local member pairing status was marked paired. P2P runtime signaling remains outside this slice."
26990
+ }
26991
+ };
26992
+ } catch (e) {
26993
+ return { success: false, code: "mesh_host_join_failed", meshId, meshHost, error: e.message };
26994
+ }
26995
+ }
25394
26996
  case "delete_mesh": {
25395
26997
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25396
26998
  if (!meshId) return { success: false, error: "meshId required" };
@@ -25473,6 +27075,8 @@ var DaemonCommandRouter = class {
25473
27075
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25474
27076
  const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
25475
27077
  if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
27078
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue cancellation");
27079
+ if (ownerFailure) return ownerFailure;
25476
27080
  try {
25477
27081
  const { cancelTask: cancelTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
25478
27082
  const reason = typeof args?.reason === "string" ? args.reason : void 0;
@@ -25487,6 +27091,8 @@ var DaemonCommandRouter = class {
25487
27091
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25488
27092
  const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
25489
27093
  if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
27094
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue requeue");
27095
+ if (ownerFailure) return ownerFailure;
25490
27096
  try {
25491
27097
  const { requeueTask: requeueTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
25492
27098
  const task = requeueTask2(meshId, taskId, {
@@ -25507,6 +27113,8 @@ var DaemonCommandRouter = class {
25507
27113
  const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
25508
27114
  if (!meshId) return { success: false, error: "meshId required" };
25509
27115
  if (!workspace) return { success: false, error: "workspace required" };
27116
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node addition");
27117
+ if (ownerFailure) return ownerFailure;
25510
27118
  try {
25511
27119
  const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
25512
27120
  const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
@@ -25515,7 +27123,8 @@ var DaemonCommandRouter = class {
25515
27123
  ...readOnly ? { readOnly: true } : {},
25516
27124
  ...providerPriority.length ? { providerPriority } : {}
25517
27125
  };
25518
- const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
27126
+ const role = normalizeMeshDaemonRole(args?.role);
27127
+ const node = addNode3(meshId, { workspace, ...policy ? { policy } : {}, ...role ? { role } : {} });
25519
27128
  if (!node) return { success: false, error: "Mesh not found" };
25520
27129
  return { success: true, node };
25521
27130
  } catch (e) {
@@ -25526,6 +27135,8 @@ var DaemonCommandRouter = class {
25526
27135
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25527
27136
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
25528
27137
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
27138
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node update");
27139
+ if (ownerFailure) return ownerFailure;
25529
27140
  try {
25530
27141
  const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
25531
27142
  const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
@@ -25549,6 +27160,8 @@ var DaemonCommandRouter = class {
25549
27160
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25550
27161
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
25551
27162
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
27163
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node removal");
27164
+ if (ownerFailure) return ownerFailure;
25552
27165
  try {
25553
27166
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
25554
27167
  const mesh = meshRecord?.mesh;
@@ -25571,30 +27184,88 @@ var DaemonCommandRouter = class {
25571
27184
  return { success: false, error: e.message };
25572
27185
  }
25573
27186
  }
27187
+ case "get_mesh_refine_config_schema": {
27188
+ return {
27189
+ success: true,
27190
+ schema: MESH_REFINE_CONFIG_SCHEMA,
27191
+ locations: MESH_REFINE_CONFIG_LOCATIONS,
27192
+ sourceOfTruth: "repo mesh/refine config",
27193
+ heuristicRole: "suggestions_only_not_execution_path"
27194
+ };
27195
+ }
27196
+ case "validate_mesh_refine_config": {
27197
+ const workspace = typeof args?.workspace === "string" ? args.workspace : process.cwd();
27198
+ const mesh = args?.inlineMesh || {};
27199
+ const loaded = args?.config !== void 0 ? { config: args.config, source: "inline", sourceType: "mesh_policy" } : loadMeshRefineConfig(mesh, workspace);
27200
+ const validation = loaded.config ? validateMeshRefineConfig(loaded.config, loaded.source) : { valid: false, errors: [loaded.error || "repo mesh/refine config unavailable"], commands: [], rejectedCommands: [] };
27201
+ return { success: validation.valid, ...loaded, ...validation };
27202
+ }
27203
+ case "suggest_mesh_refine_config": {
27204
+ const workspace = typeof args?.workspace === "string" ? args.workspace : process.cwd();
27205
+ const mesh = args?.inlineMesh || {};
27206
+ return {
27207
+ success: true,
27208
+ ...suggestMeshRefineConfig(mesh, workspace),
27209
+ note: "Suggestions are heuristic scaffold only; Refinery will not execute them until saved into repo mesh/refine config."
27210
+ };
27211
+ }
27212
+ case "plan_mesh_refine_node": {
27213
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
27214
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
27215
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
27216
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
27217
+ const mesh = meshRecord?.mesh;
27218
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
27219
+ if (!node?.workspace) return { success: false, error: `Node '${nodeId}' workspace not found` };
27220
+ return {
27221
+ success: true,
27222
+ dryRun: true,
27223
+ nodeId,
27224
+ workspace: node.workspace,
27225
+ validationPlan: buildMeshRefineValidationPlan(mesh, node.workspace),
27226
+ mergeWillRun: false,
27227
+ cleanupWillRun: false
27228
+ };
27229
+ }
25574
27230
  case "refine_mesh_node": {
25575
27231
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25576
27232
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
25577
27233
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
27234
+ const refineStages = [];
25578
27235
  try {
25579
27236
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
25580
27237
  const mesh = meshRecord?.mesh;
25581
27238
  const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
25582
- if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh` };
27239
+ if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh`, refineStages };
25583
27240
  if (!node.isLocalWorktree || !node.workspace) {
25584
- return { success: false, error: `Refinery requires a local worktree node` };
27241
+ return { success: false, error: `Refinery requires a local worktree node`, refineStages };
25585
27242
  }
25586
27243
  const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
25587
27244
  const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
25588
- if (!repoRoot) return { success: false, error: "Source node repoRoot not found" };
27245
+ if (!repoRoot) return { success: false, error: "Source node repoRoot not found", refineStages };
25589
27246
  const { execFile: execFile3 } = await import("child_process");
25590
27247
  const { promisify: promisify3 } = await import("util");
25591
27248
  const execFileAsync3 = promisify3(execFile3);
27249
+ const resolveStarted = Date.now();
25592
27250
  const { stdout: branchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: node.workspace, encoding: "utf8" });
25593
27251
  const branch = branchStdout.trim();
25594
- if (!branch) return { success: false, error: "Could not determine branch of the worktree node" };
27252
+ if (!branch) return { success: false, error: "Could not determine branch of the worktree node", refineStages };
25595
27253
  const { stdout: baseBranchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
25596
27254
  const baseBranch = baseBranchStdout.trim();
27255
+ const { stdout: baseHeadStdout } = await execFileAsync3("git", ["rev-parse", "HEAD"], { cwd: repoRoot, encoding: "utf8" });
27256
+ const { stdout: branchHeadStdout } = await execFileAsync3("git", ["rev-parse", branch], { cwd: node.workspace, encoding: "utf8" });
27257
+ const baseHead = baseHeadStdout.trim();
27258
+ const branchHead = branchHeadStdout.trim();
27259
+ recordMeshRefineStage(refineStages, "resolve_refs", "passed", resolveStarted, { branch, baseBranch, baseHead, branchHead });
27260
+ const validationStarted = Date.now();
25597
27261
  const validationSummary = await runMeshRefineValidationGate(mesh, node.workspace);
27262
+ recordMeshRefineStage(
27263
+ refineStages,
27264
+ "validation",
27265
+ validationSummary.status === "passed" ? "passed" : validationSummary.status === "failed" ? "failed" : "skipped",
27266
+ validationStarted,
27267
+ { validationStatus: validationSummary.status, commandsRun: validationSummary.commandsRun.length }
27268
+ );
25598
27269
  if (validationSummary.status === "failed") {
25599
27270
  return {
25600
27271
  success: false,
@@ -25604,6 +27275,7 @@ var DaemonCommandRouter = class {
25604
27275
  branch,
25605
27276
  into: baseBranch,
25606
27277
  validationSummary,
27278
+ refineStages,
25607
27279
  finalBranchConvergenceState: {
25608
27280
  branch,
25609
27281
  baseBranch,
@@ -25623,6 +27295,7 @@ var DaemonCommandRouter = class {
25623
27295
  branch,
25624
27296
  into: baseBranch,
25625
27297
  validationSummary,
27298
+ refineStages,
25626
27299
  finalBranchConvergenceState: {
25627
27300
  branch,
25628
27301
  baseBranch,
@@ -25633,37 +27306,121 @@ var DaemonCommandRouter = class {
25633
27306
  }
25634
27307
  };
25635
27308
  }
27309
+ const patchEquivalenceStarted = Date.now();
27310
+ const patchEquivalence = await runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead);
27311
+ recordMeshRefineStage(refineStages, "patch_equivalence", patchEquivalence.status, patchEquivalenceStarted, {
27312
+ equivalent: patchEquivalence.equivalent,
27313
+ expectedPatchId: patchEquivalence.expectedPatchId,
27314
+ actualPatchId: patchEquivalence.actualPatchId,
27315
+ error: patchEquivalence.error
27316
+ });
27317
+ if (!patchEquivalence.equivalent) {
27318
+ return {
27319
+ success: false,
27320
+ code: "patch_equivalence_failed",
27321
+ convergenceStatus: "blocked_review",
27322
+ error: "Refinery patch-equivalence preflight failed; merge/refine was not attempted.",
27323
+ branch,
27324
+ into: baseBranch,
27325
+ validationSummary,
27326
+ patchEquivalence,
27327
+ refineStages,
27328
+ finalBranchConvergenceState: {
27329
+ branch,
27330
+ baseBranch,
27331
+ merged: false,
27332
+ removed: false,
27333
+ validation: "passed",
27334
+ patchEquivalence: "failed",
27335
+ status: "blocked_review"
27336
+ }
27337
+ };
27338
+ }
27339
+ let mergeResult;
27340
+ const mergeStarted = Date.now();
25636
27341
  try {
25637
- await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
27342
+ const result = await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
27343
+ mergeResult = {
27344
+ stdout: truncateValidationOutput(result.stdout),
27345
+ stderr: truncateValidationOutput(result.stderr),
27346
+ durationMs: Date.now() - mergeStarted
27347
+ };
27348
+ recordMeshRefineStage(refineStages, "merge", "passed", mergeStarted, mergeResult);
25638
27349
  } catch (e) {
27350
+ recordMeshRefineStage(refineStages, "merge", "failed", mergeStarted, {
27351
+ error: e?.message || String(e),
27352
+ stdout: truncateValidationOutput(e?.stdout),
27353
+ stderr: truncateValidationOutput(e?.stderr)
27354
+ });
25639
27355
  return {
25640
27356
  success: false,
25641
27357
  error: `Merge failed (conflicts?): ${e.message}`,
25642
27358
  validationSummary,
27359
+ patchEquivalence,
27360
+ refineStages,
25643
27361
  finalBranchConvergenceState: {
25644
27362
  branch,
25645
27363
  baseBranch,
25646
27364
  merged: false,
25647
27365
  removed: false,
25648
27366
  validation: "passed",
27367
+ patchEquivalence: "passed",
25649
27368
  status: "not_mergeable"
25650
27369
  }
25651
27370
  };
25652
27371
  }
27372
+ const cleanupStarted = Date.now();
25653
27373
  const removeResult = await this.execute("remove_mesh_node", {
25654
27374
  meshId,
25655
27375
  nodeId,
25656
- sessionCleanupMode: "kill",
27376
+ sessionCleanupMode: "preserve",
25657
27377
  inlineMesh: args?.inlineMesh
25658
27378
  });
27379
+ recordMeshRefineStage(refineStages, "cleanup", removeResult?.success === false ? "failed" : "passed", cleanupStarted, {
27380
+ removed: removeResult?.removed,
27381
+ code: removeResult?.code,
27382
+ error: removeResult?.error
27383
+ });
27384
+ let ledgerError;
27385
+ const ledgerStarted = Date.now();
25659
27386
  try {
25660
27387
  const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
25661
27388
  appendLedgerEntry2(meshId, {
25662
27389
  kind: "node_removed",
25663
27390
  nodeId,
25664
- payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary }
27391
+ payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary, patchEquivalence }
25665
27392
  });
25666
- } catch {
27393
+ recordMeshRefineStage(refineStages, "ledger", "passed", ledgerStarted);
27394
+ } catch (e) {
27395
+ ledgerError = e?.message || String(e);
27396
+ recordMeshRefineStage(refineStages, "ledger", "failed", ledgerStarted, { error: ledgerError });
27397
+ }
27398
+ const finalBranchConvergenceState = {
27399
+ branch: baseBranch,
27400
+ mergedBranch: branch,
27401
+ baseBranch,
27402
+ merged: true,
27403
+ removed: removeResult?.success !== false,
27404
+ validation: "passed",
27405
+ patchEquivalence: "passed",
27406
+ status: removeResult?.success === false ? "merged_cleanup_failed" : "merged"
27407
+ };
27408
+ if (removeResult?.success === false) {
27409
+ return {
27410
+ success: false,
27411
+ code: "cleanup_failed",
27412
+ error: "Refinery merge completed but worktree cleanup failed; manual cleanup/retry is required.",
27413
+ merged: true,
27414
+ branch,
27415
+ into: baseBranch,
27416
+ removeResult,
27417
+ validationSummary,
27418
+ patchEquivalence,
27419
+ mergeResult,
27420
+ refineStages,
27421
+ ...ledgerError ? { ledgerError } : {},
27422
+ finalBranchConvergenceState
27423
+ };
25667
27424
  }
25668
27425
  return {
25669
27426
  success: true,
@@ -25672,18 +27429,14 @@ var DaemonCommandRouter = class {
25672
27429
  into: baseBranch,
25673
27430
  removeResult,
25674
27431
  validationSummary,
25675
- finalBranchConvergenceState: {
25676
- branch: baseBranch,
25677
- mergedBranch: branch,
25678
- baseBranch,
25679
- merged: true,
25680
- removed: removeResult?.success !== false,
25681
- validation: "passed",
25682
- status: removeResult?.success === false ? "merged_cleanup_failed" : "merged"
25683
- }
27432
+ patchEquivalence,
27433
+ mergeResult,
27434
+ refineStages,
27435
+ ...ledgerError ? { ledgerError } : {},
27436
+ finalBranchConvergenceState
25684
27437
  };
25685
27438
  } catch (e) {
25686
- return { success: false, error: e.message };
27439
+ return { success: false, error: e.message, refineStages };
25687
27440
  }
25688
27441
  }
25689
27442
  case "remove_mesh_node": {
@@ -25724,6 +27477,7 @@ var DaemonCommandRouter = class {
25724
27477
  } else {
25725
27478
  const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
25726
27479
  removed = removeNode3(meshId, nodeId);
27480
+ if (removed) this.invalidateAggregateMeshStatus(meshId);
25727
27481
  }
25728
27482
  if (removed) {
25729
27483
  try {
@@ -25758,6 +27512,8 @@ var DaemonCommandRouter = class {
25758
27512
  if (!meshId) return { success: false, error: "meshId required" };
25759
27513
  if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
25760
27514
  if (!branch) return { success: false, error: "branch required" };
27515
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "worktree clone");
27516
+ if (ownerFailure) return ownerFailure;
25761
27517
  try {
25762
27518
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
25763
27519
  const mesh = meshRecord?.mesh;
@@ -25802,6 +27558,7 @@ var DaemonCommandRouter = class {
25802
27558
  policy: { ...sourceNode.policy || {} }
25803
27559
  });
25804
27560
  if (!node) return { success: false, error: "Failed to register worktree node" };
27561
+ this.invalidateAggregateMeshStatus(meshId);
25805
27562
  }
25806
27563
  const initSubmodules = sourceNode.policy?.initSubmodulesOnClone !== false;
25807
27564
  if (initSubmodules) {
@@ -25838,6 +27595,8 @@ var DaemonCommandRouter = class {
25838
27595
  case "trigger_mesh_queue": {
25839
27596
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25840
27597
  if (!meshId) return { success: false, error: "meshId required" };
27598
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue trigger");
27599
+ if (ownerFailure) return ownerFailure;
25841
27600
  try {
25842
27601
  const { triggerMeshQueue: triggerMeshQueue2 } = await Promise.resolve().then(() => (init_mesh_events(), mesh_events_exports));
25843
27602
  if (meshId) {
@@ -25864,6 +27623,15 @@ var DaemonCommandRouter = class {
25864
27623
  mesh = getMesh3(meshId);
25865
27624
  }
25866
27625
  if (!mesh) return { success: false, error: "Mesh not found" };
27626
+ const meshHost = resolveMeshHostStatus(mesh);
27627
+ if (!meshHost.canOwnCoordinator) {
27628
+ return {
27629
+ success: false,
27630
+ ...buildMeshHostRequiredFailure(mesh, "coordinator launch"),
27631
+ meshId,
27632
+ cliType
27633
+ };
27634
+ }
25867
27635
  if (!Array.isArray(mesh.nodes) || mesh.nodes.length === 0) return { success: false, error: "No nodes in mesh" };
25868
27636
  const requestedCoordinatorNodeId = typeof args?.coordinatorNodeId === "string" ? args.coordinatorNodeId.trim() : "";
25869
27637
  const preferredCoordinatorNodeId = requestedCoordinatorNodeId || (typeof mesh.coordinator?.preferredNodeId === "string" ? mesh.coordinator.preferredNodeId.trim() : "");
@@ -25877,7 +27645,14 @@ var DaemonCommandRouter = class {
25877
27645
  cliType
25878
27646
  };
25879
27647
  }
25880
- const workspace = typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "";
27648
+ const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
27649
+ const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
27650
+ const workspace = readLiveMeshNodeWorkspace({
27651
+ meshId,
27652
+ nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || ""),
27653
+ liveSessionRecords: liveMeshSessions,
27654
+ allowCoordinatorSession: true
27655
+ }) || (typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "");
25881
27656
  if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
25882
27657
  if (!cliType) {
25883
27658
  const resolved = await resolveProviderTypeFromPriority({
@@ -26039,7 +27814,7 @@ ${block}`);
26039
27814
  workspace
26040
27815
  };
26041
27816
  }
26042
- const { existsSync: existsSync25, readFileSync: readFileSync17, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
27817
+ const { existsSync: existsSync27, readFileSync: readFileSync19, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
26043
27818
  const { dirname: dirname9 } = await import("path");
26044
27819
  const mcpConfigPath = coordinatorSetup.configPath;
26045
27820
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
@@ -26082,14 +27857,14 @@ ${block}`);
26082
27857
  if (hermesManualFallback) return returnManualFallback(message);
26083
27858
  return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
26084
27859
  }
26085
- const hadExistingMcpConfig = existsSync25(mcpConfigPath);
27860
+ const hadExistingMcpConfig = existsSync27(mcpConfigPath);
26086
27861
  let existingMcpConfig = hermesBaseConfig?.config || {};
26087
27862
  if (hermesBaseConfig) {
26088
27863
  copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
26089
27864
  }
26090
27865
  if (hadExistingMcpConfig) {
26091
27866
  try {
26092
- const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync17(mcpConfigPath, "utf-8"), configFormat);
27867
+ const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync19(mcpConfigPath, "utf-8"), configFormat);
26093
27868
  const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
26094
27869
  existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
26095
27870
  copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
@@ -26179,62 +27954,321 @@ ${block}`);
26179
27954
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
26180
27955
  const mesh = meshRecord?.mesh;
26181
27956
  if (!mesh) return { success: false, error: "Mesh not found" };
27957
+ const meshHost = resolveMeshHostStatus(mesh);
27958
+ const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
27959
+ const hadAggregateCache = this.aggregateMeshStatusCache.has(meshId);
27960
+ if (!refreshRequested) {
27961
+ const cachedStatus = this.getCachedAggregateMeshStatus(meshId, mesh, { requireDirectPeerTruth: args?.requireDirectPeerTruth === true });
27962
+ if (cachedStatus) {
27963
+ logRepoMeshStatusDebug("return_cached", {
27964
+ meshId,
27965
+ command: "mesh_status",
27966
+ refreshRequested,
27967
+ summary: summarizeRepoMeshStatusDebug(cachedStatus)
27968
+ });
27969
+ return cachedStatus;
27970
+ }
27971
+ }
27972
+ const refreshReason = refreshRequested ? "explicit_refresh" : hadAggregateCache ? "stale_pending_cache_refresh" : "cold_cache_miss";
26182
27973
  const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
26183
27974
  const queue = getQueue2(meshId);
26184
27975
  const queueSummary = getMeshQueueStats2(meshId);
26185
27976
  const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
26186
27977
  const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
26187
27978
  const ledgerSummary = getLedgerSummary2(meshId);
27979
+ const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
27980
+ const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
27981
+ const localMachineId = loadConfig().machineId || "";
27982
+ const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
27983
+ const directTruth = requireDirectPeerTruth ? await hydrateInlineMeshDirectTruth({
27984
+ mesh,
27985
+ meshSource: meshRecord.source,
27986
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
27987
+ statusInstanceId: this.deps.statusInstanceId,
27988
+ localMachineId
27989
+ }) : {
27990
+ directEvidenceCount: 0,
27991
+ localConfirmedCount: 0,
27992
+ peerAttemptedCount: 0,
27993
+ peerConfirmedCount: 0,
27994
+ unavailableNodeIds: []
27995
+ };
27996
+ const passivePeerTruthNotAttempted = requireDirectPeerTruth && !refreshRequested && directTruth.directEvidenceCount > 0 && directTruth.peerAttemptedCount === 0;
27997
+ const effectiveDirectTruth = passivePeerTruthNotAttempted ? { ...directTruth, unavailableNodeIds: [] } : directTruth;
27998
+ const directTruthSatisfied = !requireDirectPeerTruth || effectiveDirectTruth.directEvidenceCount > 0 && effectiveDirectTruth.unavailableNodeIds.length === 0;
27999
+ if (requireDirectPeerTruth && !directTruthSatisfied) {
28000
+ const failureResult = {
28001
+ success: false,
28002
+ code: "mesh_direct_peer_truth_unavailable",
28003
+ error: "Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct mesh_status probes succeed.",
28004
+ sourceOfTruth: {
28005
+ membership: meshRecord.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
28006
+ coordinatorOwnsLiveTruth: false,
28007
+ currentStatus: "direct_peer_truth_unavailable",
28008
+ directPeerTruth: {
28009
+ required: true,
28010
+ satisfied: false,
28011
+ directEvidenceCount: directTruth.directEvidenceCount,
28012
+ localConfirmedCount: directTruth.localConfirmedCount,
28013
+ peerAttemptedCount: directTruth.peerAttemptedCount,
28014
+ peerConfirmedCount: directTruth.peerConfirmedCount,
28015
+ unavailableNodeIds: directTruth.unavailableNodeIds
28016
+ }
28017
+ }
28018
+ };
28019
+ logRepoMeshStatusDebug("direct_truth_unavailable", {
28020
+ meshId,
28021
+ command: "mesh_status",
28022
+ refreshRequested,
28023
+ meshSource: meshRecord.source,
28024
+ directTruth
28025
+ });
28026
+ return failureResult;
28027
+ }
28028
+ const directTruthUnavailableNodeIds = new Set(effectiveDirectTruth.unavailableNodeIds);
28029
+ const selectedCoordinatorNodeId = readStringValue(
28030
+ mesh.coordinator?.preferredNodeId,
28031
+ mesh.nodes?.[0]?.id,
28032
+ mesh.nodes?.[0]?.nodeId
28033
+ );
28034
+ const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes) ? selectedCoordinatorNodeId : void 0;
28035
+ const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
26188
28036
  const nodeStatuses = [];
26189
- for (const node of mesh.nodes || []) {
28037
+ for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
28038
+ const nodeId = String(node.id || node.nodeId || "");
28039
+ const daemonId = readStringValue(node.daemonId);
28040
+ const providerPriority = readProviderPriorityFromPolicy(node.policy);
28041
+ const isSelfNode = Boolean(
28042
+ nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
28043
+ ) || Boolean(
28044
+ daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
28045
+ ) || Boolean(meshRecord?.inline && nodeIndex === 0);
26190
28046
  const status = {
26191
- nodeId: node.id || node.nodeId,
28047
+ nodeId,
26192
28048
  machineLabel: node.machineLabel || node.id || node.nodeId,
26193
28049
  workspace: node.workspace,
26194
28050
  repoRoot: node.repoRoot,
26195
28051
  isLocalWorktree: node.isLocalWorktree,
26196
28052
  worktreeBranch: node.worktreeBranch,
26197
- daemonId: node.daemonId,
28053
+ role: normalizeMeshDaemonRole(node.role) || (meshHost.hostNodeId && nodeId === meshHost.hostNodeId ? "host" : void 0),
28054
+ daemonId,
26198
28055
  machineId: node.machineId,
28056
+ machineStatus: node.machineStatus,
26199
28057
  health: "unknown",
26200
28058
  providers: node.providers || [],
26201
- activeSessions: []
28059
+ providerPriority,
28060
+ activeSessions: [],
28061
+ activeSessionDetails: [],
28062
+ launchReady: false
26202
28063
  };
26203
- if (node.workspace && typeof node.workspace === "string") {
26204
- if (!fs10.existsSync(node.workspace) && applyCachedInlineMeshNodeStatus(status, node)) {
26205
- nodeStatuses.push(status);
26206
- continue;
28064
+ if (isSelfNode) {
28065
+ status.connection = {
28066
+ perspective: "selected_coordinator",
28067
+ source: "mesh_peer_status",
28068
+ state: "self",
28069
+ transport: "local",
28070
+ reported: true,
28071
+ reason: "Selected coordinator daemon",
28072
+ lastStateChangeAt: refreshedAt
28073
+ };
28074
+ } else if (daemonId) {
28075
+ const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
28076
+ status.connection = connection ?? {
28077
+ perspective: "selected_coordinator",
28078
+ source: "not_reported",
28079
+ state: "unknown",
28080
+ transport: "unknown",
28081
+ reported: false,
28082
+ reason: "No live mesh peer telemetry reported by the selected coordinator yet."
28083
+ };
28084
+ } else {
28085
+ status.connection = {
28086
+ perspective: "selected_coordinator",
28087
+ source: "not_reported",
28088
+ state: "unknown",
28089
+ transport: "unknown",
28090
+ reported: false,
28091
+ reason: "Node has no daemon id, so mesh transport cannot be reported from the selected coordinator."
28092
+ };
28093
+ }
28094
+ const matchedLiveSessionRecords = collectLiveMeshSessionRecords({
28095
+ meshId,
28096
+ node,
28097
+ nodeId,
28098
+ liveSessionRecords: liveMeshSessions,
28099
+ allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
28100
+ });
28101
+ const workspace = readLiveMeshNodeWorkspace({
28102
+ meshId,
28103
+ nodeId,
28104
+ liveSessionRecords: matchedLiveSessionRecords,
28105
+ allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
28106
+ }) || (typeof node.workspace === "string" ? node.workspace : "");
28107
+ status.workspace = workspace || node.workspace;
28108
+ if (matchedLiveSessionRecords.length > 0) {
28109
+ const sessionIds = matchedLiveSessionRecords.map((record) => typeof record?.sessionId === "string" ? record.sessionId : "").filter(Boolean);
28110
+ const providerTypes = matchedLiveSessionRecords.map((record) => readStringValue(record?.providerType)).filter(Boolean);
28111
+ status.activeSessions = sessionIds;
28112
+ status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
28113
+ if (providerTypes.length > 0) {
28114
+ status.providers = Array.from(/* @__PURE__ */ new Set([...Array.isArray(status.providers) ? status.providers : [], ...providerTypes]));
26207
28115
  }
26208
- try {
26209
- const gitStatus = await getGitRepoStatus(node.workspace, { timeoutMs: 1e4 });
26210
- status.git = gitStatus;
26211
- if (gitStatus.isGitRepo) {
26212
- const dirty = gitStatus.staged + gitStatus.modified + gitStatus.untracked + gitStatus.deleted + gitStatus.renamed > 0;
26213
- status.health = gitStatus.branch ? dirty ? "dirty" : "online" : "degraded";
26214
- } else {
26215
- status.health = "degraded";
26216
- if (gitStatus.error && !status.error) status.error = gitStatus.error;
28116
+ }
28117
+ if (workspace) {
28118
+ if (!fs10.existsSync(workspace)) {
28119
+ const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
28120
+ let remoteProbeApplied = false;
28121
+ if (inlineTransitGit) {
28122
+ status.git = inlineTransitGit;
28123
+ status.health = inlineTransitGit.isGitRepo ? deriveMeshNodeHealthFromGit(inlineTransitGit) : "degraded";
28124
+ const connection = readObjectRecord(status.connection);
28125
+ const connectionState = readStringValue(connection.state);
28126
+ const connectionReported = readBooleanValue(connection.reported) ?? false;
28127
+ if (!connectionReported || connectionState === "unknown") {
28128
+ status.connection = buildLivePeerGitConnection(connection, refreshedAt);
28129
+ }
28130
+ remoteProbeApplied = true;
28131
+ } else if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand && !directTruthUnavailableNodeIds.has(nodeId)) {
28132
+ try {
28133
+ const remoteGit = await probeRemoteMeshGitStatus({
28134
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
28135
+ daemonId,
28136
+ workspace,
28137
+ timeoutMs: 8e3
28138
+ });
28139
+ if (remoteGit) {
28140
+ status.git = remoteGit;
28141
+ status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
28142
+ const connection = readObjectRecord(status.connection);
28143
+ const connectionState = readStringValue(connection.state);
28144
+ const connectionReported = readBooleanValue(connection.reported) ?? false;
28145
+ if (!connectionReported || connectionState === "unknown") {
28146
+ status.connection = buildLivePeerGitConnection(connection, refreshedAt);
28147
+ }
28148
+ recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
28149
+ remoteProbeApplied = true;
28150
+ }
28151
+ } catch {
28152
+ const refreshedConnection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
28153
+ const refreshedConnectionState = readStringValue(refreshedConnection?.state);
28154
+ if (refreshedConnection && refreshedConnectionState === "connected") {
28155
+ status.connection = refreshedConnection;
28156
+ try {
28157
+ const remoteGit = await probeRemoteMeshGitStatus({
28158
+ dispatchMeshCommand: this.deps.dispatchMeshCommand,
28159
+ daemonId,
28160
+ workspace,
28161
+ timeoutMs: 12e3
28162
+ });
28163
+ if (remoteGit) {
28164
+ status.git = remoteGit;
28165
+ status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
28166
+ const connection = readObjectRecord(status.connection);
28167
+ const connectionState = readStringValue(connection.state);
28168
+ const connectionReported = readBooleanValue(connection.reported) ?? false;
28169
+ if (!connectionReported || connectionState === "unknown") {
28170
+ status.connection = buildLivePeerGitConnection(connection, refreshedAt);
28171
+ }
28172
+ recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
28173
+ remoteProbeApplied = true;
28174
+ }
28175
+ } catch {
28176
+ }
28177
+ }
28178
+ }
26217
28179
  }
26218
- } catch {
26219
- if (!applyCachedInlineMeshNodeStatus(status, node)) {
26220
- status.health = "degraded";
28180
+ if (!remoteProbeApplied) {
28181
+ const connectionState = readStringValue(status.connection?.state);
28182
+ const pendingPeerGitProbe = !inlineTransitGit && !isSelfNode && !!daemonId && (readStringValue(status.machineStatus) === "online" || readStringValue(status.health) === "online" || connectionState === "connecting" || connectionState === "connected" || connectionState === "unknown");
28183
+ if (pendingPeerGitProbe) {
28184
+ status.gitProbePending = true;
28185
+ status.health = "unknown";
28186
+ }
28187
+ if (applyCachedInlineMeshNodeStatus(
28188
+ status,
28189
+ node,
28190
+ pendingPeerGitProbe ? { skipGit: true, skipError: true, skipHealth: true } : void 0
28191
+ )) {
28192
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
28193
+ nodeStatuses.push(status);
28194
+ continue;
28195
+ }
28196
+ if (meshRecord?.source === "inline_cache" && !isSelfNode) {
28197
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
28198
+ nodeStatuses.push(status);
28199
+ continue;
28200
+ }
28201
+ }
28202
+ } else {
28203
+ try {
28204
+ const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
28205
+ status.git = gitStatus;
28206
+ recordInlineMeshDirectGitTruth(node, gitStatus, "selected_coordinator_local_git");
28207
+ if (gitStatus.isGitRepo) {
28208
+ status.health = deriveMeshNodeHealthFromGit(gitStatus);
28209
+ } else {
28210
+ status.health = "degraded";
28211
+ if (gitStatus.error && !status.error) status.error = gitStatus.error;
28212
+ }
28213
+ } catch {
28214
+ if (!applyCachedInlineMeshNodeStatus(status, node)) {
28215
+ status.health = "degraded";
28216
+ }
26221
28217
  }
26222
28218
  }
26223
28219
  } else {
26224
28220
  applyCachedInlineMeshNodeStatus(status, node);
26225
28221
  }
28222
+ finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
26226
28223
  nodeStatuses.push(status);
26227
28224
  }
26228
- return {
28225
+ const statusResult = {
26229
28226
  success: true,
26230
28227
  meshId: mesh.id,
26231
28228
  meshName: mesh.name,
26232
28229
  repoIdentity: mesh.repoIdentity,
26233
28230
  defaultBranch: mesh.defaultBranch,
28231
+ refreshedAt,
28232
+ meshHost,
28233
+ sourceOfTruth: {
28234
+ membership: meshRecord?.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord?.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
28235
+ coordinatorOwnsLiveTruth: directTruthSatisfied,
28236
+ meshHost: {
28237
+ owner: "mesh_host_daemon",
28238
+ localRole: meshHost.role,
28239
+ hostDaemonId: meshHost.hostDaemonId,
28240
+ hostNodeId: meshHost.hostNodeId,
28241
+ hostAddress: meshHost.hostAddress
28242
+ },
28243
+ ...requireDirectPeerTruth ? {
28244
+ currentStatus: directTruthSatisfied ? "live_git_and_session_probes" : "direct_peer_truth_unavailable",
28245
+ directPeerTruth: {
28246
+ required: true,
28247
+ satisfied: directTruthSatisfied,
28248
+ directEvidenceCount: effectiveDirectTruth.directEvidenceCount,
28249
+ localConfirmedCount: effectiveDirectTruth.localConfirmedCount,
28250
+ peerAttemptedCount: effectiveDirectTruth.peerAttemptedCount,
28251
+ peerConfirmedCount: effectiveDirectTruth.peerConfirmedCount,
28252
+ unavailableNodeIds: effectiveDirectTruth.unavailableNodeIds
28253
+ }
28254
+ } : {},
28255
+ historicalEvidenceOnly: ["recoveryHints", "ledger.summary", "queue.summary"]
28256
+ },
26234
28257
  nodes: nodeStatuses,
26235
28258
  queue: { tasks: queue, summary: queueSummary },
26236
28259
  ledger: { entries: ledgerEntries, summary: ledgerSummary }
26237
28260
  };
28261
+ const rememberedStatus = this.rememberAggregateMeshStatus(meshId, statusResult, refreshReason);
28262
+ logRepoMeshStatusDebug("return_live", {
28263
+ meshId,
28264
+ command: "mesh_status",
28265
+ refreshRequested,
28266
+ refreshReason,
28267
+ meshSource: meshRecord.source,
28268
+ directTruth,
28269
+ summary: summarizeRepoMeshStatusDebug(rememberedStatus)
28270
+ });
28271
+ return rememberedStatus;
26238
28272
  } catch (e) {
26239
28273
  return { success: false, error: e.message };
26240
28274
  }
@@ -34160,6 +36194,8 @@ async function initDaemonComponents(config) {
34160
36194
  sessionHostControl: config.sessionHostControl,
34161
36195
  statusInstanceId: config.statusInstanceId,
34162
36196
  statusVersion: config.statusVersion,
36197
+ getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
36198
+ dispatchMeshCommand: config.dispatchMeshCommand,
34163
36199
  getCdpLogFn: config.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
34164
36200
  });
34165
36201
  poller = new AgentStreamPoller({
@@ -34288,6 +36324,8 @@ async function shutdownDaemonComponents(components) {
34288
36324
  InMemoryGitSnapshotStore,
34289
36325
  LOG,
34290
36326
  MAX_LEDGER_SLICE_LIMIT,
36327
+ MESH_REFINE_CONFIG_LOCATIONS,
36328
+ MESH_REFINE_CONFIG_SCHEMA,
34291
36329
  MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
34292
36330
  MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
34293
36331
  MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
@@ -34310,6 +36348,7 @@ async function shutdownDaemonComponents(components) {
34310
36348
  buildChatTailDeliverySignature,
34311
36349
  buildCoordinatorSystemPrompt,
34312
36350
  buildMachineInfo,
36351
+ buildMeshHostRequiredFailure,
34313
36352
  buildMeshLedgerReconciliationEvidence,
34314
36353
  buildMeshLedgerReplicaEvidence,
34315
36354
  buildP2pRelayFailurePayload,
@@ -34335,6 +36374,7 @@ async function shutdownDaemonComponents(components) {
34335
36374
  connectCdpManager,
34336
36375
  createDebugTraceStore,
34337
36376
  createDefaultGitCommandServices,
36377
+ createDefaultMeshHostMetadata,
34338
36378
  createGitCompactSummary,
34339
36379
  createGitSnapshotStore,
34340
36380
  createGitWorkspaceMonitor,
@@ -34398,6 +36438,7 @@ async function shutdownDaemonComponents(components) {
34398
36438
  isInternalChatMessage,
34399
36439
  isManagedStatusWaiting,
34400
36440
  isManagedStatusWorking,
36441
+ isMeshHostOwner,
34401
36442
  isP2pRelayTransportFailure,
34402
36443
  isPathInside,
34403
36444
  isSessionHostLiveRuntime,
@@ -34411,6 +36452,7 @@ async function shutdownDaemonComponents(components) {
34411
36452
  listMeshes,
34412
36453
  listWorktrees,
34413
36454
  loadConfig,
36455
+ loadMeshRefineConfig,
34414
36456
  loadState,
34415
36457
  logCommand,
34416
36458
  markSetupComplete,
@@ -34424,6 +36466,7 @@ async function shutdownDaemonComponents(components) {
34424
36466
  normalizeGitWorkspaceSubscriptionParams,
34425
36467
  normalizeInputEnvelope,
34426
36468
  normalizeManagedStatus,
36469
+ normalizeMeshDaemonRole,
34427
36470
  normalizeMessageParts,
34428
36471
  normalizeRepoIdentity,
34429
36472
  normalizeSessionModalFields,
@@ -34435,6 +36478,7 @@ async function shutdownDaemonComponents(components) {
34435
36478
  prepareSessionChatTailUpdate,
34436
36479
  prepareSessionModalUpdate,
34437
36480
  probeCdpPort,
36481
+ queuePendingMeshCoordinatorEvent,
34438
36482
  readChatHistory,
34439
36483
  readLedgerEntries,
34440
36484
  readLedgerSlice,
@@ -34443,6 +36487,7 @@ async function shutdownDaemonComponents(components) {
34443
36487
  removeNode,
34444
36488
  removeWorktree,
34445
36489
  requeueTask,
36490
+ requireMeshHostQueueOwner,
34446
36491
  resetConfig,
34447
36492
  resetDebugRuntimeConfig,
34448
36493
  resetState,
@@ -34450,6 +36495,8 @@ async function shutdownDaemonComponents(components) {
34450
36495
  resolveCurrentGlobalInstallSurface,
34451
36496
  resolveDebugRuntimeConfig,
34452
36497
  resolveGitRepository,
36498
+ resolveMeshHostStatus,
36499
+ resolveMeshRefineValidationPlan,
34453
36500
  resolveSessionHostAppName,
34454
36501
  resolveSessionHostAppNameResolution,
34455
36502
  resolveWorktreePath,
@@ -34465,6 +36512,7 @@ async function shutdownDaemonComponents(components) {
34465
36512
  shutdownDaemonComponents,
34466
36513
  spawnDetachedDaemonUpgradeHelper,
34467
36514
  startDaemonDevSupport,
36515
+ suggestMeshRefineConfig,
34468
36516
  summarizeGitStatus,
34469
36517
  syncMeshes,
34470
36518
  triggerMeshQueue,
@@ -34473,6 +36521,7 @@ async function shutdownDaemonComponents(components) {
34473
36521
  updateNode,
34474
36522
  updateSessionTaskStatus,
34475
36523
  updateTaskStatus,
34476
- upsertSavedProviderSession
36524
+ upsertSavedProviderSession,
36525
+ validateMeshRefineConfig
34477
36526
  });
34478
36527
  //# sourceMappingURL=index.js.map