@wenbin_wb/dsh-bridge 2.11.1 → 2.11.2

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.2] - 2026-10-02
8
+
9
+ > 本版为移动端修复版:解决英文界面下侧边栏(抽屉)点击后空白,以及 DSH 0.1.7 升级后右侧栏点击后不显示的问题。
10
+
11
+ ### 🐞 修复
12
+
13
+ - **移动端侧边栏(抽屉)点击后空白**:宿主按钮 aria-label 随界面语言切换(中文「打开侧边栏」/ 英文 "Open sidebar"),插件此前只按中文匹配宿主按钮,英文界面下漏取 → 抽屉滑出但会话列表不挂载。现将抽屉展开/收起/会话操作/新建会话等工作区按钮一律中英双语匹配(英文界面与中文界面行为一致)。
14
+ - **移动端右侧栏点击后不显示**:DSH 0.1.7 把宿主布局外壳改为 grid 三列布局(sidebar | center | rightbar),并把右侧栏全屏面板从 `fixed` 改为 `absolute` 相对右侧栏列定位;插件旧规则把框架强制成 flex 单列、且面板 top 让位二次叠加,导致面板被定位到视口外(点开按钮后按钮消失、右侧栏不出来)。现恢复宿主 grid 布局并显式归位三列,面板统一强制 fixed + 顶栏下方让位(兼容 0.1.5 与 0.1.7 宿主)。
15
+
16
+ ### 🧪 测试
17
+
18
+ - 新增 `test/browser/mobile-sidebar-drawer.mjs`(抽屉展开/收起,中英文按钮匹配)与 `test/browser/mobile-sidebar-right.mjs`(右侧栏 grid 布局)两个真实浏览器验收套件(共 8 套件);`test/mobile-fixed-panel-offset.test.mjs` 新增面板 fixed 与 frame grid 归位结构断言;`test/client-provide.test.mjs` 新增宿主按钮中英双语匹配断言。全量 340 项测试 100% 通过。
19
+ - 清理 CodeQL note 级告警 `js/unused-local-variable`(测试文件未使用导入)。
20
+
21
+ > ⚠️ 生效说明:纯前端改动,刷新页面即生效(无需重启 dsh)。
22
+
23
+ ---
24
+
7
25
  ## [v2.11.1] - 2026-10-02
8
26
 
9
27
  > 本版为修复版:解决 DSH 0.1.7 升级后暴露的移动端「看不到最新消息」、设置弹窗层级误抬,以及 linux 下托管误判导致的 systemd 掉线问题。
