@adhdev/daemon-standalone 0.9.82-rc.370 → 0.9.82-rc.373
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 +266 -64
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/vendor/mcp-server/index.js +66 -1
- package/vendor/mcp-server/index.js.map +1 -1
package/package.json
CHANGED
|
@@ -1210,6 +1210,7 @@ function summarizeCompactSubmodules(submodules) {
|
|
|
1210
1210
|
...outOfSync.length > 0 ? { outOfSyncPaths: outOfSync } : {}
|
|
1211
1211
|
};
|
|
1212
1212
|
}
|
|
1213
|
+
var MESH_COMPACT_PRESERVED_MARKER_FIELDS = ["dataFreshness"];
|
|
1213
1214
|
function compactMeshStatusNode(entry) {
|
|
1214
1215
|
if (!entry || typeof entry !== "object") return entry;
|
|
1215
1216
|
const next = { ...entry };
|
|
@@ -1248,8 +1249,9 @@ function compactMeshStatusNode(entry) {
|
|
|
1248
1249
|
};
|
|
1249
1250
|
}
|
|
1250
1251
|
delete next.capabilityTagsByProvider;
|
|
1252
|
+
const elideSkip = /* @__PURE__ */ new Set(["git", "machine", "branchConvergence", "staleDaemonBuild", "sessions", ...MESH_COMPACT_PRESERVED_MARKER_FIELDS]);
|
|
1251
1253
|
for (const k of Object.keys(next)) {
|
|
1252
|
-
if (k
|
|
1254
|
+
if (elideSkip.has(k)) continue;
|
|
1253
1255
|
next[k] = elideLargeNestedValue(k, next[k]);
|
|
1254
1256
|
}
|
|
1255
1257
|
return next;
|
|
@@ -1289,6 +1291,10 @@ function minimalCompactNode(entry) {
|
|
|
1289
1291
|
reason: entry.branchConvergence.reason,
|
|
1290
1292
|
branch: entry.branchConvergence.branch
|
|
1291
1293
|
} : void 0;
|
|
1294
|
+
const preservedMarkers = {};
|
|
1295
|
+
for (const field of MESH_COMPACT_PRESERVED_MARKER_FIELDS) {
|
|
1296
|
+
if (entry[field] !== void 0) preservedMarkers[field] = entry[field];
|
|
1297
|
+
}
|
|
1292
1298
|
return {
|
|
1293
1299
|
nodeId: entry.nodeId,
|
|
1294
1300
|
workspace: entry.workspace,
|
|
@@ -1303,6 +1309,7 @@ function minimalCompactNode(entry) {
|
|
|
1303
1309
|
...entry.launchBlockedReason !== void 0 ? { launchBlockedReason: entry.launchBlockedReason } : {},
|
|
1304
1310
|
...bc ? { branchConvergence: bc } : {},
|
|
1305
1311
|
...entry.sessionSummary ? { sessionSummary: entry.sessionSummary } : {},
|
|
1312
|
+
...preservedMarkers,
|
|
1306
1313
|
folded: true
|
|
1307
1314
|
};
|
|
1308
1315
|
}
|
|
@@ -2492,6 +2499,18 @@ var MESH_FAST_FORWARD_NODE_TOOL = {
|
|
|
2492
2499
|
required: ["node_id"]
|
|
2493
2500
|
}
|
|
2494
2501
|
};
|
|
2502
|
+
var MESH_RESTART_DAEMON_TOOL = {
|
|
2503
|
+
name: "mesh_restart_daemon",
|
|
2504
|
+
description: `Update a mesh node's daemon to the latest published version on its release channel and restart it \u2014 the same path as the dashboard "preview update" button, exposed as a mesh command so a coordinator can roll a worker daemon onto a freshly deployed version without a manual restart round-trip. No agent session is launched. Idle-gated: a node whose daemon has an active session (generating / waiting_approval / starting) is refused with code "blocking_sessions" so an in-flight turn is never interrupted. If the node is already on the latest version it is a no-op (no restart), matching the dashboard button (returns alreadyLatest:true). Targets a single node \u2014 call other (idle) nodes first; restarting the coordinator's OWN daemon is naturally refused while its calling turn is active. Passing channel switches the daemon's release channel (and server URL) before restarting; omit it to keep the daemon on its configured channel.`,
|
|
2505
|
+
inputSchema: {
|
|
2506
|
+
type: "object",
|
|
2507
|
+
properties: {
|
|
2508
|
+
node_id: { type: "string", description: "Target node ID \u2014 the daemon that owns this node is updated and restarted." },
|
|
2509
|
+
channel: { type: "string", enum: ["stable", "preview"], description: "Optional release channel to update from. Defaults to the daemon's configured updateChannel. Setting it also repoints the daemon's server URL to that channel." }
|
|
2510
|
+
},
|
|
2511
|
+
required: ["node_id"]
|
|
2512
|
+
}
|
|
2513
|
+
};
|
|
2495
2514
|
var MESH_CHECKPOINT_TOOL = {
|
|
2496
2515
|
name: "mesh_checkpoint",
|
|
2497
2516
|
description: "Create a git checkpoint (commit) on a mesh node workspace.",
|
|
@@ -2767,6 +2786,7 @@ var ALL_MESH_TOOLS = [
|
|
|
2767
2786
|
MESH_GIT_STATUS_TOOL,
|
|
2768
2787
|
MESH_READ_NODE_LOGS_TOOL,
|
|
2769
2788
|
MESH_FAST_FORWARD_NODE_TOOL,
|
|
2789
|
+
MESH_RESTART_DAEMON_TOOL,
|
|
2770
2790
|
MESH_CHECKPOINT_TOOL,
|
|
2771
2791
|
MESH_APPROVE_TOOL,
|
|
2772
2792
|
MESH_CLONE_NODE_TOOL,
|
|
@@ -2805,6 +2825,7 @@ async function meshStatus(ctx, args = {}) {
|
|
|
2805
2825
|
...getNodeLaunchReadiness(node),
|
|
2806
2826
|
...buildNodeCapabilityExposure(node)
|
|
2807
2827
|
};
|
|
2828
|
+
let liveTruthProbed = false;
|
|
2808
2829
|
try {
|
|
2809
2830
|
const autoDiscover = node.policy?.autoDiscoverSubmodules !== false;
|
|
2810
2831
|
const statusResult = await commandForNode(ctx, node, "git_status", {
|
|
@@ -2813,6 +2834,7 @@ async function meshStatus(ctx, args = {}) {
|
|
|
2813
2834
|
includeSubmodules: autoDiscover,
|
|
2814
2835
|
submoduleIgnorePaths: node.policy?.submoduleIgnorePaths || void 0
|
|
2815
2836
|
});
|
|
2837
|
+
liveTruthProbed = true;
|
|
2816
2838
|
const status = extractGitStatus(statusResult);
|
|
2817
2839
|
const uncommittedChanges = countUncommittedChanges(status);
|
|
2818
2840
|
const dirty = isGitStatusDirty(status);
|
|
@@ -2848,6 +2870,13 @@ async function meshStatus(ctx, args = {}) {
|
|
|
2848
2870
|
noFallbackReason: failure.noFallbackReason
|
|
2849
2871
|
});
|
|
2850
2872
|
}
|
|
2873
|
+
entry.dataFreshness = (0, import_daemon_core.buildMeshNodeProbeFreshness)({
|
|
2874
|
+
git: entry.git,
|
|
2875
|
+
liveTruthProbed,
|
|
2876
|
+
isSelfNode: entry.machine?.sameMachine === true,
|
|
2877
|
+
daemonId: readNodeDaemonId(node),
|
|
2878
|
+
node
|
|
2879
|
+
});
|
|
2851
2880
|
const recoveryContext = (0, import_daemon_core.getSessionRecoveryContext)(mesh.id, { nodeId: node.id });
|
|
2852
2881
|
if (recoveryContext.consecutiveNodeFailures > 0) {
|
|
2853
2882
|
entry.recoveryHints = {
|
|
@@ -3718,6 +3747,19 @@ async function meshSendTask(ctx, args) {
|
|
|
3718
3747
|
if (node.policy?.readOnly) {
|
|
3719
3748
|
return JSON.stringify({ error: `Node '${args.node_id}' is read-only` });
|
|
3720
3749
|
}
|
|
3750
|
+
if (taskMode === "convergence" && node.isLocalWorktree === true) {
|
|
3751
|
+
return JSON.stringify({
|
|
3752
|
+
success: false,
|
|
3753
|
+
recoverable: true,
|
|
3754
|
+
code: "mesh_convergence_target_is_worktree",
|
|
3755
|
+
reason: "mesh_convergence_target_is_worktree",
|
|
3756
|
+
nodeId: args.node_id,
|
|
3757
|
+
sessionId: args.session_id,
|
|
3758
|
+
taskMode,
|
|
3759
|
+
error: `Node '${args.node_id}' is a worktree clone; a convergence task is base-only (it merges/pushes onto base). Dispatching it to a worktree session risks a multi-worktree push/deploy race.`,
|
|
3760
|
+
nextAction: `Dispatch the convergence task to the base node for this mesh, or run the deterministic fast-forward convergence path (mesh_fast_forward_node / mesh_refine_node) instead of mesh_send_task.`
|
|
3761
|
+
});
|
|
3762
|
+
}
|
|
3721
3763
|
let explicitTargetSession;
|
|
3722
3764
|
if (args.session_id && isWorkerTaskMode(taskMode)) {
|
|
3723
3765
|
try {
|
|
@@ -4420,6 +4462,26 @@ async function meshFastForwardNode(ctx, args) {
|
|
|
4420
4462
|
}, null, 2);
|
|
4421
4463
|
}
|
|
4422
4464
|
}
|
|
4465
|
+
async function meshRestartDaemon(ctx, args) {
|
|
4466
|
+
await refreshMeshFromDaemon(ctx);
|
|
4467
|
+
const node = await findNodeWithRefresh(ctx, args.node_id);
|
|
4468
|
+
try {
|
|
4469
|
+
const result = await commandForNode(ctx, node, "restart_daemon_node", {
|
|
4470
|
+
meshId: ctx.mesh.id,
|
|
4471
|
+
nodeId: node.id,
|
|
4472
|
+
inlineMesh: ctx.mesh,
|
|
4473
|
+
...args.channel ? { channel: args.channel } : {}
|
|
4474
|
+
});
|
|
4475
|
+
return JSON.stringify(unwrapCommandPayload(result), null, 2);
|
|
4476
|
+
} catch (e) {
|
|
4477
|
+
const failure = buildCoordinatorP2pRelayFailure(e, {
|
|
4478
|
+
command: "restart_daemon_node",
|
|
4479
|
+
targetDaemonId: node.daemonId,
|
|
4480
|
+
nodeId: args.node_id
|
|
4481
|
+
});
|
|
4482
|
+
return JSON.stringify(failure, null, 2);
|
|
4483
|
+
}
|
|
4484
|
+
}
|
|
4423
4485
|
async function meshCheckpoint(ctx, args) {
|
|
4424
4486
|
const node = await findNodeWithRefresh(ctx, args.node_id);
|
|
4425
4487
|
if (node.policy?.readOnly) {
|
|
@@ -5842,6 +5904,9 @@ async function startMcpServer(opts) {
|
|
|
5842
5904
|
case "mesh_fast_forward_node":
|
|
5843
5905
|
text = await meshFastForwardNode(meshCtx, a);
|
|
5844
5906
|
break;
|
|
5907
|
+
case "mesh_restart_daemon":
|
|
5908
|
+
text = await meshRestartDaemon(meshCtx, a);
|
|
5909
|
+
break;
|
|
5845
5910
|
case "mesh_checkpoint":
|
|
5846
5911
|
text = await meshCheckpoint(meshCtx, a);
|
|
5847
5912
|
break;
|