dsh-comfyui-canvas 0.1.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.
@@ -0,0 +1,307 @@
1
+ # dsh-comfyui-canvas — v0.1.2 开发规划(完整方案)
2
+
3
+ > **本文档是 v0.1.2 的完整方案**:方向 + 细化设计(含画布会话框上传通道 A3、专属管理技能 B3)已合一,不写代码。实现时新开会话,先读本文件 + `docs/architecture.html` + `docs/architecture-flow.html` + `NEXT-VERSION-PLAN.md`(v0.1.1 记录,含架构边界与坑)。
4
+ > 最后更新:2026-09-02(已并入原独立的上传通道细化文档,本文档为唯一方案)
5
+
6
+ ---
7
+
8
+ ## 0. 一句话目标
9
+
10
+ 把「对话 ↔ 画布」的文件传输从**「仅图片」**扩展为**「通用文件」**(图像 / 音频 / 视频 / 3D),并上线**专属技能包(skill)**,让 agent 能完整驱动「生成 → 传输 → 音画合成 → 取回」的创作链路。**播放能力不做**——那是 DSH 生态的事。
11
+
12
+ ## 1. 定位与边界(先写死,避免跑偏)
13
+
14
+ ### 1.1 本插件做什么 / 不做什么
15
+
16
+ | 能力 | 本插件 | 归属 |
17
+ |---|---|---|
18
+ | **传输**(对话 ↔ 画布的文件上传 / 读取 / 取回) | ✅ **核心** | 本插件 |
19
+ | **播放**(视频/音频在对话里播放) | ❌ 不做 | DSH 生态 / 其他插件 |
20
+ | ComfyUI 节点 / 生成逻辑 | ❌ 不改 | ComfyUI 生态(已成熟) |
21
+ | TTS 生成音频 | ⚠️ 仅作为「文件传输的一类输入」 | 走通用文件传输,不专门做 |
22
+
23
+ ### 1.2 为什么不做播放 / 不加节点(决策依据)
24
+
25
+ - **播放**:DSH 核心附件系统只支持图片(png/jpeg/webp/gif),视频/音频/3D 无附件类型;播放应等 DSH 生态或第三方插件,本插件硬做只会重复造轮子。
26
+ - **节点 / 生成逻辑**:ComfyUI **原生已支持音频、视频、3D 的加载**(LoadAudio / LoadVideo / 3D 网格加载等节点),音画合成生态也已成熟(Wan2.5/Kling 2.6/LTX-2 音画同步、`VideoAddAudio`、Index-TTS/ChatterBox 等 TTS 节点)——自研节点反而让工作流更复杂、用户要学新东西。
27
+ - **TTS 的真实定位**:是「做视频时的音频/配音文件」(配旁白、音轨),本质是**传输的一类文件**,不是独立播放能力。
28
+
29
+ ### 1.3 版本衔接
30
+
31
+ - v0.1.1 已完成:`comfyui_attach_image`(图片进画布)+ `comfyui_inject_text`(文本注入)+ 启动/预览 bug 修复。
32
+ - v0.1.2 是在此之上的**传输泛化 + 技能包**,不推翻 v0.1.1 的任何接口。
33
+
34
+ ---
35
+
36
+ ## 2. 核心交付
37
+
38
+ ### A. 通用文件传输(传输能力扩展,必做)
39
+
40
+ 现状:`comfyui_attach_image` 只接受图片;`comfyui_get_outputs` 只回图片预览。
41
+
42
+ 目标:**上传 / 取回都支持 图像、音频、视频、3D 等通用文件。**
43
+
44
+ #### A1. 新增 `comfyui_attach_file`(或扩展 `attach_image`)
45
+ - **职责**:把 agent 本机任意文件上传进 ComfyUI 的 `input/` 目录(沿用 ComfyUI 原生上传端点,host 端、不经过 bridge)
46
+ - **支持类型**:`image/*`(png/jpeg/webp/gif)、`audio/*`(wav/mp3/ogg)、`video/*`(mp4/webm/mov)、`3D`(glb/gltf/obj/fbx/stl)
47
+ - **接口草案**:
48
+ ```js
49
+ comfyui_attach_file({
50
+ path: string // 本机文件绝对路径(必填)
51
+ nodeId?: number // 可选:上传后 set_param 指向对应 LoadAudio/LoadVideo/LoadImage/GLB 节点
52
+ mediaType?:string // 可选:显式指定类型;缺省按扩展名推断
53
+ })
54
+ // 返回 { filename, subfolder, mediaType, nodeId?, updated? }
55
+ ```
56
+ - **兼容**:保留 `comfyui_attach_image` 作为图片快捷别名(或标记 deprecated 由通用入口替代,二选一,实现时定)
57
+ - **验收**:对话里一个 mp4/wav/glb → `attach_file` → ComfyUI input/ 出现该文件 → 对应 Load 节点可选到它
58
+
59
+ #### A2. `comfyui_get_outputs` 泛化:结果携带文件路径/URL
60
+ - **现状**:返回图片预览(/view 直连)
61
+ - **扩展**:每条结果附加 `fileUrl` / `localPath`(若 ComfyUI 本机可及)——视频 mp4、音频 wav、3D glb 都能以「文件路径/URL」形式交回对话
62
+ - **语义**:DSH 不播放,但 agent 和用户能**拿到文件地址去打开/二次使用**
63
+ - **验收**:跑一个含视频/音频/3D 输出的工作流 → `get_outputs` 返回对应文件的 URL/路径
64
+
65
+ #### A3. 画布会话框上传通道(client 侧,与 A1 配套)
66
+
67
+ 现状:画布右侧 rail composer 只有「+ 图片」入口(`injectRailComposerPlus`),`accept` 仅图片、走 DSH 官方附件通道(`addDraftImages`)——音频/视频/3D 进不去。
68
+
69
+ 目标:**新增「+ 文件」通用入口**,两类通道并行、语义分家:
70
+
71
+ | 通道 | 类型 | 走向 | 反馈 |
72
+ |---|---|---|---|
73
+ | 图片(已有) | image/* | DSH 附件(agent 能看) | 现有附件预览 |
74
+ | 文件(新增) | audio/video/3D | host `attach_file` → ComfyUI `input/`(供 Load 节点) | 对话内提示 |
75
+
76
+ **交互形态(D 混合)**:图片「+」号不动;新增「+ 文件」按钮(样式对齐 28px 圆角虚线框),支持多选、逐个上传、失败不阻塞其余。
77
+
78
+ **类型路由**:`image/*` → 图片通道;wav/mp3/ogg/flac/m4a → 音频;mp4/webm/mov/mkv → 视频;glb/gltf/obj/fbx/stl → 3D;其余 → 一律进 `input/` 透传。
79
+
80
+ **上传流程**:
81
+ ```
82
+ 「+ 文件」→ 文件选择器(多选)
83
+ → 按扩展名推断 mediaType(路由表)
84
+ → 调 host comfyui_attach_file({ path, mediaType? }) ← host 直连原生上传
85
+ → 返回 { filename, subfolder, mediaType }
86
+ → 对话追加提示:✅ 已上传 <filename> → input/ 或 ❌ 失败 <原因>
87
+ ```
88
+
89
+ **反馈设计**:用对话消息做载体(留痕、可回看、衔接后续操作),不悬浮 toast。
90
+
91
+ **涉及文件**:`lib/client.js`(「+ 文件」入口 + 选择器 + 上传调用 + 提示)、`lib/index.js`(`attach_file`,即 A1)、README 中英、三副本同步。
92
+
93
+ **开放问题(实现时决策)**:
94
+ 1. 本地文件路径传递:浏览器文件选择器能否拿到 host 可读的绝对路径?(客户端 → host 传参通道需确认;拿不到则改 host 自行读取或走其他入口)——**硬前置,先探**
95
+ 2. 自动建 Load 节点:上传成功后是否自动 `add_node(LoadAudio/LoadVideo/3D)` 指向新文件?默认不做,可作下版增值
96
+ 3. 图片也可走文件通道(绕过 DSH 附件直接进 `input/`)?默认不放行
97
+ 4. 取回方向(3D/视频取回路径):随 A2 `get_outputs` 泛化一并考虑
98
+
99
+ ### B. 专属技能包(skill,必做)
100
+
101
+ 技能矩阵(三个,全部可随插件分发):
102
+
103
+ | 技能 | 作用域 | 必做/可选 |
104
+ |---|---|---|
105
+ | `comfyui-canvas-ops` | 画布操作 SOP(读/改/跑/取图/自检) | 必做 |
106
+ | `comfyui-video-audio-ops` | 音画创作 SOP(视频+配音/音轨) | 可选 |
107
+ | `comfyui-admin-ops` | ComfyUI 环境管理 SOP(配置/启动/更新/节点管理) | 必做 |
108
+
109
+ > 术语:ComfyUI 生态里的「**节点**」(node / custom node / node pack)即第三方自定义插件,位于 `custom_nodes/` 下;「本插件」指 DSH 侧的 `dsh-comfyui-canvas`。两者不要混称。
110
+
111
+ #### B1. 核心技能 `comfyui-canvas-ops`(画布操作 SOP)
112
+ - **目标**:agent 遇到「用画布作图/改工作流/出图」时,自动按正确顺序驱动工具
113
+ - **流程**(草案):
114
+ ```
115
+ 1. comfyui_config —— 确认画布在前台、连接正常
116
+ 2. comfyui_read_workflow —— 读当前图,向用户复述并确认关键节点
117
+ 3. comfyui_set_param / comfyui_connect / comfyui_add_node —— 按需修改
118
+ 4. comfyui_run 运行 → comfyui_get_outputs 取回出图
119
+ 5. vision_describe 自检出图 → 不达标迭代;达标交付
120
+ ```
121
+ - **注意**:读取永远只读、写操作先确认、运行前讲清改了哪些
122
+
123
+ #### B2. 可选进阶技能 `comfyui-video-audio-ops`(音画创作 SOP)
124
+ - **目标**:agent 做「视频 + 配音/音轨」时知道怎么驱动现有 ComfyUI 节点链路
125
+ - **流程**(草案):
126
+ ```
127
+ 1. 生成视频(读图/跑视频节点,如 Wan/Kling/LTX)
128
+ 2. 生成音频:TTS/音频文件 → comfyui_attach_file 上传为音轨输入
129
+ 3. 走音画合成(VideoAddAudio 或对应工作流)→ comfyui_run
130
+ 4. comfyui_get_outputs 取回含音轨的视频文件路径/URL
131
+ ```
132
+
133
+ #### B3. 新增技能 `comfyui-admin-ops`(ComfyUI 环境管理 SOP,必做)
134
+ - **目标**:agent 遇到「配置 / 启动 / 更新 ComfyUI、管理已装节点」时,知道怎么安全地驱动现有工具维护环境
135
+ - **覆盖**(运维职责;「开发调试」已升级为核心功能 C,见 §2C):
136
+ ```
137
+ 1. 配置管理 —— comfyui_config 读/改连接(baseUrl/port/networkMode/桥接 token/启动命令/rail 宽度)
138
+ 2. 启动 / 状态 —— 用 launchCommand 启动 ComfyUI,轮询 /system_stats 确认在线;launchError 读失败原因
139
+ 3. 更新 —— comfyui_upgrade:git pull 核心 + 全部节点(区分核心/节点,失败不中断)
140
+ 4. 节点管理 —— 列出已装 custom_nodes、识别 git 托管与手工目录、按需安装/更新节点
141
+ ```
142
+ - **安全注意**:更新/重启/装节点是重操作——先确认、讲清影响(如「更新 60+ 节点」「重启中断生成」);更新前看是否有运行中任务
143
+ - **边界**:本技能管「维护/操作」现有生态,**不新增生成节点、不改生成逻辑**——与 §1 决策一致
144
+
145
+ #### B4. 挂法(二选一,实现时定,推荐 A)
146
+ - **A. 源码内嵌**:插件 `inject` 加 `skills`,`ctx.skills.register(...)` 注册 runtime skill —— **随插件分发、用户零步骤**
147
+ - **B. 文件版**:包内 `.agents/skills/<name>/SKILL.md`,靠 skill-filesystem 扫描 —— 用户可见可改
148
+
149
+ ### C. 核心功能:画布内开发调试 ComfyUI 节点(升级自 B3 的「开发调试」,必做)
150
+
151
+ > 这是本插件区别于其他 DSH 插件的**独特价值**:画布正好是节点调试的观察窗——边看画布边改节点源码,全程在对话 + 画布内完成。
152
+
153
+ #### C1. 一组新工具(开发闭环)
154
+ | 新工具 | 职责 | 对应环节 |
155
+ |---|---|---|
156
+ | `comfyui_read_source` | 读某个节点包源码(`custom_nodes/<name>/` 目录树或单文件,含 `__init__.py`、前端 js) | 看代码 |
157
+ | `comfyui_edit_source` | 改节点源码(受控写文件) | 改代码 |
158
+ | `comfyui_reload` | 重启 ComfyUI 让改动生效(区分完整重启 / 是否可热重载) | 应用改动 |
159
+ | (复用现有)`comfyui_run` / `comfyui_debug` | 在画布上跑 / 校验节点 | 验证 |
160
+
161
+ **核心闭环**:`read_source` → `edit_source` → `reload` → 画布 `run` → `get_outputs` → 看效果 → 迭代
162
+
163
+ #### C2. 专属技能 `comfyui-dev-ops`(节点开发调试 SOP,必做)
164
+ - **流程**(草案):
165
+ ```
166
+ 1. comfyui_read_source 读目标节点(确认结构:__init__.py 注册、前端 js、依赖)
167
+ 2. comfyui_edit_source 修改(Python 节点逻辑 or 前端)
168
+ 3. comfyui_reload 重启 ComfyUI(讲清会中断生成;确认无运行中任务)
169
+ 4. 画布 comfyui_run 跑一个用该节点的最小工作流验证
170
+ 5. comfyui_get_outputs 看结果 → 不达标回 step 2 迭代
171
+ ```
172
+ - **安全注意**:改的是 `custom_nodes/` 下的节点源码(本机文件)——写操作先确认、讲清改哪个文件;重启前检查是否有运行中任务
173
+ - **边界**:开发调试「已有/正在开发的」节点,**不新增生成节点、不改生成逻辑**——与 §1 决策一致
174
+
175
+ #### C3. 与 admin / canvas 技能的关系
176
+ - `comfyui-admin-ops` = 运维(配置/启动/升级/节点管理),**不含开发调试**
177
+ - `comfyui-dev-ops` = 开发调试(读/改/重启/验证),独立成核心功能
178
+ - `comfyui-canvas-ops` = 用画布干活(作图/出图),供 dev 技能复用其 `run` 验证环节
179
+
180
+ ---
181
+
182
+ ## 3. 架构边界原则(沿用 v0.1.1,不跨层)
183
+
184
+ | 操作 | 归属 | 执行路径 |
185
+ |---|---|---|
186
+ | 文件传输(本机文件 ↔ ComfyUI input/) | **host** | 直连 ComfyUI 原生上传/读端点,不经过 bridge |
187
+ | 画布节点操作(增删连改/运行) | **host + bridge** | `/dsh-bridge/command` → 前端 LiteGraph |
188
+ | 读取执行结果 / 产物 | **host** | 直连 `/history/:id` + `/view` |
189
+ | 技能包(SOP 编排) | **host** | `ctx.skills.register` 或 skill-filesystem |
190
+ | 节点源码读写 / 重启 ComfyUI(开发调试 C) | **host** | 直连 `custom_nodes/`(fs)+ shell 重启,不经过 bridge |
191
+
192
+ > 一句话:**「本机文件 ↔ ComfyUI 文件」走 host + 原生 API;「动画布 / LiteGraph」走 bridge command;「读结果」走原生 API;「教 agent 怎么串」走 skill。** 不要跨层。
193
+
194
+ ---
195
+
196
+ ## 4. 实施步骤(实现时照此执行)
197
+
198
+ ```text
199
+ step 1 读本规划 + 两张架构图 + NEXT-VERSION-PLAN.md → npm run check 确认基线
200
+ step 2 通用文件传输 A1:comfyui_attach_file(host lib/index.js)
201
+ - 泛化上传:按扩展名推断 mediaType,走原生上传端点
202
+ - 决策:attach_image 保留为别名 or deprecated(实现时定)
203
+ step 3 A2:get_outputs 返回 fileUrl/localPath(不限图片)
204
+ step 4 A3:画布会话框「+ 文件」入口(client lib/client.js)
205
+ - 先探开放问题 #1(浏览器路径传递)——硬前置
206
+ - 新增按钮 + 文件选择器 + 上传调用 + 对话反馈提示
207
+ step 5 技能包 B:ctx.skills.register 内嵌(或 .agents/skills 文件版)
208
+ - 注册 comfyui-canvas-ops(必做)+ comfyui-admin-ops(必做)
209
+ - 可选 comfyui-video-audio-ops(音画创作)
210
+ step 5.5 DSH 核心改动处理(§5.5,先 C 后 A)
211
+ - 实现前调研 DSH navIcon 是否支持插件注册通道(决定 A 可行否)
212
+ - 可行 → 插件注册图标,还原核心两个文件,删 patches 备份
213
+ - 不可行 → 把补丁恢复步骤写进 README(方案 B)
214
+ step 6 核心功能 C:节点开发调试工具(host lib/index.js)
215
+ - comfyui_read_source(读 custom_nodes/<name>/ 源码)
216
+ - comfyui_edit_source(受控写文件)
217
+ - comfyui_reload(重启 ComfyUI)
218
+ - 注册 comfyui-dev-ops 技能(开发调试 SOP)
219
+ step 7 三处同步(源码 → node_modules 副本 → E 盘 custom_nodes,若涉及 bridge)
220
+ - node --check + python -m py_compile
221
+ step 8 真机验证(ComfyUI 运行中)
222
+ - attach_file:mp4/wav/glb 上传 → input/ 可见 → Load 节点可选到
223
+ - get_outputs:视频/音频/3D 工作流 → 返回 URL/路径
224
+ - 会话框「+ 文件」:多选上传 → 对话提示成功/失败
225
+ - 技能包:让 agent 跑一次画布作图,观察是否按 SOP 执行
226
+ - 开发调试:改一个节点(如 bridge)→ reload → 画布 run 验证
227
+ step 9 README(中/英):
228
+ - What you get 补「通用文件传输」+「技能包」+「节点开发调试」
229
+ - 工具计数更新(12 → 16/17,视 attach_image 去留)
230
+ step 10 npm run check → git commit → 三处同步
231
+ step 11 版本号 0.1.1 → 0.1.2(package.json 两副本同步)
232
+ step 12 发布(npm publish + awesome-dsh-plugin 收录信息若有变更)
233
+ ```
234
+
235
+ ---
236
+
237
+ ## 4.5 已完成事项(v0.1.2 前期,2026-09-02)
238
+
239
+ > 这些在方案定稿前已经落地并推送(`dfbba07` / `92474a0`),记录在此避免重复实施。
240
+
241
+ ### 市场素材已上线
242
+ - `docs/screenshots/` 三张演示图(01 启动提示 / 02 画布就绪 / 03 工作流出图)
243
+ - `screenshots.json`(package.json 旁,裸数组列相对路径)
244
+ - README 中英各嵌主图(`docs/screenshots/03-workflow-output.png`)
245
+ - `package.json` `files` 已含 `screenshots.json` + `docs`
246
+ - 已推送到 GitHub main(`7e3cd84..92474a0`)
247
+ - 待 awesome-dsh-plugin 聚合刷新后市场卡片显示截图(被动等待,无需操作)
248
+
249
+ ### 设置导航图标(核心改动 §5.5)已落地
250
+ - 见 §5.5 完整记录;核心已还原、非侵入式图标生效、已推送
251
+
252
+ ### npm publish(待办,见 §4 step 12)
253
+ - 包名 `dsh-comfyui-canvas` 在 npm **未被占用**(此前确认)
254
+ - `package.json` `files` 已覆盖 LICENSE/README/lib/comfyui-bridge/screenshots.json/docs
255
+ - 待执行:`npm config set registry https://registry.npmjs.org` → `npm publish`
256
+
257
+ ---
258
+
259
+ ## 5. 不做清单(明确排除,防范围蔓延)
260
+
261
+ - ❌ 视频/音频播放器、3D 查看器(DSH 生态的事)
262
+ - ❌ ComfyUI **新增生成节点** / 改生成逻辑(工作流保持原生)——注意:**开发调试已有节点**(核心功能 C)不算此列,C 只读写/重启已有节点,不新增生成能力
263
+ - ❌ DSH 核心附件系统扩展(不碰核心,只在插件层做文件传输)
264
+ - ❌ 独立 TTS 服务(音频只是通用文件传输的一类输入)
265
+
266
+ ---
267
+
268
+ ## 5.5 DSH 核心改动处理(必须收尾,v0.1.2 范围)
269
+
270
+ ### 现状与处理结果(2026-09-02 已完成)
271
+
272
+ 插件 v0.1.1 曾为给设置面板加 ComfyUI 导航图标,**侵入式改过 DSH 核心** `packages/client/ui-settings-general`(新增 `ComfyUIIcon.tsx` + 改 `SettingsRoot.tsx` 的 `navIcon()`)。该改动在 v0.1.2 已**彻底移除**,改为**非侵入式**:
273
+
274
+ **做法(启发自 `dsh-better-sidebar` 的 `settings-nav-icon.ts`)**:
275
+ - DSH 的 `settings.section` slot 只投影 `id/order/label`,**无图标位**;`navIcon()` 是硬编码 if 链
276
+ - 非侵入式方案:插件 `lib/client.js` 里用 **MutationObserver** 找到「文字 == 本插件 label」的设置导航按钮 → 打 `data-` 标记 → 用插件自身 CSS 的 **SVG mask**(`currentColor` 跟随主题)把核心齿轮替换成 ComfyUI 方形 C 图标
277
+ - 全程**不碰 DSH 核心**;`ctx.effect` 包装,重载/卸载自动 dispose,HMR 安全
278
+
279
+ **已落地**:
280
+ - `lib/client.js` 新增 `registerSettingsNavIcon` + `injectSettingsNavIconStyles`(图标 mask 用官方 ComfyUI 方形 C 的 path)
281
+ - 图标源文件:`docs/comfyui-nav-icon.svg`(官方 C 形,非手绘)
282
+ - DSH 核心已还原:删 `ComfyUIIcon.tsx`、还原 `SettingsRoot.tsx`,git 干净
283
+ - 删除 `patches/dsh-core-navicon-backup/`
284
+
285
+ **为什么必须处理**(已解决):
286
+ 1. DSH 升级冲突/丢失 —— ✅ 不再改核心,升级无冲突
287
+ 2. 发布孤立 —— ✅ 图标随插件 `lib/client.js` 分发
288
+ 3. 装饰性改动理应有非侵入做法 —— ✅ 照社区成熟模式实现
289
+
290
+ **残留关注**:DSH 核心 `navIcon()` 仍无「插件图标注册」通道(这是 DSH 核心能力缺口,非插件可单独解决);若未来 DSH 开放该通道,可再简化。当前非侵入式方案稳定可用,无需依赖。
291
+
292
+ ### 涉及文件(本次)
293
+ - `lib/client.js`(+registerSettingsNavIcon / +injectSettingsNavIconStyles / apply 调用)
294
+ - `docs/comfyui-nav-icon.svg`(官方 C 形图标源)
295
+ - DSH 核心 `ui-settings-general`(还原)
296
+ - 本方案文档(本段)
297
+
298
+ ---
299
+
300
+ ## 6. 风险与注意
301
+
302
+ - **上传端点**:ComfyUI 原生上传走 `/upload/image`(input 目录统一入口),音频/视频/3D 文件同样入 `input/`,配合原生 Load 节点消费——**已确认原生支持,无需自定义端点**;实现时用对应 Load 节点(LoadAudio/LoadVideo/3D 加载)验证文件名/路径约定即可
303
+ - **浏览器路径传递(A3 硬前置)**:`<input type="file">` 给的是 File 对象、不是绝对路径,而 `attach_file` 收 `path`——客户端 → host 传参通道需先确认(开放问题 #1)
304
+ - **3D 文件体积**:glb 通常大,上传/取回注意体积与超时
305
+ - **技能包触发**:runtime skill 要写清「触发条件」,避免误触发;skill 内容用中英双语(模型可能看任一种)
306
+ - **开发调试(C)风险**:`edit_source`/`reload` 会改本机 `custom_nodes/` 并重启 ComfyUI——写操作先确认、重启前查运行中任务;改坏了节点可能让 ComfyUI 起不来(应保留备份/可回退,`reload` 提供失败恢复说明)
307
+ - **版本号策略**:按用户指定,本次 **0.1.1 → 0.1.2**(新增能力做小版本增量)
@@ -0,0 +1,210 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>dsh-comfyui-canvas 流程图</title>
6
+ <style>
7
+ body { margin: 0; background: #0f1115; color: #e6e9ef; font-family: "Segoe UI","PingFang SC","Microsoft YaHei",sans-serif; }
8
+ </style>
9
+ </head>
10
+ <body>
11
+ <svg width="1240" height="980" viewBox="0 0 1240 980" xmlns="http://www.w3.org/2000/svg" font-family="'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif">
12
+
13
+ <defs>
14
+ <marker id="arr" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 Z" fill="#4f9cf9"/></marker>
15
+ <marker id="arrG" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 Z" fill="#3fb27f"/></marker>
16
+ <marker id="arrA" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto"><path d="M0,0 L7,3 L0,6 Z" fill="#d9a13b"/></marker>
17
+ <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="3" flood-color="#000" flood-opacity="0.45"/></filter>
18
+ </defs>
19
+
20
+ <!-- 标题 -->
21
+ <text x="40" y="42" font-size="24" font-weight="700" fill="#e6e9ef">dsh-comfyui-canvas — 一次画布操作的生命周期(泳道流程图)</text>
22
+ <text x="40" y="68" font-size="14" fill="#9aa3b2">以「改 seed 并运行」为例:谁在哪个环节干什么、数据怎么走、结果怎么回来。</text>
23
+
24
+ <!-- 泳道背景:四行 -->
25
+ <g>
26
+ <rect x="30" y="90" width="200" height="860" rx="10" fill="#141823"/>
27
+ <rect x="250" y="90" width="330" height="860" rx="10" fill="#151a26"/>
28
+ <rect x="600" y="90" width="300" height="860" rx="10" fill="#14221c"/>
29
+ <rect x="920" y="90" width="290" height="860" rx="10" fill="#1a1d27"/>
30
+ </g>
31
+
32
+ <!-- 泳道标题 -->
33
+ <g font-size="15" font-weight="700">
34
+ <text x="130" y="120" fill="#4f9cf9" text-anchor="middle">用户 / 浏览器</text>
35
+ <text x="415" y="120" fill="#4f9cf9" text-anchor="middle">DSH Host · agent + 插件</text>
36
+ <text x="750" y="120" fill="#3fb27f" text-anchor="middle">ComfyUI 服务</text>
37
+ <text x="1065" y="120" fill="#9b7ce8" text-anchor="middle">ComfyUI 前端</text>
38
+ </g>
39
+ <g font-size="11" fill="#5b6778">
40
+ <text x="130" y="142" fill="#5b6778" text-anchor="middle">DSH Web · ComfyUI 标签</text>
41
+ <text x="415" y="142" fill="#5b6778" text-anchor="middle">lib/index.js · 12 工具</text>
42
+ <text x="750" y="142" fill="#5b6778" text-anchor="middle">__init__.py 桥接后端</text>
43
+ <text x="1065" y="142" fill="#5b6778" text-anchor="middle">bridge.js · LiteGraph</text>
44
+ </g>
45
+
46
+ <!-- ============ 步骤 1:用户发言 ============ -->
47
+ <g filter="url(#shadow)">
48
+ <rect x="45" y="170" width="170" height="64" rx="9" fill="#1c2230" stroke="#4f9cf9"/>
49
+ <text x="130" y="196" font-size="13.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">① 用户对话</text>
50
+ <text x="130" y="216" font-size="11.5" fill="#9aa3b2" text-anchor="middle">「把 seed 改成 42 然后跑」</text>
51
+ </g>
52
+ <line x1="215" y1="202" x2="286" y2="202" stroke="#4f9cf9" stroke-width="2" marker-end="url(#arr)"/>
53
+
54
+ <g filter="url(#shadow)">
55
+ <rect x="292" y="170" width="250" height="64" rx="9" fill="#1c2230" stroke="#4f9cf9"/>
56
+ <text x="417" y="196" font-size="13.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">② agent 解析意图</text>
57
+ <text x="417" y="216" font-size="11.5" fill="#9aa3b2" text-anchor="middle">调 comfyui_set_param → 再 run</text>
58
+ </g>
59
+
60
+ <!-- ============ 步骤 3:host → 桥接 command ============ -->
61
+ <line x1="417" y1="234" x2="417" y2="284" stroke="#4f9cf9" stroke-width="2" marker-end="url(#arr)"/>
62
+ <g filter="url(#shadow)">
63
+ <rect x="292" y="290" width="250" height="64" rx="9" fill="#1c2230" stroke="#d9a13b"/>
64
+ <text x="417" y="316" font-size="13.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">③ host 发写命令</text>
65
+ <text x="417" y="336" font-size="11.5" fill="#9aa3b2" text-anchor="middle">POST /dsh-bridge/command</text>
66
+ </g>
67
+ <line x1="542" y1="322" x2="612" y2="322" stroke="#3fb27f" stroke-width="2" marker-end="url(#arrG)"/>
68
+
69
+ <g filter="url(#shadow)">
70
+ <rect x="618" y="290" width="264" height="64" rx="9" fill="#172823" stroke="#3fb27f"/>
71
+ <text x="750" y="316" font-size="13.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">④ 桥接后端接收</text>
72
+ <text x="750" y="336" font-size="11.5" fill="#9aa3b2" text-anchor="middle">clientId 定向 · 可选 token</text>
73
+ </g>
74
+ <line x1="882" y1="322" x2="952" y2="322" stroke="#3fb27f" stroke-width="2" marker-end="url(#arrG)"/>
75
+
76
+ <g filter="url(#shadow)">
77
+ <rect x="958" y="290" width="214" height="64" rx="9" fill="#1f2230" stroke="#9b7ce8"/>
78
+ <text x="1065" y="316" font-size="13.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">⑤ 前端执行</text>
79
+ <text x="1065" y="336" font-size="11.5" fill="#9aa3b2" text-anchor="middle">LiteGraph 画布实时变化</text>
80
+ </g>
81
+
82
+ <!-- ============ 步骤 6:结果回传 ============ -->
83
+ <text x="1065" y="392" font-size="24" fill="#3fb27f" text-anchor="middle">↓</text>
84
+ <g filter="url(#shadow)">
85
+ <rect x="958" y="406" width="214" height="52" rx="9" fill="#172823" stroke="#3fb27f"/>
86
+ <text x="1065" y="428" font-size="13.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">⑥ 上报执行结果</text>
87
+ <text x="1065" y="446" font-size="11" fill="#9aa3b2" text-anchor="middle">POST /dsh-bridge/result</text>
88
+ </g>
89
+ <line x1="958" y1="416" x2="900" y2="416" stroke="#3fb27f" stroke-width="2" marker-end="url(#arrG)"/>
90
+ <line x1="900" y1="432" x2="886" y2="432" stroke="#3fb27f" stroke-width="1.5" stroke-dasharray="4 3"/>
91
+ <text x="908" y="410" font-size="10.5" fill="#3fb27f">轮询</text>
92
+
93
+ <g filter="url(#shadow)">
94
+ <rect x="618" y="406" width="264" height="52" rx="9" fill="#172823" stroke="#3fb27f"/>
95
+ <text x="750" y="428" font-size="13.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">⑦ 桥接记结果</text>
96
+ <text x="750" y="446" font-size="11" fill="#9aa3b2" text-anchor="middle">_command_results 暂存</text>
97
+ </g>
98
+ <line x1="618" y1="420" x2="556" y2="420" stroke="#3fb27f" stroke-width="2" marker-end="url(#arrG)"/>
99
+
100
+ <g filter="url(#shadow)">
101
+ <rect x="292" y="406" width="250" height="52" rx="9" fill="#1c2230" stroke="#d9a13b"/>
102
+ <text x="417" y="428" font-size="13.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">⑧ host 读到结果</text>
103
+ <text x="417" y="446" font-size="11" fill="#9aa3b2" text-anchor="middle">agent 确认 set_param 成功</text>
104
+ </g>
105
+
106
+ <!-- ============ 分割:第二阶段 运行 ============ -->
107
+ <line x1="30" y1="490" x2="1210" y2="490" stroke="#2a3040" stroke-width="1.5" stroke-dasharray="6 5"/>
108
+ <text x="46" y="514" font-size="13.5" fill="#d9a13b" font-weight="600">第二阶段 · 运行与取图:</text>
109
+
110
+ <g filter="url(#shadow)">
111
+ <rect x="292" y="536" width="250" height="58" rx="9" fill="#1c2230" stroke="#d9a13b"/>
112
+ <text x="417" y="560" font-size="13" fill="#e6e9ef" text-anchor="middle" font-weight="600">⑨ comfyui_run</text>
113
+ <text x="417" y="580" font-size="11" fill="#9aa3b2" text-anchor="middle">command → queuePrompt 入队</text>
114
+ </g>
115
+ <line x1="542" y1="565" x2="612" y2="565" stroke="#3fb27f" stroke-width="2" marker-end="url(#arrG)"/>
116
+
117
+ <g filter="url(#shadow)">
118
+ <rect x="618" y="536" width="264" height="58" rx="9" fill="#172823" stroke="#3fb27f"/>
119
+ <text x="750" y="560" font-size="13" fill="#e6e9ef" text-anchor="middle" font-weight="600">⑩ POST /prompt·执行</text>
120
+ <text x="750" y="580" font-size="11" fill="#9aa3b2" text-anchor="middle">SaveImage→output/ · Preview→temp/</text>
121
+ </g>
122
+
123
+ <!-- ============ 步骤 11-13:取图 ============ -->
124
+ <line x1="417" y1="594" x2="417" y2="644" stroke="#4f9cf9" stroke-width="2" marker-end="url(#arr)"/>
125
+ <text x="300" y="700" font-size="11" fill="#9aa3b2">||</text>
126
+ <g filter="url(#shadow)">
127
+ <rect x="292" y="662" width="250" height="58" rx="9" fill="#1c2230" stroke="#4f9cf9"/>
128
+ <text x="417" y="686" font-size="13" fill="#e6e9ef" text-anchor="middle" font-weight="600">⑪ comfyui_get_outputs</text>
129
+ <text x="417" y="706" font-size="11" fill="#9aa3b2" text-anchor="middle">读 /history/:id + /view</text>
130
+ </g>
131
+ <line x1="542" y1="691" x2="612" y2="691" stroke="#3fb27f" stroke-width="2" marker-end="url(#arrG)"/>
132
+
133
+ <g filter="url(#shadow)">
134
+ <rect x="618" y="662" width="264" height="58" rx="9" fill="#172823" stroke="#3fb27f"/>
135
+ <text x="750" y="686" font-size="13" fill="#e6e9ef" text-anchor="middle" font-weight="600">⑫ 返回图片清单/URL</text>
136
+ <text x="750" y="706" font-size="11" fill="#9aa3b2" text-anchor="middle">filename · type · subfolder</text>
137
+ </g>
138
+ <line x1="618" y1="676" x2="556" y2="676" stroke="#3fb27f" stroke-width="2" marker-end="url(#arrG)"/>
139
+ <line x1="556" y1="691" x2="542" y2="691" stroke="#3fb27f" stroke-width="1.5" stroke-dasharray="4 3"/>
140
+ <text x="380" y="676" font-size="10.5" fill="#3fb27f">下载/取回</text>
141
+
142
+ <g filter="url(#shadow)">
143
+ <rect x="45" y="640" width="170" height="70" rx="9" fill="#1c2230" stroke="#4f9cf9"/>
144
+ <text x="130" y="664" font-size="13" fill="#e6e9ef" text-anchor="middle" font-weight="600">⑬ 对话展示出图</text>
145
+ <text x="130" y="684" font-size="11" fill="#9aa3b2" text-anchor="middle">图片直接带回 chat / 本地目录</text>
146
+ </g>
147
+ <line x1="292" y1="696" x2="218" y2="692" stroke="#4f9cf9" stroke-width="2" marker-end="url(#arr)"/>
148
+
149
+ <!-- ============ 批量 / 环境 / MCP 段 ============ -->
150
+ <line x1="30" y1="766" x2="1210" y2="766" stroke="#2a3040" stroke-width="1.5" stroke-dasharray="6 5"/>
151
+ <text x="46" y="792" font-size="13.5" fill="#9aa3b2" font-weight="600">批量 / 环境 / 可选 MCP:</text>
152
+
153
+ <g font-size="12">
154
+ <text x="130" y="830" text-anchor="middle" fill="#9aa3b2">agent 指令</text>
155
+ <text x="130" y="850" text-anchor="middle" fill="#5b6778" font-size="11">「跑 4 组 seed」</text>
156
+ </g>
157
+ <line x1="215" y1="840" x2="286" y2="840" stroke="#4f9cf9" stroke-width="1.5" marker-end="url(#arr)"/>
158
+ <g filter="url(#shadow)">
159
+ <rect x="292" y="812" width="250" height="52" rx="9" fill="#1c2230" stroke="#d9a13b"/>
160
+ <text x="417" y="834" font-size="13" fill="#e6e9ef" text-anchor="middle" font-weight="600">comfyui_batch_run</text>
161
+ <text x="417" y="852" font-size="11" fill="#9aa3b2" text-anchor="middle">参数矩阵逐组 queuePrompt(串行)</text>
162
+ </g>
163
+ <line x1="542" y1="838" x2="612" y2="838" stroke="#3fb27f" stroke-width="1.5" marker-end="url(#arrG)"/>
164
+ <g filter="url(#shadow)">
165
+ <rect x="618" y="812" width="264" height="52" rx="9" fill="#172823" stroke="#3fb27f"/>
166
+ <text x="750" y="834" font-size="13" fill="#e6e9ef" text-anchor="middle" font-weight="600">逐组入队 · 一并取图</text>
167
+ <text x="750" y="852" font-size="11" fill="#9aa3b2" text-anchor="middle">get_outputs 逐个 prompt_id</text>
168
+ </g>
169
+
170
+ <g font-size="12">
171
+ <text x="130" y="920" text-anchor="middle" fill="#9aa3b2">维护</text>
172
+ <text x="130" y="938" text-anchor="middle" fill="#5b6778" font-size="11">upgrade / 启动</text>
173
+ </g>
174
+ <line x1="215" y1="926" x2="286" y2="926" stroke="#d9a13b" stroke-width="1.5" marker-end="url(#arrA)"/>
175
+ <g filter="url(#shadow)">
176
+ <rect x="292" y="896" width="250" height="52" rx="9" fill="#1c2230" stroke="#d9a13b"/>
177
+ <text x="417" y="918" font-size="13" fill="#e6e9ef" text-anchor="middle" font-weight="600">comfyui_upgrade</text>
178
+ <text x="417" y="936" font-size="11" fill="#9aa3b2" text-anchor="middle">git pull 核心 + 全部自定义节点</text>
179
+ </g>
180
+ <line x1="542" y1="922" x2="612" y2="922" stroke="#3fb27f" stroke-width="1.5" marker-end="url(#arrG)"/>
181
+ <g filter="url(#shadow)">
182
+ <rect x="618" y="896" width="264" height="52" rx="9" fill="#172823" stroke="#3fb27f"/>
183
+ <text x="750" y="918" font-size="13" fill="#e6e9ef" text-anchor="middle" font-weight="600">ComfyUI 仓库</text>
184
+ <text x="750" y="936" font-size="11" fill="#9aa3b2" text-anchor="middle">core + custom_nodes 更新</text>
185
+ </g>
186
+
187
+ <g font-size="12">
188
+ <text x="130" y="960" text-anchor="middle" fill="#9b7ce8">可选 MCP</text>
189
+ </g>
190
+ <g filter="url(#shadow)">
191
+ <rect x="292" y="946" width="250" height="46" rx="9" fill="#1e1b2e" stroke="#9b7ce8"/>
192
+ <text x="417" y="966" font-size="12.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">ComfyUI MCP 服务器(comfy-cli)</text>
193
+ </g>
194
+ <line x1="542" y1="969" x2="612" y2="969" stroke="#9b7ce8" stroke-width="1.5" marker-end="url(#arr)"/>
195
+ <g filter="url(#shadow)">
196
+ <rect x="618" y="946" width="264" height="46" rx="9" fill="#1e1b2e" stroke="#9b7ce8"/>
197
+ <text x="750" y="966" font-size="12.5" fill="#e6e9ef" text-anchor="middle" font-weight="600">模板 / 模型管理 / 云端模型</text>
198
+ </g>
199
+
200
+ <!-- 图例 -->
201
+ <g font-size="11.5" fill="#9aa3b2">
202
+ <rect x="30" y="100" width="12" height="12" rx="3" fill="#4f9cf9" opacity="0.7"/><text x="48" y="110">DSH / 插件 host 动作</text>
203
+ <rect x="200" y="100" width="12" height="12" rx="3" fill="#3fb27f" opacity="0.7"/><text x="218" y="110">ComfyUI 桥接 / 服务</text>
204
+ <rect x="400" y="100" width="12" height="12" rx="3" fill="#9b7ce8" opacity="0.7"/><text x="418" y="110">前端 / 可选 MCP</text>
205
+ <rect x="560" y="100" width="12" height="12" rx="3" fill="#d9a13b" opacity="0.7"/><text x="578" y="110">host 特殊通道</text>
206
+ </g>
207
+
208
+ </svg>
209
+ </body>
210
+ </html>