package/client/client.js CHANGED
@@ -120,29 +120,49 @@ var MOBILE_STYLES_CSS = `
120
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
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
122
  [data-slot="root"] > div[class*="_frame"] {
123
- display: flex !important;
124
- flex-direction: column !important;
123
+ display: grid !important;
124
+ grid-template-columns: 0px minmax(0px, 1fr) minmax(0px, 0px) !important;
125
+ grid-template-rows: minmax(0, 100%) !important;
125
126
  width: 100vw !important;
126
127
  height: 100dvh !important;
127
128
  margin: 0 !important;
128
129
  padding-top: var(--dsh-mobile-header-h) !important;
129
130
  position: relative !important;
130
- grid-template-columns: 1fr !important;
131
131
  overflow: hidden !important;
132
132
  box-sizing: border-box !important;
133
133
  }
134
134
 
135
+ /* \u5BBF\u4E3B 0.1.7 \u7684 frame \u662F grid \u4E09\u5217\u5E03\u5C40\uFF08sidebar | center | rightbar\uFF09\uFF0CJS \u6309\u72B6\u6001\u6CE8\u5165
136
+ grid-template-columns\uFF1B\u63D2\u4EF6\u628A\u5DE6\u4FA7\u680F\u62BD\u5C49\u5316\u540E sidebarCol \u53D8\u6210 fixed\uFF08\u8131\u79BB grid \u6D41\uFF09\uFF0C
137
+ \u82E5\u4E0D\u663E\u5F0F\u6307\u5B9A\u5217\u4F4D\uFF0CcenterCol \u4F1A\u88AB\u81EA\u52A8\u6392\u8FDB\u7B2C 1 \u5217\uFF0856px \u8F68\u9053\uFF09\u3001rightbarCol \u584C\u9677\u5230
138
+ \u89C6\u53E3\u5E95\u90E8 \u2192 \u53F3\u4FA7\u680F\u70B9\u5F00\u540E\u9762\u677F\u88AB\u5B9A\u4F4D\u5230\u89C6\u53E3\u5916\uFF08\u7528\u6237\u770B\u5230\u7684\u300C\u6309\u94AE\u6D88\u5931\u3001\u53F3\u4FA7\u680F\u6CA1\u51FA\u6765\u300D\uFF09\u3002
139
+ \u8FD9\u91CC\u663E\u5F0F\u5F52\u4F4D\uFF1Asidebar \u62BD\u5C49\u4E0D\u5360\u5217\uFF08\u7B2C 1 \u5217 0px\uFF09\u3001center \u5360\u6EE1\uFF08\u7B2C 2 \u5217 1fr\uFF09\u3001
140
+ rightbar \u4FDD\u7559\u5BBF\u4E3B\u53F3\u4FA7\u680F\u5217\uFF08\u7B2C 3 \u5217 0px \u6298\u53E0\uFF0C\u5168\u5C4F\u9762\u677F fixed \u76F8\u5BF9\u89C6\u53E3\u3001\u4E0D\u4F9D\u8D56\u6B64\u5217\uFF09\u3002 */
141
+ div[class*="_centerCol"] { grid-column: 2 !important; }
142
+ div[class*="_rightbarCol"] { grid-column: 3 !important; }
143
+ div[class*="_overlayLayer"] { grid-column: 1 / -1 !important; }
144
+
135
145
  /* 1.1 fixed \u5168\u5C4F\u9762\u677F\u5355\u72EC\u8BA9\u4F4D\uFF1Aposition:fixed \u7684\u5305\u542B\u5757\u662F viewport\uFF08CSS 2.1 \xA710.1\uFF09\uFF0C
136
146
  \u4E0D\u8DDF\u968F\u4E0A\u9762 frame \u7684 padding-top\uFF0C\u56E0\u6B64\u9876\u90E8 52px \u4F1A\u843D\u8FDB\u9876\u680F\u8986\u76D6\u533A\uFF08#41\uFF09\u3002
137
- \u5B98\u65B9\u53F3\u4FA7\u680F\u5728 <768px \u81EA\u52A8\u5168\u5C4F\uFF08fixed; inset:0; z-index:40\uFF09\uFF0C\u8FD9\u91CC\u6309 data \u5C5E\u6027
138
- \u76F4\u63A5\u4F4D\u79FB\u5BB9\u5668\u672C\u8EAB\uFF0C\u4E0D\u4F9D\u8D56\u5BBF\u4E3B CSS-module \u54C8\u5E0C\u7C7B\u540D\u3002
139
- \u771F\u6B63\u8D77\u4F5C\u7528\u7684\u662F top\uFF1Bheight/max-height \u4E0E\u4E0B\u9762\u5DE5\u4F5C\u53F0\u9762\u677F\u90A3\u6BB5\u4FDD\u6301\u540C\u4E00\u5199\u6CD5\uFF1A
140
- \u5BBF\u4E3B\u5F53\u524D\u7528 inset:0\uFF08\u65E0\u663E\u5F0F\u9AD8\u5EA6\uFF09\u65F6 top \u5355\u72EC\u5373\u53EF\uFF0C\u4F46\u5BBF\u4E3B\u5C06\u6765\u82E5\u7ED9\u51FA\u663E\u5F0F\u9AD8\u5EA6\uFF0C
141
- \u663E\u5F0F height \u4ECD\u80FD\u628A\u76D2\u5B50\u6536\u5728\u9876\u680F\u4E4B\u4E0B\u3002 */
147
+ \u5B98\u65B9\u53F3\u4FA7\u680F\u5728 <768px \u81EA\u52A8\u5168\u5C4F\uFF0C\u8FD9\u91CC\u6309 data \u5C5E\u6027\u76F4\u63A5\u4F4D\u79FB\u5BB9\u5668\u672C\u8EAB\uFF0C\u4E0D\u4F9D\u8D56\u5BBF\u4E3B
148
+ CSS-module \u54C8\u5E0C\u7C7B\u540D\u3002
149
+ \u5BBF\u4E3B\u7248\u672C\u5DEE\u5F02\uFF080.1.5 vs 0.1.7\uFF09\uFF1A0.1.5 \u7684\u9762\u677F\u81EA\u8EAB\u5C31\u662F position:fixed; inset:0
150
+ \uFF08\u76F8\u5BF9\u89C6\u53E3\uFF09\uFF0Ctop \u8BA9\u4F4D\u76F4\u63A5\u751F\u6548\uFF1B0.1.7 \u628A\u9762\u677F\u6539\u6210 position:absolute \u76F8\u5BF9
151
+ rightbarCol \u5217\u5B9A\u4F4D\uFF0C\u4E14\u5BBF\u4E3B\u5DF2\u628A\u5B83\u653E\u5728\u5185\u5BB9\u533A\u8D77\u70B9\u2014\u2014\u82E5\u63D2\u4EF6\u4ECD\u53EA\u6539 top\uFF0C\u4F1A\u5728\u5BBF\u4E3B
152
+ \u5B9A\u4F4D\u4E4B\u4E0A\u518D\u53E0\u52A0 52px\uFF08\u9762\u677F\u88AB\u63A8\u5230\u89C6\u53E3\u5916\uFF0C\u8868\u73B0\u4E3A\u300C\u70B9\u5F00\u53F3\u4FA7\u680F\u6309\u94AE\u6D88\u5931\u3001\u9762\u677F\u4E0D
153
+ \u51FA\u6765\u300D\uFF09\u3002\u4FEE\u6CD5\uFF1A\u628A\u9762\u677F\u7EDF\u4E00\u5F3A\u5236\u4E3A fixed \u76F8\u5BF9\u89C6\u53E3 + top:52px \u8BA9\u4F4D\uFF0C\u4E24\u7248\u5BBF\u4E3B
154
+ \u884C\u4E3A\u4E00\u81F4\u3002 */
142
155
  [data-sidebar-right-panel="fullscreen"] {
156
+ position: fixed !important;
143
157
  top: var(--dsh-mobile-header-h, 52px) !important;
158
+ left: 0 !important;
159
+ right: 0 !important;
160
+ bottom: 0 !important;
161
+ width: 100vw !important;
144
162
  height: calc(100dvh - var(--dsh-mobile-header-h, 52px)) !important;
145
163
  max-height: calc(100dvh - var(--dsh-mobile-header-h, 52px)) !important;
164
+ z-index: 40 !important;
165
+ box-sizing: border-box !important;
146
166
  }
147
167
 
148
168
  /* 2. \u9876\u90E8\u539F\u751F\u5BFC\u822A\u6761\uFF1A100% \u8FD8\u539F DeepSeek App (\u5DE6\u4FA7\u53CC\u6A2A\u7EBF\uFF0C\u53F3\u4FA7(+)\uFF0C\u4E2D\u95F4\u7559\u767D\uFF0C\u65E0\u591A\u4F59\u8BBE\u7F6E\u6309\u94AE) */
@@ -5900,7 +5920,9 @@ function setupMobileExperience(rpcCall, ctx) {
5900
5920
  e.stopPropagation();
5901
5921
  const isOpen = document.body.classList.toggle("dsh-drawer-open");
5902
5922
  if (isOpen) {
5903
- const expand = document.querySelector('button[aria-label*="\u6253\u5F00\u4FA7\u8FB9\u680F"], button[title*="\u6253\u5F00\u4FA7\u8FB9\u680F"]');
5923
+ const expand = document.querySelector(
5924
+ 'button[aria-label*="\u6253\u5F00\u4FA7\u8FB9\u680F"], button[title*="\u6253\u5F00\u4FA7\u8FB9\u680F"], button[aria-label*="Open sidebar"], button[title*="Open sidebar"]'
5925
+ );
5904
5926
  if (expand) expand.click();
5905
5927
  }
5906
5928
  };
@@ -5924,7 +5946,7 @@ function setupMobileExperience(rpcCall, ctx) {
5924
5946
  rightBtn.onclick = () => {
5925
5947
  const openPanels = document.querySelectorAll('div[class*="nArs4W_panel"]:not([class*="panelHidden"]), div[class*="workbench_panel"]:not([class*="panelHidden"])');
5926
5948
  openPanels.forEach((p) => p.classList.add("nArs4W_panelHidden"));
5927
- const dshNewBtn = document.querySelector('button[aria-label="\u65B0\u5EFA\u4F1A\u8BDD"]');
5949
+ const dshNewBtn = document.querySelector('button[aria-label="\u65B0\u5EFA\u4F1A\u8BDD"], button[aria-label="New session"]');
5928
5950
  if (dshNewBtn) dshNewBtn.click();
5929
5951
  };
5930
5952
  header.appendChild(leftBtn);
@@ -5977,7 +5999,7 @@ function setupMobileExperience(rpcCall, ctx) {
5977
5999
  e.stopPropagation();
5978
6000
  document.body.classList.remove("dsh-workbench-open");
5979
6001
  p.classList.add("nArs4W_panelHidden");
5980
- const collapseBtn = document.querySelector('button[class*="toggleButton"][aria-label*="\u6536\u8D77"]');
6002
+ const collapseBtn = document.querySelector('button[class*="toggleButton"][aria-label*="\u6536\u8D77"], button[class*="toggleButton"][aria-label*="Collapse"]');
5981
6003
  if (collapseBtn) collapseBtn.click();
5982
6004
  };
5983
6005
  bar.appendChild(btn);
@@ -5989,14 +6011,14 @@ function setupMobileExperience(rpcCall, ctx) {
5989
6011
  window.addEventListener("resize", ensurePanelCloseButton);
5990
6012
  document.addEventListener("click", (e) => {
5991
6013
  if (typeof window === "undefined" || window.innerWidth > MOBILE_MAX_WIDTH) return;
5992
- const trigger = e.target.closest('button[aria-label*="\u9762\u677F"], button[aria-label*="\u5DE5\u4F5C\u533A"], div[class*="toggleCluster"] button, button[class*="subagent"], div[class*="headerActions"] button, div[class*="titleRow"] button');
6014
+ const trigger = e.target.closest('button[aria-label*="\u9762\u677F"], button[aria-label*="\u5DE5\u4F5C\u533A"], button[aria-label*="workspace"], button[aria-label*="Workspace"], div[class*="toggleCluster"] button, button[class*="subagent"], div[class*="headerActions"] button, div[class*="titleRow"] button');
5993
6015
  if (trigger && !trigger.classList.contains("dsh-mobile-panel-close-btn") && !trigger.classList.contains("dsh-header-menu-btn") && !trigger.classList.contains("dsh-header-new-btn")) {
5994
6016
  document.body.classList.add("dsh-workbench-open");
5995
6017
  }
5996
6018
  }, true);
5997
6019
  document.addEventListener("click", (e) => {
5998
6020
  if (typeof window === "undefined" || window.innerWidth > MOBILE_MAX_WIDTH) return;
5999
- const toggle = e.target.closest('button[aria-label*="\u6536\u8D77\u4FA7\u8FB9\u680F"], button[title*="\u6536\u8D77\u4FA7\u8FB9\u680F"]');
6021
+ const toggle = e.target.closest('button[aria-label*="\u6536\u8D77\u4FA7\u8FB9\u680F"], button[title*="\u6536\u8D77\u4FA7\u8FB9\u680F"], button[aria-label*="Collapse sidebar"], button[title*="Collapse sidebar"]');
6000
6022
  if (toggle) {
6001
6023
  document.body.classList.remove("dsh-drawer-open");
6002
6024
  }
@@ -6068,7 +6090,7 @@ function setupMobileExperience(rpcCall, ctx) {
6068
6090
  if (navigator.vibrate) navigator.vibrate(40);
6069
6091
  } catch (_) {
6070
6092
  }
6071
- const actionBtn = sessionRow.querySelector('button[aria-label*="\u64CD\u4F5C"], button[class*="iconButton"], button');
6093
+ const actionBtn = sessionRow.querySelector('button[aria-label*="\u64CD\u4F5C"], button[aria-label*="Session actions"], button[class*="iconButton"], button');
6072
6094
  if (actionBtn) {
6073
6095
  actionBtn.click();
6074
6096
  }
@@ -6095,7 +6117,9 @@ function setupMobileExperience(rpcCall, ctx) {
6095
6117
  if (Math.abs(deltaX) > 60 && Math.abs(deltaX) > Math.abs(deltaY) * 1.5) {
6096
6118
  if (deltaX > 0 && touchStartX <= 35) {
6097
6119
  document.body.classList.add("dsh-drawer-open");
6098
- const collapsedToggle = document.querySelector('div[class*="hHd-Xa_collapsed"] button[class*="hHd-Xa_toggle"]');
6120
+ const collapsedToggle = document.querySelector(
6121
+ 'div[class*="hHd-Xa_collapsed"] button[class*="hHd-Xa_toggle"], button[aria-label*="\u6253\u5F00\u4FA7\u8FB9\u680F"], button[title*="\u6253\u5F00\u4FA7\u8FB9\u680F"], button[aria-label*="Open sidebar"], button[title*="Open sidebar"]'
6122
+ );
6099
6123
  if (collapsedToggle) collapsedToggle.click();
6100
6124
  } else if (deltaX < 0 && document.body.classList.contains("dsh-drawer-open")) {
6101
6125
  document.body.classList.remove("dsh-drawer-open");
@@ -6108,7 +6132,7 @@ function setupMobileExperience(rpcCall, ctx) {
6108
6132
  if (!btn) return;
6109
6133
  if (btn.closest("#dsh-remote-workspace-modal")) return;
6110
6134
  const label = (btn.getAttribute("aria-label") || btn.innerText || btn.title || "").trim();
6111
- const isAddWorkspace = label === "\u6DFB\u52A0\u5DE5\u4F5C\u533A" || label === "\u65B0\u5EFA\u5DE5\u4F5C\u533A" || label === "\u6253\u5F00\u5DE5\u4F5C\u533A" || label === "\u6253\u5F00\u6587\u4EF6\u5939" || label === "Add Workspace" || label === "Open Folder" || label.includes("\u6DFB\u52A0\u5DE5\u4F5C\u533A") || label.includes("\u6253\u5F00\u5DE5\u4F5C\u533A") || label.includes("\u6253\u5F00\u6587\u4EF6\u5939") || btn.matches('button[aria-label*="\u5DE5\u4F5C\u533A"][aria-label*="\u6DFB\u52A0"], button[aria-label*="\u5DE5\u4F5C\u533A"][aria-label*="\u6253\u5F00"]');
6135
+ const isAddWorkspace = label === "\u6DFB\u52A0\u5DE5\u4F5C\u533A" || label === "\u65B0\u5EFA\u5DE5\u4F5C\u533A" || label === "\u6253\u5F00\u5DE5\u4F5C\u533A" || label === "\u6253\u5F00\u6587\u4EF6\u5939" || label === "Add Workspace" || label === "Open Folder" || label.includes("\u6DFB\u52A0\u5DE5\u4F5C\u533A") || label.includes("\u6253\u5F00\u5DE5\u4F5C\u533A") || label.includes("\u6253\u5F00\u6587\u4EF6\u5939") || btn.matches('button[aria-label*="\u5DE5\u4F5C\u533A"][aria-label*="\u6DFB\u52A0"], button[aria-label*="\u5DE5\u4F5C\u533A"][aria-label*="\u6253\u5F00"], button[aria-label*="Workspace"][aria-label*="add"], button[aria-label*="Workspace"][aria-label*="open"], button[aria-label*="Add workspace"], button[aria-label*="Open workspace"]');
6112
6136
  if (isAddWorkspace) {
6113
6137
  e.preventDefault();
6114
6138
  e.stopPropagation();
package/client/index.js CHANGED
@@ -3950,7 +3950,12 @@ function setupMobileExperience(rpcCall, ctx) {
3950
3950
  e.stopPropagation();
3951
3951
  const isOpen = document.body.classList.toggle('dsh-drawer-open');
3952
3952
  if (isOpen) {
3953
- const expand = document.querySelector('button[aria-label*="打开侧边栏"], button[title*="打开侧边栏"]');
3953
+ // 匹配宿主「展开侧边栏」按钮。宿主文案随界面语言切换:中文「打开侧边栏」、
3954
+ // 英文 "Open sidebar"(0.1.7 起宿主按浏览器语言渲染 en,只匹配中文会漏取,
3955
+ // 导致抽屉滑出但会话列表未挂载 → 侧边栏空白)。
3956
+ const expand = document.querySelector(
3957
+ 'button[aria-label*="打开侧边栏"], button[title*="打开侧边栏"], button[aria-label*="Open sidebar"], button[title*="Open sidebar"]',
3958
+ );
3954
3959
  if (expand) expand.click();
3955
3960
  }
3956
3961
  };
@@ -3978,7 +3983,8 @@ function setupMobileExperience(rpcCall, ctx) {
3978
3983
  rightBtn.onclick = () => {
3979
3984
  const openPanels = document.querySelectorAll('div[class*="nArs4W_panel"]:not([class*="panelHidden"]), div[class*="workbench_panel"]:not([class*="panelHidden"])');
3980
3985
  openPanels.forEach((p) => p.classList.add('nArs4W_panelHidden'));
3981
- const dshNewBtn = document.querySelector('button[aria-label="新建会话"]');
3986
+ // 宿主新建会话按钮文案随语言切换:中文「新建会话」/ 英文 "New session"(两者都要匹配,否则英文界面下 (+) 失效)
3987
+ const dshNewBtn = document.querySelector('button[aria-label="新建会话"], button[aria-label="New session"]');
3982
3988
  if (dshNewBtn) dshNewBtn.click();
3983
3989
  };
3984
3990
 
@@ -4038,7 +4044,7 @@ function setupMobileExperience(rpcCall, ctx) {
4038
4044
  e.stopPropagation();
4039
4045
  document.body.classList.remove('dsh-workbench-open');
4040
4046
  p.classList.add('nArs4W_panelHidden');
4041
- const collapseBtn = document.querySelector('button[class*="toggleButton"][aria-label*="收起"]');
4047
+ const collapseBtn = document.querySelector('button[class*="toggleButton"][aria-label*="收起"], button[class*="toggleButton"][aria-label*="Collapse"]');
4042
4048
  if (collapseBtn) collapseBtn.click();
4043
4049
  };
4044
4050
  bar.appendChild(btn);
@@ -4051,18 +4057,22 @@ function setupMobileExperience(rpcCall, ctx) {
4051
4057
  window.addEventListener('resize', ensurePanelCloseButton);
4052
4058
 
4053
4059
  // 移动端点击面板/工作区触发按钮时,自动激活 dsh-workbench-open
4060
+ // (宿主文案随语言切换:中文「面板/工作区」/ 英文 "Panel/workspace" —— 注意英文实际是
4061
+ // 小写 "Add workspace"、"Choose workspace" 与大写 "Workspace actions for …",两者都要覆盖;
4062
+ // CSS 属性子串匹配区分大小写,不能只写一种)
4054
4063
  document.addEventListener('click', (e) => {
4055
4064
  if (typeof window === 'undefined' || window.innerWidth > MOBILE_MAX_WIDTH) return;
4056
- const trigger = e.target.closest('button[aria-label*="面板"], button[aria-label*="工作区"], div[class*="toggleCluster"] button, button[class*="subagent"], div[class*="headerActions"] button, div[class*="titleRow"] button');
4065
+ const trigger = e.target.closest('button[aria-label*="面板"], button[aria-label*="工作区"], button[aria-label*="workspace"], button[aria-label*="Workspace"], div[class*="toggleCluster"] button, button[class*="subagent"], div[class*="headerActions"] button, div[class*="titleRow"] button');
4057
4066
  if (trigger && !trigger.classList.contains('dsh-mobile-panel-close-btn') && !trigger.classList.contains('dsh-header-menu-btn') && !trigger.classList.contains('dsh-header-new-btn')) {
4058
4067
  document.body.classList.add('dsh-workbench-open');
4059
4068
  }
4060
4069
  }, true);
4061
4070
 
4062
4071
  // 移动端点击 DSH 自带的收起侧边栏图标时,自动收起抽屉
4072
+ // (文案随宿主界面语言切换:中文「收起侧边栏」/ 英文 "Collapse sidebar",两者都要匹配)
4063
4073
  document.addEventListener('click', (e) => {
4064
4074
  if (typeof window === 'undefined' || window.innerWidth > MOBILE_MAX_WIDTH) return;
4065
- const toggle = e.target.closest('button[aria-label*="收起侧边栏"], button[title*="收起侧边栏"]');
4075
+ const toggle = e.target.closest('button[aria-label*="收起侧边栏"], button[title*="收起侧边栏"], button[aria-label*="Collapse sidebar"], button[title*="Collapse sidebar"]');
4066
4076
  if (toggle) {
4067
4077
  document.body.classList.remove('dsh-drawer-open');
4068
4078
  }
@@ -4170,8 +4180,8 @@ function setupMobileExperience(rpcCall, ctx) {
4170
4180
  if (navigator.vibrate) navigator.vibrate(40);
4171
4181
  } catch (_) {}
4172
4182
 
4173
- // 寻找该会话项内的三点操作按钮并触发点击
4174
- const actionBtn = sessionRow.querySelector('button[aria-label*="操作"], button[class*="iconButton"], button');
4183
+ // 寻找该会话项内的三点操作按钮并触发点击(宿主文案:中文「操作」/ 英文 "Session actions")
4184
+ const actionBtn = sessionRow.querySelector('button[aria-label*="操作"], button[aria-label*="Session actions"], button[class*="iconButton"], button');
4175
4185
  if (actionBtn) {
4176
4186
  actionBtn.click();
4177
4187
  }
@@ -4202,7 +4212,9 @@ function setupMobileExperience(rpcCall, ctx) {
4202
4212
  if (Math.abs(deltaX) > 60 && Math.abs(deltaX) > Math.abs(deltaY) * 1.5) {
4203
4213
  if (deltaX > 0 && touchStartX <= 35) {
4204
4214
  document.body.classList.add('dsh-drawer-open');
4205
- const collapsedToggle = document.querySelector('div[class*="hHd-Xa_collapsed"] button[class*="hHd-Xa_toggle"]');
4215
+ const collapsedToggle = document.querySelector(
4216
+ 'div[class*="hHd-Xa_collapsed"] button[class*="hHd-Xa_toggle"], button[aria-label*="打开侧边栏"], button[title*="打开侧边栏"], button[aria-label*="Open sidebar"], button[title*="Open sidebar"]',
4217
+ );
4206
4218
  if (collapsedToggle) collapsedToggle.click();
4207
4219
  } else if (deltaX < 0 && document.body.classList.contains('dsh-drawer-open')) {
4208
4220
  document.body.classList.remove('dsh-drawer-open');
@@ -4234,7 +4246,7 @@ function setupMobileExperience(rpcCall, ctx) {
4234
4246
  label.includes('添加工作区') ||
4235
4247
  label.includes('打开工作区') ||
4236
4248
  label.includes('打开文件夹') ||
4237
- btn.matches('button[aria-label*="工作区"][aria-label*="添加"], button[aria-label*="工作区"][aria-label*="打开"]')
4249
+ btn.matches('button[aria-label*="工作区"][aria-label*="添加"], button[aria-label*="工作区"][aria-label*="打开"], button[aria-label*="Workspace"][aria-label*="add"], button[aria-label*="Workspace"][aria-label*="open"], button[aria-label*="Add workspace"], button[aria-label*="Open workspace"]')
4238
4250
  );
4239
4251
 
4240
4252
  if (isAddWorkspace) {
@@ -89,29 +89,49 @@ export const MOBILE_STYLES_CSS = `
89
89
  表现为「看不到最新消息」。官方给该容器的规则是 flex:none;height:auto
