dsh-plugin-tool-management 0.1.2 → 0.2.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.
- package/README.md +226 -136
- package/README_EN.md +231 -136
- package/cordis.patch.yml +18 -0
- package/docs/images/agents-md.png +0 -0
- package/docs/images/history.png +0 -0
- package/docs/images/mcp.png +0 -0
- package/docs/images/skills.png +0 -0
- package/docs/images//345/234/272/346/231/257/350/256/260/345/277/206.png +0 -0
- package/lib/agents-md/service.js +240 -0
- package/lib/client.js +2173 -850
- package/lib/history/projcache.js +335 -0
- package/lib/history/tombstone.js +32 -0
- package/lib/history/workspace.js +892 -0
- package/lib/imports/parsers.js +181 -0
- package/lib/index.js +768 -2
- package/lib/rules/provider.js +121 -0
- package/lib/rules/service.js +1657 -0
- package/lib/skills/core.js +10 -1
- package/lib/skills/service.js +5 -5
- package/package.json +18 -8
- package/screenshots.json +7 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// dsh-plugin-tool-management —— 规则「自动在场层」投影(systemPrompt 段注册)。
|
|
2
|
+
//
|
|
3
|
+
// 变更单 01 的核心:把规则从"投影为 skill 目录条目(模型按需 load)"改为
|
|
4
|
+
// **投影为 system prompt 段(自动在场)**。前者即使命中,模型也要自己决定看不看,
|
|
5
|
+
// 正是用户抱怨的"每次都要解释"。
|
|
6
|
+
//
|
|
7
|
+
// 官方接口语义(@deepseek-ai/dsh-system-prompt):
|
|
8
|
+
// - `section({ name, order, text })` 在**调用者的 scope** 注册;scoped 段遮蔽同名全局段。
|
|
9
|
+
// - `text` 可以是**每次装配时求值的 provider 函数** → 切换启用场景后**下一个请求即生效**,
|
|
10
|
+
// 无需重开会话、无需重载插件。
|
|
11
|
+
// - `renderPrompt` 会**删除空段** → 无启用场景/空目录时返回 `''`,不产生空标题。
|
|
12
|
+
//
|
|
13
|
+
// 为什么注册两处(全局 + per-agent):
|
|
14
|
+
// 全局注册覆盖所有 agent(含子 agent);per-agent 注册保证即使插件 ctx 自带 scope
|
|
15
|
+
// (全局段对某些 agent 不可见)也能命中 —— 两者同名,scoped 遮蔽全局,不会重复注入。
|
|
16
|
+
//
|
|
17
|
+
// 缓存契约(§5.2):段文本是**会话级恒定**的(只由启用场景与文件内容决定),
|
|
18
|
+
// 因此前缀逐字节稳定 → 前缀缓存可命中;禁止在段里放时间戳/计数/相对时间。
|
|
19
|
+
const SECTION_NAME = 'tool-management:scene-memory';
|
|
20
|
+
/**
|
|
21
|
+
* §5.1 硬约束 2:官方 `SECTION_ORDERS` 里 2901–4999 是空档(TOOL_REPORT 2900 →
|
|
22
|
+
* TOOLS_SDK 5000),取 **3000** —— 语义上是"工具能力说明之后、输出与 SDK 约定之前",
|
|
23
|
+
* 且远离任何既有段。**不要**用官方已有数值(同号按名称排序,虽确定但难读,日后易撞)。
|
|
24
|
+
*/
|
|
25
|
+
const SECTION_ORDER = 3000;
|
|
26
|
+
const GLOBAL_KEY = '@global';
|
|
27
|
+
/** 取 scope 上的 systemPrompt 服务(Cordis 的 ctx.get 可能抛错,全部吞掉)。 */
|
|
28
|
+
function systemPromptOf(scope) {
|
|
29
|
+
if (!scope)
|
|
30
|
+
return undefined;
|
|
31
|
+
try {
|
|
32
|
+
if (typeof scope.get === 'function')
|
|
33
|
+
return scope.get('systemPrompt');
|
|
34
|
+
return scope.systemPrompt;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** 注册全局 + agent-scope 的场景记忆段。 */
|
|
41
|
+
export function createRuleProviderRegistrar(ctx, facade) {
|
|
42
|
+
const registrations = new Map();
|
|
43
|
+
const install = (scope, key) => {
|
|
44
|
+
if (!scope || registrations.has(key))
|
|
45
|
+
return;
|
|
46
|
+
const systemPrompt = systemPromptOf(scope);
|
|
47
|
+
if (!systemPrompt || typeof systemPrompt.section !== 'function')
|
|
48
|
+
return;
|
|
49
|
+
try {
|
|
50
|
+
const dispose = systemPrompt.section({
|
|
51
|
+
name: SECTION_NAME,
|
|
52
|
+
order: SECTION_ORDER,
|
|
53
|
+
// 每次装配重读活动场景 → 切换启用状态后下一个请求即生效。
|
|
54
|
+
// ⚠️ 硬约束 1:必须**同步返回 string**(不能是 Promise)——异步读取会破坏 renderPrompt。
|
|
55
|
+
text: () => facade.renderActiveScenes(),
|
|
56
|
+
});
|
|
57
|
+
registrations.set(key, { scope, dispose: typeof dispose === 'function' ? dispose : () => { } });
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
// 同层重名注册会抛错:降级为"该 scope 不注入",不影响其余 scope。
|
|
61
|
+
console.error('[dsh-plugin-tool-management] scene-memory section registration failed:', String((e && e.message) || e));
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const uninstall = (key) => {
|
|
65
|
+
const entry = registrations.get(key);
|
|
66
|
+
if (!entry)
|
|
67
|
+
return;
|
|
68
|
+
registrations.delete(key);
|
|
69
|
+
try {
|
|
70
|
+
entry.dispose();
|
|
71
|
+
}
|
|
72
|
+
catch { /* ignore */ }
|
|
73
|
+
};
|
|
74
|
+
// ① 全局:插件 ctx 的 scope(覆盖所有 agent)
|
|
75
|
+
install(ctx, GLOBAL_KEY);
|
|
76
|
+
// ② per-agent:与既有 install/uninstall 生命周期一致(agent/created、agent/disposed)
|
|
77
|
+
const on = ctx && ctx.on;
|
|
78
|
+
let stopCreated;
|
|
79
|
+
let stopDisposed;
|
|
80
|
+
if (typeof on === 'function') {
|
|
81
|
+
stopCreated = on('agent/created', (payload) => {
|
|
82
|
+
const agent = payload && payload.agent;
|
|
83
|
+
if (agent && agent.id != null)
|
|
84
|
+
install(agent.ctx, String(agent.id));
|
|
85
|
+
});
|
|
86
|
+
stopDisposed = on('agent/disposed', (payload) => {
|
|
87
|
+
const agent = payload && payload.agent;
|
|
88
|
+
if (agent && agent.id != null)
|
|
89
|
+
uninstall(String(agent.id));
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// 已存在的 agent(插件热加载场景):补注册。
|
|
93
|
+
try {
|
|
94
|
+
const agents = typeof ctx.get === 'function' ? ctx.get('agents') : undefined;
|
|
95
|
+
if (agents && typeof agents.list === 'function') {
|
|
96
|
+
for (const agent of agents.list()) {
|
|
97
|
+
if (agent && agent.id != null)
|
|
98
|
+
install(agent.ctx, String(agent.id));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch { /* agents 服务不可用 → 仅靠事件 */ }
|
|
103
|
+
return {
|
|
104
|
+
invalidate: () => {
|
|
105
|
+
for (const entry of registrations.values()) {
|
|
106
|
+
try {
|
|
107
|
+
entry.scope?.emit?.('system-prompt/change');
|
|
108
|
+
}
|
|
109
|
+
catch { /* 宿主无该事件 → 忽略 */ }
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
dispose: () => {
|
|
113
|
+
if (typeof stopCreated === 'function')
|
|
114
|
+
stopCreated();
|
|
115
|
+
if (typeof stopDisposed === 'function')
|
|
116
|
+
stopDisposed();
|
|
117
|
+
for (const key of [...registrations.keys()])
|
|
118
|
+
uninstall(key);
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|