comfyui-mcp 0.48.26 → 0.48.27
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/orchestrator/panel-tools.js +93 -0
- package/dist/orchestrator/panel-tools.js.map +1 -1
- package/dist/services/node-management.js +97 -49
- package/dist/services/node-management.js.map +1 -1
- package/dist/services/ui-bridge.js +95 -5
- package/dist/services/ui-bridge.js.map +1 -1
- package/package.json +1 -1
|
@@ -244,6 +244,57 @@ function isRetrySafeCmd(cmd) {
|
|
|
244
244
|
const name = typeof cmd.cmd === "string" ? cmd.cmd : "";
|
|
245
245
|
return RETRY_SAFE_CMDS.has(name);
|
|
246
246
|
}
|
|
247
|
+
// Graph-EDIT mutations that CHANGE the user's canvas (undoable edits). These are
|
|
248
|
+
// the #436 bug surface: a real side effect the bridge will NOT auto-retry, so —
|
|
249
|
+
// unlike a read — such a command can be neither parked mid-command nor retried
|
|
250
|
+
// once, and firing it into the post-restart "Connected: none" window fails with
|
|
251
|
+
// "no connected tab". It must await a stable binding BEFORE dispatch.
|
|
252
|
+
//
|
|
253
|
+
// This is an EXPLICIT ALLOWLIST, deliberately NOT "everything not read-only":
|
|
254
|
+
// several genuine reads/probes/views that flow through ctx.call are absent from
|
|
255
|
+
// BRIDGE_READONLY_CMDS (e.g. graph_list_subgraphs, training_get_state,
|
|
256
|
+
// graph_canvas, graph_screenshot), so an exclusion rule would wrongly make THOSE
|
|
257
|
+
// wait out the reconnect budget. Under-inclusion here is at worst an unfixed edge
|
|
258
|
+
// (a command keeps today's behavior); over-inclusion would regress a read — so we
|
|
259
|
+
// list only commands that unambiguously mutate the graph. Keep in sync when new
|
|
260
|
+
// graph-edit tools are added (mirrors the RETRY_SAFE_CMDS maintenance model).
|
|
261
|
+
const MUTATING_GRAPH_EDIT_CMDS = new Set([
|
|
262
|
+
"graph_add_node",
|
|
263
|
+
"graph_remove_node",
|
|
264
|
+
"graph_clear",
|
|
265
|
+
"graph_connect",
|
|
266
|
+
"graph_disconnect",
|
|
267
|
+
"graph_set_widget",
|
|
268
|
+
"graph_move_node",
|
|
269
|
+
"graph_resize_node",
|
|
270
|
+
"graph_set_title",
|
|
271
|
+
"graph_set_node_mode",
|
|
272
|
+
"graph_set_node_color",
|
|
273
|
+
"graph_set_node_collapsed",
|
|
274
|
+
"graph_update_node",
|
|
275
|
+
"graph_create_group",
|
|
276
|
+
"graph_edit_group",
|
|
277
|
+
"graph_remove_group",
|
|
278
|
+
"graph_move_group",
|
|
279
|
+
"graph_create_subgraph",
|
|
280
|
+
"graph_add_subgraph",
|
|
281
|
+
"graph_save_subgraph",
|
|
282
|
+
"graph_unpack_subgraph",
|
|
283
|
+
"graph_subgraph_group",
|
|
284
|
+
"graph_expose_subgraph_input",
|
|
285
|
+
"graph_expose_subgraph_output",
|
|
286
|
+
"graph_promote_widget",
|
|
287
|
+
"graph_move_rail",
|
|
288
|
+
"graph_paste_nodes",
|
|
289
|
+
"graph_auto_layout",
|
|
290
|
+
"graph_load",
|
|
291
|
+
]);
|
|
292
|
+
/** A MUTATING graph edit that must await a stable tab binding before dispatch so
|
|
293
|
+
* it never fires into the post-restart "Connected: none" window (#436). */
|
|
294
|
+
function isMutatingGraphCmd(cmd) {
|
|
295
|
+
const name = typeof cmd.cmd === "string" ? cmd.cmd : "";
|
|
296
|
+
return MUTATING_GRAPH_EDIT_CMDS.has(name);
|
|
297
|
+
}
|
|
247
298
|
/** True when an error is a TRANSIENT transport/reconnect drop (the tab went away
|
|
248
299
|
* or was replaced), NOT a genuine command error or a live-but-frozen reply
|
|
249
300
|
* timeout. Deliberately EXCLUDES "did not reply within N ms" (a backgrounded/
|
|
@@ -1525,6 +1576,21 @@ export function makePanelToolCtx(bridge, tabId, workflowTargets) {
|
|
|
1525
1576
|
};
|
|
1526
1577
|
const call = async (cmd, timeoutMs) => {
|
|
1527
1578
|
try {
|
|
1579
|
+
// #436: a MUTATING graph edit must not fire into the "Connected: none"
|
|
1580
|
+
// window a ComfyUI restart/reload opens. A read survives that window (it is
|
|
1581
|
+
// parked mid-command and is retry-safe), but a mutating edit is NEITHER — so
|
|
1582
|
+
// panel_graph_outline succeeds while the very next panel_add_node hits
|
|
1583
|
+
// resolveTarget's momentarily-empty registry and fails with
|
|
1584
|
+
// "no connected tab … Connected: none" (the flap). Await a stable binding
|
|
1585
|
+
// BEFORE dispatch — nothing is sent during the wait, so there is no
|
|
1586
|
+
// double-apply risk — exactly as workflow_open/save already do. This returns
|
|
1587
|
+
// INSTANTLY for a healthy session and only waits in the zero-tab window; the
|
|
1588
|
+
// read path (parking + retry-once below) is left exactly as-is. A wait that
|
|
1589
|
+
// times out unreached still falls through to sendRouted, whose authoritative
|
|
1590
|
+
// dispatched:false surfaces the actionable "nothing applied — rebind" message.
|
|
1591
|
+
if (isMutatingGraphCmd(cmd)) {
|
|
1592
|
+
await awaitReachable();
|
|
1593
|
+
}
|
|
1528
1594
|
ensureReachable();
|
|
1529
1595
|
return ok(await sendRouted(cmd, timeoutMs));
|
|
1530
1596
|
}
|
|
@@ -1552,6 +1618,33 @@ export function makePanelToolCtx(bridge, tabId, workflowTargets) {
|
|
|
1552
1618
|
return fail(err2);
|
|
1553
1619
|
}
|
|
1554
1620
|
}
|
|
1621
|
+
// #442 defect 4: a MUTATING command (deliberately excluded from RETRY_SAFE_CMDS)
|
|
1622
|
+
// that the bridge refused BEFORE any socket write surfaced the bare routing error
|
|
1623
|
+
// ("no connected tab … Connected: none") with no recovery path — whereas a
|
|
1624
|
+
// retry-safe read like graph_get_errors, via the branch above, names the rebind.
|
|
1625
|
+
// That asymmetry made a brief post-reconnect read/edit-channel disagreement look
|
|
1626
|
+
// like a dead agent (panel_list_workflows kept answering while panel_set_widget
|
|
1627
|
+
// failed, in a multi-tab session the strict-single silent auto-heal won't touch).
|
|
1628
|
+
// We must NOT retry the mutating command (double-apply risk), but the bridge's
|
|
1629
|
+
// AUTHORITATIVE typed flag proves nothing was dispatched (dispatchOutcomeOf ===
|
|
1630
|
+
// false) — so it is safe to state nothing was applied and name the rebind recovery,
|
|
1631
|
+
// preserving the raw cause. Keying on the TYPED flag (not error text) means a
|
|
1632
|
+
// POST-dispatch executor ok:false reply that merely quotes "no connected tab" is
|
|
1633
|
+
// never mis-wrapped as "nothing applied".
|
|
1634
|
+
if (dispatchOutcomeOf(err) === false) {
|
|
1635
|
+
const name = typeof cmd.cmd === "string" ? cmd.cmd : "panel command";
|
|
1636
|
+
// Neutral wording: a dispatched:false flag proves only that the command was NOT
|
|
1637
|
+
// dispatched — it can be a routing refusal (the bound tab is gone / reconnecting),
|
|
1638
|
+
// an ambiguous-or-multiple-tab resolver refusal (other tabs DO exist), or a socket
|
|
1639
|
+
// write failure. All share the same TRUE facts (nothing applied) and the same
|
|
1640
|
+
// recovery (rebind onto the tab that's live now); the raw cause carries the
|
|
1641
|
+
// specifics. Do NOT overstate "disconnected", which is false for the ambiguity case.
|
|
1642
|
+
return fail(`${name} could not be dispatched to this session's panel tab — nothing was applied. ` +
|
|
1643
|
+
`The tab may be disconnected, still reconnecting after a restart/reload, or the ` +
|
|
1644
|
+
`session's binding is stale (e.g. another workflow tab is now active). Retry in a ` +
|
|
1645
|
+
`moment, or rebind with panel_set_workflow_target({mode:"current"}) to follow the ` +
|
|
1646
|
+
`tab that's live now. (${err instanceof Error ? err.message : String(err)})`);
|
|
1647
|
+
}
|
|
1555
1648
|
return fail(err);
|
|
1556
1649
|
}
|
|
1557
1650
|
};
|