dsh-mobile-ui 0.2.3 → 0.2.4

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/client.js CHANGED
@@ -244,7 +244,13 @@ window.__ModuleLoader__.load({
244
244
  (退回“切换器被裁”),升级后跑 tests/mobile-layout-probe.py 的 subagent 段复核。 */
245
245
  " body.dsh-mobile-ui [class*=wSkVaW_crumbSeg] [class*=ZKlsPq_root]{flex:0 0 auto !important}",
246
246
  " body.dsh-mobile-ui [class*=wSkVaW_titleRow]{flex-wrap:wrap !important;row-gap:4px !important}",
247
- " body.dsh-mobile-ui [class*=wSkVaW_titleCluster]{flex:1 1 100% !important}",
247
+ " body.dsh-mobile-ui [class*=wSkVaW_titleCluster]{flex:1 1 100% !important;flex-wrap:wrap !important;row-gap:4px !important}",
248
+ /* ⚠️ titleCluster 必须允许换行(2026-09-14 补):会话有后台任务时,headerActions 里会
249
+ 多出一个 150px 的「N 个后台任务」切换器且**不收缩**(flex:0 0 auto)⇒ crumbs 被压到
250
+ 106px,子代理切换器(80px)溢出被裁 8px(实测 crumbs.right=126 < switcher.right=134)。
251
+ 允许换行后 space 不足时 headerActions 自动落到下一行,crumbs 独占整行;
252
+ 没有后台任务时(crumbs+actions 仅 182px)不触发换行,布局维持原样。
253
+ 代价:有后台任务的会话 header 106 → 136px。 */
248
254
  /* 极窄屏(≤360px)面包屑只留当前段:子代理会话页的面包屑是
249
255
  「父会话 / 子代理名 / N 个子代理」,320px 实测当前段标题被挤到 36px
250
256
  (只剩两三个字符,探针会判 ❌),隐藏父级段与分隔符后回到 96px。
@@ -252,6 +258,22 @@ window.__ModuleLoader__.load({
252
258
  " @media (max-width:360px){",
253
259
  " body.dsh-mobile-ui [class*=wSkVaW_crumbSeg] > [class*=wSkVaW_crumb]:not([class*=wSkVaW_crumbCurrent]),body.dsh-mobile-ui [class*=wSkVaW_crumbSeg] > [class*=wSkVaW_crumbSep]{display:none !important}",
254
260
  " }",
261
+ /* ── 移动端浮层不许出视口(2026-09-14,用户报「点后台任务/终端/session 日志显示不全」)──
262
+ 上游两处 popover 按**桌面宽度**做对齐,390px 手机上直接飞到屏幕外(实测):
263
+ · 后台任务菜单 [class*=QsffPG_menu]:absolute left:0 + 固定宽 336,锚在 x=261 的按钮上
264
+ ⇒ 右边界 597 ⇒ **右侧溢出 207px**,只剩最左 129px 可见;
265
+ · 「更多操作」菜单 [role=menu][class*=_list_1nxmc_](内含「下载 Session 日志」
266
+ 「在 GNOME Terminal 中打开工作目录」等项):absolute right:0 + 宽 218,锚在 x=100 的按钮上
267
+ ⇒ 左边界 **-90** ⇒ 左侧溢出 90px(用户就是在这一步看不到终端/日志项)。
268
+ 两处一律 fixed 到视口:左右各留 8px、宽度自适应、顶部落在 header 下方(第一行按钮 42px、
269
+ 第二行按钮 76px,用 CSS 变量区分),并补 max-height + overflow:auto 兜住长菜单。
270
+ ⚠️ 必须 fixed 而不是「用 right:0 相对容器」:absolute 的 left/right 相对**按钮容器**,
271
+ 而容器在 header 里的横坐标随「有无子代理/后台任务」变化 —— 候选方案 right:0 在容器靠右时
272
+ 可用、靠左时左溢出;fixed 与容器位置无关(实测两种场景都在视口内)。
273
+ ⚠️ hash 前缀(QsffPG_ / _1nxmc_)会随 dsh 升级漂移、失效是静默的(退回溢出),
274
+ 升级后跑 tests/live-probe.py 复核(已覆盖后台任务菜单)。 */
275
+ " body.dsh-mobile-ui [class*=QsffPG_menu],body.dsh-mobile-ui [role=menu][class*=_list_1nxmc_]{position:fixed !important;left:8px !important;right:8px !important;width:auto !important;min-width:0 !important;max-width:none !important;max-height:calc(100vh - 130px) !important;overflow:auto !important;top:calc(var(--dsh-mobile-popover-top,42px) + env(safe-area-inset-top,0px)) !important}",
276
+ " body.dsh-mobile-ui [role=menu][class*=_list_1nxmc_]{--dsh-mobile-popover-top:76px}",
255
277
  /* 输入框聚焦反馈 */
256
278
  " body.dsh-mobile-ui textarea:focus,body.dsh-mobile-ui [class*=input]:focus-within{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-brand-primary,rgba(79,124,255,.45))}",
257
279
  /* 消息流操作按钮(复制/反馈/分享)触摸目标提升。
@@ -540,10 +562,19 @@ window.__ModuleLoader__.load({
540
562
  /* 抽屉态下 sidebar 保持可见,否则隐藏 */
541
563
  side.style.display = drawerOpen ? "" : "none";
542
564
  ensureChrome();
543
- /* 菜单按钮三态判定:抽屉 / 设置面板 / 提问卡片浮层打开时都隐藏。
565
+ /* 菜单按钮四态判定:抽屉 / 设置面板 / 提问卡片浮层 / **顶部 popover 菜单**
566
+ 打开时都隐藏。
544
567
  (旧写法只看 drawerOpen,会把设置面板打开时隐藏的菜单在下次 sync 又显示回来;
545
- 提问卡片时则会浮在卡片右上角遮住问题标题) */
546
- if (tabbar) tabbar.style.display = (drawerOpen || settingsOpen || qaOpen) ? "none" : "";
568
+ 提问卡片时则会浮在卡片右上角遮住问题标题;
569
+ 2026-09-14 补第 4 态:后台任务/「更多操作」菜单被本插件的浮层规则固定到
570
+ top:42 全宽后,右上角的汉堡按钮正好压在菜单首行右侧 —— vision 复核截图时发现
571
+ 「第一行的耗时被按钮遮住」,故菜单开着时也隐藏它) */
572
+ var popOpen = !!(document.querySelector(
573
+ "[class*=QsffPG_menu],[role=menu][class*=_list_1nxmc_]"));
574
+ if (tabbar) {
575
+ tabbar.style.display = (drawerOpen || settingsOpen || qaOpen || popOpen)
576
+ ? "none" : "";
577
+ }
547
578
  } else {
548
579
  document.body.classList.remove("dsh-mobile-ui");
549
580
  qaOpen = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mobile-ui",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Mobile UI for the DeepSeek Harness Web GUI: responsive layout, overlay session drawer, 44px touch targets, safe-area support, reading enhancements (≤768px, zero desktop impact)",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -43,6 +43,15 @@ GEOM = """() => {
43
43
  crumbsText: (crumbs.innerText || '').replace(/\\n/g, ' ').slice(0, 60),
44
44
  };
45
45
  }"""
46
+ POPOVER = """(sel) => { const m = document.querySelector(sel); if (!m) return null;
47
+ const r = m.getBoundingClientRect();
48
+ const items = m.querySelectorAll('[role=menuitem],[class*=row],[class*=item_]').length;
49
+ const mid = document.elementFromPoint(r.right - 40, r.top + 16);
50
+ return { left: Math.round(r.left), right: Math.round(r.right), h: Math.round(r.height), items: items,
51
+ ok: r.left >= -0.5 && r.right <= window.innerWidth + 0.5,
52
+ topRightHit: mid ? String(mid.className || '').split(' ').pop().slice(0, 22) : null,
53
+ hamburger: (document.getElementById('dsh-mobile-menu-btn') || {}).style ? document.getElementById('dsh-mobile-menu-btn').style.display : '?' }; }"""
54
+
46
55
  DRAWER = """() => { const s = document.querySelector('[class*=sidebarCol]');
47
56
  return s ? (getComputedStyle(s).display + ':' + Math.round(s.getBoundingClientRect().width)) : 'none'; }"""
48
57
 
@@ -139,6 +148,29 @@ def run(args) -> int:
139
148
  if seq != [1, 0, 1, 0]:
140
149
  fails.append(f"点击无法临时开合:{seq}(期望 [1,0,1,0])")
141
150
 
151
+ # ③b 顶部 popover 不许出视口(2026-09-14 用户报「点后台任务/终端/session 日志显示不全」:
152
+ # 上游按桌面宽度做左/右对齐 —— 后台任务菜单 right 溢出 207px、「更多操作」菜单 left 溢出 90px)
153
+ for name, trig_sel, menu_sel in (
154
+ ("后台任务菜单", "button[class*=QsffPG_trigger]", "[class*=QsffPG_menu]"),
155
+ ("更多操作菜单", "button[class*=nL4_yW_moreButton]", "[role=menu][class*=_list_1nxmc_]"),
156
+ ):
157
+ pos = page.evaluate(
158
+ """(s) => { const b = document.querySelector(s); if (!b) return null;
159
+ const r = b.getBoundingClientRect(); return [r.x + r.width / 2, r.y + r.height / 2]; }""", trig_sel)
160
+ if not pos:
161
+ print(f" [{name}] 入口不存在,跳过")
162
+ continue
163
+ page.touchscreen.tap(pos[0], pos[1])
164
+ page.wait_for_timeout(1500)
165
+ g = page.evaluate(POPOVER, menu_sel)
166
+ print(f" [{name}] {json.dumps(g, ensure_ascii=False)}")
167
+ if not g or not g.get("ok"):
168
+ fails.append(f"{name}跑出视口({g})—— 上游对齐按桌面宽度算,插件的浮层约束失效?")
169
+ elif g.get("items", 0) < 1:
170
+ fails.append(f"{name}打开后没有任何条目({g})")
171
+ page.keyboard.press("Escape")
172
+ page.wait_for_timeout(800)
173
+
142
174
  # ④ 菜单行可进入子代理(面包屑应变成两段)
143
175
  page.touchscreen.tap(sw["x"], sw["y"])
144
176
  page.wait_for_timeout(800)