dsh-plugin 1.4.12 → 1.4.13
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/client/client.js +326 -297
- package/client/client.js.map +1 -1
- package/package.json +1 -1
- package/src/client/components/modals/NotificationsModal.tsx +12 -1
- package/src/client/components/modals/modals.tsx +13 -1
- package/src/client/locales.ts +7 -0
- package/src/client/logic/failures.ts +32 -4
- package/src/client/logic/urls.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.13",
|
|
4
4
|
"description": "A community plugin marketplace for DeepSeek Harness, built to the official plugin spec — browse, search and install 10000+ human-curated community plugins without leaving the app. · DeepSeek Harness 社区插件市场(遵循官方开发规范):10000+ 人工精选社区插件,每日更新。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -18,7 +18,7 @@ import type { MouseEvent } from 'react'
|
|
|
18
18
|
import styles from '../../styles/Modal.module.css'
|
|
19
19
|
import type { EnvInfo, Translate } from '../../types.ts'
|
|
20
20
|
import type { NotificationRecord } from '../../logic/failures.ts'
|
|
21
|
-
import { classifyFailure, npmTooLowVersion, unreachableTargetOf, registryHostOf } from '../../logic/failures.ts'
|
|
21
|
+
import { classifyFailure, missingRegistryPackageOf, npmTooLowVersion, unreachableTargetOf, registryHostOf } from '../../logic/failures.ts'
|
|
22
22
|
import type { PendingRestart, QueueTask } from '../../hooks/useTaskQueue.ts'
|
|
23
23
|
import { pluginIssueUrl, pluginSiteUrl } from '../../logic/urls.ts'
|
|
24
24
|
import { CloseIcon } from '../ui/icons.tsx'
|
|
@@ -307,6 +307,17 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
307
307
|
// 发现补丁没被用上就中止安装,任何插件都装不进来 —— 不引导提 Issue
|
|
308
308
|
return h('div', { className: styles.failPrepareHint }, t('failPnpmUnusedPatchHint'))
|
|
309
309
|
}
|
|
310
|
+
if (kind === 'pnpmMissingDep') {
|
|
311
|
+
// profile 里留着指向 registry 上不存在(404)的包的依赖:pnpm 连得上 registry,
|
|
312
|
+
// 是被明确告知包不存在 —— 该 profile 的任何安装都会先卡在这条依赖上,与本次要装的
|
|
313
|
+
// 插件无关(#73 的 issue 就是这么被误挂到正在安装的插件上的)→ 点名缺失的包 +
|
|
314
|
+
// 删除条目指引,不引导提 Issue
|
|
315
|
+
const pkg = missingRegistryPackageOf(r.message)
|
|
316
|
+
return h('div', null, [
|
|
317
|
+
pkg ? h('div', { className: styles.failNetworkTarget }, t('failPnpmMissingDepTarget', { pkg })) : null,
|
|
318
|
+
h('div', { className: styles.failPrepareHint }, t('failPnpmMissingDepHint')),
|
|
319
|
+
])
|
|
320
|
+
}
|
|
310
321
|
if (kind === 'fileLocked') {
|
|
311
322
|
// profile 里的文件被其他进程占用(Windows os error 32):通常是宿主或杀毒软件
|
|
312
323
|
// 持有句柄 —— 给出完全退出宿主的指引,不引导提 Issue
|
|
@@ -16,7 +16,7 @@ import { CloseIcon, ConfirmIcon, CopyIcon, LinkIcon } from '../ui/icons.tsx'
|
|
|
16
16
|
import { ProgressView } from './ProgressView.tsx'
|
|
17
17
|
import { installCommandOf } from '../../logic/install-command.ts'
|
|
18
18
|
import { pluginDetailUrl, pluginIssueUrl, pluginSiteUrl } from '../../logic/urls.ts'
|
|
19
|
-
import { classifyFailure, npmTooLowVersion, unreachableTargetOf, registryHostOf } from '../../logic/failures.ts'
|
|
19
|
+
import { classifyFailure, missingRegistryPackageOf, npmTooLowVersion, unreachableTargetOf, registryHostOf } from '../../logic/failures.ts'
|
|
20
20
|
|
|
21
21
|
/** 完成结果视图:绿色对勾 + 标题/描述;
|
|
22
22
|
* needsRestart=true(插件需重启才生效)→ 「稍后重启 / 立即重启」按钮对,点稍后重启后
|
|
@@ -421,6 +421,18 @@ export function ErrorModal({ message, repo, kind, command, attempts, t, env, onC
|
|
|
421
421
|
// profile 里留着指向旧版本 dsh-plugin 的补丁声明(ERR_PNPM_UNUSED_PATCH):pnpm 发现
|
|
422
422
|
// 补丁没被用上就中止整次安装,任何插件都装不进来 —— 给删除条目的指引,不引导提 Issue
|
|
423
423
|
? h('div', { className: styles.failPrepareHint }, t('failPnpmUnusedPatchHint'))
|
|
424
|
+
: failureKind === 'pnpmMissingDep'
|
|
425
|
+
// profile 里留着指向 registry 上不存在(404)的包的依赖:pnpm 连得上 registry,
|
|
426
|
+
// 是被明确告知包不存在 —— 该 profile 的任何安装都会先卡在这条依赖上,与本次要装的
|
|
427
|
+
// 插件无关(#73 的 issue 就是这么被误挂到正在安装的插件上的)→ 点名缺失的包 +
|
|
428
|
+
// 删除条目指引,不引导提 Issue
|
|
429
|
+
? h('div', null, [
|
|
430
|
+
(() => {
|
|
431
|
+
const pkg = missingRegistryPackageOf(message)
|
|
432
|
+
return pkg ? h('div', { className: styles.failNetworkTarget }, t('failPnpmMissingDepTarget', { pkg })) : null
|
|
433
|
+
})(),
|
|
434
|
+
h('div', { className: styles.failPrepareHint }, t('failPnpmMissingDepHint')),
|
|
435
|
+
])
|
|
424
436
|
: failureKind === 'fileLocked'
|
|
425
437
|
// profile 里的文件被其他进程占用(Windows os error 32):pnpm 无法替换被占用的文件,
|
|
426
438
|
// 通常是宿主或杀毒软件持有句柄 —— 给退出宿主的指引,不引导提 Issue
|
package/src/client/locales.ts
CHANGED
|
@@ -326,6 +326,9 @@ export const zh = {
|
|
|
326
326
|
failNpmMissingHint: '系统找不到 npm 命令(npm 未安装或未加入系统 PATH),无法执行全局安装。请先安装 Node.js(自带 npm),确认 npm 已加入 PATH 后重试。这不是插件本身的问题。',
|
|
327
327
|
failPnpmStoreHint: '安装器调用 pnpm 时报「store 位置不匹配」(ERR_PNPM_UNEXPECTED_STORE):你的 profile 目录里旧插件依赖是用另一个大版本的 pnpm 生成的,当前 pnpm 出于安全不认旧目录,导致任何插件装进该 profile 都会失败。请删除该 profile 目录下的 node_modules 与 pnpm-lock.yaml(可先到「系统日志」或 ~/.dsh/profiles/<profile>/hub.log 查看完整报错),再重新安装。这不是插件本身的问题。',
|
|
328
328
|
failPnpmUnusedPatchHint: '安装器调用 pnpm 时报「有些补丁没有被使用」(ERR_PNPM_UNUSED_PATCH):你的 profile 里留着一条指向旧版本 dsh-plugin 的补丁声明(例如 dsh-plugin@1.4.2),而本次安装解析到的版本已经不是它,pnpm 出于安全直接中止整次安装,因此任何插件都装不进来。这不是插件本身的问题——请在 profile 目录(~/.dsh/profiles/<profile>)的 pnpm-workspace.yaml(pnpm 11 及以上)或 package.json 的 pnpm.patchedDependencies(pnpm 10)里删除该 dsh-plugin 补丁条目后重试。',
|
|
329
|
+
// 404 依赖:点名 registry 上不存在的那个包(取不到包名时跳过这行),再给删除条目的指引
|
|
330
|
+
failPnpmMissingDepTarget: '{pkg} 在 npm registry 上不存在(404)',
|
|
331
|
+
failPnpmMissingDepHint: '安装器调用 pnpm 时报「包不存在」(ERR_PNPM_FETCH_404):你的 profile 里留着一条指向 registry 上未发布包的依赖,pnpm 每次解析依赖都会先卡在它上面,因此任何插件都装不进来。这不是插件本身的问题——请在 profile 目录(~/.dsh/profiles/<profile>)的 package.json 里删除该依赖条目(同时删掉对应的 pnpm-lock.yaml 条目或整个锁文件)后重试。',
|
|
329
332
|
failFileLockedHint: '安装过程中 pnpm 无法替换 profile 里的文件:有程序正占用着它(Windows 常见报错 os error 32「另一个程序正在使用此文件」)。通常是 DeepSeek Harness 自身或杀毒软件的实时扫描持有文件句柄。这不是插件本身的问题——请完全退出 DeepSeek Harness(Windows 可在任务管理器确认进程已结束,必要时临时关闭杀毒软件实时防护)后重试。',
|
|
330
333
|
failAccessDeniedHint: '安装过程中 pnpm 写入 profile 里的文件被系统拒绝访问(Windows 常见报错 os error 5「拒绝访问」,英文为 Access is denied;Node 下的 EPERM / EACCES 同理)。常见原因是该文件或目录正被其他进程占用、文件带只读属性、目录权限受限,或杀毒软件实时防护拦截了写入——这与「文件正被占用」(os error 32)同属本机文件系统问题,任何插件装进该目录都会一样失败,不是插件本身的问题。请完全退出 DeepSeek Harness(Windows 可在任务管理器确认进程已结束,必要时临时关闭杀毒软件实时防护)后重试;若仍然失败,请检查 profile 目录及其文件是否被设为只读,并以管理员身份重新运行。',
|
|
331
334
|
failFsUnavailableHint: '安装过程中 pnpm 无法把文件写进本机磁盘(这类报错与装哪个插件无关,任何插件装在同一目录都会失败,不是插件本身的问题)。请按报错对号入座:① 磁盘空间不足(ENOSPC / no space left on device,Windows 为 os error 112)——请清理 profile 所在磁盘的剩余空间后重试;② 磁盘或挂载点只读、带写保护(EROFS / read-only file system,Windows 为 os error 19)——请确认 profile 目录所在磁盘可写(外接盘/U 盘、带写保护的移动盘或只读挂载的分区都会触发),必要时把插件目录换到系统盘的可写位置;③ 进程可用的文件句柄被耗尽(EMFILE / ENFILE / too many open files)——请关闭占用大量文件的程序并重启 DeepSeek Harness 后重试。',
|
|
@@ -700,6 +703,10 @@ export const en = {
|
|
|
700
703
|
failNpmMissingHint: 'The npm command could not be found (npm is not installed or not on the system PATH), so a global install cannot run. Please install Node.js (which bundles npm), make sure npm is on your PATH, then retry. This is not a problem with the plugin itself.',
|
|
701
704
|
failPnpmStoreHint: 'pnpm reported an unexpected store location (ERR_PNPM_UNEXPECTED_STORE): the profile directory was previously set up with a different major version of pnpm, and the current pnpm refuses to reuse it — no plugin can be installed into that profile. Delete node_modules and pnpm-lock.yaml under the profile directory (see System Logs or ~/.dsh/profiles/<profile>/hub.log for the full output), then reinstall. This is not a problem with the plugin itself.',
|
|
702
705
|
failPnpmUnusedPatchHint: 'pnpm reported that some patches were not used (ERR_PNPM_UNUSED_PATCH): your profile still holds a patch entry for an older dsh-plugin version (for example dsh-plugin@1.4.2), while this install resolved a different version, so pnpm aborts the whole install for safety — no plugin can be installed into that profile. This is not a problem with the plugin itself. Remove that dsh-plugin patch entry from pnpm-workspace.yaml (pnpm 11+) or from pnpm.patchedDependencies in package.json (pnpm 10) inside the profile directory (~/.dsh/profiles/<profile>), then retry.',
|
|
706
|
+
// Missing dependency: name the package that 404'd (the line is skipped when it cannot be parsed),
|
|
707
|
+
// then give the removal instructions
|
|
708
|
+
failPnpmMissingDepTarget: '{pkg} was not found on the npm registry (404)',
|
|
709
|
+
failPnpmMissingDepHint: 'pnpm reported that a package does not exist on the npm registry (ERR_PNPM_FETCH_404): your profile keeps a dependency on a package that was never published, and pnpm hits it every time it resolves dependencies — no plugin can be installed into that profile. This is not a problem with the plugin itself. Remove that dependency from package.json inside the profile directory (~/.dsh/profiles/<profile>) — along with its entry in pnpm-lock.yaml, or the lockfile itself — then retry.',
|
|
703
710
|
failFileLockedHint: 'During install, pnpm could not replace a file inside the profile because another program is holding it (on Windows this shows as os error 32, "the process cannot access the file because it is being used by another process"). Usually DeepSeek Harness itself or a real-time antivirus scan holds the handle. This is not a problem with the plugin itself — fully quit DeepSeek Harness (on Windows, confirm in Task Manager that the process has ended, and temporarily disable real-time antivirus protection if needed), then retry.',
|
|
704
711
|
failAccessDeniedHint: 'During install, Windows denied pnpm access to a file inside the profile (this shows as os error 5, "Access is denied"; on Node the equivalent codes are EPERM / EACCES). Typical causes: the file or directory is held by another process, the file is marked read-only, the directory permissions are restricted, or a real-time antivirus scan blocked the write. This is the same class of local file-system problem as a locked file (os error 32) — no plugin can be installed into that directory, so it is not a problem with the plugin itself. Fully quit DeepSeek Harness (on Windows, confirm in Task Manager that the process has ended, and temporarily disable real-time antivirus protection if needed), then retry. If it still fails, check whether the profile directory or its files are read-only and run as administrator.',
|
|
705
712
|
failFsUnavailableHint: 'During install, pnpm could not write files to the local disk — this has nothing to do with which plugin you are installing: any plugin installed into the same directory would fail the same way, so it is not a problem with the plugin itself. Match the error you see: ① Out of space (ENOSPC / no space left on device, os error 112 on Windows) — free up space on the drive that holds the profile and retry. ② Read-only or write-protected volume (EROFS / read-only file system, os error 19 on Windows) — make sure the drive holding the profile directory is writable (external or USB drives, write-protected media, and read-only mounts all trigger this); move the plugin directory to a writable location on the system drive if needed. ③ File handles exhausted (EMFILE / ENFILE / too many open files) — close programs that hold many files open, restart DeepSeek Harness, then retry.',
|
|
@@ -151,7 +151,7 @@ export function removeNotification(id: number): NotificationRecord[] {
|
|
|
151
151
|
return next
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
export type FailureKind = 'npmTooOld' | 'dshMissing' | 'gitMissing' | 'pnpmMissing' | 'npmMissing' | 'pnpmStore' | 'pnpmWorkspace' | 'originRejected' | 'pnpmPolicy' | 'pnpmUnusedPatch' | 'fileLocked' | 'accessDenied' | 'fsUnavailable' | 'pnpmIgnoredBuild' | 'pluginPrepare' | 'network' | 'repo'
|
|
154
|
+
export type FailureKind = 'npmTooOld' | 'dshMissing' | 'gitMissing' | 'pnpmMissing' | 'npmMissing' | 'pnpmStore' | 'pnpmWorkspace' | 'originRejected' | 'pnpmPolicy' | 'pnpmUnusedPatch' | 'pnpmMissingDep' | 'fileLocked' | 'accessDenied' | 'fsUnavailable' | 'pnpmIgnoredBuild' | 'pluginPrepare' | 'network' | 'repo'
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
157
|
* 失败归类:把安装输出归到具体成因,供弹窗文案、是否引导提 Issue 与 issue 预填原因使用。
|
|
@@ -191,6 +191,9 @@ export type FailureKind = 'npmTooOld' | 'dshMissing' | 'gitMissing' | 'pnpmMissi
|
|
|
191
191
|
* - pnpmUnusedPatch:profile 里留着指向旧版本 dsh-plugin 的 patch 声明,本次安装解析到的版本
|
|
192
192
|
* 已经不是它(`ERR_PNPM_UNUSED_PATCH` / `The following patches were not used: dsh-plugin@1.4.2`)
|
|
193
193
|
* —— pnpm 发现补丁没被用上即中止整次安装 → 提示删掉该条目后重试
|
|
194
|
+
* - pnpmMissingDep:profile 里留着一条指向 registry 上不存在的包的依赖,pnpm 解析时收到 404
|
|
195
|
+
* (`ERR_PNPM_FETCH_404` / `Not Found - 404`)—— 该 profile 的任何安装都会先卡在这条依赖上
|
|
196
|
+
* → 提示按包名删掉该条目后重试(404 的包通常不是正在安装的插件,故不引导提 Issue)
|
|
194
197
|
* - fileLocked:pnpm 无法替换 profile 里被其他进程占用的文件(Windows `os error 32`
|
|
195
198
|
* 「另一个程序正在使用此文件」/ `EBUSY` / `resource busy or locked`)—— 通常是宿主进程或
|
|
196
199
|
* 杀毒软件实时扫描持有句柄 → 提示完全退出宿主后重试
|
|
@@ -311,8 +314,19 @@ export function classifyFailure(message: string): FailureKind {
|
|
|
311
314
|
// 装后校验拦截(服务端 verifyInstalledEntry 标记):入口文件缺失 = git 分发缺构建产物,
|
|
312
315
|
// 与 pluginPrepare 同类(插件打包/分发问题),引导去仓库提 Issue
|
|
313
316
|
if (/\[packaging\]|entry file missing/i.test(message)) return 'pluginPrepare'
|
|
317
|
+
// 依赖在 registry 上不存在(`ERR_PNPM_FETCH_404` / `Not Found - 404`):pnpm 连得上 registry,
|
|
318
|
+
// 是被明确告知「这个包不存在」—— 不是插件问题。profile 里留着一条指向未发布包的依赖条目时,
|
|
319
|
+
// 该 profile 的**任何**安装都会先卡在这条依赖上(宿主尾部只有 `dsh: plugin command failed`)。
|
|
320
|
+
// 必须在 pluginPrepare 之前:否则该尾部会被下面的 `Command failed` 判定吞成
|
|
321
|
+
// 「插件分发不完整」,把 Issue 误挂到正在安装的插件上,而不是 404 的那个依赖(#73)
|
|
322
|
+
// (两个形态:pnpm 的 `[ERR_PNPM_FETCH_404] GET <url>: Not Found - 404` 与 npm 的
|
|
323
|
+
// `npm error 404 Not Found - GET <url> - Not found`)
|
|
324
|
+
if (/ERR_PNPM_FETCH_404|404 Not Found|Not Found - 404/i.test(message)) return 'pnpmMissingDep'
|
|
314
325
|
// 再判 prepare 实际执行失败:只有构建脚本真的跑挂了才是插件问题
|
|
315
|
-
|
|
326
|
+
// (`Command failed` 区分大小写:宿主尾部提示是小写的 `dsh: plugin command failed`,
|
|
327
|
+
// 那只是「这条命令失败了」的通用说明 —— 带 /i 会让任何带该尾部的未知失败都被判成
|
|
328
|
+
// 「插件分发不完整」,把 Issue 误挂到正在安装的插件上,见 #73)
|
|
329
|
+
if (/ERR_PNPM_PREPARE_PACKAGE|ELIFECYCLE|prepare-guard/i.test(message) || /Command failed/.test(message)) return 'pluginPrepare'
|
|
316
330
|
// 其余失败(含 git prepare 被 pnpm 白名单拦截):当前通道装不上 = 插件分发/依赖的问题,一律提 Issue
|
|
317
331
|
return 'repo'
|
|
318
332
|
}
|
|
@@ -371,12 +385,26 @@ export function summarizeError(message: string, maxChars: number = MAX_CORE_CHAR
|
|
|
371
385
|
return out.length > maxChars ? `${out.slice(0, maxChars)}\n… (truncated)` : out
|
|
372
386
|
}
|
|
373
387
|
|
|
374
|
-
/** 提取首个错误代码(如 ERR_PNPM_PREPARE_PACKAGE),无则 null。
|
|
388
|
+
/** 提取首个错误代码(如 ERR_PNPM_PREPARE_PACKAGE),无则 null。
|
|
389
|
+
* 代码里可能含数字(ERR_PNPM_FETCH_404 / ERR_PNPM_EBADPLATFORM_...),字符类必须带上 0-9,
|
|
390
|
+
* 否则会被截成 `ERR_PNPM_FETCH_`(#73 的 issue 正文就是这么被截断的)。 */
|
|
375
391
|
export function coreErrorCode(message: string): string | null {
|
|
376
|
-
const m = message.match(/\[?ERR_[A-
|
|
392
|
+
const m = message.match(/\[?ERR_[A-Z0-9_]+\]?/)
|
|
377
393
|
return m ? m[0].replace(/^\[|\]$/g, '') : null
|
|
378
394
|
}
|
|
379
395
|
|
|
396
|
+
/** 提取「registry 上不存在的包名」:从 404 行(`ERR_PNPM_FETCH_404 GET <registry>/<pkg>: Not Found - 404`)
|
|
397
|
+
* 里取请求路径中的包名(含 scope,如 `@scope/name`);非 404 或提取不到返回 null。
|
|
398
|
+
* 调用方据此在提示里点名具体是哪个依赖缺失 —— 光说「有个包 404 了」用户无从下手。 */
|
|
399
|
+
export function missingRegistryPackageOf(message: string): string | null {
|
|
400
|
+
for (const line of message.split(/\r?\n/)) {
|
|
401
|
+
if (!/ERR_PNPM_FETCH_404|404/.test(line)) continue
|
|
402
|
+
const m = line.match(/GET\s+https?:\/\/[^\s/]+\/((?:@[^/\s:]+\/)?[^/\s:]+)/)
|
|
403
|
+
if (m) return m[1]
|
|
404
|
+
}
|
|
405
|
+
return null
|
|
406
|
+
}
|
|
407
|
+
|
|
380
408
|
/**
|
|
381
409
|
* 从网络类失败消息里提取「具体连不上的地址」,供弹窗精准提示(你的网络无法访问什么)。
|
|
382
410
|
* 优先取服务端 [network] 预检消息括号里的探测地址(中文「(…)」/ 英文「(…)」),
|
package/src/client/logic/urls.ts
CHANGED
|
@@ -53,6 +53,7 @@ function reasonTitleOf(kind: FailureKind): string {
|
|
|
53
53
|
case 'originRejected': return 'request origin rejected by the local service on the user machine'
|
|
54
54
|
case 'pnpmPolicy': return 'pnpm supply-chain policy blocked the install on the user machine'
|
|
55
55
|
case 'pnpmUnusedPatch': return 'stale pnpm patch entry on the user machine'
|
|
56
|
+
case 'pnpmMissingDep': return 'dependency not found on the npm registry on the user machine'
|
|
56
57
|
case 'fileLocked': return 'file locked by another process on the user machine'
|
|
57
58
|
case 'accessDenied': return 'file write access denied on the user machine'
|
|
58
59
|
case 'fsUnavailable': return 'local file system unavailable on the user machine'
|