@adhdev/daemon-core 0.9.82-rc.23 → 0.9.82-rc.25

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
@@ -1351,13 +1351,43 @@ __export(mesh_work_queue_exports, {
1351
1351
  updateSessionTaskStatus: () => updateSessionTaskStatus,
1352
1352
  updateTaskStatus: () => updateTaskStatus
1353
1353
  });
1354
- import { existsSync as existsSync6, writeFileSync as writeFileSync3, readFileSync as readFileSync4 } from "fs";
1354
+ import { existsSync as existsSync6, writeFileSync as writeFileSync3, readFileSync as readFileSync4, openSync, closeSync, unlinkSync } from "fs";
1355
1355
  import { join as join6 } from "path";
1356
1356
  import { randomUUID as randomUUID5 } from "crypto";
1357
1357
  function getQueuePath(meshId) {
1358
1358
  const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1359
1359
  return join6(getLedgerDir(), `${safe}.queue.json`);
1360
1360
  }
1361
+ function getLockPath(meshId) {
1362
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1363
+ return join6(getLedgerDir(), `${safe}.queue.lock`);
1364
+ }
1365
+ function withQueueLock(meshId, fn) {
1366
+ const lockPath = getLockPath(meshId);
1367
+ let fd = -1;
1368
+ for (let i = 0; i < 10; i++) {
1369
+ try {
1370
+ fd = openSync(lockPath, "wx");
1371
+ break;
1372
+ } catch {
1373
+ const deadline = Date.now() + 30;
1374
+ while (Date.now() < deadline) {
1375
+ }
1376
+ }
1377
+ }
1378
+ try {
1379
+ return fn();
1380
+ } finally {
1381
+ if (fd !== -1) try {
1382
+ closeSync(fd);
1383
+ } catch {
1384
+ }
1385
+ try {
1386
+ unlinkSync(lockPath);
1387
+ } catch {
1388
+ }
1389
+ }
1390
+ }
1361
1391
  function readQueue(meshId) {
1362
1392
  const path28 = getQueuePath(meshId);
1363
1393
  if (!existsSync6(path28)) return [];
@@ -1373,20 +1403,22 @@ function writeQueue(meshId, queue) {
1373
1403
  writeFileSync3(path28, JSON.stringify(queue, null, 2), "utf-8");
1374
1404
  }
1375
1405
  function enqueueTask(meshId, message, opts) {
1376
- const queue = readQueue(meshId);
1377
- const entry = {
1378
- id: randomUUID5(),
1379
- meshId,
1380
- message,
1381
- status: "pending",
1382
- targetNodeId: opts?.targetNodeId,
1383
- targetSessionId: opts?.targetSessionId,
1384
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1385
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1386
- };
1387
- queue.push(entry);
1388
- writeQueue(meshId, queue);
1389
- return entry;
1406
+ return withQueueLock(meshId, () => {
1407
+ const queue = readQueue(meshId);
1408
+ const entry = {
1409
+ id: randomUUID5(),
1410
+ meshId,
1411
+ message,
1412
+ status: "pending",
1413
+ targetNodeId: opts?.targetNodeId,
1414
+ targetSessionId: opts?.targetSessionId,
1415
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1416
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1417
+ };
1418
+ queue.push(entry);
1419
+ writeQueue(meshId, queue);
1420
+ return entry;
1421
+ });
1390
1422
  }
1391
1423
  function getQueue(meshId, opts) {
1392
1424
  let queue = readQueue(meshId);
@@ -1397,100 +1429,111 @@ function getQueue(meshId, opts) {
1397
1429
  return queue;
1398
1430
  }
1399
1431
  function claimNextTask(meshId, nodeId, sessionId) {
1400
- const queue = readQueue(meshId);
1401
- const hasActiveAssignment = queue.some((q) => q.status === "assigned" && (q.assignedSessionId === sessionId || q.assignedNodeId === nodeId));
1402
- if (hasActiveAssignment) return null;
1403
- let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetSessionId === sessionId);
1404
- if (targetIdx === -1) {
1405
- targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId && !q.targetSessionId);
1406
- }
1407
- if (targetIdx === -1) {
1408
- targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId && !q.targetSessionId);
1409
- }
1410
- if (targetIdx === -1) return null;
1411
- const entry = queue[targetIdx];
1412
- entry.status = "assigned";
1413
- entry.assignedNodeId = nodeId;
1414
- entry.assignedSessionId = sessionId;
1415
- entry.dispatchTimestamp = (/* @__PURE__ */ new Date()).toISOString();
1416
- entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1417
- writeQueue(meshId, queue);
1418
- return entry;
1432
+ return withQueueLock(meshId, () => {
1433
+ const queue = readQueue(meshId);
1434
+ const hasActiveAssignment = queue.some((q) => q.status === "assigned" && (q.assignedSessionId === sessionId || q.assignedNodeId === nodeId));
1435
+ if (hasActiveAssignment) return null;
1436
+ let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetSessionId === sessionId);
1437
+ if (targetIdx === -1) {
1438
+ targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId && !q.targetSessionId);
1439
+ }
1440
+ if (targetIdx === -1) {
1441
+ targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId && !q.targetSessionId);
1442
+ }
1443
+ if (targetIdx === -1) return null;
1444
+ const entry = queue[targetIdx];
1445
+ entry.status = "assigned";
1446
+ entry.assignedNodeId = nodeId;
1447
+ entry.assignedSessionId = sessionId;
1448
+ entry.dispatchTimestamp = (/* @__PURE__ */ new Date()).toISOString();
1449
+ entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1450
+ writeQueue(meshId, queue);
1451
+ return entry;
1452
+ });
1419
1453
  }
