comfyui-mcp 0.51.13 → 0.51.15

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.
@@ -32,15 +32,100 @@ export function isInteractiveCommand(cmd) {
32
32
  /**
33
33
  * The "verify before retrying" clause, chosen by what the command actually did.
34
34
  *
35
- * Two kinds, because they have different evidence and different costs:
35
+ * The point of OUTCOME UNKNOWN is that the caller checks instead of retrying blind.
36
+ * That only works if the check named can actually hold the answer — and for a graph
37
+ * write it did not. Every non-interactive command got the same sentence:
36
38
  *
37
- * an INTERACTIVE card nothing in the tool surface can observe it, and a
38
- * the answer to it will NEVER arrive (the panel refuses to replay a reply of
39
- * this kind across a reconnect), and a retry duplicates the card. Say all
40
- * three, and give the route that works which differs for a secret.
41
- * anything else the existing queue/output check, which is real evidence for
42
- * a run or a write.
39
+ * Verify before retrying (e.g. check queue action:"list" /
40
+ * get_image (action:"list_outputs"))
41
+ *
42
+ * which is RENDER evidence. panel#646's interrupted command was `graph_set_widget`.
43
+ * Neither the queue nor the output list can say whether a widget edit landed, so an
44
+ * agent following that advice looks somewhere structurally incapable of answering,
45
+ * learns nothing, and ends up exactly where the message was trying to keep it from:
46
+ * retry blindly or give up. The old doc here asserted the queue check was "real
47
+ * evidence for a run or a write". It is evidence for a run.
48
+ *
49
+ * So the kinds are separated by WHAT CAN BE OBSERVED:
50
+ *
51
+ * • an INTERACTIVE card — nothing in the tool surface can observe it, the answer
52
+ * will NEVER arrive, and a retry duplicates the card in front of a human.
53
+ * • a RUN — the queue and the output list are exactly right, and stay.
54
+ * • a GRAPH WRITE — read the graph back. A graph read is idempotent and safe to
55
+ * run the instant a tab is connected, which makes it a better check than
56
+ * anything the run path offers. This branch is LAST among the graph_* kinds:
57
+ * the prefix alone does not mean the effect is on the canvas, and the two cases
58
+ * above are the ones where it is not.
59
+ * • a WORKFLOW mutator — the workflow list, not the graph: these change which
60
+ * workflows exist or are open, which a canvas read does not see.
61
+ * • a LIBRARY write (`graph_save_subgraph`) — panel_list_subgraphs. The graph is
62
+ * identical after a blueprint save, so both graph readers show what they showed
63
+ * before and prove nothing (codex review).
64
+ * • a CLIPBOARD write (`graph_copy_nodes`) — nothing can read the clipboard, and
65
+ * the graph is unchanged. This is the one interrupted write where re-issuing is
66
+ * the right answer: a second copy of the same nodes is the same clipboard.
67
+ * • anything else — say to verify without naming tools that may not apply.
68
+ * Naming a plausible-but-wrong check is what this fix exists to remove; doing
69
+ * it again in the default branch would be the same defect with a different tool.
70
+ *
71
+ * Classified by NAME here rather than by importing GRAPH_CMD_EFFECT, for two
72
+ * reasons: ui-bridge.ts imports this module, so reading its table would be a cycle;
73
+ * and that table answers a different question (does this need the workflow fence),
74
+ * which is not the same as what evidence exists for it afterwards.
43
75
  */
76
+ /** The one command whose evidence really is the render queue (panel#646). */
77
+ const RUN_COMMAND = "graph_run";
78
+ /** Writes to the user's blueprint LIBRARY, not to the canvas (codex review, P1).
79
+ * `graph_save_subgraph` publishes a subgraph as a reusable blueprint; the graph is
80
+ * unchanged afterwards, so both graph readers show exactly what they showed before
81
+ * and cannot tell a save that landed from one that did not. `panel_list_subgraphs`
82
+ * is the reader that can. */
83
+ const LIBRARY_COMMANDS = new Set(["graph_save_subgraph"]);
84
+ /** Writes the CLIPBOARD, which nothing in the tool surface can read (codex review).
85
+ * Copying leaves the graph identical, so a canvas read is no evidence at all —
86
+ * but unlike everything else here, re-issuing is harmless: a second copy of the
87
+ * same nodes produces the same clipboard. That makes "just do it again" the
88
+ * correct advice rather than a dangerous one. */
89
+ const CLIPBOARD_COMMANDS = new Set(["graph_copy_nodes"]);
90
+ /** The four active-workflow mutators. A canvas read cannot see these — they change
91
+ * which workflows exist or are open, not what is on the current graph. Mirrors
92
+ * ACTIVE_WORKFLOW_MUTATORS in ui-bridge.ts, which cannot be imported here (it
93
+ * imports this module). Duplicated deliberately and kept honest by a test that
94
+ * reads the ui-bridge source and compares the two. */
95
+ const WORKFLOW_MUTATORS = new Set([
96
+ "workflow_save",
97
+ "workflow_save_as",
98
+ "workflow_rename",
99
+ "workflow_close",
100
+ ]);
101
+ /** Workflow NAVIGATION/creation. Deliberately not in ACTIVE_WORKFLOW_MUTATORS — they
102
+ * carry their own explicit or new target rather than mutating active content, so the
103
+ * fence treats them differently. The question HERE is evidence, not fencing — and the
104
+ * evidence for these is NOT the workflow list itself, which is where the first attempt
105
+ * went wrong.
106
+ *
107
+ * Found by running the LIVE panel's registered command names through this classifier
108
+ * after the fix merged — these two fell to the default branch, which names no tool.
109
+ *
110
+ * The first attempt sent them to `panel_list_workflows` on the reasoning that an opened
111
+ * workflow appears there. Codex caught it, and the panel had already written the
112
+ * rebuttal: `active` matching your target is NOT proof your open ran, because after a
113
+ * backend reconnect the frontend restores a tab BY ITSELF (#433). Naming that reader
114
+ * would have been the exact defect this module exists to remove — a confident check
115
+ * that cannot answer — for the one command class that already has a purpose-built
116
+ * correct mechanism.
117
+ *
118
+ * That mechanism is the panel's OPEN RECEIPTS (#402): every workflow_open/workflow_new
119
+ * that RAN is journaled with the selector it was asked for, the identity it resolved
120
+ * to, and whether it applied. The latest one rides in the workflow-list reply as
121
+ * `last_open` — that is the reply KEY; the panel's local variable is `lastOpenReceipt`,
122
+ * and naming THAT is how the first version of this shipped a field no reply carries
123
+ * (codex round 2), which is the very defect this module exists to remove. It answers
124
+ * ONLY for the command whose id equals its `rid` —
125
+ * so an EARLIER successful open of the same file is not evidence about a later dropped
126
+ * one. The message says both halves, because the receipt is over-readable without the
127
+ * rule that comes with it. */
128
+ const WORKFLOW_NAVIGATION = new Set(["workflow_open", "workflow_new"]);
44
129
  export function midCommandVerifyClause(cmd) {
45
130
  if (isInteractiveCommand(cmd)) {
46
131
  // WAITING IS NOT A RECOVERY, and an earlier draft of this said it was
@@ -66,8 +151,53 @@ export function midCommandVerifyClause(cmd) {
66
151
  `suppression is keyed to the socket that dropped, so this counts as a new command and the ` +
67
152
  `user may see two. Tell them which one to answer.`);
68
153
  }
69
- return (`Verify before retrying (e.g. check queue action:"list" / get_image (action:"list_outputs")) ` +
70
- `instead of re-issuing it blindly.`);
154
+ if (cmd === RUN_COMMAND) {
155
+ // The one command the original sentence was actually right about.
156
+ return (`Verify before retrying (check queue action:"list" / get_image ` +
157
+ `(action:"list_outputs")) instead of re-issuing it blindly — a second run costs ` +
158
+ `GPU time and produces a duplicate output.`);
159
+ }
160
+ if (WORKFLOW_NAVIGATION.has(cmd)) {
161
+ return (`Verify with panel_list_workflows and read its \`last_open\` — the panel's own ` +
162
+ `execution record for opens (#402). It answers ONLY for the command whose id equals ` +
163
+ `its \`rid\`: \`applied:true\` means it completed, \`applied:false\` means nothing was ` +
164
+ `applied and it is safe to re-issue, \`applied:"unknown"\` means it may have taken ` +
165
+ `effect and must NOT be blindly retried. Do NOT conclude anything from \`active\` ` +
166
+ `matching your target, and do not read an EARLIER receipt for the same file as ` +
167
+ `evidence about this one — after a backend reconnect the frontend restores a tab by ` +
168
+ `itself, which explains a matching \`active\` without your command ever running. A ` +
169
+ `blind retry costs: a second workflow_new leaves the user with two empty tabs.`);
170
+ }
171
+ if (WORKFLOW_MUTATORS.has(cmd)) {
172
+ return (`Verify with panel_list_workflows before retrying — these change which workflows ` +
173
+ `exist or are open, which a canvas read does not see. Re-issuing blindly can save ` +
174
+ `or close a second time.`);
175
+ }
176
+ if (LIBRARY_COMMANDS.has(cmd)) {
177
+ return (`Verify with panel_list_subgraphs before retrying — this writes to the blueprint ` +
178
+ `LIBRARY, not to the canvas, so the graph is identical either way and a graph read ` +
179
+ `cannot tell a save that landed from one that did not. If the blueprint is already ` +
180
+ `there, do NOT re-issue it: a second save collides on the name.`);
181
+ }
182
+ if (CLIPBOARD_COMMANDS.has(cmd)) {
183
+ return (`Nothing in the tool surface can check that — the clipboard is not readable, and the ` +
184
+ `graph is unchanged either way, so neither graph reader is evidence. Just re-issue it: ` +
185
+ `unlike the other interrupted writes, copying the same nodes twice produces the same ` +
186
+ `clipboard, so a retry here costs nothing and settles it.`);
187
+ }
188
+ if (cmd.startsWith("graph_")) {
189
+ return (`Verify with a graph READ before retrying — panel_query_graph on the node(s) this ` +
190
+ `touched (or panel_graph_outline for a structural change) and compare against what ` +
191
+ `you asked for. A read is idempotent, so it is safe the moment a tab is connected, ` +
192
+ `and it is the only check that can see a canvas edit: the render queue and the ` +
193
+ `output list cannot (panel#646). If the read shows the change already applied, do ` +
194
+ `NOT re-issue it. If the command only moved the view or the selection, it changed ` +
195
+ `no graph content, so there is nothing to verify and nothing worth re-issuing.`);
196
+ }
197
+ // Deliberately names no tool. The defect being fixed was a confidently wrong
198
+ // check; an unrecognised command is exactly where a guess would be wrong again.
199
+ return (`Verify that it applied before retrying, rather than re-issuing it blindly — the ` +
200
+ `command reached the panel, so a retry may apply it twice.`);
71
201
  }
72
202
  /** The full OUTCOME UNKNOWN sentence for a mid-command disconnect. */
73
203
  export function midCommandDisconnectMessage(opts) {
@@ -1 +1 @@
1
- {"version":3,"file":"mid-command-remedy.js","sourceRoot":"","sources":["../../src/services/mid-command-remedy.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,gBAAgB;AAChB,EAAE;AACF,iFAAiF;AACjF,yDAAyD;AACzD,EAAE;AACF,6DAA6D;AAC7D,yEAAyE;AACzE,EAAE;AACF,kFAAkF;AAClF,+EAA+E;AAC/E,oEAAoE;AACpE,EAAE;AACF,gFAAgF;AAChF,4EAA4E;AAC5E,gFAAgF;AAChF,gFAAgF;AAChF,6EAA6E;AAC7E,+EAA+E;AAC/E,iFAAiF;AACjF,aAAa;AACb,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,yEAAyE;AACzE,0DAA0D;AAE1D,sEAAsE;AACtE,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAErE,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,OAAO,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,IAAI,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,sEAAsE;QACtE,yEAAyE;QACzE,6EAA6E;QAC7E,yEAAyE;QACzE,4EAA4E;QAC5E,4EAA4E;QAC5E,oEAAoE;QACpE,MAAM,OAAO,GACX,GAAG,KAAK,gBAAgB;YACtB,CAAC,CAAC,mEAAmE;gBACnE,qEAAqE;gBACrE,iEAAiE;gBACjE,uCAAuC;gBACvC,0FAA0F;oBAC1F,wFAAwF;oBACxF,gEAAgE;YAClE,CAAC,CAAC,oFAAoF,CAAC;QAC3F,OAAO,CACL,+CAA+C;YAC/C,sFAAsF;YACtF,4FAA4F;YAC5F,4BAA4B,OAAO,oDAAoD;YACvF,2FAA2F;YAC3F,kDAAkD,CACnD,CAAC;IACJ,CAAC;IACD,OAAO,CACL,8FAA8F;QAC9F,mCAAmC,CACpC,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,2BAA2B,CAAC,IAAoC;IAC9E,MAAM,WAAW,GAAG,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,WAAW;QACzB,CAAC,CAAC,oEAAoE;QACtE,CAAC,CAAC,8GAA8G,CAAC;IACnH,OAAO,CACL,aAAa,IAAI,CAAC,KAAK,+BAA+B,IAAI,CAAC,GAAG,wBAAwB;QACtF,GAAG,OAAO,KAAK,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAClD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"mid-command-remedy.js","sourceRoot":"","sources":["../../src/services/mid-command-remedy.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "comfyui-mcp",
3
- "version": "0.51.13",
3
+ "version": "0.51.15",
4
4
  "mcpName": "io.github.artokun/comfyui-mcp",
5
5
  "description": "Local-first, agent-native control plane for ComfyUI — MCP server + autonomous sidebar agent that drives your live graph in natural language on ANY LLM: Claude/ChatGPT/Gemini on your subscription (no API key), free local models via Ollama (fully offline), or any hosted model via an OpenAI-compatible endpoint (DeepSeek, GLM, MiMo, OpenRouter). Generate images, video & audio, author and run workflows, manage models and custom nodes; a compact tool-router mode keeps even 4B models effective, and a built-in LLM Arena benchmarks them on real ComfyUI tasks. Also a Claude Code plugin with skills, slash commands, and installer packs. Local, LAN, VPS, or Comfy Cloud.",
6
6
  "homepage": "https://comfyui-mcp.artokun.io/docs",