dsh-plugin-tool-management 0.8.0 → 0.8.5

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.
@@ -9,7 +9,7 @@ import { Worker } from 'node:worker_threads';
9
9
  import { spawn } from 'node:child_process';
10
10
  import { homedir } from 'node:os';
11
11
  import { basename, join } from 'node:path';
12
- import { state, setSkillEnabled, setPreferredSkill, setSourceEnabled, setSourceRemoved, deleteSkill, restoreTrash, permanentlyDeleteTrash, importSkill, importUploadedSkill, browseDirectories, createSkill, skillDetail, listProviderCandidates, getProviderSkill, userRoots, projectRoots, readManagerState, customRootsFromState, addCustomRoot, removeCustomRoot, logPath, trashRootPath, } from './core.js';
12
+ import { state, setSkillEnabled, setPreferredSkill, markSkillsDisabled, setSourceEnabled, setSourceRemoved, deleteSkill, restoreTrash, permanentlyDeleteTrash, importSkill, importUploadedSkill, browseDirectories, createSkill, skillDetail, listProviderCandidates, getProviderSkill, userRoots, projectRoots, readManagerState, customRootsFromState, addCustomRoot, removeCustomRoot, logPath, trashRootPath, } from './core.js';
13
13
  const MAX_LOG_BYTES = 1 << 20;
14
14
  const PROVIDER_NAME = 'dsh-plugin-tool-management-external';
15
15
  const message = (e) => String((e && e.message) || e);
@@ -431,17 +431,43 @@ export function createSkillsService(ctx) {
431
431
  // requestRoot 未命中时回传原始 key,让 core 的 error.root.unknown 带上来源名
432
432
  // (否则传了不存在的 root 会收到「技能来源不存在:(空)」这种指错方向的提示)。
433
433
  const key = String(args.root || 'hub');
434
- return createSkill({ name: args.name, description: args.description, body: args.body }, log, { root: (await requestRoot(key)) || key });
434
+ const res = await createSkill({ name: args.name, description: args.description, body: args.body }, log, { root: (await requestRoot(key)) || key });
435
+ // v0.8.5:新建技能默认不启动(用户裁定)——与子智能体 / MCP 同口径。
436
+ if (res && res.ok !== false && res.name) {
437
+ await markSkillsDisabled([{ root: String(res.root || 'hub'), name: String(res.name) }], log).catch(() => undefined);
438
+ }
439
+ return res;
440
+ }), afterWrite),
441
+ 'skill-import': wrap((args) => write(async () => {
442
+ const res = await importSkill(String(args.source || ''), log, {
443
+ conflict: args.conflict === 'overwrite' ? 'overwrite' : 'skip',
444
+ dryRun: args.dryRun === true,
445
+ });
446
+ // 导入的技能默认停用;部分成功也对 imported 逐条停用。
447
+ const names = res && Array.isArray(res.imported) ? res.imported : [];
448
+ if (names.length)
449
+ await markSkillsDisabled(names.map((n) => ({ root: 'hub', name: String(n) })), log).catch(() => undefined);
450
+ return res;
451
+ }), afterWrite),
452
+ 'skill-upload': wrap((args) => write(async () => {
453
+ const res = await importUploadedSkill({ name: args.name, entries: args.entries, zip: args.zip }, log, {
454
+ conflict: args.conflict === 'overwrite' ? 'overwrite' : 'skip',
455
+ });
456
+ // 上传/导入同口径:默认停用。
457
+ const names = res && Array.isArray(res.imported) ? res.imported : (res && res.name ? [res.name] : []);
458
+ if (names.length)
459
+ await markSkillsDisabled(names.map((n) => ({ root: 'hub', name: String(n) })), log).catch(() => undefined);
460
+ return res;
435
461
  }), afterWrite),
