dsh-plugin-tool-management 0.5.1 → 0.6.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 +300 -238
- package/README_EN.md +300 -304
- package/cordis.patch.yml +9 -55
- package/docs/Changelog.md +108 -481
- package/docs/images/1/345/234/272/346/231/257.png +0 -0
- package/docs/images/1/345/234/272/346/231/257_en.png +0 -0
- package/docs/images/2MCP.png +0 -0
- package/docs/images/2MCP_en.png +0 -0
- package/docs/images/3/346/212/200/350/203/275.png +0 -0
- package/docs/images/3/346/212/200/350/203/275_en.png +0 -0
- package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223.png +0 -0
- package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223_en.png +0 -0
- package/docs/images/5/346/217/220/347/244/272/350/257/215.png +0 -0
- package/docs/images/5/346/217/220/347/244/272/350/257/215_en.png +0 -0
- package/docs/images/6/350/256/260/345/277/206.png +0 -0
- package/docs/images/6/350/256/260/345/277/206_en.png +0 -0
- package/docs/images/7/344/274/232/350/257/235.png +0 -0
- package/docs/images/7/344/274/232/350/257/235_en.png +0 -0
- package/docs/images/8/345/205/274/345/256/271.png +0 -0
- package/docs/images/8/345/205/274/345/256/271_en.png +0 -0
- package/docs/update.md +54 -0
- package/lib/agents-md/preset-id.js +49 -0
- package/lib/agents-md/service.js +138 -56
- package/lib/client.js +4142 -3560
- package/lib/compat/probe.js +665 -0
- package/lib/history/bridge.js +293 -0
- package/lib/history/workspace.js +498 -52
- package/lib/http-fence.js +73 -0
- package/lib/index.js +511 -126
- package/lib/rules/provider.js +3 -3
- package/lib/rules/service.js +264 -30
- package/lib/scene-prompt-sync.js +112 -0
- package/lib/skills/core.js +112 -35
- package/lib/skills/service.js +6 -1
- package/package.json +5 -3
- package/screenshots.json +8 -7
- package/docs/images/MCP.png +0 -0
- package/docs/images//344/274/232/350/257/235.png +0 -0
- package/docs/images//345/234/272/346/231/257.png +0 -0
- package/docs/images//345/255/220/346/231/272/350/203/275/344/275/223.png +0 -0
- package/docs/images//346/212/200/350/203/275.png +0 -0
- package/docs/images//346/217/220/347/244/272/350/257/215.png +0 -0
- package/docs/images//350/256/260/345/277/206.png +0 -0
package/docs/Changelog.md
CHANGED
|
@@ -1,517 +1,144 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
`dsh-plugin-tool-management`
|
|
3
|
+
`dsh-plugin-tool-management` 的**版本变更记录**:每个版本改了什么、有哪些已知限制。
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
5
|
+
- 只要「大致内容」→ [版本更新概要](./update.md)
|
|
6
|
+
- 功能说明与用法 → [README](../README.md) / [README_EN](../README_EN.md)
|
|
7
|
+
- 版本号 = npm 上实际发布的发布号;**日期 = npm 发布时刻(UTC)**,本地时间(UTC+8)比它晚 8 小时。
|
|
8
|
+
- 开发期的过程记录(根因分析、逐条实测数据、评审条目)不在这里,见 git 提交历史。
|
|
7
9
|
|
|
8
10
|
---
|
|
9
11
|
|
|
10
|
-
## v0.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
### 已知限制(未变)
|
|
43
|
-
- 浏览器交互验收仍**未跑**(宿主要 launch token);能进 CI 的两层是导出契约与装配/渲染测试,它们挡不住交互行为。
|
|
44
|
-
- 硬编码中文欠账未清零(提示词页 / 会话页);结构类问题与官方 Config schema 缺失见「已知问题」节。
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## v0.5.0(2026-09-13)
|
|
49
|
-
|
|
50
|
-
**已发布**:npm `dsh-plugin-tool-management@0.5.0`(2026-09-13 16:17:45 UTC)。本节与下一节「v0.5.0 详情」即该版本的内容。
|
|
51
|
-
|
|
52
|
-
本次发布把此前散落的四套变更合并成一个版本,并修掉一轮真实故障。**详细条目见下一节「v0.5.0 详情」**
|
|
53
|
-
(该节原编号为 v0.4,内容不变,只改标题以免与发布号冲突)。
|
|
54
|
-
|
|
55
|
-
**给使用者的三句话**:数据全部收进 `~/.dsh/tool-management/`(首次启动自动搬迁、只搬不删、绝不覆盖);
|
|
56
|
-
「场景」从"恰好有这个名字的目录"升级为带描述与顺序的**显式记录**,保留场景 `global` 恒定注入;
|
|
57
|
-
「工具」设置页七个标签重做,斜杠命令全部下线。
|
|
58
|
-
|
|
59
|
-
### 新增 / 变更
|
|
60
|
-
- **统一数据目录**:记忆、场景、人设、AGENTS.md 预设、新建/导入的技能、回收站、索引与配置全在 `~/.dsh/tool-management/` 下;旧位置(`$DSH_HOME/scene-memory/`、`$DSH_HOME/rules/`、`$DSH_HOME/subagents/`、插件 `data/`)首次启动自动搬入。
|
|
61
|
-
- **场景显式化**:`rules-index.json` 的 `scenes` 切片带 `label` / `description` / `order`;空场景合法;保留场景 `global`(界面「全局」)不可删;根层裸 `.md` 不再注入并会在体检里报 `noScene`。
|
|
62
|
-
- **技能来源**:新增插件自有来源(界面名 **「导入技能」**)作为新建/导入的落点,优先级高于 `~/.dsh/skills/`;`~/.agents` / `~/.codex` / `~/.claude` 与自定义目录仍为只读接入。
|
|
63
|
-
- **技能来源新增「移除来源」**(本版新增,详细条目见下一节 §界面):把某个来源从**读取范围**里摘掉——不再扫描该目录、技能页不列出、模型侧候选也不产出;**源目录与文件一个字节都不动**,界面单列一组「已移除的来源」可一键「恢复读取」。`DSH 技能` 与 `导入技能` 是保留来源,**不可移除**(否则新建/导入没有落点)。
|
|
64
|
-
- **界面**:工具页七标签(场景 / MCP / 技能 / 子智能体 / 提示词 / 记忆 / 会话);场景卡片补描述与绑定摘要;场景档案编辑器新增第 4 段「记忆」;人设表单的模型与工具限制收进「高级选项」(模型下拉 + 白/黑名单勾选器)。
|
|
65
|
-
- **契约测试 61 → 76 例**:新增客户端导出契约、装配与渲染(含带数据挂载)、技能状态文件读取韧性、技能删除权限四组。(文档口径滞后:发布时实际已 **81 例**,0.5.1 一并校正,见上节。)
|
|
66
|
-
- **DSH Market 收录徽章**:本插件已被 [DSH Market](https://dsh.market/) 收录(issue [#145](https://github.com/2BingLing/dsh-market/issues/145) 标记 `accepted`)。`README.md` 挂中文徽章、`README_EN.md` 挂英文徽章,片段取自该仓库 [PLUGIN-BADGE.md](https://github.com/2BingLing/dsh-market/blob/master/PLUGIN-BADGE.md);两张 SVG 均实测 HTTP 200。
|
|
67
|
-
- **英文 README 与中文对齐**(`README_EN.md`):此前英文版落后于中文版若干处——「Model tools」重复两行且都写 10 个(实为 12)、UI 写 "six pages"(实为七栏)、缺「记忆导入」「场景档案」「轻量子智能体」三行、多出中文版没有的「Rule checkup」一行(导致整表错位)、快速开始仍写旧的五个独立页面(实为一个「工具」面板七栏)、`rule_manager_*` 描述仍用 "rules"(应为 scene memories)。逐行核对后两版核心亮点表均为 **22 行(20 数据行)且逐行对齐**,21 条图片引用与 git 索引逐字符一致。
|
|
68
|
-
- **截图 `MCP.png` 大小写修复**:`docs/images/mcp.png` 被提交成小写而 README/screenshots.json 都引用 `MCP.png`,Windows 不区分大小写掩盖了这点,GitHub 上该图 404(其余六张正常)。两步 `git mv` 改名后实测 `MCP.png` → HTTP 200、`mcp.png` → 404。
|
|
69
|
-
- **模型工具计数与入口表更正(中英双版)**:「模型工具」由 **12 → 14**——此前两版都漏了 `agentsmd_list` / `agentsmd_apply`(模型可查/切 AGENTS.md 预设库,不提供新建/删除以免误删用户预设),现按四组写出各占几个:MCP 4 / 技能 3 / AGENTS.md 2 / 场景记忆 3 / 子智能体 2 = 14。依据是代码实测 `tools.register()` 共 14 处(`src/index.ts` 12 处 + `src/subagents/tools.ts` 2 处)。「让模型和脚本参与管理」入口表同步补上 `agentsmd_*` 与 `subagent_*` 两行(4 → 6 行数据),中英两版表格逐行对齐。
|
|
70
|
-
- **`package.json` description 补全**:原文只列 `skill_mcp_manager_*` / `skill_manager_*` / `rule_manager_*`(漏 `agentsmd_*` 与 `subagent_*`,也未提子智能体)。现补为五域 + 场景记忆注入系统提示词 + 一次性人设子代理,并写明 **14 model tools** 与五个前缀族。校验:22 项断言逐条对代码核对(各族工具数 4/3/2/3/2、`dsh.client`、`dsh.bundle`、HTTP API 路由、`systemPrompt` 段、subagent 工具)全部通过。
|
|
71
|
-
|
|
72
|
-
### 修复(本轮真实故障)
|
|
73
|
-
- **「工具」页整页白屏**:`sceneLabel` 定义在 `MemoryPage` 闭包里却被 `ScenesPage` 调用 → `ReferenceError`,被 slot 边界吞成日志。已提到模块作用域并参数化。
|
|
74
|
-
- **导出静默丢失**:`module.exports._pages` / `DICT` 写在 `apply` 方法体末尾,`apply` 提前返回就永不执行。已改为在 factory 作用域落地。
|
|
75
|
-
- **Skills 页被锁死**(弹「状态文件不可读,已拒绝覆盖」):校验器要求每个来源都在状态文件里有记录,而新增 `hub` 来源后旧文件被判非法 → fail-closed 全停用 + 锁定写入。文件其实完好。已改为校验归一化后的文档(**缺键自愈、类型错仍拒绝**)。
|
|
76
|
-
- **删除权限**:`DSH 技能` 与 `导入技能` 改为**可写不可删**(技能只能停用),删除只对项目级来源开放;服务端在碰文件之前拒绝。
|
|
77
|
-
|
|
78
|
-
### 已知限制(未变)
|
|
79
|
-
- 浏览器交互验收仍**未跑**(宿主要 launch token);能进 CI 的两层是导出契约与装配/渲染测试,它们挡不住交互行为。
|
|
80
|
-
- 硬编码中文欠账未清零(提示词页 / 会话页);结构类问题与官方 Config schema 缺失见「已知问题」节。
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## v0.5.0 详情 — 统一数据目录 + 场景显式化 + 界面重做(2026-09-13)
|
|
87
|
-
|
|
88
|
-
### 破坏性/结构性变更
|
|
89
|
-
|
|
90
|
-
**① 插件产生的文件全部收进一个 hub**:`$DSH_HOME/tool-management/`
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
~/.dsh/tool-management/
|
|
94
|
-
├─ memories/<场景>/<名>.md | <场景>/<名>/SKILL.md 记忆正文(真源)
|
|
95
|
-
├─ scenes/ 场景目录(记录本身在索引里,见下)
|
|
96
|
-
├─ agents/<人设>.md 子智能体人设
|
|
97
|
-
├─ agents-md/<预设 id>/AGENTS.md 全局指令基线预设库
|
|
98
|
-
├─ skills/ 插件新建/导入的技能
|
|
99
|
-
├─ trash/ 技能回收站;rules-trash/ 记忆回收站
|
|
100
|
-
├─ rules-index.json 启停/顺序/场景记录/档案/模式
|
|
101
|
-
├─ state.json 技能启停策略与自定义目录
|
|
102
|
-
└─ config.json 页面设置(`dsh-plugin-tool-management-settings.json` 保留原名)
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
旧位置**首次启动自动搬入**(`src/hub.ts` + `relocateLegacyLayout()` / `relocateLegacyPersonas()`):
|
|
106
|
-
`~/.dsh/scene-memory/`、更旧的 `~/.dsh/rules/`、`~/.dsh/subagents/`、插件目录 `data/agents-md-presets/`。
|
|
107
|
-
|
|
108
|
-
搬迁纪律(三条,都是为了不丢数据):**只搬不删**(源目录留空壳)、**绝不覆盖**(目标已存在同名项则跳过)、**每进程一次且失败不阻断**(旧目录仍可读)。
|
|
109
|
-
`~/.dsh/skills/`(DSH 官方技能目录)**不搬**:仍作为可切换来源列出,只是插件新建/导入的技能改落 `tool-management/skills/`(同名时 hub 版本优先)。
|
|
110
|
-
|
|
111
|
-
**② 场景从「恰好有这个名字的目录」升级为显式记录**
|
|
112
|
-
|
|
113
|
-
- 记录存 `rules-index.json` 的 `scenes` 切片:`label` / `description` / `order` / `createdAt`。
|
|
114
|
-
- **空场景合法**(可以只有描述、还没有记忆)。
|
|
115
|
-
- 保留场景 **`global`(界面显示「全局」)**:恒定存在、不可删除、其记忆注入任何对话 —— 保留了「全局」语义,但不再靠「`memories/` 根层裸 `.md`」这种隐式写法表达。
|
|
116
|
-
- **根层裸 `.md` 不再注入**,且体检会报 `noScene`(附可操作建议),不静默失效。
|
|
117
|
-
- 记忆写入要求场景**已存在**(`error.rules.sceneNotFound`);导入会自动补记录并**回传** `scenes` 让界面告知用户。
|
|
118
|
-
- 场景名单个路径段(`a/b` 在创建与删除两侧都判非法)。
|
|
119
|
-
|
|
120
|
-
**③ 斜杠命令全部下线**:`/mcp`、`/skills`、`/agents-md`、`/scene-memory`。它们只能输出纯文本快照,既不能操作也容易与面板状态不一致;面板里每一项都有等价入口。
|
|
121
|
-
|
|
122
|
-
### 界面
|
|
123
|
-
|
|
124
|
-
- **场景页**:卡片补齐「描述 + 记忆条数 + 已绑定摘要(MCP/技能/子智能体/记忆各多少)+ 磁盘目录名」;新增「改描述」(`rules-update-scene`);保留场景不显示删除/停用开关;统计标签从硬编码中文改走 i18n。
|
|
125
|
-
> **0.5.1 已取代**:用户反馈这些数量让卡片「很杂乱、丑陋」,且长描述会把卡片撑成纵向 → 卡片改为「名字/标签/开关 + 一行描述 + 动作行」,数量移入页首「当前模式」条,描述限 60 字。见上节「场景页(场景档案)排版重做」。
|
|
126
|
-
- **新建/改场景表单**:独立字段与文案(原来直接复用记忆的字段,出现「留空 = 全局」这类错误语义的占位符)。
|
|
127
|
-
- **场景档案编辑器**:新增第 4 段「记忆」(`archive.memories`,id = `<场景>/<名>`)。勾选语义与其余段同构——**段未定义 = 不碰;段已定义但没勾的记忆不进提示词**;勾选**只影响投影**,记忆文件与内容一律不动。场景改成卡片(描述 + 已勾/总数 + 「始终注入」标记),点「选记忆」进场景内的记忆明细钻取视图。四段都加筛选框。
|
|
128
|
-
> **0.5.1 已收窄**:保留场景「全局」恒定注入,「已勾 N/M」对它没有意义 → 该卡片只显示描述;名称与说明在 `.dsm-pick-main` 里由行内换行改为各占一行(长描述不再把卡片撑成纵向)。
|
|
129
|
-
> **0.5.1 已改**:「添加」不再预勾当前启用状态(改为空集 / 记忆只预勾本场景里已启用的那几条),记忆描述按 80 字截断;场景页也不再列保留场景「全局」,档案弹窗记忆段只列本场景的记忆。理由与实测数据见上节「档案弹窗:新加段默认不勾选…」「场景页(场景档案)排版重做」「记忆段只列被编辑场景自己的记忆」。
|
|
130
|
-
- **档案弹窗里的勾选区拉高**(用户反馈「记忆、各种集的选择滑动框都很小」):弹窗上限 620px → 720px,段体从写死 `height:216px` 改成 `min-height:300px` + `flex:0 0 auto`(**下限优先**),列表自身出滚动条,装不下时由 `.dsm-form` 整体滚动。
|
|
131
|
-
两种写法的取舍记一笔:`flex:1` 平分看似「填满空间」,但四项分 720px 每段只剩约 155px,**比原来的 216px 还矮**——第一版就是这么写的,算完才发现。已把这条写成断言(禁止 `flex:1`、下限 ≥ 260px、弹窗上限要装得下四段下限)。
|
|
132
|
-
- **人设表单**:模型与工具限制收进「**高级选项**」折叠区(已配置则自动展开)。模型 = 宿主 LLM 目录里的 `provider · model` 下拉 + 「自定义」手填兜底;工具白名单/黑名单 = 勾选器,候选是**全部 Agent 预设工具名的并集**并标注「当前会话可见 / 其它预设里可用」。折叠区**首次展开才拉候选**(枚举预设需要 standing mount,不该在开弹窗时付代价)。
|
|
133
|
-
- **四个表单的提示去冗余**(用户反馈「辅助提示很多余,而且杂乱」)。诊断结论不是"提示太多",而是**提示在替占位符和标签重复说同一句话**,以及**表单被当成说明书**:
|
|
134
|
-
- 人设:删「人设名」提示(校验规则在输入不合法时本来就会报)、删「描述」提示(占位符的例子已说明该写什么)、删工具白名单里解释 UI 设计的最后一句;模型字段原来一处三份说明(占位符 + 提示 + 「模型来源」自己的提示)压成一句「留空继承主会话」。
|
|
135
|
-
- 场景:删表单底部的第三段说明(功能说明归页面副标题)、删「描述」提示(筛选场景属实现细节);「场景名」提示压成「创建后不可改名。」
|
|
136
|
-
- 导入记忆 / 新建记忆:场景提示压成「留空 = 全局」;删「名称」提示与整段绝对路径说明。
|
|
137
|
-
- 顺手修掉一处**真的自相矛盾**:同一个保留场景,导入记忆里显示「所有场景」、新建记忆里显示「全局」→ 统一为「全局」。
|
|
138
|
-
- 共删 6 条提示行、改短 4 条,并同步删除词典里随之失效的 6 个键(中英各一份)。`check:i18n` 在过程中抓到一处漏删(英文词典残留 `memory.scene.field.desc.hint`),引用完整性测试抓到一处漏改(`memory.name.hint` 仍被 `t()` 调用)——两条护栏都按预期生效。
|
|
139
|
-
- **技能来源改名与删除权限**(用户裁定):
|
|
140
|
-
- hub 来源的界面名 **「管理器技能」→「导入技能」** —— 它是插件导入/新建技能的落点,不是"管理器自己的一类技能"。
|
|
141
|
-
⚠️ 第一次**只改了宿主侧**:`src/skills/core.js` 的 `label` 与 API 回传值都是「导入技能」,但客户端词典的 `root.hub` 忘了同步。而客户端显示名是**词典优先、宿主 label 兜底**(`translateOrFallback(t, 'root.' + localeKey, root.label)`),结果界面上仍显示「管理器技能」——**只查宿主侧查不出这个问题**。已补 `root.hub` 中英两条,并在 `test/skills-delete.test.mjs` 加断言(词典条目必须是「导入技能」/「Imported skills」)。
|
|
142
|
-
- **用户级来源不可删**:`DSH 技能`(`~/.dsh/skills/`)与 `导入技能`(`~/.dsh/tool-management/skills/`)**可写但不可删**,界面不再显示「移到回收站」;删除只在**项目级来源**(`<项目>/.dsh/skills`)开放。理由是用户自己放进来源目录的技能不该被插件从磁盘上搬走。
|
|
143
|
-
- 可删除位是来源定义上的显式标记(`deletable`),不再从 `mutable` 推断;服务端在**碰文件之前**拒绝,错误码 `error.skill.notDeletable`(与「只读来源」的 `error.root.readonly` 区分开,提示能说清"你还能做什么")。
|
|
144
|
-
- 注意:刷新页面即可看到名称与按钮变化,但**服务端那道闸要重启宿主才生效**。
|
|
145
|
-
- **「移除来源」= 不再读取它**(用户澄清:「是不读取这个文件夹了,不是把文件夹删除」/「不是删除,是移除可以读取」)。原来的「停用来源」仍会读取并列出技能(只是不可调用),而移除是**连目录都不扫**:
|
|
146
|
-
- 新增状态字段 `removedSources`(可持久、可恢复)。`state()` 把这些来源的技能全部排除,`listProviderCandidates()` 也不再产出它们的候选 —— 所以**模型侧同样看不到**;
|
|
147
|
-
- 源目录与文件一个字节都不动;已移除的来源仍在 `roots` 里带 `removed: true` 返回,界面单列一组「已移除的来源」,可一键「恢复读取」;
|
|
148
|
-
- `dsh`(官方技能目录)与 `hub`(导入落点)**不可移除**(`error.source.reserved`)—— 移除会让创建/导入无处落脚;
|
|
149
|
-
- 新 op:`skill-source-remove` / `skill-source-restore`;来源行新增 `removable` 字段,技能页的「移除来源」按钮据此显示。回归测试 `test/skills-source-remove.test.mjs`(4 例)断言「移除后技能不再被读取、源文件原封不动、恢复后又能读到」,并单独断言**移除 ≠ 停用**。
|
|
150
|
-
- **勾选类原语提到模块作用域**(段卡片 / 勾选行 / 筛选行 / 分组标题 / 段头动作 / 段脚注),档案编辑器与人设工具选择器共用同一套排版。
|
|
151
|
-
- **七个页面的副标题统一为同一句式**(`管理X:动作、动作与动作。`):场景从「定义式 + 两句」改为与其他页同构;子智能体去掉绝对路径;提示词页与会话页的两条原本是**硬编码中文**(英文界面下永远是中文),一并接进 i18n(新增 `prompts.desc` / `sessions.desc`)。
|
|
152
|
-
- **i18n**:MCP 页与共享状态层(级别、运行状态、表头、表单字段、详情、确认弹窗、工具栏)从硬编码中文改为 `t()`。**剩余欠账 113 条**:提示词页 38、会话页 75(见「已知问题」)。
|
|
12
|
+
## v0.6.0(2026-09-14)
|
|
13
|
+
|
|
14
|
+
**主题:宿主兼容体检。** 插件不再靠「比对官方源码文本」判断能不能动宿主数据,改为「查模块实体 + 探能力」,并把结果做成设置页里的「兼容」页;同时修掉归档会话的工作区归属、技能来源权限语义两类真缺陷。
|
|
15
|
+
|
|
16
|
+
### 新增
|
|
17
|
+
|
|
18
|
+
- **「工具 → 兼容」页(第 8 个页签,只读)**:宿主版本与要求范围、插件适配版本、能力可用数、**每个宿主动作走哪条路径**(宿主原生入口 / 插件适配层 / 不可用)、已降级能力与原因、模块实体是否与宿主同一份、阻塞项清单,以及命令行体检入口。数据来自新 op `compat-status`,页面可「重新检查」。
|
|
19
|
+
- **`node scripts/doctor.mjs`**:命令行版同一份体检,打印模块实体归属与宿主能力探测结果。
|
|
20
|
+
- **`node scripts/host-deps.mjs`(`--fix` / `--restore`)**:把插件用的 `@deepseek-ai/*` 逐包改为指向宿主安装的 junction(原始副本备份到 `.host-deps-backup/`)。两边的包不是同一份物理模块时,`instanceof` / `===` / symbol 查找都不成立,「适配宿主实现」只能退化成猜。
|
|
21
|
+
- **归档分组可重建**:工作区登记被 DSH 删除后(删登记不删目录、不删会话),归档列表按会话目录自动重建分组,标「工作区已移除」/「未登记的工作区」;目录仍在时给一个「重新登记为工作区」按钮(只在用户确认后调用宿主自己的接口,**只新增登记,不动文件与会话**)。
|
|
22
|
+
- **恢复归档顺带恢复归属**:恢复会话后按会话目录把它挂回工作区记账(新增登记 / 复用已有登记 / 挂回会话),响应里带回 `registered` / `attached` / `skipped`,界面按结果显示一句话结论。此前恢复出来的会话在宿主侧没有归属,只会掉进「未分组」。
|
|
23
|
+
- **场景可绑定一份提示词预设**:场景表单里选一个(单值字段 = 天然单选)。绑定前校验预设存在(不存在直接拒绝,不留悬空绑定),预设事后被删则场景卡片标「预设不存在」。**切换场景会直接改写 `~/.dsh/AGENTS.md`**(见下条)。
|
|
24
|
+
- **切换场景直接改写 `~/.dsh/AGENTS.md`**(同日,**反转**本轮早先「只注入一段、不碰文件」的决定 —— 用户裁定:「切换场景,对应的提示词直接把 AGENTS.md 直接修改」):启用/切换场景、改绑预设、编辑"正在驱动基线的那份预设"的正文,四个动作都会把那份预设**真写进全局基线**,与「提示词」页的「应用」同一条路(覆盖前多代备份到 `agents-md/__last-applied__/`);**关掉场景时按原文恢复"进场景之前"的基线**(那份可能是用户手写的,不一定对应任何预设)——快照存 hub 的 `scene-baseline.json`,恢复后清空,连续切场景不会覆盖快照。相应地,`tool-management:scene-prompt` 注入段**已删除**(真改文件后再注入一遍会让同一份正文进上下文两次,且用户手改基线后还会被重新注入);绑定关系只保留只读投影,用于页面「生效中」标记与"文件是否已同步"的判断(内容一致时**不写盘**)。同步逻辑提成独立模块 `src/scene-prompt-sync.ts`,可在临时目录上用真实服务端到端验证。
|
|
25
|
+
- **提示词预设库:新建即可写正文、编辑可改 id**:新建弹窗是「id + 正文文本框」(外加「或从现有预设复制」下拉,选中后把那份正文填进文本框,仍可继续改),不再是那个容易被当成搜索框的「复制来源」文本输入;编辑弹窗同样有 id 与正文两个字段。**改 id = 目录改名**(正文随目录一起走,目标已存在则拒绝、不合并),改名成功后宿主顺手把场景绑定一起改名(新增 op `rules-rebind-prompt`),不留悬空绑定。
|
|
26
|
+
- **「生效中」以场景绑定的那份为准**:场景启用且绑了提示词预设时,**提示词页把场景绑的那份标成「生效中」**(用户裁定:「场景启动了,提示词内生效中的应该是场景选择的那个」),页面顶部写明来源(`当前:life(场景「A」)`);切换场景会把它写进 `AGENTS.md`,所以「文件里是它」这个降级标记只在用户手改过基线、或写入失败时才会出现。
|
|
27
|
+
- **正在生效的提示词预设不能删除**(用户裁定):提示词页把「生效中」那行的**删除按钮禁用**并给出原因(悬停可见),宿主侧 `agentsmd-remove` 也**拒绝**删除它——生效 = 启用的场景绑定了它,否则 = 文件内容就是它;两者都不是的预设照常可删(被场景覆盖、只躺在文件里的那份也允许删)。删除按钮只是提示,真正的门在宿主:模型调用或旧页面缓存都会被挡住;被挡住时界面会把宿主返回的原因显示成错误条(`doRemove` 此前丢弃了响应,是静默失败)。判定失败时放行并记 warn——删预设不动 `~/.dsh/AGENTS.md`,最坏只是少一份副本。
|
|
28
|
+
- **技能导入弹窗新增「选择文件夹」**;人设的**工具白/黑名单按官方 Agent 预设分组**展示(同一工具属于多个预设时在对应分组各出现一次,勾选状态共享),不再把所有非当前会话工具统一标成「当前会话不可见」。
|
|
29
|
+
|
|
30
|
+
### 变更
|
|
31
|
+
|
|
32
|
+
- **兼容判定换底座**:删除「按源码文本比对官方实现」的门禁(上游改一行注释就会让归档/恢复/删除整体拒绝服务)。现在按能力路由——**有原生入口走原生、没有走受检适配层、都不行才拒绝**;拒绝信息写明**缺什么能力、后果、怎么修**,并且**永远发生在任何写入之前**。宿主本来就没有的可选原生槽位不算降级(由插件自己顶上)。
|
|
33
|
+
- **技能来源权限语义修正**(两组来源的权限正好相反):默认来源 `DSH 技能`(`~/.dsh/skills/`)与 `导入技能`(`~/.dsh/tool-management/skills/`)**必须读取**——不可移除、**也不可停用**(停用等于「读出来但不可调用」,与「路径不能不读取」冲突);但**里面的技能可以删**(进回收站,可原样恢复)。外部 Agent 目录与自定义目录相反:**可以停用或移除**(不再读取),但里面的技能**只读、不能删**。旧版本写过的 `sources.hub` / `removedSources` 残留策略位在读取时被丢弃。
|
|
34
|
+
- **用户数据搬出插件目录**:归档账本 `history-archived-at.json`、保留期 `history-retention.json`、工作区登记快照 `history-workspaces.json` 移入 `~/.dsh/tool-management/`(旧位置是插件目录 `data/`,启动时自动搬入,只搬不删、绝不覆盖)。npm 安装下 `dsh plugin update` 会整体替换插件目录,账本放那里会连累保留期基线。
|
|
35
|
+
- **归档服务改为独立门面**:`cordis.patch.yml` **只插入本插件**——不再禁用官方 `workspace` / `session-projection-cache`,不再插入竞争 provider,也不按包名推断兼容性。归档时刻改由官方持久化事件打点;宿主自带删除屏障时不包裹投影缓存,缺屏障时才包裹并在卸载后原样还原。
|
|
36
|
+
- **弹窗按钮统一**:全插件 24 处弹窗的「取消 / 关闭」只留在右上角(外加 Esc 与点遮罩),底部只留主操作。
|
|
37
|
+
- **语言跟随宿主**:客户端显式注入 `locale`(`dsh.client.inject` 精简为 `@deepseek-ai/dsh-client-locale`),面板与页签名不再恒为中文;**会话页**与 **AGENTS.md(提示词)页**整页接入中英词典(新增约 100 条词条)。`check:i18n` 新增一项检查:**代码里以字面量引用的键必须都在词典里**(挡住「界面直接显示原始键名」)。
|
|
38
|
+
- **AGENTS.md 预设「应用」保留 5 代备份**:写入 `__last-applied__/AGENTS.md.bak-<时间戳>`,按时间轮转只留最近 5 份(旧机器读取的 `__last-applied__/AGENTS.md` 照旧维护)。单槽位备份下连点两次「应用」会永久覆盖用户手写的原始内容。
|
|
39
|
+
- **提示词预设 id 口径放宽**(用户裁定「id 应该什么都能写」):不再限定小写字母/数字/连字符,中文、空格、下划线、点都可以。id 即目录名,因此只保留文件系统硬约束——不含 `/ \` 与 `< > : " | ? *`、不以点开头、不以点或空格结尾、不是 `.`/`..`、不是 Windows 保留设备名(`con`/`nul`/`com1`…)、不含控制字符、≤64 字符,以及一个保留字 `__last-applied__`(「应用」的备份槽)。口径收在新的单一模块 `src/agents-md/preset-id.ts`,AGENTS.md 预设库与场景绑定(`scenes[].prompt`)共用,避免两处漂移;导入预设的 id 也不再被压成 slug。
|
|
40
|
+
- **场景启用改单选**:除保留场景「全局」外**同时只能启用一个场景** —— 服务端拒绝多选(`error.rules.singleSceneOnly`,旧的 `all:true` 形态一并拒绝),界面把其余场景的开关**置灰**并说明被谁占用;`rules-create-scene` 会把历史默认 `active = null`(旧语义「全部启用」)**收敛成显式数组**,因此**新场景默认不启动**,并把 `collapsedActive` 回传界面如实提示;「切入此模式」现在会**同时启用该场景**(档案、记忆、提示词一起生效)。存量 `active = null` 且多个场景在场的状态**仍按旧语义读**(记忆段注入全部),场景页给一条显式「收敛为单选」按钮,而不是静默改写注入范围。
|
|
41
|
+
- **模型/脚本入口语义收紧**:`history-retention-set` 拒绝小数(原来 1.5 被静默取整成 1)并在错误里回显收到的值;`rules-set-active` 必须显式传 `all:true` 或 `scenes:[…]`(无参不再静默把注入范围清成空);`mcpm-set-enabled` 的停用分支幂等(不再每点一次就往 `cordis.patch.yml` 追加一条重复项);`skill_manager_create` 的落点与界面「创建技能」一致(都落 hub);`history-import` 改为经宿主 `agents.create` 创建会话并回读校验,导入失败如实报错(会话 id 形态变为 `session-<uuid>`)。
|
|
42
|
+
- **写操作门禁**:HTTP 路由先过宿主的 `connection.requestRejection`(Host 必须是回环 / LAN IP 字面量,叠加 browser-session cookie);宿主服务不在场时退回**本地判定**(只要求回环 Host + 非跨站 Fetch + Origin 与 Host 同源,**不含 cookie 鉴权**,比宿主栅栏弱)。`mcpm-reveal` / `mcpm-export` 这类会吐明文密钥的 op 额外要求请求带 `Origin` 头。显式配置的 `token` 是脚本 / 局域网的逃生门:令牌正确即视为已授权(并跳过栅栏)。
|
|
153
43
|
|
|
154
44
|
### 修复
|
|
155
45
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
| 场景守卫 | ✅ | `尚未创建`→`error.rules.sceneNotFound`;删 `global`→`error.rules.reservedScene`;删非空场景→`error.rules.sceneNotEmpty`;`a/b`→`error.rules.invalidGroup` |
|
|
178
|
-
| 档案记忆段三态 | ✅ | 勾一条→只注入该条;段清空→该场景全不注入而 `global` 仍在;移除段→回到「不碰」(`rules-budget` 三次输出) |
|
|
179
|
-
| 导入自动补场景 | ✅ | 返回 `{"imported":["导入场景/导入探针"],"scenes":["导入场景"]}` |
|
|
180
|
-
| 游离记忆 | ✅ | 体检报 `noScene`(warning),且不进 `rules-budget` 投影 |
|
|
181
|
-
| `model-candidates` | ✅ | 列出 4 个来源,含 `sensenova/sensenova-6.8-flash-lite` |
|
|
182
|
-
| `preset-tools` | ✅ | 4 个预设、49 个工具,其中 15 个标为当前会话可见 |
|
|
183
|
-
| 人设黑名单落盘 | ✅ | 修 mkdir 后活体复测:`subagent-create{provider:sensenova, model:sensenova-6.8-flash-lite, tools:[read_file,glob,grep], toolsDeny:[bash,pwsh]}` → 文件落在 `tool-management/agents/hub-probe.md`,frontmatter 含 `tools: read_file, glob, grep` + `toolsDeny: bash, pwsh`;`subagent-get` 原样读回 |
|
|
184
|
-
| 技能落 hub | ✅(需显式 root) | `skill-state` 来源表出现 `hub mutable=true path=...\tool-management\skills`;`skill-create{root:hub}` → 文件落 `tool-management/skills/hub-probe-skill-hub/SKILL.md`。**实测暴露**:不传 root 时仍落到 `~/.dsh/skills/`(服务层默认值漏改)→ 已修(见「修复」表) |
|
|
185
|
-
| 官方技能通道可见 hub | ✅(间接) | 插件把自己的技能源注册进官方 `ctx.skills.registerProvider`(`skills/service.ts:343`),`skill-state` 的 hub 来源与 `skill-detail` 都能列出/读取 hub 内技能;**未做**「模型真实调用 `skill` 工具读到它」的端到端(会烧 token) |
|
|
186
|
-
| 新界面(浏览器交互) | ❌ 未验证 | 见下「本轮诚实的失败」 |
|
|
187
|
-
|
|
188
|
-
### 本轮诚实的失败(记录过程,避免下次重走)
|
|
189
|
-
|
|
190
|
-
- **想用「假 React + 假 fetch 在 Node 里驱动真实 bundle」做交互级 UI 验收**,投入很大但渲染循环迟迟不收敛:
|
|
191
|
-
依次踩到 ①setState 同值高亮 → 用浅比较解决;②`build` 与事件 `insert` 顺序;③ useEffect 依赖里的
|
|
192
|
-
新闭包(`[refresh]`)导致每轮重跑 → 对函数依赖改用源码文本比较;④**按树位置给组件身份会让匿名组件撞 key**,
|
|
193
|
-
hook 状态串到别的组件上;⑤组件某轮未渲染时残留的 hook 游标会写错槽位(该条最隐蔽:`{deps,effect}`
|
|
194
|
-
被写进了 state 槽)。判定为**不可靠地基** → 整体回退删除(不留在仓库里充数)。
|
|
195
|
-
- 尝试用 Playwright 打开 3080 做界面验收失败:8123 测试宿主已停,其 token 对 3080 无效(401);
|
|
196
|
-
另起的测试宿主(8134)因 `npx` 启动链路卡住未起来。
|
|
197
|
-
- **结论**:浏览器交互验收仍以**真浏览器 + 有效 token** 为准,本轮**未跑**;能进 CI 的那两层见下
|
|
198
|
-
(`test/client-exports.test.mjs` 与 `test/client-render.test.mjs`),它们挡「导出丢失 / 装配失败 /
|
|
199
|
-
渲染期抛错」,挡不住交互行为。
|
|
200
|
-
|
|
201
|
-
### 界面故障:整页白屏(2026-09-13 用户报告,已定位并修复)
|
|
202
|
-
|
|
203
|
-
用户报告「工具打开什么都没显示」,并提供了浏览器控制台栈。**根因已确定**:
|
|
204
|
-
|
|
205
|
-
```
|
|
206
|
-
ReferenceError: sceneLabel is not defined
|
|
207
|
-
at ScenesPage (client.js:2526)
|
|
208
|
-
client.js:526 slot entry crashed in 'settings.section': ReferenceError: sceneLabel is not defined
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
`sceneLabel()` 定义在 **`MemoryPage` 函数体内部**(闭包),而 `ScenesPage` 渲染场景卡片时也调用它。
|
|
212
|
-
两个页面是各自独立的函数作用域,闭包无法共享 → `ScenesPage` 一渲染就抛 `ReferenceError`,
|
|
213
|
-
被 shell 的 slot 边界捕获成一条 `slot entry crashed` 日志,面板什么也不画(**整页空白**)。
|
|
214
|
-
|
|
215
|
-
- 修法:`sceneLabel` 提到**模块作用域**并把 `scenes` 作为参数传入(`sceneLabel(data.scenes, name)`),
|
|
216
|
-
五处调用点全部改为显式传参。
|
|
217
|
-
- 同类排查:写了一次性 AST 静态扫描(页面组件里「以调用/读取形式出现、但既不在本页声明、也不在
|
|
218
|
-
模块作用域声明」的标识符),**只有 `undefined` 与浏览器全局 `FileReader` 两处误报**,无第二处同类缺陷。
|
|
219
|
-
- 为什么前一轮的渲染测试没抓住:那一版把 `fetch` 写成直接 reject,页面停在 loading 态,
|
|
220
|
-
`(data.scenes || []).map(...)` 的回调一次都没执行。**修测试**:`test/client-render.test.mjs`
|
|
221
|
-
新增「带数据挂载」用例——假 fetch 按 op 返回**真实形状**的夹具(scenes / rules / 人设 / 归档都非空)、
|
|
222
|
-
真的执行 effect、等 promise settle 后再渲染 4 轮。已用「把 `sceneLabel` 改名为 `sceneLabelBROKEN`」
|
|
223
|
-
注入验证:该用例确实报 `ScenesPage(第 2 次渲染): sceneLabelBROKEN is not defined`。
|
|
224
|
-
- 教训(与上一节同源):**空数据的渲染测试等于没测**。列表、回调、条件分支都必须有数据走一遍。
|
|
225
|
-
|
|
226
|
-
### 排查过程留档(2026-09-13 白屏)
|
|
227
|
-
|
|
228
|
-
定位过程本身有两条可复用的教训,记下来避免重走:
|
|
229
|
-
|
|
230
|
-
- **不能进浏览器复现**:3080 宿主要求 launch token 才能开页面(`dsh-client-connection` 的
|
|
231
|
-
`authorizeIndex`),我不会去进程里取用户凭据,所以**全程没有浏览器观测**,只能靠静态分析与
|
|
232
|
-
自建 harness 逼近——最终是**用户贴出的控制台栈**一句话定位。以后遇到同类现象,第一件事就该是
|
|
233
|
-
要控制台输出,而不是先写探针。
|
|
234
|
-
- **自建探针会骗人**:我一度用自写的花括号扫描器判断作用域,被 CSS 模板串与正则里的花括号带偏,
|
|
235
|
-
得出「导出语句在 factory 作用域」的错误结论,随后连续多轮插桩自相矛盾。改用 **TypeScript
|
|
236
|
-
编译器的 AST**(`ts.createSourceFile` + `getLineAndCharacterOfPosition`)才得到权威结论:
|
|
237
|
-
`module.exports = {` 与 `return module.exports` 同属 factory,而 `_pages` 挂在 `method:apply` 里。
|
|
238
|
-
**结论:判断作用域用真解析器,不要用手写扫描器。**
|
|
239
|
-
- 已排除的假设:宿主侧插件正常(`rules-list` op 返回 200);`lib/client.js` 语法与解析正常;
|
|
240
|
-
`ctx.get('slots')` 与官方 `dsh-client-ui-layout` 注册的服务名一致;bundle 除 `react`
|
|
241
|
-
(平台种子模块)外无其它 `require`。
|
|
242
|
-
- 本轮第一个修复(导出的 `_pages`/`DICT` 静默丢失,见「修复」表)是**真缺陷但不是本次白屏的原因**,
|
|
243
|
-
两者都保留在记录里,不合并叙述。
|
|
244
|
-
|
|
245
|
-
### 契约测试
|
|
246
|
-
|
|
247
|
-
`npm test` = build + `check:i18n` + **76 例** node --test:
|
|
248
|
-
|
|
249
|
-
- `archive.test.mjs`(13):档案纯逻辑 + 引擎状态机
|
|
250
|
-
- `import.test.mjs`(16):zip/上传展开、落点规划、限额**回报**(不静默丢)
|
|
251
|
-
- `approval-policy.test.mjs`(6):`never` 审批策略探测,用真实 cordis + 真实 `ApprovalService`,兄弟 fiber 复现读取链
|
|
252
|
-
- `subagent-scene.test.mjs`(6):场景绑定必须在子代理运行**之前**拒绝
|
|
253
|
-
- `subagent-persona.test.mjs`(9):frontmatter 往返(`provider`/`model`/`toolsDeny`)、目录不存在时创建、重名拒绝
|
|
254
|
-
- `hub-layout.test.mjs`(12):旧布局搬移不覆盖、`global` 恒在且不可删、记忆必须归属已存在场景、档案记忆段只影响投影、路径回传
|
|
255
|
-
- `skills-state.test.mjs`(3):**技能状态文件读取韧性** —— 旧文档缺后来新增的来源键 → 自愈补默认值不 fail-closed;文件不存在 → 默认状态;version 不认识 / 非 JSON / 类型写错 → warning + 锁定 + 全部来源停用(fail-closed)
|
|
256
|
-
- `skills-delete.test.mjs`(4):**哪些技能可以删** —— 用户级来源(DSH 技能 / 导入技能)可写但不可删,删除在碰文件之前就被拒(`error.skill.notDeletable`);只读来源仍报 `error.root.readonly`;界面名「导入技能」
|
|
257
|
-
- `client-exports.test.mjs`(4):**运行时导出契约** —— 只求值 factory(不跑 `apply`)就必须拿到
|
|
258
|
-
`dict`/`pages`/`apply`;词典 zh/en 键集合一致、无空文案;代码里每个字面量 `t('键')` 都能解析。
|
|
259
|
-
反向护栏:禁止缩进 ≥ 8 空格的 `module.exports.X =`;另有**档案弹窗布局契约**(段体下限优先、禁止 flex:1 平分、列表自身出滚动条)
|
|
260
|
-
- `client-render.test.mjs`(4):**装配与渲染** —— 假 ctx 跑完整 `apply`,断言它往 `settings.section`
|
|
261
|
-
注入并注册 `dsm-tools`;七个页面组件都被填充;整棵组件树(自建 hook dispatcher,真实 React dispatcher
|
|
262
|
-
接口)递归渲染不抛错;**带数据挂载**:假 fetch 按 op 返回真实形状的夹具并真的执行 effect,
|
|
263
|
-
等 promise settle 后再渲染 4 轮,列表/回调/条件分支都走到。已用「注入缺陷 → 必须失败」自检过两次
|
|
264
|
-
(面板抛错;`sceneLabel` 改名 → 报 `not defined`)
|
|
265
|
-
|
|
266
|
-
辅助脚本:`npm run check:i18n`(中英键集合 + 占位符一致)、`node scripts/i18n-debt.mjs`(按页面统计硬编码中文欠账)、`node scripts/find-hardcoded-zh.mjs`(逐行定位)。
|
|
267
|
-
|
|
268
|
-
---
|
|
269
|
-
|
|
270
|
-
---
|
|
271
|
-
|
|
272
|
-
## v0.3 — 场景记忆与场景档案(2026-09-13)
|
|
273
|
-
|
|
274
|
-
### 功能
|
|
275
|
-
|
|
276
|
-
- 记忆真源从 `$DSH_HOME/rules/` 更名到 `$DSH_HOME/scene-memory/`(v0.4 已再次搬迁,见上)。
|
|
277
|
-
- **单投影**:活动场景的记忆正文 → per-agent `systemPrompt` 段(自动在场,模型无需任何工具调用)。原「始终层写 `~/.dsh/AGENTS.md`」下线,公共基线改由 `_shared/` 承担。
|
|
278
|
-
- **两相扫描 + 指纹缓存**:每次装配只做一次 `stat` 遍历产出指纹(不读正文),指纹不变直接复用上次拼接结果。**刻意不用 `fs.watch`**——Windows 上递归监听不可靠,而监听静默失效的后果是永久返回过期内容。
|
|
279
|
-
- **注入预算**:某条记忆放不下时只跳过它、继续装后面的小记忆,段尾附「未注入(超出预算)」清单,模型与用户都能看见。
|
|
280
|
-
- **场景档案**:每场景可配 MCP 工具集 / 技能集 / 子智能体绑定,段未定义 = 不改动该域,段已定义但空 = 全部停用。勾了工具/技能段的场景可「设为当前模式」:先落盘快照 → 应用 → 记忆收窄;退出按快照**原文**恢复。
|
|
281
|
-
- **轻量子智能体**:`subagent_run` 带人设独立运行、只回传结果(≤16 KiB)、跑完即弃、不进 History。
|
|
282
|
-
- **导入**:人设 / 记忆支持 `.md` 与 `.zip`(含 bundle 形态:`<场景>/<名>/SKILL.md` + 同层附件);重名跳过并报告,绝不覆盖。
|
|
283
|
-
- **UI v2**:七栏(场景 / MCP / 技能 / 子智能体 / 提示词 / 记忆 / 会话),页头同构、段卡片统一、通知两级;技能同名可选来源(`preferredSkills`)。
|
|
284
|
-
|
|
285
|
-
### 关键设计决策
|
|
286
|
-
|
|
287
|
-
| 决策 | 理由 |
|
|
288
|
-
|---|---|
|
|
289
|
-
| 勾选集存储「勾选的启用集合」,MCP 落**停用补集** | 应用时该域启停 = 与勾选集完全一致;未勾服务器 → `['*']` 整台停用(通配由 guard/restrict 原生支持,服务器后加载也被拦) |
|
|
290
|
-
| 单一「当前模式」 | 避免多场景启停冲突;退出后 `active` **不恢复** |
|
|
291
|
-
| 子智能体绑定不走模式 | 按「启用场景」并集实时生效 →「记忆 + 子智能体」型场景勾上即生效,因此这类场景不显示模式按钮 |
|
|
292
|
-
| 手动改动不自动回写档案 | 「保存到场景」是显式动作,防静默覆盖 |
|
|
293
|
-
| 子智能体走官方 `ctx.subagents` 原语自建薄工具,不用 agent-preset 组合 | preset 是会话创建时加入的插件组合,与「运行中即用即弃」不符且对轻量人设过重;preset 留作将来「重型模板」载体 |
|
|
294
|
-
| 单工具 + 参数路由,而非每人设一个工具 | 工具清单随文件增删抖动会让 tool list 不稳定 |
|
|
295
|
-
| spawn provider 惰性兜底挂载(有意偏离原设计,用户批准) | yml 的 `insert` 行是启动期解析,缺该包的宿主会因单行加载失败拖垮整棵插件树;且与运行时兜底存在双挂载窗口。改为 `ctx.subagents.list()` 探测 → 缺失才 `apply()` → 失败原因原样抛给模型 |
|
|
296
|
-
| **非干扰原则**(最高约束) | 只走官方扩展缝(`SystemPrompt.section`、`tools.register/guard/restrict`、`ctx.subagents.start`、`cordis.patch.yml`),状态全落自有命名空间。**红线**:不得为插件功能改 DSH 原生文件语义、不得改原生段名/段序、不得破坏前缀缓存契约 |
|
|
297
|
-
|
|
298
|
-
### 验收证据(活体)
|
|
299
|
-
|
|
300
|
-
| 验收项 | 结论 | 证据 |
|
|
301
|
-
|---|---|---|
|
|
302
|
-
| 档案「勾=启用」方向(只勾 github) | ✅ | 磁盘 `{github:[], tavily:['*'], context7:['*'], …}`;运行时 github on:26 / tavily off:5;5 台未勾服务器 `allToolsDisabled:true` |
|
|
303
|
-
| 勾服务器 + 只勾部分工具 | ✅ | 档案存 24 个;重进模式后停用名单**恰为**未勾的那两个 |
|
|
304
|
-
| 全不勾 = 全部停用 | ✅ | 档案 `mcp:{}` 成功持久化;进入后 6 台全 `['*']` |
|
|
305
|
-
| 退出模式完全还原 | ✅ | 退出后 `disabled={}`、全部 on、`mode=null`;两次进/退一致、无残留 |
|
|
306
|
-
| 仅记忆 / 仅子智能体场景 | ✅ | 无模式按钮;直连 API 返回结构化拒绝 |
|
|
307
|
-
| 模式中删除场景 | ✅ | 拒绝并提示先退出模式 |
|
|
308
|
-
| 记忆收窄 | ✅ | 进入后 `active:["pw-test"]`;退出后 `active` **保持** |
|
|
309
|
-
| 子代理继承场景记忆段 | **实锤(继承)** | 人设要求复述「场景记忆」段首行 → 子代理返回「这是 S3 继承验证用的场景记忆首行。」 |
|
|
310
|
-
| 绑定外运行前拒绝 | ✅ | `Error: 人设不可用: echo-test(可用: other-helper)`,且 `runSerial` **未被调用**(不白烧 token) |
|
|
311
|
-
| 跨来源模型路由(决定性证据) | ✅ | 子会话 `request/header` 与 `request/context` 均为 `{"provider":"sensenova","model":"sensenova-6.8-flash-lite"}`(contextWindow 262144);`subagent/descriptor = {mode:"one-shot", provider:"spawn", label:"other-helper"}` |
|
|
312
|
-
| never 预检(修复前后 A/B 同会话) | ✅ | 修复前 = `Error: the user rejected tool "subagent_run"`;宿主载入修复后 = never 专属文案。两次对照唯一变量 =「宿主是否载入带修复的 `lib/`」 |
|
|
313
|
-
| 三个确认门具名复跑(never 会话,真写盘) | ✅ | `rule_manager_write` → 落盘 261 B 记忆;`skill_manager_create` → 落盘 453 B 技能;两者各留 `confirm-bypass` 日志 |
|
|
314
|
-
| 官方 `subagent` / `subagent_fork` **无 ask 门** | ✅ | 两次实跑均无审批卡,会话日志该调用后**无 `approval/asked`**;对照本插件 `subagent_run` 弹卡 → `approval/decided {outcome:"allowed-once"}` |
|
|
315
|
-
| 全局记忆注入 | ✅ | 仅一条无场景记忆时 `rules-budget.usedBytes` 由 **0 → 155**(修复前恒 0:根层记忆从不注入) |
|
|
316
|
-
| bundle 导入三段贯通 | ✅ | UI 计数与徽章 → 磁盘字节数与 zip 条目逐一相等 → 下一轮 system prompt 出现该场景段 |
|
|
317
|
-
| 导入限额 7 例 | ✅ | 由其中 2 例抓出静默丢弃缺陷(见下) |
|
|
318
|
-
| 真实文件夹拖拽 | ⚠️ 部分 | Playwright 不支持目录投递;用忠实的合成 `FileSystemEntry` 树驱动插件真实代码路径(并抓出目录前缀丢失缺陷) |
|
|
319
|
-
|
|
320
|
-
### 缺陷与根因(本轮修复)
|
|
321
|
-
|
|
322
|
-
| 缺陷 | 根因 | 状态 |
|
|
323
|
-
|---|---|---|
|
|
324
|
-
| **C1** MCP 档案勾选语义方向反转 | `computeMcpPlan` 把勾选集当**停用名单**直写 sidecar | 已修(改产补集) |
|
|
325
|
-
| **C2** 模式进入缺「记忆启用集收窄为 `{S, _shared}`」,而注释/README 声称已实现 | 引擎 deps 无 active 通道 | 已修 |
|
|
326
|
-
| **C3**「段已定义但全不勾 = 全部停用」不可持久化 | `normalizeMcpSpec` 丢服务器级空清单 + 引擎删空段 | 已修 |
|
|
327
|
-
| **C4** subagent 两工具绕过 `defineTool` 注册 | 参数未编译即入库,绕过 `ToolArgsError` 校验 | 已修 |
|
|
328
|
-
| **C5** `subagents.*` i18n 键全缺(整页渲染原始键名) | zh/en 均零定义 | 已修(各补 21 键) |
|
|
329
|
-
| **C6** `['*']`(整台服务器停用)**从未真正生效** | `readDisabledTools` 用 `/^[A-Za-z0-9_-]{1,128}$/` 过滤服务器级名单,`'*'` 不匹配 → 静默丢弃。连带失效四件事:guard 热路径、整台展开、模式快照保真、勾选器 `allToolsDisabled` 标记 | 已修(解析处放行 `'*'`)。**纯自动化测不到**:引擎契约测试注入假 deps,绕过 sidecar 解析层 —— 浏览器实测抓出 |
|
|
330
|
-
| never 预检恒 false | `(ctx as any).approval` 在 `inject` 未声明 `approval` 时**抛异常**(`cannot get property "approval" without inject`),被 `try/catch` 吞成 `false`。对照 `dsh-tools` 用 `ctx.get("approval")` 取同一条缝 | 已修(抽到 `src/approval-policy.ts`,三个门共用一处前裁决) |
|
|
331
|
-
| zip 单条目 >8 MiB **静默丢弃** | fflate `filter` 回调丢弃但不回报 | 已修(逐条回报原因) |
|
|
332
|
-
| zip 条目 >2000 **静默丢弃** | 同上(只回报 2000 条) | 已修(条目数上限只报一次) |
|
|
333
|
-
| 拖文件夹时目录前缀丢失(记忆落到全局而非 `文件夹测试/…`) | 记忆/人设 `ImportModal` 用 `f.name`,丢掉 `_dssmPath` | 已修(改用 `uploadFilePath(f)`) |
|
|
334
|
-
| 人设 `model` 无法跨来源 | `resolveModel(provider, model)` 是二元组、不做 `provider/model` 拆分 | 已修(补 `provider` 键:frontmatter、list/get、表单、双语 i18n) |
|
|
335
|
-
| `SubagentResult` 诊断字段读错(读 `detail`,官方是 `diagnostic`) | 恒 undefined,失败时模型只见空输出 | 已修 |
|
|
336
|
-
| `parseModeState` v1 快照兼容分支是死代码 | 两个分支返回同一个 `{}`,升级前数据退出模式会把「快照启停」还原成「全启用」 | 已修(v1 布尔表折算为 v2 停用名单) |
|
|
337
|
-
| Minor 1 运算符优先级:allowed 为空时丢右括号且 `(无)` 永不生效 | `+` 先于 `\|\|` | 已修 |
|
|
338
|
-
| Minor 2 en 词典整块重复 + `memory.archive.emptySection` 只有 en(zh 用户看不到「全不勾 = 全部停用」提示) | 词典维护漂移 | 已修 |
|
|
339
|
-
| Minor 3 `toolStates` 不滤 `'*'` 产出 `server/*` 伪键 | 与另一处口径不一致 | 已修 |
|
|
340
|
-
| Minor 12 spawnReady 一次性标记(挂载失败也置 true 不重试) | — | 已修(每次调用先探测) |
|
|
341
|
-
| Standards 1 `lib/` 与 `src/` 同提交漂移 | lib 入库 + `lint` 只 check 2 个产物 | 已修(lib 出版本库,克隆后先 `npm run build`) |
|
|
342
|
-
| Standards 2 WRITE_OPS 漏 3 个写 op(`rules-trash-remove` / `rules-attach` / `rules-detach` 不受 token 保护) | op 表与写白名单是两份手工清单 | 已修(改为从各 service 的 `writeOps` 派生) |
|
|
343
|
-
| Standards 3 `core.js` `skillDetail` 引用未定义变量 `key`(未知来源抛 ReferenceError) | 无测试套件,只能靠运行撞上 | 已修 |
|
|
344
|
-
| Standards 12 `writeHistoryRetention` 吞错后仍返回 `ok:true` | 与其余域「失败必报」相悖 | 已修 |
|
|
46
|
+
- **进出场景模式会静默改写技能策略(数据污染)**:快照与目标状态用的是**生效状态**,写回的却是**显式策略记录**,两者不等价 → 进出一次模式就会把用户从未启用的技能写成启用、把显式启用的改写成显式停用。现在扫描一次同时给出「生效 / 被同名覆盖 / 全量键」,快照只取生效项,写回时跳过被覆盖的副本、且**已经处于目标状态的技能不再写**。修复后同一实验下状态文件与基线逐字节一致。
|
|
47
|
+
- **导入技能里删掉的技能拿不回来**:回收站元数据把非项目级来源记成了项目级,恢复时被判「原项目不在活动工作区」而拒绝。现在按作用域分岔,用户级来源按 key 重新解析路径(不信任元数据里的旧路径)。
|
|
48
|
+
- **技能回收站显示字面量 `undefined`**:项目级来源缺名称/路径时不再拼空值,统一回退到来源显示名。
|
|
49
|
+
- **面板不随宿主语言切换**、**会话页与 AGENTS.md 页整页硬编码中文**、**两个词条键写错导致界面露出原始键名**(`mcp.field.entryId` → `mcp.detail.entryId`)。
|
|
50
|
+
- **`subagent_run` 的确认门早于参数校验**:人设不存在时不再先弹确认卡(批准后才报错),直接让工具体给出真实错误。
|
|
51
|
+
- **删除链路的前置实现检查**:删除序列依赖官方声明为 private 的方法,此前失败点可能落在链路中段、留下「转录已删但归档标记还在」的部分状态。现在在任何破坏性步骤(含写屏障)之前校验所需方法,缺失即快速失败并提示更新插件。
|
|
52
|
+
- **英文界面下兼容页的结论条仍是中文**:`compat-status` 的 `summary` 由服务端拼中文,英文界面直接照抄。现改为**客户端按当前语言拼**(新增 `compat.summary.ok` / `compat.summary.degraded` 两条词条),服务端那份 `summary` 只留给日志;并加一条本地化回归断言:英文词典下渲染兼容页,结论条不得出现中文字符(只锁"不许露中文",不锁措辞)。
|
|
53
|
+
> 仍未本地化:降级项的 `label` / `detail` 与阻塞项文本仍由 `src/compat/probe.ts` 输出中文。宿主一切正常时页面上看不到它们(多数机器就是这个状态),一旦真降级,英文界面会中英混排。
|
|
54
|
+
- **`history-workspace-register` 漏了 token 门禁**:它会新增一条宿主工作区登记,属写操作却不在 `WRITE_OPS` 里 —— 配置了 `token` 时它不校验 `x-dsh-token`(仍受宿主栅栏约束)。现补入清单,与其它写 op 一致。
|
|
55
|
+
- **两处与实际行为不符的界面文案**:AGENTS.md「应用」的说明补上「备份**保留最近 5 代**」;创建技能的确认卡原写 `DSH_HOME/skills`,而该工具已改为落 `~/.dsh/tool-management/skills/`(与界面「创建技能」同根)。
|
|
56
|
+
|
|
57
|
+
### 已知限制(本版)
|
|
58
|
+
|
|
59
|
+
- **浏览器交互验收仍未跑**(宿主要 launch token)。能进 CI 的是导出契约、装配与渲染、语义契约三层,**挡不住交互行为**;破坏性路径(归档 → 恢复 → 永久删除 → 保留期清理)仍需人工在实机点一次。
|
|
60
|
+
- **与 `@michengai/dsh-archive-manager` 未做双安装验证**,不宣称与任意版本共存。归档兼容层仍是**有限兼容层**,不是零侵入:本地恢复/删除访问经检查的宿主内部状态;宿主缺自带删除屏障时会包裹投影缓存的 `put` / `write`(卸载后还原)。
|
|
61
|
+
- **依赖去重只处理「两边都有」的包**;只有插件侧存在的包会报 `SKEW` 且**不被改动**。生产布局(`profiles/<name>/node_modules/<plugin>`)不需要跑 `--fix`,开发 `link:` 布局才需要。
|
|
62
|
+
- **能力探测的版本指纹**取自 `@deepseek-ai/dsh-workspace` 的 `package.json`;官方拆包或改名时指纹退化为 `unknown`(此时仍按能力判断,不按版本)。能力评估有 5 秒 TTL,兼容页与写路由最多滞后 5 秒。
|
|
63
|
+
- **硬编码中文未清零**:`node scripts/i18n-debt.mjs` 当前报 **214 条**(提示词页 15 条 + 199 条散落在未按页统计的组件与共享壳中;会话页已清零)。该脚本按页面函数分区统计,因此「按页」只能覆盖它认得的页面。
|
|
64
|
+
- **官方 Config schema 缺失**:插件仍以 `{name, inject, apply}` 形式加载,`config.*` 裸读,没有加载期校验与默认值。
|
|
65
|
+
- **场景提示词的三个边界**:① 保留场景「全局」也可手工绑定提示词(写在 `rules-index.json` 的 `scenes.global.prompt`),但它只在**没有任何场景启用**时生效,界面暂不暴露该入口;② 场景提示词**不计入记忆字节预算**(预算只管记忆段),体量由你自己控制;③ 历史 `active = null` 的多场景状态要你点一次「收敛为单选」才进入单选语义。
|
|
66
|
+
- 其它长期边界见下方「长期约束与边界」。
|
|
345
67
|
|
|
346
68
|
---
|
|
347
69
|
|
|
348
|
-
## v0.
|
|
349
|
-
|
|
350
|
-
- 五域合并为一个设置面板:MCP / Skills / AGENTS.md 预设 / History(归档会话)。
|
|
351
|
-
- **MCP**:工具级启停(模型看不见也调不到)、重启只重连**不改变启停状态**、密钥(`env` / `headers`)默认打码、改写补丁前自动 `.bak` 时间戳备份(保留 5 份)、重复 loader id 写前拦截、跨级迁移失败自动回滚。
|
|
352
|
-
- **Skills**:接入 `~/.agents` / `~/.codex` / `~/.claude` 等官方不加载的技能目录并支持自定义任意目录(只读接入、重叠拒绝);创建 / ZIP 与文件夹导入 / 回收站(恢复、永久删除)/ 系统编辑器打开源文件;目录由后台线程监听,编辑器改完页面自动刷新。
|
|
353
|
-
- **AGENTS.md 预设**:多套全局指令基线,一键「应用」写入 `~/.dsh/AGENTS.md`(新会话生效、当前会话不变)。
|
|
354
|
-
- **History**:归档会话按项目分组、搜索、全选、批量恢复 / 永久删除、保留期自动清理;从 Claude Code / Cursor(JSONL)、Codex(Markdown)、任意文本导入对话;导出支持 Markdown / JSONL。
|
|
355
|
-
|
|
356
|
-
## 关键设计决策(长期有效)
|
|
70
|
+
## v0.5.1(2026-09-13)
|
|
357
71
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
| 审批策略探测必须用 `ctx.get('approval')` 而非 `ctx.approval` | 后者在 `approval` 不在 `inject` 且 fiber 链上无提供者时**抛错**,被 try/catch 吞掉后表现为「永远不是 never」 |
|
|
364
|
-
| 人设的工具候选取**全体预设并集** | 人设可在任意预设下被复用;只列当前会话的工具会让换预设后的子代理启动失败(官方 `toolFilter` 对未知名直接拒绝启动) |
|
|
365
|
-
| MCP 停用表存**勾选集的补集**,通配 `['*']` = 整台停用 | guard/restrict 原生支持通配,服务器后加载也会被拦 |
|
|
366
|
-
| 场景记忆的模块路径与 op 名保留 `rules-*` 内部协议 | 避免大范围改名;用户可见名称是「场景记忆」/`memories/` |
|
|
367
|
-
| `lib/` 不入版本库 | 曾出现同一提交内产物与 `src/` 漂移;克隆后必须先 `npm run build` |
|
|
368
|
-
| 浏览器端 `src/client.js` 经 `scripts/sync-client.mjs` **逐字节**复制到 `lib/` | 不走 tsc;勿改该同步语义 |
|
|
72
|
+
- **场景档案弹窗:新加的段默认一项都不勾**——MCP 工具集 / 技能集 / 子智能体绑定是空集,记忆段只预勾本场景里已启用的那几条;「全选」= 本场景全部。段脚注写明代价:空段 = 该域全部停用(子智能体段例外,空段 = 不限制)。
|
|
73
|
+
- **档案弹窗「记忆」段只列被编辑场景自己的记忆**:宿主侧按记忆所属场景取档案,列别的场景(含「全局」)勾了不起作用,属陷阱 → 改为与本弹窗其余三段同构的平铺勾选行;记忆描述按 80 字截断,全文进悬浮提示。
|
|
74
|
+
- **场景页排版重做**:卡片只留「名字 / 标签 / 开关 + 一行描述 + 动作行」,数量收进页首「当前模式」条(只在真的进入模式后出现);描述上限 60 字;「切入此模式」升为卡片主按钮。
|
|
75
|
+
- **保留场景「全局」不再出现在场景页与档案弹窗**:它恒定注入、不是可切换的预设,MCP / 技能 / 人设各有专页;标记「任何对话都注入」压成「常驻」。
|
|
76
|
+
- 客户端契约测试补上「档案弹窗默认勾选」「记忆段只认本场景的记忆」「场景页不列全局」等用例;两份 README 的测试组清单同步校正。
|
|
369
77
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
## 开发与验证约定
|
|
373
|
-
|
|
374
|
-
```bash
|
|
375
|
-
npm install
|
|
376
|
-
npm run build # tsc + 同步客户端 bundle
|
|
377
|
-
npm run lint # node --check 两个产物
|
|
378
|
-
npm run check:i18n # 中英词典键集合 + 占位符对齐
|
|
379
|
-
npm test # build + check:i18n + 全部契约测试(67 例)
|
|
380
|
-
```
|
|
78
|
+
**已知限制(未变)**:浏览器交互验收未跑;硬编码中文欠账未清零;官方 Config schema 缺失。
|
|
381
79
|
|
|
382
|
-
|
|
383
|
-
契约测试只锁语义(如「场景绑定必须在运行前拒绝」),**不能替代**浏览器/宿主实测。
|
|
384
|
-
无条件纪律:证据先于声称、诚实边界、红队自查(主动列出未验证项与做不到的事)。
|
|
80
|
+
## v0.5.0(2026-09-13)
|
|
385
81
|
|
|
386
|
-
|
|
82
|
+
**破坏性 / 结构性变更**
|
|
387
83
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
84
|
+
- **插件产生的文件全部收进 `~/.dsh/tool-management/`**:记忆、人设、AGENTS.md 预设、新建/导入的技能、回收站、索引与配置。旧位置(`~/.dsh/scene-memory/`、更旧的 `~/.dsh/rules/`、`~/.dsh/subagents/`、插件目录 `data/agents-md-presets/`)首次启动**自动搬入**,纪律四条:**只搬不删**(源目录留空壳)、**绝不覆盖**(目标同名则跳过)、**每进程一次**、**失败不阻断**。`~/.dsh/skills/`(官方技能目录)**不搬**,仍作为可切换来源。
|
|
85
|
+
- **场景从「恰好有这个名字的目录」升级为显式记录**(`rules-index.json` 的 `scenes` 切片:`label` / `description` / `order` / `createdAt`)。**空场景合法**;保留场景 `global`(界面「全局」)恒定存在、不可删除;`memories/` 根层的裸 `.md` **不再注入**并在体检里报 `noScene`;场景名单个路径段。
|
|
86
|
+
- **斜杠命令全部下线**:`/mcp`、`/skills`、`/agents-md`、`/scene-memory`——它们只能输出纯文本快照,既不能操作也容易与面板状态不一致。
|
|
391
87
|
|
|
392
|
-
|
|
88
|
+
**新增 / 变更**
|
|
393
89
|
|
|
394
|
-
|
|
395
|
-
|
|
90
|
+
- **技能来源**:新增插件自有来源 **「导入技能」**(`~/.dsh/tool-management/skills/`,新建 / 导入的落点,优先级高于 `~/.dsh/skills/`,同名时遮蔽官方那份);新增 **「移除来源」**——与「停用来源」不同,移除是**连目录都不再扫描**(技能从列表消失、不参与同名优先级、模型侧候选也不产出),**源文件一个字节都不动**,可一键恢复读取。
|
|
91
|
+
- **界面**:工具页七栏(场景 / MCP / 技能 / 子智能体 / 提示词 / 记忆 / 会话);场景档案编辑器新增第 4 段「记忆」(勾选只影响注入,文件不动);人设的模型与工具限制收进「高级选项」折叠区(模型下拉 + 工具白/黑名单勾选器);勾选区拉高(弹窗上限 620 → 720 px,段体改为下限优先);四个表单的辅助提示去冗余(删 6 条、改短 4 条)。
|
|
92
|
+
- **i18n**:MCP 页与共享状态层从硬编码中文改为词典取词;七个页面的副标题统一为同一句式。
|
|
396
93
|
|
|
397
|
-
|
|
94
|
+
**修复**
|
|
398
95
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
| Standards 6 | 五域重复基础设施 | Important | 写串行队列 ×3(逐字相同)、TTL 缓存 ×5、`message()` ×4、原子写 ×2 而另有两处裸 `writeFile`(同域四种持久化强度)、win32 identity ×3、场景名校验前后端各一份 | **未修**(收敛重复是既定方向) |
|
|
404
|
-
| Standards 7 | 错误/返回/日志约定不统一 | Important | skills 成功返回 `{ok:true,data}`、rules/index 返回扁平 `{ok:true,...}`;错误三种形状 → `translateError` 对 MCP/History/AGENTS.md 页完全失效;日志四通道(README 宣称的「运行日志」其实只有技能域在写) | **未修** |
|
|
405
|
-
| Standards 8 | 五页脚手架重复 | Important | 各页手写 title-row + 徽章 + 三格统计 + 筛选 + 空态 + 确认弹窗;操作反馈 4 种实现;缺 `PageHeader` / `SummaryBar` / `ConfirmModal` 三个共享组件 | **部分缓解**(v0.3 C 批统一了 Notice/页头/段卡片;v0.4 把勾选类原语提到共享作用域;**共享组件仍未提取**) |
|
|
406
|
-
| Standards 9 | 命名 | Minor | 模型工具三种前缀并存(`agentsmd_*` 是唯一不带 `_manager` 的);`index.ts` 注释仍写旧环境变量名 `DSH_SKILL_MCP_MANAGER_TOKEN` | **部分撤回**(「README 称 10 个工具实为 12」**误报撤回**:逐一数 `tools.register(defineTool(...))` 恰好 10 个);其余未修 |
|
|
407
|
-
| Standards 10 | 死代码 / Speculative Generality | Minor | `core.js` 的 `setSkillEnabled` 是纯转发;`client.js` DICT 里 `root.gemini/cursor/opencode/ccswitch` 与整组 `error.proto.*` 来自上游已裁剪协议 | **部分已修**(`rules/service.ts` 死代码已删);DICT 死键与 Middle Man 未处置 |
|
|
408
|
-
| Standards 11 | `index.ts` 手写 YAML 解析(约 200 行) | Minor | 注释已声明 known limitation,可接受,但它是 index.ts 膨胀主因 | **未修**(随 index.ts 拆分处理) |
|
|
96
|
+
- **工具页整页白屏**:`sceneLabel` 定义在 `MemoryPage` 闭包里却被 `ScenesPage` 调用 → `ReferenceError` 被 slot 边界吞成日志。
|
|
97
|
+
- **导出静默丢失**:`module.exports._pages` / `DICT` 写在 `apply` 方法体末尾,`apply` 提前返回就永不执行 → 改为在 factory 作用域落地。
|
|
98
|
+
- **Skills 页被锁死**:校验器要求状态文件里记录每个来源,新增 `hub` 来源后旧文件被判非法 → fail-closed 全停用 + 锁定写入(文件其实完好)。改为校验归一化后的文档:**缺键自愈、类型错仍拒绝**。
|
|
99
|
+
- 人设目录不存在时创建失败;旧布局迁移把场景目录多套一层;`skill-create` 不传 root 时落错目录。
|
|
409
100
|
|
|
410
|
-
|
|
101
|
+
**已知限制(未变)**:浏览器交互验收未跑(宿主要 launch token);硬编码中文欠账未清零;官方 Config schema 缺失。
|
|
411
102
|
|
|
412
|
-
|
|
413
|
-
- **「无测试套件」的复核结论**:`skillDetail` 的 ReferenceError 与门禁漂移恰好都是断言级测试能拦的;在 13k 行、五域复杂度下,「无测试」的决定已不成立 → 此后引入 `node:test` 契约测试(4 → 13 → 22 → 39 → 47 → 61 例)。
|
|
103
|
+
## v0.2.0 及更早(2026-09-12)
|
|
414
104
|
|
|
415
|
-
|
|
105
|
+
- 五个域合并进一个「工具」设置面板:**MCP / Skills / AGENTS.md 预设 / History(归档会话)**。
|
|
106
|
+
- **MCP**:单个工具可独立启停(模型看不见也调不到)、重启只重连**不改变启停状态**、密钥(`env` / `headers`)默认打码、改写补丁前自动留时间戳 `.bak`(保留 5 份)、重复 loader id 写前拦截、跨级迁移失败自动回滚。
|
|
107
|
+
- **Skills**:接入 `~/.agents` / `~/.codex` / `~/.claude` 与自定义目录(只读接入、重叠路径拒绝);创建 / ZIP 与文件夹导入 / 回收站 / 系统编辑器打开源文件;技能目录后台监听,编辑器改完页面自动刷新。
|
|
108
|
+
- **AGENTS.md 预设库**:多套全局指令基线,一键「应用」写入 `~/.dsh/AGENTS.md`(新会话生效,当前会话不变)。
|
|
109
|
+
- **History**:归档会话按项目分组、搜索、全选、批量恢复 / 永久删除、保留期自动清理;从 Claude Code / Cursor(JSONL)、Codex(Markdown)、任意文本导入;导出 Markdown / JSONL。
|
|
416
110
|
|
|
417
|
-
|
|
418
|
-
|---|---|---|---|---|
|
|
419
|
-
| Spec Critical 1 | `workspace` 子类触达官方私有面 | Critical | `src/history/workspace.js` 读写 `requireState` / `readSessionHeader` / `enqueueOperation` / `sessionKnown` / `requireTable` / `setState` / `headers` / `sessionPaths` 等,对照 `dsh-workspace` 类型声明**全部是 private**;官方无「可替换」承诺 | **未修** |
|
|
420
|
-
| Spec Critical 2 | `projcache` 子类同理 | Critical | 写 `this.table`、调 `installWritePath()`、`super.put`、`requireTable().delete`(均 private);注释自认依赖「`super.write` 返回后不再异步落盘」的上游实现细节。另:垫片引用的 `putSoft` 在锁定的 0.1.5-rc.2 中 grep=0(不存在),注释与本地证据不符(防御性写法,无功能故障,**历史出处待确认**) | **未修** |
|
|
421
|
-
| Spec Important 3 | 缺官方 Config schema | Important | 官方 /develop/basic/config 要求导出同名 Schemastery schema;插件只有 `{name, inject, apply}`,`config.token/presetsDir/rulesRoot/stateDir/rulesMaxBytes/maxBodyBytes` 裸读,无加载期校验与默认值(cordis 支持 Standard Schema 校验) | **未修** |
|
|
422
|
-
| Spec Important 4 | patch 语义核实 | Important | `disabled:true` 生效链路、`ctx.loader.entries()`、`!!js` 重入警告均**属实**。微偏:表达式并非只在 activation 求值,而是**每次读取都重算** | 核实项(无待修) |
|
|
423
|
-
| Spec Important 5 | inject 与实际使用漂移 | Important | — | **部分撤回 + 澄清**:①「inject `timer` 无使用」**误报撤回**——`ctx.timeout(ms)` 被 `wait()` 在 mcpm 重启轮询路径真实调用,移除会引入回归;②`ctx.get('sessions')` 在已 inject 下行为等价,判为风格项,待拆分时统一 |
|
|
424
|
-
| Spec Important 6 | 本地类型漂移(已漂移 2 处) | Important | `writeText` 第 3/4 参名义与官方完全不同(第 5 参按位置恰好对位);`prepareDocument():Promise<unknown>` vs 官方 `Promise<string\|undefined>`,却被径直当 home 路径用 | **未修** |
|
|
425
|
-
| Spec Minor 7 | 工具命名 / `defineTool` 契约 | Minor | 官方无前缀强制;`defineTool` 六字段与 `output` 强制项全部符合;审批/禁用全走官方缝 | 符合(无需修) |
|
|
426
|
-
| Spec Minor 8 | systemPrompt 约定 | Minor | `section({name,order,text:provider})` 为官方 API,order 3000 落在 2900→5000 空档合法;手动 `emit('system-prompt/change')` 越过官方「注册/注销自动 emit」约定,**多余无害** | 符合 |
|
|
427
|
-
| Spec Minor 9 | 客户端协议 | Minor | `dsh.client.platform/inject` 合规;localStorage 用法与 `{op,args}` 协议**无官方约定可对照(待确认)** | 符合(两条待确认) |
|
|
111
|
+
> 对 **0.1.1 / 0.1.2 / 0.1.3** 没有可查的记录,因此不拆分它们的差异。开发期内部编号 `v0.3`、`v0.4` 未单独发布,内容随 v0.5.0 一起发布。
|
|
428
112
|
|
|
429
|
-
|
|
430
|
-
**官方确无、必须自写**:`fs.watch`/轮询、回收站、zip 解压(fflate)、YAML patch 编辑、token 鉴权。
|
|
113
|
+
---
|
|
431
114
|
|
|
432
|
-
|
|
115
|
+
## 长期约束与边界
|
|
433
116
|
|
|
434
|
-
|
|
435
|
-
|---|---|
|
|
436
|
-
| 一次**未被任何脚本触发**的 `scene-mode-set(null)`(模式自动退出、技能快照还原、MCP 停用表回写为空) | **未解决**。已排除进程启动触发;候选解释是自动化点击与 React 重渲染的竞态或人为点击;事后「进入 → 静置 25s」重复 1 次未复现。建议下一轮用「点击后立刻断言 mode 未被退出」的脚本跑 5 次以定性 |
|
|
437
|
-
| 服务器「后加载」场景(进模式后才启动的服务器是否被 `['*']` 拦住) | **未跑** |
|
|
438
|
-
| `subagent_run` 参数不可见的线上抓包复核 | **未做**(实际表现受模型按 description 推断与 API 宽容度掩盖,但契约偏离成立) |
|
|
439
|
-
| `dsh-llm types.d.ts`、`dsh-llm-deepseek` 两处引用 | **未逐行复核**(C3 结论不依赖它们) |
|
|
440
|
-
| 全项目审查的复核范围 | 两轴由独立子代理完成,主评审**仅复核 Critical 级发现**;Important/Minor 的行号未逐条重验 |
|
|
117
|
+
跨版本有效,改代码前先读。
|
|
441
118
|
|
|
442
|
-
|
|
119
|
+
### 非干扰原则(红线)
|
|
443
120
|
|
|
444
|
-
|
|
121
|
+
任何时候不得为插件功能改写 DSH 原生文件的语义、不得给原生段改名或改序、不得让注入内容破坏前缀缓存契约。违反任意一条即视为架构回归。
|
|
445
122
|
|
|
446
|
-
|
|
123
|
+
- **前缀缓存友好**:注入段文本只由「启用场景 + 文件内容」决定,逐字节稳定;场景切换或编辑记忆只变化一次。段内不得出现时间戳、计数、相对时间等每轮变化的内容。
|
|
124
|
+
- **数据落点**:插件**不在自己的安装目录存用户数据**(npm 安装会整体替换该目录);用户数据一律在 `~/.dsh/tool-management/`。稳态零写入,唯一会「覆盖」的是运行期手改这些文件——请在停止 `dsh web` 后再改。
|
|
125
|
+
- **生效方式**:插件由宿主启动时加载 `lib/`,**改动需重启 `dsh web`**(patch 热重载不会重新 import 插件模块);`lib/` 不入版本库,克隆后先 `npm run build`。
|
|
447
126
|
|
|
448
|
-
|
|
449
|
-
|---|---|---|---|
|
|
450
|
-
| 1 | `dsh-workspace` `WorkspaceRegistry` 私有成员(`src/history/workspace.js` 的 `ArchiveWorkspaceRegistry`) | 私有成员改名/增删——**纯 JS 子类无编译期保护** | `workspace.js` 运行期 undefined 崩溃,或索引语义错位 |
|
|
451
|
-
| 2 | `dsh-session-projection-cache` 写路径(`src/history/projcache.js`:init 内写 `this.table`、`installWritePath()`、`super.put`、`requireTable().delete`) | 写路径成员变更;**alpha.2 已演示过 `putSoft` 移除** | 墓碑 / `whenIdle` 失效 |
|
|
452
|
-
| 3 | `cordis.patch.yml` 硬编码官方行 `id: workspace` / `id: session-projection-cache` 的 `disabled:true` | 官方行 id 变更或拆分即**落空** | 官方实例与子类**双注册** → 启动失败(duplicate-route throw) |
|
|
453
|
-
| 4 | `!!js` patch 表达式(`id!=='…'` 短路防递归) | `Entry.disabled` 是**未缓存 getter**、每次 evaluate 都重算;触碰自身行会重入 | 递归/重入风险(现有短路顺序论证成立,属脆弱面) |
|
|
454
|
-
| 5 | spawn provider 挂载口径(有意偏离原设计) | 若改回 yml `insert`:缺包的宿主会因单行加载失败**拖垮整棵插件树**,且与运行时兜底存在**双挂载窗口** | 现行落地是惰性探测 + 可选 peerDependency;缺 provider 时受影响面只有 `subagent_run` |
|
|
455
|
-
| 6 | `dsh-fs` / `dsh-settings` 本地类型声明漂移 | 官方签名再变时**无编译期拦截**(本地声明已不一致) | fs/settings 调用语义错位(当前靠「按位置恰对位」侥幸成立) |
|
|
456
|
-
| 7 | `inject` 声明与实际使用漂移 | `inject=['timer']` 本身正确(`ctx.timeout` 真实使用);误按「未使用」移除会引入回归 | 评价为风格项,待拆分时统一 |
|
|
457
|
-
| 8 | 缺官方 Config schema | 官方要求导出同名 Schemastery schema | 无加载期校验与默认值——配置形态变更时静默走偏 |
|
|
458
|
-
| 9 | 官方已有能力但插件自写(原子写、JSON sidecar) | 官方演进后与自写实现语义分叉 | 原子写强度不一(两处裸 `writeFile`) |
|
|
459
|
-
| 10 | 已核实的官方契约点(低风险,作升级回归基线) | `disabled:true` 链路、`ctx.loader.entries()`、`dsh.bundle.patch`、`dsh.client.platform/inject`、`defineTool` 六字段与 `output`、`PreToolDecision{kind:'ask'}` / `ToolGuard` / `ToolRestriction`、`SystemPrompt.section` order 3000 空档、`agent/created\|disposed`、`SubagentStartRequest/SubagentResult/SubagentRun` 字段(`diagnostic`、`signal` 必填、无 `provider` 字段)、`ctx.subagents.start(name, request)` **双参** | 逐点回归 |
|
|
127
|
+
### 治理与兼容边界
|
|
460
128
|
|
|
461
|
-
|
|
129
|
+
- **子代理有两条通道**:本插件的 `subagent_run` 走确认门与场景人设绑定;DSH 官方的 `subagent` / `subagent_fork` 是宿主能力,**没有确认门、也不认这套人设**。本插件的治理只覆盖 `subagent_run`。
|
|
130
|
+
- **归档兼容层**:官方目前没有完整的公开归档扩展接口,实际执行的是受检适配层(访问经检查的内部状态)。它是**有限兼容层**,不等于零侵入,也不等于与官方实现解耦。
|
|
131
|
+
- **契约测试的边界**:契约测试断言语义契约而非实现抄写,替代不了真实行为验收;浏览器交互与破坏性路径仍需人工在实机确认。
|
|
132
|
+
- **尚未验证**:与 `@michengai/dsh-archive-manager` 的双安装;官方工具在 `never` 会话下的行为;服务器「后加载」场景;`subagent_run` 参数不可见时的线上抓包复核。
|
|
462
133
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
### 做不到 / 明确的边界
|
|
466
|
-
|
|
467
|
-
| 事项 | 口径 |
|
|
468
|
-
|---|---|
|
|
469
|
-
| 子代理是否继承全局场景记忆段 | 设计期判定**静态不可判定**(in-process child 的 scope 挂接未文档化)→ 双路径:默认假设继承 + 运行时验证。**实测结论:继承**(人设复述段首行成功) |
|
|
470
|
-
| 官方 subagent 通道的治理 | 官方 `subagent` / `subagent_fork` 是宿主能力,**无 ask 门、不认插件人设**;插件的确认门与场景绑定**只覆盖 `subagent_run`**(实测:同一条消息里官方 `subagent` 无卡直接返回,紧接着的 `subagent_run` 才弹卡) |
|
|
471
|
-
| 官方工具在 `never` 会话下的行为 | **未单独实跑**:这是「无 ask 门」的直接推论(never 只作用于 ask;无 ask 可判即无可拒) |
|
|
472
|
-
| 模式期间的手动改动 | 按「手动改动不自动回写档案」,**不保留** |
|
|
473
|
-
| 档案应用写入强度 | 对 N 个工具/技能是**逐条写**(写锁内串行);量大时可优化为一次原子写,**v1 未做** |
|
|
474
|
-
| `subagent_run` 的失败分支(spawn provider 缺失) | 本机宿主最新版自带 provider,**构造不出该形态 → N/A** |
|
|
475
|
-
| 人设删除 | UI 上人设**不入回收站**(删了就是删了,v1 从简) |
|
|
476
|
-
| 人设文件不可被模型改写 | v1 **无 subagent 写工具**,只能人为编辑磁盘文件 |
|
|
477
|
-
| 子智能体并发 | v1 串行队列(同一时刻至多 1 个),`maxDepth: 1` 防递归套娃 |
|
|
478
|
-
| 子代理会话落点 | 内存态 + `dispose()` 移除,**不落盘、不进 History** |
|
|
479
|
-
| `subagent_fork` / continuable 子代理 | **未接入**(v1 范围外) |
|
|
480
|
-
| 契约测试的边界 | 引擎状态机用例是**注入假 deps** 的契约测试,替代不了真实写通道——C6 正漏在这层 |
|
|
481
|
-
| 方案 B 与宿主策略相悖(有意为之) | 插件确认门语义是「问用户」→ never 时放行并留痕;宿主 `decide()` 的 never=自动拒绝针对的是「没人可问」 |
|
|
482
|
-
| never 探测的降级边界 | 只在读取链**完整可用**时生效;无 approval 服务 / 无 `exec.agent.session` / 读取抛错一律返回 `false` → 退回正常问询,**绝不因「读不到」而擅自放行** |
|
|
483
|
-
| 首选技能指向已停用来源 | 该条目**仍赢分组**(键未失效,语义 =「这是用户选的来源」),行上如实显示「已停用」运行态(边界观察,非缺陷) |
|
|
484
|
-
| 导入的部分成功语义 | 重名**跳过并报告**(绝不覆盖);非法名 / 空内容 / 超限条目单条跳过、其余照常 |
|
|
485
|
-
| 导入的安全边界 | 绝对路径、`..` 穿越、隐藏项一律丢弃并回报 |
|
|
486
|
-
| 非干扰原则的红线 | 任何时候不得为插件功能改 DSH 原生文件语义、不得给原生段改名/改序、不得让注入内容破坏前缀缓存契约。违反任一条即**架构回归** |
|
|
487
|
-
|
|
488
|
-
### 未采纳方案
|
|
489
|
-
|
|
490
|
-
| 方案 | 理由 |
|
|
491
|
-
|---|---|
|
|
492
|
-
| 官方 agent-preset 组合当子智能体载体 | preset 是插件组合目录、会话创建时加入,与「运行中即用即弃」不符且对轻量人设过重;留作将来「重型模板」载体 |
|
|
493
|
-
| 每人设注册独立工具 | 工具清单随文件增删抖动,tool list 不稳定 |
|
|
494
|
-
| 用 `tools/restrict` 控制人设可见性 | 单工具形态下无 per-persona 工具可 restrict;改为 execute 时校验(语义等价且更简单) |
|
|
495
|
-
| 钩子(hooks) | 用户范围裁定「不做」 |
|
|
496
|
-
| 斜杠命令(新增) | 用户范围裁定「不做」(与 skills 触发方向相反、无增量);**v0.4 进一步把已有的四条也删了** |
|
|
497
|
-
|
|
498
|
-
### 计划与实现的偏离(记录实际做法)
|
|
499
|
-
|
|
500
|
-
1. 未安装 devDep `@deepseek-ai/dsh-subagent`(改用结构化 any + `createRequire`)。
|
|
501
|
-
2. spawn provider 挂载改为**惰性探测 + createRequire**(原计划的 yml 挂载行未用)。
|
|
502
|
-
3. `subagent_list` 的 `parameters` 必须能生成 `type:object`(空对象产出 `type:null` 会被模型 API 拒绝)→ 加了可选 `scene` 参数。
|
|
503
|
-
4. `ctx.subagents.start` 实际签名是 **`start(name, request)` 双参**(原计划误写单对象)。
|
|
504
|
-
5. 删除场景时联动清理档案/模式引用(原计划未覆盖;评审后进一步改为**拒绝删除当前模式场景**)。
|
|
505
|
-
6. `tsc` incremental(`tsbuildinfo`)曾导致 `lib/index.js` 未重编译、工具 schema 改动未生效 → 重建时删 `tsbuildinfo` 强制全量;**日后遇「改了没生效」先清它**。
|
|
506
|
-
7. 启动期 `refresh` 改为合并式更新(修「场景」tab 白屏);另修:客户端 null 段泄漏为空段定义、`openDrill` 引用已删 state、zh 字典丢键、弹窗缺「添加段」按钮。
|
|
507
|
-
|
|
508
|
-
### 一次性事项(照实登记)
|
|
509
|
-
|
|
510
|
-
- 首轮未跑、后续已补齐的:确认弹窗人工点击放行、`subagent_run` 端到端、拖放实拖、导入限额、bundle 导入、官方子代理无 ask 门。
|
|
511
|
-
- **仍未补**:官方工具在 `never` 会话下的行为;服务器「后加载」场景;`subagent_run` 参数不可见的抓包复核;一次未被脚本触发的 `scene-mode-set(null)` 的定性。
|
|
512
|
-
- 清理测试数据时删除的 `session-bf211678`(测试宿主首次加载自动创建的空会话)**删除前未逐一核对内容**——如实登记,该会话应为空。
|
|
513
|
-
- `skill_manager_create` 首轮 `EPERM: rename … .dssm-create-<uuid>` 重试即成功、插件已自行回滚、目标目录无残留 → 判为 Windows 瞬时锁(非插件缺陷)。
|
|
514
|
-
- 真实**文件夹拖拽**(Chromium `webkitGetAsEntry` 目录 API)无法用 Playwright 触发(`Dropping a directory is not supported`);改用**忠实的合成 `FileSystemEntry` 树**驱动插件真实代码路径(并抓出目录前缀丢失缺陷)。
|
|
515
|
-
- 测试数据清理声明「`.playwright-cli/` 已删除」与实际不符(目录仍存在)→ v0.4 已把它加进 `.gitignore`。
|
|
134
|
+
### 升级 DSH 之后(按序执行)
|
|
516
135
|
|
|
136
|
+
```bash
|
|
137
|
+
node scripts/doctor.mjs # 1. 模块实体是否同一份 + 宿主能力是否齐备
|
|
138
|
+
node scripts/host-deps.mjs --fix # 出现「两份拷贝」时执行(改动的是 node_modules,不动源码)
|
|
139
|
+
npm test # 2. 契约测试(13 组,跑 lib/ 产物)
|
|
140
|
+
# 3. 打开 设置 → 工具 → 兼容:确认宿主版本、降级项、每个动作走哪条路径
|
|
141
|
+
# 4. 破坏性路径人工回归:归档 → 恢复 → 永久删除 → 保留期清理
|
|
142
|
+
```
|
|
517
143
|
|
|
144
|
+
宿主缺某个包时,插件会拒绝受影响的动作并说明原因,不会「猜着写」。
|