dsh-plugin 1.6.4 → 1.6.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 +11 -11
- package/README.md +11 -11
- package/client/client.js +450 -405
- package/client/client.js.map +1 -1
- package/lib/http/catalog.js +132 -0
- package/lib/http/diagnostics.js +201 -0
- package/lib/http/install.js +399 -0
- package/lib/http/logs.js +164 -0
- package/lib/http/routes.js +19 -1261
- package/lib/http/settings.js +77 -0
- package/lib/http/shared.js +169 -0
- package/lib/http/task.js +208 -0
- package/lib/services/install/install.js +1 -1
- package/lib/services/install/npm-resolve.js +44 -15
- package/lib/services/install/task-queue.js +45 -16
- package/lib/services/probe.js +18 -1
- package/lib/types/http/catalog.d.ts +10 -0
- package/lib/types/http/diagnostics.d.ts +4 -0
- package/lib/types/http/install.d.ts +11 -0
- package/lib/types/http/logs.d.ts +2 -0
- package/lib/types/http/routes.d.ts +15 -20
- package/lib/types/http/settings.d.ts +2 -0
- package/lib/types/http/shared.d.ts +44 -0
- package/lib/types/http/task.d.ts +3 -0
- package/lib/types/services/install/install.d.ts +1 -1
- package/lib/types/services/install/npm-resolve.d.ts +3 -2
- package/lib/types/services/probe.d.ts +8 -0
- package/package.json +1 -1
- package/src/client/components/PluginHubSection.tsx +7 -2
- package/src/client/components/modals/HubUpdateModal.tsx +19 -10
- package/src/client/components/modals/NotificationsModal.tsx +34 -18
- package/src/client/components/modals/modals.tsx +38 -28
- package/src/client/components/views/InstalledView.tsx +23 -11
- package/src/client/hooks/useCatalog.ts +13 -9
- package/src/client/locales.ts +28 -8
- package/src/client/logic/failures.ts +36 -157
- package/src/client/logic/urls.ts +72 -1
- package/src/client/types.ts +11 -0
- package/src/server/http/catalog.ts +143 -0
- package/src/server/http/diagnostics.ts +193 -0
- package/src/server/http/install.ts +391 -0
- package/src/server/http/logs.ts +149 -0
- package/src/server/http/routes.ts +22 -1220
- package/src/server/http/settings.ts +73 -0
- package/src/server/http/shared.ts +191 -0
- package/src/server/http/task.ts +194 -0
- package/src/server/services/install/install-types.ts +9 -1
- package/src/server/services/install/install.ts +11 -1
- package/src/server/services/install/npm-resolve.ts +41 -13
- package/src/server/services/install/task-queue.ts +45 -16
- package/src/server/services/probe.ts +19 -1
|
@@ -58,12 +58,30 @@ export function activeTask(): ActiveTaskInfo[] {
|
|
|
58
58
|
for (const item of queue) {
|
|
59
59
|
const task = item.task
|
|
60
60
|
if (task.status === 'pending') {
|
|
61
|
-
found.push({
|
|
61
|
+
found.push({
|
|
62
|
+
id: task.id,
|
|
63
|
+
target: show(task),
|
|
64
|
+
action: task.action,
|
|
65
|
+
status: 'pending',
|
|
66
|
+
progress: task.progress,
|
|
67
|
+
lines: task.lines.slice(0, MAX_TASK_LINES),
|
|
68
|
+
attempts: task.attempts,
|
|
69
|
+
installChannel: task.installChannel,
|
|
70
|
+
})
|
|
62
71
|
}
|
|
63
72
|
}
|
|
64
73
|
tasks.forEach((task) => {
|
|
65
74
|
if (task.status === 'running') {
|
|
66
|
-
found.unshift({
|
|
75
|
+
found.unshift({
|
|
76
|
+
id: task.id,
|
|
77
|
+
target: show(task),
|
|
78
|
+
action: task.action,
|
|
79
|
+
status: 'running',
|
|
80
|
+
progress: task.progress,
|
|
81
|
+
lines: task.lines.slice(0, MAX_TASK_LINES),
|
|
82
|
+
attempts: task.attempts,
|
|
83
|
+
installChannel: task.installChannel,
|
|
84
|
+
})
|
|
67
85
|
}
|
|
68
86
|
})
|
|
69
87
|
return found
|
|
@@ -134,7 +152,7 @@ function cliInvocation(profile: string): Invocation {
|
|
|
134
152
|
if (entry !== undefined) {
|
|
135
153
|
// 打包桌面端(Electron):宿主入口在 app.asar 内,机器上根本没有 `dsh` 可执行文件
|
|
136
154
|
//(Windows 那条 dsh.cmd shim 只存在于宿主进程自己的 PATH 里),直接回退 PATH 必然
|
|
137
|
-
// 报 [dsh-missing]
|
|
155
|
+
// 报 [dsh-missing]。这里改用应用自己的 CLI 引导脚本调起同一份打包
|
|
138
156
|
// CLI:Electron 可执行文件 + --expose-internals + desktop-cli.js,与内置终端、
|
|
139
157
|
// 官方插件页安装完全同一条路径 —— desktop profile 由应用独占管理的授权也在其中。
|
|
140
158
|
const bootstrap = desktopCliBootstrap(entry)
|
|
@@ -189,9 +207,8 @@ export function desktopCliBootstrap(entry: string): string | null {
|
|
|
189
207
|
|
|
190
208
|
/**
|
|
191
209
|
* dsh 命令存在性探测:which/where 找 PATH 里的 dsh。
|
|
192
|
-
* Windows shell
|
|
193
|
-
*
|
|
194
|
-
* spawn 前用 which/where 探测,命令不存在则直接失败并打 ASCII 标记 [dsh-missing](乱码免疫)。
|
|
210
|
+
* 命令缺失时各平台报错形态不同(Windows shell 只回 GBK 乱码、POSIX 才抛 spawn ENOENT),
|
|
211
|
+
* 统一在 spawn 前用 which/where 探测,命令不存在则直接失败并打 ASCII 标记 [dsh-missing](乱码免疫)。
|
|
195
212
|
* 探测自身异常(which/where 不可用等)不拦截安装,交给装后校验兜底。
|
|
196
213
|
*/
|
|
197
214
|
function dshOnPath(env?: NodeJS.ProcessEnv): boolean {
|
|
@@ -270,7 +287,22 @@ export function startPluginMutation(options: {
|
|
|
270
287
|
// 卸载入队时先快照「该包是否带客户端 UI」:卸载完成后包已从磁盘删除,读不到 package.json,
|
|
271
288
|
// 只能在此刻取;卸载成功且曾存活时据此决定是否要刷新页面摘除插件面板
|
|
272
289
|
const hadClientUi = options.action === 'remove' ? hasClientUi(options.profile, options.target) : undefined
|
|
273
|
-
const task: InstallTask = {
|
|
290
|
+
const task: InstallTask = {
|
|
291
|
+
id: nextTaskId,
|
|
292
|
+
target: options.target,
|
|
293
|
+
displayTarget: options.displayTarget,
|
|
294
|
+
globalNpm: options.globalNpm,
|
|
295
|
+
action: options.action,
|
|
296
|
+
status: 'pending',
|
|
297
|
+
timedOut: false,
|
|
298
|
+
exitCode: null,
|
|
299
|
+
progress: 0,
|
|
300
|
+
lines: [],
|
|
301
|
+
attempts: options.attempts ?? [],
|
|
302
|
+
needsRestart: false,
|
|
303
|
+
hadClientUi,
|
|
304
|
+
installChannel: options.installChannel,
|
|
305
|
+
}
|
|
274
306
|
nextTaskId = nextTaskId >= Number.MAX_SAFE_INTEGER ? 1 : nextTaskId + 1
|
|
275
307
|
tasks.set(task.id, task)
|
|
276
308
|
if (tasks.size > MAX_TASKS) {
|
|
@@ -416,8 +448,8 @@ function spawnMutation(options: {
|
|
|
416
448
|
let child: ReturnType<typeof spawn>
|
|
417
449
|
try {
|
|
418
450
|
// 独立 CLI 场景(file: 'dsh',宿主加载器走 node bin 不经过这里):先探测 dsh 是否在 PATH。
|
|
419
|
-
//
|
|
420
|
-
//
|
|
451
|
+
// 命令缺失时各平台报错形态不同(GBK 乱码 / spawn ENOENT),统一前置拦截并打 ASCII 标记
|
|
452
|
+
// [dsh-missing],前端据此精准提示「dsh 未加入 PATH」而不是笼统的插件失败。
|
|
421
453
|
if (invocation.file === 'dsh' && !dshOnPath(env)) {
|
|
422
454
|
const detail = '[dsh-missing] the dsh CLI was not found on this machine (DeepSeek Harness not installed, or dsh not on the PATH)'
|
|
423
455
|
if (task) {
|
|
@@ -535,12 +567,9 @@ function spawnMutation(options: {
|
|
|
535
567
|
|
|
536
568
|
return (async () => {
|
|
537
569
|
let result = await spawnOnce(args)
|
|
538
|
-
// npm 11 的 arborist peer-set bug(`Cannot read properties of null (reading 'children')
|
|
539
|
-
//
|
|
540
|
-
//
|
|
541
|
-
// 与是不是从我们界面发起无关(终端里同样复现)。首次失败后自动带 `--legacy-peer-deps` 重试一次:
|
|
542
|
-
// 跳过 peer 自动解析即可绕过该 bug(peer 通常由同装的 @deepseek-ai/dsh 依赖树天然提供)。
|
|
543
|
-
// 二次尝试仍失败则保留其错误信息,不掩盖真正的原因。
|
|
570
|
+
// npm 11 的 arborist peer-set bug(`Cannot read properties of null (reading 'children')`)
|
|
571
|
+
// 会让 `npm install -g` 在解析阶段直接崩溃。首次失败后自动带 `--legacy-peer-deps` 重试一次:
|
|
572
|
+
// 跳过 peer 自动解析即可绕过该 bug;二次尝试仍失败则保留其错误信息,不掩盖真正的原因。
|
|
544
573
|
if (isGlobalNpm && result.exitCode !== 0 && !result.timedOut && task?.status !== 'cancelled') {
|
|
545
574
|
const retryArgs = ['install', '-g', '--legacy-peer-deps', ...(globalNpm ?? [])]
|
|
546
575
|
const retryExecuted = `npm install -g --legacy-peer-deps ${(globalNpm ?? []).join(' ')}`
|
|
@@ -645,7 +674,7 @@ function ignoredBuildKeys(output: string): string[] {
|
|
|
645
674
|
|
|
646
675
|
/** npm arborist edgesOut 崩溃 + 本机 npm 版本过低 → 把 [npm-too-low] 标记追加到任务输出,
|
|
647
676
|
* 前端据此展示「本机 npm 版本过低」的准确原因 —— 避免该报错被外层 ERR_PNPM_PREPARE_PACKAGE
|
|
648
|
-
*
|
|
677
|
+
* 误判成插件打包/分发问题。检测逻辑在独立的 npm-check.ts(本机 npm 环境职责)。 */
|
|
649
678
|
function annotateNpmTooLow(result: InstallResult, options: {
|
|
650
679
|
action: 'add' | 'remove' | 'update'
|
|
651
680
|
task?: InstallTask
|
|
@@ -165,7 +165,7 @@ function runCurl(args: string[], env: NodeJS.ProcessEnv, timeoutMs: number): Pro
|
|
|
165
165
|
* 若本机 curl 不认这个参数(curl < 7.70)则去掉参数重跑一次,保证老版本不因此直接失败;
|
|
166
166
|
* 降级后仍被吊销检查拦死(CRYPT_E_NO_REVOCATION_CHECK)时,再用 --ssl-no-revoke
|
|
167
167
|
* 彻底关掉吊销检查跑一次 —— 该参数 curl ≥ 7.19 即存在,覆盖面比降级参数更广,
|
|
168
|
-
* 否则「能上网但取不到 CRL」的 Windows
|
|
168
|
+
* 否则「能上网但取不到 CRL」的 Windows 机器会把所有通道误报成不可达。
|
|
169
169
|
* 吊销检查只影响本次探测自身的信任判断,不改变系统 TLS 配置。 */
|
|
170
170
|
async function curlWithTlsFallback(args: string[], env: NodeJS.ProcessEnv, timeoutMs: number): Promise<CurlRun> {
|
|
171
171
|
const tlsArgs = curlTlsArgs()
|
|
@@ -256,6 +256,24 @@ export function gitLsRemote(url: string, proxy: string, timeoutMs: number): Prom
|
|
|
256
256
|
})
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
+
/**
|
|
260
|
+
* 请求一个 URL 并返回重定向后的最终地址(curl -I -L -w %{url_effective})。
|
|
261
|
+
* 供 GitHub 仓库改名解析使用:对已改名仓库 GitHub 回 301,跟随跳转后的最终地址
|
|
262
|
+
* 即规范地址。与其它 GitHub 访问同口径 —— curl 子进程注入代理 env(Node 内置
|
|
263
|
+
* http(s) 读不到系统代理,直连在部分网络下不可达)。
|
|
264
|
+
* 未发生跳转(200/404)、网络失败或 curl 不可用都返回 null,调用方保留原始地址。
|
|
265
|
+
*/
|
|
266
|
+
export async function finalUrl(url: string, proxy: string, timeoutMs: number): Promise<string | null> {
|
|
267
|
+
const discard = process.platform === 'win32' ? 'NUL' : '/dev/null'
|
|
268
|
+
const r = await curlWithTlsFallback([
|
|
269
|
+
'-sS', '-I', '-L', '-o', discard, '-w', '%{url_effective}',
|
|
270
|
+
'--max-time', String(Math.max(1, Math.round(timeoutMs / 1000))),
|
|
271
|
+
url,
|
|
272
|
+
], proxyEnv(proxy), timeoutMs)
|
|
273
|
+
const final = r.stdout.trim()
|
|
274
|
+
return r.code === 0 && final !== '' ? final : null
|
|
275
|
+
}
|
|
276
|
+
|
|
259
277
|
/**
|
|
260
278
|
* curl 子进程抓取响应体(与 probeUrl 同一套代理 env 注入与 TLS 参数兜底)。
|
|
261
279
|
* 供服务端 /catalog 代理路由使用:目录/统计数据经此拉到服务端再转给浏览器,
|