436
- 'skill-import': wrap((args) => write(() => importSkill(String(args.source || ''), log, {
437
- conflict: args.conflict === 'overwrite' ? 'overwrite' : 'skip',
438
- dryRun: args.dryRun === true,
439
- })), afterWrite),
440
- 'skill-upload': wrap((args) => write(() => importUploadedSkill({ name: args.name, entries: args.entries, zip: args.zip }, log, {
441
- conflict: args.conflict === 'overwrite' ? 'overwrite' : 'skip',
442
- })), afterWrite),
443
462
  'skill-delete': wrap((args) => write(async () => deleteSkill(await requestRoot(String(args.root || 'dsh')), String(args.name || ''), log)), afterWrite),
444
- 'skill-trash-restore': wrap((args) => write(() => restoreTrash(String(args.id || ''), log, projectOptions())), afterWrite),
463
+ 'skill-trash-restore': wrap((args) => write(async () => {
464
+ const res = await restoreTrash(String(args.id || ''), log, projectOptions());
465
+ // 恢复的技能默认停用(v0.8.5 用户裁定:新建/导入/恢复一律不启动,手动开启)。
466
+ if (res && res.ok !== false && res.name) {
467
+ await markSkillsDisabled([{ root: String(res.root || 'hub'), name: String(res.name) }], log).catch(() => undefined);
468
+ }
469
+ return res;
470
+ }), afterWrite),
445
471
  'skill-trash-delete': wrap((args) => write(() => permanentlyDeleteTrashSafely(String(args.id || ''), log))),
446
472
  // 自定义技能目录:添加(绝对路径,只读接入)/ 移除(连同策略键)。
447
473
  'skill-custom-add': wrap((args) => write(() => addCustomRoot(args && args.path, args && args.label, log)), afterWrite),