1420
1454
  function updateTaskStatus(meshId, taskId, status) {
1421
- const queue = readQueue(meshId);
1422
- const idx = queue.findIndex((q) => q.id === taskId);
1423
- if (idx === -1) return null;
1424
- queue[idx].status = status;
1425
- queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1426
- writeQueue(meshId, queue);
1427
- return queue[idx];
1455
+ return withQueueLock(meshId, () => {
1456
+ const queue = readQueue(meshId);
1457
+ const idx = queue.findIndex((q) => q.id === taskId);
1458
+ if (idx === -1) return null;
1459
+ queue[idx].status = status;
1460
+ queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1461
+ writeQueue(meshId, queue);
1462
+ return queue[idx];
1463
+ });
1428
1464
  }
1429
1465
  function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
1430
- const queue = readQueue(meshId);
1431
- const idx = queue.findIndex((q) => q.id === taskId);
1432
- if (idx === -1) return null;
1433
- const now = (/* @__PURE__ */ new Date()).toISOString();
1434
- queue[idx].autoLaunch = {
1435
- ...autoLaunch,
1436
- updatedAt: now
1437
- };
1438
- queue[idx].updatedAt = now;
1439
- writeQueue(meshId, queue);
1440
- return queue[idx];
1466
+ return withQueueLock(meshId, () => {
1467
+ const queue = readQueue(meshId);
1468
+ const idx = queue.findIndex((q) => q.id === taskId);
1469
+ if (idx === -1) return null;
1470
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1471
+ queue[idx].autoLaunch = { ...autoLaunch, updatedAt: now };
1472
+ queue[idx].updatedAt = now;
1473
+ writeQueue(meshId, queue);
1474
+ return queue[idx];
1475
+ });
1441
1476
  }
1442
1477
  function cancelTask(meshId, taskId, opts) {
1443
- const queue = readQueue(meshId);
1444
- const idx = queue.findIndex((q) => q.id === taskId);
1445
- if (idx === -1) return null;
1446
- const now = (/* @__PURE__ */ new Date()).toISOString();
1447
- queue[idx].status = "cancelled";
1448
- queue[idx].updatedAt = now;
1449
- queue[idx].cancelledAt = now;
1450
- if (opts?.reason) queue[idx].cancelReason = opts.reason;
1451
- writeQueue(meshId, queue);
1452
- return queue[idx];
1478
+ return withQueueLock(meshId, () => {
1479
+ const queue = readQueue(meshId);
1480
+ const idx = queue.findIndex((q) => q.id === taskId);
1481
+ if (idx === -1) return null;
1482
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1483
+ queue[idx].status = "cancelled";
1484
+ queue[idx].updatedAt = now;
1485
+ queue[idx].cancelledAt = now;
1486
+ if (opts?.reason) queue[idx].cancelReason = opts.reason;
1487
+ writeQueue(meshId, queue);
1488
+ return queue[idx];
1489
+ });
1453
1490
  }
