dsh-plugin-tool-management 0.12.1 → 0.14.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 (57) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/README.md +90 -114
  3. package/README_EN.md +98 -119
  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 +63 -0
  21. package/lib/client.js +1086 -95
  22. package/lib/compat/preset-reach.js +6 -3
  23. package/lib/context-inject.js +183 -59
  24. package/lib/index.js +501 -49
  25. package/lib/mcp/manager.js +118 -71
  26. package/lib/mcp/secret-guard.js +21 -0
  27. package/lib/mcp/state-section.js +19 -14
  28. package/lib/memories/archive-engine.js +199 -0
  29. package/lib/memories/constants.js +72 -8
  30. package/lib/memories/index-io.js +1 -1
  31. package/lib/memories/projection.js +67 -31
  32. package/lib/memories/service.js +17 -2
  33. package/lib/memories/snapshot.js +123 -22
  34. package/lib/op-registry.js +279 -0
  35. package/lib/ops/candidates.js +11 -0
  36. package/lib/ops/compat.js +23 -2
  37. package/lib/ops/sessions.js +1 -1
  38. package/lib/ops/state-doctor.js +115 -0
  39. package/lib/prompts/service.js +25 -2
  40. package/lib/request-gate.js +21 -78
  41. package/lib/scene-settings.js +17 -0
  42. package/lib/scenes/candidates.js +56 -0
  43. package/lib/skills/catalog.js +10 -5
  44. package/lib/skills/core.js +102 -0
  45. package/lib/skills/service.js +34 -2
  46. package/lib/subagents/catalog.js +9 -5
  47. package/lib/subagents/service.js +37 -4
  48. package/lib/subagents/tools.js +19 -5
  49. package/lib/tools/deps.js +15 -0
  50. package/lib/tools/mcp.js +291 -50
  51. package/lib/tools/memory.js +170 -19
  52. package/lib/tools/prompt.js +28 -14
  53. package/lib/tools/scene.js +351 -0
  54. package/lib/tools/skills.js +168 -14
  55. package/lib/tools/subagent.js +129 -3
  56. package/lib/tools/table.js +290 -0
  57. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -10,6 +10,90 @@
10
10
 
11
11
  ---
12
12
 
