@adhdev/daemon-standalone 1.0.39-rc.4 → 1.0.39-rc.6
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/index.js +77 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/vendor/mcp-server/index.js +77 -7
- package/vendor/mcp-server/index.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/daemon-standalone",
|
|
3
|
-
"version": "1.0.39-rc.
|
|
3
|
+
"version": "1.0.39-rc.6",
|
|
4
4
|
"description": "ADHDev standalone daemon — embedded HTTP/WS server for local dashboard",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"license": "AGPL-3.0-or-later",
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@adhdev/ghostty-vt-node": "*",
|
|
40
|
-
"@adhdev/session-host-core": "1.0.39-rc.
|
|
40
|
+
"@adhdev/session-host-core": "1.0.39-rc.6",
|
|
41
41
|
"@xterm/addon-serialize": "^0.14.0",
|
|
42
42
|
"@xterm/xterm": "^6.0.0",
|
|
43
43
|
"chalk": "^5.3.0",
|
|
@@ -2404,14 +2404,32 @@ function findNode(mesh, nodeId) {
|
|
|
2404
2404
|
}
|
|
2405
2405
|
var DUPLICATE_DISPATCH_WINDOW_MS = 6e4;
|
|
2406
2406
|
async function refreshMeshFromDaemon(ctx) {
|
|
2407
|
+
const settledNodeIds = /* @__PURE__ */ new Set();
|
|
2407
2408
|
try {
|
|
2408
2409
|
const result = await ctx.transport.command("get_mesh", { meshId: ctx.mesh.id });
|
|
2409
|
-
if (!result?.success || !Array.isArray(result.mesh?.nodes)) return;
|
|
2410
|
+
if (!result?.success || !Array.isArray(result.mesh?.nodes)) return { settledNodeIds };
|
|
2410
2411
|
const refreshedNodes = result.mesh.nodes.filter((n) => n?.id).map((n) => n);
|
|
2411
|
-
|
|
2412
|
+
const merged = [...refreshedNodes];
|
|
2413
|
+
for (const existing of ctx.mesh.nodes) {
|
|
2414
|
+
const existingId = existing?.id;
|
|
2415
|
+
if (!existingId) continue;
|
|
2416
|
+
if (merged.some((n) => (0, import_daemon_core4.meshNodeIdMatches)(n, existingId))) continue;
|
|
2417
|
+
if (isLocalControlPlaneNode(ctx, existing)) {
|
|
2418
|
+
settledNodeIds.add(existingId);
|
|
2419
|
+
continue;
|
|
2420
|
+
}
|
|
2421
|
+
const clonedFromNodeId = readString(existing?.clonedFromNodeId) || readString(existing?.cloned_from_node_id);
|
|
2422
|
+
if (clonedFromNodeId && refreshedNodes.some((n) => (0, import_daemon_core4.meshNodeIdMatches)(n, clonedFromNodeId))) {
|
|
2423
|
+
settledNodeIds.add(existingId);
|
|
2424
|
+
continue;
|
|
2425
|
+
}
|
|
2426
|
+
merged.push(existing);
|
|
2427
|
+
}
|
|
2428
|
+
ctx.mesh.nodes.splice(0, ctx.mesh.nodes.length, ...merged);
|
|
2412
2429
|
ctx.mesh.updatedAt = result.mesh.updatedAt ?? ctx.mesh.updatedAt;
|
|
2413
2430
|
} catch {
|
|
2414
2431
|
}
|
|
2432
|
+
return { settledNodeIds };
|
|
2415
2433
|
}
|
|
2416
2434
|
async function syncCoordinatorDaemonMeshCache(ctx) {
|
|
2417
2435
|
if (!(ctx.transport instanceof IpcTransport)) return;
|
|
@@ -2423,19 +2441,71 @@ async function syncCoordinatorDaemonMeshCache(ctx) {
|
|
|
2423
2441
|
} catch {
|
|
2424
2442
|
}
|
|
2425
2443
|
}
|
|
2444
|
+
async function resolveNodeFromOwningDaemons(ctx, nodeId) {
|
|
2445
|
+
const transport = ctx.transport;
|
|
2446
|
+
if (typeof transport?.meshCommand !== "function") return { node: null, ownerUnreachable: false };
|
|
2447
|
+
const localDaemonId = ctx.localDaemonId;
|
|
2448
|
+
const candidates = [];
|
|
2449
|
+
const pushCandidate = (id) => {
|
|
2450
|
+
if (typeof id !== "string" || !id.trim()) return;
|
|
2451
|
+
if (localDaemonId && id === localDaemonId) return;
|
|
2452
|
+
if (!candidates.includes(id)) candidates.push(id);
|
|
2453
|
+
};
|
|
2454
|
+
for (const node of ctx.mesh.nodes) pushCandidate(node?.daemonId);
|
|
2455
|
+
pushCandidate(ctx.mesh?.meshHost?.hostDaemonId);
|
|
2456
|
+
if (candidates.length === 0) return { node: null, ownerUnreachable: false };
|
|
2457
|
+
let ownerUnreachable = false;
|
|
2458
|
+
for (const daemonId of candidates) {
|
|
2459
|
+
let result;
|
|
2460
|
+
try {
|
|
2461
|
+
result = await transport.meshCommand(daemonId, "get_mesh", { meshId: ctx.mesh.id });
|
|
2462
|
+
} catch {
|
|
2463
|
+
ownerUnreachable = true;
|
|
2464
|
+
continue;
|
|
2465
|
+
}
|
|
2466
|
+
const nodes = result?.mesh?.nodes ?? result?.result?.mesh?.nodes;
|
|
2467
|
+
if (!result?.success || !Array.isArray(nodes)) {
|
|
2468
|
+
if (result && result.success === false) ownerUnreachable = true;
|
|
2469
|
+
continue;
|
|
2470
|
+
}
|
|
2471
|
+
const found = nodes.find((n) => n?.id && (0, import_daemon_core4.meshNodeIdMatches)(n, nodeId));
|
|
2472
|
+
if (!found) continue;
|
|
2473
|
+
const existingIndex = ctx.mesh.nodes.findIndex((n) => (0, import_daemon_core4.meshNodeIdMatches)(n, nodeId));
|
|
2474
|
+
if (existingIndex >= 0) ctx.mesh.nodes[existingIndex] = found;
|
|
2475
|
+
else ctx.mesh.nodes.push(found);
|
|
2476
|
+
return { node: found, ownerUnreachable: false };
|
|
2477
|
+
}
|
|
2478
|
+
return { node: null, ownerUnreachable };
|
|
2479
|
+
}
|
|
2426
2480
|
async function findNodeWithRefresh(ctx, nodeId) {
|
|
2427
2481
|
const hit = ctx.mesh.nodes.find((n) => (0, import_daemon_core4.meshNodeIdMatches)(n, nodeId));
|
|
2428
2482
|
if (hit && !hit.isLocalWorktree) return hit;
|
|
2429
|
-
await refreshMeshFromDaemon(ctx);
|
|
2483
|
+
const { settledNodeIds } = await refreshMeshFromDaemon(ctx);
|
|
2430
2484
|
const refreshed = ctx.mesh.nodes.find((n) => (0, import_daemon_core4.meshNodeIdMatches)(n, nodeId));
|
|
2431
|
-
if (
|
|
2432
|
-
|
|
2485
|
+
if (refreshed) return refreshed;
|
|
2486
|
+
if (settledNodeIds.has(nodeId)) {
|
|
2487
|
+
throw new Error(`Node '${nodeId}' is not a member of mesh '${ctx.mesh.name}'`);
|
|
2488
|
+
}
|
|
2489
|
+
const owned = await resolveNodeFromOwningDaemons(ctx, nodeId);
|
|
2490
|
+
if (owned.node) return owned.node;
|
|
2491
|
+
if (owned.ownerUnreachable) {
|
|
2492
|
+
const err = new Error(
|
|
2493
|
+
`Node '${nodeId}' could not be resolved: the daemon that owns it is unreachable. This is NOT proof of non-membership \u2014 retry once the owning daemon is online.`
|
|
2494
|
+
);
|
|
2495
|
+
err.code = "mesh_node_owner_unreachable";
|
|
2496
|
+
throw err;
|
|
2497
|
+
}
|
|
2498
|
+
throw new Error(`Node '${nodeId}' is not a member of mesh '${ctx.mesh.name}'`);
|
|
2433
2499
|
}
|
|
2434
2500
|
async function findOptionalNodeWithRefresh(ctx, nodeId) {
|
|
2435
2501
|
const hit = ctx.mesh.nodes.find((n) => (0, import_daemon_core4.meshNodeIdMatches)(n, nodeId));
|
|
2436
2502
|
if (hit && !hit.isLocalWorktree) return hit;
|
|
2437
|
-
await refreshMeshFromDaemon(ctx);
|
|
2438
|
-
|
|
2503
|
+
const { settledNodeIds } = await refreshMeshFromDaemon(ctx);
|
|
2504
|
+
const refreshed = ctx.mesh.nodes.find((n) => (0, import_daemon_core4.meshNodeIdMatches)(n, nodeId));
|
|
2505
|
+
if (refreshed) return refreshed;
|
|
2506
|
+
if (settledNodeIds.has(nodeId)) return null;
|
|
2507
|
+
const owned = await resolveNodeFromOwningDaemons(ctx, nodeId);
|
|
2508
|
+
return owned.node;
|
|
2439
2509
|
}
|
|
2440
2510
|
function hasRecentDuplicateDispatch(ctx, args) {
|
|
2441
2511
|
const now = Date.now();
|