dsh-plugin 1.4.4 → 1.4.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-plugin",
3
- "version": "1.4.4",
4
- "description": "A community plugin marketplace for DeepSeek Harness, built to the official plugin spec — browse, search and install 8000+ human-curated community plugins without leaving the app. · DeepSeek Harness 社区插件市场(遵循官方开发规范):8000+ 人工精选社区插件,每日更新。",
3
+ "version": "1.4.6",
4
+ "description": "A community plugin marketplace for DeepSeek Harness, built to the official plugin spec — browse, search and install 9000+ human-curated community plugins without leaving the app. · DeepSeek Harness 社区插件市场(遵循官方开发规范):9000+ 人工精选社区插件,每日更新。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
@@ -313,6 +313,16 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
313
313
  // 持有句柄 —— 给出完全退出宿主的指引,不引导提 Issue(#47)
314
314
  return h('div', { className: styles.failPrepareHint }, t('failFileLockedHint'))
315
315
  }
316
+ if (kind === 'accessDenied') {
317
+ // profile 里的文件被系统拒绝写入(Windows os error 5「拒绝访问」/ EPERM / EACCES):
318
+ // 占用、只读属性、目录 ACL 或杀软拦截 —— 给退出宿主 + 检查权限的指引,不引导提 Issue(#50)
319
+ return h('div', { className: styles.failPrepareHint }, t('failAccessDeniedHint'))
320
+ }
321
+ if (kind === 'fsUnavailable') {
322
+ // 本机磁盘写不进去(ENOSPC / EROFS / EMFILE 及 Windows os error 112、19):
323
+ // 空间不足、盘只读、句柄耗尽,任何插件都装不进来 —— 按子场景给指引,不引导提 Issue
324
+ return h('div', { className: styles.failPrepareHint }, t('failFsUnavailableHint'))
325
+ }
316
326
  if (kind === 'network') {
317
327
  // 安装前预检 / 安装日志里的连接失败([network] / git fetch 超时 / DNS / TLS):
318
328
  // 是本机网络不通或代理有问题,不是插件问题 —— 提示检查网络 + 直达「系统诊断」,
@@ -425,6 +425,14 @@ export function ErrorModal({ message, repo, kind, command, attempts, t, env, onC
425
425
  // profile 里的文件被其他进程占用(Windows os error 32):pnpm 无法替换被占用的文件,
426
426
  // 通常是宿主或杀毒软件持有句柄 —— 给退出宿主的指引,不引导提 Issue(#47)
427
427
  ? h('div', { className: styles.failPrepareHint }, t('failFileLockedHint'))
428
+ : failureKind === 'accessDenied'
429
+ // profile 里的文件被系统拒绝写入(Windows os error 5「拒绝访问」/ EPERM / EACCES):
430
+ // 占用、只读属性、目录 ACL 或杀软拦截 —— 同样给退出宿主/检查权限的指引,不引导提 Issue(#50)
431
+ ? h('div', { className: styles.failPrepareHint }, t('failAccessDeniedHint'))
432
+ : failureKind === 'fsUnavailable'
433
+ // 本机磁盘写不进去(ENOSPC / EROFS / EMFILE 及 Windows os error 112、19):
434
+ // 空间不足、盘只读、句柄耗尽,任何插件都装不进来 —— 按子场景给指引,不引导提 Issue
435
+ ? h('div', { className: styles.failPrepareHint }, t('failFsUnavailableHint'))
428
436
  : failureKind === 'network'
429
437
  // 安装前预检 / 安装日志里的连接失败([network] / git fetch 超时 / DNS / TLS):
430
438
  // 是本机网络不通或代理有问题,不是插件问题 —— 提示检查网络 + 直达「系统诊断」,
@@ -319,6 +319,8 @@ export const zh = {
319
319
  failPnpmStoreHint: '安装器调用 pnpm 时报「store 位置不匹配」(ERR_PNPM_UNEXPECTED_STORE):你的 profile 目录里旧插件依赖是用另一个大版本的 pnpm 生成的,当前 pnpm 出于安全不认旧目录,导致任何插件装进该 profile 都会失败。请删除该 profile 目录下的 node_modules 与 pnpm-lock.yaml(可先到「系统日志」或 ~/.dsh/profiles/<profile>/hub.log 查看完整报错),再重新安装。这不是插件本身的问题。',
320
320
  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 补丁条目后重试。',
321
321
  failFileLockedHint: '安装过程中 pnpm 无法替换 profile 里的文件:有程序正占用着它(Windows 常见报错 os error 32「另一个程序正在使用此文件」)。通常是 DeepSeek Harness 自身或杀毒软件的实时扫描持有文件句柄。这不是插件本身的问题——请完全退出 DeepSeek Harness(Windows 可在任务管理器确认进程已结束,必要时临时关闭杀毒软件实时防护)后重试。',
322
+ failAccessDeniedHint: '安装过程中 pnpm 写入 profile 里的文件被系统拒绝访问(Windows 常见报错 os error 5「拒绝访问」,英文为 Access is denied;Node 下的 EPERM / EACCES 同理)。常见原因是该文件或目录正被其他进程占用、文件带只读属性、目录权限受限,或杀毒软件实时防护拦截了写入——这与「文件正被占用」(os error 32)同属本机文件系统问题,任何插件装进该目录都会一样失败,不是插件本身的问题。请完全退出 DeepSeek Harness(Windows 可在任务管理器确认进程已结束,必要时临时关闭杀毒软件实时防护)后重试;若仍然失败,请检查 profile 目录及其文件是否被设为只读,并以管理员身份重新运行。',
323
+ 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 后重试。',
322
324
  failPnpmWorkspaceHint: '安装器调用 pnpm 时报「不能把依赖装到 workspace 根目录」(ERR_PNPM_ADDING_TO_ROOT):你的 profile 目录被 pnpm 视为 workspace 根目录,而本次安装命令没有声明在根目录操作,pnpm 直接拒绝执行,因此任何插件装进来都会失败。这不是插件本身的问题——可在 profile 目录(~/.dsh/profiles/<profile>)的 .npmrc 里加一行 ignore-workspace-root-check=true 后重试,或把 DeepSeek Harness 升级到最新版再试。',
323
325
  failPnpmPolicyHint: '安装器调用 pnpm 时被其供应链安全策略拦截——装任何插件都会撞墙,不是插件本身的问题。分两种情况处理:① 提示「Minimum release age」(ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION):包发布还不满 24 小时,pnpm 11 出于安全会拒收这种刚发布的新包。可在 pnpm 配置(pnpm-workspace.yaml)里加 minimumReleaseAge: 0 豁免,或等满 24 小时后重试。② 提示「untrusted origin」(ERR_PNPM_UNTRUSTED_ORIGIN):依赖来源不被本机 pnpm 信任,通常是该 profile 里之前用 github: 或非官方 npm 源装过插件,锁文件记录了不受信任的来源。请删除该 profile 目录下的 node_modules 与 pnpm-lock.yaml 后重新安装(可先到「系统日志」或 ~/.dsh/profiles/<profile>/hub.log 查看完整报错)。',
324
326
  // 自定义安装三卡片入口的渠道名(报错/日志溯源:本次安装从哪个入口发起)
@@ -682,6 +684,8 @@ export const en = {
682
684
  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.',
683
685
  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.',
684
686
  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.',
687
+ 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.',
688
+ 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.',
685
689
  failPnpmWorkspaceHint: 'pnpm refused to add the dependency to the workspace root (ERR_PNPM_ADDING_TO_ROOT): the profile directory is treated as a pnpm workspace root, and this install command did not declare that it operates at the root, so pnpm rejected it outright — no plugin can be installed into that profile. This is not a problem with the plugin itself. Add `ignore-workspace-root-check=true` to the `.npmrc` inside the profile directory (~/.dsh/profiles/<profile>) and retry, or upgrade DeepSeek Harness and try again.',
686
690
  failPnpmPolicyHint: 'The installer was blocked by pnpm supply-chain security policy — every plugin install would hit the same wall, so this is not a problem with the plugin itself. Two cases: ① "Minimum release age" (ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION): the package was published less than 24 hours ago, and pnpm 11 refuses freshly-published packages for safety. Add minimumReleaseAge: 0 to your pnpm config (pnpm-workspace.yaml) to opt out, or wait until the 24 hours have passed and retry. ② "untrusted origin" (ERR_PNPM_UNTRUSTED_ORIGIN): a dependency source is not trusted by this machine, usually because plugins were previously installed via github: or a non-official npm registry, so the lockfile records an untrusted source. 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.',
687
691
  // Custom install entry channel names (the three cards) — used in error/log traceability
@@ -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' | 'pnpmPolicy' | 'pnpmUnusedPatch' | 'fileLocked' | 'pnpmIgnoredBuild' | 'pluginPrepare' | 'network' | 'repo'
154
+ export type FailureKind = 'npmTooOld' | 'dshMissing' | 'gitMissing' | 'pnpmMissing' | 'npmMissing' | 'pnpmStore' | 'pnpmWorkspace' | 'pnpmPolicy' | 'pnpmUnusedPatch' | 'fileLocked' | 'accessDenied' | 'fsUnavailable' | 'pnpmIgnoredBuild' | 'pluginPrepare' | 'network' | 'repo'
155
155
 
156
156
  /**
157
157
  * 失败归类,七态。无论底层机制如何(pnpm 白名单拦截 / 构建脚本被忽略 / prepare 失败),
@@ -202,6 +202,20 @@ export type FailureKind = 'npmTooOld' | 'dshMissing' | 'gitMissing' | 'pnpmMissi
202
202
  * - fileLocked:pnpm 无法替换 profile 里被其他进程占用的文件(Windows `os error 32`
203
203
  * 「另一个程序正在使用此文件」/ `EBUSY` / `resource busy or locked`)—— 通常是宿主进程或杀毒软件
204
204
  * 实时扫描持有句柄,不是插件问题(dsh-plugin-hub#47)→ 提示完全退出宿主后重试,不引导提 Issue
205
+ * - accessDenied:pnpm 在 profile 里替换文件时被系统拒绝写入(Windows `os error 5`
206
+ * 「拒绝访问」= ERROR_ACCESS_DENIED / Node 的 `EPERM` `EACCES` / `Access is denied`)——
207
+ * 同属本机文件系统层面的写入受阻:文件/目录被其他进程占用、只读属性、目录 ACL 受限,
208
+ * 或杀毒软件实时防护拦截写入(`os error 5` 与 `os error 32` 语义不同:前者是「拒绝访问」,
209
+ * 后者是「文件正被占用」,但用户侧处置一致)。任何插件装进该目录都会同样失败,不是插件问题
210
+ * (dsh-plugin-hub#50:Win 下 `swap: 拒绝访问。 (os error 5)` 漏判,被误报成插件侧安装失败并
211
+ * 自动提了 issue)→ 提示退出宿主/关杀软后重试,仍失败则检查只读属性并以管理员身份运行,
212
+ * 不引导提 Issue
213
+ * - fsUnavailable:本机文件系统层面根本写不进去 —— 磁盘/分区空间耗尽(`ENOSPC` /
214
+ * `no space left on device`,Windows 为 `os error 112`)、目标分卷或挂载点为只读
215
+ * (`EROFS` / `read-only file system`,Windows 写保护为 `os error 19`)、进程可用的文件句柄
216
+ * 被耗尽(`EMFILE` / `ENFILE` / `too many open files`)。这三类都在 pnpm 落盘阶段发生,
217
+ * 与具体装哪个插件无关:空间不足、盘只读、句柄不够时,任何插件都装不进来,不是插件问题
218
+ * → 提示按报错代码对号入座(清空间 / 换可写目录 / 重启宿主释放句柄),不引导提 Issue
205
219
  * - network:安装前连通性预检拦截(服务端 `[network]` 标记)、底层连接失败
206
220
  * (ERR_PNPM_GIT_FETCH_FAILED / ETIMEDOUT / DNS 解析 / TLS 握手 / 代理拒绝),或
207
221
  * registry tarball 拉取失败(`fetch failed` / `GET …/-/…tgz error (n)` —— 常见于本机
@@ -278,6 +292,19 @@ export function classifyFailure(message: string): FailureKind {
278
292
  // 通常是宿主进程或杀毒软件实时扫描持有句柄;`os error 32` 用 ASCII 特征,中文原文乱码也能命中
279
293
  // (dsh-plugin-hub#47)→ 提示完全退出宿主后重试,不引导提 Issue
280
294
  if (/os error 32|EBUSY|resource busy or locked|being used by another process/i.test(message)) return 'fileLocked'
295
+ // profile 里的文件/目录被系统拒绝写入(Windows `os error 5`「拒绝访问」= ERROR_ACCESS_DENIED /
296
+ // Node 的 EPERM、EACCES / 英文 `Access is denied`):占用、只读属性、目录 ACL 或杀软拦截,
297
+ // 同属本机文件系统问题,任何插件都装不上,不是插件问题。`os error 5` 只认 ASCII 特征 ——
298
+ // 中文原文经 GBK→UTF-8 解码会残缺,不能依赖「拒绝访问」四个字
299
+ // (dsh-plugin-hub#50:swap 阶段 `os error 5` 漏判,落 repo 兜底被误报成插件侧失败)
300
+ if (/os error 5\b|ERROR_ACCESS_DENIED|\bEPERM\b|\bEACCES\b|access is denied/i.test(message)) return 'accessDenied'
301
+ // 本机文件系统层面根本写不进去:空间耗尽(ENOSPC / no space left on device / Windows os error 112)、
302
+ // 目标盘或挂载点只读(EROFS / read-only file system / Windows 写保护 os error 19)、
303
+ // 文件句柄耗尽(EMFILE / ENFILE / too many open files)。都在 pnpm 落盘阶段发生,
304
+ // 空间不足、盘只读或句柄不够时任何插件都装不进来,不是插件问题 ——
305
+ // 必须在 network / prepare 之前判:磁盘满时 pnpm 会在日志尾部混着重试与超时特征,
306
+ // 先判网络会把「本机磁盘写不进去」误报成「你的网络不通」
307
+ if (/os error 112\b|os error 19\b|ERROR_DISK_FULL|ERROR_WRITE_PROTECT|\bENOSPC\b|\bEROFS\b|\bEMFILE\b|\bENFILE\b|no space left on device|read-only file system|too many open files/i.test(message)) return 'fsUnavailable'
281
308
  // 构建脚本被 pnpm 白名单(allowBuilds)拦截:插件的 prepare 脚本或依赖里的原生模块构建
282
309
  // 被默认拒绝(ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED / ERR_PNPM_IGNORED_BUILDS)。
283
310
  // 这类错误出现即说明 pnpm 已成功 fetch 到 tarball(网络是通的),主因是插件构建脚本
@@ -53,6 +53,8 @@ function reasonTitleOf(kind: FailureKind): string {
53
53
  case 'pnpmPolicy': return 'pnpm supply-chain policy blocked the install on the user machine'
54
54
  case 'pnpmUnusedPatch': return 'stale pnpm patch entry on the user machine'
55
55
  case 'fileLocked': return 'file locked by another process on the user machine'
56
+ case 'accessDenied': return 'file write access denied on the user machine'
57
+ case 'fsUnavailable': return 'local file system unavailable on the user machine'
56
58
  case 'pnpmIgnoredBuild': return 'build scripts blocked by pnpm allowlist'
57
59
  case 'pluginPrepare': return 'plugin distribution incomplete'
58
60
  case 'network': return 'network failure on the user side'
@@ -90,7 +92,11 @@ export function pluginIssueUrl(repo: string, message: string, env?: EnvInfo | nu
90
92
  ? 'the profile keeps a pnpm patch entry for an older dsh-plugin version, so pnpm aborted the install (local config issue)'
91
93
  : kind === 'fileLocked'
92
94
  ? 'a file in the profile is locked by another process on the user machine (local environment issue)'
93
- : 'plugin-side install failure'
95
+ : kind === 'accessDenied'
96
+ ? 'the system denied write access to a file in the profile on the user machine (local environment issue)'
97
+ : kind === 'fsUnavailable'
98
+ ? 'the local file system could not accept the write — no space left, read-only volume, or too many open file handles on the user machine (local environment issue)'
99
+ : 'plugin-side install failure'
94
100
  const code = coreErrorCode(message)
95
101
  // 按给定核心摘要预算构建完整预填 URL(含 URL 编码);预算可调,供超长时逐档缩小
96
102
  const build = (coreChars: number): string => {