@wenbin_wb/dsh-bridge 2.11.0 → 2.11.1

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 CHANGED
@@ -4,6 +4,24 @@
4
4
 
5
5
  ---
6
6
 
7
+ ## [v2.11.1] - 2026-10-02
8
+
9
+ > 本版为修复版:解决 DSH 0.1.7 升级后暴露的移动端「看不到最新消息」、设置弹窗层级误抬,以及 linux 下托管误判导致的 systemd 掉线问题。
10
+
11
+ ### 🐞 修复
12
+
13
+ - **手机上聊天区「看不到最新消息」(PR #48,感谢 imroc)**:移动端主框架规则原用 `div[class*="_frame"]` 跨包通配选择器,除了命中有意的布局外壳(`[data-slot="root"]` 直接子元素),还会误伤 DSH 0.1.7 新增的聊天记录容器(`dsh-client-ui-chat` 的 `.EvIC1a_frame`)——给它强加 `height:100dvh + overflow:hidden` 后被钳到视口高度、溢出内容被裁掉,而外层滚动区已到底,表现为「看到旧消息、看不到最新消息」。现选择器收窄为 `[data-slot="root"] > div[class*="_frame"]`,仅命中布局外壳;对 0.1.5 / 0.1.6 宿主无行为差异。
14
+ - **linux 下托管误判与 systemd 掉线**:真实 `/proc/self/cgroup` 带末尾换行且 cgroup v1 为多行,原解析按单行整体切分,导致 `endsWith('.service')` 判定失败、托管器被误判为 `self`,`Restart=on-failure` 下 dsh 掉线不自动拉起。现逐行解析并 trim;同时重启前为 `systemctl` 补齐默认 PATH 与 `XDG_RUNTIME_DIR`(`--user` 场景)、加 5s 执行超时兜底、自动创建日志目录。
15
+ - **设置弹窗自身被层级规则误抬(适配 DSH 0.1.7)**:0.1.7 把设置弹窗(`VOzbGW_overlay`)从 `#root` 内部移为 `<body>` 直接子级,满足「body 子级 + 含 `role=dialog` 子元素」的抬升特征,被一并抬到第三方模态同层,退化成按 DOM 顺序决胜,「安装确认框被盖住」可能复发。现抬升规则排除设置弹窗自身,仍只抬其它顶层模态。
16
+
17
+ ### 🧪 测试
18
+
19
+ - 新增 `test/restart-dsh.test.mjs` cgroup 多行/换行回归断言;`test/mobile-fixed-panel-offset.test.mjs` 新增 frame 规则限定回归守卫;`test/mobile-settings-narrow-layout.test.mjs` 新增抬升规则排除断言。全量 338 项测试 100% 通过。
20
+
21
+ > ⚠️ 生效说明:客户端样式刷新页面即生效;重启守护逻辑改动需重启 dsh 后生效。
22
+
23
+ ---
24
+
7
25
  ## [v2.11.0] - 2026-09-28
8
26
 
9
27
  > 本版为客户端架构升级与环境解耦:支持桌面端宿主(如 Tauri)将设置面板作为独立组件嵌入并动态管理设置页入口;同时为 Android 移动壳及第三方自适应插件引入环境自适应让位与多级特性开关,消除界面冲突与遮挡。
package/client/client.js CHANGED
@@ -78,7 +78,12 @@ var MOBILE_STYLES_CSS = `
78
78
  \u5F39\u7A97\u4E4B\u4E0A\u5E76\u76D6\u4F4F\u8BBE\u7F6E\u9875\u3002\u8FD9\u662F\u300C\u6A21\u6001\u5C31\u8BE5\u76D6\u5728\u8BBE\u7F6E\u5F39\u7A97\u4E4B\u4E0A\u300D\u7684\u65E2\u5B9A\u53D6\u820D\uFF1A\u5B81\u53EF\u8BA9\u771F\u6A21\u6001
79
79
  \u53EF\u89C1\uFF0C\u4E5F\u4E0D\u63A5\u53D7"\u5F39\u4E86\u5374\u70B9\u4E0D\u5230"\u3002\u72EC\u7ACB\u9A8C\u6536\u5DF2\u5B9E\u6D4B\u8BE5\u6784\u9020\u4F1A\u547D\u4E2D\uFF1B\u82E5\u5C06\u6765\u771F\u8E29\u5230\uFF0C
80
80
  \u5E94\u6539\u4E3A\u6309\u300C\u8BE5\u6D6E\u5C42\u662F\u5426\u53EF\u5173\u95ED\u300D\u8FDB\u4E00\u6B65\u6536\u7A84\uFF0C\u800C\u4E0D\u662F\u56DE\u9000\u8FD9\u6761\u89C4\u5219\u3002 */
81
- body:has(div[class*="VOzbGW_overlay"]) > div:has(> div[class*="mask"], > div[role="dialog"]) {
81
+ /* \u26A0\uFE0F \u5FC5\u987B\u6392\u9664\u8BBE\u7F6E\u5F39\u7A97\u81EA\u8EAB\uFF1ADSH 0.1.7 \u628A VOzbGW_overlay \u53D8\u6210\u4E86 <body> \u7684\u76F4\u63A5\u5B50\u7EA7
82
+ \uFF080.1.5 \u91CC\u5B83\u5D4C\u5728 #root \u5185\u90E8\uFF09\uFF0C\u5B83\u540C\u6837\u6EE1\u8DB3\u300Cbody \u5B50\u7EA7 + \u542B role=dialog \u5B50\u5143\u7D20\u300D\uFF0C
83
+ \u4F1A\u88AB\u672C\u6761\u4E00\u5E76\u62AC\u5230 10050 \u2014\u2014 \u4E8E\u662F\u4E0E\u7B2C\u4E09\u65B9\u6A21\u6001\u6839\u540C\u5C42\u3001\u9000\u5316\u6210\u6309 DOM \u987A\u5E8F\u51B3\u80DC\uFF0C
84
+ \u521A\u4FEE\u597D\u7684\u300C\u5B89\u88C5\u786E\u8BA4\u6846\u88AB\u76D6\u4F4F\u300D\u5C31\u53EF\u80FD\u590D\u53D1\u3002:not(...) \u628A\u5B83\u6392\u9664\uFF0C\u8BA9\u8BBE\u7F6E\u5F39\u7A97\u7EE7\u7EED\u7531
85
+ \u5B83\u81EA\u5DF1\u7684 10002 \u89C4\u5219\u5B9A\u4F4D\uFF0C\u672C\u6761\u53EA\u62AC**\u5176\u5B83**\u9876\u5C42\u6A21\u6001\u3002 */
86
+ body:has(div[class*="VOzbGW_overlay"]) > div:has(> div[class*="mask"], > div[role="dialog"]):not([class*="VOzbGW_overlay"]) {
82
87
  z-index: 10050 !important;
83
88
  }
84
89
 
@@ -104,8 +109,17 @@ var MOBILE_STYLES_CSS = `
104
109
  \uFF08dsh-client-ui-sidebar-right/lib/client.js\uFF09\uFF0C\u6545\u79FB\u52A8\u7AEF\u6837\u5F0F\u53D6 <=767px\uFF0C
105
110
  768px \u8D77\u5F7B\u5E95\u4EA4\u8FD8\u684C\u9762\u5E03\u5C40\uFF0C\u907F\u514D"\u6865\u6E32\u67D3\u9876\u680F\u3001\u5BBF\u4E3B\u5374\u672A\u5168\u5C4F"\u7684\u9519\u4F4D\u3002 */
106
111
  @media (max-width: 767px) {
107
- /* 1. \u4E3B\u6846\u67B6\u4E3A Header \u817E\u51FA\u9876\u90E8\u7A7A\u95F4 */
108
- div[class*="_frame"] {
112
+ /* 1. \u4E3B\u6846\u67B6\u4E3A Header \u817E\u51FA\u9876\u90E8\u7A7A\u95F4\u3002
113
+
114
+ \u9009\u62E9\u5668\u5FC5\u987B\u9650\u5B9A\u5728\u5E03\u5C40\u5916\u58F3\uFF08dsh-client-ui-layout \u7684 AppFrame\uFF0C\u5373
115
+ [data-slot="root"] \u7684\u76F4\u63A5\u5B50\u5143\u7D20\uFF09\u3002\u5BBF\u4E3B\u7684 CSS-module \u54C8\u5E0C\u53EA\u4FDD\u8BC1\u540C\u6587\u4EF6
116
+ \u5185\u552F\u4E00\uFF0C*="_frame" \u662F\u8DE8\u5305\u901A\u914D\uFF1A\u804A\u5929\u8BB0\u5F55\u5BB9\u5668\uFF08dsh-client-ui-chat \u7684
117
+ .EvIC1a_frame\uFF0C\u540C\u6837\u4EE5 _frame \u7ED3\u5C3E\uFF09\u4E5F\u4F1A\u88AB\u547D\u4E2D\u3002\u4E00\u65E6\u547D\u4E2D\uFF0C\u5B83\u88AB\u5F3A\u52A0
118
+ height:100dvh + overflow:hidden\uFF0C\u5728\u624B\u673A\u4E0A\u88AB\u94B3\u5230\u89C6\u53E3\u9AD8\u5EA6\u5E76\u88C1\u6389\u6EA2\u51FA\u5185\u5BB9\uFF1A
119
+ \u5916\u5C42 [data-conversation-scroll] \u5DF2\u6EDA\u5230\u5E95\u3001\u5185\u90E8\u5374\u8FD8\u6709\u6570\u5343 px \u8BFB\u4E0D\u5230\uFF0C
120
+ \u8868\u73B0\u4E3A\u300C\u770B\u4E0D\u5230\u6700\u65B0\u6D88\u606F\u300D\u3002\u5B98\u65B9\u7ED9\u8BE5\u5BB9\u5668\u7684\u89C4\u5219\u662F flex:none;height:auto
121
+ \uFF08\u8BA9\u8BB0\u5F55\u968F\u5185\u5BB9\u81EA\u7136\u589E\u9AD8\u3001\u7531\u5916\u5C42\u7EDF\u4E00\u6EDA\u52A8\uFF09\uFF0C\u4E0E\u8FD9\u91CC\u51B2\u7A81\uFF0C\u6545\u5FC5\u987B\u6392\u9664\u3002 */
122
+ [data-slot="root"] > div[class*="_frame"] {
109
123
  display: flex !important;
110
124
  flex-direction: column !important;
111
125
  width: 100vw !important;
@@ -47,7 +47,12 @@ export const MOBILE_STYLES_CSS = `
47
47
  弹窗之上并盖住设置页。这是「模态就该盖在设置弹窗之上」的既定取舍:宁可让真模态
48
48
  可见,也不接受"弹了却点不到"。独立验收已实测该构造会命中;若将来真踩到,
49
49
  应改为按「该浮层是否可关闭」进一步收窄,而不是回退这条规则。 */
50
- body:has(div[class*="VOzbGW_overlay"]) > div:has(> div[class*="mask"], > div[role="dialog"]) {
50
+ /* ⚠️ 必须排除设置弹窗自身:DSH 0.1.7 把 VOzbGW_overlay 变成了 <body> 的直接子级
51
+ (0.1.5 里它嵌在 #root 内部),它同样满足「body 子级 + 含 role=dialog 子元素」,
52
+ 会被本条一并抬到 10050 —— 于是与第三方模态根同层、退化成按 DOM 顺序决胜,
53
+ 刚修好的「安装确认框被盖住」就可能复发。:not(...) 把它排除,让设置弹窗继续由
54
+ 它自己的 10002 规则定位,本条只抬**其它**顶层模态。 */
55
+ body:has(div[class*="VOzbGW_overlay"]) > div:has(> div[class*="mask"], > div[role="dialog"]):not([class*="VOzbGW_overlay"]) {
51
56
  z-index: 10050 !important;
52
57
  }
53
58
 
@@ -73,8 +78,17 @@ export const MOBILE_STYLES_CSS = `
73
78
  (dsh-client-ui-sidebar-right/lib/client.js),故移动端样式取 <=767px,
74
79
  768px 起彻底交还桌面布局,避免"桥渲染顶栏、宿主却未全屏"的错位。 */
75
80
  @media (max-width: 767px) {
76
- /* 1. 主框架为 Header 腾出顶部空间 */
77
- div[class*="_frame"] {
81
+ /* 1. 主框架为 Header 腾出顶部空间。
82
+
83
+ 选择器必须限定在布局外壳(dsh-client-ui-layout 的 AppFrame,即
84
+ [data-slot="root"] 的直接子元素)。宿主的 CSS-module 哈希只保证同文件
85
+ 内唯一,*="_frame" 是跨包通配:聊天记录容器(dsh-client-ui-chat 的
86
+ .EvIC1a_frame,同样以 _frame 结尾)也会被命中。一旦命中,它被强加
87
+ height:100dvh + overflow:hidden,在手机上被钳到视口高度并裁掉溢出内容:
88
+ 外层 [data-conversation-scroll] 已滚到底、内部却还有数千 px 读不到,
89
+ 表现为「看不到最新消息」。官方给该容器的规则是 flex:none;height:auto
90
+ (让记录随内容自然增高、由外层统一滚动),与这里冲突,故必须排除。 */
91
+ [data-slot="root"] > div[class*="_frame"] {
78
92
  display: flex !important;
79
93
  flex-direction: column !important;
80
94
  width: 100vw !important;
@@ -20,7 +20,12 @@
20
20
 
21
21
  1. **改版本**:`package.json` 的 `version` + `releaseNotes`
22
22
  2. **写 CHANGELOG**:`CHANGELOG.md` 顶部新增对应版本条目
23
- 3. **构建与测试**:`npm run build:lark` + `npm run build:client` + `npm run build:banner` + `npm test`(全量 166 项)
23
+ 3. **构建与测试**:
24
+ - `npm run build:client`(**必须**:客户端产物要与源码同步,`npm test` 有一项断言会校验产物内嵌的 CSS 与源码逐字一致)
25
+ - `npm test` + `npm run lint`
26
+ - `npm run verify:mobile-ui`(**发布前必做**:跑真实 GUI 的移动端行为验收,6 个套件。需要 dsh web 正在运行;Chrome 路径可用 `PUPPETEER_EXECUTABLE_PATH` 指定。它不在 CI 里跑,因为 CI 没有宿主)
27
+ - `npm run build:banner`(**仅当 `docs/screenshots/` 素材有变、需要重出 README banner 时执行**;输入没变时应跳过,否则只会产生 JPEG 重编码噪声。注意该脚本默认 Chrome 路径是写死的 Windows 路径,需用 `PUPPETEER_EXECUTABLE_PATH` 覆盖)
28
+ - `npm run build:lark`(**仅在需要重建飞书 vendor bundle 时执行**。它用当前 esbuild 重新打包 `lib/feishu/lark-bundled.mjs`,产物会随 esbuild 版本漂移;**不要放进 `prepack`**,否则每次 `npm publish` 都会让线上 tarball 里的 vendor 文件与 tag 里的不一致)
24
29
  4. **提交**:合并到 `main`(fast-forward),提交信息 `release: vX.Y.Z — ...`
25
30
  5. **打 tag**:`git tag vX.Y.Z && git push origin vX.Y.Z`(触发 GitHub Actions 自动创建 Release)
26
31
  6. **npm 发布**:`npm publish`(prepack 自动构建产物)
@@ -90,4 +90,4 @@
90
90
  2. **安全白名单拦截**:
91
91
  - 仅白名单内的用户消息会被放行给 Agent;非白名单用户发送的消息会被直接忽略,绝不消耗 Token 或喂给模型。
92
92
  3. **敏感操作审批**:
93
- - 当 Agent 尝试执行系统命令或敏感文件读写时,Telegram 会自动下发 `[✓ 批准执行]` / `[✕ 拒绝执行]` 交互按键,10 分钟未处理自动超时拒绝。
93
+ - 当 Agent 尝试执行系统命令或敏感文件读写时,Telegram 会自动下发 `[✓ 批准执行]` / `[✕ 拒绝执行]` 交互按键,10 分钟未处理自动超时拒绝。