@adhdev/daemon-core 0.9.82-rc.22 → 0.9.82-rc.24

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
@@ -1360,6 +1360,36 @@ function getQueuePath(meshId) {
1360
1360
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1361
1361
  return (0, import_path4.join)(getLedgerDir(), `${safe}.queue.json`);
1362
1362
  }
1363
+ function getLockPath(meshId) {
1364
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1365
+ return (0, import_path4.join)(getLedgerDir(), `${safe}.queue.lock`);
1366
+ }
1367
+ function withQueueLock(meshId, fn) {
1368
+ const lockPath = getLockPath(meshId);
1369
+ let fd = -1;
1370
+ for (let i = 0; i < 10; i++) {
1371
+ try {
1372
+ fd = (0, import_fs4.openSync)(lockPath, "wx");
1373
+ break;
1374
+ } catch {
1375
+ const deadline = Date.now() + 30;
1376
+ while (Date.now() < deadline) {
1377
+ }
1378
+ }
1379
+ }
1380
+ try {
1381
+ return fn();
1382
+ } finally {
1383
+ if (fd !== -1) try {
1384
+ (0, import_fs4.closeSync)(fd);
1385
+ } catch {
1386
+ }
1387
+ try {
1388
+ (0, import_fs4.unlinkSync)(lockPath);
1389
+ } catch {
1390
+ }
1391
+ }
1392
+ }
1363
1393
  function readQueue(meshId) {
1364
1394
  const path28 = getQueuePath(meshId);
1365
1395
  if (!(0, import_fs4.existsSync)(path28)) return [];
@@ -1375,20 +1405,22 @@ function writeQueue(meshId, queue) {
1375
1405
  (0, import_fs4.writeFileSync)(path28, JSON.stringify(queue, null, 2), "utf-8");
1376
1406
  }
1377
1407
  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;
1408
+ return withQueueLock(meshId, () => {
1409
+ const queue = readQueue(meshId);
1410
+ const entry = {
1411
+ id: (0, import_crypto5.randomUUID)(),
1412
+ meshId,
1413
+ message,
1414
+ status: "pending",
1415
+ targetNodeId: opts?.targetNodeId,
1416
+ targetSessionId: opts?.targetSessionId,
1417
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1418
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1419
+ };
1420
+ queue.push(entry);
1421
+ writeQueue(meshId, queue);
1422
+ return entry;
1423
+ });
1392
1424
  }
1393
1425
  function getQueue(meshId, opts) {
1394
1426
  let queue = readQueue(meshId);
@@ -1399,100 +1431,109 @@ function getQueue(meshId, opts) {
1399
1431
  return queue;
1400
1432
  }
1401
1433
  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;
1434
+ return withQueueLock(meshId, () => {
1435
+ const queue = readQueue(meshId);
1436
+ const hasActiveAssignment = queue.some((q) => q.status === "assigned" && (q.assignedSessionId === sessionId || q.assignedNodeId === nodeId));
1437
+ if (hasActiveAssignment) return null;
1438
+ let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetSessionId === sessionId);
1439
+ if (targetIdx === -1) {
1440
+ targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId && !q.targetSessionId);
1441
+ }
1442
+ if (targetIdx === -1) {
1443
+ targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId && !q.targetSessionId);
1444
+ }
1445
+ if (targetIdx === -1) return null;
1446
+ const entry = queue[targetIdx];
1447
+ entry.status = "assigned";
1448
+ entry.assignedNodeId = nodeId;
1449
+ entry.assignedSessionId = sessionId;
1450
+ entry.dispatchTimestamp = (/* @__PURE__ */ new Date()).toISOString();
1451
+ entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1452
+ writeQueue(meshId, queue);
1453
+ return entry;
1454
+ });
1421
1455
  }
1422
1456
  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];
1457
+ return withQueueLock(meshId, () => {
1458
+ const queue = readQueue(meshId);
1459
+ const idx = queue.findIndex((q) => q.id === taskId);
1460
+ if (idx === -1) return null;
1461
+ queue[idx].status = status;
1462
+ queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1463
+ writeQueue(meshId, queue);
1464
+ return queue[idx];
1465
+ });
1430
1466
  }
