@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 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 plugin = marketCache.all?.plugins.find((p) => p.spec === item.name || p.name === item.name);
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
- plugin !== void 0 && plugin.stars !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pc-ver", children: [
1133
+ item.stars != null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "pc-ver", children: [
1135
1134
  "\u2605 ",
1136
- plugin.stars
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 (plugin === void 0) {
1144
- showToast(t("installFailed", { e: "\u672A\u5728\u5E02\u573A\u76EE\u5F55\u4E2D\u627E\u5230\u8BE5\u63D2\u4EF6\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5" }), "error", 8e3);
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: plugin.spec }).then(
1146
+ void rpc("install", { spec: item.spec }).then(
1148
1147
  () => {
1149
- pendingInstall.add(plugin.spec);
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 代码块):[{"name":"插件名","reason":"一句话中文推荐理由"}]';
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: [{ role: 'user', content: `用户需求:${q}\n\n候选插件列表(名称 | 星标 | 简介):\n${list}` }],
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
- maxTokens: 800,
385
- signal: AbortSignal.timeout(40000),
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
- throw new Error(`模型输出无法解析:${text.slice(0, 200)}`);
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: name, // npm package name is the install 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
- "name": "@max-null/dsh-plugin-center",
3
- "version": "0.2.0",
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 && 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
- }
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
+ }