# dsh-mobile-android **Repository Path**: yuan-junqian/dsh-mobile-android ## Basic Information - **Project Name**: dsh-mobile-android - **Description**: DSH 掌上通 · 用手机遥控电脑上的 DeepSeek Harness(Android 原生客户端 + PC 插件) - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2026-10-06 - **Last Updated**: 2026-10-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # DSH 掌上通(DSH Mobile for Android) 用手机遥控电脑上的 **DeepSeek Harness**。原生 Android 客户端,界面按豆包 / Trae 这类对话产品做: 会话列表 → 气泡对话 → 实时流式输出 → 内联审批 / 提问卡片。 [English](README.en.md) | **简体中文**

对话页 会话抽屉 我的设备

> 左起:**对话页**(玻璃气泡 + 目标卡 + 权限 / 模型 / 思考胶囊)、**会话抽屉**、**我的设备**。 > 界面为**液态玻璃**质感(折射 / 磨砂两档可切)。截图为内置演示页,**不含任何真实数据**。 --- ## 装它(约 3 分钟) ### ① 电脑:装 PC 插件 在电脑上执行(需要 PowerShell 7 / `pwsh`): ```powershell git clone https://github.com/James-Xue6/dsh-mobile-android.git cd dsh-mobile-android pwsh -File .\pc-plugin\install.ps1 ``` 脚本会:把插件复制到 `~/.dsh/local-plugins/`、把 APK 放进插件目录、在 DSH profile 里登记依赖与 bundle。 **只装这一个插件就够了** —— 协议层已**内置**在本插件里(net/,源自 MIT 许可的 dsh-plugin-mobile-gateway), 由插件自己挂载,不需要再装第二个插件。 > 用 SSH 的话,第一条命令换成 `git clone git@github.com:James-Xue6/dsh-mobile-android.git`。 ### ①′ 装完重启一次 DSH 就好(不再需要跑第二遍) ```powershell # 装完重启 DSH 桌面版即可: # · v2.0.0 起协议层已内置在插件里(net),不再依赖第三方包, # 也就不存在「补丁要等网关先装好」的问题; # · 装的时候会打印一段 [验收],六行都要是 OK。 ``` `[验收]` 长这样(任何一行是「缺失」都说明插件目录没复制全,重跑一次 `install.ps1` 即可): ``` [验收] 单插件整合是否到位 OK 内置协议层(net/index.mjs) OK Connection Peer 已并入 net 基线 OK adapter 全部出口透传 peer OK client 是合并版(含面板 + 手机接入) OK profile 不再依赖第三方网关包 OK cordis.patch.yml 里没有 mobile-gateway 行 整合完成:一个插件、一条补丁行、协议层内置。 ``` > 从 v1.x 升级过来的人:脚本会自动摘掉旧的 `dsh-plugin-mobile-gateway` 依赖与 > `cordis.patch.yml` 里的 `mobile-gateway` 行,插件列表随之从两个变成一个。 > `node_modules` 里遗留的旧网关目录已无引用,可以手动挪走。 ### ② 重启一次 DSH 桌面版 然后点左侧边栏底部的 **「移动设备」** 按钮 —— PC 端只有这一个入口。 ### ③ 手机:装 App 弹窗里第一屏就是「手机接入」卡片(一个居中的浮层,不再是右侧整栏),点 **「下载 App」**: 让**手机连同一个 WiFi** 扫弹出的二维码,直接下载安装(安装包由你这台电脑发出,局域网 8099 端口,不经网盘或 CDN)。 不方便扫码也可以直接从公开地址下载(**这两个链接永远指向最新版**): - CDN(国内通常更快):`https://cdn.jsdelivr.net/gh/James-Xue6/dsh-mobile-android@main/dist/dsh-mobile.apk` - GitHub:`https://github.com/James-Xue6/dsh-mobile-android/raw/main/dist/dsh-mobile.apk` > 想要固定版本就把 `@main` 换成 tag,例如 `@v0.87.3`。 > 当前最新版号可以读 `https://cdn.jsdelivr.net/gh/James-Xue6/dsh-mobile-android@main/dist/version.json`(`versionCode` 越大越新)。 > 每次发版脚本都会刷新 `@main` 的 CDN 缓存,所以上面两条**不会滞后**。 ### ④ 扫码配对 在同一张卡片上点 **「生成内网二维码」**(在家用)或 **「生成公网二维码」**(出门用),用 App 扫它。 **内网地址与公网地址会一次填好**,之后在家用内网、出门自动切公网,都不用手输。 > 电脑端的协议层是**随插件内置**的(net/,MIT,见 THIRD-PARTY-NOTICES.md): > 宿主侧的 ctx.plugin 把它作为子插件挂载 —— 插件列表里只有 dsh-mobile-access 一个。 ### ⑤ 更新(已经装过的怎么升) **手机 App** —— 打开就会提示新版本(启动时查一次,**6 小时内只查一次**); 没弹就去 **设置 → 关于 → 检查更新** 手动点一次。装完**不用重新扫码、不用重新配对**。 **电脑端插件** —— 拉一下仓库再重跑安装脚本,然后重启一次 DSH: ```powershell cd dsh-mobile-android git pull pwsh -File .\pc-plugin\install.ps1 ``` > 为什么必须重跑:这些补丁改的是第三方网关包的 `lib/*.mjs`(在 `node_modules` 里), > **网关升级/重装会把它们覆盖掉**。脚本幂等,重复跑没有副作用 —— > 它会自动重放全部 4 个网关补丁:跨会话提醒 / hello 带公网地址 / 地址变化广播 / 通用文件附件。 --- ## 怎么用 1. **选会话** —— 打开 App 就是会话列表(按工作区分组),点一个进去,或新建。 - 右下角 **+** = 在**默认/当前**工作区新建任务; - 每个工作区分组标题右侧的 **⋯** = 弹出该工作区菜单,选「在此工作区新建任务」, 新会话就会建在**这个**工作区里(与电脑版一致)。 2. **发消息** —— 直接输入发送。助手回复流式逐字出现,工具调用折叠成一行工具条。 3. **回答它** —— 需要你决定时会出现卡片: - **审批卡**:`批准一次` / `拒绝`; - **提问卡**:选项(可多选)+ 自定义输入; - **交付物卡**:点一下把文件下载到手机,长按复制路径。 4. 会话顶部显示当前**目标**与**任务清单**;右下角 `↓` 一键回到最新消息。 --- ## 出问题了 **手机连不上电脑** - 确认手机与电脑在同一个 WiFi;电脑端「移动设备」弹窗里,点「手机接入」卡片下方的 **「高级设置」** 能看到网关三态与「常驻开启」按钮(也可以走 设置 → 手机接入,同一套控件)。 - App 右上角 ⚙ →「当前状态」:看 `state / gen / ws` 与最近 40 条收发帧,能直接看出卡在哪一步。 - 提示「公网地址可能已失效」:公网隧道是临时域名,**电脑每次重启都会变**,重新扫一次二维码即可。 **扫码扫不出 / 点扫码相机一闪而过** - 给 App 相机权限(系统设置 → 应用 → DSH 掌上通 → 权限)。 - 也可以点「复制配对串」,在 App 里手动粘贴。 **重启 DSH 后找不到「移动设备」按钮** - 插件装完必须**重启一次 DSH 桌面版**才生效。 - 还不行就确认本插件目录里带着协议层:~/.dsh/local-plugins/dsh-mobile-access/net/index.mjs 存在。 **覆盖安装报「应用未安装」** - 说明签名和旧版不一致。只能用原来的签名密钥库(`%USERPROFILE%\.dsh-mobile-keys\dshmobile.jks`)重新打包; 该文件丢了就只能先卸载再重装。**请离线备份这个 .jks。** **想固定公网地址(不想每次重启都重新扫码)** - 手机与电脑加入同一个 Tailscale 网络,App 里填 `ws://100.x.x.x:3091/ws/mobile` (App 已把 `100.64/10` 与 `*.ts.net` 视为内网,不受明文限制、也不暴露公网)。 - 或者把域名的 NS 迁到 Cloudflare,建命名隧道(Named Tunnel)后用本机管理接口写入配置: `POST http://127.0.0.1:/mgw/cloudflare`,body `{ "mode": "named", "hostname": "gateway.example.com", "token": "", "enabled": true }`。 写好后公网地址固定为 `wss:///ws/mobile`,重启不变。 > 面板里的命名隧道输入框已按需求移除(旧「高级设置」整块删掉);需要固定域名时用上面的接口,或让我把这两个输入框挪进 设置 → 手机接入。 --- ## 开发者 | 想做什么 | 命令 | |---|---| | 构建 APK | `pwsh -File .\build.ps1` | | 跑网络层端到端测试 | `pwsh -File .\harness\build.ps1`,再 `node tools\run-e2e.mjs` | | 逐档判定分析 | `node tools\e2e-assert.mjs` | | 模拟器 + 装机(验 UI) | `tools\启动模拟器并装机.bat` | | 发版 | `pwsh -File .\release.ps1 -Version 0.5 -Notes "改了什么"` | - **构建依赖**:JDK 21 + Android SDK(`build-tools;36.0.0` 与 `platforms;android-36`)。 源码路径**不能含中文**(原生工具在 936 代码页打不开非 ASCII 路径),脚本会自动暂存到 `C:\dshstage` 再构建。 - **签名**:固定密钥库 `%USERPROFILE%\.dsh-mobile-keys\dshmobile.jks`; 口令走环境变量 `DSH_KS_PASS` 或仓库根目录的 `keystore.local.ps1`(已 gitignore,**绝不入库**)。 - **更新提醒**:App 启动时从 `@main` 拉 `dist/version.json` 比对版本;发版脚本会一并刷新它。 - 测试脚手架的用法与踩坑见 [tools/使用说明.md](tools/使用说明.md); PC 插件细节见 [pc-plugin/dsh-mobile-access/README.md](pc-plugin/dsh-mobile-access/README.md)。 ### 目录 ``` dsh-mobile-android/ ├── AndroidManifest.xml ├── build.ps1 / release.ps1 # 免 Gradle 构建 / 一键发版 ├── dist/ # 分发的 APK、校验值与更新清单 ├── libs/core-3.5.3.jar # zxing 扫码,纯 Java 无 native ├── res/ # 主题 / 图标 / 网络策略 ├── src/com/dsh/mobile/ # App:MainActivity + model/ + net/ + ui/ ├── harness/ # JVM 联调:复用 App 真实 net 层源码 ├── pc-plugin/ # PC 端「手机接入」插件 + 安装脚本 └── tools/ # 假网关、e2e 脚本、模拟器装机 ``` ### 架构 App 只实现 `dsh-mobile-v1` 协议(WebSocket + JSON),不碰 DSH 内部; 协议层**内置**在本仓库的 `pc-plugin/dsh-mobile-access/net/`(源自 MIT 的 dsh-plugin-mobile-gateway 0.9.0 + fork 补丁),`pc-plugin/` 另含接入编排与界面。 安装面只有 `dsh-mobile-access` 一个包:它声明依赖网关,并在自己的 `cordis.patch.yml` 里挂载网关的行。 ``` Android App ──ws/wss──> dsh-mobile-access(内置协议层 net)──> DSH Host (desktop profile) ``` --- ## 下一步计划 见 [NEXT-UPDATE.md](NEXT-UPDATE.md):网关补丁工程化(P0)、大文件 `uploadStream` 分块、markdown 表格渲染、交付物落点规则、跨会话提醒的最终方案等。 ## 更新日志 > 从 `v0.87.0` 起另有独立的 [CHANGELOG.md](CHANGELOG.md)(按版本逐条记录,含 `versionCode`); > 下面是按时间倒序的完整记录。 ### v0.87.3(已发布 · 2026-10-17) **修「升级后每次启动还提示装旧包」(用户点名)** - 现象:装到 0.87.2 后,之前下载的 0.87.1 包**每次开 App 都弹「立即安装」**。 - 根因:回前台自检拿**文件名**跟当前版本比;升级成功后旧包名永远 ≠ 当前版本,去重变量又只在进程内有效。 - 现在按 **APK 里真实的 `versionCode`**(`PackageManager.getPackageArchiveInfo`,与文件名无关)分类: - **≤ 当前版本**(旧包 / 已经装上的那个)⇒ 直接删除,不再提示; - **比当前新** ⇒ 只保留**最新**那个,其余更新的包也删; - 读不出信息(下了一半 / 解析失败)⇒ **不删**,避免误删正在下载的包。 - 安装完成后进程重启会再自检一遍,把装过的包一并清掉(Android 没有可靠的"安装成功"回调)。 ### v0.87.2(已发布 · 2026-10-17) **修更新链路两个真机 bug(用户实测)** - **点「去设置」跳进扫码取景页**:设备页把弹窗按钮**无条件**转给宿主,而宿主只认本页自有菜单 (`add` / `delete:`),其余一律按「扫码添加」处理 ⇒ 更新授权确认框的「去设置」被当成"扫码添加"。 改为与抽屉/设置页/对话页同一条纪律:先收起,再按 `onListPick` 分派。 - **「关于」里查到新版本却毫无提示**:更新弹窗原来**写死弹到对话页**,人在设置页/设备页时没人渲染它。 改走 `glassInScreenList()`,按**当前界面**路由。 - **授权后自动续装**:从「允许安装未知应用」页回到 App 自动拉起安装器,不用再找一遍「检查更新」。 ### v0.87.1(已发布 · 2026-10-17) **合并共创者 PR !1(7 个提交,fast-forward)** - **抽屉父子层级修复**:宿主 `session.list` 出网字段是 `parentId`,App 一直读 `parentSessionId` ⇒ 恒空 ⇒ 抽屉里每条会话都被当顶层、全平铺。现在两个名字都读。 - **工作区层可折叠**:分组表头常驻,点一下收起/展开名下会话;默认折叠,只有**当前会话所在工作区**自动展开; 显式展开/折叠两套账本落盘,与「子会话折叠」互不影响。 - **思维链一键开关**:对话页状态胶囊行新增「收起/展开思考过程」,复用既有显示模式(完整 ⇄ 简洁), 不新增第二套机制;并修 `ThinkingCard/ToolCard` 的 `remember` 缺 key(不带 key 时全局切换对已在屏上的卡片无效)。 - **思考链默认收起**(显示模式默认 compact,带一次性迁移键,老装机也生效)。 ### v0.87.0(已发布 · 2026-10-12) - 弹窗**全面玻璃化并归位到各自界面**(模型 / 权限 / 生成物 / 任务 / 更新链路 / 配对 / 重命名 / 输入框菜单); - 修更新链路**版本号不前进导致的永久更新循环**; - 修返回键关不掉弹窗、抽屉弹窗层级、待发送菜单与表单叠在一起; - 输入框改为平台控件(长按可用系统粘贴 / 全选); - 移除临时诊断埋点。 ### v0.86.10(开发中,未发布) **修「生成物」面板(用户点名)** - 旧版(v0.86.9)点开是**整个会话工作目录**,还能翻上一级、进文件夹。用户反馈: 「生成物点开这个目录内容有问题,不要显示这么多,就显示这次项目生成的这个输出文件即可, 怎么还能点上一页啥的,这些不要了」 - 现在**只列本会话产出的文件**:数据来自 `deliverables/presented` 事件(App 里本来就有), **打开即出、不用等网络**(不再有「正在读取…」);**目录下钻 / 「← 返回上级」/ 面包屑全部删除** - 顺带删掉旧方案的 `ui/ArtifactSheet.java`(无调用点、且依赖旧的目录型模型) **新增「用量」面板(用户点名)** - 底部 chip 行的「用量」原来是**弹个 Toast**,而且读的字段是错的 —— 它取 `tokenUsage.totals.inputTokens` 和 `contextPressure.surfaceTokens`,**这两个字段在真实回帧里根本不存在**, 所以「累计输入」恒显示 0 - 现在点开是**完整数据面板**(公式与电脑端**同源**,抄自 DSH 客户端 StatsPills): ``` 合计 265.0M tok 缓存命中 99% 未缓存输入 2.9M tok 缓存读取 261.7M tok 输出 474.0k tok ──────────────────── 上下文占用 228.6k / 1.0M(23%) 轮数 · 步数 29 轮 · 510 步 解码速率 267 tok/s 耗时 模型 1h23m · 工具 2m27s ``` - 数据源改用 `session-stats`(比 `context-usage` 多一份 `sessionStats`,也就是 PC 端底部那条统计) - 公式:`billedInput = uncachedInputTokens + cacheReadTokens + cacheWriteTokens`、 `total = billedInput + outputTokens`、`缓存命中 = cacheReadTokens / billedInput` —— 用真实数字反验过:`2,599,058 + 233,278,208 + 436,079 = 236,313,345`、命中 99%,与电脑端逐位一致 **修「进会话自动弹权限面板」(用户点名)** - 用户反馈:「每次点开任务都会自动弹出权限选择,这个不用这样吧,我手动改不就行了」 - 根因:进/切会话时会**静默**拉一次权限给 chip 打底,而 `onPermissionOptions()` 末尾 **无条件**弹面板 ⇒ 那次静默回帧也把面板弹了出来 - 现在只有**点了 chip** 才弹;静默那次只刷 chip 文案就返回(连"没有可选项"的 Toast 也不再弹) ### v0.86.9(已发布) **四项优化(用户点名)** - **生成物窗口**:底部 chip 行新增「生成物」——列本会话工作目录(`file-list`),可下钻目录 / 返回上级 (**注:v0.86.10 已按用户要求改成「只列本次产出文件、去掉目录浏览」**), 点文件下载到手机(进度原地更新),完成后尝试 `ACTION_VIEW` 打开 - **加号 → 文件 / 相册 / 拍照**:选中的东西**先暂存在输入框上方**(缩略图 / 文件名 / ×), 与文字或语音**一起发送**,不再"选完立即发" - **修「消息文本点一次不能立即选范围」**:单击即整段选中 + 选区手柄 + 系统「复制/分享」工具条 (`setSelection` 后合成一次长按手势触发 ActionMode);选字期间列表刷新让路(**封顶 4s**,不冻结流式输出) - **权限 chip**:chip 行新增「权限」,对齐电脑端 permission presets (`read-only` / `workspace-write` / `danger-full-access`),当前值高亮、可切换 **新增:通用文件附件(PDF / Office / 压缩包)** - 电脑端网关补丁 `pc-plugin/patches/patch-gateway-file-upload.ps1`:`message` 帧新增 `files[]`, 经宿主 `fileUploads` 换 receiptId,拼进 prompt content 的 `{type:'file',receiptId}` - 网关会在 `hello.capabilities` 宣告 **`file-uploads`**;客户端按能力门决定"发 / 明确提示暂不支持" (**不盲发** —— 未打补丁的网关会静默忽略 `files[]`,文件会悄悄丢掉) **修掉的真 bug(都是端到端实测才暴露的)** - **`clientTimeZone` 非 IANA 名会让整条消息被网关拒绝**(`must be UTC or a valid IANA Area/Location name`): 部分 ROM / 模拟器给的是 `GMT`、`GMT+08:00`,而 App 已清空输入框 → **用户以为发出去了,其实一条都没发**。 现在只在匹配 `Area/Location` 时才带该字段;4 个发送路径统一 - **发送被网关拒绝后附件被清掉** → 改为失败回填(附件放回待发送) - `permission-options` 的当前值字段是 **`sessionPermissions.currentValue`**(原实现漏了 → 会显示错误的当前权限) - `TextView` **没有** `setSelection(int,int)`(改用 `android.text.Selection`) - 权限 chip 文案前缀重复(`权限 · 权限 完全访问`) - `harness/build.ps1` 原先**编不过当前 `src/`**(垫片缺 `Context` / `Log` / `Notifier`) **验证** - 四项 + 文件附件全部在 Android 模拟器上**实测通过**(证据 `evidence/ui-4features-manual/`、`evidence/t9-file-upload/`) - 协议层一键回归:`pwsh -File harness/run-protocol-v2-test.ps1`(**10/10**) - 设备一到位就能一键验收:`pwsh -File tools/verify-4features.ps1` **PC 端(`pc-plugin`)** - **`install.ps1` 现在会重放全部 4 个网关协议补丁**(跨会话提醒 / hello 带公网地址 / 地址变化广播 / 通用文件附件)。以前它**只跑面板补丁**,其余几个都是手工打的 ⇒ **只活在 `node_modules`**, 网关升级/重装就静默失效(手机表现为:收不到跨会话提醒、出门连不上、发不了文件) - 新增 `pc-plugin/patches/patch-gateway-crosssession.ps1` —— 此前**仓库里根本没有这个脚本**, 改动只在线上。内容:放宽两道 waterfall 门 + 跨会话下发带 `global: true`; 回退用**反向替换**(不靠备份还原,避免把后来那几个补丁一起抹掉) - 插件版本 `1.0.2` → `1.0.3` **已知未覆盖** - 大文件未压测(单文件上限 24MB / 合计 48MB);更大的要走 `uploadStream` 分块(未实现) - 网关补丁改的是 `node_modules`,**网关升级/重装后需重跑 `install.ps1`**(启动自检尚未做,见 `NEXT-UPDATE.md` P0) ### v0.86.4 **通知(本轮主线)** - 修 **跨会话/后台收不到通知**:网关插件新增 `hasAnyInteractionClient()`,放宽提问/审批的两道 waterfall 门 (原门按会话作用域过滤:手机订阅会话 A 时,会话 B 的提问**不建档、不生成帧、连日志都不打**) - 修 **前台服务断线即自杀**:`KeepAliveService.sync()` 去掉 `Notifier.isConnected()` 判据,断线期间保持常驻 - 修 **无界面时帧被静默丢弃**:`GatewayClient` 新增进程级 `bgInteractionHook`,`listener==null` 时仍弹提醒 - 通知渠道 `dsh_pending` → **`dsh_pending_v2`(HIGH)**;新增独立 `dsh_service` 渠道保护后台保活 - 通知失败可诊断:`lastPostError`/`lastPostAt` + 设置页三行自查 + **渠道级深链** - 通知 id 槽位 200 → 4000;`approvalKey/questionKey` 收成唯一实现(去重与深链一致) **卡片与输入** - 修 **卡片灰框**:`Ui.CardBg` 自绘渐变在长卡片上整片压暗约 26%(设计色只在最外侧露 ~8px) → 提问/审批卡改用框架 `Ui.cardGrad()`(对角渐变 + 圆角 + 描边) - 修 **卡片底部按钮不可达**:按钮移出滚动区,常驻卡片底部 - 修 **卡片内部滚动位置每次刷新归零**:`ChatItem.cardScrollY` 跨重绑保留 - 修 **提问卡内输入框草稿丢失**:TextWatcher 边打边写回 `it.typed` - 修 **点输入框后卡片乱滚/输入框看不见**:内容区高度改固定值(不再跟随键盘),键盘弹起时**只最小幅度滚外层列表** - 新增 `MaxHeightEditText` / `MaxHeightScrollView` / `MaxHeightLinearLayout` - 底部渐隐改为跟随悬浮层实测高度(原固定 132dp);顶部**无卡时不显示** **已知未验证 / 环境限制** - V2「界面被系统销毁后仍弹通知」、V3 手机侧「断网重连补发」:本机荣耀不销毁 Activity,造不出验证条件 (V3 网关侧已验证:`interaction replay … questions=1`) - V1 渠道:荣耀会把 App 申请的 HIGH 降为 DEFAULT,**需用户手动把「需要处理」设为横幅** ### v0.85(开发中,未发布) **新增** - 顶部「待处理交互」提示栏:别的会话有待回答的提问/审批时露出,点它切过去 **修复** - **提问/审批卡「切过去闪一下就消失」**:切会话重订阅时 `session-snapshot` 整体重建列表 (`items.clear()`),而提问/审批卡是本地实时建的、不在服务端历史里 → 被冲掉。 现改为重建时**保留未处理的交互卡**(真机验证:切过去卡片稳定显示且可作答 ✓) - 跨会话提醒的第二条连接改为**后台线程建连 + 周期重连**,并把状态做进 App 内诊断 **已知未解决** - 第二条连接在**公网隧道**下握手无法完成(`[control 通道]` 停在"已发起连接(等握手)", 网关侧无第二条 `client connected`)→ 跨会话提醒在公网下仍不可用;需在**内网直连**下复验 ### v0.85 **修复** - 目标卡「点标题行没反应 / 永远只占一节」:展开状态被计划刷新重置(planExpanded 优先) - 目标卡「灰底 + 一圈黑框」:改纯色圆角底 + 去阴影、移除会覆盖底色的按压换底 - 顶部渐隐:**没有目标卡时不显示**(原先会把首行文字挡住),高度 132dp -> 64dp - 历史翻页:重连导致的 `session-snapshot` 不再重置分页(保留 hasMore / nextBeforeSeq) - 带图片消息的文字被挤成竖排单字一列(用户气泡外层应为竖排) - 排队修改内容「点了保存没反应」(网关强制要求 action=edit,协议文档漏写) - 助手消息图片不显示(卡片补渲染 + 助手回合补收集附件) **新增** - 目标卡改为**顶部浮动层**:与输入框同侧边距、点开就地向下展开、顶部渐隐与底部对称 - 任务项状态渲染(完成=打钩+删除线置灰 / 进行中=旋转指示 / 待办=空心圈) - 跨会话提醒:周期重连以获取"连接建立时的全量不限会话重放",走**系统通知栏** - 设置页「当前状态」新增 `[control 通道]` `[全局视图]` `[最近一次队列操作]` `[事件流]` 诊断 **已知未完成** - 任务项渲染缺真实数据验证(宿主对本会话的 tasks 查询返回 todos:null) - 助手消息里的 markdown 表格未渲染(按纯文本显示) - 第二条 WS 连接握手建不起来(14s 超时)——跨会话即时推送改走重连方案 ### v0.84 **修复** - **提问/审批卡「切过去闪一下就消失」**(用户实测报出):切会话会重订阅 → 网关重放提问(卡片出现) → 紧接着 `session-snapshot` 整体重建列表(`items.clear()`),而提问/审批卡是**本地实时建的、 不在服务端历史里** → 被这次替换冲掉。现改为重建时**保留未处理的交互卡**。 真机验证:切过去后卡片稳定显示且可作答 ✓ - 跨会话提醒:第二条连接改为**不带 `X-DSH-Channel` 且永不 subscribe**(协议:不订阅 = 接收所有会话), 绕开该自定义头被 Cloudflare 隧道剥掉的问题;顶部新增**待处理提示栏**,点它切到对应会话 ### v0.83 **修复(重要)** - **修改排队内容「点了保存没反应」**:根因是网关**强制要求 `action` 字段** (`queue-update` 必须是 `itemId` + `action ∈ edit/remove/steer`),而协议文档里「改文本」的 例子漏写了该字段 —— 照文档实现会被静默拒绝。现在改文本显式发 `action:"edit"`。 真机验证:`待发送 · EDIT-A` → 点修改 → 改 `EDIT-B` → 保存 → 条上变为 `EDIT-B`, 网关侧出现 `query ok: queue-update` ✓ - **带图片的消息不再显示成一大串文字**:助手/子智能体卡片原先完全不渲染图片,且助手回合 从不收集附件 id —— 两边都已补上 - 编辑弹窗被键盘挡住「保存 / 取消」 - 排队内容显示成 JSON 原文(`content` 是内容块数组,需按块解析) **新增** - 设置页「当前状态」新增 `[control 通道]`、`[最近一次队列操作]` 诊断 ### v0.82 **修复** - **带图片的消息不再显示成一大串文字**:助手/子智能体卡片原先完全不渲染图片(只有用户气泡会画), 且助手回合从不收集附件 id —— 现已两边都补上 - 修改排队内容「点了保存没反应」:补上 30 秒入站帧门禁(半开连接时明确提示并自动重连,不再静默丢帧) - 编辑弹窗被键盘挡住「保存 / 取消」按钮 - 排队内容显示成 JSON 原文(content 是内容块数组,需按块解析) **新增** - 设置页「当前状态」新增 `[control 通道]` 与 `[最近一次队列操作]` 诊断 ### v0.81 **新增** - 底部可横滑 chip 行:**项目 / 模型 / 思考 / 用量 / 任务** - 模型:列出全部模型及思考档位,选中即切换(对齐豆包) - 思考:Off / Low / High / Max 可选 - 用量:上下文占用百分比,点开看 token 明细 - 任务:展开该会话的任务列表(只读) - 项目:选工作区并直接在新工作区开对话 - 回合运行中也能发送:排队,输入框上方显示「待发送」条;每条可**立即插入 / 修改 / 删除** - 设置页「当前状态」新增事件流诊断(便于自查连接与消息接收) **修复** - 修改排队内容时显示一堆 JSON 字符(content 是内容块数组,被当成原文显示) - 修改排队「点了保存没反应」:半开连接静默丢帧 → 现在明确提示并自动重连 - 编辑弹窗被键盘挡住「保存 / 取消」按钮 - 模型名显示不更新(进会话与回合结束都会重新拉取) - 「N 子智能体」入口遮挡「回到底部」按钮 - 底部弹窗滑动后底色丢失(看起来像"一滑动就变色") ## 许可 见 [LICENSE](LICENSE)。一句话:**公开源码供学习与群内使用,但不是 OSI 自由软件**—— 商用、对外二次分发、改名换皮发布需要事先取得作者书面许可。 提交 Issue / Pull Request 参与改进是欢迎的。 ## 一起维护 想一起改这个项目?看 **[CONTRIBUTING.md](CONTRIBUTING.md)**——面向不熟 git 的人写的, 全是"点哪里",三条路任选(加协作者 / Fork + Pull Request / 直接发给我)。