@fre4x/comfyui 1.0.64 → 1.0.65-beta.1

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.
Files changed (2) hide show
  1. package/dist/index.js +77 -75
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -30501,8 +30501,10 @@ var MOCK_FIXTURES = {
30501
30501
  name: "KSampler",
30502
30502
  display_name: "KSampler",
30503
30503
  description: "",
30504
+ python_module: "",
30504
30505
  category: "sampling",
30505
- output_node: false
30506
+ output_node: false,
30507
+ has_intermediate_output: false
30506
30508
  },
30507
30509
  CheckpointLoaderSimple: {
30508
30510
  input: {
@@ -30526,9 +30528,15 @@ var MOCK_FIXTURES = {
30526
30528
  }
30527
30529
  },
30528
30530
  output: ["MODEL", "CLIP", "VAE"],
30531
+ output_is_list: [false, false, false],
30532
+ output_name: ["MODEL", "CLIP", "VAE"],
30529
30533
  name: "CheckpointLoaderSimple",
30530
30534
  display_name: "Load Checkpoint",
30531
- category: "loaders"
30535
+ description: "",
30536
+ python_module: "",
30537
+ category: "loaders",
30538
+ output_node: false,
30539
+ has_intermediate_output: false
30532
30540
  }
30533
30541
  },