13
+ ## [0.14.0] - 2026-09-23
14
+
15
+ ### 破坏性
16
+
17
+ - **模型工具改名并合并,共 20 条**:五个「新建」统一成 `_save`(有则改、无则建,回执说清走了哪条);六个域的启停统一成 `_switch`;`mcp_manager_set_enabled` + `mcp_manager_restart` 合成 `mcp_manager_switch(server, action, level?, tool?)`。场景从记忆里分出来,自成一族三条 `_list` / `_switch` / `_save`,记忆族保持 `memory_manager_*`。**旧名不留别名** —— 别名会常驻每一轮请求,比这次省下的还多。
18
+ - **出厂默认关掉 15 条工具**:每轮实发只剩 5 条 ≈1,090 tok(整表 20 条 ≈3,769)。关的是三条 `*_save`、提示词两条、三条 `*_list`、`memory_manager_read`、场景三条与 `skill` / `memory` / `subagent` 三个 `_switch`;留着 `memory_manager_list`、`memory_manager_save`、`mcp_manager_switch`、`skill_manager_read`、`subagent_manager_run`。判据是这些信息或动作常态下由注入段与面板承担。**只在从没动过那一页时生效**,存过的选择(含"一条都不关")照原样;「兼容」页可逐条打开,也能整批换回。
19
+
20
+ ### 新增
21
+
22
+ - **模型能进入 / 退出场景**(`scene_manager_switch`):与界面「进入场景」走同一条路径 —— 按档案整套启停 MCP / 技能 / 人设、注入收窄成该场景的记忆、把绑定的提示词写进 `AGENTS.md`(覆盖前留备份)。改的是整个运行时环境,默认要用户确认。
23
+ - **模型能查、能建场景**:`scene_manager_list` 列出每个场景的档案、绑定的预设、锁没锁、几条记忆;`scene_manager_save` 建场景 / 写档案 / 绑提示词。档案是**整段替换**,所以清单先看现状、回执再列出被挤掉的项(`mcp 4 项 → 2 项(-B、-C)`)。
24
+ - **MCP 三项能力**:改一台已配置的服务器(省略的字段保持原样,全程不碰明文凭据)、只停某个工具、顺手写备注。
25
+ - **技能两项**:整个来源目录启停(`source` 参数);改写本插件自己写的那份(新 op `skill-update`)。
26
+ - **人设「思考强度」**:在高级选项里与「模型」并排,档位由所选模型声明。换了模型而旧档位不在新清单里会自动清掉并告知;拉取失败不动已存的值。
27
+ - **「模型工具表」能存方案**:合计行右侧「保存方案 / 恢复方案」。方案存的是关掉的名单,最多 20 份、名字不能重复(保存永不覆盖);恢复清单第一条是不可删的**出厂默认**,自己存的可在同一弹窗里删。
28
+ - **注入按域分家**:「场景」与「记忆」各成一段,可以单独关掉记忆段而保留场景说明。⚠️ 升级后每个会话会重发一次这两段(旧消息认不出来),一次性代价。
29
+ - **提示词清单带描述**:模型能在预设之间做选择(描述上限 300 字,输入框有字数计数)。
30
+
31
+ ### 变更
32
+
33
+ - **注入只写"现在是什么"**:六个板块的"什么时候该想起我"动作句、机制解释、重复的权威声明全部删掉,框架只剩标题 + 正文 + 一句"以本份为准"。四个板块合计 **823 → 643 tok/轮**。
34
+ - **注入层级定稿**:板块 `#` / 场景 `##` / 条目 `-`(此前板块标题与记忆里的场景分组平级,模型读不出主次)。
35
+ - **场景段只剩一行**:`**「代码」—— 用户描述:写代码**`;一个具体场景都没启用时整段不注入。`global` 的分组标题改成 `## 常驻信息`。
36
+ - **记忆段的授权语定稿**,整段只说一次:`以下是当前场景对应的记忆;冲突时以实际情况和用户目前的对话为准;无关勿提;以下就是全部信息:`。
37
+ - **MCP 段不再列工具数**(模型拿这个数字做不了事);备注前缀统一成「用户提示:」。
38
+ - **关掉的工具不再被点名**:目录截断提示、"没找到 → 去调某条工具"那几句会随开关自动改写,不会把模型指向一条不存在的工具。
39
+ - **`tool-table.json` 里的旧工具名自动迁移**(读侧翻译一次并回写盘,幂等),存下的命名方案一起迁移。不认识的名字原样保留。
40
+ - **「功能总览」的「模型工具表」一行**改按"用户自己关掉的条数"判状态 —— 出厂默认不算降级。
41
+ - **`subagent_manager_run` 描述瘦身**(407 → 338 tok):删掉与参数说明逐字重复的部分,约束一句没减。
42
+ - **子智能体高级选项折叠后的摘要固定排两行**,长名字不再被折成竖排。
43
+
44
+ ### 修复
45
+
46
+ - **工具描述引用的注入板块名悬空**:记忆段拆开后板块标题改了,`memory_manager_list` 还指向旧名字,模型照着找找不到。补了一条契约测试扫描这类跨模块引用。
47
+ - **`prompt_manager_list` 报错过「生效中」**:场景接管时它按"文件内容比对"判,与界面两套答案。现在两边同源,并区分 `[active via scene]` / `[active via file]`。
48
+ - **改配置会静默清空凭据与思考强度**:`mcp_manager_save` 省略 headers/env、`subagent_manager_save` 省略 `reasoningEffort` 时会被整份重写清空 —— 现在省略即保持。
49
+ - **自定义目录里的技能"列得出、调不动"**:读取正文时不查自定义根,静默返回"没有这个技能"。
50
+ - **「采纳」统计不再把「已清空」通知当成正文**:第三列此前一直是第二列的复本。
51
+ - **记忆正文不再"逃出条目"**:正文里手写的 `#` 会渲染成与场景标题平级的大标题,现在整段包成代码块。
52
+ - **MCP / 技能族的悬停不再承诺没有的字段**:此前写着"可带 provider、模型与工具限制",而工具签名里根本没有这些参数。
53
+ - **`prompt_manager_apply` 回执的生效时机说错了**:写「next session(当前会话不变)」,而宿主每一步都会 stat 比对并重读 `AGENTS.md` —— 实际**下一轮就生效**。三处口径(回执两条分支、`prompt_manager_list` 尾注)统一,模型不再劝用户重开会话。
54
+ - **`scene_manager_save` 的参数说明引用了已删除的授权语**:还说场景说明注入后"模型会被要求照办",与注入定稿(场景段只陈述现状、不带指令)不符;改为如实说明去向(出现在「本机当前的场景」reminder 里),"写成指令而非备注"的写作引导保留。
55
+ - **静态描述与回执不再点名出厂默认关闭的工具**:场景族三条的互指改成中性说法(the scene listing / 「本机当前的场景」reminder),`scene_manager_save` 与 `subagent_manager_save` 回执里的 `_switch` 点名按 toolVisible 分叉(部分启用时模型会被指向一条自己没有的工具)。**新增契约测试**钉住「静态 description 不得点名出厂关闭的工具」,与板块名悬空那条同一族。
56
+ - **两条清单描述的口径对齐实际输出**:`mcp_manager_list` 不再说"注入的就是这份清单"(注入段是筛过的视图、停用服务器不进 —— 现在把这个盲区写成模型的行动依据:要查停用的用 all=true);`skill_manager_list` 不再说用它"拿正文"(它给的是源文件路径,正文走 `skill_manager_read` 或文件读取)。
57
+
58
+ ## [0.13.0] - 2026-09-23
59
+
60
+ ### 新增
61
+
62
+ - **模型侧补五个工具,15 → 20**:`memory_manager_set_enabled` / `_update`、`subagent_manager_set_enabled` / `_create` / `_update`。分布此前是歪的 —— 技能与 MCP 两域模型能启停能新建,记忆与子智能体却**只读**:看得到一份记忆、看得到一个人设,开关拨不了、内容改不了,只能回一句"请到界面上点"。底层那五个 op 连门禁(写令牌 / 场景冻结 / 档案同步)都齐,缺的只是接线。提示词按裁定只留 `apply`。
63
+ - **所有会改东西的工具都写明"要用户开口或先同意"**:启停类一句 `Only when the user asks or approves.`、建与改类一句 `Only on the user's instruction.`。此前只有两个工具有这句话,其余全靠确认门兜 —— 而门是可以关掉的(设置项关掉记忆确认,或会话走「完全权限」预设),描述里这句关不掉。顺手把 20 条描述删了一遍:**工具级 6,564 → 5,608、参数级 3,052 → 2,990,合计 9,616 → 8,598**(加了 consent 句之后仍净降 1,018)。删的是重复的路径、"注入的那份与本工具的关系"这类模型一看输出就懂的交代、以及同一句 `all=true` 说明了四遍。
64
+ - **模型工具表可以关**:工具表**每一轮请求都随工具发一遍**,20 个工具的整份定义合计 ≈3,450 tok(宿主口径:整份 JSON 除 4),这一轮用不上也照付。兼容页新增「模型工具表」块,逐个工具勾选、按域全开全关,关掉的**整份不进请求** —— 只把描述写短是重编码同样的事实,这才是唯一真省钱的杠杆(实测:关掉 6 个管理类工具省 ≈1,115 tok/轮)。数字全部来自**注册时量到的整份定义体积**,界面上的 ≈ 与分组合计同一个来源,默认一个都不关。配套两处:关掉的工具在**执行侧**也拦住(可见性那半边万一没生效,名字也不该被执行),注入文本里点名它的那几句跟着换话术(技能 / 子智能体目录的截断提示与两条 `how` 行)—— 点名一个模型手里没有的工具,只会让它去猜名字。**面板不受影响**:114 个 op 与工具表互不相干,关掉 `mcp_manager_add` 之后 MCP 页照样能加服务器。
65
+ - **`skill_manager_read`**:按名字一次拿到技能正文。此前要两步(`skill_manager_list` 取路径 → 自己读那个文件),而目录只有名字没有路径、同名常几份并存,自己挑路径很容易读到被覆盖的影子副本 —— 读完以为在用这个技能,其实生效的是另一份。新工具先走 `skill-state` 的胜出者判定再读,读到的就是目录列出来的那一份。
66
+ - **「进入场景」先弹一张卡说清会改什么**:新只读 op `scene-mode-preview` 复用引擎里**已有的两个纯计划函数**(`computeMcpPlan` / `computeSkillsPlan`)与同一批现状读取,只把后面的 `apply*` 与 `saveSlice` 去掉 —— 预览与实际执行不可能各说各话。逐方向列出会启停哪些服务器 / 工具 / 技能目录 / 技能 / 人设。预览失败不拦进入:它是说明卡,不是新门禁。
67
+ - **改名留下的悬空引用有地方说了**:新只读 op `state-doctor` + 场景页黄条,把档案与绑定里指向已消失名字的行数出来。这类已经真出过两次(0.9.1 / 0.10.0),而提示词绑定那一连出口都没有 —— 宿主把"绑的预设读不到正文"当成"没绑",界面上那条「预设不存在」标签永远不亮。只数不修:猜着改名字比留着更危险。
68
+ - **记忆页每行带出正文字节数**:记忆是唯一直接吃注入预算的域(场景段 128 KiB),页面上却看不出哪条大。读不到文件时**不带**这个字段、界面什么都不显示 —— 把"不知道"报成 `0 B` 是假话。
69
+ - **「新增 MCP 服务器」弹窗有了备注框**:随表单一起填,留空 = 侧车里不产生任何条目(不是写一条空串)。与服务器同一次写锁落盘(`id` 只有服务端算得出,重名会加后缀);备注写失败不回滚已建好的条目,原因并进 warning。
70
+ - **五处输入加了「字数 / 总字数」**:MCP 备注两处、人设描述、技能描述、记忆描述。分母取的是**注入段的截断长度** —— 不会再出现"界面让你写 500、模型只读到 300"。存量超长的标红。
71
+ - **场景页能搜了**:其余六页早有。匹配卡片上真会显示的四样(目录名 / 显示名 / 一行描述 / 绑定的预设 id);三格统计不跟着过滤变。
72
+ - **`/` 聚焦搜索框、Esc 清空它**:监听挂在插件自己的根节点而不是 `window`(会连宿主的键一起抢);弹窗开着时整条放行。↑/↓/Enter 留在下一步。
73
+
74
+ ### 变更
75
+
76
+ - **预览卡补两行「进入后是什么样」**:`启用 N 台 MCP:…` 与 `启用 N 条记忆:…`。上面那些行说的是"会改什么",什么都不变时 MCP 那一段整段消失,读起来像缺了一块(用户 2026-09-23 指出)。服务器那行由引擎算(场景勾着的 ∩ 配置里存在的);记忆那行在客户端算,判据与记忆页那一行同源(`!shadowed && enabled !== false && 场景 active`),只有一处差别:目标场景按"进入后它就是活动场景"算。公共基线与全局不必写死场景名 —— 服务端给这两者的 `active` 恒为 true。
77
+ - **预览卡的按钮改成两颗**:「先不进入」删掉 —— 它与右上角的「关闭」是同一个动作的两颗按钮;换成「不再显示」= 关掉卡片 + 以后不再弹(也不进入)。恢复的入口是场景页右上角新增的**「关闭提醒 / 开启提醒」**按钮(文字写的是**动作**:正在弹就写「关闭提醒」)。这项设置落在侧车 `scene-settings.json`,**刻意不进场景冻结** —— 它是界面提示,锁着场景的人在场景页照样该能关掉提醒。
78
+ - **预览卡里的技能只显示名字**:键是 `<来源>/<名字>`,而自定义来源的键是一串机器名(`custom-d38da02b873bdb5c/brainstorming`)—— 铺在卡上没人认得出那是哪个技能,现在只取最后一段。
79
+ - **注入实况那三个数改成只数「最近这一段对话」**:投递 / 调用 / 采纳原来是进程级累加,开着 DSH 用一下午之后「注入 8 次 · 从未调用」讲的是"今天这台机器",而人看这块面板问的是"我眼前这一段里模型用没用"。三组计数改挂按会话身份建的账本 —— 身份本来就有(采纳判定的"正文在不在现场"早就按 agent 记),改的只是把计数也挂上去。观测面跟着一起按会话记,`调用 = 0` 该读成"真没用"还是"遥测没接上"也随之变准。
80
+ - **场景描述上限 60 → 300 字**,并删掉「最多 60 字;超出部分在卡片上省略。」:卡片那一行靠 CSS 省略号截,再长也只占一行、撑不高卡片 —— 60 卡的是"能存多少",给的理由说的却是"显示多少",因果对不上。
81
+ - **四个注入上限重新校准**:记忆段 256 KiB → **128 KiB**;技能 / 子智能体 / MCP 三条目录 60 → **50**;MCP 备注 200 → **300** 字。目录对齐在 50 条,横向看体积才有可比性。提示词域未动(64 KiB)。
82
+ - **五张手写门禁清单合成一份 op 登记表**:`WRITE_OPS` / `SENSITIVE_OPS` / 场景冻结 / 档案同步 / 锁定注解各自抄一份 op 名字,中间**没有任何约束** —— 这条纪律历史上失守过四次,而失守的症状从来不是报错,是"没配令牌也能写"或"锁定的场景能被改"。现在 114 个 op 每一个在 `src/op-registry.ts` 登记一条判据,五张清单由它派生;**派生结果与重构前逐条相同**(36 / 2 / 51 / 9 / 5 / 2 / 1,一条不差)。启动时再拿真实 op 表反向对账四个方向,对不上就在兼容页挂一条降级。
83
+ - **注入实况顶部多了成本一行**:「累计约 X · 最费某域 · 重发最多某域」。用"当前正文 × 该域投递次数"估,中途改过内容的话历史那几次不算现在的体积,所以带"约"。纯汇总,不动任何发送文本。
84
+ - **`memory_manager_write` 的描述写清"什么不该记"**:能从代码 / 配置 / git 重新推导的一律不写、建前先查重。execute 里做一次名字与描述的相似比对,命中就在回执后附一行 —— **只说不拦**,猜错一次就把该记的东西记不下去,比多记一条代价大。
85
+ - **`skill_manager_read` 在官方 `skill` 工具在场的会话里自动让位**:两者是同一件事(按名字给正文),标准类预设下官方那个在,第二份就是白付的 174 tok/轮。判据抄官方自己的写法(`dsh-tool-skill/lib/index.js:207` 的 `ctx.tools.get('skill', agent) === skillTool`)—— 拿 agent 当 scope 问"它解析得到吗",比读预设组合文件更准:观察的是**这个 agent 实际能看见什么**(限定到该 scope 的同名 shadow 也算数)。判不出来时**不让位**(少一条拿正文的路,比多花 174 tok 糟)。让位是逐会话的:极简那类预设没有官方加载器(`presets/minimal/agent.cordis.yml` 里只有两个持久 shell 工具),我们的工具留着 —— 那正是它被造出来的场景;标准类预设下"读一个被你关掉的技能正文"这种管理动作由面板承担。
86
+ - **`subagent_manager_run` 的描述删掉与注入重复的那半句**:与官方 `subagent` / `subagent_fork` 的分界规则,注入通道的 `how` 行(`context-inject.ts` 的 `DOMAIN_FRAME.subagents`)已经逐字说过一遍,而两份都在每轮上下文里 = 同一件事付两次 token。留注入那份(它出现在"正在选工具"的那一刻)。实测 1,808 → 1,628 字节(452 → 407 tok),全表 3,498 → 3,453。代价如实记下:把子智能体域关掉、或走压制型预设时,那句分界就没人说了 —— 模型只剩描述与 `agent` 参数说明("Persona name from subagent_manager_list"),够它认出这条是带人设的委派通道,但"没有人设贴合时才用官方那两个"没了。
87
+
88
+ ### 修复
89
+
90
+ - **自定义技能目录里的技能"列得出、调不动"**:技能页与官方目录都会把 `~/.dsh/skills-SuperWork`(及任何自定义目录)里的技能列给模型,模型照名字去调却拿到 `unknown or no longer available`。根因是 provider 内部两份清单:列表用 `userRoots() + customRootsFromState()`(全集),`getProviderSkill` 却只用 `rootByKey()` —— 后者只看五个静态根,自定义根住在状态文件里恒取不到,于是静默返回"没有这个技能"。补上按 `custom-<hash>` 解析那支。**已用真实数据核验**(修复后取回 6109 / 2260 字正文)。
91
+ - **「采纳」不再把「已清空」通知当成正文**:那句提示写的是"调用发生时正文正在上下文里",代码算的却是"该域在这个会话里说过话" —— 域清空时发的那条通知同样带域标记。结果是**用户把某域关掉之后**模型凭工具描述去调它,照样记一次采纳,第三列其实一直是第二列的复本。建现场集合时按 `form` 挑掉通知条目,并显式移出"正是这一步被清空"的那些域(通知这会儿还没落到会话表面上)。仅遥测判定,不动发送文本与去重键。
92
+ - **预览卡把"没在跑的服务器"报成「停用 N 个工具」**:进入场景的预览卡拿 MCP 停用表的**目标态**与现状逐台比对,而"场景里没勾这台 = 整台停用"在计划里就是一条 `服务器/*` —— 于是 6 台**从来没启用过**的服务器被列成「停用 6 个 MCP 工具:context7/*、fastgraph/* …」(用户实测截图)。服务器没在跑的时候,那张停用表只是记账:记成"整台停用"没有任何可见效果,把它读成"要停用它们的工具"是假话。现在工具级只报**前后都在跑**的服务器(逐工具开关真正起作用的情形),服务器级的改动仍由「停用 N 台服务器」那行如实说。
93
+ - **README 关于子智能体工具那句是错的**:原文写 `_list` / `_run` "依赖宿主挂载 `dsh-subagent-*`,缺席时**不注册**(此时 13 个,界面不提示)"。读代码对不上 —— provider 缺席不影响注册,是 `ensureProvider` 在**调用那一刻**抛「子代理服务未挂载」;而真正的注册失败会逐个记下来,随子智能体页横幅与 `preset-tools` 的 `unavailable` **显示在界面上**。现在按实际写,并说明那四个管理侧工具与 provider 无关。
94
+
95
+ ---
96
+
13
97
  ## [0.12.1] - 2026-09-22
14
98
 
15
99
  ### 修复
package/README.md CHANGED
@@ -12,14 +12,13 @@
12
12
 
13
13
  **简体中文** · [English](README_EN.md) · [Changelog](CHANGELOG.md) · [版本更新概要](docs/update.md)
14
14
 
15
- - DeepSeek Harness 的 **MCP、技能、场景、记忆、子智能体、提示词与归档会话**管理插件。
16
- - 八个页签:**场景**、**MCP**、**技能**、**子智能体**、**提示词**、**记忆**、**会话**、**兼容**。
15
+ DeepSeek Harness 的 **MCP、技能、场景、记忆、子智能体、提示词与归档会话**管理插件。八个页签:场景 / MCP / 技能 / 子智能体 / 提示词 / 记忆 / 会话 / 兼容。
17
16
 
18
17
  ```sh
19
18
  dsh plugin --profile web add dsh-plugin-tool-management@latest
20
19
  ```
21
20
 
22
- 装完硬刷新浏览器(Cmd/Ctrl+Shift-R),设置 → **工具** 即安装成功。不手改 `cordis.patch.yml`,不碰技能源文件,重启与升级后配置依旧。
21
+ 装完硬刷新浏览器(Cmd/Ctrl+Shift+R),设置 → **工具**。插件只写自己的文件,不改技能源文件;重启与升级后配置都在。
23
22
 
24
23
  ---
25
24
 
@@ -40,20 +39,20 @@ dsh plugin --profile web add dsh-plugin-tool-management@latest
40
39
 
41
40
  一句话:**把「工作 / 写作 / 编程」各配成一套场景,点一下整套切换;插件管的东西,模型都看得见。**
42
41
 
43
- | 亮点 | 说明 |
44
- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
- | 一键换场景 | 每个场景各配一套:用哪些 MCP 服务器、哪些技能、哪些人设、哪些记忆;点一下整套切换,关掉自动还原 |
46
- | 记忆自动送到模型眼前 | 每个场景下写几段 `.md` 就是它的资料库,正文自动进上下文,不用每次复制粘贴 |
47
- | 给 MCP 服务器写备注 | 像「A 不可用时改用 B 兜底」这种话写进备注,模型看得到,会照做 |
48
- | 单个工具也能关 | 一台服务器里只停掉某个工具,模型看不见也调不到;「重启」只重连,不会偷偷改变开关 |
49
- | 技能状况一眼看穿 | 哪些在生效、哪些被同名技能覆盖、哪一份是首选,都标得清清楚楚 |
50
- | 子智能体 = 一个文件一个角色 | 写一份角色说明就能派活;跑完只回结果、不占你的会话记录;哪些角色能用还能按场景定 |
51
- | 提示词备好几套 | AGENTS.md 可以存多份(简洁模式 / 教学口吻……),一键切换;场景可以各自绑一份 |
52
- | 会话不再丢 | 归档按项目分组、能搜、能批量恢复;Claude Code / Cursor / Codex 的聊天记录都能导进来 |
53
- | 模型一定看得见 | 插件管的内容(记忆 / MCP / 技能 / 子智能体 / 提示词)会主动告诉模型,每个域各发一条、内容没变不重复;极简模式下默认不注入(跟随预设),可在「兼容」页逐项打开 |
54
- | 锁住就不怕手滑 | 场景可以上锁:MCP / 技能 / 子智能体 / 记忆 / 提示词五个域的**增删改**整体只读,先解锁才能改(场景本身的新建/改名/绑定/启停切换、回收站、重启等不在冻结清单内,见「场景锁定」) |
55
- | 删了能找回,配好能带走 | 技能 / 记忆 / 人设 / 提示词 / 场景的删除都进回收站,随时恢复;它们都能勾选打包成 zip 再导回来。**会话历史是例外:永久删除不经回收站,不可恢复** |
56
- | 安全、不添乱 | 密钥默认打码、看明文要令牌;只写自己的文件,技能源文件一个不动,升级重启配置都在。**打码只管界面展示**:密钥在 `cordis.patch.yml` 里始终是明文,每次改配置还会连带产生最多 5 份明文备份副本(见「配置与安全」) |
42
+ | 亮点 | 说明 |
43
+ | --------------------------- | ----------------------------------------------------------------------------------------- |
44
+ | 一键换场景 | 每个场景各配一套 MCP / 技能 / 人设 / 记忆,进入时整套切换、退出时还原;模型也能按你说的切 |
45
+ | 记忆自动送到模型眼前 | 每个场景下写几段 `.md` 就是它的资料库,正文自动进上下文,不用每次复制粘贴 |
46
+ | 给 MCP 服务器写备注 | 「A 不可用时改用 B 兜底」这类话写进备注,模型每轮都看得到,会照做 |
47
+ | 单个工具也能关 | 一台服务器里可以只停某个工具,模型看不见也调不到;「重启」只重连,不改开关状态 |
48
+ | 技能状况一眼看穿 | 哪份在生效标「首选」,被同名覆盖的标出来源 |
49
+ | 子智能体 = 一个文件一个角色 | 写一份角色说明就能派活;跑完只回结果、不占你的会话记录 |
50
+ | 提示词备好几套 | `AGENTS.md` 可以存多份、一键切换;场景可以各自绑一份 |
51
+ | 会话不再丢 | 归档按项目分组、能搜、能批量恢复;Claude Code / Cursor / Codex 的记录能导进来 |
52
+ | 模型一定看得见 | 六个域各注入一条上下文,内容没变不重发;压制型预设下默认不注入,可在「兼容」页开 |
53
+ | 锁住就不怕手滑 | 场景可以上锁:五个域的增删改整体只读,先解锁才能改 |
54
+ | 删了能找回 | 技能 / 记忆 / 人设 / 提示词 / 场景的删除都进回收站(会话永久删除是例外) |
55
+ | 安全、不添乱 | 只写自己的文件;密钥默认打码、看明文要令牌 |
57
56
 
58
57
  ## 快速开始
59
58
 
@@ -64,7 +63,7 @@ dsh plugin --profile web add dsh-plugin-tool-management@latest # 安装 / 更
64
63
  dsh plugin --profile web remove dsh-plugin-tool-management # 卸载
65
64
  ```
66
65
 
67
- 装完硬刷新浏览器,设置 → **工具** 出现八栏即成功。客户端改动热加载,宿主侧改动需重启 `dsh web`。
66
+ 装完硬刷新浏览器,设置 → **工具** 出现八栏即成功。界面改动即时生效,宿主侧改动需重启 `dsh web`。
68
67
 
69
68
  也可以让模型代劳:
70
69
 
@@ -74,139 +73,116 @@ dsh plugin --profile web add dsh-plugin-tool-management@latest
74
73
  装完提醒我硬刷新浏览器。
75
74
  ```
76
75
 
77
- 模型可用 14 个工具管理上述功能(`mcp_manager_*` / `skill_manager_*` / `prompt_manager_*` / `memory_manager_*` / `subagent_manager_*`);脚本走 `POST /dsh-plugin-tool-management/api`(`{op, args}` 协议)。其中 `subagent_manager_list` / `subagent_manager_run` 依赖宿主已挂载 `dsh-subagent-*` provider 包,缺席时**不注册**(此时是 12 个,插件只写一条日志,界面不提示)。
78
-
79
- ---
80
-
81
76
  ## 功能
82
77
 
83
78
  ### 场景与记忆
84
79
 
85
- - **场景 = 分组,记忆 = `.md` 文件**。`memories/<场景>/<名>.md`,整篇正文自动注入上下文,文件名支持中文。
86
- - **单选启用**:同时只启用一个场景(其余置灰),关掉全部 = 只注入「全局」与 `_shared`。新场景默认不启动。
87
- - **场景绑提示词**:切换场景直接改写 `~/.dsh/AGENTS.md`(覆盖前 5 代备份,关掉自动恢复基线);预设挂不到官方 AGENTS.md 通道时(极简),改为把这份正文直接注入上下文。
88
- - **场景档案**:每个场景搭配 MCP 工具集 / 技能集 / 子智能体 / 记忆(任意组合);打开场景即应用并收窄注入,关闭按快照原文恢复(开关是唯一入口)。勾选集语义:**勾的启用、没勾的停用,整段没建 = 一个都没勾 = 该域全部停用**(所以「没配 MCP 工具集」的场景进去就是全部 MCP 停用,退出再开回来)。**场景内 MCP / 技能 / 子智能体这三个域的开关照常可用**——这里的改动会同步写进该场景的档案(当下生效、下次进这个场景照旧生效),只有**锁定**才冻结;记忆域的开关本来就是单一真相源,不经过档案。
89
- - **「进/出模式」与「启用场景」是两个独立状态轴**:界面开关是唯一入口(两轴齐动)。绕过界面直接调 HTTP API 时要注意:`scene-mode-set{scene:null}` 只退运行时快照,**不清空启用集** —— 记忆与提示词仍按该场景注入;要彻底退出还需 `rules-set-active{scenes:[]}`。
90
- - **导入**:`.md` / `.zip`(目录名 = 场景,bundle 带附件),同名跳过绝不覆盖,超限逐条回报。
91
- - **导出**:勾选记忆打包成 zip,保留「场景/名称」层级;bundle 型连目录里的附件一起打进去。只读源文件。
92
- - **注入预算**:默认 256 KiB,放不下的跳过并列出清单。删除进回收站。
93
- - **子代理会话不注入记忆**:记忆只在**顶层会话**注入 —— 它是"父会话的现场",不是子代理完成任务所需的事实;子代理的上下文只留「角色 + 任务」,要记忆可用 `memory_manager_list/read` 自己取,相关事实应由父代理写进 `task`。其余域不受影响(MCP / 技能 / 提示词照常注入,人设目录按各自的 `catalogDepth`)。
94
- - **场景锁定**:锁定后 MCP / 技能 / 子智能体 / 记忆 / 提示词五个域的**增删改**整体只读,界面禁用 + 服务端守卫双侧拦截;未启动不能上锁,锁定中不能关闭,先解锁再改。**冻结的是"内容",不是"场景本身"** —— 场景的新建 / 删除 / 改名 / 提示词绑定 / 启用切换 / 回收站的恢复与永久删除、MCP 重启、导出、注入设置与令牌设置都不在冻结清单内(它们不是"场景档案里的内容")。其中「启用切换」在锁定场景正在生效时会被拒绝 —— 清空启用集合会让模型侧的写门禁失去判据(运行时却还是那个场景的档案态)。
95
- - **删除场景 = 连记忆一起删**:场景记录、档案与全部记忆进同一条回收站条目,恢复按原路径整条放回;使用中的场景拒绝删除。场景名可改(连带目录与档案,记忆正文不动)。
80
+ - **场景 = 分组,记忆 = `.md` 文件**:`memories/<场景>/<名>.md`,整篇正文自动注入上下文,文件名支持中文。
81
+ - **「启用」与「进入」是两件事**:启用决定注入按哪个场景走(单选,全关 = 只注入「全局」与 `_shared`);进入才按档案整套切换 MCP / 技能 / 人设,并把绑定的提示词写进 `AGENTS.md`。界面开关与 `scene_manager_switch` 都两轴齐动。
82
+ - **场景档案**:每个场景搭配 MCP 工具集 / 技能集 / 子智能体 / 记忆(任意组合)。语义是**勾的启用、没勾的停用**,整段没建 = 该域全部停用;退出按进场景前的快照还原。场景内这三个域的开关照常可用,改动会同步写进档案。
83
+ - **场景锁定**:锁定后 MCP / 技能 / 子智能体 / 记忆 / 提示词五个域的增删改整体只读(界面与服务端双侧拦截);场景自身的启停、MCP 重启、导出不受影响。
84
+ - **删除场景 = 连记忆一起删**:场景记录、档案与全部记忆进同一条回收站条目,恢复时按原路径整条放回;使用中的场景拒绝删除。改名会连带改目录与档案。
85
+ - **导入导出**:`.md` / `.zip`(目录名 = 场景,bundle 带附件),同名跳过绝不覆盖;导出勾选记忆打包成 zip,只读源文件。
86
+ - **注入预算**:默认 128 KiB,放不下的跳过并列出清单。
87
+ - **子代理会话不注入记忆**:记忆是父会话的现场;子代理需要的事实应由父代理写进任务。
96
88
 
97
89
  ### 子智能体
98
90
 
99
- - **一个文件一个人设**:`agents/<人设>.md`,frontmatter 全可选。
100
- - **人设进系统提示词时会带一层角色框**:正文照原样使用,外面加 `# 角色:名` 标题、一行授权(「由调用方指定;与你的默认倾向冲突时以它为准;任务说要什么,怎么做以它为准」)和一句边界(决定**怎么做**,不改变**能做什么**),正文用 `## 角色定义` 围起来;框的语言跟随正文。这是为了让模型把它读成"我被指定为一个角色",而不是身份句后面多跟的两句话——**人设文件一个字都不用改**。框里不列 `description`(那是给**调用方**选人设用的;要给人设子代理看的简介写进正文)。
101
- - **工具限制按 Agent 预设**:每个预设一份白/黑名单(互相排斥),运行期按当前预设生效——堵掉旧「全体并集」名单换预设后子代理起不来的坑。两条必须知道的行为:**① 白名单会并回当前所有 `mcp__*` 工具**(官方 `allow` 是"清单之外全砍",不并进来会把 MCP 一起砍掉),所以「只勾了 `read`」拦不住一个暴露 shell 的 MCP 服务器;**② 名单里的名字全都对不上当前工具时按"不限制"处理**(fail-open,不是 fail-closed)——极简这类预设下白名单极易整份落空。反向的失败是「写了保留名 `run_code`」:官方 `tools.restrict()` 会直接抛错(子代理起不来),所以插件会把它从名单里剔掉并在结果里说明。
102
- - **`output:` 输出要求(硬性契约)**:frontmatter 里可写多行 `output:`(**一行一条**),角色框会把它渲染成 `## 输出要求(硬性)` 单独一节(在角色定义之后)。提示词写「这个角色怎么想」(散文),`output:` 写「产出必须长什么样」(可检验:格式、分级、必标项、禁止项)—— 只有一句抽象要求的角色,产出无法判定"执行了没有";写成可检验的才会被真的遵守。编辑器里有「输出要求(硬性)」多行框,也可以直接写进文件。
103
- - **即用即弃**:`subagent_manager_run` 带人设运行、只回传结果、不进 History。子代理的上下文只有**角色 + 任务**:场景记忆不注入(要记忆可用 `memory_manager_*` 自己取,相关事实应由父代理写进 `task`)。场景可绑定可用人设。
104
- - **两种上下文模式**:默认新起独立会话(子代理看不到本次对话,任务要写全);把 `inherit` 打开则子代理**继承本次会话已完成的轮次**(与官方 `subagent_fork` 同一套机制),任务只需写新增部分。**只继承已完成的轮次**——在本轮内发起委派时这一轮的内容继承不到(实测:父代理边读边委派,子代理仍从零开始),此时 `task` 要按"写全"对待。与官方两个委派工具(`subagent` / `subagent_fork`)的分界由插件写进上下文:**贴合人设的任务一律走这里**,官方那两个只在没有人设贴合、或需要后台任务(job)时用。
105
- - **启停开关**:停用的人设不注入上下文、模型不可见(文件不动);新建 / 导入 / 恢复**默认停用**(v0.8.5 起,与技能 / MCP 同口径),要委派先在这里打开。**进场景按档案勾选集全量对齐**(勾了的开、没勾的关,整段没建 = 全关),退出按进场景前的开关精确还原;场景内这个开关照常可用,改动会同步写进该场景的档案(只有**锁定**才冻结);退出场景时回到进场景前的状态。
106
- - **人设目录自动注入**:只列名字 + 描述,模型知道有哪些人设可委派;人设名可改,场景绑定自动跟着改。
107
- - **目录注入(`catalogDepth`)**:控制常驻的人设目录出现在哪些会话里 —— 默认 `1` = 只在顶层注入;写 `2` 让子会话也收到目录;`3` 到两层子会话;界面上的「不限制嵌套」写 `99`,任何深度的会话都注入。**它不限制嵌套**:子代理始终可以继续委派,那由官方决定(宿主侧默认 `maxDepth: 3`;该包不是本插件的依赖,本插件也不再向官方传 `maxDepth`)。「不限制嵌套」是**目录注入深度** `99`,不是递归上限。子会话看不到常驻目录时,仍可用 `subagent_manager_list` 查询全部人设。三处口径同源(目录过滤、域声明、实况状态),所以"界面说没注入、实际又注入了"这类分叉不会出现。
91
+ - **一个文件一个人设**:`subagents/<人设>.md`,frontmatter 全可选。`output:` 一行一条写"产出必须长什么样"(可检验的格式要求比一句抽象要求更容易被遵守)。
92
+ - **委派**:`subagent_manager_run` 带人设运行、只回最终结果、不进 History。默认新起独立会话(任务要写全);`inherit: true` 则继承本次会话**已完成的轮次**(本轮内容继承不到,此时任务仍要写全)。
93
+ - **启停与目录**:停用的人设不注入、模型不可见(文件不动);新建 / 导入 / 恢复默认停用。人设目录只列名字 + 描述;改名后场景绑定自动跟着改。
94
+ - **目录注入深度(`catalogDepth`)**:默认 `1` = 只在顶层会话注入目录,`99` = 任何深度都注入。它只管目录,不限制嵌套深度(那由宿主决定)。
95
+ - **工具限制按 Agent 预设**:每个预设一份白 / 黑名单(互斥)。两条要知道的行为:白名单会并回当前所有 `mcp__*` 工具,所以"只勾 read"拦不住暴露 shell 的 MCP 服务器;名单里的名字全都对不上时按"不限制"处理。
96
+ - **思考强度**:在高级选项里与「模型」并排,档位由所选模型声明。换模型后旧档位若不在新清单里会自动清掉并告知;指定了模型时留空 = 回落到该模型的默认档位,不是沿用主会话那一档。
108
97
 
109
98
  ### MCP 服务
110
99
 
111
- - **增删改查 + 即改即生效**:写入 `cordis.patch.yml`,HMR 自动生效。
100
+ - **增删改查、即改即生效**:写入 `cordis.patch.yml`,改前自动备份。级别分「全局 / 应用级」,新增默认全局。
112
101
  - **工具级开关**:单个工具可独立停用(模型看不见也调不到),整台支持批量。
113
- - **停着也能看清单**:服务器没在跑时仍显示上次见过的工具名与描述(标「上次运行时」);从没跑过的可以一键「启动服务器读取工具」。
114
- - **密钥打码**:默认把凭据**整值**打码成 `••••••`(只有名字像密钥的键会打:token / secret / password / auth / api key 这类;`$VAR`、`!!js` 是间接引用,不打码;URL 的 query 整段换成 `?<redacted>`),「显示密钥」要令牌。
115
- - **打码值永远不会被写进补丁文件**:编辑弹窗的密钥框预填的就是打码值,保存时插件会用补丁里的**原值**顶替(= 这一项没改);原值本身已经是打码值(说明真值曾经被写坏过)或压根没有原值时,该键被跳过并在界面提示 —— 前者要你重新填。补丁里已经存在打码值的密钥,列表页一进来就会告警。**URL 是同一种保护、另一套形态**:查询串被打成 `?<redacted>`,保存时同样按原值顶替;补丁里没有原值可顶替时**整次保存会被拒绝**并提示重新填写完整 URL —— 只删查询串会留下一个"能连上但鉴权失败"的地址,比报错更难发现。
116
- - **迁移与备份**:跨项目级/全局迁移失败自动回滚;JSON 导出导入。
117
- - **状态与备注自动注入**:列出当前真正可用的 server;**曾经连上过、现在连不上的也会列出并标注**(`(当前未连上;上次连上时 N 个工具)`)—— 这样模型才会说"它没连上,检查一下",而不是把"配了但连不上"读成"本机没配"、建议你装一个。从未连上过的不列。你的备注作为决策提示带给模型;级别分「全局 / 应用级」,新增默认全局。注:极简这类压制型预设默认不注入(模型可用 `mcp_manager_list` 读取服务器名、启停、工具数与备注)——想让它也注入,到「兼容」页的「注入」块打开开关。
102
+ - **停着也能看清单**:没在跑的服务器仍显示上次见过的工具名与描述(标「上次运行时」);从没跑过的可以一键启动读取。
103
+ - **备注**:每台服务器可写一句给模型的提示,随状态段一起注入。曾经连上过、现在连不上的服务器会列出来并标注 —— 这样模型会说"它没连上,检查一下",而不是建议你去装一个。
104
+ - **密钥打码**:默认把凭据整值打码(`$VAR`、`!!js` 这类间接引用不动;URL 查询串换成 `?<redacted>`),看明文要令牌。打码只管界面展示,详见「配置与安全」。
105
+ - **迁移与备份**:跨项目级 / 全局迁移失败自动回滚;支持 JSON 导出导入。
118
106
 
119
107
  ### 技能
120
108
 
121
109
  - **来源一览**:项目级 / DSH / Agents / Codex / Claude / 自定义目录,按来源分组。
122
- - **两组权限相反**:默认来源(DSH / 导入技能)必须读取但技能可删;外部目录可停用/移除但技能只读。
110
+ - **两组权限相反**:默认来源的技能可删可停;外部目录可以停用或移除,但里面的技能文件只读。
123
111
  - **移除 ≠ 停用**:移除 = 连目录都不扫(文件零改动,可恢复);停用 = 仍列出但不可调用。
124
- - **同名技能一眼看出谁在生效**:真实生效的那份标「首选」,被同名覆盖的标出来源;启用被覆盖的副本会明说「这样不会生效」。
112
+ - **同名谁在生效**:真正生效的那份标「首选」,被覆盖的标出来源;启用被覆盖的副本会明说"这样不会生效"。
125
113
  - **自定义目录 / ZIP 导入导出 / 回收站**。
126
- - **目录可注入**:预设没挂官方技能目录行(如极简)时,由本插件的注入域按「兼容」页的开关兜底送达(名字 + 简介;正文照旧读文件)。
127
114
 
128
115
  ### 提示词预设
129
116
 
130
- - 多套 `~/.dsh/AGENTS.md` 基线,一键应用(宿主每步比对该文件版本、变了才重读,下一轮对话生效),保留 5 代备份。
131
- - **记得「最近一次应用的是哪份」**:就算你手改过 `AGENTS.md`,模型问「现在用的哪份预设」也答得出来源(会注明「此后文件有变」)。
132
- - **描述**:每条预设可写一句「这份是干什么的」,只显示在插件界面里;它存在同目录的 `meta.json`,不进 AGENTS.md,也就不会被注入上下文。
133
- - 新建即可写正文,编辑可改 id(= 目录改名,场景绑定自动跟着改)。**被引用的不能删**(场景绑定 / `AGENTS.md` 当前内容 / 退出场景要恢复的那一份),删除进回收站。
134
- - **正文可注入**:预设没挂官方 AGENTS.md 行(如极简)时,`~/.dsh/AGENTS.md` 的正文由本插件的注入域兜底(64 KiB 上限;可在「兼容」页关掉)。
135
- - **场景接管期间「应用」= 把该场景改绑到那一份**(同步写进场景档案,绑定改完立刻重新对齐;未锁定时可用 —— v0.9 已把「应用别的预设会被拒绝」反转为改绑);**锁定时才拒绝**。退出场景时全局基线按快照恢复。
117
+ - 多套 `~/.dsh/AGENTS.md` 基线一键应用(下一轮对话生效),保留 5 代备份。
118
+ - **记得「最近一次应用的是哪份」**:就算你手改过 `AGENTS.md`,也答得出来源(会注明"此后文件有变")。
119
+ - 每条预设可写一句"这份是干什么的",只存在插件侧、不进 `AGENTS.md`。
120
+ - **被引用的不能删**(场景绑定 / 当前内容 / 退出场景要恢复的那一份),删除进回收站。
121
+ - 场景接管期间「应用」= 把该场景改绑到那一份(同步写进场景档案);锁定时拒绝。
136
122
 
137
123
  ### 历史会话
138
124
 
139
- - 按项目分组、搜索、批量恢复 / 永久删除、保留期自动清理。
140
- - 工作区登记被删后按会话目录重建分组,可一键重新登记。
141
- - 导入 Claude Code / Cursor / Codex / 任意文本;导出 Markdown / JSONL。**导出是可读转录,不是完整备份**:只保留 user / assistant 的文本块,工具调用、图片、思考过程与 token 统计都不在里面;Markdown 正文里出现的 `## User` 这类行在再次导入时会被当成轮次分界(导出侧不转义)。要留全量请用「归档」。
125
+ - 按项目分组、搜索、批量恢复 / 永久删除、保留期自动清理;工作区登记被删后可一键重新登记。
126
+ - 导入 Claude Code / Cursor / Codex / 任意文本;导出 Markdown / JSONL。**导出是可读转录,不是完整备份**:只保留 user / assistant 的文本块,工具调用、图片、思考过程与 token 统计都不在里面。要留全量请用「归档」。
142
127
 
143
128
  ### 宿主兼容
144
129
 
145
- 插件运行期用宿主同一批 `@deepseek-ai/*` 库——必须是同一份物理模块,否则判断退化成猜。
146
-
147
- - **「兼容」页**:宿主版本、能力可用数、每个动作走原生/适配/不可用、降级项与原因。体检本身只读,但这一页有两个明确的写入口:**访问令牌**(写 profile 的 `cordis.patch.yml`,重启生效)与**注入设置**(写 `inject-settings.json`,即时生效)。
148
- - **命令行**:`node scripts/doctor.mjs`(体检)、`node scripts/host-deps.mjs --fix`(依赖对齐)、`npm run sync:profile`(把构建产物镜像到 profile 里那份本地安装 —— `file:` 装的是硬链接拷贝,构建新增的文件不会自动过去)。
149
- - `minimal` 这类**压制型预设**(persona `complete` / 关闭运行时上下文)下,本插件的注入**默认停用**(跟随预设的设计意图),提示词与技能也因官方那两行没挂而缺席 —— 兼容页逐列标出,同一页的「注入」块可以按域强制打开。
150
- - **关掉「技能」「提示词」的勾选 = 真的不再注入**:这两项在标准类预设下由宿主自己送(插件让位),所以取消勾选会**连宿主那份一起停掉**(`skill-catalog` / `agent-instructions` 的消息在这一步不再放行)。其余三项(记忆 / MCP / 子智能体)宿主本来就不送,勾选完全生效。
151
- - **注入长什么样**:每个域一条 `<system-reminder>`,开头是 `## 标题` + **加粗的一句动作**(在哪个决策点该想起它)+ 工具名 / 触发条件,之后才是正文;正文里的 `</system-reminder>` 会被转义(你写的内容不能把框架提前关掉)。每条末尾一句「本份…取代本次会话中更早注入的同类…」——注入只在内容变化时重发,旧那份还留在上下文里,所以要写明以哪份为准。写法逐条对照 Claude Code 与 Codex CLI 的官方注入。
130
+ - **「兼容」页**:宿主版本、能力可用数、每个动作走原生 / 适配 / 不可用、降级项与原因。这一页有三个写入口:**访问令牌**(重启生效)、**注入设置**、**模型工具表**。
131
+ - **命令行**:`node scripts/doctor.mjs`(体检)、`node scripts/host-deps.mjs --fix`(依赖对齐)。
132
+ - **压制型预设**(`minimal` 这类)下本插件的注入默认停用(跟随预设的设计意图),可在「兼容」页按域强制打开。
133
+ - **关掉「技能」「提示词」的勾选 = 连宿主那份一起停**(这两域在标准预设下由官方送,插件让位);其余三域宿主本来就不送,勾选完全生效。
134
+ - **注入长什么样**:每个域一条 `<system-reminder>`,`# 板块标题` + 正文 + 一句"以本份为准",只写"现在是什么"、不写指令。你写的内容里出现 `</system-reminder>` 会被转义。
152
135
 
153
136
  ---
154
137
 
155
138
  ## 数据落点
156
139
 
157
- | 内容 | 位置 |
158
- | ------------------------------------------- | ---------------------------------------------------------------------------------- |
159
- | MCP 定义 | `~/.dsh/cordis.patch.yml`(插件只写它;改前自动备份到 hub 的 `backups/`) |
160
- | 技能策略 / 自定义目录 | `~/.dsh/tool-management/skills-state.json` |
161
- | 技能 / 记忆 / 人设 / 预设 | `~/.dsh/tool-management/{skills,memories,subagents,prompts}/` |
162
- | 子智能体启停 | `~/.dsh/tool-management/subagents-index.json` |
163
- | 回收站(技能/人设/预设/场景) | `~/.dsh/tool-management/trash/{skills,subagents,prompts,scenes}-trash/` |
164
- | 记忆回收站 | `~/.dsh/tool-management/memories-trash/`(**hub 根下独立目录,不在 `trash/` 里**) |
165
- | 归档账本 / 保留期 | `~/.dsh/tool-management/history-*.json` |
166
- | 记忆索引 / 场景 / 档案 | `~/.dsh/tool-management/memories-index.json` |
167
- | MCP 侧车(停用表 / 已知工具 / 备注 / 设置) | `~/.dsh/tool-management/mcp-*.json` |
168
- | 注入设置(五个域开关 / 压制型预设口径) | `~/.dsh/tool-management/inject-settings.json` |
169
- | 运行日志 / patch 备份 | `~/.dsh/tool-management/tool-management.log` · `backups/` |
140
+ | 内容 | 位置 |
141
+ | ------------------------------------------- | ------------------------------------------------------------------------- |
142
+ | MCP 定义 | `~/.dsh/cordis.patch.yml`(插件只写它;改前自动备份到 hub 的 `backups/`) |
143
+ | 技能策略 / 自定义目录 | `~/.dsh/tool-management/skills-state.json` |
144
+ | 技能 / 记忆 / 人设 / 预设 | `~/.dsh/tool-management/{skills,memories,subagents,prompts}/` |
145
+ | 子智能体启停 | `~/.dsh/tool-management/subagents-index.json` |
146
+ | 回收站(技能 / 人设 / 预设 / 场景) | `~/.dsh/tool-management/trash/{skills,subagents,prompts,scenes}-trash/` |
147
+ | 记忆回收站 | `~/.dsh/tool-management/memories-trash/`(在 hub 根下,不在 `trash/` 里) |
148
+ | 归档账本 / 保留期 | `~/.dsh/tool-management/history-*.json` |
149
+ | 记忆索引 / 场景 / 档案 | `~/.dsh/tool-management/memories-index.json` |
150
+ | MCP 侧车(停用表 / 已知工具 / 备注 / 设置) | `~/.dsh/tool-management/mcp-*.json` |
151
+ | 注入设置(六个域开关) | `~/.dsh/tool-management/inject-settings.json` |
152
+ | 模型工具表(关掉的工具 + 存下的方案) | `~/.dsh/tool-management/tool-table.json` |
153
+ | 场景页界面设置(进场景前弹不弹预览卡) | `~/.dsh/tool-management/scene-settings.json` |
154
+ | 运行日志 / patch 备份 | `~/.dsh/tool-management/tool-management.log` · `backups/` |
155
+
156
+ **插件安装目录里不存用户数据**(`dsh plugin update` 会整体替换该目录)。备份按**每份 patch 文件各留 5 份**(全局与每个 profile 各自计),一次批量操作就可能把某层的 5 个槽位吃掉。
170
157
 
171
- **插件安装目录里不存用户数据**(`dsh plugin update` 会整体替换该目录)。
158
+ ## 配置与安全
172
159
 
173
- **`backups/` 的保留份数是「每份 patch 文件各 5 份」**:备份名带层级标签(`.global` / `.profile-<名>`),所以全局与每个 profile 各自留 5 份 —— 不是全局共 5 份。一次批量操作(如 `mcpm-set-all`、进入场景的多次写)就可能把某个层级的 5 个槽位全吃掉、挤掉更早的版本。
160
+ | 字段 | 说明 |
161
+ | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
162
+ | `token` | 访问令牌。设了之后**所有写操作 + 明文密钥**都要求 `x-dsh-token`;不设时明文接口一律关闭。也可改用环境变量 `DSH_PLUGIN_TOOL_MANAGEMENT_TOKEN`。 |
163
+ | `tokenDisabled` | `true` = 令牌保留在配置里但当前不生效(兼容页「关闭保护」写的就是这一行)。写操作不再要求令牌,明文查看仍然要。 |
164
+ | `maxBodyBytes` | 请求体上限,默认 88 MiB。 |
174
165
 
175
- ## 配置与安全
166
+ **磁盘上的明文(必读)**:打码**只发生在界面展示**。MCP 的 `env` / `headers` 与插件自己的 `token` 在 `cordis.patch.yml`(及各 profile 副本)里始终是明文,而每次改配置前插件会把整份文件备份进 `~/.dsh/tool-management/backups/`(不加密、不轮转、卸载也不回收)—— 一份密钥最多有 `5 ×(含它的 patch 文件数)+ 1` 份明文副本。令牌门禁管的是"谁能通过 HTTP 拿到明文",**管不到磁盘读取**:真正的防线是操作系统的文件权限。清理入口:**设置 → 工具 → 兼容 → 「清理旧备份」**(可按层级各删最旧的 N 份,弹窗内二次确认),也可以手工删那个目录下的旧文件。
176
167
 
177
- | 字段 | 说明 |
178
- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
179
- | `token` | 访问令牌。设了之后**所有写操作 + 明文密钥**都要求 `x-dsh-token`;**不设时明文接口一律关闭**。也是 curl / 局域网的逃生门。不想把令牌写进配置文件时,可改用环境变量 `DSH_PLUGIN_TOOL_MANAGEMENT_TOKEN`(两者都给了以 `config.token` 为准;`tokenDisabled: true` 会让两者都不生效)。 |
180
- | `tokenDisabled` | `true` = 令牌**保留在配置里**但当前不生效(在兼容页点「关闭保护」写入的就是这一行)。写操作不再要求令牌;明文查看仍然要凭令牌(明文本身就是凭据)。随时可以在兼容页「开启保护」开回来,不需要重新输一遍。 |
181
- | `maxBodyBytes` | 请求体上限,默认 88 MiB。 |
182
-
183
- **关于磁盘上的明文(必读)**:打码**只发生在界面展示**。MCP 的 `env` / `headers` 与插件自己的 `config.token` 在 `~/.dsh/cordis.patch.yml`(及其 profile 副本)里始终是明文,而每次改配置前插件会把**整份文件**备份进 `~/.dsh/tool-management/backups/`(按文件各留 5 份、不加密、不轮转、卸载也不回收)—— 于是一份密钥最多会有 `5 ×(含它的 patch 文件数)+ 1` 份明文副本。令牌门禁管的是"谁能通过 HTTP 拿到明文",**管不到磁盘读取**:本机任何对该目录有读权限的进程都能一次读走全部凭据。唯一的真实防线是操作系统的文件权限。**要清理:设置 → 工具 → 兼容 → 「清理旧备份」**(在「刷新」旁边,按钮上直接写着现有份数),可选**每个层级各一组档位**(N 份 = 把那层最旧的 N 份删掉,档位到该层现有份数为止、默认 2 份;两层各自选,所以合计能凑出任意数 —— 奇数也行)—— 每行下面写着"删完还剩几份",删除要在弹窗里再确认一次(确认那行会给出合计文件数);只删备份文件、不碰当前配置。也可以手工删除 `~/.dsh/tool-management/backups/` 下的旧文件。
184
-
185
- - **浏览器**:读写走 cookie,不需要 token;但**明文密钥**(显示密钥 / 导出)要令牌。**令牌在「工具 → 兼容」页的「访问令牌」块管理**(与页面无关的固定入口)。那一块是**一枚状态胶囊 + 一句实况 + 三行**:行名说"这一步管到哪儿"、按钮说动词,胶囊只回答"保护开没开、这一程解锁没有"。
186
- - **本次启动**:填一次,管到 DSH 退出(只写本机浏览器)。填对了,这一行**就地**变成一枚绿胶囊「已解锁」+「清除」(不是塌成一颗按钮 —— 那样看着像刚填的东西没了),宿主才认这串令牌、下面两行才动得了;宿主侧还没有令牌时这一行不出现(没东西可验)。
187
- - **宿主配置**:写进 profile 的 `cordis.patch.yml`(只动那两行,注释与 `!!js` 守卫原样保留,改前自动备份),重启 DSH 生效。宿主还没配时这一行的按钮就是主操作(「设置令牌」,点开输**两遍**新令牌防手滑);已配之后换令牌点「修改令牌」,表单里多一栏**当前令牌** —— 换令牌要能证明知道当前令牌,而**解锁过不算**(与「关闭保护」同一条口径):必须在表单里当场再输一次;点开时光标就落在这一栏,三栏**竖排**、保存与取消跟在下面(表单打开时只剩这一行,回车 = 保存),三栏齐了「保存新令牌」才可按,输错时那一格会标红。
188
- - **删除令牌**(与「修改令牌」同一行):把 `token` 与 `tokenDisabled` 两行从配置里删掉,回到**还没设置**那一态 —— 写操作不再要凭证、明文密钥随之不可见。同样就地展开确认框、当场再输一次当前令牌;回执会如实提醒"旧备份里仍有明文副本"(备份是整份配置的副本,要一并清掉用页头的「清理旧备份」)。想保留令牌、只是暂时不要门禁时用「关闭保护」,别用删除。
189
- - **保护开关**:点「关闭保护」会**就地展开确认框(此时只有这一行,与「修改令牌」同一规矩)**,要再输一次当前令牌(解锁过也要输 —— 请求头里那份已验证的凭证对"关闭"不作数,防的是解锁之后顺手一点就把防护关了);确认后只写一行 `tokenDisabled: true`,**令牌原样留在配置里**,随时点「开启保护」就能开回来(不必重新输一遍)。关闭后写操作不再要求令牌;**明文查看仍然要凭令牌**(明文本身就是凭据)。开启方向沿用原口径:解锁过,或输入框里填着当前令牌即可 —— 否则"能打开 GUI 就能关掉保护",令牌等于白配。
190
- - **状态胶囊**:还没有令牌 / 保护已关闭 / 保护已开启 · 待解锁 / 保护已开启 · 已解锁。配置改了还没重启时,胶囊下面会多一条橙色横幅说清(胶囊说的是当前进程)。
191
- - **令牌功能没在生效时,不再挂那句「去填令牌」**:那句话只在实际有门禁(当前进程存在生效令牌)时才留下;关掉或没配时它会被收掉,由面板上的状态胶囊说出实际情况。
192
- - **提示出现在哪里**:令牌没过时的那句话(含右侧的「填写令牌」按钮)**恰好只有一份** —— 有弹窗打开时在弹窗里(它是当前操作的阻塞原因,放在最显眼处),没有弹窗时在页签下方。它与"当前是哪一页、那一页怎么渲染错误"无关,所以任何一个入口(含各种弹窗里的提交、导入、导出、批量操作)都不会漏提示。
168
+ - **浏览器**:读写走 cookie,不需要令牌;**明文密钥**(显示密钥 / 导出)要令牌。令牌在「兼容」页的「访问令牌」块管理:本次启动填一次管到 DSH 退出;写进配置文件要重启生效。
169
+ - **销毁方向一律要当场再输一次当前令牌**(关闭保护 / 修改 / 删除)—— 本次启动解锁过不算,否则"能打开界面就能关掉保护"。
193
170
  - **curl / 脚本**:带 `x-dsh-token`,或带浏览器 cookie。
194
- - **HTTP 状态码口径**:除安全栅栏的 401/403 外,令牌缺失、业务失败等一律 HTTP 200 + `{ ok: false, error }` —— 脚本分流请以 `body.ok` 为准,不要按状态码。
195
- - **栅栏的降级面**:宿主缺 `connection` 服务时,栅栏退到「Host 回环 + 同源」判定(没有浏览器 cookie 可验),本机任意进程伪造 `Host: localhost` 即可调用写 op —— 把端口转发到局域网/公网的场景**务必配令牌**,它是这条降级面上的最后一道门。
196
- - **`dir-list` 的暴露面**:「选择文件夹」弹窗靠它逐级列目录,因此通过栅栏/令牌的调用方可列出**任意绝对路径**的目录(只读)。这是功能性设计,不是漏洞;但请勿把端口暴露给不可信网络。
197
- - **端口转发到公网**:建议配 token——防陌生人注入 MCP 命令(等同远程执行)与窃取密钥。
171
+ - **HTTP 状态码**:除安全栅栏的 401 / 403 外,一律 HTTP 200 + `{ ok: false, error }` —— 脚本分流请以 `body.ok` 为准。
172
+ - **端口转发**:宿主缺 `connection` 服务时栅栏退到「Host 回环 + 同源」判定,本机进程伪造 `Host: localhost` 即可调用写 op。转发到局域网 / 公网的场景**务必配令牌** —— 陌生人注入 MCP 命令等同远程执行。「选择文件夹」弹窗用的 `dir-list` 能列出任意绝对路径(只读),同一条前提。
198
173
 
199
174
  ## 常见问题
200
175
 
201
- | 现象 | 解决 |
202
- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
203
- | 装完没有页面 | 硬刷新;不行重启 DSH。 |
204
- | 重复 MCP 页签 | 删 `cordis.patch.yml` 里的旧 loader 行后重启。 |
205
- | 改坏配置 DSH 起不来 | 从 `~/.dsh/tool-management/backups/` 取最近的 `cordis.patch.yml.<层级>.bak-<时间戳>` 覆盖回去(每份 patch 各留 5 份)。 |
206
- | 升级 DSH 后动作不可用 | 设置 → 工具 → **兼容** 看原因;`doctor.mjs` → `host-deps.mjs --fix`。 |
207
- | `approval=never` 还要确认吗 | 不弹卡,直接放行并记日志;想问回来切回「工作区内修改」。 |
208
- | `subagent_manager_run` 报 provider 不可用 | 对应 provider 没注册:`spawn`(默认)/ `fork`(`inherit`)分别挂 `@deepseek-ai/dsh-subagent-spawn-in-process` / `-fork-in-process` 后重启。 |
209
- | 场景绑了 A 人设,官方 `subagent` 还跑别的 | 官方那两个是宿主的工具,本插件管不到它们的可见性;插件会把分界写进上下文(贴合人设的一律走 `subagent_manager_run`,官方只在没人设贴合或要后台跑时用),`inherit` 也已对齐 fork 的继承能力。 |
176
+ | 现象 | 解决 |
177
+ | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
178
+ | 装完没有页面 | 硬刷新;不行重启 DSH。 |
179
+ | 重复 MCP 页签 | 删 `cordis.patch.yml` 里的旧 loader 行后重启。 |
180
+ | 改坏配置 DSH 起不来 | 从 `~/.dsh/tool-management/backups/` 取最近的 `cordis.patch.yml.<层级>.bak-<时间戳>` 覆盖回去(每份 patch 各留 5 份)。 |
181
+ | 升级 DSH 后动作不可用 | 设置 → 工具 → **兼容** 看原因;`doctor.mjs` → `host-deps.mjs --fix`。 |
182
+ | 模型调不到某条工具 | 「兼容」页的**模型工具表**看它是不是被关了(出厂默认关着 15 条);面板和脚本不受影响。 |
183
+ | `approval=never` 还要确认吗 | 不弹卡,直接放行并记日志;想问回来切回「工作区内修改」。 |
184
+ | `subagent_manager_run` 报 provider 不可用 | 对应 provider 没注册:`spawn`(默认)/ `fork`(`inherit`)分别挂 `@deepseek-ai/dsh-subagent-spawn-in-process` / `-fork-in-process` 后重启。 |
185
+ | 场景绑了 A 人设,官方 `subagent` 还在跑别的 | 官方那两个是宿主的工具,本插件管不到它们的可见性;插件会把分界写进上下文 —— 贴合人设的走 `subagent_manager_run`,官方只在没有人设贴合或要后台跑时用。 |
210
186
 
211
187
  ---
212
188
 
@@ -215,14 +191,14 @@ dsh plugin --profile web add dsh-plugin-tool-management@latest
215
191
  ```bash
216
192
  npm install
217
193
  npm run build # tsc + 同步客户端
218
- npm test # 构建 + i18n + 契约测试(纯函数不变量与宿主契约;渲染类测试已于 2026-09-19 移除)
194
+ npm test # 构建 + i18n + 契约测试(纯函数不变量与宿主契约)
219
195
  npm run check:i18n # 词典自检
220
196
  npm run doctor # 宿主兼容体检
221
197
  ```
222
198
 
223
199
  `lib/` 不入版本库,克隆后先 `npm run build`。改完重启 `dsh web` 才生效。运行时依赖:`fflate`(导出打包)、`js-yaml`(写宿主补丁前的解析校验,惰性加载);`@deepseek-ai/*` 一律用宿主那份。
224
200
 
225
- > **部署注意**:`npm run build` 的 profile 镜像清单**不含 `node_modules`**,所以本地联调时新增的运行时依赖(如 `js-yaml`)要么在 profile 侧装一份,要么接受「补丁写入校验跳过并上报」的降级 —— 校验器装不上只影响这一道保险,不阻断写入。`npm install` 装到 profile 的正式安装不受影响(依赖会随包安装)。
201
+ > **部署注意**:`npm run build` 的 profile 镜像清单**不含 `node_modules`**,本地联调时新增的运行时依赖(如 `js-yaml`)要么在 profile 侧装一份,要么接受"补丁校验跳过并上报"的降级。`npm install` 装到 profile 的正式安装不受影响。
226
202
 
227
203
  ## 许可证
228
204