dsh-plugin 1.4.1 → 1.4.3

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,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "A community plugin marketplace for DeepSeek Harness, built to the official plugin spec — browse, search and install 4000+ human-curated community plugins without leaving the app. · DeepSeek Harness 社区插件市场(遵循官方开发规范):4000+ 人工精选社区插件,每日更新。",
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 } from '../../logic/failures.ts'
21
+ import { classifyFailure, 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'
@@ -286,6 +286,12 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
286
286
  // 给安装指引,不引导提 Issue
287
287
  return h('div', { className: styles.failPrepareHint }, t('failNpmMissingHint'))
288
288
  }
289
+ if (kind === 'pnpmWorkspace') {
290
+ // pnpm 拒绝把依赖装到 workspace 根目录(ERR_PNPM_ADDING_TO_ROOT):宿主在 profile
291
+ // 目录调 pnpm add 未声明在根操作,任何插件都会失败,不是插件问题 ——
292
+ // 给 .npmrc 豁免指引,不引导提 Issue(dsh-plugin-hub#40)
293
+ return h('div', { className: styles.failPrepareHint }, t('failPnpmWorkspaceHint'))
294
+ }
289
295
  if (kind === 'pnpmStore') {
290
296
  // pnpm 存在但 store 大版本不匹配(ERR_PNPM_UNEXPECTED_STORE):profile 目录旧依赖是
291
297
  // 另一大版本 pnpm 装的,当前 pnpm 不认,任何插件装进该 profile 都会失败 ——
@@ -304,6 +310,9 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
304
310
  return h('div', null, [
305
311
  // 「无法访问 …」醒目行:精准告诉用户具体哪个地址连不上(消息里取不到地址就跳过这行)
306
312
  (() => { const target = unreachableTargetOf(r.message); return target ? h('div', { className: styles.failNetworkTarget }, t('failNetworkTarget', { url: target })) : null })(),
313
+ // registry 被指向内网/自定义源(tarball 从非官方源下载失败):直接给出换源指引,
314
+ // 否则用户外网是通的会困惑「为什么连不上」(dsh-plugin-hub#32)
315
+ (() => { const host = registryHostOf(r.message); return host ? h('div', { className: styles.failPrepareHint }, t('failNetworkRegistryHint', { host })) : null })(),
307
316
  h('div', { className: styles.failPrepareHint }, t('failNetworkHint')),
308
317
  onRunDiagnostics ? h('button', {
309
318
  className: styles.failDiagBtn,
@@ -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 } from '../../logic/failures.ts'
19
+ import { classifyFailure, npmTooLowVersion, unreachableTargetOf, registryHostOf } from '../../logic/failures.ts'
20
20
 
21
21
  /** 完成结果视图:绿色对勾 + 标题/描述;
22
22
  * needsRestart=true(插件需重启才生效)→ 「稍后重启 / 立即重启」按钮对,点稍后重启后
@@ -403,6 +403,11 @@ export function ErrorModal({ message, repo, kind, command, attempts, t, env, onC
403
403
  // 全局 npm 安装通道 spawn 的 npm 找不到(Win「'npm' is not recognized」/ POSIX
404
404
  // 「npm: command not found」/ spawn ENOENT):本机 npm 未安装或不在 PATH —— 给安装指引,不引导提 Issue
405
405
  ? h('div', { className: styles.failPrepareHint }, t('failNpmMissingHint'))
406
+ : failureKind === 'pnpmWorkspace'
407
+ // pnpm 拒绝把依赖装到 workspace 根目录(ERR_PNPM_ADDING_TO_ROOT):宿主在 profile 目录
408
+ // 调 pnpm add 时未声明在根操作,任何插件都会失败,不是插件问题 ——
409
+ // 给 .npmrc 豁免指引,不引导提 Issue(dsh-plugin-hub#40)
410
+ ? h('div', { className: styles.failPrepareHint }, t('failPnpmWorkspaceHint'))
406
411
  : failureKind === 'pnpmStore'
407
412
  // pnpm 存在但 store 大版本不匹配(ERR_PNPM_UNEXPECTED_STORE):profile 目录旧依赖是
408
413
  // 另一大版本 pnpm 装的,当前 pnpm 不认,任何插件装进该 profile 都会失败 ——
@@ -419,6 +424,9 @@ export function ErrorModal({ message, repo, kind, command, attempts, t, env, onC
419
424
  ? h('div', null, [
420
425
  // 「无法访问 …」醒目行:精准告诉用户具体哪个地址连不上(消息里取不到地址就跳过这行)
421
426
  (() => { const target = unreachableTargetOf(message); return target ? h('div', { className: styles.failNetworkTarget }, t('failNetworkTarget', { url: target })) : null })(),
427
+ // registry 被指向内网/自定义源(tarball 从非官方源下载失败):直接给出换源指引,
428
+ // 否则用户外网是通的会困惑「为什么连不上」(dsh-plugin-hub#32)
429
+ (() => { const host = registryHostOf(message); return host ? h('div', { className: styles.failPrepareHint }, t('failNetworkRegistryHint', { host })) : null })(),
422
430
  h('div', { className: styles.failPrepareHint }, t('failNetworkHint')),
423
431
  onRunDiagnostics ? h('button', {
424
432
  className: styles.failDiagBtn,
@@ -308,6 +308,7 @@ export const zh = {
308
308
  // 安装前连通性预检 / 安装日志里的连接失败([network] / git fetch 超时 / DNS / TLS):本机网络或代理问题,不是插件问题,不引导提 Issue
309
309
  failNetworkHint: '安装前检测到网络不通:无法连接到安装源(可能是断网、DNS 解析失败、被防火墙拦截,或代理配置有问题)。这不是插件本身的问题 —— 请检查网络连接,或到「设置」里确认 HTTP 代理配置,再到「系统诊断」运行一次连通性检测,然后重试。',
310
310
  // 网络失败弹窗里的「无法访问 …」醒目行:直接告诉用户具体哪个地址连不上({url} 为提取的不可达地址)
311
+ failNetworkRegistryHint: '你的 npm/pnpm 源(registry)被配置为 {host},插件包需从该源下载但失败了。这通常是内网/自定义源没有同步该包(或需要内网认证)—— 请把 npm/pnpm 的 registry 指回官方源 https://registry.npmjs.org(或确认此源可访问该包)后重试。',
311
312
  failNetworkTarget: '无法访问 {url} —— 你的网络连接不通',
312
313
  // 「去系统诊断」直达按钮:网络不通提示下方的品牌实底按钮,跳到设置 → 系统诊断跑连通性检测
313
314
  failNetworkRunDiag: '去系统诊断检测网络',
@@ -316,6 +317,7 @@ export const zh = {
316
317
  failPnpmMissingHint: '安装器找到了 dsh,但系统里没有 pnpm 命令(dsh 用它来管理 profile 插件)。请先安装 pnpm(如 npm install -g pnpm),确认 pnpm 已加入 PATH 后重试。这不是插件本身的问题。',
317
318
  failNpmMissingHint: '系统找不到 npm 命令(npm 未安装或未加入系统 PATH),无法执行全局安装。请先安装 Node.js(自带 npm),确认 npm 已加入 PATH 后重试。这不是插件本身的问题。',
318
319
  failPnpmStoreHint: '安装器调用 pnpm 时报「store 位置不匹配」(ERR_PNPM_UNEXPECTED_STORE):你的 profile 目录里旧插件依赖是用另一个大版本的 pnpm 生成的,当前 pnpm 出于安全不认旧目录,导致任何插件装进该 profile 都会失败。请删除该 profile 目录下的 node_modules 与 pnpm-lock.yaml(可先到「系统日志」或 ~/.dsh/profiles/<profile>/hub.log 查看完整报错),再重新安装。这不是插件本身的问题。',
320
+ failPnpmWorkspaceHint: '安装器调用 pnpm 时报「不能把依赖装到 workspace 根目录」(ERR_PNPM_ADDING_TO_ROOT):你的 profile 目录被 pnpm 视为 workspace 根目录,而本次安装命令没有声明在根目录操作,pnpm 直接拒绝执行,因此任何插件装进来都会失败。这不是插件本身的问题——可在 profile 目录(~/.dsh/profiles/<profile>)的 .npmrc 里加一行 ignore-workspace-root-check=true 后重试,或把 DeepSeek Harness 升级到最新版再试。',
319
321
  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 查看完整报错)。',
320
322
  // 自定义安装三卡片入口的渠道名(报错/日志溯源:本次安装从哪个入口发起)
321
323
  installChannelNpm: 'NPM 包',
@@ -667,6 +669,7 @@ export const en = {
667
669
  // Pre-install connectivity probe / connection failure in the install log ([network] / git fetch timeout / DNS / TLS): a local network or proxy issue, not a plugin issue — no issue link
668
670
  failNetworkHint: 'The network could not be reached before install: the install source is unreachable (offline, DNS failure, firewall block, or a misconfigured proxy). This is not a problem with the plugin itself — please check your connection, confirm the HTTP proxy in Settings, run a connectivity check under System Diagnostics, then retry.',
669
671
  // Prominent "cannot reach …" line in the network-failure dialog: shows the exact unreachable address ({url})
672
+ failNetworkRegistryHint: 'Your npm/pnpm registry is set to {host}, and the package tarball could not be downloaded from it. This usually means a private/internal mirror that has not synced the package (or requires intranet auth) — point the registry back to https://registry.npmjs.org (or make sure this source can serve the package), then retry.',
670
673
  failNetworkTarget: 'Cannot reach {url} — your network connection is down',
671
674
  // Diagnostics shortcut button under the network-down hint: jumps to Settings → System Diagnostics
672
675
  failNetworkRunDiag: 'Run a network diagnostic',
@@ -675,6 +678,7 @@ export const en = {
675
678
  failPnpmMissingHint: 'The installer found dsh, but pnpm is missing on this machine (dsh uses it to manage profile plugins). Please install pnpm first (e.g. npm install -g pnpm), make sure it is on your PATH, then retry. This is not a problem with the plugin itself.',
676
679
  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.',
677
680
  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.',
681
+ 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.',
678
682
  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.',
679
683
  // Custom install entry channel names (the three cards) — used in error/log traceability
680
684
  installChannelNpm: 'NPM package',
@@ -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' | 'pnpmPolicy' | 'pnpmIgnoredBuild' | 'pluginPrepare' | 'network' | 'repo'
154
+ export type FailureKind = 'npmTooOld' | 'dshMissing' | 'gitMissing' | 'pnpmMissing' | 'npmMissing' | 'pnpmStore' | 'pnpmWorkspace' | 'pnpmPolicy' | 'pnpmIgnoredBuild' | 'pluginPrepare' | 'network' | 'repo'
155
155
 
156
156
  /**
157
157
  * 失败归类,七态。无论底层机制如何(pnpm 白名单拦截 / 构建脚本被忽略 / prepare 失败),
@@ -178,19 +178,29 @@ export type FailureKind = 'npmTooOld' | 'dshMissing' | 'gitMissing' | 'pnpmMissi
178
178
  * 本机 npm 未安装或不在 PATH,不是插件问题。dshMissing 的通用「not recognized」模式会把
179
179
  * `'npm' is not recognized` 吞成 dsh 缺失,所以必须在 dshMissing 之前判断
180
180
  * → 提示安装 npm(Node.js 自带)/加入 PATH,不引导提 Issue
181
- * - pnpmStore:pnpm 存在但报 store 位置不匹配(`ERR_PNPM_UNEXPECTED_STORE` / `Unexpected store
182
- * location`)—— profile 目录的 node_modules 是用不同大版本的 pnpm 生成的,当前 pnpm 不认,
183
- * 任何插件装进该 profile 都会失败;不是插件问题(dsh-plugin-hub#14:macOS 下
184
- * `ERR_PNPM_UNEXPECTED_STORE` 被误归插件侧失败)→ 提示清理 profile 依赖目录重建,不引导提 Issue
181
+ * - pnpmStore:pnpm 存在但报 store / virtual store 位置不匹配(`ERR_PNPM_UNEXPECTED_STORE` /
182
+ * `ERR_PNPM_UNEXPECTED_VIRTUAL_STORE` / `Unexpected store location`)—— profile 目录的 node_modules
183
+ * 是用不同大版本的 pnpm 生成的(或 profile 目录被复制/移动、virtual-store-dir 配置变化),
184
+ * 当前 pnpm 不认,任何插件装进该 profile 都会失败;不是插件问题(dsh-plugin-hub#14:macOS 下
185
+ * `ERR_PNPM_UNEXPECTED_STORE` 被误归插件侧失败;dsh-plugin-hub#30:`ERR_PNPM_UNEXPECTED_VIRTUAL_STORE`
186
+ * 漏判被误归插件侧失败)→ 提示清理 profile 依赖目录重建,不引导提 Issue
187
+ * - pnpmWorkspace:pnpm 在 workspace 根目录下拒绝安装(`ERR_PNPM_ADDING_TO_ROOT` —— 宿主在
188
+ * profile 目录里调用 `pnpm add` 时未声明在 workspace 根操作)。profile 目录含
189
+ * pnpm-workspace.yaml 即被 pnpm 视为 workspace 根,缺 `-w`/`--workspace-root` 就整条命令
190
+ * 被拒,任何插件都装不上,不是插件问题(dsh-plugin-hub#40)→ 提示在 profile 的 .npmrc 里
191
+ * 加 `ignore-workspace-root-check=true` 或升级宿主,不引导提 Issue
185
192
  * - pnpmPolicy:pnpm 11 的供应链安全策略拒绝安装(`ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION` /
186
193
  * `Minimum release age` —— 锁文件里包的发布时间还不满 24 小时被拒;`untrusted origin` —— 依赖来源未被
187
194
  * 本机 pnpm 信任)。拦的是「刚发布的新包」与「未被信任的来源」,装任何新插件都会撞墙,不是
188
195
  * 插件问题(dsh-plugin-hub#15/#16:用户装官方 dsh-plugin 也被这两类策略拦下并误归插件侧失败)
189
196
  * → 提示按子场景给解法(发布未满 24 小时 → `minimumReleaseAge: 0` 豁免或等满 24 小时;untrusted
190
197
  * origin → 删除 profile 的 node_modules + pnpm-lock.yaml 清掉不受信任来源后重装),不引导提 Issue
191
- * - network:安装前连通性预检拦截(服务端 `[network]` 标记)或底层连接失败
192
- * (ERR_PNPM_GIT_FETCH_FAILED / ETIMEDOUT / DNS 解析 / TLS 握手 / 代理拒绝)——
193
- * 是本机网络不通/被墙/代理有问题,不是插件问题 → 提示检查网络,不引导提 Issue
198
+ * - network:安装前连通性预检拦截(服务端 `[network]` 标记)、底层连接失败
199
+ * (ERR_PNPM_GIT_FETCH_FAILED / ETIMEDOUT / DNS 解析 / TLS 握手 / 代理拒绝),或
200
+ * registry tarball 拉取失败(`fetch failed` / `GET …/-/…tgz error (n)` —— 常见于本机
201
+ * npm/pnpm 的 registry 被指向内网/自定义源,该源取不到包)—— 是本机网络不通/被墙/
202
+ * 代理有问题/源配置异常,不是插件问题 → 提示检查网络,registry 指向自定义源时给出换源指引,
203
+ * 不引导提 Issue
194
204
  * - pnpmIgnoredBuild:插件自身或依赖的构建脚本被 pnpm 安全白名单(allowBuilds)默认拦截
195
205
  * (`ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` / `ERR_PNPM_IGNORED_BUILDS`)。只影响带安装期
196
206
  * 构建的插件,其他插件不受影响 —— 差异在插件的依赖/打包方式,属插件依赖/打包问题
@@ -229,12 +239,20 @@ export function classifyFailure(message: string): FailureKind {
229
239
  // 否则会被外层 "Command failed" 吞成「插件打包问题」,误导用户去提 Issue
230
240
  // (dsh-plugin-hub#12:Win 下 'dsh' 不在 PATH,cmd 报「不是内部或外部命令」被误归插件侧失败)
231
241
  if (/\[dsh-missing\]|不是内部或外部命令|is not recognized as an internal or external command|command not found|spawn dsh ENOENT/i.test(message)) return 'dshMissing'
232
- // pnpm 大版本不一致(ERR_PNPM_UNEXPECTED_STORE / Unexpected store location):profile 目录里
233
- // 旧依赖是另一个大版本 pnpm 生成的,当前 pnpm 出于安全不认旧 store —— 本机环境问题,
234
- // 任何插件装进该 profile 都会同样失败,不是插件问题(dsh-plugin-hub#14:macOS 下
235
- // `ERR_PNPM_UNEXPECTED_STORE` 被误归插件侧失败);提示清理依赖目录用当前 pnpm 重建,
236
- // 不引导提 Issue。必须在 pnpmMissing 之后 —— pnpm 在(能跑起来报错),不是「找不到命令」。
237
- if (/ERR_PNPM_UNEXPECTED_STORE|Unexpected store location/i.test(message)) return 'pnpmStore'
242
+ // pnpm 大版本/虚拟 store 位置不一致(ERR_PNPM_UNEXPECTED_STORE / ERR_PNPM_UNEXPECTED_VIRTUAL_STORE /
243
+ // Unexpected store location):profile 目录里旧依赖是另一个大版本 pnpm 生成的(或 profile 目录
244
+ // 被复制/移动、virtual-store-dir 配置变化导致 virtual store 位置不匹配),当前 pnpm 出于安全
245
+ // 不认旧 store —— 本机环境问题,任何插件装进该 profile 都会同样失败,不是插件问题
246
+ // (dsh-plugin-hub#14:macOS 下 ERR_PNPM_UNEXPECTED_STORE 被误归插件侧失败;
247
+ // dsh-plugin-hub#30:ERR_PNPM_UNEXPECTED_VIRTUAL_STORE 漏判被误归插件侧失败);
248
+ // 提示清理依赖目录用当前 pnpm 重建,不引导提 Issue。必须在 pnpmMissing 之后 ——
249
+ // pnpm 在(能跑起来报错),不是「找不到命令」。
250
+ if (/ERR_PNPM_UNEXPECTED_(VIRTUAL_)?STORE|Unexpected (virtual )?store location/i.test(message)) return 'pnpmStore'
251
+ // pnpm 拒绝在 workspace 根目录下安装(ERR_PNPM_ADDING_TO_ROOT):profile 目录被视为
252
+ // pnpm workspace 根,宿主调 pnpm add 时没声明在根操作(缺 -w/--workspace-root),
253
+ // pnpm 直接整条命令拒绝 —— 本机 profile/宿主调用方式问题,任何插件都装不上,不是插件问题
254
+ // (dsh-plugin-hub#40:Win 下装 hub 本体,ADDING_TO_ROOT 被误归插件侧失败)
255
+ if (/ERR_PNPM_ADDING_TO_ROOT|add the dependency to the workspace root/i.test(message)) return 'pnpmWorkspace'
238
256
  // pnpm 供应链安全策略拦截(pnpm 11:minimumReleaseAge 拒收「刚发布」的包 /
239
257
  // untrusted origin 来源不受信任):pnpm 在、也连得上,纯粹是本机策略不放行 ——
240
258
  // 装任何「新发布/非信任来源」的插件都会同样失败,不是插件问题(dsh-plugin-hub#15/#16)。
@@ -248,11 +266,15 @@ export function classifyFailure(message: string): FailureKind {
248
266
  // 「你的网络不通」(graph-memory issues #82-#84:PREPARE_NOT_ALLOWED + 尾随超时)。
249
267
  if (/ERR_PNPM_IGNORED_BUILDS|Ignored build scripts:|ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED/i.test(message)) return 'pnpmIgnoredBuild'
250
268
  // 网络问题(服务端 [network] 标记,或安装日志里的连接失败特征:git fetch 失败、
251
- // 连接超时/拒绝/重置、DNS 解析失败、TLS/SSL 握手失败)—— 是本机网络/代理问题,
252
- // 不是插件问题。必须在 prepare/Command failed 判定之前:git fetch 失败常被
269
+ // 连接超时/拒绝/重置、DNS 解析失败、TLS/SSL 握手失败,或 registry tarball 拉取失败
270
+ // —— `fetch failed` / `GET https://…/-/…tgz error (n)` 是 pnpm 下载包文件时的网络层失败,
271
+ // 常见于本机 npm/pnpm registry 被指向内网/自定义源而取不到包)—— 是本机网络/代理/源
272
+ // 配置问题,不是插件问题。必须在 prepare/Command failed 判定之前:git fetch 失败常被
253
273
  // 外层包成 "Command failed: git fetch ...",先按网络特征归类才不会误判成插件问题。
254
274
  // 404 类「目标不存在」不含这些特征,仍归 repo(那是仓库/包的问题)。
255
- if (/\[network\]|ERR_PNPM_GIT_FETCH_FAILED|ETIMEDOUT|ECONNREFUSED|ECONNRESET|ENOTFOUND|EAI_AGAIN|EPIPE|EHOSTUNREACH|ENETUNREACH|getaddrinfo|Could not connect|Could not resolve host|Network unreachable|Failed to connect|socket hang up|CERT_HAS_EXPIRED|SSL certificate problem|\bTLS\b|\bSSL\b/i.test(message)) return 'network'
275
+ // 注意:fetch failed 只在 pnpm 拉取阶段出现;prepare/构建已跑起来(tarball 到手)的
276
+ // 插件问题不带此特征,不会误伤(graph-memory #82-#84 的 allowBuilds 拦截在上一分支先判)。
277
+ if (/\[network\]|ERR_PNPM_GIT_FETCH_FAILED|ETIMEDOUT|ECONNREFUSED|ECONNRESET|ENOTFOUND|EAI_AGAIN|EPIPE|EHOSTUNREACH|ENETUNREACH|getaddrinfo|Could not connect|Could not resolve host|Network unreachable|Failed to connect|socket hang up|CERT_HAS_EXPIRED|SSL certificate problem|\bTLS\b|\bSSL\b|fetch failed|\bGET https?:\/\/\S+\.tgz\s+error \(\d+\)/i.test(message)) return 'network'
256
278
  // 装后校验拦截(服务端 verifyInstalledEntry 标记):入口文件缺失 = git 分发缺构建产物,
257
279
  // 与 pluginPrepare 同类(插件打包/分发问题),引导去仓库提 Issue
258
280
  if (/\[packaging\]|entry file missing/i.test(message)) return 'pluginPrepare'
@@ -271,6 +293,14 @@ export function npmTooLowVersion(message: string): string | null {
271
293
 
272
294
  /** 核心行特征:错误代码 / 生命周期脚本失败 / prepare 失败 / 描述性报错(子模块缺失、找不到等)/ 退出与宿主提示信息。 */
273
295
  const CORE_LINE_RE = /ERR_[A-Z_]+|ELIFECYCLE|Command failed|prepare-guard|Failed to prepare|exit code|\bprepare\b|pnpm failed in profile|git-hosted plugins build|submodule|not found|cannot find|no such|unable to|fatal|missing|error/i
296
+ /** pnpm 的 peer 依赖告警行(`missing peer …` / `Issues with peer dependencies found` /
297
+ * `Peer dependencies that should be installed`):宿主提供的 peer(@deepseek-ai/*、react、
298
+ * dsh-client-* 等,DSH profile 用 autoInstallPeers:false 不自动装)缺失是无害噪音,与插件本身
299
+ * 无关 —— 抓核心错误时必须跳过,否则会被 CORE_LINE_RE 的 `missing` 分支误抓、淹没真正的
300
+ * 错误码(如 git 源的 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED),让 issue 正文只剩一堆 peer WARN
301
+ * (dsh-plugin-hub#28:anime-find 的 auto-issue 核心错误全是 missing-peer WARN 树,真正的
302
+ * prepare 错误被盖住)。 */
303
+ const PEER_WARN_RE = /missing peer|issues with peer dependencies|peer dependencies that should be installed/i
274
304
  /** 提交 issue 时正文里错误摘要的上限字符数。GitHub 请求行上限 8192 字节,
275
305
  * 固定模板与 URL 编码开销约 1~2K,核心错误(以 ASCII 日志为主)可安全带到 ~5K;
276
306
  * 仍超长时 pluginIssueUrl 会逐档缩小核心预算,最终 URL 不会超限。 */
@@ -289,7 +319,7 @@ export function summarizeError(message: string, maxChars: number = MAX_CORE_CHAR
289
319
  const core: string[] = []
290
320
  for (const raw of message.split(/\r?\n/)) {
291
321
  const line = raw.trim()
292
- if (!line || !CORE_LINE_RE.test(line)) continue
322
+ if (!line || PEER_WARN_RE.test(line) || !CORE_LINE_RE.test(line)) continue
293
323
  const short = line.length > MAX_LINE_CHARS ? `${line.slice(0, MAX_LINE_CHARS)}…` : line
294
324
  if (!seen.has(short)) {
295
325
  seen.add(short)
@@ -330,3 +360,28 @@ export function unreachableTargetOf(message: string): string | null {
330
360
  const url = message.match(/https?:\/\/[^\s'"`<>()()]+/)
331
361
  return url ? url[0].replace(/[.,;:))\]]+$/, '') : null
332
362
  }
363
+
364
+ /** npm registry 的官方/常见公开镜像主机名:tarball 从这里下载属正常配置,
365
+ * 失败按「网络不通」提示即可,不需要额外的换源指引。 */
366
+ const PUBLIC_REGISTRY_HOSTS = new Set([
367
+ 'registry.npmjs.org',
368
+ 'registry.yarnpkg.com',
369
+ 'registry.npmmirror.com',
370
+ 'mirrors.cloud.tencent.com',
371
+ 'mirrors.huaweicloud.com',
372
+ ])
373
+
374
+ /**
375
+ * 网络类失败消息里,判断是否「npm/pnpm 的 registry 被指向了内网/自定义源导致拉包失败」。
376
+ * pnpm 下载包文件的 URL 形如 `<registry>/<pkg>/-/<pkg>-<ver>.tgz`(路径含 `/-/`);
377
+ * 若该 tarball 的主机不属于官方/常见公开镜像,说明本机 registry 被配成了私有/内网源
378
+ * (如公司 Artifactory)—— 常因源未同步该包、需内网认证或网络策略拦截而失败(dsh-plugin-hub#32)。
379
+ * 返回该主机名供前端给出「检查 registry 配置」的精准提示;官方/公开源或提取不到返回 null,
380
+ * 调用方按通用网络问题提示即可。
381
+ */
382
+ export function registryHostOf(message: string): string | null {
383
+ const m = message.match(/https?:\/\/([^/\s]+)\/[^\s'"`<>]*\/-\/[^\s'"`<>]+/)
384
+ if (!m) return null
385
+ const host = m[1].replace(/:\d+$/, '')
386
+ return PUBLIC_REGISTRY_HOSTS.has(host) ? null : host
387
+ }
@@ -49,6 +49,7 @@ function reasonTitleOf(kind: FailureKind): string {
49
49
  case 'dshMissing': return 'dsh command not found on the user machine'
50
50
  case 'pnpmMissing': return 'pnpm command not found on the user machine'
51
51
  case 'pnpmStore': return 'pnpm store version mismatch on the user machine'
52
+ case 'pnpmWorkspace': return 'pnpm workspace-root check blocked the install on the user machine'
52
53
  case 'pnpmPolicy': return 'pnpm supply-chain policy blocked the install on the user machine'
53
54
  case 'pnpmIgnoredBuild': return 'build scripts blocked by pnpm allowlist'
54
55
  case 'pluginPrepare': return 'plugin distribution incomplete'