dsh-image-gen 0.8.5 → 0.8.6
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/README.en.md +5 -0
- package/README.md +5 -0
- package/lib/client.js +104 -29
- package/lib/index.js +40 -4
- package/lib/types/client/index.d.ts +2 -5
- package/lib/types/client/settings-state.d.ts +12 -0
- package/lib/types/settings-health.d.ts +6 -0
- package/lib/types/shared.d.ts +6 -0
- package/package.json +3 -2
package/README.en.md
CHANGED
|
@@ -401,8 +401,13 @@ pnpm run typecheck
|
|
|
401
401
|
pnpm test
|
|
402
402
|
pnpm run build
|
|
403
403
|
pnpm run pack:check
|
|
404
|
+
pnpm run test:package
|
|
404
405
|
```
|
|
405
406
|
|
|
407
|
+
Saving settings on modern DSH requires the actually loaded `@deepseek-ai/schemastery >=3.18.4 <4`. The card distinguishes loading, missing host forms, remote connections that cannot persist, and incompatible schemas. Legacy DSH settings interfaces are retained. Check the dependencies resolved in the plugin profile when updating, as well as those in the source checkout.
|
|
408
|
+
|
|
409
|
+
`test:package` requires network access. It installs the current build's tarball and pinned published DSH 0.2 settings services in a temporary directory, then uses real React rendering to verify card state, the bundled save handler, profile file persistence, a fresh form, host restart, and actionable refusal with old schemastery. Image APIs, browser DOM, and RPC transport are outside this test. CI runs it on Windows and Linux.
|
|
410
|
+
|
|
406
411
|
Feedback is welcome through [Issues](https://github.com/shanliuling/dsh-image-gen/issues). Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a Pull Request.
|
|
407
412
|
|
|
408
413
|
## License
|
package/README.md
CHANGED
|
@@ -401,8 +401,13 @@ pnpm run typecheck
|
|
|
401
401
|
pnpm test
|
|
402
402
|
pnpm run build
|
|
403
403
|
pnpm run pack:check
|
|
404
|
+
pnpm run test:package
|
|
404
405
|
```
|
|
405
406
|
|
|
407
|
+
新 DSH 的设置保存需要实际加载的 `@deepseek-ai/schemastery >=3.18.4 <4`。设置卡会区分加载中、宿主未提供设置、远程连接不可保存及依赖不兼容;旧 DSH 的设置接口仍保留。更新依赖时应检查插件所在 profile 的实际依赖,而不只检查源码目录。
|
|
408
|
+
|
|
409
|
+
`test:package` 需要网络,会在临时目录安装当前构建的插件 tarball 和指定版本的 DSH 0.2 设置服务,通过真实 React 渲染验证卡片状态和保存处理、配置文件写入、重新打开表单和宿主重启后的读取,并验证旧 schemastery 的明确拒绝提示。图片 API、浏览器 DOM 和 RPC 传输不属于此测试;CI 同时在 Windows 和 Linux 执行。
|
|
410
|
+
|
|
406
411
|
欢迎通过 [Issues](https://github.com/shanliuling/dsh-image-gen/issues) 反馈问题,或阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 后提交 Pull Request。
|
|
407
412
|
|
|
408
413
|
## License
|
package/lib/client.js
CHANGED
|
@@ -87,6 +87,8 @@ window.__ModuleLoader__.load({
|
|
|
87
87
|
const SAVE_WORKSPACE_ROUTE = "/plugins/dsh-image-gen/save-workspace";
|
|
88
88
|
/** Browser route the settings card probes provider connectivity through. */
|
|
89
89
|
const TEST_CONNECTION_ROUTE = "/plugins/dsh-image-gen/test";
|
|
90
|
+
/** Non-secret settings capability probe, available even when the host cannot serve a form. */
|
|
91
|
+
const SETTINGS_HEALTH_ROUTE = "/plugins/dsh-image-gen/settings-health";
|
|
90
92
|
/** Browser route the workbench infinite canvas pushes live state through. */
|
|
91
93
|
const CANVAS_STATE_ROUTE = "/plugins/dsh-image-gen/canvas-state";
|
|
92
94
|
/** Upload a selected canvas original to the host attachment store. */
|
|
@@ -246,6 +248,38 @@ window.__ModuleLoader__.load({
|
|
|
246
248
|
"google-sub": ""
|
|
247
249
|
};
|
|
248
250
|
//#endregion
|
|
251
|
+
//#region lib/types/client/settings-state.js
|
|
252
|
+
/** Preserve modern form states while accepting legacy scopes without status/mode. */
|
|
253
|
+
function settingsState(snapshot, health) {
|
|
254
|
+
if (snapshot.mode === "memory") return "remote";
|
|
255
|
+
if (health?.settings === "live" && !health.liveSchema) return "incompatible";
|
|
256
|
+
if (snapshot.status === "loading") return "loading";
|
|
257
|
+
if (snapshot.status === "unavailable") return "unavailable";
|
|
258
|
+
return snapshot.writable ? "ready" : "readOnly";
|
|
259
|
+
}
|
|
260
|
+
/** A failed probe cannot identify the cause; keep the host's own form state. */
|
|
261
|
+
async function fetchSettingsHealth(signal) {
|
|
262
|
+
try {
|
|
263
|
+
const response = await fetch(SETTINGS_HEALTH_ROUTE, {
|
|
264
|
+
cache: "no-store",
|
|
265
|
+
signal
|
|
266
|
+
});
|
|
267
|
+
if (!response.ok) return void 0;
|
|
268
|
+
const health = await response.json();
|
|
269
|
+
if (health === null || typeof health.liveSchema !== "boolean" || ![
|
|
270
|
+
"live",
|
|
271
|
+
"legacy",
|
|
272
|
+
"unavailable"
|
|
273
|
+
].includes(health.settings ?? "")) return void 0;
|
|
274
|
+
return {
|
|
275
|
+
settings: health.settings,
|
|
276
|
+
liveSchema: health.liveSchema
|
|
277
|
+
};
|
|
278
|
+
} catch {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//#endregion
|
|
249
283
|
//#region lib/types/comfyui-workflow.js
|
|
250
284
|
/** Pure ComfyUI API-workflow validation and placeholder injection. */
|
|
251
285
|
const COMFYUI_PROMPT_PLACEHOLDER = "{{prompt}}";
|
|
@@ -124783,7 +124817,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
124783
124817
|
`;
|
|
124784
124818
|
//#endregion
|
|
124785
124819
|
//#region lib/types/client/index.js
|
|
124786
|
-
console.info(`[dsh-image-gen] canvas bundle 2026-
|
|
124820
|
+
console.info(`[dsh-image-gen] canvas bundle 2026-10-08T04:58:18.947Z`);
|
|
124787
124821
|
/** Right-sidebar tab-type registration id (DSH 0.1.5 `sidebarRightTabs`). */
|
|
124788
124822
|
const SIDEBAR_STUDIO_TAB_ID = "dsh-image-gen/studio";
|
|
124789
124823
|
/** The tab kind: a page type opened by kind, recognizing no resource address. */
|
|
@@ -124795,6 +124829,10 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
124795
124829
|
defaultProvider: "默认 Provider",
|
|
124796
124830
|
defaultProviderHint: "Agent 生图默认使用;Studio 与工具调用可临时指定其他 Provider。",
|
|
124797
124831
|
settingsReadOnly: "设置由配置文件提供,只读;如需修改请编辑对应的配置来源。",
|
|
124832
|
+
settingsLoading: "正在加载图像生成设置,请稍候。",
|
|
124833
|
+
settingsRemote: "当前连接不支持保存到宿主,请在 DSH 本机页面修改设置。",
|
|
124834
|
+
settingsUnavailable: "宿主尚未提供图像生成设置,请检查插件是否已启用及其加载日志。",
|
|
124835
|
+
settingsIncompatible: "当前加载的设置库不支持保存。请将插件所在环境的 @deepseek-ai/schemastery 更新到 3.18.4 或兼容的 3.x 版本,并重启 DSH。",
|
|
124798
124836
|
providerGoogle: "Google Gemini",
|
|
124799
124837
|
providerOpenAI: "OpenAI",
|
|
124800
124838
|
providerOpenAICompat: "OpenAI 兼容(中转站)",
|
|
@@ -124944,6 +124982,10 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
124944
124982
|
defaultProvider: "Default provider",
|
|
124945
124983
|
defaultProviderHint: "Used by the Agent by default; the Studio and tool calls can switch per call.",
|
|
124946
124984
|
settingsReadOnly: "Settings come from a profile file and are read-only; edit that source to change them.",
|
|
124985
|
+
settingsLoading: "Settings are loading; please wait.",
|
|
124986
|
+
settingsRemote: "This connection cannot save settings to the host. Edit them from the local DSH page.",
|
|
124987
|
+
settingsUnavailable: "The host has not provided image generation settings. Check that the plugin is enabled and review its load logs.",
|
|
124988
|
+
settingsIncompatible: "The loaded settings library cannot save these settings. Update @deepseek-ai/schemastery in the plugin environment to 3.18.4 or a compatible 3.x version, then restart DSH.",
|
|
124947
124989
|
providerGoogle: "Google Gemini",
|
|
124948
124990
|
providerOpenAI: "OpenAI",
|
|
124949
124991
|
providerOpenAICompat: "OpenAI-compatible (relay)",
|
|
@@ -125397,7 +125439,8 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125397
125439
|
return {
|
|
125398
125440
|
getSnapshot: () => ({
|
|
125399
125441
|
value: void 0,
|
|
125400
|
-
writable: false
|
|
125442
|
+
writable: false,
|
|
125443
|
+
status: "unavailable"
|
|
125401
125444
|
}),
|
|
125402
125445
|
subscribe: () => () => {},
|
|
125403
125446
|
set: async () => false
|
|
@@ -125737,6 +125780,9 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125737
125780
|
function ImageGenerationSettingsCard(props) {
|
|
125738
125781
|
const [open, setOpen] = (0, react.useState)(false);
|
|
125739
125782
|
const [snapshot, setSnapshot] = (0, react.useState)(() => props.scope.getSnapshot());
|
|
125783
|
+
const [health, setHealth] = (0, react.useState)();
|
|
125784
|
+
const state = settingsState(snapshot, health);
|
|
125785
|
+
const settingsWritable = state === "ready";
|
|
125740
125786
|
const [lang, setLang] = (0, react.useState)(() => props.locale?.getSnapshot?.()?.active?.startsWith("en") ? "en" : "zh");
|
|
125741
125787
|
const [defaultProvider, setDefaultProvider] = (0, react.useState)(() => props.scope.getSnapshot().value?.provider ?? "google");
|
|
125742
125788
|
const [providerMessage, setProviderMessage] = (0, react.useState)("");
|
|
@@ -125758,9 +125804,28 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125758
125804
|
const [subTick, setSubTick] = (0, react.useState)(0);
|
|
125759
125805
|
const [subBusy, setSubBusy] = (0, react.useState)({});
|
|
125760
125806
|
const [subPending, setSubPending] = (0, react.useState)([]);
|
|
125761
|
-
(0, react.useEffect)(() =>
|
|
125762
|
-
|
|
125763
|
-
|
|
125807
|
+
(0, react.useEffect)(() => {
|
|
125808
|
+
const sync = () => {
|
|
125809
|
+
setSnapshot(props.scope.getSnapshot());
|
|
125810
|
+
};
|
|
125811
|
+
const unsubscribe = props.scope.subscribe(sync);
|
|
125812
|
+
sync();
|
|
125813
|
+
return unsubscribe;
|
|
125814
|
+
}, [props.scope]);
|
|
125815
|
+
(0, react.useEffect)(() => {
|
|
125816
|
+
if (!open || snapshot.mode === "memory") return void 0;
|
|
125817
|
+
const controller = new AbortController();
|
|
125818
|
+
fetchSettingsHealth(controller.signal).then((value) => {
|
|
125819
|
+
if (!controller.signal.aborted) setHealth(value);
|
|
125820
|
+
});
|
|
125821
|
+
return () => {
|
|
125822
|
+
controller.abort();
|
|
125823
|
+
};
|
|
125824
|
+
}, [
|
|
125825
|
+
open,
|
|
125826
|
+
snapshot.status,
|
|
125827
|
+
snapshot.mode
|
|
125828
|
+
]);
|
|
125764
125829
|
(0, react.useEffect)(() => {
|
|
125765
125830
|
return props.locale?.subscribe?.(() => {
|
|
125766
125831
|
setLang(props.locale?.getSnapshot?.()?.active?.startsWith("en") ? "en" : "zh");
|
|
@@ -125912,7 +125977,17 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125912
125977
|
if (params) for (const [k, v] of Object.entries(params)) text = text.replace(`{${k}}`, v);
|
|
125913
125978
|
return text;
|
|
125914
125979
|
};
|
|
125915
|
-
const
|
|
125980
|
+
const settingsMessage = state === "ready" ? void 0 : t({
|
|
125981
|
+
loading: "settingsLoading",
|
|
125982
|
+
remote: "settingsRemote",
|
|
125983
|
+
unavailable: "settingsUnavailable",
|
|
125984
|
+
readOnly: "settingsReadOnly",
|
|
125985
|
+
incompatible: "settingsIncompatible"
|
|
125986
|
+
}[state]);
|
|
125987
|
+
const saveSetting = async (field, value) => {
|
|
125988
|
+
if (settingsMessage !== void 0) throw new Error(settingsMessage);
|
|
125989
|
+
await writeSetting(props.scope, field, value, t("settingsWriteRejected"));
|
|
125990
|
+
};
|
|
125916
125991
|
const providerLabels = {
|
|
125917
125992
|
google: t("providerGoogle"),
|
|
125918
125993
|
openai: t("providerOpenAI"),
|
|
@@ -126445,7 +126520,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126445
126520
|
updateRow(provider, { keyInput: event.target.value });
|
|
126446
126521
|
},
|
|
126447
126522
|
placeholder: row.keyStatus === "configured" ? t("apiKeyPlaceholder") : "",
|
|
126448
|
-
disabled: !
|
|
126523
|
+
disabled: !settingsWritable || keyReadOnly || keyUnavailable
|
|
126449
126524
|
}),
|
|
126450
126525
|
(0, react_jsx_runtime.jsx)("span", {
|
|
126451
126526
|
className: "dsh-ig-hint",
|
|
@@ -126470,7 +126545,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126470
126545
|
updateRow(provider, { baseURL: event.target.value });
|
|
126471
126546
|
},
|
|
126472
126547
|
required: true,
|
|
126473
|
-
disabled: !
|
|
126548
|
+
disabled: !settingsWritable
|
|
126474
126549
|
}), provider !== "openai-compat" ? (0, react_jsx_runtime.jsx)("button", {
|
|
126475
126550
|
type: "button",
|
|
126476
126551
|
className: "dsh-ig-btn-reset",
|
|
@@ -126478,7 +126553,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126478
126553
|
onClick: () => {
|
|
126479
126554
|
updateRow(provider, { baseURL: DEFAULT_BASE_URLS[provider] });
|
|
126480
126555
|
},
|
|
126481
|
-
disabled: !
|
|
126556
|
+
disabled: !settingsWritable,
|
|
126482
126557
|
children: t("reset")
|
|
126483
126558
|
}) : null]
|
|
126484
126559
|
}),
|
|
@@ -126506,7 +126581,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126506
126581
|
},
|
|
126507
126582
|
list: `dsh-ig-${provider}-model-options`,
|
|
126508
126583
|
required: provider !== "openai-compat",
|
|
126509
|
-
disabled: !
|
|
126584
|
+
disabled: !settingsWritable
|
|
126510
126585
|
}),
|
|
126511
126586
|
(0, react_jsx_runtime.jsx)("datalist", {
|
|
126512
126587
|
id: `dsh-ig-${provider}-model-options`,
|
|
@@ -126515,7 +126590,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126515
126590
|
(0, react_jsx_runtime.jsx)("button", {
|
|
126516
126591
|
type: "button",
|
|
126517
126592
|
className: "dsh-ig-btn-secondary",
|
|
126518
|
-
disabled: row.fetchingModels || row.saving || !
|
|
126593
|
+
disabled: row.fetchingModels || row.saving || !settingsWritable,
|
|
126519
126594
|
onClick: () => {
|
|
126520
126595
|
fetchProviderModels(provider);
|
|
126521
126596
|
},
|
|
@@ -126529,7 +126604,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126529
126604
|
updateRow(provider, { model: event.target.value });
|
|
126530
126605
|
},
|
|
126531
126606
|
required: true,
|
|
126532
|
-
disabled: !
|
|
126607
|
+
disabled: !settingsWritable
|
|
126533
126608
|
}),
|
|
126534
126609
|
modelPullSupported(provider) ? row.modelFetchMessage.length > 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
126535
126610
|
className: `dsh-ig-hint${row.modelFetchIsError ? " dsh-ig-hint-error" : ""}`,
|
|
@@ -126554,7 +126629,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126554
126629
|
onChange: (event) => {
|
|
126555
126630
|
updateRow(provider, { editFormat: parseEditFormat(event.target.value) });
|
|
126556
126631
|
},
|
|
126557
|
-
disabled: !
|
|
126632
|
+
disabled: !settingsWritable,
|
|
126558
126633
|
children: [
|
|
126559
126634
|
(0, react_jsx_runtime.jsx)("option", {
|
|
126560
126635
|
value: "multipart",
|
|
@@ -126590,7 +126665,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126590
126665
|
onChange: (event) => {
|
|
126591
126666
|
updateRow(provider, { outputFormat: event.target.value === "png" ? "png" : "jpeg" });
|
|
126592
126667
|
},
|
|
126593
|
-
disabled: !
|
|
126668
|
+
disabled: !settingsWritable,
|
|
126594
126669
|
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
126595
126670
|
value: "jpeg",
|
|
126596
126671
|
children: t("arkOutputFormatJpeg")
|
|
@@ -126618,7 +126693,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126618
126693
|
onChange: (event) => {
|
|
126619
126694
|
updateRow(provider, { watermark: event.target.value === "on" });
|
|
126620
126695
|
},
|
|
126621
|
-
disabled: !
|
|
126696
|
+
disabled: !settingsWritable,
|
|
126622
126697
|
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
126623
126698
|
value: "on",
|
|
126624
126699
|
children: t("arkWatermarkOn")
|
|
@@ -126646,7 +126721,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126646
126721
|
onChange: (event) => {
|
|
126647
126722
|
updateRow(provider, { background: event.target.value === "transparent" ? "transparent" : "opaque" });
|
|
126648
126723
|
},
|
|
126649
|
-
disabled: !
|
|
126724
|
+
disabled: !settingsWritable,
|
|
126650
126725
|
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
126651
126726
|
value: "opaque",
|
|
126652
126727
|
children: t("arkBackgroundOpaque")
|
|
@@ -126677,7 +126752,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126677
126752
|
},
|
|
126678
126753
|
placeholder: t("editExtraPlaceholder"),
|
|
126679
126754
|
rows: 2,
|
|
126680
|
-
disabled: !
|
|
126755
|
+
disabled: !settingsWritable
|
|
126681
126756
|
}),
|
|
126682
126757
|
(0, react_jsx_runtime.jsx)("span", {
|
|
126683
126758
|
className: "dsh-ig-hint",
|
|
@@ -126715,7 +126790,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126715
126790
|
(0, react_jsx_runtime.jsx)("button", {
|
|
126716
126791
|
className: "dsh-ig-save",
|
|
126717
126792
|
type: "submit",
|
|
126718
|
-
disabled: row.saving || row.testing || row.fetchingModels || !
|
|
126793
|
+
disabled: row.saving || row.testing || row.fetchingModels || !settingsWritable,
|
|
126719
126794
|
children: row.saving ? t("saving") : t("save")
|
|
126720
126795
|
})
|
|
126721
126796
|
]
|
|
@@ -126752,7 +126827,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126752
126827
|
updateRow("comfyui", { baseURL: event.target.value });
|
|
126753
126828
|
},
|
|
126754
126829
|
required: true,
|
|
126755
|
-
disabled: !
|
|
126830
|
+
disabled: !settingsWritable
|
|
126756
126831
|
}), (0, react_jsx_runtime.jsx)("button", {
|
|
126757
126832
|
type: "button",
|
|
126758
126833
|
className: "dsh-ig-btn-reset",
|
|
@@ -126760,7 +126835,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126760
126835
|
onClick: () => {
|
|
126761
126836
|
updateRow("comfyui", { baseURL: DEFAULT_BASE_URLS.comfyui });
|
|
126762
126837
|
},
|
|
126763
|
-
disabled: !
|
|
126838
|
+
disabled: !settingsWritable,
|
|
126764
126839
|
children: t("reset")
|
|
126765
126840
|
})]
|
|
126766
126841
|
}),
|
|
@@ -126866,7 +126941,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126866
126941
|
updateRow("comfyui", { timeoutSeconds: Number(event.target.value) });
|
|
126867
126942
|
},
|
|
126868
126943
|
required: true,
|
|
126869
|
-
disabled: !
|
|
126944
|
+
disabled: !settingsWritable
|
|
126870
126945
|
}),
|
|
126871
126946
|
(0, react_jsx_runtime.jsx)("span", {
|
|
126872
126947
|
className: "dsh-ig-hint",
|
|
@@ -126893,7 +126968,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126893
126968
|
}), (0, react_jsx_runtime.jsx)("button", {
|
|
126894
126969
|
className: "dsh-ig-save",
|
|
126895
126970
|
type: "submit",
|
|
126896
|
-
disabled: row.saving || !
|
|
126971
|
+
disabled: row.saving || !settingsWritable || row.workflows.length === 0,
|
|
126897
126972
|
children: row.saving ? t("saving") : t("save")
|
|
126898
126973
|
})]
|
|
126899
126974
|
})]
|
|
@@ -127014,7 +127089,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
127014
127089
|
}), (0, react_jsx_runtime.jsx)("button", {
|
|
127015
127090
|
className: "dsh-ig-save",
|
|
127016
127091
|
type: "submit",
|
|
127017
|
-
disabled: row.saving || !
|
|
127092
|
+
disabled: row.saving || !settingsWritable,
|
|
127018
127093
|
children: row.saving ? t("saving") : t("save")
|
|
127019
127094
|
})]
|
|
127020
127095
|
})]
|
|
@@ -127103,10 +127178,10 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
127103
127178
|
}), open ? (0, react_jsx_runtime.jsxs)("div", {
|
|
127104
127179
|
className: "dsh-ig-body",
|
|
127105
127180
|
children: [
|
|
127106
|
-
|
|
127181
|
+
settingsMessage !== void 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
127107
127182
|
className: "dsh-ig-status dsh-ig-status-readonly",
|
|
127108
127183
|
role: "note",
|
|
127109
|
-
children:
|
|
127184
|
+
children: settingsMessage
|
|
127110
127185
|
}) : null,
|
|
127111
127186
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
127112
127187
|
className: "dsh-ig-field",
|
|
@@ -127128,7 +127203,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
127128
127203
|
onChange: () => {
|
|
127129
127204
|
selectDefaultProvider(provider);
|
|
127130
127205
|
},
|
|
127131
|
-
disabled: !
|
|
127206
|
+
disabled: !settingsWritable
|
|
127132
127207
|
}), providerLabels[provider]]
|
|
127133
127208
|
}, provider))
|
|
127134
127209
|
}),
|
|
@@ -127164,7 +127239,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
127164
127239
|
onChange: (event) => {
|
|
127165
127240
|
toggleSaveToWorkspace(event.target.checked);
|
|
127166
127241
|
},
|
|
127167
|
-
disabled: !
|
|
127242
|
+
disabled: !settingsWritable
|
|
127168
127243
|
}), (0, react_jsx_runtime.jsx)("span", {
|
|
127169
127244
|
className: "dsh-ig-label",
|
|
127170
127245
|
children: t("saveToWorkspace")
|
|
@@ -127194,7 +127269,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
127194
127269
|
if (event.key === "Enter") commitWorkspaceFolder();
|
|
127195
127270
|
},
|
|
127196
127271
|
placeholder: "dsh-image-gen",
|
|
127197
|
-
disabled: !
|
|
127272
|
+
disabled: !settingsWritable
|
|
127198
127273
|
}),
|
|
127199
127274
|
(0, react_jsx_runtime.jsx)("span", {
|
|
127200
127275
|
className: "dsh-ig-hint",
|
|
@@ -127225,7 +127300,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
127225
127300
|
onChange: (event) => {
|
|
127226
127301
|
toggleShowPill(event.target.checked);
|
|
127227
127302
|
},
|
|
127228
|
-
disabled: !
|
|
127303
|
+
disabled: !settingsWritable
|
|
127229
127304
|
}), (0, react_jsx_runtime.jsx)("span", {
|
|
127230
127305
|
className: "dsh-ig-label",
|
|
127231
127306
|
children: t("showPill")
|
package/lib/index.js
CHANGED
|
@@ -5596,6 +5596,8 @@ const INSPIRATION_ROUTE = "/plugins/dsh-image-gen/inspiration";
|
|
|
5596
5596
|
const SAVE_WORKSPACE_ROUTE = "/plugins/dsh-image-gen/save-workspace";
|
|
5597
5597
|
/** Browser route the settings card probes provider connectivity through. */
|
|
5598
5598
|
const TEST_CONNECTION_ROUTE = "/plugins/dsh-image-gen/test";
|
|
5599
|
+
/** Non-secret settings capability probe, available even when the host cannot serve a form. */
|
|
5600
|
+
const SETTINGS_HEALTH_ROUTE = "/plugins/dsh-image-gen/settings-health";
|
|
5599
5601
|
/** Browser route the workbench infinite canvas pushes live state through. */
|
|
5600
5602
|
const CANVAS_STATE_ROUTE = "/plugins/dsh-image-gen/canvas-state";
|
|
5601
5603
|
/** Upload a selected canvas original to the host attachment store. */
|
|
@@ -28245,6 +28247,27 @@ function jsonError(res, status, code) {
|
|
|
28245
28247
|
json(res, status, { error: code });
|
|
28246
28248
|
}
|
|
28247
28249
|
//#endregion
|
|
28250
|
+
//#region lib/types/settings-health.js
|
|
28251
|
+
function describeSettingsHealth(settings, schema) {
|
|
28252
|
+
const service = settings;
|
|
28253
|
+
const fields = Object.values(schema.dict ?? {});
|
|
28254
|
+
return {
|
|
28255
|
+
settings: typeof service?.installSection === "function" ? "legacy" : typeof service?.describe === "function" ? "live" : "unavailable",
|
|
28256
|
+
liveSchema: fields.length > 0 && fields.every((field) => field.meta.volatile === true)
|
|
28257
|
+
};
|
|
28258
|
+
}
|
|
28259
|
+
function serveSettingsHealth(req, res, health) {
|
|
28260
|
+
res.setHeader("cache-control", "no-store");
|
|
28261
|
+
if (req.method !== "GET") {
|
|
28262
|
+
res.statusCode = 405;
|
|
28263
|
+
res.setHeader("allow", "GET");
|
|
28264
|
+
res.end();
|
|
28265
|
+
return;
|
|
28266
|
+
}
|
|
28267
|
+
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
28268
|
+
res.end(JSON.stringify(health));
|
|
28269
|
+
}
|
|
28270
|
+
//#endregion
|
|
28248
28271
|
//#region lib/types/index.js
|
|
28249
28272
|
const name = "dsh-image-gen";
|
|
28250
28273
|
const inject = [
|
|
@@ -28270,12 +28293,17 @@ function apply(ctx, config = {}) {
|
|
|
28270
28293
|
const canvasMirror = new CanvasMirror();
|
|
28271
28294
|
const subscriptionManager = new SubscriptionManager(ctx);
|
|
28272
28295
|
registerSubscriptionRoutes(ctx, subscriptionManager);
|
|
28273
|
-
installImageSettings(ctx, current(), {
|
|
28296
|
+
const settingsHealth = installImageSettings(ctx, current(), {
|
|
28274
28297
|
setSource: (source) => {
|
|
28275
28298
|
current = () => migrateOpenAICompatConfig(plainConfig(source()));
|
|
28276
28299
|
},
|
|
28277
28300
|
onChange: () => {}
|
|
28278
28301
|
});
|
|
28302
|
+
ctx.effect(() => ctx.webServer.register({
|
|
28303
|
+
kind: "exact",
|
|
28304
|
+
path: SETTINGS_HEALTH_ROUTE,
|
|
28305
|
+
handler: (req, res) => serveSettingsHealth(req, res, settingsHealth())
|
|
28306
|
+
}), "dsh-image-gen: settings health");
|
|
28279
28307
|
ctx.effect(() => ctx.webServer.register({
|
|
28280
28308
|
kind: "exact",
|
|
28281
28309
|
path: IMAGE_ROUTE,
|
|
@@ -29240,14 +29268,22 @@ function imagePresentation(result) {
|
|
|
29240
29268
|
* on the service, so the namespace registers through it; DSH 0.1.7 replaced it
|
|
29241
29269
|
* with schema-derived forms served by the loader itself (keyed by entry id),
|
|
29242
29270
|
* so its service carries no installer and a host without any settings service
|
|
29243
|
-
* simply never runs the callback
|
|
29271
|
+
* simply never runs the callback. A modern host with an unmarked schema is
|
|
29272
|
+
* incompatible and must be diagnosed, while old hosts keep their installer.
|
|
29244
29273
|
*/
|
|
29245
29274
|
function installImageSettings(ctx, config, hooks) {
|
|
29275
|
+
let service;
|
|
29246
29276
|
ctx.inject(["settings"], (settingsCtx) => {
|
|
29247
29277
|
const settings = settingsCtx.settings;
|
|
29248
|
-
|
|
29249
|
-
|
|
29278
|
+
service = settings;
|
|
29279
|
+
const health = describeSettingsHealth(settings, Config);
|
|
29280
|
+
if (health.settings === "live" && !health.liveSchema) ctx.logger.warn("dsh-image-gen: the loaded schema lacks volatile fields required by this DSH settings service. Install @deepseek-ai/schemastery >=3.18.4 <4 in the plugin profile and check which copy the plugin resolves; settings cannot be saved with this schema.");
|
|
29281
|
+
if (typeof settings.installSection === "function") settings.installSection(ctx, IMAGE_GENERATION_NAMESPACE, Config, config, hooks);
|
|
29282
|
+
return () => {
|
|
29283
|
+
service = void 0;
|
|
29284
|
+
};
|
|
29250
29285
|
});
|
|
29286
|
+
return () => describeSettingsHealth(service, Config);
|
|
29251
29287
|
}
|
|
29252
29288
|
//#endregion
|
|
29253
29289
|
export { CANVAS_STATE_ROUTE, Config, DELETE_ROUTE, IMAGE_ROUTE, IMPORT_ROUTE, INSPIRATION_ROUTE, SAVE_WORKSPACE_ROUTE, STUDIO_ROUTE, TEST_CONNECTION_ROUTE, apply, imageAttachmentFromMeta, inject, name };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import './tl/css-supports-shim.js';
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
writable: boolean;
|
|
6
|
-
}
|
|
3
|
+
import { type SettingsScopeSnapshot } from './settings-state.js';
|
|
4
|
+
export type { SettingsScopeSnapshot } from './settings-state.js';
|
|
7
5
|
export interface SettingsScope<T> {
|
|
8
6
|
getSnapshot(): SettingsScopeSnapshot<T>;
|
|
9
7
|
subscribe(listener: () => void): () => void;
|
|
@@ -116,4 +114,3 @@ export declare function GeneratedImageCard(props: ImageCardProps): import("react
|
|
|
116
114
|
export declare function GeneratedImagesCard(props: ImageCardProps): import("react").JSX.Element;
|
|
117
115
|
/** Render modern image artifacts as final conversation output instead of Tool process content. */
|
|
118
116
|
export declare function PromotedImageResultNode(props: ImageResultNodeProps): import("react").JSX.Element;
|
|
119
|
-
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Preserve modern form states while accepting legacy scopes without status/mode. */
|
|
2
|
+
import { type SettingsHealth } from '../shared.js';
|
|
3
|
+
export interface SettingsScopeSnapshot<T> {
|
|
4
|
+
value: T | undefined;
|
|
5
|
+
writable: boolean;
|
|
6
|
+
status?: 'loading' | 'ready' | 'unavailable';
|
|
7
|
+
mode?: 'host' | 'memory';
|
|
8
|
+
}
|
|
9
|
+
export type SettingsState = 'ready' | 'loading' | 'remote' | 'unavailable' | 'readOnly' | 'incompatible';
|
|
10
|
+
export declare function settingsState(snapshot: SettingsScopeSnapshot<unknown>, health?: SettingsHealth): SettingsState;
|
|
11
|
+
/** A failed probe cannot identify the cause; keep the host's own form state. */
|
|
12
|
+
export declare function fetchSettingsHealth(signal: AbortSignal): Promise<SettingsHealth | undefined>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Diagnose the actual host service and schema without reading any settings values. */
|
|
2
|
+
import type z from '@deepseek-ai/schemastery';
|
|
3
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
|
+
import type { SettingsHealth } from './shared.js';
|
|
5
|
+
export declare function describeSettingsHealth(settings: unknown, schema: z): SettingsHealth;
|
|
6
|
+
export declare function serveSettingsHealth(req: IncomingMessage, res: ServerResponse, health: SettingsHealth): void;
|
package/lib/types/shared.d.ts
CHANGED
|
@@ -14,6 +14,12 @@ export declare const INSPIRATION_ROUTE = "/plugins/dsh-image-gen/inspiration";
|
|
|
14
14
|
export declare const SAVE_WORKSPACE_ROUTE = "/plugins/dsh-image-gen/save-workspace";
|
|
15
15
|
/** Browser route the settings card probes provider connectivity through. */
|
|
16
16
|
export declare const TEST_CONNECTION_ROUTE = "/plugins/dsh-image-gen/test";
|
|
17
|
+
/** Non-secret settings capability probe, available even when the host cannot serve a form. */
|
|
18
|
+
export declare const SETTINGS_HEALTH_ROUTE = "/plugins/dsh-image-gen/settings-health";
|
|
19
|
+
export interface SettingsHealth {
|
|
20
|
+
settings: 'unavailable' | 'legacy' | 'live';
|
|
21
|
+
liveSchema: boolean;
|
|
22
|
+
}
|
|
17
23
|
/** Browser route the workbench infinite canvas pushes live state through. */
|
|
18
24
|
export declare const CANVAS_STATE_ROUTE = "/plugins/dsh-image-gen/canvas-state";
|
|
19
25
|
/** Upload a selected canvas original to the host attachment store. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-image-gen",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "Bring ChatGPT-like image generation to DeepSeek Harness — Gemini, OpenAI, Seedream, DashScope, local ComfyUI & more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "shanliuling",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"build": "tsc && tsdown",
|
|
61
61
|
"prepare": "pnpm run build",
|
|
62
62
|
"test": "vitest run",
|
|
63
|
+
"test:package": "node scripts/check-package.mjs",
|
|
63
64
|
"pack:check": "pnpm pack --dry-run"
|
|
64
65
|
},
|
|
65
66
|
"engines": {
|
|
@@ -90,7 +91,7 @@
|
|
|
90
91
|
],
|
|
91
92
|
"peerDependencies": {
|
|
92
93
|
"@deepseek-ai/cordis": ">=4.0.0 <5",
|
|
93
|
-
"@deepseek-ai/schemastery": ">=3.18.
|
|
94
|
+
"@deepseek-ai/schemastery": ">=3.18.4 <4",
|
|
94
95
|
"react": ">=18.2.0 <19"
|
|
95
96
|
},
|
|
96
97
|
"peerDependenciesMeta": {
|