comfyui-mcp 0.5.0 → 0.6.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/.dockerignore +24 -0
- package/CHANGELOG.md +61 -0
- package/Dockerfile +50 -0
- package/README.md +4 -1
- package/dist/comfyui/client.d.ts +1 -1
- package/dist/comfyui/client.d.ts.map +1 -1
- package/dist/comfyui/client.js +24 -3
- package/dist/comfyui/client.js.map +1 -1
- package/dist/comfyui/types.d.ts +9 -0
- package/dist/comfyui/types.d.ts.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/services/api-nodes.d.ts +77 -0
- package/dist/services/api-nodes.d.ts.map +1 -0
- package/dist/services/api-nodes.js +205 -0
- package/dist/services/api-nodes.js.map +1 -0
- package/dist/services/civitai-resolver.d.ts +27 -0
- package/dist/services/civitai-resolver.d.ts.map +1 -0
- package/dist/services/civitai-resolver.js +82 -0
- package/dist/services/civitai-resolver.js.map +1 -0
- package/dist/services/install-comfyui.d.ts +89 -0
- package/dist/services/install-comfyui.d.ts.map +1 -0
- package/dist/services/install-comfyui.js +288 -0
- package/dist/services/install-comfyui.js.map +1 -0
- package/dist/services/manager-config.d.ts +59 -0
- package/dist/services/manager-config.d.ts.map +1 -0
- package/dist/services/manager-config.js +309 -0
- package/dist/services/manager-config.js.map +1 -0
- package/dist/services/model-resolver.d.ts.map +1 -1
- package/dist/services/model-resolver.js +31 -2
- package/dist/services/model-resolver.js.map +1 -1
- package/dist/services/node-bisect.d.ts +105 -0
- package/dist/services/node-bisect.d.ts.map +1 -0
- package/dist/services/node-bisect.js +426 -0
- package/dist/services/node-bisect.js.map +1 -0
- package/dist/services/node-management.d.ts +90 -0
- package/dist/services/node-management.d.ts.map +1 -0
- package/dist/services/node-management.js +377 -0
- package/dist/services/node-management.js.map +1 -0
- package/dist/services/node-snapshots.d.ts +27 -0
- package/dist/services/node-snapshots.d.ts.map +1 -0
- package/dist/services/node-snapshots.js +203 -0
- package/dist/services/node-snapshots.js.map +1 -0
- package/dist/services/update-comfyui.d.ts +34 -0
- package/dist/services/update-comfyui.d.ts.map +1 -0
- package/dist/services/update-comfyui.js +206 -0
- package/dist/services/update-comfyui.js.map +1 -0
- package/dist/services/workflow-autoload.d.ts.map +1 -1
- package/dist/services/workflow-autoload.js +1 -1
- package/dist/services/workflow-autoload.js.map +1 -1
- package/dist/services/workflow-deps.d.ts +135 -0
- package/dist/services/workflow-deps.d.ts.map +1 -0
- package/dist/services/workflow-deps.js +306 -0
- package/dist/services/workflow-deps.js.map +1 -0
- package/dist/services/workflow-dsl.d.ts +4 -0
- package/dist/services/workflow-dsl.d.ts.map +1 -0
- package/dist/services/workflow-dsl.js +95 -0
- package/dist/services/workflow-dsl.js.map +1 -0
- package/dist/services/workflow-executor.d.ts +2 -0
- package/dist/services/workflow-executor.d.ts.map +1 -1
- package/dist/services/workflow-executor.js +1 -1
- package/dist/services/workflow-executor.js.map +1 -1
- package/dist/services/workspace-env.d.ts +68 -0
- package/dist/services/workspace-env.d.ts.map +1 -0
- package/dist/services/workspace-env.js +371 -0
- package/dist/services/workspace-env.js.map +1 -0
- package/dist/tools/api-nodes.d.ts +9 -0
- package/dist/tools/api-nodes.d.ts.map +1 -0
- package/dist/tools/api-nodes.js +85 -0
- package/dist/tools/api-nodes.js.map +1 -0
- package/dist/tools/generate-conditioned.js +12 -12
- package/dist/tools/generate-conditioned.js.map +1 -1
- package/dist/tools/generation-tracker.d.ts.map +1 -1
- package/dist/tools/generation-tracker.js +3 -4
- package/dist/tools/generation-tracker.js.map +1 -1
- package/dist/tools/image-management.d.ts.map +1 -1
- package/dist/tools/image-management.js +1 -3
- package/dist/tools/image-management.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +22 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/install-comfyui.d.ts +3 -0
- package/dist/tools/install-comfyui.d.ts.map +1 -0
- package/dist/tools/install-comfyui.js +51 -0
- package/dist/tools/install-comfyui.js.map +1 -0
- package/dist/tools/manager-config.d.ts +3 -0
- package/dist/tools/manager-config.d.ts.map +1 -0
- package/dist/tools/manager-config.js +45 -0
- package/dist/tools/manager-config.js.map +1 -0
- package/dist/tools/memory-management.js +1 -1
- package/dist/tools/memory-management.js.map +1 -1
- package/dist/tools/model-extras.d.ts +3 -0
- package/dist/tools/model-extras.d.ts.map +1 -0
- package/dist/tools/model-extras.js +135 -0
- package/dist/tools/model-extras.js.map +1 -0
- package/dist/tools/model-management.js +3 -3
- package/dist/tools/model-management.js.map +1 -1
- package/dist/tools/node-bisect.d.ts +3 -0
- package/dist/tools/node-bisect.d.ts.map +1 -0
- package/dist/tools/node-bisect.js +60 -0
- package/dist/tools/node-bisect.js.map +1 -0
- package/dist/tools/node-management.d.ts +3 -0
- package/dist/tools/node-management.d.ts.map +1 -0
- package/dist/tools/node-management.js +143 -0
- package/dist/tools/node-management.js.map +1 -0
- package/dist/tools/node-snapshots.d.ts +3 -0
- package/dist/tools/node-snapshots.d.ts.map +1 -0
- package/dist/tools/node-snapshots.js +59 -0
- package/dist/tools/node-snapshots.js.map +1 -0
- package/dist/tools/queue-management.js +4 -4
- package/dist/tools/queue-management.js.map +1 -1
- package/dist/tools/registry-search.js +4 -4
- package/dist/tools/registry-search.js.map +1 -1
- package/dist/tools/skill-generator.js +2 -2
- package/dist/tools/skill-generator.js.map +1 -1
- package/dist/tools/update-comfyui.d.ts +3 -0
- package/dist/tools/update-comfyui.d.ts.map +1 -0
- package/dist/tools/update-comfyui.js +27 -0
- package/dist/tools/update-comfyui.js.map +1 -0
- package/dist/tools/workflow-autoload.d.ts.map +1 -1
- package/dist/tools/workflow-autoload.js +7 -2
- package/dist/tools/workflow-autoload.js.map +1 -1
- package/dist/tools/workflow-compose.js +3 -3
- package/dist/tools/workflow-compose.js.map +1 -1
- package/dist/tools/workflow-deps.d.ts +3 -0
- package/dist/tools/workflow-deps.d.ts.map +1 -0
- package/dist/tools/workflow-deps.js +111 -0
- package/dist/tools/workflow-deps.js.map +1 -0
- package/dist/tools/workflow-dsl.d.ts +3 -0
- package/dist/tools/workflow-dsl.d.ts.map +1 -0
- package/dist/tools/workflow-dsl.js +29 -0
- package/dist/tools/workflow-dsl.js.map +1 -0
- package/dist/tools/workflow-execute.js +1 -1
- package/dist/tools/workflow-execute.js.map +1 -1
- package/dist/tools/workflow-library.js +3 -3
- package/dist/tools/workflow-library.js.map +1 -1
- package/dist/tools/workspace-env.d.ts +3 -0
- package/dist/tools/workspace-env.d.ts.map +1 -0
- package/dist/tools/workspace-env.js +55 -0
- package/dist/tools/workspace-env.js.map +1 -0
- package/dist/utils/errors.d.ts +6 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +12 -0
- package/dist/utils/errors.js.map +1 -1
- package/glama.json +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { getObjectInfo } from "../comfyui/client.js";
|
|
2
|
+
import { enqueueWorkflow } from "./workflow-executor.js";
|
|
3
|
+
import { config } from "../config.js";
|
|
4
|
+
import { ValidationError } from "../utils/errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* API / partner-node support, mirroring `comfy-cli generate` (list / schema / run).
|
|
7
|
+
*
|
|
8
|
+
* MECHANISM & ASSUMPTIONS (confirmed against ComfyUI + comfy-cli source):
|
|
9
|
+
* - These nodes run entirely on the *connected* ComfyUI server via its normal
|
|
10
|
+
* HTTP API (/object_info + /prompt), so this works against remote servers too.
|
|
11
|
+
* We reuse the existing client (getObjectInfo) and enqueue helper rather than
|
|
12
|
+
* re-implementing anything.
|
|
13
|
+
* - ComfyUI marks hosted partner/API nodes in /object_info with `api_node: true`
|
|
14
|
+
* (server.py emits this from the node class's `API_NODE` attribute). Their
|
|
15
|
+
* `category` also conventionally starts with "api node/" (e.g.
|
|
16
|
+
* "api node/image/BFL", "api node/video/Kling"). We treat EITHER signal as a
|
|
17
|
+
* match so older/newer ComfyUI builds both work.
|
|
18
|
+
* Ref: comfyanonymous/ComfyUI server.py node_info() and comfy_api_nodes/*.py.
|
|
19
|
+
* - AUTH: API nodes require a Comfy account / API key, but that credential is
|
|
20
|
+
* supplied to the *ComfyUI server* out-of-band — it is injected by the server
|
|
21
|
+
* into the node's HIDDEN inputs (`auth_token_comfy_org` / `api_key_comfy_org`)
|
|
22
|
+
* from the logged-in session. The MCP client does NOT (and should not) place
|
|
23
|
+
* the key in the workflow JSON. If the server isn't authenticated, the job
|
|
24
|
+
* will be enqueued but fail server-side; we surface that as guidance rather
|
|
25
|
+
* than trying to pass credentials ourselves. (Lower-confidence area — see
|
|
26
|
+
* docs.comfy.org/tutorials/api-nodes.)
|
|
27
|
+
*/
|
|
28
|
+
const API_CATEGORY_PREFIX = "api node";
|
|
29
|
+
const defaultDeps = {
|
|
30
|
+
getObjectInfo,
|
|
31
|
+
enqueue: enqueueWorkflow,
|
|
32
|
+
};
|
|
33
|
+
/** True if a node definition is a hosted partner/API node. */
|
|
34
|
+
export function isApiNode(def) {
|
|
35
|
+
if (def.api_node === true)
|
|
36
|
+
return true;
|
|
37
|
+
const category = (def.category ?? "").toLowerCase();
|
|
38
|
+
return category === API_CATEGORY_PREFIX || category.startsWith(`${API_CATEGORY_PREFIX}/`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Discover hosted partner/API nodes available on the connected ComfyUI.
|
|
42
|
+
* Optionally narrow by a case-insensitive substring matched against the
|
|
43
|
+
* class_type, display name, or category (e.g. "image", "kling", "video").
|
|
44
|
+
*/
|
|
45
|
+
export async function listApiNodes(filter, deps = defaultDeps) {
|
|
46
|
+
const objectInfo = await deps.getObjectInfo();
|
|
47
|
+
const needle = filter?.trim().toLowerCase();
|
|
48
|
+
const results = [];
|
|
49
|
+
for (const [classType, def] of Object.entries(objectInfo)) {
|
|
50
|
+
if (!def || !isApiNode(def))
|
|
51
|
+
continue;
|
|
52
|
+
const summary = {
|
|
53
|
+
class_type: classType,
|
|
54
|
+
display_name: def.display_name || classType,
|
|
55
|
+
category: def.category ?? "",
|
|
56
|
+
description: def.description ?? "",
|
|
57
|
+
output: Array.isArray(def.output) ? def.output : [],
|
|
58
|
+
deprecated: def.deprecated === true,
|
|
59
|
+
experimental: def.experimental === true,
|
|
60
|
+
};
|
|
61
|
+
if (needle) {
|
|
62
|
+
const haystack = `${classType} ${summary.display_name} ${summary.category}`.toLowerCase();
|
|
63
|
+
if (!haystack.includes(needle))
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
results.push(summary);
|
|
67
|
+
}
|
|
68
|
+
results.sort((a, b) => a.class_type.localeCompare(b.class_type));
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
function describeInputs(specs, required) {
|
|
72
|
+
if (!specs)
|
|
73
|
+
return [];
|
|
74
|
+
return Object.entries(specs).map(([name, spec]) => {
|
|
75
|
+
// Spec shape: [type, config?] where type is a string (e.g. "STRING") or a
|
|
76
|
+
// string[] of enum options (e.g. ["fast", "quality"]).
|
|
77
|
+
const type = Array.isArray(spec) ? spec[0] : spec;
|
|
78
|
+
const config = (Array.isArray(spec) ? spec[1] : undefined) ?? {};
|
|
79
|
+
return {
|
|
80
|
+
name,
|
|
81
|
+
type: type,
|
|
82
|
+
required,
|
|
83
|
+
config: config,
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/** Return the input schema for a given API node (from its /object_info entry). */
|
|
88
|
+
export async function getApiNodeSchema(classType, deps = defaultDeps) {
|
|
89
|
+
const objectInfo = await deps.getObjectInfo();
|
|
90
|
+
const def = objectInfo[classType];
|
|
91
|
+
if (!def) {
|
|
92
|
+
throw new ValidationError(`Node "${classType}" was not found on the connected ComfyUI. ` +
|
|
93
|
+
`Use list_api_nodes to see available API nodes.`);
|
|
94
|
+
}
|
|
95
|
+
if (!isApiNode(def)) {
|
|
96
|
+
throw new ValidationError(`Node "${classType}" exists but is not an API/partner node ` +
|
|
97
|
+
`(category "${def.category ?? ""}"). Use list_api_nodes to find API nodes.`);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
class_type: classType,
|
|
101
|
+
display_name: def.display_name || classType,
|
|
102
|
+
category: def.category ?? "",
|
|
103
|
+
description: def.description ?? "",
|
|
104
|
+
is_api_node: true,
|
|
105
|
+
is_output_node: def.output_node === true,
|
|
106
|
+
inputs: [
|
|
107
|
+
...describeInputs(def.input?.required, true),
|
|
108
|
+
...describeInputs(def.input?.optional, false),
|
|
109
|
+
],
|
|
110
|
+
hidden_inputs: def.input?.hidden ? Object.keys(def.input.hidden) : [],
|
|
111
|
+
output: Array.isArray(def.output) ? def.output : [],
|
|
112
|
+
output_name: Array.isArray(def.output_name) ? def.output_name : [],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Build a minimal single-node workflow that runs a chosen API node with the
|
|
117
|
+
* provided inputs and enqueue it. Returns the prompt_id (reuses the existing
|
|
118
|
+
* enqueue path). The API node is typically an output node, so it can stand
|
|
119
|
+
* alone as a complete graph.
|
|
120
|
+
*/
|
|
121
|
+
export async function generateWithApiNode(args, deps = defaultDeps) {
|
|
122
|
+
const schema = await getApiNodeSchema(args.class_type, deps);
|
|
123
|
+
const notes = [];
|
|
124
|
+
const provided = args.inputs ?? {};
|
|
125
|
+
const knownNames = new Set(schema.inputs.map((i) => i.name));
|
|
126
|
+
// Warn about inputs that aren't part of the node's visible schema (typos,
|
|
127
|
+
// or hidden auth fields the server should fill itself).
|
|
128
|
+
for (const key of Object.keys(provided)) {
|
|
129
|
+
if (!knownNames.has(key)) {
|
|
130
|
+
if (schema.hidden_inputs.includes(key)) {
|
|
131
|
+
notes.push(`Ignoring "${key}": it is a hidden input filled by the ComfyUI server, not the client.`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
notes.push(`Unknown input "${key}" for ${args.class_type} (passing through anyway).`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Check required inputs are present (skip enum/combo selectors that ComfyUI
|
|
139
|
+
// can default, but still flag genuinely missing scalars).
|
|
140
|
+
const missingRequired = schema.inputs
|
|
141
|
+
.filter((i) => i.required && !(i.name in provided))
|
|
142
|
+
.map((i) => i.name);
|
|
143
|
+
if (missingRequired.length > 0) {
|
|
144
|
+
notes.push(`Missing required input(s): ${missingRequired.join(", ")}. ` +
|
|
145
|
+
`The server may reject the job. Use get_api_node_schema for details.`);
|
|
146
|
+
}
|
|
147
|
+
// Drop any hidden-input values the caller mistakenly supplied — the server
|
|
148
|
+
// injects auth credentials itself.
|
|
149
|
+
const inputs = {};
|
|
150
|
+
for (const [key, value] of Object.entries(provided)) {
|
|
151
|
+
if (schema.hidden_inputs.includes(key))
|
|
152
|
+
continue;
|
|
153
|
+
inputs[key] = value;
|
|
154
|
+
}
|
|
155
|
+
const workflow = {
|
|
156
|
+
"1": {
|
|
157
|
+
class_type: args.class_type,
|
|
158
|
+
inputs,
|
|
159
|
+
_meta: { title: schema.display_name },
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
// ComfyUI only executes graphs that reach a terminal OUTPUT_NODE; a bare
|
|
163
|
+
// non-output API node fails validation with "prompt_no_outputs". If the API
|
|
164
|
+
// node isn't itself an output node, wire its IMAGE output into a SaveImage.
|
|
165
|
+
if (!schema.is_output_node) {
|
|
166
|
+
const imageIdx = schema.output.findIndex((o) => String(o).toUpperCase() === "IMAGE");
|
|
167
|
+
if (imageIdx >= 0) {
|
|
168
|
+
workflow["2"] = {
|
|
169
|
+
class_type: "SaveImage",
|
|
170
|
+
inputs: { images: ["1", imageIdx], filename_prefix: "ComfyUI" },
|
|
171
|
+
_meta: { title: "Save Image" },
|
|
172
|
+
};
|
|
173
|
+
notes.push("Added a SaveImage output node — ComfyUI requires a terminal output node " +
|
|
174
|
+
"for the prompt to execute.");
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
notes.push(`"${args.class_type}" is not an output node and has no IMAGE output, so no ` +
|
|
178
|
+
"output node was auto-added; the prompt may fail with 'prompt_no_outputs'. " +
|
|
179
|
+
"Wire a terminal output node yourself if needed.");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// comfy.org API-node credentials travel in /prompt extra_data (the server
|
|
183
|
+
// injects them into the node's hidden inputs). Supply the configured key so
|
|
184
|
+
// API nodes work even when the ComfyUI server isn't logged in itself.
|
|
185
|
+
const extraData = {};
|
|
186
|
+
if (config.comfyApiKey) {
|
|
187
|
+
extraData.api_key_comfy_org = config.comfyApiKey;
|
|
188
|
+
notes.push("Attached COMFY_API_KEY to the request (extra_data.api_key_comfy_org).");
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
notes.push("No COMFY_API_KEY configured — relying on the ComfyUI server's own logged-in " +
|
|
192
|
+
"comfy.org session for API-node auth. Set COMFY_API_KEY if the server isn't logged in.");
|
|
193
|
+
}
|
|
194
|
+
const result = await deps.enqueue(workflow, {
|
|
195
|
+
disable_random_seed: args.disable_random_seed,
|
|
196
|
+
extra_data: Object.keys(extraData).length > 0 ? extraData : undefined,
|
|
197
|
+
});
|
|
198
|
+
return {
|
|
199
|
+
prompt_id: result.prompt_id,
|
|
200
|
+
queue_remaining: result.queue_remaining,
|
|
201
|
+
workflow,
|
|
202
|
+
notes,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=api-nodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-nodes.js","sourceRoot":"","sources":["../../src/services/api-nodes.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,mBAAmB,GAAG,UAAU,CAAC;AAcvC,MAAM,WAAW,GAAiB;IAChC,aAAa;IACb,OAAO,EAAE,eAAe;CACzB,CAAC;AAEF,8DAA8D;AAC9D,MAAM,UAAU,SAAS,CAAC,GAAmB;IAC3C,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACvC,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACpD,OAAO,QAAQ,KAAK,mBAAmB,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,mBAAmB,GAAG,CAAC,CAAC;AAC5F,CAAC;AAYD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAe,EACf,OAAqB,WAAW;IAEhC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE5C,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1D,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,SAAS;QAEtC,MAAM,OAAO,GAAmB;YAC9B,UAAU,EAAE,SAAS;YACrB,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,SAAS;YAC3C,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;YAC5B,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE;YAClC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;YACnD,UAAU,EAAE,GAAG,CAAC,UAAU,KAAK,IAAI;YACnC,YAAY,EAAE,GAAG,CAAC,YAAY,KAAK,IAAI;SACxC,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,QAAQ,GAAG,GAAG,SAAS,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CAAC;YAC1F,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAAE,SAAS;QAC3C,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IACjE,OAAO,OAAO,CAAC;AACjB,CAAC;AA6BD,SAAS,cAAc,CACrB,KAAgD,EAChD,QAAiB;IAEjB,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;QAChD,0EAA0E;QAC1E,uDAAuD;QACvD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,IAA0B,CAAC;QACzE,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACjE,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,IAAyB;YAC/B,QAAQ;YACR,MAAM,EAAE,MAAiC;SAC1C,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAiB,EACjB,OAAqB,WAAW;IAEhC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;IAC9C,MAAM,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAElC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,eAAe,CACvB,SAAS,SAAS,4CAA4C;YAC5D,gDAAgD,CACnD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,eAAe,CACvB,SAAS,SAAS,0CAA0C;YAC1D,cAAc,GAAG,CAAC,QAAQ,IAAI,EAAE,2CAA2C,CAC9E,CAAC;IACJ,CAAC;IAED,OAAO;QACL,UAAU,EAAE,SAAS;QACrB,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,SAAS;QAC3C,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;QAC5B,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE;QAClC,WAAW,EAAE,IAAI;QACjB,cAAc,EAAE,GAAG,CAAC,WAAW,KAAK,IAAI;QACxC,MAAM,EAAE;YACN,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC;YAC5C,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC;SAC9C;QACD,aAAa,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;QACrE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QACnD,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;KACnE,CAAC;AACJ,CAAC;AAiBD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAA6B,EAC7B,OAAqB,WAAW;IAEhC,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAE7D,0EAA0E;IAC1E,wDAAwD;IACxD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,IAAI,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvC,KAAK,CAAC,IAAI,CACR,aAAa,GAAG,uEAAuE,CACxF,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,kBAAkB,GAAG,SAAS,IAAI,CAAC,UAAU,4BAA4B,CAAC,CAAC;YACxF,CAAC;QACH,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,0DAA0D;IAC1D,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM;SAClC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAC,CAAC;SAClD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACtB,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CACR,8BAA8B,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YAC1D,qEAAqE,CACxE,CAAC;IACJ,CAAC;IAED,2EAA2E;IAC3E,mCAAmC;IACnC,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,IAAI,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QACjD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,MAAM,QAAQ,GAAiB;QAC7B,GAAG,EAAE;YACH,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,MAAM;YACN,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,YAAY,EAAE;SACtC;KACF,CAAC;IAEF,yEAAyE;IACzE,4EAA4E;IAC5E,4EAA4E;IAC5E,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CACtC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAC3C,CAAC;QACF,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,QAAQ,CAAC,GAAG,CAAC,GAAG;gBACd,UAAU,EAAE,WAAW;gBACvB,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,eAAe,EAAE,SAAS,EAAE;gBAC/D,KAAK,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE;aAC/B,CAAC;YACF,KAAK,CAAC,IAAI,CACR,0EAA0E;gBACxE,4BAA4B,CAC/B,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CACR,IAAI,IAAI,CAAC,UAAU,yDAAyD;gBAC1E,4EAA4E;gBAC5E,iDAAiD,CACpD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,4EAA4E;IAC5E,sEAAsE;IACtE,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,SAAS,CAAC,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC;QACjD,KAAK,CAAC,IAAI,CACR,uEAAuE,CACxE,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CACR,8EAA8E;YAC5E,uFAAuF,CAC1F,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE;QAC1C,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;KACtE,CAAC,CAAC;IAEH,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,QAAQ;QACR,KAAK;KACN,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface CivitaiResolved {
|
|
2
|
+
/**
|
|
3
|
+
* Direct download URL. No credentials are embedded — `downloadModel` attaches
|
|
4
|
+
* the CivitAI token as an `Authorization` request header, so the token never
|
|
5
|
+
* leaks into logs, error messages, or redirect URLs.
|
|
6
|
+
*/
|
|
7
|
+
downloadUrl: string;
|
|
8
|
+
/** Suggested filename from CivitAI metadata, when available. */
|
|
9
|
+
filename?: string;
|
|
10
|
+
/** Resolved model-version id. */
|
|
11
|
+
versionId: number;
|
|
12
|
+
/** Model name, when resolvable. */
|
|
13
|
+
modelName?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a CivitAI model-version id directly to a download URL.
|
|
17
|
+
* Uses GET /api/v1/model-versions/{id}.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveCivitaiModelVersion(versionId: number): Promise<CivitaiResolved>;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a CivitAI model id to a download URL.
|
|
22
|
+
* Uses GET /api/v1/models/{id} and picks a model version.
|
|
23
|
+
* If `versionId` is supplied, that specific version is used; otherwise the
|
|
24
|
+
* latest (first listed) version is chosen.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveCivitaiModel(modelId: number, versionId?: number): Promise<CivitaiResolved>;
|
|
27
|
+
//# sourceMappingURL=civitai-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"civitai-resolver.d.ts","sourceRoot":"","sources":["../../src/services/civitai-resolver.ts"],"names":[],"mappings":"AA+BA,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwDD;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CAK1B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAyB1B"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { config } from "../config.js";
|
|
2
|
+
import { ModelError, ValidationError } from "../utils/errors.js";
|
|
3
|
+
import { logger } from "../utils/logger.js";
|
|
4
|
+
const CIVITAI_API_BASE = "https://civitai.com/api/v1";
|
|
5
|
+
function authHeaders() {
|
|
6
|
+
const headers = {};
|
|
7
|
+
if (config.civitaiApiToken) {
|
|
8
|
+
headers["Authorization"] = `Bearer ${config.civitaiApiToken}`;
|
|
9
|
+
}
|
|
10
|
+
return headers;
|
|
11
|
+
}
|
|
12
|
+
async function civitaiGet(path) {
|
|
13
|
+
const url = `${CIVITAI_API_BASE}${path}`;
|
|
14
|
+
logger.debug("CivitAI API request", { url });
|
|
15
|
+
const res = await fetch(url, { headers: authHeaders() });
|
|
16
|
+
if (res.status === 404) {
|
|
17
|
+
throw new ModelError(`CivitAI resource not found: ${path}`, {
|
|
18
|
+
url,
|
|
19
|
+
status: 404,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
const body = await res.text().catch(() => "");
|
|
24
|
+
throw new ModelError(`CivitAI API ${res.status}: ${res.statusText}`, {
|
|
25
|
+
url,
|
|
26
|
+
status: res.status,
|
|
27
|
+
body,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return (await res.json());
|
|
31
|
+
}
|
|
32
|
+
/** Pick the best file from a version's file list: primary first, else the first. */
|
|
33
|
+
function pickFile(version) {
|
|
34
|
+
const files = version.files ?? [];
|
|
35
|
+
return files.find((f) => f.primary) ?? files[0];
|
|
36
|
+
}
|
|
37
|
+
function resolveFromVersion(version, modelName) {
|
|
38
|
+
const file = pickFile(version);
|
|
39
|
+
const downloadUrl = file?.downloadUrl ??
|
|
40
|
+
version.downloadUrl ??
|
|
41
|
+
`https://civitai.com/api/download/models/${version.id}`;
|
|
42
|
+
return {
|
|
43
|
+
downloadUrl,
|
|
44
|
+
filename: file?.name,
|
|
45
|
+
versionId: version.id,
|
|
46
|
+
modelName,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a CivitAI model-version id directly to a download URL.
|
|
51
|
+
* Uses GET /api/v1/model-versions/{id}.
|
|
52
|
+
*/
|
|
53
|
+
export async function resolveCivitaiModelVersion(versionId) {
|
|
54
|
+
const version = await civitaiGet(`/model-versions/${versionId}`);
|
|
55
|
+
return resolveFromVersion(version);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve a CivitAI model id to a download URL.
|
|
59
|
+
* Uses GET /api/v1/models/{id} and picks a model version.
|
|
60
|
+
* If `versionId` is supplied, that specific version is used; otherwise the
|
|
61
|
+
* latest (first listed) version is chosen.
|
|
62
|
+
*/
|
|
63
|
+
export async function resolveCivitaiModel(modelId, versionId) {
|
|
64
|
+
const model = await civitaiGet(`/models/${modelId}`);
|
|
65
|
+
const versions = model.modelVersions ?? [];
|
|
66
|
+
if (versions.length === 0) {
|
|
67
|
+
throw new ModelError(`CivitAI model ${modelId} has no downloadable versions.`, { modelId });
|
|
68
|
+
}
|
|
69
|
+
let version;
|
|
70
|
+
if (versionId !== undefined) {
|
|
71
|
+
version = versions.find((v) => v.id === versionId);
|
|
72
|
+
if (!version) {
|
|
73
|
+
throw new ValidationError(`Model ${modelId} has no version with id ${versionId}. ` +
|
|
74
|
+
`Available versions: ${versions.map((v) => v.id).join(", ")}.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
version = versions[0];
|
|
79
|
+
}
|
|
80
|
+
return resolveFromVersion(version, model.name);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=civitai-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"civitai-resolver.js","sourceRoot":"","sources":["../../src/services/civitai-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export declare const COMFYUI_REPO_URL = "https://github.com/comfyanonymous/ComfyUI";
|
|
2
|
+
export declare const COMFYUI_MANAGER_REPO_URL = "https://github.com/Comfy-Org/ComfyUI-Manager";
|
|
3
|
+
/** Sub-path under the ComfyUI clone where the Manager lives (clone fallback). */
|
|
4
|
+
export declare const MANAGER_SUBDIR: string;
|
|
5
|
+
export interface InstallComfyUIOptions {
|
|
6
|
+
/** Target workspace directory to install ComfyUI into. */
|
|
7
|
+
targetPath: string;
|
|
8
|
+
/** Skip cloning ComfyUI-Manager. Default false (Manager is installed). */
|
|
9
|
+
skipManager?: boolean;
|
|
10
|
+
/** Prefer `uv pip` over plain `pip` when uv is available. Default false. */
|
|
11
|
+
useUv?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* ComfyUI git ref to check out (tag, branch, or commit). When omitted the
|
|
14
|
+
* default branch HEAD is used.
|
|
15
|
+
*/
|
|
16
|
+
version?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface StepResult {
|
|
19
|
+
step: string;
|
|
20
|
+
command: string;
|
|
21
|
+
ok: boolean;
|
|
22
|
+
output?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface InstallComfyUIResult {
|
|
25
|
+
installed: boolean;
|
|
26
|
+
targetPath: string;
|
|
27
|
+
/** Path to the workspace virtualenv python that deps were installed into. */
|
|
28
|
+
venvPath: string;
|
|
29
|
+
comfyuiUrl: string;
|
|
30
|
+
managerUrl: string | null;
|
|
31
|
+
managerInstalled: boolean;
|
|
32
|
+
/** How the Manager was installed: pip "requirements", "git-clone", or null. */
|
|
33
|
+
managerVia: "requirements" | "git-clone" | null;
|
|
34
|
+
version: string | null;
|
|
35
|
+
pythonInstaller: "uv" | "pip";
|
|
36
|
+
steps: StepResult[];
|
|
37
|
+
message: string;
|
|
38
|
+
}
|
|
39
|
+
export interface InstallDeps {
|
|
40
|
+
/** Run a command, throwing on non-zero exit. Returns combined stdout. */
|
|
41
|
+
run: (cmd: string, args: string[], cwd?: string) => string;
|
|
42
|
+
/** Detect whether a CLI tool is on PATH. */
|
|
43
|
+
hasCommand: (cmd: string) => boolean;
|
|
44
|
+
existsSync: (p: string) => boolean;
|
|
45
|
+
/** True if the path exists AND contains at least one entry. */
|
|
46
|
+
isNonEmptyDir: (p: string) => boolean;
|
|
47
|
+
mkdirp: (p: string) => void;
|
|
48
|
+
}
|
|
49
|
+
/** Build the `git clone` argv (without the leading `git`). */
|
|
50
|
+
export declare function buildCloneArgs(url: string, dest: string, version?: string): string[];
|
|
51
|
+
/** Path to the workspace venv's python interpreter. */
|
|
52
|
+
export declare function venvPythonPath(targetPath: string): string;
|
|
53
|
+
/** Build the argv that creates the workspace venv (`<target>/.venv`). */
|
|
54
|
+
export declare function buildVenvArgs(installer: "uv" | "pip", targetPath: string): {
|
|
55
|
+
cmd: string;
|
|
56
|
+
args: string[];
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Build the pip/uv install argv for a requirements file, ALWAYS targeting the
|
|
60
|
+
* workspace venv's interpreter (`venvPython`) — never the Python running this
|
|
61
|
+
* MCP server. uv targets the venv explicitly via `--python`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function buildPipInstallArgs(installer: "uv" | "pip", venvPython: string, requirementsFile: string): {
|
|
64
|
+
cmd: string;
|
|
65
|
+
args: string[];
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Validate the requested ComfyUI version, mirroring comfy-cli's
|
|
69
|
+
* `validate_version`: only "nightly", "latest", or a full semantic version
|
|
70
|
+
* (optionally v-prefixed). Raw git refs / branch names are rejected.
|
|
71
|
+
*/
|
|
72
|
+
export declare function validateVersion(version: string): {
|
|
73
|
+
kind: "nightly";
|
|
74
|
+
} | {
|
|
75
|
+
kind: "latest";
|
|
76
|
+
} | {
|
|
77
|
+
kind: "semver";
|
|
78
|
+
tag: string;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Mirrors `comfy-cli install`: clones ComfyUI (and optionally ComfyUI-Manager)
|
|
82
|
+
* into a target workspace, then installs Python requirements via pip or uv.
|
|
83
|
+
*
|
|
84
|
+
* This is a LOCAL, subprocess-only operation. It never touches a remote
|
|
85
|
+
* ComfyUI server and ignores `config.comfyuiPath` in favour of the explicit
|
|
86
|
+
* `targetPath`.
|
|
87
|
+
*/
|
|
88
|
+
export declare function installComfyUI(options: InstallComfyUIOptions, deps?: InstallDeps): InstallComfyUIResult;
|
|
89
|
+
//# sourceMappingURL=install-comfyui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-comfyui.d.ts","sourceRoot":"","sources":["../../src/services/install-comfyui.ts"],"names":[],"mappings":"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"}
|