90
90
  (让记录随内容自然增高、由外层统一滚动),与这里冲突,故必须排除。 */
91
91
  [data-slot="root"] > div[class*="_frame"] {
92
- display: flex !important;
93
- flex-direction: column !important;
92
+ display: grid !important;
93
+ grid-template-columns: 0px minmax(0px, 1fr) minmax(0px, 0px) !important;
94
+ grid-template-rows: minmax(0, 100%) !important;
94
95
  width: 100vw !important;
95
96
  height: 100dvh !important;
96
97
  margin: 0 !important;
97
98
  padding-top: var(--dsh-mobile-header-h) !important;
98
99
  position: relative !important;
99
- grid-template-columns: 1fr !important;
100
100
  overflow: hidden !important;
101
101
  box-sizing: border-box !important;
102
102
  }
103
103
 
104
+ /* 宿主 0.1.7 的 frame 是 grid 三列布局(sidebar | center | rightbar),JS 按状态注入
105
+ grid-template-columns;插件把左侧栏抽屉化后 sidebarCol 变成 fixed(脱离 grid 流),
106
+ 若不显式指定列位,centerCol 会被自动排进第 1 列(56px 轨道)、rightbarCol 塌陷到
107
+ 视口底部 → 右侧栏点开后面板被定位到视口外(用户看到的「按钮消失、右侧栏没出来」)。
108
+ 这里显式归位:sidebar 抽屉不占列(第 1 列 0px)、center 占满(第 2 列 1fr)、
109
+ rightbar 保留宿主右侧栏列(第 3 列 0px 折叠,全屏面板 fixed 相对视口、不依赖此列)。 */
110
+ div[class*="_centerCol"] { grid-column: 2 !important; }
111
+ div[class*="_rightbarCol"] { grid-column: 3 !important; }
112
+ div[class*="_overlayLayer"] { grid-column: 1 / -1 !important; }
113
+
104
114
  /* 1.1 fixed 全屏面板单独让位:position:fixed 的包含块是 viewport(CSS 2.1 §10.1),
105
115
  不跟随上面 frame 的 padding-top,因此顶部 52px 会落进顶栏覆盖区(#41)。
106
- 官方右侧栏在 <768px 自动全屏(fixed; inset:0; z-index:40),这里按 data 属性
107
- 直接位移容器本身,不依赖宿主 CSS-module 哈希类名。
108
- 真正起作用的是 top;height/max-height 与下面工作台面板那段保持同一写法:
109
- 宿主当前用 inset:0(无显式高度)时 top 单独即可,但宿主将来若给出显式高度,
110
- 显式 height 仍能把盒子收在顶栏之下。 */
116
+ 官方右侧栏在 <768px 自动全屏,这里按 data 属性直接位移容器本身,不依赖宿主
117
+ CSS-module 哈希类名。
118
+ 宿主版本差异(0.1.5 vs 0.1.7):0.1.5 的面板自身就是 position:fixed; inset:0
119
+ (相对视口),top 让位直接生效;0.1.7 把面板改成 position:absolute 相对
120
+ rightbarCol 列定位,且宿主已把它放在内容区起点——若插件仍只改 top,会在宿主
121
+ 定位之上再叠加 52px(面板被推到视口外,表现为「点开右侧栏按钮消失、面板不
122
+ 出来」)。修法:把面板统一强制为 fixed 相对视口 + top:52px 让位,两版宿主
123
+ 行为一致。 */
111
124
  [data-sidebar-right-panel="fullscreen"] {
125
+ position: fixed !important;
112
126
  top: var(--dsh-mobile-header-h, 52px) !important;
127
+ left: 0 !important;
128
+ right: 0 !important;
129
+ bottom: 0 !important;
130
+ width: 100vw !important;
113
131
  height: calc(100dvh - var(--dsh-mobile-header-h, 52px)) !important;
114
132
  max-height: calc(100dvh - var(--dsh-mobile-header-h, 52px)) !important;
133
+ z-index: 40 !important;
134
+ box-sizing: border-box !important;
115
135
  }
