dsh-plugin 1.3.5 → 1.3.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/README.en.md +30 -1
- package/README.md +30 -1
- package/client/client.js +409 -393
- package/client/client.js.map +1 -1
- package/lib/http/routes.js +6 -4
- package/lib/services/install/npm-resolve.js +3 -1
- package/lib/services/settings.js +1 -1
- package/lib/types/services/install/npm-resolve.d.ts +3 -1
- package/lib/types/services/settings.d.ts +2 -2
- package/package.json +1 -1
- package/src/client/components/PluginHubSection.tsx +11 -7
- package/src/client/components/modals/NotificationsModal.tsx +9 -3
- package/src/client/components/views/DiagnosticsView.tsx +7 -3
- package/src/client/components/views/SettingsView.tsx +20 -33
- package/src/client/hooks/useSettings.ts +3 -3
- package/src/client/hooks/useTaskQueue.ts +12 -6
- package/src/client/locales.ts +23 -9
- package/src/client/logic/failures.ts +3 -0
- package/src/client/logic/urls.ts +12 -1
- package/src/client/styles/Dropdown.module.css +10 -0
- package/src/client/styles/Modal.module.css +11 -0
- package/src/server/http/routes.ts +6 -3
- package/src/server/services/install/npm-resolve.ts +3 -1
- package/src/server/services/settings.ts +3 -3
package/lib/http/routes.js
CHANGED
|
@@ -157,13 +157,12 @@ function hostEnv(profile) {
|
|
|
157
157
|
dshHome: process.env.DSH_HOME ?? join(homedir(), '.dsh'),
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
|
-
/** 安装/卸载 CLI 的子进程环境:透传宿主环境,并按设置注入
|
|
160
|
+
/** 安装/卸载 CLI 的子进程环境:透传宿主环境,并按设置注入 HTTP(S) 代理。
|
|
161
|
+
* npm registry 不再注入 —— 安装完全沿用用户本机 npm 配置(~/.npmrc / 全局配置)。
|
|
161
162
|
* 代理优先级:设置里的代理 → 系统代理(macOS scutil / Windows 注册表)→ 宿主 env 原有值。
|
|
162
163
|
* 使安装通道与诊断使用相同的代理来源。 */
|
|
163
164
|
function mutationEnv(settings) {
|
|
164
165
|
const env = { ...process.env, CI: 'true' };
|
|
165
|
-
if (settings.npmRegistry !== '')
|
|
166
|
-
env.npm_config_registry = settings.npmRegistry;
|
|
167
166
|
const proxy = settings.proxy !== '' ? settings.proxy : (systemProxy() ?? '');
|
|
168
167
|
if (proxy !== '') {
|
|
169
168
|
env.HTTP_PROXY = proxy;
|
|
@@ -485,11 +484,14 @@ export function mountPluginHubRoutes(webServer, profile, loader) {
|
|
|
485
484
|
// 空 body / 非 JSON:视为全量探测
|
|
486
485
|
}
|
|
487
486
|
const settings = loadSettings(profile);
|
|
487
|
+
// npm 通道:设置里配置了镜像源就探测该镜像(安装通道吃同一个 registry);
|
|
488
|
+
// 未配置(空串)时探测官方源作为「跟随本机 npm 配置」的基础连通性参考。
|
|
488
489
|
const registry = settings.npmRegistry.replace(/\/+$/, '') || 'https://registry.npmjs.org';
|
|
489
490
|
// 连通性自检直接打安装通道真实访问的轻量资源:npm 源拉包元数据、git 通道探
|
|
490
491
|
// 仓库主页、目录站探 badge 小文件,避免拉取目录全量 JSON。
|
|
492
|
+
// npm 行 display:配置了镜像就显示镜像地址;未配置置空 —— 客户端显示「未配置(跟随本机 npm 配置)」。
|
|
491
493
|
const allChecks = [
|
|
492
|
-
{ key: 'npm', url: `${registry}/dsh-plugin`, display: settings.npmRegistry !== '' ?
|
|
494
|
+
{ key: 'npm', url: `${registry}/dsh-plugin`, display: settings.npmRegistry !== '' ? registry : '', cmd: `npm view dsh-plugin version --registry ${registry}` },
|
|
493
495
|
{ key: 'github', url: 'https://github.com/dshplugin/dsh-plugin-hub', display: 'github.com', cmd: 'git ls-remote https://github.com/dshplugin/dsh-plugin-hub' },
|
|
494
496
|
{ key: 'catalog', url: 'https://api.dsh-plugin.org/stats.json', display: 'api.dsh-plugin.org', cmd: 'curl -s https://api.dsh-plugin.org/stats.json' },
|
|
495
497
|
];
|
|
@@ -20,7 +20,9 @@ const REQUEST_TIMEOUT_MS = 8000;
|
|
|
20
20
|
* 反查 repo(`owner/repo`)对应的官方 npm 包名;未命中、网络异常或超时返回 null。
|
|
21
21
|
* 返回 null 不代表仓库一定没有 npm 包,只代表本次未能确认 —— 调用方应保留
|
|
22
22
|
* 原有错误路径,反查只是额外的一次尝试。
|
|
23
|
-
*
|
|
23
|
+
* registry 参数:npm 镜像源地址,空串 = 官方源;与安装通道吃同一 registry,
|
|
24
|
+
* 保证「配置了镜像」时反查和安装走同一个源(镜像节点同步完整时结果一致)。
|
|
25
|
+
* 慢网络下失败不阻塞安装。
|
|
24
26
|
*/
|
|
25
27
|
export function resolveNpmPackage(repo, registry = '') {
|
|
26
28
|
const key = repo.toLowerCase();
|
package/lib/services/settings.js
CHANGED
|
@@ -12,8 +12,8 @@ import { dirname, join } from 'node:path';
|
|
|
12
12
|
import { profileDirectory } from './profile/profile.js';
|
|
13
13
|
export const DEFAULT_SETTINGS = {
|
|
14
14
|
checkUpdatesOnStart: true,
|
|
15
|
-
npmRegistry: '',
|
|
16
15
|
proxy: '',
|
|
16
|
+
npmRegistry: '',
|
|
17
17
|
enableNpmInstall: true,
|
|
18
18
|
enableGitInstall: true,
|
|
19
19
|
enableDshInstall: true,
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* 反查 repo(`owner/repo`)对应的官方 npm 包名;未命中、网络异常或超时返回 null。
|
|
3
3
|
* 返回 null 不代表仓库一定没有 npm 包,只代表本次未能确认 —— 调用方应保留
|
|
4
4
|
* 原有错误路径,反查只是额外的一次尝试。
|
|
5
|
-
*
|
|
5
|
+
* registry 参数:npm 镜像源地址,空串 = 官方源;与安装通道吃同一 registry,
|
|
6
|
+
* 保证「配置了镜像」时反查和安装走同一个源(镜像节点同步完整时结果一致)。
|
|
7
|
+
* 慢网络下失败不阻塞安装。
|
|
6
8
|
*/
|
|
7
9
|
export declare function resolveNpmPackage(repo: string, registry?: string): Promise<string | null>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export interface HubSettings {
|
|
2
2
|
/** 启动时检查目录插件更新,发现可更新时在通知中心提示(安装不自动进行) */
|
|
3
3
|
checkUpdatesOnStart: boolean;
|
|
4
|
-
/** npm 镜像源 registry 地址(空串 = 官方 https://registry.npmjs.org) */
|
|
5
|
-
npmRegistry: string;
|
|
6
4
|
/** HTTP(S) 代理地址,用于 npm / git / 目录请求(空串 = 直连) */
|
|
7
5
|
proxy: string;
|
|
6
|
+
/** npm 镜像源 registry 地址(空串 = 未配置,跟随用户本机 npm 配置,本插件不注入任何 registry) */
|
|
7
|
+
npmRegistry: string;
|
|
8
8
|
/** 启用命令行安装 NPM 包(默认开;关掉后输入 npm 包名安装被拦截) */
|
|
9
9
|
enableNpmInstall: boolean;
|
|
10
10
|
/** 启用命令行安装 GitHub 源码(默认开;关掉后输入 GitHub 地址安装被拦截) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
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",
|
|
@@ -107,12 +107,13 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
107
107
|
const queue = useTaskQueue({
|
|
108
108
|
t,
|
|
109
109
|
refreshInstalled: catalog.refreshInstalled,
|
|
110
|
-
onInstallDone: (viaModal, repo, needsRestart) => {
|
|
110
|
+
onInstallDone: (viaModal, repo, needsRestart, update) => {
|
|
111
111
|
setInstallNeedsRestart(needsRestart)
|
|
112
112
|
if (viaModal) setInstallDone(true)
|
|
113
113
|
else setToast({ id: Date.now(), kind: 'done' })
|
|
114
|
-
//
|
|
115
|
-
|
|
114
|
+
// 安装成功也写入通知记录:通知中心里成功与失败都能看到。
|
|
115
|
+
// action 区分「安装成功」与「更新成功」(更新 = 覆盖重装,同一执行通道)
|
|
116
|
+
setNotifications(addSuccess({ kind: 'install', action: update ? 'update' : 'install', repo: repo ?? '' }))
|
|
116
117
|
},
|
|
117
118
|
onUninstallDone: (viaModal, repo, needsRestart) => {
|
|
118
119
|
setUninstallNeedsRestart(needsRestart)
|
|
@@ -120,13 +121,16 @@ export function PluginHubSection({ t: _hostT, locale }: SectionProps) {
|
|
|
120
121
|
else setToast({ id: Date.now(), kind: 'removed' })
|
|
121
122
|
setNotifications(addSuccess({ kind: 'uninstall', repo: repo ?? '' }))
|
|
122
123
|
},
|
|
123
|
-
onError: (message, repo, kind, command, attempts) => {
|
|
124
|
+
onError: (message, repo, kind, command, attempts, update) => {
|
|
124
125
|
// 提 Issue 目标先反查仓库身份:npm 包名能在已安装表/目录里反查到 owner/repo 才保留,
|
|
125
|
-
// 反查不到置 null ——
|
|
126
|
+
// 反查不到置 null —— 错误弹窗据此不显示「一键提 Issue」按钮(防提到错误仓库)
|
|
126
127
|
const issueRepo = issueRepoOf(repo ?? '', catalog.installedItems, catalog.plugins)
|
|
127
128
|
setErrorMsg({ message, repo: issueRepo, kind, command, attempts })
|
|
128
|
-
//
|
|
129
|
-
|
|
129
|
+
// 失败自动写入通知记录:任务在后台结束时没人盯着也能留痕。
|
|
130
|
+
// 存原始 repo(可能只是裸包名)而非反查结果 —— 反查只服务于提 Issue,
|
|
131
|
+
// 通知中心的展示反查由 NotificationsModal 做、查不到会回退显示原始值,
|
|
132
|
+
// 若这里就丢掉原始值,通知里会连名字都看不到;action 区分「安装失败/更新失败」
|
|
133
|
+
setNotifications(addFailure({ kind, action: update ? 'update' : 'install', repo: repo ?? '', message, command, attempts }))
|
|
130
134
|
},
|
|
131
135
|
installPlugin: confirmPlugin,
|
|
132
136
|
installCustomTarget: confirmCustomTarget,
|
|
@@ -193,8 +193,12 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
193
193
|
h('span', {
|
|
194
194
|
className: r.ok ? styles.noticeTextOk : styles.noticeTextFail,
|
|
195
195
|
}, r.ok
|
|
196
|
-
? (isUpdate
|
|
197
|
-
|
|
196
|
+
? (isUpdate
|
|
197
|
+
? t('updateNoticeTitle')
|
|
198
|
+
: (r.action === 'update' ? t('updateDone') : (r.kind === 'install' ? t('installDone') : t('uninstallDone'))))
|
|
199
|
+
: (r.action === 'update'
|
|
200
|
+
? t('errorTitleUpdate')
|
|
201
|
+
: (r.kind === 'install' ? t('errorTitleInstall') : t('errorTitleUninstall')))),
|
|
198
202
|
// 更新提醒:新版本号紧随标题展示;repo 为纯文本(整行点击即去更新,不跳官网外链)
|
|
199
203
|
isUpdate && r.version
|
|
200
204
|
? h('span', { className: styles.noticeVersion, title: r.version }, `v${r.version}`)
|
|
@@ -211,7 +215,9 @@ export function NotificationsModal({ records, tasks, pendingRestarts, t, env, on
|
|
|
211
215
|
rel: 'noopener noreferrer',
|
|
212
216
|
title: shownRepo,
|
|
213
217
|
}, shownRepo)
|
|
214
|
-
|
|
218
|
+
// 反查不到仓库身份(如命令行安装的裸 npm 包名):回退显示记录里的原始值,
|
|
219
|
+
// 保证通知永不只剩一句「安装/更新成功」没有名字 —— 只是不给官网外链(查不到不敢乱跳)
|
|
220
|
+
: h('span', { className: styles.failRepo, title: r.repo }, r.repo))
|
|
215
221
|
: null,
|
|
216
222
|
!r.ok && h('button', {
|
|
217
223
|
className: styles.failCopy,
|
|
@@ -40,7 +40,8 @@ interface RowState {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const INITIAL_ROWS: RowState[] = [
|
|
43
|
-
|
|
43
|
+
// npm 行 display 初始置空:设置里未配置镜像时显示「未配置(跟随本机)」,探测结果回来再用服务端 display 覆盖
|
|
44
|
+
{ key: 'npm', display: '', nameKey: 'diagNpm', status: 'idle', ms: null, statusCode: null },
|
|
44
45
|
{ key: 'github', display: 'github.com', nameKey: 'diagGithub', status: 'idle', ms: null, statusCode: null },
|
|
45
46
|
{ key: 'catalog', display: 'api.dsh-plugin.org', nameKey: 'diagCatalog', status: 'idle', ms: null, statusCode: null },
|
|
46
47
|
]
|
|
@@ -87,12 +88,14 @@ export function DiagnosticsView({ t, env, onCopy }: {
|
|
|
87
88
|
const raw = buf.slice(0, nl).trim()
|
|
88
89
|
buf = buf.slice(nl + 1)
|
|
89
90
|
if (raw !== '') {
|
|
90
|
-
const ev = JSON.parse(raw) as { type?: string; key?: string; ms?: number | null; status?: number | null }
|
|
91
|
+
const ev = JSON.parse(raw) as { type?: string; key?: string; ms?: number | null; status?: number | null; display?: string }
|
|
91
92
|
if (ev.type === 'ok' || ev.type === 'fail') {
|
|
92
93
|
patchRows(ev.key as ProbeKey, {
|
|
93
94
|
status: ev.type === 'ok' ? 'ok' : 'fail',
|
|
94
95
|
ms: typeof ev.ms === 'number' ? ev.ms : null,
|
|
95
96
|
statusCode: typeof ev.status === 'number' ? ev.status : null,
|
|
97
|
+
// 服务端带出实际使用的源地址(配置镜像 → 镜像地址;未配置 → 空串)
|
|
98
|
+
display: typeof ev.display === 'string' ? ev.display : '',
|
|
96
99
|
})
|
|
97
100
|
}
|
|
98
101
|
}
|
|
@@ -159,7 +162,8 @@ export function DiagnosticsView({ t, env, onCopy }: {
|
|
|
159
162
|
title: t('diagRecheck'),
|
|
160
163
|
},
|
|
161
164
|
h('span', { className: styles.name }, t(r.nameKey)),
|
|
162
|
-
|
|
165
|
+
// npm 行未配置镜像:display 为空 → 显示「未配置(跟随本机)」,不误导成官方源
|
|
166
|
+
h('span', { className: styles.display }, r.display !== '' ? r.display : t('diagNpmUnset')),
|
|
163
167
|
h('span', { className: styles.meta }, r.status === 'ok' && r.ms !== null ? `${r.ms} ms` : ''),
|
|
164
168
|
badge,
|
|
165
169
|
)
|
|
@@ -18,9 +18,10 @@
|
|
|
18
18
|
import { createElement as h, useState } from 'react'
|
|
19
19
|
import type { ChangeEvent, MouseEvent, ReactNode } from 'react'
|
|
20
20
|
import styles from '../../styles/SettingsView.module.css'
|
|
21
|
+
import dropdownStyles from '../../styles/Dropdown.module.css'
|
|
21
22
|
import modalStyles from '../../styles/Modal.module.css'
|
|
22
|
-
import { Dropdown } from '../ui/Dropdown.tsx'
|
|
23
23
|
import { Toggle } from '../ui/Toggle.tsx'
|
|
24
|
+
import { Dropdown } from '../ui/Dropdown.tsx'
|
|
24
25
|
import { DiagnosticsView } from './DiagnosticsView.tsx'
|
|
25
26
|
import { LogsView } from './LogsView.tsx'
|
|
26
27
|
import {
|
|
@@ -31,6 +32,16 @@ import type { HubSettings } from '../../hooks/useSettings.ts'
|
|
|
31
32
|
|
|
32
33
|
type SettingsSection = 'updates' | 'security' | 'diagnostics' | 'logs' | 'reset'
|
|
33
34
|
|
|
35
|
+
/** npm 镜像源预设:空串 = 未配置(跟随用户本机 npm 配置,本插件不注入任何 registry)。
|
|
36
|
+
* 只提供常见国内顶级镜像下拉,不做自定义输入 —— 想用其它镜像直接在 ~/.npmrc 配置即可。 */
|
|
37
|
+
const MIRROR_PRESETS: Array<{ value: string; labelKey: string }> = [
|
|
38
|
+
{ value: '', labelKey: 'mirrorNone' },
|
|
39
|
+
{ value: 'https://registry.npmjs.org', labelKey: 'mirrorOfficial' },
|
|
40
|
+
{ value: 'https://registry.npmmirror.com', labelKey: 'mirrorNpmmirror' },
|
|
41
|
+
{ value: 'https://mirrors.cloud.tencent.com/npm/', labelKey: 'mirrorTencent' },
|
|
42
|
+
{ value: 'https://mirrors.tuna.tsinghua.edu.cn/npm/', labelKey: 'mirrorTsinghua' },
|
|
43
|
+
]
|
|
44
|
+
|
|
34
45
|
/** 左侧导航:顺序即展示顺序;labelKey 是分组标题,icon 是行内小图标。 */
|
|
35
46
|
const NAV: Array<{ key: SettingsSection; labelKey: string; icon: () => ReturnType<typeof h> }> = [
|
|
36
47
|
{ key: 'updates', labelKey: 'settingsUpdate', icon: UpdatesIcon },
|
|
@@ -40,13 +51,6 @@ const NAV: Array<{ key: SettingsSection; labelKey: string; icon: () => ReturnTyp
|
|
|
40
51
|
{ key: 'reset', labelKey: 'settingsReset', icon: ResetIcon },
|
|
41
52
|
]
|
|
42
53
|
|
|
43
|
-
/** npm 镜像源预设:空串 = 官方源;值相等即视为选中对应预设,其余进入「自定义」输入。 */
|
|
44
|
-
const MIRROR_PRESETS: Array<{ value: string; labelKey: string }> = [
|
|
45
|
-
{ value: '', labelKey: 'mirrorOfficial' },
|
|
46
|
-
{ value: 'https://registry.npmmirror.com', labelKey: 'mirrorNpmmirror' },
|
|
47
|
-
{ value: 'https://mirrors.cloud.tencent.com/npm/', labelKey: 'mirrorTencent' },
|
|
48
|
-
]
|
|
49
|
-
|
|
50
54
|
/** 设置行:默认标签左控件右;stack=true 时控件独占一行(文本框整行显示),hairline 分隔。 */
|
|
51
55
|
function SettingRow({ title, desc, children, stack = false }: {
|
|
52
56
|
title: string
|
|
@@ -76,13 +80,8 @@ export function SettingsView({ t, settings, update, reset, env, onCopy }: {
|
|
|
76
80
|
/** 恢复默认确认弹窗:点按钮先弹窗询问,确认后才真正 reset(不做两段式按钮) */
|
|
77
81
|
const [resetConfirm, setResetConfirm] = useState(false)
|
|
78
82
|
|
|
79
|
-
const mirrorCustom = !MIRROR_PRESETS.some((p) => p.value === settings.npmRegistry)
|
|
80
|
-
const onMirrorChange = (value: string) => {
|
|
81
|
-
if (value === 'custom') return // 进入自定义输入:保持当前值,下方出现输入框
|
|
82
|
-
update({ npmRegistry: value })
|
|
83
|
-
}
|
|
84
|
-
const onMirrorInput = (e: ChangeEvent<HTMLInputElement>) => update({ npmRegistry: e.target.value })
|
|
85
83
|
const onProxyChange = (e: ChangeEvent<HTMLInputElement>) => update({ proxy: e.target.value })
|
|
84
|
+
const onMirrorChange = (value: string) => update({ npmRegistry: value })
|
|
86
85
|
|
|
87
86
|
/** 每个分组的页面副标题(导航标题之上再补一句说明,保持桌面设置质感) */
|
|
88
87
|
const pageDesc: Record<SettingsSection, string> = {
|
|
@@ -106,31 +105,19 @@ export function SettingsView({ t, settings, update, reset, env, onCopy }: {
|
|
|
106
105
|
title: t('settingsCheckOnStart'),
|
|
107
106
|
}),
|
|
108
107
|
}),
|
|
108
|
+
// npm 镜像源:预设下拉(默认未配置跟随本机),选国内顶级镜像可加速安装;
|
|
109
|
+
// 不做自定义输入,其它镜像写在 ~/.npmrc 即可被天然尊重。
|
|
110
|
+
// 独占一行(同代理文本框):标签在上、下拉在下整行展开,长描述不会挤压控件
|
|
109
111
|
h(SettingRow, {
|
|
110
112
|
title: t('settingsMirror'),
|
|
111
113
|
desc: t('settingsMirrorDesc'),
|
|
114
|
+
stack: true,
|
|
112
115
|
children: h(Dropdown, {
|
|
113
|
-
value:
|
|
114
|
-
options:
|
|
115
|
-
...MIRROR_PRESETS.map((p) => ({ value: p.value, label: t(p.labelKey) })),
|
|
116
|
-
{ value: 'custom', label: t('mirrorCustom') },
|
|
117
|
-
],
|
|
116
|
+
value: settings.npmRegistry,
|
|
117
|
+
options: MIRROR_PRESETS.map((m) => ({ value: m.value, label: t(m.labelKey) })),
|
|
118
118
|
onChange: onMirrorChange,
|
|
119
119
|
title: t('settingsMirror'),
|
|
120
|
-
className: styles.controlDropdown
|
|
121
|
-
}),
|
|
122
|
-
}),
|
|
123
|
-
// 自定义镜像源:下拉选中「自定义」或已存非预设值时,追加一行输入框(文本框独占一行)
|
|
124
|
-
mirrorCustom && h(SettingRow, {
|
|
125
|
-
title: t('mirrorCustom'),
|
|
126
|
-
stack: true,
|
|
127
|
-
children: h('input', {
|
|
128
|
-
className: styles.textInput,
|
|
129
|
-
type: 'url',
|
|
130
|
-
value: settings.npmRegistry,
|
|
131
|
-
placeholder: 'https://registry.npmjs.org',
|
|
132
|
-
spellCheck: false,
|
|
133
|
-
onChange: onMirrorInput,
|
|
120
|
+
className: `${styles.controlDropdown} ${dropdownStyles.dropdownFill}`,
|
|
134
121
|
}),
|
|
135
122
|
}),
|
|
136
123
|
// 代理地址:文本框独占一行,整行输入,便于粘贴长代理地址
|
|
@@ -14,10 +14,10 @@ import { useCallback, useEffect, useState } from 'react'
|
|
|
14
14
|
export interface HubSettings {
|
|
15
15
|
/** 启动时检查目录插件更新,发现可更新时在通知中心提示(安装不自动进行) */
|
|
16
16
|
checkUpdatesOnStart: boolean
|
|
17
|
-
/** npm 镜像源 registry 地址(空串 = 官方 https://registry.npmjs.org) */
|
|
18
|
-
npmRegistry: string
|
|
19
17
|
/** HTTP(S) 代理地址,用于 npm / git / 目录请求(空串 = 直连) */
|
|
20
18
|
proxy: string
|
|
19
|
+
/** npm 镜像源 registry 地址(空串 = 未配置,跟随用户本机 npm 配置,不注入任何 registry) */
|
|
20
|
+
npmRegistry: string
|
|
21
21
|
/** 启用命令行安装 NPM 包(默认开) */
|
|
22
22
|
enableNpmInstall: boolean
|
|
23
23
|
/** 启用命令行安装 GitHub 源码(默认开) */
|
|
@@ -30,8 +30,8 @@ export interface HubSettings {
|
|
|
30
30
|
|
|
31
31
|
export const DEFAULT_SETTINGS: HubSettings = {
|
|
32
32
|
checkUpdatesOnStart: true,
|
|
33
|
-
npmRegistry: '',
|
|
34
33
|
proxy: '',
|
|
34
|
+
npmRegistry: '',
|
|
35
35
|
enableNpmInstall: true,
|
|
36
36
|
enableGitInstall: true,
|
|
37
37
|
enableDshInstall: true,
|
|
@@ -28,6 +28,9 @@ export interface QueueTask {
|
|
|
28
28
|
desc?: string
|
|
29
29
|
/** 所属插件仓库(owner/repo):失败时错误弹窗据此提供「去仓库反馈」入口;卸载为 null */
|
|
30
30
|
repo: string | null
|
|
31
|
+
/** 实际动作(add/update/remove):成功通知据此区分「安装成功」与「更新成功」。
|
|
32
|
+
* 服务端 /active 带回真实动作;本地乐观入队按 update 标记推断。 */
|
|
33
|
+
action?: 'add' | 'update' | 'remove'
|
|
31
34
|
/** 安装时的目录信号快照(版本 + 仓库更新时间):任务成功后在本地记录,供「有更新」比对 */
|
|
32
35
|
version?: string
|
|
33
36
|
updatedAt?: string
|
|
@@ -63,11 +66,12 @@ export interface TaskQueueOptions {
|
|
|
63
66
|
t: Translate
|
|
64
67
|
refreshInstalled: () => void
|
|
65
68
|
/** 任务成功完成:viaModal 表示任务对应当前打开弹窗(弹窗切结果视图),否则走 Toast;repo 供成功通知记录;
|
|
66
|
-
* needsRestart 表示该任务完成后是否仍需宿主重启(结果视图据此给「重启 / 仅完成」)。
|
|
67
|
-
|
|
69
|
+
* needsRestart 表示该任务完成后是否仍需宿主重启(结果视图据此给「重启 / 仅完成」)。
|
|
70
|
+
* update 表示实际执行的是更新(覆盖重装)而非首次安装:通知中心据此显示「更新成功」而非「安装成功」。 */
|
|
71
|
+
onInstallDone: (viaModal: boolean, repo: string | null, needsRestart: boolean, update?: boolean) => void
|
|
68
72
|
onUninstallDone: (viaModal: boolean, repo: string | null, needsRestart: boolean) => void
|
|
69
|
-
/** 任务失败:完整输出或兜底文案 + 所属插件仓库 + 操作类型(安装/卸载)+ 实际执行的安装命令(issue 预填用,可缺省)+ 尝试过的安装方式(npm
|
|
70
|
-
onError: (message: string, repo: string | null, kind: 'install' | 'uninstall', command?: string, attempts?: string[]) => void
|
|
73
|
+
/** 任务失败:完整输出或兜底文案 + 所属插件仓库 + 操作类型(安装/卸载)+ 实际执行的安装命令(issue 预填用,可缺省)+ 尝试过的安装方式(npm 反查/执行命令,可缺省)+ 是否更新。 */
|
|
74
|
+
onError: (message: string, repo: string | null, kind: 'install' | 'uninstall', command?: string, attempts?: string[], update?: boolean) => void
|
|
71
75
|
/** 当前打开的安装/卸载弹窗插件:用于在弹窗内匹配进行中的任务。 */
|
|
72
76
|
installPlugin: HubPlugin | null
|
|
73
77
|
/** 当前打开的自定义安装(命令行)确认弹窗目标:与应用商店同一弹窗机制,匹配进行中的 custom 安装任务。 */
|
|
@@ -195,14 +199,14 @@ export function useTaskQueue(opts: TaskQueueOptions) {
|
|
|
195
199
|
// 同时缓存展示信息,待重启列表(服务端已登记)合并时直接补齐简介/版本
|
|
196
200
|
void syncInstalledVersion(q.repo, q.version, q.updatedAt)
|
|
197
201
|
pendingInfoRef.current.set(q.target, { desc: q.desc, version: q.version })
|
|
198
|
-
onInstallDone(modalTaskRef.current === q.id, q.repo, q.needsRestart)
|
|
202
|
+
onInstallDone(modalTaskRef.current === q.id, q.repo, q.needsRestart, q.action === 'update')
|
|
199
203
|
}
|
|
200
204
|
} else {
|
|
201
205
|
// 失败:完整展示全部输出行(最新在前,逆序为日志阅读顺序),不裁剪
|
|
202
206
|
const detail = lines.length > 0
|
|
203
207
|
? [...lines].reverse().join('\n')
|
|
204
208
|
: q.kind === 'uninstall' ? t('uninstallFail') : t('installFail')
|
|
205
|
-
onError(detail, q.repo, q.kind, q.command, q.attempts)
|
|
209
|
+
onError(detail, q.repo, q.kind, q.command, q.attempts, q.action === 'update')
|
|
206
210
|
}
|
|
207
211
|
maybeStopPoll()
|
|
208
212
|
}
|
|
@@ -367,6 +371,7 @@ export function useTaskQueue(opts: TaskQueueOptions) {
|
|
|
367
371
|
kind: (isRemove ? 'uninstall' : 'install') as 'install' | 'uninstall',
|
|
368
372
|
target: isRemove ? fallback : (display || fallback),
|
|
369
373
|
repo: isRemove ? null : (display || fallback),
|
|
374
|
+
action: (a.action === 'add' || a.action === 'update' || a.action === 'remove') ? a.action : 'add',
|
|
370
375
|
status: a.status === 'running' ? 'running' : 'pending',
|
|
371
376
|
progress: typeof a.progress === 'number' ? a.progress : 0,
|
|
372
377
|
lines: Array.isArray(a.lines) ? (a.lines as string[]) : [],
|
|
@@ -421,6 +426,7 @@ export function useTaskQueue(opts: TaskQueueOptions) {
|
|
|
421
426
|
version: input.version, updatedAt: input.updatedAt,
|
|
422
427
|
status: 'running', progress: 0, lines: [], optimistic: true,
|
|
423
428
|
command: input.command,
|
|
429
|
+
action: input.update ? 'update' : 'add',
|
|
424
430
|
// 服务端登记后 /active 会带回真实尝试记录(npm 反查 + 执行命令),先占位空列表
|
|
425
431
|
attempts: [], needsRestart: true,
|
|
426
432
|
}])
|
package/src/client/locales.ts
CHANGED
|
@@ -108,14 +108,15 @@ export const zh = {
|
|
|
108
108
|
settingsUpdateDesc: '更新检查方式与安装走到的网络通道',
|
|
109
109
|
settingsCheckOnStart: '启动时检查更新',
|
|
110
110
|
settingsCheckOnStartDesc: '打开插件中心时检查已安装插件是否有新版,发现更新会提示',
|
|
111
|
+
settingsProxy: 'HTTP 代理',
|
|
112
|
+
settingsProxyDesc: 'npm / git / 目录数据请求统一走该代理;留空直连',
|
|
111
113
|
settingsMirror: 'npm 镜像源',
|
|
112
|
-
settingsMirrorDesc: 'npm
|
|
114
|
+
settingsMirrorDesc: '默认跟随本机 npm 配置;官方源慢可换国内镜像',
|
|
115
|
+
mirrorNone: '未配置(跟随本机 npm 配置)',
|
|
113
116
|
mirrorOfficial: '官方源 registry.npmjs.org',
|
|
114
117
|
mirrorNpmmirror: '阿里云 npmmirror',
|
|
115
118
|
mirrorTencent: '腾讯云镜像',
|
|
116
|
-
|
|
117
|
-
settingsProxy: 'HTTP 代理',
|
|
118
|
-
settingsProxyDesc: 'npm / git / 目录数据请求统一走该代理;留空直连',
|
|
119
|
+
mirrorTsinghua: '清华大学 TUNA 镜像',
|
|
119
120
|
settingsSecurity: '安全信任',
|
|
120
121
|
settingsSecurityDesc: '命令行安装的三个通道开关:NPM 包、GitHub 源码与 DSH 命令',
|
|
121
122
|
settingsEnableNpm: '启用 NPM 安装',
|
|
@@ -181,6 +182,8 @@ export const zh = {
|
|
|
181
182
|
settingsDiagFail: '不可达',
|
|
182
183
|
// 系统诊断通道列表:一键全量诊断 + 一行一个,可点重测
|
|
183
184
|
diagNpm: 'npm 源',
|
|
185
|
+
// 诊断页 npm 行:未配置镜像时的展示(探测目标仍为官方源,代表本机无配置时的回退)
|
|
186
|
+
diagNpmUnset: '未配置(跟随本机 npm 配置)',
|
|
184
187
|
diagGithub: 'GitHub',
|
|
185
188
|
diagCatalog: '目录站点',
|
|
186
189
|
diagOk: 'OK',
|
|
@@ -231,6 +234,8 @@ export const zh = {
|
|
|
231
234
|
installNow: '直接安装',
|
|
232
235
|
installing: '安装中…',
|
|
233
236
|
installDone: '安装成功',
|
|
237
|
+
// 更新成功(通知中心区分安装/更新):更新 = 已安装目标覆盖重装到最新,与首次安装不同语义
|
|
238
|
+
updateDone: '更新成功',
|
|
234
239
|
installResultTitle: '插件安装成功',
|
|
235
240
|
installResultDesc: '',
|
|
236
241
|
// 更新语义:已安装插件点「更新」走同一条 add 命令原位覆盖重装,弹窗文案区分安装/更新
|
|
@@ -275,6 +280,8 @@ export const zh = {
|
|
|
275
280
|
errorTitle: '操作失败',
|
|
276
281
|
errorTitleInstall: '安装失败',
|
|
277
282
|
errorTitleUninstall: '卸载失败',
|
|
283
|
+
// 更新失败(通知中心区分安装/更新):更新目标覆盖重装失败,与首次安装失败不同语义
|
|
284
|
+
errorTitleUpdate: '更新失败',
|
|
278
285
|
errorPlugin: '插件',
|
|
279
286
|
errorClose: '知道了',
|
|
280
287
|
errorCopy: '复制错误信息',
|
|
@@ -436,14 +443,15 @@ export const en = {
|
|
|
436
443
|
settingsCheckOnStartDesc: 'Check installed plugins for new versions when the hub opens; you will be notified when updates are found',
|
|
437
444
|
settingsAutoInstall: 'Auto-install updates',
|
|
438
445
|
settingsAutoInstallDesc: 'Install detected updates in the background without asking (a host restart applies them)',
|
|
439
|
-
|
|
440
|
-
|
|
446
|
+
settingsProxy: 'HTTP proxy',
|
|
447
|
+
settingsProxyDesc: 'Route npm, git and catalog requests through this proxy; leave empty to connect directly',
|
|
448
|
+
settingsMirror: 'npm mirror',
|
|
449
|
+
settingsMirrorDesc: 'Unset by default — follows local npm config; pick a domestic mirror if slow',
|
|
450
|
+
mirrorNone: 'Unset (follow local npm config)',
|
|
441
451
|
mirrorOfficial: 'Official registry.npmjs.org',
|
|
442
452
|
mirrorNpmmirror: 'Alibaba npmmirror',
|
|
443
453
|
mirrorTencent: 'Tencent Cloud mirror',
|
|
444
|
-
|
|
445
|
-
settingsProxy: 'HTTP proxy',
|
|
446
|
-
settingsProxyDesc: 'Route npm, git and catalog requests through this proxy; leave empty to connect directly',
|
|
454
|
+
mirrorTsinghua: 'Tsinghua TUNA mirror',
|
|
447
455
|
settingsSecurity: 'Security & Trust',
|
|
448
456
|
settingsSecurityDesc: 'Toggles for the three command-line install channels: npm packages, GitHub sources and DSH commands',
|
|
449
457
|
settingsEnableNpm: 'Enable npm installs',
|
|
@@ -509,6 +517,8 @@ export const en = {
|
|
|
509
517
|
settingsDiagFail: 'Unreachable',
|
|
510
518
|
// System diagnostics channel list: one-click full check + one row per channel, click to re-probe
|
|
511
519
|
diagNpm: 'npm registry',
|
|
520
|
+
// Diagnostics npm row: shown when no mirror is configured (probe still targets the official registry, the fallback)
|
|
521
|
+
diagNpmUnset: 'Unset (follow local npm config)',
|
|
512
522
|
diagGithub: 'GitHub',
|
|
513
523
|
diagCatalog: 'Catalog site',
|
|
514
524
|
diagOk: 'OK',
|
|
@@ -559,6 +569,8 @@ export const en = {
|
|
|
559
569
|
installNow: 'Install',
|
|
560
570
|
installing: 'Installing…',
|
|
561
571
|
installDone: 'Installed',
|
|
572
|
+
// Updated (notification center distinguishes install/update): update = in-place reinstall to latest
|
|
573
|
+
updateDone: 'Updated',
|
|
562
574
|
installResultTitle: 'Plugin installed successfully',
|
|
563
575
|
installResultDesc: '',
|
|
564
576
|
// Update semantics: the "update" action re-runs add in place — copy differentiates install vs update
|
|
@@ -602,6 +614,8 @@ export const en = {
|
|
|
602
614
|
errorTitle: 'Operation failed',
|
|
603
615
|
errorTitleInstall: 'Install failed',
|
|
604
616
|
errorTitleUninstall: 'Removal failed',
|
|
617
|
+
// Update failed (notification center distinguishes install/update): update target reinstall failed
|
|
618
|
+
errorTitleUpdate: 'Update failed',
|
|
605
619
|
errorPlugin: 'Plugin',
|
|
606
620
|
errorClose: 'Got it',
|
|
607
621
|
errorCopy: 'Copy error',
|
|
@@ -18,6 +18,9 @@ export interface NotificationRecord {
|
|
|
18
18
|
ok: boolean
|
|
19
19
|
/** owner/repo(可能为空:请求层失败但拿不到仓库时) */
|
|
20
20
|
repo: string
|
|
21
|
+
/** 实际动作(install/update/uninstall):成功/失败通知据此区分「安装成功」与「更新成功」。
|
|
22
|
+
* 缺省按 kind 兜底(历史记录可能没有该字段)。更新提醒(kind='update')不用此字段。 */
|
|
23
|
+
action?: 'install' | 'update' | 'uninstall'
|
|
21
24
|
/** 失败时的完整错误日志;成功记录为空串 */
|
|
22
25
|
message: string
|
|
23
26
|
/** 更新提醒:目录里的新版本号(展示用;其余通知省略) */
|
package/src/client/logic/urls.ts
CHANGED
|
@@ -33,6 +33,15 @@ export function pluginSiteUrl(repo: string): string {
|
|
|
33
33
|
return `${SITE_URL}plugins/${repo}`
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/** 根据实际执行的命令判定失败动作标签(安装/更新/卸载):
|
|
37
|
+
* 命令形如 `dsh plugin --profile web add|update|remove <target>`,
|
|
38
|
+
* 出现 remove/update 动词即对应归类,其余(add、全局 npm 命令、未知)一律算安装。 */
|
|
39
|
+
function actionLabelOf(command: string | undefined): string {
|
|
40
|
+
if (command && /\s+remove\s+/i.test(command)) return 'Remove'
|
|
41
|
+
if (command && /\s+update\s+/i.test(command)) return 'Update'
|
|
42
|
+
return 'Install'
|
|
43
|
+
}
|
|
44
|
+
|
|
36
45
|
/**
|
|
37
46
|
* 一键反馈 GitHub Issue 的预填链接:标题带「来自 dsh-plugin.org」标识,正文只带
|
|
38
47
|
* 核心信息 —— 原因判定 + 关键错误代码 + 尝试过的安装方式 + 宿主机器环境快照 +
|
|
@@ -43,7 +52,9 @@ export function pluginSiteUrl(repo: string): string {
|
|
|
43
52
|
* 组织 scope 与 GitHub 用户名不一致时也能直接指认正确的 npm 包名。
|
|
44
53
|
*/
|
|
45
54
|
export function pluginIssueUrl(repo: string, message: string, env?: EnvInfo | null, command?: string, attempts?: string[]): string {
|
|
46
|
-
|
|
55
|
+
// 标题按实际执行的动作区分(安装/更新/卸载),避免作者误读 —— 旧版固定写死
|
|
56
|
+
// 「Install/Remove」会让更新失败被当成删除失败。
|
|
57
|
+
const title = `[dsh-plugin.org | dsh-plugin-hub] ${actionLabelOf(command)} failed: ${repo}`
|
|
47
58
|
// 原因判定:按失败类型归类,便于作者判断问题是否出在插件侧。
|
|
48
59
|
// [packaging](预检/装后校验拦截)单独列:无论走 npm 还是 git 通道,都是分发物不完整
|
|
49
60
|
// (package.json 声明的入口文件在发布物里缺失),作者照此补齐即可。
|
|
@@ -12,6 +12,16 @@
|
|
|
12
12
|
flex-shrink: 0;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/* 全宽变体:设置页「独占一行」的下拉与文本框同宽,按钮铺满整行 */
|
|
16
|
+
.dropdownFill {
|
|
17
|
+
width: 100%;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.dropdownFill > .dropdownBtn {
|
|
21
|
+
width: 100%;
|
|
22
|
+
justify-content: space-between;
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
/* 触发器:工具栏按钮风格 —— 细边框 + 次级灰底,与通知入口按钮同一视觉语言,
|
|
16
26
|
只占一个按钮位,给工具栏后续新增按钮留空间 */
|
|
17
27
|
.dropdownBtn {
|
|
@@ -1355,6 +1355,17 @@
|
|
|
1355
1355
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
1356
1356
|
}
|
|
1357
1357
|
|
|
1358
|
+
/* 用户反馈群二维码(renderMarkdown 对 dsh-plugin-user-group-qr- 前缀图片加了
|
|
1359
|
+
width/height="250"):固定 250×250 正方形。必须显式覆盖通用 max-height 上限 ——
|
|
1360
|
+
CSS max-height 对 height 有最终裁决权,不覆盖的话高度被压成 220 而宽度保持 250,
|
|
1361
|
+
图片就会变成非正方形(看起来像「250×250 没生效」) */
|
|
1362
|
+
.aboutContent img[width="250"] {
|
|
1363
|
+
width: 250px;
|
|
1364
|
+
height: 250px;
|
|
1365
|
+
max-height: 250px;
|
|
1366
|
+
object-fit: contain;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1358
1369
|
/* 更新时间小字:弱化展示在内容区下方 */
|
|
1359
1370
|
.aboutMeta {
|
|
1360
1371
|
font-size: 11px;
|
|
@@ -184,12 +184,12 @@ function hostEnv(profile: string): Record<string, string | null> {
|
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
/** 安装/卸载 CLI 的子进程环境:透传宿主环境,并按设置注入
|
|
187
|
+
/** 安装/卸载 CLI 的子进程环境:透传宿主环境,并按设置注入 HTTP(S) 代理。
|
|
188
|
+
* npm registry 不再注入 —— 安装完全沿用用户本机 npm 配置(~/.npmrc / 全局配置)。
|
|
188
189
|
* 代理优先级:设置里的代理 → 系统代理(macOS scutil / Windows 注册表)→ 宿主 env 原有值。
|
|
189
190
|
* 使安装通道与诊断使用相同的代理来源。 */
|
|
190
191
|
function mutationEnv(settings: HubSettings): NodeJS.ProcessEnv {
|
|
191
192
|
const env: NodeJS.ProcessEnv = { ...process.env, CI: 'true' }
|
|
192
|
-
if (settings.npmRegistry !== '') env.npm_config_registry = settings.npmRegistry
|
|
193
193
|
const proxy = settings.proxy !== '' ? settings.proxy : (systemProxy() ?? '')
|
|
194
194
|
if (proxy !== '') {
|
|
195
195
|
env.HTTP_PROXY = proxy
|
|
@@ -488,11 +488,14 @@ export function mountPluginHubRoutes(webServer: WebServerService, profile: strin
|
|
|
488
488
|
// 空 body / 非 JSON:视为全量探测
|
|
489
489
|
}
|
|
490
490
|
const settings = loadSettings(profile)
|
|
491
|
+
// npm 通道:设置里配置了镜像源就探测该镜像(安装通道吃同一个 registry);
|
|
492
|
+
// 未配置(空串)时探测官方源作为「跟随本机 npm 配置」的基础连通性参考。
|
|
491
493
|
const registry = settings.npmRegistry.replace(/\/+$/, '') || 'https://registry.npmjs.org'
|
|
492
494
|
// 连通性自检直接打安装通道真实访问的轻量资源:npm 源拉包元数据、git 通道探
|
|
493
495
|
// 仓库主页、目录站探 badge 小文件,避免拉取目录全量 JSON。
|
|
496
|
+
// npm 行 display:配置了镜像就显示镜像地址;未配置置空 —— 客户端显示「未配置(跟随本机 npm 配置)」。
|
|
494
497
|
const allChecks: Array<{ key: string; url: string; display: string; cmd: string }> = [
|
|
495
|
-
{ key: 'npm', url: `${registry}/dsh-plugin`, display: settings.npmRegistry !== '' ?
|
|
498
|
+
{ key: 'npm', url: `${registry}/dsh-plugin`, display: settings.npmRegistry !== '' ? registry : '', cmd: `npm view dsh-plugin version --registry ${registry}` },
|
|
496
499
|
{ key: 'github', url: 'https://github.com/dshplugin/dsh-plugin-hub', display: 'github.com', cmd: 'git ls-remote https://github.com/dshplugin/dsh-plugin-hub' },
|
|
497
500
|
{ key: 'catalog', url: 'https://api.dsh-plugin.org/stats.json', display: 'api.dsh-plugin.org', cmd: 'curl -s https://api.dsh-plugin.org/stats.json' },
|
|
498
501
|
]
|
|
@@ -23,7 +23,9 @@ const REQUEST_TIMEOUT_MS = 8000
|
|
|
23
23
|
* 反查 repo(`owner/repo`)对应的官方 npm 包名;未命中、网络异常或超时返回 null。
|
|
24
24
|
* 返回 null 不代表仓库一定没有 npm 包,只代表本次未能确认 —— 调用方应保留
|
|
25
25
|
* 原有错误路径,反查只是额外的一次尝试。
|
|
26
|
-
*
|
|
26
|
+
* registry 参数:npm 镜像源地址,空串 = 官方源;与安装通道吃同一 registry,
|
|
27
|
+
* 保证「配置了镜像」时反查和安装走同一个源(镜像节点同步完整时结果一致)。
|
|
28
|
+
* 慢网络下失败不阻塞安装。
|
|
27
29
|
*/
|
|
28
30
|
export function resolveNpmPackage(repo: string, registry = ''): Promise<string | null> {
|
|
29
31
|
const key = repo.toLowerCase()
|
|
@@ -14,10 +14,10 @@ import { profileDirectory } from './profile/profile.ts'
|
|
|
14
14
|
export interface HubSettings {
|
|
15
15
|
/** 启动时检查目录插件更新,发现可更新时在通知中心提示(安装不自动进行) */
|
|
16
16
|
checkUpdatesOnStart: boolean
|
|
17
|
-
/** npm 镜像源 registry 地址(空串 = 官方 https://registry.npmjs.org) */
|
|
18
|
-
npmRegistry: string
|
|
19
17
|
/** HTTP(S) 代理地址,用于 npm / git / 目录请求(空串 = 直连) */
|
|
20
18
|
proxy: string
|
|
19
|
+
/** npm 镜像源 registry 地址(空串 = 未配置,跟随用户本机 npm 配置,本插件不注入任何 registry) */
|
|
20
|
+
npmRegistry: string
|
|
21
21
|
/** 启用命令行安装 NPM 包(默认开;关掉后输入 npm 包名安装被拦截) */
|
|
22
22
|
enableNpmInstall: boolean
|
|
23
23
|
/** 启用命令行安装 GitHub 源码(默认开;关掉后输入 GitHub 地址安装被拦截) */
|
|
@@ -30,8 +30,8 @@ export interface HubSettings {
|
|
|
30
30
|
|
|
31
31
|
export const DEFAULT_SETTINGS: HubSettings = {
|
|
32
32
|
checkUpdatesOnStart: true,
|
|
33
|
-
npmRegistry: '',
|
|
34
33
|
proxy: '',
|
|
34
|
+
npmRegistry: '',
|
|
35
35
|
enableNpmInstall: true,
|
|
36
36
|
enableGitInstall: true,
|
|
37
37
|
enableDshInstall: true,
|