dsh-plugin-tool-management 0.8.0 → 0.9.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 (60) hide show
  1. package/CHANGELOG.md +67 -1
  2. package/README.md +53 -48
  3. package/README_EN.md +47 -44
  4. package/docs/images/1-EN.png +0 -0
  5. package/docs/images/1.png +0 -0
  6. package/docs/images/2-EN.png +0 -0
  7. package/docs/images/2.png +0 -0
  8. package/docs/images/3-EN.png +0 -0
  9. package/docs/images/3.png +0 -0
  10. package/docs/images/4-EN.png +0 -0
  11. package/docs/images/4.png +0 -0
  12. package/docs/images/5-EN.png +0 -0
  13. package/docs/images/5.png +0 -0
  14. package/docs/images/6-EN.png +0 -0
  15. package/docs/images/6.png +0 -0
  16. package/docs/images/7-EN.png +0 -0
  17. package/docs/images/7.png +0 -0
  18. package/docs/images/8-EN.png +0 -0
  19. package/docs/images/8.png +0 -0
  20. package/docs/update.md +39 -0
  21. package/lib/agents-md/preset-id.js +1 -1
  22. package/lib/agents-md/service.js +46 -9
  23. package/lib/approval-policy.js +1 -1
  24. package/lib/client.js +431 -135
  25. package/lib/compat/preset-reach.js +155 -93
  26. package/lib/compat/probe.js +6 -4
  27. package/lib/context-inject.js +304 -0
  28. package/lib/hub.js +155 -13
  29. package/lib/imports/upload.js +34 -14
  30. package/lib/index.js +870 -226
  31. package/lib/mcp/state-section.js +46 -15
  32. package/lib/rules/archive-engine.js +182 -57
  33. package/lib/rules/archive.js +57 -1
  34. package/lib/rules/service.js +386 -156
  35. package/lib/scene-prompt-sync.js +101 -12
  36. package/lib/skills/catalog.js +125 -0
  37. package/lib/skills/core.js +38 -4
  38. package/lib/skills/service.js +36 -10
  39. package/lib/subagents/catalog.js +15 -5
  40. package/lib/subagents/service.js +39 -28
  41. package/lib/subagents/tools.js +18 -13
  42. package/package.json +14 -9
  43. package/screenshots.json +8 -8
  44. package/docs/images/1/345/234/272/346/231/257.png +0 -0
  45. package/docs/images/1/345/234/272/346/231/257_en.png +0 -0
  46. package/docs/images/2MCP.png +0 -0
  47. package/docs/images/2MCP_en.png +0 -0
  48. package/docs/images/3/346/212/200/350/203/275.png +0 -0
  49. package/docs/images/3/346/212/200/350/203/275_en.png +0 -0
  50. package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223.png +0 -0
  51. package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223_en.png +0 -0
  52. package/docs/images/5/346/217/220/347/244/272/350/257/215.png +0 -0
  53. package/docs/images/5/346/217/220/347/244/272/350/257/215_en.png +0 -0
  54. package/docs/images/6/350/256/260/345/277/206.png +0 -0
  55. package/docs/images/6/350/256/260/345/277/206_en.png +0 -0
  56. package/docs/images/7/344/274/232/350/257/235.png +0 -0
  57. package/docs/images/7/344/274/232/350/257/235_en.png +0 -0
  58. package/docs/images/8/345/205/274/345/256/271.png +0 -0
  59. package/docs/images/8/345/205/274/345/256/271_en.png +0 -0
  60. package/lib/prompt-sections.js +0 -148
@@ -16,31 +16,36 @@ export async function filterBySceneBinding(docs, enabledSceneLists) {
16
16
  const allowed = live.filter((d) => bound.has(d.name));
17
17
  return { allowed, reason: allowed.length ? null : `当前启用场景的子智能体绑定: ${[...bound].join('、')}` };
18
18
  }
