dsh-plugin-tool-management 0.13.0 → 0.15.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 (62) hide show
  1. package/CHANGELOG.md +560 -474
  2. package/README.md +91 -123
  3. package/README_EN.md +99 -126
  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 +391 -337
  21. package/lib/audit-log.js +157 -0
  22. package/lib/client.js +4204 -2454
  23. package/lib/compat/patch-dialect.js +3 -1
  24. package/lib/compat/preset-reach.js +43 -9
  25. package/lib/compat/probe.js +149 -7
  26. package/lib/context-inject.js +91 -35
  27. package/lib/index.js +479 -114
  28. package/lib/mcp/loader-token.js +53 -28
  29. package/lib/mcp/manager.js +149 -21
  30. package/lib/mcp/secret-guard.js +21 -0
  31. package/lib/mcp/state-section.js +13 -11
  32. package/lib/memories/archive-engine.js +70 -2
  33. package/lib/memories/archive.js +8 -1
  34. package/lib/memories/constants.js +72 -8
  35. package/lib/memories/index-io.js +7 -1
  36. package/lib/memories/projection.js +67 -31
  37. package/lib/memories/service.js +17 -2
  38. package/lib/memories/snapshot.js +113 -22
  39. package/lib/op-registry.js +26 -6
  40. package/lib/ops/candidates.js +11 -0
  41. package/lib/ops/compat.js +113 -31
  42. package/lib/ops/scene-records.js +34 -0
  43. package/lib/ops/scene-sync.js +12 -1
  44. package/lib/ops/sessions.js +24 -9
  45. package/lib/ops/snapshot.js +596 -0
  46. package/lib/prompts/service.js +25 -2
  47. package/lib/scenes/candidates.js +66 -5
  48. package/lib/sessions/bridge.js +5 -0
  49. package/lib/sessions/workspace.js +17 -5
  50. package/lib/skills/core.js +105 -3
  51. package/lib/skills/service.js +34 -2
  52. package/lib/subagents/service.js +37 -4
  53. package/lib/subagents/tools.js +11 -4
  54. package/lib/tools/deps.js +16 -1
  55. package/lib/tools/mcp.js +291 -50
  56. package/lib/tools/memory.js +131 -80
  57. package/lib/tools/prompt.js +27 -13
  58. package/lib/tools/scene.js +351 -0
  59. package/lib/tools/skills.js +93 -17
  60. package/lib/tools/subagent.js +56 -45
  61. package/lib/tools/table.js +208 -15
  62. package/package.json +24 -20
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,147 +73,116 @@ dsh plugin --profile web add dsh-plugin-tool-management@latest
74
73
  装完提醒我硬刷新浏览器。
