@adhdev/daemon-standalone 1.0.56-rc.6 → 1.0.56-rc.8
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 +1759 -1037
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/public/assets/{index-B43wNsru.js → index-keXYbbIn.js} +1 -1
- package/public/index.html +1 -1
- package/vendor/mcp-server/index.js +137 -7
- package/vendor/mcp-server/index.js.map +1 -1
package/public/index.html
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<meta name="description" content="ADHDev self-hosted dashboard for controlling AI agents" />
|
|
8
8
|
<link rel="icon" href="/otter-logo.png" />
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet" />
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-keXYbbIn.js"></script>
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/vendor-DgFmqOGd.js">
|
|
12
12
|
<link rel="stylesheet" crossorigin href="/assets/index-BN4rzCA5.css">
|
|
13
13
|
</head>
|
|
@@ -1323,7 +1323,7 @@ var MESH_QUEUE_CANCEL_TOOL = {
|
|
|
1323
1323
|
};
|
|
1324
1324
|
var MESH_QUEUE_REQUEUE_TOOL = {
|
|
1325
1325
|
name: "mesh_queue_requeue",
|
|
1326
|
-
description: "Return a mesh queue task to pending for retry. By default clears stale assigned owner and target session so another live session can claim it. When the task has exceeded its retry cap it is auto-failed instead; use force=true to override.",
|
|
1326
|
+
description: "Return a mesh queue task to pending for retry, optionally re-targeting it and/or REWRITING its instruction. By default clears stale assigned owner and target session so another live session can claim it. When the task has exceeded its retry cap it is auto-failed instead; use force=true to override. This is also the way OUT of parking: a task whose target-session pin went stale is PARKED (held, still addressed, claimable by nobody) and any requeue unparks it \u2014 see parkedTasks in mesh_view_queue.",
|
|
1327
1327
|
inputSchema: {
|
|
1328
1328
|
type: "object",
|
|
1329
1329
|
properties: {
|
|
@@ -1333,7 +1333,8 @@ var MESH_QUEUE_REQUEUE_TOOL = {
|
|
|
1333
1333
|
target_session_id: { type: "string", description: "Optional replacement target runtime session ID." },
|
|
1334
1334
|
clear_target_node: { type: "boolean", description: "When true, remove any existing target node constraint." },
|
|
1335
1335
|
keep_target_session: { type: "boolean", description: "When true, preserve an existing target session if target_session_id is not provided. Defaults false to avoid stale session targets." },
|
|
1336
|
-
force: { type: "boolean", description: "When true, bypass the retry cap and requeue even if maxRetries has been exceeded. Use only for explicit operator recovery." }
|
|
1336
|
+
force: { type: "boolean", description: "When true, bypass the retry cap and requeue even if maxRetries has been exceeded. Use only for explicit operator recovery." },
|
|
1337
|
+
message: { type: "string", description: "Optional REPLACEMENT instruction for the task. Use when the situation moved on while the task waited \u2014 the common case for a parked delta, e.g. the worker already finished the part your correction was about, so the original wording would now be wrong or redundant. Preserves the task id, mission linkage and dependents (unlike cancel + re-enqueue). Omitted or blank leaves the existing message untouched." }
|
|
1337
1338
|
},
|
|
1338
1339
|
required: ["task_id"]
|
|
1339
1340
|
}
|
|
@@ -1353,7 +1354,13 @@ var MESH_SEND_TASK_TOOL = {
|
|
|
1353
1354
|
read_only: { type: "boolean", description: "Snake-case alias for readonly." },
|
|
1354
1355
|
mission_id: { type: "string", description: "Mission this task belongs to (mesh_mission record id, full/exact). When set, the directly dispatched task is attributed to the mission task aggregates exactly like mesh_enqueue_task, including terminal completion. Omit for an unattributed direct dispatch. An unresolvable id is REJECTED before dispatch (mission_not_found), never silently attached." },
|
|
1355
1356
|
missionId: { type: "string", description: "CamelCase alias for mission_id." },
|
|
1356
|
-
difficulty: { type: "string", enum: ["easy", "medium", "difficult", "freeform"], description: "REQUIRED task execution difficulty. Classify each task by how hard the work actually is. On a direct dispatch the target node/session is already chosen, so difficulty is not used to ROUTE \u2014 it is recorded on the task so scheduling analytics, mission aggregates and (critically) failure-recovery relaunch all see the same axis a queued task carries. A recovery relaunch inherits this value from the ledger, so an unclassified direct dispatch would silently downgrade its own retry." }
|
|
1357
|
+
difficulty: { type: "string", enum: ["easy", "medium", "difficult", "freeform"], description: "REQUIRED task execution difficulty. Classify each task by how hard the work actually is. On a direct dispatch the target node/session is already chosen, so difficulty is not used to ROUTE \u2014 it is recorded on the task so scheduling analytics, mission aggregates and (critically) failure-recovery relaunch all see the same axis a queued task carries. A recovery relaunch inherits this value from the ledger, so an unclassified direct dispatch would silently downgrade its own retry." },
|
|
1358
|
+
delivery_mode: {
|
|
1359
|
+
type: "string",
|
|
1360
|
+
enum: ["when_idle", "interrupt"],
|
|
1361
|
+
description: "How to deliver when the target session is BUSY. Default 'when_idle': never disturbs the running turn \u2014 the task is queued and auto-delivered the moment the session goes idle. \u2605'interrupt' ABORTS the turn currently in flight by pressing the provider's own stop control (Ctrl-C, or ESC on antigravity-cli), then delivers this task once the session settles. THE WORK IN PROGRESS IS DISCARDED \u2014 whatever the agent had not yet finished is lost, and any partial edits it was mid-way through are left as they are. Use it only when the running turn is genuinely going the wrong way and finishing it is worse than losing it. If the target provider cannot interrupt (no stop control declared, or an empty stop key), the dispatch is REJECTED rather than quietly falling back to when_idle \u2014 so a steering attempt never reports success while the session actually runs on to completion under the old instructions. Re-send with 'when_idle' if delivery-after-completion is acceptable. Has no effect on an idle session (delivered immediately either way)."
|
|
1362
|
+
},
|
|
1363
|
+
deliveryMode: { type: "string", enum: ["when_idle", "interrupt"], description: "CamelCase alias for delivery_mode." }
|
|
1357
1364
|
},
|
|
1358
1365
|
required: ["node_id", "session_id", "message", "difficulty"]
|
|
1359
1366
|
}
|
|
@@ -5754,6 +5761,16 @@ async function meshViewQueue(ctx, args) {
|
|
|
5754
5761
|
via: e.payload?.via,
|
|
5755
5762
|
failedAt: e.payload?.dispatchFailedAt || e.timestamp
|
|
5756
5763
|
}));
|
|
5764
|
+
const parkedTasks = fullQueue.filter((task) => task?.parked?.reason).map((task) => ({
|
|
5765
|
+
taskId: task.id,
|
|
5766
|
+
parkedAt: task.parked.parkedAt,
|
|
5767
|
+
reason: task.parked.reason,
|
|
5768
|
+
originalTargetSessionId: task.parked.targetSessionId,
|
|
5769
|
+
originalTargetNodeId: task.parked.targetNodeId,
|
|
5770
|
+
currentTargetSessionId: task.targetSessionId,
|
|
5771
|
+
missionId: task.missionId,
|
|
5772
|
+
message: summarizeTaskMessage(task.message)
|
|
5773
|
+
}));
|
|
5757
5774
|
const staleAssignedTasks = maintenance.staleAssignedTasks || [];
|
|
5758
5775
|
const requestedHistoricalRows = queue.some((task) => HISTORICAL_QUEUE_STATUSES.has(String(task?.status || "")));
|
|
5759
5776
|
const pollingGuidance = buildActiveWorkPollingGuidance(activeWorkEvidence.summary);
|
|
@@ -5808,6 +5825,11 @@ async function meshViewQueue(ctx, args) {
|
|
|
5808
5825
|
historicalCount: summary.historicalCount,
|
|
5809
5826
|
visibleActiveCount: visibleSummary.activeCount,
|
|
5810
5827
|
visibleHistoricalCount: visibleSummary.historicalCount,
|
|
5828
|
+
...parkedTasks.length > 0 ? {
|
|
5829
|
+
parkedTasks,
|
|
5830
|
+
parkedTaskCount: parkedTasks.length,
|
|
5831
|
+
parkedTaskNote: "PARKED tasks are held for an explicit coordinator decision and are claimable by NOBODY \u2014 their delta was addressed to a session whose pin went stale, and the daemon deliberately will not re-home it onto another session. Nothing will move them until you act. Exits: mesh_queue_requeue(task_id, target_session_id=<live session>) to re-target, or with clear_target_session=true to let any compatible session take it; add message=<rewritten instruction> to the same call if the situation moved on while it waited; mesh_queue_cancel(task_id) if it is moot. Any requeue unparks the task. Left untouched they are failed (with a notification) once past the parked-task retention window."
|
|
5832
|
+
} : {},
|
|
5811
5833
|
staleAssignedTasks: compact ? staleAssignedTasks.slice(0, 10).map(compactQueueRow) : staleAssignedTasks,
|
|
5812
5834
|
staleAssignedCount: maintenance.staleAssignedCount,
|
|
5813
5835
|
queueMaintenance: maintenanceForResponse,
|
|
@@ -5913,6 +5935,7 @@ async function meshQueueRequeue(ctx, args) {
|
|
|
5913
5935
|
const clearTargetNode = args.clear_target_node === true || args.clearTargetNode === true;
|
|
5914
5936
|
const clearTargetSession = targetSessionId ? false : !keepTargetSession;
|
|
5915
5937
|
const force = args.force === true;
|
|
5938
|
+
const message = typeof args.message === "string" && args.message.trim() ? args.message : void 0;
|
|
5916
5939
|
if (ctx.transport instanceof IpcTransport) {
|
|
5917
5940
|
const raw = await ctx.transport.command("requeue_mesh_queue_task", {
|
|
5918
5941
|
meshId: ctx.mesh.id,
|
|
@@ -5922,7 +5945,8 @@ async function meshQueueRequeue(ctx, args) {
|
|
|
5922
5945
|
...targetSessionId ? { targetSessionId } : {},
|
|
5923
5946
|
clearTargetNode,
|
|
5924
5947
|
clearTargetSession,
|
|
5925
|
-
force
|
|
5948
|
+
force,
|
|
5949
|
+
...message ? { message } : {}
|
|
5926
5950
|
});
|
|
5927
5951
|
const result = unwrapCommandPayload(raw) || {};
|
|
5928
5952
|
if (result.success === false) {
|
|
@@ -5953,7 +5977,8 @@ async function meshQueueRequeue(ctx, args) {
|
|
|
5953
5977
|
targetSessionId,
|
|
5954
5978
|
clearTargetNode,
|
|
5955
5979
|
clearTargetSession,
|
|
5956
|
-
force
|
|
5980
|
+
force,
|
|
5981
|
+
...message ? { message } : {}
|
|
5957
5982
|
});
|
|
5958
5983
|
if (!task) return JSON.stringify({ success: false, error: `Queue task '${taskId}' not found` });
|
|
5959
5984
|
if (task.status === "failed" && task.cancelReason?.startsWith("max_retries_exceeded")) {
|
|
@@ -8426,8 +8451,107 @@ async function meshSendTask(ctx, args) {
|
|
|
8426
8451
|
}
|
|
8427
8452
|
if (explicitTargetSession && !isIdleSessionRecord(explicitTargetSession) && !isTerminalSessionRecord(explicitTargetSession)) {
|
|
8428
8453
|
const sessionStatus = typeof explicitTargetSession?.status === "string" ? explicitTargetSession.status : "unknown";
|
|
8429
|
-
const { resolveDeliveryDecision } = await import("@adhdev/daemon-core");
|
|
8430
|
-
const
|
|
8454
|
+
const { resolveDeliveryDecision, normalizeDeliveryMode } = await import("@adhdev/daemon-core");
|
|
8455
|
+
const modeInput = args.delivery_mode ?? args.deliveryMode;
|
|
8456
|
+
const { mode: deliveryMode, unrecognized: unrecognizedDeliveryMode } = normalizeDeliveryMode(modeInput);
|
|
8457
|
+
let interruptSupported = false;
|
|
8458
|
+
let interruptUnsupportedMessage;
|
|
8459
|
+
let interruptConfidence;
|
|
8460
|
+
if (deliveryMode === "interrupt") {
|
|
8461
|
+
try {
|
|
8462
|
+
const probe = unwrapCommandPayload(await commandForNode(ctx, node, "agent_command", {
|
|
8463
|
+
targetSessionId: args.session_id,
|
|
8464
|
+
agentType: resolvedProviderType,
|
|
8465
|
+
cliType: resolvedProviderType,
|
|
8466
|
+
providerType: resolvedProviderType,
|
|
8467
|
+
action: "interrupt_capability"
|
|
8468
|
+
}));
|
|
8469
|
+
interruptSupported = probe?.supported === true;
|
|
8470
|
+
interruptUnsupportedMessage = typeof probe?.message === "string" ? probe.message : void 0;
|
|
8471
|
+
interruptConfidence = typeof probe?.confidence === "string" ? probe.confidence : void 0;
|
|
8472
|
+
} catch (e) {
|
|
8473
|
+
interruptSupported = false;
|
|
8474
|
+
interruptUnsupportedMessage = `Could not determine interrupt capability for provider '${resolvedProviderType}' on node '${args.node_id}': ${e?.message || e}. Refusing to interrupt on an unverified capability.`;
|
|
8475
|
+
}
|
|
8476
|
+
}
|
|
8477
|
+
const policyResult = resolveDeliveryDecision(sessionStatus, {
|
|
8478
|
+
kind: "task",
|
|
8479
|
+
deliveryMode,
|
|
8480
|
+
interruptSupported,
|
|
8481
|
+
...interruptUnsupportedMessage ? { interruptUnsupportedMessage } : {}
|
|
8482
|
+
});
|
|
8483
|
+
if (policyResult.decision === "rejected" && policyResult.reason === "interrupt_unsupported_for_provider") {
|
|
8484
|
+
return JSON.stringify({
|
|
8485
|
+
success: false,
|
|
8486
|
+
dispatched: false,
|
|
8487
|
+
decision: "interrupt_unsupported",
|
|
8488
|
+
reason: policyResult.reason,
|
|
8489
|
+
nodeId: args.node_id,
|
|
8490
|
+
sessionId: args.session_id,
|
|
8491
|
+
sessionStatus,
|
|
8492
|
+
providerType: resolvedProviderType,
|
|
8493
|
+
requestedDeliveryMode: deliveryMode,
|
|
8494
|
+
message: policyResult.message,
|
|
8495
|
+
nextAction: `Re-send this task with delivery_mode 'when_idle' to have it delivered when session '${args.session_id}' finishes on its own, or stop the session and launch a fresh one if the in-flight work must not complete.`
|
|
8496
|
+
});
|
|
8497
|
+
}
|
|
8498
|
+
if (policyResult.decision === "interrupt") {
|
|
8499
|
+
const interruptResult = unwrapCommandPayload(await commandForNode(ctx, node, "agent_command", {
|
|
8500
|
+
targetSessionId: args.session_id,
|
|
8501
|
+
agentType: resolvedProviderType,
|
|
8502
|
+
cliType: resolvedProviderType,
|
|
8503
|
+
providerType: resolvedProviderType,
|
|
8504
|
+
action: "interrupt_turn",
|
|
8505
|
+
dispatchSource: "mesh-tools-session:mesh_send_task:interrupt"
|
|
8506
|
+
}));
|
|
8507
|
+
if (interruptResult?.success !== true || interruptResult?.interrupted !== true) {
|
|
8508
|
+
return JSON.stringify({
|
|
8509
|
+
success: false,
|
|
8510
|
+
dispatched: false,
|
|
8511
|
+
decision: "interrupt_failed",
|
|
8512
|
+
reason: interruptResult?.reason || "interrupt_rejected",
|
|
8513
|
+
nodeId: args.node_id,
|
|
8514
|
+
sessionId: args.session_id,
|
|
8515
|
+
sessionStatus,
|
|
8516
|
+
providerType: resolvedProviderType,
|
|
8517
|
+
error: interruptResult?.error || "The provider did not accept the interrupt.",
|
|
8518
|
+
nextAction: `Nothing was cancelled and nothing was delivered. Re-send with delivery_mode 'when_idle', or inspect the session with mesh_read_terminal before retrying.`
|
|
8519
|
+
});
|
|
8520
|
+
}
|
|
8521
|
+
const interruptedTask = (0, import_daemon_core6.enqueueTask)(ctx.mesh.id, message, {
|
|
8522
|
+
targetNodeId: args.node_id,
|
|
8523
|
+
targetSessionId: args.session_id,
|
|
8524
|
+
taskMode,
|
|
8525
|
+
difficulty,
|
|
8526
|
+
...readonly ? { readonly: true } : {},
|
|
8527
|
+
...missionId ? { missionId } : {},
|
|
8528
|
+
...ctx.coordinatorSessionId ? { sourceCoordinatorSessionId: ctx.coordinatorSessionId } : {}
|
|
8529
|
+
});
|
|
8530
|
+
return JSON.stringify({
|
|
8531
|
+
success: true,
|
|
8532
|
+
dispatched: false,
|
|
8533
|
+
decision: "interrupted_and_queued",
|
|
8534
|
+
taskId: interruptedTask.id,
|
|
8535
|
+
reason: policyResult.reason,
|
|
8536
|
+
nodeId: args.node_id,
|
|
8537
|
+
sessionId: args.session_id,
|
|
8538
|
+
sessionStatus,
|
|
8539
|
+
providerType: resolvedProviderType,
|
|
8540
|
+
taskMode: taskMode || void 0,
|
|
8541
|
+
interrupt: {
|
|
8542
|
+
sent: true,
|
|
8543
|
+
key: interruptResult?.keyName,
|
|
8544
|
+
// 'declared' means the stop key is declared by the spec but the
|
|
8545
|
+
// busy->idle effect was not measured live for this provider.
|
|
8546
|
+
confidence: interruptResult?.confidence || interruptConfidence || "declared"
|
|
8547
|
+
},
|
|
8548
|
+
turnDiscarded: true,
|
|
8549
|
+
message: `Interrupted the in-flight turn on session '${args.session_id}' via ${interruptResult?.keyName || "the stop control"}. That turn was cancelled and its unfinished work is lost. Task '${interruptedTask.id}' is pinned to this session and delivers as soon as it reports idle.`,
|
|
8550
|
+
nextAction: interruptResult?.confidence === "proven" ? `Track with mesh_status; no manual resend needed.` : `Interrupt support for '${resolvedProviderType}' is DECLARED by its spec but not live-verified. Confirm with mesh_status that the session returned to idle and picked up the task; if it did not, use mesh_read_terminal to inspect.`,
|
|
8551
|
+
...unrecognizedDeliveryMode ? { deliveryModeWarning: `Unrecognized delivery_mode '${unrecognizedDeliveryMode}' ignored.` } : {},
|
|
8552
|
+
...buildMissionInactiveWarning(ctx, missionId) ?? {}
|
|
8553
|
+
});
|
|
8554
|
+
}
|
|
8431
8555
|
if (policyResult.decision === "queued") {
|
|
8432
8556
|
const queuedTask = (0, import_daemon_core6.enqueueTask)(ctx.mesh.id, message, {
|
|
8433
8557
|
targetNodeId: args.node_id,
|
|
@@ -8450,6 +8574,12 @@ async function meshSendTask(ctx, args) {
|
|
|
8450
8574
|
taskMode: taskMode || void 0,
|
|
8451
8575
|
message: policyResult.message,
|
|
8452
8576
|
nextAction: `Task '${queuedTask.id}' is queued and pinned to session '${args.session_id}' \u2014 it auto-delivers the moment the session goes idle. Use mesh_status or mesh_task_history to track it; no manual resend needed.`,
|
|
8577
|
+
// A misspelled delivery_mode silently became when_idle. Say so — a
|
|
8578
|
+
// caller who meant to interrupt must not read this queued result as
|
|
8579
|
+
// "my steering landed".
|
|
8580
|
+
...unrecognizedDeliveryMode ? {
|
|
8581
|
+
deliveryModeWarning: `Unrecognized delivery_mode '${unrecognizedDeliveryMode}' was ignored; this task was queued (when_idle) and the running turn was NOT interrupted. Valid values are 'when_idle' and 'interrupt'.`
|
|
8582
|
+
} : {},
|
|
8453
8583
|
...buildMissionInactiveWarning(ctx, missionId) ?? {}
|
|
8454
8584
|
});
|
|
8455
8585
|
}
|