@xlight-oss/visionary-dsh 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 +5 -3
- package/lib/index.mjs +78 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,13 +31,15 @@ dsh plugin --profile web add /path/to/packages/dsh-plugin
|
|
|
31
31
|
|
|
32
32
|
## 前置要求
|
|
33
33
|
|
|
34
|
-
`visionary-server`
|
|
34
|
+
`visionary-server` 二进制需可被找到(三者任一,按优先序):
|
|
35
35
|
|
|
36
36
|
1. `Config.binaryPath`(插件配置,绝对路径)
|
|
37
37
|
2. `DEEPSEEK_VISIONARY_BIN` 环境变量
|
|
38
|
-
3. 在 PATH
|
|
38
|
+
3. 在 PATH 中(Windows 额外支持 npm 全局包的 `.cmd` / `.ps1` shim——插件自动解析 shim 定位包内 `node_modules/.bin_real/visionary-server.exe` 真身)
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
二进制路径在**每次工具调用时**重新解析(懒解析):修改 PATH 或设置 `DEEPSEEK_VISIONARY_BIN` 后无需重启 DSH 即生效。
|
|
41
|
+
|
|
42
|
+
安装二进制见 [DeepSeek Visionary 安装章节](https://github.com/xlight/deepseek-visionary#安装)(install.sh / brew / npm)。未找到时工具返回含安装指引的错误(Windows 提示 npm / binaryPath 指引)。
|
|
41
43
|
|
|
42
44
|
## 配置
|
|
43
45
|
|
package/lib/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
16
16
|
import z from "@deepseek-ai/schemastery";
|
|
17
17
|
import { spawn } from "node:child_process";
|
|
18
|
-
import { statSync } from "node:fs";
|
|
18
|
+
import { statSync, readFileSync } from "node:fs";
|
|
19
19
|
import { promises as fs } from "node:fs";
|
|
20
20
|
import os from "node:os";
|
|
21
21
|
import path from "node:path";
|
|
@@ -52,6 +52,43 @@ const Config = z.object({
|
|
|
52
52
|
|
|
53
53
|
// --- binary resolution -------------------------------------------------------
|
|
54
54
|
|
|
55
|
+
// npm 全局安装(@xlight-oss/visionary-server)在 Windows 上只在 PATH 生成
|
|
56
|
+
// .cmd/.ps1 shim(node 包装脚本),真实 exe 在包内 node_modules/.bin_real/。
|
|
57
|
+
// shim 层用 spawnSync + stdio:"inherit" 转发——直接 spawn shim 会丢 stdout 管道、
|
|
58
|
+
// kill 链路断裂(孤儿进程)。故:解析 shim 文本定位 exe 真身,spawn 真身。
|
|
59
|
+
const NPM_PKG_SHIM_RE =
|
|
60
|
+
/node_modules[\\/]@xlight-oss[\\/]visionary-server[\\/]run-visionary-server\.js/;
|
|
61
|
+
|
|
62
|
+
// 从 npm shim(.cmd/.ps1)文本中解析出 exe 真身路径。
|
|
63
|
+
// shim 内容形如:... "%dp0%\node_modules\@xlight-oss\visionary-server\run-visionary-server.js" ...
|
|
64
|
+
// 包目录 = <shim目录>\node_modules\@xlight-oss\visionary-server
|
|
65
|
+
// 真身 = <包目录>\node_modules\.bin_real\visionary-server.exe
|
|
66
|
+
function resolveFromNpmShim(shimPath) {
|
|
67
|
+
let text;
|
|
68
|
+
try {
|
|
69
|
+
text = readFileSync(shimPath, "utf8");
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const m = NPM_PKG_SHIM_RE.exec(text);
|
|
74
|
+
if (!m) return null;
|
|
75
|
+
// shim 文本使用反斜杠分隔符(Windows 产物);手动切分保证在任意平台
|
|
76
|
+
// (包括测试跑的 macOS/Linux)都能解析,不依赖 path.dirname 的分隔符语义。
|
|
77
|
+
const pkgParts = m[0].split(/[\\/]+/).filter(Boolean);
|
|
78
|
+
if (pkgParts.length < 3) return null;
|
|
79
|
+
// node_modules\@xlight-oss\visionary-server\run-visionary-server.js → 去掉末段(文件名)
|
|
80
|
+
// npm shim 是 Windows 产物(.cmd/.ps1),包内 exe 恒为 visionary-server.exe,
|
|
81
|
+
// 与 process.platform 无关——固定扩展名保证任意平台测试/解析一致。
|
|
82
|
+
const pkgDir = path.join(path.dirname(shimPath), ...pkgParts.slice(0, -1));
|
|
83
|
+
const candidate = path.join(pkgDir, "node_modules", ".bin_real", "visionary-server.exe");
|
|
84
|
+
try {
|
|
85
|
+
if (statSync(candidate).isFile()) return candidate;
|
|
86
|
+
} catch {
|
|
87
|
+
// keep looking
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
55
92
|
function resolveBinaryPath(config) {
|
|
56
93
|
if (config.binaryPath) return config.binaryPath;
|
|
57
94
|
const fromEnv = process.env.DEEPSEEK_VISIONARY_BIN;
|
|
@@ -65,17 +102,40 @@ function resolveBinaryPath(config) {
|
|
|
65
102
|
// keep looking
|
|
66
103
|
}
|
|
67
104
|
}
|
|
105
|
+
// win32 追加:npm 全局包 shim(.cmd / .ps1)→ 解析 exe 真身
|
|
106
|
+
if (process.platform === "win32") {
|
|
107
|
+
for (const shimName of ["visionary-server.cmd", "visionary-server.ps1"]) {
|
|
108
|
+
for (const dir of (process.env.PATH || "").split(path.delimiter).filter(Boolean)) {
|
|
109
|
+
const shim = path.join(dir, shimName);
|
|
110
|
+
try {
|
|
111
|
+
if (statSync(shim).isFile()) {
|
|
112
|
+
const resolved = resolveFromNpmShim(shim);
|
|
113
|
+
if (resolved) return resolved;
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
// keep looking
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
68
121
|
return null;
|
|
69
122
|
}
|
|
70
123
|
|
|
71
124
|
const binaryMissingHelp = () =>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
125
|
+
process.platform === "win32"
|
|
126
|
+
? [
|
|
127
|
+
"visionary-server binary not found. Install it and retry:",
|
|
128
|
+
" - npm: npm install -g @xlight-oss/visionary-server (then restart DSH)",
|
|
129
|
+
" - or download from GitHub Releases: https://github.com/xlight/deepseek-visionary/releases/latest",
|
|
130
|
+
"Or point the plugin at the binary via Config.binaryPath / DEEPSEEK_VISIONARY_BIN.",
|
|
131
|
+
].join("\n")
|
|
132
|
+
: [
|
|
133
|
+
"visionary-server binary not found. Install it and retry:",
|
|
134
|
+
" - One-liner: curl -LsSf https://github.com/xlight/deepseek-visionary/releases/latest/download/visionary-server-installer.sh | sh",
|
|
135
|
+
" - Homebrew: brew install <tap>/visionary-server",
|
|
136
|
+
" - npm: npm install -g @xlight-oss/visionary-server",
|
|
137
|
+
"Or point the plugin at the binary via Config.binaryPath / DEEPSEEK_VISIONARY_BIN.",
|
|
138
|
+
].join("\n");
|
|
79
139
|
|
|
80
140
|
// --- subprocess --------------------------------------------------------------
|
|
81
141
|
|
|
@@ -172,16 +232,20 @@ function parseMinor(v) {
|
|
|
172
232
|
// --- tools -------------------------------------------------------------------
|
|
173
233
|
|
|
174
234
|
function apply(ctx, config) {
|
|
175
|
-
const binary = resolveBinaryPath(config);
|
|
176
235
|
const loginSeconds = (() => {
|
|
177
236
|
const raw = Number(process.env.DEEPSEEK_LOGIN_TIMEOUT);
|
|
178
237
|
if (Number.isFinite(raw) && raw > 0) return raw;
|
|
179
238
|
return config.loginTimeoutSeconds > 0 ? config.loginTimeoutSeconds : 600;
|
|
180
239
|
})();
|
|
181
240
|
|
|
241
|
+
// 版本探测:apply 时 fire-and-forget(仅用于结果附带版本警告)。
|
|
242
|
+
// 注意:二进制路径【不在此缓存】——每次工具调用经 requireBinary()
|
|
243
|
+
// 重新 resolveBinaryPath(config),用户修改 PATH / DEEPSEEK_VISIONARY_BIN
|
|
244
|
+
// 后无需重启 DSH 即生效(懒解析,成本为数次 statSync)。
|
|
182
245
|
let versionInfo = { known: false, compatible: true, version: "" };
|
|
183
|
-
|
|
184
|
-
|
|
246
|
+
const probeBinary = resolveBinaryPath(config);
|
|
247
|
+
if (probeBinary) {
|
|
248
|
+
runCli(probeBinary, ["--version"], { timeoutMs: 5000 })
|
|
185
249
|
.then((r) => {
|
|
186
250
|
const version = (r.stdout || r.stderr).trim();
|
|
187
251
|
versionInfo = {
|
|
@@ -219,7 +283,9 @@ function apply(ctx, config) {
|
|
|
219
283
|
});
|
|
220
284
|
}
|
|
221
285
|
|
|
286
|
+
// 懒解析:每次工具调用重新定位二进制(PATH / 环境变量改动即时生效)。
|
|
222
287
|
const requireBinary = () => {
|
|
288
|
+
const binary = resolveBinaryPath(config);
|
|
223
289
|
if (!binary) throw new Error(binaryMissingHelp());
|
|
224
290
|
return binary;
|
|
225
291
|
};
|
|
@@ -412,4 +478,4 @@ function apply(ctx, config) {
|
|
|
412
478
|
);
|
|
413
479
|
}
|
|
414
480
|
|
|
415
|
-
export { name, inject, Config, apply };
|
|
481
|
+
export { name, inject, Config, apply, resolveBinaryPath, resolveFromNpmShim };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xlight-oss/visionary-dsh",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "DeepSeek Visionary native plugin for DeepSeek Harness: deepseek_vision / status / login / logout native tools plus the text-model image bridge, all backed by the visionary-server CLI (DeepSeek web vision model, no API key).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.mjs",
|