comfyui-mcp 0.52.38 → 0.52.39
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.
|
@@ -3165,6 +3165,35 @@ function appendToolResultText(res, extra) {
|
|
|
3165
3165
|
content[idx] = { type: "text", text: `${block.text}${extra}` };
|
|
3166
3166
|
return { ...res, content };
|
|
3167
3167
|
}
|
|
3168
|
+
/**
|
|
3169
|
+
* #1873 — Save-As onto an EXISTING name 409s on purpose. ComfyUI's userdata POST
|
|
3170
|
+
* returns 409 when overwrite=false; the frontend's saveWorkflowAs then prompts
|
|
3171
|
+
* and, on confirm, DELETES the occupant. The panel refuses that delete path and
|
|
3172
|
+
* surfaces "choose a different name", which is what forced a third workflow file.
|
|
3173
|
+
*
|
|
3174
|
+
* Matched on the panel's relocating-save collision (`conflictError` in
|
|
3175
|
+
* workflow-save.js), not a generic "409 Conflict" — an in-place save can 409
|
|
3176
|
+
* over its OWN file (#442) and that remedy is not this one.
|
|
3177
|
+
*/
|
|
3178
|
+
function isSaveAsNameConflict(res) {
|
|
3179
|
+
if (!res.isError)
|
|
3180
|
+
return false;
|
|
3181
|
+
const text = textOfToolResult(res);
|
|
3182
|
+
return /already exists \(409 Conflict\)/i.test(text) && /choose a different name/i.test(text);
|
|
3183
|
+
}
|
|
3184
|
+
const SAVE_AS_NAME_CONFLICT_NOTE = `\n\nDo NOT pick a third name. Save-As never overwrites an existing file — that 409 is ` +
|
|
3185
|
+
`the copy contract, not a missing overwrite switch. To land the edited copy under the ` +
|
|
3186
|
+
`intended original name while keeping a backup of the pre-edit original:\n` +
|
|
3187
|
+
`1. panel_rename_workflow({path: "<original>", name: "<original>_pre_edit"}) — path can ` +
|
|
3188
|
+
`target a CLOSED listed workflow, so this does not disturb the active tab.\n` +
|
|
3189
|
+
`2. panel_rename_workflow({name: "<original>"}) — no path, so this renames the ACTIVE ` +
|
|
3190
|
+
`copy onto the freed name; the tab follows the file.\n` +
|
|
3191
|
+
`3. panel_save_workflow() — in-place save from then on.`;
|
|
3192
|
+
function withSaveAsNameConflictNote(res) {
|
|
3193
|
+
if (!isSaveAsNameConflict(res))
|
|
3194
|
+
return res;
|
|
3195
|
+
return appendToolResultText(res, SAVE_AS_NAME_CONFLICT_NOTE);
|
|
3196
|
+
}
|
|
3168
3197
|
// ---- #1695: bound the panel_set_widget previous/new echo --------------------
|
|
3169
3198
|
//
|
|
3170
3199
|
// Code-mode clients (Codex `functions.exec`) batch several panel_set_widget
|
|
@@ -12210,7 +12239,7 @@ export function buildPanelToolDefs() {
|
|
|
12210
12239
|
multi_select: args.multi_select,
|
|
12211
12240
|
});
|
|
12212
12241
|
}),
|
|
12213
|
-
def("panel_save_workflow", "Save the user's open workflow PROGRAMMATICALLY — no Save/Rename dialog ever pops. With no `name`: saves in place (or auto-names + persists a never-saved workflow). With `name`: if the workflow is ALREADY saved under a different name this is a SAVE-AS — it writes a NEW file and leaves the original untouched on disk (it NEVER renames/moves/destroys the original); for a never-saved workflow it is simply the first save. The result reports what happened: `saved_as`+`copied_from`+`original_on_disk` (a disk-verified check that the original file still exists) for a Save-As copy, or `first_save` for a brand-new workflow. Use this freely (e.g. after building a graph) — it won't interrupt the user.", { name: z.string().optional().describe("Name for the workflow (no .json needed). If the workflow is already saved under a different name, this writes a NEW file (Save-As COPY) and leaves the original in place — it never renames/moves/destroys it. Omit to save in place / auto-name an unsaved workflow.") }, async (args, ctx) => {
|
|
12242
|
+
def("panel_save_workflow", "Save the user's open workflow PROGRAMMATICALLY — no Save/Rename dialog ever pops. With no `name`: saves in place (or auto-names + persists a never-saved workflow). With `name`: if the workflow is ALREADY saved under a different name this is a SAVE-AS — it writes a NEW file and leaves the original untouched on disk (it NEVER renames/moves/destroys the original); for a never-saved workflow it is simply the first save. The result reports what happened: `saved_as`+`copied_from`+`original_on_disk` (a disk-verified check that the original file still exists) for a Save-As copy, or `first_save` for a brand-new workflow. A Save-As onto an EXISTING name is a 409 Conflict (the copy never overwrites) — do NOT pick a third name; panel_rename_workflow can target a closed listed original to free the name, then rename the active copy onto it, then panel_save_workflow() in place. Use this freely (e.g. after building a graph) — it won't interrupt the user.", { name: z.string().optional().describe("Name for the workflow (no .json needed). If the workflow is already saved under a different name, this writes a NEW file (Save-As COPY) and leaves the original in place — it never renames/moves/destroys it. An existing target name 409s; do not invent a third name — use panel_rename_workflow to free the original then rename the active copy onto it. Omit to save in place / auto-name an unsaved workflow.") }, async (args, ctx) => {
|
|
12214
12243
|
// #402: await a stable tab binding before dispatching the (mutating) save, so
|
|
12215
12244
|
// a save issued in the post-restart "Connected: none" window reaches a live
|
|
12216
12245
|
// tab instead of failing with a bare "Failed to fetch"/OUTCOME UNKNOWN. Pre-
|
|
@@ -12237,8 +12266,11 @@ export function buildPanelToolDefs() {
|
|
|
12237
12266
|
}
|
|
12238
12267
|
}
|
|
12239
12268
|
}
|
|
12240
|
-
if (res.isError)
|
|
12241
|
-
|
|
12269
|
+
if (res.isError) {
|
|
12270
|
+
// #1873 — named Save-As 409s by contract; the panel's "choose a different
|
|
12271
|
+
// name" is what forced a third file. Keep the 409 and name the rename path.
|
|
12272
|
+
return args.name ? withSaveAsNameConflictNote(res) : res;
|
|
12273
|
+
}
|
|
12242
12274
|
// #1045 — a SAVE-AS replaces the active workflow instance: the canvas is
|
|
12243
12275
|
// now the NEW file, with its own identity, while this session's command
|
|
12244
12276
|
// fence still names the pre-save one. Every graph call afterwards fails
|
|
@@ -13000,9 +13032,9 @@ CHECKED FOR YOU: the graph read this message prescribes was just run, and it ` +
|
|
|
13000
13032
|
// ack-timeout, confirm via the authoritative workflow_list active identity
|
|
13001
13033
|
// before reporting failure — see openWorkflowWithVerify.
|
|
13002
13034
|
async (args, ctx) => openWorkflowWithVerify(args.path, ctx)),
|
|
13003
|
-
def("panel_rename_workflow", "Rename a workflow (the active one, or the one matching `path`).", {
|
|
13035
|
+
def("panel_rename_workflow", "Rename a workflow (the active one, or the one matching `path`). `path` can name a CLOSED listed workflow — renaming it does not disturb the active tab. After a Save-As copy, this is how to land the edited graph under the original name without a third file: rename the closed original aside (`path` + new name), then rename the active copy onto the freed name (no `path`), then panel_save_workflow().", {
|
|
13004
13036
|
name: z.string().describe("New name (no .json needed)."),
|
|
13005
|
-
path: z.string().optional().describe("Which workflow to rename; omit for the active one."),
|
|
13037
|
+
path: z.string().optional().describe("Which workflow to rename; omit for the active one. Can name a CLOSED listed workflow (does not disturb the active tab)."),
|
|
13006
13038
|
}, async (args, ctx) => ctx.call({ cmd: "workflow_rename", name: args.name, path: args.path }, 15000)),
|
|
13007
13039
|
def("panel_close_workflow", "Close a workflow tab (the active one, or the one matching `path`). Refuses if it has unsaved changes unless force:true — save first to avoid losing the user's work.", {
|
|
13008
13040
|
path: z.string().optional().describe("Which workflow to close; omit for the active one."),
|