@artenx/dshb 0.1.27 → 0.1.29

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.
@@ -11,7 +11,6 @@ input,textarea,select,[contenteditable="true"]{font-size:16px!important}
11
11
  [class*="_line_1gdtu_"]{min-width:max-content!important;overflow-x:visible!important;max-height:999999px!important}
12
12
  [class*="_copyButton_1gdtu_"]{position:sticky!important;right:0}
13
13
  [class*="7KE1Ra_modelName"],[class*="7KE1Ra_description"],[class*="modelName"]{white-space:normal!important;overflow-wrap:break-word;text-overflow:clip!important;overflow:visible!important}
14
- [class*="7KE1Ra_menu"],[class*="_menu"]:has([class*="modelName"]){left:0!important;right:auto!important;width:calc(100vw - 32px)!important;min-width:0!important;max-width:calc(100vw - 32px)!important}
15
14
  [class*="_copyButton_"]{touch-action:manipulation!important}
16
15
  [class*="_copyAnchor_"],[class*="_body_1ye18_"],[class*="_root_4qrvp_"]{touch-action:pan-x pan-y!important}
17
16
  [class*="_root_4qrvp_1"]{width:100%!important;min-width:0!important;overflow-x:auto!important}
@@ -1 +1 @@
1
- {"version":3,"file":"loopback-compat.js","names":[],"sources":["../../src/auth/loopback-compat.ts"],"sourcesContent":["const MOBILE_CSS = `\n<style id=\"dshb-mobile-fix\">\n@media (max-width:1023px),(display-mode:standalone){\nhtml{-webkit-text-size-adjust:100%!important;text-size-adjust:100%!important}\ninput,textarea,select,[contenteditable=\"true\"]{font-size:16px!important}\n[class*=\"_command_1gdtu_\"]{min-width:max-content!important;max-width:none!important;overflow:visible!important;white-space:pre!important;text-overflow:clip!important;max-height:999999px!important}\n[class*=\"_prompt_1gdtu_\"],[class*=\"_promptLine_1gdtu_\"]{min-width:max-content!important;max-height:999999px!important}\n[class*=\"_header_1gdtu_\"]{min-width:0!important;max-width:100%!important;overflow-x:auto!important;overscroll-behavior-x:contain;touch-action:pan-x pan-y!important}\n[class*=\"_output_1gdtu_\"]{overflow-x:auto!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;touch-action:pan-x pan-y!important}\n[class*=\"_line_1gdtu_\"]{min-width:max-content!important;overflow-x:visible!important;max-height:999999px!important}\n[class*=\"_copyButton_1gdtu_\"]{position:sticky!important;right:0}\n[class*=\"7KE1Ra_modelName\"],[class*=\"7KE1Ra_description\"],[class*=\"modelName\"]{white-space:normal!important;overflow-wrap:break-word;text-overflow:clip!important;overflow:visible!important}\n[class*=\"7KE1Ra_menu\"],[class*=\"_menu\"]:has([class*=\"modelName\"]){left:0!important;right:auto!important;width:calc(100vw - 32px)!important;min-width:0!important;max-width:calc(100vw - 32px)!important}\n[class*=\"_copyButton_\"]{touch-action:manipulation!important}\n[class*=\"_copyAnchor_\"],[class*=\"_body_1ye18_\"],[class*=\"_root_4qrvp_\"]{touch-action:pan-x pan-y!important}\n[class*=\"_root_4qrvp_1\"]{width:100%!important;min-width:0!important;overflow-x:auto!important}\n[class*=\"_container_4qrvp_\"]{width:auto!important;min-width:100%!important;max-width:none!important}\n[class*=\"_expandedTopLevel_4qrvp_\"]{width:auto!important;min-width:100%!important;max-width:none!important}\n[class*=\"_body_biesw_\"],[class*=\"_body_srovd_\"],[class*=\"_body_s66q0_\"]{overflow-x:auto!important;-webkit-overflow-scrolling:touch}\n[class*=\"_line_biesw_\"],[class*=\"_line_srovd_\"],[class*=\"_line_s66q0_\"]{min-width:max-content!important}\n[class*=\"_block_1gdtu_\"]{padding-left:0!important;overflow-x:auto!important}\n}\n</style>`\n\nexport function loopbackCompatScript(): string {\n return `<script>\n;(function () {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID !== 'function' && typeof crypto.getRandomValues === 'function') {\n crypto.randomUUID = function () {\n var b = crypto.getRandomValues(new Uint8Array(16))\n b[6] = (b[6] & 0x0f) | 0x40\n b[8] = (b[8] & 0x3f) | 0x80\n var h = ''\n for (var i = 0; i < 16; i++) {\n if (i === 4 || i === 6 || i === 8 || i === 10) h += '-'\n var hex = b[i].toString(16)\n if (hex.length < 2) hex = '0' + hex\n h += hex\n }\n return h\n }\n }\n function installIsLoopbackOverride() {\n var loader = window.__ModuleLoader__\n if (!loader || loader.__dshbIsLoopbackHooked) return false\n if (loader.mode !== 'live') return false\n loader.__dshbIsLoopbackHooked = true\n var origLoad = loader.load.bind(loader)\n loader.load = function (handoff) {\n var factory = handoff && handoff.factory\n if (typeof factory === 'function') {\n handoff.factory = function (require) {\n var exports = factory(require)\n var apply = exports && exports.apply\n if (typeof apply === 'function') {\n exports.apply = function (ctx) {\n var result = apply(ctx)\n try {\n var connection = ctx && ctx.get && ctx.get('connection')\n if (connection) {\n Object.defineProperty(connection, 'isLoopback', { configurable: true, get: function () { return true } })\n }\n } catch (e) {}\n return result\n }\n }\n return exports\n }\n }\n return origLoad(handoff)\n }\n return true\n }\n function tryInstall() { if (!installIsLoopbackOverride()) setTimeout(tryInstall, 0) }\n tryInstall()\n})()\n;(async function () {\n try {\n var res = await fetch('/api/auth/status')\n var data = await res.json()\n if (window.location.pathname !== '/login' && !data.authenticated) {\n window.location.replace('/login')\n return\n }\n } catch (e) {}\n})()\n</script>`\n}\n\nexport function installLoopbackCompat(html: string): string {\n return html.replace('</head>', `${MOBILE_CSS}${loopbackCompatScript()}</head>`)\n}\n"],"mappings":";AAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;AAwBnB,SAAgB,uBAA+B;CAC7C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DT;AAEA,SAAgB,sBAAsB,MAAsB;CAC1D,OAAO,KAAK,QAAQ,WAAW,GAAG,aAAa,qBAAqB,EAAE,QAAQ;AAChF"}
1
+ {"version":3,"file":"loopback-compat.js","names":[],"sources":["../../src/auth/loopback-compat.ts"],"sourcesContent":["const MOBILE_CSS = `\n<style id=\"dshb-mobile-fix\">\n@media (max-width:1023px),(display-mode:standalone){\nhtml{-webkit-text-size-adjust:100%!important;text-size-adjust:100%!important}\ninput,textarea,select,[contenteditable=\"true\"]{font-size:16px!important}\n[class*=\"_command_1gdtu_\"]{min-width:max-content!important;max-width:none!important;overflow:visible!important;white-space:pre!important;text-overflow:clip!important;max-height:999999px!important}\n[class*=\"_prompt_1gdtu_\"],[class*=\"_promptLine_1gdtu_\"]{min-width:max-content!important;max-height:999999px!important}\n[class*=\"_header_1gdtu_\"]{min-width:0!important;max-width:100%!important;overflow-x:auto!important;overscroll-behavior-x:contain;touch-action:pan-x pan-y!important}\n[class*=\"_output_1gdtu_\"]{overflow-x:auto!important;overflow-y:auto!important;-webkit-overflow-scrolling:touch;touch-action:pan-x pan-y!important}\n[class*=\"_line_1gdtu_\"]{min-width:max-content!important;overflow-x:visible!important;max-height:999999px!important}\n[class*=\"_copyButton_1gdtu_\"]{position:sticky!important;right:0}\n[class*=\"7KE1Ra_modelName\"],[class*=\"7KE1Ra_description\"],[class*=\"modelName\"]{white-space:normal!important;overflow-wrap:break-word;text-overflow:clip!important;overflow:visible!important}\n[class*=\"_copyButton_\"]{touch-action:manipulation!important}\n[class*=\"_copyAnchor_\"],[class*=\"_body_1ye18_\"],[class*=\"_root_4qrvp_\"]{touch-action:pan-x pan-y!important}\n[class*=\"_root_4qrvp_1\"]{width:100%!important;min-width:0!important;overflow-x:auto!important}\n[class*=\"_container_4qrvp_\"]{width:auto!important;min-width:100%!important;max-width:none!important}\n[class*=\"_expandedTopLevel_4qrvp_\"]{width:auto!important;min-width:100%!important;max-width:none!important}\n[class*=\"_body_biesw_\"],[class*=\"_body_srovd_\"],[class*=\"_body_s66q0_\"]{overflow-x:auto!important;-webkit-overflow-scrolling:touch}\n[class*=\"_line_biesw_\"],[class*=\"_line_srovd_\"],[class*=\"_line_s66q0_\"]{min-width:max-content!important}\n[class*=\"_block_1gdtu_\"]{padding-left:0!important;overflow-x:auto!important}\n}\n</style>`\n\nexport function loopbackCompatScript(): string {\n return `<script>\n;(function () {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID !== 'function' && typeof crypto.getRandomValues === 'function') {\n crypto.randomUUID = function () {\n var b = crypto.getRandomValues(new Uint8Array(16))\n b[6] = (b[6] & 0x0f) | 0x40\n b[8] = (b[8] & 0x3f) | 0x80\n var h = ''\n for (var i = 0; i < 16; i++) {\n if (i === 4 || i === 6 || i === 8 || i === 10) h += '-'\n var hex = b[i].toString(16)\n if (hex.length < 2) hex = '0' + hex\n h += hex\n }\n return h\n }\n }\n function installIsLoopbackOverride() {\n var loader = window.__ModuleLoader__\n if (!loader || loader.__dshbIsLoopbackHooked) return false\n if (loader.mode !== 'live') return false\n loader.__dshbIsLoopbackHooked = true\n var origLoad = loader.load.bind(loader)\n loader.load = function (handoff) {\n var factory = handoff && handoff.factory\n if (typeof factory === 'function') {\n handoff.factory = function (require) {\n var exports = factory(require)\n var apply = exports && exports.apply\n if (typeof apply === 'function') {\n exports.apply = function (ctx) {\n var result = apply(ctx)\n try {\n var connection = ctx && ctx.get && ctx.get('connection')\n if (connection) {\n Object.defineProperty(connection, 'isLoopback', { configurable: true, get: function () { return true } })\n }\n } catch (e) {}\n return result\n }\n }\n return exports\n }\n }\n return origLoad(handoff)\n }\n return true\n }\n function tryInstall() { if (!installIsLoopbackOverride()) setTimeout(tryInstall, 0) }\n tryInstall()\n})()\n;(async function () {\n try {\n var res = await fetch('/api/auth/status')\n var data = await res.json()\n if (window.location.pathname !== '/login' && !data.authenticated) {\n window.location.replace('/login')\n return\n }\n } catch (e) {}\n})()\n</script>`\n}\n\nexport function installLoopbackCompat(html: string): string {\n return html.replace('</head>', `${MOBILE_CSS}${loopbackCompatScript()}</head>`)\n}\n"],"mappings":";AAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;AAuBnB,SAAgB,uBAA+B;CAC7C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8DT;AAEA,SAAgB,sBAAsB,MAAsB;CAC1D,OAAO,KAAK,QAAQ,WAAW,GAAG,aAAa,qBAAqB,EAAE,QAAQ;AAChF"}
package/lib/client.js CHANGED
@@ -1158,19 +1158,8 @@ window.__ModuleLoader__.load({
1158
1158
  overflow: visible !important;
1159
1159
  }
1160
1160
 
1161
- /* 模型选择器弹窗:JS(installModelMenuPosition)在窄屏下改为 position:fixed
1162
- 视口级浮层(fixed 不受祖先 overflow 裁剪),这里仅做静态兜底(JS 未生效时
1163
- 仍从触发按钮左缘向右展开、宽度收进视口)。 */
1164
- [class*="7KE1Ra_menu"],
1165
- [class*="_menu"]:has([class*="modelName"]) {
1166
- left: 0 !important;
1167
- right: auto !important;
1168
- width: calc(100vw - 32px) !important;
1169
- min-width: 0 !important;
1170
- max-width: calc(100vw - 32px) !important;
1171
- overflow-y: auto !important;
1172
- max-height: calc(100vh - 120px) !important;
1173
- }
1161
+ /* 菜单定位完全交还上游(0.2.1-rc.2 起菜单 position:fixed 且自带视口钳制;
1162
+ 此前插件的 left/width !important 兜底会覆盖上游 place() 的计算结果)。 */
1174
1163
 
1175
1164
  /* 工具调用执行结果/代码/JSON:窄屏可横向滑动。details 抽屉宽 min(92%,420px)
1176
1165
  较窄,命令行输出/JSON 长行溢出被外层 overflow:hidden 裁剪看不到。命令行输出
@@ -1595,69 +1584,11 @@ window.__ModuleLoader__.load({
1595
1584
  };
1596
1585
  }, "dshb-mobile: stats line");
1597
1586
  }
1598
- /** 浮层 fixed 定位需管理的内联样式键,清理时逐一移除以交还上游 CSS。 */
1599
- const SHEET_PROPS = [
1600
- "position",
1601
- "width",
1602
- "left",
1603
- "right",
1604
- "top",
1605
- "bottom",
1606
- "min-width",
1607
- "max-width",
1608
- "max-height",
1609
- "overflow-y",
1610
- "box-sizing"
1611
- ];
1612
1587
  /** 幂等写入 important 内联样式:值未变化时跳过,避免 MutationObserver(attributes) 自触发循环。 */
1613
1588
  function setImportantIfChanged(el, prop, value) {
1614
1589
  if (el.style.getPropertyValue(prop) === value && el.style.getPropertyPriority(prop) === "important") return;
1615
1590
  el.style.setProperty(prop, value, "important");
1616
1591
  }
1617
- /** 当前视口下的可视区域(手机键盘弹出时 visualViewport 与布局视口错位)。 */
1618
- function visibleViewport() {
1619
- const vv = window.visualViewport;
1620
- if (vv) return {
1621
- vw: vv.width,
1622
- vh: vv.offsetTop + vv.height,
1623
- top: vv.offsetTop
1624
- };
1625
- return {
1626
- vw: window.innerWidth,
1627
- vh: window.innerHeight,
1628
- top: 0
1629
- };
1630
- }
1631
- /** Keep the model menu anchored to its trigger while fitting it in the viewport. */
1632
- function positionAnchoredMenu(el, triggerRect, maxWidth, maxHeight) {
1633
- const margin = 8;
1634
- const { vw, vh } = visibleViewport();
1635
- setImportantIfChanged(el, "position", "fixed");
1636
- setImportantIfChanged(el, "box-sizing", "border-box");
1637
- setImportantIfChanged(el, "left", "0");
1638
- setImportantIfChanged(el, "right", "auto");
1639
- setImportantIfChanged(el, "top", "0");
1640
- setImportantIfChanged(el, "bottom", "auto");
1641
- setImportantIfChanged(el, "min-width", "0");
1642
- setImportantIfChanged(el, "max-width", `${Math.max(0, Math.min(maxWidth, vw - 16))}px`);
1643
- setImportantIfChanged(el, "max-height", `${Math.max(0, Math.min(maxHeight, vh - 16))}px`);
1644
- setImportantIfChanged(el, "overflow-y", "auto");
1645
- let width = el.offsetWidth;
1646
- let height = el.offsetHeight;
1647
- const { top: viewportTop } = visibleViewport();
1648
- const spaceAbove = Math.max(0, triggerRect.top - viewportTop - 16);
1649
- const spaceBelow = Math.max(0, vh - triggerRect.bottom - 16);
1650
- const expandUp = height <= spaceAbove || spaceAbove >= spaceBelow;
1651
- const available = expandUp ? spaceAbove : spaceBelow;
1652
- if (height > available) {
1653
- setImportantIfChanged(el, "max-height", `${Math.max(0, available - margin)}px`);
1654
- height = el.offsetHeight;
1655
- width = el.offsetWidth;
1656
- }
1657
- const top = expandUp ? triggerRect.top - margin - height : triggerRect.bottom + margin;
1658
- setImportantIfChanged(el, "left", `${Math.max(margin, Math.min(triggerRect.right - width, vw - width - margin))}px`);
1659
- setImportantIfChanged(el, "top", `${Math.max(viewportTop + margin, Math.min(top, vh - height - margin))}px`);
1660
- }
1661
1592
  /**
1662
1593
  * 模型名多为纯连字符词(DeepSeek-V4-Flash-Vision-Exp);white-space:normal 下
1663
1594
  * 每个 "-" 都是软断点,名字一旦超列宽就在第一个连字符处断行("换行太早")。
@@ -1709,18 +1640,13 @@ window.__ModuleLoader__.load({
1709
1640
  n.style.removeProperty("font-size");
1710
1641
  }
1711
1642
  }
1712
- /** 清除 anchored menu 写入的内联样式,交还上游 CSS。 */
1713
- function clearFixedSheet(el) {
1714
- if (el === null || el === void 0) return;
1715
- for (const key of SHEET_PROPS) el.style.removeProperty(key);
1716
- }
1717
1643
  /**
1718
- * 模型选择弹窗(dsh-client-ui-model-selection)是两级 pane 的同一个 `_7KE1Ra_menu`
1719
- * 元素:一级 Model/Effort 单元格列表(cellLabel),点击后切到模型列表(modelName)
1720
- * 或档位列表。上游默认 `position:absolute;right:0` 贴触发按钮右缘,触发按钮在
1721
- * 可横向滚动的 stats 行内时菜单会整体出屏。两级 pane 都必须接管(不能只按
1722
- * modelName 匹配,否则一级 pane 漏掉)。所有视口都把菜单锚定到触发按钮,
1723
- * 在上方/下方可用空间中选择更合适的一侧,避免上游空间不足时把菜单钳到屏幕顶端。
1644
+ * 模型选择弹窗(dsh-client-ui-model-selection):上游 0.2.1-rc.2 起菜单已是
1645
+ * `position:fixed` 并自带 place() 视口钳制定位(portal 到 body,ResizeObserver
1646
+ * 跟随尺寸变化)。插件不再接管定位——此前写入的 fixed/left/top 与上游 menuPos
1647
+ * 内联样式互相拉扯;且对自动聚焦搜索框的 blur 拦截会触发上游 onBlur 的
1648
+ * close()(焦点移出菜单即关闭),手机上表现为菜单刚打开就被关掉("弹不出来")。
1649
+ * 这里只保留窄屏下的视觉适配:模型名不换行连字符 + 按最宽名字缩放字号。
1724
1650
  */
1725
1651
  function installModelMenuPosition(ctx) {
1726
1652
  ctx.effect(() => {
@@ -1734,45 +1660,27 @@ window.__ModuleLoader__.load({
1734
1660
  fallbackLast = now;
1735
1661
  return Array.from(document.querySelectorAll("[class*=\"_menu\"]")).filter((el) => el.querySelector("[class*=\"cellLabel\"], [class*=\"modelName\"]") !== null);
1736
1662
  };
1737
- const findTrigger = (menu) => {
1738
- if (menu.id) {
1739
- const controlled = Array.from(document.querySelectorAll("[aria-controls]")).find((el) => el.getAttribute("aria-controls") === menu.id);
1740
- if (controlled) return controlled;
1741
- }
1742
- return document.querySelector("[class*=\"7KE1Ra_trigger\"][aria-expanded=\"true\"]");
1743
- };
1744
1663
  let fittedVw = 0;
1745
1664
  let fittedSig = -1;
1746
1665
  let fittedMenus = [];
1747
- let positionedMenus = [];
1748
1666
  const sync = () => {
1749
- const menus = findMenus();
1750
1667
  let vw = 0;
1751
1668
  let sig = 0;
1752
1669
  const modelMenus = [];
1753
- const visibleMenus = [];
1754
- for (const menu of menus) {
1755
- const trigger = findTrigger(menu);
1756
- if (trigger === null || trigger.getAttribute("aria-expanded") !== "true") continue;
1757
- const rect = menu.getBoundingClientRect();
1758
- if (rect.width === 0 && rect.height === 0) continue;
1759
- positionAnchoredMenu(menu, trigger.getBoundingClientRect(), Math.min(420, window.innerWidth - 16), 360);
1760
- visibleMenus.push(menu);
1761
- if (menu.querySelector("[class*=\"modelName\"]")) {
1762
- modelMenus.push(menu);
1763
- if (narrow.matches) {
1764
- applyNonBreakingHyphens(menu);
1765
- vw = window.innerWidth;
1766
- for (const n of menu.querySelectorAll("[class*=\"modelName\"]")) sig += n.textContent?.length ?? 0;
1767
- }
1670
+ for (const menu of findMenus()) {
1671
+ if (!menu.querySelector("[class*=\"modelName\"]")) continue;
1672
+ if (menu.getBoundingClientRect().width === 0) continue;
1673
+ modelMenus.push(menu);
1674
+ if (narrow.matches) {
1675
+ applyNonBreakingHyphens(menu);
1676
+ vw = window.innerWidth;
1677
+ for (const n of menu.querySelectorAll("[class*=\"modelName\"]")) sig += n.textContent?.length ?? 0;
1768
1678
  }
1769
1679
  }
1770
- for (const previous of positionedMenus) {
1771
- if (visibleMenus.includes(previous)) continue;
1772
- clearFixedSheet(previous);
1680
+ for (const previous of fittedMenus) {
1681
+ if (modelMenus.includes(previous)) continue;
1773
1682
  clearModelNameFit(previous);
1774
1683
  }
1775
- positionedMenus = visibleMenus;
1776
1684
  if (!narrow.matches) {
1777
1685
  for (const menu of modelMenus) clearModelNameFit(menu);
1778
1686
  fittedVw = 0;
@@ -1792,42 +1700,14 @@ window.__ModuleLoader__.load({
1792
1700
  const mo = new MutationObserver(() => requestAnimationFrame(sync));
1793
1701
  mo.observe(document.documentElement, {
1794
1702
  childList: true,
1795
- subtree: true,
1796
- attributes: true,
1797
- attributeFilter: ["style"]
1703
+ subtree: true
1798
1704
  });
1799
1705
  narrow.addEventListener("change", sync);
1800
1706
  window.addEventListener("resize", sync);
1801
- window.addEventListener("scroll", sync, true);
1802
- window.visualViewport?.addEventListener("resize", sync);
1803
- window.visualViewport?.addEventListener("scroll", sync);
1804
- let lastPointerTarget = null;
1805
- const keyboardLikelyOpen = () => {
1806
- const vv = window.visualViewport;
1807
- if (!vv) return false;
1808
- return window.innerHeight - vv.height > 150;
1809
- };
1810
- const onPointerDown = (event) => {
1811
- lastPointerTarget = event.target instanceof Element ? event.target : null;
1812
- };
1813
- const onFocusIn = (event) => {
1814
- if (!narrow.matches || !(event.target instanceof Element) || keyboardLikelyOpen()) return;
1815
- const input = event.target.closest("input");
1816
- if (!input || input.closest("[class*=\"7KE1Ra_menu\"], [class*=\"_menu\"]") === null) return;
1817
- if (lastPointerTarget !== null && (lastPointerTarget === input || input.contains(lastPointerTarget))) return;
1818
- input.blur();
1819
- };
1820
- document.addEventListener("pointerdown", onPointerDown, true);
1821
- document.addEventListener("focusin", onFocusIn, true);
1822
1707
  return () => {
1823
1708
  mo.disconnect();
1824
1709
  narrow.removeEventListener("change", sync);
1825
1710
  window.removeEventListener("resize", sync);
1826
- window.removeEventListener("scroll", sync, true);
1827
- window.visualViewport?.removeEventListener("resize", sync);
1828
- window.visualViewport?.removeEventListener("scroll", sync);
1829
- document.removeEventListener("pointerdown", onPointerDown, true);
1830
- document.removeEventListener("focusin", onFocusIn, true);
1831
1711
  };
1832
1712
  }, "dshb-mobile: model menu position");
1833
1713
  }
@@ -4734,10 +4614,6 @@ window.__ModuleLoader__.load({
4734
4614
  position:fixed 经 portal 渲染。子代理很多时 flex 压缩 node(flex-shrink:1 默认),
4735
4615
  文字挤压且不触发滚动。给 node flex-shrink:0 让 menu 整体 overflow:auto 滚动。 */
4736
4616
  [class*="_menu"] [class*="_node"] { flex-shrink: 0 !important; }
4737
- /* 模型选择弹窗(dsh-client-ui-model-selection):Ra_menu 上游 max-width 420px,
4738
- 长模型名单行放不下被 ellipsis 截断。放宽到 720px 让模型名单行完整显示。
4739
- [class*="Ra_menu"] 精确匹配模型弹窗,避免误伤其他菜单。Ra_ 为 hash,上游升级需同步。 */
4740
- [class*="Ra_menu"] { max-width: 720px !important; width: auto !important; }
4741
4617
  /* 终端组件(dsh-web-frontend,CSS 模块前缀 1gdtu_)桌面端修复:上游 _command_ 默认
4742
4618
  overflow:hidden+text-overflow:ellipsis,LLM 调 bash 的长命令在桌面端被省略号
4743
4619
  截断、看不到完整内容(输出区 _output_ 本就可横向滚动,唯命令区不行)。宽屏与