1454
1491
  function requeueTask(meshId, taskId, opts) {
1455
- const queue = readQueue(meshId);
1456
- const idx = queue.findIndex((q) => q.id === taskId);
1457
- if (idx === -1) return null;
1458
- const entry = queue[idx];
1459
- const now = (/* @__PURE__ */ new Date()).toISOString();
1460
- entry.status = "pending";
1461
- delete entry.assignedNodeId;
1462
- delete entry.assignedSessionId;
1463
- delete entry.cancelledAt;
1464
- delete entry.cancelReason;
1465
- if (opts?.clearTargetNode) delete entry.targetNodeId;
1466
- if (typeof opts?.targetNodeId === "string") entry.targetNodeId = opts.targetNodeId;
1467
- if (opts?.clearTargetSession !== false) delete entry.targetSessionId;
1468
- if (typeof opts?.targetSessionId === "string") entry.targetSessionId = opts.targetSessionId;
1469
- entry.updatedAt = now;
1470
- entry.requeuedAt = now;
1471
- entry.requeueCount = (entry.requeueCount || 0) + 1;
1472
- if (opts?.reason) entry.requeueReason = opts.reason;
1473
- writeQueue(meshId, queue);
1474
- return entry;
1475
- }
1476
- function updateSessionTaskStatus(meshId, sessionId, status) {
1477
- const queue = readQueue(meshId);
1478
- let bestIdx = -1;
1479
- let bestTime = 0;
1480
- for (let i = queue.length - 1; i >= 0; i--) {
1481
- if (queue[i].assignedSessionId === sessionId && queue[i].status === "assigned") {
1492
+ return withQueueLock(meshId, () => {
1493
+ const queue = readQueue(meshId);
1494
+ const idx = queue.findIndex((q) => q.id === taskId);
1495
+ if (idx === -1) return null;
1496
+ const entry = queue[idx];
1497
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1498
+ entry.status = "pending";
1499
+ delete entry.assignedNodeId;
1500
+ delete entry.assignedSessionId;
1501
+ delete entry.cancelledAt;
1502
+ delete entry.cancelReason;
1503
+ if (opts?.clearTargetNode) delete entry.targetNodeId;
1504
+ if (typeof opts?.targetNodeId === "string") entry.targetNodeId = opts.targetNodeId;
1505
+ if (opts?.clearTargetSession !== false) delete entry.targetSessionId;
1506
+ if (typeof opts?.targetSessionId === "string") entry.targetSessionId = opts.targetSessionId;
1507
+ entry.updatedAt = now;
1508
+ entry.requeuedAt = now;
1509
+ entry.requeueCount = (entry.requeueCount || 0) + 1;
1510
+ if (opts?.reason) entry.requeueReason = opts.reason;
1511
+ writeQueue(meshId, queue);
1512
+ return entry;
1513
+ });
1514
+ }
1515
+ function updateSessionTaskStatus(meshId, sessionId, status, opts) {
1516
+ return withQueueLock(meshId, () => {
1517
+ const queue = readQueue(meshId);
1518
+ const occurredAtTime = opts?.occurredAt ? new Date(opts.occurredAt).getTime() : Number.NaN;
1519
+ const hasOccurredAt = Number.isFinite(occurredAtTime);
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") continue;
1482
1524
  const time = new Date(queue[i].dispatchTimestamp || queue[i].updatedAt).getTime();
1525
+ if (hasOccurredAt && Number.isFinite(time) && time > occurredAtTime) continue;
1483
1526
  if (time > bestTime) {
1484
1527
  bestTime = time;
1485
1528
  bestIdx = i;
1486
1529
  }
1487
1530
  }
1488
- }
1489
- if (bestIdx === -1) return null;
1490
- queue[bestIdx].status = status;
1491
- queue[bestIdx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
1492
- writeQueue(meshId, queue);
1493
- return queue[bestIdx];
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
+ });
1494
1537
  }
1495
1538
  function getMeshQueueStats(meshId) {
1496
1539
  const queue = readQueue(meshId);
@@ -1895,21 +1938,72 @@ __export(mesh_events_exports, {
1895
1938
  triggerMeshQueue: () => triggerMeshQueue,
1896
1939
  tryAssignQueueTask: () => tryAssignQueueTask
1897
1940
  });
1941
+ import { appendFileSync as appendFileSync3, existsSync as existsSync9, readFileSync as readFileSync5, unlinkSync as unlinkSync3 } from "fs";
1942
+ import { join as join9 } from "path";
1943
+ function sweepExpiredRemoteIdleSessions() {
1944
+ const now = Date.now();
1945
+ for (const [key, session] of remoteIdleSessions) {
1946
+ if (session.expiresAt <= now) remoteIdleSessions.delete(key);
1947
+ }
1948
+ }
1949
+ function getPendingEventsPath(meshId) {
1950
+ const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
1951
+ return join9(getLedgerDir(), `${safe}.pending-events.jsonl`);
1952
+ }
1898
1953
  function queuePendingMeshCoordinatorEvent(event) {
1899
- if (pendingMeshCoordinatorEvents.length >= MAX_PENDING_EVENTS) {
1954
+ try {
1955
+ appendFileSync3(getPendingEventsPath(event.meshId), JSON.stringify(event) + "\n", "utf-8");
1956
+ return true;
1957
+ } catch (e) {
1958
+ LOG.warn("MeshEvents", `Failed to persist pending coordinator event: ${e?.message || e}`);
1900
1959
  return false;
1901
1960
  }
1902
- pendingMeshCoordinatorEvents.push(event);
1903
- return true;
1904
1961
  }
1905
- function drainPendingMeshCoordinatorEvents() {
1906
- return pendingMeshCoordinatorEvents.splice(0);
1962
+ function drainPendingMeshCoordinatorEvents(meshId) {
1963
+ if (!meshId) return [];
1964
+ const path28 = getPendingEventsPath(meshId);
1965
+ if (!existsSync9(path28)) return [];
1966
+ try {
1967
+ const raw = readFileSync5(path28, "utf-8");
1968
+ try {
1969
+ unlinkSync3(path28);
1970
+ } catch {
1971
+ }
1972
+ return raw.split("\n").filter(Boolean).flatMap((line) => {
1973
+ try {
1974
+ return [JSON.parse(line)];
1975
+ } catch {
1976
+ return [];
1977
+ }
1978
+ });
1979
+ } catch {
1980
+ return [];
1981
+ }
1907
1982
  }
1908
- function getPendingMeshCoordinatorEvents() {
1909
- return pendingMeshCoordinatorEvents.slice();
1983
+ function getPendingMeshCoordinatorEvents(meshId) {
1984
+ if (!meshId) return [];
1985
+ const path28 = getPendingEventsPath(meshId);
1986
+ if (!existsSync9(path28)) return [];
1987
+ try {
1988
+ const raw = readFileSync5(path28, "utf-8");
1989
+ return raw.split("\n").filter(Boolean).flatMap((line) => {
1990
+ try {
1991
+ return [JSON.parse(line)];
1992
+ } catch {
1993
+ return [];
1994
+ }
1995
+ });
1996
+ } catch {
1997
+ return [];
1998
+ }
1910
1999
  }
1911
- function clearPendingMeshCoordinatorEvents() {
1912
- pendingMeshCoordinatorEvents.splice(0);
2000
+ function clearPendingMeshCoordinatorEvents(meshId) {
2001
+ if (!meshId) return;
2002
+ const path28 = getPendingEventsPath(meshId);
2003
+ if (existsSync9(path28)) try {
2004
+ unlinkSync3(path28);
2005
+ } catch {
2006
+ }
1913
2007
  }
1914
2008
  function readNonEmptyString(value) {
1915
2009
  return typeof value === "string" && value.trim() ? value.trim() : "";
@@ -1955,6 +2049,38 @@ function shouldSuppressIntentionalCleanupStop(args) {
1955
2049
  if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
1956
2050
  return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
1957
2051
  }
2052
+ function readEventTimestamp(value) {
2053
+ if (typeof value === "number" && Number.isFinite(value)) return value;
2054
+ if (typeof value === "string" && value.trim()) {
2055
+ const numeric = Number(value);
2056
+ if (Number.isFinite(numeric)) return numeric;
2057
+ const parsed = Date.parse(value);
2058
+ if (Number.isFinite(parsed)) return parsed;
2059
+ }
2060
+ return null;
2061
+ }
2062
+ function buildMeshCompletionFingerprint(args) {
2063
+ const timestampPart = Number.isFinite(args.timestamp) ? String(args.timestamp) : readNonEmptyString(args.finalSummary).slice(0, 200);
2064
+ return [
2065
+ args.meshId,
2066
+ args.event,
2067
+ args.sessionId,
2068
+ args.providerType || "",
2069
+ args.providerSessionId || "",
2070
+ timestampPart
2071
+ ].join("::");
2072
+ }
2073
+ function isDuplicateMeshCompletionEvent(args) {
2074
+ const fingerprint = buildMeshCompletionFingerprint(args);
2075
+ if (!fingerprint) return false;
2076
+ const now = Date.now();
2077
+ for (const [key, seenAt] of recentCompletionFingerprints.entries()) {
2078
+ if (now - seenAt > RECENT_COMPLETION_FINGERPRINT_TTL_MS) recentCompletionFingerprints.delete(key);
2079
+ }
2080
+ if (recentCompletionFingerprints.has(fingerprint)) return true;
2081
+ recentCompletionFingerprints.set(fingerprint, now);
2082
+ return false;
2083
+ }
1958
2084
  function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
1959
2085
  const task = claimNextTask(meshId, nodeId, sessionId);
1960
2086
  if (!task) {
@@ -1973,7 +2099,16 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
1973
2099
  message: task.message
1974
2100
  }).catch((e) => {
1975
2101
  LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
1976
- updateTaskStatus(meshId, task.id, "failed");
2102
+ updateTaskStatus(meshId, task.id, "pending");
2103
+ try {
2104
+ appendLedgerEntry(meshId, {
2105
+ kind: "dispatch_failed",
2106
+ nodeId,
2107
+ sessionId,
2108
+ payload: { taskId: task.id, error: e?.message, retryable: true }
2109
+ });
2110
+ } catch {
2111
+ }
1977
2112
  });
1978
2113
  return true;
1979
2114
  }
@@ -2307,18 +2442,36 @@ function injectMeshSystemMessage(components, args) {
2307
2442
  LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
2308
2443
  return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
2309
2444
  }
2445
+ const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
2446
+ if (args.event === "agent:generating_completed" && eventSessionId) {
2447
+ const duplicateCompletion = isDuplicateMeshCompletionEvent({
2448
+ meshId: args.meshId,
2449
+ event: args.event,
2450
+ sessionId: eventSessionId,
2451
+ providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
2452
+ providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
2453
+ timestamp: eventTimestamp,
2454
+ finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
2455
+ });
2456
+ if (duplicateCompletion) {
2457
+ LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
2458
+ return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
2459
+ }
2460
+ }
2310
2461
  let completedTaskForLedger = null;
2311
2462
  if (args.event === "agent:generating_completed") {
2312
2463
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
2313
2464
  const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
2314
2465
  const providerType = readNonEmptyString(args.metadataEvent.providerType);
2315
2466
  if (sessionId) {
2316
- const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed");
2467
+ const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed", {
2468
+ occurredAt: eventTimestamp !== null ? new Date(eventTimestamp).toISOString() : void 0
2469
+ });
2317
2470
  completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
2318
2471
  if (nodeId && providerType) {
2319
- setTimeout(() => {
2472
+ setImmediate(() => {
2320
2473
  tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
2321
- }, 500);
2474
+ });
2322
2475
  }
2323
2476
  }
2324
2477
  } else if (args.event === "agent:ready") {
@@ -2356,13 +2509,17 @@ function injectMeshSystemMessage(components, args) {
2356
2509
  }
2357
2510
  }
2358
2511
  if (sessionId && nodeId && providerType) {
2359
- remoteIdleSessions.set(`${nodeId}:${sessionId}`, { nodeId, sessionId, providerType });
2360
- setTimeout(() => {
2512
+ sweepExpiredRemoteIdleSessions();
2513
+ remoteIdleSessions.set(`${nodeId}:${sessionId}`, {
2514
+ nodeId,
2515
+ sessionId,
2516
+ providerType,
2517
+ expiresAt: Date.now() + REMOTE_IDLE_SESSION_TTL_MS
2518
+ });
2519
+ setImmediate(() => {
2361
2520
  const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
2362
- if (assigned) {
2363
- remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
2364
- }
2365
- }, 500);
2521
+ if (assigned) remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
2522
+ });
2366
2523
  }
2367
2524
  } else if (args.event === "agent:generating_started") {
2368
2525
  const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
@@ -2523,6 +2680,7 @@ function handleMeshForwardEvent(components, payload) {
2523
2680
  providerType: readNonEmptyString(payload.providerType),
2524
2681
  providerSessionId: readNonEmptyString(payload.providerSessionId),
2525
2682
  finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
2683
+ ...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
2526
2684
  intentional: payload.intentional === true,
2527
2685
  intentionalStop: payload.intentionalStop === true,
2528
2686
  operatorCleanup: payload.operatorCleanup === true,
@@ -2565,7 +2723,7 @@ function setupMeshEventForwarding(components) {
2565
2723
  });
2566
2724
  });
2567
2725
  }