1431
1467
  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];
1468
+ return withQueueLock(meshId, () => {
1469
+ const queue = readQueue(meshId);
1470
+ const idx = queue.findIndex((q) => q.id === taskId);
1471
+ if (idx === -1) return null;
1472
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1473
+ queue[idx].autoLaunch = { ...autoLaunch, updatedAt: now };
1474
+ queue[idx].updatedAt = now;
1475
+ writeQueue(meshId, queue);
1476
+ return queue[idx];
1477
+ });
1443
1478
  }
1444
1479
  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];
1480
+ return withQueueLock(meshId, () => {
1481
+ const queue = readQueue(meshId);
1482
+ const idx = queue.findIndex((q) => q.id === taskId);
1483
+ if (idx === -1) return null;
1484
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1485
+ queue[idx].status = "cancelled";
1486
+ queue[idx].updatedAt = now;
1487
+ queue[idx].cancelledAt = now;
1488
+ if (opts?.reason) queue[idx].cancelReason = opts.reason;
1489
+ writeQueue(meshId, queue);
1490
+ return queue[idx];
1491
+ });
1455
1492
  }
1456
1493
  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;
1494
+ return withQueueLock(meshId, () => {
1495
+ const queue = readQueue(meshId);
1496
+ const idx = queue.findIndex((q) => q.id === taskId);
1497
+ if (idx === -1) return null;
1498
+ const entry = queue[idx];
1499
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1500
+ entry.status = "pending";
1501
+ delete entry.assignedNodeId;
1502
+ delete entry.assignedSessionId;
1503
+ delete entry.cancelledAt;
1504
+ delete entry.cancelReason;
1505
+ if (opts?.clearTargetNode) delete entry.targetNodeId;
1506
+ if (typeof opts?.targetNodeId === "string") entry.targetNodeId = opts.targetNodeId;
1507
+ if (opts?.clearTargetSession !== false) delete entry.targetSessionId;
1508
+ if (typeof opts?.targetSessionId === "string") entry.targetSessionId = opts.targetSessionId;
1509
+ entry.updatedAt = now;
1510
+ entry.requeuedAt = now;
1511
+ entry.requeueCount = (entry.requeueCount || 0) + 1;
1512
+ if (opts?.reason) entry.requeueReason = opts.reason;
1513
+ writeQueue(meshId, queue);
1514
+ return entry;
1515
+ });
1477
1516
  }
1478
1517
  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") {
1484
- const time = new Date(queue[i].dispatchTimestamp || queue[i].updatedAt).getTime();
1485
- if (time > bestTime) {
1486
- bestTime = time;
1487
- bestIdx = i;
1488
- }
1489
- }
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];
1518
+ return withQueueLock(meshId, () => {
1519
+ const queue = readQueue(meshId);
1520
+ let bestIdx = -1;
1521
+ let bestTime = 0;
1522
+ for (let i = queue.length - 1; i >= 0; i--) {
1523
+ if (queue[i].assignedSessionId === sessionId && queue[i].status === "assigned") {
1524
+ const time = new Date(queue[i].dispatchTimestamp || queue[i].updatedAt).getTime();
1525
+ if (time > bestTime) {
1526
+ bestTime = time;
1527
+ bestIdx = i;
1528
+ }
1529
+ }
1530
+ }
1531
+ if (bestIdx === -1) return null;
1532
+ queue[bestIdx].status = status;
1533
+ queue[bestIdx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1534
+ writeQueue(meshId, queue);
1535
+ return queue[bestIdx];
1536
+ });
1496
1537
  }
