@adhdev/daemon-core 0.9.82-rc.48 → 0.9.82-rc.49

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.mjs CHANGED
@@ -657,23 +657,97 @@ var init_config = __esm({
657
657
  }
658
658
  });
659
659
 
660
+ // src/mesh/mesh-host-ownership.ts
661
+ function readObject(value) {
662
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
663
+ }
664
+ function readString(value) {
665
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
666
+ }
667
+ function normalizeMeshDaemonRole(value) {
668
+ return value === "host" || value === "member" ? value : void 0;
669
+ }
670
+ function resolveMeshHostStatus(mesh) {
671
+ const meshRecord = readObject(mesh);
672
+ const raw = readObject(meshRecord?.meshHost);
673
+ const role = normalizeMeshDaemonRole(raw?.role) ?? "host";
674
+ const pairing = readObject(raw?.pairing);
675
+ const normalized = {
676
+ role,
677
+ canOwnCoordinator: role === "host",
678
+ canOwnQueue: role === "host",
679
+ defaulted: !raw
680
+ };
681
+ const hostDaemonId = readString(raw?.hostDaemonId);
682
+ const hostNodeId = readString(raw?.hostNodeId);
683
+ const hostAddress = readString(raw?.hostAddress);
684
+ if (hostDaemonId) normalized.hostDaemonId = hostDaemonId;
685
+ if (hostNodeId) normalized.hostNodeId = hostNodeId;
686
+ if (hostAddress) normalized.hostAddress = hostAddress;
687
+ if (pairing) {
688
+ const status = pairing.status === "pairing" || pairing.status === "paired" || pairing.status === "rejected" || pairing.status === "revoked" ? pairing.status : "not_configured";
689
+ normalized.pairing = {
690
+ status,
691
+ ...readString(pairing.tokenId) ? { tokenId: readString(pairing.tokenId) } : {},
692
+ ...readString(pairing.joinedAt) ? { joinedAt: readString(pairing.joinedAt) } : {},
693
+ ...readString(pairing.lastPairedAt) ? { lastPairedAt: readString(pairing.lastPairedAt) } : {},
694
+ ...readString(pairing.lastRejectedAt) ? { lastRejectedAt: readString(pairing.lastRejectedAt) } : {},
695
+ ...readString(pairing.expiresAt) ? { expiresAt: readString(pairing.expiresAt) } : {}
696
+ };
697
+ }
698
+ return normalized;
699
+ }
700
+ function isMeshHostOwner(mesh) {
701
+ return resolveMeshHostStatus(mesh).role === "host";
702
+ }
703
+ function buildMeshHostRequiredFailure(mesh, operation) {
704
+ const meshHost = resolveMeshHostStatus(mesh);
705
+ return {
706
+ success: false,
707
+ code: "mesh_host_required",
708
+ error: `Mesh Host daemon required for ${operation}; member daemons must pair with the host and cannot own coordinator/queue mutations.`,
709
+ meshHost
710
+ };
711
+ }
712
+ function requireMeshHostQueueOwner(opts) {
713
+ if (opts?.ownerRole === "member") {
714
+ throw new Error("Mesh Host daemon required to mutate mesh queue; member daemons must use the host-owned queue.");
715
+ }
716
+ }
717
+ function createDefaultMeshHostMetadata() {
718
+ return {
719
+ role: "host",
720
+ pairing: { status: "not_configured" }
721
+ };
722
+ }
723
+ var init_mesh_host_ownership = __esm({
724
+ "src/mesh/mesh-host-ownership.ts"() {
725
+ "use strict";
726
+ }
727
+ });
728
+
660
729
  // src/config/mesh-config.ts
661
730
  var mesh_config_exports = {};
662
731
  __export(mesh_config_exports, {
663
732
  addNode: () => addNode,
733
+ applyMeshHostJoinRequest: () => applyMeshHostJoinRequest,
734
+ configureMeshHostPairing: () => configureMeshHostPairing,
664
735
  createMesh: () => createMesh,
736
+ createMeshHostPairingToken: () => createMeshHostPairingToken,
665
737
  deleteMesh: () => deleteMesh,
666
738
  getMesh: () => getMesh,
667
739
  getMeshByRepo: () => getMeshByRepo,
668
740
  listMeshes: () => listMeshes,
741
+ markMeshHostPairingJoined: () => markMeshHostPairingJoined,
669
742
  normalizeRepoIdentity: () => normalizeRepoIdentity,
670
743
  removeNode: () => removeNode,
744
+ tokenIdForManualPairing: () => tokenIdForManualPairing,
671
745
  updateMesh: () => updateMesh,
672
746
  updateNode: () => updateNode
673
747
  });
674
748
  import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
675
749
  import { join as join4 } from "path";
676
- import { randomUUID as randomUUID3 } from "crypto";
750
+ import { createHash, randomBytes, randomUUID as randomUUID3 } from "crypto";
677
751
  function getMeshConfigPath() {
678
752
  return join4(getConfigDir(), "meshes.json");
679
753
  }
