dsh-plugin-tool-management 0.20.2 → 0.21.0

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +60 -1
  2. package/README.md +4 -1
  3. package/README_EN.md +4 -1
  4. package/docs/update.md +3 -1
  5. package/lib/client.js +225 -54
  6. package/lib/compat/capability-specs.js +60 -1
  7. package/lib/compat/host-contracts.js +72 -0
  8. package/lib/compat/host-probe.js +59 -0
  9. package/lib/compat/host-roots.js +1 -1
  10. package/lib/compat/probe.js +84 -13
  11. package/lib/context-inject-frame.js +134 -26
  12. package/lib/context-inject.js +12 -9
  13. package/lib/http-api.js +3 -2
  14. package/lib/http-fence.js +26 -1
  15. package/lib/index.js +5 -2
  16. package/lib/mcp/manager.js +6 -1
  17. package/lib/mcp/state-section.js +75 -34
  18. package/lib/memories/constants.js +39 -7
  19. package/lib/memories/projection.js +18 -18
  20. package/lib/memories/service.js +8 -7
  21. package/lib/memories/snapshot.js +27 -17
  22. package/lib/ops/compat.js +64 -2
  23. package/lib/ops/memory.js +2 -2
  24. package/lib/ops/prompts.js +30 -2
  25. package/lib/request-gate.js +5 -4
  26. package/lib/skills/catalog.js +2 -2
  27. package/lib/subagents/catalog.js +4 -4
  28. package/lib/subagents/child-preset.js +120 -0
  29. package/lib/subagents/persona-parse.js +9 -9
  30. package/lib/subagents/run-provider.js +218 -62
  31. package/lib/subagents/tool-filter.js +12 -12
  32. package/lib/subagents/tools.js +29 -22
  33. package/lib/tools/deps.js +4 -4
  34. package/lib/tools/mcp.js +34 -34
  35. package/lib/tools/memory.js +34 -34
  36. package/lib/tools/prompt.js +5 -5
  37. package/lib/tools/remove.js +17 -17
  38. package/lib/tools/scene.js +66 -66
  39. package/lib/tools/skills.js +21 -21
  40. package/lib/tools/subagent.js +13 -13
  41. package/lib/tools/table.js +2 -2
  42. package/package.json +25 -24
