dsh-plugin 1.1.1 → 1.2.0
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 +5 -5
- package/README.md +5 -5
- package/client/client.js +4772 -1659
- package/client/client.js.map +1 -1
- package/lib/http/routes.js +451 -28
- package/lib/index.js +5 -1
- package/lib/services/{install-types.js → install/install-types.js} +8 -2
- package/lib/services/install/install.js +4 -0
- package/lib/services/install/npm-check.js +55 -0
- package/lib/services/{npm-resolve.js → install/npm-resolve.js} +11 -5
- package/lib/services/{preflight.js → install/preflight.js} +23 -7
- package/lib/services/{task-queue.js → install/task-queue.js} +166 -71
- package/lib/services/loader.js +60 -1
- package/lib/services/log.js +138 -0
- package/lib/services/probe.js +157 -0
- package/lib/services/{installed-versions.js → profile/installed-versions.js} +5 -1
- package/lib/services/{pending-restart.js → profile/pending-restart.js} +1 -1
- package/lib/services/{profile.js → profile/profile.js} +59 -4
- package/lib/services/{progress.js → profile/progress.js} +4 -0
- package/lib/services/settings.js +60 -0
- package/lib/types/http/routes.d.ts +1 -1
- package/lib/types/index.d.ts +5 -1
- package/lib/types/services/{install-types.d.ts → install/install-types.d.ts} +13 -4
- package/lib/types/services/{install.d.ts → install/install.d.ts} +9 -5
- package/lib/types/services/install/npm-check.d.ts +12 -0
- package/lib/types/services/{npm-resolve.d.ts → install/npm-resolve.d.ts} +2 -1
- package/lib/types/services/{task-queue.d.ts → install/task-queue.d.ts} +5 -1
- package/lib/types/services/loader.d.ts +14 -4
- package/lib/types/services/log.d.ts +49 -0
- package/lib/types/services/probe.d.ts +30 -0
- package/lib/types/services/{pending-restart.d.ts → profile/pending-restart.d.ts} +9 -3
- package/lib/types/services/{profile.d.ts → profile/profile.d.ts} +6 -2
- package/lib/types/services/{progress.d.ts → profile/progress.d.ts} +4 -0
- package/lib/types/services/settings.d.ts +24 -0
- package/package.json +1 -1
- package/src/client/components/PluginHubSection.tsx +346 -121
- package/src/client/components/{CatalogList.tsx → catalog/CatalogList.tsx} +15 -7
- package/src/client/components/{PluginCard.tsx → catalog/PluginCard.tsx} +10 -5
- package/src/client/components/layout/CatalogControls.tsx +80 -0
- package/src/client/components/{CatalogHeader.tsx → layout/CatalogHeader.tsx} +8 -4
- package/src/client/components/{CategoryTabs.tsx → layout/CategoryTabs.tsx} +7 -3
- package/src/client/components/layout/SectionTabs.tsx +60 -0
- package/src/client/components/{AboutModal.tsx → modals/AboutModal.tsx} +11 -7
- package/src/client/components/{HubUpdateModal.tsx → modals/HubUpdateModal.tsx} +9 -5
- package/src/client/components/modals/InstalledDetailModal.tsx +193 -0
- package/src/client/components/modals/LogsModal.tsx +301 -0
- package/src/client/components/modals/LogsPathModal.tsx +161 -0
- package/src/client/components/{NotificationsModal.tsx → modals/NotificationsModal.tsx} +51 -20
- package/src/client/components/{ProgressView.tsx → modals/ProgressView.tsx} +6 -2
- package/src/client/components/{modals.tsx → modals/modals.tsx} +121 -40
- package/src/client/components/{Dropdown.tsx → ui/Dropdown.tsx} +18 -6
- package/src/client/components/ui/Toggle.tsx +28 -0
- package/src/client/components/ui/icons.tsx +343 -0
- package/src/client/components/views/CustomInstallView.tsx +250 -0
- package/src/client/components/views/DiagnosticsView.tsx +172 -0
- package/src/client/components/views/InstalledView.tsx +328 -0
- package/src/client/components/views/LogsView.tsx +150 -0
- package/src/client/components/views/MarketView.tsx +66 -0
- package/src/client/components/views/SettingsView.tsx +273 -0
- package/src/client/data/catalog.ts +38 -0
- package/src/client/data/host.ts +107 -0
- package/src/client/data/hub.ts +41 -0
- package/src/client/hooks/useCatalog.ts +77 -117
- package/src/client/hooks/useIncrementalList.ts +46 -0
- package/src/client/hooks/useLanguage.ts +40 -0
- package/src/client/hooks/useSettings.ts +90 -0
- package/src/client/hooks/useTaskQueue.ts +168 -47
- package/src/client/index.tsx +4 -0
- package/src/client/locales.ts +365 -39
- package/src/client/logic/constants.ts +87 -0
- package/src/client/{lib → logic}/failures.ts +99 -74
- package/src/client/{lib → logic}/format.ts +4 -0
- package/src/client/logic/install-command.ts +56 -0
- package/src/client/logic/installed.ts +207 -0
- package/src/client/logic/normalize.ts +52 -0
- package/src/client/{lib → logic}/renderMarkdown.ts +4 -0
- package/src/client/logic/urls.ts +125 -0
- package/src/client/styles/CustomInstallView.module.css +191 -0
- package/src/client/styles/DiagnosticsView.module.css +231 -0
- package/src/client/styles/Dropdown.module.css +46 -41
- package/src/client/styles/Header.module.css +105 -133
- package/src/client/styles/InstalledView.module.css +447 -0
- package/src/client/styles/List.module.css +11 -1
- package/src/client/styles/LogsView.module.css +503 -0
- package/src/client/styles/Modal.module.css +357 -71
- package/src/client/styles/SectionTabs.module.css +142 -0
- package/src/client/styles/SettingsView.module.css +232 -0
- package/src/client/styles/Toggle.module.css +60 -0
- package/src/client/styles/tokens.module.css +6 -1
- package/src/client/types.ts +28 -4
- package/src/server/http/routes.ts +426 -28
- package/src/server/index.ts +5 -1
- package/src/server/services/{install-types.ts → install/install-types.ts} +13 -5
- package/src/server/services/{install.ts → install/install.ts} +9 -5
- package/src/server/services/install/npm-check.ts +53 -0
- package/src/server/services/{npm-resolve.ts → install/npm-resolve.ts} +11 -5
- package/src/server/services/{preflight.ts → install/preflight.ts} +24 -7
- package/src/server/services/{task-queue.ts → install/task-queue.ts} +168 -68
- package/src/server/services/loader.ts +59 -1
- package/src/server/services/log.ts +167 -0
- package/src/server/services/probe.ts +157 -0
- package/src/server/services/{installed-versions.ts → profile/installed-versions.ts} +5 -1
- package/src/server/services/{pending-restart.ts → profile/pending-restart.ts} +9 -3
- package/src/server/services/{profile.ts → profile/profile.ts} +58 -4
- package/src/server/services/{progress.ts → profile/progress.ts} +4 -0
- package/src/server/services/settings.ts +79 -0
- package/lib/services/install.js +0 -4
- package/src/client/components/CatalogControls.tsx +0 -104
- package/src/client/components/icons.tsx +0 -125
- package/src/client/lib/catalog.ts +0 -272
- package/src/client/lib/env.ts +0 -16
- /package/lib/types/services/{preflight.d.ts → install/preflight.d.ts} +0 -0
- /package/lib/types/services/{installed-versions.d.ts → profile/installed-versions.d.ts} +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSH-Plugin Hub — the community plugin marketplace for DeepSeek Harness.
|
|
3
|
+
* Website: https://dsh-plugin.org
|
|
4
|
+
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
5
|
+
*
|
|
6
|
+
* URL builders: catalog detail pages, plugin site links and the pre-filled
|
|
7
|
+
* GitHub issue URL used by the failure modal. Pure functions — the issue
|
|
8
|
+
* URL stays within GitHub's 8192-byte request limit.
|
|
9
|
+
*/
|
|
10
|
+
import type { EnvInfo, HubPlugin, LocaleId } from '../types.ts'
|
|
11
|
+
import { GITHUB_URL, PLUGIN_VERSION, SITE_URL } from './constants.ts'
|
|
12
|
+
import { MAX_CORE_CHARS, classifyFailure, coreErrorCode, summarizeError } from './failures.ts'
|
|
13
|
+
|
|
14
|
+
/** dsh-plugin.org 中文页挂在 /zh/ 前缀下,英文在根路径。 */
|
|
15
|
+
export function langPathOf(lang: LocaleId): string {
|
|
16
|
+
return lang === 'zh' ? 'zh/' : ''
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 官网详情页两级路径:/plugins/{ownerSlug}/{slug};
|
|
21
|
+
* 缺 ownerSlug 时从 repo 推导(卡片详情按钮与弹窗来源行共用)。
|
|
22
|
+
*/
|
|
23
|
+
export function pluginDetailUrl(plugin: HubPlugin, langPath: string): string {
|
|
24
|
+
const repo = plugin.source?.repo ?? ''
|
|
25
|
+
return `${SITE_URL}${langPath}plugins/${plugin.ownerSlug ?? repo.split('/')[0]?.toLowerCase() ?? ''}/${plugin.slug}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 失败弹窗里仓库地址的跳转目标:官网详情页(含插件收录信息),
|
|
30
|
+
* 与 issue 正文的 Catalog 链接同一形式(单级 /plugins/{repo})。
|
|
31
|
+
*/
|
|
32
|
+
export function pluginSiteUrl(repo: string): string {
|
|
33
|
+
return `${SITE_URL}plugins/${repo}`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 一键反馈 GitHub Issue 的预填链接:标题带「来自 dsh-plugin.org」标识,正文只带
|
|
38
|
+
* 核心信息 —— 原因判定 + 关键错误代码 + 尝试过的安装方式 + 宿主机器环境快照 +
|
|
39
|
+
* 错误核心摘要(完整日志太长,塞进 URL 会被 GitHub 以「request URL too long」拒绝,
|
|
40
|
+
* 故只收集重点)。错误弹窗、失败记录共用此逻辑。
|
|
41
|
+
* env 取不到时为 null,链接照常生成、只是少环境段。
|
|
42
|
+
* attempts(尝试过的安装方式,npm 反查 + 实际执行命令):作者看到我们查过/试过的命令,
|
|
43
|
+
* 组织 scope 与 GitHub 用户名不一致时也能直接指认正确的 npm 包名。
|
|
44
|
+
*/
|
|
45
|
+
export function pluginIssueUrl(repo: string, message: string, env?: EnvInfo | null, command?: string, attempts?: string[]): string {
|
|
46
|
+
const title = `[dsh-plugin.org | dsh-plugin-hub] Install/Remove failed: ${repo}`
|
|
47
|
+
// 原因判定:按失败类型归类,便于作者判断问题是否出在插件侧。
|
|
48
|
+
// [packaging](预检/装后校验拦截)单独列:无论走 npm 还是 git 通道,都是分发物不完整
|
|
49
|
+
// (package.json 声明的入口文件在发布物里缺失),作者照此补齐即可。
|
|
50
|
+
const kind = classifyFailure(message)
|
|
51
|
+
const reason = /\[packaging\]/i.test(message)
|
|
52
|
+
? 'plugin distribution is incomplete — the entry file declared in package.json is missing from the published package (github tarball or npm package); please commit build output or publish a complete package'
|
|
53
|
+
: kind === 'pluginPrepare'
|
|
54
|
+
? 'plugin prepare/build script failed during install (packaging/distribution issue)'
|
|
55
|
+
: kind === 'pnpmIgnoredBuild'
|
|
56
|
+
? 'plugin depends on a native module whose build script pnpm blocks by default (use a prebuilt variant)'
|
|
57
|
+
: 'plugin-side install failure'
|
|
58
|
+
const code = coreErrorCode(message)
|
|
59
|
+
// 按给定核心摘要预算构建完整预填 URL(含 URL 编码);预算可调,供超长时逐档缩小
|
|
60
|
+
const build = (coreChars: number): string => {
|
|
61
|
+
const body = [
|
|
62
|
+
'## Summary',
|
|
63
|
+
`- Cause: ${reason}`,
|
|
64
|
+
...(code ? [`- Key error: \`${code}\``] : []),
|
|
65
|
+
'',
|
|
66
|
+
// 来源说明:标题(链官网)+ 一句来源(链仓库)+ 实际执行的安装命令(含 --profile)与执行结果,链接由常量动态拼接
|
|
67
|
+
`## [DSH-Plugin 插件中心](${SITE_URL}) · 安装 Plugin 失败错误信息`,
|
|
68
|
+
`本错误信息由 [dsh-plugin-hub](${GITHUB_URL}) 插件中心的安装程序自动生成,随本次安装失败一并提交。`,
|
|
69
|
+
`- 实际执行的安装命令:\`${command ?? `dsh plugin${env?.profile ? ` --profile ${env.profile}` : ''} add git+https://github.com/${repo}.git`}\``,
|
|
70
|
+
`- 执行结果:安装失败,未能安装该插件。`,
|
|
71
|
+
// 尝试过的安装方式(npm 反查 + 实际执行命令,按先后顺序):作者据此反推正确的
|
|
72
|
+
// npm 包名 —— 组织 scope 与 GitHub 用户名不一致时仅凭仓库名猜不到,作者看到我们
|
|
73
|
+
// 查过/试过的命令就能直接指认
|
|
74
|
+
...(attempts && attempts.length > 0
|
|
75
|
+
? ['', '## Attempted install channels(已尝试的安装方式)', ...attempts.map((a) => `- ${a}`)]
|
|
76
|
+
: []),
|
|
77
|
+
// [packaging] 场景:说明两种官方安装通道(npm 包 / git 直装),当前插件在对应通道下分发不完整
|
|
78
|
+
...(/\[packaging\]/i.test(message)
|
|
79
|
+
? [
|
|
80
|
+
'',
|
|
81
|
+
'## 安装方式说明',
|
|
82
|
+
'DSH 插件支持两种官方安装通道:`dsh plugin add <npm-package>`(npm 分发,需发布完整构建产物)与 `dsh plugin add git+https://github.com/owner/repo.git`(Git 直装,仓库需提交构建产物或在 package.json 提供 `prepare` 脚本)。当前插件的分发物缺少 package.json 声明的入口文件,请按所用通道补齐后重新发布。',
|
|
83
|
+
]
|
|
84
|
+
: []),
|
|
85
|
+
'',
|
|
86
|
+
'## Environment',
|
|
87
|
+
`- Plugin: \`${repo}\``,
|
|
88
|
+
// 宿主机器环境快照:便于作者本地复现;某字段缺失时如实写 unknown,不编造
|
|
89
|
+
...(env
|
|
90
|
+
? [
|
|
91
|
+
`- DSH: ${env.dshVersion ? `v${env.dshVersion}` : 'unknown'}`,
|
|
92
|
+
`- Plugin Hub: v${PLUGIN_VERSION}`,
|
|
93
|
+
`- Node: ${env.nodeVersion}`,
|
|
94
|
+
`- OS: ${env.platform} ${env.arch} (${env.release})`,
|
|
95
|
+
`- Profile: \`${env.profile}\``,
|
|
96
|
+
`- DSH Home: \`${env.dshHome}\``,
|
|
97
|
+
]
|
|
98
|
+
: []),
|
|
99
|
+
// 该插件在插件中心的收录位置(详情页链接)
|
|
100
|
+
`- Catalog: [${pluginSiteUrl(repo)}](${pluginSiteUrl(repo)})`,
|
|
101
|
+
'',
|
|
102
|
+
'## Error (core)',
|
|
103
|
+
'',
|
|
104
|
+
'```',
|
|
105
|
+
// 核心错误收集器:只挑关键行(错误代码/构建失败/退出信息),去重截断,URL 才不至于超长
|
|
106
|
+
summarizeError(message, coreChars),
|
|
107
|
+
'```',
|
|
108
|
+
'',
|
|
109
|
+
'---',
|
|
110
|
+
// 底部署名:报错来自内置在 DeepSeek Harness 里的 dsh-plugin-hub 安装程序
|
|
111
|
+
`This error was produced by the [dsh-plugin-hub](${GITHUB_URL}) installer bundled with DeepSeek Harness.`,
|
|
112
|
+
].join('\n')
|
|
113
|
+
return `https://github.com/${repo}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`
|
|
114
|
+
}
|
|
115
|
+
// GitHub 请求行上限 8192 字节:先用宽松预算(最多 ~5K 核心错误)构建,超长再逐档缩小,保证最终 URL 不超限
|
|
116
|
+
const MAX_URL_CHARS = 7600
|
|
117
|
+
let url = build(MAX_CORE_CHARS)
|
|
118
|
+
if (url.length > MAX_URL_CHARS) {
|
|
119
|
+
for (const budget of [4000, 2500, 1400, 800, 400]) {
|
|
120
|
+
url = build(budget)
|
|
121
|
+
if (url.length <= MAX_URL_CHARS) break
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return url
|
|
125
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/* DSH-Plugin Hub — the community plugin marketplace for DeepSeek Harness.
|
|
2
|
+
* Website: https://dsh-plugin.org
|
|
3
|
+
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
4
|
+
*
|
|
5
|
+
* Custom install view: a standalone top-level section for manually
|
|
6
|
+
* installing npm packages or GitHub sources outside the catalog. The two
|
|
7
|
+
* installer cards (npm / GitHub) stack one per line; each card = channel
|
|
8
|
+
* label + example hint above the input + input row (input + install button)
|
|
9
|
+
* + optional format-error note. Colors resolve through the --hub-* tokens.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
.root {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
gap: 10px;
|
|
16
|
+
min-width: 0;
|
|
17
|
+
/* 输入面板集中在左侧可读宽度,避免在宽窗口里把输入框拉得过长 */
|
|
18
|
+
max-width: 560px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* 页面说明:一行灰字,交代这是做什么的、装完去哪看 */
|
|
22
|
+
.desc {
|
|
23
|
+
margin: 0;
|
|
24
|
+
font-size: 12px;
|
|
25
|
+
line-height: 18px;
|
|
26
|
+
color: var(--hub-text-tertiary);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* —— 输入卡片:NPM / GitHub 两块,一行一个 —— */
|
|
30
|
+
.installCards {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
gap: 10px;
|
|
34
|
+
flex-shrink: 0;
|
|
35
|
+
min-width: 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.installCard {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
gap: 8px;
|
|
42
|
+
min-width: 0;
|
|
43
|
+
padding: 10px 12px;
|
|
44
|
+
background: var(--hub-bg-1);
|
|
45
|
+
border: 1px solid var(--hub-border-1);
|
|
46
|
+
border-radius: 8px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.installCardHead {
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
min-width: 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.installLabel {
|
|
56
|
+
font-size: 12px;
|
|
57
|
+
line-height: 18px;
|
|
58
|
+
font-weight: 600;
|
|
59
|
+
color: var(--hub-text-primary);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* 文本框上方的示例:灰字小字,告诉用户该通道的推荐写法 */
|
|
63
|
+
.installExample {
|
|
64
|
+
font-size: 11px;
|
|
65
|
+
line-height: 16px;
|
|
66
|
+
color: var(--hub-text-tertiary);
|
|
67
|
+
white-space: nowrap;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
text-overflow: ellipsis;
|
|
70
|
+
min-width: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.installRow {
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
gap: 8px;
|
|
77
|
+
min-width: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.installInput {
|
|
81
|
+
flex: 1 1 auto;
|
|
82
|
+
min-width: 0;
|
|
83
|
+
height: 28px;
|
|
84
|
+
padding: 0 9px;
|
|
85
|
+
font-size: 12px;
|
|
86
|
+
line-height: 26px;
|
|
87
|
+
color: var(--hub-text-primary);
|
|
88
|
+
background: transparent;
|
|
89
|
+
border: 1px solid var(--hub-border-2);
|
|
90
|
+
border-radius: 6px;
|
|
91
|
+
outline: none;
|
|
92
|
+
transition: border-color 120ms ease;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.installInput::placeholder {
|
|
96
|
+
color: var(--hub-text-tertiary);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.installInput:focus {
|
|
100
|
+
border-color: var(--hub-brand);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.installInputError,
|
|
104
|
+
.installInputError:focus {
|
|
105
|
+
border-color: var(--hub-danger-text);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.installBtn {
|
|
109
|
+
flex-shrink: 0;
|
|
110
|
+
font-family: inherit;
|
|
111
|
+
font-size: 12px;
|
|
112
|
+
line-height: 18px;
|
|
113
|
+
font-weight: 500;
|
|
114
|
+
color: #fff;
|
|
115
|
+
background: var(--hub-brand);
|
|
116
|
+
border: none;
|
|
117
|
+
border-radius: 6px;
|
|
118
|
+
padding: 5px 14px;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
user-select: none;
|
|
121
|
+
transition: background 120ms ease, opacity 120ms ease;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.installBtn:hover {
|
|
125
|
+
background: var(--hub-brand-hover);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.installBtn:disabled {
|
|
129
|
+
opacity: 0.45;
|
|
130
|
+
cursor: default;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* 通道关闭(安全信任开关关掉):卡片整体压暗,输入行换成提示行 */
|
|
134
|
+
.installCardDisabled {
|
|
135
|
+
opacity: 0.8;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* 通道关闭提示行:琥珀色提示 + 「前往设置」按钮,替代示例与输入行 */
|
|
139
|
+
.channelOff {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: space-between;
|
|
143
|
+
gap: 8px;
|
|
144
|
+
min-width: 0;
|
|
145
|
+
padding: 6px 9px;
|
|
146
|
+
font-size: 12px;
|
|
147
|
+
line-height: 16px;
|
|
148
|
+
color: var(--hub-warn);
|
|
149
|
+
background: var(--hub-warn-tint);
|
|
150
|
+
border: 1px solid var(--hub-warn-border);
|
|
151
|
+
border-radius: 6px;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.channelOffText {
|
|
155
|
+
min-width: 0;
|
|
156
|
+
overflow: hidden;
|
|
157
|
+
text-overflow: ellipsis;
|
|
158
|
+
white-space: nowrap;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.channelOffBtn {
|
|
162
|
+
flex-shrink: 0;
|
|
163
|
+
font-family: inherit;
|
|
164
|
+
font-size: 12px;
|
|
165
|
+
line-height: 18px;
|
|
166
|
+
font-weight: 500;
|
|
167
|
+
color: var(--hub-warn-strong);
|
|
168
|
+
background: transparent;
|
|
169
|
+
border: 1px solid var(--hub-warn-border);
|
|
170
|
+
border-radius: 6px;
|
|
171
|
+
padding: 3px 10px;
|
|
172
|
+
cursor: pointer;
|
|
173
|
+
white-space: nowrap;
|
|
174
|
+
transition: background 120ms ease, color 120ms ease;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.channelOffBtn:hover {
|
|
178
|
+
background: var(--hub-warn-tint);
|
|
179
|
+
color: var(--hub-warn);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* 格式错误:输入框红边框 + 卡片下方红字提示(给出该通道的推荐写法) */
|
|
183
|
+
.installError {
|
|
184
|
+
font-size: 12px;
|
|
185
|
+
line-height: 16px;
|
|
186
|
+
color: var(--hub-danger-text);
|
|
187
|
+
background: var(--hub-danger-tint);
|
|
188
|
+
border: 1px solid var(--hub-danger-border);
|
|
189
|
+
border-radius: 6px;
|
|
190
|
+
padding: 5px 8px;
|
|
191
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/* DSH-Plugin Hub — the community plugin marketplace for DeepSeek Harness.
|
|
2
|
+
* Website: https://dsh-plugin.org
|
|
3
|
+
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
4
|
+
*
|
|
5
|
+
* System diagnostics list: every connectivity probe is one row — name,
|
|
6
|
+
* target address, latency and a live status badge (200 OK / Unreachable /
|
|
7
|
+
* Checking…). The list runs automatically when the page opens; each row is
|
|
8
|
+
* a button — click to re-probe just that channel with a visible
|
|
9
|
+
* running→result feedback loop. Colors resolve through the --hub-* tokens. */
|
|
10
|
+
|
|
11
|
+
.panel {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
min-width: 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* —— 系统版本(最顶部)—— */
|
|
18
|
+
|
|
19
|
+
/* 版本行:左侧标题+说明,右侧「复制」按钮;与设置行同构,置顶展示 */
|
|
20
|
+
.envRow {
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
gap: 10px;
|
|
24
|
+
padding: 8px 12px;
|
|
25
|
+
border-bottom: 1px solid var(--hub-border-1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.envLabel {
|
|
29
|
+
flex: 1;
|
|
30
|
+
min-width: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.envTitle {
|
|
34
|
+
font-size: 12.5px;
|
|
35
|
+
line-height: 18px;
|
|
36
|
+
font-weight: 500;
|
|
37
|
+
color: var(--hub-text-primary);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.envDesc {
|
|
41
|
+
font-size: 11px;
|
|
42
|
+
line-height: 16px;
|
|
43
|
+
color: var(--hub-text-tertiary);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.envCopyBtn {
|
|
47
|
+
flex: none;
|
|
48
|
+
height: 24px;
|
|
49
|
+
padding: 0 12px;
|
|
50
|
+
font-size: 11.5px;
|
|
51
|
+
font-weight: 500;
|
|
52
|
+
color: var(--hub-text-secondary);
|
|
53
|
+
background: var(--hub-bg-hover);
|
|
54
|
+
border: 1px solid var(--hub-border-2);
|
|
55
|
+
border-radius: 6px;
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
user-select: none;
|
|
58
|
+
transition: color 0.12s ease, background-color 0.12s ease, border-color 0.12s ease;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.envCopyBtn:hover:not(:disabled) {
|
|
62
|
+
color: var(--hub-text-primary);
|
|
63
|
+
background: var(--hub-bg-2);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.envCopyBtn:disabled {
|
|
67
|
+
opacity: 0.55;
|
|
68
|
+
cursor: default;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* 头部行:左侧说明文字,右侧「立即诊断」品牌色按钮 */
|
|
72
|
+
.head {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
gap: 10px;
|
|
76
|
+
padding: 8px 12px;
|
|
77
|
+
border-bottom: 1px solid var(--hub-border-1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.headHint {
|
|
81
|
+
flex: 1;
|
|
82
|
+
min-width: 0;
|
|
83
|
+
font-size: 11px;
|
|
84
|
+
line-height: 16px;
|
|
85
|
+
color: var(--hub-text-tertiary);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.runBtn {
|
|
89
|
+
flex: none;
|
|
90
|
+
height: 24px;
|
|
91
|
+
padding: 0 12px;
|
|
92
|
+
font-size: 11.5px;
|
|
93
|
+
font-weight: 500;
|
|
94
|
+
color: var(--hub-brand);
|
|
95
|
+
background: var(--hub-brand-tint);
|
|
96
|
+
border: 1px solid transparent;
|
|
97
|
+
border-radius: 6px;
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
user-select: none;
|
|
100
|
+
transition: color 0.12s ease, background-color 0.12s ease, border-color 0.12s ease;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.runBtn:hover:not(:disabled) {
|
|
104
|
+
color: #ffffff;
|
|
105
|
+
background: var(--hub-brand);
|
|
106
|
+
border-color: var(--hub-brand);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.runBtn:disabled {
|
|
110
|
+
opacity: 0.55;
|
|
111
|
+
cursor: default;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* 一行一个通道:整行可点击重测,悬浮高亮,检测中置灰不可点 */
|
|
115
|
+
.row {
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
gap: 10px;
|
|
119
|
+
width: 100%;
|
|
120
|
+
min-width: 0;
|
|
121
|
+
box-sizing: border-box;
|
|
122
|
+
padding: 9px 12px;
|
|
123
|
+
border: none;
|
|
124
|
+
border-bottom: 1px solid var(--hub-border-1);
|
|
125
|
+
background: transparent;
|
|
126
|
+
font: inherit;
|
|
127
|
+
text-align: left;
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
user-select: none;
|
|
130
|
+
transition: background-color 0.12s ease;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.row:last-of-type {
|
|
134
|
+
border-bottom: none;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.row:hover:not(:disabled) {
|
|
138
|
+
background: var(--hub-bg-hover);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.row:disabled {
|
|
142
|
+
cursor: default;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.name {
|
|
146
|
+
flex: none;
|
|
147
|
+
font-size: 12.5px;
|
|
148
|
+
line-height: 18px;
|
|
149
|
+
font-weight: 500;
|
|
150
|
+
color: var(--hub-text-primary);
|
|
151
|
+
white-space: nowrap;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* 目标地址(registry 地址 / github.com / dsh-plugin.org):次级灰,过长省略 */
|
|
155
|
+
.display {
|
|
156
|
+
flex: 1;
|
|
157
|
+
min-width: 0;
|
|
158
|
+
font-size: 11px;
|
|
159
|
+
line-height: 16px;
|
|
160
|
+
color: var(--hub-text-tertiary);
|
|
161
|
+
white-space: nowrap;
|
|
162
|
+
overflow: hidden;
|
|
163
|
+
text-overflow: ellipsis;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* 耗时:成功时显示,如 42ms,等宽数字 */
|
|
167
|
+
.meta {
|
|
168
|
+
flex: none;
|
|
169
|
+
font-size: 11px;
|
|
170
|
+
line-height: 16px;
|
|
171
|
+
color: var(--hub-text-tertiary);
|
|
172
|
+
font-variant-numeric: tabular-nums;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* 状态徽章:成功绿 / 失败红 / 检测中灰底闪烁 / 待检空 */
|
|
176
|
+
.badge {
|
|
177
|
+
flex: none;
|
|
178
|
+
padding: 0 8px;
|
|
179
|
+
height: 17px;
|
|
180
|
+
border-radius: 999px;
|
|
181
|
+
font-size: 10.5px;
|
|
182
|
+
line-height: 17px;
|
|
183
|
+
text-align: center;
|
|
184
|
+
white-space: nowrap;
|
|
185
|
+
font-variant-numeric: tabular-nums;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.badgeOk {
|
|
189
|
+
color: var(--hub-success);
|
|
190
|
+
background: var(--hub-success-tint);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.badgeFail {
|
|
194
|
+
color: var(--hub-danger-text);
|
|
195
|
+
background: var(--hub-danger-tint);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.badgeRunning {
|
|
199
|
+
color: var(--hub-text-secondary);
|
|
200
|
+
background: var(--hub-bg-hover);
|
|
201
|
+
animation: diagPulse 1s ease-in-out infinite;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.badgeIdle {
|
|
205
|
+
color: var(--hub-text-disabled);
|
|
206
|
+
background: var(--hub-bg-hover);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@keyframes diagPulse {
|
|
210
|
+
0%, 100% { opacity: 1; }
|
|
211
|
+
50% { opacity: 0.4; }
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* 底部总览:全部通过 / 存在异常 / 检测中,与列表行左对齐 */
|
|
215
|
+
.summary {
|
|
216
|
+
padding: 8px 12px 10px;
|
|
217
|
+
font-size: 11px;
|
|
218
|
+
line-height: 16px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.summaryOk {
|
|
222
|
+
color: var(--hub-success);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.summaryFail {
|
|
226
|
+
color: var(--hub-danger-text);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.summaryRunning {
|
|
230
|
+
color: var(--hub-text-tertiary);
|
|
231
|
+
}
|
|
@@ -1,66 +1,72 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
1
|
+
/* DSH-Plugin Hub — the community plugin marketplace for DeepSeek Harness.
|
|
2
|
+
* Website: https://dsh-plugin.org
|
|
3
|
+
* GitHub: https://github.com/dshplugin/dsh-plugin-hub
|
|
4
|
+
*
|
|
5
|
+
* Button-style dropdown: the trigger reads as a compact toolbar button
|
|
6
|
+
* (hairline border + subtle fill + current value + chevron), the panel is
|
|
7
|
+
* a floating menu with hover fills and a brand-highlighted active option.
|
|
8
|
+
* Colors resolve through the --hub-* design tokens. */
|
|
9
|
+
|
|
3
10
|
.dropdown {
|
|
4
11
|
position: relative;
|
|
5
|
-
display: inline-flex;
|
|
6
12
|
flex-shrink: 0;
|
|
7
13
|
}
|
|
8
14
|
|
|
15
|
+
/* 触发器:工具栏按钮风格 —— 细边框 + 次级灰底,与通知入口按钮同一视觉语言,
|
|
16
|
+
只占一个按钮位,给工具栏后续新增按钮留空间 */
|
|
9
17
|
.dropdownBtn {
|
|
10
18
|
display: inline-flex;
|
|
11
19
|
align-items: center;
|
|
12
20
|
gap: 6px;
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
box-sizing: border-box;
|
|
22
|
+
height: 28px;
|
|
23
|
+
padding: 0 10px;
|
|
24
|
+
border: 1px solid var(--hub-border-2);
|
|
25
|
+
border-radius: 6px;
|
|
15
26
|
font-size: 12px;
|
|
16
|
-
line-height:
|
|
27
|
+
line-height: 26px;
|
|
17
28
|
color: var(--hub-text-primary);
|
|
18
|
-
background:
|
|
19
|
-
border: none;
|
|
20
|
-
border-radius: 6px;
|
|
29
|
+
background: var(--hub-bg-hover);
|
|
21
30
|
cursor: pointer;
|
|
22
31
|
user-select: none;
|
|
23
|
-
|
|
24
|
-
transition: background 120ms ease;
|
|
32
|
+
transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
.dropdownBtn:hover {
|
|
28
|
-
background:
|
|
36
|
+
background: rgba(128, 128, 128, 0.28);
|
|
29
37
|
}
|
|
30
38
|
|
|
31
39
|
.dropdownLabel {
|
|
32
|
-
|
|
33
|
-
overflow: hidden;
|
|
34
|
-
text-overflow: ellipsis;
|
|
40
|
+
white-space: nowrap;
|
|
35
41
|
}
|
|
36
42
|
|
|
43
|
+
/* 箭头:弱化灰,展开时 180° 翻转并加深,提示可收起 */
|
|
37
44
|
.dropdownArrow,
|
|
38
45
|
.dropdownArrowOpen {
|
|
39
46
|
display: inline-flex;
|
|
40
|
-
align-items: center;
|
|
41
|
-
justify-content: center;
|
|
42
47
|
color: var(--hub-text-tertiary);
|
|
43
|
-
transition: transform 120ms ease;
|
|
48
|
+
transition: transform 120ms ease, color 120ms ease;
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
.dropdownArrowOpen {
|
|
52
|
+
color: var(--hub-text-secondary);
|
|
47
53
|
transform: rotate(180deg);
|
|
48
54
|
}
|
|
49
55
|
|
|
56
|
+
/* 浮层:跟随按钮左对齐(left:0),浅底 + 细边框,不加模糊背景投影,克制不抢内容 */
|
|
50
57
|
.dropdownPanel {
|
|
51
58
|
position: absolute;
|
|
52
59
|
top: calc(100% + 4px);
|
|
53
60
|
left: 0;
|
|
54
|
-
z-index: 50;
|
|
55
61
|
min-width: 100%;
|
|
56
|
-
|
|
57
|
-
flex-direction: column;
|
|
58
|
-
gap: 2px;
|
|
62
|
+
z-index: 20;
|
|
59
63
|
padding: 4px;
|
|
60
|
-
background: var(--hub-bg-1);
|
|
61
64
|
border: 1px solid var(--hub-border-2);
|
|
62
65
|
border-radius: 8px;
|
|
63
|
-
|
|
66
|
+
background: var(--hub-bg-1);
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
gap: 1px;
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
.dropdownItem,
|
|
@@ -68,38 +74,37 @@
|
|
|
68
74
|
display: flex;
|
|
69
75
|
align-items: center;
|
|
70
76
|
justify-content: space-between;
|
|
71
|
-
gap:
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
gap: 12px;
|
|
78
|
+
width: 100%;
|
|
79
|
+
padding: 5px 8px;
|
|
74
80
|
border: none;
|
|
75
81
|
border-radius: 6px;
|
|
76
|
-
|
|
82
|
+
font-size: 12px;
|
|
83
|
+
line-height: 16px;
|
|
84
|
+
text-align: left;
|
|
77
85
|
cursor: pointer;
|
|
78
86
|
user-select: none;
|
|
79
|
-
|
|
80
|
-
text-align: left;
|
|
81
|
-
transition: background 120ms ease, color 120ms ease;
|
|
87
|
+
transition: color 120ms ease, background 120ms ease;
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
.dropdownItem {
|
|
85
|
-
color: var(--hub-text-
|
|
91
|
+
color: var(--hub-text-secondary);
|
|
86
92
|
background: transparent;
|
|
87
93
|
}
|
|
88
94
|
|
|
89
|
-
/* 悬浮选项:明显加重底色,保证「看得见、点得准」。 */
|
|
90
95
|
.dropdownItem:hover {
|
|
96
|
+
color: var(--hub-text-primary);
|
|
91
97
|
background: var(--hub-bg-hover);
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
.dropdownItemActive {
|
|
95
|
-
color: var(--hub-
|
|
96
|
-
background: var(--hub-
|
|
101
|
+
color: var(--hub-brand);
|
|
102
|
+
background: var(--hub-brand-tint);
|
|
103
|
+
font-weight: 600;
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
.dropdownItemLabel {
|
|
100
|
-
|
|
101
|
-
overflow: hidden;
|
|
102
|
-
text-overflow: ellipsis;
|
|
107
|
+
white-space: nowrap;
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
.dropdownCount,
|
|
@@ -107,7 +112,7 @@
|
|
|
107
112
|
font-size: 10px;
|
|
108
113
|
line-height: 14px;
|
|
109
114
|
border-radius: 999px;
|
|
110
|
-
padding: 0
|
|
115
|
+
padding: 0 5px;
|
|
111
116
|
min-width: 16px;
|
|
112
117
|
text-align: center;
|
|
113
118
|
}
|
|
@@ -117,7 +122,7 @@
|
|
|
117
122
|
background: var(--hub-bg-btn);
|
|
118
123
|
}
|
|
119
124
|
|
|
120
|
-
.
|
|
125
|
+
.dropdownCountActive {
|
|
121
126
|
color: var(--hub-text-on-fill);
|
|
122
|
-
background: var(--hub-
|
|
127
|
+
background: var(--hub-btn-fill);
|
|
123
128
|
}
|