@max-null/dsh-plugin-center 0.2.0 → 0.2.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/client.js +7 -8
- package/dist/engine.d.ts +4 -0
- package/dist/engine.js +39 -9
- package/dist/market.js +22 -1
- package/package.json +85 -85
package/client.js
CHANGED
|
@@ -1125,28 +1125,27 @@ function CenterPanel({ variant = "section" }) {
|
|
|
1125
1125
|
] }),
|
|
1126
1126
|
aiError !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "pc-sub", style: { color: "var(--dsw-alias-state-error-primary)" }, children: t("aiFail", { e: aiError }) }),
|
|
1127
1127
|
aiResult !== null && aiResult.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pc-grid single", children: aiResult.map((item) => {
|
|
1128
|
-
const
|
|
1129
|
-
const installed = plugin?.installed === true || (installedCache ?? []).some((p) => p.name === item.name);
|
|
1128
|
+
const installed = (installedCache ?? []).some((p) => p.name === item.name || p.spec === item.spec || p.name === item.spec);
|
|
1130
1129
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-card", children: [
|
|
1131
1130
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pc-row", children: [
|
|
1132
1131
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-name", children: item.name }),
|
|
1133
1132
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-spacer" }),
|
|
1134
|
-
|
|
1133
|
+
item.stars != null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pc-ver", children: [
|
|
1135
1134
|
"\u2605 ",
|
|
1136
|
-
|
|
1135
|
+
item.stars
|
|
1137
1136
|
] }),
|
|
1138
1137
|
installed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pc-tag", children: t("installedTag") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1139
1138
|
"button",
|
|
1140
1139
|
{
|
|
1141
1140
|
className: "pc-btn primary",
|
|
1142
1141
|
onClick: () => {
|
|
1143
|
-
if (
|
|
1144
|
-
showToast(t("installFailed", { e: "\u672A\
|
|
1142
|
+
if (item.spec === void 0 || item.spec === null || item.spec === "") {
|
|
1143
|
+
showToast(t("installFailed", { e: "\u672A\u627E\u5230\u8BE5\u63D2\u4EF6\u7684\u5B89\u88C5 spec" }), "error", 8e3);
|
|
1145
1144
|
return;
|
|
1146
1145
|
}
|
|
1147
|
-
void rpc("install", { spec:
|
|
1146
|
+
void rpc("install", { spec: item.spec }).then(
|
|
1148
1147
|
() => {
|
|
1149
|
-
pendingInstall.add(
|
|
1148
|
+
pendingInstall.add(item.spec);
|
|
1150
1149
|
showToast(t("installQueued", { n: item.name }), "ok", 5e3);
|
|
1151
1150
|
},
|
|
1152
1151
|
(e) => showToast(t("installFailed", { e: e instanceof Error ? e.message : String(e) }), "error", 15e3)
|
package/dist/engine.d.ts
CHANGED
|
@@ -26,6 +26,10 @@ export interface MarketSnapshot {
|
|
|
26
26
|
export interface Suggestion {
|
|
27
27
|
name: string;
|
|
28
28
|
reason: string;
|
|
29
|
+
/** Install spec resolved at suggest time (npm name or github:owner/repo). */
|
|
30
|
+
spec: string | null;
|
|
31
|
+
/** GitHub stars when the catalog knows them. */
|
|
32
|
+
stars: number | null;
|
|
29
33
|
}
|
|
30
34
|
/** One-shot diagnostics report (diagnostics). */
|
|
31
35
|
export interface DiagnosticsReport {
|
package/dist/engine.js
CHANGED
|
@@ -375,25 +375,40 @@ export class PluginCenterEngine extends Service {
|
|
|
375
375
|
if (scored.length === 0)
|
|
376
376
|
return [];
|
|
377
377
|
const list = scored.map(({ p }) => `- ${p.name} | ${p.stars ?? 0}★ | ${p.description.zh.slice(0, 60)}`).join('\n');
|
|
378
|
-
const system = '你是 DeepSeek Harness 插件市场的推荐助手。根据用户需求从候选插件中选择 3-5 个最合适的,只输出一个 JSON 数组(不要 markdown
|
|
378
|
+
const system = '你是 DeepSeek Harness 插件市场的推荐助手。根据用户需求从候选插件中选择 3-5 个最合适的,只输出一个 JSON 数组(不要 markdown 代码块、不要任何多余文字):[{"name":"插件名","reason":"一句话中文推荐理由(20 字以内)"}]';
|
|
379
|
+
// Message 契约:content 是 ContentBlock 数组(非字符串),且需要 id/source。
|
|
379
380
|
const chunks = llm.stream({
|
|
380
381
|
provider: 'deepseek-official',
|
|
381
382
|
model: 'deepseek-v4-flash',
|
|
382
|
-
messages: [{
|
|
383
|
+
messages: [{
|
|
384
|
+
id: 'plugin-center-suggest',
|
|
385
|
+
role: 'user',
|
|
386
|
+
content: [{ type: 'text', text: `用户需求:${q}\n\n候选插件列表(名称 | 星标 | 简介):\n${list}` }],
|
|
387
|
+
source: { kind: 'plugin', plugin: 'dsh-plugin-center' },
|
|
388
|
+
}],
|
|
383
389
|
system,
|
|
384
|
-
|
|
385
|
-
|
|
390
|
+
// 800 会把 3-5 条中文推荐截断成不完整 JSON(2026-08-22 实测
|
|
391
|
+
// "模型输出无法解析" + 截断的 JSON 片段);2000 留足余量。
|
|
392
|
+
maxTokens: 2000,
|
|
393
|
+
signal: AbortSignal.timeout(90000),
|
|
386
394
|
});
|
|
387
395
|
let text = '';
|
|
388
396
|
let failed = false;
|
|
397
|
+
let failureDetail = '';
|
|
389
398
|
for await (const chunk of chunks) {
|
|
390
399
|
if (chunk.type === 'text-delta')
|
|
391
400
|
text += chunk.text ?? '';
|
|
392
|
-
else if (chunk.type === 'finish' && (chunk.reason?.kind === 'error' || chunk.reason?.kind === 'aborted'))
|
|
401
|
+
else if (chunk.type === 'finish' && (chunk.reason?.kind === 'error' || chunk.reason?.kind === 'aborted')) {
|
|
393
402
|
failed = true;
|
|
403
|
+
// LlmFailure { code, message }——必须透出,否则用户只看到笼统的
|
|
404
|
+
// "模型推荐失败"而无法诊断(2026-08-22 实测空 text + 无详情)。
|
|
405
|
+
const f = chunk.reason.failure;
|
|
406
|
+
failureDetail = f ? `${f.code ?? 'unknown'}: ${f.message ?? ''}` : chunk.reason.kind;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (failed || text.trim() === '') {
|
|
410
|
+
throw new Error(`模型推荐失败,请重试${failureDetail !== '' ? `(${failureDetail.slice(0, 200)})` : text === '' ? '' : `(模型返回:${text.slice(0, 80)})`}`);
|
|
394
411
|
}
|
|
395
|
-
if (failed || text.trim() === '')
|
|
396
|
-
throw new Error('模型推荐失败,请重试');
|
|
397
412
|
const start = text.indexOf('[');
|
|
398
413
|
const end = text.lastIndexOf(']');
|
|
399
414
|
if (start < 0 || end <= start)
|
|
@@ -402,14 +417,29 @@ export class PluginCenterEngine extends Service {
|
|
|
402
417
|
const parsed = JSON.parse(text.slice(start, end + 1));
|
|
403
418
|
if (!Array.isArray(parsed))
|
|
404
419
|
throw new Error('bad shape');
|
|
420
|
+
// Attach the catalog identity (spec/stars) here, so the client never
|
|
421
|
+
// has to reverse-match by name — the model may echo either the npm
|
|
422
|
+
// name or the owner/repo form (2026-08-22: stars went missing because
|
|
423
|
+
// "Deepseek-Harness-EAC" (npm) did not match the cache key
|
|
424
|
+
// "zouyuxuan122/Deepseek-Harness-EAC").
|
|
405
425
|
return parsed
|
|
406
426
|
.filter((item) => item !== null && typeof item === 'object'
|
|
407
427
|
&& typeof item.name === 'string'
|
|
408
428
|
&& typeof item.reason === 'string')
|
|
409
|
-
.slice(0, 5)
|
|
429
|
+
.slice(0, 5)
|
|
430
|
+
.map(item => {
|
|
431
|
+
const hit = this.dshMarketCache.find(p => p.name === item.name || p.spec === item.name || p.npm === item.name);
|
|
432
|
+
return {
|
|
433
|
+
name: item.name,
|
|
434
|
+
reason: item.reason,
|
|
435
|
+
spec: hit?.spec ?? null,
|
|
436
|
+
stars: hit?.stars ?? null,
|
|
437
|
+
};
|
|
438
|
+
});
|
|
410
439
|
}
|
|
411
440
|
catch {
|
|
412
|
-
|
|
441
|
+
// 截断的 JSON(maxTokens 用尽/中止)会解析失败——展示更长片段辅助诊断。
|
|
442
|
+
throw new Error(`模型输出无法解析:${text.slice(0, 400)}`);
|
|
413
443
|
}
|
|
414
444
|
}
|
|
415
445
|
/** Wait for the dsh-market catalog (fetch or failure), with a hard deadline. */
|
package/dist/market.js
CHANGED
|
@@ -59,6 +59,22 @@ export async function fetchOhMyDshOverrides() {
|
|
|
59
59
|
return {};
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Derive an install spec for a dsh-market entry: a reliable single command
|
|
64
|
+
* parsed from the README (`dsh plugin add <spec>` / `pnpm add <spec>` /
|
|
65
|
+
* `git clone`) yields its package/spec; anything else falls back to the
|
|
66
|
+
* GitHub form (`github:owner/repo`), which dsh always accepts — many
|
|
67
|
+
* catalog entries are NOT on npm (e.g. Deepseek-Harness-EAC 404, 2026-08-22).
|
|
68
|
+
*/
|
|
69
|
+
function installSpecOf(p, name, full) {
|
|
70
|
+
const cmd = (p.install?.commands ?? []).find(c => /\b(?:dsh\s+plugin\s+add|pnpm\s+add|npm\s+install|git\s+clone)\b/u.test(c));
|
|
71
|
+
if (cmd !== undefined) {
|
|
72
|
+
const match = /\b(?:add|install)\s+([^\s"'`]+)/u.exec(cmd);
|
|
73
|
+
if (match !== null && !/<[^>]+>/u.test(match[1]))
|
|
74
|
+
return match[1];
|
|
75
|
+
}
|
|
76
|
+
return `github:${full}`;
|
|
77
|
+
}
|
|
62
78
|
/** Category keywords for dsh-market tag → CATEGORIES mapping (prefix match). */
|
|
63
79
|
const CATEGORY_KEYWORDS = [
|
|
64
80
|
['ui', ['ui', 'interface', 'sidebar', 'panel', 'widget', '界面', '面板', '侧栏', '导航']],
|
|
@@ -101,6 +117,11 @@ export async function fetchDshMarketPlugins() {
|
|
|
101
117
|
const json = await res.json();
|
|
102
118
|
const out = [];
|
|
103
119
|
for (const p of json.plugins ?? []) {
|
|
120
|
+
// Skill entries install into ~/.agents/skills via a different mechanism
|
|
121
|
+
// (npx skills add); the pnpm-driven center cannot install them, so they
|
|
122
|
+
// are excluded from the catalog rather than offered with a broken spec.
|
|
123
|
+
if (p.type === 'skill' || p.install?.method === 'skills-add')
|
|
124
|
+
continue;
|
|
104
125
|
const name = typeof p.name === 'string' && p.name !== '' ? p.name : '';
|
|
105
126
|
const full = typeof p.fullName === 'string' && p.fullName !== '' ? p.fullName : name;
|
|
106
127
|
if (full === '')
|
|
@@ -111,7 +132,7 @@ export async function fetchDshMarketPlugins() {
|
|
|
111
132
|
// Merge key / display name: owner/repo (matches the awesome source).
|
|
112
133
|
name: full,
|
|
113
134
|
url: `https://github.com/${full}`,
|
|
114
|
-
spec:
|
|
135
|
+
spec: installSpecOf(p, name, full),
|
|
115
136
|
categories: categorizeTags(p.tags),
|
|
116
137
|
description: { en: descEn, zh: descZh },
|
|
117
138
|
stars: typeof p.stars === 'number' ? p.stars : null,
|
package/package.json
CHANGED
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@max-null/dsh-plugin-center",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Plugin center for DeepSeek Harness — installed metadata, community market, update detection, and What's New",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./client": "./client.js",
|
|
18
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
19
|
+
"./package.json": "./package.json"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"client.js",
|
|
24
|
+
"cordis.patch.yml",
|
|
25
|
+
"assets"
|
|
26
|
+
],
|
|
27
|
+
"dsh": {
|
|
28
|
+
"bundle": {
|
|
29
|
+
"patch": "./cordis.patch.yml"
|
|
30
|
+
},
|
|
31
|
+
"client": {
|
|
32
|
+
"inject": [
|
|
33
|
+
"@deepseek-ai/dsh-client-connection",
|
|
34
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
35
|
+
"@deepseek-ai/dsh-client-locale",
|
|
36
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
37
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
38
|
+
"@deepseek-ai/dsh-client-ui-slots",
|
|
39
|
+
"@deepseek-ai/dsh-api-remotes"
|
|
40
|
+
],
|
|
41
|
+
"platform": "web",
|
|
42
|
+
"immediately": true
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"deepseek",
|
|
47
|
+
"harness",
|
|
48
|
+
"dsh",
|
|
49
|
+
"dsh-plugin",
|
|
50
|
+
"deepseek-harness",
|
|
51
|
+
"plugin",
|
|
52
|
+
"market",
|
|
53
|
+
"update",
|
|
54
|
+
"cordis"
|
|
55
|
+
],
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/Max-Null/dsh-plugin-center.git"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsc -p tsconfig.json \u0026\u0026 node build-client.mjs",
|
|
62
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"js-yaml": "^4.1.0"
|
|
66
|
+
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
69
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.2",
|
|
70
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.1-rc.1",
|
|
71
|
+
"@deepseek-ai/dsh-host-apiproxy": "^0.1.1-rc.1"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
75
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.2",
|
|
76
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.1-rc.1",
|
|
77
|
+
"@deepseek-ai/dsh-host-apiproxy": "^0.1.1-rc.1",
|
|
78
|
+
"@types/js-yaml": "^4.0.9",
|
|
79
|
+
"@types/node": "^26.2.0",
|
|
80
|
+
"@types/react": "~18.3.1",
|
|
81
|
+
"esbuild": "^0.24.0",
|
|
82
|
+
"react": "^18.2.0",
|
|
83
|
+
"typescript": "^5.5.0"
|
|
84
|
+
}
|
|
85
|
+
}
|