comfyui-mcp 0.52.60 → 0.52.62

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.
@@ -3989,6 +3989,46 @@ function rewriteToolResultJson(res, payload) {
3989
3989
  content: res.content.map((c, i) => i === idx && c.type === "text" ? { ...c, text: JSON.stringify(payload, null, 2) } : c),
3990
3990
  };
3991
3991
  }
3992
+ /**
3993
+ * #2075 — a verified widget write that fell back to last-observed schema still
3994
+ * succeeded. The panel's `schema_note` (#1223) tells the agent the live probes
3995
+ * went silent and to re-read "once ComfyUI is responding again", which makes a
3996
+ * routine canvas edit look degraded while ComfyUI and the panel bridge are
3997
+ * healthy.
3998
+ *
3999
+ * Sibling panel#1582 skips re-waiting on later writes once silence is known.
4000
+ * This report is the write immediately after adding a node: that add records a
4001
+ * live map and unlatches the skip, so the next set_widget re-probes, times out
4002
+ * inside the 2000 ms snapshot budget, and re-emits the note. Matched on the
4003
+ * panel's own snapshotAuthorizationNote wording. Used ONLY to drop the note
4004
+ * from a write the panel already verified against an unchanged backend —
4005
+ * never to authorize anything, never on a refusal, never when `set` is missing.
4006
+ */
4007
+ function stripVerifiedLastObservedSchemaNote(res) {
4008
+ if (res.isError)
4009
+ return res;
4010
+ const payload = parseToolResultJson(res);
4011
+ if (!payload)
4012
+ return res;
4013
+ if (payload.schema_source !== "last-observed")
4014
+ return res;
4015
+ if (typeof payload.schema_note !== "string")
4016
+ return res;
4017
+ const note = payload.schema_note;
4018
+ if (!/write SUCCEEDED and was verified/i.test(note))
4019
+ return res;
4020
+ if (!/last whole \/?object_info observed/i.test(note))
4021
+ return res;
4022
+ if (!/backend has not reconnected/i.test(note))
4023
+ return res;
4024
+ const set = payload.set;
4025
+ if (!set || typeof set !== "object" || Array.isArray(set))
4026
+ return res;
4027
+ const next = { ...payload };
4028
+ delete next.schema_note;
4029
+ delete next.schema_source;
4030
+ return rewriteToolResultJson(res, next);
4031
+ }
3992
4032
  async function exitSubgraphLevels(ctx, count) {
3993
4033
  const failures = [];
3994
4034
  for (let i = 0; i < count; i++) {
@@ -8723,13 +8763,20 @@ export function makePanelToolCtx(bridge, tabId, workflowTargets, onRunTicketOpen
8723
8763
  // here is the same recovery, just delayed until a canvas tab exists; it is
8724
8764
  // not a silent re-target.
8725
8765
  if (isScopeAddress(ctx.tabId)) {
8726
- if (ctx.pendingScopeRecoveryConsent) {
8766
+ const deferredConsent = ctx.pendingScopeRecoveryConsent === true ||
8767
+ (typeof bridge.hasScopeRecoveryConsent === "function" &&
8768
+ bridge.hasScopeRecoveryConsent(ctx.tabId));
8769
+ if (deferredConsent) {
8727
8770
  try {
8728
8771
  const out = rebindToActiveTab({ scopeRecoveryConsent: true });
8729
- if (out.rebound)
8772
+ if (out.rebound) {
8730
8773
  ctx.pendingScopeRecoveryConsent = false;
8731
- else if ((interactiveTabIds() ?? []).length > 0)
8774
+ bridge.clearScopeRecoveryConsent?.(ctx.tabId);
8775
+ }
8776
+ else if ((interactiveTabIds() ?? []).length > 0) {
8732
8777
  ctx.pendingScopeRecoveryConsent = false;
8778
+ bridge.clearScopeRecoveryConsent?.(ctx.tabId);
8779
+ }
8733
8780
  }
8734
8781
  catch {
8735
8782
  // still nothing bindable — keep the consent for the next attempt
@@ -12164,7 +12211,7 @@ export function buildPanelToolDefs() {
12164
12211
  // to the raw success reply so a later appendToolResultText disclosure
12165
12212
  // (which makes the text no longer parse as JSON) cannot dodge it.
12166
12213
  const echoFull = args.echo === "full";
12167
- const write = async (nodeId, widget) => summarizeSetWidgetEcho(await ctx.call({ cmd: "graph_set_widget", node_id: nodeId, widget, value }, OBJECT_INFO_REFRESH_ACK_TIMEOUT_MS), echoFull);
12214
+ const write = async (nodeId, widget) => stripVerifiedLastObservedSchemaNote(summarizeSetWidgetEcho(await ctx.call({ cmd: "graph_set_widget", node_id: nodeId, widget, value }, OBJECT_INFO_REFRESH_ACK_TIMEOUT_MS), echoFull));
12168
12215
  let first = await write(args.node_id, args.widget);
12169
12216
  if (!first.isError) {
12170
12217
  markPanelSchemaReady(panelSchemaKey(ctx));
@@ -13992,10 +14039,12 @@ export function buildPanelToolDefs() {
13992
14039
  if (recoveringScope)
13993
14040
  ctx.bridge.endScopeRecovery?.(before);
13994
14041
  }
13995
- // panel#1557 — the consent survives a zero-tab DEFER so a graph call
13996
- // after the canvas reconnects can finish the recovery.
13997
- if (deferredBind && recoveringScope)
14042
+ // panel#1557 — the consent survives a zero-tab DEFER so a later graph
14043
+ // call (possibly on a fresh HTTP MCP ctx) can finish the recovery.
14044
+ if (deferredBind && recoveringScope) {
13998
14045
  ctx.pendingScopeRecoveryConsent = true;
14046
+ ctx.bridge.armScopeRecoveryConsent?.(before);
14047
+ }
13999
14048
  // Detect the rebind regardless of whether awaitReachable or rebindToActiveTab
14000
14049
  // performed it (either mutates ctx.tabId), so the note is never swallowed.
14001
14050
  if (!deferredBind && ctx.tabId !== before) {