30534
30542
  prompt_response: {
@@ -30577,8 +30585,11 @@ var UI_CONTROL_VALUES = /* @__PURE__ */ new Set([
30577
30585
  "decrement",
30578
30586
  "randomize"
30579
30587
  ]);
30588
+ function isRecord(value) {
30589
+ return typeof value === "object" && value !== null;
30590
+ }
30580
30591
  function isWebUIFormat(json2) {
30581
- return typeof json2 === "object" && json2 !== null && Array.isArray(json2.nodes) && Array.isArray(json2.links);
30592
+ return isRecord(json2) && Array.isArray(json2.nodes) && Array.isArray(json2.links);
30582
30593
  }
30583
30594
  function isLinkData(link) {
30584
30595
  return Array.isArray(link) && link.length >= 6 && typeof link[0] === "number" && typeof link[1] === "number" && typeof link[2] === "number" && typeof link[3] === "number" && typeof link[4] === "number" && typeof link[5] === "string";
@@ -30738,16 +30749,41 @@ var WorkflowInputError = class extends Error {
30738
30749
  this.name = "WorkflowInputError";
30739
30750
  }
30740
30751
  };
30741
- function isRecord(value) {
30752
+ function isRecord2(value) {
30742
30753
  return typeof value === "object" && value !== null;
30743
30754
  }
30755
+ function isComfyPromptNode(value) {
30756
+ return isRecord2(value) && typeof value.class_type === "string" && isRecord2(value.inputs);
30757
+ }
30758
+ function isUiOnlyPromptNode(nodeId, node) {
30759
+ return nodeId === "meta" || ["Note", "MarkdownNote", "PrimitiveNode"].includes(node.class_type);
30760
+ }
30761
+ function extractRunnablePromptNodes(prompt) {
30762
+ const runnablePrompt = {};
30763
+ for (const [nodeId, rawNode] of Object.entries(prompt)) {
30764
+ if (!isComfyPromptNode(rawNode) || isUiOnlyPromptNode(nodeId, rawNode)) {
30765
+ continue;
30766
+ }
30767
+ runnablePrompt[nodeId] = rawNode;
30768
+ }
30769
+ if (Object.keys(runnablePrompt).length === 0) {
30770
+ throw new WorkflowInputError(
30771
+ "Workflow prompt does not contain any runnable ComfyUI nodes.",
30772
+ "workflow"
30773
+ );
30774
+ }
30775
+ return runnablePrompt;
30776
+ }
30777
+ function toStructuredContent(value) {
30778
+ return isRecord2(value) ? value : {};
30779
+ }
30744
30780
  function summarizeNodeErrors(nodeErrors) {
30745
- if (!isRecord(nodeErrors)) {
30781
+ if (!isRecord2(nodeErrors)) {
30746
30782
  return [];
30747
30783
  }
30748
30784
  const lines = [];
30749
30785
  for (const [nodeId, rawNodeError] of Object.entries(nodeErrors)) {
30750
- if (!isRecord(rawNodeError)) {
30786
+ if (!isRecord2(rawNodeError)) {
30751
30787
  continue;
30752
30788
  }
30753
30789
  const classType = typeof rawNodeError.class_type === "string" ? ` (${rawNodeError.class_type})` : "";
@@ -30755,7 +30791,7 @@ function summarizeNodeErrors(nodeErrors) {
30755
30791
  const missingInputs = [];
30756
30792
  const otherMessages = [];
30757
30793
  for (const rawError of rawErrors) {
30758
- if (!isRecord(rawError)) {
30794
+ if (!isRecord2(rawError)) {
30759
30795
  continue;
30760
30796
  }
30761
30797
  const errorType = rawError.type;
@@ -30785,11 +30821,11 @@ function summarizeNodeErrors(nodeErrors) {
30785
30821
  return lines;
30786
30822
  }
30787
30823
  function summarizeComfyErrorDetails(details) {
30788
- if (!isRecord(details)) {
30824
+ if (!isRecord2(details)) {
30789
30825
  return "";
30790
30826
  }
30791
30827
  const lines = [];
30792
- const errorDetails = isRecord(details.error) ? details.error : void 0;
30828
+ const errorDetails = isRecord2(details.error) ? details.error : void 0;
30793
30829
  if (typeof errorDetails?.message === "string") {
30794
30830
  lines.push(errorDetails.message);
30795
30831
  } else if (typeof details.message === "string") {
@@ -30921,7 +30957,7 @@ function handleComfyError(error48) {
30921
30957
  ${detailSummary}` : error48.message
30922
30958
  }
30923
30959
  ],
30924
- structuredContent: error48.details || {},
30960
+ structuredContent: toStructuredContent(error48.details),
30925
30961
  isError: true
30926
30962
  };
30927
30963
  }
@@ -30984,9 +31020,7 @@ function isConnectionValue(value) {
30984
31020
  return Array.isArray(value) && value.length >= 2 && (typeof value[0] === "string" || typeof value[0] === "number") && typeof value[1] === "number";
30985
31021
  }
30986
31022
  async function getObjectInfo() {
30987
- return IS_MOCK ? MOCK_FIXTURES.object_info : await fetchComfyJson(
30988
- "/object_info"
30989
- );
31023
+ return IS_MOCK ? MOCK_FIXTURES.object_info : await fetchComfyJson("/object_info");
30990
31024
  }
30991
31025
  async function resolveWorkflowReference(args) {
30992
31026
  if (args.workflow_file_path) {
@@ -31064,7 +31098,7 @@ async function resolveWorkflowReference(args) {
31064
31098
  );
31065
31099
  }
31066
31100
  async function normalizeWorkflowPrompt(workflow) {
31067
- if (!isRecord(workflow)) {
31101
+ if (!isRecord2(workflow)) {
31068
31102
  throw new WorkflowInputError(
31069
31103
  "Workflow must be a JSON object.",
31070
31104
  "workflow"
@@ -31079,15 +31113,15 @@ async function normalizeWorkflowPrompt(workflow) {
31079
31113
  await getObjectInfo()
31080
31114
  );
31081
31115
  }
31082
- const prompt = isRecord(normalizedWorkflow.prompt) && normalizedWorkflow.prompt ? normalizedWorkflow.prompt : normalizedWorkflow;
31083
- if (!isRecord(prompt)) {
31116
+ const promptCandidate = isRecord2(normalizedWorkflow.prompt) && normalizedWorkflow.prompt ? normalizedWorkflow.prompt : normalizedWorkflow;
31117
+ if (!isRecord2(promptCandidate)) {
31084
31118
  throw new WorkflowInputError(
31085
31119
  "Workflow prompt must be a JSON object.",
31086
31120
  "workflow"
31087
31121
  );
31088
31122
  }
31089
31123
  return {
31090
- prompt,
31124
+ prompt: extractRunnablePromptNodes(promptCandidate),
31091
31125
  sourceFormat
31092
31126
  };
31093
31127
  }
@@ -31165,15 +31199,8 @@ function formatValuePreview(value) {
31165
31199
  }
31166
31200
  function analyzeEditableInputs(prompt) {
31167
31201
  const consumerMap = /* @__PURE__ */ new Map();
31168
- for (const [nodeId, rawNode] of Object.entries(prompt)) {
31169
- if (!isRecord(rawNode) || !isRecord(rawNode.inputs)) {
31170
- continue;
31171
- }
31172
- const classType = typeof rawNode.class_type === "string" ? rawNode.class_type : "";
31173
- if (!classType || ["Note", "MarkdownNote", "PrimitiveNode"].includes(classType) || nodeId === "meta") {
31174
- continue;
31175
- }
31176
- for (const [inputName, value] of Object.entries(rawNode.inputs)) {
31202
+ for (const [nodeId, node] of Object.entries(prompt)) {
31203
+ for (const [inputName, value] of Object.entries(node.inputs)) {
31177
31204
  if (!isConnectionValue(value)) {
31178
31205
  continue;
31179
31206
  }
@@ -31181,35 +31208,28 @@ function analyzeEditableInputs(prompt) {
31181
31208
  const consumers = consumerMap.get(sourceNodeId) ?? [];
31182
31209
  consumers.push({
31183
31210
  inputName,
31184
- classType,
31211
+ classType: node.class_type,
31185
31212
  nodeId
31186
31213
  });
31187
31214
  consumerMap.set(sourceNodeId, consumers);
31188
31215
  }
31189
31216
  }
31190
31217
  const editableInputs = [];
31191
- for (const [nodeId, rawNode] of Object.entries(prompt)) {
31192
- if (!isRecord(rawNode) || !isRecord(rawNode.inputs)) {
31193
- continue;
31194
- }
31195
- const classType = typeof rawNode.class_type === "string" ? rawNode.class_type : "";
31196
- if (!classType || ["Note", "MarkdownNote", "PrimitiveNode"].includes(classType) || nodeId === "meta") {
31197
- continue;
31198
- }
31199
- for (const [inputName, value] of Object.entries(rawNode.inputs)) {
31218
+ for (const [nodeId, node] of Object.entries(prompt)) {
31219
+ for (const [inputName, value] of Object.entries(node.inputs)) {
31200
31220
  if (isConnectionValue(value)) {
31201
31221
  continue;
31202
31222
  }
31203
31223
  editableInputs.push({
31204
31224
  path: `${nodeId}.inputs.${inputName}`,
31205
31225
  node_id: nodeId,
31206
- class_type: classType,
31226
+ class_type: node.class_type,
31207
31227
  input_name: inputName,
31208
31228
  value,
31209
31229
  value_preview: formatValuePreview(value),
31210
31230
  role: inferEditableRole(
31211
31231
  nodeId,
31212
- classType,
31232
+ node.class_type,
31213
31233
  inputName,
31214
31234
  consumerMap
31215
31235
  )
@@ -31245,13 +31265,14 @@ function applyOverrides(prompt, overrides) {
31245
31265
  let current = prompt;
31246
31266
  for (let i = 0; i < parts.length - 1; i++) {
31247
31267
  const part = parts[i];
31248
- if (typeof current[part] !== "object" || current[part] === null) {
31268
+ const next = current[part];
31269
+ if (!isRecord2(next)) {
31249
31270
  throw new WorkflowInputError(
31250
31271
  `Invalid override path: '${key}'. The segment '${part}' does not exist or is not an object. Please check the editable inputs using 'comfyui_get_workflow' to find the correct path.`,
31251
31272
  "overrides"
31252
31273
  );
31253
31274
  }
31254
- current = current[part];
31275
+ current = next;
31255
31276
  }
31256
31277
  current[parts[parts.length - 1]] = value;
31257
31278
  }
@@ -31298,9 +31319,7 @@ var WaitForWorkflowSchema = z3.object({
31298
31319
  });
31299
31320
  async function handleInspectNode(args) {
31300
31321
  try {
31301
- const rawInfo = IS_MOCK ? MOCK_FIXTURES.object_info : await fetchComfyJson(
31302
- "/object_info"
31303
- );
31322
+ const rawInfo = await getObjectInfo();
31304
31323
  if (args.node_class) {
31305
31324
  const node = rawInfo[args.node_class];
31306
31325
  if (!node) {
@@ -31312,7 +31331,7 @@ async function handleInspectNode(args) {
31312
31331
  content: [
31313
31332
  { type: "text", text: JSON.stringify(node, null, 2) }
31314
31333
  ],
31315
- structuredContent: node
31334
+ structuredContent: { ...node }
31316
31335
  };
31317
31336
  }
31318
31337
  let classes = Object.keys(rawInfo);
@@ -31446,9 +31465,16 @@ async function waitForWorkflowResult(prompt_id, timeout_seconds) {
31446
31465
  const start = Date.now();
31447
31466
  const end = start + timeout_seconds * 1e3;
31448
31467
  while (Date.now() < end) {
31449
- const history = IS_MOCK ? MOCK_FIXTURES.history : await fetchComfyJson(
31450
- `/history/${prompt_id}`
31451
- ).catch(() => ({}));
31468
+ let history = MOCK_FIXTURES.history;
31469
+ if (!IS_MOCK) {
31470
+ try {
31471
+ history = await fetchComfyJson(
31472
+ `/history/${prompt_id}`
31473
+ );
31474
+ } catch {
31475
+ history = {};
31476
+ }
31477
+ }
31452
31478
  if (history?.[prompt_id]) {
31453
31479
  return history[prompt_id];
31454
31480
  }
@@ -31542,20 +31568,7 @@ async function handleGetWorkflow(args) {
31542
31568
  editable_inputs: editableInputs
31543
31569
  };
31544
31570
  if (args.include_prompt) {
31545
- const filteredPrompt = {};
31546
- for (const [nodeId, node] of Object.entries(
31547
- loadedWorkflow.prompt
31548
- )) {
31549
- if (isRecord(node)) {
31550
- const classType = typeof node.class_type === "string" ? node.class_type : "";
31551
- if (classType && !["Note", "MarkdownNote", "PrimitiveNode"].includes(
31552
- classType
31553
- ) && nodeId !== "meta") {
31554
- filteredPrompt[nodeId] = node;
31555
- }
31556
- }
31557
- }
31558
- structuredContent.prompt = filteredPrompt;
31571
+ structuredContent.prompt = loadedWorkflow.prompt;
31559
31572
  }
31560
31573
  return {
31561
31574
  content: [{ type: "text", text }],
@@ -31627,18 +31640,7 @@ async function handleSaveWorkflow(args) {
31627
31640
  editable_inputs: editableInputs
31628
31641
  };
31629
31642
  if (args.include_prompt) {
31630
- const filteredPrompt = {};
31631
- for (const [nodeId, node] of Object.entries(prompt)) {
31632
- if (isRecord(node)) {
31633
- const classType = typeof node.class_type === "string" ? node.class_type : "";
31634
- if (classType && !["Note", "MarkdownNote", "PrimitiveNode"].includes(
31635
- classType
31636
- ) && nodeId !== "meta") {
31637
- filteredPrompt[nodeId] = node;
31638
- }
31639
- }
31640
- }
31641
- structuredContent.prompt = filteredPrompt;
31643
+ structuredContent.prompt = prompt;
31642
31644
  }
31643
31645
  const persistedChanges = args.overrides && Object.keys(args.overrides).length > 0 ? `Persisted ${Object.keys(args.overrides).length} override(s).` : "No overrides were applied.";
31644
31646
  const text = [
@@ -31678,7 +31680,7 @@ async function handleWorkflowRun(args) {
31678
31680
  text: formatWorkflowNodeErrors(result.node_errors)
31679
31681
  }
31680
31682
  ],
31681
- structuredContent: result,
31683
+ structuredContent: { ...result },
31682
31684
  isError: true
31683
31685
  };
31684
31686
  }
@@ -31697,7 +31699,7 @@ async function handleWorkflowRun(args) {
31697
31699
  To retrieve the final results or check its status later, use the 'comfyui_wait_for_workflow' tool with this prompt_id.`
31698
31700
  }
31699
31701
  ],
31700
- structuredContent: result
31702
+ structuredContent: { ...result }
31701
31703
  };
31702
31704
  } catch (error48) {
31703
31705
  return handleComfyError(error48);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fre4x/comfyui",
3
- "version": "1.0.64",
3
+ "version": "1.0.65-beta.1",
4
4
  "description": "MCP server for ComfyUI. Execute workflows and probe server state remotely.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,9 +15,9 @@
15
15
  "dev": "tsx watch src/index.ts",
16
16
  "typecheck": "node --max-old-space-size=4096 ../node_modules/typescript/bin/tsc --noEmit",
17
17
  "prepublishOnly": "npm run typecheck && npm run build",
18
- "test": "vitest run --exclude dist",
19
- "test:watch": "vitest",
20
- "test:e2e": "cross-env COMFYUI_E2E=true vitest run src/e2e.test.ts",
18
+ "test": "node ../scripts/run-vitest.mjs run --exclude dist",
19
+ "test:watch": "node ../scripts/run-vitest.mjs",
20
+ "test:e2e": "cross-env COMFYUI_E2E=true node ../scripts/run-vitest.mjs run src/e2e.test.ts",
21
21
  "inspector": "npm run build && node ../scripts/run-official-inspector.mjs node dist/index.js"
22
22
  },
23
23
  "dependencies": {