@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/commands/router.d.ts +2 -0
- package/dist/index.js +345 -166
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +345 -166
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +14 -5
- package/dist/mesh/mesh-work-queue.d.ts +3 -1
- package/package.json +1 -1
- package/src/commands/router.ts +48 -22
- package/src/mesh/mesh-events.ts +157 -30
- package/src/mesh/mesh-work-queue.ts +135 -119
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
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
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,111 @@ function getQueue(meshId, opts) {
|
|
|
1399
1431
|
return queue;
|
|
1400
1432
|
}
|
|
1401
1433
|
function claimNextTask(meshId, nodeId, sessionId) {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
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
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
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
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
...autoLaunch,
|
|
1438
|
-
updatedAt
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
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
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
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
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
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
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
function updateSessionTaskStatus(meshId, sessionId, status, opts) {
|
|
1518
|
+
return withQueueLock(meshId, () => {
|
|
1519
|
+
const queue = readQueue(meshId);
|
|
1520
|
+
const occurredAtTime = opts?.occurredAt ? new Date(opts.occurredAt).getTime() : Number.NaN;
|
|
1521
|
+
const hasOccurredAt = Number.isFinite(occurredAtTime);
|
|
1522
|
+
let bestIdx = -1;
|
|
1523
|
+
let bestTime = 0;
|
|
1524
|
+
for (let i = queue.length - 1; i >= 0; i--) {
|
|
1525
|
+
if (queue[i].assignedSessionId !== sessionId || queue[i].status !== "assigned") continue;
|
|
1484
1526
|
const time = new Date(queue[i].dispatchTimestamp || queue[i].updatedAt).getTime();
|
|
1527
|
+
if (hasOccurredAt && Number.isFinite(time) && time > occurredAtTime) continue;
|
|
1485
1528
|
if (time > bestTime) {
|
|
1486
1529
|
bestTime = time;
|
|
1487
1530
|
bestIdx = i;
|
|
1488
1531
|
}
|
|
1489
1532
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1533
|
+
if (bestIdx === -1) return null;
|
|
1534
|
+
queue[bestIdx].status = status;
|
|
1535
|
+
queue[bestIdx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1536
|
+
writeQueue(meshId, queue);
|
|
1537
|
+
return queue[bestIdx];
|
|
1538
|
+
});
|
|
1496
1539
|
}
|
|
1497
1540
|
function getMeshQueueStats(meshId) {
|
|
1498
1541
|
const queue = readQueue(meshId);
|
|
@@ -1901,21 +1944,70 @@ __export(mesh_events_exports, {
|
|
|
1901
1944
|
triggerMeshQueue: () => triggerMeshQueue,
|
|
1902
1945
|
tryAssignQueueTask: () => tryAssignQueueTask
|
|
1903
1946
|
});
|
|
1947
|
+
function sweepExpiredRemoteIdleSessions() {
|
|
1948
|
+
const now = Date.now();
|
|
1949
|
+
for (const [key, session] of remoteIdleSessions) {
|
|
1950
|
+
if (session.expiresAt <= now) remoteIdleSessions.delete(key);
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
function getPendingEventsPath(meshId) {
|
|
1954
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1955
|
+
return (0, import_path5.join)(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
1956
|
+
}
|
|
1904
1957
|
function queuePendingMeshCoordinatorEvent(event) {
|
|
1905
|
-
|
|
1958
|
+
try {
|
|
1959
|
+
(0, import_fs6.appendFileSync)(getPendingEventsPath(event.meshId), JSON.stringify(event) + "\n", "utf-8");
|
|
1960
|
+
return true;
|
|
1961
|
+
} catch (e) {
|
|
1962
|
+
LOG.warn("MeshEvents", `Failed to persist pending coordinator event: ${e?.message || e}`);
|
|
1906
1963
|
return false;
|
|
1907
1964
|
}
|
|
1908
|
-
pendingMeshCoordinatorEvents.push(event);
|
|
1909
|
-
return true;
|
|
1910
1965
|
}
|
|
1911
|
-
function drainPendingMeshCoordinatorEvents() {
|
|
1912
|
-
|
|
1966
|
+
function drainPendingMeshCoordinatorEvents(meshId) {
|
|
1967
|
+
if (!meshId) return [];
|
|
1968
|
+
const path28 = getPendingEventsPath(meshId);
|
|
1969
|
+
if (!(0, import_fs6.existsSync)(path28)) return [];
|
|
1970
|
+
try {
|
|
1971
|
+
const raw = (0, import_fs6.readFileSync)(path28, "utf-8");
|
|
1972
|
+
try {
|
|
1973
|
+
(0, import_fs6.unlinkSync)(path28);
|
|
1974
|
+
} catch {
|
|
1975
|
+
}
|
|
1976
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
1977
|
+
try {
|
|
1978
|
+
return [JSON.parse(line)];
|
|
1979
|
+
} catch {
|
|
1980
|
+
return [];
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
} catch {
|
|
1984
|
+
return [];
|
|
1985
|
+
}
|
|
1913
1986
|
}
|
|
1914
|
-
function getPendingMeshCoordinatorEvents() {
|
|
1915
|
-
|
|
1987
|
+
function getPendingMeshCoordinatorEvents(meshId) {
|
|
1988
|
+
if (!meshId) return [];
|
|
1989
|
+
const path28 = getPendingEventsPath(meshId);
|
|
1990
|
+
if (!(0, import_fs6.existsSync)(path28)) return [];
|
|
1991
|
+
try {
|
|
1992
|
+
const raw = (0, import_fs6.readFileSync)(path28, "utf-8");
|
|
1993
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
1994
|
+
try {
|
|
1995
|
+
return [JSON.parse(line)];
|
|
1996
|
+
} catch {
|
|
1997
|
+
return [];
|
|
1998
|
+
}
|
|
1999
|
+
});
|
|
2000
|
+
} catch {
|
|
2001
|
+
return [];
|
|
2002
|
+
}
|
|
1916
2003
|
}
|
|
1917
|
-
function clearPendingMeshCoordinatorEvents() {
|
|
1918
|
-
|
|
2004
|
+
function clearPendingMeshCoordinatorEvents(meshId) {
|
|
2005
|
+
if (!meshId) return;
|
|
2006
|
+
const path28 = getPendingEventsPath(meshId);
|
|
2007
|
+
if ((0, import_fs6.existsSync)(path28)) try {
|
|
2008
|
+
(0, import_fs6.unlinkSync)(path28);
|
|
2009
|
+
} catch {
|
|
2010
|
+
}
|
|
1919
2011
|
}
|
|
1920
2012
|
function readNonEmptyString(value) {
|
|
1921
2013
|
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
@@ -1961,6 +2053,38 @@ function shouldSuppressIntentionalCleanupStop(args) {
|
|
|
1961
2053
|
if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
|
|
1962
2054
|
return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
|
|
1963
2055
|
}
|
|
2056
|
+
function readEventTimestamp(value) {
|
|
2057
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2058
|
+
if (typeof value === "string" && value.trim()) {
|
|
2059
|
+
const numeric = Number(value);
|
|
2060
|
+
if (Number.isFinite(numeric)) return numeric;
|
|
2061
|
+
const parsed = Date.parse(value);
|
|
2062
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
2063
|
+
}
|
|
2064
|
+
return null;
|
|
2065
|
+
}
|
|
2066
|
+
function buildMeshCompletionFingerprint(args) {
|
|
2067
|
+
const timestampPart = Number.isFinite(args.timestamp) ? String(args.timestamp) : readNonEmptyString(args.finalSummary).slice(0, 200);
|
|
2068
|
+
return [
|
|
2069
|
+
args.meshId,
|
|
2070
|
+
args.event,
|
|
2071
|
+
args.sessionId,
|
|
2072
|
+
args.providerType || "",
|
|
2073
|
+
args.providerSessionId || "",
|
|
2074
|
+
timestampPart
|
|
2075
|
+
].join("::");
|
|
2076
|
+
}
|
|
2077
|
+
function isDuplicateMeshCompletionEvent(args) {
|
|
2078
|
+
const fingerprint = buildMeshCompletionFingerprint(args);
|
|
2079
|
+
if (!fingerprint) return false;
|
|
2080
|
+
const now = Date.now();
|
|
2081
|
+
for (const [key, seenAt] of recentCompletionFingerprints.entries()) {
|
|
2082
|
+
if (now - seenAt > RECENT_COMPLETION_FINGERPRINT_TTL_MS) recentCompletionFingerprints.delete(key);
|
|
2083
|
+
}
|
|
2084
|
+
if (recentCompletionFingerprints.has(fingerprint)) return true;
|
|
2085
|
+
recentCompletionFingerprints.set(fingerprint, now);
|
|
2086
|
+
return false;
|
|
2087
|
+
}
|
|
1964
2088
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
1965
2089
|
const task = claimNextTask(meshId, nodeId, sessionId);
|
|
1966
2090
|
if (!task) {
|
|
@@ -1979,7 +2103,16 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
1979
2103
|
message: task.message
|
|
1980
2104
|
}).catch((e) => {
|
|
1981
2105
|
LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
|
|
1982
|
-
updateTaskStatus(meshId, task.id, "
|
|
2106
|
+
updateTaskStatus(meshId, task.id, "pending");
|
|
2107
|
+
try {
|
|
2108
|
+
appendLedgerEntry(meshId, {
|
|
2109
|
+
kind: "dispatch_failed",
|
|
2110
|
+
nodeId,
|
|
2111
|
+
sessionId,
|
|
2112
|
+
payload: { taskId: task.id, error: e?.message, retryable: true }
|
|
2113
|
+
});
|
|
2114
|
+
} catch {
|
|
2115
|
+
}
|
|
1983
2116
|
});
|
|
1984
2117
|
return true;
|
|
1985
2118
|
}
|
|
@@ -2313,18 +2446,36 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2313
2446
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
2314
2447
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
2315
2448
|
}
|
|
2449
|
+
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
2450
|
+
if (args.event === "agent:generating_completed" && eventSessionId) {
|
|
2451
|
+
const duplicateCompletion = isDuplicateMeshCompletionEvent({
|
|
2452
|
+
meshId: args.meshId,
|
|
2453
|
+
event: args.event,
|
|
2454
|
+
sessionId: eventSessionId,
|
|
2455
|
+
providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
|
|
2456
|
+
providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
|
|
2457
|
+
timestamp: eventTimestamp,
|
|
2458
|
+
finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
|
|
2459
|
+
});
|
|
2460
|
+
if (duplicateCompletion) {
|
|
2461
|
+
LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
2462
|
+
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2316
2465
|
let completedTaskForLedger = null;
|
|
2317
2466
|
if (args.event === "agent:generating_completed") {
|
|
2318
2467
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
2319
2468
|
const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
|
|
2320
2469
|
const providerType = readNonEmptyString(args.metadataEvent.providerType);
|
|
2321
2470
|
if (sessionId) {
|
|
2322
|
-
const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed"
|
|
2471
|
+
const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed", {
|
|
2472
|
+
occurredAt: eventTimestamp !== null ? new Date(eventTimestamp).toISOString() : void 0
|
|
2473
|
+
});
|
|
2323
2474
|
completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
|
|
2324
2475
|
if (nodeId && providerType) {
|
|
2325
|
-
|
|
2476
|
+
setImmediate(() => {
|
|
2326
2477
|
tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
2327
|
-
}
|
|
2478
|
+
});
|
|
2328
2479
|
}
|
|
2329
2480
|
}
|
|
2330
2481
|
} else if (args.event === "agent:ready") {
|
|
@@ -2362,13 +2513,17 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2362
2513
|
}
|
|
2363
2514
|
}
|
|
2364
2515
|
if (sessionId && nodeId && providerType) {
|
|
2365
|
-
|
|
2366
|
-
|
|
2516
|
+
sweepExpiredRemoteIdleSessions();
|
|
2517
|
+
remoteIdleSessions.set(`${nodeId}:${sessionId}`, {
|
|
2518
|
+
nodeId,
|
|
2519
|
+
sessionId,
|
|
2520
|
+
providerType,
|
|
2521
|
+
expiresAt: Date.now() + REMOTE_IDLE_SESSION_TTL_MS
|
|
2522
|
+
});
|
|
2523
|
+
setImmediate(() => {
|
|
2367
2524
|
const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
2368
|
-
if (assigned) {
|
|
2369
|
-
|
|
2370
|
-
}
|
|
2371
|
-
}, 500);
|
|
2525
|
+
if (assigned) remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
|
|
2526
|
+
});
|
|
2372
2527
|
}
|
|
2373
2528
|
} else if (args.event === "agent:generating_started") {
|
|
2374
2529
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
@@ -2529,6 +2684,7 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
2529
2684
|
providerType: readNonEmptyString(payload.providerType),
|
|
2530
2685
|
providerSessionId: readNonEmptyString(payload.providerSessionId),
|
|
2531
2686
|
finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
|
|
2687
|
+
...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
|
|
2532
2688
|
intentional: payload.intentional === true,
|
|
2533
2689
|
intentionalStop: payload.intentionalStop === true,
|
|
2534
2690
|
operatorCleanup: payload.operatorCleanup === true,
|
|
@@ -2571,19 +2727,20 @@ function setupMeshEventForwarding(components) {
|
|
|
2571
2727
|
});
|
|
2572
2728
|
});
|
|
2573
2729
|
}
|
|
2574
|
-
var
|
|
2730
|
+
var import_fs6, import_path5, 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;
|
|
2575
2731
|
var init_mesh_events = __esm({
|
|
2576
2732
|
"src/mesh/mesh-events.ts"() {
|
|
2577
2733
|
"use strict";
|
|
2734
|
+
import_fs6 = require("fs");
|
|
2735
|
+
import_path5 = require("path");
|
|
2578
2736
|
init_config();
|
|
2579
2737
|
init_mesh_config();
|
|
2580
2738
|
init_cli_detector();
|
|
2581
2739
|
init_logger();
|
|
2582
2740
|
init_mesh_ledger();
|
|
2583
2741
|
init_mesh_work_queue();
|
|
2742
|
+
REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
|
|
2584
2743
|
remoteIdleSessions = /* @__PURE__ */ new Map();
|
|
2585
|
-
MAX_PENDING_EVENTS = 50;
|
|
2586
|
-
pendingMeshCoordinatorEvents = [];
|
|
2587
2744
|
MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
|
|
2588
2745
|
"agent:generating_started",
|
|
2589
2746
|
"agent:generating_completed",
|
|
@@ -2599,6 +2756,8 @@ var init_mesh_events = __esm({
|
|
|
2599
2756
|
"monitor:long_generating": "task_stalled"
|
|
2600
2757
|
};
|
|
2601
2758
|
INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
|
|
2759
|
+
RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
|
|
2760
|
+
recentCompletionFingerprints = /* @__PURE__ */ new Map();
|
|
2602
2761
|
autoLaunchInProgress = /* @__PURE__ */ new Set();
|
|
2603
2762
|
autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
|
|
2604
2763
|
AUTO_LAUNCH_COOLDOWN_MS = 5e3;
|
|
@@ -7872,8 +8031,8 @@ var P2pRelayFailureError = class extends Error {
|
|
|
7872
8031
|
};
|
|
7873
8032
|
|
|
7874
8033
|
// src/config/state-store.ts
|
|
7875
|
-
var
|
|
7876
|
-
var
|
|
8034
|
+
var import_fs7 = require("fs");
|
|
8035
|
+
var import_path6 = require("path");
|
|
7877
8036
|
init_config();
|
|
7878
8037
|
var DEFAULT_STATE = {
|
|
7879
8038
|
recentActivity: [],
|
|
@@ -7887,7 +8046,7 @@ function isPlainObject2(value) {
|
|
|
7887
8046
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
7888
8047
|
}
|
|
7889
8048
|
function getStatePath() {
|
|
7890
|
-
return (0,
|
|
8049
|
+
return (0, import_path6.join)(getConfigDir(), "state.json");
|
|
7891
8050
|
}
|
|
7892
8051
|
function normalizeState(raw) {
|
|
7893
8052
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -7923,11 +8082,11 @@ function normalizeState(raw) {
|
|
|
7923
8082
|
}
|
|
7924
8083
|
function loadState() {
|
|
7925
8084
|
const statePath = getStatePath();
|
|
7926
|
-
if (!(0,
|
|
8085
|
+
if (!(0, import_fs7.existsSync)(statePath)) {
|
|
7927
8086
|
return { ...DEFAULT_STATE };
|
|
7928
8087
|
}
|
|
7929
8088
|
try {
|
|
7930
|
-
const raw = (0,
|
|
8089
|
+
const raw = (0, import_fs7.readFileSync)(statePath, "utf-8");
|
|
7931
8090
|
return normalizeState(JSON.parse(raw));
|
|
7932
8091
|
} catch {
|
|
7933
8092
|
return { ...DEFAULT_STATE };
|
|
@@ -7936,7 +8095,7 @@ function loadState() {
|
|
|
7936
8095
|
function saveState(state) {
|
|
7937
8096
|
const statePath = getStatePath();
|
|
7938
8097
|
const normalized = normalizeState(state);
|
|
7939
|
-
(0,
|
|
8098
|
+
(0, import_fs7.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
7940
8099
|
}
|
|
7941
8100
|
function resetState() {
|
|
7942
8101
|
saveState({ ...DEFAULT_STATE });
|
|
@@ -7944,7 +8103,7 @@ function resetState() {
|
|
|
7944
8103
|
|
|
7945
8104
|
// src/detection/ide-detector.ts
|
|
7946
8105
|
var import_child_process2 = require("child_process");
|
|
7947
|
-
var
|
|
8106
|
+
var import_fs8 = require("fs");
|
|
7948
8107
|
var import_os2 = require("os");
|
|
7949
8108
|
var path10 = __toESM(require("path"));
|
|
7950
8109
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
@@ -7968,7 +8127,7 @@ function findCliCommand(command) {
|
|
|
7968
8127
|
if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
7969
8128
|
const candidate = trimmed.startsWith("~") ? path10.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
|
|
7970
8129
|
const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
|
|
7971
|
-
return (0,
|
|
8130
|
+
return (0, import_fs8.existsSync)(resolved) ? resolved : null;
|
|
7972
8131
|
}
|
|
7973
8132
|
try {
|
|
7974
8133
|
const result = (0, import_child_process2.execSync)(
|
|
@@ -7999,9 +8158,9 @@ function checkPathExists(paths) {
|
|
|
7999
8158
|
if (normalized.includes("*")) {
|
|
8000
8159
|
const username = home.split(/[\\/]/).pop() || "";
|
|
8001
8160
|
const resolved = normalized.replace("*", username);
|
|
8002
|
-
if ((0,
|
|
8161
|
+
if ((0, import_fs8.existsSync)(resolved)) return resolved;
|
|
8003
8162
|
} else {
|
|
8004
|
-
if ((0,
|
|
8163
|
+
if ((0, import_fs8.existsSync)(normalized)) return normalized;
|
|
8005
8164
|
}
|
|
8006
8165
|
}
|
|
8007
8166
|
return null;
|
|
@@ -8015,7 +8174,7 @@ async function detectIDEs(providerLoader) {
|
|
|
8015
8174
|
let resolvedCli = cliPath;
|
|
8016
8175
|
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
8017
8176
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
8018
|
-
if ((0,
|
|
8177
|
+
if ((0, import_fs8.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
8019
8178
|
}
|
|
8020
8179
|
if (!resolvedCli && appPath && os22 === "win32") {
|
|
8021
8180
|
const { dirname: dirname9 } = await import("path");
|
|
@@ -8028,7 +8187,7 @@ async function detectIDEs(providerLoader) {
|
|
|
8028
8187
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
8029
8188
|
];
|
|
8030
8189
|
for (const c of candidates) {
|
|
8031
|
-
if ((0,
|
|
8190
|
+
if ((0, import_fs8.existsSync)(c)) {
|
|
8032
8191
|
resolvedCli = c;
|
|
8033
8192
|
break;
|
|
8034
8193
|
}
|
|
@@ -17181,7 +17340,7 @@ var DaemonCommandHandler = class {
|
|
|
17181
17340
|
var os13 = __toESM(require("os"));
|
|
17182
17341
|
var path18 = __toESM(require("path"));
|
|
17183
17342
|
var crypto4 = __toESM(require("crypto"));
|
|
17184
|
-
var
|
|
17343
|
+
var import_fs9 = require("fs");
|
|
17185
17344
|
var import_child_process6 = require("child_process");
|
|
17186
17345
|
var import_chalk = __toESM(require("chalk"));
|
|
17187
17346
|
init_provider_cli_adapter();
|
|
@@ -19653,7 +19812,7 @@ function commandExists(command) {
|
|
|
19653
19812
|
const trimmed = command.trim();
|
|
19654
19813
|
if (!trimmed) return false;
|
|
19655
19814
|
if (isExplicitCommand(trimmed)) {
|
|
19656
|
-
return (0,
|
|
19815
|
+
return (0, import_fs9.existsSync)(expandExecutable(trimmed));
|
|
19657
19816
|
}
|
|
19658
19817
|
try {
|
|
19659
19818
|
(0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -19682,10 +19841,10 @@ function hasCliArg(args, flag) {
|
|
|
19682
19841
|
}
|
|
19683
19842
|
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
19684
19843
|
const baseDir = path18.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
19685
|
-
(0,
|
|
19844
|
+
(0, import_fs9.mkdirSync)(baseDir, { recursive: true });
|
|
19686
19845
|
const workspaceHash = crypto4.createHash("sha256").update(path18.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
19687
19846
|
const filePath = path18.join(baseDir, `${workspaceHash}.json`);
|
|
19688
|
-
(0,
|
|
19847
|
+
(0, import_fs9.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
19689
19848
|
return filePath;
|
|
19690
19849
|
}
|
|
19691
19850
|
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
@@ -23864,7 +24023,7 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
|
|
|
23864
24023
|
|
|
23865
24024
|
// src/commands/router.ts
|
|
23866
24025
|
var import_os3 = require("os");
|
|
23867
|
-
var
|
|
24026
|
+
var import_path7 = require("path");
|
|
23868
24027
|
var fs10 = __toESM(require("fs"));
|
|
23869
24028
|
var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
|
|
23870
24029
|
var CHANNEL_SERVER_URL = {
|
|
@@ -24294,7 +24453,7 @@ function truncateValidationOutput(value) {
|
|
|
24294
24453
|
}
|
|
24295
24454
|
function readPackageScripts(workspace) {
|
|
24296
24455
|
try {
|
|
24297
|
-
const packageJsonPath = (0,
|
|
24456
|
+
const packageJsonPath = (0, import_path7.join)(workspace, "package.json");
|
|
24298
24457
|
const parsed = JSON.parse(fs10.readFileSync(packageJsonPath, "utf-8"));
|
|
24299
24458
|
return parsed?.scripts && typeof parsed.scripts === "object" && !Array.isArray(parsed.scripts) ? parsed.scripts : {};
|
|
24300
24459
|
} catch {
|
|
@@ -24502,13 +24661,13 @@ function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
|
24502
24661
|
}
|
|
24503
24662
|
function resolveHermesUserHome() {
|
|
24504
24663
|
const explicitHome = process.env.HERMES_HOME?.trim();
|
|
24505
|
-
return explicitHome || (0,
|
|
24664
|
+
return explicitHome || (0, import_path7.join)((0, import_os3.homedir)(), ".hermes");
|
|
24506
24665
|
}
|
|
24507
24666
|
function loadHermesCoordinatorBaseConfig(targetConfigPath) {
|
|
24508
24667
|
const sourceHome = resolveHermesUserHome();
|
|
24509
|
-
const sourceConfigPath = (0,
|
|
24668
|
+
const sourceConfigPath = (0, import_path7.join)(sourceHome, "config.yaml");
|
|
24510
24669
|
if (!fs10.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
24511
|
-
if ((0,
|
|
24670
|
+
if ((0, import_path7.resolve)(sourceConfigPath) === (0, import_path7.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
24512
24671
|
const parsed = parseMeshCoordinatorMcpConfig(fs10.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
|
|
24513
24672
|
const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
|
|
24514
24673
|
return { config: baseConfig, sourceHome, sourceConfigPath };
|
|
@@ -24542,10 +24701,10 @@ function stripHermesCoordinatorTempModelProviderOverrides(config) {
|
|
|
24542
24701
|
return sanitized;
|
|
24543
24702
|
}
|
|
24544
24703
|
function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
|
|
24545
|
-
if ((0,
|
|
24704
|
+
if ((0, import_path7.resolve)(sourceHome) === (0, import_path7.resolve)(targetHome)) return;
|
|
24546
24705
|
for (const fileName of [".env", "auth.json"]) {
|
|
24547
|
-
const sourcePath = (0,
|
|
24548
|
-
const targetPath = (0,
|
|
24706
|
+
const sourcePath = (0, import_path7.join)(sourceHome, fileName);
|
|
24707
|
+
const targetPath = (0, import_path7.join)(targetHome, fileName);
|
|
24549
24708
|
if (!fs10.existsSync(sourcePath)) continue;
|
|
24550
24709
|
try {
|
|
24551
24710
|
fs10.copyFileSync(sourcePath, targetPath);
|
|
@@ -24752,7 +24911,7 @@ var DaemonCommandRouter = class {
|
|
|
24752
24911
|
}
|
|
24753
24912
|
const { resolveWorktreePath: resolveWorktreePath2, listWorktrees: listWorktrees2, removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
24754
24913
|
const normalizePath = (value) => {
|
|
24755
|
-
const resolved = (0,
|
|
24914
|
+
const resolved = (0, import_path7.resolve)(value);
|
|
24756
24915
|
try {
|
|
24757
24916
|
return fs10.realpathSync(resolved);
|
|
24758
24917
|
} catch {
|
|
@@ -25153,7 +25312,8 @@ var DaemonCommandRouter = class {
|
|
|
25153
25312
|
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
25154
25313
|
}
|
|
25155
25314
|
case "get_pending_mesh_events": {
|
|
25156
|
-
const
|
|
25315
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25316
|
+
const events = drainPendingMeshCoordinatorEvents(meshId || void 0);
|
|
25157
25317
|
return { success: true, events };
|
|
25158
25318
|
}
|
|
25159
25319
|
case "launch_cli":
|
|
@@ -26374,7 +26534,7 @@ ${block}`);
|
|
|
26374
26534
|
workspace
|
|
26375
26535
|
};
|
|
26376
26536
|
}
|
|
26377
|
-
const { existsSync:
|
|
26537
|
+
const { existsSync: existsSync26, readFileSync: readFileSync18, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
|
|
26378
26538
|
const { dirname: dirname9 } = await import("path");
|
|
26379
26539
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
26380
26540
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -26417,14 +26577,14 @@ ${block}`);
|
|
|
26417
26577
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
26418
26578
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
26419
26579
|
}
|
|
26420
|
-
const hadExistingMcpConfig =
|
|
26580
|
+
const hadExistingMcpConfig = existsSync26(mcpConfigPath);
|
|
26421
26581
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
26422
26582
|
if (hermesBaseConfig) {
|
|
26423
26583
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
|
|
26424
26584
|
}
|
|
26425
26585
|
if (hadExistingMcpConfig) {
|
|
26426
26586
|
try {
|
|
26427
|
-
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
26587
|
+
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync18(mcpConfigPath, "utf-8"), configFormat);
|
|
26428
26588
|
const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
|
|
26429
26589
|
existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
|
|
26430
26590
|
copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
|
|
@@ -26612,29 +26772,48 @@ ${block}`);
|
|
|
26612
26772
|
}
|
|
26613
26773
|
if (workspace) {
|
|
26614
26774
|
if (!fs10.existsSync(workspace)) {
|
|
26615
|
-
|
|
26616
|
-
|
|
26617
|
-
|
|
26618
|
-
|
|
26619
|
-
|
|
26620
|
-
|
|
26621
|
-
|
|
26622
|
-
|
|
26623
|
-
|
|
26775
|
+
let remoteProbeApplied = false;
|
|
26776
|
+
if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand) {
|
|
26777
|
+
try {
|
|
26778
|
+
const remoteResult = await Promise.race([
|
|
26779
|
+
this.deps.dispatchMeshCommand(daemonId, "git_status", { workspace }),
|
|
26780
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 8e3))
|
|
26781
|
+
]);
|
|
26782
|
+
const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
|
|
26783
|
+
if (remoteGit && typeof remoteGit === "object" && typeof remoteGit.isGitRepo === "boolean") {
|
|
26784
|
+
status.git = remoteGit;
|
|
26785
|
+
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
26786
|
+
remoteProbeApplied = true;
|
|
26787
|
+
}
|
|
26788
|
+
} catch {
|
|
26789
|
+
}
|
|
26624
26790
|
}
|
|
26625
|
-
|
|
26626
|
-
|
|
26627
|
-
|
|
26628
|
-
|
|
26629
|
-
|
|
26630
|
-
|
|
26631
|
-
|
|
26632
|
-
|
|
26633
|
-
|
|
26791
|
+
if (!remoteProbeApplied) {
|
|
26792
|
+
if (applyCachedInlineMeshNodeStatus(status, node)) {
|
|
26793
|
+
status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
|
|
26794
|
+
nodeStatuses.push(status);
|
|
26795
|
+
continue;
|
|
26796
|
+
}
|
|
26797
|
+
if (meshRecord?.source === "inline_cache" && !isSelfNode) {
|
|
26798
|
+
status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
|
|
26799
|
+
nodeStatuses.push(status);
|
|
26800
|
+
continue;
|
|
26801
|
+
}
|
|
26634
26802
|
}
|
|
26635
|
-
}
|
|
26636
|
-
|
|
26637
|
-
|
|
26803
|
+
} else {
|
|
26804
|
+
try {
|
|
26805
|
+
const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
26806
|
+
status.git = gitStatus;
|
|
26807
|
+
if (gitStatus.isGitRepo) {
|
|
26808
|
+
status.health = deriveMeshNodeHealthFromGit(gitStatus);
|
|
26809
|
+
} else {
|
|
26810
|
+
status.health = "degraded";
|
|
26811
|
+
if (gitStatus.error && !status.error) status.error = gitStatus.error;
|
|
26812
|
+
}
|
|
26813
|
+
} catch {
|
|
26814
|
+
if (!applyCachedInlineMeshNodeStatus(status, node)) {
|
|
26815
|
+
status.health = "degraded";
|
|
26816
|
+
}
|
|
26638
26817
|
}
|
|
26639
26818
|
}
|
|
26640
26819
|
} else {
|