dsh-m 0.3.0 → 0.4.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/lib/tools.js CHANGED
@@ -2,6 +2,7 @@ import { defineTool } from '@deepseek-ai/dsh-tools';
2
2
  import { installTimeoutMs } from './core/env.js';
3
3
  import { installFromRegistry, listInstalledWithMeta, listMarket, uninstallPlugin, upgradePlugin, } from './core/market.js';
4
4
  import { appExitFromContext, scheduleRestart } from './core/restart.js';
5
+ import { togglePlugin as coreTogglePlugin } from './core/toggle.js';
5
6
  export const CATEGORY_LABELS = {
6
7
  market: '市场',
7
8
  tools: '工具',
@@ -25,6 +26,9 @@ export function registerTools(ctx, cfg, deps = {}) {
25
26
  upgradePlugin: deps.upgradePlugin ?? upgradePlugin,
26
27
  };
27
28
  const restart = deps.restart ?? ((port = null) => scheduleRestart(port, { appExit: appExitFromContext(ctx) }));
29
+ const toggle = deps.togglePlugin ?? coreTogglePlugin;
30
+ // 开关委派服务探测(ADR-0001):运行时按存在性,不判版本号
31
+ const getService = () => ctx.get?.('pluginManager');
28
32
  ctx.tools.register(defineTool({
29
33
  name: 'dshm_search',
30
34
  description: 'Search your personal 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 their curated DSH plugins (插件). Call EXACTLY ONCE per user message; extract a real keyword (主题, 搜索) rather than pasting the whole sentence. Omit query to browse all listings. After cards appear, reply with AT MOST one short sentence. Do not print install commands.',
@@ -130,10 +134,11 @@ export function registerTools(ctx, cfg, deps = {}) {
130
134
  }));
131
135
  ctx.tools.register(defineTool({
132
136
  name: 'dshm_install',
133
- description: 'Install a plugin from the dsh-m registry into the current web profile after the user names one (装 dsh-skins / 安装 web-search). Pass the id from dshm_search results. npm 源锁定最新精确版本,github 源锁定 commit SHA。Do not print CLI commands. After success, tell the user it needs a restart of dsh web, and offer dshm_restart.',
137
+ description: 'Install a plugin from the dsh-m registry into the current web profile after the user names one (装 dsh-skins / 安装 web-search). Pass the id from dshm_search results. npm 源锁定最新精确版本,github 源锁定 commit SHA。安装前做 peer 兼容预检(只检 @deepseek-ai/dsh(-*);github 源不预检):不兼容时返回结构化结果,向用户说明风险,用户确认后带 force: true 重试(force 等价 forceIncompatible)。Do not print CLI commands. After success, tell the user it needs a restart of dsh web, and offer dshm_restart.',
134
138
  parameters: {
135
139
  id: { type: 'string', required: true, description: '收录 id from dshm_search, e.g. dsh-skins' },
136
140
  version: { type: 'string', description: 'Optional exact semver (npm 源). Default latest.' },
141
+ force: { type: 'boolean', description: '用户已确认兼容风险后重试时置 true(跳过 peer 预检拦截)。' },
137
142
  },
138
143
  output: {
139
144
  schema: { type: 'object', additionalProperties: true },
@@ -152,7 +157,40 @@ export function registerTools(ctx, cfg, deps = {}) {
152
157
  if (!id)
153
158
  throw new Error('缺少收录 id');
154
159
  const version = typeof args.version === 'string' && args.version.trim() ? args.version.trim() : undefined;
155
- return cloneJson(await m.installFromRegistry(id, cfg, { version, namespace: 'host' }));
160
+ const force = args.force === true;
161
+ return cloneJson(await m.installFromRegistry(id, cfg, { version, forceIncompatible: force, namespace: 'host' }));
162
+ },
163
+ }));
164
+ ctx.tools.register(defineTool({
165
+ name: 'dshm_toggle',
166
+ description: 'Toggle a DSH plugin on/off (切换运行状态). Pass pkg from dshm_list and enabled (true=启用 / false=停用). 可逆操作:默认先与用户确认;用户同一句消息已明确表达(如「把 skins 关掉」)可直接执行。结果 applied=live 时告知已即时生效;restart-required 时提示需重启并提供 dshm_restart。受保护插件(dsh-m 自身与官方宿主命脉)会被拒绝。',
167
+ parameters: {
168
+ pkg: { type: 'string', required: true, description: '包名 from dshm_list, e.g. dsh-better-sidebar' },
169
+ enabled: { type: 'boolean', required: true, description: 'true = 启用,false = 停用' },
170
+ },
171
+ output: {
172
+ schema: { type: 'object', additionalProperties: true },
173
+ render: (_args, value) => [{ type: 'text', text: renderToggle(value) }],
174
+ presentationMeta: (_args, value) => ({ kind: 'dshm-toggle', ...value }),
175
+ },
176
+ presentCall: (args) => ({
177
+ card: 'generic',
178
+ title: `${args.enabled === true ? '启用' : '停用'} · ${String(args.pkg || '')}`,
179
+ content: [],
180
+ }),
181
+ presentResult: (_args, { isError, meta }) => ({
182
+ card: 'generic',
183
+ title: isError ? '开关操作失败' : `已${meta?.enabled === true ? '启用' : '停用'} · ${meta?.pkg || ''}`,
184
+ content: [],
185
+ }),
186
+ timeoutMs: 30_000,
187
+ async execute(args) {
188
+ const target = String(args.pkg || '').trim();
189
+ if (!target)
190
+ throw new Error('缺少 pkg');
191
+ if (typeof args.enabled !== 'boolean')
192
+ throw new Error('缺少 enabled(boolean)');
193
+ return cloneJson(await toggle(target, args.enabled, { getService: getService }));
156
194
  },
157
195
  }));
158
196
  ctx.tools.register(defineTool({
@@ -272,11 +310,29 @@ export function registerTools(ctx, cfg, deps = {}) {
272
310
  `Plugin categories: ${Object.entries(CATEGORY_LABELS).map(([k, v]) => `${k}=${v}`).join(', ')}.`,
273
311
  'Install only after the user names a card: dshm_install with its id. Then one short sentence mentioning the restart requirement; offer dshm_restart.',
274
312
  'For installed plugins, call dshm_list / dshm_outdated. Upgrade only after the user confirms which one: dshm_upgrade. Uninstall only after confirmation: dshm_uninstall.',
313
+ 'dshm_toggle switches a plugin on/off: confirm first unless the user already said it in the same message (把 skins 关掉 → execute directly); report live vs restart-required accordingly. ',
275
314
  'dshm_restart only after the user agrees to restart; afterwards tell them to refresh once the page recovers.',
276
315
  ].join(' '),
277
316
  });
278
317
  });
279
318
  }
319
+ /** 开关结果渲染(Task 15)。 */
320
+ function renderToggle(out) {
321
+ const word = out.enabled ? '已启用' : '已停用';
322
+ if (out.applied === 'live') {
323
+ return `✅ ${out.pkg} ${word}(即时生效)。${out.warnings.join(';')}`;
324
+ }
325
+ return `✅ ${out.pkg} ${word}(需重启生效——询问是否 dshm_restart)。${out.warnings.join(';')}`;
326
+ }
327
+ /** 构建放行文案(ADR-0002):列包名;兜底全量放行如实标注。 */
328
+ function buildsNote(out) {
329
+ if (out.fallbackAllBuilds)
330
+ return '注意:该插件执行了构建脚本(名单不可读,已全量兜底放行)。';
331
+ const names = out.buildApprovals ?? [];
332
+ if (names.length === 0)
333
+ return '';
334
+ return `注意:该插件执行了构建脚本,已精确放行:${names.join('、')}。`;
335
+ }
280
336
  function renderSearch(out) {
281
337
  if (!out.items?.length)
282
338
  return '收录清单中没有匹配的插件。对用户只说一句:没找到,可以换个词再搜。不要写长文。';
@@ -307,11 +363,19 @@ function renderList(out) {
307
363
  ].join('\n');
308
364
  }
309
365
  function renderInstall(out) {
310
- const extra = out.usedAllowAllBuilds ? '注意:该插件执行了构建脚本(已按策略放行)。' : '';
366
+ const extra = buildsNote(out);
367
+ const compatNote = out.compat
368
+ ? '注意:该版本与当前 DSH 运行时 peer 不兼容,已按用户确认强制安装。'
369
+ : out.compatSkipped === 'github-source'
370
+ ? '注意:github 源未做兼容预检。'
371
+ : '';
372
+ const bundleNote = out.bundleWarning === 'no-patch-layer'
373
+ ? '注意:该包无补丁层(cordis.patch.yml 缺失且未进 bundles),已装入为纯依赖不会生效;如非预期可卸载(dshm_uninstall)或到收录仓库反馈。'
374
+ : '';
311
375
  const heals = out.healActions?.length
312
376
  ? `安装过程含 ${out.healActions.length} 步自愈(${out.healActions.map((h) => h.code).join('、')})。`
313
377
  : '';
314
- return `✅ ${out.pkg} 已安装(${out.spec})。${extra}${heals}需要重启 DSH Web 生效——告知用户并询问是否 dshm_restart。不要打印安装命令。`;
378
+ return `✅ ${out.pkg} 已安装(${out.spec})。${extra}${compatNote}${bundleNote}${heals}需要重启 DSH Web 生效——告知用户并询问是否 dshm_restart。不要打印安装命令。`;
315
379
  }
316
380
  function renderUninstall(out) {
317
381
  const parts = [`✅ ${out.pkg} 已卸载。`];
@@ -338,7 +402,7 @@ function renderOutdated(out) {
338
402
  function renderUpgrade(out) {
339
403
  const from = out.fromVersion ? `v${out.fromVersion} → ` : '';
340
404
  const to = out.version ? `v${out.version}` : out.sha ? out.sha.slice(0, 7) : '最新';
341
- const extra = out.usedAllowAllBuilds ? '注意:该插件执行了构建脚本。' : '';
405
+ const extra = buildsNote(out);
342
406
  return `✅ ${out.pkg} 已升级(${from}${to})。${extra}需要重启生效——询问是否 dshm_restart。`;
343
407
  }
344
408
  function clamp(n, min, max) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-m",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "可自定义收录清单的 DSH 插件市场:收录、安装、卸载、升级一站完成,附 agent 工具与 dshm CLI。",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -74,9 +74,15 @@
74
74
  "@types/node": "^24.0.0",
75
75
  "@types/react": "^18.3.0",
76
76
  "@types/react-dom": "^18.3.0",
77
+ "@types/semver": "7.8.0",
77
78
  "esbuild": "^0.25.0",
78
79
  "react": "^18.3.1",
79
80
  "react-dom": "^18.3.1",
80
81
  "typescript": "^5.6.0"
82
+ },
83
+ "dependencies": {
84
+ "@deepseek-ai/dsh-atomic-write": "0.1.7-rc.2",
85
+ "semver": "7.8.5",
86
+ "yaml": "2.9.1"
81
87
  }
82
88
  }
package/registry.json CHANGED
@@ -6,7 +6,17 @@
6
6
  "name": "DSH Marketplace",
7
7
  "description": "自定义清单的 DSH 插件市场,收录/安装/卸载/升级;已适配 0.1.2-rc.1、0.1.5-rc.1/rc.2 与 0.1.7-rc.1/rc.2,详见仓库。",
8
8
  "category": "market",
9
- "tags": ["市场", "插件管理"],
9
+ "tags": [
10
+ "市场",
11
+ "插件管理"
12
+ ],
13
+ "verified": [
14
+ "0.1.2-rc.1",
15
+ "0.1.5-rc.1",
16
+ "0.1.5-rc.2",
17
+ "0.1.7-rc.1",
18
+ "0.1.7-rc.2"
19
+ ],
10
20
  "source": "npm",
11
21
  "npm": "dsh-m",
12
22
  "github": "iasiv5/dsh-m",
@@ -17,7 +27,14 @@
17
27
  "name": "DSH Skins",
18
28
  "description": "DSH Web 皮肤插件:多套品牌皮肤侧栏热切换,一键回到官方界面。",
19
29
  "category": "ui",
20
- "tags": ["皮肤", "主题", "美化"],
30
+ "tags": [
31
+ "皮肤",
32
+ "主题",
33
+ "美化"
34
+ ],
35
+ "verified": [
36
+ "0.1.2-rc.1"
37
+ ],
21
38
  "source": "npm",
22
39
  "npm": "@iasiv5/dsh-skins",
23
40
  "github": "iasiv5/dsh-skins",
@@ -26,9 +43,16 @@
26
43
  {
27
44
  "id": "dsh-copilot-auth",
28
45
  "name": "DSH Copilot Auth",
29
- "description": "为内置 Copilot 提供方补设备码登录/注销设置页,预置开箱路由;凭据入内置凭据库,模型目录兜底不覆盖定制。",
46
+ "description": "为内置 Copilot 提供方补登录/注销设置页与开箱路由;模型目录兜底不覆盖定制。适配 0.1.7-rc.2,旧版用 1.1.x。",
30
47
  "category": "tools",
31
- "tags": ["Copilot", "认证", "模型接入"],
48
+ "tags": [
49
+ "Copilot",
50
+ "认证",
51
+ "模型接入"
52
+ ],
53
+ "verified": [
54
+ "0.1.7-rc.2"
55
+ ],
32
56
  "source": "npm",
33
57
  "npm": "@inventec/dsh-copilot-auth",
34
58
  "github": "iasiv5/dsh-copilot-auth",
@@ -37,9 +61,20 @@
37
61
  {
38
62
  "id": "dsh-skip-browser-auth",
39
63
  "name": "DSH Skip Browser Auth",
40
- "description": "替换官方 Connection 提供方跳过 BrowserAuth,免输 Token;已适配 0.1.2-rc.1、0.1.5-rc.1/rc.2 与 0.1.7-rc.1/rc.2,详见仓库。",
64
+ "description": "替换官方 Connection 提供方跳过 BrowserAuth,免输 Token;已适配 0.1.2-rc.1、0.1.5-rc.1/rc.2 与 0.1.7-rc.1/rc.2。",
41
65
  "category": "tools",
42
- "tags": ["BrowserAuth", "连接", "安全"],
66
+ "tags": [
67
+ "BrowserAuth",
68
+ "连接",
69
+ "安全"
70
+ ],
71
+ "verified": [
72
+ "0.1.2-rc.1",
73
+ "0.1.5-rc.1",
74
+ "0.1.5-rc.2",
75
+ "0.1.7-rc.1",
76
+ "0.1.7-rc.2"
77
+ ],
43
78
  "source": "npm",
44
79
  "npm": "@iasiv5/dsh-skip-browser-auth",
45
80
  "github": "iasiv5/dsh-skip-browser-auth",
@@ -50,7 +85,15 @@
50
85
  "name": "DSH Surf",
51
86
  "description": "网络冲浪入口:设置一级菜单一键打开自托管 Selkies/Chrome 远程桌面,视频流直连;需自建容器并挂认证反代。",
52
87
  "category": "tools",
53
- "tags": ["浏览器", "远程桌面", "Selkies", "网络冲浪"],
88
+ "tags": [
89
+ "浏览器",
90
+ "远程桌面",
91
+ "Selkies",
92
+ "网络冲浪"
93
+ ],
94
+ "verified": [
95
+ "0.1.7-rc.2"
96
+ ],
54
97
  "source": "npm",
55
98
  "npm": "@iasiv5/dsh-surf",
56
99
  "github": "iasiv5/dsh-surf",
@@ -61,7 +104,16 @@
61
104
  "name": "DSH OBMC Web",
62
105
  "description": "在 DSH 里打开 OpenBMC 控制台:同源代理走 SSH 隧道,设置面板一键开启,支持 IP 探测与隧道重定向;需 SSH 跳板可达 BMC。",
63
106
  "category": "tools",
64
- "tags": ["OpenBMC", "远程管理", "SSH 隧道", "KVM"],
107
+ "tags": [
108
+ "OpenBMC",
109
+ "远程管理",
110
+ "SSH 隧道",
111
+ "KVM"
112
+ ],
113
+ "verified": [
114
+ "0.1.7-rc.1",
115
+ "0.1.7-rc.2"
116
+ ],
65
117
  "source": "npm",
66
118
  "npm": "@iasiv5/dsh-obmc-web",
67
119
  "github": "iasiv5/dsh-obmc-web",
@@ -72,7 +124,12 @@
72
124
  "name": "DSH Better Sidebar",
73
125
  "description": "开放的侧边栏底座,支持三方拓展注册侧边栏页面;内置文件编辑、终端、侧边对话、Git 与子代理页。",
74
126
  "category": "ui",
75
- "tags": ["侧边栏", "文件编辑", "终端", "Git"],
127
+ "tags": [
128
+ "侧边栏",
129
+ "文件编辑",
130
+ "终端",
131
+ "Git"
132
+ ],
76
133
  "source": "npm",
77
134
  "npm": "dsh-better-sidebar",
78
135
  "github": "omdsh-dev/DSH-better-sidebar",
@@ -83,7 +140,11 @@
83
140
  "name": "ModSearch",
84
141
  "description": "免费网页搜索、X 搜索与页面抓取插件,支持 Firecrawl、Tavily、Exa 等引擎自动故障切换。",
85
142
  "category": "search",
86
- "tags": ["搜索", "网页抓取", "X"],
143
+ "tags": [
144
+ "搜索",
145
+ "网页抓取",
146
+ "X"
147
+ ],
87
148
  "source": "npm",
88
149
  "npm": "@liustack/modsearch",
89
150
  "github": "liustack/modsearch",
@@ -94,7 +155,11 @@
94
155
  "name": "DSH Docs Panel",
95
156
  "description": "侧边栏「全局文档」:全局 Markdown 笔记任何工作区可读,支持大纲跳转与一键转编辑器;需 better-sidebar ≥0.4.0。",
96
157
  "category": "ui",
97
- "tags": ["文档", "Markdown", "侧边栏"],
158
+ "tags": [
159
+ "文档",
160
+ "Markdown",
161
+ "侧边栏"
162
+ ],
98
163
  "source": "npm",
99
164
  "npm": "dsh-docs-panel",
100
165
  "github": "mlosun/dsh-docs-panel",
@@ -105,7 +170,12 @@
105
170
  "name": "DSH Server Deck",
106
171
  "description": "服务器卡片仪表盘:实时 CPU/内存/磁盘与趋势图(1h~30d),点卡片进 xterm 终端;可选集成 better-sidebar。",
107
172
  "category": "tools",
108
- "tags": ["服务器", "监控", "终端", "趋势图"],
173
+ "tags": [
174
+ "服务器",
175
+ "监控",
176
+ "终端",
177
+ "趋势图"
178
+ ],
109
179
  "source": "npm",
110
180
  "npm": "dsh-server-deck",
111
181
  "github": "meyaomiao/dsh-server-deck",
@@ -116,7 +186,11 @@
116
186
  "name": "DSH Flowglass",
117
187
  "description": "流镜:把当前会话画成三列泳道流程图,展示工具调用、并行分组与子代理分支;可选集成 better-sidebar。",
118
188
  "category": "ui",
119
- "tags": ["可视化", "流程图", "会话"],
189
+ "tags": [
190
+ "可视化",
191
+ "流程图",
192
+ "会话"
193
+ ],
120
194
  "source": "npm",
121
195
  "npm": "dsh-flowglass",
122
196
  "github": "Iwctwbh/dsh-flowglass",
@@ -127,7 +201,10 @@
127
201
  "name": "DSH Auth",
128
202
  "description": "DSH Web 管理员认证:Argon2id 口令与可撤销会话,经 Caddy forward_auth 保护页面、API、下载、SSE 与 WebSocket。",
129
203
  "category": "tools",
130
- "tags": ["认证", "安全"],
204
+ "tags": [
205
+ "认证",
206
+ "安全"
207
+ ],
131
208
  "source": "npm",
132
209
  "npm": "dsh-auth",
133
210
  "github": "hxy91819/dsh-auth",
@@ -138,7 +215,11 @@
138
215
  "name": "DeepSeek Harness Lark",
139
216
  "description": "飞书 / Lark 通道插件:把飞书消息桥接进 DeepSeek Harness 对话,支持文本与图片收发。",
140
217
  "category": "other",
141
- "tags": ["飞书", "Lark", "通道"],
218
+ "tags": [
219
+ "飞书",
220
+ "Lark",
221
+ "通道"
222
+ ],
142
223
  "source": "npm",
143
224
  "npm": "deepseek-harness-lark",
144
225
  "github": "sliverp/DeepSeek-harness-lark",
@@ -149,7 +230,10 @@
149
230
  "name": "DeepSeek Harness QQBot",
150
231
  "description": "QQ Bot 通道插件:把 QQ 机器人消息桥接进 DeepSeek Harness 对话,支持文本与图片收发。",
151
232
  "category": "other",
152
- "tags": ["QQ", "通道"],
233
+ "tags": [
234
+ "QQ",
235
+ "通道"
236
+ ],
153
237
  "source": "npm",
154
238
  "npm": "deepseek-harness-qqbot",
155
239
  "github": "sliverp/DeepSeek-harness-qqbot",
@@ -160,7 +244,10 @@
160
244
  "name": "DeepSeek Harness Weixin",
161
245
  "description": "微信通道插件:扫码登录,收发文本与图片消息,桥接进 DeepSeek Harness 对话。",
162
246
  "category": "other",
163
- "tags": ["微信", "通道"],
247
+ "tags": [
248
+ "微信",
249
+ "通道"
250
+ ],
164
251
  "source": "npm",
165
252
  "npm": "deepseek-harness-weixin",
166
253
  "github": "sliverp/DeepSeek-harness-weixin",
@@ -171,7 +258,10 @@
171
258
  "name": "DeepSeek Harness WeCom",
172
259
  "description": "企业微信 AI Bot 通道插件:把企业微信消息桥接进 DeepSeek Harness 对话,支持文本与图片收发。",
173
260
  "category": "other",
174
- "tags": ["企业微信", "通道"],
261
+ "tags": [
262
+ "企业微信",
263
+ "通道"
264
+ ],
175
265
  "source": "npm",
176
266
  "npm": "deepseek-harness-wecom",
177
267
  "github": "sliverp/DeepSeek-harness-wecom",
@@ -182,7 +272,10 @@
182
272
  "name": "DeepSeek Harness DingTalk",
183
273
  "description": "钉钉 Stream 通道插件:把钉钉消息桥接进 DeepSeek Harness 对话,支持文本与图片收发。",
184
274
  "category": "other",
185
- "tags": ["钉钉", "通道"],
275
+ "tags": [
276
+ "钉钉",
277
+ "通道"
278
+ ],
186
279
  "source": "npm",
187
280
  "npm": "deepseek-harness-dingtalk",
188
281
  "github": "sliverp/DeepSeek-harness-dingtalk",
@@ -193,7 +286,11 @@
193
286
  "name": "BrowserSkill",
194
287
  "description": "浏览器自动化:把 BrowserSkill 的 browser_* 工具暴露给模型,让模型在对话中操作浏览器,详见仓库。",
195
288
  "category": "tools",
196
- "tags": ["浏览器", "自动化", "工具调用"],
289
+ "tags": [
290
+ "浏览器",
291
+ "自动化",
292
+ "工具调用"
293
+ ],
197
294
  "source": "npm",
198
295
  "npm": "@wxg-prc-cpg/browser-skill-dsh-plugin",
199
296
  "github": "Tencent/BrowserSkill",
@@ -204,7 +301,11 @@
204
301
  "name": "WeKnora",
205
302
  "description": "知识库检索:把 WeKnora 接入模型,提供语义搜索、文档阅读与 RAG 问答等工具,可用自有知识库,详见仓库。",
206
303
  "category": "tools",
207
- "tags": ["知识库", "RAG", "检索"],
304
+ "tags": [
305
+ "知识库",
306
+ "RAG",
307
+ "检索"
308
+ ],
208
309
  "source": "npm",
209
310
  "npm": "@wxg-prc-cpg/dsh-weknora",
210
311
  "github": "Tencent/WeKnora",
@@ -215,7 +316,12 @@
215
316
  "name": "DSH Chat Manager",
216
317
  "description": "会话管理器:在原生侧边栏搜索归档聊天、恢复会话并安全永久删除;需按内核版本选装,详见仓库。",
217
318
  "category": "tools",
218
- "tags": ["会话管理", "归档", "聊天记录", "恢复"],
319
+ "tags": [
320
+ "会话管理",
321
+ "归档",
322
+ "聊天记录",
323
+ "恢复"
324
+ ],
219
325
  "source": "npm",
220
326
  "npm": "dsh-chat-manager",
221
327
  "github": "WSL043/dsh-chat-manager",