116
136
 
117
137
  /* 2. 顶部原生导航条:100% 还原 DeepSeek App (左侧双横线,右侧(+),中间留白,无多余设置按钮) */
@@ -23,7 +23,7 @@
23
23
  3. **构建与测试**:
24
24
  - `npm run build:client`(**必须**:客户端产物要与源码同步,`npm test` 有一项断言会校验产物内嵌的 CSS 与源码逐字一致)
25
25
  - `npm test` + `npm run lint`
26
- - `npm run verify:mobile-ui`(**发布前必做**:跑真实 GUI 的移动端行为验收,6 个套件。需要 dsh web 正在运行;Chrome 路径可用 `PUPPETEER_EXECUTABLE_PATH` 指定。它不在 CI 里跑,因为 CI 没有宿主)
26
+ - `npm run verify:mobile-ui`(**发布前必做**:跑真实 GUI 的移动端行为验收,8 个套件。需要 dsh web 正在运行;Chrome 路径可用 `PUPPETEER_EXECUTABLE_PATH` 指定。它不在 CI 里跑,因为 CI 没有宿主)
27
27
  - `npm run build:banner`(**仅当 `docs/screenshots/` 素材有变、需要重出 README banner 时执行**;输入没变时应跳过,否则只会产生 JPEG 重编码噪声。注意该脚本默认 Chrome 路径是写死的 Windows 路径,需用 `PUPPETEER_EXECUTABLE_PATH` 覆盖)