@@ -38,7 +38,8 @@ export function renderSubagentCatalog(allowed, maxEntries = DEFAULT_CATALOG_MAX_
38
38
  const out = [
39
39
  '## 子智能体(人设)',
40
40
  '',
41
- '需要委派独立任务时,用 `subagent_run` 并指定下面的人设名。',
41
+ '如需要委派独立任务,可从下面的人设中选用合适的(也可先用 `subagent_list` 查看全部人设)。',
42
+ '用 `subagent_run` 委派时,该人设的完整提示词会成为子代理的系统提示词,子代理在独立上下文中执行,只返回最终结果。',
42
43
  '',
43
44
  ...lines,
44
45
  ];
@@ -161,19 +161,17 @@ export function createSubagentService(ctx, opts) {
161
161
  await writeFile(stateFile, JSON.stringify({ version: 1, enabled: list }, null, 2), 'utf8');
162
162
  enabledCache = list;
163
163
  }
164
- /** 新建/导入/恢复的人设默认启用;文件缺失(本来就全启用)时无需写。 */
165
- async function enablePersonaNames(names) {
164
+ /** 新建/导入/恢复的人设默认停用(v0.8.5 用户裁定,与技能 / MCP 同口径):
165
+ * 文件缺失(含旧数据)时先把「全部启用」物化成显式全集**并排除新名**——
166
+ * 否则新名会随"文件缺失=全启用"的兼容语义被误判为启用。已有显式集合时新名
167
+ * 不在集合里,天然停用,无需写盘。 */
168
+ async function materializeEnabledExcluding(names) {
166
169
  const set = await readEnabled();
167
- if (set === null)
170
+ if (set !== null)
168
171
  return;
169
- let dirty = false;
170
- for (const n of names)
171
- if (set.indexOf(n) < 0) {
172
- set.push(n);
173
- dirty = true;
174
- }
175
- if (dirty)
176
- await writeEnabled(set);
172
+ const docs = await list();
173
+ await writeEnabled(docs.map((d) => d.name).filter((n) => names.indexOf(n) < 0));
174
+ cache = null;
177
175
  }
178
176
  /** 改名跟随:旧名在集合里就改新名;不在(停用中)保持停用。 */
179
177
  async function renamePersonaInEnabled(from, to) {
@@ -354,8 +352,8 @@ export function createSubagentService(ctx, opts) {
354
352
  return { ok: false, error: `创建人设目录失败: ${dir}(${message(e)})` };
355
353
  }
356
354
  await writeFile(target, serializePersona(args), 'utf8');
357
- // 新建即启用(文件缺失 = 本来全启用,无需写);缓存失效让下次 list 带上新成员。
358
- await enablePersonaNames([name]).catch(() => undefined);
355
+ // v0.8.5:新建默认不启动——显式集合下新名天然停用;文件缺失时先物化全集并排除新名。
356
+ await materializeEnabledExcluding([name]).catch(() => undefined);
359
357
  cache = null;
360
358
  return { ok: true, name };
361
359
  },
@@ -440,8 +438,8 @@ export function createSubagentService(ctx, opts) {
440
438
  return { ok: false, error: `恢复失败: ${message(e)}` };
441
439
  }
442
440
  await purgeTrashEntry('agents', id);
443
- // 恢复 = 拿回来用:自动启用(文件缺失本来就全启用,无需写)。
444
- await enablePersonaNames([entry.name]).catch(() => undefined);
441
+ // v0.8.5:回收站恢复默认不启动(与新建/导入同口径)。
442
+ await materializeEnabledExcluding([entry.name]).catch(() => undefined);
445
443
  cache = null;
446
444
  return { ok: true, name: entry.name };
447
445
  },
@@ -492,7 +490,7 @@ export function createSubagentService(ctx, opts) {
492
490
  imported.push(target.name);
493
491
  }
494
492
  if (imported.length) {
495
- await enablePersonaNames(imported).catch(() => undefined);
493
+ await materializeEnabledExcluding(imported).catch(() => undefined);
496
494
  cache = null;
497
495
  }
498
496
  return { ok: true, imported, skipped };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-plugin-tool-management",
3
- "version": "0.8.0",
4
- "description": "DSH plugin: one settings panel for MCP servers, Skills, AGENTS.md presets, archived sessions and scene memories — plus scene memory injected into the system prompt and one-shot persona subagents. Settings UI + HTTP API + 14 model tools (skill_mcp_manager_*, skill_manager_*, agentsmd_*, rule_manager_*, subagent_*). Install with one command: dsh plugin --profile web add dsh-plugin-tool-management@latest",
3
+ "version": "0.8.5",
4
+ "description": "DSH plugin: one settings panel for MCP servers, skills, scenes, memories, subagents, AGENTS.md presets and archived sessions — scene memory injects into the system prompt, scene lock freezes all five domains, deleted workspaces re-register with one click. Settings UI + HTTP API + 14 model tools (skill_mcp_manager_*, skill_manager_*, agentsmd_*, rule_manager_*, subagent_*). Install with one command: dsh plugin --profile web add dsh-plugin-tool-management@latest",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/ouli-1242/dsh-plugin-tool-management"
@@ -66,12 +66,12 @@
66
66
  },
67
67
  "peerDependencies": {
68
68
  "@deepseek-ai/cordis": "^4.0.1",
69
- "@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.2.0-0",
70
- "@deepseek-ai/dsh-workspace": ">=0.1.5-rc.2 <0.2.0-0",
71
- "@deepseek-ai/dsh-spill-local": ">=0.1.5-rc.2 <0.2.0-0",
72
- "@deepseek-ai/dsh-session-projection-cache": ">=0.1.5-rc.2 <0.2.0-0",
73
- "@deepseek-ai/dsh-storage-domain": ">=0.1.5-rc.2 <0.2.0-0",
74
- "@deepseek-ai/dsh-subagent-spawn-in-process": ">=0.1.5-rc.2 <0.2.0-0",
69
+ "@deepseek-ai/dsh-tools": ">=0.1.5-rc.2",
70
+ "@deepseek-ai/dsh-workspace": ">=0.1.5-rc.2",
71
+ "@deepseek-ai/dsh-spill-local": ">=0.1.5-rc.2",
72
+ "@deepseek-ai/dsh-session-projection-cache": ">=0.1.5-rc.2",
73
+ "@deepseek-ai/dsh-storage-domain": ">=0.1.5-rc.2",
74
+ "@deepseek-ai/dsh-subagent-spawn-in-process": ">=0.1.5-rc.2",
75
75
  "react": "^18.2.0"
76
76
  },
77
77
  "peerDependenciesMeta": {