dsh-composer-ux 0.19.1 → 0.20.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/CHANGELOG.md +72 -0
- package/README.md +48 -5
- package/lib/client.js +6 -5
- package/lib/client.js.map +2 -2
- package/lib/index.js +40 -5
- package/lib/index.js.map +3 -3
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,78 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [0.20.0] — 2026-10-10(适配 DSH 0.2.1-alpha.2:真机测出并修掉三处真问题)
|
|
6
|
+
|
|
7
|
+
用户 2026-10-10:把 `D:\DeepSeek Harness`(未封装版检出)升到最新(`dsh-v0.2.1-alpha.2`)并用它测插件。
|
|
8
|
+
|
|
9
|
+
升级步骤(踩过的坑写在括号里):`git fetch --tags` → 新建分支 `upgrade-0.2.1-alpha.2` 检出该 tag →
|
|
10
|
+
**`pnpm run clean`(必须清:`lib/` 是 gitignore 的,0.1.7 时代的旧产物会让新构建直接 `MISSING_EXPORT`)**
|
|
11
|
+
→ `pnpm install` → `pnpm run build`。
|
|
12
|
+
|
|
13
|
+
### 真机测出来的三处真问题(都已修)
|
|
14
|
+
|
|
15
|
+
1. **设置页点开关直接炸**:`TypeError: setField is not a function`(新实例 + 真浏览器实测的控制台原话)。
|
|
16
|
+
根因:0.17.0(通知卡)与 0.19.0(工作区目录选择卡)都把 `setField` 当成**槽位给的 props** 用
|
|
17
|
+
(`setField={setField}`),而 `0.1.7-rc.1` / `0.2.0-rc.2` / `0.2.1-alpha.2` 三版
|
|
18
|
+
`settings.section` 的持有方契约**都只有 `close`**;正确路径是插件自己注入的 `actions.setField`
|
|
19
|
+
(同一个设置页里其它开关用的都是它)⇒ **这个 bug 在 0.19.x 上同样存在**,点一下就炸。
|
|
20
|
+
为什么 tsc 没拦住:手写类型面把该 props 写成开放索引,组件的 props 类型又并了 `PropsRuntime` /
|
|
21
|
+
`InjectFace`(两者都带 `[key: string]: any`)。三处一起收紧,并反向验证过:写错 props 名
|
|
22
|
+
`npx tsc --noEmit` 当场 `TS2339`。
|
|
23
|
+
2. **依赖窗口不含新运行时**:`>=0.2.0-rc.1 <0.3.0` 在 semver 下**不覆盖** `0.2.1-alpha.2`(带预发布的版本
|
|
24
|
+
只有在同号段比较符也带预发布时才算满足)⇒ pnpm 装了 `0.2.0-rc.2`,宿主按 tool-terminal 的**精确
|
|
25
|
+
peerDeps** 对齐检查后把 `composer-ux-tool-terminal` 那一行**禁用**(只禁一行,插件其余部分照常加载)。
|
|
26
|
+
新窗口:`>=0.1.7-rc.1 <0.1.8 || >=0.2.0-rc.1 <0.2.1-alpha.0 || >=0.2.1-alpha.1 <0.3.0`。
|
|
27
|
+
3. **启动期迁移撞锁被静默跳过**:`quick section migration skipped Error: atomic-write: timed out waiting
|
|
28
|
+
for the writer lock … package.json.lock` —— 迁移跑在插件 apply 时,而宿主启动期自己也在写 profile
|
|
29
|
+
清单。新增 `retryWrite`(退避重试:4 次 / 基数 300ms),迁移改走它,并单测覆盖。
|
|
30
|
+
|
|
31
|
+
### 顺带修掉的两处真机渲染瑕疵(干净 profile 上才看得见)
|
|
32
|
+
|
|
33
|
+
- 「微信通知」概览被 `FoldCard` 前缀两次 ⇒ 显示成「未启用 · 未启用 · 只能通知,不能回」;
|
|
34
|
+
- 「设置面板」概览在没存过尺寸时显示 `undefined×undefined` ⇒ 改成「尺寸用官方默认」。
|
|
35
|
+
|
|
36
|
+
### 形状核对脚本扩写(升级时的第一道门)
|
|
37
|
+
|
|
38
|
+
`scripts/dsh-shape-check.mjs` 原来只有 4 节、只认识 0.13 时代的依赖;现在补到 7 节:新增
|
|
39
|
+
客户端槽位 shadow(0.18.0 目录选择的地基:优先级 / fail-loud / 持有方 prop 名)、四个通知事件
|
|
40
|
+
(两个 waterfall 必须原样透传)、`configForms` + 终端依赖范围;并修掉一条**过期断言**
|
|
41
|
+
(0.2.1 起官方拒绝 `0.0.0.0`,改成核对 `normalizeBindAddress` / `isWildcardAddress`)。
|
|
42
|
+
对着 0.2.1-alpha.2 跑:**36 条全过**。
|
|
43
|
+
|
|
44
|
+
**验证**:`npm test` —— **30 个套件 2569 passed / 0 failed**(新增 `test/retry-write.mjs` 9 条;
|
|
45
|
+
`settings-render` 102→107;`client-registration` 265→271;`terminal-mount` 的依赖窗口断言改为按语义
|
|
46
|
+
核对三条预发布线)。`npm run test:mutations` —— **189 条全部咬住**(新增 HI–HO 7 条:顶层 setField 复发、
|
|
47
|
+
props 类型放宽、类型面改回开放索引、迁移不重试、通知概览双前缀、面板概览不兜底、retryWrite 不重试)。
|
|
48
|
+
|
|
49
|
+
## [0.19.2] — 2026-10-09(修:设置字段必须进宿主 schema —— 补回 0.17.0 漏掉的 5 个通知字段)
|
|
50
|
+
|
|
51
|
+
**怎么发现的**:给「工作区目录选择」加开关时顺手核对宿主 schema(`src/host.ts` 的 `ownSchema()`)
|
|
52
|
+
与设置契约,发现那张表到 `priceAutoSync` 就结束了 —— **0.17.0 的 5 个通知字段
|
|
53
|
+
(`notifyEnabled` / `notifyChannel` / `notifyPushplusToken` / `notifyWecomWebhook` / `notifyKinds`)
|
|
54
|
+
从来没进去过**。
|
|
55
|
+
|
|
56
|
+
**为什么这不是"界面少一块"而是真故障**:写设置走宿主设置服务的 `settings.mutate`,它对每个
|
|
57
|
+
path 先查 `isVolatilePath(schema, path)`,字段没声明就**直接抛**
|
|
58
|
+
`Config field "…" is not volatile`(DSH 源码 `packages/settings/settings/src/index.ts` 的 `write`)。
|
|
59
|
+
所以通知卡那几个开关**一直存不住**:用户一拨就会看到本插件那条「写入失败」提示条,值也不会留下。
|
|
60
|
+
本期的目录选择开关若不补 schema,会是同一个下场。
|
|
61
|
+
|
|
62
|
+
**改动**:
|
|
63
|
+
|
|
64
|
+
- `src/host.ts`:`ownSchema()` 补 6 个字段(5 个通知 + `DIRECTORY_PICK_ENABLED_FIELD`),
|
|
65
|
+
并把这段事故与判据写在注释里。
|
|
66
|
+
- `test/client-registration.mjs` 第 16 节(新增 9 条):**逐字段核对** —— 设置契约里所有
|
|
67
|
+
`*_FIELD` 常量(49 个)必须都出现在 `ownSchema()` 里,再点名 6 个关键字段。
|
|
68
|
+
以后任何新字段漏进 schema 都会当场变红,而不是等用户去拨开关。
|
|
69
|
+
- `test/mutation-guards.mjs`:新增 `HG`(schema 漏目录选择字段)、`HH`(schema 再漏通知总开关)。
|
|
70
|
+
|
|
71
|
+
**验证**:`npm test` —— **29 个套件 2549 passed / 0 failed**(`client-registration` 256→265);
|
|
72
|
+
`npm run test:mutations` —— **182 条全部咬住**。
|
|
73
|
+
|
|
74
|
+
**注意**:0.17.0 那 5 个通知字段此前存不住值 —— 如果你之前拨过通知卡上的开关、看到过「写入失败」
|
|
75
|
+
或"拨了又弹回",那不是你看错,就是这个原因;现在可以正常拨了。
|
|
76
|
+
|
|
5
77
|
## [0.19.1] — 2026-10-09(只改文档:README 的变异条数写旧了)
|
|
6
78
|
|
|
7
79
|
0.19.0 发版时 README 里那句变异条数还写着上一版的 **174**,而这一版实际跑出来是 **180**
|
package/README.md
CHANGED
|
@@ -553,8 +553,9 @@ Windows 上 DSH 给模型的终端工具是 **PowerShell**(工具名 `pwsh`)
|
|
|
553
553
|
| 工具循环的消息形状 / 轮次封顶 / 异常必须降级 | 同上第 6 节(假 llm 驱动整条循环,逐条检查 `role:'tool'` 与 `toolCallId`) |
|
|
554
554
|
| 工具路径:默认关、开了才派、**查完吐散文必须回落**、拿不到工作目录就不派 | `test/quick-commands.mjs` 5g 节(13 条,真路由 + 假 llm) |
|
|
555
555
|
| 工具读到的内容不进台账 | 同 5g 节:断言台账里只有工具名与次数、没有读到的文件内容 |
|
|
556
|
-
| 变异守卫真的会咬人,且**必须是指定的那条测试变红** | `npm run test:mutations`:**
|
|
556
|
+
| 变异守卫真的会咬人,且**必须是指定的那条测试变红** | `npm run test:mutations`:**189 条全部咬住**(判据是 `red.some(line => line.includes(item.expect))`,不是"有红就行") |
|
|
557
557
|
| **桌面应用里弹系统文件夹框**(0.18.0 起;0.19.0 起默认关、设置页可开) | ✅ **有真机证据**:2026-10-09 用户在桌面应用点「选择工作区目录」,实测「成功替换为系统文件管理器」(先用 profile 补丁验过一次,之后的插件内 shadow 版走的是同一条 preload 桥);`node test/directory-flow.mjs` 49 条 + 变异 FS–FY(判定/状态机)与 GZ/HA(开关幂等装卸)罩着 |
|
|
558
|
+
| **设置字段全部进了宿主 schema**(0.19.2 起) | `test/client-registration.mjs` 第 16 节:把设置契约里 49 个 `*_FIELD` 常量逐个核对 `ownSchema()`,再点名 6 个(5 个通知 + 目录选择)+ 变异 HG/HH。**为什么值得单列一行**:写设置走 `settings.mutate`,字段没进 schema 会被直接抛 `Config field "…" is not volatile` —— 0.17.0 的 5 个通知字段就是这么漏的(症状是"开关拨不动 + 写入失败提示"),2026-10-09 才发现并修掉 |
|
|
558
559
|
| 发布门禁三条判据 | `npm run gates` 全过;`check:tag` 实测 `v0.12.0` 的 tag 名与所指提交里的版本一致 |
|
|
559
560
|
| 三平台 CI | GitHub Actions:ubuntu / windows / macos × Node 20(`npm ci → typecheck → build → test → check:pack → check:docs`) |
|
|
560
561
|
|
|
@@ -689,9 +690,9 @@ node build.mjs # 产出 lib/index.js + lib/client.js
|
|
|
689
690
|
# ⚠️ 宿主半会**内联** schemastery / cosmokit:
|
|
690
691
|
# 优先用 DSH 检出里的 vendor 副本,检出不在时退到 node_modules
|
|
691
692
|
# 里同版本的 npm 包(两者逐字节相同)——CI 上走的就是退路
|
|
692
|
-
npm test #
|
|
693
|
+
npm test # 30 个套件;当前 2569 passed, 0 failed(2026-10-09 实测;CI 三平台同样全绿)
|
|
693
694
|
# 走 scripts/run-tests.mjs:顺带把"多少套件/多少条"记进 test/.last-run.json
|
|
694
|
-
npm run test:mutations # 手动跑:变异测试,证明那套护栏真的在咬人(
|
|
695
|
+
npm run test:mutations # 手动跑:变异测试,证明那套护栏真的在咬人(189 条,须单独跑)
|
|
695
696
|
# 同样记录结果,供下面的文档门禁核对
|
|
696
697
|
npm run gates # 发版门禁三条一起跑:tag 指向 / 包内容 / 文档数字
|
|
697
698
|
npm run check:tag # ① tag 名里的版本 == 该 tag 所指提交里的 package.json 版本
|
|
@@ -765,5 +766,47 @@ Remove-Item "$env:USERPROFILE\.dsh\profiles\web\package.json.lock" -Force
|
|
|
765
766
|
|
|
766
767
|
## 与官方版本兼容提示
|
|
767
768
|
|
|
768
|
-
|
|
769
|
-
|
|
769
|
+
**实测过的 DSH 版本**(每次升级都对着源码跑形状核对,再在未封装版上真机点一遍):
|
|
770
|
+
|
|
771
|
+
| DSH 版本 | 状态 | 备注 |
|
|
772
|
+
|---|---|---|
|
|
773
|
+
| 0.1.7-rc.1 / rc.2 | 可用 | 依赖窗口的第一段 |
|
|
774
|
+
| 0.2.0-rc.1 / rc.2 | 可用 | 桌面版装的这一版 |
|
|
775
|
+
| **0.2.1-alpha.1 / alpha.2** | **可用(0.20.0 起)** | 2026-10-10 把 `D:\DeepSeek Harness` 未封装版升上去后真机验证(含设置页开关点击与写入落盘) |
|
|
776
|
+
|
|
777
|
+
**依赖窗口**:`@deepseek-ai/dsh-tool-terminal` 声明为
|
|
778
|
+
`>=0.1.7-rc.1 <0.1.8 || >=0.2.0-rc.1 <0.2.1-alpha.0 || >=0.2.1-alpha.1 <0.3.0`。
|
|
779
|
+
|
|
780
|
+
⚠️ **为什么预发布线必须单列一段**:semver 下「带预发布的版本」只有在**同号段的比较符也带预发布**时才算被
|
|
781
|
+
满足 —— 旧的 `>=0.2.0-rc.1 <0.3.0` 并不包含 `0.2.1-alpha.2`。后果不只是"装错个版本":pnpm 会装
|
|
782
|
+
`0.2.0-rc.2`,而宿主对每个插件行做**精确版本对齐检查**(tool-terminal 的 peerDeps 是精确版本),
|
|
783
|
+
于是那一行被直接禁用:
|
|
784
|
+
|
|
785
|
+
```
|
|
786
|
+
dsh: disabling profile plugin row "composer-ux-tool-terminal":
|
|
787
|
+
Plugin @deepseek-ai/dsh-tool-terminal@0.2.0-rc.2 is incompatible with dsh 0.2.1-alpha.2
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
**升级 DSH 后怎么自查**(都只读,不改任何东西):
|
|
791
|
+
|
|
792
|
+
```sh
|
|
793
|
+
node scripts/dsh-shape-check.mjs "D:/DeepSeek Harness" # 形状核对:服务名 / 返回字段 / 槽位契约 / 事件 / 依赖范围
|
|
794
|
+
npm test && npm run gates # 本仓 30 个套件 + 门禁
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
形状核对覆盖七块:会话与用量(`sessions` / `sessionQuery`)、设置服务两代读法(`describe` / `mutate` +
|
|
798
|
+
volatile)、路由与信任关卡(`webServer.register` / `connection.requestRejection` + 绑定策略)、
|
|
799
|
+
客户端槽位 shadow(目录选择「影子接管」的地基:优先级、fail-loud、持有方 prop 名)、四个通知事件
|
|
800
|
+
(两个 waterfall 必须原样透传 `next()`)、客户端设置表单 `configForms`、终端依赖范围。
|
|
801
|
+
|
|
802
|
+
**已知的版本敏感点**(升级后优先看这几处):
|
|
803
|
+
|
|
804
|
+
- **`settings.section` 槽位的持有方 props 只有 `close`**:设置页要写设置必须走**自己注入的** `actions`
|
|
805
|
+
(0.20.0 修:0.17~0.19 期间通知卡与目录选择卡误用了不存在的顶层 `setField` ⇒ 真机上点一下必炸
|
|
806
|
+
`TypeError: setField is not a function`)。类型面已按真实契约收紧,写错 props 名 `tsc` 当场红。
|
|
807
|
+
- **插件行的启用与否由宿主按 `dsh-tool-terminal` 的 peerDeps 精确对齐判定**:版本对不上时**只禁用那一行**,
|
|
808
|
+
插件其余部分照常加载(优雅降级,不崩)。
|
|
809
|
+
- **启动期写设置会撞宿主自己的 profile 写锁**(`atomic-write: timed out waiting for the writer lock
|
|
810
|
+
… package.json.lock`)⇒ 凡启动期的写都要退避重试(见 `retryWrite` 与「快捷指令」迁移)。
|
|
811
|
+
- **`0.0.0.0` 从 0.2.1 起被官方拒绝**(只接受具体 IP 字面量)—— 不影响本插件,但形状核对里那条
|
|
812
|
+
「连接可绑非回环地址」的断言依据随之改了。
|
package/lib/client.js
CHANGED
|
@@ -5898,7 +5898,7 @@ function NotifyCard({ settings, setField }) {
|
|
|
5898
5898
|
FoldCard,
|
|
5899
5899
|
{
|
|
5900
5900
|
name: "\u5FAE\u4FE1\u901A\u77E5",
|
|
5901
|
-
summary: on ? `\u5DF2\u5F00 \xB7 ${channel === "pushplus" ? "PushPlus" : "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA"} \xB7 \u53EA\u80FD\u901A\u77E5\uFF0C\u4E0D\u80FD\u56DE` : "\
|
|
5901
|
+
summary: on ? `\u5DF2\u5F00 \xB7 ${channel === "pushplus" ? "PushPlus" : "\u4F01\u4E1A\u5FAE\u4FE1\u673A\u5668\u4EBA"} \xB7 \u53EA\u80FD\u901A\u77E5\uFF0C\u4E0D\u80FD\u56DE` : "\u53EA\u80FD\u901A\u77E5\uFF0C\u4E0D\u80FD\u56DE",
|
|
5902
5902
|
toggle: { checked: on, onChange: (next) => {
|
|
5903
5903
|
setField(NOTIFY_ENABLED_FIELD, next);
|
|
5904
5904
|
} },
|
|
@@ -6084,7 +6084,7 @@ function RestartBanner({ restart }) {
|
|
|
6084
6084
|
}, children: "\u77E5\u9053\u4E86" }) })
|
|
6085
6085
|
] });
|
|
6086
6086
|
}
|
|
6087
|
-
function SettingsSection({ useLive, useBook, useBookStatus, useWriteNotice, actions
|
|
6087
|
+
function SettingsSection({ useLive, useBook, useBookStatus, useWriteNotice, actions }) {
|
|
6088
6088
|
const settings = useLive((item) => item);
|
|
6089
6089
|
const book = useBook((item) => item);
|
|
6090
6090
|
const bookStatus = useBookStatus((item) => item);
|
|
@@ -6105,7 +6105,8 @@ function SettingsSection({ useLive, useBook, useBookStatus, useWriteNotice, acti
|
|
|
6105
6105
|
const menuEnabled = MENU_ITEMS.filter((item) => settings[item.field]).length;
|
|
6106
6106
|
const keySummary = `\u53D1\u9001 ${displayChord(settings.sendKey)} \xB7 \u6362\u884C ${displayChord(settings.newlineKey)}`;
|
|
6107
6107
|
const menuSummary = settings.menuMode === "official" ? "\u5F53\u524D\uFF1A\u5B98\u65B9\u4E0D\u4ECB\u5165" : settings.menuMode === "browser" ? "\u5F53\u524D\uFF1A\u6D4F\u89C8\u5668\u83DC\u5355\uFF08\u7C98\u8D34\u514D\u6388\u6743\uFF09" : `\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49\u83DC\u5355 \xB7 ${menuEnabled} / ${MENU_ITEMS.length} \u9879\u5F00\u542F`;
|
|
6108
|
-
const
|
|
6108
|
+
const panelSize = typeof settings.panelWidth === "number" && typeof settings.panelHeight === "number" ? `${settings.panelWidth}\xD7${settings.panelHeight}` : "\u5C3A\u5BF8\u7528\u5B98\u65B9\u9ED8\u8BA4";
|
|
6109
|
+
const panelSummary = `\u8FB9\u7F18\u7F29\u653E ${settings.panelResize ? "\u5F00" : "\u5173"} \xB7 ${panelSize}`;
|
|
6109
6110
|
const headerSummary = settings.headerEnabled ? settings.headerStatus === "" ? "\u5DF2\u542F\u7528" : settings.headerStatus : "\u672A\u542F\u7528";
|
|
6110
6111
|
const quickCounts = bookCounts(book);
|
|
6111
6112
|
const quickSummary = `${quickCounts.categories} \u4E2A\u5206\u7C7B \xB7 ${quickCounts.prompts} \u6761 \xB7 \u6BCF\u6B21 ${quickCounts.always} \xB7 \u4EC5\u9996\u6B21 ${quickCounts.first} \xB7 \u4F18\u5316\u6863\u4F4D ${OPTIMIZER_TIERS.find((item) => item.id === settings.optimizerTier)?.label ?? "\u9AD8\u7EA7"}`;
|
|
@@ -6162,8 +6163,8 @@ function SettingsSection({ useLive, useBook, useBookStatus, useWriteNotice, acti
|
|
|
6162
6163
|
)
|
|
6163
6164
|
] })
|
|
6164
6165
|
] }),
|
|
6165
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NotifyCard, { settings, setField }),
|
|
6166
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DirectoryPickCard, { settings, setField }),
|
|
6166
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NotifyCard, { settings, setField: actions.setField }),
|
|
6167
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DirectoryPickCard, { settings, setField: actions.setField }),
|
|
6167
6168
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RestartBanner, { restart }),
|
|
6168
6169
|
writeNotice !== "" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-ux-restartBanner dsh-ux-restartBannerFailed", role: "status", children: [
|
|
6169
6170
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "dsh-ux-restartBannerText", children: [
|