移动端 Web UI 适配 (mobui)
以静态 Cordis 客户端插件方式为 DeepSeek Harness Web GUI 做移动端适配,不改动产品源码,从 profile 卸载即完整还原。
插件身份与状态
- 插件:
mobui-static(静态客户端插件,挂在 dsh profile 的 loader 层) - 当前版本: pkg-14(模型选择底部弹层 + Bash 命令横向滑动查看 + 320px 发送按钮防裁切 + 底部统计折叠 + 模型名单行紧凑 + 顶部单行紧凑头 + 工作模式/Details 底部左右布局)
- 历史: 前身为会话动态插件
mobui-1/mobui-2(进程重启即失);已静态化——随 profile 启动自动加载,重启不丢,不依赖会话 - 宿主半: 空实现(仅为 loader 激活 + client-modules 发现)
- 客户端半:
/plugins/mobui-static/client.js,经window.__ModuleLoader__注入页面
安装(一键)
./install.sh # 装入 web profile
DSH_PROFILE=demo ./install.sh # 装入其他 profile
脚本幂等,可重复执行。装完重启 profile 生效(web: 重启 web 进程)并刷新浏览器。
手动安装等价步骤(脚本做的事):
# 1) 从源码生成静态插件包(package.json + index.js + client.js)
node scripts/build-static.js mobui7-plugin-client.js ~/dsh-plugins/mobui-static
# 2) 装入 profile
dsh plugin --profile web add ~/dsh-plugins/mobui-static
# 3) 在 profile 的 cordis.patch.yml 挂载 loader 条目
- insert:
- id: mobui
name: 'mobui-static'
# 4) 重启 profile
功能(pkg-14)
移动端(max-width: 1023.98px)下:
- 左侧导航:侧栏整列 fixed 离屏成抽屉(320px),中列独占全宽;左上角 FAB(汉堡)触发抽屉;抽屉内点会话行自动关抽屉。
- 遮罩/捕捉层:根作用域(
shell.overlay插槽,idmobui7-fab/mobui7-scrim),点遮罩即关抽屉;会话与 hero 均可点。 - 设置/插件页全屏:修复 fixed 后代落入抽屉 transform 包含块被压窄的根因(侧栏列
transform:none+100vw,对话框position:fixed inset:0全屏,nav 变顶部横向滚动行);[data-cordis-panel]同陷阱一并修复(钉进抽屉盒内,实测 296px 完整内嵌)。 - 发送按钮保护:composer 行 tools 可缩、trailing 使用
flex:1 1 auto+nowrap,模型名单行省略,发送按钮flex:0 0 auto; min-width:34px在 320px 窄屏也不出视口;抽屉滞留遮挡发送的路径已被"选定会话即关抽屉"消除。 - Bash 卡片摘要:仅对
data-variant="bash"的卡片移除单行摘要省略号,摘要自动换行完整显示;Think/Tool call 等 disclosure 行保持产品原有折叠。 - 底部运行统计折叠:composer 底部统计默认收起,只保留一个
Details展开按钮,点击展开/收起,节省纵向空间。 - 顶部单行紧凑头:会话头改为单行(Session log + 对话/轨迹标签),不再占两行。
- 底部工作模式 + Details:工作模式固定在左下角、Details 展开按钮固定在右下角,底部预留独立空间;工作模式名称过长时省略,点击可展开完整名称。
- 模型选择底部弹层:移动端模型选择菜单固定为底部弹层,不再跑出屏幕外,可正常打开。
- Bash 命令横向滑动:Chat 展开的 Bash 终端与 Trajectory Bash 预览均改为单行 + 横向滚动,左右滑动即可查看完整命令,不再用省略号截断。
- composer 回车 = 换行(IME 合成回车不受影响),不提交。
- safe-area、
prefers-reduced-motion尊重、Toast 层级协议(内容 auto < 遮罩 29 < 抽屉 30 < 详情 31 < Toast 32)。
设计决策
- 表现层接管,而非替换 shipped 插槽占位者。 实时 Slot 树确认
root/sidebar/conversation/details均为replaceRisk: shadows-shipped-ui的单一占位者;替换它们会连带拆除其声明的全部子插槽。插件改为在@media (max-width: 1023.98px)下用全局样式表重排现有布局。 - *只依赖稳定的 `data-
钩子,不碰 CSS Modules 类名。** 构建产物中类名是哈希的(如.pI_x6G_frame),跨构建不稳定。插件锚定 AppFrame 写出的data-sidebar-collapsed/data-details-collapsed/data-shell-overlay/data-side属性与结构选择器(:has()+:nth-child),并对帧内联的grid-template-columns用!important` 覆盖。 - 状态由产品布局商店驱动。 抽屉开合不引入自有状态:rail 折叠开关 → 布局商店 → 帧属性 → CSS 呈现;点击捕捉层经
ctx.get('layout').toggleSidebar()写回同一商店。 - 层级协议(移动端): 中列内容(auto) < 遮罩/捕捉层(29) < 侧栏抽屉(30) < 详情抽屉(31) < Toast 浮层(32)。
运行时依赖
客户端半依赖宿主 shell 提供:
React(经 module loaderrequire('react'))- 客户端服务
layout(@deepseek-ai/dsh-client-ui-layout)与slots(@deepseek-ai/dsh-client-runtime)——已在dsh.client.inject声明
已知边界
- details 面板:视口 <996px 时被产品布局求解器强制关为 0 宽(纯 CSS 无法拦截);996–1023px 区间以右侧抽屉呈现。替换
details占位者受 chatStore 跨插件私有限制,<996px 的详情可用性属上游产品缺口。 - iOS 键盘顶起 / visualViewport、composer 触控目标放大等需 DOM 级 JS,当前静态客户端插件环境未覆盖。
- 回车拦截依赖
document全局:若插件运行环境屏蔽该全局,该功能静默失效(有 typeof 守卫,不会报错)。 - 点遮罩关闭依赖
layout服务的toggleSidebar();若产品未来改变该服务面,插件需同步更新。
工作区文件
mobui7-plugin-client.js— 单一事实源(CSS + 行为 + 插槽注册的完整客户端插件函数体)mobui7.css— 内嵌 CSS 的可读独立副本mobui7-page.js— 页面行为逻辑的可读独立副本(mobui7Install(api)抽象)scripts/build-static.js— 源码 → 静态插件包生成器install.sh— 一键安装(幂等)
历史调试脚本(probe-/sim-/verify-mobile.cjs)与截图(p7/p7b/s7/s8/shot-/sim-/v5-*.png)及上游克隆
repo/已清理;旧验证结论见 git 历史。