28
28
  - `npm run build:lark`(**仅在需要重建飞书 vendor bundle 时执行**。它用当前 esbuild 重新打包 `lib/feishu/lark-bundled.mjs`,产物会随 esbuild 版本漂移;**不要放进 `prepack`**,否则每次 `npm publish` 都会让线上 tarball 里的 vendor 文件与 tag 里的不一致)
29
29
  4. **提交**:合并到 `main`(fast-forward),提交信息 `release: vX.Y.Z — ...`
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@wenbin_wb/dsh-bridge",
3
- "version": "2.11.1",
3
+ "version": "2.11.2",
4
4
  "description": "手机扫码即可在移动端/公网继续用 DeepSeek Harness,人不在电脑前也能接着干。一键局域网二维码、Cloudflare 公网隧道、自建隧道与微信 / QQ / 飞书 / Telegram Bot(多工作区/会话持久化/媒体/卡片审批/流式输出),无需自己搭公网服务器。",
5
- "releaseNotes": "【v2.11.1】修复与 DSH 0.1.7 相关的界面与稳定性问题\n• 修复:手机上聊天区「看不到最新消息」——移动端框架规则限定到布局外壳,不再误伤聊天记录容器(感谢外部贡献者 imroc,PR #48)\n• 修复:linux 下托管误判与 systemd 掉线(cgroup 解析支持多行/换行,重启前补齐 systemctl 执行环境)\n• 修复:设置弹窗自身不再被层级规则误抬,避免与第三方模态同层(适配 DSH 0.1.7)\n• 说明:纯前端 + 重启守护逻辑改动,刷新页面即生效",
5
+ "releaseNotes": "【v2.11.2】移动端侧边栏/右侧栏修复与 DSH 0.1.7 布局适配\n• 修复:移动端侧边栏(抽屉)点击后空白——宿主按钮文案随界面语言切换,插件只按中文匹配,英文界面漏取导致会话列表不挂载\n• 修复:移动端右侧栏点击后不显示——适配 DSH 0.1.7 的 grid 三列布局与面板定位变化,右侧栏面板回到顶栏下方可见\n• 说明:纯前端改动,刷新页面即生效",
6
6
  "type": "module",
7
7
  "main": "lib/index.js",
8
8
  "exports": {