@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.mjs
CHANGED
|
@@ -1351,13 +1351,43 @@ __export(mesh_work_queue_exports, {
|
|
|
1351
1351
|
updateSessionTaskStatus: () => updateSessionTaskStatus,
|
|
1352
1352
|
updateTaskStatus: () => updateTaskStatus
|
|
1353
1353
|
});
|
|
1354
|
-
import { existsSync as existsSync6, writeFileSync as writeFileSync3, readFileSync as readFileSync4 } from "fs";
|
|
1354
|
+
import { existsSync as existsSync6, writeFileSync as writeFileSync3, readFileSync as readFileSync4, openSync, closeSync, unlinkSync } from "fs";
|
|
1355
1355
|
import { join as join6 } from "path";
|
|
1356
1356
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
1357
1357
|
function getQueuePath(meshId) {
|
|
1358
1358
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1359
1359
|
return join6(getLedgerDir(), `${safe}.queue.json`);
|
|
1360
1360
|
}
|
|
1361
|
+
function getLockPath(meshId) {
|
|
1362
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1363
|
+
return join6(getLedgerDir(), `${safe}.queue.lock`);
|
|
1364
|
+
}
|
|
1365
|
+
function withQueueLock(meshId, fn) {
|
|
1366
|
+
const lockPath = getLockPath(meshId);
|
|
1367
|
+
let fd = -1;
|
|
1368
|
+
for (let i = 0; i < 10; i++) {
|
|
1369
|
+
try {
|
|
1370
|
+
fd = openSync(lockPath, "wx");
|
|
1371
|
+
break;
|
|
1372
|
+
} catch {
|
|
1373
|
+
const deadline = Date.now() + 30;
|
|
1374
|
+
while (Date.now() < deadline) {
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
try {
|
|
1379
|
+
return fn();
|
|
1380
|
+
} finally {
|
|
1381
|
+
if (fd !== -1) try {
|
|
1382
|
+
closeSync(fd);
|
|
1383
|
+
} catch {
|
|
1384
|
+
}
|
|
1385
|
+
try {
|
|
1386
|
+
unlinkSync(lockPath);
|
|
1387
|
+
} catch {
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1361
1391
|
function readQueue(meshId) {
|
|
1362
1392
|
const path28 = getQueuePath(meshId);
|
|
1363
1393
|
if (!existsSync6(path28)) return [];
|
|
@@ -1373,20 +1403,22 @@ function writeQueue(meshId, queue) {
|
|
|
1373
1403
|
writeFileSync3(path28, JSON.stringify(queue, null, 2), "utf-8");
|
|
1374
1404
|
}
|
|
1375
1405
|
function enqueueTask(meshId, message, opts) {
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1406
|
+
return withQueueLock(meshId, () => {
|
|
1407
|
+
const queue = readQueue(meshId);
|
|
1408
|
+
const entry = {
|
|
1409
|
+
id: randomUUID5(),
|
|
1410
|
+
meshId,
|
|
1411
|
+
message,
|
|
1412
|
+
status: "pending",
|
|
1413
|
+
targetNodeId: opts?.targetNodeId,
|
|
1414
|
+
targetSessionId: opts?.targetSessionId,
|
|
1415
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1416
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1417
|
+
};
|
|
1418
|
+
queue.push(entry);
|
|
1419
|
+
writeQueue(meshId, queue);
|
|
1420
|
+
return entry;
|
|
1421
|
+
});
|
|
1390
1422
|
}
|
|
1391
1423
|
function getQueue(meshId, opts) {
|
|
1392
1424
|
let queue = readQueue(meshId);
|
|
@@ -1397,100 +1429,111 @@ function getQueue(meshId, opts) {
|
|
|
1397
1429
|
return queue;
|
|
1398
1430
|
}
|
|
1399
1431
|
function claimNextTask(meshId, nodeId, sessionId) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1432
|
+
return withQueueLock(meshId, () => {
|
|
1433
|
+
const queue = readQueue(meshId);
|
|
1434
|
+
const hasActiveAssignment = queue.some((q) => q.status === "assigned" && (q.assignedSessionId === sessionId || q.assignedNodeId === nodeId));
|
|
1435
|
+
if (hasActiveAssignment) return null;
|
|
1436
|
+
let targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetSessionId === sessionId);
|
|
1437
|
+
if (targetIdx === -1) {
|
|
1438
|
+
targetIdx = queue.findIndex((q) => q.status === "pending" && q.targetNodeId === nodeId && !q.targetSessionId);
|
|
1439
|
+
}
|
|
1440
|
+
if (targetIdx === -1) {
|
|
1441
|
+
targetIdx = queue.findIndex((q) => q.status === "pending" && !q.targetNodeId && !q.targetSessionId);
|
|
1442
|
+
}
|
|
1443
|
+
if (targetIdx === -1) return null;
|
|
1444
|
+
const entry = queue[targetIdx];
|
|
1445
|
+
entry.status = "assigned";
|
|
1446
|
+
entry.assignedNodeId = nodeId;
|
|
1447
|
+
entry.assignedSessionId = sessionId;
|
|
1448
|
+
entry.dispatchTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1449
|
+
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1450
|
+
writeQueue(meshId, queue);
|
|
1451
|
+
return entry;
|
|
1452
|
+
});
|
|
1419
1453
|
}
|
|
1420
1454
|
function updateTaskStatus(meshId, taskId, status) {
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1455
|
+
return withQueueLock(meshId, () => {
|
|
1456
|
+
const queue = readQueue(meshId);
|
|
1457
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
1458
|
+
if (idx === -1) return null;
|
|
1459
|
+
queue[idx].status = status;
|
|
1460
|
+
queue[idx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1461
|
+
writeQueue(meshId, queue);
|
|
1462
|
+
return queue[idx];
|
|
1463
|
+
});
|
|
1428
1464
|
}
|
|
1429
1465
|
function recordTaskAutoLaunch(meshId, taskId, autoLaunch) {
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
...autoLaunch,
|
|
1436
|
-
updatedAt
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
return queue[idx];
|
|
1466
|
+
return withQueueLock(meshId, () => {
|
|
1467
|
+
const queue = readQueue(meshId);
|
|
1468
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
1469
|
+
if (idx === -1) return null;
|
|
1470
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1471
|
+
queue[idx].autoLaunch = { ...autoLaunch, updatedAt: now };
|
|
1472
|
+
queue[idx].updatedAt = now;
|
|
1473
|
+
writeQueue(meshId, queue);
|
|
1474
|
+
return queue[idx];
|
|
1475
|
+
});
|
|
1441
1476
|
}
|
|
1442
1477
|
function cancelTask(meshId, taskId, opts) {
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1478
|
+
return withQueueLock(meshId, () => {
|
|
1479
|
+
const queue = readQueue(meshId);
|
|
1480
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
1481
|
+
if (idx === -1) return null;
|
|
1482
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1483
|
+
queue[idx].status = "cancelled";
|
|
1484
|
+
queue[idx].updatedAt = now;
|
|
1485
|
+
queue[idx].cancelledAt = now;
|
|
1486
|
+
if (opts?.reason) queue[idx].cancelReason = opts.reason;
|
|
1487
|
+
writeQueue(meshId, queue);
|
|
1488
|
+
return queue[idx];
|
|
1489
|
+
});
|
|
1453
1490
|
}
|
|
1454
1491
|
function requeueTask(meshId, taskId, opts) {
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1492
|
+
return withQueueLock(meshId, () => {
|
|
1493
|
+
const queue = readQueue(meshId);
|
|
1494
|
+
const idx = queue.findIndex((q) => q.id === taskId);
|
|
1495
|
+
if (idx === -1) return null;
|
|
1496
|
+
const entry = queue[idx];
|
|
1497
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1498
|
+
entry.status = "pending";
|
|
1499
|
+
delete entry.assignedNodeId;
|
|
1500
|
+
delete entry.assignedSessionId;
|
|
1501
|
+
delete entry.cancelledAt;
|
|
1502
|
+
delete entry.cancelReason;
|
|
1503
|
+
if (opts?.clearTargetNode) delete entry.targetNodeId;
|
|
1504
|
+
if (typeof opts?.targetNodeId === "string") entry.targetNodeId = opts.targetNodeId;
|
|
1505
|
+
if (opts?.clearTargetSession !== false) delete entry.targetSessionId;
|
|
1506
|
+
if (typeof opts?.targetSessionId === "string") entry.targetSessionId = opts.targetSessionId;
|
|
1507
|
+
entry.updatedAt = now;
|
|
1508
|
+
entry.requeuedAt = now;
|
|
1509
|
+
entry.requeueCount = (entry.requeueCount || 0) + 1;
|
|
1510
|
+
if (opts?.reason) entry.requeueReason = opts.reason;
|
|
1511
|
+
writeQueue(meshId, queue);
|
|
1512
|
+
return entry;
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
function updateSessionTaskStatus(meshId, sessionId, status, opts) {
|
|
1516
|
+
return withQueueLock(meshId, () => {
|
|
1517
|
+
const queue = readQueue(meshId);
|
|
1518
|
+
const occurredAtTime = opts?.occurredAt ? new Date(opts.occurredAt).getTime() : Number.NaN;
|
|
1519
|
+
const hasOccurredAt = Number.isFinite(occurredAtTime);
|
|
1520
|
+
let bestIdx = -1;
|
|
1521
|
+
let bestTime = 0;
|
|
1522
|
+
for (let i = queue.length - 1; i >= 0; i--) {
|
|
1523
|
+
if (queue[i].assignedSessionId !== sessionId || queue[i].status !== "assigned") continue;
|
|
1482
1524
|
const time = new Date(queue[i].dispatchTimestamp || queue[i].updatedAt).getTime();
|
|
1525
|
+
if (hasOccurredAt && Number.isFinite(time) && time > occurredAtTime) continue;
|
|
1483
1526
|
if (time > bestTime) {
|
|
1484
1527
|
bestTime = time;
|
|
1485
1528
|
bestIdx = i;
|
|
1486
1529
|
}
|
|
1487
1530
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1531
|
+
if (bestIdx === -1) return null;
|
|
1532
|
+
queue[bestIdx].status = status;
|
|
1533
|
+
queue[bestIdx].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1534
|
+
writeQueue(meshId, queue);
|
|
1535
|
+
return queue[bestIdx];
|
|
1536
|
+
});
|
|
1494
1537
|
}
|
|
1495
1538
|
function getMeshQueueStats(meshId) {
|
|
1496
1539
|
const queue = readQueue(meshId);
|
|
@@ -1890,18 +1933,77 @@ __export(mesh_events_exports, {
|
|
|
1890
1933
|
drainPendingMeshCoordinatorEvents: () => drainPendingMeshCoordinatorEvents,
|
|
1891
1934
|
getPendingMeshCoordinatorEvents: () => getPendingMeshCoordinatorEvents,
|
|
1892
1935
|
handleMeshForwardEvent: () => handleMeshForwardEvent,
|
|
1936
|
+
queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
|
|
1893
1937
|
setupMeshEventForwarding: () => setupMeshEventForwarding,
|
|
1894
1938
|
triggerMeshQueue: () => triggerMeshQueue,
|
|
1895
1939
|
tryAssignQueueTask: () => tryAssignQueueTask
|
|
1896
1940
|
});
|
|
1897
|
-
|
|
1898
|
-
|
|
1941
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync9, readFileSync as readFileSync5, unlinkSync as unlinkSync3 } from "fs";
|
|
1942
|
+
import { join as join9 } from "path";
|
|
1943
|
+
function sweepExpiredRemoteIdleSessions() {
|
|
1944
|
+
const now = Date.now();
|
|
1945
|
+
for (const [key, session] of remoteIdleSessions) {
|
|
1946
|
+
if (session.expiresAt <= now) remoteIdleSessions.delete(key);
|
|
1947
|
+
}
|
|
1899
1948
|
}
|
|
1900
|
-
function
|
|
1901
|
-
|
|
1949
|
+
function getPendingEventsPath(meshId) {
|
|
1950
|
+
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1951
|
+
return join9(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
1952
|
+
}
|
|
1953
|
+
function queuePendingMeshCoordinatorEvent(event) {
|
|
1954
|
+
try {
|
|
1955
|
+
appendFileSync3(getPendingEventsPath(event.meshId), JSON.stringify(event) + "\n", "utf-8");
|
|
1956
|
+
return true;
|
|
1957
|
+
} catch (e) {
|
|
1958
|
+
LOG.warn("MeshEvents", `Failed to persist pending coordinator event: ${e?.message || e}`);
|
|
1959
|
+
return false;
|
|
1960
|
+
}
|
|
1902
1961
|
}
|
|
1903
|
-
function
|
|
1904
|
-
|
|
1962
|
+
function drainPendingMeshCoordinatorEvents(meshId) {
|
|
1963
|
+
if (!meshId) return [];
|
|
1964
|
+
const path28 = getPendingEventsPath(meshId);
|
|
1965
|
+
if (!existsSync9(path28)) return [];
|
|
1966
|
+
try {
|
|
1967
|
+
const raw = readFileSync5(path28, "utf-8");
|
|
1968
|
+
try {
|
|
1969
|
+
unlinkSync3(path28);
|
|
1970
|
+
} catch {
|
|
1971
|
+
}
|
|
1972
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
1973
|
+
try {
|
|
1974
|
+
return [JSON.parse(line)];
|
|
1975
|
+
} catch {
|
|
1976
|
+
return [];
|
|
1977
|
+
}
|
|
1978
|
+
});
|
|
1979
|
+
} catch {
|
|
1980
|
+
return [];
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
function getPendingMeshCoordinatorEvents(meshId) {
|
|
1984
|
+
if (!meshId) return [];
|
|
1985
|
+
const path28 = getPendingEventsPath(meshId);
|
|
1986
|
+
if (!existsSync9(path28)) return [];
|
|
1987
|
+
try {
|
|
1988
|
+
const raw = readFileSync5(path28, "utf-8");
|
|
1989
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
1990
|
+
try {
|
|
1991
|
+
return [JSON.parse(line)];
|
|
1992
|
+
} catch {
|
|
1993
|
+
return [];
|
|
1994
|
+
}
|
|
1995
|
+
});
|
|
1996
|
+
} catch {
|
|
1997
|
+
return [];
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
function clearPendingMeshCoordinatorEvents(meshId) {
|
|
2001
|
+
if (!meshId) return;
|
|
2002
|
+
const path28 = getPendingEventsPath(meshId);
|
|
2003
|
+
if (existsSync9(path28)) try {
|
|
2004
|
+
unlinkSync3(path28);
|
|
2005
|
+
} catch {
|
|
2006
|
+
}
|
|
1905
2007
|
}
|
|
1906
2008
|
function readNonEmptyString(value) {
|
|
1907
2009
|
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
@@ -1947,6 +2049,38 @@ function shouldSuppressIntentionalCleanupStop(args) {
|
|
|
1947
2049
|
if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
|
|
1948
2050
|
return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
|
|
1949
2051
|
}
|
|
2052
|
+
function readEventTimestamp(value) {
|
|
2053
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2054
|
+
if (typeof value === "string" && value.trim()) {
|
|
2055
|
+
const numeric = Number(value);
|
|
2056
|
+
if (Number.isFinite(numeric)) return numeric;
|
|
2057
|
+
const parsed = Date.parse(value);
|
|
2058
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
2059
|
+
}
|
|
2060
|
+
return null;
|
|
2061
|
+
}
|
|
2062
|
+
function buildMeshCompletionFingerprint(args) {
|
|
2063
|
+
const timestampPart = Number.isFinite(args.timestamp) ? String(args.timestamp) : readNonEmptyString(args.finalSummary).slice(0, 200);
|
|
2064
|
+
return [
|
|
2065
|
+
args.meshId,
|
|
2066
|
+
args.event,
|
|
2067
|
+
args.sessionId,
|
|
2068
|
+
args.providerType || "",
|
|
2069
|
+
args.providerSessionId || "",
|
|
2070
|
+
timestampPart
|
|
2071
|
+
].join("::");
|
|
2072
|
+
}
|
|
2073
|
+
function isDuplicateMeshCompletionEvent(args) {
|
|
2074
|
+
const fingerprint = buildMeshCompletionFingerprint(args);
|
|
2075
|
+
if (!fingerprint) return false;
|
|
2076
|
+
const now = Date.now();
|
|
2077
|
+
for (const [key, seenAt] of recentCompletionFingerprints.entries()) {
|
|
2078
|
+
if (now - seenAt > RECENT_COMPLETION_FINGERPRINT_TTL_MS) recentCompletionFingerprints.delete(key);
|
|
2079
|
+
}
|
|
2080
|
+
if (recentCompletionFingerprints.has(fingerprint)) return true;
|
|
2081
|
+
recentCompletionFingerprints.set(fingerprint, now);
|
|
2082
|
+
return false;
|
|
2083
|
+
}
|
|
1950
2084
|
function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType) {
|
|
1951
2085
|
const task = claimNextTask(meshId, nodeId, sessionId);
|
|
1952
2086
|
if (!task) {
|
|
@@ -1965,7 +2099,16 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
1965
2099
|
message: task.message
|
|
1966
2100
|
}).catch((e) => {
|
|
1967
2101
|
LOG.error("MeshQueue", `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
|
|
1968
|
-
updateTaskStatus(meshId, task.id, "
|
|
2102
|
+
updateTaskStatus(meshId, task.id, "pending");
|
|
2103
|
+
try {
|
|
2104
|
+
appendLedgerEntry(meshId, {
|
|
2105
|
+
kind: "dispatch_failed",
|
|
2106
|
+
nodeId,
|
|
2107
|
+
sessionId,
|
|
2108
|
+
payload: { taskId: task.id, error: e?.message, retryable: true }
|
|
2109
|
+
});
|
|
2110
|
+
} catch {
|
|
2111
|
+
}
|
|
1969
2112
|
});
|
|
1970
2113
|
return true;
|
|
1971
2114
|
}
|
|
@@ -2299,18 +2442,36 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2299
2442
|
LOG.info("MeshEvents", `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || "(unknown session)"}`);
|
|
2300
2443
|
return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
|
|
2301
2444
|
}
|
|
2445
|
+
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
2446
|
+
if (args.event === "agent:generating_completed" && eventSessionId) {
|
|
2447
|
+
const duplicateCompletion = isDuplicateMeshCompletionEvent({
|
|
2448
|
+
meshId: args.meshId,
|
|
2449
|
+
event: args.event,
|
|
2450
|
+
sessionId: eventSessionId,
|
|
2451
|
+
providerType: readNonEmptyString(args.metadataEvent.providerType) || void 0,
|
|
2452
|
+
providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || void 0,
|
|
2453
|
+
timestamp: eventTimestamp,
|
|
2454
|
+
finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || void 0
|
|
2455
|
+
});
|
|
2456
|
+
if (duplicateCompletion) {
|
|
2457
|
+
LOG.info("MeshEvents", `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
|
|
2458
|
+
return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2302
2461
|
let completedTaskForLedger = null;
|
|
2303
2462
|
if (args.event === "agent:generating_completed") {
|
|
2304
2463
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
2305
2464
|
const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
|
|
2306
2465
|
const providerType = readNonEmptyString(args.metadataEvent.providerType);
|
|
2307
2466
|
if (sessionId) {
|
|
2308
|
-
const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed"
|
|
2467
|
+
const completedTask = updateSessionTaskStatus(args.meshId, sessionId, "completed", {
|
|
2468
|
+
occurredAt: eventTimestamp !== null ? new Date(eventTimestamp).toISOString() : void 0
|
|
2469
|
+
});
|
|
2309
2470
|
completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
|
|
2310
2471
|
if (nodeId && providerType) {
|
|
2311
|
-
|
|
2472
|
+
setImmediate(() => {
|
|
2312
2473
|
tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
2313
|
-
}
|
|
2474
|
+
});
|
|
2314
2475
|
}
|
|
2315
2476
|
}
|
|
2316
2477
|
} else if (args.event === "agent:ready") {
|
|
@@ -2348,13 +2509,17 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2348
2509
|
}
|
|
2349
2510
|
}
|
|
2350
2511
|
if (sessionId && nodeId && providerType) {
|
|
2351
|
-
|
|
2352
|
-
|
|
2512
|
+
sweepExpiredRemoteIdleSessions();
|
|
2513
|
+
remoteIdleSessions.set(`${nodeId}:${sessionId}`, {
|
|
2514
|
+
nodeId,
|
|
2515
|
+
sessionId,
|
|
2516
|
+
providerType,
|
|
2517
|
+
expiresAt: Date.now() + REMOTE_IDLE_SESSION_TTL_MS
|
|
2518
|
+
});
|
|
2519
|
+
setImmediate(() => {
|
|
2353
2520
|
const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
|
|
2354
|
-
if (assigned) {
|
|
2355
|
-
|
|
2356
|
-
}
|
|
2357
|
-
}, 500);
|
|
2521
|
+
if (assigned) remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
|
|
2522
|
+
});
|
|
2358
2523
|
}
|
|
2359
2524
|
} else if (args.event === "agent:generating_started") {
|
|
2360
2525
|
const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
|
|
@@ -2465,17 +2630,18 @@ function injectMeshSystemMessage(components, args) {
|
|
|
2465
2630
|
return true;
|
|
2466
2631
|
});
|
|
2467
2632
|
if (coordinatorInstances.length === 0) {
|
|
2468
|
-
if (
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
}
|
|
2477
|
-
|
|
2478
|
-
|
|
2633
|
+
if (queuePendingMeshCoordinatorEvent({
|
|
2634
|
+
event: args.event,
|
|
2635
|
+
meshId: args.meshId,
|
|
2636
|
+
nodeLabel: args.nodeLabel,
|
|
2637
|
+
nodeId: args.nodeId || void 0,
|
|
2638
|
+
workspace: readNonEmptyString(args.metadataEvent.workspace),
|
|
2639
|
+
metadataEvent: {
|
|
2640
|
+
...args.metadataEvent,
|
|
2641
|
+
...recoveryContext ? { recoveryContext } : {}
|
|
2642
|
+
},
|
|
2643
|
+
queuedAt: Date.now()
|
|
2644
|
+
})) {
|
|
2479
2645
|
LOG.info("MeshEvents", `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
|
|
2480
2646
|
}
|
|
2481
2647
|
return { success: true, forwarded: 0 };
|
|
@@ -2514,6 +2680,7 @@ function handleMeshForwardEvent(components, payload) {
|
|
|
2514
2680
|
providerType: readNonEmptyString(payload.providerType),
|
|
2515
2681
|
providerSessionId: readNonEmptyString(payload.providerSessionId),
|
|
2516
2682
|
finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
|
|
2683
|
+
...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
|
|
2517
2684
|
intentional: payload.intentional === true,
|
|
2518
2685
|
intentionalStop: payload.intentionalStop === true,
|
|
2519
2686
|
operatorCleanup: payload.operatorCleanup === true,
|
|
@@ -2556,7 +2723,7 @@ function setupMeshEventForwarding(components) {
|
|
|
2556
2723
|
});
|
|
2557
2724
|
});
|
|
2558
2725
|
}
|
|
2559
|
-
var
|
|
2726
|
+
var REMOTE_IDLE_SESSION_TTL_MS, remoteIdleSessions, MESH_COORDINATOR_EVENTS, EVENT_TO_LEDGER_KIND, INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS, RECENT_COMPLETION_FINGERPRINT_TTL_MS, recentCompletionFingerprints, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS;
|
|
2560
2727
|
var init_mesh_events = __esm({
|
|
2561
2728
|
"src/mesh/mesh-events.ts"() {
|
|
2562
2729
|
"use strict";
|
|
@@ -2566,9 +2733,8 @@ var init_mesh_events = __esm({
|
|
|
2566
2733
|
init_logger();
|
|
2567
2734
|
init_mesh_ledger();
|
|
2568
2735
|
init_mesh_work_queue();
|
|
2736
|
+
REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1e3;
|
|
2569
2737
|
remoteIdleSessions = /* @__PURE__ */ new Map();
|
|
2570
|
-
MAX_PENDING_EVENTS = 50;
|
|
2571
|
-
pendingMeshCoordinatorEvents = [];
|
|
2572
2738
|
MESH_COORDINATOR_EVENTS = /* @__PURE__ */ new Set([
|
|
2573
2739
|
"agent:generating_started",
|
|
2574
2740
|
"agent:generating_completed",
|
|
@@ -2584,6 +2750,8 @@ var init_mesh_events = __esm({
|
|
|
2584
2750
|
"monitor:long_generating": "task_stalled"
|
|
2585
2751
|
};
|
|
2586
2752
|
INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1e3;
|
|
2753
|
+
RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1e3;
|
|
2754
|
+
recentCompletionFingerprints = /* @__PURE__ */ new Map();
|
|
2587
2755
|
autoLaunchInProgress = /* @__PURE__ */ new Set();
|
|
2588
2756
|
autoLaunchCooldownUntil = /* @__PURE__ */ new Map();
|
|
2589
2757
|
AUTO_LAUNCH_COOLDOWN_MS = 5e3;
|
|
@@ -5676,8 +5844,14 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5676
5844
|
const includeSubmodules = options.includeSubmodules !== false;
|
|
5677
5845
|
try {
|
|
5678
5846
|
const repo = await resolveGitRepository(workspace, options);
|
|
5679
|
-
|
|
5680
|
-
|
|
5847
|
+
let parsed = await readPorcelainStatus(repo, options);
|
|
5848
|
+
let upstreamProbe = getInitialUpstreamProbe(parsed);
|
|
5849
|
+
if (options.refreshUpstream) {
|
|
5850
|
+
upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
|
|
5851
|
+
if (upstreamProbe.upstreamStatus === "fresh") {
|
|
5852
|
+
parsed = await readPorcelainStatus(repo, options);
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5681
5855
|
const head = await readHead(repo, options);
|
|
5682
5856
|
const stashCount = await readStashCount(repo, options);
|
|
5683
5857
|
let submodules;
|
|
@@ -5692,6 +5866,9 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5692
5866
|
headCommit: head.commit,
|
|
5693
5867
|
headMessage: head.message,
|
|
5694
5868
|
upstream: parsed.upstream,
|
|
5869
|
+
upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
|
|
5870
|
+
upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
|
|
5871
|
+
upstreamFetchError: upstreamProbe.upstreamFetchError,
|
|
5695
5872
|
ahead: parsed.ahead,
|
|
5696
5873
|
behind: parsed.behind,
|
|
5697
5874
|
staged: parsed.staged,
|
|
@@ -5716,6 +5893,60 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5716
5893
|
);
|
|
5717
5894
|
}
|
|
5718
5895
|
}
|
|
5896
|
+
async function readPorcelainStatus(repo, options) {
|
|
5897
|
+
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
5898
|
+
return parsePorcelainV2Status(statusOutput.stdout);
|
|
5899
|
+
}
|
|
5900
|
+
function getInitialUpstreamProbe(parsed) {
|
|
5901
|
+
return {
|
|
5902
|
+
upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
|
|
5903
|
+
};
|
|
5904
|
+
}
|
|
5905
|
+
async function refreshTrackedUpstream(repo, parsed, options) {
|
|
5906
|
+
if (!parsed.upstream || !parsed.branch) {
|
|
5907
|
+
return { upstreamStatus: "no_upstream" };
|
|
5908
|
+
}
|
|
5909
|
+
const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
|
|
5910
|
+
if (!remoteName) {
|
|
5911
|
+
return {
|
|
5912
|
+
upstreamStatus: "stale",
|
|
5913
|
+
upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
|
|
5914
|
+
};
|
|
5915
|
+
}
|
|
5916
|
+
try {
|
|
5917
|
+
await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
|
|
5918
|
+
return {
|
|
5919
|
+
upstreamStatus: "fresh",
|
|
5920
|
+
upstreamFetchedAt: Date.now()
|
|
5921
|
+
};
|
|
5922
|
+
} catch (error) {
|
|
5923
|
+
return {
|
|
5924
|
+
upstreamStatus: "stale",
|
|
5925
|
+
upstreamFetchError: formatGitError(error)
|
|
5926
|
+
};
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5929
|
+
async function readBranchRemote(repo, branch, options) {
|
|
5930
|
+
try {
|
|
5931
|
+
const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
|
|
5932
|
+
return result.stdout.trim() || null;
|
|
5933
|
+
} catch {
|
|
5934
|
+
return null;
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
function inferRemoteName(upstream) {
|
|
5938
|
+
const [remoteName] = upstream.split("/");
|
|
5939
|
+
return remoteName?.trim() || null;
|
|
5940
|
+
}
|
|
5941
|
+
function formatGitError(error) {
|
|
5942
|
+
if (error instanceof GitCommandError) {
|
|
5943
|
+
return error.stderr || error.message;
|
|
5944
|
+
}
|
|
5945
|
+
if (error instanceof Error) {
|
|
5946
|
+
return error.message;
|
|
5947
|
+
}
|
|
5948
|
+
return String(error);
|
|
5949
|
+
}
|
|
5719
5950
|
function parsePorcelainV2Status(output) {
|
|
5720
5951
|
const parsed = {
|
|
5721
5952
|
branch: null,
|
|
@@ -5810,6 +6041,7 @@ function emptyStatus(workspace, lastCheckedAt, error) {
|
|
|
5810
6041
|
headCommit: null,
|
|
5811
6042
|
headMessage: null,
|
|
5812
6043
|
upstream: null,
|
|
6044
|
+
upstreamStatus: "unavailable",
|
|
5813
6045
|
ahead: 0,
|
|
5814
6046
|
behind: 0,
|
|
5815
6047
|
staged: 0,
|
|
@@ -6090,6 +6322,9 @@ function createGitCompactSummary(status, diffSummary) {
|
|
|
6090
6322
|
isGitRepo: status.isGitRepo,
|
|
6091
6323
|
repoRoot: status.repoRoot,
|
|
6092
6324
|
branch: status.branch,
|
|
6325
|
+
upstreamStatus: status.upstreamStatus,
|
|
6326
|
+
upstreamFetchedAt: status.upstreamFetchedAt,
|
|
6327
|
+
upstreamFetchError: status.upstreamFetchError,
|
|
6093
6328
|
dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
|
|
6094
6329
|
changedFiles,
|
|
6095
6330
|
ahead: status.ahead,
|
|
@@ -6434,7 +6669,7 @@ var defaultSnapshotStore = createGitSnapshotStore({
|
|
|
6434
6669
|
});
|
|
6435
6670
|
function createDefaultGitCommandServices() {
|
|
6436
6671
|
return {
|
|
6437
|
-
getStatus: ({ workspace }) => getGitRepoStatus(workspace),
|
|
6672
|
+
getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
|
|
6438
6673
|
getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
|
|
6439
6674
|
getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
|
|
6440
6675
|
createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
|
|
@@ -6520,7 +6755,7 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
|
|
|
6520
6755
|
switch (command) {
|
|
6521
6756
|
case "git_status": {
|
|
6522
6757
|
if (!services.getStatus) return serviceNotImplemented(command);
|
|
6523
|
-
const status = await runService(() => services.getStatus({ workspace }));
|
|
6758
|
+
const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
|
|
6524
6759
|
return "success" in status ? status : { success: true, status };
|
|
6525
6760
|
}
|
|
6526
6761
|
case "git_diff_summary": {
|
|
@@ -7559,8 +7794,8 @@ var P2pRelayFailureError = class extends Error {
|
|
|
7559
7794
|
|
|
7560
7795
|
// src/config/state-store.ts
|
|
7561
7796
|
init_config();
|
|
7562
|
-
import { existsSync as
|
|
7563
|
-
import { join as
|
|
7797
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
7798
|
+
import { join as join10 } from "path";
|
|
7564
7799
|
var DEFAULT_STATE = {
|
|
7565
7800
|
recentActivity: [],
|
|
7566
7801
|
savedProviderSessions: [],
|
|
@@ -7573,7 +7808,7 @@ function isPlainObject2(value) {
|
|
|
7573
7808
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
7574
7809
|
}
|
|
7575
7810
|
function getStatePath() {
|
|
7576
|
-
return
|
|
7811
|
+
return join10(getConfigDir(), "state.json");
|
|
7577
7812
|
}
|
|
7578
7813
|
function normalizeState(raw) {
|
|
7579
7814
|
const parsed = isPlainObject2(raw) ? raw : {};
|
|
@@ -7609,11 +7844,11 @@ function normalizeState(raw) {
|
|
|
7609
7844
|
}
|
|
7610
7845
|
function loadState() {
|
|
7611
7846
|
const statePath = getStatePath();
|
|
7612
|
-
if (!
|
|
7847
|
+
if (!existsSync10(statePath)) {
|
|
7613
7848
|
return { ...DEFAULT_STATE };
|
|
7614
7849
|
}
|
|
7615
7850
|
try {
|
|
7616
|
-
const raw =
|
|
7851
|
+
const raw = readFileSync6(statePath, "utf-8");
|
|
7617
7852
|
return normalizeState(JSON.parse(raw));
|
|
7618
7853
|
} catch {
|
|
7619
7854
|
return { ...DEFAULT_STATE };
|
|
@@ -7630,7 +7865,7 @@ function resetState() {
|
|
|
7630
7865
|
|
|
7631
7866
|
// src/detection/ide-detector.ts
|
|
7632
7867
|
import { execSync } from "child_process";
|
|
7633
|
-
import { existsSync as
|
|
7868
|
+
import { existsSync as existsSync11 } from "fs";
|
|
7634
7869
|
import { platform as platform2, homedir as homedir5 } from "os";
|
|
7635
7870
|
import * as path10 from "path";
|
|
7636
7871
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
@@ -7654,7 +7889,7 @@ function findCliCommand(command) {
|
|
|
7654
7889
|
if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
7655
7890
|
const candidate = trimmed.startsWith("~") ? path10.join(homedir5(), trimmed.slice(1)) : trimmed;
|
|
7656
7891
|
const resolved = path10.isAbsolute(candidate) ? candidate : path10.resolve(candidate);
|
|
7657
|
-
return
|
|
7892
|
+
return existsSync11(resolved) ? resolved : null;
|
|
7658
7893
|
}
|
|
7659
7894
|
try {
|
|
7660
7895
|
const result = execSync(
|
|
@@ -7685,9 +7920,9 @@ function checkPathExists(paths) {
|
|
|
7685
7920
|
if (normalized.includes("*")) {
|
|
7686
7921
|
const username = home.split(/[\\/]/).pop() || "";
|
|
7687
7922
|
const resolved = normalized.replace("*", username);
|
|
7688
|
-
if (
|
|
7923
|
+
if (existsSync11(resolved)) return resolved;
|
|
7689
7924
|
} else {
|
|
7690
|
-
if (
|
|
7925
|
+
if (existsSync11(normalized)) return normalized;
|
|
7691
7926
|
}
|
|
7692
7927
|
}
|
|
7693
7928
|
return null;
|
|
@@ -7701,7 +7936,7 @@ async function detectIDEs(providerLoader) {
|
|
|
7701
7936
|
let resolvedCli = cliPath;
|
|
7702
7937
|
if (!resolvedCli && appPath && os22 === "darwin") {
|
|
7703
7938
|
const bundledCli = `${appPath}/Contents/Resources/app/bin/${def.cli}`;
|
|
7704
|
-
if (
|
|
7939
|
+
if (existsSync11(bundledCli)) resolvedCli = bundledCli;
|
|
7705
7940
|
}
|
|
7706
7941
|
if (!resolvedCli && appPath && os22 === "win32") {
|
|
7707
7942
|
const { dirname: dirname9 } = await import("path");
|
|
@@ -7714,7 +7949,7 @@ async function detectIDEs(providerLoader) {
|
|
|
7714
7949
|
`${appDir}\\\\resources\\\\app\\\\bin\\\\${def.cli}.cmd`
|
|
7715
7950
|
];
|
|
7716
7951
|
for (const c of candidates) {
|
|
7717
|
-
if (
|
|
7952
|
+
if (existsSync11(c)) {
|
|
7718
7953
|
resolvedCli = c;
|
|
7719
7954
|
break;
|
|
7720
7955
|
}
|
|
@@ -9606,7 +9841,8 @@ var StatusMonitor = class {
|
|
|
9606
9841
|
};
|
|
9607
9842
|
|
|
9608
9843
|
// src/providers/chat-message-normalization.ts
|
|
9609
|
-
|
|
9844
|
+
var DEFAULT_FINAL_SUMMARY_MAX_CHARS = 4e3;
|
|
9845
|
+
function extractFinalSummaryFromMessages(messages, maxChars = DEFAULT_FINAL_SUMMARY_MAX_CHARS) {
|
|
9610
9846
|
if (!Array.isArray(messages) || messages.length === 0) return "";
|
|
9611
9847
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
9612
9848
|
const msg = messages[i];
|
|
@@ -16869,7 +17105,7 @@ init_config();
|
|
|
16869
17105
|
import * as os13 from "os";
|
|
16870
17106
|
import * as path18 from "path";
|
|
16871
17107
|
import * as crypto4 from "crypto";
|
|
16872
|
-
import { existsSync as
|
|
17108
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
16873
17109
|
import { execFileSync } from "child_process";
|
|
16874
17110
|
import chalk from "chalk";
|
|
16875
17111
|
|
|
@@ -19343,7 +19579,7 @@ function commandExists(command) {
|
|
|
19343
19579
|
const trimmed = command.trim();
|
|
19344
19580
|
if (!trimmed) return false;
|
|
19345
19581
|
if (isExplicitCommand(trimmed)) {
|
|
19346
|
-
return
|
|
19582
|
+
return existsSync15(expandExecutable(trimmed));
|
|
19347
19583
|
}
|
|
19348
19584
|
try {
|
|
19349
19585
|
execFileSync(process.platform === "win32" ? "where" : "which", [trimmed], {
|
|
@@ -22612,10 +22848,10 @@ import * as yaml from "js-yaml";
|
|
|
22612
22848
|
// src/commands/mesh-coordinator.ts
|
|
22613
22849
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
22614
22850
|
import { createHash as createHash2 } from "crypto";
|
|
22615
|
-
import { existsSync as
|
|
22851
|
+
import { existsSync as existsSync18, readdirSync as readdirSync7, realpathSync as realpathSync2 } from "fs";
|
|
22616
22852
|
import { createRequire as createRequire2 } from "module";
|
|
22617
22853
|
import * as os17 from "os";
|
|
22618
|
-
import { dirname as dirname4, isAbsolute as isAbsolute11, join as
|
|
22854
|
+
import { dirname as dirname4, isAbsolute as isAbsolute11, join as join21, resolve as resolve13 } from "path";
|
|
22619
22855
|
var DEFAULT_SERVER_NAME = "adhdev-mesh";
|
|
22620
22856
|
var DEFAULT_ADHDEV_MCP_COMMAND = "adhdev-mcp";
|
|
22621
22857
|
var HERMES_CLI_TYPE = "hermes-cli";
|
|
@@ -22638,7 +22874,7 @@ function resolveHermesMeshCoordinatorSetup(options) {
|
|
|
22638
22874
|
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
22639
22875
|
};
|
|
22640
22876
|
}
|
|
22641
|
-
const configPath =
|
|
22877
|
+
const configPath = join21(resolveHermesCoordinatorHome(options.meshId, options.workspace), "config.yaml");
|
|
22642
22878
|
if (!configPath.trim()) {
|
|
22643
22879
|
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
22644
22880
|
}
|
|
@@ -22759,14 +22995,14 @@ function resolveHermesCoordinatorHome(meshId, workspace) {
|
|
|
22759
22995
|
const key = `${meshId || "mesh"}
|
|
22760
22996
|
${resolve13(workspace || os17.tmpdir())}`;
|
|
22761
22997
|
const hash = createHash2("sha256").update(key).digest("hex").slice(0, 16);
|
|
22762
|
-
return
|
|
22998
|
+
return join21(os17.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash}`);
|
|
22763
22999
|
}
|
|
22764
23000
|
function resolveMcpConfigPath(configPath, workspace) {
|
|
22765
23001
|
const trimmed = configPath.trim();
|
|
22766
23002
|
if (trimmed === "~") return os17.homedir();
|
|
22767
|
-
if (trimmed.startsWith("~/")) return
|
|
23003
|
+
if (trimmed.startsWith("~/")) return join21(os17.homedir(), trimmed.slice(2));
|
|
22768
23004
|
if (isAbsolute11(trimmed)) return trimmed;
|
|
22769
|
-
return
|
|
23005
|
+
return join21(workspace, trimmed);
|
|
22770
23006
|
}
|
|
22771
23007
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
22772
23008
|
const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
@@ -22822,15 +23058,15 @@ function addNodeCandidatesFromPath(pathValue, addCandidate) {
|
|
|
22822
23058
|
for (const entry of (pathValue || "").split(":")) {
|
|
22823
23059
|
const dir = entry.trim();
|
|
22824
23060
|
if (!dir) continue;
|
|
22825
|
-
addCandidate(
|
|
23061
|
+
addCandidate(join21(dir, "node"));
|
|
22826
23062
|
}
|
|
22827
23063
|
}
|
|
22828
23064
|
function addNodeCandidatesFromNvm(homeDir, addCandidate) {
|
|
22829
|
-
const versionsDir =
|
|
23065
|
+
const versionsDir = join21(homeDir, ".nvm", "versions", "node");
|
|
22830
23066
|
try {
|
|
22831
23067
|
const versionDirs = readdirSync7(versionsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(compareNodeVersionNamesDescending);
|
|
22832
23068
|
for (const versionDir of versionDirs) {
|
|
22833
|
-
addCandidate(
|
|
23069
|
+
addCandidate(join21(versionsDir, versionDir, "bin", "node"));
|
|
22834
23070
|
}
|
|
22835
23071
|
} catch {
|
|
22836
23072
|
}
|
|
@@ -22881,7 +23117,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
22881
23117
|
if (normalized) return normalized;
|
|
22882
23118
|
}
|
|
22883
23119
|
try {
|
|
22884
|
-
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] :
|
|
23120
|
+
const requireBase = process.argv[1] ? normalizeExistingPath(process.argv[1]) || process.argv[1] : join21(process.cwd(), "adhdev-daemon.js");
|
|
22885
23121
|
const req = createRequire2(requireBase);
|
|
22886
23122
|
const resolvedModule = req.resolve("@adhdev/mcp-server");
|
|
22887
23123
|
return normalizeExistingPath(resolvedModule) || resolvedModule;
|
|
@@ -22891,7 +23127,7 @@ function resolveAdhdevMcpEntryPath(explicitPath) {
|
|
|
22891
23127
|
}
|
|
22892
23128
|
function normalizeExistingPath(filePath) {
|
|
22893
23129
|
try {
|
|
22894
|
-
if (!
|
|
23130
|
+
if (!existsSync18(filePath)) return null;
|
|
22895
23131
|
return realpathSync2.native(filePath);
|
|
22896
23132
|
} catch {
|
|
22897
23133
|
return null;
|
|
@@ -23603,55 +23839,45 @@ function readBooleanValue(...values) {
|
|
|
23603
23839
|
}
|
|
23604
23840
|
return void 0;
|
|
23605
23841
|
}
|
|
23606
|
-
function
|
|
23607
|
-
const
|
|
23608
|
-
const
|
|
23609
|
-
if (
|
|
23610
|
-
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
|
|
23614
|
-
|
|
23615
|
-
|
|
23616
|
-
|
|
23617
|
-
|
|
23618
|
-
|
|
23619
|
-
|
|
23620
|
-
|
|
23621
|
-
|
|
23622
|
-
|
|
23623
|
-
|
|
23624
|
-
|
|
23625
|
-
|
|
23626
|
-
|
|
23627
|
-
|
|
23628
|
-
|
|
23629
|
-
|
|
23630
|
-
|
|
23631
|
-
|
|
23632
|
-
|
|
23633
|
-
|
|
23634
|
-
|
|
23635
|
-
}
|
|
23636
|
-
}
|
|
23637
|
-
const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
|
|
23638
|
-
const gitResult = readObjectRecord(rawGit.result);
|
|
23639
|
-
const directStatus = readObjectRecord(rawGit.status);
|
|
23640
|
-
const nestedStatus = readObjectRecord(gitResult.status);
|
|
23641
|
-
const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
|
|
23642
|
-
const probeGit = readObjectRecord(rawProbe.git);
|
|
23643
|
-
const probeGitResult = readObjectRecord(probeGit.result);
|
|
23644
|
-
const probeDirectStatus = readObjectRecord(probeGit.status);
|
|
23645
|
-
const probeNestedStatus = readObjectRecord(probeGitResult.status);
|
|
23646
|
-
const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
|
|
23842
|
+
function joinRepoPath(root, relativePath) {
|
|
23843
|
+
const normalizedRoot = typeof root === "string" ? root.trim().replace(/[\\/]+$/, "") : "";
|
|
23844
|
+
const normalizedPath = typeof relativePath === "string" ? relativePath.trim() : "";
|
|
23845
|
+
if (!normalizedPath) return void 0;
|
|
23846
|
+
if (/^(?:[A-Za-z]:[\\/]|\/)/.test(normalizedPath)) return normalizedPath;
|
|
23847
|
+
if (!normalizedRoot) return void 0;
|
|
23848
|
+
return `${normalizedRoot}/${normalizedPath.replace(/^[\\/]+/, "")}`;
|
|
23849
|
+
}
|
|
23850
|
+
function readGitSubmodules(value, parentRepoRoot) {
|
|
23851
|
+
if (!Array.isArray(value)) return void 0;
|
|
23852
|
+
const submodules = value.map((entry) => {
|
|
23853
|
+
const submodule = readObjectRecord(entry);
|
|
23854
|
+
const path28 = readStringValue(submodule.path);
|
|
23855
|
+
const commit = readStringValue(submodule.commit);
|
|
23856
|
+
const repoPath = readStringValue(submodule.repoPath, submodule.repo_root) ?? joinRepoPath(parentRepoRoot, path28);
|
|
23857
|
+
if (!path28 || !commit || !repoPath) return null;
|
|
23858
|
+
return {
|
|
23859
|
+
path: path28,
|
|
23860
|
+
commit,
|
|
23861
|
+
repoPath,
|
|
23862
|
+
dirty: readBooleanValue(submodule.dirty) ?? false,
|
|
23863
|
+
outOfSync: readBooleanValue(submodule.outOfSync, submodule.out_of_sync) ?? false,
|
|
23864
|
+
lastCheckedAt: readNumberValue(submodule.lastCheckedAt, submodule.last_checked_at) ?? Date.now(),
|
|
23865
|
+
...readStringValue(submodule.error) ? { error: readStringValue(submodule.error) } : {}
|
|
23866
|
+
};
|
|
23867
|
+
}).filter((entry) => entry !== null);
|
|
23868
|
+
return submodules.length > 0 ? submodules : void 0;
|
|
23869
|
+
}
|
|
23870
|
+
function normalizeInlineMeshGitStatus(status, node, options) {
|
|
23647
23871
|
const isGitRepo = readBooleanValue(status.isGitRepo);
|
|
23648
23872
|
if (!Object.keys(status).length || isGitRepo === void 0) return void 0;
|
|
23649
23873
|
const conflictFiles = Array.isArray(status.conflictFiles) ? status.conflictFiles.filter((value) => typeof value === "string") : [];
|
|
23650
23874
|
const conflictCount = readNumberValue(status.conflicts) ?? conflictFiles.length;
|
|
23651
23875
|
const hasConflicts = readBooleanValue(status.hasConflicts) ?? conflictCount > 0;
|
|
23876
|
+
const repoRoot = readStringValue(status.repoRoot, status.repo_root, node?.repoRoot, node?.repo_root, status.workspace, node?.workspace) || void 0;
|
|
23877
|
+
const submodules = readGitSubmodules(status.submodules, repoRoot);
|
|
23652
23878
|
return {
|
|
23653
23879
|
workspace: readStringValue(status.workspace, node?.workspace) || "",
|
|
23654
|
-
repoRoot:
|
|
23880
|
+
repoRoot: repoRoot ?? null,
|
|
23655
23881
|
isGitRepo,
|
|
23656
23882
|
branch: readStringValue(status.branch) ?? null,
|
|
23657
23883
|
headCommit: readStringValue(status.headCommit) ?? null,
|
|
@@ -23667,29 +23893,412 @@ function buildCachedInlineMeshGitStatus(node) {
|
|
|
23667
23893
|
hasConflicts,
|
|
23668
23894
|
conflictFiles,
|
|
23669
23895
|
stashCount: readNumberValue(status.stashCount) ?? 0,
|
|
23670
|
-
lastCheckedAt: Date.now()
|
|
23896
|
+
lastCheckedAt: options?.lastCheckedAt ?? readNumberValue(status.lastCheckedAt) ?? Date.now(),
|
|
23897
|
+
...submodules ? { submodules } : {}
|
|
23671
23898
|
};
|
|
23672
23899
|
}
|
|
23673
|
-
function
|
|
23900
|
+
function buildInlineMeshTransitGitStatus(node) {
|
|
23901
|
+
const rawGit = readObjectRecord(node?.lastGit ?? node?.last_git);
|
|
23902
|
+
const gitResult = readObjectRecord(rawGit.result);
|
|
23903
|
+
const directStatus = readObjectRecord(rawGit.status);
|
|
23904
|
+
const nestedStatus = readObjectRecord(gitResult.status);
|
|
23905
|
+
const rawProbe = readObjectRecord(node?.lastProbe ?? node?.last_probe);
|
|
23906
|
+
const probeGit = readObjectRecord(rawProbe.git);
|
|
23907
|
+
const probeGitResult = readObjectRecord(probeGit.result);
|
|
23908
|
+
const probeDirectStatus = readObjectRecord(probeGit.status);
|
|
23909
|
+
const probeNestedStatus = readObjectRecord(probeGitResult.status);
|
|
23910
|
+
const status = Object.keys(directStatus).length ? directStatus : Object.keys(nestedStatus).length ? nestedStatus : Object.keys(probeDirectStatus).length ? probeDirectStatus : Object.keys(probeNestedStatus).length ? probeNestedStatus : {};
|
|
23911
|
+
return normalizeInlineMeshGitStatus(status, node, { lastCheckedAt: Date.now() });
|
|
23912
|
+
}
|
|
23913
|
+
function recordInlineMeshDirectGitTruth(node, git, source) {
|
|
23914
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return;
|
|
23915
|
+
const checkedAt = readNumberValue(git.lastCheckedAt) ?? Date.now();
|
|
23916
|
+
const updatedAt = new Date(checkedAt).toISOString();
|
|
23917
|
+
const nextGit = {
|
|
23918
|
+
...git,
|
|
23919
|
+
lastCheckedAt: checkedAt
|
|
23920
|
+
};
|
|
23921
|
+
node.lastGit = {
|
|
23922
|
+
source,
|
|
23923
|
+
checkedAt,
|
|
23924
|
+
status: nextGit
|
|
23925
|
+
};
|
|
23926
|
+
node.last_git = node.lastGit;
|
|
23927
|
+
node.machineStatus = "online";
|
|
23928
|
+
node.updatedAt = updatedAt;
|
|
23929
|
+
node.lastSeenAt = updatedAt;
|
|
23930
|
+
const repoRoot = readStringValue(nextGit.repoRoot);
|
|
23931
|
+
if (repoRoot && !readStringValue(node.repoRoot)) node.repoRoot = repoRoot;
|
|
23932
|
+
}
|
|
23933
|
+
function buildCachedInlineMeshGitStatus(node) {
|
|
23934
|
+
const liveGit = buildInlineMeshTransitGitStatus(node);
|
|
23935
|
+
if (liveGit) return liveGit;
|
|
23674
23936
|
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
23675
|
-
const
|
|
23676
|
-
|
|
23677
|
-
|
|
23937
|
+
const cachedGit = readObjectRecord(cachedStatus.git);
|
|
23938
|
+
if (!Object.keys(cachedGit).length) return void 0;
|
|
23939
|
+
return normalizeInlineMeshGitStatus(cachedGit, node);
|
|
23940
|
+
}
|
|
23941
|
+
function shouldDiscardCachedInlineMeshStatus(node) {
|
|
23942
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
23943
|
+
if (!Object.keys(cachedStatus).length) return false;
|
|
23944
|
+
const cachedGit = readObjectRecord(cachedStatus.git);
|
|
23945
|
+
const workspaceError = readStringValue(cachedStatus.error, node?.error);
|
|
23946
|
+
if (workspaceError && /workspace must be an existing directory/i.test(workspaceError)) return true;
|
|
23947
|
+
const isGitRepo = readBooleanValue(cachedGit.isGitRepo);
|
|
23948
|
+
const branch = readStringValue(cachedGit.branch);
|
|
23949
|
+
const headCommit = readStringValue(cachedGit.headCommit);
|
|
23950
|
+
return isGitRepo === false && !branch && !headCommit;
|
|
23951
|
+
}
|
|
23952
|
+
function stripInlineMeshTransientNodeState(node) {
|
|
23953
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return node;
|
|
23954
|
+
const {
|
|
23955
|
+
cachedStatus,
|
|
23956
|
+
lastGit: _lastGit,
|
|
23957
|
+
last_git: _lastGitLegacy,
|
|
23958
|
+
lastProbe: _lastProbe,
|
|
23959
|
+
last_probe: _lastProbeLegacy,
|
|
23960
|
+
error: _error,
|
|
23961
|
+
health: _health,
|
|
23962
|
+
machineStatus: _machineStatus,
|
|
23963
|
+
lastSeenAt: _lastSeenAt,
|
|
23964
|
+
last_seen_at: _lastSeenAtLegacy,
|
|
23965
|
+
updatedAt: _updatedAt,
|
|
23966
|
+
updated_at: _updatedAtLegacy,
|
|
23967
|
+
activeSession: _activeSession,
|
|
23968
|
+
active_session: _activeSessionLegacy,
|
|
23969
|
+
activeSessionId: _activeSessionId,
|
|
23970
|
+
active_session_id: _activeSessionIdLegacy,
|
|
23971
|
+
sessionId: _sessionId,
|
|
23972
|
+
session_id: _sessionIdLegacy,
|
|
23973
|
+
providerType: _providerType,
|
|
23974
|
+
provider_type: _providerTypeLegacy,
|
|
23975
|
+
...rest
|
|
23976
|
+
} = node;
|
|
23977
|
+
if (cachedStatus && !shouldDiscardCachedInlineMeshStatus(node)) {
|
|
23978
|
+
return { ...rest, cachedStatus };
|
|
23979
|
+
}
|
|
23980
|
+
return rest;
|
|
23981
|
+
}
|
|
23982
|
+
function hasInlineMeshTransientNodeState(node) {
|
|
23983
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) return false;
|
|
23984
|
+
return "cachedStatus" in node || "lastGit" in node || "last_git" in node || "lastProbe" in node || "last_probe" in node || "error" in node || "health" in node || "machineStatus" in node || "lastSeenAt" in node || "last_seen_at" in node || "updatedAt" in node || "updated_at" in node || "activeSession" in node || "active_session" in node || "activeSessionId" in node || "active_session_id" in node || "sessionId" in node || "session_id" in node || "providerType" in node || "provider_type" in node;
|
|
23985
|
+
}
|
|
23986
|
+
function inlineMeshCarriesTransientNodeTruth(inlineMesh) {
|
|
23987
|
+
if (!inlineMesh || typeof inlineMesh !== "object" || Array.isArray(inlineMesh)) return false;
|
|
23988
|
+
if (!Array.isArray(inlineMesh.nodes) || inlineMesh.nodes.length === 0) return false;
|
|
23989
|
+
return inlineMesh.nodes.some((node) => hasInlineMeshTransientNodeState(node));
|
|
23990
|
+
}
|
|
23991
|
+
function readInlineMeshNodeId(node) {
|
|
23992
|
+
return readStringValue(node?.id, node?.nodeId) || "";
|
|
23993
|
+
}
|
|
23994
|
+
function sanitizeInlineMesh(inlineMesh) {
|
|
23995
|
+
if (!inlineMesh || typeof inlineMesh !== "object" || Array.isArray(inlineMesh)) return inlineMesh;
|
|
23996
|
+
if (!Array.isArray(inlineMesh.nodes)) return inlineMesh;
|
|
23997
|
+
let changed = false;
|
|
23998
|
+
const nodes = inlineMesh.nodes.map((node) => {
|
|
23999
|
+
if (!hasInlineMeshTransientNodeState(node)) return node;
|
|
24000
|
+
changed = true;
|
|
24001
|
+
return stripInlineMeshTransientNodeState(node);
|
|
24002
|
+
});
|
|
24003
|
+
if (!changed) return inlineMesh;
|
|
24004
|
+
return {
|
|
24005
|
+
...inlineMesh,
|
|
24006
|
+
nodes
|
|
24007
|
+
};
|
|
24008
|
+
}
|
|
24009
|
+
function reconcileInlineMeshCache(cached, incoming) {
|
|
24010
|
+
if (!cached || typeof cached !== "object" || Array.isArray(cached)) return incoming;
|
|
24011
|
+
if (!incoming || typeof incoming !== "object" || Array.isArray(incoming)) return cached;
|
|
24012
|
+
const cachedNodes = Array.isArray(cached.nodes) ? cached.nodes : [];
|
|
24013
|
+
const incomingNodes = Array.isArray(incoming.nodes) ? incoming.nodes : [];
|
|
24014
|
+
if (!cachedNodes.length || !incomingNodes.length) return { ...cached, ...incoming };
|
|
24015
|
+
const incomingById = /* @__PURE__ */ new Map();
|
|
24016
|
+
for (const node of incomingNodes) {
|
|
24017
|
+
const nodeId = readInlineMeshNodeId(node);
|
|
24018
|
+
if (nodeId) incomingById.set(nodeId, node);
|
|
24019
|
+
}
|
|
24020
|
+
const nodes = cachedNodes.map((cachedNode) => {
|
|
24021
|
+
const nodeId = readInlineMeshNodeId(cachedNode);
|
|
24022
|
+
const incomingNode = nodeId ? incomingById.get(nodeId) : void 0;
|
|
24023
|
+
if (!incomingNode) return cachedNode;
|
|
24024
|
+
if (hasInlineMeshTransientNodeState(incomingNode)) {
|
|
24025
|
+
return { ...cachedNode, ...incomingNode };
|
|
24026
|
+
}
|
|
24027
|
+
return { ...stripInlineMeshTransientNodeState(cachedNode), ...incomingNode };
|
|
24028
|
+
});
|
|
24029
|
+
return {
|
|
24030
|
+
...cached,
|
|
24031
|
+
...incoming,
|
|
24032
|
+
nodes
|
|
24033
|
+
};
|
|
24034
|
+
}
|
|
24035
|
+
function hasGitWorktreeChanges(git) {
|
|
24036
|
+
if (!git) return false;
|
|
24037
|
+
return Number(git.staged || 0) + Number(git.modified || 0) + Number(git.untracked || 0) + Number(git.deleted || 0) + Number(git.renamed || 0) > 0;
|
|
24038
|
+
}
|
|
24039
|
+
function getGitSubmoduleDriftState(git) {
|
|
24040
|
+
const submodules = Array.isArray(git?.submodules) ? git.submodules : [];
|
|
24041
|
+
let dirty = false;
|
|
24042
|
+
let outOfSync = false;
|
|
24043
|
+
for (const entry of submodules) {
|
|
24044
|
+
const submodule = readObjectRecord(entry);
|
|
24045
|
+
if (readBooleanValue(submodule.dirty) === true) dirty = true;
|
|
24046
|
+
if (readBooleanValue(submodule.outOfSync) === true || !!readStringValue(submodule.error)) outOfSync = true;
|
|
24047
|
+
}
|
|
24048
|
+
return { dirty, outOfSync };
|
|
24049
|
+
}
|
|
24050
|
+
function deriveMeshNodeHealthFromGit(git) {
|
|
24051
|
+
if (!git || readBooleanValue(git.isGitRepo) === false) return "degraded";
|
|
24052
|
+
const branch = readStringValue(git.branch);
|
|
24053
|
+
if (!branch) return "degraded";
|
|
24054
|
+
const submoduleDrift = getGitSubmoduleDriftState(git);
|
|
24055
|
+
if (submoduleDrift.outOfSync) return "degraded";
|
|
24056
|
+
if (submoduleDrift.dirty || hasGitWorktreeChanges(git)) return "dirty";
|
|
24057
|
+
return "online";
|
|
24058
|
+
}
|
|
24059
|
+
function readCachedInlineMeshActiveSessions(node) {
|
|
24060
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24061
|
+
const activeSession = readObjectRecord(cachedStatus.activeSession);
|
|
24062
|
+
const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
|
|
24063
|
+
const sessionId = readStringValue(fallbackSession.id, fallbackSession.sessionId, fallbackSession.session_id, node?.activeSessionId, node?.active_session_id, node?.sessionId, node?.session_id);
|
|
24064
|
+
return sessionId ? [sessionId] : [];
|
|
24065
|
+
}
|
|
24066
|
+
function readCachedInlineMeshActiveSessionDetails(node) {
|
|
24067
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24068
|
+
const activeSession = readObjectRecord(cachedStatus.activeSession);
|
|
24069
|
+
const fallbackSession = Object.keys(activeSession).length ? activeSession : readObjectRecord(node?.activeSession ?? node?.active_session);
|
|
24070
|
+
const sessionId = readStringValue(
|
|
24071
|
+
fallbackSession.id,
|
|
24072
|
+
fallbackSession.sessionId,
|
|
24073
|
+
fallbackSession.session_id,
|
|
24074
|
+
node?.activeSessionId,
|
|
24075
|
+
node?.active_session_id,
|
|
24076
|
+
node?.sessionId,
|
|
24077
|
+
node?.session_id
|
|
24078
|
+
);
|
|
24079
|
+
if (!sessionId) return [];
|
|
24080
|
+
return [{
|
|
24081
|
+
sessionId,
|
|
24082
|
+
providerType: readStringValue(
|
|
24083
|
+
fallbackSession.providerType,
|
|
24084
|
+
fallbackSession.provider_type,
|
|
24085
|
+
fallbackSession.cliType,
|
|
24086
|
+
fallbackSession.cli_type,
|
|
24087
|
+
fallbackSession.provider,
|
|
24088
|
+
node?.providerType,
|
|
24089
|
+
node?.provider_type
|
|
24090
|
+
),
|
|
24091
|
+
state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
|
|
24092
|
+
lifecycle: readStringValue(fallbackSession.lifecycle),
|
|
24093
|
+
title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
|
|
24094
|
+
workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
|
|
24095
|
+
lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
|
|
24096
|
+
recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
|
|
24097
|
+
isCached: true
|
|
24098
|
+
}];
|
|
24099
|
+
}
|
|
24100
|
+
function readLiveMeshSessionState(record) {
|
|
24101
|
+
return readStringValue(
|
|
24102
|
+
record?.meta?.sessionStatus,
|
|
24103
|
+
record?.meta?.status,
|
|
24104
|
+
record?.meta?.providerStatus,
|
|
24105
|
+
record?.status,
|
|
24106
|
+
record?.state,
|
|
24107
|
+
record?.lifecycle
|
|
24108
|
+
);
|
|
24109
|
+
}
|
|
24110
|
+
function toIsoTimestamp(value) {
|
|
24111
|
+
if (typeof value === "number" && Number.isFinite(value)) return new Date(value).toISOString();
|
|
24112
|
+
const stringValue = readStringValue(value);
|
|
24113
|
+
return stringValue || null;
|
|
24114
|
+
}
|
|
24115
|
+
function synthesizeMeshNodeFreshnessFromConnection(status) {
|
|
24116
|
+
const connection = readObjectRecord(status.connection);
|
|
24117
|
+
const connectionFreshAt = toIsoTimestamp(connection.lastCommandAt ?? connection.lastConnectedAt ?? connection.lastStateChangeAt);
|
|
24118
|
+
const git = readObjectRecord(status.git);
|
|
24119
|
+
const gitCheckedAt = toIsoTimestamp(git.lastCheckedAt);
|
|
24120
|
+
if (!status.lastSeenAt && connectionFreshAt) status.lastSeenAt = connectionFreshAt;
|
|
24121
|
+
if (!status.updatedAt && (gitCheckedAt || connectionFreshAt)) {
|
|
24122
|
+
status.updatedAt = gitCheckedAt ?? connectionFreshAt;
|
|
24123
|
+
}
|
|
24124
|
+
}
|
|
24125
|
+
function finalizeMeshNodeStatus(args) {
|
|
24126
|
+
const { status, node, daemonId, isSelfNode } = args;
|
|
24127
|
+
if (!readStringValue(status.machineStatus)) {
|
|
24128
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24129
|
+
const machineStatus = readStringValue(cachedStatus.machineStatus, cachedStatus.machine_status, node?.machineStatus);
|
|
24130
|
+
if (machineStatus) status.machineStatus = machineStatus;
|
|
24131
|
+
}
|
|
24132
|
+
synthesizeMeshNodeFreshnessFromConnection(status);
|
|
24133
|
+
const connectionState = readStringValue(readObjectRecord(status.connection).state);
|
|
24134
|
+
status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || connectionState === "connected" || isSelfNode);
|
|
24135
|
+
}
|
|
24136
|
+
async function probeRemoteMeshGitStatus(args) {
|
|
24137
|
+
if (!args.dispatchMeshCommand) return null;
|
|
24138
|
+
const remoteResult = await Promise.race([
|
|
24139
|
+
args.dispatchMeshCommand(args.daemonId, "git_status", { workspace: args.workspace }),
|
|
24140
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), args.timeoutMs))
|
|
24141
|
+
]);
|
|
24142
|
+
const remoteGit = remoteResult?.status ?? remoteResult?.git ?? remoteResult;
|
|
24143
|
+
return remoteGit && typeof remoteGit === "object" && typeof remoteGit.isGitRepo === "boolean" ? remoteGit : null;
|
|
24144
|
+
}
|
|
24145
|
+
async function hydrateInlineMeshDirectTruth(args) {
|
|
24146
|
+
const nodes = Array.isArray(args.mesh?.nodes) ? args.mesh.nodes : [];
|
|
24147
|
+
if (!nodes.length) {
|
|
24148
|
+
return {
|
|
24149
|
+
directEvidenceCount: 0,
|
|
24150
|
+
localConfirmedCount: 0,
|
|
24151
|
+
peerAttemptedCount: 0,
|
|
24152
|
+
peerConfirmedCount: 0,
|
|
24153
|
+
unavailableNodeIds: []
|
|
24154
|
+
};
|
|
24155
|
+
}
|
|
24156
|
+
const selectedCoordinatorNodeId = readStringValue(
|
|
24157
|
+
args.mesh?.coordinator?.preferredNodeId,
|
|
24158
|
+
nodes[0]?.id,
|
|
24159
|
+
nodes[0]?.nodeId
|
|
24160
|
+
);
|
|
24161
|
+
let localConfirmedCount = 0;
|
|
24162
|
+
let peerAttemptedCount = 0;
|
|
24163
|
+
let peerConfirmedCount = 0;
|
|
24164
|
+
const unavailableNodeIds = [];
|
|
24165
|
+
for (const [nodeIndex, node] of nodes.entries()) {
|
|
24166
|
+
const nodeId = readStringValue(node?.id, node?.nodeId) || `node_${nodeIndex}`;
|
|
24167
|
+
const workspace = readStringValue(node?.workspace);
|
|
24168
|
+
const daemonId = readStringValue(node?.daemonId);
|
|
24169
|
+
const isSelfNode = Boolean(
|
|
24170
|
+
nodeId && selectedCoordinatorNodeId && nodeId === selectedCoordinatorNodeId
|
|
24171
|
+
) || Boolean(
|
|
24172
|
+
daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId)
|
|
24173
|
+
) || Boolean(args.meshSource !== "local_config" && nodeIndex === 0);
|
|
24174
|
+
if (!workspace) {
|
|
24175
|
+
if (!isSelfNode && daemonId) unavailableNodeIds.push(nodeId);
|
|
24176
|
+
continue;
|
|
24177
|
+
}
|
|
24178
|
+
if (isSelfNode && fs10.existsSync(workspace)) {
|
|
24179
|
+
try {
|
|
24180
|
+
const localGit = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
24181
|
+
if (localGit?.isGitRepo) {
|
|
24182
|
+
recordInlineMeshDirectGitTruth(node, localGit, "selected_coordinator_local_git");
|
|
24183
|
+
localConfirmedCount += 1;
|
|
24184
|
+
continue;
|
|
24185
|
+
}
|
|
24186
|
+
} catch {
|
|
24187
|
+
}
|
|
24188
|
+
}
|
|
24189
|
+
if (!daemonId || !args.dispatchMeshCommand) {
|
|
24190
|
+
if (!isSelfNode) unavailableNodeIds.push(nodeId);
|
|
24191
|
+
continue;
|
|
24192
|
+
}
|
|
24193
|
+
peerAttemptedCount += 1;
|
|
24194
|
+
try {
|
|
24195
|
+
const remoteGit = await probeRemoteMeshGitStatus({
|
|
24196
|
+
dispatchMeshCommand: args.dispatchMeshCommand,
|
|
24197
|
+
daemonId,
|
|
24198
|
+
workspace,
|
|
24199
|
+
timeoutMs: 8e3
|
|
24200
|
+
});
|
|
24201
|
+
if (remoteGit) {
|
|
24202
|
+
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
24203
|
+
peerConfirmedCount += 1;
|
|
24204
|
+
continue;
|
|
24205
|
+
}
|
|
24206
|
+
} catch {
|
|
24207
|
+
}
|
|
24208
|
+
unavailableNodeIds.push(nodeId);
|
|
24209
|
+
}
|
|
24210
|
+
return {
|
|
24211
|
+
directEvidenceCount: localConfirmedCount + peerConfirmedCount,
|
|
24212
|
+
localConfirmedCount,
|
|
24213
|
+
peerAttemptedCount,
|
|
24214
|
+
peerConfirmedCount,
|
|
24215
|
+
unavailableNodeIds
|
|
24216
|
+
};
|
|
24217
|
+
}
|
|
24218
|
+
function summarizeMeshSessionRecord(record) {
|
|
24219
|
+
return {
|
|
24220
|
+
sessionId: readStringValue(record?.sessionId) || "unknown",
|
|
24221
|
+
providerType: readStringValue(record?.providerType),
|
|
24222
|
+
state: readLiveMeshSessionState(record),
|
|
24223
|
+
lifecycle: readStringValue(record?.lifecycle),
|
|
24224
|
+
surfaceKind: getSessionHostSurfaceKind(record),
|
|
24225
|
+
recoveryState: readStringValue(record?.meta?.runtimeRecoveryState) ?? null,
|
|
24226
|
+
workspace: readStringValue(record?.workspace) ?? null,
|
|
24227
|
+
title: readStringValue(record?.displayName, record?.workspaceLabel) ?? null,
|
|
24228
|
+
lastActivityAt: toIsoTimestamp(record?.updatedAt ?? record?.lastActivityAt ?? record?.last_activity_at),
|
|
24229
|
+
isCached: false
|
|
24230
|
+
};
|
|
24231
|
+
}
|
|
24232
|
+
function liveSessionRecordMatchesMeshNode(record, meshId, nodeId) {
|
|
24233
|
+
const recordNodeId = readStringValue(record?.meta?.meshNodeId);
|
|
24234
|
+
if (!recordNodeId || recordNodeId !== nodeId) return false;
|
|
24235
|
+
const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
|
|
24236
|
+
return !recordMeshId || recordMeshId === meshId;
|
|
24237
|
+
}
|
|
24238
|
+
function liveSessionRecordMatchesMeshWorkspace(record, meshId, workspace) {
|
|
24239
|
+
const recordWorkspace = readStringValue(record?.workspace);
|
|
24240
|
+
if (!recordWorkspace || !workspace || recordWorkspace !== workspace) return false;
|
|
24241
|
+
const recordMeshId = readStringValue(record?.meta?.meshNodeFor);
|
|
24242
|
+
if (recordMeshId) return recordMeshId === meshId;
|
|
24243
|
+
return record?.meta?.launchedByCoordinator === true || !!readStringValue(record?.meta?.meshNodeId);
|
|
24244
|
+
}
|
|
24245
|
+
function readLiveMeshNodeWorkspace(args) {
|
|
24246
|
+
const directNodeWorkspace = args.liveSessionRecords.find((record) => liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId) && readStringValue(record?.workspace));
|
|
24247
|
+
if (directNodeWorkspace) {
|
|
24248
|
+
return readStringValue(directNodeWorkspace.workspace) || "";
|
|
24249
|
+
}
|
|
24250
|
+
if (args.allowCoordinatorSession) {
|
|
24251
|
+
const coordinatorWorkspace = args.liveSessionRecords.find((record) => readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId && readStringValue(record?.workspace));
|
|
24252
|
+
if (coordinatorWorkspace) {
|
|
24253
|
+
return readStringValue(coordinatorWorkspace.workspace) || "";
|
|
24254
|
+
}
|
|
24255
|
+
}
|
|
24256
|
+
return "";
|
|
24257
|
+
}
|
|
24258
|
+
function collectLiveMeshSessionRecords(args) {
|
|
24259
|
+
const matches = args.liveSessionRecords.filter((record) => {
|
|
24260
|
+
const nodeWorkspace = readStringValue(args.node?.workspace);
|
|
24261
|
+
if (liveSessionRecordMatchesMeshNode(record, args.meshId, args.nodeId)) return true;
|
|
24262
|
+
return !!nodeWorkspace && liveSessionRecordMatchesMeshWorkspace(record, args.meshId, nodeWorkspace);
|
|
24263
|
+
});
|
|
24264
|
+
if (args.allowCoordinatorSession) {
|
|
24265
|
+
for (const record of args.liveSessionRecords) {
|
|
24266
|
+
if (readStringValue(record?.meta?.meshCoordinatorFor) !== args.meshId) continue;
|
|
24267
|
+
const sessionId = readStringValue(record?.sessionId);
|
|
24268
|
+
if (sessionId && matches.some((entry) => readStringValue(entry?.sessionId) === sessionId)) continue;
|
|
24269
|
+
matches.push(record);
|
|
24270
|
+
}
|
|
24271
|
+
}
|
|
24272
|
+
return matches;
|
|
24273
|
+
}
|
|
24274
|
+
function applyCachedInlineMeshNodeStatus(status, node, options) {
|
|
24275
|
+
const cachedStatus = readObjectRecord(node?.cachedStatus);
|
|
24276
|
+
const liveGit = buildInlineMeshTransitGitStatus(node);
|
|
24277
|
+
const git = options?.skipGit ? void 0 : liveGit ?? buildCachedInlineMeshGitStatus(node);
|
|
24278
|
+
const error = options?.skipError ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.error, node?.error);
|
|
24279
|
+
const health = options?.skipHealth ? void 0 : liveGit ? void 0 : readStringValue(cachedStatus.health, node?.health);
|
|
23678
24280
|
const machineStatus = readStringValue(cachedStatus.machineStatus, node?.machineStatus);
|
|
23679
|
-
|
|
23680
|
-
|
|
24281
|
+
const lastSeenAt = toIsoTimestamp(cachedStatus.lastSeenAt ?? cachedStatus.last_seen_at ?? node?.lastSeenAt ?? node?.last_seen_at);
|
|
24282
|
+
const updatedAt = toIsoTimestamp(cachedStatus.updatedAt ?? cachedStatus.updated_at ?? node?.updatedAt ?? node?.updated_at);
|
|
24283
|
+
const activeSessions = readCachedInlineMeshActiveSessions(node);
|
|
24284
|
+
const activeSessionDetails = readCachedInlineMeshActiveSessionDetails(node);
|
|
24285
|
+
if (!git && !error && !health && !machineStatus && !lastSeenAt && !updatedAt && activeSessions.length === 0) return false;
|
|
23681
24286
|
if (git) status.git = git;
|
|
23682
24287
|
if (error) status.error = error;
|
|
24288
|
+
if (machineStatus) status.machineStatus = machineStatus;
|
|
24289
|
+
if (lastSeenAt) status.lastSeenAt = lastSeenAt;
|
|
24290
|
+
if (updatedAt) status.updatedAt = updatedAt;
|
|
24291
|
+
if (activeSessions.length > 0) status.activeSessions = activeSessions;
|
|
24292
|
+
if (activeSessionDetails.length > 0) status.activeSessionDetails = activeSessionDetails;
|
|
23683
24293
|
if (health) {
|
|
23684
24294
|
status.health = health;
|
|
23685
24295
|
return true;
|
|
23686
24296
|
}
|
|
23687
24297
|
if (git) {
|
|
23688
|
-
|
|
23689
|
-
status.health = git.isGitRepo === false ? "degraded" : dirty ? "dirty" : "online";
|
|
24298
|
+
status.health = deriveMeshNodeHealthFromGit(git);
|
|
23690
24299
|
return true;
|
|
23691
24300
|
}
|
|
23692
|
-
return
|
|
24301
|
+
return activeSessions.length > 0 || !!machineStatus || !!lastSeenAt || !!updatedAt;
|
|
23693
24302
|
}
|
|
23694
24303
|
async function resolveProviderTypeFromPriority(args) {
|
|
23695
24304
|
if (!args.providerPriority.length) {
|
|
@@ -23719,12 +24328,89 @@ var REFINE_VALIDATION_TIMEOUT_MS = 12e4;
|
|
|
23719
24328
|
var REFINE_VALIDATION_OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
23720
24329
|
var REFINE_VALIDATION_SUMMARY_CHARS = 2e3;
|
|
23721
24330
|
var REFINE_VALIDATION_MAX_COMMANDS = 4;
|
|
24331
|
+
var REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
23722
24332
|
function truncateValidationOutput(value) {
|
|
23723
24333
|
const text = typeof value === "string" ? value : value == null ? "" : String(value);
|
|
23724
24334
|
if (text.length <= REFINE_VALIDATION_SUMMARY_CHARS) return text;
|
|
23725
24335
|
return `${text.slice(0, REFINE_VALIDATION_SUMMARY_CHARS)}
|
|
23726
24336
|
[truncated ${text.length - REFINE_VALIDATION_SUMMARY_CHARS} chars]`;
|
|
23727
24337
|
}
|
|
24338
|
+
function recordMeshRefineStage(stages, stage, status, startedAt, details) {
|
|
24339
|
+
stages.push({
|
|
24340
|
+
stage,
|
|
24341
|
+
status,
|
|
24342
|
+
durationMs: Date.now() - startedAt,
|
|
24343
|
+
...details || {}
|
|
24344
|
+
});
|
|
24345
|
+
}
|
|
24346
|
+
async function computeGitPatchId(cwd, fromRef, toRef) {
|
|
24347
|
+
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
24348
|
+
const diff = execFileSync4("git", ["diff", "--patch", "--full-index", fromRef, toRef], {
|
|
24349
|
+
cwd,
|
|
24350
|
+
encoding: "utf8",
|
|
24351
|
+
maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
|
|
24352
|
+
});
|
|
24353
|
+
if (!diff.trim()) return "";
|
|
24354
|
+
const patchId = execFileSync4("git", ["patch-id", "--stable"], {
|
|
24355
|
+
cwd,
|
|
24356
|
+
input: diff,
|
|
24357
|
+
encoding: "utf8",
|
|
24358
|
+
maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
|
|
24359
|
+
}).trim();
|
|
24360
|
+
return patchId.split(/\s+/)[0] || "";
|
|
24361
|
+
}
|
|
24362
|
+
async function runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead) {
|
|
24363
|
+
const startedAt = Date.now();
|
|
24364
|
+
try {
|
|
24365
|
+
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
24366
|
+
const git = (args) => execFileSync4("git", args, {
|
|
24367
|
+
cwd: repoRoot,
|
|
24368
|
+
encoding: "utf8",
|
|
24369
|
+
maxBuffer: REFINE_PATCH_EQUIVALENCE_OUTPUT_LIMIT_BYTES
|
|
24370
|
+
});
|
|
24371
|
+
const mergeBase = git(["merge-base", baseHead, branchHead]).trim();
|
|
24372
|
+
const mergeTreeStdout = git(["merge-tree", "--write-tree", baseHead, branchHead]);
|
|
24373
|
+
const mergedTree = mergeTreeStdout.trim().split(/\s+/)[0] || "";
|
|
24374
|
+
if (!mergeBase || !mergedTree) {
|
|
24375
|
+
return {
|
|
24376
|
+
status: "failed",
|
|
24377
|
+
equivalent: false,
|
|
24378
|
+
baseHead,
|
|
24379
|
+
branchHead,
|
|
24380
|
+
mergeBase: mergeBase || void 0,
|
|
24381
|
+
mergedTree: mergedTree || void 0,
|
|
24382
|
+
durationMs: Date.now() - startedAt,
|
|
24383
|
+
error: "patch equivalence preflight could not resolve merge-base or synthetic merge tree",
|
|
24384
|
+
stdout: truncateValidationOutput(mergeTreeStdout)
|
|
24385
|
+
};
|
|
24386
|
+
}
|
|
24387
|
+
const expectedPatchId = await computeGitPatchId(repoRoot, mergeBase, branchHead);
|
|
24388
|
+
const actualPatchId = await computeGitPatchId(repoRoot, baseHead, mergedTree);
|
|
24389
|
+
const equivalent = expectedPatchId === actualPatchId;
|
|
24390
|
+
return {
|
|
24391
|
+
status: equivalent ? "passed" : "failed",
|
|
24392
|
+
equivalent,
|
|
24393
|
+
baseHead,
|
|
24394
|
+
branchHead,
|
|
24395
|
+
mergeBase,
|
|
24396
|
+
mergedTree,
|
|
24397
|
+
expectedPatchId,
|
|
24398
|
+
actualPatchId,
|
|
24399
|
+
durationMs: Date.now() - startedAt
|
|
24400
|
+
};
|
|
24401
|
+
} catch (e) {
|
|
24402
|
+
return {
|
|
24403
|
+
status: "failed",
|
|
24404
|
+
equivalent: false,
|
|
24405
|
+
baseHead,
|
|
24406
|
+
branchHead,
|
|
24407
|
+
durationMs: Date.now() - startedAt,
|
|
24408
|
+
error: e?.message || String(e),
|
|
24409
|
+
stdout: truncateValidationOutput(e?.stdout),
|
|
24410
|
+
stderr: truncateValidationOutput(e?.stderr)
|
|
24411
|
+
};
|
|
24412
|
+
}
|
|
24413
|
+
}
|
|
23728
24414
|
function readPackageScripts(workspace) {
|
|
23729
24415
|
try {
|
|
23730
24416
|
const packageJsonPath = pathJoin(workspace, "package.json");
|
|
@@ -24082,30 +24768,97 @@ var DaemonCommandRouter = class {
|
|
|
24082
24768
|
* Allows the MCP server to query mesh data via get_mesh even when
|
|
24083
24769
|
* the mesh doesn't exist in the local meshes.json file. */
|
|
24084
24770
|
inlineMeshCache = /* @__PURE__ */ new Map();
|
|
24771
|
+
/** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default. */
|
|
24772
|
+
aggregateMeshStatusCache = /* @__PURE__ */ new Map();
|
|
24085
24773
|
constructor(deps) {
|
|
24086
24774
|
this.deps = deps;
|
|
24087
24775
|
}
|
|
24776
|
+
cloneJsonValue(value) {
|
|
24777
|
+
if (typeof structuredClone === "function") return structuredClone(value);
|
|
24778
|
+
return JSON.parse(JSON.stringify(value));
|
|
24779
|
+
}
|
|
24780
|
+
getCachedAggregateMeshStatus(meshId) {
|
|
24781
|
+
const cached = this.aggregateMeshStatusCache.get(meshId);
|
|
24782
|
+
if (!cached?.snapshot || cached.snapshot.success !== true || !Array.isArray(cached.snapshot.nodes)) return null;
|
|
24783
|
+
const snapshot = this.cloneJsonValue(cached.snapshot);
|
|
24784
|
+
const ageMs = Math.max(0, Date.now() - cached.builtAt);
|
|
24785
|
+
const sourceOfTruth = snapshot.sourceOfTruth && typeof snapshot.sourceOfTruth === "object" ? snapshot.sourceOfTruth : {};
|
|
24786
|
+
snapshot.sourceOfTruth = {
|
|
24787
|
+
...sourceOfTruth,
|
|
24788
|
+
aggregateSnapshot: {
|
|
24789
|
+
...sourceOfTruth.aggregateSnapshot && typeof sourceOfTruth.aggregateSnapshot === "object" ? sourceOfTruth.aggregateSnapshot : {},
|
|
24790
|
+
owner: "coordinator_daemon_memory",
|
|
24791
|
+
cached: true,
|
|
24792
|
+
source: "memory",
|
|
24793
|
+
refreshReason: "memory_cache_hit",
|
|
24794
|
+
ageMs,
|
|
24795
|
+
cachedAt: new Date(cached.builtAt).toISOString(),
|
|
24796
|
+
returnedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24797
|
+
}
|
|
24798
|
+
};
|
|
24799
|
+
return snapshot;
|
|
24800
|
+
}
|
|
24801
|
+
rememberAggregateMeshStatus(meshId, snapshot, refreshReason) {
|
|
24802
|
+
if (!snapshot || typeof snapshot !== "object" || snapshot.success !== true || !Array.isArray(snapshot.nodes)) return snapshot;
|
|
24803
|
+
const builtAt = Date.now();
|
|
24804
|
+
const next = this.cloneJsonValue(snapshot);
|
|
24805
|
+
const sourceOfTruth = next.sourceOfTruth && typeof next.sourceOfTruth === "object" ? next.sourceOfTruth : {};
|
|
24806
|
+
next.sourceOfTruth = {
|
|
24807
|
+
...sourceOfTruth,
|
|
24808
|
+
aggregateSnapshot: {
|
|
24809
|
+
owner: "coordinator_daemon_memory",
|
|
24810
|
+
cached: false,
|
|
24811
|
+
source: "live_refresh",
|
|
24812
|
+
refreshReason,
|
|
24813
|
+
ageMs: 0,
|
|
24814
|
+
cachedAt: new Date(builtAt).toISOString(),
|
|
24815
|
+
returnedAt: new Date(builtAt).toISOString()
|
|
24816
|
+
}
|
|
24817
|
+
};
|
|
24818
|
+
this.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: this.cloneJsonValue(next) });
|
|
24819
|
+
return next;
|
|
24820
|
+
}
|
|
24088
24821
|
getCachedInlineMesh(meshId, inlineMesh) {
|
|
24089
24822
|
if (inlineMesh && typeof inlineMesh === "object") {
|
|
24090
|
-
this.
|
|
24091
|
-
return inlineMesh;
|
|
24823
|
+
return this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24092
24824
|
}
|
|
24093
24825
|
return this.inlineMeshCache.get(meshId);
|
|
24094
24826
|
}
|
|
24827
|
+
warmInlineMeshCache(meshId, inlineMesh) {
|
|
24828
|
+
if (!inlineMesh || typeof inlineMesh !== "object") return void 0;
|
|
24829
|
+
const sanitizedInlineMesh = sanitizeInlineMesh(inlineMesh);
|
|
24830
|
+
const cached = this.inlineMeshCache.get(meshId);
|
|
24831
|
+
if (cached) {
|
|
24832
|
+
const merged = reconcileInlineMeshCache(cached, sanitizedInlineMesh);
|
|
24833
|
+
this.inlineMeshCache.set(meshId, merged);
|
|
24834
|
+
return merged;
|
|
24835
|
+
}
|
|
24836
|
+
this.inlineMeshCache.set(meshId, sanitizedInlineMesh);
|
|
24837
|
+
return sanitizedInlineMesh;
|
|
24838
|
+
}
|
|
24095
24839
|
async getMeshForCommand(meshId, inlineMesh, options) {
|
|
24096
24840
|
const preferInline = options?.preferInline === true;
|
|
24097
24841
|
if (preferInline) {
|
|
24098
|
-
const cached2 = this.getCachedInlineMesh(meshId
|
|
24099
|
-
if (cached2) return { mesh: cached2, inline: true };
|
|
24842
|
+
const cached2 = this.getCachedInlineMesh(meshId);
|
|
24843
|
+
if (cached2) return { mesh: cached2, inline: true, source: "inline_cache" };
|
|
24844
|
+
if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
|
|
24845
|
+
this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24846
|
+
return { mesh: inlineMesh, inline: true, source: "inline_bootstrap" };
|
|
24847
|
+
}
|
|
24100
24848
|
}
|
|
24101
24849
|
try {
|
|
24102
24850
|
const { getMesh: getMesh3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
24103
24851
|
const mesh = getMesh3(meshId);
|
|
24104
|
-
if (mesh) return { mesh, inline: false };
|
|
24852
|
+
if (mesh) return { mesh, inline: false, source: "local_config" };
|
|
24105
24853
|
} catch {
|
|
24106
24854
|
}
|
|
24107
|
-
const cached = this.getCachedInlineMesh(meshId
|
|
24108
|
-
|
|
24855
|
+
const cached = this.getCachedInlineMesh(meshId);
|
|
24856
|
+
if (cached) return { mesh: cached, inline: true, source: "inline_cache" };
|
|
24857
|
+
const warmedInline = this.warmInlineMeshCache(meshId, inlineMesh);
|
|
24858
|
+
return warmedInline ? { mesh: warmedInline, inline: true, source: "inline_bootstrap" } : null;
|
|
24859
|
+
}
|
|
24860
|
+
invalidateAggregateMeshStatus(meshId) {
|
|
24861
|
+
this.aggregateMeshStatusCache.delete(meshId);
|
|
24109
24862
|
}
|
|
24110
24863
|
updateInlineMeshNode(meshId, mesh, node) {
|
|
24111
24864
|
if (!mesh || !Array.isArray(mesh.nodes) || !node?.id) return;
|
|
@@ -24114,6 +24867,7 @@ var DaemonCommandRouter = class {
|
|
|
24114
24867
|
else mesh.nodes.push(node);
|
|
24115
24868
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24116
24869
|
this.inlineMeshCache.set(meshId, mesh);
|
|
24870
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
24117
24871
|
}
|
|
24118
24872
|
removeInlineMeshNode(meshId, mesh, nodeId) {
|
|
24119
24873
|
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
@@ -24122,6 +24876,7 @@ var DaemonCommandRouter = class {
|
|
|
24122
24876
|
mesh.nodes.splice(idx, 1);
|
|
24123
24877
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24124
24878
|
this.inlineMeshCache.set(meshId, mesh);
|
|
24879
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
24125
24880
|
return true;
|
|
24126
24881
|
}
|
|
24127
24882
|
normalizeMeshSessionCleanupMode(value) {
|
|
@@ -24334,6 +25089,7 @@ var DaemonCommandRouter = class {
|
|
|
24334
25089
|
const deletedSessionIds = [];
|
|
24335
25090
|
const skippedSessionIds = [];
|
|
24336
25091
|
const skippedLiveSessionIds = [];
|
|
25092
|
+
const skippedCoordinatorSessionIds = [];
|
|
24337
25093
|
const deleteUnsupportedSessionIds = [];
|
|
24338
25094
|
const recordsRemainSessionIds = [];
|
|
24339
25095
|
const errors = [];
|
|
@@ -24366,6 +25122,12 @@ var DaemonCommandRouter = class {
|
|
|
24366
25122
|
const completed = this.isCompletedHostedSession(record);
|
|
24367
25123
|
const surfaceKind = getSessionHostSurfaceKind(record);
|
|
24368
25124
|
const liveRuntime = surfaceKind === "live_runtime";
|
|
25125
|
+
const coordinatorSession = readStringValue(record?.meta?.meshCoordinatorFor) === args.meshId;
|
|
25126
|
+
if (!hasExplicitSessionIds && coordinatorSession) {
|
|
25127
|
+
skippedSessionIds.push(sessionId);
|
|
25128
|
+
skippedCoordinatorSessionIds.push(sessionId);
|
|
25129
|
+
continue;
|
|
25130
|
+
}
|
|
24369
25131
|
if (!hasExplicitSessionIds && liveRuntime) {
|
|
24370
25132
|
skippedSessionIds.push(sessionId);
|
|
24371
25133
|
skippedLiveSessionIds.push(sessionId);
|
|
@@ -24431,6 +25193,7 @@ var DaemonCommandRouter = class {
|
|
|
24431
25193
|
deletedSessionIds,
|
|
24432
25194
|
skippedSessionIds,
|
|
24433
25195
|
skippedLiveSessionIds,
|
|
25196
|
+
skippedCoordinatorSessionIds,
|
|
24434
25197
|
...deleteUnsupported ? {
|
|
24435
25198
|
deleteUnsupported: true,
|
|
24436
25199
|
effectiveCleanup: args.mode === "stop_and_delete" ? "stopped_only_records_remain" : "delete_unsupported_records_remain",
|
|
@@ -24563,7 +25326,8 @@ var DaemonCommandRouter = class {
|
|
|
24563
25326
|
return handleMeshForwardEvent({ instanceManager: this.deps.instanceManager }, args);
|
|
24564
25327
|
}
|
|
24565
25328
|
case "get_pending_mesh_events": {
|
|
24566
|
-
const
|
|
25329
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25330
|
+
const events = drainPendingMeshCoordinatorEvents(meshId || void 0);
|
|
24567
25331
|
return { success: true, events };
|
|
24568
25332
|
}
|
|
24569
25333
|
case "launch_cli":
|
|
@@ -25092,15 +25856,39 @@ var DaemonCommandRouter = class {
|
|
|
25092
25856
|
case "get_mesh": {
|
|
25093
25857
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25094
25858
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
25095
|
-
|
|
25096
|
-
|
|
25097
|
-
|
|
25098
|
-
|
|
25099
|
-
|
|
25859
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
25860
|
+
if (!meshRecord?.mesh) return { success: false, error: "Mesh not found" };
|
|
25861
|
+
const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
|
|
25862
|
+
const directTruth = await hydrateInlineMeshDirectTruth({
|
|
25863
|
+
mesh: meshRecord.mesh,
|
|
25864
|
+
meshSource: meshRecord.source,
|
|
25865
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
25866
|
+
statusInstanceId: this.deps.statusInstanceId,
|
|
25867
|
+
localMachineId: loadConfig().machineId || ""
|
|
25868
|
+
});
|
|
25869
|
+
const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
|
|
25870
|
+
const sourceOfTruth = {
|
|
25871
|
+
membership: meshRecord.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
25872
|
+
coordinatorOwnsLiveTruth: directTruthSatisfied,
|
|
25873
|
+
directPeerTruth: {
|
|
25874
|
+
required: requireDirectPeerTruth,
|
|
25875
|
+
satisfied: directTruthSatisfied,
|
|
25876
|
+
directEvidenceCount: directTruth.directEvidenceCount,
|
|
25877
|
+
localConfirmedCount: directTruth.localConfirmedCount,
|
|
25878
|
+
peerAttemptedCount: directTruth.peerAttemptedCount,
|
|
25879
|
+
peerConfirmedCount: directTruth.peerConfirmedCount,
|
|
25880
|
+
unavailableNodeIds: directTruth.unavailableNodeIds
|
|
25881
|
+
}
|
|
25882
|
+
};
|
|
25883
|
+
if (requireDirectPeerTruth && !directTruthSatisfied) {
|
|
25884
|
+
return {
|
|
25885
|
+
success: false,
|
|
25886
|
+
code: "mesh_direct_peer_truth_unavailable",
|
|
25887
|
+
error: "Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct get_mesh probes succeed.",
|
|
25888
|
+
sourceOfTruth
|
|
25889
|
+
};
|
|
25100
25890
|
}
|
|
25101
|
-
|
|
25102
|
-
if (cached) return { success: true, mesh: cached };
|
|
25103
|
-
return { success: false, error: "Mesh not found" };
|
|
25891
|
+
return { success: true, mesh: meshRecord.mesh, sourceOfTruth };
|
|
25104
25892
|
}
|
|
25105
25893
|
case "create_mesh": {
|
|
25106
25894
|
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
@@ -25130,6 +25918,7 @@ var DaemonCommandRouter = class {
|
|
|
25130
25918
|
const mesh = updateMesh2(meshId, patch);
|
|
25131
25919
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
25132
25920
|
this.inlineMeshCache.set(meshId, mesh);
|
|
25921
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
25133
25922
|
return { success: true, mesh };
|
|
25134
25923
|
} catch (e) {
|
|
25135
25924
|
return { success: false, error: e.message };
|
|
@@ -25319,26 +26108,41 @@ var DaemonCommandRouter = class {
|
|
|
25319
26108
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
25320
26109
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
25321
26110
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
26111
|
+
const refineStages = [];
|
|
25322
26112
|
try {
|
|
25323
26113
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh);
|
|
25324
26114
|
const mesh = meshRecord?.mesh;
|
|
25325
26115
|
const node = mesh?.nodes?.find((n) => n.id === nodeId || n.nodeId === nodeId);
|
|
25326
|
-
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh
|
|
26116
|
+
if (!node) return { success: false, error: `Node '${nodeId}' not found in mesh`, refineStages };
|
|
25327
26117
|
if (!node.isLocalWorktree || !node.workspace) {
|
|
25328
|
-
return { success: false, error: `Refinery requires a local worktree node
|
|
26118
|
+
return { success: false, error: `Refinery requires a local worktree node`, refineStages };
|
|
25329
26119
|
}
|
|
25330
26120
|
const sourceNode = node.clonedFromNodeId ? mesh?.nodes.find((n) => n.id === node.clonedFromNodeId || n.nodeId === node.clonedFromNodeId) : mesh?.nodes.find((n) => !n.isLocalWorktree);
|
|
25331
26121
|
const repoRoot = sourceNode?.repoRoot || sourceNode?.workspace;
|
|
25332
|
-
if (!repoRoot) return { success: false, error: "Source node repoRoot not found" };
|
|
26122
|
+
if (!repoRoot) return { success: false, error: "Source node repoRoot not found", refineStages };
|
|
25333
26123
|
const { execFile: execFile3 } = await import("child_process");
|
|
25334
26124
|
const { promisify: promisify3 } = await import("util");
|
|
25335
26125
|
const execFileAsync3 = promisify3(execFile3);
|
|
26126
|
+
const resolveStarted = Date.now();
|
|
25336
26127
|
const { stdout: branchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: node.workspace, encoding: "utf8" });
|
|
25337
26128
|
const branch = branchStdout.trim();
|
|
25338
|
-
if (!branch) return { success: false, error: "Could not determine branch of the worktree node" };
|
|
26129
|
+
if (!branch) return { success: false, error: "Could not determine branch of the worktree node", refineStages };
|
|
25339
26130
|
const { stdout: baseBranchStdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" });
|
|
25340
26131
|
const baseBranch = baseBranchStdout.trim();
|
|
26132
|
+
const { stdout: baseHeadStdout } = await execFileAsync3("git", ["rev-parse", "HEAD"], { cwd: repoRoot, encoding: "utf8" });
|
|
26133
|
+
const { stdout: branchHeadStdout } = await execFileAsync3("git", ["rev-parse", branch], { cwd: node.workspace, encoding: "utf8" });
|
|
26134
|
+
const baseHead = baseHeadStdout.trim();
|
|
26135
|
+
const branchHead = branchHeadStdout.trim();
|
|
26136
|
+
recordMeshRefineStage(refineStages, "resolve_refs", "passed", resolveStarted, { branch, baseBranch, baseHead, branchHead });
|
|
26137
|
+
const validationStarted = Date.now();
|
|
25341
26138
|
const validationSummary = await runMeshRefineValidationGate(mesh, node.workspace);
|
|
26139
|
+
recordMeshRefineStage(
|
|
26140
|
+
refineStages,
|
|
26141
|
+
"validation",
|
|
26142
|
+
validationSummary.status === "passed" ? "passed" : validationSummary.status === "failed" ? "failed" : "skipped",
|
|
26143
|
+
validationStarted,
|
|
26144
|
+
{ validationStatus: validationSummary.status, commandsRun: validationSummary.commandsRun.length }
|
|
26145
|
+
);
|
|
25342
26146
|
if (validationSummary.status === "failed") {
|
|
25343
26147
|
return {
|
|
25344
26148
|
success: false,
|
|
@@ -25348,6 +26152,7 @@ var DaemonCommandRouter = class {
|
|
|
25348
26152
|
branch,
|
|
25349
26153
|
into: baseBranch,
|
|
25350
26154
|
validationSummary,
|
|
26155
|
+
refineStages,
|
|
25351
26156
|
finalBranchConvergenceState: {
|
|
25352
26157
|
branch,
|
|
25353
26158
|
baseBranch,
|
|
@@ -25367,6 +26172,7 @@ var DaemonCommandRouter = class {
|
|
|
25367
26172
|
branch,
|
|
25368
26173
|
into: baseBranch,
|
|
25369
26174
|
validationSummary,
|
|
26175
|
+
refineStages,
|
|
25370
26176
|
finalBranchConvergenceState: {
|
|
25371
26177
|
branch,
|
|
25372
26178
|
baseBranch,
|
|
@@ -25377,37 +26183,121 @@ var DaemonCommandRouter = class {
|
|
|
25377
26183
|
}
|
|
25378
26184
|
};
|
|
25379
26185
|
}
|
|
26186
|
+
const patchEquivalenceStarted = Date.now();
|
|
26187
|
+
const patchEquivalence = await runMeshRefinePatchEquivalenceGate(repoRoot, baseHead, branchHead);
|
|
26188
|
+
recordMeshRefineStage(refineStages, "patch_equivalence", patchEquivalence.status, patchEquivalenceStarted, {
|
|
26189
|
+
equivalent: patchEquivalence.equivalent,
|
|
26190
|
+
expectedPatchId: patchEquivalence.expectedPatchId,
|
|
26191
|
+
actualPatchId: patchEquivalence.actualPatchId,
|
|
26192
|
+
error: patchEquivalence.error
|
|
26193
|
+
});
|
|
26194
|
+
if (!patchEquivalence.equivalent) {
|
|
26195
|
+
return {
|
|
26196
|
+
success: false,
|
|
26197
|
+
code: "patch_equivalence_failed",
|
|
26198
|
+
convergenceStatus: "blocked_review",
|
|
26199
|
+
error: "Refinery patch-equivalence preflight failed; merge/refine was not attempted.",
|
|
26200
|
+
branch,
|
|
26201
|
+
into: baseBranch,
|
|
26202
|
+
validationSummary,
|
|
26203
|
+
patchEquivalence,
|
|
26204
|
+
refineStages,
|
|
26205
|
+
finalBranchConvergenceState: {
|
|
26206
|
+
branch,
|
|
26207
|
+
baseBranch,
|
|
26208
|
+
merged: false,
|
|
26209
|
+
removed: false,
|
|
26210
|
+
validation: "passed",
|
|
26211
|
+
patchEquivalence: "failed",
|
|
26212
|
+
status: "blocked_review"
|
|
26213
|
+
}
|
|
26214
|
+
};
|
|
26215
|
+
}
|
|
26216
|
+
let mergeResult;
|
|
26217
|
+
const mergeStarted = Date.now();
|
|
25380
26218
|
try {
|
|
25381
|
-
await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
|
|
26219
|
+
const result = await execFileAsync3("git", ["merge", "--no-ff", branch, "-m", `Auto-merge branch '${branch}' via Refinery`], { cwd: repoRoot, encoding: "utf8" });
|
|
26220
|
+
mergeResult = {
|
|
26221
|
+
stdout: truncateValidationOutput(result.stdout),
|
|
26222
|
+
stderr: truncateValidationOutput(result.stderr),
|
|
26223
|
+
durationMs: Date.now() - mergeStarted
|
|
26224
|
+
};
|
|
26225
|
+
recordMeshRefineStage(refineStages, "merge", "passed", mergeStarted, mergeResult);
|
|
25382
26226
|
} catch (e) {
|
|
26227
|
+
recordMeshRefineStage(refineStages, "merge", "failed", mergeStarted, {
|
|
26228
|
+
error: e?.message || String(e),
|
|
26229
|
+
stdout: truncateValidationOutput(e?.stdout),
|
|
26230
|
+
stderr: truncateValidationOutput(e?.stderr)
|
|
26231
|
+
});
|
|
25383
26232
|
return {
|
|
25384
26233
|
success: false,
|
|
25385
26234
|
error: `Merge failed (conflicts?): ${e.message}`,
|
|
25386
26235
|
validationSummary,
|
|
26236
|
+
patchEquivalence,
|
|
26237
|
+
refineStages,
|
|
25387
26238
|
finalBranchConvergenceState: {
|
|
25388
26239
|
branch,
|
|
25389
26240
|
baseBranch,
|
|
25390
26241
|
merged: false,
|
|
25391
26242
|
removed: false,
|
|
25392
26243
|
validation: "passed",
|
|
26244
|
+
patchEquivalence: "passed",
|
|
25393
26245
|
status: "not_mergeable"
|
|
25394
26246
|
}
|
|
25395
26247
|
};
|
|
25396
26248
|
}
|
|
26249
|
+
const cleanupStarted = Date.now();
|
|
25397
26250
|
const removeResult = await this.execute("remove_mesh_node", {
|
|
25398
26251
|
meshId,
|
|
25399
26252
|
nodeId,
|
|
25400
|
-
sessionCleanupMode: "
|
|
26253
|
+
sessionCleanupMode: "preserve",
|
|
25401
26254
|
inlineMesh: args?.inlineMesh
|
|
25402
26255
|
});
|
|
26256
|
+
recordMeshRefineStage(refineStages, "cleanup", removeResult?.success === false ? "failed" : "passed", cleanupStarted, {
|
|
26257
|
+
removed: removeResult?.removed,
|
|
26258
|
+
code: removeResult?.code,
|
|
26259
|
+
error: removeResult?.error
|
|
26260
|
+
});
|
|
26261
|
+
let ledgerError;
|
|
26262
|
+
const ledgerStarted = Date.now();
|
|
25403
26263
|
try {
|
|
25404
26264
|
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
25405
26265
|
appendLedgerEntry2(meshId, {
|
|
25406
26266
|
kind: "node_removed",
|
|
25407
26267
|
nodeId,
|
|
25408
|
-
payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary }
|
|
26268
|
+
payload: { refined: true, mergedBranch: branch, into: baseBranch, validationSummary, patchEquivalence }
|
|
25409
26269
|
});
|
|
25410
|
-
|
|
26270
|
+
recordMeshRefineStage(refineStages, "ledger", "passed", ledgerStarted);
|
|
26271
|
+
} catch (e) {
|
|
26272
|
+
ledgerError = e?.message || String(e);
|
|
26273
|
+
recordMeshRefineStage(refineStages, "ledger", "failed", ledgerStarted, { error: ledgerError });
|
|
26274
|
+
}
|
|
26275
|
+
const finalBranchConvergenceState = {
|
|
26276
|
+
branch: baseBranch,
|
|
26277
|
+
mergedBranch: branch,
|
|
26278
|
+
baseBranch,
|
|
26279
|
+
merged: true,
|
|
26280
|
+
removed: removeResult?.success !== false,
|
|
26281
|
+
validation: "passed",
|
|
26282
|
+
patchEquivalence: "passed",
|
|
26283
|
+
status: removeResult?.success === false ? "merged_cleanup_failed" : "merged"
|
|
26284
|
+
};
|
|
26285
|
+
if (removeResult?.success === false) {
|
|
26286
|
+
return {
|
|
26287
|
+
success: false,
|
|
26288
|
+
code: "cleanup_failed",
|
|
26289
|
+
error: "Refinery merge completed but worktree cleanup failed; manual cleanup/retry is required.",
|
|
26290
|
+
merged: true,
|
|
26291
|
+
branch,
|
|
26292
|
+
into: baseBranch,
|
|
26293
|
+
removeResult,
|
|
26294
|
+
validationSummary,
|
|
26295
|
+
patchEquivalence,
|
|
26296
|
+
mergeResult,
|
|
26297
|
+
refineStages,
|
|
26298
|
+
...ledgerError ? { ledgerError } : {},
|
|
26299
|
+
finalBranchConvergenceState
|
|
26300
|
+
};
|
|
25411
26301
|
}
|
|
25412
26302
|
return {
|
|
25413
26303
|
success: true,
|
|
@@ -25416,18 +26306,14 @@ var DaemonCommandRouter = class {
|
|
|
25416
26306
|
into: baseBranch,
|
|
25417
26307
|
removeResult,
|
|
25418
26308
|
validationSummary,
|
|
25419
|
-
|
|
25420
|
-
|
|
25421
|
-
|
|
25422
|
-
|
|
25423
|
-
|
|
25424
|
-
removed: removeResult?.success !== false,
|
|
25425
|
-
validation: "passed",
|
|
25426
|
-
status: removeResult?.success === false ? "merged_cleanup_failed" : "merged"
|
|
25427
|
-
}
|
|
26309
|
+
patchEquivalence,
|
|
26310
|
+
mergeResult,
|
|
26311
|
+
refineStages,
|
|
26312
|
+
...ledgerError ? { ledgerError } : {},
|
|
26313
|
+
finalBranchConvergenceState
|
|
25428
26314
|
};
|
|
25429
26315
|
} catch (e) {
|
|
25430
|
-
return { success: false, error: e.message };
|
|
26316
|
+
return { success: false, error: e.message, refineStages };
|
|
25431
26317
|
}
|
|
25432
26318
|
}
|
|
25433
26319
|
case "remove_mesh_node": {
|
|
@@ -25468,6 +26354,7 @@ var DaemonCommandRouter = class {
|
|
|
25468
26354
|
} else {
|
|
25469
26355
|
const { removeNode: removeNode3 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
25470
26356
|
removed = removeNode3(meshId, nodeId);
|
|
26357
|
+
if (removed) this.invalidateAggregateMeshStatus(meshId);
|
|
25471
26358
|
}
|
|
25472
26359
|
if (removed) {
|
|
25473
26360
|
try {
|
|
@@ -25546,6 +26433,7 @@ var DaemonCommandRouter = class {
|
|
|
25546
26433
|
policy: { ...sourceNode.policy || {} }
|
|
25547
26434
|
});
|
|
25548
26435
|
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
26436
|
+
this.invalidateAggregateMeshStatus(meshId);
|
|
25549
26437
|
}
|
|
25550
26438
|
const initSubmodules = sourceNode.policy?.initSubmodulesOnClone !== false;
|
|
25551
26439
|
if (initSubmodules) {
|
|
@@ -25621,7 +26509,14 @@ var DaemonCommandRouter = class {
|
|
|
25621
26509
|
cliType
|
|
25622
26510
|
};
|
|
25623
26511
|
}
|
|
25624
|
-
const
|
|
26512
|
+
const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
|
|
26513
|
+
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
26514
|
+
const workspace = readLiveMeshNodeWorkspace({
|
|
26515
|
+
meshId,
|
|
26516
|
+
nodeId: String(coordinatorNode.id || coordinatorNode.nodeId || preferredCoordinatorNodeId || ""),
|
|
26517
|
+
liveSessionRecords: liveMeshSessions,
|
|
26518
|
+
allowCoordinatorSession: true
|
|
26519
|
+
}) || (typeof coordinatorNode.workspace === "string" ? coordinatorNode.workspace.trim() : "");
|
|
25625
26520
|
if (!workspace) return { success: false, error: "Coordinator node workspace required", meshId, cliType };
|
|
25626
26521
|
if (!cliType) {
|
|
25627
26522
|
const resolved = await resolveProviderTypeFromPriority({
|
|
@@ -25783,7 +26678,7 @@ ${block}`);
|
|
|
25783
26678
|
workspace
|
|
25784
26679
|
};
|
|
25785
26680
|
}
|
|
25786
|
-
const { existsSync:
|
|
26681
|
+
const { existsSync: existsSync26, readFileSync: readFileSync18, writeFileSync: writeFileSync15, copyFileSync: copyFileSync4, mkdirSync: mkdirSync17 } = await import("fs");
|
|
25787
26682
|
const { dirname: dirname9 } = await import("path");
|
|
25788
26683
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
25789
26684
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -25826,14 +26721,14 @@ ${block}`);
|
|
|
25826
26721
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
25827
26722
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
25828
26723
|
}
|
|
25829
|
-
const hadExistingMcpConfig =
|
|
26724
|
+
const hadExistingMcpConfig = existsSync26(mcpConfigPath);
|
|
25830
26725
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
25831
26726
|
if (hermesBaseConfig) {
|
|
25832
26727
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname9(mcpConfigPath));
|
|
25833
26728
|
}
|
|
25834
26729
|
if (hadExistingMcpConfig) {
|
|
25835
26730
|
try {
|
|
25836
|
-
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
26731
|
+
const parsedExistingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync18(mcpConfigPath, "utf-8"), configFormat);
|
|
25837
26732
|
const existingCoordinatorConfig = hermesManualFallback ? stripHermesCoordinatorTempModelProviderOverrides(parsedExistingMcpConfig) : parsedExistingMcpConfig;
|
|
25838
26733
|
existingMcpConfig = { ...existingMcpConfig, ...existingCoordinatorConfig };
|
|
25839
26734
|
copyFileSync4(mcpConfigPath, mcpConfigPath + ".backup");
|
|
@@ -25923,110 +26818,264 @@ ${block}`);
|
|
|
25923
26818
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
25924
26819
|
const mesh = meshRecord?.mesh;
|
|
25925
26820
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
26821
|
+
const refreshRequested = args?.refresh === true || args?.forceRefresh === true;
|
|
26822
|
+
if (!refreshRequested) {
|
|
26823
|
+
const cachedStatus = this.getCachedAggregateMeshStatus(meshId);
|
|
26824
|
+
if (cachedStatus) return cachedStatus;
|
|
26825
|
+
}
|
|
26826
|
+
const refreshReason = refreshRequested ? "explicit_refresh" : "cold_cache_miss";
|
|
25926
26827
|
const { getMeshQueueStats: getMeshQueueStats2, getQueue: getQueue2 } = await Promise.resolve().then(() => (init_mesh_work_queue(), mesh_work_queue_exports));
|
|
25927
26828
|
const queue = getQueue2(meshId);
|
|
25928
26829
|
const queueSummary = getMeshQueueStats2(meshId);
|
|
25929
26830
|
const { readLedgerEntries: readLedgerEntries2, getLedgerSummary: getLedgerSummary2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
25930
26831
|
const ledgerEntries = readLedgerEntries2(meshId, { tail: 20 });
|
|
25931
26832
|
const ledgerSummary = getLedgerSummary2(meshId);
|
|
26833
|
+
const sessionHostRecords = this.deps.sessionHostControl?.listSessions ? await this.deps.sessionHostControl.listSessions().catch(() => []) : [];
|
|
26834
|
+
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
26835
|
+
const localMachineId = loadConfig().machineId || "";
|
|
26836
|
+
const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
|
|
26837
|
+
const directTruth = requireDirectPeerTruth ? await hydrateInlineMeshDirectTruth({
|
|
26838
|
+
mesh,
|
|
26839
|
+
meshSource: meshRecord.source,
|
|
26840
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
26841
|
+
statusInstanceId: this.deps.statusInstanceId,
|
|
26842
|
+
localMachineId
|
|
26843
|
+
}) : {
|
|
26844
|
+
directEvidenceCount: 0,
|
|
26845
|
+
localConfirmedCount: 0,
|
|
26846
|
+
peerAttemptedCount: 0,
|
|
26847
|
+
peerConfirmedCount: 0,
|
|
26848
|
+
unavailableNodeIds: []
|
|
26849
|
+
};
|
|
26850
|
+
const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
|
|
26851
|
+
if (requireDirectPeerTruth && !directTruthSatisfied) {
|
|
26852
|
+
return {
|
|
26853
|
+
success: false,
|
|
26854
|
+
code: "mesh_direct_peer_truth_unavailable",
|
|
26855
|
+
error: "Selected coordinator could not confirm direct mesh truth yet. Bootstrap inventory stays unavailable until direct mesh_status probes succeed.",
|
|
26856
|
+
sourceOfTruth: {
|
|
26857
|
+
membership: meshRecord.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
26858
|
+
coordinatorOwnsLiveTruth: false,
|
|
26859
|
+
currentStatus: "direct_peer_truth_unavailable",
|
|
26860
|
+
directPeerTruth: {
|
|
26861
|
+
required: true,
|
|
26862
|
+
satisfied: false,
|
|
26863
|
+
directEvidenceCount: directTruth.directEvidenceCount,
|
|
26864
|
+
localConfirmedCount: directTruth.localConfirmedCount,
|
|
26865
|
+
peerAttemptedCount: directTruth.peerAttemptedCount,
|
|
26866
|
+
peerConfirmedCount: directTruth.peerConfirmedCount,
|
|
26867
|
+
unavailableNodeIds: directTruth.unavailableNodeIds
|
|
26868
|
+
}
|
|
26869
|
+
}
|
|
26870
|
+
};
|
|
26871
|
+
}
|
|
26872
|
+
const directTruthUnavailableNodeIds = new Set(directTruth.unavailableNodeIds);
|
|
26873
|
+
const selectedCoordinatorNodeId = readStringValue(
|
|
26874
|
+
mesh.coordinator?.preferredNodeId,
|
|
26875
|
+
mesh.nodes?.[0]?.id,
|
|
26876
|
+
mesh.nodes?.[0]?.nodeId
|
|
26877
|
+
);
|
|
26878
|
+
const inlineCoordinatorNodeId = meshRecord?.inline && Array.isArray(mesh.nodes) ? selectedCoordinatorNodeId : void 0;
|
|
26879
|
+
const refreshedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25932
26880
|
const nodeStatuses = [];
|
|
25933
|
-
for (const node of mesh.nodes || []) {
|
|
26881
|
+
for (const [nodeIndex, node] of (mesh.nodes || []).entries()) {
|
|
26882
|
+
const nodeId = String(node.id || node.nodeId || "");
|
|
26883
|
+
const daemonId = readStringValue(node.daemonId);
|
|
26884
|
+
const providerPriority = readProviderPriorityFromPolicy(node.policy);
|
|
26885
|
+
const isSelfNode = Boolean(
|
|
26886
|
+
nodeId && inlineCoordinatorNodeId && nodeId === inlineCoordinatorNodeId
|
|
26887
|
+
) || Boolean(
|
|
26888
|
+
daemonId && (daemonId === localMachineId || daemonId === this.deps.statusInstanceId)
|
|
26889
|
+
) || Boolean(meshRecord?.inline && nodeIndex === 0);
|
|
25934
26890
|
const status = {
|
|
25935
|
-
nodeId
|
|
26891
|
+
nodeId,
|
|
25936
26892
|
machineLabel: node.machineLabel || node.id || node.nodeId,
|
|
25937
26893
|
workspace: node.workspace,
|
|
25938
26894
|
repoRoot: node.repoRoot,
|
|
25939
26895
|
isLocalWorktree: node.isLocalWorktree,
|
|
25940
26896
|
worktreeBranch: node.worktreeBranch,
|
|
25941
|
-
daemonId
|
|
26897
|
+
daemonId,
|
|
25942
26898
|
machineId: node.machineId,
|
|
26899
|
+
machineStatus: node.machineStatus,
|
|
25943
26900
|
health: "unknown",
|
|
25944
26901
|
providers: node.providers || [],
|
|
25945
|
-
|
|
26902
|
+
providerPriority,
|
|
26903
|
+
activeSessions: [],
|
|
26904
|
+
activeSessionDetails: [],
|
|
26905
|
+
launchReady: false
|
|
25946
26906
|
};
|
|
25947
|
-
if (
|
|
25948
|
-
|
|
25949
|
-
|
|
25950
|
-
|
|
26907
|
+
if (isSelfNode) {
|
|
26908
|
+
status.connection = {
|
|
26909
|
+
perspective: "selected_coordinator",
|
|
26910
|
+
source: "mesh_peer_status",
|
|
26911
|
+
state: "self",
|
|
26912
|
+
transport: "local",
|
|
26913
|
+
reported: true,
|
|
26914
|
+
reason: "Selected coordinator daemon",
|
|
26915
|
+
lastStateChangeAt: refreshedAt
|
|
26916
|
+
};
|
|
26917
|
+
} else if (daemonId) {
|
|
26918
|
+
const connection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
|
|
26919
|
+
status.connection = connection ?? {
|
|
26920
|
+
perspective: "selected_coordinator",
|
|
26921
|
+
source: "not_reported",
|
|
26922
|
+
state: "unknown",
|
|
26923
|
+
transport: "unknown",
|
|
26924
|
+
reported: false,
|
|
26925
|
+
reason: "No live mesh peer telemetry reported by the selected coordinator yet."
|
|
26926
|
+
};
|
|
26927
|
+
} else {
|
|
26928
|
+
status.connection = {
|
|
26929
|
+
perspective: "selected_coordinator",
|
|
26930
|
+
source: "not_reported",
|
|
26931
|
+
state: "unknown",
|
|
26932
|
+
transport: "unknown",
|
|
26933
|
+
reported: false,
|
|
26934
|
+
reason: "Node has no daemon id, so mesh transport cannot be reported from the selected coordinator."
|
|
26935
|
+
};
|
|
26936
|
+
}
|
|
26937
|
+
const matchedLiveSessionRecords = collectLiveMeshSessionRecords({
|
|
26938
|
+
meshId,
|
|
26939
|
+
node,
|
|
26940
|
+
nodeId,
|
|
26941
|
+
liveSessionRecords: liveMeshSessions,
|
|
26942
|
+
allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
|
|
26943
|
+
});
|
|
26944
|
+
const workspace = readLiveMeshNodeWorkspace({
|
|
26945
|
+
meshId,
|
|
26946
|
+
nodeId,
|
|
26947
|
+
liveSessionRecords: matchedLiveSessionRecords,
|
|
26948
|
+
allowCoordinatorSession: nodeId === selectedCoordinatorNodeId
|
|
26949
|
+
}) || (typeof node.workspace === "string" ? node.workspace : "");
|
|
26950
|
+
status.workspace = workspace || node.workspace;
|
|
26951
|
+
if (matchedLiveSessionRecords.length > 0) {
|
|
26952
|
+
const sessionIds = matchedLiveSessionRecords.map((record) => typeof record?.sessionId === "string" ? record.sessionId : "").filter(Boolean);
|
|
26953
|
+
const providerTypes = matchedLiveSessionRecords.map((record) => readStringValue(record?.providerType)).filter(Boolean);
|
|
26954
|
+
status.activeSessions = sessionIds;
|
|
26955
|
+
status.activeSessionDetails = matchedLiveSessionRecords.map(summarizeMeshSessionRecord);
|
|
26956
|
+
if (providerTypes.length > 0) {
|
|
26957
|
+
status.providers = Array.from(/* @__PURE__ */ new Set([...Array.isArray(status.providers) ? status.providers : [], ...providerTypes]));
|
|
25951
26958
|
}
|
|
25952
|
-
|
|
25953
|
-
|
|
25954
|
-
|
|
25955
|
-
const
|
|
25956
|
-
|
|
25957
|
-
|
|
25958
|
-
|
|
25959
|
-
|
|
25960
|
-
|
|
25961
|
-
|
|
25962
|
-
|
|
25963
|
-
|
|
25964
|
-
|
|
25965
|
-
|
|
25966
|
-
|
|
25967
|
-
|
|
25968
|
-
|
|
25969
|
-
|
|
25970
|
-
|
|
25971
|
-
|
|
25972
|
-
|
|
25973
|
-
|
|
25974
|
-
|
|
25975
|
-
|
|
26959
|
+
}
|
|
26960
|
+
if (workspace) {
|
|
26961
|
+
if (!fs10.existsSync(workspace)) {
|
|
26962
|
+
const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
|
|
26963
|
+
let remoteProbeApplied = false;
|
|
26964
|
+
if (inlineTransitGit) {
|
|
26965
|
+
status.git = inlineTransitGit;
|
|
26966
|
+
status.health = inlineTransitGit.isGitRepo ? deriveMeshNodeHealthFromGit(inlineTransitGit) : "degraded";
|
|
26967
|
+
remoteProbeApplied = true;
|
|
26968
|
+
} else if (!isSelfNode && daemonId && this.deps.dispatchMeshCommand && !directTruthUnavailableNodeIds.has(nodeId)) {
|
|
26969
|
+
try {
|
|
26970
|
+
const remoteGit = await probeRemoteMeshGitStatus({
|
|
26971
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
26972
|
+
daemonId,
|
|
26973
|
+
workspace,
|
|
26974
|
+
timeoutMs: 8e3
|
|
26975
|
+
});
|
|
26976
|
+
if (remoteGit) {
|
|
26977
|
+
status.git = remoteGit;
|
|
26978
|
+
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
26979
|
+
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
26980
|
+
remoteProbeApplied = true;
|
|
26981
|
+
}
|
|
26982
|
+
} catch {
|
|
26983
|
+
const refreshedConnection = this.deps.getMeshPeerConnectionStatus?.(daemonId);
|
|
26984
|
+
const refreshedConnectionState = readStringValue(refreshedConnection?.state);
|
|
26985
|
+
if (refreshedConnection && refreshedConnectionState === "connected") {
|
|
26986
|
+
status.connection = refreshedConnection;
|
|
26987
|
+
try {
|
|
26988
|
+
const remoteGit = await probeRemoteMeshGitStatus({
|
|
26989
|
+
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
26990
|
+
daemonId,
|
|
26991
|
+
workspace,
|
|
26992
|
+
timeoutMs: 12e3
|
|
26993
|
+
});
|
|
26994
|
+
if (remoteGit) {
|
|
26995
|
+
status.git = remoteGit;
|
|
26996
|
+
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
26997
|
+
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
26998
|
+
remoteProbeApplied = true;
|
|
26999
|
+
}
|
|
27000
|
+
} catch {
|
|
27001
|
+
}
|
|
27002
|
+
}
|
|
25976
27003
|
}
|
|
25977
27004
|
}
|
|
25978
|
-
|
|
25979
|
-
|
|
25980
|
-
|
|
25981
|
-
|
|
25982
|
-
|
|
25983
|
-
|
|
25984
|
-
|
|
25985
|
-
if (
|
|
25986
|
-
|
|
25987
|
-
|
|
27005
|
+
if (!remoteProbeApplied) {
|
|
27006
|
+
const connectionState = readStringValue(status.connection?.state);
|
|
27007
|
+
const pendingPeerGitProbe = !inlineTransitGit && !isSelfNode && !!daemonId && (readStringValue(status.machineStatus) === "online" || readStringValue(status.health) === "online" || connectionState === "connecting" || connectionState === "connected" || connectionState === "unknown");
|
|
27008
|
+
if (pendingPeerGitProbe) {
|
|
27009
|
+
status.gitProbePending = true;
|
|
27010
|
+
status.health = "unknown";
|
|
27011
|
+
}
|
|
27012
|
+
if (applyCachedInlineMeshNodeStatus(
|
|
27013
|
+
status,
|
|
27014
|
+
node,
|
|
27015
|
+
pendingPeerGitProbe ? { skipGit: true, skipError: true, skipHealth: true } : void 0
|
|
27016
|
+
)) {
|
|
27017
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
27018
|
+
nodeStatuses.push(status);
|
|
27019
|
+
continue;
|
|
27020
|
+
}
|
|
27021
|
+
if (meshRecord?.source === "inline_cache" && !isSelfNode) {
|
|
27022
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
27023
|
+
nodeStatuses.push(status);
|
|
27024
|
+
continue;
|
|
27025
|
+
}
|
|
25988
27026
|
}
|
|
25989
|
-
|
|
25990
|
-
|
|
25991
|
-
|
|
25992
|
-
|
|
25993
|
-
|
|
25994
|
-
|
|
25995
|
-
|
|
25996
|
-
|
|
25997
|
-
|
|
25998
|
-
|
|
25999
|
-
|
|
26000
|
-
|
|
26001
|
-
|
|
26002
|
-
|
|
26003
|
-
|
|
26004
|
-
hasConflicts: false,
|
|
26005
|
-
conflictFiles: [],
|
|
26006
|
-
stashCount: stashCount ? stashCount.split("\n").filter(Boolean).length : 0,
|
|
26007
|
-
lastCheckedAt: Date.now()
|
|
26008
|
-
};
|
|
26009
|
-
status.health = branch ? dirty ? "dirty" : "online" : "degraded";
|
|
26010
|
-
} catch {
|
|
26011
|
-
if (!applyCachedInlineMeshNodeStatus(status, node)) {
|
|
26012
|
-
status.health = "degraded";
|
|
27027
|
+
} else {
|
|
27028
|
+
try {
|
|
27029
|
+
const gitStatus = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
27030
|
+
status.git = gitStatus;
|
|
27031
|
+
recordInlineMeshDirectGitTruth(node, gitStatus, "selected_coordinator_local_git");
|
|
27032
|
+
if (gitStatus.isGitRepo) {
|
|
27033
|
+
status.health = deriveMeshNodeHealthFromGit(gitStatus);
|
|
27034
|
+
} else {
|
|
27035
|
+
status.health = "degraded";
|
|
27036
|
+
if (gitStatus.error && !status.error) status.error = gitStatus.error;
|
|
27037
|
+
}
|
|
27038
|
+
} catch {
|
|
27039
|
+
if (!applyCachedInlineMeshNodeStatus(status, node)) {
|
|
27040
|
+
status.health = "degraded";
|
|
27041
|
+
}
|
|
26013
27042
|
}
|
|
26014
27043
|
}
|
|
26015
27044
|
} else {
|
|
26016
27045
|
applyCachedInlineMeshNodeStatus(status, node);
|
|
26017
27046
|
}
|
|
27047
|
+
finalizeMeshNodeStatus({ status, node, daemonId, isSelfNode });
|
|
26018
27048
|
nodeStatuses.push(status);
|
|
26019
27049
|
}
|
|
26020
|
-
|
|
27050
|
+
const statusResult = {
|
|
26021
27051
|
success: true,
|
|
26022
27052
|
meshId: mesh.id,
|
|
26023
27053
|
meshName: mesh.name,
|
|
26024
27054
|
repoIdentity: mesh.repoIdentity,
|
|
26025
27055
|
defaultBranch: mesh.defaultBranch,
|
|
27056
|
+
refreshedAt,
|
|
27057
|
+
sourceOfTruth: {
|
|
27058
|
+
membership: meshRecord?.source === "inline_cache" ? "coordinator_inline_mesh_cache" : meshRecord?.source === "local_config" ? "local_mesh_config" : "inline_bootstrap_snapshot",
|
|
27059
|
+
coordinatorOwnsLiveTruth: directTruthSatisfied,
|
|
27060
|
+
...requireDirectPeerTruth ? {
|
|
27061
|
+
currentStatus: directTruthSatisfied ? "live_git_and_session_probes" : "direct_peer_truth_unavailable",
|
|
27062
|
+
directPeerTruth: {
|
|
27063
|
+
required: true,
|
|
27064
|
+
satisfied: directTruthSatisfied,
|
|
27065
|
+
directEvidenceCount: directTruth.directEvidenceCount,
|
|
27066
|
+
localConfirmedCount: directTruth.localConfirmedCount,
|
|
27067
|
+
peerAttemptedCount: directTruth.peerAttemptedCount,
|
|
27068
|
+
peerConfirmedCount: directTruth.peerConfirmedCount,
|
|
27069
|
+
unavailableNodeIds: directTruth.unavailableNodeIds
|
|
27070
|
+
}
|
|
27071
|
+
} : {},
|
|
27072
|
+
historicalEvidenceOnly: ["recoveryHints", "ledger.summary", "queue.summary"]
|
|
27073
|
+
},
|
|
26026
27074
|
nodes: nodeStatuses,
|
|
26027
27075
|
queue: { tasks: queue, summary: queueSummary },
|
|
26028
27076
|
ledger: { entries: ledgerEntries, summary: ledgerSummary }
|
|
26029
27077
|
};
|
|
27078
|
+
return this.rememberAggregateMeshStatus(meshId, statusResult, refreshReason);
|
|
26030
27079
|
} catch (e) {
|
|
26031
27080
|
return { success: false, error: e.message };
|
|
26032
27081
|
}
|
|
@@ -33957,6 +35006,7 @@ async function initDaemonComponents(config) {
|
|
|
33957
35006
|
sessionHostControl: config.sessionHostControl,
|
|
33958
35007
|
statusInstanceId: config.statusInstanceId,
|
|
33959
35008
|
statusVersion: config.statusVersion,
|
|
35009
|
+
getMeshPeerConnectionStatus: config.getMeshPeerConnectionStatus,
|
|
33960
35010
|
getCdpLogFn: config.getCdpLogFn || ((ideType) => LOG.forComponent(`CDP:${ideType}`).asLogFn())
|
|
33961
35011
|
});
|
|
33962
35012
|
poller = new AgentStreamPoller({
|
|
@@ -34231,6 +35281,7 @@ export {
|
|
|
34231
35281
|
prepareSessionChatTailUpdate,
|
|
34232
35282
|
prepareSessionModalUpdate,
|
|
34233
35283
|
probeCdpPort,
|
|
35284
|
+
queuePendingMeshCoordinatorEvent,
|
|
34234
35285
|
readChatHistory,
|
|
34235
35286
|
readLedgerEntries,
|
|
34236
35287
|
readLedgerSlice,
|