@adhdev/daemon-core 0.9.82-rc.3 → 0.9.82-rc.30
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/boot/daemon-lifecycle.d.ts +2 -0
- package/dist/commands/router.d.ts +5 -0
- package/dist/git/git-commands.d.ts +1 -0
- package/dist/git/git-status.d.ts +5 -0
- package/dist/git/git-types.d.ts +10 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +863 -291
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +862 -291
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events.d.ts +17 -5
- package/dist/mesh/mesh-work-queue.d.ts +3 -1
- package/dist/providers/chat-message-normalization.d.ts +1 -0
- package/dist/repo-mesh-types.d.ts +128 -0
- package/package.json +1 -1
- package/src/boot/daemon-lifecycle.ts +3 -0
- package/src/commands/router.ts +588 -147
- package/src/git/git-commands.ts +3 -3
- package/src/git/git-status.ts +97 -6
- package/src/git/git-summary.ts +3 -0
- package/src/git/git-types.ts +11 -0
- package/src/index.ts +9 -1
- package/src/mesh/mesh-events.ts +168 -30
- package/src/mesh/mesh-work-queue.ts +135 -119
- package/src/providers/chat-message-normalization.ts +3 -1
- package/src/repo-mesh-types.ts +138 -0
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
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
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
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
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
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
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
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
...autoLaunch,
|
|
1436
|
-
updatedAt
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
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
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
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
|
-
|
|
1456
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
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);
|
|
@@ -1890,18 +1933,77 @@ __export(mesh_events_exports, {
|
|
|
1890
1933
|
drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
|
|
1891
1934
|
getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
|
|
1892
1935
|
handleMeshForwardEvent: () => handleMeshForwardEvent,
|
|
1936
|
+
queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
|
|
1893
1937
|
setupMeshEventForwarding: () => setupMeshEventForwarding,
|
|
1894
1938
|
triggerMeshQueue: () => triggerMeshQueue,
|
|
1895
1939
|
tryAssignQueueTask: () => tryAssignQueueTask
|
|
1896
1940
|
});
|
|
1897
|
-
|
|
1898
|
-
|
|
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
|
+
}
|
|
1899
1948
|
}
|
|
1900
|
-
function
|
|
1901
|
-
|
|
1949
|
+
function getPendingEventsPath(meshId) {
|
|
1950
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1951
|
+
return join9(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
1902
1952
|
}
|
|
1903
|
-
function
|
|
1904
|
-
|
|
1953
|
+
function queuePendingMeshCoordinatorEvent(event) {
|
|
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}`);
|
|
1959
|
+
return false;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
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
|
+
}
|
|
1982
|
+
}
|
|
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
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
function clearPendingMeshCoordinatorEvents(meshId) {
|
|
2001
|
+
if (!meshId) return;
|
|
2002
|
+
const path28 = getPendingEventsPath(meshId);
|
|
2003
|
+
if (existsSync9(path28)) try {
|
|
2004
|
+
unlinkSync3(path28);
|
|
2005
|
+
} catch {
|
|
2006
|
+
}
|
|
1905
2007
|
}
|
|
1906
2008
|
function readNonEmptyString(value) {
|
|
1907
2009
|
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
@@ -1947,6 +2049,38 @@ function shouldSuppressIntentionalCleanupStop(args) {
|
|
|
1947
2049
|
if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
|
|
1948
2050
|
return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
|
|
1949
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
|
+
}
|
|
1950
2084
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
1951
2085
|
const task = claimNextTask(meshId, nodeId, sessionId);
|
|
1952
2086
|
if (!task) {
|
|
@@ -1965,7 +2099,16 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
1965
2099
|
message: task.message
|
|
1966
2100
|
}).catch((e) => {
|
|
1967
2101
|
LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
|
|
1968
|
-
updateTaskStatus(meshId, task.id, "
|
|
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
|
+
}
|
|
1969
2112
|
});
|
|
1970
2113
|
return true;
|
|
1971
2114
|
}
|
|
@@ -2299,18 +2442,36 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2299
2442
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
2300
2443
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
2301
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
|
+
}
|
|
2302
2461
|
let completedTaskForLedger = null;
|
|
2303
2462
|
if (args.event === "agent:generating_completed") {
|
|
2304
2463
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
2305
2464
|
const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
|
|
2306
2465
|
const providerType = readNonEmptyString(args.metadataEvent.providerType);
|
|
2307
2466
|
if (sessionId) {
|
|
2308
|
-
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
|
+
});
|
|
2309
2470
|
completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
|
|
2310
2471
|
if (nodeId && providerType) {
|
|
2311
|
-
|
|
2472
|
+
setImmediate(() => {
|
|
2312
2473
|
tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
2313
|
-
}
|
|
2474
|
+
});
|
|
2314
2475
|
}
|
|
2315
2476
|
}
|
|
2316
2477
|
} else if (args.event === "agent:ready") {
|
|
@@ -2348,13 +2509,17 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2348
2509
|
}
|
|
2349
2510
|
}
|
|
2350
2511
|
if (sessionId && nodeId && providerType) {
|
|
2351
|
-
|
|
2352
|
-
|
|
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(() => {
|
|
2353
2520
|
const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
2354
|
-
if (assigned) {
|
|
2355
|
-
|
|
2356
|
-
}
|
|
2357
|
-
}, 500);
|
|
2521
|
+
if (assigned) remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
|
|
2522
|
+
});
|
|
2358
2523
|
}
|
|
2359
2524
|
} else if (args.event === "agent:generating_started") {
|
|
2360
2525
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
@@ -2465,17 +2630,18 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2465
2630
|
return true;
|
|
2466
2631
|
});
|
|
2467
2632
|
if (coordinatorInstances.length === 0) {
|
|
2468
|
-
if (
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
}
|
|
2477
|
-
|
|
2478
|
-
|
|
2633
|
+
if (queuePendingMeshCoordinatorEvent({
|
|
2634
|
+
event: args.event,
|
|
2635
|
+
meshId: args.meshId,
|
|
2636
|
+
nodeLabel: args.nodeLabel,
|
|
2637
|
+
nodeId: args.nodeId || void 0,
|
|
2638
|
+
workspace: readNonEmptyString(args.metadataEvent.workspace),
|
|
2639
|
+
metadataEvent: {
|
|
2640
|
+
...args.metadataEvent,
|
|
2641
|
+
...recoveryContext ? { recoveryContext } : {}
|
|
2642
|
+
},
|
|
2643
|
+
queuedAt: Date.now()
|
|
2644
|
+
})) {
|
|
2479
2645
|
LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
|
|
2480
2646
|
}
|
|
2481
2647
|
return { success: true, forwarded: 0 };
|
|
@@ -2514,6 +2680,7 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
2514
2680
|
providerType: readNonEmptyString(payload.providerType),
|
|
2515
2681
|
providerSessionId: readNonEmptyString(payload.providerSessionId),
|
|
2516
2682
|
finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
|
|
2683
|
+
...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
|
|
2517
2684
|
intentional: payload.intentional === true,
|
|
2518
2685
|
intentionalStop: payload.intentionalStop === true,
|
|
2519
2686
|
operatorCleanup: payload.operatorCleanup === true,
|
|
@@ -2556,7 +2723,7 @@ function setupMeshEventForwarding(components) {
|
|
|
2556
2723
|
});
|
|
2557
2724
|
});
|
|
2558
2725
|
}
|
|
2559
|
-
var
|
|
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;
|
|
2560
2727
|
var init_mesh_events = __esm({
|
|
2561
2728
|
"src/mesh/mesh-events.ts"() {
|
|
2562
2729
|
"use strict";
|
|
@@ -2566,9 +2733,8 @@ var init_mesh_events = __esm({
|
|
|
2566
2733
|
init_logger();
|
|
2567
2734
|
init_mesh_ledger();
|
|
2568
2735
|
init_mesh_work_queue();
|
|
2736
|
+
REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
|
|
2569
2737
|
remoteIdleSessions = /* @__PURE__ */ new Map();
|
|
2570
|
-
MAX_PENDING_EVENTS = 50;
|
|
2571
|
-
pendingMeshCoordinatorEvents = [];
|
|
2572
2738
|
MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
|
|
2573
2739
|
"agent:generating_started",
|
|
2574
2740
|
"agent:generating_completed",
|
|
@@ -2584,6 +2750,8 @@ var init_mesh_events = __esm({
|
|
|
2584
2750
|
"monitor:long_generating": "task_stalled"
|
|
2585
2751
|
};
|
|
2586
2752
|
INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
|
|
2753
|
+
RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
|
|
2754
|
+
recentCompletionFingerprints = /* @__PURE__ */ new Map();
|
|
2587
2755
|
autoLaunchInProgress = /* @__PURE__ */ new Set();
|
|
2588
2756
|
autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
|
|
2589
2757
|
AUTO_LAUNCH_COOLDOWN_MS = 5e3;
|
|
@@ -5676,8 +5844,14 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5676
5844
|
const includeSubmodules = options.includeSubmodules !== false;
|
|
5677
5845
|
try {
|
|
5678
5846
|
const repo = await resolveGitRepository(workspace, options);
|
|
5679
|
-
|
|
5680
|
-
|
|
5847
|
+
let parsed = await readPorcelainStatus(repo, options);
|
|
5848
|
+
let upstreamProbe = getInitialUpstreamProbe(parsed);
|
|
5849
|
+
if (options.refreshUpstream) {
|
|
5850
|
+
upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
|
|
5851
|
+
if (upstreamProbe.upstreamStatus === "fresh") {
|
|
5852
|
+
parsed = await readPorcelainStatus(repo, options);
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5681
5855
|
const head = await readHead(repo, options);
|
|
5682
5856
|
const stashCount = await readStashCount(repo, options);
|
|
5683
5857
|
let submodules;
|
|
@@ -5692,6 +5866,9 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5692
5866
|
headCommit: head.commit,
|
|
5693
5867
|
headMessage: head.message,
|
|
5694
5868
|
upstream: parsed.upstream,
|
|
5869
|
+
upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
|
|
5870
|
+
upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
|
|
5871
|
+
upstreamFetchError: upstreamProbe.upstreamFetchError,
|
|
5695
5872
|
ahead: parsed.ahead,
|
|
5696
5873
|
behind: parsed.behind,
|
|
5697
5874
|
staged: parsed.staged,
|
|
@@ -5716,6 +5893,60 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5716
5893
|
);
|
|
5717
5894
|
}
|
|
5718
5895
|
}
|
|
5896
|
+
async function readPorcelainStatus(repo, options) {
|
|
5897
|
+
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
5898
|
+
return parsePorcelainV2Status(statusOutput.stdout);
|
|
5899
|
+
}
|
|
5900
|
+
function getInitialUpstreamProbe(parsed) {
|
|
5901
|
+
return {
|
|
5902
|
+
upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
|
|
5903
|
+
};
|
|
5904
|
+
}
|
|
5905
|
+
async function refreshTrackedUpstream(repo, parsed, options) {
|
|
5906
|
+
if (!parsed.upstream || !parsed.branch) {
|
|
5907
|
+
return { upstreamStatus: "no_upstream" };
|
|
5908
|
+
}
|
|
5909
|
+
const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
|
|
5910
|
+
if (!remoteName) {
|
|
5911
|
+
return {
|
|
5912
|
+
upstreamStatus: "stale",
|
|
5913
|
+
upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
|
|
5914
|
+
};
|
|
5915
|
+
}
|
|
5916
|
+
try {
|
|
5917
|
+
await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
|
|
5918
|
+
return {
|
|
5919
|
+
upstreamStatus: "fresh",
|
|
5920
|
+
upstreamFetchedAt: Date.now()
|
|
5921
|
+
};
|
|
5922
|
+
} catch (error) {
|
|
5923
|
+
return {
|
|
5924
|
+
upstreamStatus: "stale",
|
|
5925
|
+
upstreamFetchError: formatGitError(error)
|
|
5926
|
+
};
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5929
|
+
async function readBranchRemote(repo, branch, options) {
|
|
5930
|
+
try {
|
|
5931
|
+
const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
|
|
5932
|
+
return result.stdout.trim() || null;
|
|
5933
|
+
} catch {
|
|
5934
|
+
return null;
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
function inferRemoteName(upstream) {
|
|
5938
|
+
const [remoteName] = upstream.split("/");
|
|
5939
|
+
return remoteName?.trim() || null;
|
|
5940
|
+
}
|
|
5941
|
+
function formatGitError(error) {
|
|
5942
|
+
if (error instanceof GitCommandError) {
|
|
5943
|
+
return error.stderr || error.message;
|
|
5944
|
+
}
|
|
5945
|
+
if (error instanceof Error) {
|
|
5946
|
+
return error.message;
|
|
5947
|
+
}
|
|
5948
|
+
return String(error);
|
|
5949
|
+
}
|
|
5719
5950
|
function parsePorcelainV2Status(output) {
|
|
5720
5951
|
const parsed = {
|
|
5721
5952
|
branch: null,
|
|
@@ -5810,6 +6041,7 @@ function emptyStatus(workspace, lastCheckedAt, error) {
|
|
|
5810
6041
|
headCommit: null,
|
|
5811
6042
|
headMessage: null,
|
|
5812
6043
|
upstream: null,
|
|
6044
|
+
upstreamStatus: "unavailable",
|
|
5813
6045
|
ahead: 0,
|
|
5814
6046
|
behind: 0,
|
|
5815
6047
|
staged: 0,
|
|
@@ -6090,6 +6322,9 @@ function createGitCompactSummary(status, diffSummary) {
|
|
|
6090
6322
|
isGitRepo: status.isGitRepo,
|
|
6091
6323
|
repoRoot: status.repoRoot,
|
|
6092
6324
|
branch: status.branch,
|
|
6325
|
+
upstreamStatus: status.upstreamStatus,
|
|
6326
|
+
upstreamFetchedAt: status.upstreamFetchedAt,
|
|
6327
|
+
upstreamFetchError: status.upstreamFetchError,
|
|
6093
6328
|
dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
|
|
6094
6329
|
changedFiles,
|
|
6095
6330
|
ahead: status.ahead,
|
|
@@ -6434,7 +6669,7 @@ var defaultSnapshotStore = createGitSnapshotStore({
|
|
|
6434
6669
|
});
|
|
6435
6670
|
function createDefaultGitCommandServices() {
|
|
6436
6671
|
return {
|
|
6437
|
-
getStatus: ({ workspace }) => getGitRepoStatus(workspace),
|
|
6672
|
+
getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
|
|
6438
6673
|
getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
|
|
6439
6674
|
getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
|
|
6440
6675
|
createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
|
|
@@ -6520,7 +6755,7 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
|
|
|
6520
6755
|
switch (command) {
|
|
6521
6756
|
case "git_status": {
|
|
6522
6757
|
if (!services.getStatus) return serviceNotImplemented(command);
|
|
6523
|
-
const status = await runService(() => services.getStatus({ workspace }));
|
|
6758
|
+
const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
|
|
6524
6759
|
return "success" in status ? status : { success: true, status };
|
|
6525
6760
|
}
|
|
6526
6761
|
case "git_diff_summary": {
|
|
@@ -7559,8 +7794,8 @@ var P2pRelayFailureError = class extends Error {
|
|
|
7559
7794
|
|
|
7560
7795
|
// src/config/state-store.ts
|
|
7561
7796
|
init_config();
|
|
7562
|
-
import { existsSync as
|
|
7563
|
-
import { join as
|
|
7797
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
7798
|
+
import { join as join10 } from "path";
|
|
7564
7799
|
var DEFAULT_STATE = {
|
|
7565
7800
|
recentActivity: [],
|
|
7566
7801
|
savedProviderSessions: [],
|
|
@@ -7573,7 +7808,7 @@ function isPlainObject2(value) {
|
|
|
7573
7808
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
7574
7809
|
}
|
|
7575
7810
|
function getStatePath() {
|
|
7576
|
-
return
|
|
7811
|
+
return join10(getConfigDir(), "state.json");
|
|
7577
7812
|
}
|
|
7578
7813
|
function normalizeState(raw) {
|
|
7579
7814
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -7609,11 +7844,11 @@ function normalizeState(raw) {
|
|
|
7609
7844
|
}
|
|
7610
7845
|
function loadState() {
|
|
7611
7846
|
const statePath = getStatePath();
|
|
7612
|
-
if (!
|
|
7847
|
+
if (!existsSync10(statePath)) {
|
|
7613
7848
|
return { ...DEFAULT_STATE };
|
|
7614
7849
|
}
|
|
7615
7850
|
try {
|
|
7616
|
-
const raw =
|
|
7851
|
+
const raw = readFileSync6(statePath, "utf-8");
|
|
7617
7852
|
return normalizeState(JSON.parse(raw));
|
|
7618
7853
|
} catch {
|
|
7619
7854
|
return { ...DEFAULT_STATE };
|
|
@@ -7630,7 +7865,7 @@ function resetState() {
|
|
|
7630
7865
|
|
|
7631
7866
|
// src/detection/ide-detector.ts
|
|
7632
7867
|
import { execSync } from "child_process";
|
|
7633
|
-
import { existsSync as
|
|
7868
|
+
import { existsSync as existsSync11 } from "fs";
|
|
7634
7869
|
import { platform as platform2, homedir as homedir5 } from "os";
|
|
7635
7870
|
import * as path10 from "path";
|
|
7636
7871
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
@@ -7654,7 +7889,7 @@ function findCliCommand(command) {
|
|
|
7654
7889
|
if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
7655
7890
|
const candidate = trimmed.startsWith("~") ? path10.join(homedir5(), trimmed.slice(1)) : trimmed;
|
|
7656
7891
|
const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
|
|
7657
|
-
return
|
|
7892
|
+
return existsSync11(resolved) ? resolved : null;
|
|
7658
7893
|
}
|
|
7659
7894
|
try {
|
|
7660
7895
|
const result = execSync(
|
|
@@ -7685,9 +7920,9 @@ function checkPathExists(paths) {
|
|
|
7685
7920
|
if (normalized.includes("*")) {
|
|
7686
7921
|
const username = home.split(/[\\/]/).pop() || "";
|
|
7687
7922
|
const resolved = normalized.replace("*", username);
|
|
7688
|
-
if (
|
|
7923
|
+
if (existsSync11(resolved)) return resolved;
|
|
7689
7924
|
} else {
|
|
7690
|
-
if (
|
|
7925
|
+
if (existsSync11(normalized)) return normalized;
|
|
7691
7926
|
}
|
|
7692
7927
|
}
|
|
7693
7928
|
return null;
|
|
@@ -7701,7 +7936,7 @@ async function detectIDEs(providerLoader) {
|
|
|
7701
7936
|
let resolvedCli = cliPath;
|
|
7702
7937
|
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
7703
7938
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
7704
|
-
if (
|
|
7939
|
+
if (existsSync11(bundledCli)) resolvedCli = bundledCli;
|
|
7705
7940
|
}
|
|
7706
7941
|
if (!resolvedCli && appPath && os22 === "win32") {
|
|
7707
7942
|
const { dirname: dirname9 } = await import("path");
|
|
@@ -7714,7 +7949,7 @@ async function detectIDEs(providerLoader) {
|
|
|
7714
7949
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
7715
7950
|
];
|
|
7716
7951
|
for (const c of candidates) {
|
|
7717
|
-
if (
|
|
7952
|
+
if (existsSync11(c)) {
|
|
7718
7953
|
resolvedCli = c;
|
|
7719
7954
|
break;
|
|
7720
7955
|
}
|
|
@@ -9606,7 +9841,8 @@ var StatusMonitor = class {
|
|
|
9606
9841
|
};
|
|
9607
9842
|
|
|
9608
9843
|
// src/providers/chat-message-normalization.ts
|
|
9609
|
-
|
|
9844
|
+
var DEFAULT_FINAL_SUMMARY_MAX_CHARS = 4e3;
|
|
9845
|
+
function extractFinalSummaryFromMessages(messages, maxChars = DEFAULT_FINAL_SUMMARY_MAX_CHARS) {
|
|
9610
9846
|
if (!Array.isArray(messages) || messages.length === 0) return "";
|
|
9611
9847
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
9612
9848
|
const msg = messages[i];
|
|
@@ -16869,7 +17105,7 @@ init_config();
|
|
|
16869
17105
|
import * as os13 from "os";
|
|
16870
17106
|
import * as path18 from "path";
|
|
16871
17107
|
import * as crypto4 from "crypto";
|
|
16872
|
-
import { existsSync as
|
|
17108
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
16873
17109
|
import { execFileSync } from "child_process";
|
|
16874
17110
|
import chalk from "chalk";
|
|
16875
17111
|
|
|
@@ -19343,7 +19579,7 @@ function commandExists(command) {
|
|
|
19343
19579
|
const trimmed = command.trim();
|
|
19344
19580
|
if (!trimmed) return false;
|
|
19345
19581
|
if (isExplicitCommand(trimmed)) {
|
|
19346
|
-
return
|
|
19582
|
+
return existsSync15(expandExecutable(trimmed));
|
|
19347
19583
|
}
|
|
19348
19584
|
try {
|
|
19349
19585
|
execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -22612,10 +22848,10 @@ import * as yaml from "js-yaml";
|
|
|
22612
22848
|
// src/commands/mesh-coordinator.ts
|
|
22613
22849
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
22614
22850
|
import { createHash as createHash2 } from "crypto";
|
|
22615
|
-
import { existsSync as
|
|
22851
|
+
import { existsSync as existsSync18, readdirSync as readdirSync7, realpathSync as realpathSync2 } from "fs";
|
|
22616
22852
|
import { createRequire as createRequire2 } from "module";
|
|
22617
22853
|
import * as os17 from "os";
|
|
22618
|
-
import { dirname as dirname4, isAbsolute as isAbsolute11, join as
|
|
22854
|
+
import { dirname as dirname4, isAbsolute as isAbsolute11, join as join21, resolve as resolve13 } from "path";
|
|
22619
22855
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
22620
22856
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
22621
22857
|
var HERMES_CLI_TYPE = "hermes-cli";
|
|
@@ -22638,7 +22874,7 @@ function resolveHermesMeshCoordinatorSetup(options) {
|
|
|
22638
22874
|
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
22639
22875
|
};
|
|
22640
22876
|
}
|
|
22641
|
-
const configPath =
|
|
22877
|
+
const configPath = join21(resolveHermesCoordinatorHome(options.meshId, options.workspace), "config.yaml");
|
|
22642
22878
|
if (!configPath.trim()) {
|
|
22643
22879
|
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
22644
22880
|
}
|
|
@@ -22759,14 +22995,14 @@ function resolveHermesCoordinatorHome(meshId, workspace) {
|
|
|
22759
22995
|
const key = `${meshId || "mesh"}
|
|
22760
22996
|
${resolve13(workspace || os17.tmpdir())}`;
|
|
22761
22997
|
const hash = createHash2("sha256").update(key).digest("hex").slice(0, 16);
|
|
22762
|
-
return
|
|
22998
|
+
return join21(os17.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash}`);
|
|
22763
22999
|
}
|
|
22764
23000
|
function resolveMcpConfigPath(configPath, workspace) {
|
|
22765
23001
|
const trimmed = configPath.trim();
|
|
22766
23002
|
if (trimmed === "~") return os17.homedir();
|
|
22767
|
-
if (trimmed.startsWith("~/")) return
|
|
23003
|
+
if (trimmed.startsWith("~/")) return join21(os17.homedir(), trimmed.slice(2));
|
|
22768
23004
|
if (isAbsolute11(trimmed)) return trimmed;
|
|
22769
|
-
return
|
|
23005
|
+
return join21(workspace, trimmed);
|
|
22770
23006
|
}
|
|
22771
23007
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
22772
23008
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
@@ -22822,15 +23058,15 @@ function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
|
22822
23058
|
for (const entry of (pathValue || "").split(":")) {
|
|
22823
23059
|
const dir = entry.trim();
|
|
22824
23060
|
if (!dir) continue;
|
|
22825
|
-
addCandidate(
|
|
23061
|
+
addCandidate(join21(dir, "node"));
|
|
22826
23062
|
}
|
|
22827
23063
|
}
|
|
22828
23064
|
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
22829
|
-
const versionsDir =
|
|
23065
|
+
const versionsDir = join21(homeDir, ".nvm", "versions", "node");
|
|
22830
23066
|
try {
|
|
22831
23067
|
const versionDirs = readdirSync7(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
22832
23068
|
for (const versionDir of versionDirs) {
|
|
22833
|
-
addCandidate(
|
|
23069
|
+
addCandidate(join21(versionsDir, versionDir, "bin", "node"));
|
|
22834
23070
|
}
|
|
22835
23071
|
} catch {
|
|
22836
23072
|
}
|
|
@@ -22881,7 +23117,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
22881
23117
|
if (normalized) return normalized;
|
|
22882
23118
|
}
|
|
22883
23119
|
try {
|
|
22884
|
-
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] :
|
|
23120
|
+
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join21(process.cwd(), "adhdev-daemon.js");
|
|
22885
23121
|
const req = createRequire2(requireBase);
|
|
22886
23122
|
const resolvedModule = req.resolve("@adhdev/mcp-server");
|
|
22887
23123
|
return normalizeExistingPath(resolvedModule) || resolvedModule;
|
|
@@ -22891,7 +23127,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
22891
23127
|
}
|
|
22892
23128
|
function normalizeExistingPath(filePath) {
|
|
22893
23129
|
try {
|
|
22894
|
-
if (!
|
|
23130
|
+
if (!existsSync18(filePath)) return null;
|
|
22895
23131
|
return realpathSync2.native(filePath);
|
|
22896
23132
|
} catch {
|
|
22897
23133
|
return null;
|
|
@@ -23603,52 +23839,33 @@ function readBooleanValue(...values) {
|
|
|
23603
23839
|
}
|
|
23604
23840
|
return void 0;
|
|
23605
23841
|
}
|
|
23606
|
-
function
|
|
23607
|
-
|
|
23608
|
-
const
|
|
23609
|
-
|
|
23610
|
-
const
|
|
23611
|
-
const
|
|
23612
|
-
const
|
|
23613
|
-
|
|
23614
|
-
|
|
23615
|
-
|
|
23616
|
-
|
|
23617
|
-
|
|
23618
|
-
|
|
23619
|
-
|
|
23620
|
-
|
|
23621
|
-
|
|
23622
|
-
|
|
23623
|
-
|
|
23624
|
-
|
|
23625
|
-
|
|
23626
|
-
|
|
23627
|
-
untracked: readNumberValue(cachedGit.untracked) ?? 0,
|
|
23628
|
-
deleted: readNumberValue(cachedGit.deleted) ?? 0,
|
|
23629
|
-
renamed: readNumberValue(cachedGit.renamed) ?? 0,
|
|
23630
|
-
hasConflicts: hasConflicts2,
|
|
23631
|
-
conflictFiles: conflictFiles2,
|
|
23632
|
-
stashCount: readNumberValue(cachedGit.stashCount) ?? 0,
|
|
23633
|
-
lastCheckedAt: readNumberValue(cachedGit.lastCheckedAt) ?? Date.now()
|
|
23634
|
-
};
|
|
23635
|
-
}
|
|
23636
|
-
}
|
|
23637
|
-
const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
|
|
23638
|
-
const gitResult = readObjectRecord(rawGit.result);
|
|
23639
|
-
const directStatus = readObjectRecord(rawGit.status);
|
|
23640
|
-
const nestedStatus = readObjectRecord(gitResult.status);
|
|
23641
|
-
const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
|
|
23642
|
-
const probeGit = readObjectRecord(rawProbe.git);
|
|
23643
|
-
const probeGitResult = readObjectRecord(probeGit.result);
|
|
23644
|
-
const probeDirectStatus = readObjectRecord(probeGit.status);
|
|
23645
|
-
const probeNestedStatus = readObjectRecord(probeGitResult.status);
|
|
23646
|
-
const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
|
|
23842
|
+
function readGitSubmodules(value) {
|
|
23843
|
+
if (!Array.isArray(value)) return void 0;
|
|
23844
|
+
const submodules = value.map((entry) => {
|
|
23845
|
+
const submodule = readObjectRecord(entry);
|
|
23846
|
+
const path28 = readStringValue(submodule.path);
|
|
23847
|
+
const commit = readStringValue(submodule.commit);
|
|
23848
|
+
const repoPath = readStringValue(submodule.repoPath, submodule.repo_root);
|
|
23849
|
+
if (!path28 || !commit || !repoPath) return null;
|
|
23850
|
+
return {
|
|
23851
|
+
path: path28,
|
|
23852
|
+
commit,
|
|
23853
|
+
repoPath,
|
|
23854
|
+
dirty: readBooleanValue(submodule.dirty) ?? false,
|
|
23855
|
+
outOfSync: readBooleanValue(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
23856
|
+
lastCheckedAt: readNumberValue(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now(),
|
|
23857
|
+
...readStringValue(submodule.error) ? { error: readStringValue(submodule.error) } : {}
|
|
23858
|
+
};
|
|
23859
|
+
}).filter((entry) => entry !== null);
|
|
23860
|
+
return submodules.length > 0 ? submodules : void 0;
|
|
23861
|
+
}
|
|
23862
|
+
function normalizeInlineMeshGitStatus(status, node, options) {
|
|
23647
23863
|
const isGitRepo = readBooleanValue(status.isGitRepo);
|
|
23648
23864
|
if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
|
|
23649
23865
|
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((value) => typeof value === "string") : [];
|
|
23650
23866
|
const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
|
|
23651
23867
|
const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
|
|
23868
|
+
const submodules = readGitSubmodules(status.submodules);
|
|
23652
23869
|
return {
|
|
23653
23870
|
workspace: readStringValue(status.workspace, node?.workspace) || "",
|
|
23654
23871
|
repoRoot: readStringValue(status.repoRoot, node?.repoRoot, node?.workspace) || null,
|
|
@@ -23667,29 +23884,285 @@ function buildCachedInlineMeshGitStatus(node) {
|
|
|
23667
23884
|
hasConflicts,
|
|
23668
23885
|
conflictFiles,
|
|
23669
23886
|
stashCount: readNumberValue(status.stashCount) ?? 0,
|
|
23670
|
-
lastCheckedAt: Date.now()
|
|
23887
|
+
lastCheckedAt: options?.lastCheckedAt ?? readNumberValue(status.lastCheckedAt) ?? Date.now(),
|
|
23888
|
+
...submodules ? { submodules } : {}
|
|
23889
|
+
};
|
|
23890
|
+
}
|
|
23891
|
+
function buildInlineMeshTransitGitStatus(node) {
|
|
23892
|
+
const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
|
|
23893
|
+
const gitResult = readObjectRecord(rawGit.result);
|
|
23894
|
+
const directStatus = readObjectRecord(rawGit.status);
|
|
23895
|
+
const nestedStatus = readObjectRecord(gitResult.status);
|
|
23896
|
+
const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
|
|
23897
|
+
const probeGit = readObjectRecord(rawProbe.git);
|
|
23898
|
+
const probeGitResult = readObjectRecord(probeGit.result);
|
|
23899
|
+
const probeDirectStatus = readObjectRecord(probeGit.status);
|
|
23900
|
+
const probeNestedStatus = readObjectRecord(probeGitResult.status);
|
|
23901
|
+
const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
|
|
23902
|
+
return normalizeInlineMeshGitStatus(status, node, { lastCheckedAt: Date.now() });
|
|
23903
|
+
}
|
|
23904
|
+
function buildCachedInlineMeshGitStatus(node) {
|
|
23905
|
+
const liveGit = buildInlineMeshTransitGitStatus(node);
|
|
23906
|
+
if (liveGit) return liveGit;
|
|
23907
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
23908
|
+
const cachedGit = readObjectRecord(cachedStatus.git);
|
|
23909
|
+
if (!Object.keys(cachedGit).length) return void 0;
|
|
23910
|
+
return normalizeInlineMeshGitStatus(cachedGit, node);
|
|
23911
|
+
}
|
|
23912
|
+
function shouldDiscardCachedInlineMeshStatus(node) {
|
|
23913
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
23914
|
+
if (!Object.keys(cachedStatus).length) return false;
|
|
23915
|
+
const cachedGit = readObjectRecord(cachedStatus.git);
|
|
23916
|
+
const workspaceError = readStringValue(cachedStatus.error, node?.error);
|
|
23917
|
+
if (workspaceError && /workspace must be an existing directory/i.test(workspaceError)) return true;
|
|
23918
|
+
const isGitRepo = readBooleanValue(cachedGit.isGitRepo);
|
|
23919
|
+
const branch = readStringValue(cachedGit.branch);
|
|
23920
|
+
const headCommit = readStringValue(cachedGit.headCommit);
|
|
23921
|
+
return isGitRepo === false && !branch && !headCommit;
|
|
23922
|
+
}
|
|
23923
|
+
function stripInlineMeshTransientNodeState(node) {
|
|
23924
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return node;
|
|
23925
|
+
const {
|
|
23926
|
+
cachedStatus,
|
|
23927
|
+
lastGit: _lastGit,
|
|
23928
|
+
last_git: _lastGitLegacy,
|
|
23929
|
+
lastProbe: _lastProbe,
|
|
23930
|
+
last_probe: _lastProbeLegacy,
|
|
23931
|
+
error: _error,
|
|
23932
|
+
health: _health,
|
|
23933
|
+
machineStatus: _machineStatus,
|
|
23934
|
+
lastSeenAt: _lastSeenAt,
|
|
23935
|
+
last_seen_at: _lastSeenAtLegacy,
|
|
23936
|
+
updatedAt: _updatedAt,
|
|
23937
|
+
updated_at: _updatedAtLegacy,
|
|
23938
|
+
activeSession: _activeSession,
|
|
23939
|
+
active_session: _activeSessionLegacy,
|
|
23940
|
+
activeSessionId: _activeSessionId,
|
|
23941
|
+
active_session_id: _activeSessionIdLegacy,
|
|
23942
|
+
sessionId: _sessionId,
|
|
23943
|
+
session_id: _sessionIdLegacy,
|
|
23944
|
+
providerType: _providerType,
|
|
23945
|
+
provider_type: _providerTypeLegacy,
|
|
23946
|
+
providers: _providers,
|
|
23947
|
+
...rest
|
|
23948
|
+
} = node;
|
|
23949
|
+
if (cachedStatus && !shouldDiscardCachedInlineMeshStatus(node)) {
|
|
23950
|
+
return { ...rest, cachedStatus };
|
|
23951
|
+
}
|
|
23952
|
+
return rest;
|
|
23953
|
+
}
|
|
23954
|
+
function hasInlineMeshTransientNodeState(node) {
|
|
23955
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return false;
|
|
23956
|
+
return "cachedStatus" in node || "lastGit" in node || "last_git" in node || "lastProbe" in node || "last_probe" in node || "error" in node || "health" in node || "machineStatus" in node || "lastSeenAt" in node || "last_seen_at" in node || "updatedAt" in node || "updated_at" in node || "activeSession" in node || "active_session" in node || "activeSessionId" in node || "active_session_id" in node || "sessionId" in node || "session_id" in node || "providerType" in node || "provider_type" in node || "providers" in node;
|
|
23957
|
+
}
|
|
23958
|
+
function readInlineMeshNodeId(node) {
|
|
23959
|
+
return readStringValue(node?.id, node?.nodeId) || "";
|
|
23960
|
+
}
|
|
23961
|
+
function sanitizeInlineMesh(inlineMesh) {
|
|
23962
|
+
if (!inlineMesh || typeof inlineMesh !== "object" || Array.isArray(inlineMesh)) return inlineMesh;
|
|
23963
|
+
if (!Array.isArray(inlineMesh.nodes)) return inlineMesh;
|
|
23964
|
+
let changed = false;
|
|
23965
|
+
const nodes = inlineMesh.nodes.map((node) => {
|
|
23966
|
+
if (!hasInlineMeshTransientNodeState(node)) return node;
|
|
23967
|
+
changed = true;
|
|
23968
|
+
return stripInlineMeshTransientNodeState(node);
|
|
23969
|
+
});
|
|
23970
|
+
if (!changed) return inlineMesh;
|
|
23971
|
+
return {
|
|
23972
|
+
...inlineMesh,
|
|
23973
|
+
nodes
|
|
23974
|
+
};
|
|
23975
|
+
}
|
|
23976
|
+
function reconcileInlineMeshCache(cached, incoming) {
|
|
23977
|
+
if (!cached || typeof cached !== "object" || Array.isArray(cached)) return incoming;
|
|
23978
|
+
if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return cached;
|
|
23979
|
+
const cachedNodes = Array.isArray(cached.nodes) ? cached.nodes : [];
|
|
23980
|
+
const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
|
|
23981
|
+
if (!cachedNodes.length || !incomingNodes.length) return { ...cached, ...incoming };
|
|
23982
|
+
const incomingById = /* @__PURE__ */ new Map();
|
|
23983
|
+
for (const node of incomingNodes) {
|
|
23984
|
+
const nodeId = readInlineMeshNodeId(node);
|
|
23985
|
+
if (nodeId) incomingById.set(nodeId, node);
|
|
23986
|
+
}
|
|
23987
|
+
const nodes = cachedNodes.map((cachedNode) => {
|
|
23988
|
+
const nodeId = readInlineMeshNodeId(cachedNode);
|
|
23989
|
+
const incomingNode = nodeId ? incomingById.get(nodeId) : void 0;
|
|
23990
|
+
if (!incomingNode) return cachedNode;
|
|
23991
|
+
if (hasInlineMeshTransientNodeState(incomingNode)) {
|
|
23992
|
+
return { ...cachedNode, ...incomingNode };
|
|
23993
|
+
}
|
|
23994
|
+
return { ...stripInlineMeshTransientNodeState(cachedNode), ...incomingNode };
|
|
23995
|
+
});
|
|
23996
|
+
return {
|
|
23997
|
+
...cached,
|
|
23998
|
+
...incoming,
|
|
23999
|
+
nodes
|
|
24000
|
+
};
|
|
24001
|
+
}
|
|
24002
|
+
function hasGitWorktreeChanges(git) {
|
|
24003
|
+
if (!git) return false;
|
|
24004
|
+
return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
|
|
24005
|
+
}
|
|
24006
|
+
function getGitSubmoduleDriftState(git) {
|
|
24007
|
+
const submodules = Array.isArray(git?.submodules) ? git.submodules : [];
|
|
24008
|
+
let dirty = false;
|
|
24009
|
+
let outOfSync = false;
|
|
24010
|
+
for (const entry of submodules) {
|
|
24011
|
+
const submodule = readObjectRecord(entry);
|
|
24012
|
+
if (readBooleanValue(submodule.dirty) === true) dirty = true;
|
|
24013
|
+
if (readBooleanValue(submodule.outOfSync) === true || !!readStringValue(submodule.error)) outOfSync = true;
|
|
24014
|
+
}
|
|
24015
|
+
return { dirty, outOfSync };
|
|
24016
|
+
}
|
|
24017
|
+
function deriveMeshNodeHealthFromGit(git) {
|
|
24018
|
+
if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
|
|
24019
|
+
const branch = readStringValue(git.branch);
|
|
24020
|
+
if (!branch) return "degraded";
|
|
24021
|
+
const submoduleDrift = getGitSubmoduleDriftState(git);
|
|
24022
|
+
if (submoduleDrift.outOfSync) return "degraded";
|
|
24023
|
+
if (submoduleDrift.dirty || hasGitWorktreeChanges(git)) return "dirty";
|
|
24024
|
+
return "online";
|
|
24025
|
+
}
|
|
24026
|
+
function readCachedInlineMeshActiveSessions(node) {
|
|
24027
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24028
|
+
const activeSession = readObjectRecord(cachedStatus.activeSession);
|
|
24029
|
+
const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
|
|
24030
|
+
const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
|
|
24031
|
+
return sessionId ? [sessionId] : [];
|
|
24032
|
+
}
|
|
24033
|
+
function readCachedInlineMeshActiveSessionDetails(node) {
|
|
24034
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24035
|
+
const activeSession = readObjectRecord(cachedStatus.activeSession);
|
|
24036
|
+
const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
|
|
24037
|
+
const sessionId = readStringValue(
|
|
24038
|
+
fallbackSession.id,
|
|
24039
|
+
fallbackSession.sessionId,
|
|
24040
|
+
fallbackSession.session_id,
|
|
24041
|
+
node?.activeSessionId,
|
|
24042
|
+
node?.active_session_id,
|
|
24043
|
+
node?.sessionId,
|
|
24044
|
+
node?.session_id
|
|
24045
|
+
);
|
|
24046
|
+
if (!sessionId) return [];
|
|
24047
|
+
return [{
|
|
24048
|
+
sessionId,
|
|
24049
|
+
providerType: readStringValue(
|
|
24050
|
+
fallbackSession.providerType,
|
|
24051
|
+
fallbackSession.provider_type,
|
|
24052
|
+
fallbackSession.cliType,
|
|
24053
|
+
fallbackSession.cli_type,
|
|
24054
|
+
fallbackSession.provider,
|
|
24055
|
+
node?.providerType,
|
|
24056
|
+
node?.provider_type
|
|
24057
|
+
),
|
|
24058
|
+
state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
|
|
24059
|
+
lifecycle: readStringValue(fallbackSession.lifecycle),
|
|
24060
|
+
title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
|
|
24061
|
+
workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
|
|
24062
|
+
lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
|
|
24063
|
+
recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
|
|
24064
|
+
isCached: true
|
|
24065
|
+
}];
|
|
24066
|
+
}
|
|
24067
|
+
function readLiveMeshSessionState(record) {
|
|
24068
|
+
return readStringValue(
|
|
24069
|
+
record?.meta?.sessionStatus,
|
|
24070
|
+
record?.meta?.status,
|
|
24071
|
+
record?.meta?.providerStatus,
|
|
24072
|
+
record?.status,
|
|
24073
|
+
record?.state,
|
|
24074
|
+
record?.lifecycle
|
|
24075
|
+
);
|
|
24076
|
+
}
|
|
24077
|
+
function toIsoTimestamp(value) {
|
|
24078
|
+
if (typeof value === "number" && Number.isFinite(value)) return new Date(value).toISOString();
|
|
24079
|
+
const stringValue = readStringValue(value);
|
|
24080
|
+
return stringValue || null;
|
|
24081
|
+
}
|
|
24082
|
+
function summarizeMeshSessionRecord(record) {
|
|
24083
|
+
return {
|
|
24084
|
+
sessionId: readStringValue(record?.sessionId) || "unknown",
|
|
24085
|
+
providerType: readStringValue(record?.providerType),
|
|
24086
|
+
state: readLiveMeshSessionState(record),
|
|
24087
|
+
lifecycle: readStringValue(record?.lifecycle),
|
|
24088
|
+
surfaceKind: getSessionHostSurfaceKind(record),
|
|
24089
|
+
recoveryState: readStringValue(record?.meta?.runtimeRecoveryState) ?? null,
|
|
24090
|
+
workspace: readStringValue(record?.workspace) ?? null,
|
|
24091
|
+
title: readStringValue(record?.displayName, record?.workspaceLabel) ?? null,
|
|
24092
|
+
lastActivityAt: toIsoTimestamp(record?.updatedAt ?? record?.lastActivityAt ?? record?.last_activity_at),
|
|
24093
|
+
isCached: false
|
|
23671
24094
|
};
|
|
23672
24095
|
}
|
|
23673
|
-
function
|
|
24096
|
+
function liveSessionRecordMatchesMeshNode(record, meshId, nodeId) {
|
|
24097
|
+
const recordNodeId = readStringValue(record?.meta?.meshNodeId);
|
|
24098
|
+
if (!recordNodeId || recordNodeId !== nodeId) return false;
|
|
24099
|
+
const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
|
|
24100
|
+
return !recordMeshId || recordMeshId === meshId;
|
|
24101
|
+
}
|
|
24102
|
+
function liveSessionRecordMatchesMeshWorkspace(record, meshId, workspace) {
|
|
24103
|
+
const recordWorkspace = readStringValue(record?.workspace);
|
|
24104
|
+
if (!recordWorkspace || !workspace || recordWorkspace !== workspace) return false;
|
|
24105
|
+
const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
|
|
24106
|
+
if (recordMeshId) return recordMeshId === meshId;
|
|
24107
|
+
return record?.meta?.launchedByCoordinator === true || !!readStringValue(record?.meta?.meshNodeId);
|
|
24108
|
+
}
|
|
24109
|
+
function readLiveMeshNodeWorkspace(args) {
|
|
24110
|
+
const directNodeWorkspace = args.liveSessionRecords.find((record) => liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId) && readStringValue(record?.workspace));
|
|
24111
|
+
if (directNodeWorkspace) {
|
|
24112
|
+
return readStringValue(directNodeWorkspace.workspace) || "";
|
|
24113
|
+
}
|
|
24114
|
+
if (args.allowCoordinatorSession) {
|
|
24115
|
+
const coordinatorWorkspace = args.liveSessionRecords.find((record) => readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId && readStringValue(record?.workspace));
|
|
24116
|
+
if (coordinatorWorkspace) {
|
|
24117
|
+
return readStringValue(coordinatorWorkspace.workspace) || "";
|
|
24118
|
+
}
|
|
24119
|
+
}
|
|
24120
|
+
return "";
|
|
24121
|
+
}
|
|
24122
|
+
function collectLiveMeshSessionRecords(args) {
|
|
24123
|
+
const matches = args.liveSessionRecords.filter((record) => {
|
|
24124
|
+
const nodeWorkspace = readStringValue(args.node?.workspace);
|
|
24125
|
+
if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)) return true;
|
|
24126
|
+
return !!nodeWorkspace && liveSessionRecordMatchesMeshWorkspace(record, args.meshId, nodeWorkspace);
|
|
24127
|
+
});
|
|
24128
|
+
if (args.allowCoordinatorSession) {
|
|
24129
|
+
for (const record of args.liveSessionRecords) {
|
|
24130
|
+
if (readStringValue(record?.meta?.meshCoordinatorFor) !== args.meshId) continue;
|
|
24131
|
+
const sessionId = readStringValue(record?.sessionId);
|
|
24132
|
+
if (sessionId && matches.some((entry) => readStringValue(entry?.sessionId) === sessionId)) continue;
|
|
24133
|
+
matches.push(record);
|
|
24134
|
+
}
|
|
24135
|
+
}
|
|
24136
|
+
return matches;
|
|
24137
|
+
}
|
|
24138
|
+
function applyCachedInlineMeshNodeStatus(status, node, options) {
|
|
23674
24139
|
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
23675
|
-
const
|
|
23676
|
-
const
|
|
23677
|
-
const
|
|
24140
|
+
const liveGit = buildInlineMeshTransitGitStatus(node);
|
|
24141
|
+
const git = options?.skipGit ? void 0 : liveGit ?? buildCachedInlineMeshGitStatus(node);
|
|
24142
|
+
const error = options?.skipError ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.error, node?.error);
|
|
24143
|
+
const health = options?.skipHealth ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.health, node?.health);
|
|
23678
24144
|
const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
|
|
23679
|
-
|
|
23680
|
-
|
|
24145
|
+
const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
|
|
24146
|
+
const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
|
|
24147
|
+
const activeSessions = readCachedInlineMeshActiveSessions(node);
|
|
24148
|
+
const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
|
|
24149
|
+
if (!git && !error && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
|
|
23681
24150
|
if (git) status.git = git;
|
|
23682
24151
|
if (error) status.error = error;
|
|
24152
|
+
if (machineStatus) status.machineStatus = machineStatus;
|
|
24153
|
+
if (lastSeenAt) status.lastSeenAt = lastSeenAt;
|
|
24154
|
+
if (updatedAt) status.updatedAt = updatedAt;
|
|
24155
|
+
if (activeSessions.length > 0) status.activeSessions = activeSessions;
|
|
24156
|
+
if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
|
|
23683
24157
|
if (health) {
|
|
23684
24158
|
status.health = health;
|
|
23685
24159
|
return true;
|
|
23686
24160
|
}
|
|
23687
24161
|
if (git) {
|
|
23688
|
-
|
|
23689
|
-
status.health = git.isGitRepo === false ? "degraded" : dirty ? "dirty" : "online";
|
|
24162
|
+
status.health = deriveMeshNodeHealthFromGit(git);
|
|
23690
24163
|
return true;
|
|
23691
24164
|
}
|
|
23692
|
-
return
|
|
24165
|
+
return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
|
|
23693
24166
|
}
|
|
23694
24167
|
async function resolveProviderTypeFromPriority(args) {
|
|
23695
24168
|
if (!args.providerPriority.length) {
|
|
@@ -24087,25 +24560,40 @@ var DaemonCommandRouter = class {
|
|
|
24087
24560
|
}
|
|
24088
24561
|
getCachedInlineMesh(meshId, inlineMesh) {
|
|
24089
24562
|
if (inlineMesh && typeof inlineMesh === "object") {
|
|
24090
|
-
this.
|
|
24091
|
-
return inlineMesh;
|
|
24563
|
+
return this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24092
24564
|
}
|
|
24093
24565
|
return this.inlineMeshCache.get(meshId);
|
|
24094
24566
|
}
|
|
24567
|
+
warmInlineMeshCache(meshId, inlineMesh) {
|
|
24568
|
+
if (!inlineMesh || typeof inlineMesh !== "object") return void 0;
|
|
24569
|
+
const sanitizedInlineMesh = sanitizeInlineMesh(inlineMesh);
|
|
24570
|
+
const cached = this.inlineMeshCache.get(meshId);
|
|
24571
|
+
if (cached) {
|
|
24572
|
+
const merged = reconcileInlineMeshCache(cached, sanitizedInlineMesh);
|
|
24573
|
+
this.inlineMeshCache.set(meshId, merged);
|
|
24574
|
+
return merged;
|
|
24575
|
+
}
|
|
24576
|
+
this.inlineMeshCache.set(meshId, sanitizedInlineMesh);
|
|
24577
|
+
return sanitizedInlineMesh;
|
|
24578
|
+
}
|
|
24095
24579
|
async getMeshForCommand(meshId, inlineMesh, options) {
|
|
24096
24580
|
const preferInline = options?.preferInline === true;
|
|
24097
24581
|
if (preferInline) {
|
|
24098
|
-
const cached2 = this.getCachedInlineMesh(meshId
|
|
24099
|
-
if (cached2) return { mesh: cached2, inline: true };
|
|
24582
|
+
const cached2 = this.getCachedInlineMesh(meshId);
|
|
24583
|
+
if (cached2) return { mesh: cached2, inline: true, source: "inline_cache" };
|
|
24584
|
+
const warmedInline2 = this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24585
|
+
if (warmedInline2) return { mesh: warmedInline2, inline: true, source: "inline_bootstrap" };
|
|
24100
24586
|
}
|
|
24101
24587
|
try {
|
|
24102
24588
|
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
24103
24589
|
const mesh = getMesh3(meshId);
|
|
24104
|
-
if (mesh) return { mesh, inline: false };
|
|
24590
|
+
if (mesh) return { mesh, inline: false, source: "local_config" };
|
|
24105
24591
|
} catch {
|
|
24106
24592
|
}
|
|
24107
|
-
const cached = this.getCachedInlineMesh(meshId
|
|
24108
|
-
|
|
24593
|
+
const cached = this.getCachedInlineMesh(meshId);
|
|
24594
|
+
if (cached) return { mesh: cached, inline: true, source: "inline_cache" };
|
|
24595
|
+
const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24596
|
+
return warmedInline ? { mesh: warmedInline, inline: true, source: "inline_bootstrap" } : null;
|
|
24109
24597
|
}
|
|
24110
24598
|
updateInlineMeshNode(meshId, mesh, node) {
|
|
24111
24599
|
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
@@ -24334,6 +24822,7 @@ var DaemonCommandRouter = class {
|
|
|
24334
24822
|
const deletedSessionIds = [];
|
|
24335
24823
|
const skippedSessionIds = [];
|
|
24336
24824
|
const skippedLiveSessionIds = [];
|
|
24825
|
+
const skippedCoordinatorSessionIds = [];
|
|
24337
24826
|
const deleteUnsupportedSessionIds = [];
|
|
24338
24827
|
const recordsRemainSessionIds = [];
|
|
24339
24828
|
const errors = [];
|
|
@@ -24366,6 +24855,12 @@ var DaemonCommandRouter = class {
|
|
|
24366
24855
|
const completed = this.isCompletedHostedSession(record);
|
|
24367
24856
|
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
24368
24857
|
const liveRuntime = surfaceKind === "live_runtime";
|
|
24858
|
+
const coordinatorSession = readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId;
|
|
24859
|
+
if (!hasExplicitSessionIds && coordinatorSession) {
|
|
24860
|
+
skippedSessionIds.push(sessionId);
|
|
24861
|
+
skippedCoordinatorSessionIds.push(sessionId);
|
|
24862
|
+
continue;
|
|
24863
|
+
}
|
|
24369
24864
|
if (!hasExplicitSessionIds && liveRuntime) {
|
|
24370
24865
|
skippedSessionIds.push(sessionId);
|
|
24371
24866
|
skippedLiveSessionIds.push(sessionId);
|
|
@@ -24431,6 +24926,7 @@ var DaemonCommandRouter = class {
|
|
|
24431
24926
|
deletedSessionIds,
|
|
24432
24927
|
skippedSessionIds,
|
|
24433
24928
|
skippedLiveSessionIds,
|
|
24929
|
+
skippedCoordinatorSessionIds,
|
|
24434
24930
|
...deleteUnsupported ? {
|
|
24435
24931
|
deleteUnsupported: true,
|
|
24436
24932
|
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
@@ -24563,7 +25059,8 @@ var DaemonCommandRouter = class {
|
|
|
24563
25059
|
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
24564
25060
|
}
|
|
24565
25061
|
case "get_pending_mesh_events": {
|
|
24566
|
-
const
|
|
25062
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25063
|
+
const events = drainPendingMeshCoordinatorEvents(meshId || void 0);
|
|
24567
25064
|
return { success: true, events };
|
|
24568
25065
|
}
|
|
24569
25066
|
case "launch_cli":
|
|
@@ -25092,14 +25589,8 @@ var DaemonCommandRouter = class {
|
|
|
25092
25589
|
case "get_mesh": {
|
|
25093
25590
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25094
25591
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
25095
|
-
|
|
25096
|
-
|
|
25097
|
-
const mesh = getMesh3(meshId);
|
|
25098
|
-
if (mesh) return { success: true, mesh };
|
|
25099
|
-
} catch {
|
|
25100
|
-
}
|
|
25101
|
-
const cached = this.inlineMeshCache.get(meshId);
|
|
25102
|
-
if (cached) return { success: true, mesh: cached };
|
|
25592
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
25593
|
+
if (meshRecord?.mesh) return { success: true, mesh: meshRecord.mesh };
|
|
25103
25594
|
return { success: false, error: "Mesh not found" };
|
|
25104
25595
|
}
|
|
25105
25596
|
case "create_mesh": {
|
|
@@ -25621,7 +26112,14 @@ var DaemonCommandRouter = class {
|
|
|
25621
26112
|
cliType
|
|
25622
26113
|
};
|
|
25623
26114
|
}
|
|
25624
|
-
const
|
|
26115
|
+
const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
|
|
26116
|
+
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
26117
|
+
const workspace = readLiveMeshNodeWorkspace({
|
|
26118
|
+
meshId,
|
|
26119
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || ""),
|
|
26120
|
+
liveSessionRecords: liveMeshSessions,
|
|
26121
|
+
allowCoordinatorSession: true
|
|
26122
|
+
}) || (typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "");
|
|
25625
26123
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
25626
26124
|
if (!cliType) {
|
|
25627
26125
|
const resolved = await resolveProviderTypeFromPriority({
|
|
@@ -25783,7 +26281,7 @@ ${block}`);
|
|
|
25783
26281
|
workspace
|
|
25784
26282
|
};
|
|
25785
26283
|
}
|
|
25786
|
-
const { existsSync:
|
|
26284
|
+
const { existsSync: existsSync26, readFileSync: readFileSync18, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
|
|
25787
26285
|
const { dirname: dirname9 } = await import("path");
|
|
25788
26286
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
25789
26287
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -25826,14 +26324,14 @@ ${block}`);
|
|
|
25826
26324
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
25827
26325
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
25828
26326
|
}
|
|
25829
|
-
const hadExistingMcpConfig =
|
|
26327
|
+
const hadExistingMcpConfig = existsSync26(mcpConfigPath);
|
|
25830
26328
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
25831
26329
|
if (hermesBaseConfig) {
|
|
25832
26330
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
|
|
25833
26331
|
}
|
|
25834
26332
|
if (hadExistingMcpConfig) {
|
|
25835
26333
|
try {
|
|
25836
|
-
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
26334
|
+
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync18(mcpConfigPath, "utf-8"), configFormat);
|
|
25837
26335
|
const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
|
|
25838
26336
|
existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
|
|
25839
26337
|
copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
|
|
@@ -25929,92 +26427,157 @@ ${block}`);
|
|
|
25929
26427
|
const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
25930
26428
|
const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
|
|
25931
26429
|
const ledgerSummary = getLedgerSummary2(meshId);
|
|
26430
|
+
const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
|
|
26431
|
+
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
26432
|
+
const localMachineId = loadConfig().machineId || "";
|
|
26433
|
+
const selectedCoordinatorNodeId = readStringValue(
|
|
26434
|
+
mesh.coordinator?.preferredNodeId,
|
|
26435
|
+
mesh.nodes?.[0]?.id,
|
|
26436
|
+
mesh.nodes?.[0]?.nodeId
|
|
26437
|
+
);
|
|
26438
|
+
const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes) ? selectedCoordinatorNodeId : void 0;
|
|
26439
|
+
const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25932
26440
|
const nodeStatuses = [];
|
|
25933
|
-
for (const node of mesh.nodes || []) {
|
|
26441
|
+
for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
|
|
26442
|
+
const nodeId = String(node.id || node.nodeId || "");
|
|
26443
|
+
const daemonId = readStringValue(node.daemonId);
|
|
26444
|
+
const providerPriority = readProviderPriorityFromPolicy(node.policy);
|
|
26445
|
+
const isSelfNode = Boolean(
|
|
26446
|
+
nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
|
|
26447
|
+
) || Boolean(
|
|
26448
|
+
daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
|
|
26449
|
+
) || Boolean(meshRecord?.inline && nodeIndex === 0);
|
|
25934
26450
|
const status = {
|
|
25935
|
-
nodeId
|
|
26451
|
+
nodeId,
|
|
25936
26452
|
machineLabel: node.machineLabel || node.id || node.nodeId,
|
|
25937
26453
|
workspace: node.workspace,
|
|
25938
26454
|
repoRoot: node.repoRoot,
|
|
25939
26455
|
isLocalWorktree: node.isLocalWorktree,
|
|
25940
26456
|
worktreeBranch: node.worktreeBranch,
|
|
25941
|
-
daemonId
|
|
26457
|
+
daemonId,
|
|
25942
26458
|
machineId: node.machineId,
|
|
26459
|
+
machineStatus: node.machineStatus,
|
|
25943
26460
|
health: "unknown",
|
|
25944
26461
|
providers: node.providers || [],
|
|
25945
|
-
|
|
26462
|
+
providerPriority,
|
|
26463
|
+
activeSessions: [],
|
|
26464
|
+
activeSessionDetails: [],
|
|
26465
|
+
launchReady: false
|
|
25946
26466
|
};
|
|
25947
|
-
if (
|
|
25948
|
-
|
|
25949
|
-
|
|
25950
|
-
|
|
26467
|
+
if (isSelfNode) {
|
|
26468
|
+
status.connection = {
|
|
26469
|
+
perspective: "selected_coordinator",
|
|
26470
|
+
source: "mesh_peer_status",
|
|
26471
|
+
state: "self",
|
|
26472
|
+
transport: "local",
|
|
26473
|
+
reported: true,
|
|
26474
|
+
reason: "Selected coordinator daemon",
|
|
26475
|
+
lastStateChangeAt: refreshedAt
|
|
26476
|
+
};
|
|
26477
|
+
} else if (daemonId) {
|
|
26478
|
+
const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
|
|
26479
|
+
status.connection = connection ?? {
|
|
26480
|
+
perspective: "selected_coordinator",
|
|
26481
|
+
source: "not_reported",
|
|
26482
|
+
state: "unknown",
|
|
26483
|
+
transport: "unknown",
|
|
26484
|
+
reported: false,
|
|
26485
|
+
reason: "No live mesh peer telemetry reported by the selected coordinator yet."
|
|
26486
|
+
};
|
|
26487
|
+
} else {
|
|
26488
|
+
status.connection = {
|
|
26489
|
+
perspective: "selected_coordinator",
|
|
26490
|
+
source: "not_reported",
|
|
26491
|
+
state: "unknown",
|
|
26492
|
+
transport: "unknown",
|
|
26493
|
+
reported: false,
|
|
26494
|
+
reason: "Node has no daemon id, so mesh transport cannot be reported from the selected coordinator."
|
|
26495
|
+
};
|
|
26496
|
+
}
|
|
26497
|
+
const matchedLiveSessionRecords = collectLiveMeshSessionRecords({
|
|
26498
|
+
meshId,
|
|
26499
|
+
node,
|
|
26500
|
+
nodeId,
|
|
26501
|
+
liveSessionRecords: liveMeshSessions,
|
|
26502
|
+
allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
|
|
26503
|
+
});
|
|
26504
|
+
const workspace = readLiveMeshNodeWorkspace({
|
|
26505
|
+
meshId,
|
|
26506
|
+
nodeId,
|
|
26507
|
+
liveSessionRecords: matchedLiveSessionRecords,
|
|
26508
|
+
allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
|
|
26509
|
+
}) || (typeof node.workspace === "string" ? node.workspace : "");
|
|
26510
|
+
status.workspace = workspace || node.workspace;
|
|
26511
|
+
if (matchedLiveSessionRecords.length > 0) {
|
|
26512
|
+
const sessionIds = matchedLiveSessionRecords.map((record) => typeof record?.sessionId === "string" ? record.sessionId : "").filter(Boolean);
|
|
26513
|
+
const providerTypes = matchedLiveSessionRecords.map((record) => readStringValue(record?.providerType)).filter(Boolean);
|
|
26514
|
+
status.activeSessions = sessionIds;
|
|
26515
|
+
status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
|
|
26516
|
+
if (providerTypes.length > 0) {
|
|
26517
|
+
status.providers = Array.from(/* @__PURE__ */ new Set([...Array.isArray(status.providers) ? status.providers : [], ...providerTypes]));
|
|
25951
26518
|
}
|
|
25952
|
-
|
|
25953
|
-
|
|
25954
|
-
|
|
25955
|
-
|
|
25956
|
-
|
|
25957
|
-
|
|
25958
|
-
|
|
25959
|
-
|
|
25960
|
-
|
|
25961
|
-
|
|
25962
|
-
|
|
25963
|
-
|
|
25964
|
-
|
|
25965
|
-
|
|
25966
|
-
|
|
25967
|
-
|
|
25968
|
-
|
|
25969
|
-
const stashCount = await runGit2(["stash", "list"]).catch(() => "");
|
|
25970
|
-
let ahead = 0, behind = 0;
|
|
25971
|
-
if (aheadBehind) {
|
|
25972
|
-
const parts = aheadBehind.split(/\s+/);
|
|
25973
|
-
if (parts.length >= 2) {
|
|
25974
|
-
behind = parseInt(parts[0], 10) || 0;
|
|
25975
|
-
ahead = parseInt(parts[1], 10) || 0;
|
|
26519
|
+
}
|
|
26520
|
+
if (workspace) {
|
|
26521
|
+
if (!fs10.existsSync(workspace)) {
|
|
26522
|
+
let remoteProbeApplied = false;
|
|
26523
|
+
if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand) {
|
|
26524
|
+
try {
|
|
26525
|
+
const remoteResult = await Promise.race([
|
|
26526
|
+
this.deps.dispatchMeshCommand(daemonId, "git_status", { workspace }),
|
|
26527
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 8e3))
|
|
26528
|
+
]);
|
|
26529
|
+
const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
|
|
26530
|
+
if (remoteGit && typeof remoteGit === "object" && typeof remoteGit.isGitRepo === "boolean") {
|
|
26531
|
+
status.git = remoteGit;
|
|
26532
|
+
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
26533
|
+
remoteProbeApplied = true;
|
|
26534
|
+
}
|
|
26535
|
+
} catch {
|
|
25976
26536
|
}
|
|
25977
26537
|
}
|
|
25978
|
-
|
|
25979
|
-
|
|
25980
|
-
|
|
25981
|
-
|
|
25982
|
-
|
|
25983
|
-
|
|
25984
|
-
|
|
25985
|
-
|
|
25986
|
-
if (
|
|
25987
|
-
|
|
26538
|
+
if (!remoteProbeApplied) {
|
|
26539
|
+
const connectionState = readStringValue(status.connection?.state);
|
|
26540
|
+
const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
|
|
26541
|
+
const pendingPeerGitProbe = !inlineTransitGit && !isSelfNode && !!daemonId && (readStringValue(status.machineStatus) === "online" || readStringValue(status.health) === "online" || connectionState === "connecting" || connectionState === "connected" || connectionState === "unknown");
|
|
26542
|
+
if (pendingPeerGitProbe) {
|
|
26543
|
+
status.gitProbePending = true;
|
|
26544
|
+
status.health = "unknown";
|
|
26545
|
+
}
|
|
26546
|
+
if (applyCachedInlineMeshNodeStatus(
|
|
26547
|
+
status,
|
|
26548
|
+
node,
|
|
26549
|
+
pendingPeerGitProbe ? { skipGit: true, skipError: true, skipHealth: true } : void 0
|
|
26550
|
+
)) {
|
|
26551
|
+
status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
|
|
26552
|
+
nodeStatuses.push(status);
|
|
26553
|
+
continue;
|
|
26554
|
+
}
|
|
26555
|
+
if (meshRecord?.source === "inline_cache" && !isSelfNode) {
|
|
26556
|
+
status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
|
|
26557
|
+
nodeStatuses.push(status);
|
|
26558
|
+
continue;
|
|
26559
|
+
}
|
|
25988
26560
|
}
|
|
25989
|
-
|
|
25990
|
-
|
|
25991
|
-
|
|
25992
|
-
|
|
25993
|
-
|
|
25994
|
-
|
|
25995
|
-
|
|
25996
|
-
|
|
25997
|
-
|
|
25998
|
-
|
|
25999
|
-
|
|
26000
|
-
|
|
26001
|
-
|
|
26002
|
-
|
|
26003
|
-
renamed,
|
|
26004
|
-
hasConflicts: false,
|
|
26005
|
-
conflictFiles: [],
|
|
26006
|
-
stashCount: stashCount ? stashCount.split("\n").filter(Boolean).length : 0,
|
|
26007
|
-
lastCheckedAt: Date.now()
|
|
26008
|
-
};
|
|
26009
|
-
status.health = branch ? dirty ? "dirty" : "online" : "degraded";
|
|
26010
|
-
} catch {
|
|
26011
|
-
if (!applyCachedInlineMeshNodeStatus(status, node)) {
|
|
26012
|
-
status.health = "degraded";
|
|
26561
|
+
} else {
|
|
26562
|
+
try {
|
|
26563
|
+
const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
26564
|
+
status.git = gitStatus;
|
|
26565
|
+
if (gitStatus.isGitRepo) {
|
|
26566
|
+
status.health = deriveMeshNodeHealthFromGit(gitStatus);
|
|
26567
|
+
} else {
|
|
26568
|
+
status.health = "degraded";
|
|
26569
|
+
if (gitStatus.error && !status.error) status.error = gitStatus.error;
|
|
26570
|
+
}
|
|
26571
|
+
} catch {
|
|
26572
|
+
if (!applyCachedInlineMeshNodeStatus(status, node)) {
|
|
26573
|
+
status.health = "degraded";
|
|
26574
|
+
}
|
|
26013
26575
|
}
|
|
26014
26576
|
}
|
|
26015
26577
|
} else {
|
|
26016
26578
|
applyCachedInlineMeshNodeStatus(status, node);
|
|
26017
26579
|
}
|
|
26580
|
+
status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || isSelfNode);
|
|
26018
26581
|
nodeStatuses.push(status);
|
|
26019
26582
|
}
|
|
26020
26583
|
return {
|
|
@@ -26023,6 +26586,12 @@ ${block}`);
|
|
|
26023
26586
|
meshName: mesh.name,
|
|
26024
26587
|
repoIdentity: mesh.repoIdentity,
|
|
26025
26588
|
defaultBranch: mesh.defaultBranch,
|
|
26589
|
+
refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26590
|
+
sourceOfTruth: {
|
|
26591
|
+
membership: meshRecord?.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord?.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
26592
|
+
coordinatorOwnsLiveTruth: meshRecord?.source !== "inline_bootstrap",
|
|
26593
|
+
historicalEvidenceOnly: ["recoveryHints", "ledger.summary", "queue.summary"]
|
|
26594
|
+
},
|
|
26026
26595
|
nodes: nodeStatuses,
|
|
26027
26596
|
queue: { tasks: queue, summary: queueSummary },
|
|
26028
26597
|
ledger: { entries: ledgerEntries, summary: ledgerSummary }
|
|
@@ -33957,6 +34526,7 @@ async function initDaemonComponents(config) {
|
|
|
33957
34526
|
sessionHostControl: config.sessionHostControl,
|
|
33958
34527
|
statusInstanceId: config.statusInstanceId,
|
|
33959
34528
|
statusVersion: config.statusVersion,
|
|
34529
|
+
getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
|
|
33960
34530
|
getCdpLogFn: config.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
|
|
33961
34531
|
});
|
|
33962
34532
|
poller = new AgentStreamPoller({
|
|
@@ -34231,6 +34801,7 @@ export {
|
|
|
34231
34801
|
prepareSessionChatTailUpdate,
|
|
34232
34802
|
prepareSessionModalUpdate,
|
|
34233
34803
|
probeCdpPort,
|
|
34804
|
+
queuePendingMeshCoordinatorEvent,
|
|
34234
34805
|
readChatHistory,
|
|
34235
34806
|
readLedgerEntries,
|
|
34236
34807
|
readLedgerSlice,
|