dsh-plugin 1.3.9 → 1.3.10
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 +9 -9
- package/README.md +9 -9
- package/client/client.js +309 -296
- package/client/client.js.map +1 -1
- package/lib/http/routes.js +19 -1
- package/package.json +1 -1
- package/src/client/components/modals/NotificationsModal.tsx +6 -0
- package/src/client/components/modals/modals.tsx +5 -0
- package/src/client/locales.ts +2 -0
- package/src/client/logic/failures.ts +11 -1
- package/src/client/logic/urls.ts +8 -0
- package/src/client/types.ts +6 -0
- package/src/server/http/routes.ts +18 -1
package/lib/http/routes.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
12
12
|
import { homedir, release } from 'node:os';
|
|
13
13
|
import { dirname, join, resolve } from 'node:path';
|
|
14
|
-
import { spawn } from 'node:child_process';
|
|
14
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
15
15
|
import { fetchViaCurl, gitLsRemote, probeUrl, systemProxy } from '../services/probe.js';
|
|
16
16
|
import { activeTask, cancelTask, dumpLoaderEntries, getTask, githubRepoOf, githubTarget, globalNpmPackagesOf, hasQueuedTarget, installTargetOf, listPendingRestarts, readProfileArg, startPluginMutation, validPackageName } from '../services/install/install.js';
|
|
17
17
|
import { recordInstalledVersion, recordResolvedNpmPackage, readInstalledVersions, removeInstalledVersion } from '../services/profile/installed-versions.js';
|
|
@@ -145,11 +145,29 @@ function hostDshVersion() {
|
|
|
145
145
|
}
|
|
146
146
|
return null;
|
|
147
147
|
}
|
|
148
|
+
/** 探测命令行工具的版本号(pnpm --version / npm --version / git --version):
|
|
149
|
+
* 未安装 / 不在 PATH / 超时一律返回 null —— issue 环境快照如实写 unknown,绝不挂起。
|
|
150
|
+
* (同步探测仅用于启动期/请求期的低频率 /env 快照,安装通道不经过这里。) */
|
|
151
|
+
function toolVersion(cmd, args) {
|
|
152
|
+
try {
|
|
153
|
+
const r = spawnSync(cmd, args, { timeout: 1500, encoding: 'utf8' });
|
|
154
|
+
if (r.error || r.status !== 0)
|
|
155
|
+
return null;
|
|
156
|
+
const v = (r.stdout ?? '').trim().split(/\r?\n/)[0];
|
|
157
|
+
return v || null;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
148
163
|
/** 宿主环境快照:提交 bug 时随 issue 附上,便于作者复现(前端 /env 端点返回)。 */
|
|
149
164
|
function hostEnv(profile) {
|
|
150
165
|
return {
|
|
151
166
|
dshVersion: hostDshVersion(),
|
|
152
167
|
nodeVersion: process.version,
|
|
168
|
+
pnpmVersion: toolVersion('pnpm', ['--version']),
|
|
169
|
+
npmVersion: toolVersion('npm', ['--version']),
|
|
170
|
+
gitVersion: toolVersion('git', ['--version']),
|
|
153
171
|
platform: process.platform,
|
|
154
172
|
arch: process.arch,
|
|
155
173
|
release: release(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.10",
|
|
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",
|
|
@@ -276,6 +276,12 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
276
276
|
// 本机缺 pnpm,不是插件问题 —— 给安装指引,不引导提 Issue
|
|
277
277
|
return h('div', { className: styles.failPrepareHint }, t('failPnpmMissingHint'))
|
|
278
278
|
}
|
|
279
|
+
if (kind === 'pnpmStore') {
|
|
280
|
+
// pnpm 存在但 store 大版本不匹配(ERR_PNPM_UNEXPECTED_STORE):profile 目录旧依赖是
|
|
281
|
+
// 另一大版本 pnpm 装的,当前 pnpm 不认,任何插件装进该 profile 都会失败 ——
|
|
282
|
+
// 给清理重建指引,不引导提 Issue
|
|
283
|
+
return h('div', { className: styles.failPrepareHint }, t('failPnpmStoreHint'))
|
|
284
|
+
}
|
|
279
285
|
if (kind === 'network') {
|
|
280
286
|
// 安装前预检 / 安装日志里的连接失败([network] / git fetch 超时 / DNS / TLS):
|
|
281
287
|
// 是本机网络不通或代理有问题,不是插件问题 —— 提示检查网络 + 直达「系统诊断」,
|
|
@@ -395,6 +395,11 @@ export function ErrorModal({ message, repo, kind, command, attempts, t, env, onC
|
|
|
395
395
|
// 找到了 dsh 但缺 pnpm(dsh 用它管理 profile 插件;dsh 报 pnpm not found on PATH):
|
|
396
396
|
// 本机缺 pnpm,不是插件问题 —— 给安装指引,不引导提 Issue
|
|
397
397
|
? h('div', { className: styles.failPrepareHint }, t('failPnpmMissingHint'))
|
|
398
|
+
: failureKind === 'pnpmStore'
|
|
399
|
+
// pnpm 存在但 store 大版本不匹配(ERR_PNPM_UNEXPECTED_STORE):profile 目录旧依赖是
|
|
400
|
+
// 另一大版本 pnpm 装的,当前 pnpm 不认,任何插件装进该 profile 都会失败 ——
|
|
401
|
+
// 给清理重建指引,不引导提 Issue
|
|
402
|
+
? h('div', { className: styles.failPrepareHint }, t('failPnpmStoreHint'))
|
|
398
403
|
: failureKind === 'network'
|
|
399
404
|
// 安装前预检 / 安装日志里的连接失败([network] / git fetch 超时 / DNS / TLS):
|
|
400
405
|
// 是本机网络不通或代理有问题,不是插件问题 —— 提示检查网络 + 直达「系统诊断」,
|
package/src/client/locales.ts
CHANGED
|
@@ -313,6 +313,7 @@ export const zh = {
|
|
|
313
313
|
failNetworkRunDiag: '去系统诊断检测网络',
|
|
314
314
|
failDshMissingHint: '系统找不到 dsh 命令(dsh 未加入系统 PATH),无法调用安装器执行安装。请确认 DeepSeek Harness 已正确安装、dsh 已加入 PATH(或重新安装),然后重试。这不是插件本身的问题。',
|
|
315
315
|
failPnpmMissingHint: '安装器找到了 dsh,但系统里没有 pnpm 命令(dsh 用它来管理 profile 插件)。请先安装 pnpm(如 npm install -g pnpm),确认 pnpm 已加入 PATH 后重试。这不是插件本身的问题。',
|
|
316
|
+
failPnpmStoreHint: '安装器调用 pnpm 时报「store 位置不匹配」(ERR_PNPM_UNEXPECTED_STORE):你的 profile 目录里旧插件依赖是用另一个大版本的 pnpm 生成的,当前 pnpm 出于安全不认旧目录,导致任何插件装进该 profile 都会失败。请删除该 profile 目录下的 node_modules 与 pnpm-lock.yaml(可先到「系统日志」或 ~/.dsh/profiles/<profile>/hub.log 查看完整报错),再重新安装。这不是插件本身的问题。',
|
|
316
317
|
// 自定义安装三卡片入口的渠道名(报错/日志溯源:本次安装从哪个入口发起)
|
|
317
318
|
installChannelNpm: 'NPM 包',
|
|
318
319
|
installChannelGit: 'GitHub 源码',
|
|
@@ -668,6 +669,7 @@ export const en = {
|
|
|
668
669
|
failNetworkRunDiag: 'Run a network diagnostic',
|
|
669
670
|
failDshMissingHint: 'The dsh command could not be found (it is not on the system PATH), so the installer could not run. Please make sure DeepSeek Harness is installed correctly and dsh is on your PATH (or reinstall it), then retry. This is not a problem with the plugin itself.',
|
|
670
671
|
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.',
|
|
672
|
+
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.',
|
|
671
673
|
// Custom install entry channel names (the three cards) — used in error/log traceability
|
|
672
674
|
installChannelNpm: 'NPM package',
|
|
673
675
|
installChannelGit: 'GitHub source',
|
|
@@ -151,7 +151,7 @@ export function removeNotification(id: number): NotificationRecord[] {
|
|
|
151
151
|
return next
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
export type FailureKind = 'npmTooOld' | 'dshMissing' | 'pnpmMissing' | 'pnpmIgnoredBuild' | 'pluginPrepare' | 'network' | 'repo'
|
|
154
|
+
export type FailureKind = 'npmTooOld' | 'dshMissing' | 'pnpmMissing' | 'pnpmStore' | 'pnpmIgnoredBuild' | 'pluginPrepare' | 'network' | 'repo'
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
157
|
* 失败归类,七态。无论底层机制如何(pnpm 白名单拦截 / 构建脚本被忽略 / prepare 失败),
|
|
@@ -167,6 +167,10 @@ export type FailureKind = 'npmTooOld' | 'dshMissing' | 'pnpmMissing' | 'pnpmIgno
|
|
|
167
167
|
* 「pnpm: command not found」/ spawn ENOENT)—— 本机缺 pnpm(dsh 用 pnpm 管理 profile 插件),
|
|
168
168
|
* 不是插件问题(dsh-plugin-hub#13:Linux 下 `dsh: pnpm not found on PATH` 被误归插件侧失败)
|
|
169
169
|
* → 提示安装/开启 pnpm,不引导提 Issue
|
|
170
|
+
* - pnpmStore:pnpm 存在但报 store 位置不匹配(`ERR_PNPM_UNEXPECTED_STORE` / `Unexpected store
|
|
171
|
+
* location`)—— profile 目录的 node_modules 是用不同大版本的 pnpm 生成的,当前 pnpm 不认,
|
|
172
|
+
* 任何插件装进该 profile 都会失败;不是插件问题(dsh-plugin-hub#14:macOS 下
|
|
173
|
+
* `ERR_PNPM_UNEXPECTED_STORE` 被误归插件侧失败)→ 提示清理 profile 依赖目录重建,不引导提 Issue
|
|
170
174
|
* - network:安装前连通性预检拦截(服务端 `[network]` 标记)或底层连接失败
|
|
171
175
|
* (ERR_PNPM_GIT_FETCH_FAILED / ETIMEDOUT / DNS 解析 / TLS 握手 / 代理拒绝)——
|
|
172
176
|
* 是本机网络不通/被墙/代理有问题,不是插件问题 → 提示检查网络,不引导提 Issue
|
|
@@ -196,6 +200,12 @@ export function classifyFailure(message: string): FailureKind {
|
|
|
196
200
|
// 否则会被外层 "Command failed" 吞成「插件打包问题」,误导用户去提 Issue
|
|
197
201
|
// (dsh-plugin-hub#12:Win 下 'dsh' 不在 PATH,cmd 报「不是内部或外部命令」被误归插件侧失败)
|
|
198
202
|
if (/\[dsh-missing\]|不是内部或外部命令|is not recognized as an internal or external command|command not found|spawn dsh ENOENT/i.test(message)) return 'dshMissing'
|
|
203
|
+
// pnpm 大版本不一致(ERR_PNPM_UNEXPECTED_STORE / Unexpected store location):profile 目录里
|
|
204
|
+
// 旧依赖是另一个大版本 pnpm 生成的,当前 pnpm 出于安全不认旧 store —— 本机环境问题,
|
|
205
|
+
// 任何插件装进该 profile 都会同样失败,不是插件问题(dsh-plugin-hub#14:macOS 下
|
|
206
|
+
// `ERR_PNPM_UNEXPECTED_STORE` 被误归插件侧失败);提示清理依赖目录用当前 pnpm 重建,
|
|
207
|
+
// 不引导提 Issue。必须在 pnpmMissing 之后 —— pnpm 在(能跑起来报错),不是「找不到命令」。
|
|
208
|
+
if (/ERR_PNPM_UNEXPECTED_STORE|Unexpected store location/i.test(message)) return 'pnpmStore'
|
|
199
209
|
// 构建脚本被 pnpm 白名单(allowBuilds)拦截:插件的 prepare 脚本或依赖里的原生模块构建
|
|
200
210
|
// 被默认拒绝(ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED / ERR_PNPM_IGNORED_BUILDS)。
|
|
201
211
|
// 这类错误出现即说明 pnpm 已成功 fetch 到 tarball(网络是通的),主因是插件构建脚本
|
package/src/client/logic/urls.ts
CHANGED
|
@@ -42,6 +42,7 @@ function reasonTitleOf(kind: FailureKind): string {
|
|
|
42
42
|
case 'npmTooOld': return 'npm too old to install'
|
|
43
43
|
case 'dshMissing': return 'dsh command not found on the user machine'
|
|
44
44
|
case 'pnpmMissing': return 'pnpm command not found on the user machine'
|
|
45
|
+
case 'pnpmStore': return 'pnpm store version mismatch on the user machine'
|
|
45
46
|
case 'pnpmIgnoredBuild': return 'build scripts blocked by pnpm allowlist'
|
|
46
47
|
case 'pluginPrepare': return 'plugin distribution incomplete'
|
|
47
48
|
case 'network': return 'network failure on the user side'
|
|
@@ -110,9 +111,16 @@ export function pluginIssueUrl(repo: string, message: string, env?: EnvInfo | nu
|
|
|
110
111
|
`- DSH: ${env.dshVersion ? `v${env.dshVersion}` : 'unknown'}`,
|
|
111
112
|
`- Plugin Hub: v${PLUGIN_VERSION}`,
|
|
112
113
|
`- Node: ${env.nodeVersion}`,
|
|
114
|
+
// 工具链版本:pnpm/npm/git —— 排查 ERR_PNPM_UNEXPECTED_STORE(store 大版本不匹配)
|
|
115
|
+
// 这类环境问题,作者一眼就能对号入座;探测不到如实写 unknown
|
|
116
|
+
`- pnpm: ${env.pnpmVersion ? `v${env.pnpmVersion}` : 'unknown'}`,
|
|
117
|
+
`- npm: ${env.npmVersion ? `v${env.npmVersion}` : 'unknown'}`,
|
|
118
|
+
`- git: ${env.gitVersion ? `v${env.gitVersion}` : 'unknown'}`,
|
|
113
119
|
`- OS: ${env.platform} ${env.arch} (${env.release})`,
|
|
114
120
|
`- Profile: \`${env.profile}\``,
|
|
115
121
|
`- DSH Home: \`${env.dshHome}\``,
|
|
122
|
+
// 完整安装日志所在(正文受 URL 长度限制只能带摘要,完整日志在 hub.log,可复制/附加给作者)
|
|
123
|
+
`- Full log: \`~/.dsh/profiles/${env.profile}/hub.log\` (paste or attach for the full output)`,
|
|
116
124
|
]
|
|
117
125
|
: []),
|
|
118
126
|
// 该插件在插件中心的收录位置(详情页链接)
|
package/src/client/types.ts
CHANGED
|
@@ -87,6 +87,12 @@ export interface ToastState {
|
|
|
87
87
|
export interface EnvInfo {
|
|
88
88
|
dshVersion: string | null
|
|
89
89
|
nodeVersion: string
|
|
90
|
+
/** 本机 pnpm 版本(pnpm --version 首行;缺失返回 null)—— 排查 ERR_PNPM_UNEXPECTED_STORE 等 pnpm 环境问题 */
|
|
91
|
+
pnpmVersion: string | null
|
|
92
|
+
/** 本机 npm 版本(npm --version 首行;缺失返回 null) */
|
|
93
|
+
npmVersion: string | null
|
|
94
|
+
/** 本机 git 版本(git --version 首行;缺失返回 null) */
|
|
95
|
+
gitVersion: string | null
|
|
90
96
|
platform: string
|
|
91
97
|
arch: string
|
|
92
98
|
release: string
|
|
@@ -12,7 +12,7 @@ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
|
12
12
|
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
13
13
|
import { homedir, release } from 'node:os'
|
|
14
14
|
import { dirname, join, resolve } from 'node:path'
|
|
15
|
-
import { spawn } from 'node:child_process'
|
|
15
|
+
import { spawn, spawnSync } from 'node:child_process'
|
|
16
16
|
import { fetchViaCurl, gitLsRemote, probeUrl, systemProxy } from '../services/probe.ts'
|
|
17
17
|
import { activeTask, cancelTask, dumpLoaderEntries, getTask, githubRepoOf, githubTarget, globalNpmPackagesOf, hasQueuedTarget, installTargetOf, listPendingRestarts, readProfileArg, startPluginMutation, validPackageName, type LoaderHandle } from '../services/install/install.ts'
|
|
18
18
|
import { recordInstalledVersion, recordResolvedNpmPackage, readInstalledVersions, removeInstalledVersion } from '../services/profile/installed-versions.ts'
|
|
@@ -171,11 +171,28 @@ function hostDshVersion(): string | null {
|
|
|
171
171
|
return null
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
/** 探测命令行工具的版本号(pnpm --version / npm --version / git --version):
|
|
175
|
+
* 未安装 / 不在 PATH / 超时一律返回 null —— issue 环境快照如实写 unknown,绝不挂起。
|
|
176
|
+
* (同步探测仅用于启动期/请求期的低频率 /env 快照,安装通道不经过这里。) */
|
|
177
|
+
function toolVersion(cmd: string, args: string[]): string | null {
|
|
178
|
+
try {
|
|
179
|
+
const r = spawnSync(cmd, args, { timeout: 1500, encoding: 'utf8' })
|
|
180
|
+
if (r.error || r.status !== 0) return null
|
|
181
|
+
const v = (r.stdout ?? '').trim().split(/\r?\n/)[0]
|
|
182
|
+
return v || null
|
|
183
|
+
} catch {
|
|
184
|
+
return null
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
174
188
|
/** 宿主环境快照:提交 bug 时随 issue 附上,便于作者复现(前端 /env 端点返回)。 */
|
|
175
189
|
function hostEnv(profile: string): Record<string, string | null> {
|
|
176
190
|
return {
|
|
177
191
|
dshVersion: hostDshVersion(),
|
|
178
192
|
nodeVersion: process.version,
|
|
193
|
+
pnpmVersion: toolVersion('pnpm', ['--version']),
|
|
194
|
+
npmVersion: toolVersion('npm', ['--version']),
|
|
195
|
+
gitVersion: toolVersion('git', ['--version']),
|
|
179
196
|
platform: process.platform,
|
|
180
197
|
arch: process.arch,
|
|
181
198
|
release: release(),
|