comfyui-mcp 0.9.6 → 0.10.0

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/CHANGELOG.md CHANGED
@@ -6,6 +6,31 @@ All notable changes to this project are documented here. This project adheres to
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ### Added
10
+
11
+ - **`lock_workflow` + `verify_workflow_lock`** — provenance sidecars for
12
+ saved workflows. `lock_workflow` walks a workflow's model loaders
13
+ (`CheckpointLoaderSimple`, `UNETLoader`, `VAELoader`, `LoraLoader`,
14
+ `ControlNetLoader`, `CLIPLoader`/`DualCLIPLoader`, `UpscaleModelLoader`,
15
+ …), SHA-256s every referenced model, records the git commit currently
16
+ checked out for every custom node pack the workflow's `class_type`s
17
+ resolve to, captures ComfyUI's reported version, and writes
18
+ `<filename>.lock.json` next to the workflow in ComfyUI's user library.
19
+ `verify_workflow_lock` re-computes the lock and surfaces structured drift
20
+ (changed model SHA-256s, packs on different commits, ComfyUI version
21
+ bumps). Local install required for v1 (SHA-256 needs file bytes;
22
+ commits come from `custom_nodes/*/.git/HEAD`). Idea from
23
+ [josephoibrahim/comfy-cozy](https://github.com/josephoibrahim/comfy-cozy).
24
+
25
+ - **Resumable model downloads.** Big-model fetches (10–40 GB checkpoints over
26
+ flaky connections to HuggingFace / CivitAI / S3) used to start from byte 0
27
+ every retry. The download cache now writes to a deterministic
28
+ `~/.comfyui-mcp/cache/.<hash>.<ext>.partial` file, sends `Range: bytes=N-`
29
+ on the next attempt, appends on `206 Partial Content`, and falls back
30
+ cleanly to a full overwrite when the server replies `200` (Range
31
+ unsupported). Idea from
32
+ [josephoibrahim/comfy-cozy](https://github.com/josephoibrahim/comfy-cozy).
33
+
9
34
  ### Fixed
10
35
 
11
36
  - **`list_local_models` now sees `extra_model_paths.yaml` redirects + works
@@ -1,4 +1,4 @@
1
- import { createHash, randomUUID } from "node:crypto";
1
+ import { createHash } from "node:crypto";
2
2
  import { createWriteStream } from "node:fs";
3
3
  import { copyFile, link, mkdir, readdir, rename, rm, stat, utimes, } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
@@ -48,13 +48,21 @@ async function touch(path) {
48
48
  const now = new Date();
49
49
  await downloadCacheFs.utimes(path, now, now);
50
50
  }
51
- async function streamUrlToFile(url, targetPath, headers, logUrl = redactUrlForLogs(url), storageAuth = {}) {
51
+ async function streamUrlToFile(url, targetPath, headers, logUrl = redactUrlForLogs(url), storageAuth = {}, resumeFromBytes = 0) {
52
52
  if (supportsCloudDownload(url)) {
53
53
  await downloadCloudUrlToFile(url, targetPath, storageAuth);
54
54
  return;
55
55
  }
56
+ // Resumable downloads: when a partial file exists at targetPath we ask the
57
+ // server for the remaining bytes via Range. If the server returns 206 with
58
+ // matching Content-Range we append; if it returns 200 (range unsupported,
59
+ // or the file changed upstream) we truncate and restart. Idea from
60
+ // josephoibrahim/comfy-cozy.
56
61
  let currentUrl = url;
57
62
  let currentHeaders = headers;
63
+ if (resumeFromBytes > 0) {
64
+ currentHeaders = { ...currentHeaders, Range: `bytes=${resumeFromBytes}-` };
65
+ }
58
66
  let res;
59
67
  for (let redirectCount = 0;; redirectCount += 1) {
60
68
  res = await fetch(currentUrl, { headers: currentHeaders, redirect: "manual" });
@@ -90,8 +98,13 @@ async function streamUrlToFile(url, targetPath, headers, logUrl = redactUrlForLo
90
98
  if (!res.body) {
91
99
  throw new ModelError("Download response has no body", { url: logUrl });
92
100
  }
101
+ // Decide append vs truncate based on the response. If we asked for a range
102
+ // and got 206, append; any other 2xx (typically 200) means the server is
103
+ // sending the full file so we must overwrite.
104
+ const appendMode = resumeFromBytes > 0 && res.status === 206;
105
+ const flags = appendMode ? "a" : "w";
93
106
  const nodeStream = Readable.fromWeb(res.body);
94
- const fileStream = createWriteStream(targetPath);
107
+ const fileStream = createWriteStream(targetPath, { flags });
95
108
  await pipeline(nodeStream, fileStream);
96
109
  }
97
110
  async function downloadIntoCache(url, headers, logUrl, storageAuth = {}) {
@@ -112,15 +125,44 @@ async function downloadIntoCache(url, headers, logUrl, storageAuth = {}) {
112
125
  catch {
113
126
  // Cache miss.
114
127
  }
115
- const tmp = join(cacheDir(), `.${basename(target)}.${process.pid}.${randomUUID()}.tmp`);
128
+ // Deterministic .partial filename so a crashed/interrupted download
129
+ // resumes from the byte it left off on the next call, rather than
130
+ // restarting from zero. (See streamUrlToFile for the Range + flags
131
+ // handshake.) Cleanup on terminal failure stays unchanged.
132
+ const partial = join(cacheDir(), `.${basename(target)}.partial`);
133
+ let resumeFromBytes = 0;
134
+ try {
135
+ const existing = await downloadCacheFs.stat(partial);
136
+ if (existing.isFile() && existing.size > 0) {
137
+ resumeFromBytes = existing.size;
138
+ logger.info("Resuming partial download", {
139
+ url: logUrl,
140
+ bytes: resumeFromBytes,
141
+ });
142
+ }
143
+ }
144
+ catch {
145
+ // No partial — fresh download.
146
+ }
116
147
  try {
117
- await streamUrlToFile(url, tmp, headers, logUrl, storageAuth);
118
- await downloadCacheFs.rename(tmp, target);
148
+ await streamUrlToFile(url, partial, headers, logUrl, storageAuth, resumeFromBytes);
149
+ await downloadCacheFs.rename(partial, target);
119
150
  await touch(target);
120
151
  return target;
121
152
  }
122
153
  catch (err) {
123
- await downloadCacheFs.rm(tmp, { force: true }).catch(() => undefined);
154
+ // Leave the partial on disk for a future resume; only nuke it if it
155
+ // is now empty (server said the previous partial was bogus, or our
156
+ // first write failed).
157
+ try {
158
+ const remaining = await downloadCacheFs.stat(partial);
159
+ if (remaining.size === 0) {
160
+ await downloadCacheFs.rm(partial, { force: true }).catch(() => undefined);
161
+ }
162
+ }
163
+ catch {
164
+ // Partial gone — nothing to clean.
165
+ }
124
166
  throw err;
125
167
  }
126
168
  })();
@@ -1 +1 @@
1
- {"version":3,"file":"download-cache.js","sourceRoot":"","sources":["../../src/services/download-cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"download-cache.js","sourceRoot":"","sources":["../../src/services/download-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,259 @@
1
+ // Provenance sidecar for saved ComfyUI workflows.
2
+ //
3
+ // Captures everything that determines whether a workflow will produce the
4
+ // same output tomorrow as it did today:
5
+ // - Every model file the workflow references, with SHA-256.
6
+ // - Every custom-node pack the workflow's class_types come from, with the
7
+ // git commit currently checked out at custom_nodes/<pack>/.git/HEAD.
8
+ // - The ComfyUI version reported by /system_stats.
9
+ //
10
+ // Idea credited to josephoibrahim/comfy-cozy. The lock file lives next to the
11
+ // workflow in ComfyUI's user library as `workflows/<name>.lock.json`, so it
12
+ // travels with the workflow.
13
+ import { createHash } from "node:crypto";
14
+ import { createReadStream } from "node:fs";
15
+ import { readFile, stat } from "node:fs/promises";
16
+ import { join } from "node:path";
17
+ import { getObjectInfo, getSystemStats } from "../comfyui/client.js";
18
+ import { config } from "../config.js";
19
+ import { ProcessControlError } from "../utils/errors.js";
20
+ import { logger } from "../utils/logger.js";
21
+ import { MODEL_SUBDIRS } from "./model-resolver.js";
22
+ // Which class_type → which input field carries the model filename. This list
23
+ // covers the loaders ComfyUI core ships; custom packs are walked best-effort
24
+ // via the same input-field heuristic (any string input ending in a model
25
+ // extension that resolves under <models>/<subdir>/).
26
+ const KNOWN_LOADERS = [
27
+ { classType: "CheckpointLoaderSimple", field: "ckpt_name", modelType: "checkpoints" },
28
+ { classType: "UNETLoader", field: "unet_name", modelType: "diffusion_models" },
29
+ { classType: "VAELoader", field: "vae_name", modelType: "vae" },
30
+ { classType: "CLIPLoader", field: "clip_name", modelType: "text_encoders" },
31
+ { classType: "DualCLIPLoader", field: "clip_name1", modelType: "text_encoders" },
32
+ { classType: "DualCLIPLoader", field: "clip_name2", modelType: "text_encoders" },
33
+ { classType: "LoraLoader", field: "lora_name", modelType: "loras" },
34
+ { classType: "LoraLoaderModelOnly", field: "lora_name", modelType: "loras" },
35
+ { classType: "ControlNetLoader", field: "control_net_name", modelType: "controlnet" },
36
+ { classType: "UpscaleModelLoader", field: "model_name", modelType: "upscale_models" },
37
+ { classType: "CLIPVisionLoader", field: "clip_name", modelType: "clip_vision" },
38
+ { classType: "StyleModelLoader", field: "style_model_name", modelType: "style_models" },
39
+ ];
40
+ function requireLocal(op) {
41
+ if (!config.comfyuiPath) {
42
+ throw new ProcessControlError(`${op} requires a local ComfyUI install (COMFYUI_PATH). Lock generation needs to read model file bytes for SHA-256 and inspect custom_nodes/*/.git/HEAD.`);
43
+ }
44
+ return config.comfyuiPath;
45
+ }
46
+ function extractReferencedModels(workflow) {
47
+ const seen = new Map(); // key: `${type}/${name}` → type
48
+ for (const node of Object.values(workflow)) {
49
+ if (!node?.class_type || !node.inputs)
50
+ continue;
51
+ const classMatches = KNOWN_LOADERS.filter((l) => l.classType === node.class_type);
52
+ for (const match of classMatches) {
53
+ const value = node.inputs[match.field];
54
+ if (typeof value !== "string" || !value)
55
+ continue;
56
+ seen.set(`${match.modelType}/${value}`, match.modelType);
57
+ }
58
+ }
59
+ return Array.from(seen.entries()).map(([key, type]) => ({
60
+ name: key.slice(type.length + 1),
61
+ type,
62
+ }));
63
+ }
64
+ async function hashFile(filePath) {
65
+ return new Promise((resolve, reject) => {
66
+ const hash = createHash("sha256");
67
+ const stream = createReadStream(filePath);
68
+ stream.on("data", (chunk) => hash.update(chunk));
69
+ stream.on("end", () => resolve(hash.digest("hex")));
70
+ stream.on("error", reject);
71
+ });
72
+ }
73
+ async function findModelOnDisk(comfyPath, modelType, filename) {
74
+ // Try the canonical subdir first; ComfyUI's extra_model_paths.yaml may add
75
+ // others, but those resolve at workflow-execution time and we don't have a
76
+ // good way to enumerate them without parsing the YAML.
77
+ const subdirs = MODEL_SUBDIRS.includes(modelType)
78
+ ? [modelType]
79
+ : [modelType, ...MODEL_SUBDIRS];
80
+ for (const subdir of subdirs) {
81
+ const candidate = join(comfyPath, "models", subdir, filename);
82
+ try {
83
+ const info = await stat(candidate);
84
+ if (info.isFile())
85
+ return candidate;
86
+ }
87
+ catch {
88
+ // Keep looking.
89
+ }
90
+ }
91
+ return undefined;
92
+ }
93
+ async function readGitHeadCommit(packPath) {
94
+ const headPath = join(packPath, ".git", "HEAD");
95
+ try {
96
+ const head = (await readFile(headPath, "utf-8")).trim();
97
+ if (head.startsWith("ref: ")) {
98
+ const refPath = join(packPath, ".git", head.slice(5).trim());
99
+ try {
100
+ return (await readFile(refPath, "utf-8")).trim();
101
+ }
102
+ catch {
103
+ // Packed refs path — fall back to refs/packed.
104
+ try {
105
+ const packed = await readFile(join(packPath, ".git", "packed-refs"), "utf-8");
106
+ const wanted = head.slice(5).trim();
107
+ for (const line of packed.split("\n")) {
108
+ if (line.endsWith(` ${wanted}`)) {
109
+ return line.split(" ")[0].trim();
110
+ }
111
+ }
112
+ }
113
+ catch {
114
+ return undefined;
115
+ }
116
+ }
117
+ }
118
+ // Detached HEAD: contents are the commit SHA directly.
119
+ if (/^[0-9a-f]{7,40}$/.test(head))
120
+ return head;
121
+ }
122
+ catch {
123
+ return undefined;
124
+ }
125
+ return undefined;
126
+ }
127
+ async function buildClassTypeOriginMap() {
128
+ const byClass = new Map();
129
+ const info = (await getObjectInfo());
130
+ for (const [classType, def] of Object.entries(info ?? {})) {
131
+ const mod = def?.python_module ?? "";
132
+ // `python_module` is e.g. "custom_nodes.ComfyUI-WanVideoWrapper.nodes" for
133
+ // a custom pack, or "comfy_extras.nodes_*" / "nodes" for built-ins.
134
+ if (mod.startsWith("custom_nodes.")) {
135
+ const pack = mod.split(".")[1] ?? null;
136
+ byClass.set(classType, { pack, builtin: false });
137
+ }
138
+ else if (mod) {
139
+ byClass.set(classType, { pack: null, builtin: true });
140
+ }
141
+ }
142
+ return { byClass };
143
+ }
144
+ async function packsReferencedByWorkflow(workflow, origins) {
145
+ const packs = new Set();
146
+ for (const node of Object.values(workflow)) {
147
+ const classType = node?.class_type;
148
+ if (!classType)
149
+ continue;
150
+ const origin = origins.byClass.get(classType);
151
+ if (origin?.pack)
152
+ packs.add(origin.pack);
153
+ }
154
+ return Array.from(packs).sort();
155
+ }
156
+ export async function generateLock(workflow) {
157
+ const comfyPath = requireLocal("generateLock");
158
+ const stats = (await getSystemStats());
159
+ const comfyuiVersion = stats.system?.comfyui_version ?? "unknown";
160
+ const models = extractReferencedModels(workflow);
161
+ const lockedModels = [];
162
+ for (const m of models) {
163
+ const path = await findModelOnDisk(comfyPath, m.type, m.name);
164
+ if (!path) {
165
+ lockedModels.push({ ...m, missing: true });
166
+ continue;
167
+ }
168
+ try {
169
+ const sha256 = await hashFile(path);
170
+ lockedModels.push({ ...m, sha256 });
171
+ }
172
+ catch (err) {
173
+ logger.warn("Could not SHA-256 model file", {
174
+ name: m.name,
175
+ error: err instanceof Error ? err.message : err,
176
+ });
177
+ lockedModels.push({ ...m, missing: true });
178
+ }
179
+ }
180
+ const origins = await buildClassTypeOriginMap();
181
+ const packIds = await packsReferencedByWorkflow(workflow, origins);
182
+ const lockedPacks = [];
183
+ for (const id of packIds) {
184
+ const packPath = join(comfyPath, "custom_nodes", id);
185
+ const commit = await readGitHeadCommit(packPath);
186
+ lockedPacks.push(commit ? { id, commit_sha: commit } : { id });
187
+ }
188
+ // Built-in dependencies don't get a separate row — the ComfyUI version field
189
+ // covers them. Only custom packs appear in node_packs.
190
+ return {
191
+ generated_at: new Date().toISOString(),
192
+ comfyui_version: comfyuiVersion,
193
+ models: lockedModels,
194
+ node_packs: lockedPacks,
195
+ };
196
+ }
197
+ export function diffLocks(lock, current) {
198
+ const drift = { models: [], node_packs: [] };
199
+ if (lock.comfyui_version !== current.comfyui_version) {
200
+ drift.comfyui_version = { lock: lock.comfyui_version, current: current.comfyui_version };
201
+ }
202
+ const lockModels = new Map(lock.models.map((m) => [`${m.type}/${m.name}`, m]));
203
+ const currentModels = new Map(current.models.map((m) => [`${m.type}/${m.name}`, m]));
204
+ for (const [key, m] of lockModels) {
205
+ const c = currentModels.get(key);
206
+ if (!c || c.missing) {
207
+ drift.models.push({
208
+ name: m.name,
209
+ type: m.type,
210
+ lock_sha256: m.sha256,
211
+ status: "missing",
212
+ });
213
+ continue;
214
+ }
215
+ if (m.sha256 && c.sha256 && m.sha256 !== c.sha256) {
216
+ drift.models.push({
217
+ name: m.name,
218
+ type: m.type,
219
+ lock_sha256: m.sha256,
220
+ current_sha256: c.sha256,
221
+ status: "changed",
222
+ });
223
+ }
224
+ }
225
+ for (const [key, c] of currentModels) {
226
+ if (!lockModels.has(key)) {
227
+ drift.models.push({
228
+ name: c.name,
229
+ type: c.type,
230
+ current_sha256: c.sha256,
231
+ status: "added",
232
+ });
233
+ }
234
+ }
235
+ const lockPacks = new Map(lock.node_packs.map((p) => [p.id, p]));
236
+ const currentPacks = new Map(current.node_packs.map((p) => [p.id, p]));
237
+ for (const [id, p] of lockPacks) {
238
+ const c = currentPacks.get(id);
239
+ if (!c) {
240
+ drift.node_packs.push({ id, lock_commit: p.commit_sha, status: "missing" });
241
+ continue;
242
+ }
243
+ if (p.commit_sha && c.commit_sha && p.commit_sha !== c.commit_sha) {
244
+ drift.node_packs.push({
245
+ id,
246
+ lock_commit: p.commit_sha,
247
+ current_commit: c.commit_sha,
248
+ status: "changed",
249
+ });
250
+ }
251
+ }
252
+ for (const [id, c] of currentPacks) {
253
+ if (!lockPacks.has(id)) {
254
+ drift.node_packs.push({ id, current_commit: c.commit_sha, status: "added" });
255
+ }
256
+ }
257
+ return drift;
258
+ }
259
+ //# sourceMappingURL=workflow-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-lock.js","sourceRoot":"","sources":["../../src/services/workflow-lock.ts"],"names":[],"mappings":"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"}
@@ -34,6 +34,7 @@ import { registerManifestTools } from "./manifest.js";
34
34
  import { registerImageConvertTools } from "./image-convert.js";
35
35
  import { registerStorageUploadTools } from "./storage-upload.js";
36
36
  import { registerHealthCheckTools } from "./health-check.js";
37
+ import { registerWorkflowLockTools } from "./workflow-lock.js";
37
38
  import { DefaultsManager } from "../services/defaults-manager.js";
38
39
  export async function registerAllTools(server) {
39
40
  // Hydrate persisted defaults before any tool registration so subsequent
@@ -74,6 +75,7 @@ export async function registerAllTools(server) {
74
75
  registerImageConvertTools(server);
75
76
  registerStorageUploadTools(server);
76
77
  registerHealthCheckTools(server);
78
+ registerWorkflowLockTools(server);
77
79
  await registerAutoloadedWorkflows(server);
78
80
  }
79
81
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ import { z } from "zod";
2
+ import { getClient } from "../comfyui/client.js";
3
+ import { diffLocks, generateLock, } from "../services/workflow-lock.js";
4
+ import { errorToToolResult, ValidationError } from "../utils/errors.js";
5
+ async function loadWorkflowFromLibrary(filename) {
6
+ const client = getClient();
7
+ const encoded = encodeURIComponent(`workflows/${filename}`);
8
+ const res = await client.fetchApi(`/api/userdata/${encoded}`);
9
+ if (!res.ok) {
10
+ throw new ValidationError(`Workflow not found in user library: ${filename} (${res.status})`);
11
+ }
12
+ return (await res.json());
13
+ }
14
+ async function loadLockFromLibrary(filename) {
15
+ const lockName = `${filename}.lock.json`;
16
+ const client = getClient();
17
+ const encoded = encodeURIComponent(`workflows/${lockName}`);
18
+ const res = await client.fetchApi(`/api/userdata/${encoded}`);
19
+ if (!res.ok) {
20
+ throw new ValidationError(`No lock found for "${filename}". Run lock_workflow first to create one.`);
21
+ }
22
+ return (await res.json());
23
+ }
24
+ async function saveLockToLibrary(filename, lock) {
25
+ const lockName = `${filename}.lock.json`;
26
+ const client = getClient();
27
+ const encoded = encodeURIComponent(`workflows/${lockName}`);
28
+ const res = await client.fetchApi(`/api/userdata/${encoded}`, {
29
+ method: "POST",
30
+ body: JSON.stringify(lock, null, 2),
31
+ });
32
+ if (!res.ok) {
33
+ const text = await res.text().catch(() => "");
34
+ throw new ValidationError(`Failed to save lock file for ${filename}: ${res.status} ${res.statusText}${text ? `\n${text}` : ""}`);
35
+ }
36
+ }
37
+ export function registerWorkflowLockTools(server) {
38
+ server.tool("lock_workflow", "Capture a provenance lock for a saved workflow so it can be exactly reproduced later. Walks the workflow's model loaders (CheckpointLoaderSimple, UNETLoader, VAELoader, LoraLoader, ControlNetLoader, etc.), SHA-256s every referenced model file, records the git commit currently checked out for every custom node pack the workflow's class_types come from, and captures ComfyUI's reported version. Writes `<filename>.lock.json` next to the workflow in ComfyUI's user library. Requires a local install (COMFYUI_PATH) — SHA-256 needs raw file bytes and pack commits come from `custom_nodes/*/.git/HEAD`. Pair with verify_workflow_lock later to detect drift.", {
39
+ filename: z
40
+ .string()
41
+ .describe("Workflow filename in the ComfyUI user library (e.g. 'my_workflow.json'). The lock is written as '<filename>.lock.json' alongside."),
42
+ }, async (args) => {
43
+ try {
44
+ const workflow = await loadWorkflowFromLibrary(args.filename);
45
+ const lock = await generateLock(workflow);
46
+ await saveLockToLibrary(args.filename, lock);
47
+ return {
48
+ content: [
49
+ {
50
+ type: "text",
51
+ text: `Locked "${args.filename}" against ComfyUI ${lock.comfyui_version}.\n` +
52
+ `- ${lock.models.length} model(s), ${lock.models.filter((m) => m.sha256).length} hashed, ${lock.models.filter((m) => m.missing).length} missing on disk.\n` +
53
+ `- ${lock.node_packs.length} custom pack(s), ${lock.node_packs.filter((p) => p.commit_sha).length} with commit recorded.\n\n` +
54
+ "```json\n" +
55
+ JSON.stringify(lock, null, 2) +
56
+ "\n```",
57
+ },
58
+ ],
59
+ };
60
+ }
61
+ catch (err) {
62
+ return errorToToolResult(err);
63
+ }
64
+ });
65
+ server.tool("verify_workflow_lock", "Compare a saved workflow's lock file against the current state of the local install and report drift. Loads `<filename>.lock.json` from ComfyUI's user library, re-computes a current lock from the same workflow, and diffs: which models have a different SHA-256, which custom node packs are on a different commit, whether ComfyUI's version changed. Use before re-running an important workflow days or weeks later to confirm it'll behave the same. Requires a local install (COMFYUI_PATH). Returns a structured drift report (empty arrays everywhere mean perfect parity).", {
66
+ filename: z
67
+ .string()
68
+ .describe("Workflow filename whose lock to verify (e.g. 'my_workflow.json')."),
69
+ }, async (args) => {
70
+ try {
71
+ const [workflow, lock] = await Promise.all([
72
+ loadWorkflowFromLibrary(args.filename),
73
+ loadLockFromLibrary(args.filename),
74
+ ]);
75
+ const current = await generateLock(workflow);
76
+ const drift = diffLocks(lock, current);
77
+ const driftCount = drift.models.length + drift.node_packs.length + (drift.comfyui_version ? 1 : 0);
78
+ if (driftCount === 0) {
79
+ return {
80
+ content: [
81
+ {
82
+ type: "text",
83
+ text: `No drift — "${args.filename}" still matches its lock from ${lock.generated_at}.`,
84
+ },
85
+ ],
86
+ };
87
+ }
88
+ const lines = [
89
+ `**Drift detected for "${args.filename}"** — ${driftCount} change(s) since the lock was generated at ${lock.generated_at}.`,
90
+ "",
91
+ ];
92
+ if (drift.comfyui_version) {
93
+ lines.push(`**ComfyUI version**: locked at ${drift.comfyui_version.lock}, currently ${drift.comfyui_version.current}.`, "");
94
+ }
95
+ if (drift.models.length > 0) {
96
+ lines.push("**Models:**");
97
+ for (const m of drift.models) {
98
+ if (m.status === "missing") {
99
+ lines.push(`- 🚫 missing — ${m.type}/${m.name} (locked sha256 \`${m.lock_sha256?.slice(0, 12) ?? "?"}\`)`);
100
+ }
101
+ else if (m.status === "changed") {
102
+ lines.push(`- ✏️ changed — ${m.type}/${m.name} (locked \`${m.lock_sha256?.slice(0, 12)}\` → current \`${m.current_sha256?.slice(0, 12)}\`)`);
103
+ }
104
+ else {
105
+ lines.push(`- ➕ added — ${m.type}/${m.name}`);
106
+ }
107
+ }
108
+ lines.push("");
109
+ }
110
+ if (drift.node_packs.length > 0) {
111
+ lines.push("**Node packs:**");
112
+ for (const p of drift.node_packs) {
113
+ if (p.status === "missing") {
114
+ lines.push(`- 🚫 missing — ${p.id} (locked commit \`${p.lock_commit?.slice(0, 7) ?? "?"}\`)`);
115
+ }
116
+ else if (p.status === "changed") {
117
+ lines.push(`- ✏️ commit changed — ${p.id} (\`${p.lock_commit?.slice(0, 7)}\` → \`${p.current_commit?.slice(0, 7)}\`)`);
118
+ }
119
+ else {
120
+ lines.push(`- ➕ added — ${p.id}`);
121
+ }
122
+ }
123
+ lines.push("");
124
+ }
125
+ lines.push("```json\n" + JSON.stringify(drift, null, 2) + "\n```");
126
+ return {
127
+ content: [{ type: "text", text: lines.join("\n") }],
128
+ };
129
+ }
130
+ catch (err) {
131
+ return errorToToolResult(err);
132
+ }
133
+ });
134
+ }
135
+ //# sourceMappingURL=workflow-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-lock.js","sourceRoot":"","sources":["../../src/tools/workflow-lock.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.9.6",
3
+ "version": "0.10.0",
4
4
  "mcpName": "io.github.artokun/comfyui-mcp",
5
5
  "description": "MCP server for ComfyUI — workflow execution, visualization, composition, registry, and skill generation",
6
6
  "homepage": "https://comfyui-mcp.artokun.io/docs",
@@ -105,7 +105,7 @@ const CATEGORIES: Array<{
105
105
  slug: "workflow-library",
106
106
  icon: "folder-open",
107
107
  description: "Save, load, analyze, and extract workflows.",
108
- tools: ["list_workflows", "get_workflow", "save_workflow", "analyze_workflow", "workflow_from_image"],
108
+ tools: ["list_workflows", "get_workflow", "save_workflow", "analyze_workflow", "workflow_from_image", "lock_workflow", "verify_workflow_lock"],
109
109
  },
110
110
  {
111
111
  group: "Assets & Images",