75
74
  ```
76
75
 
77
- 模型可用 20 个工具管理上述功能(`mcp_manager_*` / `skill_manager_*` / `prompt_manager_*` / `memory_manager_*` / `subagent_manager_*`);脚本走 `POST /dsh-plugin-tool-management/api`(`{op, args}` 协议)。
78
-
79
- 这 20 个工具的说明合计约 3,450 token,而工具表**每一轮请求都随工具发一遍**。用不上的可以在「兼容」页的**「模型工具表」**块里逐个关掉(也能按域全关)——关掉的整份不进请求,这是唯一真省 token 的办法。关掉之后模型调不到它,**面板不受影响**(114 个 op 与工具表互不相干)。默认一个都不关。
80
-
81
- 另外有一个工具会**自动让位**:会话里已经挂了官方 `skill` 工具(标准类预设都挂)时,我们那个「按名字读技能正文」的 `skill_manager_read` 不再下发 —— 两份干的是同一件事。极简模式没有官方那件,我们的照旧留着。
82
-
83
- 其中 `subagent_manager_run` 依赖宿主已挂载 `dsh-subagent-*` provider 包 —— 但**注册不依赖**它:provider 缺席时工具照样注册,是**调用那一刻**报「子代理服务未挂载(ctx.subagents 缺失)」(`src/subagents/service.ts` 的 `ensureProvider`)。另外四个(`_list` / `_set_enabled` / `_create` / `_update`)动的只是 hub 里的人设文件与启停名单,与 provider 无关,任何时候都该可用。真正的注册失败(宿主 API 变更等)会被逐个记下,随子智能体页的横幅与 `preset-tools` 的 `unavailable` 一起显示出来。
84
-
85
- ---
86
-
87
76
  ## 功能
88
77
 
89
78
  ### 场景与记忆
90
79
 
91
- - **场景 = 分组,记忆 = `.md` 文件**。`memories/<场景>/<名>.md`,整篇正文自动注入上下文,文件名支持中文。
92
- - **单选启用**:同时只启用一个场景(其余置灰),关掉全部 = 只注入「全局」与 `_shared`。新场景默认不启动。
93
- - **场景绑提示词**:切换场景直接改写 `~/.dsh/AGENTS.md`(覆盖前 5 代备份,关掉自动恢复基线);预设挂不到官方 AGENTS.md 通道时(极简),改为把这份正文直接注入上下文。
94
- - **场景档案**:每个场景搭配 MCP 工具集 / 技能集 / 子智能体 / 记忆(任意组合);打开场景即应用并收窄注入,关闭按快照原文恢复(开关是唯一入口)。勾选集语义:**勾的启用、没勾的停用,整段没建 = 一个都没勾 = 该域全部停用**(所以「没配 MCP 工具集」的场景进去就是全部 MCP 停用,退出再开回来)。**场景内 MCP / 技能 / 子智能体这三个域的开关照常可用**——这里的改动会同步写进该场景的档案(当下生效、下次进这个场景照旧生效),只有**锁定**才冻结;记忆域的开关本来就是单一真相源,不经过档案。
95
- - **「进/出模式」与「启用场景」是两个独立状态轴**:界面开关是唯一入口(两轴齐动)。绕过界面直接调 HTTP API 时要注意:`scene-mode-set{scene:null}` 只退运行时快照,**不清空启用集** —— 记忆与提示词仍按该场景注入;要彻底退出还需 `rules-set-active{scenes:[]}`。
96
- - **导入**:`.md` / `.zip`(目录名 = 场景,bundle 带附件),同名跳过绝不覆盖,超限逐条回报。
97
- - **导出**:勾选记忆打包成 zip,保留「场景/名称」层级;bundle 型连目录里的附件一起打进去。只读源文件。
98
- - **注入预算**:默认 128 KiB,放不下的跳过并列出清单。删除进回收站。
99
- - **子代理会话不注入记忆**:记忆只在**顶层会话**注入 —— 它是"父会话的现场",不是子代理完成任务所需的事实;子代理的上下文只留「角色 + 任务」,要记忆可用 `memory_manager_list/read` 自己取,相关事实应由父代理写进 `task`。其余域不受影响(MCP / 技能 / 提示词照常注入,人设目录按各自的 `catalogDepth`)。
100
- - **场景锁定**:锁定后 MCP / 技能 / 子智能体 / 记忆 / 提示词五个域的**增删改**整体只读,界面禁用 + 服务端守卫双侧拦截;未启动不能上锁,锁定中不能关闭,先解锁再改。**冻结的是"内容",不是"场景本身"** —— 场景的新建 / 删除 / 改名 / 提示词绑定 / 启用切换 / 回收站的恢复与永久删除、MCP 重启、导出、注入设置与令牌设置都不在冻结清单内(它们不是"场景档案里的内容")。其中「启用切换」在锁定场景正在生效时会被拒绝 —— 清空启用集合会让模型侧的写门禁失去判据(运行时却还是那个场景的档案态)。
101
- - **删除场景 = 连记忆一起删**:场景记录、档案与全部记忆进同一条回收站条目,恢复按原路径整条放回;使用中的场景拒绝删除。场景名可改(连带目录与档案,记忆正文不动)。
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
+ - **子代理会话不注入记忆**:记忆是父会话的现场;子代理需要的事实应由父代理写进任务。
102
88
 
103
89
  ### 子智能体
104
90
 
105
- - **一个文件一个人设**:`agents/<人设>.md`,frontmatter 全可选。
106
- - **人设进系统提示词时会带一层角色框**:正文照原样使用,外面加 `# 角色:名` 标题、一行授权(「由调用方指定;与你的默认倾向冲突时以它为准;任务说要什么,怎么做以它为准」)和一句边界(决定**怎么做**,不改变**能做什么**),正文用 `## 角色定义` 围起来;框的语言跟随正文。这是为了让模型把它读成"我被指定为一个角色",而不是身份句后面多跟的两句话——**人设文件一个字都不用改**。框里不列 `description`(那是给**调用方**选人设用的;要给人设子代理看的简介写进正文)。
107
- - **工具限制按 Agent 预设**:每个预设一份白/黑名单(互相排斥),运行期按当前预设生效——堵掉旧「全体并集」名单换预设后子代理起不来的坑。两条必须知道的行为:**① 白名单会并回当前所有 `mcp__*` 工具**(官方 `allow` 是"清单之外全砍",不并进来会把 MCP 一起砍掉),所以「只勾了 `read`」拦不住一个暴露 shell 的 MCP 服务器;**② 名单里的名字全都对不上当前工具时按"不限制"处理**(fail-open,不是 fail-closed)——极简这类预设下白名单极易整份落空。反向的失败是「写了保留名 `run_code`」:官方 `tools.restrict()` 会直接抛错(子代理起不来),所以插件会把它从名单里剔掉并在结果里说明。
108
- - **`output:` 输出要求(硬性契约)**:frontmatter 里可写多行 `output:`(**一行一条**),角色框会把它渲染成 `## 输出要求(硬性)` 单独一节(在角色定义之后)。提示词写「这个角色怎么想」(散文),`output:` 写「产出必须长什么样」(可检验:格式、分级、必标项、禁止项)—— 只有一句抽象要求的角色,产出无法判定"执行了没有";写成可检验的才会被真的遵守。编辑器里有「输出要求(硬性)」多行框,也可以直接写进文件。
109
- - **即用即弃**:`subagent_manager_run` 带人设运行、只回传结果、不进 History。子代理的上下文只有**角色 + 任务**:场景记忆不注入(要记忆可用 `memory_manager_*` 自己取,相关事实应由父代理写进 `task`)。场景可绑定可用人设。
110
- - **两种上下文模式**:默认新起独立会话(子代理看不到本次对话,任务要写全);把 `inherit` 打开则子代理**继承本次会话已完成的轮次**(与官方 `subagent_fork` 同一套机制),任务只需写新增部分。**只继承已完成的轮次**——在本轮内发起委派时这一轮的内容继承不到(实测:父代理边读边委派,子代理仍从零开始),此时 `task` 要按"写全"对待。与官方两个委派工具(`subagent` / `subagent_fork`)的分界由插件写进上下文:**贴合人设的任务一律走这里**,官方那两个只在没有人设贴合、或需要后台任务(job)时用。
111
- - **启停开关**:停用的人设不注入上下文、模型不可见(文件不动);新建 / 导入 / 恢复**默认停用**(v0.8.5 起,与技能 / MCP 同口径),要委派先在这里打开。**进场景按档案勾选集全量对齐**(勾了的开、没勾的关,整段没建 = 全关),退出按进场景前的开关精确还原;场景内这个开关照常可用,改动会同步写进该场景的档案(只有**锁定**才冻结);退出场景时回到进场景前的状态。
112
- - **人设目录自动注入**:只列名字 + 描述,模型知道有哪些人设可委派;人设名可改,场景绑定自动跟着改。
113
- - **目录注入(`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
+ - **思考强度**:在高级选项里与「模型」并排,档位由所选模型声明。换模型后旧档位若不在新清单里会自动清掉并告知;指定了模型时留空 = 回落到该模型的默认档位,不是沿用主会话那一档。
114
97
 
115
98
  ### MCP 服务
116
99
 
117
- - **增删改查 + 即改即生效**:写入 `cordis.patch.yml`,HMR 自动生效。
100
+ - **增删改查、即改即生效**:写入 `cordis.patch.yml`,改前自动备份。级别分「全局 / 应用级」,新增默认全局。
118
101
  - **工具级开关**:单个工具可独立停用(模型看不见也调不到),整台支持批量。
119
- - **停着也能看清单**:服务器没在跑时仍显示上次见过的工具名与描述(标「上次运行时」);从没跑过的可以一键「启动服务器读取工具」。
120
- - **密钥打码**:默认把凭据**整值**打码成 `••••••`(只有名字像密钥的键会打:token / secret / password / auth / api key 这类;`$VAR`、`!!js` 是间接引用,不打码;URL 的 query 整段换成 `?<redacted>`),「显示密钥」要令牌。
121
- - **打码值永远不会被写进补丁文件**:编辑弹窗的密钥框预填的就是打码值,保存时插件会用补丁里的**原值**顶替(= 这一项没改);原值本身已经是打码值(说明真值曾经被写坏过)或压根没有原值时,该键被跳过并在界面提示 —— 前者要你重新填。补丁里已经存在打码值的密钥,列表页一进来就会告警。**URL 是同一种保护、另一套形态**:查询串被打成 `?<redacted>`,保存时同样按原值顶替;补丁里没有原值可顶替时**整次保存会被拒绝**并提示重新填写完整 URL —— 只删查询串会留下一个"能连上但鉴权失败"的地址,比报错更难发现。
122
- - **迁移与备份**:跨项目级/全局迁移失败自动回滚;JSON 导出导入。
123
- - **状态与备注自动注入**:列出当前真正可用的 server;**曾经连上过、现在连不上的也会列出并标注**(`(当前未连上;上次连上时 N 个工具)`)—— 这样模型才会说"它没连上,检查一下",而不是把"配了但连不上"读成"本机没配"、建议你装一个。从未连上过的不列。你的备注作为决策提示带给模型;级别分「全局 / 应用级」,新增默认全局。注:极简这类压制型预设默认不注入(模型可用 `mcp_manager_list` 读取服务器名、启停、工具数与备注)——想让它也注入,到「兼容」页的「注入」块打开开关。
102
+ - **停着也能看清单**:没在跑的服务器仍显示上次见过的工具名与描述(标「上次运行时」);从没跑过的可以一键启动读取。
103
+ - **备注**:每台服务器可写一句给模型的提示,随状态段一起注入。曾经连上过、现在连不上的服务器会列出来并标注 —— 这样模型会说"它没连上,检查一下",而不是建议你去装一个。
104
+ - **密钥打码**:默认把凭据整值打码(`$VAR`、`!!js` 这类间接引用不动;URL 查询串换成 `?<redacted>`),看明文要令牌。打码只管界面展示,详见「配置与安全」。
105
+ - **迁移与备份**:跨项目级 / 全局迁移失败自动回滚;支持 JSON 导出导入。
124
106
 
125
107
  ### 技能
126
108
 
127
109
  - **来源一览**:项目级 / DSH / Agents / Codex / Claude / 自定义目录,按来源分组。
128
- - **两组权限相反**:默认来源(DSH / 导入技能)必须读取但技能可删;外部目录可停用/移除但技能只读。
110
+ - **两组权限相反**:默认来源的技能可删可停;外部目录可以停用或移除,但里面的技能文件只读。
129
111
  - **移除 ≠ 停用**:移除 = 连目录都不扫(文件零改动,可恢复);停用 = 仍列出但不可调用。
130
- - **同名技能一眼看出谁在生效**:真实生效的那份标「首选」,被同名覆盖的标出来源;启用被覆盖的副本会明说「这样不会生效」。
112
+ - **同名谁在生效**:真正生效的那份标「首选」,被覆盖的标出来源;启用被覆盖的副本会明说"这样不会生效"。
131
113
  - **自定义目录 / ZIP 导入导出 / 回收站**。
132
- - **目录可注入**:预设没挂官方技能目录行(如极简)时,由本插件的注入域按「兼容」页的开关兜底送达(名字 + 简介;正文照旧读文件)。
133
114
 
134
115
  ### 提示词预设
135
116
 
136
- - 多套 `~/.dsh/AGENTS.md` 基线,一键应用(宿主每步比对该文件版本、变了才重读,下一轮对话生效),保留 5 代备份。
137
- - **记得「最近一次应用的是哪份」**:就算你手改过 `AGENTS.md`,模型问「现在用的哪份预设」也答得出来源(会注明「此后文件有变」)。
138
- - **描述**:每条预设可写一句「这份是干什么的」,只显示在插件界面里;它存在同目录的 `meta.json`,不进 AGENTS.md,也就不会被注入上下文。
139
- - 新建即可写正文,编辑可改 id(= 目录改名,场景绑定自动跟着改)。**被引用的不能删**(场景绑定 / `AGENTS.md` 当前内容 / 退出场景要恢复的那一份),删除进回收站。
140
- - **正文可注入**:预设没挂官方 AGENTS.md 行(如极简)时,`~/.dsh/AGENTS.md` 的正文由本插件的注入域兜底(64 KiB 上限;可在「兼容」页关掉)。
141
- - **场景接管期间「应用」= 把该场景改绑到那一份**(同步写进场景档案,绑定改完立刻重新对齐;未锁定时可用 —— v0.9 已把「应用别的预设会被拒绝」反转为改绑);**锁定时才拒绝**。退出场景时全局基线按快照恢复。
117
+ - 多套 `~/.dsh/AGENTS.md` 基线一键应用(下一轮对话生效),保留 5 代备份。
118
+ - **记得「最近一次应用的是哪份」**:就算你手改过 `AGENTS.md`,也答得出来源(会注明"此后文件有变")。
119
+ - 每条预设可写一句"这份是干什么的",只存在插件侧、不进 `AGENTS.md`。
120
+ - **被引用的不能删**(场景绑定 / 当前内容 / 退出场景要恢复的那一份),删除进回收站。
121
+ - 场景接管期间「应用」= 把该场景改绑到那一份(同步写进场景档案);锁定时拒绝。
142
122
 
143
123
  ### 历史会话
144
124
 
145
- - 按项目分组、搜索、批量恢复 / 永久删除、保留期自动清理。
146
- - 工作区登记被删后按会话目录重建分组,可一键重新登记。
147
- - 导入 Claude Code / Cursor / Codex / 任意文本;导出 Markdown / JSONL。**导出是可读转录,不是完整备份**:只保留 user / assistant 的文本块,工具调用、图片、思考过程与 token 统计都不在里面;Markdown 正文里出现的 `## User` 这类行在再次导入时会被当成轮次分界(导出侧不转义)。要留全量请用「归档」。
125
+ - 按项目分组、搜索、批量恢复 / 永久删除、保留期自动清理;工作区登记被删后可一键重新登记。
126
+ - 导入 Claude Code / Cursor / Codex / 任意文本;导出 Markdown / JSONL。**导出是可读转录,不是完整备份**:只保留 user / assistant 的文本块,工具调用、图片、思考过程与 token 统计都不在里面。要留全量请用「归档」。
148
127
 
149
128
  ### 宿主兼容
150
129
 
151
- 插件运行期用宿主同一批 `@deepseek-ai/*` 库——必须是同一份物理模块,否则判断退化成猜。
152
-
153
- - **「兼容」页**:宿主版本、能力可用数、每个动作走原生/适配/不可用、降级项与原因。体检本身只读,但这一页有三个明确的写入口:**访问令牌**(写 profile 的 `cordis.patch.yml`,重启生效)、**注入设置**(写 `inject-settings.json`,即时生效)与**模型工具表**(写 `tool-table.json`,即时生效)。
154
- - **命令行**:`node scripts/doctor.mjs`(体检)、`node scripts/host-deps.mjs --fix`(依赖对齐)、`npm run sync:profile`(把构建产物镜像到 profile 里那份本地安装 —— `file:` 装的是硬链接拷贝,构建新增的文件不会自动过去)。
155
- - `minimal` 这类**压制型预设**(persona `complete` / 关闭运行时上下文)下,本插件的注入**默认停用**(跟随预设的设计意图),提示词与技能也因官方那两行没挂而缺席 —— 兼容页逐列标出,同一页的「注入」块可以按域强制打开。
156
- - **关掉「技能」「提示词」的勾选 = 真的不再注入**:这两项在标准类预设下由宿主自己送(插件让位),所以取消勾选会**连宿主那份一起停掉**(`skill-catalog` / `agent-instructions` 的消息在这一步不再放行)。其余三项(记忆 / MCP / 子智能体)宿主本来就不送,勾选完全生效。
157
- - **注入长什么样**:每个域一条 `<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>` 会被转义。
158
135
 
159
136
  ---
160
137
 
161
138
  ## 数据落点
162
139
 
163
- | 内容 | 位置 |
164
- | ------------------------------------------- | ---------------------------------------------------------------------------------- |
165
- | MCP 定义 | `~/.dsh/cordis.patch.yml`(插件只写它;改前自动备份到 hub 的 `backups/`) |
166
- | 技能策略 / 自定义目录 | `~/.dsh/tool-management/skills-state.json` |
167
- | 技能 / 记忆 / 人设 / 预设 | `~/.dsh/tool-management/{skills,memories,subagents,prompts}/` |
168
- | 子智能体启停 | `~/.dsh/tool-management/subagents-index.json` |
169
- | 回收站(技能/人设/预设/场景) | `~/.dsh/tool-management/trash/{skills,subagents,prompts,scenes}-trash/` |
170
- | 记忆回收站 | `~/.dsh/tool-management/memories-trash/`(**hub 根下独立目录,不在 `trash/` 里**) |
171
- | 归档账本 / 保留期 | `~/.dsh/tool-management/history-*.json` |
172
- | 记忆索引 / 场景 / 档案 | `~/.dsh/tool-management/memories-index.json` |
173
- | MCP 侧车(停用表 / 已知工具 / 备注 / 设置) | `~/.dsh/tool-management/mcp-*.json` |
174
- | 注入设置(五个域开关 / 压制型预设口径) | `~/.dsh/tool-management/inject-settings.json` |
175
- | 模型工具表(不发给模型的工具) | `~/.dsh/tool-management/tool-table.json` |
176
- | 场景页界面设置(进场景前弹不弹预览卡) | `~/.dsh/tool-management/scene-settings.json` |
177
- | 运行日志 / patch 备份 | `~/.dsh/tool-management/tool-management.log` · `backups/` |
178
-
179
- **插件安装目录里不存用户数据**(`dsh plugin update` 会整体替换该目录)。
180
-
181
- **`backups/` 的保留份数是「每份 patch 文件各 5 份」**:备份名带层级标签(`.global` / `.profile-<名>`),所以全局与每个 profile 各自留 5 份 —— 不是全局共 5 份。一次批量操作(如 `mcpm-set-all`、进入场景的多次写)就可能把某个层级的 5 个槽位全吃掉、挤掉更早的版本。
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 个槽位吃掉。
182
157
 
183
158
  ## 配置与安全
184
159
 
185
- | 字段 | 说明 |
186
- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
187
- | `token` | 访问令牌。设了之后**所有写操作 + 明文密钥**都要求 `x-dsh-token`;**不设时明文接口一律关闭**。也是 curl / 局域网的逃生门。不想把令牌写进配置文件时,可改用环境变量 `DSH_PLUGIN_TOOL_MANAGEMENT_TOKEN`(两者都给了以 `config.token` 为准;`tokenDisabled: true` 会让两者都不生效)。 |
188
- | `tokenDisabled` | `true` = 令牌**保留在配置里**但当前不生效(在兼容页点「关闭保护」写入的就是这一行)。写操作不再要求令牌;明文查看仍然要凭令牌(明文本身就是凭据)。随时可以在兼容页「开启保护」开回来,不需要重新输一遍。 |
189
- | `maxBodyBytes` | 请求体上限,默认 88 MiB。 |
190
-
191
- **关于磁盘上的明文(必读)**:打码**只发生在界面展示**。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/` 下的旧文件。
192
-
193
- - **浏览器**:读写走 cookie,不需要 token;但**明文密钥**(显示密钥 / 导出)要令牌。**令牌在「工具 → 兼容」页的「访问令牌」块管理**(与页面无关的固定入口)。那一块是**一枚状态胶囊 + 一句实况 + 三行**:行名说"这一步管到哪儿"、按钮说动词,胶囊只回答"保护开没开、这一程解锁没有"。
194
- - **本次启动**:填一次,管到 DSH 退出(只写本机浏览器)。填对了,这一行**就地**变成一枚绿胶囊「已解锁」+「清除」(不是塌成一颗按钮 —— 那样看着像刚填的东西没了),宿主才认这串令牌、下面两行才动得了;宿主侧还没有令牌时这一行不出现(没东西可验)。
195
- - **宿主配置**:写进 profile 的 `cordis.patch.yml`(只动那两行,注释与 `!!js` 守卫原样保留,改前自动备份),重启 DSH 生效。宿主还没配时这一行的按钮就是主操作(「设置令牌」,点开输**两遍**新令牌防手滑);已配之后换令牌点「修改令牌」,表单里多一栏**当前令牌** —— 换令牌要能证明知道当前令牌,而**解锁过不算**(与「关闭保护」同一条口径):必须在表单里当场再输一次;点开时光标就落在这一栏,三栏**竖排**、保存与取消跟在下面(表单打开时只剩这一行,回车 = 保存),三栏齐了「保存新令牌」才可按,输错时那一格会标红。
196
- - **删除令牌**(与「修改令牌」同一行):把 `token` 与 `tokenDisabled` 两行从配置里删掉,回到**还没设置**那一态 —— 写操作不再要凭证、明文密钥随之不可见。同样就地展开确认框、当场再输一次当前令牌;回执会如实提醒"旧备份里仍有明文副本"(备份是整份配置的副本,要一并清掉用页头的「清理旧备份」)。想保留令牌、只是暂时不要门禁时用「关闭保护」,别用删除。
197
- - **保护开关**:点「关闭保护」会**就地展开确认框(此时只有这一行,与「修改令牌」同一规矩)**,要再输一次当前令牌(解锁过也要输 —— 请求头里那份已验证的凭证对"关闭"不作数,防的是解锁之后顺手一点就把防护关了);确认后只写一行 `tokenDisabled: true`,**令牌原样留在配置里**,随时点「开启保护」就能开回来(不必重新输一遍)。关闭后写操作不再要求令牌;**明文查看仍然要凭令牌**(明文本身就是凭据)。开启方向沿用原口径:解锁过,或输入框里填着当前令牌即可 —— 否则"能打开 GUI 就能关掉保护",令牌等于白配。
198
- - **状态胶囊**:还没有令牌 / 保护已关闭 / 保护已开启 · 待解锁 / 保护已开启 · 已解锁。配置改了还没重启时,胶囊下面会多一条橙色横幅说清(胶囊说的是当前进程)。
199
- - **令牌功能没在生效时,不再挂那句「去填令牌」**:那句话只在实际有门禁(当前进程存在生效令牌)时才留下;关掉或没配时它会被收掉,由面板上的状态胶囊说出实际情况。
200
- - **提示出现在哪里**:令牌没过时的那句话(含右侧的「填写令牌」按钮)**恰好只有一份** —— 有弹窗打开时在弹窗里(它是当前操作的阻塞原因,放在最显眼处),没有弹窗时在页签下方。它与"当前是哪一页、那一页怎么渲染错误"无关,所以任何一个入口(含各种弹窗里的提交、导入、导出、批量操作)都不会漏提示。
160
+ | 字段 | 说明 |
161
+ | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
162
+ | `token` | 访问令牌。设了之后**所有写操作 + 明文密钥**都要求 `x-dsh-token`;不设时明文接口一律关闭。也可改用环境变量 `DSH_PLUGIN_TOOL_MANAGEMENT_TOKEN`。 |
163
+ | `tokenDisabled` | `true` = 令牌保留在配置里但当前不生效(兼容页「关闭保护」写的就是这一行)。写操作不再要求令牌,明文查看仍然要。 |
164
+ | `maxBodyBytes` | 请求体上限,默认 88 MiB。 |
165
+
166
+ **磁盘上的明文(必读)**:打码**只发生在界面展示**。MCP 的 `env` / `headers` 与插件自己的 `token` 在 `cordis.patch.yml`(及各 profile 副本)里始终是明文,而每次改配置前插件会把整份文件备份进 `~/.dsh/tool-management/backups/`(不加密、不轮转、卸载也不回收)—— 一份密钥最多有 `5 ×(含它的 patch 文件数)+ 1` 份明文副本。令牌门禁管的是"谁能通过 HTTP 拿到明文",**管不到磁盘读取**:真正的防线是操作系统的文件权限。清理入口:**设置 → 工具 → 兼容 → 「清理旧备份」**(可按层级各删最旧的 N 份,弹窗内二次确认),也可以手工删那个目录下的旧文件。
167
+
168
+ - **浏览器**:读写走 cookie,不需要令牌;**明文密钥**(显示密钥 / 导出)要令牌。令牌在「兼容」页的「访问令牌」块管理:本次启动填一次管到 DSH 退出;写进配置文件要重启生效。
169
+ - **销毁方向一律要当场再输一次当前令牌**(关闭保护 / 修改 / 删除)—— 本次启动解锁过不算,否则"能打开界面就能关掉保护"。
201
170
  - **curl / 脚本**:带 `x-dsh-token`,或带浏览器 cookie。
202
- - **HTTP 状态码口径**:除安全栅栏的 401/403 外,令牌缺失、业务失败等一律 HTTP 200 + `{ ok: false, error }` —— 脚本分流请以 `body.ok` 为准,不要按状态码。
203
- - **栅栏的降级面**:宿主缺 `connection` 服务时,栅栏退到「Host 回环 + 同源」判定(没有浏览器 cookie 可验),本机任意进程伪造 `Host: localhost` 即可调用写 op —— 把端口转发到局域网/公网的场景**务必配令牌**,它是这条降级面上的最后一道门。
204
- - **`dir-list` 的暴露面**:「选择文件夹」弹窗靠它逐级列目录,因此通过栅栏/令牌的调用方可列出**任意绝对路径**的目录(只读)。这是功能性设计,不是漏洞;但请勿把端口暴露给不可信网络。
205
- - **端口转发到公网**:建议配 token——防陌生人注入 MCP 命令(等同远程执行)与窃取密钥。
171
+ - **HTTP 状态码**:除安全栅栏的 401 / 403 外,一律 HTTP 200 + `{ ok: false, error }` —— 脚本分流请以 `body.ok` 为准。
172
+ - **端口转发**:宿主缺 `connection` 服务时栅栏退到「Host 回环 + 同源」判定,本机进程伪造 `Host: localhost` 即可调用写 op。转发到局域网 / 公网的场景**务必配令牌** —— 陌生人注入 MCP 命令等同远程执行。「选择文件夹」弹窗用的 `dir-list` 能列出任意绝对路径(只读),同一条前提。
206
173
 
207
174
  ## 常见问题
208
175
 
209
- | 现象 | 解决 |
210
- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
211
- | 装完没有页面 | 硬刷新;不行重启 DSH。 |
212
- | 重复 MCP 页签 | 删 `cordis.patch.yml` 里的旧 loader 行后重启。 |
213
- | 改坏配置 DSH 起不来 | 从 `~/.dsh/tool-management/backups/` 取最近的 `cordis.patch.yml.<层级>.bak-<时间戳>` 覆盖回去(每份 patch 各留 5 份)。 |
214
- | 升级 DSH 后动作不可用 | 设置 → 工具 → **兼容** 看原因;`doctor.mjs` → `host-deps.mjs --fix`。 |
215
- | `approval=never` 还要确认吗 | 不弹卡,直接放行并记日志;想问回来切回「工作区内修改」。 |
216
- | `subagent_manager_run` 报 provider 不可用 | 对应 provider 没注册:`spawn`(默认)/ `fork`(`inherit`)分别挂 `@deepseek-ai/dsh-subagent-spawn-in-process` / `-fork-in-process` 后重启。 |
217
- | 场景绑了 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`,官方只在没有人设贴合或要后台跑时用。 |
218
186
 
219
187
  ---
220
188
 
@@ -223,14 +191,14 @@ dsh plugin --profile web add dsh-plugin-tool-management@latest
223
191
  ```bash
224
192
  npm install
225
193
  npm run build # tsc + 同步客户端
226
- npm test # 构建 + i18n + 契约测试(纯函数不变量与宿主契约;渲染类测试已于 2026-09-19 移除)
194
+ npm test # 构建 + i18n + 契约测试(纯函数不变量与宿主契约)
227
195
  npm run check:i18n # 词典自检
228
196
  npm run doctor # 宿主兼容体检
229
197
  ```
230
198
 
231
199
  `lib/` 不入版本库,克隆后先 `npm run build`。改完重启 `dsh web` 才生效。运行时依赖:`fflate`(导出打包)、`js-yaml`(写宿主补丁前的解析校验,惰性加载);`@deepseek-ai/*` 一律用宿主那份。
232
200
 
233
- > **部署注意**:`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 的正式安装不受影响。
234
202
 
235
203
  ## 许可证
236
204