@mokuyoaxis/dsh-iris 0.2.7 → 0.3.0-alpha.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 (160) hide show
  1. package/CHANGELOG.md +81 -1
  2. package/README.en.md +103 -312
  3. package/README.md +100 -310
  4. package/bin/dsh-iris.js +333 -65
  5. package/docs/AGENT_CORE_QUICKSTART.md +64 -0
  6. package/docs/AGENT_QUICKSTART.md +2 -0
  7. package/docs/ARCHITECTURE.md +13 -3
  8. package/docs/AUDIO_FLOWS.md +71 -0
  9. package/docs/CONTACT_SHEET.md +62 -0
  10. package/docs/CORE_CONNECTIONS.md +99 -0
  11. package/docs/CORE_QUICKSTART.md +108 -0
  12. package/docs/CORE_RUNTIME_CONTRACT.md +7 -2
  13. package/docs/CORE_SERVICE.md +97 -0
  14. package/docs/CORE_SKILLS.md +35 -3
  15. package/docs/DSH_COMPATIBILITY.md +10 -0
  16. package/docs/DSH_RC2_ADAPTATION.md +1 -1
  17. package/docs/DSH_RUNTIME.md +6 -2
  18. package/docs/HEADLESS_CLI.md +2 -2
  19. package/docs/IMAGE_FLOW.md +4 -0
  20. package/docs/IMAGE_GENERATION.md +127 -0
  21. package/docs/LOCAL_API.md +4 -2
  22. package/docs/LOCAL_API_CONTRACT.md +39 -14
  23. package/docs/LOCAL_CREATION.md +7 -1
  24. package/docs/LOCAL_OPERATIONS.md +46 -0
  25. package/docs/LOCAL_SELECTION.md +57 -0
  26. package/docs/LOCAL_WEB.md +201 -0
  27. package/docs/MCP.md +191 -0
  28. package/docs/MUSIC.md +2 -0
  29. package/docs/PANEL_EXTENSIONS.md +64 -0
  30. package/docs/PLUGINS.md +189 -0
  31. package/docs/PLUGIN_STARTUP.md +100 -0
  32. package/docs/PROVIDER_ADAPTER_CONTRACT.md +1 -1
  33. package/docs/PROVIDER_EXTENSIONS.md +78 -0
  34. package/docs/PROVIDER_HEALTH.md +3 -1
  35. package/docs/PROVIDER_SETTINGS.md +85 -0
  36. package/docs/PROVIDER_SUBMISSION_CONTRACT.md +6 -0
  37. package/docs/ROADMAP.md +17 -7
  38. package/docs/VISION_CLI.md +1 -1
  39. package/docs/WEB_PROTOTYPE.md +21 -6
  40. package/docs/WEB_RECOVERY.md +46 -0
  41. package/docs/WORKBENCH_LOGIN.md +63 -0
  42. package/docs/assets/screenshots/core-connections-preview.webp +0 -0
  43. package/docs/assets/screenshots/core-model-pools-preview.webp +0 -0
  44. package/docs/assets/screenshots/core-overview-preview.webp +0 -0
  45. package/docs/assets/screenshots/core-spectrum-preview.webp +0 -0
  46. package/docs/assets/screenshots/core-studio-dark-preview.webp +0 -0
  47. package/docs/assets/screenshots/core-studio-mobile-preview.webp +0 -0
  48. package/docs/assets/screenshots/core-studio-preview.webp +0 -0
  49. package/docs/releases/0.3.0-alpha.1.md +51 -0
  50. package/docs/screenshots.md +41 -1
  51. package/lib/actions.js +53 -2
  52. package/lib/adapters.js +20 -11
  53. package/lib/application-runtime.js +34 -7
  54. package/lib/audio-flow-input.js +37 -0
  55. package/lib/client.js +346 -53
  56. package/lib/comfyui-adapter.js +94 -0
  57. package/lib/comfyui-client.js +51 -0
  58. package/lib/comfyui-inspection.js +73 -0
  59. package/lib/comfyui-workflow.js +94 -0
  60. package/lib/config.js +36 -1
  61. package/lib/configured-image-runtime.js +50 -0
  62. package/lib/connection-skill.js +89 -0
  63. package/lib/connection-template.js +23 -0
  64. package/lib/core-artifact-store.js +16 -2
  65. package/lib/core-bridge-selection.js +31 -0
  66. package/lib/core-bridge-tools.js +83 -0
  67. package/lib/core-capability-catalog.js +182 -0
  68. package/lib/core-connection-diagnostics.js +49 -0
  69. package/lib/core-connection-store.js +277 -0
  70. package/lib/core-connections.js +225 -0
  71. package/lib/core-maintenance.js +9 -3
  72. package/lib/core-runtime.js +2 -1
  73. package/lib/core-service-client.js +170 -0
  74. package/lib/core-tasks.js +29 -12
  75. package/lib/core-writer-lease.js +16 -0
  76. package/lib/creation-request-store.js +38 -64
  77. package/lib/dsh-host-adapter.js +4 -1
  78. package/lib/dsh-service-bridge.js +66 -0
  79. package/lib/execution-ownership.js +43 -0
  80. package/lib/flow-store.js +105 -10
  81. package/lib/generation-input.js +10 -1
  82. package/lib/headless-vision.js +7 -7
  83. package/lib/image-edit-input.js +1 -1
  84. package/lib/image-flow.js +73 -29
  85. package/lib/index.js +37 -17
  86. package/lib/local-api-projection.js +10 -5
  87. package/lib/local-api-token-directory.js +31 -0
  88. package/lib/local-api.js +769 -67
  89. package/lib/local-creation.js +89 -24
  90. package/lib/local-operations.js +36 -0
  91. package/lib/local-request-root.js +86 -0
  92. package/lib/local-web-assets.js +37 -0
  93. package/lib/mcp-bridge.js +58 -0
  94. package/lib/mcp-check.js +26 -0
  95. package/lib/mcp-config.js +42 -0
  96. package/lib/mcp-delivery.js +46 -0
  97. package/lib/mcp-http.js +101 -0
  98. package/lib/mcp-server.js +47 -0
  99. package/lib/model-directory-service.js +16 -6
  100. package/lib/model-directory.js +3 -3
  101. package/lib/models.js +2 -2
  102. package/lib/music-transport.js +2 -1
  103. package/lib/operation-runner.js +236 -0
  104. package/lib/operation-store.js +216 -0
  105. package/lib/panel-extension.js +36 -0
  106. package/lib/plugin-contract.js +194 -0
  107. package/lib/plugin-execution.js +51 -0
  108. package/lib/plugin-launch.js +86 -0
  109. package/lib/plugin-operation-store.js +101 -0
  110. package/lib/plugin-operations.js +28 -0
  111. package/lib/plugin-registry.js +109 -0
  112. package/lib/plugin-selection.js +15 -0
  113. package/lib/plugin-source-image.js +5 -0
  114. package/lib/plugin-web-assets.js +54 -0
  115. package/lib/plugins.d.ts +288 -0
  116. package/lib/plugins.js +58 -0
  117. package/lib/provider-adapter.js +5 -1
  118. package/lib/provider-adapters.js +56 -18
  119. package/lib/provider-catalog.js +40 -29
  120. package/lib/provider-config-service.js +105 -23
  121. package/lib/provider-diagnostics.js +56 -0
  122. package/lib/provider-extensions.js +29 -0
  123. package/lib/provider-health.js +8 -1
  124. package/lib/provider-monitor.js +79 -0
  125. package/lib/provider-protocol.js +70 -20
  126. package/lib/provider-registry.js +118 -0
  127. package/lib/provider-response.js +28 -0
  128. package/lib/provider-settings.js +134 -0
  129. package/lib/provider-task-runner.js +22 -9
  130. package/lib/skill-installation.js +23 -11
  131. package/lib/vision-model-routing.js +3 -0
  132. package/lib/web/app.js +642 -0
  133. package/lib/web/appearance.js +111 -0
  134. package/lib/web/comfyui.js +146 -0
  135. package/lib/web/connections.js +377 -0
  136. package/lib/web/creation.js +355 -0
  137. package/lib/web/flow-view.js +33 -0
  138. package/lib/web/gallery.js +132 -0
  139. package/lib/web/index.html +291 -0
  140. package/lib/web/media-client.js +204 -0
  141. package/lib/web/plugin-panel.js +221 -0
  142. package/lib/web/plugin-surface.css +17 -0
  143. package/lib/web/providers.js +492 -0
  144. package/lib/web/recovery.js +105 -0
  145. package/lib/web/startup.js +18 -0
  146. package/lib/web/styles.css +518 -0
  147. package/lib/web/transport.js +96 -0
  148. package/lib/web/workbench-login.js +165 -0
  149. package/lib/workbench-auth-cli.js +47 -0
  150. package/lib/workbench-auth.js +200 -0
  151. package/package.json +20 -5
  152. package/plugins/contact-sheet/index.d.mts +4 -0
  153. package/plugins/contact-sheet/index.mjs +33 -0
  154. package/plugins/contact-sheet/web/board.css +14 -0
  155. package/plugins/contact-sheet/web/board.mjs +93 -0
  156. package/skills/iris-core/SKILL.md +8 -4
  157. package/skills/iris-core/references/cli.md +2 -2
  158. package/skills/iris-core/references/comfyui.md +69 -0
  159. package/skills/iris-core/references/tasks.md +2 -0
  160. package/user_guide.md +5 -1
