dsh-mobile:DSH 远程访问插件
手机在局域网或任意网络(Tailscale)访问本机 dsh web 并完整交互, 窄屏(<720px)呈现 DeepSeek App 式布局;桌面端(127.0.0.1)零变化。
形态:out-of-tree bundle(符合 DSH 插件规范)
本仓库是一个 DSH bundle 插件包(dsh.bundle.patch 清单),经官方插件通道安装, 不做任何全局安装/源码手术:
dsh-mobile/
package.json "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
cordis.patch.yml 禁用上游 web-startup/connection 行 + insert 本插件两行
src/web-startup.mjs WEB_STARTUP_SERVICE 同面实现: --host 0.0.0.0 解锁 +
随机/固定 --pair-pin
src/connection.mjs /api 传输 fork + PIN 配对门(非 loopback 必须配对,
限速 5 次/分, 特权方法仍锁本机) + 启动公告行
patches/ harness 源码补丁(移动端 UI 与 PWA, 供 UI 构建)
legacy/ v1 补丁包工具(apply/revert/build-frontend/stage,
当前线上部署仍由它维护; 迁移完成后可删除)安装与启动
# 1. 安装进 web profile(官方通道, 追加在 web-app bundle 之后)
dsh plugin --profile web add /绝对路径/dsh-mobile # 或 file:/路径
# 自升级: dsh plugin --profile web add <新版路径或 git URL> 重装即可
# 2. 启动(与往常一致)
dsh web --host 0.0.0.0 # 终端打印:
# dsh-mobile: pairing PIN for non-local clients: 483920 (LAN: http://192.168.0.108:3080, …)
# 3. 手机连同一 Wi-Fi 打开 http://192.168.0.108:3080 -> 输 PIN 配对
# 本机 127.0.0.1 不需要 PIN; 固定 PIN: --pair-pin 483920- 卸载/停用:
dsh plugin --profile web remove dsh-mobile(回到上游纯本机行为)。 - bundle 安装在 profile 目录(
$DSH_HOME/profiles/web),与全局 dsh 升级互不干扰;
上游升级后重跑一次 dsh plugin add 即可对齐版本。
- 首次监听 0.0.0.0 时 macOS 防火墙若弹窗,允许 node 入站。
安全模型
Host 围栏(上游,防 DNS rebinding/跨站)只判「来源是不是可信地址」,不判人; PIN 配对补上「这个设备是不是被授权」。PIN 与配对 token 仅存内存,服务重启后 终端打印新 PIN,手机需重新配对。settings/credentials 等特权方法对远程设备仍 403。
验证矩阵(已实测):loopback 免配对;LAN 未配对 401 + WWW-Authenticate: DSH-Pair; 错 PIN 限速 5 次/分(429 + Retry-After);正确 PIN 发 HttpOnly/SameSite=Strict Cookie;WS 升级同受门禁;跨站 403。
外网访问(Tailscale)
Mac 与手机装 Tailscale 登录同一账号,保持 --host 0.0.0.0 启动(覆盖 Tailscale 接口),手机用 http://<本机 100.x IP>:3080 访问。MagicDNS 域名访问需追加 --trusted-host <机器名>.<tailnet>.ts.net; 直接用 100.x IP 无需额外参数。
移动端 UI(已并入 bundle)
移动端 UI 已客户端插件化:禁用上游 ui-layout 行 + insert 本包双面行 (唯一 root 注册者, 重新声明 sidebar/conversation/details/shell.overlay, 自带 layout store 与主题投影; 顶栏/抽屉/全屏工具面板/配对页 <720px 生效, 桌面布局与上游一致)。PWA 外壳由宿主半身 src/host.mjs 提供(tapIndex + manifest/图标精确路由)。构建:node build-ui.mjs(在一次性基线克隆内全量 构建, 产出 client.js)。
已知问题(不影响核心功能):首次页面加载时 Cordis inventory 面板会报两行 console 错误(remote.dynamicCordisRunner.inventory is not a function), 刷新一次即恢复正常。成因:替换 connection 行后本包位于名单末尾, api-remotes 的异步挂载与 ui-cordis 的应用在首载并行(上游靠行序掩蔽的时序), 刷新后挂载先完成。会话/聊天/工具调用不受影响。
本机部署状态(2026-08-14)
- 真实 web profile(
~/.dsh/profiles/web):bundle 已装入(手链
node_modules/dsh-mobile + dsh.profile.bundles 追加, 保留 llm-balance 等 自有插件)。
- 全局安装:
legacy/revert.mjs已还原为纯净 rc.6(v1 手术全部撤销)。 - 重启
dsh web后生效(当前运行实例仍为旧内存代码)。
版本适配
- bundle 经 profile 安装(手链或
dsh plugin add),升级/重装重跑即可,不碰全局安装。 src/connection.mjs是上游client-connection宿主面的 fork(~750 行),
vendor/dsh-mobile 是 ui-layout + connection 客户端半身的 fork;上游变更时 对照重基线。自动化检测(轮询新版本 + CI 校验)待建。