dsh-m 0.6.1 → 0.8.4
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 +79 -10
- package/README.md +78 -9
- package/docs/DESIGN.md +27 -4
- package/lib/cli.js +39 -8
- package/lib/client.js +1728 -471
- package/lib/core/community-adapter.js +16 -0
- package/lib/core/community.js +3 -2
- package/lib/core/host-api.js +39 -5
- package/lib/core/market.js +141 -24
- package/lib/core/registry-controller.js +27 -0
- package/lib/core/search-relevance.js +110 -0
- package/lib/tools.js +44 -9
- package/package.json +2 -2
- package/registry.json +23 -4
package/lib/tools.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
2
2
|
import { installTimeoutMs } from './core/env.js';
|
|
3
3
|
import { installFromRegistry, listInstalledWithMeta, listMarket, uninstallPlugin, upgradePlugin, InstallGuardError, } from './core/market.js';
|
|
4
|
+
import { COMMUNITY_CATEGORY_LABELS } from './core/community.js';
|
|
4
5
|
import { appExitFromContext, scheduleRestart } from './core/restart.js';
|
|
5
6
|
import { togglePlugin as coreTogglePlugin } from './core/toggle.js';
|
|
6
7
|
export const CATEGORY_LABELS = {
|
|
@@ -10,6 +11,12 @@ export const CATEGORY_LABELS = {
|
|
|
10
11
|
search: '搜索',
|
|
11
12
|
other: '其他',
|
|
12
13
|
};
|
|
14
|
+
/** 分类中文标签(0.7.0 Task 5):精选 5 类 + 社区已知标签(单一事实源 COMMUNITY_CATEGORY_LABELS);未知 slug 原样。 */
|
|
15
|
+
function categoryLabelOf(category) {
|
|
16
|
+
return (CATEGORY_LABELS[category] ??
|
|
17
|
+
COMMUNITY_CATEGORY_LABELS[category] ??
|
|
18
|
+
category);
|
|
19
|
+
}
|
|
13
20
|
/** 工具 deadline 对齐(M1 Task 7):search 45s(core 44s)、list/outdated 65s(core 60s + 5s 回包余量)。 */
|
|
14
21
|
const SEARCH_TOOL_TIMEOUT_MS = 45_000;
|
|
15
22
|
const SEARCH_CORE_DEADLINE_MS = 44_000;
|
|
@@ -63,15 +70,19 @@ export function registerTools(ctx, cfg, deps = {}) {
|
|
|
63
70
|
const getService = () => ctx.get?.('pluginManager');
|
|
64
71
|
ctx.tools.register(defineTool({
|
|
65
72
|
name: 'dshm_search',
|
|
66
|
-
description: 'Search
|
|
73
|
+
description: 'Search the DSH plugin marketplace (dsh-m) and show clickable plugin cards. ALWAYS call this instead of web_search or bash when the user wants to find/recommend/browse DSH plugins (插件). Call EXACTLY ONCE per user message; extract a real keyword (主题, 搜索) rather than pasting the whole sentence. Dual catalog: ~22 hand-curated 精选 entries plus a 4,000+ community catalog — default searches all; pass source="community" or "primary" to zone in. Returns 10 cards by default; use offset (take nextOffset from the result) for more batches. After cards appear, reply with AT MOST one short sentence. Do not print install commands.',
|
|
67
74
|
parameters: {
|
|
68
|
-
query: { type: 'string', description: 'Main keyword, e.g. 主题 or 搜索. Optional.' },
|
|
75
|
+
query: { type: 'string', description: 'Main keyword, e.g. 主题 or 搜索. Optional; omit to browse.' },
|
|
69
76
|
category: {
|
|
70
77
|
type: 'string',
|
|
71
78
|
description: `Optional category: curated ${Object.keys(CATEGORY_LABELS).join('/')} or any community slug ([a-z0-9-]{1,32}, e.g. theme/memory/git).`,
|
|
72
79
|
},
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
source: {
|
|
81
|
+
type: 'string',
|
|
82
|
+
description: 'Zone filter: "community" (4,000+ community catalog), "primary" (hand-curated 精选), or "all" (default).',
|
|
83
|
+
},
|
|
84
|
+
limit: { type: 'number', description: 'Cards in this batch. Default 10, clamp 1-80.' },
|
|
85
|
+
offset: { type: 'number', description: 'Pagination offset (0-based). Pass nextOffset from the previous result to fetch the next batch.' },
|
|
75
86
|
},
|
|
76
87
|
output: {
|
|
77
88
|
schema: { type: 'object', additionalProperties: true },
|
|
@@ -80,7 +91,7 @@ export function registerTools(ctx, cfg, deps = {}) {
|
|
|
80
91
|
},
|
|
81
92
|
presentCall: (args) => ({
|
|
82
93
|
card: 'generic',
|
|
83
|
-
title: `DSH 市场 · ${String(args.query || args.category || '浏览')}`,
|
|
94
|
+
title: `DSH 市场 · ${String(args.query || args.category || (args.source && args.source !== 'all' ? args.source : '') || '浏览')}`,
|
|
84
95
|
kind: 'search',
|
|
85
96
|
content: [],
|
|
86
97
|
}),
|
|
@@ -99,16 +110,24 @@ export function registerTools(ctx, cfg, deps = {}) {
|
|
|
99
110
|
else
|
|
100
111
|
throw new Error(`非法分类: ${categoryRaw}(需精选分类或 [a-z0-9-]{1,32} slug)`);
|
|
101
112
|
}
|
|
113
|
+
// 分区参数(0.7.0 Task 5):与 GUI 分区对齐;primary_only 已删除(D6a 允许破坏性变更)
|
|
114
|
+
const sourceRaw = typeof args.source === 'string' ? args.source.trim() : '';
|
|
115
|
+
if (sourceRaw !== '' && sourceRaw !== 'primary' && sourceRaw !== 'community' && sourceRaw !== 'all') {
|
|
116
|
+
throw new Error(`非法 source: ${sourceRaw}(需 primary/community/all)`);
|
|
117
|
+
}
|
|
118
|
+
const source = sourceRaw === '' ? 'all' : sourceRaw;
|
|
102
119
|
const rawLimit = Number(args.limit);
|
|
103
|
-
const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? clamp(rawLimit, 1, 80) :
|
|
120
|
+
const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? clamp(rawLimit, 1, 80) : 10;
|
|
121
|
+
const rawOffset = Number(args.offset);
|
|
122
|
+
const offset = Number.isFinite(rawOffset) && rawOffset > 0 ? Math.floor(rawOffset) : 0;
|
|
104
123
|
// metadata-only:agent 卡片不需要 latest;与 Host GUI 共用 host namespace;
|
|
105
124
|
// deadline 44s 是本 waiter 的绝对上限(工具 timeout 45s 先到兜底)
|
|
106
125
|
const result = await m.listMarket(cfg, {
|
|
107
126
|
query: String(args.query || ''),
|
|
108
127
|
category,
|
|
109
|
-
|
|
128
|
+
source,
|
|
129
|
+
offset,
|
|
110
130
|
limit,
|
|
111
|
-
primaryOnly: args.primary_only === true,
|
|
112
131
|
withLatest: false,
|
|
113
132
|
namespace: 'host',
|
|
114
133
|
deadlineMs: SEARCH_CORE_DEADLINE_MS,
|
|
@@ -120,9 +139,14 @@ export function registerTools(ctx, cfg, deps = {}) {
|
|
|
120
139
|
if (!result.installedComplete && result.items.length > 0) {
|
|
121
140
|
throw new Error('读取 web profile 安装状态失败,安装标注不可用;请稍后重试');
|
|
122
141
|
}
|
|
142
|
+
const shown = result.items.length;
|
|
143
|
+
const nextOffset = offset + shown < result.total ? offset + shown : null;
|
|
123
144
|
return cloneJson({
|
|
124
145
|
query: String(args.query || ''),
|
|
125
146
|
category,
|
|
147
|
+
source,
|
|
148
|
+
offset,
|
|
149
|
+
nextOffset,
|
|
126
150
|
total: result.total,
|
|
127
151
|
registry: summaryOf(result.registryState),
|
|
128
152
|
community: communityToolSummary(result.community),
|
|
@@ -131,6 +155,7 @@ export function registerTools(ctx, cfg, deps = {}) {
|
|
|
131
155
|
name: e.name,
|
|
132
156
|
description: e.description,
|
|
133
157
|
category: e.category,
|
|
158
|
+
categoryLabel: categoryLabelOf(e.category),
|
|
134
159
|
tags: e.tags,
|
|
135
160
|
source: e.source,
|
|
136
161
|
npm: e.npm,
|
|
@@ -139,6 +164,9 @@ export function registerTools(ctx, cfg, deps = {}) {
|
|
|
139
164
|
installed: e.installed,
|
|
140
165
|
installedPkg: e.installedPkg,
|
|
141
166
|
installedVersion: e.installedVersion,
|
|
167
|
+
community: e.community === true,
|
|
168
|
+
downloads: e.downloads ?? null,
|
|
169
|
+
stars: e.stars ?? null,
|
|
142
170
|
})),
|
|
143
171
|
});
|
|
144
172
|
},
|
|
@@ -427,13 +455,20 @@ function buildsNote(out) {
|
|
|
427
455
|
function renderSearch(out) {
|
|
428
456
|
if (!out.items?.length)
|
|
429
457
|
return '收录清单中没有匹配的插件。对用户只说一句:没找到,可以换个词再搜。不要写长文。';
|
|
458
|
+
const offset = out.offset ?? 0;
|
|
430
459
|
const lines = out.items.map((it, i) => {
|
|
431
460
|
const inst = it.installed ? `(已安装 v${it.installedVersion || '?'})` : '';
|
|
432
|
-
|
|
461
|
+
const zone = it.community === true ? '[社区]' : '';
|
|
462
|
+
return `${i + 1}. ${it.name} · ${it.id}${zone}${inst} · ${it.categoryLabel || it.category}`;
|
|
433
463
|
});
|
|
464
|
+
// 翻页尾行(0.7.0 Task 5):nextOffset 为空 = 已到末尾
|
|
465
|
+
const pager = typeof out.nextOffset === 'number'
|
|
466
|
+
? `共 ${out.total ?? out.items.length} 条 · 已显示 ${offset + 1}–${offset + out.items.length} · 传 offset=${out.nextOffset} 翻页`
|
|
467
|
+
: `共 ${out.total ?? out.items.length} 条 · 已到末尾`;
|
|
434
468
|
return [
|
|
435
469
|
`插件卡片已展示 ${out.items.length}${out.total && out.total > out.items.length ? `/${out.total}` : ''} 条(内部序号,禁止复述给用户):`,
|
|
436
470
|
lines.join('\n'),
|
|
471
|
+
pager,
|
|
437
472
|
'对用户最多回一句短话。禁止清单和长文。用户点名安装时才调 dshm_install(id)。',
|
|
438
473
|
].join('\n');
|
|
439
474
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-m",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"description": "可自定义收录清单的 DSH 插件市场:收录、安装、卸载、升级一站完成,附 agent 工具与 dshm CLI。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"@deepseek-ai/cordis": "*",
|
|
66
|
-
"@deepseek-ai/dsh-tools": "
|
|
66
|
+
"@deepseek-ai/dsh-tools": "^0.1.7-rc.2 || ^0.2.0-rc.1 || >=0.2.0",
|
|
67
67
|
"@deepseek-ai/schemastery": "*",
|
|
68
68
|
"react": "^18.2.0"
|
|
69
69
|
},
|
package/registry.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
{
|
|
5
5
|
"id": "dsh-m",
|
|
6
6
|
"name": "DSH Marketplace",
|
|
7
|
-
"description": "自定义清单的 DSH 插件市场,收录/安装/卸载/升级;已适配 0.1.5-rc.1 至 0.2.0-rc.1 各代,详见仓库。",
|
|
7
|
+
"description": "自定义清单的 DSH 插件市场,收录/安装/卸载/升级;已适配 0.1.5-rc.1 至 0.2.0-rc.1/rc.2 各代,详见仓库。",
|
|
8
8
|
"category": "market",
|
|
9
9
|
"tags": [
|
|
10
10
|
"市场",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"0.1.5-rc.2",
|
|
17
17
|
"0.1.7-rc.1",
|
|
18
18
|
"0.1.7-rc.2",
|
|
19
|
-
"0.2.0-rc.1"
|
|
19
|
+
"0.2.0-rc.1",
|
|
20
|
+
"0.2.0-rc.2"
|
|
20
21
|
],
|
|
21
22
|
"source": "npm",
|
|
22
23
|
"npm": "dsh-m",
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
{
|
|
66
67
|
"id": "dsh-skip-browser-auth",
|
|
67
68
|
"name": "DSH Skip Browser Auth",
|
|
68
|
-
"description": "替换官方 Connection
|
|
69
|
+
"description": "替换官方 Connection 跳过 BrowserAuth,免 Token;已适配 0.1.2-rc.1、0.1.5-rc.1/rc.2、0.1.7-rc.1/rc.2 与 0.2.0-rc.1/rc.2。",
|
|
69
70
|
"category": "tools",
|
|
70
71
|
"tags": [
|
|
71
72
|
"BrowserAuth",
|
|
@@ -77,7 +78,9 @@
|
|
|
77
78
|
"0.1.5-rc.1",
|
|
78
79
|
"0.1.5-rc.2",
|
|
79
80
|
"0.1.7-rc.1",
|
|
80
|
-
"0.1.7-rc.2"
|
|
81
|
+
"0.1.7-rc.2",
|
|
82
|
+
"0.2.0-rc.1",
|
|
83
|
+
"0.2.0-rc.2"
|
|
81
84
|
],
|
|
82
85
|
"source": "npm",
|
|
83
86
|
"npm": "@iasiv5/dsh-skip-browser-auth",
|
|
@@ -367,6 +370,22 @@
|
|
|
367
370
|
"npm": "dsh-chat-manager",
|
|
368
371
|
"github": "WSL043/dsh-chat-manager",
|
|
369
372
|
"homepage": "https://github.com/WSL043/dsh-chat-manager"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"id": "dsh-context",
|
|
376
|
+
"name": "DSH Context",
|
|
377
|
+
"description": "上下文透视:Context 仪表盘、侧栏面板与 /context 命令,查看上下文组成、演进趋势与压缩剪枝等事件,支持跨会话用量统计。",
|
|
378
|
+
"category": "ui",
|
|
379
|
+
"tags": [
|
|
380
|
+
"上下文",
|
|
381
|
+
"Token 统计",
|
|
382
|
+
"可视化",
|
|
383
|
+
"仪表盘"
|
|
384
|
+
],
|
|
385
|
+
"source": "npm",
|
|
386
|
+
"npm": "dsh-context",
|
|
387
|
+
"github": "bowenliang123/dsh-context",
|
|
388
|
+
"homepage": "https://github.com/bowenliang123/dsh-context"
|
|
370
389
|
}
|
|
371
390
|
]
|
|
372
391
|
}
|