@adhdev/daemon-core 0.9.82-rc.3 → 0.9.82-rc.31
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 +1052 -292
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1051 -292
- 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 +836 -149
- 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
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
function getPendingEventsPath(meshId) {
|
|
1950
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1951
|
+
return join9(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
1899
1952
|
}
|
|
1900
|
-
function
|
|
1901
|
-
|
|
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
|
+
}
|
|
1902
1961
|
}
|
|
1903
|
-
function
|
|
1904
|
-
|
|
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,55 +23839,45 @@ function readBooleanValue(...values) {
|
|
|
23603
23839
|
}
|
|
23604
23840
|
return void 0;
|
|
23605
23841
|
}
|
|
23606
|
-
function
|
|
23607
|
-
const
|
|
23608
|
-
const
|
|
23609
|
-
if (
|
|
23610
|
-
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
|
|
23614
|
-
|
|
23615
|
-
|
|
23616
|
-
|
|
23617
|
-
|
|
23618
|
-
|
|
23619
|
-
|
|
23620
|
-
|
|
23621
|
-
|
|
23622
|
-
|
|
23623
|
-
|
|
23624
|
-
|
|
23625
|
-
|
|
23626
|
-
|
|
23627
|
-
|
|
23628
|
-
|
|
23629
|
-
|
|
23630
|
-
|
|
23631
|
-
|
|
23632
|
-
|
|
23633
|
-
|
|
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 joinRepoPath(root, relativePath) {
|
|
23843
|
+
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
23844
|
+
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
23845
|
+
if (!normalizedPath) return void 0;
|
|
23846
|
+
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
23847
|
+
if (!normalizedRoot) return void 0;
|
|
23848
|
+
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
23849
|
+
}
|
|
23850
|
+
function readGitSubmodules(value, parentRepoRoot) {
|
|
23851
|
+
if (!Array.isArray(value)) return void 0;
|
|
23852
|
+
const submodules = value.map((entry) => {
|
|
23853
|
+
const submodule = readObjectRecord(entry);
|
|
23854
|
+
const path28 = readStringValue(submodule.path);
|
|
23855
|
+
const commit = readStringValue(submodule.commit);
|
|
23856
|
+
const repoPath = readStringValue(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path28);
|
|
23857
|
+
if (!path28 || !commit || !repoPath) return null;
|
|
23858
|
+
return {
|
|
23859
|
+
path: path28,
|
|
23860
|
+
commit,
|
|
23861
|
+
repoPath,
|
|
23862
|
+
dirty: readBooleanValue(submodule.dirty) ?? false,
|
|
23863
|
+
outOfSync: readBooleanValue(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
23864
|
+
lastCheckedAt: readNumberValue(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now(),
|
|
23865
|
+
...readStringValue(submodule.error) ? { error: readStringValue(submodule.error) } : {}
|
|
23866
|
+
};
|
|
23867
|
+
}).filter((entry) => entry !== null);
|
|
23868
|
+
return submodules.length > 0 ? submodules : void 0;
|
|
23869
|
+
}
|
|
23870
|
+
function normalizeInlineMeshGitStatus(status, node, options) {
|
|
23647
23871
|
const isGitRepo = readBooleanValue(status.isGitRepo);
|
|
23648
23872
|
if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
|
|
23649
23873
|
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((value) => typeof value === "string") : [];
|
|
23650
23874
|
const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
|
|
23651
23875
|
const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
|
|
23876
|
+
const repoRoot = readStringValue(status.repoRoot, status.repo_root, node?.repoRoot, node?.repo_root, status.workspace, node?.workspace) || void 0;
|
|
23877
|
+
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
23652
23878
|
return {
|
|
23653
23879
|
workspace: readStringValue(status.workspace, node?.workspace) || "",
|
|
23654
|
-
repoRoot:
|
|
23880
|
+
repoRoot: repoRoot ?? null,
|
|
23655
23881
|
isGitRepo,
|
|
23656
23882
|
branch: readStringValue(status.branch) ?? null,
|
|
23657
23883
|
headCommit: readStringValue(status.headCommit) ?? null,
|
|
@@ -23667,29 +23893,407 @@ function buildCachedInlineMeshGitStatus(node) {
|
|
|
23667
23893
|
hasConflicts,
|
|
23668
23894
|
conflictFiles,
|
|
23669
23895
|
stashCount: readNumberValue(status.stashCount) ?? 0,
|
|
23670
|
-
lastCheckedAt: Date.now()
|
|
23896
|
+
lastCheckedAt: options?.lastCheckedAt ?? readNumberValue(status.lastCheckedAt) ?? Date.now(),
|
|
23897
|
+
...submodules ? { submodules } : {}
|
|
23898
|
+
};
|
|
23899
|
+
}
|
|
23900
|
+
function buildInlineMeshTransitGitStatus(node) {
|
|
23901
|
+
const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
|
|
23902
|
+
const gitResult = readObjectRecord(rawGit.result);
|
|
23903
|
+
const directStatus = readObjectRecord(rawGit.status);
|
|
23904
|
+
const nestedStatus = readObjectRecord(gitResult.status);
|
|
23905
|
+
const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
|
|
23906
|
+
const probeGit = readObjectRecord(rawProbe.git);
|
|
23907
|
+
const probeGitResult = readObjectRecord(probeGit.result);
|
|
23908
|
+
const probeDirectStatus = readObjectRecord(probeGit.status);
|
|
23909
|
+
const probeNestedStatus = readObjectRecord(probeGitResult.status);
|
|
23910
|
+
const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
|
|
23911
|
+
return normalizeInlineMeshGitStatus(status, node, { lastCheckedAt: Date.now() });
|
|
23912
|
+
}
|
|
23913
|
+
function recordInlineMeshDirectGitTruth(node, git, source) {
|
|
23914
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return;
|
|
23915
|
+
const checkedAt = readNumberValue(git.lastCheckedAt) ?? Date.now();
|
|
23916
|
+
const updatedAt = new Date(checkedAt).toISOString();
|
|
23917
|
+
const nextGit = {
|
|
23918
|
+
...git,
|
|
23919
|
+
lastCheckedAt: checkedAt
|
|
23671
23920
|
};
|
|
23921
|
+
node.lastGit = {
|
|
23922
|
+
source,
|
|
23923
|
+
checkedAt,
|
|
23924
|
+
status: nextGit
|
|
23925
|
+
};
|
|
23926
|
+
node.last_git = node.lastGit;
|
|
23927
|
+
node.machineStatus = "online";
|
|
23928
|
+
node.updatedAt = updatedAt;
|
|
23929
|
+
node.lastSeenAt = updatedAt;
|
|
23930
|
+
const repoRoot = readStringValue(nextGit.repoRoot);
|
|
23931
|
+
if (repoRoot && !readStringValue(node.repoRoot)) node.repoRoot = repoRoot;
|
|
23672
23932
|
}
|
|
23673
|
-
function
|
|
23933
|
+
function buildCachedInlineMeshGitStatus(node) {
|
|
23934
|
+
const liveGit = buildInlineMeshTransitGitStatus(node);
|
|
23935
|
+
if (liveGit) return liveGit;
|
|
23674
23936
|
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
23675
|
-
const
|
|
23676
|
-
|
|
23677
|
-
|
|
23937
|
+
const cachedGit = readObjectRecord(cachedStatus.git);
|
|
23938
|
+
if (!Object.keys(cachedGit).length) return void 0;
|
|
23939
|
+
return normalizeInlineMeshGitStatus(cachedGit, node);
|
|
23940
|
+
}
|
|
23941
|
+
function shouldDiscardCachedInlineMeshStatus(node) {
|
|
23942
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
23943
|
+
if (!Object.keys(cachedStatus).length) return false;
|
|
23944
|
+
const cachedGit = readObjectRecord(cachedStatus.git);
|
|
23945
|
+
const workspaceError = readStringValue(cachedStatus.error, node?.error);
|
|
23946
|
+
if (workspaceError && /workspace must be an existing directory/i.test(workspaceError)) return true;
|
|
23947
|
+
const isGitRepo = readBooleanValue(cachedGit.isGitRepo);
|
|
23948
|
+
const branch = readStringValue(cachedGit.branch);
|
|
23949
|
+
const headCommit = readStringValue(cachedGit.headCommit);
|
|
23950
|
+
return isGitRepo === false && !branch && !headCommit;
|
|
23951
|
+
}
|
|
23952
|
+
function stripInlineMeshTransientNodeState(node) {
|
|
23953
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return node;
|
|
23954
|
+
const {
|
|
23955
|
+
cachedStatus,
|
|
23956
|
+
lastGit: _lastGit,
|
|
23957
|
+
last_git: _lastGitLegacy,
|
|
23958
|
+
lastProbe: _lastProbe,
|
|
23959
|
+
last_probe: _lastProbeLegacy,
|
|
23960
|
+
error: _error,
|
|
23961
|
+
health: _health,
|
|
23962
|
+
machineStatus: _machineStatus,
|
|
23963
|
+
lastSeenAt: _lastSeenAt,
|
|
23964
|
+
last_seen_at: _lastSeenAtLegacy,
|
|
23965
|
+
updatedAt: _updatedAt,
|
|
23966
|
+
updated_at: _updatedAtLegacy,
|
|
23967
|
+
activeSession: _activeSession,
|
|
23968
|
+
active_session: _activeSessionLegacy,
|
|
23969
|
+
activeSessionId: _activeSessionId,
|
|
23970
|
+
active_session_id: _activeSessionIdLegacy,
|
|
23971
|
+
sessionId: _sessionId,
|
|
23972
|
+
session_id: _sessionIdLegacy,
|
|
23973
|
+
providerType: _providerType,
|
|
23974
|
+
provider_type: _providerTypeLegacy,
|
|
23975
|
+
...rest
|
|
23976
|
+
} = node;
|
|
23977
|
+
if (cachedStatus && !shouldDiscardCachedInlineMeshStatus(node)) {
|
|
23978
|
+
return { ...rest, cachedStatus };
|
|
23979
|
+
}
|
|
23980
|
+
return rest;
|
|
23981
|
+
}
|
|
23982
|
+
function hasInlineMeshTransientNodeState(node) {
|
|
23983
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return false;
|
|
23984
|
+
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;
|
|
23985
|
+
}
|
|
23986
|
+
function readInlineMeshNodeId(node) {
|
|
23987
|
+
return readStringValue(node?.id, node?.nodeId) || "";
|
|
23988
|
+
}
|
|
23989
|
+
function sanitizeInlineMesh(inlineMesh) {
|
|
23990
|
+
if (!inlineMesh || typeof inlineMesh !== "object" || Array.isArray(inlineMesh)) return inlineMesh;
|
|
23991
|
+
if (!Array.isArray(inlineMesh.nodes)) return inlineMesh;
|
|
23992
|
+
let changed = false;
|
|
23993
|
+
const nodes = inlineMesh.nodes.map((node) => {
|
|
23994
|
+
if (!hasInlineMeshTransientNodeState(node)) return node;
|
|
23995
|
+
changed = true;
|
|
23996
|
+
return stripInlineMeshTransientNodeState(node);
|
|
23997
|
+
});
|
|
23998
|
+
if (!changed) return inlineMesh;
|
|
23999
|
+
return {
|
|
24000
|
+
...inlineMesh,
|
|
24001
|
+
nodes
|
|
24002
|
+
};
|
|
24003
|
+
}
|
|
24004
|
+
function reconcileInlineMeshCache(cached, incoming) {
|
|
24005
|
+
if (!cached || typeof cached !== "object" || Array.isArray(cached)) return incoming;
|
|
24006
|
+
if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return cached;
|
|
24007
|
+
const cachedNodes = Array.isArray(cached.nodes) ? cached.nodes : [];
|
|
24008
|
+
const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
|
|
24009
|
+
if (!cachedNodes.length || !incomingNodes.length) return { ...cached, ...incoming };
|
|
24010
|
+
const incomingById = /* @__PURE__ */ new Map();
|
|
24011
|
+
for (const node of incomingNodes) {
|
|
24012
|
+
const nodeId = readInlineMeshNodeId(node);
|
|
24013
|
+
if (nodeId) incomingById.set(nodeId, node);
|
|
24014
|
+
}
|
|
24015
|
+
const nodes = cachedNodes.map((cachedNode) => {
|
|
24016
|
+
const nodeId = readInlineMeshNodeId(cachedNode);
|
|
24017
|
+
const incomingNode = nodeId ? incomingById.get(nodeId) : void 0;
|
|
24018
|
+
if (!incomingNode) return cachedNode;
|
|
24019
|
+
if (hasInlineMeshTransientNodeState(incomingNode)) {
|
|
24020
|
+
return { ...cachedNode, ...incomingNode };
|
|
24021
|
+
}
|
|
24022
|
+
return { ...stripInlineMeshTransientNodeState(cachedNode), ...incomingNode };
|
|
24023
|
+
});
|
|
24024
|
+
return {
|
|
24025
|
+
...cached,
|
|
24026
|
+
...incoming,
|
|
24027
|
+
nodes
|
|
24028
|
+
};
|
|
24029
|
+
}
|
|
24030
|
+
function hasGitWorktreeChanges(git) {
|
|
24031
|
+
if (!git) return false;
|
|
24032
|
+
return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
|
|
24033
|
+
}
|
|
24034
|
+
function getGitSubmoduleDriftState(git) {
|
|
24035
|
+
const submodules = Array.isArray(git?.submodules) ? git.submodules : [];
|
|
24036
|
+
let dirty = false;
|
|
24037
|
+
let outOfSync = false;
|
|
24038
|
+
for (const entry of submodules) {
|
|
24039
|
+
const submodule = readObjectRecord(entry);
|
|
24040
|
+
if (readBooleanValue(submodule.dirty) === true) dirty = true;
|
|
24041
|
+
if (readBooleanValue(submodule.outOfSync) === true || !!readStringValue(submodule.error)) outOfSync = true;
|
|
24042
|
+
}
|
|
24043
|
+
return { dirty, outOfSync };
|
|
24044
|
+
}
|
|
24045
|
+
function deriveMeshNodeHealthFromGit(git) {
|
|
24046
|
+
if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
|
|
24047
|
+
const branch = readStringValue(git.branch);
|
|
24048
|
+
if (!branch) return "degraded";
|
|
24049
|
+
const submoduleDrift = getGitSubmoduleDriftState(git);
|
|
24050
|
+
if (submoduleDrift.outOfSync) return "degraded";
|
|
24051
|
+
if (submoduleDrift.dirty || hasGitWorktreeChanges(git)) return "dirty";
|
|
24052
|
+
return "online";
|
|
24053
|
+
}
|
|
24054
|
+
function readCachedInlineMeshActiveSessions(node) {
|
|
24055
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24056
|
+
const activeSession = readObjectRecord(cachedStatus.activeSession);
|
|
24057
|
+
const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
|
|
24058
|
+
const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
|
|
24059
|
+
return sessionId ? [sessionId] : [];
|
|
24060
|
+
}
|
|
24061
|
+
function readCachedInlineMeshActiveSessionDetails(node) {
|
|
24062
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24063
|
+
const activeSession = readObjectRecord(cachedStatus.activeSession);
|
|
24064
|
+
const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
|
|
24065
|
+
const sessionId = readStringValue(
|
|
24066
|
+
fallbackSession.id,
|
|
24067
|
+
fallbackSession.sessionId,
|
|
24068
|
+
fallbackSession.session_id,
|
|
24069
|
+
node?.activeSessionId,
|
|
24070
|
+
node?.active_session_id,
|
|
24071
|
+
node?.sessionId,
|
|
24072
|
+
node?.session_id
|
|
24073
|
+
);
|
|
24074
|
+
if (!sessionId) return [];
|
|
24075
|
+
return [{
|
|
24076
|
+
sessionId,
|
|
24077
|
+
providerType: readStringValue(
|
|
24078
|
+
fallbackSession.providerType,
|
|
24079
|
+
fallbackSession.provider_type,
|
|
24080
|
+
fallbackSession.cliType,
|
|
24081
|
+
fallbackSession.cli_type,
|
|
24082
|
+
fallbackSession.provider,
|
|
24083
|
+
node?.providerType,
|
|
24084
|
+
node?.provider_type
|
|
24085
|
+
),
|
|
24086
|
+
state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
|
|
24087
|
+
lifecycle: readStringValue(fallbackSession.lifecycle),
|
|
24088
|
+
title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
|
|
24089
|
+
workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
|
|
24090
|
+
lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
|
|
24091
|
+
recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
|
|
24092
|
+
isCached: true
|
|
24093
|
+
}];
|
|
24094
|
+
}
|
|
24095
|
+
function readLiveMeshSessionState(record) {
|
|
24096
|
+
return readStringValue(
|
|
24097
|
+
record?.meta?.sessionStatus,
|
|
24098
|
+
record?.meta?.status,
|
|
24099
|
+
record?.meta?.providerStatus,
|
|
24100
|
+
record?.status,
|
|
24101
|
+
record?.state,
|
|
24102
|
+
record?.lifecycle
|
|
24103
|
+
);
|
|
24104
|
+
}
|
|
24105
|
+
function toIsoTimestamp(value) {
|
|
24106
|
+
if (typeof value === "number" && Number.isFinite(value)) return new Date(value).toISOString();
|
|
24107
|
+
const stringValue = readStringValue(value);
|
|
24108
|
+
return stringValue || null;
|
|
24109
|
+
}
|
|
24110
|
+
function synthesizeMeshNodeFreshnessFromConnection(status) {
|
|
24111
|
+
const connection = readObjectRecord(status.connection);
|
|
24112
|
+
const connectionFreshAt = toIsoTimestamp(connection.lastCommandAt ?? connection.lastConnectedAt ?? connection.lastStateChangeAt);
|
|
24113
|
+
const git = readObjectRecord(status.git);
|
|
24114
|
+
const gitCheckedAt = toIsoTimestamp(git.lastCheckedAt);
|
|
24115
|
+
if (!status.lastSeenAt && connectionFreshAt) status.lastSeenAt = connectionFreshAt;
|
|
24116
|
+
if (!status.updatedAt && (gitCheckedAt || connectionFreshAt)) {
|
|
24117
|
+
status.updatedAt = gitCheckedAt ?? connectionFreshAt;
|
|
24118
|
+
}
|
|
24119
|
+
}
|
|
24120
|
+
function finalizeMeshNodeStatus(args) {
|
|
24121
|
+
const { status, node, daemonId, isSelfNode } = args;
|
|
24122
|
+
if (!readStringValue(status.machineStatus)) {
|
|
24123
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24124
|
+
const machineStatus = readStringValue(cachedStatus.machineStatus, cachedStatus.machine_status, node?.machineStatus);
|
|
24125
|
+
if (machineStatus) status.machineStatus = machineStatus;
|
|
24126
|
+
}
|
|
24127
|
+
synthesizeMeshNodeFreshnessFromConnection(status);
|
|
24128
|
+
const connectionState = readStringValue(readObjectRecord(status.connection).state);
|
|
24129
|
+
status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || connectionState === "connected" || isSelfNode);
|
|
24130
|
+
}
|
|
24131
|
+
async function probeRemoteMeshGitStatus(args) {
|
|
24132
|
+
if (!args.dispatchMeshCommand) return null;
|
|
24133
|
+
const remoteResult = await Promise.race([
|
|
24134
|
+
args.dispatchMeshCommand(args.daemonId, "git_status", { workspace: args.workspace }),
|
|
24135
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), args.timeoutMs))
|
|
24136
|
+
]);
|
|
24137
|
+
const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
|
|
24138
|
+
return remoteGit && typeof remoteGit === "object" && typeof remoteGit.isGitRepo === "boolean" ? remoteGit : null;
|
|
24139
|
+
}
|
|
24140
|
+
async function hydrateInlineMeshDirectTruth(args) {
|
|
24141
|
+
const nodes = Array.isArray(args.mesh?.nodes) ? args.mesh.nodes : [];
|
|
24142
|
+
if (!nodes.length) {
|
|
24143
|
+
return {
|
|
24144
|
+
directEvidenceCount: 0,
|
|
24145
|
+
localConfirmedCount: 0,
|
|
24146
|
+
peerAttemptedCount: 0,
|
|
24147
|
+
peerConfirmedCount: 0,
|
|
24148
|
+
unavailableNodeIds: []
|
|
24149
|
+
};
|
|
24150
|
+
}
|
|
24151
|
+
const selectedCoordinatorNodeId = readStringValue(
|
|
24152
|
+
args.mesh?.coordinator?.preferredNodeId,
|
|
24153
|
+
nodes[0]?.id,
|
|
24154
|
+
nodes[0]?.nodeId
|
|
24155
|
+
);
|
|
24156
|
+
let localConfirmedCount = 0;
|
|
24157
|
+
let peerAttemptedCount = 0;
|
|
24158
|
+
let peerConfirmedCount = 0;
|
|
24159
|
+
const unavailableNodeIds = [];
|
|
24160
|
+
for (const [nodeIndex, node] of nodes.entries()) {
|
|
24161
|
+
const nodeId = readStringValue(node?.id, node?.nodeId) || `node_${nodeIndex}`;
|
|
24162
|
+
const workspace = readStringValue(node?.workspace);
|
|
24163
|
+
const daemonId = readStringValue(node?.daemonId);
|
|
24164
|
+
const isSelfNode = Boolean(
|
|
24165
|
+
nodeId && selectedCoordinatorNodeId && nodeId === selectedCoordinatorNodeId
|
|
24166
|
+
) || Boolean(
|
|
24167
|
+
daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId)
|
|
24168
|
+
) || Boolean(args.meshSource !== "local_config" && nodeIndex === 0);
|
|
24169
|
+
if (!workspace) {
|
|
24170
|
+
if (!isSelfNode && daemonId) unavailableNodeIds.push(nodeId);
|
|
24171
|
+
continue;
|
|
24172
|
+
}
|
|
24173
|
+
if (isSelfNode && fs10.existsSync(workspace)) {
|
|
24174
|
+
try {
|
|
24175
|
+
const localGit = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
24176
|
+
if (localGit?.isGitRepo) {
|
|
24177
|
+
recordInlineMeshDirectGitTruth(node, localGit, "selected_coordinator_local_git");
|
|
24178
|
+
localConfirmedCount += 1;
|
|
24179
|
+
continue;
|
|
24180
|
+
}
|
|
24181
|
+
} catch {
|
|
24182
|
+
}
|
|
24183
|
+
}
|
|
24184
|
+
if (!daemonId || !args.dispatchMeshCommand) {
|
|
24185
|
+
if (!isSelfNode) unavailableNodeIds.push(nodeId);
|
|
24186
|
+
continue;
|
|
24187
|
+
}
|
|
24188
|
+
peerAttemptedCount += 1;
|
|
24189
|
+
try {
|
|
24190
|
+
const remoteGit = await probeRemoteMeshGitStatus({
|
|
24191
|
+
dispatchMeshCommand: args.dispatchMeshCommand,
|
|
24192
|
+
daemonId,
|
|
24193
|
+
workspace,
|
|
24194
|
+
timeoutMs: 8e3
|
|
24195
|
+
});
|
|
24196
|
+
if (remoteGit) {
|
|
24197
|
+
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
24198
|
+
peerConfirmedCount += 1;
|
|
24199
|
+
continue;
|
|
24200
|
+
}
|
|
24201
|
+
} catch {
|
|
24202
|
+
}
|
|
24203
|
+
unavailableNodeIds.push(nodeId);
|
|
24204
|
+
}
|
|
24205
|
+
return {
|
|
24206
|
+
directEvidenceCount: localConfirmedCount + peerConfirmedCount,
|
|
24207
|
+
localConfirmedCount,
|
|
24208
|
+
peerAttemptedCount,
|
|
24209
|
+
peerConfirmedCount,
|
|
24210
|
+
unavailableNodeIds
|
|
24211
|
+
};
|
|
24212
|
+
}
|
|
24213
|
+
function summarizeMeshSessionRecord(record) {
|
|
24214
|
+
return {
|
|
24215
|
+
sessionId: readStringValue(record?.sessionId) || "unknown",
|
|
24216
|
+
providerType: readStringValue(record?.providerType),
|
|
24217
|
+
state: readLiveMeshSessionState(record),
|
|
24218
|
+
lifecycle: readStringValue(record?.lifecycle),
|
|
24219
|
+
surfaceKind: getSessionHostSurfaceKind(record),
|
|
24220
|
+
recoveryState: readStringValue(record?.meta?.runtimeRecoveryState) ?? null,
|
|
24221
|
+
workspace: readStringValue(record?.workspace) ?? null,
|
|
24222
|
+
title: readStringValue(record?.displayName, record?.workspaceLabel) ?? null,
|
|
24223
|
+
lastActivityAt: toIsoTimestamp(record?.updatedAt ?? record?.lastActivityAt ?? record?.last_activity_at),
|
|
24224
|
+
isCached: false
|
|
24225
|
+
};
|
|
24226
|
+
}
|
|
24227
|
+
function liveSessionRecordMatchesMeshNode(record, meshId, nodeId) {
|
|
24228
|
+
const recordNodeId = readStringValue(record?.meta?.meshNodeId);
|
|
24229
|
+
if (!recordNodeId || recordNodeId !== nodeId) return false;
|
|
24230
|
+
const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
|
|
24231
|
+
return !recordMeshId || recordMeshId === meshId;
|
|
24232
|
+
}
|
|
24233
|
+
function liveSessionRecordMatchesMeshWorkspace(record, meshId, workspace) {
|
|
24234
|
+
const recordWorkspace = readStringValue(record?.workspace);
|
|
24235
|
+
if (!recordWorkspace || !workspace || recordWorkspace !== workspace) return false;
|
|
24236
|
+
const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
|
|
24237
|
+
if (recordMeshId) return recordMeshId === meshId;
|
|
24238
|
+
return record?.meta?.launchedByCoordinator === true || !!readStringValue(record?.meta?.meshNodeId);
|
|
24239
|
+
}
|
|
24240
|
+
function readLiveMeshNodeWorkspace(args) {
|
|
24241
|
+
const directNodeWorkspace = args.liveSessionRecords.find((record) => liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId) && readStringValue(record?.workspace));
|
|
24242
|
+
if (directNodeWorkspace) {
|
|
24243
|
+
return readStringValue(directNodeWorkspace.workspace) || "";
|
|
24244
|
+
}
|
|
24245
|
+
if (args.allowCoordinatorSession) {
|
|
24246
|
+
const coordinatorWorkspace = args.liveSessionRecords.find((record) => readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId && readStringValue(record?.workspace));
|
|
24247
|
+
if (coordinatorWorkspace) {
|
|
24248
|
+
return readStringValue(coordinatorWorkspace.workspace) || "";
|
|
24249
|
+
}
|
|
24250
|
+
}
|
|
24251
|
+
return "";
|
|
24252
|
+
}
|
|
24253
|
+
function collectLiveMeshSessionRecords(args) {
|
|
24254
|
+
const matches = args.liveSessionRecords.filter((record) => {
|
|
24255
|
+
const nodeWorkspace = readStringValue(args.node?.workspace);
|
|
24256
|
+
if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)) return true;
|
|
24257
|
+
return !!nodeWorkspace && liveSessionRecordMatchesMeshWorkspace(record, args.meshId, nodeWorkspace);
|
|
24258
|
+
});
|
|
24259
|
+
if (args.allowCoordinatorSession) {
|
|
24260
|
+
for (const record of args.liveSessionRecords) {
|
|
24261
|
+
if (readStringValue(record?.meta?.meshCoordinatorFor) !== args.meshId) continue;
|
|
24262
|
+
const sessionId = readStringValue(record?.sessionId);
|
|
24263
|
+
if (sessionId && matches.some((entry) => readStringValue(entry?.sessionId) === sessionId)) continue;
|
|
24264
|
+
matches.push(record);
|
|
24265
|
+
}
|
|
24266
|
+
}
|
|
24267
|
+
return matches;
|
|
24268
|
+
}
|
|
24269
|
+
function applyCachedInlineMeshNodeStatus(status, node, options) {
|
|
24270
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24271
|
+
const liveGit = buildInlineMeshTransitGitStatus(node);
|
|
24272
|
+
const git = options?.skipGit ? void 0 : liveGit ?? buildCachedInlineMeshGitStatus(node);
|
|
24273
|
+
const error = options?.skipError ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.error, node?.error);
|
|
24274
|
+
const health = options?.skipHealth ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.health, node?.health);
|
|
23678
24275
|
const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
|
|
23679
|
-
|
|
23680
|
-
|
|
24276
|
+
const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
|
|
24277
|
+
const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
|
|
24278
|
+
const activeSessions = readCachedInlineMeshActiveSessions(node);
|
|
24279
|
+
const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
|
|
24280
|
+
if (!git && !error && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
|
|
23681
24281
|
if (git) status.git = git;
|
|
23682
24282
|
if (error) status.error = error;
|
|
24283
|
+
if (machineStatus) status.machineStatus = machineStatus;
|
|
24284
|
+
if (lastSeenAt) status.lastSeenAt = lastSeenAt;
|
|
24285
|
+
if (updatedAt) status.updatedAt = updatedAt;
|
|
24286
|
+
if (activeSessions.length > 0) status.activeSessions = activeSessions;
|
|
24287
|
+
if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
|
|
23683
24288
|
if (health) {
|
|
23684
24289
|
status.health = health;
|
|
23685
24290
|
return true;
|
|
23686
24291
|
}
|
|
23687
24292
|
if (git) {
|
|
23688
|
-
|
|
23689
|
-
status.health = git.isGitRepo === false ? "degraded" : dirty ? "dirty" : "online";
|
|
24293
|
+
status.health = deriveMeshNodeHealthFromGit(git);
|
|
23690
24294
|
return true;
|
|
23691
24295
|
}
|
|
23692
|
-
return
|
|
24296
|
+
return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
|
|
23693
24297
|
}
|
|
23694
24298
|
async function resolveProviderTypeFromPriority(args) {
|
|
23695
24299
|
if (!args.providerPriority.length) {
|
|
@@ -24087,25 +24691,40 @@ var DaemonCommandRouter = class {
|
|
|
24087
24691
|
}
|
|
24088
24692
|
getCachedInlineMesh(meshId, inlineMesh) {
|
|
24089
24693
|
if (inlineMesh && typeof inlineMesh === "object") {
|
|
24090
|
-
this.
|
|
24091
|
-
return inlineMesh;
|
|
24694
|
+
return this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24092
24695
|
}
|
|
24093
24696
|
return this.inlineMeshCache.get(meshId);
|
|
24094
24697
|
}
|
|
24698
|
+
warmInlineMeshCache(meshId, inlineMesh) {
|
|
24699
|
+
if (!inlineMesh || typeof inlineMesh !== "object") return void 0;
|
|
24700
|
+
const sanitizedInlineMesh = sanitizeInlineMesh(inlineMesh);
|
|
24701
|
+
const cached = this.inlineMeshCache.get(meshId);
|
|
24702
|
+
if (cached) {
|
|
24703
|
+
const merged = reconcileInlineMeshCache(cached, sanitizedInlineMesh);
|
|
24704
|
+
this.inlineMeshCache.set(meshId, merged);
|
|
24705
|
+
return merged;
|
|
24706
|
+
}
|
|
24707
|
+
this.inlineMeshCache.set(meshId, sanitizedInlineMesh);
|
|
24708
|
+
return sanitizedInlineMesh;
|
|
24709
|
+
}
|
|
24095
24710
|
async getMeshForCommand(meshId, inlineMesh, options) {
|
|
24096
24711
|
const preferInline = options?.preferInline === true;
|
|
24097
24712
|
if (preferInline) {
|
|
24098
|
-
const cached2 = this.getCachedInlineMesh(meshId
|
|
24099
|
-
if (cached2) return { mesh: cached2, inline: true };
|
|
24713
|
+
const cached2 = this.getCachedInlineMesh(meshId);
|
|
24714
|
+
if (cached2) return { mesh: cached2, inline: true, source: "inline_cache" };
|
|
24715
|
+
const warmedInline2 = this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24716
|
+
if (warmedInline2) return { mesh: warmedInline2, inline: true, source: "inline_bootstrap" };
|
|
24100
24717
|
}
|
|
24101
24718
|
try {
|
|
24102
24719
|
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
24103
24720
|
const mesh = getMesh3(meshId);
|
|
24104
|
-
if (mesh) return { mesh, inline: false };
|
|
24721
|
+
if (mesh) return { mesh, inline: false, source: "local_config" };
|
|
24105
24722
|
} catch {
|
|
24106
24723
|
}
|
|
24107
|
-
const cached = this.getCachedInlineMesh(meshId
|
|
24108
|
-
|
|
24724
|
+
const cached = this.getCachedInlineMesh(meshId);
|
|
24725
|
+
if (cached) return { mesh: cached, inline: true, source: "inline_cache" };
|
|
24726
|
+
const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24727
|
+
return warmedInline ? { mesh: warmedInline, inline: true, source: "inline_bootstrap" } : null;
|
|
24109
24728
|
}
|
|
24110
24729
|
updateInlineMeshNode(meshId, mesh, node) {
|
|
24111
24730
|
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
@@ -24334,6 +24953,7 @@ var DaemonCommandRouter = class {
|
|
|
24334
24953
|
const deletedSessionIds = [];
|
|
24335
24954
|
const skippedSessionIds = [];
|
|
24336
24955
|
const skippedLiveSessionIds = [];
|
|
24956
|
+
const skippedCoordinatorSessionIds = [];
|
|
24337
24957
|
const deleteUnsupportedSessionIds = [];
|
|
24338
24958
|
const recordsRemainSessionIds = [];
|
|
24339
24959
|
const errors = [];
|
|
@@ -24366,6 +24986,12 @@ var DaemonCommandRouter = class {
|
|
|
24366
24986
|
const completed = this.isCompletedHostedSession(record);
|
|
24367
24987
|
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
24368
24988
|
const liveRuntime = surfaceKind === "live_runtime";
|
|
24989
|
+
const coordinatorSession = readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId;
|
|
24990
|
+
if (!hasExplicitSessionIds && coordinatorSession) {
|
|
24991
|
+
skippedSessionIds.push(sessionId);
|
|
24992
|
+
skippedCoordinatorSessionIds.push(sessionId);
|
|
24993
|
+
continue;
|
|
24994
|
+
}
|
|
24369
24995
|
if (!hasExplicitSessionIds && liveRuntime) {
|
|
24370
24996
|
skippedSessionIds.push(sessionId);
|
|
24371
24997
|
skippedLiveSessionIds.push(sessionId);
|
|
@@ -24431,6 +25057,7 @@ var DaemonCommandRouter = class {
|
|
|
24431
25057
|
deletedSessionIds,
|
|
24432
25058
|
skippedSessionIds,
|
|
24433
25059
|
skippedLiveSessionIds,
|
|
25060
|
+
skippedCoordinatorSessionIds,
|
|
24434
25061
|
...deleteUnsupported ? {
|
|
24435
25062
|
deleteUnsupported: true,
|
|
24436
25063
|
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
@@ -24563,7 +25190,8 @@ var DaemonCommandRouter = class {
|
|
|
24563
25190
|
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
24564
25191
|
}
|
|
24565
25192
|
case "get_pending_mesh_events": {
|
|
24566
|
-
const
|
|
25193
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25194
|
+
const events = drainPendingMeshCoordinatorEvents(meshId || void 0);
|
|
24567
25195
|
return { success: true, events };
|
|
24568
25196
|
}
|
|
24569
25197
|
case "launch_cli":
|
|
@@ -25092,15 +25720,39 @@ var DaemonCommandRouter = class {
|
|
|
25092
25720
|
case "get_mesh": {
|
|
25093
25721
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25094
25722
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
25095
|
-
|
|
25096
|
-
|
|
25097
|
-
|
|
25098
|
-
|
|
25099
|
-
|
|
25723
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
25724
|
+
if (!meshRecord?.mesh) return { success: false, error: "Mesh not found" };
|
|
25725
|
+
const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
|
|
25726
|
+
const directTruth = await hydrateInlineMeshDirectTruth({
|
|
25727
|
+
mesh: meshRecord.mesh,
|
|
25728
|
+
meshSource: meshRecord.source,
|
|
25729
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
25730
|
+
statusInstanceId: this.deps.statusInstanceId,
|
|
25731
|
+
localMachineId: loadConfig().machineId || ""
|
|
25732
|
+
});
|
|
25733
|
+
const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
|
|
25734
|
+
const sourceOfTruth = {
|
|
25735
|
+
membership: meshRecord.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
25736
|
+
coordinatorOwnsLiveTruth: directTruthSatisfied,
|
|
25737
|
+
directPeerTruth: {
|
|
25738
|
+
required: requireDirectPeerTruth,
|
|
25739
|
+
satisfied: directTruthSatisfied,
|
|
25740
|
+
directEvidenceCount: directTruth.directEvidenceCount,
|
|
25741
|
+
localConfirmedCount: directTruth.localConfirmedCount,
|
|
25742
|
+
peerAttemptedCount: directTruth.peerAttemptedCount,
|
|
25743
|
+
peerConfirmedCount: directTruth.peerConfirmedCount,
|
|
25744
|
+
unavailableNodeIds: directTruth.unavailableNodeIds
|
|
25745
|
+
}
|
|
25746
|
+
};
|
|
25747
|
+
if (requireDirectPeerTruth && !directTruthSatisfied) {
|
|
25748
|
+
return {
|
|
25749
|
+
success: false,
|
|
25750
|
+
code: "mesh_direct_peer_truth_unavailable",
|
|
25751
|
+
error: "Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct get_mesh probes succeed.",
|
|
25752
|
+
sourceOfTruth
|
|
25753
|
+
};
|
|
25100
25754
|
}
|
|
25101
|
-
|
|
25102
|
-
if (cached) return { success: true, mesh: cached };
|
|
25103
|
-
return { success: false, error: "Mesh not found" };
|
|
25755
|
+
return { success: true, mesh: meshRecord.mesh, sourceOfTruth };
|
|
25104
25756
|
}
|
|
25105
25757
|
case "create_mesh": {
|
|
25106
25758
|
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
@@ -25621,7 +26273,14 @@ var DaemonCommandRouter = class {
|
|
|
25621
26273
|
cliType
|
|
25622
26274
|
};
|
|
25623
26275
|
}
|
|
25624
|
-
const
|
|
26276
|
+
const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
|
|
26277
|
+
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
26278
|
+
const workspace = readLiveMeshNodeWorkspace({
|
|
26279
|
+
meshId,
|
|
26280
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || ""),
|
|
26281
|
+
liveSessionRecords: liveMeshSessions,
|
|
26282
|
+
allowCoordinatorSession: true
|
|
26283
|
+
}) || (typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "");
|
|
25625
26284
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
25626
26285
|
if (!cliType) {
|
|
25627
26286
|
const resolved = await resolveProviderTypeFromPriority({
|
|
@@ -25783,7 +26442,7 @@ ${block}`);
|
|
|
25783
26442
|
workspace
|
|
25784
26443
|
};
|
|
25785
26444
|
}
|
|
25786
|
-
const { existsSync:
|
|
26445
|
+
const { existsSync: existsSync26, readFileSync: readFileSync18, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
|
|
25787
26446
|
const { dirname: dirname9 } = await import("path");
|
|
25788
26447
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
25789
26448
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -25826,14 +26485,14 @@ ${block}`);
|
|
|
25826
26485
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
25827
26486
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
25828
26487
|
}
|
|
25829
|
-
const hadExistingMcpConfig =
|
|
26488
|
+
const hadExistingMcpConfig = existsSync26(mcpConfigPath);
|
|
25830
26489
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
25831
26490
|
if (hermesBaseConfig) {
|
|
25832
26491
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
|
|
25833
26492
|
}
|
|
25834
26493
|
if (hadExistingMcpConfig) {
|
|
25835
26494
|
try {
|
|
25836
|
-
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
26495
|
+
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync18(mcpConfigPath, "utf-8"), configFormat);
|
|
25837
26496
|
const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
|
|
25838
26497
|
existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
|
|
25839
26498
|
copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
|
|
@@ -25929,92 +26588,184 @@ ${block}`);
|
|
|
25929
26588
|
const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
25930
26589
|
const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
|
|
25931
26590
|
const ledgerSummary = getLedgerSummary2(meshId);
|
|
26591
|
+
const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
|
|
26592
|
+
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
26593
|
+
const localMachineId = loadConfig().machineId || "";
|
|
26594
|
+
const selectedCoordinatorNodeId = readStringValue(
|
|
26595
|
+
mesh.coordinator?.preferredNodeId,
|
|
26596
|
+
mesh.nodes?.[0]?.id,
|
|
26597
|
+
mesh.nodes?.[0]?.nodeId
|
|
26598
|
+
);
|
|
26599
|
+
const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes) ? selectedCoordinatorNodeId : void 0;
|
|
26600
|
+
const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25932
26601
|
const nodeStatuses = [];
|
|
25933
|
-
for (const node of mesh.nodes || []) {
|
|
26602
|
+
for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
|
|
26603
|
+
const nodeId = String(node.id || node.nodeId || "");
|
|
26604
|
+
const daemonId = readStringValue(node.daemonId);
|
|
26605
|
+
const providerPriority = readProviderPriorityFromPolicy(node.policy);
|
|
26606
|
+
const isSelfNode = Boolean(
|
|
26607
|
+
nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
|
|
26608
|
+
) || Boolean(
|
|
26609
|
+
daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
|
|
26610
|
+
) || Boolean(meshRecord?.inline && nodeIndex === 0);
|
|
25934
26611
|
const status = {
|
|
25935
|
-
nodeId
|
|
26612
|
+
nodeId,
|
|
25936
26613
|
machineLabel: node.machineLabel || node.id || node.nodeId,
|
|
25937
26614
|
workspace: node.workspace,
|
|
25938
26615
|
repoRoot: node.repoRoot,
|
|
25939
26616
|
isLocalWorktree: node.isLocalWorktree,
|
|
25940
26617
|
worktreeBranch: node.worktreeBranch,
|
|
25941
|
-
daemonId
|
|
26618
|
+
daemonId,
|
|
25942
26619
|
machineId: node.machineId,
|
|
26620
|
+
machineStatus: node.machineStatus,
|
|
25943
26621
|
health: "unknown",
|
|
25944
26622
|
providers: node.providers || [],
|
|
25945
|
-
|
|
26623
|
+
providerPriority,
|
|
26624
|
+
activeSessions: [],
|
|
26625
|
+
activeSessionDetails: [],
|
|
26626
|
+
launchReady: false
|
|
25946
26627
|
};
|
|
25947
|
-
if (
|
|
25948
|
-
|
|
25949
|
-
|
|
25950
|
-
|
|
26628
|
+
if (isSelfNode) {
|
|
26629
|
+
status.connection = {
|
|
26630
|
+
perspective: "selected_coordinator",
|
|
26631
|
+
source: "mesh_peer_status",
|
|
26632
|
+
state: "self",
|
|
26633
|
+
transport: "local",
|
|
26634
|
+
reported: true,
|
|
26635
|
+
reason: "Selected coordinator daemon",
|
|
26636
|
+
lastStateChangeAt: refreshedAt
|
|
26637
|
+
};
|
|
26638
|
+
} else if (daemonId) {
|
|
26639
|
+
const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
|
|
26640
|
+
status.connection = connection ?? {
|
|
26641
|
+
perspective: "selected_coordinator",
|
|
26642
|
+
source: "not_reported",
|
|
26643
|
+
state: "unknown",
|
|
26644
|
+
transport: "unknown",
|
|
26645
|
+
reported: false,
|
|
26646
|
+
reason: "No live mesh peer telemetry reported by the selected coordinator yet."
|
|
26647
|
+
};
|
|
26648
|
+
} else {
|
|
26649
|
+
status.connection = {
|
|
26650
|
+
perspective: "selected_coordinator",
|
|
26651
|
+
source: "not_reported",
|
|
26652
|
+
state: "unknown",
|
|
26653
|
+
transport: "unknown",
|
|
26654
|
+
reported: false,
|
|
26655
|
+
reason: "Node has no daemon id, so mesh transport cannot be reported from the selected coordinator."
|
|
26656
|
+
};
|
|
26657
|
+
}
|
|
26658
|
+
const matchedLiveSessionRecords = collectLiveMeshSessionRecords({
|
|
26659
|
+
meshId,
|
|
26660
|
+
node,
|
|
26661
|
+
nodeId,
|
|
26662
|
+
liveSessionRecords: liveMeshSessions,
|
|
26663
|
+
allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
|
|
26664
|
+
});
|
|
26665
|
+
const workspace = readLiveMeshNodeWorkspace({
|
|
26666
|
+
meshId,
|
|
26667
|
+
nodeId,
|
|
26668
|
+
liveSessionRecords: matchedLiveSessionRecords,
|
|
26669
|
+
allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
|
|
26670
|
+
}) || (typeof node.workspace === "string" ? node.workspace : "");
|
|
26671
|
+
status.workspace = workspace || node.workspace;
|
|
26672
|
+
if (matchedLiveSessionRecords.length > 0) {
|
|
26673
|
+
const sessionIds = matchedLiveSessionRecords.map((record) => typeof record?.sessionId === "string" ? record.sessionId : "").filter(Boolean);
|
|
26674
|
+
const providerTypes = matchedLiveSessionRecords.map((record) => readStringValue(record?.providerType)).filter(Boolean);
|
|
26675
|
+
status.activeSessions = sessionIds;
|
|
26676
|
+
status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
|
|
26677
|
+
if (providerTypes.length > 0) {
|
|
26678
|
+
status.providers = Array.from(/* @__PURE__ */ new Set([...Array.isArray(status.providers) ? status.providers : [], ...providerTypes]));
|
|
25951
26679
|
}
|
|
25952
|
-
|
|
25953
|
-
|
|
25954
|
-
|
|
25955
|
-
const
|
|
25956
|
-
|
|
25957
|
-
|
|
25958
|
-
|
|
25959
|
-
|
|
25960
|
-
|
|
25961
|
-
|
|
25962
|
-
|
|
25963
|
-
|
|
25964
|
-
|
|
25965
|
-
|
|
25966
|
-
|
|
25967
|
-
|
|
25968
|
-
|
|
25969
|
-
|
|
25970
|
-
|
|
25971
|
-
|
|
25972
|
-
|
|
25973
|
-
|
|
25974
|
-
|
|
25975
|
-
|
|
26680
|
+
}
|
|
26681
|
+
if (workspace) {
|
|
26682
|
+
if (!fs10.existsSync(workspace)) {
|
|
26683
|
+
const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
|
|
26684
|
+
let remoteProbeApplied = false;
|
|
26685
|
+
if (inlineTransitGit) {
|
|
26686
|
+
status.git = inlineTransitGit;
|
|
26687
|
+
status.health = inlineTransitGit.isGitRepo ? deriveMeshNodeHealthFromGit(inlineTransitGit) : "degraded";
|
|
26688
|
+
remoteProbeApplied = true;
|
|
26689
|
+
} else if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand) {
|
|
26690
|
+
try {
|
|
26691
|
+
const remoteGit = await probeRemoteMeshGitStatus({
|
|
26692
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
26693
|
+
daemonId,
|
|
26694
|
+
workspace,
|
|
26695
|
+
timeoutMs: 8e3
|
|
26696
|
+
});
|
|
26697
|
+
if (remoteGit) {
|
|
26698
|
+
status.git = remoteGit;
|
|
26699
|
+
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
26700
|
+
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
26701
|
+
remoteProbeApplied = true;
|
|
26702
|
+
}
|
|
26703
|
+
} catch {
|
|
26704
|
+
const refreshedConnection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
|
|
26705
|
+
const refreshedConnectionState = readStringValue(refreshedConnection?.state);
|
|
26706
|
+
if (refreshedConnection && refreshedConnectionState === "connected") {
|
|
26707
|
+
status.connection = refreshedConnection;
|
|
26708
|
+
try {
|
|
26709
|
+
const remoteGit = await probeRemoteMeshGitStatus({
|
|
26710
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
26711
|
+
daemonId,
|
|
26712
|
+
workspace,
|
|
26713
|
+
timeoutMs: 12e3
|
|
26714
|
+
});
|
|
26715
|
+
if (remoteGit) {
|
|
26716
|
+
status.git = remoteGit;
|
|
26717
|
+
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
26718
|
+
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
26719
|
+
remoteProbeApplied = true;
|
|
26720
|
+
}
|
|
26721
|
+
} catch {
|
|
26722
|
+
}
|
|
26723
|
+
}
|
|
25976
26724
|
}
|
|
25977
26725
|
}
|
|
25978
|
-
|
|
25979
|
-
|
|
25980
|
-
|
|
25981
|
-
|
|
25982
|
-
|
|
25983
|
-
|
|
25984
|
-
|
|
25985
|
-
if (
|
|
25986
|
-
|
|
25987
|
-
|
|
26726
|
+
if (!remoteProbeApplied) {
|
|
26727
|
+
const connectionState = readStringValue(status.connection?.state);
|
|
26728
|
+
const pendingPeerGitProbe = !inlineTransitGit && !isSelfNode && !!daemonId && (readStringValue(status.machineStatus) === "online" || readStringValue(status.health) === "online" || connectionState === "connecting" || connectionState === "connected" || connectionState === "unknown");
|
|
26729
|
+
if (pendingPeerGitProbe) {
|
|
26730
|
+
status.gitProbePending = true;
|
|
26731
|
+
status.health = "unknown";
|
|
26732
|
+
}
|
|
26733
|
+
if (applyCachedInlineMeshNodeStatus(
|
|
26734
|
+
status,
|
|
26735
|
+
node,
|
|
26736
|
+
pendingPeerGitProbe ? { skipGit: true, skipError: true, skipHealth: true } : void 0
|
|
26737
|
+
)) {
|
|
26738
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
26739
|
+
nodeStatuses.push(status);
|
|
26740
|
+
continue;
|
|
26741
|
+
}
|
|
26742
|
+
if (meshRecord?.source === "inline_cache" && !isSelfNode) {
|
|
26743
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
26744
|
+
nodeStatuses.push(status);
|
|
26745
|
+
continue;
|
|
26746
|
+
}
|
|
25988
26747
|
}
|
|
25989
|
-
|
|
25990
|
-
|
|
25991
|
-
|
|
25992
|
-
|
|
25993
|
-
|
|
25994
|
-
|
|
25995
|
-
|
|
25996
|
-
|
|
25997
|
-
|
|
25998
|
-
|
|
25999
|
-
|
|
26000
|
-
|
|
26001
|
-
|
|
26002
|
-
|
|
26003
|
-
|
|
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";
|
|
26748
|
+
} else {
|
|
26749
|
+
try {
|
|
26750
|
+
const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
26751
|
+
status.git = gitStatus;
|
|
26752
|
+
recordInlineMeshDirectGitTruth(node, gitStatus, "selected_coordinator_local_git");
|
|
26753
|
+
if (gitStatus.isGitRepo) {
|
|
26754
|
+
status.health = deriveMeshNodeHealthFromGit(gitStatus);
|
|
26755
|
+
} else {
|
|
26756
|
+
status.health = "degraded";
|
|
26757
|
+
if (gitStatus.error && !status.error) status.error = gitStatus.error;
|
|
26758
|
+
}
|
|
26759
|
+
} catch {
|
|
26760
|
+
if (!applyCachedInlineMeshNodeStatus(status, node)) {
|
|
26761
|
+
status.health = "degraded";
|
|
26762
|
+
}
|
|
26013
26763
|
}
|
|
26014
26764
|
}
|
|
26015
26765
|
} else {
|
|
26016
26766
|
applyCachedInlineMeshNodeStatus(status, node);
|
|
26017
26767
|
}
|
|
26768
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
26018
26769
|
nodeStatuses.push(status);
|
|
26019
26770
|
}
|
|
26020
26771
|
return {
|
|
@@ -26023,6 +26774,12 @@ ${block}`);
|
|
|
26023
26774
|
meshName: mesh.name,
|
|
26024
26775
|
repoIdentity: mesh.repoIdentity,
|
|
26025
26776
|
defaultBranch: mesh.defaultBranch,
|
|
26777
|
+
refreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26778
|
+
sourceOfTruth: {
|
|
26779
|
+
membership: meshRecord?.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord?.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
26780
|
+
coordinatorOwnsLiveTruth: meshRecord?.source !== "inline_bootstrap",
|
|
26781
|
+
historicalEvidenceOnly: ["recoveryHints", "ledger.summary", "queue.summary"]
|
|
26782
|
+
},
|
|
26026
26783
|
nodes: nodeStatuses,
|
|
26027
26784
|
queue: { tasks: queue, summary: queueSummary },
|
|
26028
26785
|
ledger: { entries: ledgerEntries, summary: ledgerSummary }
|
|
@@ -33957,6 +34714,7 @@ async function initDaemonComponents(config) {
|
|
|
33957
34714
|
sessionHostControl: config.sessionHostControl,
|
|
33958
34715
|
statusInstanceId: config.statusInstanceId,
|
|
33959
34716
|
statusVersion: config.statusVersion,
|
|
34717
|
+
getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
|
|
33960
34718
|
getCdpLogFn: config.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
|
|
33961
34719
|
});
|
|
33962
34720
|
poller = new AgentStreamPoller({
|
|
@@ -34231,6 +34989,7 @@ export {
|
|
|
34231
34989
|
prepareSessionChatTailUpdate,
|
|
34232
34990
|
prepareSessionModalUpdate,
|
|
34233
34991
|
probeCdpPort,
|
|
34992
|
+
queuePendingMeshCoordinatorEvent,
|
|
34234
34993
|
readChatHistory,
|
|
34235
34994
|
readLedgerEntries,
|
|
34236
34995
|
readLedgerSlice,
|