dsh-m 0.2.8 → 0.2.10

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/lib/host.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import Schema from '@deepseek-ai/schemastery';
3
- import { withMutationLock } from './core/market.js';
4
3
  import { createApiDispatcher } from './core/host-api.js';
5
4
  import { bindLoaderHost } from './core/live-plugin.js';
6
5
  import { createRegistryController } from './core/registry-controller.js';
@@ -36,7 +35,7 @@ export function apply(ctx, config) {
36
35
  // 本地 API:单路由 + method 分发(防护与状态映射在 core/host-api.ts)
37
36
  ctx.inject(['webServer'], (c) => {
38
37
  const server = c.webServer;
39
- const handleApi = createApiDispatcher({ controller, pkg, onMutation: withMutationLock });
38
+ const handleApi = createApiDispatcher({ controller, pkg });
40
39
  server.register({
41
40
  kind: 'exact',
42
41
  path: '/dshm',
package/lib/tools.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { defineTool } from '@deepseek-ai/dsh-tools';
2
2
  import { installTimeoutMs } from './core/env.js';
3
- import { installFromRegistry, listInstalledWithMeta, listMarket, uninstallPlugin, upgradePlugin, withMutationLock, } from './core/market.js';
3
+ import { installFromRegistry, listInstalledWithMeta, listMarket, uninstallPlugin, upgradePlugin, } from './core/market.js';
4
4
  import { scheduleRestart } from './core/restart.js';
5
5
  export const CATEGORY_LABELS = {
6
6
  market: '市场',
@@ -15,18 +15,6 @@ function cloneJson(value) {
15
15
  function summaryOf(state) {
16
16
  return { isDefault: state.isDefault, status: state.status, stale: state.stale };
17
17
  }
18
- function matchInstalledByEntry(entry, installed) {
19
- return installed.find((it) => {
20
- if (entry.npm && (it.pkg === entry.npm || it.name === entry.npm))
21
- return true;
22
- if (entry.github && it.source === 'github') {
23
- const m = /^github:([^#]+)/.exec(it.spec);
24
- if (m && m[1] === entry.github)
25
- return true;
26
- }
27
- return false;
28
- });
29
- }
30
18
  export function registerTools(ctx, cfg, deps = {}) {
31
19
  const timeoutMs = cfg.timeoutMs ?? 20_000;
32
20
  const m = {
@@ -77,18 +65,18 @@ export function registerTools(ctx, cfg, deps = {}) {
77
65
  withLatest: false,
78
66
  namespace: 'host',
79
67
  });
80
- const installed = await import('./core/installed.js');
81
- const inst = await installed.listInstalledPlugins();
82
- const merged = result.items.map((e) => {
83
- const i = matchInstalledByEntry(e, inst.items);
84
- return { ...e, installed: Boolean(i), installedPkg: i?.pkg, installedVersion: i?.version };
85
- });
68
+ // 安装标注唯一来源:listMarket 的单次 profile 快照。
69
+ // 状态不完整且存在可被误标的条目时 fail-closed——不把未知安装状态呈现成未安装;
70
+ // 空结果(registry 不可用/超时/无匹配)无可误标条目,维持优雅空结果。
71
+ if (!result.installedComplete && result.items.length > 0) {
72
+ throw new Error('读取 web profile 安装状态失败,安装标注不可用;请稍后重试');
73
+ }
86
74
  return cloneJson({
87
75
  query: String(args.query || ''),
88
76
  category,
89
77
  total: result.total,
90
78
  registry: summaryOf(result.registryState),
91
- items: merged.map((e) => ({
79
+ items: result.items.map((e) => ({
92
80
  id: e.id,
93
81
  name: e.name,
94
82
  description: e.description,
@@ -163,7 +151,7 @@ export function registerTools(ctx, cfg, deps = {}) {
163
151
  if (!id)
164
152
  throw new Error('缺少收录 id');
165
153
  const version = typeof args.version === 'string' && args.version.trim() ? args.version.trim() : undefined;
166
- return cloneJson(await withMutationLock(() => m.installFromRegistry(id, cfg, { version, namespace: 'host' })));
154
+ return cloneJson(await m.installFromRegistry(id, cfg, { version, namespace: 'host' }));
167
155
  },
168
156
  }));
169
157
  ctx.tools.register(defineTool({
@@ -188,7 +176,7 @@ export function registerTools(ctx, cfg, deps = {}) {
188
176
  const target = String(args.pkg || '').trim();
189
177
  if (!target)
190
178
  throw new Error('缺少 pkg');
191
- return cloneJson(await withMutationLock(() => m.uninstallPlugin(target, cfg, { namespace: 'host' })));
179
+ return cloneJson(await m.uninstallPlugin(target, cfg, { namespace: 'host' }));
192
180
  },
193
181
  }));
194
182
  ctx.tools.register(defineTool({
@@ -247,7 +235,7 @@ export function registerTools(ctx, cfg, deps = {}) {
247
235
  const target = String(args.pkg || '').trim();
248
236
  if (!target)
249
237
  throw new Error('缺少 pkg');
250
- return cloneJson(await withMutationLock(() => m.upgradePlugin(target, cfg, { namespace: 'host' })));
238
+ return cloneJson(await m.upgradePlugin(target, cfg, { namespace: 'host' }));
251
239
  },
252
240
  }));
253
241
  ctx.tools.register(defineTool({
@@ -319,7 +307,10 @@ function renderList(out) {
319
307
  }
320
308
  function renderInstall(out) {
321
309
  const extra = out.usedAllowAllBuilds ? '注意:该插件执行了构建脚本(已按策略放行)。' : '';
322
- return `✅ ${out.pkg} 已安装(${out.spec})。${extra}需要重启 DSH Web 生效——告知用户并询问是否 dshm_restart。不要打印安装命令。`;
310
+ const heals = out.healActions?.length
311
+ ? `安装过程含 ${out.healActions.length} 步自愈(${out.healActions.map((h) => h.code).join('、')})。`
312
+ : '';
313
+ return `✅ ${out.pkg} 已安装(${out.spec})。${extra}${heals}需要重启 DSH Web 生效——告知用户并询问是否 dshm_restart。不要打印安装命令。`;
323
314
  }
324
315
  function renderUninstall(out) {
325
316
  const parts = [`✅ ${out.pkg} 已卸载。`];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-m",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "DSH Marketplace — 个人自用的 DeepSeek Harness 插件市场:收录、安装、卸载、升级 DSH 插件",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,6 +45,7 @@
45
45
  "build": "node scripts/build.mjs",
46
46
  "typecheck": "tsc -p tsconfig.json --noEmit",
47
47
  "test": "node --test tests/*.test.mjs",
48
+ "pretest": "npm run build",
48
49
  "prepare": "npm run build"
49
50
  },
50
51
  "dsh": {
package/registry.json CHANGED
@@ -67,6 +67,39 @@
67
67
  "github": "liustack/modsearch",
68
68
  "homepage": "https://github.com/liustack/modsearch"
69
69
  },
70
+ {
71
+ "id": "dsh-docs-panel",
72
+ "name": "DSH Docs Panel",
73
+ "description": "DSH 侧边栏里的「全局文档」:全局 Markdown 笔记,任何工作区随时可读,支持大纲跳转与一键转编辑器。(需先安装 dsh-better-sidebar ≥0.4.0)",
74
+ "category": "ui",
75
+ "tags": ["文档", "Markdown", "侧边栏", "需 better-sidebar"],
76
+ "source": "npm",
77
+ "npm": "dsh-docs-panel",
78
+ "github": "mlosun/dsh-docs-panel",
79
+ "homepage": "https://github.com/mlosun/dsh-docs-panel"
80
+ },
81
+ {
82
+ "id": "dsh-server-deck",
83
+ "name": "DSH Server Deck",
84
+ "description": "服务器卡片仪表盘:实时状态/CPU/内存/磁盘 + 趋势记录与可视化(1h/24h/7d/30d),点卡片进入 xterm 交互终端。可选集成 dsh-better-sidebar:装后注册为侧边栏「服务器」页签,装载顺序无关。",
85
+ "category": "tools",
86
+ "tags": ["服务器", "监控", "终端", "推荐 better-sidebar"],
87
+ "source": "npm",
88
+ "npm": "dsh-server-deck",
89
+ "github": "meyaomiao/dsh-server-deck",
90
+ "homepage": "https://github.com/meyaomiao/dsh-server-deck"
91
+ },
92
+ {
93
+ "id": "dsh-flowglass",
94
+ "name": "DSH Flowglass",
95
+ "description": "流镜:实时会话流程图插件,把当前会话画成三列泳道,展示工具调用、并行分组与子代理分支,支持逐层钻取。可选集成 dsh-better-sidebar:装后注册为按会话隔离的侧边栏 Tab。",
96
+ "category": "ui",
97
+ "tags": ["可视化", "流程图", "会话", "推荐 better-sidebar"],
98
+ "source": "npm",
99
+ "npm": "dsh-flowglass",
100
+ "github": "Iwctwbh/dsh-flowglass",
101
+ "homepage": "https://github.com/Iwctwbh/dsh-flowglass"
102
+ },
70
103
  {
71
104
  "id": "dsh-auth",
72
105
  "name": "DSH Auth",