@artenx/dshb 0.1.28 → 0.1.30

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
@@ -1641,16 +1641,57 @@ window.__ModuleLoader__.load({
1641
1641
  }
1642
1642
  }
1643
1643
  /**
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
- * 这里只保留窄屏下的视觉适配:模型名不换行连字符 + 按最宽名字缩放字号。
1644
+ * 模型选择弹窗(dsh-client-ui-model-selection):定位完全交还上游的 fixed + place()。
1645
+ * 第二层模型列表含自动聚焦的搜索框;窄屏下以 inputmode=none 阻止自动唤起虚拟键盘,
1646
+ * 用户主动点搜索框时切回 search。保持焦点有效,避免 blur 触发上游关闭菜单。
1647
+ * 同时保留模型名的窄屏视觉适配。
1650
1648
  */
1651
- function installModelMenuPosition(ctx) {
1649
+ function installModelMenuBehavior(ctx) {
1652
1650
  ctx.effect(() => {
1653
1651
  const narrow = window.matchMedia(NARROW_QUERY);
1652
+ const manualKeyboardInputs = /* @__PURE__ */ new WeakSet();
1653
+ const isModelSearchInput = (target) => {
1654
+ if (!(target instanceof HTMLInputElement) || target.getAttribute("role") !== "searchbox") return false;
1655
+ const menu = target.closest("[class*=\"_menu\"]");
1656
+ return menu !== null && menu.querySelector("[class*=\"modelName\"]") !== null;
1657
+ };
1658
+ const setAutoKeyboardMode = (input) => {
1659
+ if (narrow.matches && isModelSearchInput(input) && !manualKeyboardInputs.has(input)) input.inputMode = "none";
1660
+ };
1661
+ const prepareSearchInputs = (node) => {
1662
+ if (!narrow.matches) return;
1663
+ if (node instanceof HTMLInputElement) setAutoKeyboardMode(node);
1664
+ else if (node instanceof Element) for (const input of node.querySelectorAll("input[role=\"searchbox\"]")) setAutoKeyboardMode(input);
1665
+ };
1666
+ const onSearchFocus = (event) => {
1667
+ const input = event.target;
1668
+ if (input instanceof HTMLInputElement) setAutoKeyboardMode(input);
1669
+ };
1670
+ const onSearchPointerDown = (event) => {
1671
+ const input = event.target;
1672
+ if (!narrow.matches || !isModelSearchInput(input)) return;
1673
+ manualKeyboardInputs.add(input);
1674
+ input.inputMode = "search";
1675
+ };
1676
+ const onSearchBlur = (event) => {
1677
+ const input = event.target;
1678
+ if (!isModelSearchInput(input)) return;
1679
+ manualKeyboardInputs.delete(input);
1680
+ if (narrow.matches) input.inputMode = "none";
1681
+ else input.removeAttribute("inputmode");
1682
+ };
1683
+ const restoreSearchInputs = () => {
1684
+ for (const input of document.querySelectorAll("input[role=\"searchbox\"]")) if (isModelSearchInput(input)) input.removeAttribute("inputmode");
1685
+ };
1686
+ const onNarrowChange = () => {
1687
+ if (narrow.matches) prepareSearchInputs(document.documentElement);
1688
+ else restoreSearchInputs();
1689
+ sync();
1690
+ };
1691
+ document.addEventListener("focus", onSearchFocus, true);
1692
+ document.addEventListener("pointerdown", onSearchPointerDown, true);
1693
+ document.addEventListener("blur", onSearchBlur, true);
1694
+ prepareSearchInputs(document.documentElement);
1654
1695
  let fallbackLast = 0;
1655
1696
  const findMenus = () => {
1656
1697
  const byHash = Array.from(document.querySelectorAll("[class*=\"7KE1Ra_menu\"]"));
@@ -1697,19 +1738,26 @@ window.__ModuleLoader__.load({
1697
1738
  }
1698
1739
  };
1699
1740
  sync();
1700
- const mo = new MutationObserver(() => requestAnimationFrame(sync));
1741
+ const mo = new MutationObserver((records) => {
1742
+ for (const record of records) for (const node of record.addedNodes) prepareSearchInputs(node);
1743
+ requestAnimationFrame(sync);
1744
+ });
1701
1745
  mo.observe(document.documentElement, {
1702
1746
  childList: true,
1703
1747
  subtree: true
1704
1748
  });
1705
- narrow.addEventListener("change", sync);
1749
+ narrow.addEventListener("change", onNarrowChange);
1706
1750
  window.addEventListener("resize", sync);
1707
1751
  return () => {
1708
1752
  mo.disconnect();
1709
- narrow.removeEventListener("change", sync);
1753
+ document.removeEventListener("focus", onSearchFocus, true);
1754
+ document.removeEventListener("pointerdown", onSearchPointerDown, true);
1755
+ document.removeEventListener("blur", onSearchBlur, true);
1756
+ narrow.removeEventListener("change", onNarrowChange);
1710
1757
  window.removeEventListener("resize", sync);
1758
+ restoreSearchInputs();
1711
1759
  };
1712
- }, "dshb-mobile: model menu position");
1760
+ }, "dshb-mobile: model menu behavior");
1713
1761
  }
1714
1762
  /**
1715
1763
  * 上下文用量弹窗(ContextMeter .JObwrW_panel,dsh-client-ui-conversation)上游是
@@ -1908,7 +1956,7 @@ window.__ModuleLoader__.load({
1908
1956
  installViewport(ctx);
1909
1957
  installFrameMarker(ctx);
1910
1958
  installStatsLine(ctx);
1911
- installModelMenuPosition(ctx);
1959
+ installModelMenuBehavior(ctx);
1912
1960
  installContextPanelPosition(ctx);
1913
1961
  const layout = ctx.layout;
1914
1962
  const slots = ctx.slots;
@@ -4614,10 +4662,6 @@ window.__ModuleLoader__.load({
4614
4662
  position:fixed 经 portal 渲染。子代理很多时 flex 压缩 node(flex-shrink:1 默认),
4615
4663
  文字挤压且不触发滚动。给 node flex-shrink:0 让 menu 整体 overflow:auto 滚动。 */
4616
4664
  [class*="_menu"] [class*="_node"] { flex-shrink: 0 !important; }
4617
- /* 模型选择弹窗(dsh-client-ui-model-selection):Ra_menu 上游 max-width 420px,
4618
- 长模型名单行放不下被 ellipsis 截断。放宽到 720px 让模型名单行完整显示。
4619
- [class*="Ra_menu"] 精确匹配模型弹窗,避免误伤其他菜单。Ra_ 为 hash,上游升级需同步。 */
4620
- [class*="Ra_menu"] { max-width: 720px !important; width: auto !important; }
4621
4665
  /* 终端组件(dsh-web-frontend,CSS 模块前缀 1gdtu_)桌面端修复:上游 _command_ 默认
4622
4666
  overflow:hidden+text-overflow:ellipsis,LLM 调 bash 的长命令在桌面端被省略号
4623
4667
  截断、看不到完整内容(输出区 _output_ 本就可横向滚动,唯命令区不行)。宽屏与