@adhdev/daemon-core 0.9.82-rc.4 → 0.9.82-rc.41
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 +11 -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 +1363 -311
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1362 -311
- 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 +1200 -169
- 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.js
CHANGED
|
@@ -1360,6 +1360,36 @@ function getQueuePath(meshId) {
|
|
|
1360
1360
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1361
1361
|
return (0, import_path4.join)(getLedgerDir(), `${safe}.queue.json`);
|
|
1362
1362
|
}
|
|
1363
|
+
function getLockPath(meshId) {
|
|
1364
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1365
|
+
return (0, import_path4.join)(getLedgerDir(), `${safe}.queue.lock`);
|
|
1366
|
+
}
|
|
1367
|
+
function withQueueLock(meshId, fn) {
|
|
1368
|
+
const lockPath = getLockPath(meshId);
|
|
1369
|
+
let fd = -1;
|
|
1370
|
+
for (let i = 0; i < 10; i++) {
|
|
1371
|
+
try {
|
|
1372
|
+
fd = (0, import_fs4.openSync)(lockPath, "wx");
|
|
1373
|
+
break;
|
|
1374
|
+
} catch {
|
|
1375
|
+
const deadline = Date.now() + 30;
|
|
1376
|
+
while (Date.now() < deadline) {
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
try {
|
|
1381
|
+
return fn();
|
|
1382
|
+
} finally {
|
|
1383
|
+
if (fd !== -1) try {
|
|
1384
|
+
(0, import_fs4.closeSync)(fd);
|
|
1385
|
+
} catch {
|
|
1386
|
+
}
|
|
1387
|
+
try {
|
|
1388
|
+
(0, import_fs4.unlinkSync)(lockPath);
|
|
1389
|
+
} catch {
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1363
1393
|
function readQueue(meshId) {
|
|
1364
1394
|
const path28 = getQueuePath(meshId);
|
|
1365
1395
|
if (!(0, import_fs4.existsSync)(path28)) return [];
|
|
@@ -1375,20 +1405,22 @@ function writeQueue(meshId, queue) {
|
|
|
1375
1405
|
(0, import_fs4.writeFileSync)(path28, JSON.stringify(queue, null, 2), "utf-8");
|
|
1376
1406
|
}
|
|
1377
1407
|
function enqueueTask(meshId, message, opts) {
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1408
|
+
return withQueueLock(meshId, () => {
|
|
1409
|
+
const queue = readQueue(meshId);
|
|
1410
|
+
const entry = {
|
|
1411
|
+
id: (0, import_crypto5.randomUUID)(),
|
|
1412
|
+
meshId,
|
|
1413
|
+
message,
|
|
1414
|
+
status: "pending",
|
|
1415
|
+
targetNodeId: opts?.targetNodeId,
|
|
1416
|
+
targetSessionId: opts?.targetSessionId,
|
|
1417
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1418
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1419
|
+
};
|
|
1420
|
+
queue.push(entry);
|
|
1421
|
+
writeQueue(meshId, queue);
|
|
1422
|
+
return entry;
|
|
1423
|
+
});
|
|
1392
1424
|
}
|
|
1393
1425
|
function getQueue(meshId, opts) {
|
|
1394
1426
|
let queue = readQueue(meshId);
|
|
@@ -1399,100 +1431,111 @@ function getQueue(meshId, opts) {
|
|
|
1399
1431
|
return queue;
|
|
1400
1432
|
}
|
|
1401
1433
|
function claimNextTask(meshId, nodeId, sessionId) {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1434
|
+
return withQueueLock(meshId, () => {
|
|
1435
|
+
const queue = readQueue(meshId);
|
|
1436
|
+
const hasActiveAssignment = queue.some((q) => q.status === "assigned" && (q.assignedSessionId === sessionId || q.assignedNodeId === nodeId));
|
|
1437
|
+
if (hasActiveAssignment) return null;
|
|
1438
|
+
let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetSessionId === sessionId);
|
|
1439
|
+
if (targetIdx === -1) {
|
|
1440
|
+
targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId && !q.targetSessionId);
|
|
1441
|
+
}
|
|
1442
|
+
if (targetIdx === -1) {
|
|
1443
|
+
targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId && !q.targetSessionId);
|
|
1444
|
+
}
|
|
1445
|
+
if (targetIdx === -1) return null;
|
|
1446
|
+
const entry = queue[targetIdx];
|
|
1447
|
+
entry.status = "assigned";
|
|
1448
|
+
entry.assignedNodeId = nodeId;
|
|
1449
|
+
entry.assignedSessionId = sessionId;
|
|
1450
|
+
entry.dispatchTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1451
|
+
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1452
|
+
writeQueue(meshId, queue);
|
|
1453
|
+
return entry;
|
|
1454
|
+
});
|
|
1421
1455
|
}
|
|
1422
1456
|
function updateTaskStatus(meshId, taskId, status) {
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1457
|
+
return withQueueLock(meshId, () => {
|
|
1458
|
+
const queue = readQueue(meshId);
|
|
1459
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
1460
|
+
if (idx === -1) return null;
|
|
1461
|
+
queue[idx].status = status;
|
|
1462
|
+
queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1463
|
+
writeQueue(meshId, queue);
|
|
1464
|
+
return queue[idx];
|
|
1465
|
+
});
|
|
1430
1466
|
}
|
|
1431
1467
|
function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
...autoLaunch,
|
|
1438
|
-
updatedAt
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
return queue[idx];
|
|
1468
|
+
return withQueueLock(meshId, () => {
|
|
1469
|
+
const queue = readQueue(meshId);
|
|
1470
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
1471
|
+
if (idx === -1) return null;
|
|
1472
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1473
|
+
queue[idx].autoLaunch = { ...autoLaunch, updatedAt: now };
|
|
1474
|
+
queue[idx].updatedAt = now;
|
|
1475
|
+
writeQueue(meshId, queue);
|
|
1476
|
+
return queue[idx];
|
|
1477
|
+
});
|
|
1443
1478
|
}
|
|
1444
1479
|
function cancelTask(meshId, taskId, opts) {
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1480
|
+
return withQueueLock(meshId, () => {
|
|
1481
|
+
const queue = readQueue(meshId);
|
|
1482
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
1483
|
+
if (idx === -1) return null;
|
|
1484
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1485
|
+
queue[idx].status = "cancelled";
|
|
1486
|
+
queue[idx].updatedAt = now;
|
|
1487
|
+
queue[idx].cancelledAt = now;
|
|
1488
|
+
if (opts?.reason) queue[idx].cancelReason = opts.reason;
|
|
1489
|
+
writeQueue(meshId, queue);
|
|
1490
|
+
return queue[idx];
|
|
1491
|
+
});
|
|
1455
1492
|
}
|
|
1456
1493
|
function requeueTask(meshId, taskId, opts) {
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1494
|
+
return withQueueLock(meshId, () => {
|
|
1495
|
+
const queue = readQueue(meshId);
|
|
1496
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
1497
|
+
if (idx === -1) return null;
|
|
1498
|
+
const entry = queue[idx];
|
|
1499
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1500
|
+
entry.status = "pending";
|
|
1501
|
+
delete entry.assignedNodeId;
|
|
1502
|
+
delete entry.assignedSessionId;
|
|
1503
|
+
delete entry.cancelledAt;
|
|
1504
|
+
delete entry.cancelReason;
|
|
1505
|
+
if (opts?.clearTargetNode) delete entry.targetNodeId;
|
|
1506
|
+
if (typeof opts?.targetNodeId === "string") entry.targetNodeId = opts.targetNodeId;
|
|
1507
|
+
if (opts?.clearTargetSession !== false) delete entry.targetSessionId;
|
|
1508
|
+
if (typeof opts?.targetSessionId === "string") entry.targetSessionId = opts.targetSessionId;
|
|
1509
|
+
entry.updatedAt = now;
|
|
1510
|
+
entry.requeuedAt = now;
|
|
1511
|
+
entry.requeueCount = (entry.requeueCount || 0) + 1;
|
|
1512
|
+
if (opts?.reason) entry.requeueReason = opts.reason;
|
|
1513
|
+
writeQueue(meshId, queue);
|
|
1514
|
+
return entry;
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
function updateSessionTaskStatus(meshId, sessionId, status, opts) {
|
|
1518
|
+
return withQueueLock(meshId, () => {
|
|
1519
|
+
const queue = readQueue(meshId);
|
|
1520
|
+
const occurredAtTime = opts?.occurredAt ? new Date(opts.occurredAt).getTime() : Number.NaN;
|
|
1521
|
+
const hasOccurredAt = Number.isFinite(occurredAtTime);
|
|
1522
|
+
let bestIdx = -1;
|
|
1523
|
+
let bestTime = 0;
|
|
1524
|
+
for (let i = queue.length - 1; i >= 0; i--) {
|
|
1525
|
+
if (queue[i].assignedSessionId !== sessionId || queue[i].status !== "assigned") continue;
|
|
1484
1526
|
const time = new Date(queue[i].dispatchTimestamp || queue[i].updatedAt).getTime();
|
|
1527
|
+
if (hasOccurredAt && Number.isFinite(time) && time > occurredAtTime) continue;
|
|
1485
1528
|
if (time > bestTime) {
|
|
1486
1529
|
bestTime = time;
|
|
1487
1530
|
bestIdx = i;
|
|
1488
1531
|
}
|
|
1489
1532
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1533
|
+
if (bestIdx === -1) return null;
|
|
1534
|
+
queue[bestIdx].status = status;
|
|
1535
|
+
queue[bestIdx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1536
|
+
writeQueue(meshId, queue);
|
|
1537
|
+
return queue[bestIdx];
|
|
1538
|
+
});
|
|
1496
1539
|
}
|
|
1497
1540
|
function getMeshQueueStats(meshId) {
|
|
1498
1541
|
const queue = readQueue(meshId);
|
|
@@ -1896,18 +1939,75 @@ __export(mesh_events_exports, {
|
|
|
1896
1939
|
drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
|
|
1897
1940
|
getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
|
|
1898
1941
|
handleMeshForwardEvent: () => handleMeshForwardEvent,
|
|
1942
|
+
queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
|
|
1899
1943
|
setupMeshEventForwarding: () => setupMeshEventForwarding,
|
|
1900
1944
|
triggerMeshQueue: () => triggerMeshQueue,
|
|
1901
1945
|
tryAssignQueueTask: () => tryAssignQueueTask
|
|
1902
1946
|
});
|
|
1903
|
-
function
|
|
1904
|
-
|
|
1947
|
+
function sweepExpiredRemoteIdleSessions() {
|
|
1948
|
+
const now = Date.now();
|
|
1949
|
+
for (const [key, session] of remoteIdleSessions) {
|
|
1950
|
+
if (session.expiresAt <= now) remoteIdleSessions.delete(key);
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
function getPendingEventsPath(meshId) {
|
|
1954
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1955
|
+
return (0, import_path5.join)(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
1905
1956
|
}
|
|
1906
|
-
function
|
|
1907
|
-
|
|
1957
|
+
function queuePendingMeshCoordinatorEvent(event) {
|
|
1958
|
+
try {
|
|
1959
|
+
(0, import_fs6.appendFileSync)(getPendingEventsPath(event.meshId), JSON.stringify(event) + "\n", "utf-8");
|
|
1960
|
+
return true;
|
|
1961
|
+
} catch (e) {
|
|
1962
|
+
LOG.warn("MeshEvents", `Failed to persist pending coordinator event: ${e?.message || e}`);
|
|
1963
|
+
return false;
|
|
1964
|
+
}
|
|
1908
1965
|
}
|
|
1909
|
-
function
|
|
1910
|
-
|
|
1966
|
+
function drainPendingMeshCoordinatorEvents(meshId) {
|
|
1967
|
+
if (!meshId) return [];
|
|
1968
|
+
const path28 = getPendingEventsPath(meshId);
|
|
1969
|
+
if (!(0, import_fs6.existsSync)(path28)) return [];
|
|
1970
|
+
try {
|
|
1971
|
+
const raw = (0, import_fs6.readFileSync)(path28, "utf-8");
|
|
1972
|
+
try {
|
|
1973
|
+
(0, import_fs6.unlinkSync)(path28);
|
|
1974
|
+
} catch {
|
|
1975
|
+
}
|
|
1976
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
1977
|
+
try {
|
|
1978
|
+
return [JSON.parse(line)];
|
|
1979
|
+
} catch {
|
|
1980
|
+
return [];
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
} catch {
|
|
1984
|
+
return [];
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
function getPendingMeshCoordinatorEvents(meshId) {
|
|
1988
|
+
if (!meshId) return [];
|
|
1989
|
+
const path28 = getPendingEventsPath(meshId);
|
|
1990
|
+
if (!(0, import_fs6.existsSync)(path28)) return [];
|
|
1991
|
+
try {
|
|
1992
|
+
const raw = (0, import_fs6.readFileSync)(path28, "utf-8");
|
|
1993
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
1994
|
+
try {
|
|
1995
|
+
return [JSON.parse(line)];
|
|
1996
|
+
} catch {
|
|
1997
|
+
return [];
|
|
1998
|
+
}
|
|
1999
|
+
});
|
|
2000
|
+
} catch {
|
|
2001
|
+
return [];
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
function clearPendingMeshCoordinatorEvents(meshId) {
|
|
2005
|
+
if (!meshId) return;
|
|
2006
|
+
const path28 = getPendingEventsPath(meshId);
|
|
2007
|
+
if ((0, import_fs6.existsSync)(path28)) try {
|
|
2008
|
+
(0, import_fs6.unlinkSync)(path28);
|
|
2009
|
+
} catch {
|
|
2010
|
+
}
|
|
1911
2011
|
}
|
|
1912
2012
|
function readNonEmptyString(value) {
|
|
1913
2013
|
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
@@ -1953,6 +2053,38 @@ function shouldSuppressIntentionalCleanupStop(args) {
|
|
|
1953
2053
|
if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
|
|
1954
2054
|
return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
|
|
1955
2055
|
}
|
|
2056
|
+
function readEventTimestamp(value) {
|
|
2057
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2058
|
+
if (typeof value === "string" && value.trim()) {
|
|
2059
|
+
const numeric = Number(value);
|
|
2060
|
+
if (Number.isFinite(numeric)) return numeric;
|
|
2061
|
+
const parsed = Date.parse(value);
|
|
2062
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
2063
|
+
}
|
|
2064
|
+
return null;
|
|
2065
|
+
}
|
|
2066
|
+
function buildMeshCompletionFingerprint(args) {
|
|
2067
|
+
const timestampPart = Number.isFinite(args.timestamp) ? String(args.timestamp) : readNonEmptyString(args.finalSummary).slice(0, 200);
|
|
2068
|
+
return [
|
|
2069
|
+
args.meshId,
|
|
2070
|
+
args.event,
|
|
2071
|
+
args.sessionId,
|
|
2072
|
+
args.providerType || "",
|
|
2073
|
+
args.providerSessionId || "",
|
|
2074
|
+
timestampPart
|
|
2075
|
+
].join("::");
|
|
2076
|
+
}
|
|
2077
|
+
function isDuplicateMeshCompletionEvent(args) {
|
|
2078
|
+
const fingerprint = buildMeshCompletionFingerprint(args);
|
|
2079
|
+
if (!fingerprint) return false;
|
|
2080
|
+
const now = Date.now();
|
|
2081
|
+
for (const [key, seenAt] of recentCompletionFingerprints.entries()) {
|
|
2082
|
+
if (now - seenAt > RECENT_COMPLETION_FINGERPRINT_TTL_MS) recentCompletionFingerprints.delete(key);
|
|
2083
|
+
}
|
|
2084
|
+
if (recentCompletionFingerprints.has(fingerprint)) return true;
|
|
2085
|
+
recentCompletionFingerprints.set(fingerprint, now);
|
|
2086
|
+
return false;
|
|
2087
|
+
}
|
|
1956
2088
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
1957
2089
|
const task = claimNextTask(meshId, nodeId, sessionId);
|
|
1958
2090
|
if (!task) {
|
|
@@ -1971,7 +2103,16 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
1971
2103
|
message: task.message
|
|
1972
2104
|
}).catch((e) => {
|
|
1973
2105
|
LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
|
|
1974
|
-
updateTaskStatus(meshId, task.id, "
|
|
2106
|
+
updateTaskStatus(meshId, task.id, "pending");
|
|
2107
|
+
try {
|
|
2108
|
+
appendLedgerEntry(meshId, {
|
|
2109
|
+
kind: "dispatch_failed",
|
|
2110
|
+
nodeId,
|
|
2111
|
+
sessionId,
|
|
2112
|
+
payload: { taskId: task.id, error: e?.message, retryable: true }
|
|
2113
|
+
});
|
|
2114
|
+
} catch {
|
|
2115
|
+
}
|
|
1975
2116
|
});
|
|
1976
2117
|
return true;
|
|
1977
2118
|
}
|
|
@@ -2305,18 +2446,36 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2305
2446
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
2306
2447
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
2307
2448
|
}
|
|
2449
|
+
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
2450
|
+
if (args.event === "agent:generating_completed" && eventSessionId) {
|
|
2451
|
+
const duplicateCompletion = isDuplicateMeshCompletionEvent({
|
|
2452
|
+
meshId: args.meshId,
|
|
2453
|
+
event: args.event,
|
|
2454
|
+
sessionId: eventSessionId,
|
|
2455
|
+
providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
|
|
2456
|
+
providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
|
|
2457
|
+
timestamp: eventTimestamp,
|
|
2458
|
+
finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
|
|
2459
|
+
});
|
|
2460
|
+
if (duplicateCompletion) {
|
|
2461
|
+
LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
2462
|
+
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2308
2465
|
let completedTaskForLedger = null;
|
|
2309
2466
|
if (args.event === "agent:generating_completed") {
|
|
2310
2467
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
2311
2468
|
const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
|
|
2312
2469
|
const providerType = readNonEmptyString(args.metadataEvent.providerType);
|
|
2313
2470
|
if (sessionId) {
|
|
2314
|
-
const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed"
|
|
2471
|
+
const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed", {
|
|
2472
|
+
occurredAt: eventTimestamp !== null ? new Date(eventTimestamp).toISOString() : void 0
|
|
2473
|
+
});
|
|
2315
2474
|
completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
|
|
2316
2475
|
if (nodeId && providerType) {
|
|
2317
|
-
|
|
2476
|
+
setImmediate(() => {
|
|
2318
2477
|
tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
2319
|
-
}
|
|
2478
|
+
});
|
|
2320
2479
|
}
|
|
2321
2480
|
}
|
|
2322
2481
|
} else if (args.event === "agent:ready") {
|
|
@@ -2354,13 +2513,17 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2354
2513
|
}
|
|
2355
2514
|
}
|
|
2356
2515
|
if (sessionId && nodeId && providerType) {
|
|
2357
|
-
|
|
2358
|
-
|
|
2516
|
+
sweepExpiredRemoteIdleSessions();
|
|
2517
|
+
remoteIdleSessions.set(`${nodeId}:${sessionId}`, {
|
|
2518
|
+
nodeId,
|
|
2519
|
+
sessionId,
|
|
2520
|
+
providerType,
|
|
2521
|
+
expiresAt: Date.now() + REMOTE_IDLE_SESSION_TTL_MS
|
|
2522
|
+
});
|
|
2523
|
+
setImmediate(() => {
|
|
2359
2524
|
const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
2360
|
-
if (assigned) {
|
|
2361
|
-
|
|
2362
|
-
}
|
|
2363
|
-
}, 500);
|
|
2525
|
+
if (assigned) remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
|
|
2526
|
+
});
|
|
2364
2527
|
}
|
|
2365
2528
|
} else if (args.event === "agent:generating_started") {
|
|
2366
2529
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
@@ -2471,17 +2634,18 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2471
2634
|
return true;
|
|
2472
2635
|
});
|
|
2473
2636
|
if (coordinatorInstances.length === 0) {
|
|
2474
|
-
if (
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
}
|
|
2483
|
-
|
|
2484
|
-
|
|
2637
|
+
if (queuePendingMeshCoordinatorEvent({
|
|
2638
|
+
event: args.event,
|
|
2639
|
+
meshId: args.meshId,
|
|
2640
|
+
nodeLabel: args.nodeLabel,
|
|
2641
|
+
nodeId: args.nodeId || void 0,
|
|
2642
|
+
workspace: readNonEmptyString(args.metadataEvent.workspace),
|
|
2643
|
+
metadataEvent: {
|
|
2644
|
+
...args.metadataEvent,
|
|
2645
|
+
...recoveryContext ? { recoveryContext } : {}
|
|
2646
|
+
},
|
|
2647
|
+
queuedAt: Date.now()
|
|
2648
|
+
})) {
|
|
2485
2649
|
LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
|
|
2486
2650
|
}
|
|
2487
2651
|
return { success: true, forwarded: 0 };
|
|
@@ -2520,6 +2684,7 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
2520
2684
|
providerType: readNonEmptyString(payload.providerType),
|
|
2521
2685
|
providerSessionId: readNonEmptyString(payload.providerSessionId),
|
|
2522
2686
|
finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
|
|
2687
|
+
...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
|
|
2523
2688
|
intentional: payload.intentional === true,
|
|
2524
2689
|
intentionalStop: payload.intentionalStop === true,
|
|
2525
2690
|
operatorCleanup: payload.operatorCleanup === true,
|
|
@@ -2562,19 +2727,20 @@ function setupMeshEventForwarding(components) {
|
|
|
2562
2727
|
});
|
|
2563
2728
|
});
|
|
2564
2729
|
}
|
|
2565
|
-
var
|
|
2730
|
+
var import_fs6, import_path5, REMOTE_IDLE_SESSION_TTL_MS, remoteIdleSessions, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, recentCompletionFingerprints, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
|
|
2566
2731
|
var init_mesh_events = __esm({
|
|
2567
2732
|
"src/mesh/mesh-events.ts"() {
|
|
2568
2733
|
"use strict";
|
|
2734
|
+
import_fs6 = require("fs");
|
|
2735
|
+
import_path5 = require("path");
|
|
2569
2736
|
init_config();
|
|
2570
2737
|
init_mesh_config();
|
|
2571
2738
|
init_cli_detector();
|
|
2572
2739
|
init_logger();
|
|
2573
2740
|
init_mesh_ledger();
|
|
2574
2741
|
init_mesh_work_queue();
|
|
2742
|
+
REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
|
|
2575
2743
|
remoteIdleSessions = /* @__PURE__ */ new Map();
|
|
2576
|
-
MAX_PENDING_EVENTS = 50;
|
|
2577
|
-
pendingMeshCoordinatorEvents = [];
|
|
2578
2744
|
MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
|
|
2579
2745
|
"agent:generating_started",
|
|
2580
2746
|
"agent:generating_completed",
|
|
@@ -2590,6 +2756,8 @@ var init_mesh_events = __esm({
|
|
|
2590
2756
|
"monitor:long_generating": "task_stalled"
|
|
2591
2757
|
};
|
|
2592
2758
|
INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
|
|
2759
|
+
RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
|
|
2760
|
+
recentCompletionFingerprints = /* @__PURE__ */ new Map();
|
|
2593
2761
|
autoLaunchInProgress = /* @__PURE__ */ new Set();
|
|
2594
2762
|
autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
|
|
2595
2763
|
AUTO_LAUNCH_COOLDOWN_MS = 5e3;
|
|
@@ -5860,6 +6028,7 @@ __export(index_exports, {
|
|
|
5860
6028
|
prepareSessionChatTailUpdate: () => prepareSessionChatTailUpdate,
|
|
5861
6029
|
prepareSessionModalUpdate: () => prepareSessionModalUpdate,
|
|
5862
6030
|
probeCdpPort: () => probeCdpPort,
|
|
6031
|
+
queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
|
|
5863
6032
|
readChatHistory: () => readChatHistory,
|
|
5864
6033
|
readLedgerEntries: () => readLedgerEntries,
|
|
5865
6034
|
readLedgerSlice: () => readLedgerSlice,
|
|
@@ -5913,8 +6082,14 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5913
6082
|
const includeSubmodules = options.includeSubmodules !== false;
|
|
5914
6083
|
try {
|
|
5915
6084
|
const repo = await resolveGitRepository(workspace, options);
|
|
5916
|
-
|
|
5917
|
-
|
|
6085
|
+
let parsed = await readPorcelainStatus(repo, options);
|
|
6086
|
+
let upstreamProbe = getInitialUpstreamProbe(parsed);
|
|
6087
|
+
if (options.refreshUpstream) {
|
|
6088
|
+
upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
|
|
6089
|
+
if (upstreamProbe.upstreamStatus === "fresh") {
|
|
6090
|
+
parsed = await readPorcelainStatus(repo, options);
|
|
6091
|
+
}
|
|
6092
|
+
}
|
|
5918
6093
|
const head = await readHead(repo, options);
|
|
5919
6094
|
const stashCount = await readStashCount(repo, options);
|
|
5920
6095
|
let submodules;
|
|
@@ -5929,6 +6104,9 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5929
6104
|
headCommit: head.commit,
|
|
5930
6105
|
headMessage: head.message,
|
|
5931
6106
|
upstream: parsed.upstream,
|
|
6107
|
+
upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
|
|
6108
|
+
upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
|
|
6109
|
+
upstreamFetchError: upstreamProbe.upstreamFetchError,
|
|
5932
6110
|
ahead: parsed.ahead,
|
|
5933
6111
|
behind: parsed.behind,
|
|
5934
6112
|
staged: parsed.staged,
|
|
@@ -5953,6 +6131,60 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5953
6131
|
);
|
|
5954
6132
|
}
|
|
5955
6133
|
}
|
|
6134
|
+
async function readPorcelainStatus(repo, options) {
|
|
6135
|
+
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
6136
|
+
return parsePorcelainV2Status(statusOutput.stdout);
|
|
6137
|
+
}
|
|
6138
|
+
function getInitialUpstreamProbe(parsed) {
|
|
6139
|
+
return {
|
|
6140
|
+
upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
|
|
6141
|
+
};
|
|
6142
|
+
}
|
|
6143
|
+
async function refreshTrackedUpstream(repo, parsed, options) {
|
|
6144
|
+
if (!parsed.upstream || !parsed.branch) {
|
|
6145
|
+
return { upstreamStatus: "no_upstream" };
|
|
6146
|
+
}
|
|
6147
|
+
const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
|
|
6148
|
+
if (!remoteName) {
|
|
6149
|
+
return {
|
|
6150
|
+
upstreamStatus: "stale",
|
|
6151
|
+
upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
|
|
6152
|
+
};
|
|
6153
|
+
}
|
|
6154
|
+
try {
|
|
6155
|
+
await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
|
|
6156
|
+
return {
|
|
6157
|
+
upstreamStatus: "fresh",
|
|
6158
|
+
upstreamFetchedAt: Date.now()
|
|
6159
|
+
};
|
|
6160
|
+
} catch (error) {
|
|
6161
|
+
return {
|
|
6162
|
+
upstreamStatus: "stale",
|
|
6163
|
+
upstreamFetchError: formatGitError(error)
|
|
6164
|
+
};
|
|
6165
|
+
}
|
|
6166
|
+
}
|
|
6167
|
+
async function readBranchRemote(repo, branch, options) {
|
|
6168
|
+
try {
|
|
6169
|
+
const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
|
|
6170
|
+
return result.stdout.trim() || null;
|
|
6171
|
+
} catch {
|
|
6172
|
+
return null;
|
|
6173
|
+
}
|
|
6174
|
+
}
|
|
6175
|
+
function inferRemoteName(upstream) {
|
|
6176
|
+
const [remoteName] = upstream.split("/");
|
|
6177
|
+
return remoteName?.trim() || null;
|
|
6178
|
+
}
|
|
6179
|
+
function formatGitError(error) {
|
|
6180
|
+
if (error instanceof GitCommandError) {
|
|
6181
|
+
return error.stderr || error.message;
|
|
6182
|
+
}
|
|
6183
|
+
if (error instanceof Error) {
|
|
6184
|
+
return error.message;
|
|
6185
|
+
}
|
|
6186
|
+
return String(error);
|
|
6187
|
+
}
|
|
5956
6188
|
function parsePorcelainV2Status(output) {
|
|
5957
6189
|
const parsed = {
|
|
5958
6190
|
branch: null,
|
|
@@ -6047,6 +6279,7 @@ function emptyStatus(workspace, lastCheckedAt, error) {
|
|
|
6047
6279
|
headCommit: null,
|
|
6048
6280
|
headMessage: null,
|
|
6049
6281
|
upstream: null,
|
|
6282
|
+
upstreamStatus: "unavailable",
|
|
6050
6283
|
ahead: 0,
|
|
6051
6284
|
behind: 0,
|
|
6052
6285
|
staged: 0,
|
|
@@ -6327,6 +6560,9 @@ function createGitCompactSummary(status, diffSummary) {
|
|
|
6327
6560
|
isGitRepo: status.isGitRepo,
|
|
6328
6561
|
repoRoot: status.repoRoot,
|
|
6329
6562
|
branch: status.branch,
|
|
6563
|
+
upstreamStatus: status.upstreamStatus,
|
|
6564
|
+
upstreamFetchedAt: status.upstreamFetchedAt,
|
|
6565
|
+
upstreamFetchError: status.upstreamFetchError,
|
|
6330
6566
|
dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
|
|
6331
6567
|
changedFiles,
|
|
6332
6568
|
ahead: status.ahead,
|
|
@@ -6671,7 +6907,7 @@ var defaultSnapshotStore = createGitSnapshotStore({
|
|
|
6671
6907
|
});
|
|
6672
6908
|
function createDefaultGitCommandServices() {
|
|
6673
6909
|
return {
|
|
6674
|
-
getStatus: ({ workspace }) => getGitRepoStatus(workspace),
|
|
6910
|
+
getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
|
|
6675
6911
|
getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
|
|
6676
6912
|
getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
|
|
6677
6913
|
createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
|
|
@@ -6757,7 +6993,7 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
|
|
|
6757
6993
|
switch (command) {
|
|
6758
6994
|
case "git_status": {
|
|
6759
6995
|
if (!services.getStatus) return serviceNotImplemented(command);
|
|
6760
|
-
const status = await runService(() => services.getStatus({ workspace }));
|
|
6996
|
+
const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
|
|
6761
6997
|
return "success" in status ? status : { success: true, status };
|
|
6762
6998
|
}
|
|
6763
6999
|
case "git_diff_summary": {
|
|
@@ -7795,8 +8031,8 @@ var P2pRelayFailureError = class extends Error {
|
|
|
7795
8031
|
};
|
|
7796
8032
|
|
|
7797
8033
|
// src/config/state-store.ts
|
|
7798
|
-
var
|
|
7799
|
-
var
|
|
8034
|
+
var import_fs7 = require("fs");
|
|
8035
|
+
var import_path6 = require("path");
|
|
7800
8036
|
init_config();
|
|
7801
8037
|
var DEFAULT_STATE = {
|
|
7802
8038
|
recentActivity: [],
|
|
@@ -7810,7 +8046,7 @@ function isPlainObject2(value) {
|
|
|
7810
8046
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
7811
8047
|
}
|
|
7812
8048
|
function getStatePath() {
|
|
7813
|
-
return (0,
|
|
8049
|
+
return (0, import_path6.join)(getConfigDir(), "state.json");
|
|
7814
8050
|
}
|
|
7815
8051
|
function normalizeState(raw) {
|
|
7816
8052
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -7846,11 +8082,11 @@ function normalizeState(raw) {
|
|
|
7846
8082
|
}
|
|
7847
8083
|
function loadState() {
|
|
7848
8084
|
const statePath = getStatePath();
|
|
7849
|
-
if (!(0,
|
|
8085
|
+
if (!(0, import_fs7.existsSync)(statePath)) {
|
|
7850
8086
|
return { ...DEFAULT_STATE };
|
|
7851
8087
|
}
|
|
7852
8088
|
try {
|
|
7853
|
-
const raw = (0,
|
|
8089
|
+
const raw = (0, import_fs7.readFileSync)(statePath, "utf-8");
|
|
7854
8090
|
return normalizeState(JSON.parse(raw));
|
|
7855
8091
|
} catch {
|
|
7856
8092
|
return { ...DEFAULT_STATE };
|
|
@@ -7859,7 +8095,7 @@ function loadState() {
|
|
|
7859
8095
|
function saveState(state) {
|
|
7860
8096
|
const statePath = getStatePath();
|
|
7861
8097
|
const normalized = normalizeState(state);
|
|
7862
|
-
(0,
|
|
8098
|
+
(0, import_fs7.writeFileSync)(statePath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
7863
8099
|
}
|
|
7864
8100
|
function resetState() {
|
|
7865
8101
|
saveState({ ...DEFAULT_STATE });
|
|
@@ -7867,7 +8103,7 @@ function resetState() {
|
|
|
7867
8103
|
|
|
7868
8104
|
// src/detection/ide-detector.ts
|
|
7869
8105
|
var import_child_process2 = require("child_process");
|
|
7870
|
-
var
|
|
8106
|
+
var import_fs8 = require("fs");
|
|
7871
8107
|
var import_os2 = require("os");
|
|
7872
8108
|
var path10 = __toESM(require("path"));
|
|
7873
8109
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
@@ -7891,7 +8127,7 @@ function findCliCommand(command) {
|
|
|
7891
8127
|
if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
7892
8128
|
const candidate = trimmed.startsWith("~") ? path10.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
|
|
7893
8129
|
const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
|
|
7894
|
-
return (0,
|
|
8130
|
+
return (0, import_fs8.existsSync)(resolved) ? resolved : null;
|
|
7895
8131
|
}
|
|
7896
8132
|
try {
|
|
7897
8133
|
const result = (0, import_child_process2.execSync)(
|
|
@@ -7922,9 +8158,9 @@ function checkPathExists(paths) {
|
|
|
7922
8158
|
if (normalized.includes("*")) {
|
|
7923
8159
|
const username = home.split(/[\\/]/).pop() || "";
|
|
7924
8160
|
const resolved = normalized.replace("*", username);
|
|
7925
|
-
if ((0,
|
|
8161
|
+
if ((0, import_fs8.existsSync)(resolved)) return resolved;
|
|
7926
8162
|
} else {
|
|
7927
|
-
if ((0,
|
|
8163
|
+
if ((0, import_fs8.existsSync)(normalized)) return normalized;
|
|
7928
8164
|
}
|
|
7929
8165
|
}
|
|
7930
8166
|
return null;
|
|
@@ -7938,7 +8174,7 @@ async function detectIDEs(providerLoader) {
|
|
|
7938
8174
|
let resolvedCli = cliPath;
|
|
7939
8175
|
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
7940
8176
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
7941
|
-
if ((0,
|
|
8177
|
+
if ((0, import_fs8.existsSync)(bundledCli)) resolvedCli = bundledCli;
|
|
7942
8178
|
}
|
|
7943
8179
|
if (!resolvedCli && appPath && os22 === "win32") {
|
|
7944
8180
|
const { dirname: dirname9 } = await import("path");
|
|
@@ -7951,7 +8187,7 @@ async function detectIDEs(providerLoader) {
|
|
|
7951
8187
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
7952
8188
|
];
|
|
7953
8189
|
for (const c of candidates) {
|
|
7954
|
-
if ((0,
|
|
8190
|
+
if ((0, import_fs8.existsSync)(c)) {
|
|
7955
8191
|
resolvedCli = c;
|
|
7956
8192
|
break;
|
|
7957
8193
|
}
|
|
@@ -9843,7 +10079,8 @@ var StatusMonitor = class {
|
|
|
9843
10079
|
};
|
|
9844
10080
|
|
|
9845
10081
|
// src/providers/chat-message-normalization.ts
|
|
9846
|
-
|
|
10082
|
+
var DEFAULT_FINAL_SUMMARY_MAX_CHARS = 4e3;
|
|
10083
|
+
function extractFinalSummaryFromMessages(messages, maxChars = DEFAULT_FINAL_SUMMARY_MAX_CHARS) {
|
|
9847
10084
|
if (!Array.isArray(messages) || messages.length === 0) return "";
|
|
9848
10085
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
9849
10086
|
const msg = messages[i];
|
|
@@ -17103,7 +17340,7 @@ var DaemonCommandHandler = class {
|
|
|
17103
17340
|
var os13 = __toESM(require("os"));
|
|
17104
17341
|
var path18 = __toESM(require("path"));
|
|
17105
17342
|
var crypto4 = __toESM(require("crypto"));
|
|
17106
|
-
var
|
|
17343
|
+
var import_fs9 = require("fs");
|
|
17107
17344
|
var import_child_process6 = require("child_process");
|
|
17108
17345
|
var import_chalk = __toESM(require("chalk"));
|
|
17109
17346
|
init_provider_cli_adapter();
|
|
@@ -19575,7 +19812,7 @@ function commandExists(command) {
|
|
|
19575
19812
|
const trimmed = command.trim();
|
|
19576
19813
|
if (!trimmed) return false;
|
|
19577
19814
|
if (isExplicitCommand(trimmed)) {
|
|
19578
|
-
return (0,
|
|
19815
|
+
return (0, import_fs9.existsSync)(expandExecutable(trimmed));
|
|
19579
19816
|
}
|
|
19580
19817
|
try {
|
|
19581
19818
|
(0, import_child_process6.execFileSync)(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -19604,10 +19841,10 @@ function hasCliArg(args, flag) {
|
|
|
19604
19841
|
}
|
|
19605
19842
|
function ensureEmptyDelegatedMcpConfig(workspace) {
|
|
19606
19843
|
const baseDir = path18.join(os13.tmpdir(), "adhdev-delegated-agent-empty-mcp");
|
|
19607
|
-
(0,
|
|
19844
|
+
(0, import_fs9.mkdirSync)(baseDir, { recursive: true });
|
|
19608
19845
|
const workspaceHash = crypto4.createHash("sha256").update(path18.resolve(workspace || os13.tmpdir())).digest("hex").slice(0, 16);
|
|
19609
19846
|
const filePath = path18.join(baseDir, `${workspaceHash}.json`);
|
|
19610
|
-
(0,
|
|
19847
|
+
(0, import_fs9.writeFileSync)(filePath, JSON.stringify({ mcpServers: {} }, null, 2), "utf-8");
|
|
19611
19848
|
return filePath;
|
|
19612
19849
|
}
|
|
19613
19850
|
function buildCoordinatorDelegatedCliLaunchOptions(input) {
|
|
@@ -23786,7 +24023,7 @@ async function maybeRunDaemonUpgradeHelperFromEnv() {
|
|
|
23786
24023
|
|
|
23787
24024
|
// src/commands/router.ts
|
|
23788
24025
|
var import_os3 = require("os");
|
|
23789
|
-
var
|
|
24026
|
+
var import_path7 = require("path");
|
|
23790
24027
|
var fs10 = __toESM(require("fs"));
|
|
23791
24028
|
var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
|
|
23792
24029
|
var CHANNEL_SERVER_URL = {
|
|
@@ -23835,55 +24072,45 @@ function readBooleanValue(...values) {
|
|
|
23835
24072
|
}
|
|
23836
24073
|
return void 0;
|
|
23837
24074
|
}
|
|
23838
|
-
function
|
|
23839
|
-
const
|
|
23840
|
-
const
|
|
23841
|
-
if (
|
|
23842
|
-
|
|
23843
|
-
|
|
23844
|
-
|
|
23845
|
-
|
|
23846
|
-
|
|
23847
|
-
|
|
23848
|
-
|
|
23849
|
-
|
|
23850
|
-
|
|
23851
|
-
|
|
23852
|
-
|
|
23853
|
-
|
|
23854
|
-
|
|
23855
|
-
|
|
23856
|
-
|
|
23857
|
-
|
|
23858
|
-
|
|
23859
|
-
|
|
23860
|
-
|
|
23861
|
-
|
|
23862
|
-
|
|
23863
|
-
|
|
23864
|
-
|
|
23865
|
-
|
|
23866
|
-
|
|
23867
|
-
}
|
|
23868
|
-
}
|
|
23869
|
-
const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
|
|
23870
|
-
const gitResult = readObjectRecord(rawGit.result);
|
|
23871
|
-
const directStatus = readObjectRecord(rawGit.status);
|
|
23872
|
-
const nestedStatus = readObjectRecord(gitResult.status);
|
|
23873
|
-
const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
|
|
23874
|
-
const probeGit = readObjectRecord(rawProbe.git);
|
|
23875
|
-
const probeGitResult = readObjectRecord(probeGit.result);
|
|
23876
|
-
const probeDirectStatus = readObjectRecord(probeGit.status);
|
|
23877
|
-
const probeNestedStatus = readObjectRecord(probeGitResult.status);
|
|
23878
|
-
const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
|
|
24075
|
+
function joinRepoPath(root, relativePath) {
|
|
24076
|
+
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
24077
|
+
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
24078
|
+
if (!normalizedPath) return void 0;
|
|
24079
|
+
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
24080
|
+
if (!normalizedRoot) return void 0;
|
|
24081
|
+
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
24082
|
+
}
|
|
24083
|
+
function readGitSubmodules(value, parentRepoRoot) {
|
|
24084
|
+
if (!Array.isArray(value)) return void 0;
|
|
24085
|
+
const submodules = value.map((entry) => {
|
|
24086
|
+
const submodule = readObjectRecord(entry);
|
|
24087
|
+
const path28 = readStringValue(submodule.path);
|
|
24088
|
+
const commit = readStringValue(submodule.commit);
|
|
24089
|
+
const repoPath = readStringValue(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path28);
|
|
24090
|
+
if (!path28 || !commit || !repoPath) return null;
|
|
24091
|
+
return {
|
|
24092
|
+
path: path28,
|
|
24093
|
+
commit,
|
|
24094
|
+
repoPath,
|
|
24095
|
+
dirty: readBooleanValue(submodule.dirty) ?? false,
|
|
24096
|
+
outOfSync: readBooleanValue(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
24097
|
+
lastCheckedAt: readNumberValue(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now(),
|
|
24098
|
+
...readStringValue(submodule.error) ? { error: readStringValue(submodule.error) } : {}
|
|
24099
|
+
};
|
|
24100
|
+
}).filter((entry) => entry !== null);
|
|
24101
|
+
return submodules.length > 0 ? submodules : void 0;
|
|
24102
|
+
}
|
|
24103
|
+
function normalizeInlineMeshGitStatus(status, node, options) {
|
|
23879
24104
|
const isGitRepo = readBooleanValue(status.isGitRepo);
|
|
23880
24105
|
if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
|
|
23881
24106
|
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((value) => typeof value === "string") : [];
|
|
23882
24107
|
const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
|
|
23883
24108
|
const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
|
|
24109
|
+
const repoRoot = readStringValue(status.repoRoot, status.repo_root, node?.repoRoot, node?.repo_root, status.workspace, node?.workspace) || void 0;
|
|
24110
|
+
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
23884
24111
|
return {
|
|
23885
24112
|
workspace: readStringValue(status.workspace, node?.workspace) || "",
|
|
23886
|
-
repoRoot:
|
|
24113
|
+
repoRoot: repoRoot ?? null,
|
|
23887
24114
|
isGitRepo,
|
|
23888
24115
|
branch: readStringValue(status.branch) ?? null,
|
|
23889
24116
|
headCommit: readStringValue(status.headCommit) ?? null,
|
|
@@ -23899,29 +24126,412 @@ function buildCachedInlineMeshGitStatus(node) {
|
|
|
23899
24126
|
hasConflicts,
|
|
23900
24127
|
conflictFiles,
|
|
23901
24128
|
stashCount: readNumberValue(status.stashCount) ?? 0,
|
|
23902
|
-
lastCheckedAt: Date.now()
|
|
24129
|
+
lastCheckedAt: options?.lastCheckedAt ?? readNumberValue(status.lastCheckedAt) ?? Date.now(),
|
|
24130
|
+
...submodules ? { submodules } : {}
|
|
23903
24131
|
};
|
|
23904
24132
|
}
|
|
23905
|
-
function
|
|
24133
|
+
function buildInlineMeshTransitGitStatus(node) {
|
|
24134
|
+
const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
|
|
24135
|
+
const gitResult = readObjectRecord(rawGit.result);
|
|
24136
|
+
const directStatus = readObjectRecord(rawGit.status);
|
|
24137
|
+
const nestedStatus = readObjectRecord(gitResult.status);
|
|
24138
|
+
const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
|
|
24139
|
+
const probeGit = readObjectRecord(rawProbe.git);
|
|
24140
|
+
const probeGitResult = readObjectRecord(probeGit.result);
|
|
24141
|
+
const probeDirectStatus = readObjectRecord(probeGit.status);
|
|
24142
|
+
const probeNestedStatus = readObjectRecord(probeGitResult.status);
|
|
24143
|
+
const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
|
|
24144
|
+
return normalizeInlineMeshGitStatus(status, node, { lastCheckedAt: Date.now() });
|
|
24145
|
+
}
|
|
24146
|
+
function recordInlineMeshDirectGitTruth(node, git, source) {
|
|
24147
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return;
|
|
24148
|
+
const checkedAt = readNumberValue(git.lastCheckedAt) ?? Date.now();
|
|
24149
|
+
const updatedAt = new Date(checkedAt).toISOString();
|
|
24150
|
+
const nextGit = {
|
|
24151
|
+
...git,
|
|
24152
|
+
lastCheckedAt: checkedAt
|
|
24153
|
+
};
|
|
24154
|
+
node.lastGit = {
|
|
24155
|
+
source,
|
|
24156
|
+
checkedAt,
|
|
24157
|
+
status: nextGit
|
|
24158
|
+
};
|
|
24159
|
+
node.last_git = node.lastGit;
|
|
24160
|
+
node.machineStatus = "online";
|
|
24161
|
+
node.updatedAt = updatedAt;
|
|
24162
|
+
node.lastSeenAt = updatedAt;
|
|
24163
|
+
const repoRoot = readStringValue(nextGit.repoRoot);
|
|
24164
|
+
if (repoRoot && !readStringValue(node.repoRoot)) node.repoRoot = repoRoot;
|
|
24165
|
+
}
|
|
24166
|
+
function buildCachedInlineMeshGitStatus(node) {
|
|
24167
|
+
const liveGit = buildInlineMeshTransitGitStatus(node);
|
|
24168
|
+
if (liveGit) return liveGit;
|
|
23906
24169
|
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
23907
|
-
const
|
|
23908
|
-
|
|
23909
|
-
|
|
24170
|
+
const cachedGit = readObjectRecord(cachedStatus.git);
|
|
24171
|
+
if (!Object.keys(cachedGit).length) return void 0;
|
|
24172
|
+
return normalizeInlineMeshGitStatus(cachedGit, node);
|
|
24173
|
+
}
|
|
24174
|
+
function shouldDiscardCachedInlineMeshStatus(node) {
|
|
24175
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24176
|
+
if (!Object.keys(cachedStatus).length) return false;
|
|
24177
|
+
const cachedGit = readObjectRecord(cachedStatus.git);
|
|
24178
|
+
const workspaceError = readStringValue(cachedStatus.error, node?.error);
|
|
24179
|
+
if (workspaceError && /workspace must be an existing directory/i.test(workspaceError)) return true;
|
|
24180
|
+
const isGitRepo = readBooleanValue(cachedGit.isGitRepo);
|
|
24181
|
+
const branch = readStringValue(cachedGit.branch);
|
|
24182
|
+
const headCommit = readStringValue(cachedGit.headCommit);
|
|
24183
|
+
return isGitRepo === false && !branch && !headCommit;
|
|
24184
|
+
}
|
|
24185
|
+
function stripInlineMeshTransientNodeState(node) {
|
|
24186
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return node;
|
|
24187
|
+
const {
|
|
24188
|
+
cachedStatus,
|
|
24189
|
+
lastGit: _lastGit,
|
|
24190
|
+
last_git: _lastGitLegacy,
|
|
24191
|
+
lastProbe: _lastProbe,
|
|
24192
|
+
last_probe: _lastProbeLegacy,
|
|
24193
|
+
error: _error,
|
|
24194
|
+
health: _health,
|
|
24195
|
+
machineStatus: _machineStatus,
|
|
24196
|
+
lastSeenAt: _lastSeenAt,
|
|
24197
|
+
last_seen_at: _lastSeenAtLegacy,
|
|
24198
|
+
updatedAt: _updatedAt,
|
|
24199
|
+
updated_at: _updatedAtLegacy,
|
|
24200
|
+
activeSession: _activeSession,
|
|
24201
|
+
active_session: _activeSessionLegacy,
|
|
24202
|
+
activeSessionId: _activeSessionId,
|
|
24203
|
+
active_session_id: _activeSessionIdLegacy,
|
|
24204
|
+
sessionId: _sessionId,
|
|
24205
|
+
session_id: _sessionIdLegacy,
|
|
24206
|
+
providerType: _providerType,
|
|
24207
|
+
provider_type: _providerTypeLegacy,
|
|
24208
|
+
...rest
|
|
24209
|
+
} = node;
|
|
24210
|
+
if (cachedStatus && !shouldDiscardCachedInlineMeshStatus(node)) {
|
|
24211
|
+
return { ...rest, cachedStatus };
|
|
24212
|
+
}
|
|
24213
|
+
return rest;
|
|
24214
|
+
}
|
|
24215
|
+
function hasInlineMeshTransientNodeState(node) {
|
|
24216
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return false;
|
|
24217
|
+
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;
|
|
24218
|
+
}
|
|
24219
|
+
function inlineMeshCarriesTransientNodeTruth(inlineMesh) {
|
|
24220
|
+
if (!inlineMesh || typeof inlineMesh !== "object" || Array.isArray(inlineMesh)) return false;
|
|
24221
|
+
if (!Array.isArray(inlineMesh.nodes) || inlineMesh.nodes.length === 0) return false;
|
|
24222
|
+
return inlineMesh.nodes.some((node) => hasInlineMeshTransientNodeState(node));
|
|
24223
|
+
}
|
|
24224
|
+
function readInlineMeshNodeId(node) {
|
|
24225
|
+
return readStringValue(node?.id, node?.nodeId) || "";
|
|
24226
|
+
}
|
|
24227
|
+
function sanitizeInlineMesh(inlineMesh) {
|
|
24228
|
+
if (!inlineMesh || typeof inlineMesh !== "object" || Array.isArray(inlineMesh)) return inlineMesh;
|
|
24229
|
+
if (!Array.isArray(inlineMesh.nodes)) return inlineMesh;
|
|
24230
|
+
let changed = false;
|
|
24231
|
+
const nodes = inlineMesh.nodes.map((node) => {
|
|
24232
|
+
if (!hasInlineMeshTransientNodeState(node)) return node;
|
|
24233
|
+
changed = true;
|
|
24234
|
+
return stripInlineMeshTransientNodeState(node);
|
|
24235
|
+
});
|
|
24236
|
+
if (!changed) return inlineMesh;
|
|
24237
|
+
return {
|
|
24238
|
+
...inlineMesh,
|
|
24239
|
+
nodes
|
|
24240
|
+
};
|
|
24241
|
+
}
|
|
24242
|
+
function reconcileInlineMeshCache(cached, incoming) {
|
|
24243
|
+
if (!cached || typeof cached !== "object" || Array.isArray(cached)) return incoming;
|
|
24244
|
+
if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return cached;
|
|
24245
|
+
const cachedNodes = Array.isArray(cached.nodes) ? cached.nodes : [];
|
|
24246
|
+
const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
|
|
24247
|
+
if (!cachedNodes.length || !incomingNodes.length) return { ...cached, ...incoming };
|
|
24248
|
+
const incomingById = /* @__PURE__ */ new Map();
|
|
24249
|
+
for (const node of incomingNodes) {
|
|
24250
|
+
const nodeId = readInlineMeshNodeId(node);
|
|
24251
|
+
if (nodeId) incomingById.set(nodeId, node);
|
|
24252
|
+
}
|
|
24253
|
+
const nodes = cachedNodes.map((cachedNode) => {
|
|
24254
|
+
const nodeId = readInlineMeshNodeId(cachedNode);
|
|
24255
|
+
const incomingNode = nodeId ? incomingById.get(nodeId) : void 0;
|
|
24256
|
+
if (!incomingNode) return cachedNode;
|
|
24257
|
+
if (hasInlineMeshTransientNodeState(incomingNode)) {
|
|
24258
|
+
return { ...cachedNode, ...incomingNode };
|
|
24259
|
+
}
|
|
24260
|
+
return { ...stripInlineMeshTransientNodeState(cachedNode), ...incomingNode };
|
|
24261
|
+
});
|
|
24262
|
+
return {
|
|
24263
|
+
...cached,
|
|
24264
|
+
...incoming,
|
|
24265
|
+
nodes
|
|
24266
|
+
};
|
|
24267
|
+
}
|
|
24268
|
+
function hasGitWorktreeChanges(git) {
|
|
24269
|
+
if (!git) return false;
|
|
24270
|
+
return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
|
|
24271
|
+
}
|
|
24272
|
+
function getGitSubmoduleDriftState(git) {
|
|
24273
|
+
const submodules = Array.isArray(git?.submodules) ? git.submodules : [];
|
|
24274
|
+
let dirty = false;
|
|
24275
|
+
let outOfSync = false;
|
|
24276
|
+
for (const entry of submodules) {
|
|
24277
|
+
const submodule = readObjectRecord(entry);
|
|
24278
|
+
if (readBooleanValue(submodule.dirty) === true) dirty = true;
|
|
24279
|
+
if (readBooleanValue(submodule.outOfSync) === true || !!readStringValue(submodule.error)) outOfSync = true;
|
|
24280
|
+
}
|
|
24281
|
+
return { dirty, outOfSync };
|
|
24282
|
+
}
|
|
24283
|
+
function deriveMeshNodeHealthFromGit(git) {
|
|
24284
|
+
if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
|
|
24285
|
+
const branch = readStringValue(git.branch);
|
|
24286
|
+
if (!branch) return "degraded";
|
|
24287
|
+
const submoduleDrift = getGitSubmoduleDriftState(git);
|
|
24288
|
+
if (submoduleDrift.outOfSync) return "degraded";
|
|
24289
|
+
if (submoduleDrift.dirty || hasGitWorktreeChanges(git)) return "dirty";
|
|
24290
|
+
return "online";
|
|
24291
|
+
}
|
|
24292
|
+
function readCachedInlineMeshActiveSessions(node) {
|
|
24293
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24294
|
+
const activeSession = readObjectRecord(cachedStatus.activeSession);
|
|
24295
|
+
const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
|
|
24296
|
+
const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
|
|
24297
|
+
return sessionId ? [sessionId] : [];
|
|
24298
|
+
}
|
|
24299
|
+
function readCachedInlineMeshActiveSessionDetails(node) {
|
|
24300
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24301
|
+
const activeSession = readObjectRecord(cachedStatus.activeSession);
|
|
24302
|
+
const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
|
|
24303
|
+
const sessionId = readStringValue(
|
|
24304
|
+
fallbackSession.id,
|
|
24305
|
+
fallbackSession.sessionId,
|
|
24306
|
+
fallbackSession.session_id,
|
|
24307
|
+
node?.activeSessionId,
|
|
24308
|
+
node?.active_session_id,
|
|
24309
|
+
node?.sessionId,
|
|
24310
|
+
node?.session_id
|
|
24311
|
+
);
|
|
24312
|
+
if (!sessionId) return [];
|
|
24313
|
+
return [{
|
|
24314
|
+
sessionId,
|
|
24315
|
+
providerType: readStringValue(
|
|
24316
|
+
fallbackSession.providerType,
|
|
24317
|
+
fallbackSession.provider_type,
|
|
24318
|
+
fallbackSession.cliType,
|
|
24319
|
+
fallbackSession.cli_type,
|
|
24320
|
+
fallbackSession.provider,
|
|
24321
|
+
node?.providerType,
|
|
24322
|
+
node?.provider_type
|
|
24323
|
+
),
|
|
24324
|
+
state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
|
|
24325
|
+
lifecycle: readStringValue(fallbackSession.lifecycle),
|
|
24326
|
+
title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
|
|
24327
|
+
workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
|
|
24328
|
+
lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
|
|
24329
|
+
recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
|
|
24330
|
+
isCached: true
|
|
24331
|
+
}];
|
|
24332
|
+
}
|
|
24333
|
+
function readLiveMeshSessionState(record) {
|
|
24334
|
+
return readStringValue(
|
|
24335
|
+
record?.meta?.sessionStatus,
|
|
24336
|
+
record?.meta?.status,
|
|
24337
|
+
record?.meta?.providerStatus,
|
|
24338
|
+
record?.status,
|
|
24339
|
+
record?.state,
|
|
24340
|
+
record?.lifecycle
|
|
24341
|
+
);
|
|
24342
|
+
}
|
|
24343
|
+
function toIsoTimestamp(value) {
|
|
24344
|
+
if (typeof value === "number" && Number.isFinite(value)) return new Date(value).toISOString();
|
|
24345
|
+
const stringValue = readStringValue(value);
|
|
24346
|
+
return stringValue || null;
|
|
24347
|
+
}
|
|
24348
|
+
function synthesizeMeshNodeFreshnessFromConnection(status) {
|
|
24349
|
+
const connection = readObjectRecord(status.connection);
|
|
24350
|
+
const connectionFreshAt = toIsoTimestamp(connection.lastCommandAt ?? connection.lastConnectedAt ?? connection.lastStateChangeAt);
|
|
24351
|
+
const git = readObjectRecord(status.git);
|
|
24352
|
+
const gitCheckedAt = toIsoTimestamp(git.lastCheckedAt);
|
|
24353
|
+
if (!status.lastSeenAt && connectionFreshAt) status.lastSeenAt = connectionFreshAt;
|
|
24354
|
+
if (!status.updatedAt && (gitCheckedAt || connectionFreshAt)) {
|
|
24355
|
+
status.updatedAt = gitCheckedAt ?? connectionFreshAt;
|
|
24356
|
+
}
|
|
24357
|
+
}
|
|
24358
|
+
function finalizeMeshNodeStatus(args) {
|
|
24359
|
+
const { status, node, daemonId, isSelfNode } = args;
|
|
24360
|
+
if (!readStringValue(status.machineStatus)) {
|
|
24361
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24362
|
+
const machineStatus = readStringValue(cachedStatus.machineStatus, cachedStatus.machine_status, node?.machineStatus);
|
|
24363
|
+
if (machineStatus) status.machineStatus = machineStatus;
|
|
24364
|
+
}
|
|
24365
|
+
synthesizeMeshNodeFreshnessFromConnection(status);
|
|
24366
|
+
const connectionState = readStringValue(readObjectRecord(status.connection).state);
|
|
24367
|
+
status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || connectionState === "connected" || isSelfNode);
|
|
24368
|
+
}
|
|
24369
|
+
async function probeRemoteMeshGitStatus(args) {
|
|
24370
|
+
if (!args.dispatchMeshCommand) return null;
|
|
24371
|
+
const remoteResult = await Promise.race([
|
|
24372
|
+
args.dispatchMeshCommand(args.daemonId, "git_status", { workspace: args.workspace }),
|
|
24373
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), args.timeoutMs))
|
|
24374
|
+
]);
|
|
24375
|
+
const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
|
|
24376
|
+
return remoteGit && typeof remoteGit === "object" && typeof remoteGit.isGitRepo === "boolean" ? remoteGit : null;
|
|
24377
|
+
}
|
|
24378
|
+
async function hydrateInlineMeshDirectTruth(args) {
|
|
24379
|
+
const nodes = Array.isArray(args.mesh?.nodes) ? args.mesh.nodes : [];
|
|
24380
|
+
if (!nodes.length) {
|
|
24381
|
+
return {
|
|
24382
|
+
directEvidenceCount: 0,
|
|
24383
|
+
localConfirmedCount: 0,
|
|
24384
|
+
peerAttemptedCount: 0,
|
|
24385
|
+
peerConfirmedCount: 0,
|
|
24386
|
+
unavailableNodeIds: []
|
|
24387
|
+
};
|
|
24388
|
+
}
|
|
24389
|
+
const selectedCoordinatorNodeId = readStringValue(
|
|
24390
|
+
args.mesh?.coordinator?.preferredNodeId,
|
|
24391
|
+
nodes[0]?.id,
|
|
24392
|
+
nodes[0]?.nodeId
|
|
24393
|
+
);
|
|
24394
|
+
let localConfirmedCount = 0;
|
|
24395
|
+
let peerAttemptedCount = 0;
|
|
24396
|
+
let peerConfirmedCount = 0;
|
|
24397
|
+
const unavailableNodeIds = [];
|
|
24398
|
+
for (const [nodeIndex, node] of nodes.entries()) {
|
|
24399
|
+
const nodeId = readStringValue(node?.id, node?.nodeId) || `node_${nodeIndex}`;
|
|
24400
|
+
const workspace = readStringValue(node?.workspace);
|
|
24401
|
+
const daemonId = readStringValue(node?.daemonId);
|
|
24402
|
+
const isSelfNode = Boolean(
|
|
24403
|
+
nodeId && selectedCoordinatorNodeId && nodeId === selectedCoordinatorNodeId
|
|
24404
|
+
) || Boolean(
|
|
24405
|
+
daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId)
|
|
24406
|
+
) || Boolean(args.meshSource !== "local_config" && nodeIndex === 0);
|
|
24407
|
+
if (!workspace) {
|
|
24408
|
+
if (!isSelfNode && daemonId) unavailableNodeIds.push(nodeId);
|
|
24409
|
+
continue;
|
|
24410
|
+
}
|
|
24411
|
+
if (isSelfNode && fs10.existsSync(workspace)) {
|
|
24412
|
+
try {
|
|
24413
|
+
const localGit = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
24414
|
+
if (localGit?.isGitRepo) {
|
|
24415
|
+
recordInlineMeshDirectGitTruth(node, localGit, "selected_coordinator_local_git");
|
|
24416
|
+
localConfirmedCount += 1;
|
|
24417
|
+
continue;
|
|
24418
|
+
}
|
|
24419
|
+
} catch {
|
|
24420
|
+
}
|
|
24421
|
+
}
|
|
24422
|
+
if (!daemonId || !args.dispatchMeshCommand) {
|
|
24423
|
+
if (!isSelfNode) unavailableNodeIds.push(nodeId);
|
|
24424
|
+
continue;
|
|
24425
|
+
}
|
|
24426
|
+
peerAttemptedCount += 1;
|
|
24427
|
+
try {
|
|
24428
|
+
const remoteGit = await probeRemoteMeshGitStatus({
|
|
24429
|
+
dispatchMeshCommand: args.dispatchMeshCommand,
|
|
24430
|
+
daemonId,
|
|
24431
|
+
workspace,
|
|
24432
|
+
timeoutMs: 8e3
|
|
24433
|
+
});
|
|
24434
|
+
if (remoteGit) {
|
|
24435
|
+
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
24436
|
+
peerConfirmedCount += 1;
|
|
24437
|
+
continue;
|
|
24438
|
+
}
|
|
24439
|
+
} catch {
|
|
24440
|
+
}
|
|
24441
|
+
unavailableNodeIds.push(nodeId);
|
|
24442
|
+
}
|
|
24443
|
+
return {
|
|
24444
|
+
directEvidenceCount: localConfirmedCount + peerConfirmedCount,
|
|
24445
|
+
localConfirmedCount,
|
|
24446
|
+
peerAttemptedCount,
|
|
24447
|
+
peerConfirmedCount,
|
|
24448
|
+
unavailableNodeIds
|
|
24449
|
+
};
|
|
24450
|
+
}
|
|
24451
|
+
function summarizeMeshSessionRecord(record) {
|
|
24452
|
+
return {
|
|
24453
|
+
sessionId: readStringValue(record?.sessionId) || "unknown",
|
|
24454
|
+
providerType: readStringValue(record?.providerType),
|
|
24455
|
+
state: readLiveMeshSessionState(record),
|
|
24456
|
+
lifecycle: readStringValue(record?.lifecycle),
|
|
24457
|
+
surfaceKind: getSessionHostSurfaceKind(record),
|
|
24458
|
+
recoveryState: readStringValue(record?.meta?.runtimeRecoveryState) ?? null,
|
|
24459
|
+
workspace: readStringValue(record?.workspace) ?? null,
|
|
24460
|
+
title: readStringValue(record?.displayName, record?.workspaceLabel) ?? null,
|
|
24461
|
+
lastActivityAt: toIsoTimestamp(record?.updatedAt ?? record?.lastActivityAt ?? record?.last_activity_at),
|
|
24462
|
+
isCached: false
|
|
24463
|
+
};
|
|
24464
|
+
}
|
|
24465
|
+
function liveSessionRecordMatchesMeshNode(record, meshId, nodeId) {
|
|
24466
|
+
const recordNodeId = readStringValue(record?.meta?.meshNodeId);
|
|
24467
|
+
if (!recordNodeId || recordNodeId !== nodeId) return false;
|
|
24468
|
+
const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
|
|
24469
|
+
return !recordMeshId || recordMeshId === meshId;
|
|
24470
|
+
}
|
|
24471
|
+
function liveSessionRecordMatchesMeshWorkspace(record, meshId, workspace) {
|
|
24472
|
+
const recordWorkspace = readStringValue(record?.workspace);
|
|
24473
|
+
if (!recordWorkspace || !workspace || recordWorkspace !== workspace) return false;
|
|
24474
|
+
const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
|
|
24475
|
+
if (recordMeshId) return recordMeshId === meshId;
|
|
24476
|
+
return record?.meta?.launchedByCoordinator === true || !!readStringValue(record?.meta?.meshNodeId);
|
|
24477
|
+
}
|
|
24478
|
+
function readLiveMeshNodeWorkspace(args) {
|
|
24479
|
+
const directNodeWorkspace = args.liveSessionRecords.find((record) => liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId) && readStringValue(record?.workspace));
|
|
24480
|
+
if (directNodeWorkspace) {
|
|
24481
|
+
return readStringValue(directNodeWorkspace.workspace) || "";
|
|
24482
|
+
}
|
|
24483
|
+
if (args.allowCoordinatorSession) {
|
|
24484
|
+
const coordinatorWorkspace = args.liveSessionRecords.find((record) => readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId && readStringValue(record?.workspace));
|
|
24485
|
+
if (coordinatorWorkspace) {
|
|
24486
|
+
return readStringValue(coordinatorWorkspace.workspace) || "";
|
|
24487
|
+
}
|
|
24488
|
+
}
|
|
24489
|
+
return "";
|
|
24490
|
+
}
|
|
24491
|
+
function collectLiveMeshSessionRecords(args) {
|
|
24492
|
+
const matches = args.liveSessionRecords.filter((record) => {
|
|
24493
|
+
const nodeWorkspace = readStringValue(args.node?.workspace);
|
|
24494
|
+
if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)) return true;
|
|
24495
|
+
return !!nodeWorkspace && liveSessionRecordMatchesMeshWorkspace(record, args.meshId, nodeWorkspace);
|
|
24496
|
+
});
|
|
24497
|
+
if (args.allowCoordinatorSession) {
|
|
24498
|
+
for (const record of args.liveSessionRecords) {
|
|
24499
|
+
if (readStringValue(record?.meta?.meshCoordinatorFor) !== args.meshId) continue;
|
|
24500
|
+
const sessionId = readStringValue(record?.sessionId);
|
|
24501
|
+
if (sessionId && matches.some((entry) => readStringValue(entry?.sessionId) === sessionId)) continue;
|
|
24502
|
+
matches.push(record);
|
|
24503
|
+
}
|
|
24504
|
+
}
|
|
24505
|
+
return matches;
|
|
24506
|
+
}
|
|
24507
|
+
function applyCachedInlineMeshNodeStatus(status, node, options) {
|
|
24508
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24509
|
+
const liveGit = buildInlineMeshTransitGitStatus(node);
|
|
24510
|
+
const git = options?.skipGit ? void 0 : liveGit ?? buildCachedInlineMeshGitStatus(node);
|
|
24511
|
+
const error = options?.skipError ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.error, node?.error);
|
|
24512
|
+
const health = options?.skipHealth ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.health, node?.health);
|
|
23910
24513
|
const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
|
|
23911
|
-
|
|
23912
|
-
|
|
24514
|
+
const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
|
|
24515
|
+
const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
|
|
24516
|
+
const activeSessions = readCachedInlineMeshActiveSessions(node);
|
|
24517
|
+
const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
|
|
24518
|
+
if (!git && !error && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
|
|
23913
24519
|
if (git) status.git = git;
|
|
23914
24520
|
if (error) status.error = error;
|
|
24521
|
+
if (machineStatus) status.machineStatus = machineStatus;
|
|
24522
|
+
if (lastSeenAt) status.lastSeenAt = lastSeenAt;
|
|
24523
|
+
if (updatedAt) status.updatedAt = updatedAt;
|
|
24524
|
+
if (activeSessions.length > 0) status.activeSessions = activeSessions;
|
|
24525
|
+
if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
|
|
23915
24526
|
if (health) {
|
|
23916
24527
|
status.health = health;
|
|
23917
24528
|
return true;
|
|
23918
24529
|
}
|
|
23919
24530
|
if (git) {
|
|
23920
|
-
|
|
23921
|
-
status.health = git.isGitRepo === false ? "degraded" : dirty ? "dirty" : "online";
|
|
24531
|
+
status.health = deriveMeshNodeHealthFromGit(git);
|
|
23922
24532
|
return true;
|
|
23923
24533
|
}
|
|
23924
|
-
return
|
|
24534
|
+
return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
|
|
23925
24535
|
}
|
|
23926
24536
|
async function resolveProviderTypeFromPriority(args) {
|
|
23927
24537
|
if (!args.providerPriority.length) {
|
|
@@ -23951,15 +24561,92 @@ var REFINE_VALIDATION_TIMEOUT_MS = 12e4;
|
|
|
23951
24561
|
var REFINE_VALIDATION_OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
23952
24562
|
var REFINE_VALIDATION_SUMMARY_CHARS = 2e3;
|
|
23953
24563
|
var REFINE_VALIDATION_MAX_COMMANDS = 4;
|
|
24564
|
+
var REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
23954
24565
|
function truncateValidationOutput(value) {
|
|
23955
24566
|
const text = typeof value === "string" ? value : value == null ? "" : String(value);
|
|
23956
24567
|
if (text.length <= REFINE_VALIDATION_SUMMARY_CHARS) return text;
|
|
23957
24568
|
return `${text.slice(0, REFINE_VALIDATION_SUMMARY_CHARS)}
|
|
23958
24569
|
[truncated ${text.length - REFINE_VALIDATION_SUMMARY_CHARS} chars]`;
|
|
23959
24570
|
}
|
|
24571
|
+
function recordMeshRefineStage(stages, stage, status, startedAt, details) {
|
|
24572
|
+
stages.push({
|
|
24573
|
+
stage,
|
|
24574
|
+
status,
|
|
24575
|
+
durationMs: Date.now() - startedAt,
|
|
24576
|
+
...details || {}
|
|
24577
|
+
});
|
|
24578
|
+
}
|
|
24579
|
+
async function computeGitPatchId(cwd, fromRef, toRef) {
|
|
24580
|
+
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
24581
|
+
const diff = execFileSync4("git", ["diff", "--patch", "--full-index", fromRef, toRef], {
|
|
24582
|
+
cwd,
|
|
24583
|
+
encoding: "utf8",
|
|
24584
|
+
maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
|
|
24585
|
+
});
|
|
24586
|
+
if (!diff.trim()) return "";
|
|
24587
|
+
const patchId = execFileSync4("git", ["patch-id", "--stable"], {
|
|
24588
|
+
cwd,
|
|
24589
|
+
input: diff,
|
|
24590
|
+
encoding: "utf8",
|
|
24591
|
+
maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
|
|
24592
|
+
}).trim();
|
|
24593
|
+
return patchId.split(/\s+/)[0] || "";
|
|
24594
|
+
}
|
|
24595
|
+
async function runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead) {
|
|
24596
|
+
const startedAt = Date.now();
|
|
24597
|
+
try {
|
|
24598
|
+
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
24599
|
+
const git = (args) => execFileSync4("git", args, {
|
|
24600
|
+
cwd: repoRoot,
|
|
24601
|
+
encoding: "utf8",
|
|
24602
|
+
maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
|
|
24603
|
+
});
|
|
24604
|
+
const mergeBase = git(["merge-base", baseHead, branchHead]).trim();
|
|
24605
|
+
const mergeTreeStdout = git(["merge-tree", "--write-tree", baseHead, branchHead]);
|
|
24606
|
+
const mergedTree = mergeTreeStdout.trim().split(/\s+/)[0] || "";
|
|
24607
|
+
if (!mergeBase || !mergedTree) {
|
|
24608
|
+
return {
|
|
24609
|
+
status: "failed",
|
|
24610
|
+
equivalent: false,
|
|
24611
|
+
baseHead,
|
|
24612
|
+
branchHead,
|
|
24613
|
+
mergeBase: mergeBase || void 0,
|
|
24614
|
+
mergedTree: mergedTree || void 0,
|
|
24615
|
+
durationMs: Date.now() - startedAt,
|
|
24616
|
+
error: "patch equivalence preflight could not resolve merge-base or synthetic merge tree",
|
|
24617
|
+
stdout: truncateValidationOutput(mergeTreeStdout)
|
|
24618
|
+
};
|
|
24619
|
+
}
|
|
24620
|
+
const expectedPatchId = await computeGitPatchId(repoRoot, mergeBase, branchHead);
|
|
24621
|
+
const actualPatchId = await computeGitPatchId(repoRoot, baseHead, mergedTree);
|
|
24622
|
+
const equivalent = expectedPatchId === actualPatchId;
|
|
24623
|
+
return {
|
|
24624
|
+
status: equivalent ? "passed" : "failed",
|
|
24625
|
+
equivalent,
|
|
24626
|
+
baseHead,
|
|
24627
|
+
branchHead,
|
|
24628
|
+
mergeBase,
|
|
24629
|
+
mergedTree,
|
|
24630
|
+
expectedPatchId,
|
|
24631
|
+
actualPatchId,
|
|
24632
|
+
durationMs: Date.now() - startedAt
|
|
24633
|
+
};
|
|
24634
|
+
} catch (e) {
|
|
24635
|
+
return {
|
|
24636
|
+
status: "failed",
|
|
24637
|
+
equivalent: false,
|
|
24638
|
+
baseHead,
|
|
24639
|
+
branchHead,
|
|
24640
|
+
durationMs: Date.now() - startedAt,
|
|
24641
|
+
error: e?.message || String(e),
|
|
24642
|
+
stdout: truncateValidationOutput(e?.stdout),
|
|
24643
|
+
stderr: truncateValidationOutput(e?.stderr)
|
|
24644
|
+
};
|
|
24645
|
+
}
|
|
24646
|
+
}
|
|
23960
24647
|
function readPackageScripts(workspace) {
|
|
23961
24648
|
try {
|
|
23962
|
-
const packageJsonPath = (0,
|
|
24649
|
+
const packageJsonPath = (0, import_path7.join)(workspace, "package.json");
|
|
23963
24650
|
const parsed = JSON.parse(fs10.readFileSync(packageJsonPath, "utf-8"));
|
|
23964
24651
|
return parsed?.scripts && typeof parsed.scripts === "object" && !Array.isArray(parsed.scripts) ? parsed.scripts : {};
|
|
23965
24652
|
} catch {
|
|
@@ -24167,13 +24854,13 @@ function serializeMeshCoordinatorMcpConfig(config, format) {
|
|
|
24167
24854
|
}
|
|
24168
24855
|
function resolveHermesUserHome() {
|
|
24169
24856
|
const explicitHome = process.env.HERMES_HOME?.trim();
|
|
24170
|
-
return explicitHome || (0,
|
|
24857
|
+
return explicitHome || (0, import_path7.join)((0, import_os3.homedir)(), ".hermes");
|
|
24171
24858
|
}
|
|
24172
24859
|
function loadHermesCoordinatorBaseConfig(targetConfigPath) {
|
|
24173
24860
|
const sourceHome = resolveHermesUserHome();
|
|
24174
|
-
const sourceConfigPath = (0,
|
|
24861
|
+
const sourceConfigPath = (0, import_path7.join)(sourceHome, "config.yaml");
|
|
24175
24862
|
if (!fs10.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
24176
|
-
if ((0,
|
|
24863
|
+
if ((0, import_path7.resolve)(sourceConfigPath) === (0, import_path7.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
24177
24864
|
const parsed = parseMeshCoordinatorMcpConfig(fs10.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
|
|
24178
24865
|
const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
|
|
24179
24866
|
return { config: baseConfig, sourceHome, sourceConfigPath };
|
|
@@ -24207,10 +24894,10 @@ function stripHermesCoordinatorTempModelProviderOverrides(config) {
|
|
|
24207
24894
|
return sanitized;
|
|
24208
24895
|
}
|
|
24209
24896
|
function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
|
|
24210
|
-
if ((0,
|
|
24897
|
+
if ((0, import_path7.resolve)(sourceHome) === (0, import_path7.resolve)(targetHome)) return;
|
|
24211
24898
|
for (const fileName of [".env", "auth.json"]) {
|
|
24212
|
-
const sourcePath = (0,
|
|
24213
|
-
const targetPath = (0,
|
|
24899
|
+
const sourcePath = (0, import_path7.join)(sourceHome, fileName);
|
|
24900
|
+
const targetPath = (0, import_path7.join)(targetHome, fileName);
|
|
24214
24901
|
if (!fs10.existsSync(sourcePath)) continue;
|
|
24215
24902
|
try {
|
|
24216
24903
|
fs10.copyFileSync(sourcePath, targetPath);
|
|
@@ -24314,30 +25001,97 @@ var DaemonCommandRouter = class {
|
|
|
24314
25001
|
* Allows the MCP server to query mesh data via get_mesh even when
|
|
24315
25002
|
* the mesh doesn't exist in the local meshes.json file. */
|
|
24316
25003
|
inlineMeshCache = /* @__PURE__ */ new Map();
|
|
25004
|
+
/** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default. */
|
|
25005
|
+
aggregateMeshStatusCache = /* @__PURE__ */ new Map();
|
|
24317
25006
|
constructor(deps) {
|
|
24318
25007
|
this.deps = deps;
|
|
24319
25008
|
}
|
|
25009
|
+
cloneJsonValue(value) {
|
|
25010
|
+
if (typeof structuredClone === "function") return structuredClone(value);
|
|
25011
|
+
return JSON.parse(JSON.stringify(value));
|
|
25012
|
+
}
|
|
25013
|
+
getCachedAggregateMeshStatus(meshId) {
|
|
25014
|
+
const cached = this.aggregateMeshStatusCache.get(meshId);
|
|
25015
|
+
if (!cached?.snapshot || cached.snapshot.success !== true || !Array.isArray(cached.snapshot.nodes)) return null;
|
|
25016
|
+
const snapshot = this.cloneJsonValue(cached.snapshot);
|
|
25017
|
+
const ageMs = Math.max(0, Date.now() - cached.builtAt);
|
|
25018
|
+
const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
|
|
25019
|
+
snapshot.sourceOfTruth = {
|
|
25020
|
+
...sourceOfTruth,
|
|
25021
|
+
aggregateSnapshot: {
|
|
25022
|
+
...sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === "object" ? sourceOfTruth.aggregateSnapshot : {},
|
|
25023
|
+
owner: "coordinator_daemon_memory",
|
|
25024
|
+
cached: true,
|
|
25025
|
+
source: "memory",
|
|
25026
|
+
refreshReason: "memory_cache_hit",
|
|
25027
|
+
ageMs,
|
|
25028
|
+
cachedAt: new Date(cached.builtAt).toISOString(),
|
|
25029
|
+
returnedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25030
|
+
}
|
|
25031
|
+
};
|
|
25032
|
+
return snapshot;
|
|
25033
|
+
}
|
|
25034
|
+
rememberAggregateMeshStatus(meshId, snapshot, refreshReason) {
|
|
25035
|
+
if (!snapshot || typeof snapshot !== "object" || snapshot.success !== true || !Array.isArray(snapshot.nodes)) return snapshot;
|
|
25036
|
+
const builtAt = Date.now();
|
|
25037
|
+
const next = this.cloneJsonValue(snapshot);
|
|
25038
|
+
const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === "object" ? next.sourceOfTruth : {};
|
|
25039
|
+
next.sourceOfTruth = {
|
|
25040
|
+
...sourceOfTruth,
|
|
25041
|
+
aggregateSnapshot: {
|
|
25042
|
+
owner: "coordinator_daemon_memory",
|
|
25043
|
+
cached: false,
|
|
25044
|
+
source: "live_refresh",
|
|
25045
|
+
refreshReason,
|
|
25046
|
+
ageMs: 0,
|
|
25047
|
+
cachedAt: new Date(builtAt).toISOString(),
|
|
25048
|
+
returnedAt: new Date(builtAt).toISOString()
|
|
25049
|
+
}
|
|
25050
|
+
};
|
|
25051
|
+
this.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: this.cloneJsonValue(next) });
|
|
25052
|
+
return next;
|
|
25053
|
+
}
|
|
24320
25054
|
getCachedInlineMesh(meshId, inlineMesh) {
|
|
24321
25055
|
if (inlineMesh && typeof inlineMesh === "object") {
|
|
24322
|
-
this.
|
|
24323
|
-
return inlineMesh;
|
|
25056
|
+
return this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24324
25057
|
}
|
|
24325
25058
|
return this.inlineMeshCache.get(meshId);
|
|
24326
25059
|
}
|
|
25060
|
+
warmInlineMeshCache(meshId, inlineMesh) {
|
|
25061
|
+
if (!inlineMesh || typeof inlineMesh !== "object") return void 0;
|
|
25062
|
+
const sanitizedInlineMesh = sanitizeInlineMesh(inlineMesh);
|
|
25063
|
+
const cached = this.inlineMeshCache.get(meshId);
|
|
25064
|
+
if (cached) {
|
|
25065
|
+
const merged = reconcileInlineMeshCache(cached, sanitizedInlineMesh);
|
|
25066
|
+
this.inlineMeshCache.set(meshId, merged);
|
|
25067
|
+
return merged;
|
|
25068
|
+
}
|
|
25069
|
+
this.inlineMeshCache.set(meshId, sanitizedInlineMesh);
|
|
25070
|
+
return sanitizedInlineMesh;
|
|
25071
|
+
}
|
|
24327
25072
|
async getMeshForCommand(meshId, inlineMesh, options) {
|
|
24328
25073
|
const preferInline = options?.preferInline === true;
|
|
24329
25074
|
if (preferInline) {
|
|
24330
|
-
const cached2 = this.getCachedInlineMesh(meshId
|
|
24331
|
-
if (cached2) return { mesh: cached2, inline: true };
|
|
25075
|
+
const cached2 = this.getCachedInlineMesh(meshId);
|
|
25076
|
+
if (cached2) return { mesh: cached2, inline: true, source: "inline_cache" };
|
|
25077
|
+
if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
|
|
25078
|
+
this.warmInlineMeshCache(meshId, inlineMesh);
|
|
25079
|
+
return { mesh: inlineMesh, inline: true, source: "inline_bootstrap" };
|
|
25080
|
+
}
|
|
24332
25081
|
}
|
|
24333
25082
|
try {
|
|
24334
25083
|
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
24335
25084
|
const mesh = getMesh3(meshId);
|
|
24336
|
-
if (mesh) return { mesh, inline: false };
|
|
25085
|
+
if (mesh) return { mesh, inline: false, source: "local_config" };
|
|
24337
25086
|
} catch {
|
|
24338
25087
|
}
|
|
24339
|
-
const cached = this.getCachedInlineMesh(meshId
|
|
24340
|
-
|
|
25088
|
+
const cached = this.getCachedInlineMesh(meshId);
|
|
25089
|
+
if (cached) return { mesh: cached, inline: true, source: "inline_cache" };
|
|
25090
|
+
const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
|
|
25091
|
+
return warmedInline ? { mesh: warmedInline, inline: true, source: "inline_bootstrap" } : null;
|
|
25092
|
+
}
|
|
25093
|
+
invalidateAggregateMeshStatus(meshId) {
|
|
25094
|
+
this.aggregateMeshStatusCache.delete(meshId);
|
|
24341
25095
|
}
|
|
24342
25096
|
updateInlineMeshNode(meshId, mesh, node) {
|
|
24343
25097
|
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
@@ -24346,6 +25100,7 @@ var DaemonCommandRouter = class {
|
|
|
24346
25100
|
else mesh.nodes.push(node);
|
|
24347
25101
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24348
25102
|
this.inlineMeshCache.set(meshId, mesh);
|
|
25103
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
24349
25104
|
}
|
|
24350
25105
|
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
24351
25106
|
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
@@ -24354,6 +25109,7 @@ var DaemonCommandRouter = class {
|
|
|
24354
25109
|
mesh.nodes.splice(idx, 1);
|
|
24355
25110
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24356
25111
|
this.inlineMeshCache.set(meshId, mesh);
|
|
25112
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
24357
25113
|
return true;
|
|
24358
25114
|
}
|
|
24359
25115
|
normalizeMeshSessionCleanupMode(value) {
|
|
@@ -24402,7 +25158,7 @@ var DaemonCommandRouter = class {
|
|
|
24402
25158
|
}
|
|
24403
25159
|
const { resolveWorktreePath: resolveWorktreePath2, listWorktrees: listWorktrees2, removeWorktree: removeWorktree2 } = await Promise.resolve().then(() => (init_git_worktree(), git_worktree_exports));
|
|
24404
25160
|
const normalizePath = (value) => {
|
|
24405
|
-
const resolved = (0,
|
|
25161
|
+
const resolved = (0, import_path7.resolve)(value);
|
|
24406
25162
|
try {
|
|
24407
25163
|
return fs10.realpathSync(resolved);
|
|
24408
25164
|
} catch {
|
|
@@ -24566,6 +25322,7 @@ var DaemonCommandRouter = class {
|
|
|
24566
25322
|
const deletedSessionIds = [];
|
|
24567
25323
|
const skippedSessionIds = [];
|
|
24568
25324
|
const skippedLiveSessionIds = [];
|
|
25325
|
+
const skippedCoordinatorSessionIds = [];
|
|
24569
25326
|
const deleteUnsupportedSessionIds = [];
|
|
24570
25327
|
const recordsRemainSessionIds = [];
|
|
24571
25328
|
const errors = [];
|
|
@@ -24598,6 +25355,12 @@ var DaemonCommandRouter = class {
|
|
|
24598
25355
|
const completed = this.isCompletedHostedSession(record);
|
|
24599
25356
|
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
24600
25357
|
const liveRuntime = surfaceKind === "live_runtime";
|
|
25358
|
+
const coordinatorSession = readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId;
|
|
25359
|
+
if (!hasExplicitSessionIds && coordinatorSession) {
|
|
25360
|
+
skippedSessionIds.push(sessionId);
|
|
25361
|
+
skippedCoordinatorSessionIds.push(sessionId);
|
|
25362
|
+
continue;
|
|
25363
|
+
}
|
|
24601
25364
|
if (!hasExplicitSessionIds && liveRuntime) {
|
|
24602
25365
|
skippedSessionIds.push(sessionId);
|
|
24603
25366
|
skippedLiveSessionIds.push(sessionId);
|
|
@@ -24663,6 +25426,7 @@ var DaemonCommandRouter = class {
|
|
|
24663
25426
|
deletedSessionIds,
|
|
24664
25427
|
skippedSessionIds,
|
|
24665
25428
|
skippedLiveSessionIds,
|
|
25429
|
+
skippedCoordinatorSessionIds,
|
|
24666
25430
|
...deleteUnsupported ? {
|
|
24667
25431
|
deleteUnsupported: true,
|
|
24668
25432
|
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
@@ -24795,7 +25559,8 @@ var DaemonCommandRouter = class {
|
|
|
24795
25559
|
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
24796
25560
|
}
|
|
24797
25561
|
case "get_pending_mesh_events": {
|
|
24798
|
-
const
|
|
25562
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25563
|
+
const events = drainPendingMeshCoordinatorEvents(meshId || void 0);
|
|
24799
25564
|
return { success: true, events };
|
|
24800
25565
|
}
|
|
24801
25566
|
case "launch_cli":
|
|
@@ -25324,15 +26089,39 @@ var DaemonCommandRouter = class {
|
|
|
25324
26089
|
case "get_mesh": {
|
|
25325
26090
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25326
26091
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
25327
|
-
|
|
25328
|
-
|
|
25329
|
-
|
|
25330
|
-
|
|
25331
|
-
|
|
26092
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
26093
|
+
if (!meshRecord?.mesh) return { success: false, error: "Mesh not found" };
|
|
26094
|
+
const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
|
|
26095
|
+
const directTruth = await hydrateInlineMeshDirectTruth({
|
|
26096
|
+
mesh: meshRecord.mesh,
|
|
26097
|
+
meshSource: meshRecord.source,
|
|
26098
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
26099
|
+
statusInstanceId: this.deps.statusInstanceId,
|
|
26100
|
+
localMachineId: loadConfig().machineId || ""
|
|
26101
|
+
});
|
|
26102
|
+
const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
|
|
26103
|
+
const sourceOfTruth = {
|
|
26104
|
+
membership: meshRecord.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
26105
|
+
coordinatorOwnsLiveTruth: directTruthSatisfied,
|
|
26106
|
+
directPeerTruth: {
|
|
26107
|
+
required: requireDirectPeerTruth,
|
|
26108
|
+
satisfied: directTruthSatisfied,
|
|
26109
|
+
directEvidenceCount: directTruth.directEvidenceCount,
|
|
26110
|
+
localConfirmedCount: directTruth.localConfirmedCount,
|
|
26111
|
+
peerAttemptedCount: directTruth.peerAttemptedCount,
|
|
26112
|
+
peerConfirmedCount: directTruth.peerConfirmedCount,
|
|
26113
|
+
unavailableNodeIds: directTruth.unavailableNodeIds
|
|
26114
|
+
}
|
|
26115
|
+
};
|
|
26116
|
+
if (requireDirectPeerTruth && !directTruthSatisfied) {
|
|
26117
|
+
return {
|
|
26118
|
+
success: false,
|
|
26119
|
+
code: "mesh_direct_peer_truth_unavailable",
|
|
26120
|
+
error: "Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct get_mesh probes succeed.",
|
|
26121
|
+
sourceOfTruth
|
|
26122
|
+
};
|
|
25332
26123
|
}
|
|
25333
|
-
|
|
25334
|
-
if (cached) return { success: true, mesh: cached };
|
|
25335
|
-
return { success: false, error: "Mesh not found" };
|
|
26124
|
+
return { success: true, mesh: meshRecord.mesh, sourceOfTruth };
|
|
25336
26125
|
}
|
|
25337
26126
|
case "create_mesh": {
|
|
25338
26127
|
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
@@ -25362,6 +26151,7 @@ var DaemonCommandRouter = class {
|
|
|
25362
26151
|
const mesh = updateMesh2(meshId, patch);
|
|
25363
26152
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
25364
26153
|
this.inlineMeshCache.set(meshId, mesh);
|
|
26154
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
25365
26155
|
return { success: true, mesh };
|
|
25366
26156
|
} catch (e) {
|
|
25367
26157
|
return { success: false, error: e.message };
|
|
@@ -25551,26 +26341,41 @@ var DaemonCommandRouter = class {
|
|
|
25551
26341
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25552
26342
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
25553
26343
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
26344
|
+
const refineStages = [];
|
|
25554
26345
|
try {
|
|
25555
26346
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
25556
26347
|
const mesh = meshRecord?.mesh;
|
|
25557
26348
|
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
25558
|
-
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh
|
|
26349
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh`, refineStages };
|
|
25559
26350
|
if (!node.isLocalWorktree || !node.workspace) {
|
|
25560
|
-
return { success: false, error: `Refinery requires a local worktree node
|
|
26351
|
+
return { success: false, error: `Refinery requires a local worktree node`, refineStages };
|
|
25561
26352
|
}
|
|
25562
26353
|
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
25563
26354
|
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
25564
|
-
if (!repoRoot) return { success: false, error: "Source node repoRoot not found" };
|
|
26355
|
+
if (!repoRoot) return { success: false, error: "Source node repoRoot not found", refineStages };
|
|
25565
26356
|
const { execFile: execFile3 } = await import("child_process");
|
|
25566
26357
|
const { promisify: promisify3 } = await import("util");
|
|
25567
26358
|
const execFileAsync3 = promisify3(execFile3);
|
|
26359
|
+
const resolveStarted = Date.now();
|
|
25568
26360
|
const { stdout: branchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: node.workspace, encoding: "utf8" });
|
|
25569
26361
|
const branch = branchStdout.trim();
|
|
25570
|
-
if (!branch) return { success: false, error: "Could not determine branch of the worktree node" };
|
|
26362
|
+
if (!branch) return { success: false, error: "Could not determine branch of the worktree node", refineStages };
|
|
25571
26363
|
const { stdout: baseBranchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
|
|
25572
26364
|
const baseBranch = baseBranchStdout.trim();
|
|
26365
|
+
const { stdout: baseHeadStdout } = await execFileAsync3("git", ["rev-parse", "HEAD"], { cwd: repoRoot, encoding: "utf8" });
|
|
26366
|
+
const { stdout: branchHeadStdout } = await execFileAsync3("git", ["rev-parse", branch], { cwd: node.workspace, encoding: "utf8" });
|
|
26367
|
+
const baseHead = baseHeadStdout.trim();
|
|
26368
|
+
const branchHead = branchHeadStdout.trim();
|
|
26369
|
+
recordMeshRefineStage(refineStages, "resolve_refs", "passed", resolveStarted, { branch, baseBranch, baseHead, branchHead });
|
|
26370
|
+
const validationStarted = Date.now();
|
|
25573
26371
|
const validationSummary = await runMeshRefineValidationGate(mesh, node.workspace);
|
|
26372
|
+
recordMeshRefineStage(
|
|
26373
|
+
refineStages,
|
|
26374
|
+
"validation",
|
|
26375
|
+
validationSummary.status === "passed" ? "passed" : validationSummary.status === "failed" ? "failed" : "skipped",
|
|
26376
|
+
validationStarted,
|
|
26377
|
+
{ validationStatus: validationSummary.status, commandsRun: validationSummary.commandsRun.length }
|
|
26378
|
+
);
|
|
25574
26379
|
if (validationSummary.status === "failed") {
|
|
25575
26380
|
return {
|
|
25576
26381
|
success: false,
|
|
@@ -25580,6 +26385,7 @@ var DaemonCommandRouter = class {
|
|
|
25580
26385
|
branch,
|
|
25581
26386
|
into: baseBranch,
|
|
25582
26387
|
validationSummary,
|
|
26388
|
+
refineStages,
|
|
25583
26389
|
finalBranchConvergenceState: {
|
|
25584
26390
|
branch,
|
|
25585
26391
|
baseBranch,
|
|
@@ -25599,6 +26405,7 @@ var DaemonCommandRouter = class {
|
|
|
25599
26405
|
branch,
|
|
25600
26406
|
into: baseBranch,
|
|
25601
26407
|
validationSummary,
|
|
26408
|
+
refineStages,
|
|
25602
26409
|
finalBranchConvergenceState: {
|
|
25603
26410
|
branch,
|
|
25604
26411
|
baseBranch,
|
|
@@ -25609,37 +26416,121 @@ var DaemonCommandRouter = class {
|
|
|
25609
26416
|
}
|
|
25610
26417
|
};
|
|
25611
26418
|
}
|
|
26419
|
+
const patchEquivalenceStarted = Date.now();
|
|
26420
|
+
const patchEquivalence = await runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead);
|
|
26421
|
+
recordMeshRefineStage(refineStages, "patch_equivalence", patchEquivalence.status, patchEquivalenceStarted, {
|
|
26422
|
+
equivalent: patchEquivalence.equivalent,
|
|
26423
|
+
expectedPatchId: patchEquivalence.expectedPatchId,
|
|
26424
|
+
actualPatchId: patchEquivalence.actualPatchId,
|
|
26425
|
+
error: patchEquivalence.error
|
|
26426
|
+
});
|
|
26427
|
+
if (!patchEquivalence.equivalent) {
|
|
26428
|
+
return {
|
|
26429
|
+
success: false,
|
|
26430
|
+
code: "patch_equivalence_failed",
|
|
26431
|
+
convergenceStatus: "blocked_review",
|
|
26432
|
+
error: "Refinery patch-equivalence preflight failed; merge/refine was not attempted.",
|
|
26433
|
+
branch,
|
|
26434
|
+
into: baseBranch,
|
|
26435
|
+
validationSummary,
|
|
26436
|
+
patchEquivalence,
|
|
26437
|
+
refineStages,
|
|
26438
|
+
finalBranchConvergenceState: {
|
|
26439
|
+
branch,
|
|
26440
|
+
baseBranch,
|
|
26441
|
+
merged: false,
|
|
26442
|
+
removed: false,
|
|
26443
|
+
validation: "passed",
|
|
26444
|
+
patchEquivalence: "failed",
|
|
26445
|
+
status: "blocked_review"
|
|
26446
|
+
}
|
|
26447
|
+
};
|
|
26448
|
+
}
|
|
26449
|
+
let mergeResult;
|
|
26450
|
+
const mergeStarted = Date.now();
|
|
25612
26451
|
try {
|
|
25613
|
-
await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
|
|
26452
|
+
const result = await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
|
|
26453
|
+
mergeResult = {
|
|
26454
|
+
stdout: truncateValidationOutput(result.stdout),
|
|
26455
|
+
stderr: truncateValidationOutput(result.stderr),
|
|
26456
|
+
durationMs: Date.now() - mergeStarted
|
|
26457
|
+
};
|
|
26458
|
+
recordMeshRefineStage(refineStages, "merge", "passed", mergeStarted, mergeResult);
|
|
25614
26459
|
} catch (e) {
|
|
26460
|
+
recordMeshRefineStage(refineStages, "merge", "failed", mergeStarted, {
|
|
26461
|
+
error: e?.message || String(e),
|
|
26462
|
+
stdout: truncateValidationOutput(e?.stdout),
|
|
26463
|
+
stderr: truncateValidationOutput(e?.stderr)
|
|
26464
|
+
});
|
|
25615
26465
|
return {
|
|
25616
26466
|
success: false,
|
|
25617
26467
|
error: `Merge failed (conflicts?): ${e.message}`,
|
|
25618
26468
|
validationSummary,
|
|
26469
|
+
patchEquivalence,
|
|
26470
|
+
refineStages,
|
|
25619
26471
|
finalBranchConvergenceState: {
|
|
25620
26472
|
branch,
|
|
25621
26473
|
baseBranch,
|
|
25622
26474
|
merged: false,
|
|
25623
26475
|
removed: false,
|
|
25624
26476
|
validation: "passed",
|
|
26477
|
+
patchEquivalence: "passed",
|
|
25625
26478
|
status: "not_mergeable"
|
|
25626
26479
|
}
|
|
25627
26480
|
};
|
|
25628
26481
|
}
|
|
26482
|
+
const cleanupStarted = Date.now();
|
|
25629
26483
|
const removeResult = await this.execute("remove_mesh_node", {
|
|
25630
26484
|
meshId,
|
|
25631
26485
|
nodeId,
|
|
25632
|
-
sessionCleanupMode: "
|
|
26486
|
+
sessionCleanupMode: "preserve",
|
|
25633
26487
|
inlineMesh: args?.inlineMesh
|
|
25634
26488
|
});
|
|
26489
|
+
recordMeshRefineStage(refineStages, "cleanup", removeResult?.success === false ? "failed" : "passed", cleanupStarted, {
|
|
26490
|
+
removed: removeResult?.removed,
|
|
26491
|
+
code: removeResult?.code,
|
|
26492
|
+
error: removeResult?.error
|
|
26493
|
+
});
|
|
26494
|
+
let ledgerError;
|
|
26495
|
+
const ledgerStarted = Date.now();
|
|
25635
26496
|
try {
|
|
25636
26497
|
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
25637
26498
|
appendLedgerEntry2(meshId, {
|
|
25638
26499
|
kind: "node_removed",
|
|
25639
26500
|
nodeId,
|
|
25640
|
-
payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary }
|
|
26501
|
+
payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary, patchEquivalence }
|
|
25641
26502
|
});
|
|
25642
|
-
|
|
26503
|
+
recordMeshRefineStage(refineStages, "ledger", "passed", ledgerStarted);
|
|
26504
|
+
} catch (e) {
|
|
26505
|
+
ledgerError = e?.message || String(e);
|
|
26506
|
+
recordMeshRefineStage(refineStages, "ledger", "failed", ledgerStarted, { error: ledgerError });
|
|
26507
|
+
}
|
|
26508
|
+
const finalBranchConvergenceState = {
|
|
26509
|
+
branch: baseBranch,
|
|
26510
|
+
mergedBranch: branch,
|
|
26511
|
+
baseBranch,
|
|
26512
|
+
merged: true,
|
|
26513
|
+
removed: removeResult?.success !== false,
|
|
26514
|
+
validation: "passed",
|
|
26515
|
+
patchEquivalence: "passed",
|
|
26516
|
+
status: removeResult?.success === false ? "merged_cleanup_failed" : "merged"
|
|
26517
|
+
};
|
|
26518
|
+
if (removeResult?.success === false) {
|
|
26519
|
+
return {
|
|
26520
|
+
success: false,
|
|
26521
|
+
code: "cleanup_failed",
|
|
26522
|
+
error: "Refinery merge completed but worktree cleanup failed; manual cleanup/retry is required.",
|
|
26523
|
+
merged: true,
|
|
26524
|
+
branch,
|
|
26525
|
+
into: baseBranch,
|
|
26526
|
+
removeResult,
|
|
26527
|
+
validationSummary,
|
|
26528
|
+
patchEquivalence,
|
|
26529
|
+
mergeResult,
|
|
26530
|
+
refineStages,
|
|
26531
|
+
...ledgerError ? { ledgerError } : {},
|
|
26532
|
+
finalBranchConvergenceState
|
|
26533
|
+
};
|
|
25643
26534
|
}
|
|
25644
26535
|
return {
|
|
25645
26536
|
success: true,
|
|
@@ -25648,18 +26539,14 @@ var DaemonCommandRouter = class {
|
|
|
25648
26539
|
into: baseBranch,
|
|
25649
26540
|
removeResult,
|
|
25650
26541
|
validationSummary,
|
|
25651
|
-
|
|
25652
|
-
|
|
25653
|
-
|
|
25654
|
-
|
|
25655
|
-
|
|
25656
|
-
removed: removeResult?.success !== false,
|
|
25657
|
-
validation: "passed",
|
|
25658
|
-
status: removeResult?.success === false ? "merged_cleanup_failed" : "merged"
|
|
25659
|
-
}
|
|
26542
|
+
patchEquivalence,
|
|
26543
|
+
mergeResult,
|
|
26544
|
+
refineStages,
|
|
26545
|
+
...ledgerError ? { ledgerError } : {},
|
|
26546
|
+
finalBranchConvergenceState
|
|
25660
26547
|
};
|
|
25661
26548
|
} catch (e) {
|
|
25662
|
-
return { success: false, error: e.message };
|
|
26549
|
+
return { success: false, error: e.message, refineStages };
|
|
25663
26550
|
}
|
|
25664
26551
|
}
|
|
25665
26552
|
case "remove_mesh_node": {
|
|
@@ -25700,6 +26587,7 @@ var DaemonCommandRouter = class {
|
|
|
25700
26587
|
} else {
|
|
25701
26588
|
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
25702
26589
|
removed = removeNode3(meshId, nodeId);
|
|
26590
|
+
if (removed) this.invalidateAggregateMeshStatus(meshId);
|
|
25703
26591
|
}
|
|
25704
26592
|
if (removed) {
|
|
25705
26593
|
try {
|
|
@@ -25778,6 +26666,7 @@ var DaemonCommandRouter = class {
|
|
|
25778
26666
|
policy: { ...sourceNode.policy || {} }
|
|
25779
26667
|
});
|
|
25780
26668
|
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
26669
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
25781
26670
|
}
|
|
25782
26671
|
const initSubmodules = sourceNode.policy?.initSubmodulesOnClone !== false;
|
|
25783
26672
|
if (initSubmodules) {
|
|
@@ -25853,7 +26742,14 @@ var DaemonCommandRouter = class {
|
|
|
25853
26742
|
cliType
|
|
25854
26743
|
};
|
|
25855
26744
|
}
|
|
25856
|
-
const
|
|
26745
|
+
const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
|
|
26746
|
+
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
26747
|
+
const workspace = readLiveMeshNodeWorkspace({
|
|
26748
|
+
meshId,
|
|
26749
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || ""),
|
|
26750
|
+
liveSessionRecords: liveMeshSessions,
|
|
26751
|
+
allowCoordinatorSession: true
|
|
26752
|
+
}) || (typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "");
|
|
25857
26753
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
25858
26754
|
if (!cliType) {
|
|
25859
26755
|
const resolved = await resolveProviderTypeFromPriority({
|
|
@@ -26015,7 +26911,7 @@ ${block}`);
|
|
|
26015
26911
|
workspace
|
|
26016
26912
|
};
|
|
26017
26913
|
}
|
|
26018
|
-
const { existsSync:
|
|
26914
|
+
const { existsSync: existsSync26, readFileSync: readFileSync18, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
|
|
26019
26915
|
const { dirname: dirname9 } = await import("path");
|
|
26020
26916
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
26021
26917
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -26058,14 +26954,14 @@ ${block}`);
|
|
|
26058
26954
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
26059
26955
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
26060
26956
|
}
|
|
26061
|
-
const hadExistingMcpConfig =
|
|
26957
|
+
const hadExistingMcpConfig = existsSync26(mcpConfigPath);
|
|
26062
26958
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
26063
26959
|
if (hermesBaseConfig) {
|
|
26064
26960
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
|
|
26065
26961
|
}
|
|
26066
26962
|
if (hadExistingMcpConfig) {
|
|
26067
26963
|
try {
|
|
26068
|
-
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
26964
|
+
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync18(mcpConfigPath, "utf-8"), configFormat);
|
|
26069
26965
|
const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
|
|
26070
26966
|
existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
|
|
26071
26967
|
copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
|
|
@@ -26155,110 +27051,264 @@ ${block}`);
|
|
|
26155
27051
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
26156
27052
|
const mesh = meshRecord?.mesh;
|
|
26157
27053
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
27054
|
+
const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
|
|
27055
|
+
if (!refreshRequested) {
|
|
27056
|
+
const cachedStatus = this.getCachedAggregateMeshStatus(meshId);
|
|
27057
|
+
if (cachedStatus) return cachedStatus;
|
|
27058
|
+
}
|
|
27059
|
+
const refreshReason = refreshRequested ? "explicit_refresh" : "cold_cache_miss";
|
|
26158
27060
|
const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
26159
27061
|
const queue = getQueue2(meshId);
|
|
26160
27062
|
const queueSummary = getMeshQueueStats2(meshId);
|
|
26161
27063
|
const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
26162
27064
|
const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
|
|
26163
27065
|
const ledgerSummary = getLedgerSummary2(meshId);
|
|
27066
|
+
const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
|
|
27067
|
+
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
27068
|
+
const localMachineId = loadConfig().machineId || "";
|
|
27069
|
+
const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
|
|
27070
|
+
const directTruth = requireDirectPeerTruth ? await hydrateInlineMeshDirectTruth({
|
|
27071
|
+
mesh,
|
|
27072
|
+
meshSource: meshRecord.source,
|
|
27073
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
27074
|
+
statusInstanceId: this.deps.statusInstanceId,
|
|
27075
|
+
localMachineId
|
|
27076
|
+
}) : {
|
|
27077
|
+
directEvidenceCount: 0,
|
|
27078
|
+
localConfirmedCount: 0,
|
|
27079
|
+
peerAttemptedCount: 0,
|
|
27080
|
+
peerConfirmedCount: 0,
|
|
27081
|
+
unavailableNodeIds: []
|
|
27082
|
+
};
|
|
27083
|
+
const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
|
|
27084
|
+
if (requireDirectPeerTruth && !directTruthSatisfied) {
|
|
27085
|
+
return {
|
|
27086
|
+
success: false,
|
|
27087
|
+
code: "mesh_direct_peer_truth_unavailable",
|
|
27088
|
+
error: "Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct mesh_status probes succeed.",
|
|
27089
|
+
sourceOfTruth: {
|
|
27090
|
+
membership: meshRecord.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
27091
|
+
coordinatorOwnsLiveTruth: false,
|
|
27092
|
+
currentStatus: "direct_peer_truth_unavailable",
|
|
27093
|
+
directPeerTruth: {
|
|
27094
|
+
required: true,
|
|
27095
|
+
satisfied: false,
|
|
27096
|
+
directEvidenceCount: directTruth.directEvidenceCount,
|
|
27097
|
+
localConfirmedCount: directTruth.localConfirmedCount,
|
|
27098
|
+
peerAttemptedCount: directTruth.peerAttemptedCount,
|
|
27099
|
+
peerConfirmedCount: directTruth.peerConfirmedCount,
|
|
27100
|
+
unavailableNodeIds: directTruth.unavailableNodeIds
|
|
27101
|
+
}
|
|
27102
|
+
}
|
|
27103
|
+
};
|
|
27104
|
+
}
|
|
27105
|
+
const directTruthUnavailableNodeIds = new Set(directTruth.unavailableNodeIds);
|
|
27106
|
+
const selectedCoordinatorNodeId = readStringValue(
|
|
27107
|
+
mesh.coordinator?.preferredNodeId,
|
|
27108
|
+
mesh.nodes?.[0]?.id,
|
|
27109
|
+
mesh.nodes?.[0]?.nodeId
|
|
27110
|
+
);
|
|
27111
|
+
const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes) ? selectedCoordinatorNodeId : void 0;
|
|
27112
|
+
const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
26164
27113
|
const nodeStatuses = [];
|
|
26165
|
-
for (const node of mesh.nodes || []) {
|
|
27114
|
+
for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
|
|
27115
|
+
const nodeId = String(node.id || node.nodeId || "");
|
|
27116
|
+
const daemonId = readStringValue(node.daemonId);
|
|
27117
|
+
const providerPriority = readProviderPriorityFromPolicy(node.policy);
|
|
27118
|
+
const isSelfNode = Boolean(
|
|
27119
|
+
nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
|
|
27120
|
+
) || Boolean(
|
|
27121
|
+
daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
|
|
27122
|
+
) || Boolean(meshRecord?.inline && nodeIndex === 0);
|
|
26166
27123
|
const status = {
|
|
26167
|
-
nodeId
|
|
27124
|
+
nodeId,
|
|
26168
27125
|
machineLabel: node.machineLabel || node.id || node.nodeId,
|
|
26169
27126
|
workspace: node.workspace,
|
|
26170
27127
|
repoRoot: node.repoRoot,
|
|
26171
27128
|
isLocalWorktree: node.isLocalWorktree,
|
|
26172
27129
|
worktreeBranch: node.worktreeBranch,
|
|
26173
|
-
daemonId
|
|
27130
|
+
daemonId,
|
|
26174
27131
|
machineId: node.machineId,
|
|
27132
|
+
machineStatus: node.machineStatus,
|
|
26175
27133
|
health: "unknown",
|
|
26176
27134
|
providers: node.providers || [],
|
|
26177
|
-
|
|
27135
|
+
providerPriority,
|
|
27136
|
+
activeSessions: [],
|
|
27137
|
+
activeSessionDetails: [],
|
|
27138
|
+
launchReady: false
|
|
26178
27139
|
};
|
|
26179
|
-
if (
|
|
26180
|
-
|
|
26181
|
-
|
|
26182
|
-
|
|
27140
|
+
if (isSelfNode) {
|
|
27141
|
+
status.connection = {
|
|
27142
|
+
perspective: "selected_coordinator",
|
|
27143
|
+
source: "mesh_peer_status",
|
|
27144
|
+
state: "self",
|
|
27145
|
+
transport: "local",
|
|
27146
|
+
reported: true,
|
|
27147
|
+
reason: "Selected coordinator daemon",
|
|
27148
|
+
lastStateChangeAt: refreshedAt
|
|
27149
|
+
};
|
|
27150
|
+
} else if (daemonId) {
|
|
27151
|
+
const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
|
|
27152
|
+
status.connection = connection ?? {
|
|
27153
|
+
perspective: "selected_coordinator",
|
|
27154
|
+
source: "not_reported",
|
|
27155
|
+
state: "unknown",
|
|
27156
|
+
transport: "unknown",
|
|
27157
|
+
reported: false,
|
|
27158
|
+
reason: "No live mesh peer telemetry reported by the selected coordinator yet."
|
|
27159
|
+
};
|
|
27160
|
+
} else {
|
|
27161
|
+
status.connection = {
|
|
27162
|
+
perspective: "selected_coordinator",
|
|
27163
|
+
source: "not_reported",
|
|
27164
|
+
state: "unknown",
|
|
27165
|
+
transport: "unknown",
|
|
27166
|
+
reported: false,
|
|
27167
|
+
reason: "Node has no daemon id, so mesh transport cannot be reported from the selected coordinator."
|
|
27168
|
+
};
|
|
27169
|
+
}
|
|
27170
|
+
const matchedLiveSessionRecords = collectLiveMeshSessionRecords({
|
|
27171
|
+
meshId,
|
|
27172
|
+
node,
|
|
27173
|
+
nodeId,
|
|
27174
|
+
liveSessionRecords: liveMeshSessions,
|
|
27175
|
+
allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
|
|
27176
|
+
});
|
|
27177
|
+
const workspace = readLiveMeshNodeWorkspace({
|
|
27178
|
+
meshId,
|
|
27179
|
+
nodeId,
|
|
27180
|
+
liveSessionRecords: matchedLiveSessionRecords,
|
|
27181
|
+
allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
|
|
27182
|
+
}) || (typeof node.workspace === "string" ? node.workspace : "");
|
|
27183
|
+
status.workspace = workspace || node.workspace;
|
|
27184
|
+
if (matchedLiveSessionRecords.length > 0) {
|
|
27185
|
+
const sessionIds = matchedLiveSessionRecords.map((record) => typeof record?.sessionId === "string" ? record.sessionId : "").filter(Boolean);
|
|
27186
|
+
const providerTypes = matchedLiveSessionRecords.map((record) => readStringValue(record?.providerType)).filter(Boolean);
|
|
27187
|
+
status.activeSessions = sessionIds;
|
|
27188
|
+
status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
|
|
27189
|
+
if (providerTypes.length > 0) {
|
|
27190
|
+
status.providers = Array.from(/* @__PURE__ */ new Set([...Array.isArray(status.providers) ? status.providers : [], ...providerTypes]));
|
|
26183
27191
|
}
|
|
26184
|
-
|
|
26185
|
-
|
|
26186
|
-
|
|
26187
|
-
const
|
|
26188
|
-
|
|
26189
|
-
|
|
26190
|
-
|
|
26191
|
-
|
|
26192
|
-
|
|
26193
|
-
|
|
26194
|
-
|
|
26195
|
-
|
|
26196
|
-
|
|
26197
|
-
|
|
26198
|
-
|
|
26199
|
-
|
|
26200
|
-
|
|
26201
|
-
|
|
26202
|
-
|
|
26203
|
-
|
|
26204
|
-
|
|
26205
|
-
|
|
26206
|
-
|
|
26207
|
-
|
|
27192
|
+
}
|
|
27193
|
+
if (workspace) {
|
|
27194
|
+
if (!fs10.existsSync(workspace)) {
|
|
27195
|
+
const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
|
|
27196
|
+
let remoteProbeApplied = false;
|
|
27197
|
+
if (inlineTransitGit) {
|
|
27198
|
+
status.git = inlineTransitGit;
|
|
27199
|
+
status.health = inlineTransitGit.isGitRepo ? deriveMeshNodeHealthFromGit(inlineTransitGit) : "degraded";
|
|
27200
|
+
remoteProbeApplied = true;
|
|
27201
|
+
} else if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand && !directTruthUnavailableNodeIds.has(nodeId)) {
|
|
27202
|
+
try {
|
|
27203
|
+
const remoteGit = await probeRemoteMeshGitStatus({
|
|
27204
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
27205
|
+
daemonId,
|
|
27206
|
+
workspace,
|
|
27207
|
+
timeoutMs: 8e3
|
|
27208
|
+
});
|
|
27209
|
+
if (remoteGit) {
|
|
27210
|
+
status.git = remoteGit;
|
|
27211
|
+
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
27212
|
+
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
27213
|
+
remoteProbeApplied = true;
|
|
27214
|
+
}
|
|
27215
|
+
} catch {
|
|
27216
|
+
const refreshedConnection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
|
|
27217
|
+
const refreshedConnectionState = readStringValue(refreshedConnection?.state);
|
|
27218
|
+
if (refreshedConnection && refreshedConnectionState === "connected") {
|
|
27219
|
+
status.connection = refreshedConnection;
|
|
27220
|
+
try {
|
|
27221
|
+
const remoteGit = await probeRemoteMeshGitStatus({
|
|
27222
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
27223
|
+
daemonId,
|
|
27224
|
+
workspace,
|
|
27225
|
+
timeoutMs: 12e3
|
|
27226
|
+
});
|
|
27227
|
+
if (remoteGit) {
|
|
27228
|
+
status.git = remoteGit;
|
|
27229
|
+
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
27230
|
+
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
27231
|
+
remoteProbeApplied = true;
|
|
27232
|
+
}
|
|
27233
|
+
} catch {
|
|
27234
|
+
}
|
|
27235
|
+
}
|
|
26208
27236
|
}
|
|
26209
27237
|
}
|
|
26210
|
-
|
|
26211
|
-
|
|
26212
|
-
|
|
26213
|
-
|
|
26214
|
-
|
|
26215
|
-
|
|
26216
|
-
|
|
26217
|
-
if (
|
|
26218
|
-
|
|
26219
|
-
|
|
27238
|
+
if (!remoteProbeApplied) {
|
|
27239
|
+
const connectionState = readStringValue(status.connection?.state);
|
|
27240
|
+
const pendingPeerGitProbe = !inlineTransitGit && !isSelfNode && !!daemonId && (readStringValue(status.machineStatus) === "online" || readStringValue(status.health) === "online" || connectionState === "connecting" || connectionState === "connected" || connectionState === "unknown");
|
|
27241
|
+
if (pendingPeerGitProbe) {
|
|
27242
|
+
status.gitProbePending = true;
|
|
27243
|
+
status.health = "unknown";
|
|
27244
|
+
}
|
|
27245
|
+
if (applyCachedInlineMeshNodeStatus(
|
|
27246
|
+
status,
|
|
27247
|
+
node,
|
|
27248
|
+
pendingPeerGitProbe ? { skipGit: true, skipError: true, skipHealth: true } : void 0
|
|
27249
|
+
)) {
|
|
27250
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
27251
|
+
nodeStatuses.push(status);
|
|
27252
|
+
continue;
|
|
27253
|
+
}
|
|
27254
|
+
if (meshRecord?.source === "inline_cache" && !isSelfNode) {
|
|
27255
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
27256
|
+
nodeStatuses.push(status);
|
|
27257
|
+
continue;
|
|
27258
|
+
}
|
|
26220
27259
|
}
|
|
26221
|
-
|
|
26222
|
-
|
|
26223
|
-
|
|
26224
|
-
|
|
26225
|
-
|
|
26226
|
-
|
|
26227
|
-
|
|
26228
|
-
|
|
26229
|
-
|
|
26230
|
-
|
|
26231
|
-
|
|
26232
|
-
|
|
26233
|
-
|
|
26234
|
-
|
|
26235
|
-
|
|
26236
|
-
hasConflicts: false,
|
|
26237
|
-
conflictFiles: [],
|
|
26238
|
-
stashCount: stashCount ? stashCount.split("\n").filter(Boolean).length : 0,
|
|
26239
|
-
lastCheckedAt: Date.now()
|
|
26240
|
-
};
|
|
26241
|
-
status.health = branch ? dirty ? "dirty" : "online" : "degraded";
|
|
26242
|
-
} catch {
|
|
26243
|
-
if (!applyCachedInlineMeshNodeStatus(status, node)) {
|
|
26244
|
-
status.health = "degraded";
|
|
27260
|
+
} else {
|
|
27261
|
+
try {
|
|
27262
|
+
const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
27263
|
+
status.git = gitStatus;
|
|
27264
|
+
recordInlineMeshDirectGitTruth(node, gitStatus, "selected_coordinator_local_git");
|
|
27265
|
+
if (gitStatus.isGitRepo) {
|
|
27266
|
+
status.health = deriveMeshNodeHealthFromGit(gitStatus);
|
|
27267
|
+
} else {
|
|
27268
|
+
status.health = "degraded";
|
|
27269
|
+
if (gitStatus.error && !status.error) status.error = gitStatus.error;
|
|
27270
|
+
}
|
|
27271
|
+
} catch {
|
|
27272
|
+
if (!applyCachedInlineMeshNodeStatus(status, node)) {
|
|
27273
|
+
status.health = "degraded";
|
|
27274
|
+
}
|
|
26245
27275
|
}
|
|
26246
27276
|
}
|
|
26247
27277
|
} else {
|
|
26248
27278
|
applyCachedInlineMeshNodeStatus(status, node);
|
|
26249
27279
|
}
|
|
27280
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
26250
27281
|
nodeStatuses.push(status);
|
|
26251
27282
|
}
|
|
26252
|
-
|
|
27283
|
+
const statusResult = {
|
|
26253
27284
|
success: true,
|
|
26254
27285
|
meshId: mesh.id,
|
|
26255
27286
|
meshName: mesh.name,
|
|
26256
27287
|
repoIdentity: mesh.repoIdentity,
|
|
26257
27288
|
defaultBranch: mesh.defaultBranch,
|
|
27289
|
+
refreshedAt,
|
|
27290
|
+
sourceOfTruth: {
|
|
27291
|
+
membership: meshRecord?.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord?.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
27292
|
+
coordinatorOwnsLiveTruth: directTruthSatisfied,
|
|
27293
|
+
...requireDirectPeerTruth ? {
|
|
27294
|
+
currentStatus: directTruthSatisfied ? "live_git_and_session_probes" : "direct_peer_truth_unavailable",
|
|
27295
|
+
directPeerTruth: {
|
|
27296
|
+
required: true,
|
|
27297
|
+
satisfied: directTruthSatisfied,
|
|
27298
|
+
directEvidenceCount: directTruth.directEvidenceCount,
|
|
27299
|
+
localConfirmedCount: directTruth.localConfirmedCount,
|
|
27300
|
+
peerAttemptedCount: directTruth.peerAttemptedCount,
|
|
27301
|
+
peerConfirmedCount: directTruth.peerConfirmedCount,
|
|
27302
|
+
unavailableNodeIds: directTruth.unavailableNodeIds
|
|
27303
|
+
}
|
|
27304
|
+
} : {},
|
|
27305
|
+
historicalEvidenceOnly: ["recoveryHints", "ledger.summary", "queue.summary"]
|
|
27306
|
+
},
|
|
26258
27307
|
nodes: nodeStatuses,
|
|
26259
27308
|
queue: { tasks: queue, summary: queueSummary },
|
|
26260
27309
|
ledger: { entries: ledgerEntries, summary: ledgerSummary }
|
|
26261
27310
|
};
|
|
27311
|
+
return this.rememberAggregateMeshStatus(meshId, statusResult, refreshReason);
|
|
26262
27312
|
} catch (e) {
|
|
26263
27313
|
return { success: false, error: e.message };
|
|
26264
27314
|
}
|
|
@@ -34184,6 +35234,7 @@ async function initDaemonComponents(config) {
|
|
|
34184
35234
|
sessionHostControl: config.sessionHostControl,
|
|
34185
35235
|
statusInstanceId: config.statusInstanceId,
|
|
34186
35236
|
statusVersion: config.statusVersion,
|
|
35237
|
+
getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
|
|
34187
35238
|
getCdpLogFn: config.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
|
|
34188
35239
|
});
|
|
34189
35240
|
poller = new AgentStreamPoller({
|
|
@@ -34459,6 +35510,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
34459
35510
|
prepareSessionChatTailUpdate,
|
|
34460
35511
|
prepareSessionModalUpdate,
|
|
34461
35512
|
probeCdpPort,
|
|
35513
|
+
queuePendingMeshCoordinatorEvent,
|
|
34462
35514
|
readChatHistory,
|
|
34463
35515
|
readLedgerEntries,
|
|
34464
35516
|
readLedgerSlice,
|