19
- export function defineSubagentListTool(subagents) {
19
+ export function defineSubagentManagerListTool(subagents) {
20
20
  return {
21
- name: 'subagent_list',
22
- description: 'List available personas (pre-configured subagent profiles) with their descriptions. Call before subagent_run.',
23
- parameters: {
24
- scene: { type: 'string', description: 'Optional scene name filter (informational; the tool already reflects scene binding).' },
25
- },
21
+ name: 'subagent_manager_list',
22
+ description: 'List available personas (pre-configured subagent profiles) with their descriptions. Call before subagent_manager_run.',
23
+ parameters: {},
26
24
  output: {
27
25
  schema: { type: 'string' },
28
26
  render: (_a, v) => text(String(v)),
29
27
  },
30
- async execute() {
28
+ async execute(_args, exec) {
31
29
  const { allowed, reason } = await filterBySceneBinding(await subagents.list(), await subagents.sceneLists());
32
30
  const lines = allowed.map((p) => '- ' + p.name + ' — ' + (p.description || '(无描述)'));
33
- return '人设子智能体(' + allowed.length + '):\n' + (lines.join('\n') || '(无)') + (reason ? '\n注意:' + reason : '');
31
+ let notice = '';
32
+ try {
33
+ notice = typeof subagents.noticeFor === 'function' ? await subagents.noticeFor(exec) : '';
34
+ }
35
+ catch {
36
+ notice = '';
37
+ }
38
+ return '人设子智能体(' + allowed.length + '):\n' + (lines.join('\n') || '(无)') + (reason ? '\n注意:' + reason : '') + notice;
34
39
  },
35
40
  };
36
41
  }
37
- export function defineSubagentRunTool(subagents) {
42
+ export function defineSubagentManagerRunTool(subagents) {
38
43
  return {
39
- name: 'subagent_run',
40
- description: 'Run a named persona as a one-shot subagent: it receives the persona as its own system prompt, works on `task` in a fresh context, and returns only its final output. Discover personas with subagent_list first. Each run is stateless and ephemeral; it does not see this conversation.',
44
+ name: 'subagent_manager_run',
45
+ description: 'Run a named persona as a one-shot subagent: it gets the persona as its own system prompt, works on `task` in a fresh context, and returns only its final output. Stateless — it does not see this conversation. Expensive: starts a fresh model session, so use it only for self-contained work.',
41
46
  parameters: {
42
- agent: { type: 'string', required: true, description: 'Persona name from subagent_list.' },
43
- task: { type: 'string', required: true, description: 'Complete, self-contained task for the subagent (include all context it needs).' },
47
+ agent: { type: 'string', required: true, description: 'Persona name from subagent_manager_list.' },
48
+ task: { type: 'string', required: true, description: 'Self-contained task, with all context the subagent needs.' },
44
49
  },
45
50
  output: {
46
51
  schema: { type: 'string' },
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.9.0",
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 (mcp_manager_*, skill_manager_*, prompt_manager_*, memory_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"
@@ -41,7 +41,8 @@
41
41
  "check:host": "node scripts/host-deps.mjs && node scripts/doctor.mjs",
42
42
  "host-deps": "node scripts/host-deps.mjs --fix",
43
43
  "doctor": "node scripts/doctor.mjs",
44
- "test": "npm run build && npm run check:i18n && node --test test/archive.test.mjs test/import.test.mjs test/approval-policy.test.mjs test/subagent-scene.test.mjs test/subagent-persona.test.mjs test/hub-layout.test.mjs test/skills-state.test.mjs test/skills-delete.test.mjs test/skills-source-remove.test.mjs test/client-exports.test.mjs test/client-render.test.mjs test/compat-probe.test.mjs test/compat-fallback.test.mjs test/preset-reach.test.mjs test/rules-toggle-args.test.mjs"
44
+ "test": "npm run build && npm run check:i18n && node --test test/client-exports.test.mjs test/client-render.test.mjs",
45
+ "sync:profile": "node scripts/sync-profile.mjs"
45
46
  },
46
47
  "keywords": [
47
48
  "dsh",
@@ -66,12 +67,14 @@
66
67
  },
67
68
  "peerDependencies": {
68
69
  "@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",
70
+ "@deepseek-ai/dsh-llm": ">=0.1.5-rc.2",
71
+ "@deepseek-ai/dsh-session": ">=0.1.5-rc.2",
72
+ "@deepseek-ai/dsh-session-projection-cache": ">=0.1.5-rc.2",
73
+ "@deepseek-ai/dsh-spill-local": ">=0.1.5-rc.2",
74
+ "@deepseek-ai/dsh-storage-domain": ">=0.1.5-rc.2",
75
+ "@deepseek-ai/dsh-subagent-spawn-in-process": ">=0.1.5-rc.2",
76
+ "@deepseek-ai/dsh-tools": ">=0.1.5-rc.2",
77
+ "@deepseek-ai/dsh-workspace": ">=0.1.5-rc.2",
75
78
  "react": "^18.2.0"
76
79
  },
77
80
  "peerDependenciesMeta": {
@@ -81,6 +84,8 @@
81
84
  },
82
85
  "devDependencies": {
83
86
  "@deepseek-ai/cordis": "^4.0.1",
87
+ "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
88
+ "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
84
89
  "@deepseek-ai/dsh-session-projection-cache": "^0.1.5-rc.2",
85
90
  "@deepseek-ai/dsh-spill-local": "^0.1.5-rc.2",
86
91
  "@deepseek-ai/dsh-storage-domain": "^0.1.5-rc.2",
package/screenshots.json CHANGED
@@ -1,10 +1,10 @@
1
1
  [
2
- "docs/images/1场景.png",
3
- "docs/images/2MCP.png",
4
- "docs/images/3技能.png",
5
- "docs/images/4子智能体.png",
6
- "docs/images/5提示词.png",
7
- "docs/images/6记忆.png",
8
- "docs/images/7会话.png",
9
- "docs/images/8兼容.png"
2
+ "docs/images/1.png",
3
+ "docs/images/2.png",
4
+ "docs/images/3.png",
5
+ "docs/images/4.png",
6
+ "docs/images/5.png",
7
+ "docs/images/6.png",
8
+ "docs/images/7.png",
9
+ "docs/images/8.png"
10
10
  ]
Binary file
Binary file
@@ -1,148 +0,0 @@
1
- // dsh-plugin-tool-management —— systemPrompt 段注册(通用骨架)。
2
- //
3
- // 本模块是「把插件状态投影为 system prompt 段(自动在场)」的**唯一实现**。
4
- // 场景记忆段(src/rules/service.ts)、子智能体人设段、MCP 状态段
5
- // (src/index.ts)都经它注册,避免每个域各抄一份 scope 遍历逻辑。
6
- //
7
- // 官方接口语义(@deepseek-ai/dsh-system-prompt):
8
- // - `section({ name, order, text })` 在**调用者的 scope** 注册;scoped 段遮蔽同名全局段。
9
- // - `text` 可以是**每次装配时求值的 provider 函数** → 切换启用状态后**下一个请求即生效**,
10
- // 无需重开会话、无需重载插件。
11
- // - `renderPrompt` 会**删除空段** → 无内容时返回 `''`,不产生空标题、零 token 成本。
12
- //
13
- // 为什么每个段都注册两处(全局 + per-agent):
14
- // 全局注册覆盖所有 agent(含子 agent);per-agent 注册保证即使插件 ctx 自带 scope
15
- // (全局段对某些 agent 不可见)也能命中 —— 两者同名,scoped 遮蔽全局,不会重复注入。
16
- //
17
- // 缓存契约(§5.2):段文本必须**会话级恒定**(只由持久化配置与文件内容决定),
18
- // 因此前缀逐字节稳定 → 前缀缓存可命中;**禁止**在段里放时间戳/计数/相对时间。
19
- // 异步数据源(人设目录、MCP 清单)走 stale-while-revalidate:`text()` 同步返回缓存值,
20
- // 由调用方在写操作后触发重算,绝不在 `text()` 里发起 IO。
21
- const GLOBAL_KEY = '@global';
22
- /** 复合 key 的分隔符:NUL 不会出现在 agent id 或段名里。 */
23
- const KEY_SEP = '\u0000';
24
- /** 取 scope 上的 systemPrompt 服务(Cordis 的 ctx.get 可能抛错,全部吞掉)。 */
25
- function systemPromptOf(scope) {
26
- if (!scope)
27
- return undefined;
28
- try {
29
- if (typeof scope.get === 'function')
30
- return scope.get('systemPrompt');
31
- return scope.systemPrompt;
32
- }
33
- catch {
34
- return undefined;
35
- }
36
- }
37
- /**
38
- * 注册一组 systemPrompt 段:全局 scope + 每个活动 agent 的 scope。
39
- *
40
- * 任一 scope / 任一段注册失败都只降级为"该段不注入",不影响其余段与其余 scope。
41
- */
42
- export function createPromptSectionRegistrar(ctx, sections) {
43
- const registrations = new Map();
44
- const install = (scope, scopeKey) => {
45
- if (!scope)
46
- return;
47
- const systemPrompt = systemPromptOf(scope);
48
- if (!systemPrompt || typeof systemPrompt.section !== 'function')
49
- return;
50
- for (const spec of sections) {
51
- const key = scopeKey + KEY_SEP + spec.name;
52
- if (registrations.has(key))
53
- continue;
54
- try {
55
- const dispose = systemPrompt.section({
56
- name: spec.name,
57
- order: spec.order,
58
- // 每次装配重读 → 切换启用状态后下一个请求即生效。
59
- // 包一层箭头函数:spec.text 自身若被替换(热更新)也能跟上。
60
- text: () => spec.text(),
61
- });
62
- registrations.set(key, { scope, dispose: typeof dispose === 'function' ? dispose : () => { } });
63
- }
64
- catch (e) {
65
- // 同层重名注册会抛错:降级为"该段不注入",不影响其余 scope 与其余段。
66
- console.error(`[dsh-plugin-tool-management] ${spec.name} section registration failed:`, String((e && e.message) || e));
67
- }
68
- }
69
- };
70
- const uninstall = (scopeKey) => {
71
- const prefix = scopeKey + KEY_SEP;
72
- for (const key of [...registrations.keys()]) {
73
- if (!key.startsWith(prefix))
74
- continue;
75
- const entry = registrations.get(key);
76
- registrations.delete(key);
77
- try {
78
- entry?.dispose();
79
- }
80
- catch { /* ignore */ }
81
- }
82
- };
83
- // ① 全局:插件 ctx 的 scope(覆盖所有 agent)
84
- install(ctx, GLOBAL_KEY);
85
- // ② per-agent:与既有 install/uninstall 生命周期一致(agent/created、agent/disposed)
86
- const on = ctx && ctx.on;
87
- let stopCreated;
88
- let stopDisposed;
89
- if (typeof on === 'function') {
90
- stopCreated = on('agent/created', (payload) => {
91
- const agent = payload && payload.agent;
92
- if (agent && agent.id != null)
93
- install(agent.ctx, String(agent.id));
94
- });
95
- stopDisposed = on('agent/disposed', (payload) => {
96
- const agent = payload && payload.agent;
97
- if (agent && agent.id != null)
98
- uninstall(String(agent.id));
99
- });
100
- }
101
- // 已存在的 agent(插件热加载场景):补注册。
102
- try {
103
- const agents = typeof ctx.get === 'function' ? ctx.get('agents') : undefined;
104
- if (agents && typeof agents.list === 'function') {
105
- for (const agent of agents.list()) {
106
- if (agent && agent.id != null)
107
- install(agent.ctx, String(agent.id));
108
- }
109
- }
110
- }
111
- catch { /* agents 服务不可用 → 仅靠事件 */ }
112
- return {
113
- invalidate: () => {
114
- for (const entry of registrations.values()) {
115
- try {
116
- entry.scope?.emit?.('system-prompt/change');
117
- }
118
- catch { /* 宿主无该事件 → 忽略 */ }
119
- }
120
- },
121
- dispose: () => {
122
- if (typeof stopCreated === 'function')
123
- stopCreated();
124
- if (typeof stopDisposed === 'function')
125
- stopDisposed();
126
- for (const key of [...registrations.keys()]) {
127
- const entry = registrations.get(key);
128
- registrations.delete(key);
129
- try {
130
- entry?.dispose();
131
- }
132
- catch { /* ignore */ }
133
- }
134
- },
135
- };
136
- }
137
- /**
138
- * 官方 `SECTION_ORDERS` 里 2901–4999 是空档,本插件的段全部落在该区间。
139
- * 数值本身无外部含义,只决定同一次装配里的相对顺序(小在前)。
140
- */
141
- export const SECTION_ORDER = {
142
- /** 场景记忆(rules 服务)。 */
143
- sceneMemory: 3000,
144
- /** 子智能体人设目录。 */
145
- subagents: 3010,
146
- /** MCP 服务器状态与用户备注。 */
147
- mcpState: 3020,
148
- };