1497
1538
  function getMeshQueueStats(meshId) {
1498
1539
  const queue = readQueue(meshId);
@@ -1901,21 +1942,70 @@ __export(mesh_events_exports, {
1901
1942
  triggerMeshQueue: () => triggerMeshQueue,
1902
1943
  tryAssignQueueTask: () => tryAssignQueueTask
1903
1944
  });
1945
+ function sweepExpiredRemoteIdleSessions() {
1946
+ const now = Date.now();
1947
+ for (const [key, session] of remoteIdleSessions) {
1948
+ if (session.expiresAt <= now) remoteIdleSessions.delete(key);
1949
+ }
1950
+ }
1951
+ function getPendingEventsPath(meshId) {
1952
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1953
+ return (0, import_path5.join)(getLedgerDir(), `${safe}.pending-events.jsonl`);
1954
+ }
1904
1955
  function queuePendingMeshCoordinatorEvent(event) {
1905
- if (pendingMeshCoordinatorEvents.length >= MAX_PENDING_EVENTS) {
1956
+ try {
1957
+ (0, import_fs6.appendFileSync)(getPendingEventsPath(event.meshId), JSON.stringify(event) + "\n", "utf-8");
1958
+ return true;
1959
+ } catch (e) {
1960
+ LOG.warn("MeshEvents", `Failed to persist pending coordinator event: ${e?.message || e}`);
1906
1961
  return false;
1907
1962
  }
1908
- pendingMeshCoordinatorEvents.push(event);
1909
- return true;
1910
1963
  }
1911
- function drainPendingMeshCoordinatorEvents() {
1912
- return pendingMeshCoordinatorEvents.splice(0);
1964
+ function drainPendingMeshCoordinatorEvents(meshId) {
1965
+ if (!meshId) return [];
1966
+ const path28 = getPendingEventsPath(meshId);
1967
+ if (!(0, import_fs6.existsSync)(path28)) return [];
1968
+ try {
1969
+ const raw = (0, import_fs6.readFileSync)(path28, "utf-8");
1970
+ try {
1971
+ (0, import_fs6.unlinkSync)(path28);
1972
+ } catch {
1973
+ }
1974
+ return raw.split("\n").filter(Boolean).flatMap((line) => {
1975
+ try {
1976
+ return [JSON.parse(line)];
1977
+ } catch {
1978
+ return [];
1979
+ }
1980
+ });
1981
+ } catch {
1982
+ return [];
1983
+ }
1913
1984
  }
1914
- function getPendingMeshCoordinatorEvents() {
1915
- return pendingMeshCoordinatorEvents.slice();
1985
+ function getPendingMeshCoordinatorEvents(meshId) {
1986
+ if (!meshId) return [];
1987
+ const path28 = getPendingEventsPath(meshId);
1988
+ if (!(0, import_fs6.existsSync)(path28)) return [];
1989
+ try {
1990
+ const raw = (0, import_fs6.readFileSync)(path28, "utf-8");
1991
+ return raw.split("\n").filter(Boolean).flatMap((line) => {
1992
+ try {
1993
+ return [JSON.parse(line)];
1994
+ } catch {
1995
+ return [];
1996
+ }
1997
+ });
1998
+ } catch {
1999
+ return [];
2000
+ }
1916
2001
  }
1917
- function clearPendingMeshCoordinatorEvents() {
1918
- pendingMeshCoordinatorEvents.splice(0);
2002
+ function clearPendingMeshCoordinatorEvents(meshId) {
2003
+ if (!meshId) return;
2004
+ const path28 = getPendingEventsPath(meshId);
2005
+ if ((0, import_fs6.existsSync)(path28)) try {
2006
+ (0, import_fs6.unlinkSync)(path28);
2007
+ } catch {
2008
+ }
1919
2009
  }
1920
2010
  function readNonEmptyString(value) {
1921
2011
  return typeof value === "string" && value.trim() ? value.trim() : "";
@@ -1979,7 +2069,16 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
1979
2069
  message: task.message
1980
2070
  }).catch((e) => {
1981
2071
  LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
1982
- updateTaskStatus(meshId, task.id, "failed");
2072
+ updateTaskStatus(meshId, task.id, "pending");
2073
+ try {
2074
+ appendLedgerEntry(meshId, {
2075
+ kind: "dispatch_failed",
2076
+ nodeId,
2077
+ sessionId,
2078
+ payload: { taskId: task.id, error: e?.message, retryable: true }
2079
+ });
2080
+ } catch {
2081
+ }
1983
2082
  });
1984
2083
  return true;
1985
2084
  }
@@ -2322,9 +2421,9 @@ function injectMeshSystemMessage(components, args) {
2322
2421
  const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed");
2323
2422
  completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
2324
2423
  if (nodeId && providerType) {
2325
- setTimeout(() => {
2424
+ setImmediate(() => {
2326
2425
  tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
2327
- }, 500);
2426
+ });
2328
2427
  }
2329
2428
  }
2330
2429
  } else if (args.event === "agent:ready") {
@@ -2362,13 +2461,17 @@ function injectMeshSystemMessage(components, args) {
2362
2461
  }
2363
2462
  }
2364
2463
  if (sessionId && nodeId && providerType) {
2365
- remoteIdleSessions.set(`${nodeId}:${sessionId}`, { nodeId, sessionId, providerType });
2366
- setTimeout(() => {
2464
+ sweepExpiredRemoteIdleSessions();
2465
+ remoteIdleSessions.set(`${nodeId}:${sessionId}`, {
2466
+ nodeId,
2467
+ sessionId,
2468
+ providerType,
2469
+ expiresAt: Date.now() + REMOTE_IDLE_SESSION_TTL_MS
2470
+ });
2471
+ setImmediate(() => {
2367
2472
  const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
2368
- if (assigned) {
2369
- remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
2370
- }
2371
- }, 500);
2473
+ if (assigned) remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
2474
+ });
2372
2475
  }
2373
2476
  } else if (args.event === "agent:generating_started") {
2374
2477
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
@@ -2571,19 +2674,20 @@ function setupMeshEventForwarding(components) {
2571
2674
  });
2572
2675
  });
