dsh-mobile-layout
DeepSeek Harness Web UI 移动端体验套件:让 dsh web 在手机上好看、好用。
零依赖,装上即用;关闭皮肤即完全还原 stock 外观。
0.9.1 起适配 dsh 0.1.5:文件浏览已由 0.1.5 内置能力(右侧边栏「文件」
标签 + 文档预览)接管,本插件不再自带文件浏览器。下载与上传能力保留,
以「下载到设备」/「上传」按钮挂接到内置文件面板上。0.9.7 起下载只保留
预览头一个入口(文件树行的下载按钮已移除);0.9.8 修正下载路径来源
(改用预览根的 contentId,杜绝下载到错文件),目录行上传按钮改为只在
文件夹展开时出现并锚定到行元素;0.9.9 预览头新增「复制路径」按钮
(与下载同源)、下载请求的 sessionId 优先取 contentId 所属会话(跨会话
预览加固)。0.9.10 修正 Android 下载:0.9.9 曾让移动端走「导航式下载」,
被 Android 厂商下载管理器(XiaoMi/MIUI)接管后脱离页面上下文重发请求、
不带会话 Cookie → 401;现移动端与桌面统一走 XHR + blob(带会话
Cookie、有真实进度),文件名改从响应头 Content-Disposition 解析
(RFC5987 中文保真)。上传的工具栏入口不变:目录行上传到该目录、工具栏
上传到工作区 upload/。同时修复手机视口下内置面板在玻璃/半透明皮肤下的
透明问题。0.9.11 修正 Windows 路径:在此之前下载与
「上传到此目录」在 Windows 上一律 400(bad-path / bad-dir)——
宿主与客户端都用 POSIX 判据 startsWith("/") 认定「绝对路径」,而
Windows 工作区根是 C:\...;同时拼路径恒用 / 会得到 C:\ws/sub/f.txt
这类混用分隔符的非法路径。现改用 node:path.isAbsolute()(POSIX / 盘符 /
UNC 通吃)、按根的分隔符拼接,并在 win32 上按大小写折叠做包含性判定
(realpath 保留磁盘大小写,workspace 注册表里的路径大小写可能与磁盘
不一致)。macOS / Linux 行为不变。
功能一览
1. 移动端阅读布局(<1024px 自动生效)
banner
- 侧栏抽屉化:无常驻窄栏,会话区占满全宽;顶栏左上角鲸鱼按钮开合会话抽屉
- 字体密度:正文 / 标题 / 代码适度收缩,一屏容纳更多内容
- 表格:自然宽度 + 横向触摸滚动;长词、链接自动换行不再溢出
- 输入框:上滑阅读、切换已有会话或刷新恢复已有会话时默认收起(不会唤起手机输入法),点击消息文字即可显示并聚焦;空白新会话保持可见,桌面端不受影响
- 设置面板:导航横排适配手机宽度;模型编辑等长表单在内容区独立触摸滚动,底部操作不会被截断
2. 换肤(侧边栏「主题与背景」按钮)
banner
- 模式:无 / 玻璃 / 半透明,表面不透明度滑杆 0–100%
- 极光背景:四套预设——蓝紫 / 暖阳 / 青绿(浅色底)+ 单色·墨(深色底),
彩色光斑缓慢漂移 + 电影颗粒质感
- 自定义背景:图片 URL 或手机相册选图
- 文字对比度自动适配:按背景明暗自动切换应用的深/浅文字主题,文字始终清晰
- 透明化:用户气泡、代码块、滚动条滑杆随表面同源半透明,文字保持不透明
- 0.1.5 右侧边栏覆盖:玻璃/半透明模式同样覆盖新右栏列(
_rightbarCol),
内置文件面板保持磨砂可读,不会透出底层内容
3. 内置文件面板「复制路径 / 下载到设备」挂接(预览头单入口)
- 0.1.5 内置的右侧边栏「文件」标签负责浏览,点击文件由内置文档预览打开;
本插件用 MutationObserver 给文档预览头(与自带 reload 工具并排,顺序
[wrap] [复制路径] [下载到设备] [reload])注入两个工具按钮(data-dml-*
标记,样式与面板自带工具按钮一致)。0.9.7 起文件树行不再注入下载按钮,
下载只在预览头这一个出口。
- 复制路径(0.9.9 新增):手机上长按选中路径文本很不方便,点这个按钮
即把当前预览文件的绝对路径写进剪贴板(
navigator.clipboard.writeText,
非安全上下文/被拒绝时自动回退 textarea + execCommand('copy')),成功
短暂显示「已复制」。与下载按钮共用同一个路径解析结果,两者永不可能
指向不同文件;解析不出绝对路径时两个按钮都不显示。
- 下载走本插件保留的流式端点
GET /mobile-files/download,不受预览大小
上限影响,可下任意大小的二进制。0.9.10 起全端统一走 XHR + blob +
<a download>(请求带会话 Cookie、按钮内有真实百分比进度、完成/失败
走状态机复位)。0.9.9 曾让移动端改走「导航式下载」,但 Android 厂商下载
管理器(XiaoMi/MIUI)会接管导航、脱离页面上下文重发请求且不带会话
Cookie → 服务端 401(nginx 日志实测);故 0.9.10 移除该分支。文件名
取自响应头 Content-Disposition(RFC5987,非 ASCII 中文保真),经
getAllResponseHeaders() 大小写不敏感解析(规避厂商 WebView 对非标准
响应头的大小写敏感问题)。
- 路径来源(0.9.8 修正、0.9.9 加固):优先取预览根元素的
data-textpreview-url(= 该预览 tab 的 contentId,形如
dsh-resource://file/session/<id>/<path> 或 file/absolute/<abs>,即
「预览正在读的那个文件」),经与内置 parseFileAddress 同款规则解出路径,
按工作区根化为绝对路径;其次才回退预览头 title 的绝对值(展示字符串,
异步推导,不可作首选)。0.9.8 起定不出绝对路径时直接移除按钮,绝不
留一个会下错文件的旧按钮。
- sessionId 归属(0.9.9 加固):下载请求携带的 sessionId 优先取
contentId 里的所属会话(预览可能属于另一个会话,例如从聊天卡片打开),
回退当前会话——Host 在服务端按该会话重新解析工作区根并拒绝越界路径,
会话失效只会得到可见报错,绝不会静默下错文件
- 上传能力保留:工具栏「上传」按钮维持原语义——进
<workspace>/upload
(自动创建,不污染根目录)。0.9.8 起目录行上传按钮只在文件夹展开时
出现、并锚定到行元素([class*='_row'],position:relative)而非整个
li——li 还包住展开的子树,旧写法让展开文件夹的按钮飘到子树中间
(已按几何坐标实测复现)。仍走本插件端点 POST /mobile-files/upload:
名字强制单段、dir 必须 realpath 落在工作区内、重名自动 (n) 不覆盖、
默认 500 MB 上限
4. 稳定性增强
- 历史加载 abort 错误自动重试愈合(全端生效)
- 移动端从阅读态新建空白会话时强制恢复输入区,避免 body 级收起状态跨会话残留而只剩背景
安装
dsh plugin --profile <name> add github:crwsr124/dsh-mobile-layout
# 或本地源码: dsh plugin --profile <name> add file:<本目录绝对路径>
首次安装后重启一次 dsh web 进程(host 半的下载路由是冷路径;改 host 半
代码后同样需要重启)。client 半(布局/皮肤/下载按钮)随新页面热生效。
下载无需配置目录:根目录自动取当前会话所属的已注册工作区,无任何可选配置项。
Host 根据 sessionId 从服务端 Workspace 注册表解析 canonical path;浏览器传入的绝对路径只能位于该根内(含符号链接逃逸拒绝)。
作用范围
- 仅移动端(媒体查询门控):阅读布局、输入框滚动收起、Session log 隐藏、
设置面板移动端布局
- 跨端功能(有意为之):换肤、内置文件面板下载/上传挂接、abort 自愈
- 平台:POSIX 与 Windows 同等支持(0.9.11 起)。路径校验用
node:path.isAbsolute(),容器判定在 win32 上大小写折叠;C:\...、C:/...
与 UNC \\server\share 均可作为 path / dir 传入
- 皮肤关闭 / 卸载插件 = 完全还原 stock 外观
已知限制
- 会话轨迹(details)列在手机上无法打开(app shell 框架限制,CSS 无法干预)
- 下载/上传路由无内置认证——公网部署务必保持 nginx basic auth 等外部防护
- 0.8.x 的
/mobile-files/list|read 已从代码移除(/download 保留、
/upload 于 0.9.1 恢复);已运行的 dsh web 进程在重启前仍会挂载旧版
四动作路由面(冷路径),属预期过渡态
- 老内核浏览器:无毛玻璃模糊(透明与背景仍生效,面板内有支持诊断)
开发与设计细节
实现原理、兼容性处理、选择器约定与版本历史见 docs/DESIGN.md。
License
MIT