@@ -0,0 +1,93 @@
1
+ const element = (tag, text, className) => { const node = document.createElement(tag); if (text) node.textContent = text; if (className) node.className = className; return node; };
2
+
3
+ export async function mount({ container, api, session, signal }) {
4
+ const service = api.pluginOperations, urls = new Set(), timers = new Set();
5
+ const keyName = 'iris.contact-sheet.' + session.rootId, operationId = 'community.contact-sheet.create';
6
+ let request, selected = [], catalog, busy = false;
7
+ const intro = element('div', '', 'intro'); intro.append(element('h2', '让灵感,并排相遇。'), element('p', '选择现有图片,离线排成一张对照板。原图保持不变。', 'muted'));
8
+ const layout = element('div', '', 'board-layout'), choices = element('div', '', 'image-choices'), editor = element('form', '', 'card');
9
+ choices.setAttribute('aria-label', '选择来源图片');
10
+ const columnsLabel = element('label', '每行图片数'), columns = document.createElement('select'); columns.name = 'columns';
11
+ for (let i = 1; i <= 4; i++) columns.add(new Option(String(i), String(i))); columns.value = '2'; columnsLabel.append(columns);
12
+ const sizeLabel = element('label', '单张边长'), size = document.createElement('select'); size.name = 'size';
13
+ for (const i of [128, 256, 512]) size.add(new Option(i + ' px', String(i))); size.value = '256'; sizeLabel.append(size);
14
+ const count = element('p', '尚未选择图片', 'field-note'), submit = element('button', '制作对照板'); submit.type = 'submit'; submit.disabled = true;
15
+ const fresh = element('button', '新建一张', 'secondary'); fresh.type = 'button'; fresh.hidden = true;
16
+ const recover = element('button', '查询原操作', 'secondary'); recover.type = 'button'; recover.hidden = true;
17
+ const more = element('button', '加载更多图片', 'secondary'); more.type = 'button'; more.hidden = true;
18
+ editor.append(columnsLabel, sizeLabel, count, submit, recover, fresh, more);
19
+ const status = element('p', '正在读取现有作品…', 'field-note'); status.setAttribute('role', 'status'); status.dataset.boardStatus = 'true';
20
+ const output = element('section', '', 'board-result'); output.hidden = true;
21
+ layout.append(choices, editor); container.append(intro, layout, status, output);
22
+ function remember(value) {
23
+ request = value;
24
+ try { value ? sessionStorage.setItem(keyName, JSON.stringify(value)) : sessionStorage.removeItem(keyName); }
25
+ catch (_) { status.textContent = '浏览器无法保存恢复标识;请保留本次 Operation ID。'; }
26
+ }
27
+ function controls() {
28
+ const locked = busy || Boolean(request);
29
+ submit.disabled = locked || !selected.length || !catalog?.operations.some(item => item.id === operationId && item.available);
30
+ columns.disabled = size.disabled = locked; more.disabled = busy;
31
+ for (const checkbox of choices.querySelectorAll('input')) checkbox.disabled = locked || !checkbox.checked && selected.length >= 16;
32
+ }
33
+ function note(error) { status.textContent = [error.message, error.code, error.requestId].filter(Boolean).join(' · '); }
34
+ async function present(operation) {
35
+ signal.throwIfAborted();
36
+ if (operation.action !== 'plugin.execute' || operation.operationId !== operationId) throw new Error('恢复标识不属于此对照板业务,请核对业务记录');
37
+ status.textContent = ({ queued: '已接收,正在等待处理', running: '正在排版', succeeded: '对照板已保存', interrupted: '处理已中断,保留原记录;不会自动重做', canceled: '已停止,原记录保留', failed: '处理未完成,请核对插件与授权' })[operation.state]
38
+ + ' · ' + operation.id;
39
+ fresh.hidden = ['queued', 'running'].includes(operation.state);
40
+ recover.hidden = true;
41
+ if (operation.state === 'succeeded' && operation.result.artifactIds.length) {
42
+ const id = operation.result.artifactIds[0], blob = await api.artifact({ id, mediaType: 'image/png' }); signal.throwIfAborted();
43
+ const url = URL.createObjectURL(blob); urls.add(url); const image = element('img'); image.src = url; image.alt = '已保存的多图对照板';
44
+ const link = element('a', '下载原始 PNG'); link.href = url; link.download = 'iris-contact-sheet-' + id + '.png';
45
+ output.replaceChildren(image, link); output.hidden = false;
46
+ } else if (['queued', 'running'].includes(operation.state)) {
47
+ const timer = setTimeout(() => { timers.delete(timer); void poll(operation.id); }, 450); timers.add(timer);
48
+ }
49
+ }
50
+ async function poll(id) { try { await present((await service.inspect(id)).operation); } catch (error) { if (!signal.aborted) { note(error); recover.hidden = false; } } }
51
+ editor.addEventListener('submit', async event => {
52
+ event.preventDefault(); if (busy || request || !selected.length) return;
53
+ const contribution = catalog.operations.find(item => item.id === operationId && item.available); if (!contribution) return;
54
+ busy = true; remember({ key: crypto.randomUUID(), operationId, dependency: contribution.dependency,
55
+ input: { artifactIds: selected, columns: Number(columns.value), cellSize: Number(size.value) } }); controls(); status.textContent = '正在保存本次操作…';
56
+ try { const result = await service.execute(request); await present(result.operation); }
57
+ catch (error) { if (!signal.aborted) { note(error); status.textContent += '。请查询原操作,未自动重做。'; recover.hidden = false; } }
58
+ finally { busy = false; if (!signal.aborted) controls(); }
59
+ });
60
+ fresh.addEventListener('click', () => { remember(null); output.hidden = true; output.replaceChildren(); fresh.hidden = recover.hidden = true; status.textContent = '选择图片后可以新建一次操作。'; controls(); });
61
+ async function lookup() {
62
+ try { await present((await service.lookup(request.key)).operation); }
63
+ catch (error) { if (!signal.aborted) { note(error); recover.hidden = false; if (error.status === 404) fresh.hidden = false; } }
64
+ }
65
+ recover.addEventListener('click', () => { if (!busy && request) void lookup(); });
66
+ signal.addEventListener('abort', () => { for (const timer of timers) clearTimeout(timer); for (const url of urls) URL.revokeObjectURL(url); }, { once: true });
67
+ if (!service) { status.textContent = '此服务未开启插件业务执行。'; return; }
68
+ catalog = await service.catalog({ limit: '30' }); signal.throwIfAborted();
69
+ async function appendImages(page) { for (const artifact of page.artifacts) {
70
+ const label = element('label', '', 'image-choice'), checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.value = artifact.id;
71
+ const image = element('img'); image.alt = '来源图片 ' + artifact.id;
72
+ label.append(checkbox, image, element('span', artifact.id.slice(-8), 'muted')); choices.append(label);
73
+ const blob = await api.artifact({ id: artifact.id, mediaType: artifact.mediaType }); signal.throwIfAborted();
74
+ const url = URL.createObjectURL(blob); urls.add(url); image.src = url;
75
+ checkbox.addEventListener('change', () => { selected = checkbox.checked ? [...selected, artifact.id] : selected.filter(id => id !== artifact.id);
76
+ count.textContent = '已选择 ' + selected.length + ' 张 · 按选择顺序排版'; controls(); });
77
+ } more.hidden = page.nextOffset === null || page.nextOffset === undefined; controls(); }
78
+ more.addEventListener('click', async () => {
79
+ if (busy || catalog.nextOffset === null) return;
80
+ busy = true; controls();
81
+ try { catalog = await service.catalog({ limit: '30', offset: String(catalog.nextOffset) }); signal.throwIfAborted(); await appendImages(catalog); }
82
+ catch (error) { if (!signal.aborted) note(error); }
83
+ finally { busy = false; if (!signal.aborted) controls(); }
84
+ });
85
+ await appendImages(catalog);
86
+ if (!catalog.artifacts.length) choices.append(element('p', '当前没有可用图片,请先通过现有创作入口或 CLI 导入。', 'muted'));
87
+ status.textContent = '最多选择 16 张图片,不调用模型。';
88
+ try { const saved = sessionStorage.getItem(keyName); if (saved) request = JSON.parse(saved); }
89
+ catch (_) { status.textContent = '原恢复标识无法读取,请先核对业务记录。'; }
90
+ if (request) await lookup();
91
+ controls();
92
+ return () => { for (const timer of timers) clearTimeout(timer); for (const url of urls) URL.revokeObjectURL(url); container.replaceChildren(); };
93
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: iris-core
3
- description: "Create, edit, and retrieve persistent Iris images through the standalone CLI without a running DSH host. Use for local image imports, revisions, existing task inspection, and artifact export."
3
+ description: "Create, edit, and retrieve persistent Iris images through the standalone CLI without a running DSH host. Use for API images, configured ComfyUI workflows and LoRA parameters, local imports, revisions, task recovery, and artifact export."
4
4
  ---
5
5
 
6
6
  # Iris Core · 核心图片工作流
@@ -11,13 +11,17 @@ Organize the work around the image the user wants to receive. Reuse existing ass
11
11
 
12
12
  Use the [standalone CLI reference](references/cli.md) to confirm the installed command, explicit data root, and private provider configuration needed for generation. Reuse information already established in the conversation. Do not scan another application's configuration or assume a personal directory, provider, or model.
13
13
 
14
- A visible skill does not prove that its execution tools are available. Report a missing command, connection, or capability precisely. This edition binds to the existing CLI; future MCP and independent workbench integrations need their own verified invocation instructions.
14
+ A visible skill does not prove that its execution tools are available. Report a missing command, connection, or capability precisely. This skill binds to the CLI. For an explicitly selected MCP connection, use its connection-specific skill and actual authorized tools; do not bypass a missing MCP capability through the CLI.
15
+
16
+ ## Clarify a ComfyUI request · 先确认工作流与要求
17
+
18
+ For ComfyUI, read the [workflow, parameters, LoRA and recovery reference](references/comfyui.md). Ask a concise, bundled question for missing image requirements, workflow choice and parameter preferences before creating or executing work. Read-only catalog inspection may help the user choose. Reuse answers and authorization already given; a complete request needs no repeated questionnaire. API-only requests follow their established configuration and do not require ComfyUI setup questions.
15
19
 
16
20
  ## Plan the image work · 按作品组织步骤
17
21
 
18
22
  - Import a local image when it needs to become a persistent source. Reuse an existing Artifact in the current root without importing it again.
19
23
  - Generate for a new image request. For a revision, pass the source Artifact and requested changes to create a related version while retaining the original. Retrieve existing results instead of regenerating them.
20
- - Omit the model override unless the user specifies one, allowing the configured capability policy to select candidates. An explicit model must be allowed for that capability. Names, catalog entries, and past success do not establish present availability.
24
+ - For ordinary API work, use the configured capability policy when it matches the user's choice. If the pool mixes API and ComfyUI, choose an actual allowed API reference explicitly to keep an API-only request on that path. ComfyUI always uses a specific workflow confirmed from the current catalog; never guess from a model family name. Names, catalog entries, and past success do not establish present availability.
21
25
  - Add only steps needed for the requested result. An explicit edit can proceed directly; a generation request does not require extra paid vision checks or another generation.
22
26
  - Wait for actual delivery before starting a dependent operation. When content verification is required, use an image-reading capability available in the current host. Metadata and file existence alone do not establish visual correctness.
23
27
 
@@ -37,4 +41,4 @@ Preserve the original Task after interruption or unknown acceptance; do not prob
37
41
 
38
42
  Return the actual image file or a host-accessible asset, with the Task/Artifact IDs needed to continue. Distinguish availability, export, display in the conversation, and visual verification. Report partial results and unmet conditions accurately.
39
43
 
40
- This edition covers images and their tasks. It does not imply support for video, speech, UI operations, or a production MCP service in this entry point. Existing DSH skills continue to guide DSH-native tools and workbench workflows.
44
+ This skill covers images and their tasks. The ComfyUI path requires 0.3.0-alpha.1 or compatible source; stable npm 0.2.7 does not include it. Check the actual installed version. Existing DSH skills continue to guide DSH-native tools and workbench workflows.
@@ -2,7 +2,7 @@
2
2
 
3
3
  The current executable binding is `dsh-iris`, which uses shared Application/Core operations without a running DSH host. Check the installed command with `dsh-iris --help`. In a confirmed source checkout, `node /absolute/path/to/iris/bin/dsh-iris.js` is also available. A missing command does not authorize installing software or changing package versions.
4
4
 
5
- These image, artifact, and task commands exist in 0.2.6. This skill is a new, unreleased package resource. Development-only Flow commands, local HTTP writes, and a future UI are not prerequisites.
5
+ These image, artifact, and task commands exist in 0.2.6; the Core skill is bundled from 0.2.7. The development [ComfyUI reference](comfyui.md) has its own version and parameter requirements. Flow commands and a workbench are not prerequisites for the standalone API image path below.
6
6
 
7
7
  ## Establish the context · 明确本次上下文
8
8
 
@@ -50,7 +50,7 @@ Write the user's original or authorized revised request into the input file, for
50
50
  dsh-iris run image --data-root "$IRIS_DATA_ROOT" --provider-config "$IRIS_PROVIDER_FILE" --input-file "$IRIS_INPUT_FILE"
51
51
  ```
52
52
 
53
- Set `n` to the requested count (1–4); do not increase it for testing. Supply `size` only when requested and supported. Omit `model_ref` unless a model was specified; use an allowed `providerId::modelId` for an explicit choice. An explicit choice has no candidate fallback. Default candidate switching requires evidence of non-acceptance.
53
+ Set `n` to the requested count (1–4); do not increase it for testing. Supply `size` only when requested and supported. Use the configured API policy when it matches the request; explicitly select an actual allowed API model when a mixed pool could choose ComfyUI. ComfyUI always requires the confirmed workflow and `n:1`; follow its separate reference. An explicit choice has no candidate fallback. Default candidate switching requires evidence of non-acceptance.
54
54
 
55
55
  ## Edit an existing image · 编辑已有图片
56
56
 
@@ -0,0 +1,69 @@
1
+ # ComfyUI workflows · 工作流、参数与 API 搭配
2
+
3
+ This reference describes the **unreleased 0.3-target implementation**, not npm 0.2.7. Confirm the installed command and returned catalog before using it; missing support does not authorize installing or upgrading software. Keep the explicit roots and private provider file from the [CLI reference](cli.md).
4
+
5
+ ## Ask before creating · 提问确认需求
6
+
7
+ ComfyUI selects an executable workflow with its own exposed controls. Before creating or executing a request, establish:
8
+
9
+ - The desired subject, style, changes and output. Ask whether a source image must be preserved when the request suggests editing.
10
+ - The configured workflow to use, or whether the user prefers API generation or wants a recommendation from the available workflows.
11
+ - Any required LoRA and separate model/CLIP weights; size, seed or reproducibility requirements. Offer to keep the workflow defaults for unspecified settings; do not require the user to understand every sampler control.
12
+
13
+ Ask only for missing information, preferably in one compact question. For example: “What should the image contain and look like? Which of these configured workflows should I use? Do you need a particular LoRA, size or seed, or should I keep that workflow's defaults?” Use the user's language and real catalog choices. If the user delegates selection, choose a suitable actual workflow and state the choice and assumptions. Reuse established answers and authorization; do not ask again before each already authorized stage.
14
+
15
+ Read-only directory inspection may precede the question. While essential choices remain unanswered, do not generate a sample, create a trial Run/Task, change a provider, or install a workflow/model. A missing workflow is a configuration gap to explain, not permission to fabricate a template or silently substitute an API model.
16
+
17
+ ## Read the actual directory · 使用真实目录
18
+
19
+ ```bash
20
+ dsh-iris models list --provider-config "$IRIS_PROVIDER_FILE"
21
+ ```
22
+
23
+ Choose the returned model `ref`. A `comfyWorkflow` summary identifies the configured template; read its `parameters` for actual IDs, labels, types, defaults, ranges and declared choices. Use `imageRouting` and edit support to distinguish API models from workflows, rather than guessing from names such as SDXL or Flux. A configured entry is not proof that the service, nodes or GPU are usable.
24
+
25
+ LoRA names belong to **existing workflow slots**. Read current available choices through an explicit read-only workflow check when needed and authorized. The check queries node definitions without generating or changing configuration; it cannot establish real inference success. If options are truncated, do not claim an unseen name was verified. Ask for the intended installed name or retain the confirmed default.
26
+
27
+ Only override declared parameter IDs and supported scalar values. Keep model and CLIP weights separate, including zero/negative values when allowed; do not set them equal without the user's intent. Multiple LoRAs require existing slots in the workflow. A fixed v0 template exposes no runtime parameters. Do not invent a node, a LoRA filename, an arbitrary graph patch or an undeclared negative-prompt field. Integer seeds must fit the JavaScript safe range; keep sampler defaults unless a change is requested or delegated.
28
+
29
+ ## Execute the selected path · 执行明确入口
30
+
31
+ For CLI image generation, write the approved input to a new private JSON file: actual `model_ref`, `prompt`, `n:1`, optional supported `size`, and optional `workflow_parameters` containing only requested overrides. Omit an empty parameter map. Omit size when the workflow has no size binding. Then use the existing image entry:
32
+
33
+ ```bash
34
+ dsh-iris run image --data-root "$IRIS_DATA_ROOT" --provider-config "$IRIS_PROVIDER_FILE" --input-file "$IRIS_INPUT_FILE"
35
+ ```
36
+
37
+ An optional static check uses a **separate** input file containing just `workflow_parameters` with the same approved overrides; omit `--input` if there are none:
38
+
39
+ ```bash
40
+ dsh-iris models workflow-check "$IRIS_MODEL_REF" --provider-config "$IRIS_PROVIDER_FILE" --input "$(cat "$IRIS_CHECK_FILE")"
41
+ ```
42
+
43
+ The file contains data, not executable shell text. Never substitute prompt text directly into shell code. Read the check's `ok`, issues and limits; exit code 0 alone is not a passing inspection. Checking and generating are separate actions.
44
+
45
+ For persistent Flow creation, the input also uses `model_ref` and `workflow_parameters`. Text-to-image requires an explicitly initialized new v2 execution root; do not migrate an existing root. Create once, keep the returned Run, and explicitly continue it. A Flow retains private request input, while a standalone Task does not retain the prompt. Follow the invocation supported by the installed version rather than switching formats mid-task.
46
+
47
+ For an authorized MCP connection, follow its generated skill and actual tool schemas: the directory returns `modelRef`, creation uses `workflowParameters`, and creation saves a Run without generating. A missing directory or execution tool is a capability gap; do not call an unavailable tool or switch to shell commands to bypass it. Owner workflow checks are not automatically available through media MCP tools.
48
+
49
+ ## Combine API and ComfyUI · 选择与串联
50
+
51
+ | User goal | Supported approach |
52
+ |---|---|
53
+ | A quick API image | Use the configured API policy or an explicit allowed API model; skip the ComfyUI questionnaire unless the request needs it |
54
+ | An existing workflow, LoRA or controlled seed | Confirm the actual ComfyUI workflow and exposed parameters before generation |
55
+ | ComfyUI base image, followed by API revision | Generate once, wait for the original Artifact, then pass that same-root Artifact to an explicitly chosen API model that supports editing |
56
+ | API image refined by ComfyUI | Explain that the current Iris ComfyUI adapter has no source-image upload/binding; do not claim a reverse image-edit chain works |
57
+ | Compare API and ComfyUI | Only when requested, plan two independent generations and their additional work/cost; keep distinct task identities, then show actual results |
58
+
59
+ For the supported ComfyUI → API chain, use the existing image-edit input: `source_artifact_id` for CLI or `sourceArtifactId` for MCP. Do not carry `workflow_parameters`/`workflowParameters` into the API edit. Both stages need their actual permissions and user intent; authorization for the whole stated chain need not be requested again per step. Keep the original image and the second stage's lineage. If stage two fails, recover stage two instead of regenerating stage one.
60
+
61
+ Do not silently switch backends as recovery. An API substitute may lose LoRA, workflow or seed semantics. If a substitute is already authorized, establish the original request's acceptance and what tradeoffs that authorization covers; unknown acceptance still requires preserving the original task and any possible duplicate work/billing. Never rebind an old Task/Run to a different model or new template.
62
+
63
+ ## Recover original facts · 恢复原任务
64
+
65
+ - Standalone CLI: inspect the returned Task in its original root, then use [task recovery](tasks.md) to observe, wait or redeliver that same Task. Preserve it when acceptance is unknown; do not test by submitting again.
66
+ - Persistent Flow/MCP: retain Run/Operation/Task/Artifact IDs, current Run revision and original request UUIDs. Read the original records after interruption. An Operation completing does not prove the remote image completed; explicitly continue the original Run only when authorized and supported by its state. Do not apply standalone Task retry to work around a Flow binding.
67
+ - A lost creation reply does not justify a new key. Recover the original creation identity when the selected entry supports it; otherwise read the original records and report any remaining uncertainty before further work.
68
+ - Query the original remote job rather than rechecking node catalogs as a substitute for task observation. A changed template can block old-task rebinding; preserve the old record and explain the mismatch.
69
+ - Stopping local waiting is not confirmed remote cancellation. The current ComfyUI adapter does not send `/interrupt`. Retrieve and present the actual delivered image; visual quality requires viewing it, not just reading metadata.
@@ -2,6 +2,8 @@
2
2
 
3
3
  Inspect the Task in its original data root first. Tasks do not persist prompts; do not reconstruct the user's input from a task summary. Inspection has no provider side effects. Observe or recover only as needed for the current request.
4
4
 
5
+ For ComfyUI and mixed API work, see [workflow and recovery details](comfyui.md). Keep each stage's original Task. A persistent Flow uses its original Run/Operation and binding; do not use a standalone retry to change that Flow's model or template.
6
+
5
7
  | Recorded fact | Action |
6
8
  |---|---|
7
9
  | Accepted and still queued/running | Observe or wait for the original Task; do not create another generation |
package/user_guide.md CHANGED
@@ -64,6 +64,10 @@ DSH 已配好同一媒体服务时,可在第 1 步选择连接来源,明确
64
64
 
65
65
  保存供应商和修改能力分配都会立即生效,不需要重启 DSH。
66
66
 
67
+ ## ComfyUI 工作台(未发布源码)
68
+
69
+ npm 0.2.7 尚不含此界面。当前源码可在“+ 添加供应商”选择“ComfyUI · 已有服务”,保存地址/认证后导入 API 图或 Iris 参数模板,明确节点和公开参数;检查、保存不生成图片。画图时选择具体工作流,可调整 LoRA 双权重、种子等声明参数,并从只读检查取得可用选项。Iris 不安装 ComfyUI 或模型,静态检查不等于真实 GPU 验收。完整操作与限制见 [DSH ComfyUI 入口](docs/IMAGE_GENERATION.md#dsh-工作台入口03-alpha)。
70
+
67
71
  ## 供应商与协议
68
72
 
69
73
  Iris 当前支持两类调用路径:
@@ -220,7 +224,7 @@ $DSH_HOME/iris/v1/providers.json
220
224
 
221
225
  `mediaBaseUrl` 可以省略或留空,此时媒体调用沿用 `baseUrl`。`assignments` 可以省略,但从 0.2.4 起缺失分配不发起对应功能的新调用;0.2.6 也不会将其静默改为自动池。包含特殊字符的 provider 或模型引用会经过 URL 编码,复杂引用建议在工作台中生成,不要手写。
222
226
 
223
- 可为明确不需要认证的本地端点设置 `"auth": "none"` 并省略 `apiKey`;缺省或 `"auth": "bearer"` 仍要求 Key,保持旧配置行为。无认证模式不会发送 Authorization 头,已有的旧 Key 也不会被带入该模式的媒体请求。工作台尚无专门的无认证开关,需要按上述停机原则编辑私有配置;不要对需要认证的公网端点使用 `auth:none`。
227
+ 可为明确不需要认证的本地端点设置 `"auth": "none"` 并省略 `apiKey`;缺省或 `"auth": "bearer"` 仍要求 Key,保持旧配置行为。无认证模式不会发送 Authorization 头,已有的旧 Key 也不会被带入该模式的媒体请求。0.2.7 工作台尚无专门的无认证开关,需按上述停机原则编辑私有配置;未发布源码已在添加供应商与认证设置中提供选择。不要对需要认证的公网端点使用 `auth:none`。
224
228
 
225
229
  API Key 以明文保存在宿主侧的 `providers.json` 中。POSIX 上 Iris 目录为 `0700`、文件为 `0600`,0.1.1 首次启动会收紧既有 Iris 树但不修改内容或跟随符号链接;Windows 的 mode 不能替代 ACL。状态接口和界面只返回掩码,不会显示完整 Key。不要把这个文件提交到版本库或发给他人。
226
230