comfyui-mcp 0.50.22 → 0.50.23
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.
|
@@ -2520,8 +2520,33 @@ refusalCause) {
|
|
|
2520
2520
|
: ` It has no graph command fence; whether graph reads work is unknown, because the ` +
|
|
2521
2521
|
`read that would have told us is the one that failed.`) +
|
|
2522
2522
|
` This is not a rebind — it is an unknown.` +
|
|
2523
|
-
|
|
2524
|
-
|
|
2523
|
+
// #1071 — WHY the read failed decides the remedy, exactly as the
|
|
2524
|
+
// no_identity case below already does. Bucketing them would hand half the
|
|
2525
|
+
// callers an instruction they cannot act on.
|
|
2526
|
+
//
|
|
2527
|
+
// - REFUSED BY THE FENCE: retrying is provably useless. This rebind reads
|
|
2528
|
+
// workflow_list, which the panel fences, so the fence being wrong is
|
|
2529
|
+
// precisely what makes the read fail — every time, forever. A reporter
|
|
2530
|
+
// called this five times over twenty minutes on "retry in a moment" and
|
|
2531
|
+
// lost the canvas for the rest of the task. workflow_open is the one
|
|
2532
|
+
// command the fence EXEMPTS, so it still runs while everything else is
|
|
2533
|
+
// refused, and it now re-derives the fence from its own reply.
|
|
2534
|
+
// - ANY OTHER CAUSE (a dead tab, a transport drop, a busy panel): the
|
|
2535
|
+
// panel is not answering at all, so reopening would fail too and
|
|
2536
|
+
// retrying really is the reachable move.
|
|
2537
|
+
(/workflow instance mismatch/i.test(r.detail)
|
|
2538
|
+
? `\n\nWHAT TO DO: reopen the workflow you want with panel_open_workflow(<path>). ` +
|
|
2539
|
+
`The panel refused the read because of the FENCE itself, so retrying this call ` +
|
|
2540
|
+
`cannot work — it needs the very read the fence blocks. The panel's fence EXEMPTS ` +
|
|
2541
|
+
`workflow_open, so it still runs while everything else is refused, and it ` +
|
|
2542
|
+
`re-derives this session's fence from its own reply. Note panel_list_workflows is ` +
|
|
2543
|
+
`fenced too, so if you do not already know the path, ask the user rather than ` +
|
|
2544
|
+
`guessing. If the canvas you want is an UNSAVED one (a blank workflow you just ` +
|
|
2545
|
+
`created), there is no path to reopen and opening anything else would abandon it — ` +
|
|
2546
|
+
`that case needs the tab refresh below, not a reopen. If reopening also fails: ` +
|
|
2547
|
+
`${RELOAD_TAB_REMEDY}`
|
|
2548
|
+
: `\n\nWHAT TO DO: retry in a moment — a busy or mid-reconnect panel often answers ` +
|
|
2549
|
+
`on the next attempt. If it keeps failing: ${RELOAD_TAB_REMEDY}`) +
|
|
2525
2550
|
`\n\nUNDERLYING CAUSE (quoted verbatim — disregard any rebind advice inside it; ` +
|
|
2526
2551
|
`rebinding is what just failed): ${r.detail}`,
|
|
2527
2552
|
};
|
|
@@ -2621,18 +2646,52 @@ async function refreshOpenWorkflowUuid(ctx, requestedPath, openResult) {
|
|
|
2621
2646
|
: null;
|
|
2622
2647
|
if (!requestedIdentity || requestedIdentity !== openedIdentity)
|
|
2623
2648
|
return;
|
|
2649
|
+
// THREE outcomes for this corroborating read, not two — and conflating the last
|
|
2650
|
+
// two is #1071 (also #932/#1043).
|
|
2651
|
+
//
|
|
2652
|
+
// `workflow_list` is NOT exempt from the panel's fence (activeWorkflowFenceApplies
|
|
2653
|
+
// exempts only canvas-independent ops, workflow_open/new, and non-active-targeted
|
|
2654
|
+
// rename/close). So in exactly the state this refresh exists to repair — a session
|
|
2655
|
+
// fenced to a workflow instance that is no longer active — the read is REFUSED by
|
|
2656
|
+
// the stale fence, the old code took the `return` / `catch`, and the fence was
|
|
2657
|
+
// never refreshed. The recovery was gated behind the one call the wedge blocks.
|
|
2658
|
+
//
|
|
2659
|
+
// The open reply already carries what is needed. The panel publishes
|
|
2660
|
+
// `workflow_uuid` there only after a FINAL SYNCHRONOUS check that `target` is
|
|
2661
|
+
// still the active workflow (#716, activeWorkflowUuidForOpenReply) — omitting it
|
|
2662
|
+
// otherwise, expressly so "the MCP keeps its existing fence fail-closed". It is a
|
|
2663
|
+
// fence-quality value the panel went out of its way to prove; using it when the
|
|
2664
|
+
// read cannot be made is what it is for.
|
|
2665
|
+
let list = null;
|
|
2666
|
+
let readable = false;
|
|
2624
2667
|
try {
|
|
2625
|
-
const
|
|
2626
|
-
if (!
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
refreshWorkflowUuid(ctx, list.active) || refreshWorkflowUuid(ctx, parseToolResultJson(openResult));
|
|
2668
|
+
const res = await ctx.call({ cmd: "workflow_list" }, 6000);
|
|
2669
|
+
if (!res?.isError) {
|
|
2670
|
+
list = parseToolResultJson(res);
|
|
2671
|
+
readable = list !== null;
|
|
2672
|
+
}
|
|
2631
2673
|
}
|
|
2632
2674
|
catch {
|
|
2633
|
-
|
|
2634
|
-
|
|
2675
|
+
readable = false;
|
|
2676
|
+
}
|
|
2677
|
+
if (readable) {
|
|
2678
|
+
// ANSWERED. It either confirms our target is active — prefer the just-read
|
|
2679
|
+
// value, which is fresher than the reply — or it names a DIFFERENT active
|
|
2680
|
+
// workflow, in which case another tab won the slot and adopting our target's
|
|
2681
|
+
// uuid would fence this session to a canvas that is not mounted. Adopt nothing.
|
|
2682
|
+
if (!activeMatchesOpenRefreshTarget(list.active, requestedPath))
|
|
2683
|
+
return;
|
|
2684
|
+
refreshWorkflowUuid(ctx, list.active) || refreshWorkflowUuid(ctx, parsedOpen);
|
|
2685
|
+
return;
|
|
2635
2686
|
}
|
|
2687
|
+
// COULD NOT ASK — the wedged case. Fall back to the reply's proven uuid rather
|
|
2688
|
+
// than leaving the session fenced to a dead instance forever. This is strictly
|
|
2689
|
+
// safer than the alternative it replaces: a stamp the panel proved against its
|
|
2690
|
+
// own active workflow can only authorize commands naming the canvas that is
|
|
2691
|
+
// actually mounted, whereas doing nothing here guarantees every subsequent
|
|
2692
|
+
// command is refused. A reply that carries no uuid (the panel could not prove
|
|
2693
|
+
// it) still refreshes nothing, so fail-closed is preserved.
|
|
2694
|
+
refreshWorkflowUuid(ctx, parsedOpen);
|
|
2636
2695
|
}
|
|
2637
2696
|
/** Exact resolved-path check for an open receipt. A filename/basename is not a
|
|
2638
2697
|
* workflow identity: `other/foo.json` must never confirm `wanted/foo.json`. */
|