dsh-mcp-connector 0.2.14 → 0.2.16
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/CHANGELOG.md +22 -0
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/package.json +1 -1
- package/ui/index.html +44 -18
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.2.16] - 2026-08-24
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- 市场分类栏移入固定 Header 第二行,不再悬浮覆盖滚动中的卡片;切换到“已安装”时自动隐藏并收回空间。
|
|
12
|
+
- 移除市场正文中的冗余连接器数量与操作提示,把市场/已安装总数改为页签内的轻量徽标。
|
|
13
|
+
|
|
14
|
+
### Verification
|
|
15
|
+
|
|
16
|
+
- 插件 88 项自动测试、lint 与 npm 发布文件白名单/敏感内容扫描通过。
|
|
17
|
+
- 使用 UI harness 验证桌面分类标签无横向溢出;滚动后 Header 与分类栏坐标保持不变,分类点击与已安装页签切换正常。
|
|
18
|
+
|
|
19
|
+
## [0.2.15] - 2026-08-24
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- 未连接且目录没有工具快照的卡片详情不再误报“当前连接异常”;现在保持未连接状态,并提示连接后读取服务端工具清单。
|
|
24
|
+
|
|
25
|
+
### Verification
|
|
26
|
+
|
|
27
|
+
- 新增详情状态回归,插件自动测试增至 87 项;使用本机 DSH 对 Seedream 未配置详情进行实机验收。
|
|
28
|
+
|
|
7
29
|
## [0.2.14] - 2026-08-24
|
|
8
30
|
|
|
9
31
|
### Added
|
package/README.en.md
CHANGED
|
@@ -101,7 +101,7 @@ npm run dev:ui
|
|
|
101
101
|
|
|
102
102
|
`npm run check` performs syntax checks, automated tests, and an npm package allowlist/sensitive-content audit. `npm run market:check` tracks the external DSH marketplace PR and live directory. Tags matching `v*` trigger GitHub Actions; the tag must match `package.json`. npm releases use Trusted Publishing through GitHub OIDC and do not require a long-lived `NPM_TOKEN`.
|
|
103
103
|
|
|
104
|
-
The current public version is [`dsh-mcp-connector@0.2.
|
|
104
|
+
The current public version is [`dsh-mcp-connector@0.2.16`](https://www.npmjs.com/package/dsh-mcp-connector), with [GitHub Release v0.2.16](https://github.com/duhu2000/dsh-mcp-connector/releases/tag/v0.2.16).
|
|
105
105
|
|
|
106
106
|
See [CHANGELOG.md](CHANGELOG.md) for version history and [docs/DESKTOP-E2E.md](docs/DESKTOP-E2E.md) for the Desktop release checklist.
|
|
107
107
|
|
package/README.md
CHANGED
|
@@ -96,7 +96,7 @@ npm run dev:ui
|
|
|
96
96
|
|
|
97
97
|
`check` 执行语法检查、自动测试和 npm 发布包白名单校验;`market:check` 检查外部 DSH 市场 PR 与线上目录;`dev:ui` 启动不含真实凭据的本地 mock 市场。CI 使用 `--legacy-peer-deps` 安装显式测试依赖,DSH 运行期 peer 仍由 Host 提供。`v*` Tag 会触发 GitHub Actions;Tag 必须与 `package.json` 版本一致。Release 通过 npm Trusted Publishing (GitHub OIDC) 发布,不依赖长期 `NPM_TOKEN`。
|
|
98
98
|
|
|
99
|
-
当前公开版本为 [`dsh-mcp-connector@0.2.
|
|
99
|
+
当前公开版本为 [`dsh-mcp-connector@0.2.16`](https://www.npmjs.com/package/dsh-mcp-connector),对应 [GitHub Release v0.2.16](https://github.com/duhu2000/dsh-mcp-connector/releases/tag/v0.2.16)。
|
|
100
100
|
|
|
101
101
|
版本能力与变更记录见 [CHANGELOG.md](CHANGELOG.md)。
|
|
102
102
|
Desktop 发版回归见 [docs/DESKTOP-E2E.md](docs/DESKTOP-E2E.md)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mcp-connector",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.16",
|
|
4
4
|
"description": "General-purpose MCP connector, connection manager, plugin extension, and integration marketplace for DeepSeek Harness, initiated and maintained by Qichacha/QCC.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
package/ui/index.html
CHANGED
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
|
|
62
62
|
/* Header */
|
|
63
63
|
header {
|
|
64
|
-
display: flex; align-items: center; gap: 12px;
|
|
64
|
+
display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
|
|
65
65
|
padding: 16px 24px; border-bottom: 1px solid var(--line);
|
|
66
66
|
background: var(--card); position: sticky; top: 0; z-index: 5;
|
|
67
67
|
flex-shrink: 0;
|
|
@@ -70,12 +70,20 @@
|
|
|
70
70
|
header .logo .puzzle { font-size: 22px; }
|
|
71
71
|
.tabs { display: flex; gap: 0; background: var(--bg); padding: 3px; border-radius: 10px; }
|
|
72
72
|
.tabs button {
|
|
73
|
+
display: inline-flex; align-items: center; gap: 5px;
|
|
73
74
|
border: 0; background: transparent; color: var(--text-2);
|
|
74
75
|
padding: 6px 16px; border-radius: 8px; cursor: pointer; font-size: 13px; font-weight: 500;
|
|
75
76
|
transition: all .15s;
|
|
76
77
|
}
|
|
77
78
|
.tabs button:hover { color: var(--text); }
|
|
78
79
|
.tabs button.active { background: var(--card); color: var(--accent); box-shadow: var(--shadow); font-weight: 600; }
|
|
80
|
+
.tab-count {
|
|
81
|
+
min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px;
|
|
82
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
83
|
+
background: var(--line); color: var(--text-2); font-size: 10px; line-height: 1;
|
|
84
|
+
}
|
|
85
|
+
.tabs button.active .tab-count { background: var(--accent-light); color: var(--accent); }
|
|
86
|
+
.tab-count:empty { display: none; }
|
|
79
87
|
.header-spacer { flex: 1; }
|
|
80
88
|
.search-box {
|
|
81
89
|
display: flex; align-items: center; gap: 8px;
|
|
@@ -104,13 +112,8 @@
|
|
|
104
112
|
.stats { display: flex; align-items: center; gap: 16px; margin-bottom: 20px; }
|
|
105
113
|
.stats .count { font-size: 13px; color: var(--text-2); }
|
|
106
114
|
.stats .count strong { color: var(--text); font-weight: 600; }
|
|
107
|
-
.market-
|
|
108
|
-
|
|
109
|
-
display: flex; align-items: center;
|
|
110
|
-
margin: -8px 0 14px; padding: 10px 12px;
|
|
111
|
-
background: var(--card); border: 1px solid var(--line); border-radius: 10px;
|
|
112
|
-
box-shadow: 0 8px 14px color-mix(in srgb, var(--bg) 88%, transparent);
|
|
113
|
-
}
|
|
115
|
+
.market-nav { flex: 0 0 100%; min-width: 0; order: 4; }
|
|
116
|
+
.market-filters { position: static; display: flex; align-items: center; }
|
|
114
117
|
.filter-chips { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
|
115
118
|
.filter-chip {
|
|
116
119
|
border: 1px solid var(--line); background: var(--bg); color: var(--text-2);
|
|
@@ -365,7 +368,7 @@
|
|
|
365
368
|
.inline-error.show { display: block; }
|
|
366
369
|
|
|
367
370
|
@media (max-width: 620px) {
|
|
368
|
-
header { padding: 12px;
|
|
371
|
+
header { padding: 12px; }
|
|
369
372
|
.header-spacer { display: none; }
|
|
370
373
|
.search-box { order: 3; width: 100%; }
|
|
371
374
|
main { padding: 14px; }
|
|
@@ -388,8 +391,8 @@
|
|
|
388
391
|
<div class="app">
|
|
389
392
|
<header>
|
|
390
393
|
<div class="tabs" id="tabs">
|
|
391
|
-
<button data-view="market" class="active"
|
|
392
|
-
<button data-view="installed"
|
|
394
|
+
<button data-view="market" class="active">市场 <span class="tab-count" id="market-tab-count"></span></button>
|
|
395
|
+
<button data-view="installed">已安装 <span class="tab-count" id="installed-tab-count"></span></button>
|
|
393
396
|
</div>
|
|
394
397
|
<div class="header-spacer"></div>
|
|
395
398
|
<div class="search-box">
|
|
@@ -398,6 +401,7 @@
|
|
|
398
401
|
</div>
|
|
399
402
|
<button class="icon-btn primary" id="add-connection" type="button">+ 添加连接</button>
|
|
400
403
|
<button class="icon-btn" id="refresh">刷新</button>
|
|
404
|
+
<div class="market-nav" id="market-nav" aria-label="市场分类导航"></div>
|
|
401
405
|
</header>
|
|
402
406
|
<main id="main"></main>
|
|
403
407
|
|
|
@@ -742,6 +746,18 @@
|
|
|
742
746
|
return `<div class="market-filters" role="group" aria-label="市场分类"><div class="filter-chips category-chips" role="group" aria-label="按分类筛选">${categoryChips}</div></div>`;
|
|
743
747
|
}
|
|
744
748
|
|
|
749
|
+
function syncMarketNav() {
|
|
750
|
+
const nav = $('#market-nav');
|
|
751
|
+
nav.hidden = view !== 'market';
|
|
752
|
+
nav.innerHTML = view === 'market' ? marketFilterHtml() : '';
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
function setTabCount(tab, count) {
|
|
756
|
+
const node = $(`#${tab}-tab-count`);
|
|
757
|
+
node.textContent = Number.isFinite(count) ? String(count) : '';
|
|
758
|
+
node.setAttribute('aria-label', Number.isFinite(count) ? `${count} 个` : '');
|
|
759
|
+
}
|
|
760
|
+
|
|
745
761
|
function marketSectionHtml(value, label, items) {
|
|
746
762
|
if (!items.length) return '';
|
|
747
763
|
const expanded = expandedMarketSections.has(value);
|
|
@@ -767,23 +783,23 @@
|
|
|
767
783
|
|
|
768
784
|
async function loadMarket({ checkHealth = true, preserveScroll = false } = {}) {
|
|
769
785
|
const previousScrollTop = preserveScroll ? main.scrollTop : 0;
|
|
786
|
+
syncMarketNav();
|
|
770
787
|
main.innerHTML = '<div class="empty">加载中…</div>';
|
|
771
|
-
const r = await call('catalog', {});
|
|
788
|
+
const [r, status] = await Promise.all([call('catalog', {}), call('status', {})]);
|
|
789
|
+
if (status.ok) setTabCount('installed', (status.detail?.items ?? []).length);
|
|
772
790
|
if (!r.ok) { main.innerHTML = `<div class="empty">${esc(r.message)}</div>`; return; }
|
|
773
791
|
const items = r.detail?.items ?? [];
|
|
792
|
+
setTabCount('market', items.length);
|
|
774
793
|
if (!items.length) { main.innerHTML = '<div class="empty">暂无已上架的连接器</div>'; return; }
|
|
775
794
|
marketItems = {};
|
|
776
795
|
items.forEach((d) => { marketItems[d.id] = d; });
|
|
777
796
|
const filtered = items.filter(matchesMarketFilters);
|
|
778
|
-
const count = marketCategory ? filtered.length : items.filter(matchesSearch).length;
|
|
779
|
-
const categoryLabel = CATEGORIES.find((cat) => cat.value === marketCategory)?.label;
|
|
780
|
-
const filterSummary = marketCategory ? ` · 分类「${esc(categoryLabel)}」` : '';
|
|
781
797
|
const resultHtml = !marketCategory
|
|
782
798
|
? groupedMarketHtml(items)
|
|
783
799
|
: filtered.length > 0
|
|
784
800
|
? `<div class="grid">${filtered.map(cardHtml).join('')}</div>`
|
|
785
801
|
: '<div class="empty">没有匹配当前筛选条件的连接器</div>';
|
|
786
|
-
main.innerHTML =
|
|
802
|
+
main.innerHTML = resultHtml;
|
|
787
803
|
if (preserveScroll) main.scrollTop = previousScrollTop;
|
|
788
804
|
if (checkHealth && !initialHealthCheckStarted && items.some((item) => item.connected?.length > 0)) {
|
|
789
805
|
initialHealthCheckStarted = true;
|
|
@@ -831,10 +847,12 @@
|
|
|
831
847
|
}
|
|
832
848
|
|
|
833
849
|
async function loadInstalled() {
|
|
850
|
+
syncMarketNav();
|
|
834
851
|
main.innerHTML = '<div class="empty">加载中…</div>';
|
|
835
852
|
const [r, migration] = await Promise.all([call('status', {}), call('migrationPreview', { scanStored: false })]);
|
|
836
853
|
if (!r.ok) { main.innerHTML = `<div class="empty">${esc(r.message)}</div>`; return; }
|
|
837
854
|
const items = r.detail?.items ?? [];
|
|
855
|
+
setTabCount('installed', items.length);
|
|
838
856
|
const pendingMigration = migration.ok ? migration.detail?.pendingCount || 0 : 0;
|
|
839
857
|
const migrationHtml = pendingMigration > 0 ? `<div class="migration-banner"><div class="copy"><strong>发现旧企查查 MCP 授权</strong>可安全复制 ${pendingMigration} 组授权到 MCP连接器;不会删除旧插件或原凭据。</div><button class="btn" type="button" onclick="window.__mcp.migrateLegacy()">迁移</button></div>` : '';
|
|
840
858
|
if (!items.length) { main.innerHTML = `${migrationHtml}<div class="stats"><span class="count">可从旧企查查 OAuth 插件复制已有授权</span><button class="btn ghost" type="button" onclick="window.__mcp.scanLegacy()">检测旧插件</button></div><div class="empty">还没有连接任何 MCP · 到「市场」里连接一个吧</div>`; return; }
|
|
@@ -1169,6 +1187,12 @@
|
|
|
1169
1187
|
$('#detail-try-btn').textContent = detailNeedsReconfigure
|
|
1170
1188
|
? d.authMode === 'oauth2-pkce' && detailFailureState === 'reauth' ? '🔐 重新授权' : needsCredential && detailFailureState === 'reauth' ? t('reconfigureCredential') : '🔄 重新检查'
|
|
1171
1189
|
: d.connected?.length > 0 ? t('try') : needsCredential ? t('configureConnect') : t('connectTry');
|
|
1190
|
+
if (!d.connected?.length && !d.toolsSnapshot?.length) {
|
|
1191
|
+
$('#tools-summary').textContent = '连接后查看工具';
|
|
1192
|
+
$('#detail-tools').innerHTML = '<div class="tools-empty">连接后可读取服务端工具清单</div>';
|
|
1193
|
+
renderPromptPage();
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1172
1196
|
const toolsResult = await call('toolsList', { connectorId });
|
|
1173
1197
|
if (loadId !== detailLoadId || !$('#detail-overlay').classList.contains('active')) return;
|
|
1174
1198
|
if (!toolsResult.ok) {
|
|
@@ -1329,16 +1353,18 @@
|
|
|
1329
1353
|
function refresh() { return view === 'market' ? loadMarket() : loadInstalled(); }
|
|
1330
1354
|
function syncTabs() {
|
|
1331
1355
|
document.querySelectorAll('#tabs button').forEach((button) => button.classList.toggle('active', button.dataset.view === view));
|
|
1356
|
+
syncMarketNav();
|
|
1332
1357
|
}
|
|
1333
1358
|
|
|
1334
1359
|
$('#add-connection').addEventListener('click', () => openAddConnection('json'));
|
|
1335
|
-
|
|
1360
|
+
$('#market-nav').addEventListener('click', (event) => {
|
|
1336
1361
|
const categoryFilter = event.target.closest('[data-category-filter]');
|
|
1337
1362
|
if (categoryFilter) {
|
|
1338
1363
|
marketCategory = categoryFilter.dataset.categoryFilter || '';
|
|
1339
1364
|
loadMarket({ checkHealth: false });
|
|
1340
|
-
return;
|
|
1341
1365
|
}
|
|
1366
|
+
});
|
|
1367
|
+
main.addEventListener('click', (event) => {
|
|
1342
1368
|
const sectionToggle = event.target.closest('[data-section-toggle]');
|
|
1343
1369
|
if (sectionToggle) {
|
|
1344
1370
|
const section = sectionToggle.dataset.sectionToggle;
|