comfyui-mcp 0.52.58 → 0.52.60
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 +84 -3
- package/dist/orchestrator/panel-tools.js.map +1 -1
- package/dist/services/missing-models.js +37 -5
- package/dist/services/missing-models.js.map +1 -1
- package/dist/services/ui-bridge.js +303 -31
- package/dist/services/ui-bridge.js.map +1 -1
- package/package.json +1 -1
|
@@ -41,7 +41,7 @@ import { isPanelAnsweredError } from "../services/panel-answered.js";
|
|
|
41
41
|
import { isPreExecutorRefusal } from "../services/panel-refusal.js";
|
|
42
42
|
import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
|
|
43
43
|
import { parse as parseYaml } from "yaml";
|
|
44
|
-
import { requiredPanelVersion, SEMVER_RE, LATE_ASK_TTL_MS, tabIncarnationSlot, } from "../services/ui-bridge.js";
|
|
44
|
+
import { requiredPanelVersion, SEMVER_RE, LATE_ASK_TTL_MS, tabIncarnationSlot, SHOW_MEDIA_KIND_MIN_PANEL_VERSION, showMediaItemsPanelCannotPaint, } from "../services/ui-bridge.js";
|
|
45
45
|
import { compareSemver } from "../services/self-update.js";
|
|
46
46
|
import { describeInstallPanelAction } from "../services/panel-recovery.js";
|
|
47
47
|
import { peekResolvedPanelBase, primePanelBase, verifiedPanelDiskVersion, } from "../services/panel-workspace.js";
|
|
@@ -1303,6 +1303,8 @@ const RECONNECT_WAIT_MAX_MS = 60_000;
|
|
|
1303
1303
|
* healthy (panel#654): `panel_graph_outline` reported Connected: none and only a
|
|
1304
1304
|
* hard refresh restored the tab. 35s covers those recoveries; the 60s ceiling stays. */
|
|
1305
1305
|
const RECONNECT_WAIT_DEFAULT_S = 35;
|
|
1306
|
+
/** Fresh original-tab hello must persist this long before graph tools are ready (#2067). */
|
|
1307
|
+
const POST_RESTART_RECONNECT_STABLE_MS = 2000;
|
|
1306
1308
|
function reconnectWaitTiming() {
|
|
1307
1309
|
if (reconnectWaitTimingOverride)
|
|
1308
1310
|
return reconnectWaitTimingOverride;
|
|
@@ -3768,6 +3770,56 @@ function tabAdvertisedPanelVersion(ctx) {
|
|
|
3768
3770
|
const v = reading?.version;
|
|
3769
3771
|
return typeof v === "string" && SEMVER_RE.test(v.trim()) ? v.trim() : undefined;
|
|
3770
3772
|
}
|
|
3773
|
+
function tabPanelVersionReading(ctx) {
|
|
3774
|
+
const fn = ctx.bridge.advertisedPanelVersion;
|
|
3775
|
+
if (typeof fn !== "function")
|
|
3776
|
+
return {};
|
|
3777
|
+
try {
|
|
3778
|
+
return fn.call(ctx.bridge, ctx.tabId) ?? {};
|
|
3779
|
+
}
|
|
3780
|
+
catch {
|
|
3781
|
+
return {};
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3784
|
+
function tabAdvertisedShowMediaKinds(ctx) {
|
|
3785
|
+
const fn = ctx.bridge.tabShowMediaKinds;
|
|
3786
|
+
if (typeof fn !== "function")
|
|
3787
|
+
return undefined;
|
|
3788
|
+
try {
|
|
3789
|
+
return fn.call(ctx.bridge, ctx.tabId);
|
|
3790
|
+
}
|
|
3791
|
+
catch {
|
|
3792
|
+
return undefined;
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
/**
|
|
3796
|
+
* #2017 — refuse a kind this panel is proven unable to paint, rather than send
|
|
3797
|
+
* an item that becomes a broken-image card and reports success.
|
|
3798
|
+
*
|
|
3799
|
+
* Names the advertised version (when we have one) and the upgrade; a restart
|
|
3800
|
+
* alone leaves cached JS running, so the hard-refresh is part of the remedy.
|
|
3801
|
+
*/
|
|
3802
|
+
function formatShowMediaKindUnsupported(blocked) {
|
|
3803
|
+
const kinds = [...new Set(blocked.map((b) => b.kind))];
|
|
3804
|
+
const kindList = kinds.map((k) => `"${k}"`).join(", ");
|
|
3805
|
+
const needed = blocked.find((b) => b.needed)?.needed ??
|
|
3806
|
+
kinds.map((k) => SHOW_MEDIA_KIND_MIN_PANEL_VERSION[k]).find((v) => typeof v === "string");
|
|
3807
|
+
const version = blocked.find((b) => b.version)?.version;
|
|
3808
|
+
const items = blocked.map((b) => ` - ${b.filename} (${b.kind})`).join("\n");
|
|
3809
|
+
const update = describeInstallPanelAction("update", "update the ComfyUI-MCP panel via ComfyUI Manager");
|
|
3810
|
+
const floor = needed ? ` to ≥${needed}` : " to a build that can paint it";
|
|
3811
|
+
const detected = version ? ` This tab announced panel ${version}.` : "";
|
|
3812
|
+
const why = blocked.some((b) => b.reason === "not_in_hello")
|
|
3813
|
+
? `The panel advertised the kinds it can paint and ${kindList} ${kinds.length === 1 ? "is" : "are"} not among them.`
|
|
3814
|
+
: `kind ${kindList} ${kinds.length === 1 ? "is" : "are"} only understood by panels from #710 onward` +
|
|
3815
|
+
(needed ? ` (first shipped in ${needed})` : "") +
|
|
3816
|
+
".";
|
|
3817
|
+
return (`This panel cannot paint ${kindList}.${detected} ${why} ` +
|
|
3818
|
+
`Sending ${blocked.length === 1 ? "it" : "them"} would show a broken-image card and report success.\n` +
|
|
3819
|
+
`Items not sent:\n${items}\n` +
|
|
3820
|
+
`${update}${floor}, then HARD-REFRESH the browser tab (Ctrl+Shift+R, or Cmd+Shift+R on macOS); ` +
|
|
3821
|
+
`a restart alone leaves the tab running cached old JS.`);
|
|
3822
|
+
}
|
|
3771
3823
|
/**
|
|
3772
3824
|
* #1828 — an allowlisted frontend-only type refused as "backend does not
|
|
3773
3825
|
* provide it" is version skew when the tab's advertised panel is below this
|
|
@@ -8770,6 +8822,11 @@ export function makePanelToolCtx(bridge, tabId, workflowTargets, onRunTicketOpen
|
|
|
8770
8822
|
// fresh hello can keep the same tab/socket id or arrive under a new one; in the
|
|
8771
8823
|
// latter case only rebind after the old target is gone, preserving strict
|
|
8772
8824
|
// multi-tab routing and never guessing away from a still-live pre-restart tab.
|
|
8825
|
+
//
|
|
8826
|
+
// #2067 — the first newer generation is not durable. A ComfyUI restart can
|
|
8827
|
+
// hello, then drop the socket a moment later; returning true there reports
|
|
8828
|
+
// graph_tools_ready while the next graph call sees Connected: none. The same
|
|
8829
|
+
// identity must still be present after a short stability window.
|
|
8773
8830
|
const awaitPostRestartReachable = async (before, budgetMs) => {
|
|
8774
8831
|
// The actual UiBridge exposes a tab-session binding. Preserve historical
|
|
8775
8832
|
// lightweight/mock-context behavior only when that capability does not exist
|
|
@@ -8781,14 +8838,24 @@ export function makePanelToolCtx(bridge, tabId, workflowTargets, onRunTicketOpen
|
|
|
8781
8838
|
const timing = reconnectWaitTiming();
|
|
8782
8839
|
const budget = Math.max(0, budgetMs != null ? Math.min(budgetMs, timing.budgetMs) : timing.budgetMs);
|
|
8783
8840
|
const deadline = Date.now() + budget;
|
|
8841
|
+
const stableMs = Math.max(0, timing.stableMs ?? POST_RESTART_RECONNECT_STABLE_MS);
|
|
8784
8842
|
const isOriginalTabReconnected = () => {
|
|
8785
8843
|
const current = panelConnectionIdentity();
|
|
8786
8844
|
return (current != null &&
|
|
8787
8845
|
current.generation > before.generation &&
|
|
8788
8846
|
current.tabSessionId === before.tabSessionId);
|
|
8789
8847
|
};
|
|
8848
|
+
const originalTabStayedReconnected = async () => {
|
|
8849
|
+
if (!isOriginalTabReconnected())
|
|
8850
|
+
return false;
|
|
8851
|
+
const left = deadline - Date.now();
|
|
8852
|
+
if (left <= 0)
|
|
8853
|
+
return false;
|
|
8854
|
+
await sleep(Math.min(stableMs, left));
|
|
8855
|
+
return isOriginalTabReconnected();
|
|
8856
|
+
};
|
|
8790
8857
|
for (;;) {
|
|
8791
|
-
if (
|
|
8858
|
+
if (await originalTabStayedReconnected())
|
|
8792
8859
|
return true;
|
|
8793
8860
|
// A new tab id cannot resolve through the retired binding. Once that binding is
|
|
8794
8861
|
// actually gone, the existing conservative rebind can follow the sole new tab.
|
|
@@ -8796,7 +8863,7 @@ export function makePanelToolCtx(bridge, tabId, workflowTargets, onRunTicketOpen
|
|
|
8796
8863
|
const interactive = interactiveTabIds() ?? [];
|
|
8797
8864
|
if (interactive.length > 0)
|
|
8798
8865
|
ensureReachable();
|
|
8799
|
-
if (
|
|
8866
|
+
if (await originalTabStayedReconnected())
|
|
8800
8867
|
return true;
|
|
8801
8868
|
}
|
|
8802
8869
|
const left = deadline - Date.now();
|
|
@@ -16508,6 +16575,20 @@ CHECKED FOR YOU: the graph read this message prescribes was just run, and it ` +
|
|
|
16508
16575
|
}
|
|
16509
16576
|
}
|
|
16510
16577
|
}
|
|
16578
|
+
// #2017 — do not send a painter kind this panel is proven unable to
|
|
16579
|
+
// render. A pre-#710 panel paints `audio` as `<img>` and reports
|
|
16580
|
+
// success; refusing with the version and the upgrade is strictly better
|
|
16581
|
+
// than a broken-image card. Fail-OPEN when the version is unknown or
|
|
16582
|
+
// inherited (same tri-state as the #392 command gate) so a current
|
|
16583
|
+
// panel that omitted the field is never told to update. Image/video
|
|
16584
|
+
// skip the check entirely.
|
|
16585
|
+
const blocked = showMediaItemsPanelCannotPaint(resolved, {
|
|
16586
|
+
reading: tabPanelVersionReading(ctx),
|
|
16587
|
+
advertisedKinds: tabAdvertisedShowMediaKinds(ctx),
|
|
16588
|
+
});
|
|
16589
|
+
if (blocked.length > 0) {
|
|
16590
|
+
return fail(formatShowMediaKindUnsupported(blocked));
|
|
16591
|
+
}
|
|
16511
16592
|
// #2010 — the reply below is the CLIENT's, and one of the two clients
|
|
16512
16593
|
// that answer show_media says `{shown:true}` without reading the items.
|
|
16513
16594
|
// Correct the claim against what the reply actually accounted for BEFORE
|