2568
- var remoteIdleSessions, MAX_PENDING_EVENTS, pendingMeshCoordinatorEvents, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2726
+ var REMOTE_IDLE_SESSION_TTL_MS, remoteIdleSessions, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, recentCompletionFingerprints, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
2569
2727
  var init_mesh_events = __esm({
2570
2728
  "src/mesh/mesh-events.ts"() {
2571
2729
  "use strict";
@@ -2575,9 +2733,8 @@ var init_mesh_events = __esm({
2575
2733
  init_logger();
2576
2734
  init_mesh_ledger();
2577
2735
  init_mesh_work_queue();
2736
+ REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
2578
2737
  remoteIdleSessions = /* @__PURE__ */ new Map();
2579
- MAX_PENDING_EVENTS = 50;
2580
- pendingMeshCoordinatorEvents = [];
2581
2738
  MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
2582
2739
  "agent:generating_started",
2583
2740
  "agent:generating_completed",
@@ -2593,6 +2750,8 @@ var init_mesh_events = __esm({
2593
2750
  "monitor:long_generating": "task_stalled"
2594
2751
  };
2595
2752
  INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
2753
+ RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
2754
+ recentCompletionFingerprints = /* @__PURE__ */ new Map();
2596
2755
  autoLaunchInProgress = /* @__PURE__ */ new Set();
2597
2756
  autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
2598
2757
  AUTO_LAUNCH_COOLDOWN_MS = 5e3;
@@ -7635,8 +7794,8 @@ var P2pRelayFailureError = class extends Error {
7635
7794
 
7636
7795
  // src/config/state-store.ts
7637
7796
  init_config();
7638
- import { existsSync as existsSync9, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
7639
- import { join as join9 } from "path";
7797
+ import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
7798
+ import { join as join10 } from "path";
7640
7799
  var DEFAULT_STATE = {
7641
7800
  recentActivity: [],
7642
7801
  savedProviderSessions: [],
@@ -7649,7 +7808,7 @@ function isPlainObject2(value) {
7649
7808
  return !!value && typeof value === "object" && !Array.isArray(value);
7650
7809
  }
7651
7810
  function getStatePath() {
7652
- return join9(getConfigDir(), "state.json");
7811
+ return join10(getConfigDir(), "state.json");
7653
7812
  }
7654
7813
  function normalizeState(raw) {
7655
7814
  const parsed = isPlainObject2(raw) ? raw : {};
@@ -7685,11 +7844,11 @@ function normalizeState(raw) {
7685
7844
  }
7686
7845
  function loadState() {
7687
7846
  const statePath = getStatePath();
7688
- if (!existsSync9(statePath)) {
7847
+ if (!existsSync10(statePath)) {
7689
7848
  return { ...DEFAULT_STATE };
7690
7849
  }
7691
7850
  try {
7692
- const raw = readFileSync5(statePath, "utf-8");
7851
+ const raw = readFileSync6(statePath, "utf-8");
7693
7852
  return normalizeState(JSON.parse(raw));
7694
7853
  } catch {
7695
7854
  return { ...DEFAULT_STATE };
@@ -7706,7 +7865,7 @@ function resetState() {
7706
7865
 
7707
7866
  // src/detection/ide-detector.ts
7708
7867
  import { execSync } from "child_process";
7709
- import { existsSync as existsSync10 } from "fs";
7868
+ import { existsSync as existsSync11 } from "fs";
7710
7869
  import { platform as platform2, homedir as homedir5 } from "os";
7711
7870
  import * as path10 from "path";
7712
7871
  var BUILTIN_IDE_DEFINITIONS = [];
@@ -7730,7 +7889,7 @@ function findCliCommand(command) {
7730
7889
  if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
7731
7890
  const candidate = trimmed.startsWith("~") ? path10.join(homedir5(), trimmed.slice(1)) : trimmed;
7732
7891
  const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
7733
- return existsSync10(resolved) ? resolved : null;
7892
+ return existsSync11(resolved) ? resolved : null;
7734
7893
  }
7735
7894
  try {
7736
7895
  const result = execSync(
@@ -7761,9 +7920,9 @@ function checkPathExists(paths) {
7761
7920
  if (normalized.includes("*")) {
7762
7921
  const username = home.split(/[\\/]/).pop() || "";
7763
7922
  const resolved = normalized.replace("*", username);
7764
- if (existsSync10(resolved)) return resolved;
7923
+ if (existsSync11(resolved)) return resolved;
7765
7924
  } else {
7766
- if (existsSync10(normalized)) return normalized;
7925
+ if (existsSync11(normalized)) return normalized;
7767
7926
  }
7768
7927
  }
7769
7928
  return null;
@@ -7777,7 +7936,7 @@ async function detectIDEs(providerLoader) {
7777
7936
  let resolvedCli = cliPath;
7778
7937
  if (!resolvedCli && appPath && os22 === "darwin") {
7779
7938
  const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
7780
- if (existsSync10(bundledCli)) resolvedCli = bundledCli;
7939
+ if (existsSync11(bundledCli)) resolvedCli = bundledCli;
7781
7940
  }
7782
7941
  if (!resolvedCli && appPath && os22 === "win32") {
7783
7942
  const { dirname: dirname9 } = await import("path");
@@ -7790,7 +7949,7 @@ async function detectIDEs(providerLoader) {
7790
7949
  `${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
7791
7950
  ];
7792
7951
  for (const c of candidates) {
7793
- if (existsSync10(c)) {
7952
+ if (existsSync11(c)) {
7794
7953
  resolvedCli = c;
7795
7954
  break;
7796
7955
  }
@@ -16946,7 +17105,7 @@ init_config();
16946
17105
  import * as os13 from "os";
16947
17106
  import * as path18 from "path";
16948
17107
  import * as crypto4 from "crypto";
16949
- import { existsSync as existsSync14, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
17108
+ import { existsSync as existsSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
16950
17109
  import { execFileSync } from "child_process";
16951
17110
  import chalk from "chalk";
16952
17111
 
@@ -19420,7 +19579,7 @@ function commandExists(command) {
19420
19579
  const trimmed = command.trim();
19421
19580
  if (!trimmed) return false;
19422
19581
  if (isExplicitCommand(trimmed)) {
19423
- return existsSync14(expandExecutable(trimmed));
19582
+ return existsSync15(expandExecutable(trimmed));
19424
19583
  }
19425
19584
  try {
19426
19585
  execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
@@ -22689,10 +22848,10 @@ import * as yaml from "js-yaml";
22689
22848
  // src/commands/mesh-coordinator.ts
22690
22849
  import { execFileSync as execFileSync2 } from "child_process";
22691
22850
  import { createHash as createHash2 } from "crypto";
22692
- import { existsSync as existsSync17, readdirSync as readdirSync7, realpathSync as realpathSync2 } from "fs";
22851
+ import { existsSync as existsSync18, readdirSync as readdirSync7, realpathSync as realpathSync2 } from "fs";
22693
22852
  import { createRequire as createRequire2 } from "module";
22694
22853
  import * as os17 from "os";
22695
- import { dirname as dirname4, isAbsolute as isAbsolute11, join as join20, resolve as resolve13 } from "path";
22854
+ import { dirname as dirname4, isAbsolute as isAbsolute11, join as join21, resolve as resolve13 } from "path";
22696
22855
  var DEFAULT_SERVER_NAME = "adhdev-mesh";
22697
22856
  var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
22698
22857
  var HERMES_CLI_TYPE = "hermes-cli";
@@ -22715,7 +22874,7 @@ function resolveHermesMeshCoordinatorSetup(options) {
22715
22874
  reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
22716
22875
  };
22717
22876
  }
22718
- const configPath = join20(resolveHermesCoordinatorHome(options.meshId, options.workspace), "config.yaml");
22877
+ const configPath = join21(resolveHermesCoordinatorHome(options.meshId, options.workspace), "config.yaml");
22719
22878
  if (!configPath.trim()) {
22720
22879
  return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
22721
22880
  }
@@ -22836,14 +22995,14 @@ function resolveHermesCoordinatorHome(meshId, workspace) {
22836
22995
  const key = `${meshId || "mesh"}
22837
22996
  ${resolve13(workspace || os17.tmpdir())}`;
22838
22997
  const hash = createHash2("sha256").update(key).digest("hex").slice(0, 16);
22839
- return join20(os17.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash}`);
22998
+ return join21(os17.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash}`);
22840
22999
  }
22841
23000
  function resolveMcpConfigPath(configPath, workspace) {
22842
23001
  const trimmed = configPath.trim();
22843
23002
  if (trimmed === "~") return os17.homedir();
22844
- if (trimmed.startsWith("~/")) return join20(os17.homedir(), trimmed.slice(2));
23003
+ if (trimmed.startsWith("~/")) return join21(os17.homedir(), trimmed.slice(2));
22845
23004
  if (isAbsolute11(trimmed)) return trimmed;
22846
- return join20(workspace, trimmed);
23005
+ return join21(workspace, trimmed);
22847
23006
  }
22848
23007
  function resolveAdhdevMcpServerLaunch(options) {
22849
23008
  const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
@@ -22899,15 +23058,15 @@ function addNodeCandidatesFromPath(pathValue, addCandidate) {
22899
23058
  for (const entry of (pathValue || "").split(":")) {
22900
23059
  const dir = entry.trim();
22901
23060
  if (!dir) continue;
22902
- addCandidate(join20(dir, "node"));
23061
+ addCandidate(join21(dir, "node"));
22903
23062
  }
22904
23063
  }
22905
23064
  function addNodeCandidatesFromNvm(homeDir, addCandidate) {
22906
- const versionsDir = join20(homeDir, ".nvm", "versions", "node");
23065
+ const versionsDir = join21(homeDir, ".nvm", "versions", "node");
22907
23066
  try {
22908
23067
  const versionDirs = readdirSync7(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
22909
23068
  for (const versionDir of versionDirs) {
22910
- addCandidate(join20(versionsDir, versionDir, "bin", "node"));
23069
+ addCandidate(join21(versionsDir, versionDir, "bin", "node"));
22911
23070
  }
22912
23071
  } catch {
22913
23072
  }
@@ -22958,7 +23117,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
22958
23117
  if (normalized) return normalized;
22959
23118
  }
22960
23119
  try {
22961
- const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join20(process.cwd(), "adhdev-daemon.js");
23120
+ const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join21(process.cwd(), "adhdev-daemon.js");
22962
23121
  const req = createRequire2(requireBase);
22963
23122
  const resolvedModule = req.resolve("@adhdev/mcp-server");
22964
23123
  return normalizeExistingPath(resolvedModule) || resolvedModule;
@@ -22968,7 +23127,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
22968
23127
  }
22969
23128
  function normalizeExistingPath(filePath) {
22970
23129
  try {
22971
- if (!existsSync17(filePath)) return null;
23130
+ if (!existsSync18(filePath)) return null;
22972
23131
  return realpathSync2.native(filePath);
22973
23132
  } catch {
22974
23133
  return null;
@@ -24920,7 +25079,8 @@ var DaemonCommandRouter = class {
24920
25079
  return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
24921
25080
  }
24922
25081
  case "get_pending_mesh_events": {
24923
- const events = drainPendingMeshCoordinatorEvents();
25082
+ const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
25083
+ const events = drainPendingMeshCoordinatorEvents(meshId || void 0);
24924
25084
  return { success: true, events };
24925
25085
  }
24926
25086
  case "launch_cli":
@@ -26141,7 +26301,7 @@ ${block}`);
26141
26301
  workspace
26142
26302
  };
26143
26303
  }
26144
- const { existsSync: existsSync25, readFileSync: readFileSync17, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
26304
+ const { existsSync: existsSync26, readFileSync: readFileSync18, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
26145
26305
  const { dirname: dirname9 } = await import("path");
26146
26306
  const mcpConfigPath = coordinatorSetup.configPath;
26147
26307
  const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
@@ -26184,14 +26344,14 @@ ${block}`);
26184
26344
  if (hermesManualFallback) return returnManualFallback(message);
26185
26345
  return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
26186
26346
  }
26187
- const hadExistingMcpConfig = existsSync25(mcpConfigPath);
26347
+ const hadExistingMcpConfig = existsSync26(mcpConfigPath);
26188
26348
  let existingMcpConfig = hermesBaseConfig?.config || {};
26189
26349
  if (hermesBaseConfig) {
26190
26350
  copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
26191
26351
  }
26192
26352
  if (hadExistingMcpConfig) {
26193
26353
  try {
26194
- const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync17(mcpConfigPath, "utf-8"), configFormat);
26354
+ const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync18(mcpConfigPath, "utf-8"), configFormat);
26195
26355
  const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
26196
26356
  existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
26197
26357
  copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
@@ -26379,29 +26539,48 @@ ${block}`);
26379
26539
  }
26380
26540
  if (workspace) {
26381
26541
  if (!fs10.existsSync(workspace)) {
26382
- if (applyCachedInlineMeshNodeStatus(status, node)) {
26383
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26384
- nodeStatuses.push(status);
26385
- continue;
26386
- }
26387
- if (meshRecord?.source === "inline_cache" && !isSelfNode) {
26388
- status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26389
- nodeStatuses.push(status);
26390
- continue;
26542
+ let remoteProbeApplied = false;
26543
+ if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand) {
26544
+ try {
26545
+ const remoteResult = await Promise.race([
26546
+ this.deps.dispatchMeshCommand(daemonId, "git_status", { workspace }),
26547
+ new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 8e3))
26548
+ ]);
26549
+ const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
26550
+ if (remoteGit && typeof remoteGit === "object" && typeof remoteGit.isGitRepo === "boolean") {
26551
+ status.git = remoteGit;
26552
+ status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
26553
+ remoteProbeApplied = true;
26554
+ }
26555
+ } catch {
26556
+ }
26391
26557
  }
26392
- }
26393
- try {
26394
- const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
26395
- status.git = gitStatus;
26396
- if (gitStatus.isGitRepo) {
26397
- status.health = deriveMeshNodeHealthFromGit(gitStatus);
26398
- } else {
26399
- status.health = "degraded";
26400
- if (gitStatus.error && !status.error) status.error = gitStatus.error;
26558
+ if (!remoteProbeApplied) {
26559
+ if (applyCachedInlineMeshNodeStatus(status, node)) {
26560
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26561
+ nodeStatuses.push(status);
26562
+ continue;
26563
+ }
26564
+ if (meshRecord?.source === "inline_cache" && !isSelfNode) {
26565
+ status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
26566
+ nodeStatuses.push(status);
26567
+ continue;
26568
+ }
26401
26569
  }
26402
- } catch {
26403
- if (!applyCachedInlineMeshNodeStatus(status, node)) {
26404
- status.health = "degraded";
26570
+ } else {
26571
+ try {
26572
+ const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
26573
+ status.git = gitStatus;
26574
+ if (gitStatus.isGitRepo) {
26575
+ status.health = deriveMeshNodeHealthFromGit(gitStatus);
26576
+ } else {
26577
+ status.health = "degraded";
26578
+ if (gitStatus.error && !status.error) status.error = gitStatus.error;
26579
+ }
26580
+ } catch {
26581
+ if (!applyCachedInlineMeshNodeStatus(status, node)) {
26582
+ status.health = "degraded";
26583
+ }
26405
26584
  }
26406
26585
  }
26407
26586
  } else {