dsh-comfyui 0.5.0 → 0.5.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.
- package/client/client.js +4 -0
- package/client/client.js.map +1 -1
- package/lib/analyze.d.ts +3 -1
- package/lib/analyze.js +2 -1
- package/lib/convert.d.ts +0 -9
- package/lib/convert.js +15 -7
- package/lib/graph.d.ts +15 -0
- package/lib/graph.js +48 -0
- package/lib/index.js +9 -2
- package/package.json +1 -1
package/lib/analyze.d.ts
CHANGED
|
@@ -20,7 +20,9 @@ export interface GraphGroupLike {
|
|
|
20
20
|
}
|
|
21
21
|
export interface GraphLike {
|
|
22
22
|
nodes: GraphNodeLike[];
|
|
23
|
-
|
|
23
|
+
/** Saved rows are positional or object entries depending on the frontend
|
|
24
|
+
* version — always consumed through {@link normalizeLinks}. */
|
|
25
|
+
links: unknown[];
|
|
24
26
|
groups?: GraphGroupLike[];
|
|
25
27
|
}
|
|
26
28
|
export interface IsolatedNode {
|
package/lib/analyze.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* graph links (with bypassed and dangling nodes excluded). The analysis feeds
|
|
6
6
|
* the extract (拆分) choices in the panel and the agent-facing skill.
|
|
7
7
|
*/
|
|
8
|
+
import { normalizeLinks } from './graph.js';
|
|
8
9
|
function isObject(value) {
|
|
9
10
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
10
11
|
}
|
|
@@ -27,7 +28,7 @@ export function analyzeGraph(graph) {
|
|
|
27
28
|
return { ok: false, error: '无法解析图文件(缺少 nodes/links)' };
|
|
28
29
|
}
|
|
29
30
|
const nodes = graph.nodes;
|
|
30
|
-
const links = graph.links;
|
|
31
|
+
const links = normalizeLinks(graph.links);
|
|
31
32
|
const groups = Array.isArray(graph.groups) ? graph.groups : [];
|
|
32
33
|
const active = nodes.filter((node) => node.mode !== 4);
|
|
33
34
|
const activeById = new Map(active.map((node) => [node.id, node]));
|
package/lib/convert.d.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Convert a ComfyUI UI-graph workflow (the format the ComfyUI frontend saves
|
|
3
|
-
* to the server via /api/userdata) into the API format accepted by POST
|
|
4
|
-
* /prompt. Modeled on the frontend's convertToApiFormat: input links become
|
|
5
|
-
* [nodeId, slot] references, widgets_values are zipped onto input names in
|
|
6
|
-
* object_info order (control_after_generate is the extra seed widget), and
|
|
7
|
-
* Reroute / bypassed (mode 4) nodes are skipped with their links rewired.
|
|
8
|
-
* Nodes the conversion cannot represent fail loudly with the offending type.
|
|
9
|
-
*/
|
|
10
1
|
export interface ApiWorkflow {
|
|
11
2
|
[nodeId: string]: {
|
|
12
3
|
class_type: string;
|
package/lib/convert.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a ComfyUI UI-graph workflow (the format the ComfyUI frontend saves
|
|
3
|
+
* to the server via /api/userdata) into the API format accepted by POST
|
|
4
|
+
* /prompt. Modeled on the frontend's convertToApiFormat: input links become
|
|
5
|
+
* [nodeId, slot] references, widgets_values are zipped onto input names in
|
|
6
|
+
* object_info order (control_after_generate is the extra seed widget), and
|
|
7
|
+
* Reroute / bypassed (mode 4) nodes are skipped with their links rewired.
|
|
8
|
+
* Nodes the conversion cannot represent fail loudly with the offending type.
|
|
9
|
+
*/
|
|
10
|
+
import { normalizeLinks } from './graph.js';
|
|
1
11
|
/** Node types that exist only in the UI and carry no data flow. */
|
|
2
12
|
const UI_ONLY = new Set(['Note', 'StickyNote', 'Reroute', 'Fast Groups Bypasser (rgthree)']);
|
|
3
13
|
function isObject(value) {
|
|
@@ -195,13 +205,11 @@ export function convertGraphToApi(graph, objectInfo, options) {
|
|
|
195
205
|
};
|
|
196
206
|
});
|
|
197
207
|
const links = new Map();
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
links.set(link[0], link);
|
|
204
|
-
}
|
|
208
|
+
// normalizeLinks accepts both the legacy positional rows and the v0.4
|
|
209
|
+
// frontend's object entries; anything unreadable is skipped, exactly like
|
|
210
|
+
// the old array-only guard did.
|
|
211
|
+
for (const link of normalizeLinks(rawLinks))
|
|
212
|
+
links.set(link[0], link);
|
|
205
213
|
const nodesById = new Map(nodes.map((node) => [node.id, node]));
|
|
206
214
|
const included = options?.includeNodeIds;
|
|
207
215
|
const candidates = included !== undefined ? nodes.filter((node) => included.has(node.id)) : nodes;
|
package/lib/graph.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ComfyUI UI-graph link normalization. The frontend changed how saved graphs
|
|
3
|
+
* serialize the `links` array: rows used to be positional
|
|
4
|
+
* (`[id, originId, originSlot, targetId, targetSlot, type]`), while the v0.4
|
|
5
|
+
* frontend writes object entries
|
|
6
|
+
* (`{ id, origin_id, origin_slot, target_id, target_slot, type }`). Analysis
|
|
7
|
+
* and conversion both want one canonical shape, so both go through
|
|
8
|
+
* {@link normalizeLinks} before touching a graph.
|
|
9
|
+
*/
|
|
10
|
+
/** Canonical link row: [linkId, originId, originSlot, targetId, targetSlot, type]. */
|
|
11
|
+
export type GraphLink = [number, number, number, number, number, string];
|
|
12
|
+
/** Normalize one link entry; undefined when the entry is not a readable link. */
|
|
13
|
+
export declare function normalizeLink(raw: unknown): GraphLink | undefined;
|
|
14
|
+
/** Normalize a whole `links` array, skipping entries that are not readable. */
|
|
15
|
+
export declare function normalizeLinks(raw: unknown): GraphLink[];
|
package/lib/graph.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ComfyUI UI-graph link normalization. The frontend changed how saved graphs
|
|
3
|
+
* serialize the `links` array: rows used to be positional
|
|
4
|
+
* (`[id, originId, originSlot, targetId, targetSlot, type]`), while the v0.4
|
|
5
|
+
* frontend writes object entries
|
|
6
|
+
* (`{ id, origin_id, origin_slot, target_id, target_slot, type }`). Analysis
|
|
7
|
+
* and conversion both want one canonical shape, so both go through
|
|
8
|
+
* {@link normalizeLinks} before touching a graph.
|
|
9
|
+
*/
|
|
10
|
+
function isObject(value) {
|
|
11
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
/** Normalize one link entry; undefined when the entry is not a readable link. */
|
|
14
|
+
export function normalizeLink(raw) {
|
|
15
|
+
if (Array.isArray(raw)) {
|
|
16
|
+
if (raw.length < 6)
|
|
17
|
+
return undefined;
|
|
18
|
+
const [id, origin, originSlot, target, targetSlot, type] = raw;
|
|
19
|
+
if (typeof id !== 'number' || typeof origin !== 'number' ||
|
|
20
|
+
typeof originSlot !== 'number' || typeof target !== 'number' ||
|
|
21
|
+
typeof targetSlot !== 'number') {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return [id, origin, originSlot, target, targetSlot, typeof type === 'string' ? type : ''];
|
|
25
|
+
}
|
|
26
|
+
if (isObject(raw)) {
|
|
27
|
+
const { id, origin_id: origin, origin_slot: originSlot, target_id: target, target_slot: targetSlot, type } = raw;
|
|
28
|
+
if (typeof id !== 'number' || typeof origin !== 'number' ||
|
|
29
|
+
typeof originSlot !== 'number' || typeof target !== 'number' ||
|
|
30
|
+
typeof targetSlot !== 'number') {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return [id, origin, originSlot, target, targetSlot, typeof type === 'string' ? type : ''];
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
/** Normalize a whole `links` array, skipping entries that are not readable. */
|
|
38
|
+
export function normalizeLinks(raw) {
|
|
39
|
+
if (!Array.isArray(raw))
|
|
40
|
+
return [];
|
|
41
|
+
const links = [];
|
|
42
|
+
for (const entry of raw) {
|
|
43
|
+
const link = normalizeLink(entry);
|
|
44
|
+
if (link !== undefined)
|
|
45
|
+
links.push(link);
|
|
46
|
+
}
|
|
47
|
+
return links;
|
|
48
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -217,7 +217,9 @@ export async function apply(ctx, entryConfig) {
|
|
|
217
217
|
const entries = await client.listUserData('workflows');
|
|
218
218
|
const library = await store.listWorkflows();
|
|
219
219
|
return entries
|
|
220
|
-
|
|
220
|
+
// Dot entries are ComfyUI bookkeeping (e.g. `.index.json`), not graphs.
|
|
221
|
+
.filter((entry) => entry.type === 'file' && entry.name.endsWith('.json')
|
|
222
|
+
&& entry.name.split(/[\\/]/).every((segment) => !segment.startsWith('.')))
|
|
221
223
|
.map((entry) => {
|
|
222
224
|
const derived = library.filter((workflow) => workflow.comfyuiFile === entry.name);
|
|
223
225
|
return {
|
|
@@ -319,7 +321,12 @@ export async function apply(ctx, entryConfig) {
|
|
|
319
321
|
// service simply never registers it, and the entry config stands as composed.
|
|
320
322
|
let source = () => resolved;
|
|
321
323
|
ctx.inject(['settings'], (settingsCtx) => {
|
|
322
|
-
settingsCtx.settings
|
|
324
|
+
const settings = settingsCtx.settings;
|
|
325
|
+
if (typeof settings.installSection !== 'function') {
|
|
326
|
+
ctx.logger.warn('comfyui: settings service lacks installSection — settings page stays read-only, entry config stands');
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
settings.installSection(ctx, COMFYUI_NS, Config, resolved, {
|
|
323
330
|
setSource: (current) => {
|
|
324
331
|
source = current;
|
|
325
332
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-comfyui",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Let the DeepSeek Harness agent smartly drive a local or remote ComfyUI to generate anything, with workflow and asset management panels, per-workflow skill packs, a companion skill and a same-origin media proxy. / 让 DeepSeek Harness 的 Agent 智能驱动本地或远程 ComfyUI 生成任何内容。附带工作流、资产管理面板与技能包管理挂载。配套 skill 与同源媒体代理。",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|