dsh-tool-vision 0.6.0 → 0.6.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/README.md +1 -1
- package/client.js +3 -3
- package/cordis.patch.yml +8 -8
- package/package.json +2 -2
- package/vendor/dsh-settings-expose.js +75 -75
package/README.md
CHANGED
|
@@ -169,7 +169,7 @@ Example endpoints (`baseURL`):
|
|
|
169
169
|
> once more** and the section appears. A dsh update overwrites the patch;
|
|
170
170
|
> the next plugin start re-applies it.
|
|
171
171
|
> - Settings changes hot-apply (no restart needed).
|
|
172
|
-
> - Tested against DSH `0.1.0-rc.6`.
|
|
172
|
+
> - Tested against DSH `0.1.0-rc.6`, `0.1.0-rc.7`, and `0.1.0-rc.8`.
|
|
173
173
|
|
|
174
174
|
## Pixel-level vision tools (v0.6.0, ported from dsh-vision-router)
|
|
175
175
|
|
package/client.js
CHANGED
|
@@ -183,7 +183,7 @@ window.__ModuleLoader__.load({
|
|
|
183
183
|
var [error, setError] = react.useState(null);
|
|
184
184
|
|
|
185
185
|
react.useEffect(function () {
|
|
186
|
-
scope.load();
|
|
186
|
+
if (typeof scope.load === "function") scope.load();
|
|
187
187
|
var alive = true;
|
|
188
188
|
var sync = function () { if (alive) setSnapshot(scope.getSnapshot()); };
|
|
189
189
|
var un = typeof scope.subscribe === "function" ? scope.subscribe(sync) : null;
|
|
@@ -246,7 +246,7 @@ window.__ModuleLoader__.load({
|
|
|
246
246
|
});
|
|
247
247
|
Promise.all(writes).then(function () {
|
|
248
248
|
setBusy(false); setNotice(t("saved"));
|
|
249
|
-
if (scope.load) scope.load();
|
|
249
|
+
if (typeof scope.load === "function") scope.load();
|
|
250
250
|
}).catch(function (e) {
|
|
251
251
|
setBusy(false); setError(t("error") + ": " + String(e && e.message || e));
|
|
252
252
|
});
|
|
@@ -482,7 +482,7 @@ window.__ModuleLoader__.load({
|
|
|
482
482
|
var t = ctx.locale.bind(NS);
|
|
483
483
|
ctx.effect(function () { return ctx.locale.register(NS, { zh: zh, en: en }); }, "dsh-tool-vision: dictionaries");
|
|
484
484
|
var scope = ctx.settingsScope.bind({ namespace: "tool-vision" });
|
|
485
|
-
scope.load();
|
|
485
|
+
if (typeof scope.load === "function") scope.load();
|
|
486
486
|
attachBridgePreview(ctx, scope);
|
|
487
487
|
ctx.slots.inject("settings.section", function () {
|
|
488
488
|
return ctx.slots.register({
|
package/cordis.patch.yml
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# dsh-tool-vision — bundle patch layer
|
|
2
|
-
#
|
|
3
|
-
# Declares the plugin as a Cordis loader entry, making the package a standard
|
|
4
|
-
# profile bundle: `dsh plugin --profile <p> add dsh-tool-vision` installs and
|
|
5
|
-
# mounts it without manual cordis.patch.yml edits.
|
|
6
|
-
- insert:
|
|
7
|
-
- id: tool-vision
|
|
8
|
-
name: 'dsh-tool-vision'
|
|
1
|
+
# dsh-tool-vision — bundle patch layer
|
|
2
|
+
#
|
|
3
|
+
# Declares the plugin as a Cordis loader entry, making the package a standard
|
|
4
|
+
# profile bundle: `dsh plugin --profile <p> add dsh-tool-vision` installs and
|
|
5
|
+
# mounts it without manual cordis.patch.yml edits.
|
|
6
|
+
- insert:
|
|
7
|
+
- id: tool-vision
|
|
8
|
+
name: 'dsh-tool-vision'
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-tool-vision",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "DeepSeek Harness 外置视觉模型插件:inspect_image 把本地图片或 http(s) 图片 URL 发给任意 OpenAI 兼容端点,视觉模型看图的文字回答直接带回对话;附 Web UI 设置栏。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"test": "node tests/preview-regex.test.mjs && node tests/preview-route.test.mjs && node tests/auto-image.test.mjs && node --test tests/vision-tools.test.js tests/vision-tools-tools.test.js"
|
|
8
|
+
"test": "node tests/preview-regex.test.mjs && node tests/preview-route.test.mjs && node tests/auto-image.test.mjs && node --test tests/vision-tools.test.js tests/vision-tools-tools.test.js && node tests/settings-scope-compat.test.mjs"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./index.js",
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* dsh-host-apiproxy exposes only namespaces listed in its hard-coded
|
|
3
|
-
* WEB_SETTINGS_NAMESPACES allowlist to the Web settings client. A namespace
|
|
4
|
-
* registered by a third-party plugin answers `settings-not-exposed` even
|
|
5
|
-
* though it is registered — upstream explicitly defers letting plugins
|
|
6
|
-
* expose their own configuration.
|
|
7
|
-
*
|
|
8
|
-
* This module idempotently patches that allowlist in the dsh installation
|
|
9
|
-
* actually loaded by the host process, so the plugin's settings section
|
|
10
|
-
* becomes visible in the Web UI without manual edits. A dsh update
|
|
11
|
-
* overwrites the file; the next plugin start re-patches it.
|
|
12
|
-
*/
|
|
13
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
-
import { createRequire } from "node:module";
|
|
15
|
-
import { dirname, join, sep } from "node:path";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Ensure `nsName` is present in dsh-host-apiproxy's WEB_SETTINGS_NAMESPACES.
|
|
19
|
-
* No-op when already exposed or when the file cannot be located/patched.
|
|
20
|
-
* @param {import("cordis").Context} ctx
|
|
21
|
-
* @param {string} nsName - settings namespace short name (e.g. "tdai-memory").
|
|
22
|
-
* @param {{info?: Function, warn?: Function}} logger - dsh logger.
|
|
23
|
-
*/
|
|
24
|
-
export function ensureSettingsNamespaceExposed(ctx, nsName, logger) {
|
|
25
|
-
void ctx;
|
|
26
|
-
try {
|
|
27
|
-
const target = findApiproxyIndex();
|
|
28
|
-
if (!target) {
|
|
29
|
-
logger?.warn?.(`[settings-expose] could not locate dsh-host-apiproxy; add "${nsName}" to WEB_SETTINGS_NAMESPACES in dsh-host-apiproxy/lib/index.js to get a Web settings section`);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
let src;
|
|
33
|
-
try {
|
|
34
|
-
src = readFileSync(target, "utf8");
|
|
35
|
-
} catch (error) {
|
|
36
|
-
logger?.warn?.(`[settings-expose] cannot read ${target}: ${String(error)}`);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const body = src.match(/const WEB_SETTINGS_NAMESPACES = \[([\s\S]*?)\];/)?.[1] ?? "";
|
|
40
|
-
if (body.includes(`"${nsName}"`)) return; // already exposed (manual or previous patch)
|
|
41
|
-
const patched = src.replace(/(const WEB_SETTINGS_NAMESPACES = \[[\s\S]*?)(\n\s*\];)/, (_, pre, post) => {
|
|
42
|
-
const trailingComma = /,\s*$/.test(pre) ? "" : ",";
|
|
43
|
-
const sep2 = pre.trimEnd().endsWith("[") ? "" : trailingComma;
|
|
44
|
-
return `${pre}${sep2}\n\t"${nsName}"${post}`;
|
|
45
|
-
});
|
|
46
|
-
if (patched === src) {
|
|
47
|
-
logger?.warn?.(`[settings-expose] allowlist pattern not found in ${target}; add "${nsName}" to WEB_SETTINGS_NAMESPACES manually`);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
writeFileSync(target, patched, "utf8");
|
|
51
|
-
logger?.info?.(`[settings-expose] added "${nsName}" to WEB_SETTINGS_NAMESPACES (${target}) — restart dsh web for the settings section to appear`);
|
|
52
|
-
} catch (error) {
|
|
53
|
-
logger?.warn?.(`[settings-expose] failed: ${String(error)}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function findApiproxyIndex() {
|
|
58
|
-
// 1) The host process has already loaded dsh-host-apiproxy: read the real
|
|
59
|
-
// module path from the CommonJS module cache (any install layout).
|
|
60
|
-
try {
|
|
61
|
-
const Module = createRequire(import.meta.url)("module");
|
|
62
|
-
const cache = Module._cache ?? {};
|
|
63
|
-
for (const key of Object.keys(cache)) {
|
|
64
|
-
if (key.includes(`${sep}dsh-host-apiproxy${sep}`) && key.endsWith(`${sep}index.js`)) return key;
|
|
65
|
-
}
|
|
66
|
-
} catch { /* fall through */ }
|
|
67
|
-
// 2) Fallback: sibling of @deepseek-ai/dsh-settings (dsh's nested layout).
|
|
68
|
-
try {
|
|
69
|
-
const require = createRequire(import.meta.url);
|
|
70
|
-
const settingsEntry = require.resolve("@deepseek-ai/dsh-settings");
|
|
71
|
-
const candidate = join(dirname(dirname(dirname(settingsEntry))), "dsh-host-apiproxy", "lib", "index.js");
|
|
72
|
-
if (existsSync(candidate)) return candidate;
|
|
73
|
-
} catch { /* fall through */ }
|
|
74
|
-
return "";
|
|
75
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* dsh-host-apiproxy exposes only namespaces listed in its hard-coded
|
|
3
|
+
* WEB_SETTINGS_NAMESPACES allowlist to the Web settings client. A namespace
|
|
4
|
+
* registered by a third-party plugin answers `settings-not-exposed` even
|
|
5
|
+
* though it is registered — upstream explicitly defers letting plugins
|
|
6
|
+
* expose their own configuration.
|
|
7
|
+
*
|
|
8
|
+
* This module idempotently patches that allowlist in the dsh installation
|
|
9
|
+
* actually loaded by the host process, so the plugin's settings section
|
|
10
|
+
* becomes visible in the Web UI without manual edits. A dsh update
|
|
11
|
+
* overwrites the file; the next plugin start re-patches it.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
15
|
+
import { dirname, join, sep } from "node:path";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Ensure `nsName` is present in dsh-host-apiproxy's WEB_SETTINGS_NAMESPACES.
|
|
19
|
+
* No-op when already exposed or when the file cannot be located/patched.
|
|
20
|
+
* @param {import("cordis").Context} ctx
|
|
21
|
+
* @param {string} nsName - settings namespace short name (e.g. "tdai-memory").
|
|
22
|
+
* @param {{info?: Function, warn?: Function}} logger - dsh logger.
|
|
23
|
+
*/
|
|
24
|
+
export function ensureSettingsNamespaceExposed(ctx, nsName, logger) {
|
|
25
|
+
void ctx;
|
|
26
|
+
try {
|
|
27
|
+
const target = findApiproxyIndex();
|
|
28
|
+
if (!target) {
|
|
29
|
+
logger?.warn?.(`[settings-expose] could not locate dsh-host-apiproxy; add "${nsName}" to WEB_SETTINGS_NAMESPACES in dsh-host-apiproxy/lib/index.js to get a Web settings section`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let src;
|
|
33
|
+
try {
|
|
34
|
+
src = readFileSync(target, "utf8");
|
|
35
|
+
} catch (error) {
|
|
36
|
+
logger?.warn?.(`[settings-expose] cannot read ${target}: ${String(error)}`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const body = src.match(/const WEB_SETTINGS_NAMESPACES = \[([\s\S]*?)\];/)?.[1] ?? "";
|
|
40
|
+
if (body.includes(`"${nsName}"`)) return; // already exposed (manual or previous patch)
|
|
41
|
+
const patched = src.replace(/(const WEB_SETTINGS_NAMESPACES = \[[\s\S]*?)(\n\s*\];)/, (_, pre, post) => {
|
|
42
|
+
const trailingComma = /,\s*$/.test(pre) ? "" : ",";
|
|
43
|
+
const sep2 = pre.trimEnd().endsWith("[") ? "" : trailingComma;
|
|
44
|
+
return `${pre}${sep2}\n\t"${nsName}"${post}`;
|
|
45
|
+
});
|
|
46
|
+
if (patched === src) {
|
|
47
|
+
logger?.warn?.(`[settings-expose] allowlist pattern not found in ${target}; add "${nsName}" to WEB_SETTINGS_NAMESPACES manually`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
writeFileSync(target, patched, "utf8");
|
|
51
|
+
logger?.info?.(`[settings-expose] added "${nsName}" to WEB_SETTINGS_NAMESPACES (${target}) — restart dsh web for the settings section to appear`);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
logger?.warn?.(`[settings-expose] failed: ${String(error)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function findApiproxyIndex() {
|
|
58
|
+
// 1) The host process has already loaded dsh-host-apiproxy: read the real
|
|
59
|
+
// module path from the CommonJS module cache (any install layout).
|
|
60
|
+
try {
|
|
61
|
+
const Module = createRequire(import.meta.url)("module");
|
|
62
|
+
const cache = Module._cache ?? {};
|
|
63
|
+
for (const key of Object.keys(cache)) {
|
|
64
|
+
if (key.includes(`${sep}dsh-host-apiproxy${sep}`) && key.endsWith(`${sep}index.js`)) return key;
|
|
65
|
+
}
|
|
66
|
+
} catch { /* fall through */ }
|
|
67
|
+
// 2) Fallback: sibling of @deepseek-ai/dsh-settings (dsh's nested layout).
|
|
68
|
+
try {
|
|
69
|
+
const require = createRequire(import.meta.url);
|
|
70
|
+
const settingsEntry = require.resolve("@deepseek-ai/dsh-settings");
|
|
71
|
+
const candidate = join(dirname(dirname(dirname(settingsEntry))), "dsh-host-apiproxy", "lib", "index.js");
|
|
72
|
+
if (existsSync(candidate)) return candidate;
|
|
73
|
+
} catch { /* fall through */ }
|
|
74
|
+
return "";
|
|
75
|
+
}
|