2573
2676
  }
2574
- var remoteIdleSessions, MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2677
+ var import_fs6, import_path5, REMOTE_IDLE_SESSION_TTL_MS, remoteIdleSessions, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2575
2678
  var init_mesh_events = __esm({
2576
2679
  "src/mesh/mesh-events.ts"() {
2577
2680
  "use strict";
2681
+ import_fs6 = require("fs");
2682
+ import_path5 = require("path");
2578
2683
  init_config();
2579
2684
  init_mesh_config();
2580
2685
  init_cli_detector();
2581
2686
  init_logger();
2582
2687
  init_mesh_ledger();
2583
2688
  init_mesh_work_queue();
2689
+ REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
2584
2690
  remoteIdleSessions = /* @__PURE__ */ new Map();
2585
- MAX_PENDING_EVENTS = 50;
2586
- pendingMeshCoordinatorEvents = [];
2587
2691
  MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
2588
2692
  "agent:generating_started",
2589
2693
  "agent:generating_completed",
@@ -7872,8 +7976,8 @@ var P2pRelayFailureError = class extends Error {
7872
7976
  };
7873
7977
 
7874
7978
  // src/config/state-store.ts
7875
- var import_fs6 = require("fs");
7876
- var import_path5 = require("path");
7979
+ var import_fs7 = require("fs");
7980
+ var import_path6 = require("path");
7877
7981
  init_config();
7878
7982
  var DEFAULT_STATE = {
7879
7983
  recentActivity: [],
@@ -7887,7 +7991,7 @@ function isPlainObject2(value) {
7887
7991
  return !!value && typeof value === "object" && !Array.isArray(value);
7888
7992
  }
7889
7993
  function getStatePath() {
7890
- return (0, import_path5.join)(getConfigDir(), "state.json");
7994
+ return (0, import_path6.join)(getConfigDir(), "state.json");
7891
7995
  }
7892
7996
  function normalizeState(raw) {
7893
7997
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -7923,11 +8027,11 @@ function normalizeState(raw) {
7923
8027
  }
7924
8028
  function loadState() {
7925
8029
  const statePath = getStatePath();
7926
- if (!(0, import_fs6.existsSync)(statePath)) {
8030
+ if (!(0, import_fs7.existsSync)(statePath)) {
7927
8031
  return { ...DEFAULT_STATE };
7928
8032
  }
7929
8033
  try {
7930
- const raw = (0, import_fs6.readFileSync)(statePath, "utf-8");
8034
+ const raw = (0, import_fs7.readFileSync)(statePath, "utf-8");
7931
8035
  return normalizeState(JSON.parse(raw));
7932
8036
  } catch {
7933
8037
  return { ...DEFAULT_STATE };
@@ -7936,7 +8040,7 @@ function loadState() {
7936
8040
  function saveState(state) {
7937
8041
  const statePath = getStatePath();
7938
8042
  const normalized = normalizeState(state);
7939
- (0, import_fs6.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
8043
+ (0, import_fs7.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
7940
8044
  }
7941
8045
  function resetState() {
7942
8046
  saveState({ ...DEFAULT_STATE });
@@ -7944,7 +8048,7 @@ function resetState() {
7944
8048
 
7945
8049
  // src/detection/ide-detector.ts
7946
8050
  var import_child_process2 = require("child_process");
7947
- var import_fs7 = require("fs");
8051
+ var import_fs8 = require("fs");
7948
8052
  var import_os2 = require("os");
7949
8053
  var path10 = __toESM(require("path"));
7950
8054
  var BUILTIN_IDE_DEFINITIONS = [];
@@ -7968,7 +8072,7 @@ function findCliCommand(command) {
7968
8072
  if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
7969
8073
  const candidate = trimmed.startsWith("~") ? path10.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
7970
8074
  const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
7971
- return (0, import_fs7.existsSync)(resolved) ? resolved : null;
8075
+ return (0, import_fs8.existsSync)(resolved) ? resolved : null;
7972
8076
  }
7973
8077
  try {
7974
8078
  const result = (0, import_child_process2.execSync)(
@@ -7999,9 +8103,9 @@ function checkPathExists(paths) {
7999
8103
  if (normalized.includes("*")) {
8000
8104
  const username = home.split(/[\\/]/).pop() || "";
8001
8105
  const resolved = normalized.replace("*", username);
8002
- if ((0, import_fs7.existsSync)(resolved)) return resolved;
8106
+ if ((0, import_fs8.existsSync)(resolved)) return resolved;
8003
8107
  } else {
8004
- if ((0, import_fs7.existsSync)(normalized)) return normalized;
8108
+ if ((0, import_fs8.existsSync)(normalized)) return normalized;
8005
8109
  }
8006
8110
  }
8007
8111
  return null;
@@ -8015,7 +8119,7 @@ async function detectIDEs(providerLoader) {
8015
8119
  let resolvedCli = cliPath;
8016
8120
  if (!resolvedCli && appPath && os22 === "darwin") {
8017
8121
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
8018
- if ((0, import_fs7.existsSync)(bundledCli)) resolvedCli = bundledCli;
8122
+ if ((0, import_fs8.existsSync)(bundledCli)) resolvedCli = bundledCli;
8019
8123
  }
8020
8124
  if (!resolvedCli && appPath && os22 === "win32") {
8021
8125
  const { dirname: dirname9 } = await import("path");
@@ -8028,7 +8132,7 @@ async function detectIDEs(providerLoader) {
8028
8132
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
8029
8133
  ];
8030
8134
  for (const c of candidates) {
8031
- if ((0, import_fs7.existsSync)(c)) {
8135
+ if ((0, import_fs8.existsSync)(c)) {
8032
8136
  resolvedCli = c;
8033
8137
  break;
8034
8138
  }
@@ -17181,7 +17285,7 @@ var DaemonCommandHandler = class {
17181
17285
  var os13 = __toESM(require("os"));
17182
17286
  var path18 = __toESM(require("path"));
17183
17287
  var crypto4 = __toESM(require("crypto"));
17184
- var import_fs8 = require("fs");
17288
+ var import_fs9 = require("fs");
17185
17289
  var import_child_process6 = require("child_process");
17186
17290
  var import_chalk = __toESM(require("chalk"));
17187
17291
  init_provider_cli_adapter();
@@ -19653,7 +19757,7 @@ function commandExists(command) {
19653
19757
  const trimmed = command.trim();
19654
19758
  if (!trimmed) return false;
19655
19759
  if (isExplicitCommand(trimmed)) {
19656
- return (0, import_fs8.existsSync)(expandExecutable(trimmed));
19760
+ return (0, import_fs9.existsSync)(expandExecutable(trimmed));
19657
19761
  }
19658
19762
  try {
19659
19763
  (0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -19682,10 +19786,10 @@ function hasCliArg(args, flag) {
19682
19786
  }
19683
19787
  function ensureEmptyDelegatedMcpConfig(workspace) {
19684
19788
  const baseDir = path18.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
19685
- (0, import_fs8.mkdirSync)(baseDir, { recursive: true });
19789
+ (0, import_fs9.mkdirSync)(baseDir, { recursive: true });
19686
19790
  const workspaceHash = crypto4.createHash("sha256").update(path18.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
19687
19791
  const filePath = path18.join(baseDir, `${workspaceHash}.json`);
19688
- (0, import_fs8.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
19792
+ (0, import_fs9.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
19689
19793
  return filePath;
19690
19794
  }
19691
19795
  function buildCoordinatorDelegatedCliLaunchOptions(input) {
@@ -23864,7 +23968,7 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
23864
23968
 
23865
23969
  // src/commands/router.ts
23866
23970
  var import_os3 = require("os");
23867
- var import_path6 = require("path");
23971
+ var import_path7 = require("path");
23868
23972
  var fs10 = __toESM(require("fs"));
23869
23973
  var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
23870
23974
  var CHANNEL_SERVER_URL = {
@@ -24188,8 +24292,21 @@ function summarizeMeshSessionRecord(record) {
24188
24292
  isCached: false
24189
24293
  };
24190
24294
  }
24295
+ function liveSessionRecordMatchesMeshNode(record, meshId, nodeId) {
24296
+ const recordNodeId = readStringValue(record?.meta?.meshNodeId);
24297
+ if (!recordNodeId || recordNodeId !== nodeId) return false;
24298
+ const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
24299
+ return !recordMeshId || recordMeshId === meshId;
24300
+ }
24301
+ function liveSessionRecordMatchesMeshWorkspace(record, meshId, workspace) {
24302
+ const recordWorkspace = readStringValue(record?.workspace);
24303
+ if (!recordWorkspace || !workspace || recordWorkspace !== workspace) return false;
24304
+ const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
24305
+ if (recordMeshId) return recordMeshId === meshId;
24306
+ return record?.meta?.launchedByCoordinator === true || !!readStringValue(record?.meta?.meshNodeId);
24307
+ }
24191
24308
  function readLiveMeshNodeWorkspace(args) {
24192
- const directNodeWorkspace = args.liveSessionRecords.find((record) => readStringValue(record?.meta?.meshNodeId) === args.nodeId && readStringValue(record?.workspace));
24309
+ const directNodeWorkspace = args.liveSessionRecords.find((record) => liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId) && readStringValue(record?.workspace));
24193
24310
  if (directNodeWorkspace) {
24194
24311
  return readStringValue(directNodeWorkspace.workspace) || "";
24195
24312
  }
@@ -24203,10 +24320,9 @@ function readLiveMeshNodeWorkspace(args) {
24203
24320
  }
24204
24321
  function collectLiveMeshSessionRecords(args) {
24205
24322
  const matches = args.liveSessionRecords.filter((record) => {
24206
- if (readStringValue(record?.meta?.meshNodeId) === args.nodeId) return true;
24207
- const recordWorkspace = readStringValue(record?.workspace);
24208
24323
  const nodeWorkspace = readStringValue(args.node?.workspace);
24209
- return !!recordWorkspace && !!nodeWorkspace && recordWorkspace === nodeWorkspace;
24324
+ if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)) return true;
24325
+ return !!nodeWorkspace && liveSessionRecordMatchesMeshWorkspace(record, args.meshId, nodeWorkspace);
24210
24326
  });
24211
24327
  if (args.allowCoordinatorSession) {
24212
24328
  for (const record of args.liveSessionRecords) {
@@ -24282,7 +24398,7 @@ function truncateValidationOutput(value) {
24282
24398
  }
24283
24399
  function readPackageScripts(workspace) {
24284
24400
  try {
24285
- const packageJsonPath = (0, import_path6.join)(workspace, "package.json");
24401
+ const packageJsonPath = (0, import_path7.join)(workspace, "package.json");
24286
24402
  const parsed = JSON.parse(fs10.readFileSync(packageJsonPath, "utf-8"));
24287
24403
  return parsed?.scripts && typeof parsed.scripts === "object" && !Array.isArray(parsed.scripts) ? parsed.scripts : {};
24288
24404
  } catch {
@@ -24490,13 +24606,13 @@ function serializeMeshCoordinatorMcpConfig(config, format) {
24490
24606
  }
24491
24607
  function resolveHermesUserHome() {
24492
24608
  const explicitHome = process.env.HERMES_HOME?.trim();
24493
- return explicitHome || (0, import_path6.join)((0, import_os3.homedir)(), ".hermes");
24609
+ return explicitHome || (0, import_path7.join)((0, import_os3.homedir)(), ".hermes");
24494
24610
  }
24495
24611
  function loadHermesCoordinatorBaseConfig(targetConfigPath) {
24496
24612
  const sourceHome = resolveHermesUserHome();
24497
- const sourceConfigPath = (0, import_path6.join)(sourceHome, "config.yaml");
24613
+ const sourceConfigPath = (0, import_path7.join)(sourceHome, "config.yaml");
24498
24614
  if (!fs10.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
24499
- if ((0, import_path6.resolve)(sourceConfigPath) === (0, import_path6.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
24615
+ if ((0, import_path7.resolve)(sourceConfigPath) === (0, import_path7.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
24500
24616
  const parsed = parseMeshCoordinatorMcpConfig(fs10.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
24501
24617
  const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
24502
24618
  return { config: baseConfig, sourceHome, sourceConfigPath };
@@ -24530,10 +24646,10 @@ function stripHermesCoordinatorTempModelProviderOverrides(config) {
24530
24646
  return sanitized;
24531
24647
  }
24532
24648
  function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
24533
- if ((0, import_path6.resolve)(sourceHome) === (0, import_path6.resolve)(targetHome)) return;
24649
+ if ((0, import_path7.resolve)(sourceHome) === (0, import_path7.resolve)(targetHome)) return;
24534
24650
  for (const fileName of [".env", "auth.json"]) {
24535
- const sourcePath = (0, import_path6.join)(sourceHome, fileName);
24536
- const targetPath = (0, import_path6.join)(targetHome, fileName);
24651
+ const sourcePath = (0, import_path7.join)(sourceHome, fileName);
24652
+ const targetPath = (0, import_path7.join)(targetHome, fileName);
24537
24653
  if (!fs10.existsSync(sourcePath)) continue;
24538
24654
  try {
24539
24655
  fs10.copyFileSync(sourcePath, targetPath);
@@ -24740,7 +24856,7 @@ var DaemonCommandRouter = class {
24740
24856
  }
24741
24857
  const { resolveWorktreePath: resolveWorktreePath2, listWorktrees: listWorktrees2, removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
24742
24858
  const normalizePath = (value) => {
24743
- const resolved = (0, import_path6.resolve)(value);
24859
+ const resolved = (0, import_path7.resolve)(value);
24744
24860
  try {
24745
24861
  return fs10.realpathSync(resolved);
24746
24862
  } catch {
@@ -25141,7 +25257,8 @@ var DaemonCommandRouter = class {
25141
25257
  return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
25142
25258
  }
25143
25259
  case "get_pending_mesh_events": {
25144
- const events = drainPendingMeshCoordinatorEvents();
25260
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25261
+ const events = drainPendingMeshCoordinatorEvents(meshId || void 0);
25145
25262
  return { success: true, events };
25146
25263
  }
25147
25264
  case "launch_cli":
@@ -26362,7 +26479,7 @@ ${block}`);
26362
26479
  workspace
26363
26480
  };
26364
26481
  }
26365
- const { existsSync: existsSync25, readFileSync: readFileSync17, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
26482
+ const { existsSync: existsSync26, readFileSync: readFileSync18, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
26366
26483
  const { dirname: dirname9 } = await import("path");
26367
26484
  const mcpConfigPath = coordinatorSetup.configPath;
26368
26485
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
@@ -26405,14 +26522,14 @@ ${block}`);
26405
26522
  if (hermesManualFallback) return returnManualFallback(message);
26406
26523
  return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
26407
26524
  }
26408
- const hadExistingMcpConfig = existsSync25(mcpConfigPath);
26525
+ const hadExistingMcpConfig = existsSync26(mcpConfigPath);
26409
26526
  let existingMcpConfig = hermesBaseConfig?.config || {};
26410
26527
  if (hermesBaseConfig) {
26411
26528
  copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
26412
26529
  }
26413
26530
  if (hadExistingMcpConfig) {
26414
26531
  try {
26415
- const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync17(mcpConfigPath, "utf-8"), configFormat);
26532
+ const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync18(mcpConfigPath, "utf-8"), configFormat);
26416
26533
  const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
26417
26534
  existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
26418
26535
  copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
@@ -26600,29 +26717,48 @@ ${block}`);
26600
26717
  }
26601
26718
  if (workspace) {
26602
26719
  if (!fs10.existsSync(workspace)) {
26603
- if (applyCachedInlineMeshNodeStatus(status, node)) {
26604
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26605
- nodeStatuses.push(status);
26606
- continue;
26607
- }
26608
- if (meshRecord?.source === "inline_cache" && !isSelfNode) {
26609
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26610
- nodeStatuses.push(status);
26611
- continue;
26720
+ let remoteProbeApplied = false;
26721
+ if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand) {
26722
+ try {
26723
+ const remoteResult = await Promise.race([
26724
+ this.deps.dispatchMeshCommand(daemonId, "git_status", { workspace }),
26725
+ new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 8e3))
26726
+ ]);
26727
+ const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
26728
+ if (remoteGit && typeof remoteGit === "object" && typeof remoteGit.isGitRepo === "boolean") {
26729
+ status.git = remoteGit;
26730
+ status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
26731
+ remoteProbeApplied = true;
26732
+ }
26733
+ } catch {
26734
+ }
26612
26735
  }
26613
- }
26614
- try {
26615
- const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
26616
- status.git = gitStatus;
26617
- if (gitStatus.isGitRepo) {
26618
- status.health = deriveMeshNodeHealthFromGit(gitStatus);
26619
- } else {
26620
- status.health = "degraded";
26621
- if (gitStatus.error && !status.error) status.error = gitStatus.error;
26736
+ if (!remoteProbeApplied) {
26737
+ if (applyCachedInlineMeshNodeStatus(status, node)) {
26738
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26739
+ nodeStatuses.push(status);
26740
+ continue;
26741
+ }
26742
+ if (meshRecord?.source === "inline_cache" && !isSelfNode) {
26743
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26744
+ nodeStatuses.push(status);
26745
+ continue;
26746
+ }
26622
26747
  }
26623
- } catch {
26624
- if (!applyCachedInlineMeshNodeStatus(status, node)) {
26625
- status.health = "degraded";
26748
+ } else {
26749
+ try {
26750
+ const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
26751
+ status.git = gitStatus;
26752
+ if (gitStatus.isGitRepo) {
26753
+ status.health = deriveMeshNodeHealthFromGit(gitStatus);
26754
+ } else {
26755
+ status.health = "degraded";
26756
+ if (gitStatus.error && !status.error) status.error = gitStatus.error;
26757
+ }
26758
+ } catch {
26759
+ if (!applyCachedInlineMeshNodeStatus(status, node)) {
26760
+ status.health = "degraded";
26761
+ }
26626
26762
  }
26627
26763
  }
26628
26764
  } else {