@@ -16,7 +16,7 @@ export function buildSkillTools(deps) {
16
16
  // (2026-10-15 注入文本审查):可行动的那半句已经写在 `skill_manager_read` 的描述里
17
17
  // ("Not sent when the official `skill` tool is mounted — use that instead."),
18
18
  // 这里再预告一遍同一个条件,只是同一件事付两次 token。
19
- description: 'List skills with enabled state, effective/shadowed status and source file path. The「当前技能目录」reminder carries callable skills and summaries only; use this for entries that are off, for each entry\'s source-file path, and to see which source wins a name collision. Defaults to enabled only; all=true for every entry. A copy marked "shadowed-by:<root>" stays inactive even if enabled; "preferred" marks the copy that wins a name collision.',
19
+ description: 'List skills with enabled state, effective/shadowed status and source file path. The "Current skills" reminder carries callable skills and summaries only; use this for entries that are off, for each entry\'s source-file path, and to see which source wins a name collision. Defaults to enabled only; all=true for every entry. A copy marked "shadowed-by:<root>" stays inactive even if enabled; "preferred" marks the copy that wins a name collision.',
20
20
  parameters: {
21
21
  all: { type: 'boolean', description: 'Include disabled and shadowed entries (default false).' },
22
22
  },
@@ -84,7 +84,7 @@ export function buildSkillTools(deps) {
84
84
  // 已在上面标出胜出者),再走 `skill-detail` 读那一份 —— 读到的永远是目录列出来的那一份。
85
85
  register(defineTool({
86
86
  name: 'skill_manager_read',
87
- description: 'Read one skill\'s full SKILL.md body by name — what the「当前技能目录」reminder deliberately leaves out (it has names and summaries only). Also lists the other files living in that skill folder (references/, scripts/), which the body often points at. Resolves name collisions the same way, so you get the copy actually in effect; pass root only to inspect a specific (e.g. shadowed) source. Not sent when the official `skill` tool is mounted — use that instead.',
87
+ description: 'Read one skill\'s full SKILL.md body by name — what the "Current skills" reminder deliberately leaves out (it has names and summaries only). Also lists the other files living in that skill folder (references/, scripts/), which the body often points at. Resolves name collisions the same way, so you get the copy actually in effect; pass root only to inspect a specific (e.g. shadowed) source. Not sent when the official `skill` tool is mounted — use that instead.',
88
88
  parameters: {
89
89
  name: { type: 'string', required: true, description: 'Skill name, exactly as it appears in the catalog (kebab-case).' },
90
90
  root: { type: 'string', description: 'Source root key (dsh/hub/agents/codex/claude, a project key, or a custom one). Default: the winning copy of this name.' },
@@ -204,35 +204,35 @@ export function buildSkillTools(deps) {
204
204
  const preferGiven = Boolean(args && args.prefer !== undefined);
205
205
  const prefer = args && args.prefer === true;
206
206
  if (preferGiven && typeof args.prefer !== 'boolean')
207
- throw new Error('prefer 必须是 true 或 false');
207
+ throw new Error('prefer must be true or false');
208
208
  if (name && source)
209
- throw new Error('name 与 source 只能给一个:name 是单个技能,source 是整个来源目录');
209
+ throw new Error('give either name or source, not both: name is one skill, source is a whole source folder');
210
210
  if (preferGiven && source)
211
- throw new Error('prefer 只对单个技能有意义:给 name,不要给 source');
211
+ throw new Error('prefer only makes sense for a single skill: pass name, not source');
212
212
  if (!name && !source)
213
- throw new Error('缺少参数:name(单个技能)或 source(整个来源目录)');
213
+ throw new Error('missing argument: name (one skill) or source (a whole source folder)');
214
214
  if (preferGiven && !name)
215
- throw new Error('缺少参数:prefer 需要 name');
215
+ throw new Error('missing argument: prefer needs name');
216
216
  if (preferGiven && String((args && args.root) || '').trim() === '') {
217
- throw new Error('prefer 需要 root:明确指定哪一份同名副本胜出(dsh / hub / agents / codex / claude 或项目键)');
217
+ throw new Error('prefer needs root: name the copy that should win this collision (dsh / hub / agents / codex / claude or a project key)');
218
218
  }
219
219
  // 两个动作一个都没给就拒:`args.enabled ? enable : disable` 会把"忘了给"静默当成"停用"。
220
220
  if (args.enabled === undefined && !preferGiven) {
221
- throw new Error('缺少参数:enabled 必须是 true 或 false(只想改同名首选就传 prefer)');
221
+ throw new Error('missing argument: enabled must be true or false (pass prefer if you only want to change which copy wins the collision)');
222
222
  }
223
223
  if (source) {
224
224
  // 来源级启停:登记表里 `skill-source-enable` / `skill-source-disable` 都是
225
225
  // `{ serviceWrite, frozen, syncsArchive }`,所以守卫已过、档案也要同步
226
226
  // —— 同步的入参是 `{ root }`(来源级没有独立字段,档案靠"来源下有没有被勾的技能"反推)。
227
227
  if (args.root !== undefined)
228
- throw new Error('source 已经是来源级的键,不要再给 root');
228
+ throw new Error('source is already a source-level key; do not pass root with it');
229
229
  const op = args.enabled ? 'skill-source-enable' : 'skill-source-disable';
230
230
  const r = await deps.skillsOps[op]({ root: source });
231
231
  if (!r || r.ok === false)
232
232
  throw new Error((r && r.error) || 'skill source toggle failed');
233
233
  const syncErr = await deps.syncSwitchToScene(op, { root: source, enabled: args.enabled === true });
234
234
  return 'OK: source ' + source + ' now ' + (args.enabled ? 'enabled' : 'disabled') +
235
- (syncErr ? '\nWARN: 当前场景档案未同步(' + syncErr + ')' : '');
235
+ (syncErr ? '\nWARN: the current scene archive was not synced (' + syncErr + ')' : '');
236
236
  }
237
237
  // 不给 root 就在全部来源里找(2026-10-15 smoke-test P0-1):`skill_manager_save` 的落点
238
238
  // 是 hub(`tool-management/skills/`),而这里的默认值原本是 dsh —— 「建完就启用」这条
@@ -248,7 +248,7 @@ export function buildSkillTools(deps) {
248
248
  // 探得到、就是没这个技能:当场把"查过哪些来源"说清楚。否则模型收到 op 那句不带
249
249
  // 来源信息的「技能不存在」后,只能猜该传哪个 root(smoke-test P1-4-old 同一处)。
250
250
  if (found.ok) {
251
- throw new Error('技能不存在: ' + name + (found.roots.length ? '(已查 ' + found.roots.join('、') + ')' : ''));
251
+ throw new Error('no such skill: ' + name + (found.roots.length ? ' (searched ' + found.roots.join(', ') + ')' : ''));
252
252
  }
253
253
  // 探不到(skill-state 失败)就别在这里编结论:退回旧默认,交给 op 报它自己的错。
254
254
  return 'dsh';
@@ -262,7 +262,7 @@ export function buildSkillTools(deps) {
262
262
  const op = prefer ? 'skill-prefer' : 'skill-unprefer';
263
263
  const p = await deps.skillsOps[op]({ name: args.name, root });
264
264
  if (!p || p.ok === false)
265
- throw new Error((p && p.error) || '设置同名首选失败');
265
+ throw new Error((p && p.error) || 'failed to set the collision winner');
266
266
  // `skill-prefer` 会在"记下了但不会生效"时回 ok:true + warning(首选指向**停用**的来源,
267
267
  // 而同名首选会挡住其他副本 → 两份都不生效)。原样转出去,否则模型以为已经生效。
268
268
  out.push((prefer
@@ -303,7 +303,7 @@ export function buildSkillTools(deps) {
303
303
  const warn = shadowedBy
304
304
  ? ' — BUT this copy is shadowed by the same-name skill in "' + shadowedBy + '", so it stays inactive: enable that copy instead, or make it win with prefer=true and root="' + shadowedBy + '"'
305
305
  : '';
306
- const sceneWarn = syncErr ? '\nWARN: 当前场景档案未同步(' + syncErr + ')' : '';
306
+ const sceneWarn = syncErr ? '\nWARN: the current scene archive was not synced (' + syncErr + ')' : '';
307
307
  out.push('OK: ' + args.name + ' now ' + (args.enabled ? 'enabled' : 'disabled') + warn + sceneWarn);
308
308
  }
309
309
  return out.join('\n');
@@ -339,10 +339,10 @@ export function buildSkillTools(deps) {
339
339
  throw new Error(blocked);
340
340
  const wanted = String((args && args.name) || '').trim();
341
341
  if (!wanted)
342
- throw new Error('缺少参数:name');
342
+ throw new Error('missing argument: name');
343
343
  const kebab = toKebab(wanted);
344
344
  if (!kebab)
345
- throw new Error('无法生成合法 kebab-case 名称(原始名: ' + wanted + ')');
345
+ throw new Error('cannot build a valid kebab-case name (raw name: ' + wanted + ')');
346
346
  // 建还是改:先看这个(规范化后的)名字在不在。`skill-create` 对同名是**拒绝**的,
347
347
  // 所以这条判定只能在这里做 —— 不能指望 op 层兜,也不能让模型自己先查一次
348
348
  // (它手里的清单可能已经过期)。
@@ -367,7 +367,7 @@ export function buildSkillTools(deps) {
367
367
  body === '' ? 'body' : '',
368
368
  ].filter((x) => x !== '');
369
369
  if (missing.length)
370
- throw new Error('新建技能必须给 ' + missing.join(' 与 ') + '(' + kebab + ' 还不存在)');
370
+ throw new Error('creating a skill needs ' + missing.join(' and ') + ' (' + kebab + ' does not exist yet)');
371
371
  const r = await deps.skillsOps['skill-create']({ name: wanted, description: args.description, body: args.body });
372
372
  if (!r || r.ok === false)
373
373
  throw new Error((r && r.error) || 'skill create failed');
@@ -377,8 +377,8 @@ export function buildSkillTools(deps) {
377
377
  // 里只有这一条不报启用状态)。点名的 `skill_manager_switch` 在出厂默认名单里就是关着的,
378
378
  // 关着就改说"用户启用后才能用",别指一条模型没有的工具。
379
379
  const enableHint = deps.toolVisible('skill_manager_switch')
380
- ? '(默认未启用,要启用先 skill_manager_switch)'
381
- : '(默认未启用,用户启用后才能用)';
380
+ ? ' (created disabled; use skill_manager_switch to enable it)'
381
+ : ' (created disabled; the user has to enable it first)';
382
382
  return 'Created DSH skill ' + (data.name || kebab) + ' at ' + (data.path || '(unknown)') + enableHint;
383
383
  }
384
384
  // 改的分支:省略 = 保持。两个可改字段一个都没给就拒 —— op 会按"保持原样"重写一次文件
@@ -389,12 +389,12 @@ export function buildSkillTools(deps) {
389
389
  if (args.body !== undefined)
390
390
  touched.push('body');
391
391
  if (!touched.length)
392
- throw new Error('没有要改的东西:description / body 至少给一个');
392
+ throw new Error('nothing to change: pass description and/or body');
393
393
  const r = await deps.skillsOps['skill-update']({ name: wanted, description: args.description, body: args.body });
394
394
  if (!r || r.ok === false)
395
395
  throw new Error((r && r.error) || 'skill update failed');
396
396
  const data = r.data || {};
397
- return 'Updated DSH skill ' + (data.name || kebab) + ' at ' + (data.path || '(unknown)') + '(改了 ' + touched.join('、') + ')';
397
+ return 'Updated DSH skill ' + (data.name || kebab) + ' at ' + (data.path || '(unknown)') + ' (changed ' + touched.join(', ') + ')';
398
398
  },
399
399
  }));
400
400
  }
@@ -78,7 +78,7 @@ export function buildSubagentTools(deps) {
78
78
  try {
79
79
  register(deps.defineTool({
80
80
  name: 'subagent_manager_switch',
81
- description: 'Enable or disable one persona. Only enabled personas appear in the「当前子智能体」catalog and can be given work. Reversible. Only when the user asks or approves.',
81
+ description: 'Enable or disable one persona. Only enabled personas appear in the "Current subagents" catalog and can be given work. Reversible. Only when the user asks or approves.',
82
82
  parameters: {
83
83
  name: { type: 'string', required: true, description: 'Persona name.' },
84
84
  enabled: { type: 'boolean', required: true, description: 'true = enable, false = disable; omission is refused.' },
@@ -91,12 +91,12 @@ export function buildSubagentTools(deps) {
91
91
  const name = String((args && args.name) || '').trim();
92
92
  const r = await ops()['subagent-toggle']({ name, enabled: args.enabled === true });
93
93
  if (!r || r.ok === false)
94
- throw new Error((r && r.error) || '切换人设启停失败');
94
+ throw new Error((r && r.error) || 'failed to toggle the persona');
95
95
  // 场景内改开关要同步进当前场景档案(与 HTTP 层 syncsArchive 同一口径 —— 模型工具
96
96
  // 直接调 service op,绕过了那一层包装,所以这里自己叫一声)。
97
97
  const syncErr = await deps.syncSwitchToScene('subagent-toggle', { name, enabled: args.enabled === true });
98
98
  return 'OK: persona ' + name + ' ' + (args.enabled === true ? 'enabled' : 'disabled') +
99
- (syncErr ? '\nWARN: 当前场景档案未同步(' + syncErr + ')' : '');
99
+ (syncErr ? '\nWARN: the current scene archive was not synced (' + syncErr + ')' : '');
100
100
  },
101
101
  }));
102
102
  }
@@ -138,11 +138,11 @@ export function buildSubagentTools(deps) {
138
138
  // 高级字段的形状校验:填错会在 op 侧**静默**(`serializePersona` 对非数组 `tools`
139
139
  // 是"当空处理",等于把用户原有的名单清掉)。在这里先挡一句。
140
140
  if (args && args.continuable !== undefined && typeof args.continuable !== 'boolean') {
141
- throw new Error('continuable 必须是 true 或 false');
141
+ throw new Error('continuable must be true or false');
142
142
  }
143
143
  for (const k of ['tools', 'toolsDeny']) {
144
144
  if (args && args[k] !== undefined && !Array.isArray(args[k])) {
145
- throw new Error(k + ' 必须是字符串数组([] = 清空)');
145
+ throw new Error(k + ' must be an array of strings ([] = clear)');
146
146
  }
147
147
  }
148
148
  const current = await ops()['subagent-get']({ name });
@@ -156,17 +156,17 @@ export function buildSubagentTools(deps) {
156
156
  body === '' ? 'body' : '',
157
157
  ].filter((x) => x !== '');
158
158
  if (missing.length)
159
- throw new Error('新建人设必须给 ' + missing.join(' 与 ') + '(' + name + ' 还不存在)');
159
+ throw new Error('creating a persona needs ' + missing.join(' and ') + ' (' + name + ' does not exist yet)');
160
160
  const r = await ops()['subagent-create']({ name, description: args.description, body: args.body, output: args.output, ...advancedArgs(args) });
161
161
  if (!r || r.ok === false)
162
- throw new Error((r && r.error) || '创建人设失败');
162
+ throw new Error((r && r.error) || 'failed to create the persona');
163
163
  // 新建的人设默认停用(与 MCP / 技能同口径)。这句必须留:不说的话模型会直接去委派,
164
164
  // 然后收到"人设不可用",而它并不知道自己少拨了一个开关。点名的 subagent_manager_switch
165
165
  // 在出厂默认名单里就是关着的 —— 关着就改说"用户启用后才能委派",别指一条模型没有的
166
166
  // 工具(与 mcp/skill 的 listHint 同一条纪律)。
167
167
  const enableHint = deps.toolVisible('subagent_manager_switch')
168
- ? '(默认未启用,要委派它先 subagent_manager_switch)'
169
- : '(默认未启用,用户启用后才能委派)';
168
+ ? ' (created disabled; use subagent_manager_switch to enable it before delegating)'
169
+ : ' (created disabled; the user has to enable it before you can delegate)';
170
170
  return 'OK: persona ' + String(r.name || name) + ' created' + enableHint;
171
171
  }
172
172
  const keep = current.persona || {};
@@ -179,7 +179,7 @@ export function buildSubagentTools(deps) {
179
179
  touched.push(k);
180
180
  }
181
181
  if (!touched.length)
182
- throw new Error('没有要改的东西:description / body / output / nextName 或任一高级字段至少给一个');
182
+ throw new Error('nothing to change: pass at least one of description / body / output / nextName or any advanced field');
183
183
  const merged = {
184
184
  name,
185
185
  nextName: args.nextName,
@@ -200,9 +200,9 @@ export function buildSubagentTools(deps) {
200
200
  };
201
201
  const r = await ops()['subagent-update'](merged);
202
202
  if (!r || r.ok === false)
203
- throw new Error((r && r.error) || '更新人设失败');
204
- return 'OK: persona ' + String(r.name || name) + ' updated(改了 ' + touched.join('、') + ')' +
205
- (r.renamedFrom ? ' — 原名「' + r.renamedFrom + '」,场景档案里的绑定已一起改名' : '');
203
+ throw new Error((r && r.error) || 'failed to update the persona');
204
+ return 'OK: persona ' + String(r.name || name) + ' updated (changed ' + touched.join(', ') + ')' +
205
+ (r.renamedFrom ? ' — was named "' + r.renamedFrom + '"; the scene-archive binding was renamed too' : '');
206
206
  },
207
207
  }));
208
208
  }
@@ -35,7 +35,7 @@ import { INJECT_DOMAIN_KEYS, domainOfTool } from '../context-inject.js';
35
35
  * 判据是用户 2026-09-23 的三轮裁定,同一条:**这些信息或动作常态下由注入段与面板承担,
36
36
  * 平时也用不到模型自己伸手**。三组:
37
37
  * · **写侧五条** —— 三个 `*_save`(MCP / 技能 / 人设:配置本体在面板上改)+ 提示词两条
38
- * (这一族只有两条,而当前生效的那份本来就在「当前提示词」注入段里)。
38
+ * (这一族只有两条,而当前生效的那份本来就在 `Current prompt` 注入段里)。
39
39
  * · **读侧三条** —— 两个 `*_list`(MCP / 技能)+ `memory_manager_read`。会话开头注入的那几段
40
40
  * 目录已经写了当前有什么,模型不必每轮再带一份查询工具。
41
41
  * · **场景三条 + 开关三条** —— 场景一族(建 / 勾档案 / 进入退出)与 `skill` / `memory` /
@@ -58,7 +58,7 @@ import { INJECT_DOMAIN_KEYS, domainOfTool } from '../context-inject.js';
58
58
  * 绑定且深度够的、技能目录只列可调用的),所以"没开的那几台 / 被同名覆盖的那份技能 / 没进
59
59
  * 上下文的记忆正文"在会话里查不到;`*_switch` 关掉后模型也不能再替你拨启停。三处配套改动为
60
60
  * 的就是不把模型往墙上推:目录被条数上限截断时那句「用 `X_manager_list` 查」自动退回「另有
61
- * N 个未列出。」(`listToolVisible`);`mcp_manager_list` / `skill_manager_read` 里"没找到 →
61
+ * N more not listed.)」(`listToolVisible`);`mcp_manager_list` / `skill_manager_read` 里"没找到 →
62
62
  * 去调 list"那两句先问 `deps.toolVisible`;`memory_manager_list` 的描述不再点名已关的工具。
63
63
  *
64
64
  * 只在**用户从没记过选择**时生效(见 index.ts 的 `toolTableSettingsFrom`:侧车文件读不出来
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-tool-management",
3
- "version": "0.20.2",
3
+ "version": "0.21.0",
4
4
  "description": "一个设置面板,统一管理 MCP、技能、记忆、子智能体、提示词和归档会话;可自定义搭配场景,一个场景即可切换整个环境;Agent也能帮你操作这个插件。",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,6 +26,7 @@
26
26
  "docs/update.md"
27
27
  ],
28
28
  "engines": {
29
+ "dsh": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
29
30
  "node": ">=18"
30
31
  },
31
32
  "publishConfig": {
@@ -68,17 +69,17 @@
68
69
  },
69
70
  "peerDependencies": {
70
71
  "@deepseek-ai/cordis": "^4.0.2",
71
- "@deepseek-ai/dsh-agent-preset-registry": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
72
- "@deepseek-ai/dsh-llm": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
73
- "@deepseek-ai/dsh-session": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
74
- "@deepseek-ai/dsh-session-projection-cache": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
75
- "@deepseek-ai/dsh-settings": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
76
- "@deepseek-ai/dsh-spill-local": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
77
- "@deepseek-ai/dsh-storage-domain": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
78
- "@deepseek-ai/dsh-subagent-fork-in-process": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
79
- "@deepseek-ai/dsh-subagent-spawn-in-process": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
80
- "@deepseek-ai/dsh-tools": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
81
- "@deepseek-ai/dsh-workspace": ">=0.1.7-rc.2 || >=0.2.0-rc.1",
72
+ "@deepseek-ai/dsh-agent-preset-registry": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
73
+ "@deepseek-ai/dsh-llm": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
74
+ "@deepseek-ai/dsh-session": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
75
+ "@deepseek-ai/dsh-session-projection-cache": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
76
+ "@deepseek-ai/dsh-settings": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
77
+ "@deepseek-ai/dsh-spill-local": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
78
+ "@deepseek-ai/dsh-storage-domain": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
79
+ "@deepseek-ai/dsh-subagent-fork-in-process": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
80
+ "@deepseek-ai/dsh-subagent-spawn-in-process": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
81
+ "@deepseek-ai/dsh-tools": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
82
+ "@deepseek-ai/dsh-workspace": ">=0.1.7-rc.2 <0.2.0-rc.1 || >=0.2.0-rc.1 <0.2.1-rc.2 || >=0.2.1-rc.2 <0.2.2",
82
83
  "react": "^18.2.0"
83
84
  },
84
85
  "peerDependenciesMeta": {
@@ -90,18 +91,18 @@
90
91
  }
91
92
  },
92
93
  "devDependencies": {
93
- "@deepseek-ai/cordis": "^4.0.1",
94
- "@deepseek-ai/dsh-agent-preset-registry": "^0.2.0-rc.2",
95
- "@deepseek-ai/dsh-llm": "^0.2.0-rc.2",
96
- "@deepseek-ai/dsh-session": "^0.2.0-rc.2",
97
- "@deepseek-ai/dsh-session-projection-cache": "^0.2.0-rc.2",
98
- "@deepseek-ai/dsh-settings": "^0.2.0-rc.2",
99
- "@deepseek-ai/dsh-spill-local": "^0.2.0-rc.2",
100
- "@deepseek-ai/dsh-storage-domain": "^0.2.0-rc.2",
101
- "@deepseek-ai/dsh-subagent-fork-in-process": "^0.2.0-rc.2",
102
- "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.2.0-rc.2",
103
- "@deepseek-ai/dsh-tools": "^0.2.0-rc.2",
104
- "@deepseek-ai/dsh-workspace": "^0.2.0-rc.2",
94
+ "@deepseek-ai/cordis": "^4.0.5",
95
+ "@deepseek-ai/dsh-agent-preset-registry": "^0.2.1-rc.2",
96
+ "@deepseek-ai/dsh-llm": "^0.2.1-rc.2",
97
+ "@deepseek-ai/dsh-session": "^0.2.1-rc.2",
98
+ "@deepseek-ai/dsh-session-projection-cache": "^0.2.1-rc.2",
99
+ "@deepseek-ai/dsh-settings": "^0.2.1-rc.2",
100
+ "@deepseek-ai/dsh-spill-local": "^0.2.1-rc.2",
101
+ "@deepseek-ai/dsh-storage-domain": "^0.2.1-rc.2",
102
+ "@deepseek-ai/dsh-subagent-fork-in-process": "^0.2.1-rc.2",
103
+ "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.2.1-rc.2",
104
+ "@deepseek-ai/dsh-tools": "^0.2.1-rc.2",
105
+ "@deepseek-ai/dsh-workspace": "^0.2.1-rc.2",
105
106
  "@types/js-yaml": "^4.0.9",
106
107
  "@types/node": "^24.0.0",
107
108
  "react": "^18.2.0",