dsh-plugin 1.6.12 → 2.0.1
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 +13 -13
- package/README.md +13 -13
- package/client/client.js +791 -761
- package/client/client.js.map +1 -1
- package/lib/http/catalog.js +2 -3
- package/lib/http/diagnostics.js +6 -7
- package/lib/http/install.js +47 -213
- package/lib/http/logs.js +1 -2
- package/lib/http/npm-release-age.js +42 -0
- package/lib/http/routes.js +8 -7
- package/lib/http/settings.js +2 -2
- package/lib/http/shared.js +2 -2
- package/lib/http/task.js +1 -2
- package/lib/index.js +5 -6
- package/lib/services/install/install-types.js +4 -4
- package/lib/services/install/install.js +1 -1
- package/lib/services/install/npm-check.js +3 -2
- package/lib/services/install/npm-resolve.js +9 -96
- package/lib/services/install/operation-log.js +53 -1
- package/lib/services/install/package-entry.js +6 -11
- package/lib/services/install/registry-check.js +2 -2
- package/lib/services/install/release-target.js +8 -9
- package/lib/services/install/task-queue.js +44 -48
- package/lib/services/npm-release-age.js +119 -0
- package/lib/services/probe.js +4 -4
- package/lib/services/profile/installed-versions.js +15 -21
- package/lib/services/profile/profile.js +16 -44
- package/lib/services/profile/progress.js +8 -11
- package/lib/services/settings.js +2 -5
- package/lib/types/http/catalog.d.ts +1 -1
- package/lib/types/http/install.d.ts +2 -2
- package/lib/types/http/npm-release-age.d.ts +2 -0
- package/lib/types/http/routes.d.ts +10 -12
- package/lib/types/http/shared.d.ts +5 -6
- package/lib/types/index.d.ts +7 -8
- package/lib/types/services/install/install-types.d.ts +12 -13
- package/lib/types/services/install/install.d.ts +1 -1
- package/lib/types/services/install/npm-resolve.d.ts +4 -16
- package/lib/types/services/install/operation-log.d.ts +9 -0
- package/lib/types/services/install/package-entry.d.ts +6 -11
- package/lib/types/services/install/release-target.d.ts +7 -8
- package/lib/types/services/install/task-queue.d.ts +25 -30
- package/lib/types/services/npm-release-age.d.ts +15 -0
- package/lib/types/services/probe.d.ts +4 -4
- package/lib/types/services/profile/installed-versions.d.ts +5 -7
- package/lib/types/services/profile/profile.d.ts +14 -18
- package/lib/types/services/profile/progress.d.ts +7 -10
- package/lib/types/services/settings.d.ts +0 -4
- package/package.json +1 -1
- package/src/client/components/PluginHubSection.tsx +26 -22
- package/src/client/components/catalog/CatalogList.tsx +2 -4
- package/src/client/components/catalog/PluginCard.tsx +2 -3
- package/src/client/components/layout/CatalogControls.tsx +5 -6
- package/src/client/components/layout/CatalogHeader.tsx +1 -2
- package/src/client/components/layout/CategoryTabs.tsx +2 -3
- package/src/client/components/layout/SectionTabs.tsx +3 -5
- package/src/client/components/modals/ConfirmDialog.tsx +4 -6
- package/src/client/components/modals/InstalledDetailModal.tsx +3 -6
- package/src/client/components/modals/LogsModal.tsx +7 -12
- package/src/client/components/modals/NotificationsModal.tsx +74 -24
- package/src/client/components/modals/ProgressView.tsx +3 -4
- package/src/client/components/modals/modals.tsx +75 -26
- package/src/client/components/ui/Dropdown.tsx +4 -6
- package/src/client/components/ui/Toggle.tsx +2 -3
- package/src/client/components/ui/icons.tsx +1 -2
- package/src/client/components/views/CustomInstallView.tsx +20 -178
- package/src/client/components/views/DiagnosticsView.tsx +3 -6
- package/src/client/components/views/InstalledView.tsx +6 -11
- package/src/client/components/views/MarketView.tsx +2 -4
- package/src/client/components/views/SettingsView.tsx +9 -32
- package/src/client/css-modules.d.ts +1 -1
- package/src/client/data/catalog.ts +2 -3
- package/src/client/data/host.ts +26 -3
- package/src/client/data/hub.ts +2 -3
- package/src/client/hooks/useCatalog.ts +79 -24
- package/src/client/hooks/useIncrementalList.ts +3 -5
- package/src/client/hooks/useLanguage.ts +4 -6
- package/src/client/hooks/useSettings.ts +4 -11
- package/src/client/hooks/useTaskQueue.ts +36 -42
- package/src/client/index.tsx +2 -3
- package/src/client/locales.ts +187 -114
- package/src/client/logic/constants.ts +1 -2
- package/src/client/logic/ensure-plugin-css.ts +8 -12
- package/src/client/logic/failures.ts +20 -19
- package/src/client/logic/format.ts +1 -1
- package/src/client/logic/install-command.ts +14 -35
- package/src/client/logic/installed.ts +15 -10
- package/src/client/logic/normalize.ts +3 -3
- package/src/client/logic/release-age.ts +19 -0
- package/src/client/logic/urls.ts +24 -21
- package/src/client/styles/CustomInstallView.module.css +3 -30
- package/src/client/styles/DiagnosticsView.module.css +3 -5
- package/src/client/styles/Dropdown.module.css +2 -4
- package/src/client/styles/Header.module.css +6 -7
- package/src/client/styles/InstalledView.module.css +4 -7
- package/src/client/styles/List.module.css +4 -5
- package/src/client/styles/LogsView.module.css +2 -3
- package/src/client/styles/Modal.module.css +46 -6
- package/src/client/styles/SectionTabs.module.css +2 -4
- package/src/client/styles/SettingsView.module.css +3 -5
- package/src/client/styles/Toggle.module.css +2 -4
- package/src/client/styles/tokens.module.css +14 -18
- package/src/client/types.ts +11 -11
- package/src/server/http/catalog.ts +2 -3
- package/src/server/http/diagnostics.ts +6 -7
- package/src/server/http/install.ts +47 -208
- package/src/server/http/logs.ts +1 -2
- package/src/server/http/npm-release-age.ts +42 -0
- package/src/server/http/routes.ts +12 -12
- package/src/server/http/settings.ts +2 -2
- package/src/server/http/shared.ts +5 -6
- package/src/server/http/task.ts +1 -2
- package/src/server/index.ts +7 -8
- package/src/server/services/install/install-types.ts +12 -13
- package/src/server/services/install/install.ts +0 -1
- package/src/server/services/install/npm-check.ts +3 -2
- package/src/server/services/install/npm-resolve.ts +9 -99
- package/src/server/services/install/operation-log.ts +47 -1
- package/src/server/services/install/package-entry.ts +6 -11
- package/src/server/services/install/registry-check.ts +2 -2
- package/src/server/services/install/release-target.ts +8 -9
- package/src/server/services/install/task-queue.ts +51 -54
- package/src/server/services/npm-release-age.ts +107 -0
- package/src/server/services/probe.ts +4 -4
- package/src/server/services/profile/installed-versions.ts +16 -22
- package/src/server/services/profile/profile.ts +16 -42
- package/src/server/services/profile/progress.ts +8 -11
- package/src/server/services/settings.ts +2 -9
- package/lib/services/install/preflight.js +0 -178
- package/lib/types/services/install/preflight.d.ts +0 -23
- package/src/server/services/install/preflight.ts +0 -184
|
@@ -3,15 +3,11 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* remove task — successes and failures alike.
|
|
6
|
+
* 通知中心弹窗:每个已结算的安装/卸载任务(成功与失败)的持久化清单。
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* success, red cross for failure) with white glyph and message text;
|
|
13
|
-
* failures keep their copy / fix / file-an-issue actions. Opened from the
|
|
14
|
-
* header entry button (after the Settings tab).
|
|
8
|
+
* 记录在结算时写入 localStorage(见 logic/failures.ts),即使弹窗被关闭或用户离开,
|
|
9
|
+
* 结果也不会丢失。每条带圆形状态徽标(成功绿勾、失败红叉,白色图形)与消息文本;
|
|
10
|
+
* 失败项保留复制/修复/提 Issue 动作。由头部入口按钮(「设置」tab 之后)打开。
|
|
15
11
|
*/
|
|
16
12
|
import { createElement as h, useState } from 'react'
|
|
17
13
|
import type { MouseEvent } from 'react'
|
|
@@ -206,14 +202,19 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
206
202
|
? (isUpdate
|
|
207
203
|
? h('span', { className: styles.failRepo, title: r.repo }, r.repo)
|
|
208
204
|
: shownRepo
|
|
209
|
-
?
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
205
|
+
? (() => {
|
|
206
|
+
const url = pluginSiteUrl(shownRepo)
|
|
207
|
+
return h('a', {
|
|
208
|
+
className: styles.failRepo,
|
|
209
|
+
// 跳官网「插件详情」页;文字里直接给出目标地址(去掉协议)
|
|
210
|
+
href: url,
|
|
211
|
+
target: '_blank',
|
|
212
|
+
rel: 'noopener noreferrer',
|
|
213
|
+
title: url,
|
|
214
|
+
},
|
|
215
|
+
h('span', { className: styles.failRepoLabel }, `${t('detailTitle')} · `),
|
|
216
|
+
h('span', { className: styles.failRepoUrl }, url.replace(/^https?:\/\//, '').split('?')[0]))
|
|
217
|
+
})()
|
|
217
218
|
// 反查不到仓库身份(如命令行安装的裸 npm 包名):回退显示记录里的原始值,
|
|
218
219
|
// 保证通知永不只剩一句「安装/更新成功」没有名字 —— 只是不给官网外链(查不到不敢乱跳)
|
|
219
220
|
: h('span', { className: styles.failRepo, title: r.repo }, r.repo))
|
|
@@ -251,6 +252,16 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
251
252
|
onClick: (e: MouseEvent<HTMLButtonElement>) => { e.stopPropagation(); setConfirmRemoveId(r.id) },
|
|
252
253
|
}, h(CloseIcon)),
|
|
253
254
|
),
|
|
255
|
+
// 统一失败卡片头部:报错类型 + 一句话原因(具体指引在下面的分支里)
|
|
256
|
+
!r.ok && (() => {
|
|
257
|
+
const k = classifyFailure(r.message)
|
|
258
|
+
return h('div', null, [
|
|
259
|
+
h('div', { className: styles.failKindTitle }, t(`failKind_${k}`, k === 'hostIncompatible'
|
|
260
|
+
? { version: /incompatible with dsh\s+([^\s:;,]+)/i.exec(r.message ?? '')?.[1] ?? '' }
|
|
261
|
+
: undefined)),
|
|
262
|
+
k === 'hostIncompatible' ? null : h('div', { className: styles.failReason }, t(`failReason_${k}`)),
|
|
263
|
+
])
|
|
264
|
+
})(),
|
|
254
265
|
// 每条失败记录是一个独立卡片:头部(状态/仓库/时间/复制完整日志)→ 修复或提 Issue 动作。
|
|
255
266
|
// 卡片不展示错误日志预览,完整日志靠「复制完整日志」按钮带走,避免每条卡片被日志撑高
|
|
256
267
|
!r.ok && (() => {
|
|
@@ -334,9 +345,25 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
334
345
|
}, t('failIssueBig')) : null,
|
|
335
346
|
])
|
|
336
347
|
}
|
|
348
|
+
if (kind === 'hostIncompatible') {
|
|
349
|
+
// 宿主版本门禁:插件声明的兼容范围不含当前 dsh 版本,安装前就被拒绝。
|
|
350
|
+
// 作者能修(把该版本加进兼容清单),故引导到作者仓库;同时说明本地可临时授权
|
|
351
|
+
const version = /incompatible with dsh\s+([^\s:;,]+)/i.exec(r.message ?? '')?.[1] ?? ''
|
|
352
|
+
return h('div', null, [
|
|
353
|
+
h('div', { className: styles.failReason }, t('failHostIncompatibleReason', { version })),
|
|
354
|
+
h('div', { className: styles.failPrepareHint }, t('failHostIncompatibleHint')),
|
|
355
|
+
r.repo && shownRepo ? h('a', {
|
|
356
|
+
className: styles.failBigIssue,
|
|
357
|
+
href: pluginIssueUrl(shownRepo, r.message, env, r.command, r.attempts, action),
|
|
358
|
+
target: '_blank',
|
|
359
|
+
rel: 'noopener noreferrer',
|
|
360
|
+
title: t('failIssueHint'),
|
|
361
|
+
}, t('failIssueBig')) : null,
|
|
362
|
+
])
|
|
363
|
+
}
|
|
337
364
|
if (kind === 'registryVersionStale') {
|
|
338
365
|
// 要装的版本在「实际执行安装的那个源」里查不到(ERR_PNPM_NO_MATCHING_VERSION / ETARGET):
|
|
339
|
-
// 常见于镜像滞后 ——
|
|
366
|
+
// 常见于镜像滞后 —— 实际安装沿用本机 ~/.npmrc 的源;
|
|
340
367
|
// 也可能只是版本号写错。与插件作者无关 —— 给对齐源 / 显式走官方源 / 离线包指引,不引导提 Issue
|
|
341
368
|
return h('div', { className: styles.failPrepareHint }, t('failRegistryVersionStaleHint'))
|
|
342
369
|
}
|
|
@@ -367,7 +394,7 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
367
394
|
return h('div', { className: styles.failPrepareHint }, t('failOriginRejectedHint', { profile: env?.profile ?? '<profile>' }))
|
|
368
395
|
}
|
|
369
396
|
if (kind === 'network') {
|
|
370
|
-
//
|
|
397
|
+
// 安装前网络探测 / 安装日志里的连接失败([network] / git fetch 超时 / DNS / TLS):
|
|
371
398
|
// 是本机网络不通或代理有问题,不是插件问题 —— 提示检查网络 + 直达「系统诊断」,
|
|
372
399
|
// 不引导提 Issue
|
|
373
400
|
return h('div', null, [
|
|
@@ -384,7 +411,7 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
384
411
|
])
|
|
385
412
|
}
|
|
386
413
|
if (kind === 'pluginPrepare') {
|
|
387
|
-
// [packaging]
|
|
414
|
+
// [packaging](装后校验拦截:分发缺产物)与
|
|
388
415
|
// prepare 构建脚本实际执行失败:唯一确有证据的插件打包分发问题 —— 引导到插件仓库提 Issue
|
|
389
416
|
return h('div', null, [
|
|
390
417
|
h('div', { className: styles.failPrepareHint }, /\[packaging\]/i.test(r.message) ? t('failPackagingHint') : t('failPrepareHint')),
|
|
@@ -395,7 +422,7 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
395
422
|
rel: 'noopener noreferrer',
|
|
396
423
|
title: t('failIssueHint'),
|
|
397
424
|
}, t('failIssueBig')) : null,
|
|
398
|
-
// 次要入口:这条分支的判据([packaging]
|
|
425
|
+
// 次要入口:这条分支的判据([packaging] 装后校验、prepare 摘要)是插件中心
|
|
399
426
|
// 自己产出的,不是 pnpm 原文 —— 判错时用户会被送去作者仓库、我们永远收不到反馈
|
|
400
427
|
r.repo && shownRepo ? h('div', null, [
|
|
401
428
|
h('div', { className: styles.failPrepareHint }, t('failMisjudgeHint')),
|
|
@@ -433,11 +460,34 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
433
460
|
h('div', { className: styles.failPrepareHint }, t('failHostCliSpawnHint')),
|
|
434
461
|
])
|
|
435
462
|
}
|
|
436
|
-
|
|
463
|
+
if (kind === 'pnpmIgnoredBuild') {
|
|
464
|
+
// 插件的依赖需要在用户机器上编译原生模块,pnpm 默认拦住;我们已自动放行
|
|
465
|
+
// allowBuilds 并重试过一次,仍失败说明任何用户都装不上 —— 属作者侧(发预构建产物 / 走 release 包)
|
|
466
|
+
return h('div', null, [
|
|
467
|
+
h('div', { className: styles.failPrepareHint }, t('failIgnoredBuild')),
|
|
468
|
+
r.repo && shownRepo ? h('a', {
|
|
469
|
+
className: styles.failBigIssue,
|
|
470
|
+
href: pluginIssueUrl(shownRepo, r.message, env, r.command, r.attempts, action),
|
|
471
|
+
target: '_blank',
|
|
472
|
+
rel: 'noopener noreferrer',
|
|
473
|
+
title: t('failIssueHint'),
|
|
474
|
+
}, t('failIssueBig')) : null,
|
|
475
|
+
// 这条判定里也有我们的动作(自动放行过 allowBuilds),判错时得留一条回到插件中心的路
|
|
476
|
+
r.repo && shownRepo ? h('div', null, [
|
|
477
|
+
h('div', { className: styles.failPrepareHint }, t('failMisjudgeHint')),
|
|
478
|
+
h('a', {
|
|
479
|
+
className: styles.failMisjudgeLink,
|
|
480
|
+
href: hubIssueUrl(shownRepo, r.message, env, r.command, r.attempts, 'misjudge', action),
|
|
481
|
+
target: '_blank',
|
|
482
|
+
rel: 'noopener noreferrer',
|
|
483
|
+
title: t('failHubIssueHint'),
|
|
484
|
+
}, t('failMisjudgeLink')),
|
|
485
|
+
]) : null,
|
|
486
|
+
])
|
|
487
|
+
}
|
|
488
|
+
// 未知失败:不归到插件作者,改为引导到插件中心仓库排查
|
|
437
489
|
return h('div', null, [
|
|
438
|
-
|
|
439
|
-
? h('div', { className: styles.failPrepareHint }, t('failIgnoredBuild'))
|
|
440
|
-
: h('div', { className: styles.failPrepareHint }, t('failUnclassifiedHint', { action: actionWord })),
|
|
490
|
+
h('div', { className: styles.failPrepareHint }, t('failUnclassifiedHint', { action: actionWord })),
|
|
441
491
|
h('a', {
|
|
442
492
|
className: styles.failBigIssue,
|
|
443
493
|
href: hubIssueUrl(shownRepo || r.repo, r.message, env, r.command, r.attempts, 'triage', action),
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* empty for most of the run; failures surface their full output in ErrorModal.
|
|
6
|
+
* 安装与卸载弹窗共用的内联进度块:真实百分比进度条(服务端估算、客户端轮询)。
|
|
7
|
+
* 不做实时终端窗口 —— pnpm 在 git clone/构建期间几乎无输出,日志面板大部分时间是空的;
|
|
8
|
+
* 失败时完整输出在 ErrorModal 里展示。
|
|
10
9
|
*/
|
|
11
10
|
import { createElement as h } from 'react'
|
|
12
11
|
import styles from '../../styles/Modal.module.css'
|
|
@@ -3,11 +3,9 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* the common case (the page refreshes on close so the change applies), or a
|
|
10
|
-
* single "restart now" for the rare changes a refresh cannot pick up.
|
|
6
|
+
* 插件中心的弹窗层:安装确认弹窗、卸载弹窗与全局 Toast。两个弹窗在变更执行期间
|
|
7
|
+
* 自我锁定,随后切到只有一个动作的结果视图 —— 常见情况给「完成」(关闭时刷新页面即生效),
|
|
8
|
+
* 刷新解决不了的少数情况才给单个「立即重启」。
|
|
11
9
|
*/
|
|
12
10
|
import { createElement as h } from 'react'
|
|
13
11
|
import type { MouseEvent } from 'react'
|
|
@@ -343,7 +341,7 @@ export function ErrorModal({ message, repo, action, command, attempts, t, env, o
|
|
|
343
341
|
repo: string | null
|
|
344
342
|
action: FailureAction
|
|
345
343
|
command?: string
|
|
346
|
-
/**
|
|
344
|
+
/** 实际执行/重试过的安装命令:issue 预填一并贴给作者 */
|
|
347
345
|
attempts?: string[]
|
|
348
346
|
t: Translate
|
|
349
347
|
env: EnvInfo | null
|
|
@@ -352,7 +350,7 @@ export function ErrorModal({ message, repo, action, command, attempts, t, env, o
|
|
|
352
350
|
/** 网络不通时的「去系统诊断」直达按钮:跳到设置 → 系统诊断跑连通性检测(由宿主提供) */
|
|
353
351
|
onRunDiagnostics?: () => void
|
|
354
352
|
}) {
|
|
355
|
-
//
|
|
353
|
+
// 失败归类:装不上 = 插件分发/依赖的问题,一律引导提 Issue
|
|
356
354
|
const failureKind = classifyFailure(message)
|
|
357
355
|
// 动作词:标题、徽标与提示里的 {action} 统一取这一个词
|
|
358
356
|
const actionWord = t(action === 'uninstall' ? 'actionUninstall' : action === 'update' ? 'actionUpdate' : 'actionInstall')
|
|
@@ -387,22 +385,32 @@ export function ErrorModal({ message, repo, action, command, attempts, t, env, o
|
|
|
387
385
|
// 与失败记录一致的布局:类型徽标 + 仓库超链接 + 顶部隐蔽复制按钮
|
|
388
386
|
h('div', { className: styles.failRow },
|
|
389
387
|
h('div', { className: styles.failHead },
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
388
|
+
// 跳官网「插件详情」页;文字里直接给出目标地址(去掉协议),点前就知道会去哪
|
|
389
|
+
repo ? (() => {
|
|
390
|
+
const url = pluginSiteUrl(repo)
|
|
391
|
+
return h('a', {
|
|
392
|
+
className: styles.failRepo,
|
|
393
|
+
href: url,
|
|
394
|
+
target: '_blank',
|
|
395
|
+
rel: 'noopener noreferrer',
|
|
396
|
+
title: url,
|
|
397
|
+
},
|
|
398
|
+
h('span', { className: styles.failRepoLabel }, `${t('detailTitle')} · `),
|
|
399
|
+
h('span', { className: styles.failRepoUrl }, url.replace(/^https?:\/\//, '').split('?')[0]),
|
|
400
|
+
)
|
|
401
|
+
})() : null,
|
|
401
402
|
// 复制按钮放最上面、浅灰隐蔽;报错正文不允许鼠标选择复制,只能点这里
|
|
402
403
|
h('button', { className: styles.errorCopySoft, onClick: () => onCopy(copyText) }, t('errorCopy')),
|
|
403
404
|
),
|
|
404
405
|
// 报错信息完整展示(可滚动),比失败记录的预览看得更多
|
|
405
406
|
h('pre', { className: styles.errorBox }, message),
|
|
407
|
+
// 统一失败卡片头部:报错类型 + 一句话原因(各类型的具体指引仍在下面的分支里)
|
|
408
|
+
h('div', { className: styles.failKindTitle }, t(`failKind_${failureKind}`, failureKind === 'hostIncompatible'
|
|
409
|
+
? { version: /incompatible with dsh\s+([^\s:;,]+)/i.exec(message)?.[1] ?? '' }
|
|
410
|
+
: undefined)),
|
|
411
|
+
failureKind === 'hostIncompatible'
|
|
412
|
+
? null
|
|
413
|
+
: h('div', { className: styles.failReason }, t(`failReason_${failureKind}`)),
|
|
406
414
|
// npm 内部崩溃(edgesOut)+ 本机 npm 版本过低:npm 自身已知缺陷,不是插件问题 ——
|
|
407
415
|
// 直接给升级指引,不引导提 Issue(提了也是 npm 的问题,插件作者无法修复)
|
|
408
416
|
failureKind === 'npmTooOld'
|
|
@@ -467,9 +475,28 @@ export function ErrorModal({ message, repo, action, command, attempts, t, env, o
|
|
|
467
475
|
title: t('failIssueHint'),
|
|
468
476
|
}, t('failIssueBig')) : null,
|
|
469
477
|
])
|
|
478
|
+
: failureKind === 'hostIncompatible'
|
|
479
|
+
// 宿主版本门禁:插件声明的兼容范围不含当前 dsh 版本,安装前就被宿主拒绝。
|
|
480
|
+
// 这是作者能修的(把该版本加进兼容清单),故直接引导到作者仓库;同时说明本地可临时授权
|
|
481
|
+
? h('div', null, [
|
|
482
|
+
(() => {
|
|
483
|
+
const version = /incompatible with dsh\s+([^\s:;,]+)/i.exec(message)?.[1] ?? ''
|
|
484
|
+
return h('div', null, [
|
|
485
|
+
h('div', { className: styles.failReason }, t('failHostIncompatibleReason', { version })),
|
|
486
|
+
h('div', { className: styles.failPrepareHint }, t('failHostIncompatibleHint')),
|
|
487
|
+
])
|
|
488
|
+
})(),
|
|
489
|
+
repo ? h('a', {
|
|
490
|
+
className: styles.failBigIssue,
|
|
491
|
+
href: pluginIssueUrl(repo, message, env, command, attempts, action),
|
|
492
|
+
target: '_blank',
|
|
493
|
+
rel: 'noopener noreferrer',
|
|
494
|
+
title: t('failIssueHint'),
|
|
495
|
+
}, t('failIssueBig')) : null,
|
|
496
|
+
])
|
|
470
497
|
: failureKind === 'registryVersionStale'
|
|
471
498
|
// 要装的版本在「实际执行安装的那个源」里查不到(ERR_PNPM_NO_MATCHING_VERSION / ETARGET):
|
|
472
|
-
// 常见于镜像滞后 ——
|
|
499
|
+
// 常见于镜像滞后 —— 实际安装沿用本机 ~/.npmrc 的源,
|
|
473
500
|
// 官方源刚发布而镜像还没同步;也可能只是版本号写错。与插件作者无关 ——
|
|
474
501
|
// 给「对齐源 / 那一次显式走官方源 / 用离线包」的指引,不引导提 Issue
|
|
475
502
|
? h('div', { className: styles.failPrepareHint }, t('failRegistryVersionStaleHint'))
|
|
@@ -492,7 +519,7 @@ export function ErrorModal({ message, repo, action, command, attempts, t, env, o
|
|
|
492
519
|
// 安装流程,与插件无关 —— 引导从本机地址重新打开市场,不引导提 Issue
|
|
493
520
|
? h('div', { className: styles.failPrepareHint }, t('failOriginRejectedHint', { profile: env?.profile ?? '<profile>' }))
|
|
494
521
|
: failureKind === 'network'
|
|
495
|
-
//
|
|
522
|
+
// 安装前网络探测 / 安装日志里的连接失败([network] / git fetch 超时 / DNS / TLS):
|
|
496
523
|
// 是本机网络不通或代理有问题,不是插件问题 —— 提示检查网络 + 直达「系统诊断」,
|
|
497
524
|
// 不引导提 Issue
|
|
498
525
|
? h('div', null, [
|
|
@@ -509,7 +536,7 @@ export function ErrorModal({ message, repo, action, command, attempts, t, env, o
|
|
|
509
536
|
])
|
|
510
537
|
: failureKind === 'pluginPrepare'
|
|
511
538
|
? h('div', null, [
|
|
512
|
-
// [packaging]
|
|
539
|
+
// [packaging](装后校验拦截:分发缺产物)与
|
|
513
540
|
// prepare 构建脚本实际执行失败:唯一确有证据的插件打包分发问题 —— 引导到插件仓库提 Issue
|
|
514
541
|
h('div', { className: styles.failPrepareHint }, /\[packaging\]/i.test(message) ? t('failPackagingHint') : t('failPrepareHint')),
|
|
515
542
|
repo ? h('a', {
|
|
@@ -519,7 +546,7 @@ export function ErrorModal({ message, repo, action, command, attempts, t, env, o
|
|
|
519
546
|
rel: 'noopener noreferrer',
|
|
520
547
|
title: t('failIssueHint'),
|
|
521
548
|
}, t('failIssueBig')) : null,
|
|
522
|
-
// 次要入口:这条分支的判据([packaging]
|
|
549
|
+
// 次要入口:这条分支的判据([packaging] 装后校验、prepare 摘要)是插件中心
|
|
523
550
|
// 自己产出的,不是 pnpm 原文 —— 判错时用户会被送去作者仓库、我们永远收不到反馈,
|
|
524
551
|
// 故另给一条「可能是市场误判」的反馈通道(正文自我说明它来自哪条分支)
|
|
525
552
|
repo ? h('div', null, [
|
|
@@ -553,11 +580,33 @@ export function ErrorModal({ message, repo, action, command, attempts, t, env, o
|
|
|
553
580
|
// 宿主自身入口起不来:环境问题,给提示、不引导提 Issue
|
|
554
581
|
h('div', { className: styles.failPrepareHint }, t('failHostCliSpawnHint')),
|
|
555
582
|
])
|
|
583
|
+
: failureKind === 'pnpmIgnoredBuild'
|
|
584
|
+
// 该类型的插件依赖需要在用户机器上编译原生模块,pnpm 默认拦住;我们已自动放行
|
|
585
|
+
// allowBuilds 并重试过一次,仍失败说明任何用户都装不上 —— 属作者侧(发预构建产物 / 走 release 包)。
|
|
586
|
+
? h('div', null, [
|
|
587
|
+
h('div', { className: styles.failPrepareHint }, t('failIgnoredBuild')),
|
|
588
|
+
repo ? h('a', {
|
|
589
|
+
className: styles.failBigIssue,
|
|
590
|
+
href: pluginIssueUrl(repo, message, env, command, attempts, action),
|
|
591
|
+
target: '_blank',
|
|
592
|
+
rel: 'noopener noreferrer',
|
|
593
|
+
title: t('failIssueHint'),
|
|
594
|
+
}, t('failIssueBig')) : null,
|
|
595
|
+
// 这条判定里也有我们的动作(我们自动放行过 allowBuilds),判错时得留一条回到插件中心的路
|
|
596
|
+
repo ? h('div', null, [
|
|
597
|
+
h('div', { className: styles.failPrepareHint }, t('failMisjudgeHint')),
|
|
598
|
+
h('a', {
|
|
599
|
+
className: styles.failMisjudgeLink,
|
|
600
|
+
href: hubIssueUrl(repo, message, env, command, attempts, 'misjudge', action),
|
|
601
|
+
target: '_blank',
|
|
602
|
+
rel: 'noopener noreferrer',
|
|
603
|
+
title: t('failHubIssueHint'),
|
|
604
|
+
}, t('failMisjudgeLink')),
|
|
605
|
+
]) : null,
|
|
606
|
+
])
|
|
556
607
|
: h('div', null, [
|
|
557
|
-
//
|
|
558
|
-
|
|
559
|
-
? h('div', { className: styles.failPrepareHint }, t('failIgnoredBuild'))
|
|
560
|
-
: h('div', { className: styles.failPrepareHint }, t('failUnclassifiedHint', { action: actionWord })),
|
|
608
|
+
// 未分类(hub):不归到插件作者,改为引导到插件中心仓库分诊
|
|
609
|
+
h('div', { className: styles.failPrepareHint }, t('failUnclassifiedHint', { action: actionWord })),
|
|
561
610
|
h('a', {
|
|
562
611
|
className: styles.failBigIssue,
|
|
563
612
|
href: hubIssueUrl(repo, message, env, command, attempts, 'triage', action),
|
|
@@ -3,13 +3,11 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* 按钮式下拉框(替代原生 <select>)。
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* outside or pressing Esc closes the panel; options get a hover fill and
|
|
12
|
-
* the active one a brand highlight, all driven by the --hub-* tokens.
|
|
8
|
+
* 触发器是紧凑的工具栏按钮 —— 细边框 + 淡灰填充 + 当前值 + 箭头 —— 与其它工具栏按钮
|
|
9
|
+
* 并排自然,只占一格横向空间。点击外部或按 Esc 关闭面板;选项有 hover 填充、
|
|
10
|
+
* 激活项为品牌高亮,全部由 --hub-* 变量驱动。
|
|
13
11
|
*/
|
|
14
12
|
import { createElement as h, useEffect, useRef, useState } from 'react'
|
|
15
13
|
import type { JSX } from 'react'
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* by the --hub-* tokens (on = brand fill, off = neutral track).
|
|
6
|
+
* 设置行用的紧凑开关。基于原生 button,可键盘聚焦并通过 aria-checked 播报状态;
|
|
7
|
+
* 样式由 --hub-* 变量驱动(开 = 品牌填充,关 = 中性轨道)。
|
|
9
8
|
*/
|
|
10
9
|
import { createElement as h } from 'react'
|
|
11
10
|
import styles from '../../styles/Toggle.module.css'
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
* Website: https://dsh-plugin.org
|
|
4
4
|
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* they adapt to themes and disabled states automatically.
|
|
6
|
+
* 客户端各处使用的内联 SVG 图标。图标继承 currentColor,自动适配主题与禁用态。
|
|
8
7
|
*/
|
|
9
8
|
import { createElement as h } from 'react'
|
|
10
9
|
import headerStyles from '../../styles/Header.module.css'
|