@@ -746,6 +820,7 @@ function createMesh(opts) {
746
820
  defaultBranch: opts.defaultBranch,
747
821
  policy: mergeMeshPolicy(void 0, opts.policy),
748
822
  coordinator: opts.coordinator || {},
823
+ meshHost: opts.meshHost || createDefaultMeshHostMetadata(),
749
824
  nodes: [],
750
825
  createdAt: now,
751
826
  updatedAt: now
@@ -762,6 +837,7 @@ function updateMesh(meshId, opts) {
762
837
  if (opts.defaultBranch !== void 0) mesh.defaultBranch = opts.defaultBranch;
763
838
  if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
764
839
  if (opts.coordinator) mesh.coordinator = opts.coordinator;
840
+ if (opts.meshHost) mesh.meshHost = opts.meshHost;
765
841
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
766
842
  saveMeshConfig(config);
767
843
  return mesh;
@@ -774,6 +850,186 @@ function deleteMesh(meshId) {
774
850
  saveMeshConfig(config);
775
851
  return true;
776
852
  }
853
+ function normalizeManualHostAddress(hostAddress) {
854
+ const normalized = hostAddress.trim().replace(/\/+$/, "");
855
+ if (!normalized) throw new Error("hostAddress required");
856
+ let parsed;
857
+ try {
858
+ parsed = new URL(normalized);
859
+ } catch {
860
+ throw new Error("hostAddress must be a valid http(s) or ws(s) URL");
861
+ }
862
+ if (!["http:", "https:", "ws:", "wss:"].includes(parsed.protocol)) {
863
+ throw new Error("hostAddress must use http, https, ws, or wss");
864
+ }
865
+ return normalized;
866
+ }
867
+ function tokenIdForManualPairing(token) {
868
+ return `tok_${createHash("sha256").update(token).digest("hex").slice(0, 16)}`;
869
+ }
870
+ function normalizeTokenExpiry(value) {
871
+ if (typeof value !== "string" || !value.trim()) return void 0;
872
+ const date = new Date(value);
873
+ if (Number.isNaN(date.getTime())) throw new Error("expiresAt must be a valid ISO date");
874
+ return date.toISOString();
875
+ }
876
+ function assertPairingTokenValid(pairing, rawToken, nowIso) {
877
+ const token = rawToken.trim();
878
+ if (!token) return { ok: false, reason: "token required" };
879
+ const presentedTokenId = tokenIdForManualPairing(token);
880
+ const expectedTokenId = pairing?.tokenId;
881
+ if (!expectedTokenId || pairing?.status === "not_configured" || pairing?.status === "revoked") {
882
+ return { ok: false, reason: "host pairing token is not configured", presentedTokenId };
883
+ }
884
+ if (pairing.expiresAt && new Date(pairing.expiresAt).getTime() <= new Date(nowIso).getTime()) {
885
+ return { ok: false, reason: "host pairing token expired", expectedTokenId, presentedTokenId };
886
+ }
887
+ if (presentedTokenId !== expectedTokenId) {
888
+ return { ok: false, reason: "invalid pairing token", expectedTokenId, presentedTokenId };
889
+ }
890
+ return { ok: true, tokenId: presentedTokenId };
891
+ }
892
+ function configureMeshHostPairing(meshId, opts) {
893
+ const hostAddress = normalizeManualHostAddress(opts.hostAddress);
894
+ const token = opts.token.trim();
895
+ if (!token) throw new Error("token required");
896
+ const config = loadMeshConfig();
897
+ const mesh = config.meshes.find((m) => m.id === meshId);
898
+ if (!mesh) return void 0;
899
+ const now = opts.now || (/* @__PURE__ */ new Date()).toISOString();
900
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
901
+ const meshHost = {
902
+ ...previous,
903
+ role: "member",
904
+ hostAddress,
905
+ pairing: {
906
+ status: "pairing",
907
+ tokenId: tokenIdForManualPairing(token),
908
+ lastPairedAt: now
909
+ }
910
+ };
911
+ mesh.meshHost = meshHost;
912
+ mesh.updatedAt = now;
913
+ saveMeshConfig(config);
914
+ return { mesh, meshHost, hostAddress };
915
+ }
916
+ function createMeshHostPairingToken(meshId, opts = {}) {
917
+ const config = loadMeshConfig();
918
+ const mesh = config.meshes.find((m) => m.id === meshId);
919
+ if (!mesh) return void 0;
920
+ const now = opts.now || (/* @__PURE__ */ new Date()).toISOString();
921
+ const token = (opts.token || `mhj_${randomBytes(24).toString("base64url")}`).trim();
922
+ if (!token) throw new Error("token required");
923
+ const tokenId = tokenIdForManualPairing(token);
924
+ const expiresAt = normalizeTokenExpiry(opts.expiresAt);
925
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
926
+ if (previous.role === "member") {
927
+ throw new Error("Mesh Host daemon required to create host pairing tokens; member daemons cannot mint host join tokens.");
928
+ }
929
+ const meshHost = {
930
+ ...previous,
931
+ role: "host",
932
+ pairing: {
933
+ status: "pairing",
934
+ tokenId,
935
+ lastPairedAt: now,
936
+ ...expiresAt ? { expiresAt } : {}
937
+ }
938
+ };
939
+ mesh.meshHost = meshHost;
940
+ mesh.updatedAt = now;
941
+ saveMeshConfig(config);
942
+ return { mesh, meshHost, token, tokenId, ...expiresAt ? { expiresAt } : {} };
943
+ }
944
+ function applyMeshHostJoinRequest(meshId, opts) {
945
+ const config = loadMeshConfig();
946
+ const mesh = config.meshes.find((m) => m.id === meshId);
947
+ if (!mesh) return void 0;
948
+ const now = opts.now || (/* @__PURE__ */ new Date()).toISOString();
949
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
950
+ if (previous.role === "member") {
951
+ return { accepted: false, mesh, meshHost: previous, reason: "Mesh Host daemon required to accept join requests" };
952
+ }
953
+ const meshHost = { ...previous, role: "host" };
954
+ const validation = assertPairingTokenValid(meshHost.pairing, opts.token, now);
955
+ if (!validation.ok) {
956
+ mesh.meshHost = {
957
+ ...meshHost,
958
+ pairing: {
959
+ ...meshHost.pairing || { status: "not_configured" },
960
+ status: "rejected",
961
+ lastRejectedAt: now
962
+ }
963
+ };
964
+ mesh.updatedAt = now;
965
+ saveMeshConfig(config);
966
+ return { accepted: false, mesh, meshHost: mesh.meshHost, tokenId: validation.presentedTokenId, reason: validation.reason };
967
+ }
968
+ const workspace = opts.memberNode.workspace.trim();
969
+ if (!workspace) throw new Error("memberNode.workspace required");
970
+ const memberId = opts.memberNode.id?.trim();
971
+ let node = mesh.nodes.find((n) => memberId && n.id === memberId || n.workspace === workspace);
972
+ if (node) {
973
+ node.workspace = workspace;
974
+ node.repoRoot = opts.memberNode.repoRoot;
975
+ node.daemonId = opts.memberNode.daemonId;
976
+ node.machineId = opts.memberNode.machineId;
977
+ node.userOverrides = opts.memberNode.userOverrides || node.userOverrides || {};
978
+ node.policy = { ...node.policy || {}, ...opts.memberNode.policy || {} };
979
+ node.role = "member";
980
+ } else {
981
+ if (mesh.nodes.length >= 10) throw new Error("Maximum 10 nodes per mesh");
982
+ node = {
983
+ id: memberId || `node_${randomUUID3().replace(/-/g, "")}`,
984
+ workspace,
985
+ repoRoot: opts.memberNode.repoRoot,
986
+ daemonId: opts.memberNode.daemonId,
987
+ machineId: opts.memberNode.machineId,
988
+ userOverrides: opts.memberNode.userOverrides || {},
989
+ policy: opts.memberNode.policy || {},
990
+ role: "member"
991
+ };
992
+ mesh.nodes.push(node);
993
+ }
994
+ mesh.meshHost = {
995
+ ...meshHost,
996
+ pairing: {
997
+ ...meshHost.pairing || {},
998
+ status: "paired",
999
+ tokenId: validation.tokenId,
1000
+ joinedAt: now,
1001
+ lastPairedAt: meshHost.pairing?.lastPairedAt || now,
1002
+ ...meshHost.pairing?.expiresAt ? { expiresAt: meshHost.pairing.expiresAt } : {}
1003
+ }
1004
+ };
1005
+ mesh.updatedAt = now;
1006
+ saveMeshConfig(config);
1007
+ return { accepted: true, mesh, meshHost: mesh.meshHost, node, tokenId: validation.tokenId };
1008
+ }
1009
+ function markMeshHostPairingJoined(meshId, opts) {
1010
+ const config = loadMeshConfig();
1011
+ const mesh = config.meshes.find((m) => m.id === meshId);
1012
+ if (!mesh) return void 0;
1013
+ const now = opts.joinedAt || (/* @__PURE__ */ new Date()).toISOString();
1014
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
1015
+ const tokenId = opts.tokenId || (opts.token ? tokenIdForManualPairing(opts.token) : previous.pairing?.tokenId);
1016
+ mesh.meshHost = {
1017
+ ...previous,
1018
+ role: "member",
1019
+ ...opts.hostDaemonId ? { hostDaemonId: opts.hostDaemonId } : {},
1020
+ ...opts.hostNodeId ? { hostNodeId: opts.hostNodeId } : {},
1021
+ pairing: {
1022
+ ...previous.pairing || {},
1023
+ status: "paired",
1024
+ ...tokenId ? { tokenId } : {},
1025
+ joinedAt: now,
1026
+ lastPairedAt: previous.pairing?.lastPairedAt || now
1027
+ }
1028
+ };
1029
+ mesh.updatedAt = now;
1030
+ saveMeshConfig(config);
1031
+ return { mesh, meshHost: mesh.meshHost };
1032
+ }
777
1033
  function addNode(meshId, opts) {
778
1034
  const config = loadMeshConfig();
779
1035
  const mesh = config.meshes.find((m) => m.id === meshId);
@@ -794,7 +1050,8 @@ function addNode(meshId, opts) {
794
1050
  policy: opts.policy || {},
795
1051
  isLocalWorktree: opts.isLocalWorktree,
796
1052
  worktreeBranch: opts.worktreeBranch,
797
- clonedFromNodeId: opts.clonedFromNodeId
1053
+ clonedFromNodeId: opts.clonedFromNodeId,
1054
+ role: opts.role
798
1055
  };
799
1056
  mesh.nodes.push(node);
800
1057
  mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -830,6 +1087,7 @@ var init_mesh_config = __esm({
830
1087
  "use strict";
831
1088
  init_config();
832
1089
  init_repo_mesh_types();
1090
+ init_mesh_host_ownership();
833
1091
  SESSION_CLEANUP_MODES = /* @__PURE__ */ new Set(["preserve", "stop", "delete_stopped", "stop_and_delete"]);
834
1092
  SPAWNED_SESSION_VISIBILITY_MODES = /* @__PURE__ */ new Set(["visible", "hidden"]);
835
1093
  }
@@ -1007,8 +1265,8 @@ __export(mesh_ledger_exports, {
1007
1265
  readLedgerEntries: () => readLedgerEntries,
1008
1266
  readLedgerSlice: () => readLedgerSlice
1009
1267
  });
1010
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync3, appendFileSync, statSync as statSync2, renameSync } from "fs";
1011
- import { join as join5 } from "path";
1268
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4, appendFileSync, statSync as statSync2, renameSync } from "fs";
1269
+ import { join as join6 } from "path";
1012
1270
  import { randomUUID as randomUUID4 } from "crypto";
1013
1271
  import { EventEmitter } from "events";
1014
1272
  function isIntentionalCleanupStopEntry(entry) {
@@ -1017,19 +1275,19 @@ function isIntentionalCleanupStopEntry(entry) {
1017
1275
  return payload.intentional === true && (payload.reason === "operator_cleanup" || payload.intentionalStopReason === "operator_cleanup" || payload.source === "mesh_cleanup_sessions" || payload.source === "mesh_remove_node");
1018
1276
  }
1019
1277
  function getLedgerDir() {
1020
- const dir = join5(getConfigDir(), LEDGER_DIR_NAME);
1021
- if (!existsSync5(dir)) {
1278
+ const dir = join6(getConfigDir(), LEDGER_DIR_NAME);
1279
+ if (!existsSync6(dir)) {
1022
1280
  mkdirSync3(dir, { recursive: true, mode: 448 });
1023
1281
  }
1024
1282
  return dir;
1025
1283
  }
1026
1284
  function getLedgerPath(meshId) {
1027
1285
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1028
- return join5(getLedgerDir(), `${safe}.jsonl`);
1286
+ return join6(getLedgerDir(), `${safe}.jsonl`);
1029
1287
  }
1030
1288
  function getRotatedPath(meshId, index) {
1031
1289
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1032
- return join5(getLedgerDir(), `${safe}.${index}.jsonl`);
1290
+ return join6(getLedgerDir(), `${safe}.${index}.jsonl`);
1033
1291
  }
1034
1292
  function buildTaskCompletionEvidence(opts) {
1035
1293
  const providerSessionId = opts.providerSessionId?.trim() || void 0;
@@ -1070,7 +1328,7 @@ function appendLedgerEntry(meshId, partial) {
1070
1328
  ...partial
1071
1329
  };
1072
1330
  const filePath = getLedgerPath(meshId);
1073
- if (existsSync5(filePath)) {
1331
+ if (existsSync6(filePath)) {
1074
1332
  try {
1075
1333
  const stat2 = statSync2(filePath);
1076
1334
  if (stat2.size >= MAX_FILE_SIZE_BYTES) {
@@ -1137,10 +1395,10 @@ function appendRemoteLedgerEntries(meshId, entries) {
1137
1395
  }
1138
1396
  function readLedgerEntries(meshId, opts) {
1139
1397
  const filePath = getLedgerPath(meshId);
1140
- if (!existsSync5(filePath)) return [];
1398
+ if (!existsSync6(filePath)) return [];
1141
1399
  let content;
1142
1400
  try {
1143
- content = readFileSync3(filePath, "utf-8");
1401
+ content = readFileSync4(filePath, "utf-8");
1144
1402
  } catch {
1145
1403
  return [];
1146
1404
  }
@@ -1312,7 +1570,7 @@ function getSessionRecoveryContext(meshId, opts) {
1312
1570
  }
1313
1571
  function rotateLedgerFile(meshId, currentPath) {
1314
1572
  let index = 1;
1315
- while (existsSync5(getRotatedPath(meshId, index))) {
1573
+ while (existsSync6(getRotatedPath(meshId, index))) {
1316
1574
  index++;
1317
1575
  if (index > 10) break;
1318
1576
  }
@@ -1351,16 +1609,16 @@ __export(mesh_work_queue_exports, {
1351
1609
  updateSessionTaskStatus: () => updateSessionTaskStatus,
1352
1610
  updateTaskStatus: () => updateTaskStatus
1353
1611
  });
1354
- import { existsSync as existsSync6, writeFileSync as writeFileSync3, readFileSync as readFileSync4, openSync, closeSync, unlinkSync } from "fs";
1355
- import { join as join6 } from "path";
1612
+ import { existsSync as existsSync7, writeFileSync as writeFileSync3, readFileSync as readFileSync5, openSync, closeSync, unlinkSync } from "fs";
1613
+ import { join as join7 } from "path";
1356
1614
  import { randomUUID as randomUUID5 } from "crypto";
1357
1615
  function getQueuePath(meshId) {
1358
1616
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1359
- return join6(getLedgerDir(), `${safe}.queue.json`);
1617
+ return join7(getLedgerDir(), `${safe}.queue.json`);
1360
1618
  }
1361
1619
  function getLockPath(meshId) {
1362
1620
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1363
- return join6(getLedgerDir(), `${safe}.queue.lock`);
1621
+ return join7(getLedgerDir(), `${safe}.queue.lock`);
1364
1622
  }
1365
1623
  function withQueueLock(meshId, fn) {
1366
1624
  const lockPath = getLockPath(meshId);
@@ -1390,9 +1648,9 @@ function withQueueLock(meshId, fn) {
1390
1648
  }
1391
1649
  function readQueue(meshId) {
1392
1650
  const path28 = getQueuePath(meshId);
1393
- if (!existsSync6(path28)) return [];
1651
+ if (!existsSync7(path28)) return [];
1394
1652
  try {
1395
- const content = readFileSync4(path28, "utf-8");
1653
+ const content = readFileSync5(path28, "utf-8");
1396
1654
  return JSON.parse(content);
1397
1655
  } catch {
1398
1656
  return [];
@@ -1403,6 +1661,7 @@ function writeQueue(meshId, queue) {
1403
1661
  writeFileSync3(path28, JSON.stringify(queue, null, 2), "utf-8");
1404
1662
  }
1405
1663
  function enqueueTask(meshId, message, opts) {
1664
+ requireMeshHostQueueOwner(opts);
1406
1665
  return withQueueLock(meshId, () => {
1407
1666
  const queue = readQueue(meshId);
1408
1667
  const entry = {
@@ -1451,7 +1710,8 @@ function claimNextTask(meshId, nodeId, sessionId) {
1451
1710
  return entry;
1452
1711
  });
1453
1712
  }
1454
- function updateTaskStatus(meshId, taskId, status) {
1713
+ function updateTaskStatus(meshId, taskId, status, opts) {
1714
+ requireMeshHostQueueOwner(opts);
1455
1715
  return withQueueLock(meshId, () => {
1456
1716
  const queue = readQueue(meshId);
1457
1717
  const idx = queue.findIndex((q) => q.id === taskId);
@@ -1475,6 +1735,7 @@ function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
1475
1735
  });
1476
1736
  }
1477
1737
  function cancelTask(meshId, taskId, opts) {
1738
+ requireMeshHostQueueOwner(opts);
1478
1739
  return withQueueLock(meshId, () => {
1479
1740
  const queue = readQueue(meshId);
1480
1741
  const idx = queue.findIndex((q) => q.id === taskId);
@@ -1489,6 +1750,7 @@ function cancelTask(meshId, taskId, opts) {
1489
1750
  });
1490
1751
  }
1491
1752
  function requeueTask(meshId, taskId, opts) {
1753
+ requireMeshHostQueueOwner(opts);
1492
1754
  return withQueueLock(meshId, () => {
1493
1755
  const queue = readQueue(meshId);
1494
1756
  const idx = queue.findIndex((q) => q.id === taskId);
@@ -1573,6 +1835,7 @@ var init_mesh_work_queue = __esm({
1573
1835
  "src/mesh/mesh-work-queue.ts"() {
1574
1836
  "use strict";
1575
1837
  init_mesh_ledger();
1838
+ init_mesh_host_ownership();
1576
1839
  ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
1577
1840
  HISTORICAL_MESH_QUEUE_STATUSES = ["completed", "failed", "cancelled"];
1578
1841
  }
@@ -1582,7 +1845,7 @@ var init_mesh_work_queue = __esm({
1582
1845
  import { exec } from "child_process";
1583
1846
  import * as os2 from "os";
1584
1847
  import * as path8 from "path";
1585
- import { existsSync as existsSync7 } from "fs";
1848
+ import { existsSync as existsSync8 } from "fs";
1586
1849
  function parseVersion(raw) {
1587
1850
  const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
1588
1851
  return match ? match[1] : raw.split("\n")[0].slice(0, 100);
@@ -1606,7 +1869,7 @@ function resolveCommandPath(command) {
1606
1869
  if (isExplicitCommandPath(trimmed)) {
1607
1870
  const expanded = expandHome(trimmed);
1608
1871
  const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
1609
- return existsSync7(candidate) ? candidate : null;
1872
+ return existsSync8(candidate) ? candidate : null;
1610
1873
  }
1611
1874
  return null;
1612
1875
  }
@@ -1938,8 +2201,8 @@ __export(mesh_events_exports, {
1938
2201
  triggerMeshQueue: () => triggerMeshQueue,
1939
2202
  tryAssignQueueTask: () => tryAssignQueueTask
1940
2203
  });
1941
- import { appendFileSync as appendFileSync3, existsSync as existsSync9, readFileSync as readFileSync5, unlinkSync as unlinkSync3 } from "fs";
1942
- import { join as join9 } from "path";
2204
+ import { appendFileSync as appendFileSync3, existsSync as existsSync10, readFileSync as readFileSync6, unlinkSync as unlinkSync3 } from "fs";
2205
+ import { join as join10 } from "path";
1943
2206
  function sweepExpiredRemoteIdleSessions() {
1944
2207
  const now = Date.now();
1945
2208
  for (const [key, session] of remoteIdleSessions) {
@@ -1948,7 +2211,7 @@ function sweepExpiredRemoteIdleSessions() {
1948
2211
  }
1949
2212
  function getPendingEventsPath(meshId) {
1950
2213
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1951
- return join9(getLedgerDir(), `${safe}.pending-events.jsonl`);
2214
+ return join10(getLedgerDir(), `${safe}.pending-events.jsonl`);
1952
2215
  }
1953
2216
  function queuePendingMeshCoordinatorEvent(event) {
1954
2217
  try {
@@ -1962,9 +2225,9 @@ function queuePendingMeshCoordinatorEvent(event) {
1962
2225
  function drainPendingMeshCoordinatorEvents(meshId) {
1963
2226
  if (!meshId) return [];
1964
2227
  const path28 = getPendingEventsPath(meshId);
1965
- if (!existsSync9(path28)) return [];
2228
+ if (!existsSync10(path28)) return [];
1966
2229
  try {
1967
- const raw = readFileSync5(path28, "utf-8");
2230
+ const raw = readFileSync6(path28, "utf-8");
1968
2231
  try {
1969
2232
  unlinkSync3(path28);
1970
2233
  } catch {
@@ -1983,9 +2246,9 @@ function drainPendingMeshCoordinatorEvents(meshId) {
1983
2246
  function getPendingMeshCoordinatorEvents(meshId) {
1984
2247
  if (!meshId) return [];
1985
2248
  const path28 = getPendingEventsPath(meshId);
1986
- if (!existsSync9(path28)) return [];
2249
+ if (!existsSync10(path28)) return [];
1987
2250
  try {
1988
- const raw = readFileSync5(path28, "utf-8");
2251
+ const raw = readFileSync6(path28, "utf-8");
1989
2252
  return raw.split("\n").filter(Boolean).flatMap((line) => {
1990
2253
  try {
1991
2254
  return [JSON.parse(line)];
@@ -2000,7 +2263,7 @@ function getPendingMeshCoordinatorEvents(meshId) {
2000
2263
  function clearPendingMeshCoordinatorEvents(meshId) {
2001
2264
  if (!meshId) return;
2002
2265
  const path28 = getPendingEventsPath(meshId);
2003
- if (existsSync9(path28)) try {
2266
+ if (existsSync10(path28)) try {
2004
2267
  unlinkSync3(path28);
2005
2268
  } catch {
2006
2269
  }
@@ -7561,6 +7824,238 @@ function getSavedProviderSessions(state, filters) {
7561
7824
  init_mesh_config();
7562
7825
  init_coordinator_prompt();
7563
7826
 
7827
+ // src/mesh/refine-config.ts
7828
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
7829
+ import { join as join5 } from "path";
7830
+ import * as yaml from "js-yaml";
7831
+ var MESH_REFINE_VALIDATION_CATEGORIES = ["typecheck", "test", "lint", "build"];
7832
+ var MESH_REFINE_CONFIG_LOCATIONS = [
7833
+ ".adhdev/refine.json",
7834
+ ".adhdev/refine.yaml",
7835
+ ".adhdev/refine.yml",
7836
+ ".adhdev/repo-mesh-refine.json",
7837
+ ".adhdev/repo-mesh-refine.yaml",
7838
+ ".adhdev/repo-mesh-refine.yml",
7839
+ "repo-mesh.refine.json",
7840
+ "repo-mesh.refine.yaml",
7841
+ "repo-mesh.refine.yml"
7842
+ ];
7843
+ var MESH_REFINE_CONFIG_SCHEMA = {
7844
+ $schema: "https://json-schema.org/draft/2020-12/schema",
7845
+ title: "ADHDev Repo Mesh Refinery Config",
7846
+ type: "object",
7847
+ additionalProperties: false,
7848
+ required: ["version"],
7849
+ properties: {
7850
+ version: { const: 1 },
7851
+ validation: {
7852
+ type: "object",
7853
+ additionalProperties: false,
7854
+ properties: {
7855
+ required: { type: "boolean", default: true },
7856
+ commands: {
7857
+ type: "array",
7858
+ minItems: 1,
7859
+ maxItems: 8,
7860
+ items: {
7861
+ type: "object",
7862
+ additionalProperties: false,
7863
+ required: ["command"],
7864
+ properties: {
7865
+ command: { type: "string", minLength: 1 },
7866
+ args: { type: "array", items: { type: "string" } },
7867
+ category: { enum: [...MESH_REFINE_VALIDATION_CATEGORIES, "custom"] },
7868
+ cwd: { type: "string" },
7869
+ timeoutMs: { type: "number", minimum: 1e3, maximum: 6e5 },
7870
+ env: { type: "object", additionalProperties: { type: "string" } }
7871
+ }
7872
+ }
7873
+ }
7874
+ }
7875
+ }
7876
+ }
7877
+ };
7878
+ function isRecord(value) {
7879
+ return !!value && typeof value === "object" && !Array.isArray(value);
7880
+ }
7881
+ function tokenizeCommandString(command) {
7882
+ const trimmed = command.trim();
7883
+ if (!trimmed) return null;
7884
+ if (/[;&|<>`$\\\n\r'\"]/.test(trimmed)) return null;
7885
+ const tokens = trimmed.split(/\s+/).filter(Boolean);
7886
+ if (!tokens.length) return null;
7887
+ if (tokens.some((token) => !/^[A-Za-z0-9_@./:=+-]+$/.test(token))) return null;
7888
+ return tokens;
7889
+ }
7890
+ function validateCategory(value) {
7891
+ return typeof value === "string" && [...MESH_REFINE_VALIDATION_CATEGORIES, "custom"].includes(value) ? value : "custom";
7892
+ }
7893
+ function normalizeCommandConfig(entry, source) {
7894
+ if (!isRecord(entry) || typeof entry.command !== "string") {
7895
+ return { rejected: { source, reason: "validation command must be an object with a command string" } };
7896
+ }
7897
+ const commandText = entry.command.trim();
7898
+ const explicitArgs = Array.isArray(entry.args) ? entry.args : void 0;
7899
+ if (explicitArgs && !explicitArgs.every((arg) => typeof arg === "string")) {
7900
+ return { rejected: { source, command: commandText, reason: "args must be an array of strings" } };
7901
+ }
7902
+ let command = commandText;
7903
+ let args = explicitArgs ? [...explicitArgs] : [];
7904
+ if (!explicitArgs) {
7905
+ const tokens = tokenizeCommandString(commandText);
7906
+ if (!tokens) return { rejected: { source, command: commandText, reason: "unsafe command string is not allowlisted" } };
7907
+ command = tokens[0];
7908
+ args = tokens.slice(1);
7909
+ } else if (!tokenizeCommandString(command)) {
7910
+ return { rejected: { source, command: commandText, reason: "unsafe executable name is not allowlisted" } };
7911
+ }
7912
+ if (args.some((arg) => /[\n\r\0]/.test(arg))) {
7913
+ return { rejected: { source, command: commandText, reason: "args cannot contain control characters" } };
7914
+ }
7915
+ if (entry.cwd !== void 0 && typeof entry.cwd !== "string") {
7916
+ return { rejected: { source, command: commandText, reason: "cwd must be a string when provided" } };
7917
+ }
7918
+ if (entry.timeoutMs !== void 0 && (typeof entry.timeoutMs !== "number" || !Number.isFinite(entry.timeoutMs) || entry.timeoutMs < 1e3 || entry.timeoutMs > 6e5)) {
7919
+ return { rejected: { source, command: commandText, reason: "timeoutMs must be between 1000 and 600000" } };
7920
+ }
7921
+ if (entry.env !== void 0 && (!isRecord(entry.env) || !Object.values(entry.env).every((value) => typeof value === "string"))) {
7922
+ return { rejected: { source, command: commandText, reason: "env must be an object of string values" } };
7923
+ }
7924
+ return {
7925
+ command: {
7926
+ command,
7927
+ args,
7928
+ displayCommand: [command, ...args].join(" "),
7929
+ category: validateCategory(entry.category),
7930
+ source,
7931
+ ...typeof entry.cwd === "string" && entry.cwd.trim() ? { cwd: entry.cwd.trim() } : {},
7932
+ ...typeof entry.timeoutMs === "number" ? { timeoutMs: entry.timeoutMs } : {},
7933
+ ...isRecord(entry.env) ? { env: entry.env } : {}
7934
+ }
7935
+ };
7936
+ }
7937
+ function validateMeshRefineConfig(config, source = "inline") {
7938
+ const errors = [];
7939
+ const commands = [];
7940
+ const rejectedCommands = [];
7941
+ if (!isRecord(config)) return { valid: false, errors: ["config must be an object"], commands, rejectedCommands };
7942
+ if (config.version !== 1) errors.push("version must be 1");
7943
+ const validation = config.validation;
7944
+ if (validation !== void 0 && !isRecord(validation)) errors.push("validation must be an object");
7945
+ const rawCommands = isRecord(validation) ? validation.commands : void 0;
7946
+ if (rawCommands !== void 0 && !Array.isArray(rawCommands)) errors.push("validation.commands must be an array");
7947
+ if (Array.isArray(rawCommands)) {
7948
+ rawCommands.forEach((entry, index) => {
7949
+ const normalized = normalizeCommandConfig(entry, `${source}:validation.commands[${index}]`);
7950
+ if (normalized.command) commands.push(normalized.command);
7951
+ if (normalized.rejected) rejectedCommands.push(normalized.rejected);
7952
+ });
7953
+ }
7954
+ if (rejectedCommands.length) errors.push("one or more validation commands are invalid");
7955
+ return { valid: errors.length === 0, errors, commands, rejectedCommands };
7956
+ }
7957
+ function parseConfigText(path28, text) {
7958
+ if (/\.json$/i.test(path28)) return JSON.parse(text);
7959
+ return yaml.load(text);
7960
+ }
7961
+ function loadMeshRefineConfig(mesh, workspace) {
7962
+ const policy = mesh?.policy && typeof mesh.policy === "object" && !Array.isArray(mesh.policy) ? mesh.policy : {};
7963
+ const inline = mesh?.refineConfig || policy.refineConfig || policy.refine;
7964
+ if (inline !== void 0) {
7965
+ const validation = validateMeshRefineConfig(inline, "mesh.policy.refineConfig");
7966
+ if (!validation.valid) return { source: "mesh.policy.refineConfig", sourceType: "invalid", error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
7967
+ return { config: inline, source: "mesh.policy.refineConfig", sourceType: "mesh_policy" };
7968
+ }
7969
+ for (const relative3 of MESH_REFINE_CONFIG_LOCATIONS) {
7970
+ const configPath = join5(workspace, relative3);
7971
+ if (!existsSync5(configPath)) continue;
7972
+ try {
7973
+ const parsed = parseConfigText(configPath, readFileSync3(configPath, "utf-8"));
7974
+ const validation = validateMeshRefineConfig(parsed, relative3);
7975
+ if (!validation.valid) return { source: relative3, sourceType: "invalid", path: configPath, error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
7976
+ return { config: parsed, source: relative3, sourceType: "repo_file", path: configPath };
7977
+ } catch (error) {
7978
+ return { source: relative3, sourceType: "invalid", path: configPath, error: error?.message || String(error) };
7979
+ }
7980
+ }
7981
+ return {
7982
+ source: "unavailable",
7983
+ sourceType: "unavailable",
7984
+ error: `No repo mesh/refine config found. Checked: ${MESH_REFINE_CONFIG_LOCATIONS.join(", ")}`
7985
+ };
7986
+ }
7987
+ function readPackageScripts(workspace) {
7988
+ try {
7989
+ const parsed = JSON.parse(readFileSync3(join5(workspace, "package.json"), "utf-8"));
7990
+ return isRecord(parsed?.scripts) ? parsed.scripts : {};
7991
+ } catch {
7992
+ return {};
7993
+ }
7994
+ }
7995
+ function collectProjectContextSuggestions(mesh) {
7996
+ const commands = mesh?.projectContext?.commands;
7997
+ if (!isRecord(commands)) return [];
7998
+ const suggestions = [];
7999
+ for (const category of MESH_REFINE_VALIDATION_CATEGORIES) {
8000
+ const entries = Array.isArray(commands[category]) ? commands[category] : [];
8001
+ for (const entry of entries) {
8002
+ if (isRecord(entry) && typeof entry.command === "string") suggestions.push({ command: entry.command, category });
8003
+ }
8004
+ }
8005
+ return suggestions;
8006
+ }
8007
+ function collectPackageScriptSuggestions(workspace) {
8008
+ const scripts = readPackageScripts(workspace);
8009
+ const suggestions = [];
8010
+ for (const category of MESH_REFINE_VALIDATION_CATEGORIES) {
8011
+ for (const scriptName of Object.keys(scripts)) {
8012
+ if (scriptName === category || scriptName.startsWith(`${category}:`)) {
8013
+ suggestions.push({ command: "npm", args: ["run", scriptName], category });
8014
+ }
8015
+ }
8016
+ }
8017
+ return suggestions;
8018
+ }
8019
+ function suggestMeshRefineConfig(mesh, workspace) {
8020
+ const seen = /* @__PURE__ */ new Set();
8021
+ const suggestions = [];
8022
+ for (const entry of [...collectProjectContextSuggestions(mesh), ...collectPackageScriptSuggestions(workspace)]) {
8023
+ const key = `${entry.command} ${(entry.args || []).join(" ")}`.trim();
8024
+ if (seen.has(key)) continue;
8025
+ seen.add(key);
8026
+ suggestions.push(entry);
8027
+ }
8028
+ return {
8029
+ suggestions,
8030
+ suggestedConfig: suggestions.length ? { version: 1, validation: { required: true, commands: suggestions.slice(0, 4) } } : void 0
8031
+ };
8032
+ }
8033
+ function resolveMeshRefineValidationPlan(mesh, workspace) {
8034
+ const loaded = loadMeshRefineConfig(mesh, workspace);
8035
+ const suggestion = suggestMeshRefineConfig(mesh, workspace);
8036
+ if (!loaded.config) {
8037
+ return {
8038
+ source: loaded.source,
8039
+ sourceType: loaded.sourceType,
8040
+ commands: [],
8041
+ rejectedCommands: loaded.error ? [{ source: loaded.source, reason: loaded.error }] : [],
8042
+ suggestions: suggestion.suggestions,
8043
+ suggestedConfig: suggestion.suggestedConfig,
8044
+ unavailableReason: loaded.error || "validation_unavailable: repo mesh/refine config missing"
8045
+ };
8046
+ }
8047
+ const validation = validateMeshRefineConfig(loaded.config, loaded.source);
8048
+ return {
8049
+ source: loaded.path || loaded.source,
8050
+ sourceType: loaded.sourceType,
8051
+ commands: validation.commands,
8052
+ rejectedCommands: validation.rejectedCommands,
8053
+ suggestions: suggestion.suggestions,
8054
+ suggestedConfig: suggestion.suggestedConfig,
8055
+ unavailableReason: validation.commands.length ? void 0 : "validation_unavailable: repo mesh/refine config has no validation.commands"
8056
+ };
8057
+ }
8058
+
7564
8059
  // src/mesh/mesh-sync.ts
7565
8060
  init_mesh_config();
7566
8061
  async function syncMeshes(transport) {
@@ -7680,6 +8175,7 @@ function buildMeshLedgerReconciliationEvidence(meshId, replicas) {
7680
8175
 
7681
8176
  // src/index.ts
7682
8177
  init_mesh_work_queue();
8178
+ init_mesh_host_ownership();
7683
8179
  init_mesh_events();
7684
8180
 
7685
8181
  // src/mesh/p2p-relay-failure.ts
@@ -7794,8 +8290,8 @@ var P2pRelayFailureError = class extends Error {
7794
8290
 
7795
8291
  // src/config/state-store.ts
7796
8292
  init_config();
7797
- import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
7798
- import { join as join10 } from "path";
8293
+ import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
8294
+ import { join as join11 } from "path";
7799
8295
  var DEFAULT_STATE = {
7800
8296
  recentActivity: [],
7801
8297
  savedProviderSessions: [],
@@ -7808,7 +8304,7 @@ function isPlainObject2(value) {
7808
8304
  return !!value && typeof value === "object" && !Array.isArray(value);
7809
8305
  }
7810
8306
  function getStatePath() {
7811
- return join10(getConfigDir(), "state.json");
8307
+ return join11(getConfigDir(), "state.json");
7812
8308
  }
7813
8309
  function normalizeState(raw) {
7814
8310
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -7844,11 +8340,11 @@ function normalizeState(raw) {
7844
8340
  }
7845
8341
  function loadState() {
7846
8342
  const statePath = getStatePath();
7847
- if (!existsSync10(statePath)) {
8343
+ if (!existsSync11(statePath)) {
7848
8344
  return { ...DEFAULT_STATE };
7849
8345
  }
7850
8346
  try {
7851
- const raw = readFileSync6(statePath, "utf-8");
8347
+ const raw = readFileSync7(statePath, "utf-8");
7852
8348
  return normalizeState(JSON.parse(raw));
7853
8349
  } catch {
7854
8350
  return { ...DEFAULT_STATE };
@@ -7865,7 +8361,7 @@ function resetState() {
7865
8361
 
7866
8362
  // src/detection/ide-detector.ts
7867
8363
  import { execSync } from "child_process";
7868
- import { existsSync as existsSync11 } from "fs";
8364
+ import { existsSync as existsSync12 } from "fs";
7869
8365
  import { platform as platform2, homedir as homedir5 } from "os";
7870
8366
  import * as path10 from "path";
7871
8367
  var BUILTIN_IDE_DEFINITIONS = [];
@@ -7889,7 +8385,7 @@ function findCliCommand(command) {
7889
8385
  if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
7890
8386
  const candidate = trimmed.startsWith("~") ? path10.join(homedir5(), trimmed.slice(1)) : trimmed;
7891
8387
  const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
7892
- return existsSync11(resolved) ? resolved : null;
8388
+ return existsSync12(resolved) ? resolved : null;
7893
8389
  }
7894
8390
  try {
7895
8391
  const result = execSync(
@@ -7920,9 +8416,9 @@ function checkPathExists(paths) {
7920
8416
  if (normalized.includes("*")) {
7921
8417
  const username = home.split(/[\\/]/).pop() || "";
7922
8418
  const resolved = normalized.replace("*", username);
7923
- if (existsSync11(resolved)) return resolved;
8419
+ if (existsSync12(resolved)) return resolved;
7924
8420
  } else {
7925
- if (existsSync11(normalized)) return normalized;
8421
+ if (existsSync12(normalized)) return normalized;
7926
8422
  }
7927
8423
  }
7928
8424
  return null;
@@ -7936,7 +8432,7 @@ async function detectIDEs(providerLoader) {
7936
8432
  let resolvedCli = cliPath;
7937
8433
  if (!resolvedCli && appPath && os22 === "darwin") {
7938
8434
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
7939
- if (existsSync11(bundledCli)) resolvedCli = bundledCli;
8435
+ if (existsSync12(bundledCli)) resolvedCli = bundledCli;
7940
8436
  }
7941
8437
  if (!resolvedCli && appPath && os22 === "win32") {
7942
8438
  const { dirname: dirname9 } = await import("path");
@@ -7949,7 +8445,7 @@ async function detectIDEs(providerLoader) {
7949
8445
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
7950
8446
  ];
7951
8447
  for (const c of candidates) {
7952
- if (existsSync11(c)) {
8448
+ if (existsSync12(c)) {
7953
8449
  resolvedCli = c;
7954
8450
  break;
7955
8451
  }
@@ -17105,7 +17601,7 @@ init_config();
17105
17601
  import * as os13 from "os";
17106
17602
  import * as path18 from "path";
17107
17603
  import * as crypto4 from "crypto";
17108
- import { existsSync as existsSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
17604
+ import { existsSync as existsSync16, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
17109
17605
  import { execFileSync } from "child_process";
17110
17606
  import chalk from "chalk";
17111
17607
 
@@ -19579,7 +20075,7 @@ function commandExists(command) {
19579
20075
  const trimmed = command.trim();
19580
20076
  if (!trimmed) return false;
19581
20077
  if (isExplicitCommand(trimmed)) {
19582
- return existsSync15(expandExecutable(trimmed));
20078
+ return existsSync16(expandExecutable(trimmed));
19583
20079
  }
19584
20080
  try {
19585
20081
  execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -22843,15 +23339,15 @@ cleanOldFiles();
22843
23339
 
22844
23340
  // src/commands/router.ts
22845
23341
  init_logger();
22846
- import * as yaml from "js-yaml";
23342
+ import * as yaml2 from "js-yaml";
22847
23343
 
22848
23344
  // src/commands/mesh-coordinator.ts
22849
23345
  import { execFileSync as execFileSync2 } from "child_process";
22850
- import { createHash as createHash2 } from "crypto";
22851
- import { existsSync as existsSync18, readdirSync as readdirSync7, realpathSync as realpathSync2 } from "fs";
23346
+ import { createHash as createHash3 } from "crypto";
23347
+ import { existsSync as existsSync19, readdirSync as readdirSync7, realpathSync as realpathSync2 } from "fs";
22852
23348
  import { createRequire as createRequire2 } from "module";
22853
23349
  import * as os17 from "os";
22854
- import { dirname as dirname4, isAbsolute as isAbsolute11, join as join21, resolve as resolve13 } from "path";
23350
+ import { dirname as dirname4, isAbsolute as isAbsolute11, join as join22, resolve as resolve13 } from "path";
22855
23351
  var DEFAULT_SERVER_NAME = "adhdev-mesh";
22856
23352
  var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
22857
23353
  var HERMES_CLI_TYPE = "hermes-cli";
@@ -22874,7 +23370,7 @@ function resolveHermesMeshCoordinatorSetup(options) {
22874
23370
  reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
22875
23371
  };
22876
23372
  }
22877
- const configPath = join21(resolveHermesCoordinatorHome(options.meshId, options.workspace), "config.yaml");
23373
+ const configPath = join22(resolveHermesCoordinatorHome(options.meshId, options.workspace), "config.yaml");
22878
23374
  if (!configPath.trim()) {
22879
23375
  return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
22880
23376
  }
@@ -22994,15 +23490,15 @@ function renderMeshCoordinatorTemplate(template, values) {
22994
23490
  function resolveHermesCoordinatorHome(meshId, workspace) {
22995
23491
  const key = `${meshId || "mesh"}
22996
23492
  ${resolve13(workspace || os17.tmpdir())}`;
22997
- const hash = createHash2("sha256").update(key).digest("hex").slice(0, 16);
22998
- return join21(os17.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash}`);
23493
+ const hash = createHash3("sha256").update(key).digest("hex").slice(0, 16);
23494
+ return join22(os17.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash}`);
22999
23495
  }
23000
23496
  function resolveMcpConfigPath(configPath, workspace) {
23001
23497
  const trimmed = configPath.trim();
23002
23498
  if (trimmed === "~") return os17.homedir();
23003
- if (trimmed.startsWith("~/")) return join21(os17.homedir(), trimmed.slice(2));
23499
+ if (trimmed.startsWith("~/")) return join22(os17.homedir(), trimmed.slice(2));
23004
23500
  if (isAbsolute11(trimmed)) return trimmed;
23005
- return join21(workspace, trimmed);
23501
+ return join22(workspace, trimmed);
23006
23502
  }
23007
23503
  function resolveAdhdevMcpServerLaunch(options) {
23008
23504
  const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
@@ -23058,15 +23554,15 @@ function addNodeCandidatesFromPath(pathValue, addCandidate) {
23058
23554
  for (const entry of (pathValue || "").split(":")) {
23059
23555
  const dir = entry.trim();
23060
23556
  if (!dir) continue;
23061
- addCandidate(join21(dir, "node"));
23557
+ addCandidate(join22(dir, "node"));
23062
23558
  }
23063
23559
  }
23064
23560
  function addNodeCandidatesFromNvm(homeDir, addCandidate) {
23065
- const versionsDir = join21(homeDir, ".nvm", "versions", "node");
23561
+ const versionsDir = join22(homeDir, ".nvm", "versions", "node");
23066
23562
  try {
23067
23563
  const versionDirs = readdirSync7(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
23068
23564
  for (const versionDir of versionDirs) {
23069
- addCandidate(join21(versionsDir, versionDir, "bin", "node"));
23565
+ addCandidate(join22(versionsDir, versionDir, "bin", "node"));
23070
23566
  }
23071
23567
  } catch {
23072
23568
  }
@@ -23117,7 +23613,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
23117
23613
  if (normalized) return normalized;
23118
23614
  }
23119
23615
  try {
23120
- const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join21(process.cwd(), "adhdev-daemon.js");
23616
+ const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join22(process.cwd(), "adhdev-daemon.js");
23121
23617
  const req = createRequire2(requireBase);
23122
23618
  const resolvedModule = req.resolve("@adhdev/mcp-server");
23123
23619
  return normalizeExistingPath(resolvedModule) || resolvedModule;
@@ -23127,7 +23623,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
23127
23623
  }
23128
23624
  function normalizeExistingPath(filePath) {
23129
23625
  try {
23130
- if (!existsSync18(filePath)) return null;
23626
+ if (!existsSync19(filePath)) return null;
23131
23627
  return realpathSync2.native(filePath);
23132
23628
  } catch {
23133
23629
  return null;
@@ -23136,6 +23632,7 @@ function normalizeExistingPath(filePath) {
23136
23632
 
23137
23633
  // src/commands/router.ts
23138
23634
  init_mesh_events();
23635
+ init_mesh_host_ownership();
23139
23636
 
23140
23637
  // src/status/snapshot.ts
23141
23638
  init_config();
@@ -24431,11 +24928,9 @@ async function resolveProviderTypeFromPriority(args) {
24431
24928
  }
24432
24929
  return { error: `No usable provider detected for node '${args.nodeId}' from providerPriority: ${failed.join("; ")}` };
24433
24930
  }
24434
- var REFINE_VALIDATION_CATEGORIES = ["typecheck", "test", "lint", "build"];
24435
24931
  var REFINE_VALIDATION_TIMEOUT_MS = 12e4;
24436
24932
  var REFINE_VALIDATION_OUTPUT_LIMIT_BYTES = 128 * 1024;
24437
24933
  var REFINE_VALIDATION_SUMMARY_CHARS = 2e3;
24438
- var REFINE_VALIDATION_MAX_COMMANDS = 4;
24439
24934
  var REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
24440
24935
  function truncateValidationOutput(value) {
24441
24936
  const text = typeof value === "string" ? value : value == null ? "" : String(value);
@@ -24519,141 +25014,30 @@ async function runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead)
24519
25014
  };
24520
25015
  }
24521
25016
  }
24522
- function readPackageScripts(workspace) {
24523
- try {
24524
- const packageJsonPath = pathJoin(workspace, "package.json");
24525
- const parsed = JSON.parse(fs10.readFileSync(packageJsonPath, "utf-8"));
24526
- return parsed?.scripts && typeof parsed.scripts === "object" && !Array.isArray(parsed.scripts) ? parsed.scripts : {};
24527
- } catch {
24528
- return {};
24529
- }
24530
- }
24531
- function tokenizeValidationCommand(command) {
24532
- const trimmed = command.trim();
24533
- if (!trimmed) return null;
24534
- if (/[;&|<>`$\\\n\r'\"]/.test(trimmed)) return null;
24535
- const tokens = trimmed.split(/\s+/).filter(Boolean);
24536
- if (!tokens.length) return null;
24537
- if (tokens.some((token) => !/^[A-Za-z0-9_@./:=+-]+$/.test(token))) return null;
24538
- return tokens;
24539
- }
24540
- function scriptMatchesValidationCategory(scriptName, category) {
24541
- return scriptName === category || scriptName.startsWith(`${category}:`);
24542
- }
24543
- function parsePackageManagerValidationCommand(rawCommand, category, scripts, source) {
24544
- const tokens = tokenizeValidationCommand(rawCommand);
24545
- if (!tokens) {
24546
- return { rejected: { command: rawCommand, category, source, reason: "unsafe command string is not allowlisted" } };
24547
- }
24548
- const [binary, second, third, ...rest] = tokens;
24549
- let scriptName = "";
24550
- let command = binary;
24551
- let args = [];
24552
- if ((binary === "npm" || binary === "pnpm" || binary === "bun") && second === "run" && third) {
24553
- scriptName = third;
24554
- args = ["run", scriptName, ...rest];
24555
- } else if (binary === "npm" && second === "test" && !third) {
24556
- scriptName = "test";
24557
- args = ["test"];
24558
- } else if (binary === "yarn" && second === "run" && third) {
24559
- scriptName = third;
24560
- args = ["run", scriptName, ...rest];
24561
- } else if (binary === "yarn" && second && !third) {
24562
- scriptName = second;
24563
- args = [scriptName];
24564
- } else {
24565
- return { rejected: { command: rawCommand, category, source, reason: "command is not a supported package-manager script invocation" } };
24566
- }
24567
- if (!scriptName || !Object.prototype.hasOwnProperty.call(scripts, scriptName)) {
24568
- return { rejected: { command: rawCommand, category, source, script: scriptName, reason: "script is not declared in package.json" } };
24569
- }
24570
- if (!scriptMatchesValidationCategory(scriptName, category)) {
24571
- return { rejected: { command: rawCommand, category, source, script: scriptName, reason: "script name is outside the validation category allowlist" } };
24572
- }
24573
- return {
24574
- command: {
24575
- command,
24576
- args,
24577
- displayCommand: [command, ...args].join(" "),
24578
- category,
24579
- source
24580
- }
24581
- };
24582
- }
24583
- function collectProjectContextValidationCandidates(mesh) {
24584
- const commands = mesh?.projectContext?.commands;
24585
- if (!commands || typeof commands !== "object" || Array.isArray(commands)) return [];
24586
- const candidates = [];
24587
- for (const category of REFINE_VALIDATION_CATEGORIES) {
24588
- const entries = Array.isArray(commands[category]) ? commands[category] : [];
24589
- for (const entry of entries) {
24590
- if (typeof entry?.command !== "string") continue;
24591
- candidates.push({
24592
- command: entry.command,
24593
- category,
24594
- source: typeof entry.sourcePath === "string" ? entry.sourcePath : "projectContext.commands",
24595
- confidence: typeof entry.confidence === "string" ? entry.confidence : void 0
24596
- });
24597
- }
24598
- }
24599
- return candidates.sort((a, b) => {
24600
- const rank = (value) => value === "high" ? 0 : value === "medium" ? 1 : 2;
24601
- return rank(a.confidence) - rank(b.confidence);
24602
- });
24603
- }
24604
- function collectPolicyValidationCandidates(mesh) {
24605
- const policy = mesh?.policy && typeof mesh.policy === "object" && !Array.isArray(mesh.policy) ? mesh.policy : {};
24606
- const configured = Array.isArray(policy.validationCommands) ? policy.validationCommands : Array.isArray(policy.validationGate?.commands) ? policy.validationGate.commands : [];
24607
- return configured.map((entry) => typeof entry === "string" ? { command: entry, category: "", source: "mesh.policy.validationCommands" } : entry).filter((entry) => entry && typeof entry.command === "string").map((entry) => {
24608
- const commandText = entry.command.trim();
24609
- const category = REFINE_VALIDATION_CATEGORIES.find((cat) => commandText.includes(` ${cat}`)) ?? "";
24610
- return { command: commandText, category, source: "mesh.policy.validationCommands" };
24611
- }).filter((entry) => !!entry.category);
24612
- }
24613
- function selectMeshRefineValidationCommands(mesh, workspace) {
24614
- const scripts = readPackageScripts(workspace);
24615
- const rejectedCommands = [];
24616
- const selected = [];
24617
- const seen = /* @__PURE__ */ new Set();
24618
- const candidates = [
24619
- ...collectPolicyValidationCandidates(mesh),
24620
- ...collectProjectContextValidationCandidates(mesh)
24621
- ];
24622
- for (const candidate of candidates) {
24623
- const parsed = parsePackageManagerValidationCommand(candidate.command, candidate.category, scripts, candidate.source);
24624
- if (parsed.rejected) {
24625
- rejectedCommands.push(parsed.rejected);
24626
- continue;
24627
- }
24628
- if (!parsed.command || seen.has(parsed.command.displayCommand)) continue;
24629
- selected.push(parsed.command);
24630
- seen.add(parsed.command.displayCommand);
24631
- if (selected.length >= REFINE_VALIDATION_MAX_COMMANDS) break;
24632
- }
24633
- if (!selected.length && candidates.length === 0) {
24634
- for (const category of REFINE_VALIDATION_CATEGORIES) {
24635
- if (!Object.prototype.hasOwnProperty.call(scripts, category)) continue;
24636
- const fallback = parsePackageManagerValidationCommand(`npm run ${category}`, category, scripts, "package.json:scripts");
24637
- if (fallback.command && !seen.has(fallback.command.displayCommand)) {
24638
- selected.push(fallback.command);
24639
- seen.add(fallback.command.displayCommand);
24640
- } else if (fallback.rejected) {
24641
- rejectedCommands.push(fallback.rejected);
24642
- }
24643
- if (selected.length >= 2) break;
24644
- }
24645
- }
25017
+ function buildMeshRefineValidationPlan(mesh, workspace) {
25018
+ const plan = resolveMeshRefineValidationPlan(mesh, workspace);
24646
25019
  return {
24647
- commands: selected,
24648
- rejectedCommands,
24649
- 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"
25020
+ source: plan.source,
25021
+ sourceType: plan.sourceType,
25022
+ commands: plan.commands.map((command) => ({
25023
+ displayCommand: command.displayCommand,
25024
+ category: command.category,
25025
+ source: command.source,
25026
+ cwd: command.cwd,
25027
+ timeoutMs: command.timeoutMs
25028
+ })),
25029
+ unavailableReason: plan.unavailableReason,
25030
+ rejectedCommands: plan.rejectedCommands,
25031
+ suggestions: plan.suggestions,
25032
+ suggestedConfig: plan.suggestedConfig,
25033
+ 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."
24650
25034
  };
24651
25035
  }
24652
25036
  async function runMeshRefineValidationGate(mesh, workspace) {
24653
25037
  const { execFile: execFile3 } = await import("child_process");
24654
25038
  const { promisify: promisify3 } = await import("util");
24655
25039
  const execFileAsync3 = promisify3(execFile3);
24656
- const selection = selectMeshRefineValidationCommands(mesh, workspace);
25040
+ const selection = resolveMeshRefineValidationPlan(mesh, workspace);
24657
25041
  const summary = {
24658
25042
  status: "skipped",
24659
25043
  required: true,
@@ -24661,21 +25045,27 @@ async function runMeshRefineValidationGate(mesh, workspace) {
24661
25045
  rejectedCommands: selection.rejectedCommands,
24662
25046
  skippedReason: void 0,
24663
25047
  timeoutMs: REFINE_VALIDATION_TIMEOUT_MS,
24664
- outputLimitBytes: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES
25048
+ outputLimitBytes: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES,
25049
+ configSource: selection.source,
25050
+ configSourceType: selection.sourceType,
25051
+ suggestions: selection.suggestions,
25052
+ suggestedConfig: selection.suggestedConfig
24665
25053
  };
24666
25054
  if (!selection.commands.length) {
24667
- summary.skippedReason = "validation_unavailable: no allowlisted projectContext, mesh policy, or package.json build/test/typecheck/lint command was available";
25055
+ summary.skippedReason = selection.unavailableReason || "validation_unavailable: repo mesh/refine config did not provide executable validation.commands";
24668
25056
  return summary;
24669
25057
  }
24670
25058
  for (const candidate of selection.commands) {
24671
25059
  const startedAt = Date.now();
25060
+ const cwd = candidate.cwd ? pathResolve(workspace, candidate.cwd) : workspace;
25061
+ const timeout = candidate.timeoutMs || REFINE_VALIDATION_TIMEOUT_MS;
24672
25062
  try {
24673
25063
  const result = await execFileAsync3(candidate.command, candidate.args, {
24674
- cwd: workspace,
25064
+ cwd,
24675
25065
  encoding: "utf8",
24676
- timeout: REFINE_VALIDATION_TIMEOUT_MS,
25066
+ timeout,
24677
25067
  maxBuffer: REFINE_VALIDATION_OUTPUT_LIMIT_BYTES,
24678
- env: { ...process.env, CI: process.env.CI || "1" }
25068
+ env: { ...process.env, CI: process.env.CI || "1", ...candidate.env || {} }
24679
25069
  });
24680
25070
  summary.commandsRun.push({
24681
25071
  command: candidate.command,
@@ -24683,6 +25073,7 @@ async function runMeshRefineValidationGate(mesh, workspace) {
24683
25073
  displayCommand: candidate.displayCommand,
24684
25074
  category: candidate.category,
24685
25075
  source: candidate.source,
25076
+ cwd,
24686
25077
  passed: true,
24687
25078
  exitCode: 0,
24688
25079
  durationMs: Date.now() - startedAt,
@@ -24696,6 +25087,7 @@ async function runMeshRefineValidationGate(mesh, workspace) {
24696
25087
  displayCommand: candidate.displayCommand,
24697
25088
  category: candidate.category,
24698
25089
  source: candidate.source,
25090
+ cwd,
24699
25091
  passed: false,
24700
25092
  exitCode: typeof error?.code === "number" ? error.code : null,
24701
25093
  signal: typeof error?.signal === "string" ? error.signal : null,
@@ -24712,7 +25104,7 @@ async function runMeshRefineValidationGate(mesh, workspace) {
24712
25104
  return summary;
24713
25105
  }
24714
25106
  function loadYamlModule() {
24715
- return yaml;
25107
+ return yaml2;
24716
25108
  }
24717
25109
  function getMcpServersKey(format) {
24718
25110
  return format === "hermes_config_yaml" ? "mcp_servers" : "mcpServers";
@@ -24870,6 +25262,34 @@ function summarizeSessionHostPruneResult(result) {
24870
25262
  keptCount: Array.isArray(value.keptSessionIds) ? value.keptSessionIds.length : void 0
24871
25263
  };
24872
25264
  }
25265
+ function normalizeStandaloneHostCommandUrl(hostAddress) {
25266
+ const raw = hostAddress.trim();
25267
+ if (!raw) throw new Error("hostAddress required");
25268
+ const url = new URL(raw.replace(/^ws:/, "http:").replace(/^wss:/, "https:"));
25269
+ url.pathname = "/api/v1/command";
25270
+ url.search = "";
25271
+ url.hash = "";
25272
+ return url.toString();
25273
+ }
25274
+ function buildMemberJoinNode(mesh, args, fallbackDaemonId) {
25275
+ const requestedNodeId = typeof args?.memberNodeId === "string" ? args.memberNodeId.trim() : "";
25276
+ const explicit = args?.memberNode && typeof args.memberNode === "object" && !Array.isArray(args.memberNode) ? args.memberNode : null;
25277
+ const configured = Array.isArray(mesh?.nodes) ? requestedNodeId ? mesh.nodes.find((node) => node?.id === requestedNodeId || node?.nodeId === requestedNodeId) : mesh.nodes[0] : null;
25278
+ const source = explicit || configured;
25279
+ const workspace = typeof source?.workspace === "string" && source.workspace.trim() ? source.workspace.trim() : typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : process.cwd();
25280
+ if (!workspace) return null;
25281
+ const nodeId = typeof source?.id === "string" && source.id.trim() ? source.id.trim() : typeof source?.nodeId === "string" && source.nodeId.trim() ? source.nodeId.trim() : void 0;
25282
+ return {
25283
+ ...nodeId ? { id: nodeId } : {},
25284
+ workspace,
25285
+ ...typeof source?.repoRoot === "string" && source.repoRoot.trim() ? { repoRoot: source.repoRoot.trim() } : {},
25286
+ ...typeof source?.daemonId === "string" && source.daemonId.trim() ? { daemonId: source.daemonId.trim() } : fallbackDaemonId ? { daemonId: fallbackDaemonId } : {},
25287
+ ...typeof source?.machineId === "string" && source.machineId.trim() ? { machineId: source.machineId.trim() } : {},
25288
+ userOverrides: source?.userOverrides && typeof source.userOverrides === "object" && !Array.isArray(source.userOverrides) ? source.userOverrides : {},
25289
+ policy: source?.policy && typeof source.policy === "object" && !Array.isArray(source.policy) ? source.policy : {},
25290
+ role: "member"
25291
+ };
25292
+ }
24873
25293
  var DaemonCommandRouter = class {
24874
25294
  deps;
24875
25295
  /** In-memory cache for cloud-originating meshes passed via inlineMesh.
@@ -25043,6 +25463,16 @@ var DaemonCommandRouter = class {
25043
25463
  invalidateAggregateMeshStatus(meshId) {
25044
25464
  this.aggregateMeshStatusCache.delete(meshId);
25045
25465
  }
25466
+ async requireMeshHostMutationOwner(meshId, inlineMesh, operation) {
25467
+ const meshRecord = await this.getMeshForCommand(meshId, inlineMesh, { preferInline: true });
25468
+ const mesh = meshRecord?.mesh;
25469
+ if (!mesh) return { success: false, error: "Mesh not found" };
25470
+ const meshHost = resolveMeshHostStatus(mesh);
25471
+ if (!meshHost.canOwnCoordinator || !meshHost.canOwnQueue) {
25472
+ return { ...buildMeshHostRequiredFailure(mesh, operation), success: false, meshId };
25473
+ }
25474
+ return null;
25475
+ }
25046
25476
  updateInlineMeshNode(meshId, mesh, node) {
25047
25477
  if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
25048
25478
  const idx = mesh.nodes.findIndex((entry) => entry?.id === node.id || entry?.nodeId === node.id);
@@ -26081,7 +26511,8 @@ var DaemonCommandRouter = class {
26081
26511
  if (!name) return { success: false, error: "name required" };
26082
26512
  try {
26083
26513
  const { createMesh: createMesh2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26084
- const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy });
26514
+ const meshHost = args?.meshHost && typeof args.meshHost === "object" && !Array.isArray(args.meshHost) ? args.meshHost : void 0;
26515
+ const mesh = createMesh2({ name, repoIdentity, repoRemoteUrl, defaultBranch, policy: args?.policy, meshHost });
26085
26516
  return { success: true, mesh };
26086
26517
  } catch (e) {
26087
26518
  return { success: false, error: e.message };
@@ -26097,6 +26528,7 @@ var DaemonCommandRouter = class {
26097
26528
  if (typeof args?.defaultBranch === "string") patch.defaultBranch = args.defaultBranch;
26098
26529
  if (args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy)) patch.policy = args.policy;
26099
26530
  if (args?.coordinator && typeof args.coordinator === "object" && !Array.isArray(args.coordinator)) patch.coordinator = args.coordinator;
26531
+ if (args?.meshHost && typeof args.meshHost === "object" && !Array.isArray(args.meshHost)) patch.meshHost = args.meshHost;
26100
26532
  if (!Object.keys(patch).length) return { success: false, error: "No updates provided" };
26101
26533
  const mesh = updateMesh2(meshId, patch);
26102
26534
  if (!mesh) return { success: false, error: "Mesh not found" };
@@ -26107,6 +26539,215 @@ var DaemonCommandRouter = class {
26107
26539
  return { success: false, error: e.message };
26108
26540
  }
26109
26541
  }
26542
+ case "get_mesh_host_pairing": {
26543
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26544
+ if (!meshId) return { success: false, error: "meshId required" };
26545
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
26546
+ const mesh = meshRecord?.mesh;
26547
+ if (!mesh) return { success: false, error: "Mesh not found" };
26548
+ const meshHost = resolveMeshHostStatus(mesh);
26549
+ const pairingStatus = meshHost.pairing?.status || "not_configured";
26550
+ return {
26551
+ success: true,
26552
+ code: pairingStatus === "not_configured" ? "mesh_host_pairing_not_configured" : "mesh_host_pairing_pending",
26553
+ meshId,
26554
+ hostAddress: meshHost.hostAddress,
26555
+ meshHost,
26556
+ manualPairing: {
26557
+ status: pairingStatus,
26558
+ joinImplemented: true,
26559
+ protocol: "standalone_command_direct_v1",
26560
+ 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."
26561
+ }
26562
+ };
26563
+ }
26564
+ case "configure_mesh_host_pairing": {
26565
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26566
+ const hostAddress = typeof args?.hostAddress === "string" ? args.hostAddress.trim() : "";
26567
+ const token = typeof args?.token === "string" ? args.token.trim() : "";
26568
+ if (!meshId) return { success: false, error: "meshId required" };
26569
+ if (!hostAddress || !token) return { success: false, error: "hostAddress and token required" };
26570
+ try {
26571
+ const { configureMeshHostPairing: configureMeshHostPairing2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26572
+ const configured = configureMeshHostPairing2(meshId, { hostAddress, token });
26573
+ if (!configured) return { success: false, error: "Mesh not found" };
26574
+ this.inlineMeshCache.set(meshId, configured.mesh);
26575
+ const meshHost = resolveMeshHostStatus(configured.mesh);
26576
+ return {
26577
+ success: true,
26578
+ code: "mesh_host_pairing_pending",
26579
+ meshId,
26580
+ hostAddress: configured.hostAddress,
26581
+ meshHost,
26582
+ manualPairing: {
26583
+ status: meshHost.pairing?.status || "pairing",
26584
+ joinImplemented: true,
26585
+ protocol: "standalone_command_direct_v1",
26586
+ 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."
26587
+ }
26588
+ };
26589
+ } catch (e) {
26590
+ return { success: false, code: "mesh_host_pairing_invalid", meshId, hostAddress, error: e.message };
26591
+ }
26592
+ }
26593
+ case "create_mesh_host_pairing_token": {
26594
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26595
+ if (!meshId) return { success: false, error: "meshId required" };
26596
+ try {
26597
+ const { createMeshHostPairingToken: createMeshHostPairingToken2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26598
+ const created = createMeshHostPairingToken2(meshId, {
26599
+ token: typeof args?.token === "string" ? args.token : void 0,
26600
+ expiresAt: typeof args?.expiresAt === "string" ? args.expiresAt : void 0
26601
+ });
26602
+ if (!created) return { success: false, error: "Mesh not found" };
26603
+ this.inlineMeshCache.set(meshId, created.mesh);
26604
+ this.invalidateAggregateMeshStatus(meshId);
26605
+ return {
26606
+ success: true,
26607
+ code: "mesh_host_pairing_token_created",
26608
+ meshId,
26609
+ token: created.token,
26610
+ tokenId: created.tokenId,
26611
+ expiresAt: created.expiresAt,
26612
+ meshHost: resolveMeshHostStatus(created.mesh),
26613
+ warning: "Raw token is returned once and is not persisted; share it with member daemons over a trusted channel."
26614
+ };
26615
+ } catch (e) {
26616
+ return { success: false, code: "mesh_host_pairing_token_invalid", meshId, error: e.message };
26617
+ }
26618
+ }
26619
+ case "apply_mesh_host_join": {
26620
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26621
+ const token = typeof args?.token === "string" ? args.token.trim() : "";
26622
+ const memberNode = args?.memberNode && typeof args.memberNode === "object" && !Array.isArray(args.memberNode) ? args.memberNode : null;
26623
+ if (!meshId) return { success: false, error: "meshId required" };
26624
+ if (!token || !memberNode) return { success: false, error: "token and memberNode required" };
26625
+ try {
26626
+ const { applyMeshHostJoinRequest: applyMeshHostJoinRequest2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26627
+ const applied = applyMeshHostJoinRequest2(meshId, {
26628
+ token,
26629
+ memberNode,
26630
+ memberMeshId: typeof args?.memberMeshId === "string" ? args.memberMeshId : void 0
26631
+ });
26632
+ if (!applied) return { success: false, error: "Mesh not found" };
26633
+ if (!applied.accepted) {
26634
+ return {
26635
+ success: false,
26636
+ code: "mesh_host_join_rejected",
26637
+ meshId,
26638
+ tokenId: applied.tokenId,
26639
+ meshHost: applied.meshHost ? resolveMeshHostStatus({ meshHost: applied.meshHost }) : void 0,
26640
+ error: applied.reason
26641
+ };
26642
+ }
26643
+ this.inlineMeshCache.set(meshId, applied.mesh);
26644
+ this.invalidateAggregateMeshStatus(meshId);
26645
+ try {
26646
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
26647
+ appendLedgerEntry2(meshId, {
26648
+ kind: "node_joined",
26649
+ nodeId: applied.node.id,
26650
+ payload: { role: "member", tokenId: applied.tokenId, workspace: applied.node.workspace }
26651
+ });
26652
+ } catch {
26653
+ }
26654
+ return {
26655
+ success: true,
26656
+ code: "mesh_host_join_accepted",
26657
+ meshId,
26658
+ node: applied.node,
26659
+ tokenId: applied.tokenId,
26660
+ meshHost: resolveMeshHostStatus(applied.mesh)
26661
+ };
26662
+ } catch (e) {
26663
+ return { success: false, code: "mesh_host_join_failed", meshId, error: e.message };
26664
+ }
26665
+ }
26666
+ case "join_mesh_host_pairing": {
26667
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26668
+ const token = typeof args?.token === "string" ? args.token.trim() : "";
26669
+ if (!meshId) return { success: false, error: "meshId required" };
26670
+ if (!token) return { success: false, error: "token required because raw pairing tokens are not persisted" };
26671
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
26672
+ const mesh = meshRecord?.mesh;
26673
+ if (!mesh) return { success: false, error: "Mesh not found" };
26674
+ const meshHost = resolveMeshHostStatus(mesh);
26675
+ if (meshHost.role !== "member") {
26676
+ 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." };
26677
+ }
26678
+ try {
26679
+ const { tokenIdForManualPairing: tokenIdForManualPairing2, markMeshHostPairingJoined: markMeshHostPairingJoined2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26680
+ const tokenId = tokenIdForManualPairing2(token);
26681
+ if (meshHost.pairing?.tokenId && meshHost.pairing.tokenId !== tokenId) {
26682
+ return { success: false, code: "mesh_host_join_rejected", meshId, tokenId, meshHost, error: "invalid pairing token" };
26683
+ }
26684
+ const memberNode = buildMemberJoinNode(mesh, args, this.deps.statusInstanceId);
26685
+ if (!memberNode) return { success: false, error: "member node metadata unavailable" };
26686
+ const hostMeshId = typeof args?.hostMeshId === "string" && args.hostMeshId.trim() ? args.hostMeshId.trim() : meshId;
26687
+ const hostDaemonId = typeof args?.hostDaemonId === "string" && args.hostDaemonId.trim() ? args.hostDaemonId.trim() : meshHost.hostDaemonId;
26688
+ let hostResult;
26689
+ let transport;
26690
+ if (hostDaemonId && this.deps.dispatchMeshCommand) {
26691
+ transport = "mesh_command_dispatch";
26692
+ hostResult = await this.deps.dispatchMeshCommand(hostDaemonId, "apply_mesh_host_join", {
26693
+ meshId: hostMeshId,
26694
+ token,
26695
+ memberMeshId: meshId,
26696
+ memberNode
26697
+ });
26698
+ } else if (meshHost.hostAddress) {
26699
+ transport = "standalone_http_command";
26700
+ const commandUrl = normalizeStandaloneHostCommandUrl(meshHost.hostAddress);
26701
+ const response = await fetch(commandUrl, {
26702
+ method: "POST",
26703
+ headers: { "Content-Type": "application/json" },
26704
+ body: JSON.stringify({ type: "apply_mesh_host_join", payload: { meshId: hostMeshId, token, memberMeshId: meshId, memberNode } })
26705
+ });
26706
+ hostResult = await response.json().catch(() => ({ success: false, error: `Host returned HTTP ${response.status}` }));
26707
+ if (!response.ok && hostResult?.success !== false) hostResult = { success: false, error: `Host returned HTTP ${response.status}` };
26708
+ } else {
26709
+ return {
26710
+ success: false,
26711
+ code: "mesh_host_join_transport_unavailable",
26712
+ meshId,
26713
+ meshHost,
26714
+ error: "No hostDaemonId dispatch path or hostAddress HTTP command path is available. P2P signaling join is not implemented in this slice."
26715
+ };
26716
+ }
26717
+ if (!hostResult?.success) {
26718
+ return { success: false, code: hostResult?.code || "mesh_host_join_rejected", meshId, meshHost, transport, error: hostResult?.error || "Mesh Host rejected join request", hostResult };
26719
+ }
26720
+ const joined = meshRecord.inline ? null : markMeshHostPairingJoined2(meshId, {
26721
+ tokenId: hostResult.tokenId || tokenId,
26722
+ hostDaemonId: hostResult.meshHost?.hostDaemonId || hostDaemonId,
26723
+ hostNodeId: hostResult.meshHost?.hostNodeId,
26724
+ joinedAt: hostResult.meshHost?.pairing?.joinedAt
26725
+ });
26726
+ if (joined) {
26727
+ this.inlineMeshCache.set(meshId, joined.mesh);
26728
+ this.invalidateAggregateMeshStatus(meshId);
26729
+ }
26730
+ return {
26731
+ success: true,
26732
+ code: "mesh_host_join_applied",
26733
+ meshId,
26734
+ hostMeshId,
26735
+ transport,
26736
+ node: hostResult.node,
26737
+ tokenId: hostResult.tokenId || tokenId,
26738
+ meshHost: joined ? resolveMeshHostStatus(joined.mesh) : { ...meshHost, pairing: { ...meshHost.pairing || {}, status: "paired", tokenId: hostResult.tokenId || tokenId } },
26739
+ hostResult,
26740
+ manualPairing: {
26741
+ status: "paired",
26742
+ joinImplemented: true,
26743
+ protocol: "standalone_command_direct_v1",
26744
+ description: "Mesh Host accepted the join and local member pairing status was marked paired. P2P runtime signaling remains outside this slice."
26745
+ }
26746
+ };
26747
+ } catch (e) {
26748
+ return { success: false, code: "mesh_host_join_failed", meshId, meshHost, error: e.message };
26749
+ }
26750
+ }
26110
26751
  case "delete_mesh": {
26111
26752
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26112
26753
  if (!meshId) return { success: false, error: "meshId required" };
@@ -26189,6 +26830,8 @@ var DaemonCommandRouter = class {
26189
26830
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26190
26831
  const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
26191
26832
  if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
26833
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue cancellation");
26834
+ if (ownerFailure) return ownerFailure;
26192
26835
  try {
26193
26836
  const { cancelTask: cancelTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
26194
26837
  const reason = typeof args?.reason === "string" ? args.reason : void 0;
@@ -26203,6 +26846,8 @@ var DaemonCommandRouter = class {
26203
26846
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26204
26847
  const taskId = typeof args?.taskId === "string" ? args.taskId.trim() : "";
26205
26848
  if (!meshId || !taskId) return { success: false, error: "meshId and taskId required" };
26849
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue requeue");
26850
+ if (ownerFailure) return ownerFailure;
26206
26851
  try {
26207
26852
  const { requeueTask: requeueTask2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
26208
26853
  const task = requeueTask2(meshId, taskId, {
@@ -26223,6 +26868,8 @@ var DaemonCommandRouter = class {
26223
26868
  const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
26224
26869
  if (!meshId) return { success: false, error: "meshId required" };
26225
26870
  if (!workspace) return { success: false, error: "workspace required" };
26871
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node addition");
26872
+ if (ownerFailure) return ownerFailure;
26226
26873
  try {
26227
26874
  const { addNode: addNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26228
26875
  const providerPriority = Array.isArray(args?.providerPriority) ? args.providerPriority.map((type) => typeof type === "string" ? type.trim() : "").filter(Boolean) : [];
@@ -26231,7 +26878,8 @@ var DaemonCommandRouter = class {
26231
26878
  ...readOnly ? { readOnly: true } : {},
26232
26879
  ...providerPriority.length ? { providerPriority } : {}
26233
26880
  };
26234
- const node = addNode3(meshId, { workspace, ...policy ? { policy } : {} });
26881
+ const role = normalizeMeshDaemonRole(args?.role);
26882
+ const node = addNode3(meshId, { workspace, ...policy ? { policy } : {}, ...role ? { role } : {} });
26235
26883
  if (!node) return { success: false, error: "Mesh not found" };
26236
26884
  return { success: true, node };
26237
26885
  } catch (e) {
@@ -26242,6 +26890,8 @@ var DaemonCommandRouter = class {
26242
26890
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26243
26891
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
26244
26892
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
26893
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node update");
26894
+ if (ownerFailure) return ownerFailure;
26245
26895
  try {
26246
26896
  const { updateNode: updateNode2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
26247
26897
  const policy = args?.policy && typeof args.policy === "object" && !Array.isArray(args.policy) ? { ...args.policy } : {};
@@ -26265,6 +26915,8 @@ var DaemonCommandRouter = class {
26265
26915
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26266
26916
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
26267
26917
  if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
26918
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "node removal");
26919
+ if (ownerFailure) return ownerFailure;
26268
26920
  try {
26269
26921
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
26270
26922
  const mesh = meshRecord?.mesh;
@@ -26287,6 +26939,49 @@ var DaemonCommandRouter = class {
26287
26939
  return { success: false, error: e.message };
26288
26940
  }
26289
26941
  }
26942
+ case "get_mesh_refine_config_schema": {
26943
+ return {
26944
+ success: true,
26945
+ schema: MESH_REFINE_CONFIG_SCHEMA,
26946
+ locations: MESH_REFINE_CONFIG_LOCATIONS,
26947
+ sourceOfTruth: "repo mesh/refine config",
26948
+ heuristicRole: "suggestions_only_not_execution_path"
26949
+ };
26950
+ }
26951
+ case "validate_mesh_refine_config": {
26952
+ const workspace = typeof args?.workspace === "string" ? args.workspace : process.cwd();
26953
+ const mesh = args?.inlineMesh || {};
26954
+ const loaded = args?.config !== void 0 ? { config: args.config, source: "inline", sourceType: "mesh_policy" } : loadMeshRefineConfig(mesh, workspace);
26955
+ const validation = loaded.config ? validateMeshRefineConfig(loaded.config, loaded.source) : { valid: false, errors: [loaded.error || "repo mesh/refine config unavailable"], commands: [], rejectedCommands: [] };
26956
+ return { success: validation.valid, ...loaded, ...validation };
26957
+ }
26958
+ case "suggest_mesh_refine_config": {
26959
+ const workspace = typeof args?.workspace === "string" ? args.workspace : process.cwd();
26960
+ const mesh = args?.inlineMesh || {};
26961
+ return {
26962
+ success: true,
26963
+ ...suggestMeshRefineConfig(mesh, workspace),
26964
+ note: "Suggestions are heuristic scaffold only; Refinery will not execute them until saved into repo mesh/refine config."
26965
+ };
26966
+ }
26967
+ case "plan_mesh_refine_node": {
26968
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26969
+ const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
26970
+ if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
26971
+ const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
26972
+ const mesh = meshRecord?.mesh;
26973
+ const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
26974
+ if (!node?.workspace) return { success: false, error: `Node '${nodeId}' workspace not found` };
26975
+ return {
26976
+ success: true,
26977
+ dryRun: true,
26978
+ nodeId,
26979
+ workspace: node.workspace,
26980
+ validationPlan: buildMeshRefineValidationPlan(mesh, node.workspace),
26981
+ mergeWillRun: false,
26982
+ cleanupWillRun: false
26983
+ };
26984
+ }
26290
26985
  case "refine_mesh_node": {
26291
26986
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26292
26987
  const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
@@ -26572,6 +27267,8 @@ var DaemonCommandRouter = class {
26572
27267
  if (!meshId) return { success: false, error: "meshId required" };
26573
27268
  if (!sourceNodeId) return { success: false, error: "sourceNodeId required" };
26574
27269
  if (!branch) return { success: false, error: "branch required" };
27270
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "worktree clone");
27271
+ if (ownerFailure) return ownerFailure;
26575
27272
  try {
26576
27273
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
26577
27274
  const mesh = meshRecord?.mesh;
@@ -26653,6 +27350,8 @@ var DaemonCommandRouter = class {
26653
27350
  case "trigger_mesh_queue": {
26654
27351
  const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
26655
27352
  if (!meshId) return { success: false, error: "meshId required" };
27353
+ const ownerFailure = await this.requireMeshHostMutationOwner(meshId, args?.inlineMesh, "queue trigger");
27354
+ if (ownerFailure) return ownerFailure;
26656
27355
  try {
26657
27356
  const { triggerMeshQueue: triggerMeshQueue2 } = await Promise.resolve().then(() => (init_mesh_events(), mesh_events_exports));
26658
27357
  if (meshId) {
@@ -26679,6 +27378,15 @@ var DaemonCommandRouter = class {
26679
27378
  mesh = getMesh3(meshId);
26680
27379
  }
26681
27380
  if (!mesh) return { success: false, error: "Mesh not found" };
27381
+ const meshHost = resolveMeshHostStatus(mesh);
27382
+ if (!meshHost.canOwnCoordinator) {
27383
+ return {
27384
+ success: false,
27385
+ ...buildMeshHostRequiredFailure(mesh, "coordinator launch"),
27386
+ meshId,
27387
+ cliType
27388
+ };
27389
+ }
26682
27390
  if (!Array.isArray(mesh.nodes) || mesh.nodes.length === 0) return { success: false, error: "No nodes in mesh" };
26683
27391
  const requestedCoordinatorNodeId = typeof args?.coordinatorNodeId === "string" ? args.coordinatorNodeId.trim() : "";
26684
27392
  const preferredCoordinatorNodeId = requestedCoordinatorNodeId || (typeof mesh.coordinator?.preferredNodeId === "string" ? mesh.coordinator.preferredNodeId.trim() : "");
@@ -26861,7 +27569,7 @@ ${block}`);
26861
27569
  workspace
26862
27570
  };
26863
27571
  }
26864
- const { existsSync: existsSync26, readFileSync: readFileSync18, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
27572
+ const { existsSync: existsSync27, readFileSync: readFileSync19, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
26865
27573
  const { dirname: dirname9 } = await import("path");
26866
27574
  const mcpConfigPath = coordinatorSetup.configPath;
26867
27575
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
@@ -26904,14 +27612,14 @@ ${block}`);
26904
27612
  if (hermesManualFallback) return returnManualFallback(message);
26905
27613
  return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
26906
27614
  }
26907
- const hadExistingMcpConfig = existsSync26(mcpConfigPath);
27615
+ const hadExistingMcpConfig = existsSync27(mcpConfigPath);
26908
27616
  let existingMcpConfig = hermesBaseConfig?.config || {};
26909
27617
  if (hermesBaseConfig) {
26910
27618
  copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
26911
27619
  }
26912
27620
  if (hadExistingMcpConfig) {
26913
27621
  try {
26914
- const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync18(mcpConfigPath, "utf-8"), configFormat);
27622
+ const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync19(mcpConfigPath, "utf-8"), configFormat);
26915
27623
  const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
26916
27624
  existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
26917
27625
  copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
@@ -27001,6 +27709,7 @@ ${block}`);
27001
27709
  const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
27002
27710
  const mesh = meshRecord?.mesh;
27003
27711
  if (!mesh) return { success: false, error: "Mesh not found" };
27712
+ const meshHost = resolveMeshHostStatus(mesh);
27004
27713
  const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
27005
27714
  const hadAggregateCache = this.aggregateMeshStatusCache.has(meshId);
27006
27715
  if (!refreshRequested) {
@@ -27096,6 +27805,7 @@ ${block}`);
27096
27805
  repoRoot: node.repoRoot,
27097
27806
  isLocalWorktree: node.isLocalWorktree,
27098
27807
  worktreeBranch: node.worktreeBranch,
27808
+ role: normalizeMeshDaemonRole(node.role) || (meshHost.hostNodeId && nodeId === meshHost.hostNodeId ? "host" : void 0),
27099
27809
  daemonId,
27100
27810
  machineId: node.machineId,
27101
27811
  machineStatus: node.machineStatus,
@@ -27274,9 +27984,17 @@ ${block}`);
27274
27984
  repoIdentity: mesh.repoIdentity,
27275
27985
  defaultBranch: mesh.defaultBranch,
27276
27986
  refreshedAt,
27987
+ meshHost,
27277
27988
  sourceOfTruth: {
27278
27989
  membership: meshRecord?.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord?.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
27279
27990
  coordinatorOwnsLiveTruth: directTruthSatisfied,
27991
+ meshHost: {
27992
+ owner: "mesh_host_daemon",
27993
+ localRole: meshHost.role,
27994
+ hostDaemonId: meshHost.hostDaemonId,
27995
+ hostNodeId: meshHost.hostNodeId,
27996
+ hostAddress: meshHost.hostAddress
27997
+ },
27280
27998
  ...requireDirectPeerTruth ? {
27281
27999
  currentStatus: directTruthSatisfied ? "live_git_and_session_probes" : "direct_peer_truth_unavailable",
27282
28000
  directPeerTruth: {
@@ -35364,6 +36082,8 @@ export {
35364
36082
  InMemoryGitSnapshotStore,
35365
36083
  LOG,
35366
36084
  MAX_LEDGER_SLICE_LIMIT,
36085
+ MESH_REFINE_CONFIG_LOCATIONS,
36086
+ MESH_REFINE_CONFIG_SCHEMA,
35367
36087
  MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
35368
36088
  MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
35369
36089
  MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
@@ -35386,6 +36106,7 @@ export {
35386
36106
  buildChatTailDeliverySignature,
35387
36107
  buildCoordinatorSystemPrompt,
35388
36108
  buildMachineInfo,
36109
+ buildMeshHostRequiredFailure,
35389
36110
  buildMeshLedgerReconciliationEvidence,
35390
36111
  buildMeshLedgerReplicaEvidence,
35391
36112
  buildP2pRelayFailurePayload,
@@ -35411,6 +36132,7 @@ export {
35411
36132
  connectCdpManager,
35412
36133
  createDebugTraceStore,
35413
36134
  createDefaultGitCommandServices,
36135
+ createDefaultMeshHostMetadata,
35414
36136
  createGitCompactSummary,
35415
36137
  createGitSnapshotStore,
35416
36138
  createGitWorkspaceMonitor,
@@ -35474,6 +36196,7 @@ export {
35474
36196
  isInternalChatMessage,
35475
36197
  isManagedStatusWaiting,
35476
36198
  isManagedStatusWorking,
36199
+ isMeshHostOwner,
35477
36200
  isP2pRelayTransportFailure,
35478
36201
  isPathInside,
35479
36202
  isSessionHostLiveRuntime,
@@ -35487,6 +36210,7 @@ export {
35487
36210
  listMeshes,
35488
36211
  listWorktrees,
35489
36212
  loadConfig,
36213
+ loadMeshRefineConfig,
35490
36214
  loadState,
35491
36215
  logCommand,
35492
36216
  markSetupComplete,
@@ -35500,6 +36224,7 @@ export {
35500
36224
  normalizeGitWorkspaceSubscriptionParams,
35501
36225
  normalizeInputEnvelope,
35502
36226
  normalizeManagedStatus,
36227
+ normalizeMeshDaemonRole,
35503
36228
  normalizeMessageParts,
35504
36229
  normalizeRepoIdentity,
35505
36230
  normalizeSessionModalFields,
@@ -35520,6 +36245,7 @@ export {
35520
36245
  removeNode,
35521
36246
  removeWorktree,
35522
36247
  requeueTask,
36248
+ requireMeshHostQueueOwner,
35523
36249
  resetConfig,
35524
36250
  resetDebugRuntimeConfig,
35525
36251
  resetState,
@@ -35527,6 +36253,8 @@ export {
35527
36253
  resolveCurrentGlobalInstallSurface,
35528
36254
  resolveDebugRuntimeConfig,
35529
36255
  resolveGitRepository,
36256
+ resolveMeshHostStatus,
36257
+ resolveMeshRefineValidationPlan,
35530
36258
  resolveSessionHostAppName,
35531
36259
  resolveSessionHostAppNameResolution,
35532
36260
  resolveWorktreePath,
@@ -35542,6 +36270,7 @@ export {
35542
36270
  shutdownDaemonComponents,
35543
36271
  spawnDetachedDaemonUpgradeHelper,
35544
36272
  startDaemonDevSupport,
36273
+ suggestMeshRefineConfig,
35545
36274
  summarizeGitStatus,
35546
36275
  syncMeshes,
35547
36276
  triggerMeshQueue,
@@ -35550,6 +36279,7 @@ export {
35550
36279
  updateNode,
35551
36280
  updateSessionTaskStatus,
35552
36281
  updateTaskStatus,
35553
- upsertSavedProviderSession
36282
+ upsertSavedProviderSession,
36283
+ validateMeshRefineConfig
35554
36284
  };
35555
36285
  //# sourceMappingURL=index.mjs.map