Repository navigation
Releases: T1gerD/open-whale
Release list
Open Whale v2.2.1
变更记录
本项目遵循 Keep a Changelog 与语义化版本。
[2.2.1] - 2026-10-26
修复 iOS / 网页版扫第二个二维码打不开的问题。
修复
- 网页版二维码按地址分开生成:v2.2.0 只渲染排序第一的地址,
auto模式下通常是
Tailscale 的100.x;没装/没连 Tailscale 的 iPhone 根本连不上,表现为「扫了打不开网页」。
现在局域网、Tailscale、公网隧道各生成一个二维码,局域网排最前,每张都标注线路。 - 二维码改为短链接并自动绑定:网页版二维码不再只是裸地址(之前扫码打开后还要手动粘贴
配对内容),也不再往二维码里塞整段载荷。现在编码
/openwhale/app?s=<一次性配对密钥>(约 90 个字符,iOS 相机一扫即中),网页端向同源
/openwhale/pairing.json兑换载荷并校验密钥一致后自动完成绑定。 - 配对页补充 iOS 提示:第一次访问局域网地址会询问「本地网络」权限,请选「允许」。
文档
docs/install.md增加「iPhone / 网页版连不上」排查:选局域网二维码、检查同一 Wi-Fi、
iOS 本地网络权限、Windows 防火墙放行(插件端口 8787)。- 版本号 2.2.1;安卓 versionCode 10、iOS buildNumber 2。
[2.2.0] - 2026-10-26
连接、协作与多端的整体升级。 修掉 9 个用户反馈的问题与缺陷清单里的 10 条,新增鸿蒙/iOS
可用的网页版客户端与 Tailscale 专属连接方式,并首次把插件发布到 npm。
新增
- Tailscale 成为独立连接方式:不再混在「局域网」里。插件与手机端都能显式选择
自动 / 局域网 / Tailscale / 公网隧道,自动的顺序是「上次成功 → Tailscale → 局域网 →
公网隧道」,不会再让公网隧道抢在直连前面。 - 网页版 / PWA 客户端(鸿蒙 NEXT、iOS、任意浏览器):插件在
/openwhale/app提供一套
零安装的网页客户端,用系统相机扫第二个二维码即可绑定;支持聊天、流式回复、附件、多端同步,
可「添加到主屏幕」。这是本轮鸿蒙适配的交付形态(RNOH 尚未支持 RN 0.86,详见
docs/iOS-HarmonyOS.md)。 - iOS 出包配置:
app.json补 iOS 段与权限文案,新增eas.json、GitHub Actions 的
iOS 模拟器构建工作流(未签名 .app,真机/TestFlight 需 Apple 账号)。 - 相册识图绑定:扫码页新增「相册识图」,选一张二维码截图即可绑定;原生识别失败时用纯 JS
解码兜底(华为等无 GMS 机型也能用)。 - 手动输入地址:不扫码也能填
host:port,先探测/openwhale/health再保存;已配对设备
可随时改地址。 - 分块上传:手机发附件改为 512 KiB 分块 + 背压 + 进度 + 断点重试,单附件上限 32 MiB →
64 MiB;上传落盘到会话工作目录内,修复「模型读不到手机发的图片」。 - 电脑 → 手机发文件:配对页新增「发送到手机」,选一个文件即可在手机聊天里收到下载卡片
(仅本机浏览器可操作)。 - 协作模式可见化:手机端可开关协作模式,聊天页显示在线参与者,多人消息带昵称与
chat/echo回显。 - 长按菜单:长按气泡可复制 / 重新发送 / 删除;长按代码块只复制代码。
- 手机端 UI 全面重做(WorkBuddy 风格的底部输入栏、状态胶囊、参与者头像条、深浅色、空态)。
修复
- 同一条消息被投递两次(AI 回复两遍):电脑端新增按
(设备, msgId)的幂等表,手机离线
队列的重发只会收到duplicateack,不再重复送入会话;bridge 层再加一道callId保护。 - 协作模式下回复文本重复拼接:助手消息改为按 DSH 的
messageId聚合并整条下发
(chat/message),不再按设备循环追加;一条回复只渲染一次。 - 多设备同会话不同步:新增
chat/echo广播、会话事件日志与游标追赶
(session/state/session/events)、在线成员(session/participants)。新加入或断线
重连的手机能看到别人发的内容和正在生成的回复。 - 重启后不自动重连、且没有提示:记住上次成功地址、前两个候选并发竞速、失败给出可操作
文案(含尝试过的地址与「换连接方式 / 重新扫码」建议)。 - 重新绑定复用旧连接导致绑定超时:配对时先销毁同 id 的旧连接、丢弃旧地址列表。
- 解绑提示里的电脑地址不再写死过期端口。
- 公网隧道不再是唯一"常规连接":局域网默认可用,Tailscale 地址按独立类型参与排序。
- 会改变电脑状态的 HTTP 接口(协作开关、解绑、改名、发送文件、连接方式)限制为仅本机
浏览器可写,避免经公网隧道被他人操作。
变更
- 协议升到 1.1.0:只增不改(能力协商 + 新帧),2.1.0 与 2.2.0 可以混用。
- 插件包开始携带网页版静态资源(
webchat/),体积略增。 - 版本号全仓统一为 2.2.0。
优化
- 安装包重新瘦身:新增
plugins/withReleaseSize.jsconfig plugin,把「只发布 arm64
(reactNativeArchitectures=arm64-v8a)+ R8/资源裁剪 + R8 keep 规则」写进 prebuild 生成工程。
此前android/不进仓库,CI 重新 prebuild 会丢掉这些手工设置(首次 CI 构建的通用包 =
126 MB、lib 带 4 个 ABI 合计 101 MB);现在源码即事实来源,CI 与本地一致。 - 手机端分块上传/流式下载、连接竞速、会话事件日志都做了内存与背压上限,避免大文件/长会话
把手机或电脑拖垮。
测试
- 43 个测试文件 / 656 项测试全绿(协议 31、插件 341、手机端 157、网页版 127),
零依赖直接node scripts/run-tests.mjs运行。 - 真实装机验收:隔离 DSH 中安装打包产物后,
node scripts/verify-install.mjs的
health / 二维码载荷 / 网页版静态资源 / Ed25519 绑定与签名 / 能力协商 / 会话同步 /
幂等重发 全部通过;网页版在 headless Chrome 中完成绑定、在线、发消息与刷新重连。
已知限制
- iOS / 鸿蒙:本版交付网页版与 iOS 出包流水线;鸿蒙原生包需等 RNOH 支持 RN 0.86。
- npm:v2.2.0 发布时 npm 网页注册被 Cloudflare 按出口 IP 拦截,npm 包待补发(详见
docs/PUBLISHING.md§3);插件市场条目使用 GitHub Release 的 tarball,不受影响。 - 手机端审批仍与电脑端一致(DSH 原生弹窗),沙箱边界不变。
[2.1.0] - 2026-10-25
版本号统一:本版内容与 1.0.8 完全一致,仅把版本标识从 1.0.8 统一为 2.1.0,
使 tag、产物文件名与源码中的版本号三者一致。
变更
- 源码、产物与 tag 三者版本号统一为 2.1.0
- 附件更名为
open-whale-2.1.0.apk/dsh-openwhale-2.1.0.tgz - 安装包换用 39.7 MB 的 arm64-only 构建(原 CI 产物为 125 MB 通用包)
[1.0.8] - 2026-10-24
一台电脑可绑定多台手机,并支持多人协作。 同时把安卓安装包体积压到原来的六成。
新增
- 一台电脑最多绑定 5 台手机(
MAX_DEVICES),配对页展示已绑定设备与剩余名额 - 单台解绑:
POST /openwhale/unbind?deviceId=…(不带参数仍是全量解绑) - 设备昵称:
POST /openwhale/device-rename,多人协作时消息带[昵称]前缀 - 多人协作模式:
GET/POST /openwhale/collaboration,多台手机共用同一个会话;
开关在运行时读取,切换后不需要重启插件 - 手机端「我在对话里的昵称」设置项
修复
- 打开会话时没有滚动到最后一条消息(历史异步加载 + 虚拟化列表导致只滚到中途)
- 解绑失败提示里的电脑地址写死了过期端口,改用固定端口 8787
优化
- 安卓安装包 66.7 MB → 39.7 MB:只保留 arm64,并开启 R8 代码压缩与资源裁剪
(配置与实测见docs/RELEASE-SIZE.md;android/是 prebuild 产物,不进仓库) - 把 expo 系依赖的
*换成实际解析到的具体版本,保证重新安装得到同一套依赖
1.0.7 - 2026-10-14
首个带可安装产物的版本。 电脑端插件安装包与安卓 APK 均由 GitHub Actions 构建并随
Release 发布。
新增
- 发布流水线(
.github/workflows/release.yml):在 tag 上构建插件 tarball 与 APK,
生成SHA256SUMS.txt,并创建 GitHub Release scripts/build-plugin-package.mjs:可复现的插件打包(显式文件清单、标准 npm 布局、
缺文件即失败)- 安装包 tarball 的端到端验证:在隔离
DSH_HOME中真实安装并启动,10/10 项通过
(健康检查、二维码生成与手机侧校验、携带公钥、WebSocket 握手、设备绑定、用二维码公钥
验签、聊天到达助手层、已绑定设备免扫码重连)
修复
这一版几乎全部工作都在「让别人的机器上也能构建成功」。以下每个问题都是 CI 实测出来的:
- 云隧道路径拼接:
node:path.join按运行平台拼分隔符,而模块参数里的platform
是目标平台;在 Linux 上会构造出C:\cache/x这类混合路径,导致发现逻辑静默失败 - 大文件传输缺少背压:整个文件灌入 socket 内部队列,macOS 上 700 KB 即超时;
改为「发一帧 → 若缓冲则等 drain」 - 协议副本比对绑定 checkout 行尾:Windows 的 CRLF 使哈希不一致;生成器与测试统一
按内容(LF)判定,sync --check同理 android-actions/setup-android@v3已损坏:它会安装早已移除的tools包;
改用 runner 预装的 SDKbabel-preset-expo版本号写错:Expo SDK 是 57.0.28,而该 preset 的版本线是
57.0.15;错误版本直接让pnpm install失败.mts未被剥离类型:Metro 只把.ts/.tsx当 TypeScript,export interface
在打包时报语法错误;最终在顶层 presets 加入@babel/preset-typescript
(overrides写法会因 Metro 不传文件名而失败)- 关闭握手回显被 RST 丢弃、升级前 HTTP 头被当作帧、非本插件 upgrade 路径连接悬挂、
gateway.close()永不返回
变更
- 仓库内所有版本号统一为
1.0.7(此前 tag 与产物名不一致) - 通过 API 创建的 tag 不触发
push事件,release.yml因此支持手动传入tag
1.0.0 - 2026-10-13
第一版。电脑端 DSH 插件 + 手机端 Expo 应用,两侧通过配对后的加密身份互相认证,
手机以个人助理聊天的方式远程使用电脑上的 DeepSeek Harness。
新增
电脑端插件 dsh-openwhale
- 为每台绑定手机建立一个专属 DSH 会话,与桌面正在进行的对话互不干扰
- 在该会话自己的作用域内注入「个人助理口语化语气」段落,桌面会话语气不受影响
- 展示一次性绑定二维码:浏览器页
/openwhale、DSH 命令/openwhale(终端渲染)、PNG / SVG 端点 - HTTP + WebSocket 服务:帧路由、心跳、文件分片、一次性 HTTP 下载兜底
- 工具活动以状态行推送给手机,不混入助理正文
- 远程关机 / 重启:可取消的宽限窗口;
cancel在策略禁用关机后仍然可用 - 局域网唤醒代发(WOL 魔术包)与唤醒前置条件检查清单
- 可选公网隧道:cloudflared 快速隧道的完整生命周期管理(含限流识别与退避)
手机端 @openwhale/mobile
- 扫码绑定(expo-camera)、多助理列表、助理备注可改
- 之后打开应用无需再次扫码:用设备私钥签名完成重连
- 流式回复渲染、工具活动行、文件卡片与进度
- 离线待发队列、断线指数退避重连、多地址轮换
- 助理详情页的远程电源操作与唤醒引导
协议 @openwhale/protocol
- 帧词汇、配对载荷、握手签名、防重放、文本截断等共享契约
- 插件内的副本由脚本生成,一致性由测试与 CI 的
--check保证
安全
- 二维码只含一次性、10 分钟有效的绑定密钥;绑定即失效,重发作废
- 长期凭据从不经网络传输:手机私钥保存在系统安全存储,电脑身份密钥保存在
state.json(0600) - 已绑定设备以 Ed25519 签名握手认证,服务端用随机数防重放表拒绝重放
- 二维码携带电脑公钥,手机据此验证
hello/ack,可识别冒名顶替的隧道 - 一台电脑只能绑定一台手机:即使持有有效二维码,第二台设备也会被拒绝
- 手机只能拉取本次对话中产出的文件,不能请求电脑上的任意路径
修复(开发期间发现并修正,均已在源码中体现)
- 协议副本随「复制安装」失效:改为包内生成副本 + 一致性测试
- 已绑定设备无法重连(服务端用客户端无从得知的 nonce 验签):改为客户端 nonce + 防重放表
- 二维码曾只携带 32 字节原始公钥,手机无法导入:改为完整 SPKI DER
- 手机会话未接线模型,导致每条消息都报
{{model}}无值:补齐 inject 与四级回退 autoApproveTools曾用 guard 实现(guard 只能拒绝):改为应答approval/request- 关闭握手回显被 RST 丢弃、升级前 HTTP 头被当作帧、非本插件 upgrade 路径连接悬挂、
gateway.close()永不返回
已知限制
- 远程开机受物理条件限制:电脑关机后其自身无法唤醒自己,需要同一局域网内一台常开设备
代发唤醒包,并且需在 BIOS 打开 Wake on Magic Packet、关闭 Windows 快速启动 - 手机 UI 与 Expo 原生模块未在真机验证:开发环境没有 Android SDK;纯逻辑层有 88 项单测
- 暂无端到端加密:公网模式依赖隧道提供的 TLS;中继方在技术上可见流量内容
- 快速隧道官方定位为测试用途:无可用性保证、域名每次重启会变、部分地区不稳定
- 手机端尚未实现:Wake-on-LAN 原生模块、后台保活、手机→电脑的大文件分块上传、iOS 上架
测试
- 382 项测试 / 24 个文件,零依赖即可运行:
node scripts/run-tests.mjs - 二维码用独立实现的解码器验证(格式信息、掩码、数据路径、Reed-Solomon 全零 syndrome)
- 端到端覆盖防冒充、防二维码重放、防单机双绑、附件落盘、大文件分片哈希一致
- 发布包(tarball)另行做了「安装后启动并完成绑定/对话/重连」的实测
Open Whale v2.2.0
Open Whale v2.2.0 🐳
把手机变成你这台电脑上 DeepSeek Harness 的个人助理:扫一次码,之后聊天、收发图片/文件、
看回复流式输出;多台手机还能在同一个会话里协作。三种客户端共用这一个插件:
安卓 App / 网页版(鸿蒙 NEXT、iOS、任意浏览器)/ iOS 构建流水线。
这版做了什么
连接(问题 2、3 与缺陷 P0-1/P0-2/P1-3/P1-4/P1-7)
- Tailscale 成为独立连接方式,不再混在「局域网」里;自动模式顺序改为
「上次成功 → Tailscale → 局域网 → 公网隧道」,公网隧道不再抢占 - 相册识图绑定、手动输入地址(先探 health 再保存)、前两个候选并发竞速
- 同一设备允许最多 3 条并发会话,竞速/多窗口不再互踢成 1 秒重连循环
- 连续失败给可操作文案(尝试过的地址 + 换连接方式/重新扫码建议)
协作与多端同步(问题 3 症状、4、5、6)
- 按
(设备, msgId)幂等:离线队列重发不会再让 AI 回两遍 - 助手消息按 DSH
messageId聚合:修掉协作模式下回复重复拼接 chat/echo广播 + 会话事件日志/游标追赶 + 在线成员:新加入或断线的手机能看到
别人发的内容和正在生成的回复
文件(问题 8 与缺陷 P1-10)
- 手机 → 电脑:512 KiB 分块 + 背压 + 进度 + 断点重试,单附件上限 64 MiB;
落盘在会话工作目录内(修复「模型读不到手机图片」) - 电脑 → 手机:配对页「发送到手机」,手机聊天里收到一次性下载卡片
- 下载改流式落盘;失败按「网络可重试 / 电脑端拒绝」分流提示
界面(问题 9 与缺陷 P2-9)
- 手机端 UI 重做:底部固定输入栏、状态胶囊、参与者头像条、深浅色、气泡分组、空态引导
- 长按复制/重发/删除、代码块只复制代码、文件卡片、回到底部
跨端(问题 7)
- 插件内置网页版
/openwhale/app(零构建 PWA,可添加到主屏幕) - iOS:
app.jsoniOS 段 +eas.json+ GitHub Actions 模拟器构建(未签名.app,CI 已通过) - 鸿蒙结论与 ArkTS Web 壳示例见
docs/iOS-HarmonyOS.md(RNOH 尚未支持 RN 0.86)
其他
- 协议升到 1.1.0(只增不改,2.1.0 客户端可与 2.2.0 插件混用)
- 会改变电脑状态的 HTTP 接口(协作/解绑/改名/发文件/连接方式)仅本机可写,经隧道不可操作
- 安装包重新瘦身:126 MB → 40.9 MB(arm64-only + R8 + keep 规则,由
plugins/withReleaseSize.js在 prebuild 阶段写入,源码即事实来源)
下载与安装
| 文件 | 装到哪 | 怎么装 |
|---|---|---|
dsh-openwhale-2.2.0.tgz(或固定名 dsh-openwhale.tgz) |
电脑 | dsh plugin --profile <你的profile> add ./dsh-openwhale-2.2.0.tgz,然后重启 DSH |
open-whale-2.2.0.apk(或 open-whale.apk) |
安卓手机 | 允许安装未知来源后点击安装;仅 arm64(绝大多数手机) |
| 网页版 | 鸿蒙 / iOS / 任意浏览器 | 重启 DSH 后打开 http://<电脑地址>:8787/openwhale/app,或扫配对页的第二个二维码 |
校验:SHA256SUMS.txt 随 Release 提供。
npm 包(
dsh-openwhale)本次发布时 npm 网页注册被 Cloudflare 按出口 IP 拦截,待补发;
插件市场条目使用本 Release 的固定名 tarball,安装不受影响。补发步骤见仓库docs/PUBLISHING.md。
验证
- 43 个测试文件 / 656 项测试全绿(协议 31、插件 341、手机端 157、网页版 127),
三平台 CI(ubuntu/windows/macos × Node 22/24)通过 - 隔离 DSH 真实装机验收:打包产物安装后运行
scripts/verify-install.mjs,health / 配对载荷
(真实协议解析)/ 网页版静态资源 / Ed25519 绑定与 hello-ack 签名 / 能力协商 / 会话快照 /
同一 msgId 重发只受理一次 —— 全部通过 - 网页版浏览器端到端:headless Chrome 完成绑定→在线→发消息→刷新签名重连,零 console 异常
- iOS 模拟器构建:Xcode 26.3 + 未签名
.app产物(CI 通过) - APK 实测:42.9 MB / 仅
arm64-v8a/ 含 JS bundle 与 MLKit 条码模型
已知限制
- npm 包待补发(原因见上);
dsh-openwhale名称在 npm 上仍可用 - iOS 真机 / TestFlight 需 Apple 开发者账号(走 EAS Build);模拟器包不能装真机
- 鸿蒙原生包需等 RNOH 支持 RN 0.86,本版用网页版覆盖
- release APK 只含 arm64;x86_64 模拟器请用 debug 包
- 手机端审批仍与电脑端一致(DSH 原生弹窗),Windows 受限令牌沙箱边界不变
完整变更见 CHANGELOG。
Open Whale v2.1.0
变更记录
本项目遵循 Keep a Changelog 与语义化版本。
[2.1.0] - 2026-10-25
版本号统一:本版内容与 1.0.8 完全一致,仅把版本标识从 1.0.8 统一为 2.1.0,
使 tag、产物文件名与源码中的版本号三者一致。
变更
- 源码、产物与 tag 三者版本号统一为 2.1.0
- 附件更名为
open-whale-2.1.0.apk/dsh-openwhale-2.1.0.tgz - 安装包换用 39.7 MB 的 arm64-only 构建(原 CI 产物为 125 MB 通用包)
[1.0.8] - 2026-10-24
一台电脑可绑定多台手机,并支持多人协作。 同时把安卓安装包体积压到原来的六成。
新增
- 一台电脑最多绑定 5 台手机(
MAX_DEVICES),配对页展示已绑定设备与剩余名额 - 单台解绑:
POST /openwhale/unbind?deviceId=…(不带参数仍是全量解绑) - 设备昵称:
POST /openwhale/device-rename,多人协作时消息带[昵称]前缀 - 多人协作模式:
GET/POST /openwhale/collaboration,多台手机共用同一个会话;
开关在运行时读取,切换后不需要重启插件 - 手机端「我在对话里的昵称」设置项
修复
- 打开会话时没有滚动到最后一条消息(历史异步加载 + 虚拟化列表导致只滚到中途)
- 解绑失败提示里的电脑地址写死了过期端口,改用固定端口 8787
优化
- 安卓安装包 66.7 MB → 39.7 MB:只保留 arm64,并开启 R8 代码压缩与资源裁剪
(配置与实测见docs/RELEASE-SIZE.md;android/是 prebuild 产物,不进仓库) - 把 expo 系依赖的
*换成实际解析到的具体版本,保证重新安装得到同一套依赖
1.0.7 - 2026-10-14
首个带可安装产物的版本。 电脑端插件安装包与安卓 APK 均由 GitHub Actions 构建并随
Release 发布。
新增
- 发布流水线(
.github/workflows/release.yml):在 tag 上构建插件 tarball 与 APK,
生成SHA256SUMS.txt,并创建 GitHub Release scripts/build-plugin-package.mjs:可复现的插件打包(显式文件清单、标准 npm 布局、
缺文件即失败)- 安装包 tarball 的端到端验证:在隔离
DSH_HOME中真实安装并启动,10/10 项通过
(健康检查、二维码生成与手机侧校验、携带公钥、WebSocket 握手、设备绑定、用二维码公钥
验签、聊天到达助手层、已绑定设备免扫码重连)
修复
这一版几乎全部工作都在「让别人的机器上也能构建成功」。以下每个问题都是 CI 实测出来的:
- 云隧道路径拼接:
node:path.join按运行平台拼分隔符,而模块参数里的platform
是目标平台;在 Linux 上会构造出C:\cache/x这类混合路径,导致发现逻辑静默失败 - 大文件传输缺少背压:整个文件灌入 socket 内部队列,macOS 上 700 KB 即超时;
改为「发一帧 → 若缓冲则等 drain」 - 协议副本比对绑定 checkout 行尾:Windows 的 CRLF 使哈希不一致;生成器与测试统一
按内容(LF)判定,sync --check同理 android-actions/setup-android@v3已损坏:它会安装早已移除的tools包;
改用 runner 预装的 SDKbabel-preset-expo版本号写错:Expo SDK 是 57.0.28,而该 preset 的版本线是
57.0.15;错误版本直接让pnpm install失败.mts未被剥离类型:Metro 只把.ts/.tsx当 TypeScript,export interface
在打包时报语法错误;最终在顶层 presets 加入@babel/preset-typescript
(overrides写法会因 Metro 不传文件名而失败)- 关闭握手回显被 RST 丢弃、升级前 HTTP 头被当作帧、非本插件 upgrade 路径连接悬挂、
gateway.close()永不返回
变更
- 仓库内所有版本号统一为
1.0.7(此前 tag 与产物名不一致) - 通过 API 创建的 tag 不触发
push事件,release.yml因此支持手动传入tag
1.0.0 - 2026-10-13
第一版。电脑端 DSH 插件 + 手机端 Expo 应用,两侧通过配对后的加密身份互相认证,
手机以个人助理聊天的方式远程使用电脑上的 DeepSeek Harness。
新增
电脑端插件 dsh-openwhale
- 为每台绑定手机建立一个专属 DSH 会话,与桌面正在进行的对话互不干扰
- 在该会话自己的作用域内注入「个人助理口语化语气」段落,桌面会话语气不受影响
- 展示一次性绑定二维码:浏览器页
/openwhale、DSH 命令/openwhale(终端渲染)、PNG / SVG 端点 - HTTP + WebSocket 服务:帧路由、心跳、文件分片、一次性 HTTP 下载兜底
- 工具活动以状态行推送给手机,不混入助理正文
- 远程关机 / 重启:可取消的宽限窗口;
cancel在策略禁用关机后仍然可用 - 局域网唤醒代发(WOL 魔术包)与唤醒前置条件检查清单
- 可选公网隧道:cloudflared 快速隧道的完整生命周期管理(含限流识别与退避)
手机端 @openwhale/mobile
- 扫码绑定(expo-camera)、多助理列表、助理备注可改
- 之后打开应用无需再次扫码:用设备私钥签名完成重连
- 流式回复渲染、工具活动行、文件卡片与进度
- 离线待发队列、断线指数退避重连、多地址轮换
- 助理详情页的远程电源操作与唤醒引导
协议 @openwhale/protocol
- 帧词汇、配对载荷、握手签名、防重放、文本截断等共享契约
- 插件内的副本由脚本生成,一致性由测试与 CI 的
--check保证
安全
- 二维码只含一次性、10 分钟有效的绑定密钥;绑定即失效,重发作废
- 长期凭据从不经网络传输:手机私钥保存在系统安全存储,电脑身份密钥保存在
state.json(0600) - 已绑定设备以 Ed25519 签名握手认证,服务端用随机数防重放表拒绝重放
- 二维码携带电脑公钥,手机据此验证
hello/ack,可识别冒名顶替的隧道 - 一台电脑只能绑定一台手机:即使持有有效二维码,第二台设备也会被拒绝
- 手机只能拉取本次对话中产出的文件,不能请求电脑上的任意路径
修复(开发期间发现并修正,均已在源码中体现)
- 协议副本随「复制安装」失效:改为包内生成副本 + 一致性测试
- 已绑定设备无法重连(服务端用客户端无从得知的 nonce 验签):改为客户端 nonce + 防重放表
- 二维码曾只携带 32 字节原始公钥,手机无法导入:改为完整 SPKI DER
- 手机会话未接线模型,导致每条消息都报
{{model}}无值:补齐 inject 与四级回退 autoApproveTools曾用 guard 实现(guard 只能拒绝):改为应答approval/request- 关闭握手回显被 RST 丢弃、升级前 HTTP 头被当作帧、非本插件 upgrade 路径连接悬挂、
gateway.close()永不返回
已知限制
- 远程开机受物理条件限制:电脑关机后其自身无法唤醒自己,需要同一局域网内一台常开设备
代发唤醒包,并且需在 BIOS 打开 Wake on Magic Packet、关闭 Windows 快速启动 - 手机 UI 与 Expo 原生模块未在真机验证:开发环境没有 Android SDK;纯逻辑层有 88 项单测
- 暂无端到端加密:公网模式依赖隧道提供的 TLS;中继方在技术上可见流量内容
- 快速隧道官方定位为测试用途:无可用性保证、域名每次重启会变、部分地区不稳定
- 手机端尚未实现:Wake-on-LAN 原生模块、后台保活、手机→电脑的大文件分块上传、iOS 上架
测试
- 382 项测试 / 24 个文件,零依赖即可运行:
node scripts/run-tests.mjs - 二维码用独立实现的解码器验证(格式信息、掩码、数据路径、Reed-Solomon 全零 syndrome)
- 端到端覆盖防冒充、防二维码重放、防单机双绑、附件落盘、大文件分片哈希一致
- 发布包(tarball)另行做了「安装后启动并完成绑定/对话/重连」的实测
Open Whale v2.0.0
版本记录
V2 — 2026-10
面向"可日常使用"的一版,重点解决连接稳定性与消息即时性。
新增
- 高级连接方式:局域网直连与 USB 调试通道收纳到「设置 → 高级连接方式」,
默认只用公网隧道;USB 通道仅在「内部测试模式」下可用。 - 公网隧道:插件可自动拉起并监管
cloudflared快速隧道,隧道地址自动进入端点列表与配对载荷。 - 连接策略层:新增
connection-policy,集中管理"哪些地址类型允许使用"。
修复
- 修复连接抖动:关闭连接时未摘除事件回调,导致旧连接回调触发额外重连,
与电脑端的"踢掉旧连接"叠加形成每秒一次的重连循环。60 秒内建连次数 15 → 1。 - 修复消息延迟:重试次数在"写入连接"时就计数,抖动几次即耗尽自动重发机会。
改为"未获确认才计数",并提高上限。端到端 10 分钟 → 5.4 秒。 - 修复手动重试无效:重试未清零计数,导致点击后仍不会发送。
- 修复助手无响应:插件以链接方式安装时无法解析宿主内置依赖,改为从宿主包解析。
已知限制
- 临时公网隧道每次重启会更换域名,需要重新扫码(固定域名列入 V3)。
- 一台电脑只能绑定一台手机(多设备列入 V3)。
- 存在客户端隔离的网络下,局域网直连不可用。
Open Whale v1.0.7
变更记录
本项目遵循 Keep a Changelog 与语义化版本。
1.0.7 - 2026-10-14
首个带可安装产物的版本。 电脑端插件安装包与安卓 APK 均由 GitHub Actions 构建并随
Release 发布。
新增
- 发布流水线(
.github/workflows/release.yml):在 tag 上构建插件 tarball 与 APK,
生成SHA256SUMS.txt,并创建 GitHub Release scripts/build-plugin-package.mjs:可复现的插件打包(显式文件清单、标准 npm 布局、
缺文件即失败)- 安装包 tarball 的端到端验证:在隔离
DSH_HOME中真实安装并启动,10/10 项通过
(健康检查、二维码生成与手机侧校验、携带公钥、WebSocket 握手、设备绑定、用二维码公钥
验签、聊天到达助手层、已绑定设备免扫码重连)
修复
这一版几乎全部工作都在「让别人的机器上也能构建成功」。以下每个问题都是 CI 实测出来的:
- 云隧道路径拼接:
node:path.join按运行平台拼分隔符,而模块参数里的platform
是目标平台;在 Linux 上会构造出C:\cache/x这类混合路径,导致发现逻辑静默失败 - 大文件传输缺少背压:整个文件灌入 socket 内部队列,macOS 上 700 KB 即超时;
改为「发一帧 → 若缓冲则等 drain」 - 协议副本比对绑定 checkout 行尾:Windows 的 CRLF 使哈希不一致;生成器与测试统一
按内容(LF)判定,sync --check同理 android-actions/setup-android@v3已损坏:它会安装早已移除的tools包;
改用 runner 预装的 SDKbabel-preset-expo版本号写错:Expo SDK 是 57.0.28,而该 preset 的版本线是
57.0.15;错误版本直接让pnpm install失败.mts未被剥离类型:Metro 只把.ts/.tsx当 TypeScript,export interface
在打包时报语法错误;最终在顶层 presets 加入@babel/preset-typescript
(overrides写法会因 Metro 不传文件名而失败)- 关闭握手回显被 RST 丢弃、升级前 HTTP 头被当作帧、非本插件 upgrade 路径连接悬挂、
gateway.close()永不返回
变更
- 仓库内所有版本号统一为
1.0.7(此前 tag 与产物名不一致) - 通过 API 创建的 tag 不触发
push事件,release.yml因此支持手动传入tag
1.0.0 - 2026-10-13
第一版。电脑端 DSH 插件 + 手机端 Expo 应用,两侧通过配对后的加密身份互相认证,
手机以个人助理聊天的方式远程使用电脑上的 DeepSeek Harness。
新增
电脑端插件 dsh-openwhale
- 为每台绑定手机建立一个专属 DSH 会话,与桌面正在进行的对话互不干扰
- 在该会话自己的作用域内注入「个人助理口语化语气」段落,桌面会话语气不受影响
- 展示一次性绑定二维码:浏览器页
/openwhale、DSH 命令/openwhale(终端渲染)、PNG / SVG 端点 - HTTP + WebSocket 服务:帧路由、心跳、文件分片、一次性 HTTP 下载兜底
- 工具活动以状态行推送给手机,不混入助理正文
- 远程关机 / 重启:可取消的宽限窗口;
cancel在策略禁用关机后仍然可用 - 局域网唤醒代发(WOL 魔术包)与唤醒前置条件检查清单
- 可选公网隧道:cloudflared 快速隧道的完整生命周期管理(含限流识别与退避)
手机端 @openwhale/mobile
- 扫码绑定(expo-camera)、多助理列表、助理备注可改
- 之后打开应用无需再次扫码:用设备私钥签名完成重连
- 流式回复渲染、工具活动行、文件卡片与进度
- 离线待发队列、断线指数退避重连、多地址轮换
- 助理详情页的远程电源操作与唤醒引导
协议 @openwhale/protocol
- 帧词汇、配对载荷、握手签名、防重放、文本截断等共享契约
- 插件内的副本由脚本生成,一致性由测试与 CI 的
--check保证
安全
- 二维码只含一次性、10 分钟有效的绑定密钥;绑定即失效,重发作废
- 长期凭据从不经网络传输:手机私钥保存在系统安全存储,电脑身份密钥保存在
state.json(0600) - 已绑定设备以 Ed25519 签名握手认证,服务端用随机数防重放表拒绝重放
- 二维码携带电脑公钥,手机据此验证
hello/ack,可识别冒名顶替的隧道 - 一台电脑只能绑定一台手机:即使持有有效二维码,第二台设备也会被拒绝
- 手机只能拉取本次对话中产出的文件,不能请求电脑上的任意路径
修复(开发期间发现并修正,均已在源码中体现)
- 协议副本随「复制安装」失效:改为包内生成副本 + 一致性测试
- 已绑定设备无法重连(服务端用客户端无从得知的 nonce 验签):改为客户端 nonce + 防重放表
- 二维码曾只携带 32 字节原始公钥,手机无法导入:改为完整 SPKI DER
- 手机会话未接线模型,导致每条消息都报
{{model}}无值:补齐 inject 与四级回退 autoApproveTools曾用 guard 实现(guard 只能拒绝):改为应答approval/request- 关闭握手回显被 RST 丢弃、升级前 HTTP 头被当作帧、非本插件 upgrade 路径连接悬挂、
gateway.close()永不返回
已知限制
- 远程开机受物理条件限制:电脑关机后其自身无法唤醒自己,需要同一局域网内一台常开设备
代发唤醒包,并且需在 BIOS 打开 Wake on Magic Packet、关闭 Windows 快速启动 - 手机 UI 与 Expo 原生模块未在真机验证:开发环境没有 Android SDK;纯逻辑层有 88 项单测
- 暂无端到端加密:公网模式依赖隧道提供的 TLS;中继方在技术上可见流量内容
- 快速隧道官方定位为测试用途:无可用性保证、域名每次重启会变、部分地区不稳定
- 手机端尚未实现:Wake-on-LAN 原生模块、后台保活、手机→电脑的大文件分块上传、iOS 上架
测试
- 382 项测试 / 24 个文件,零依赖即可运行:
node scripts/run-tests.mjs - 二维码用独立实现的解码器验证(格式信息、掩码、数据路径、Reed-Solomon 全零 syndrome)
- 端到端覆盖防冒充、防二维码重放、防单机双绑、附件落盘、大文件分片哈希一致
- 发布包(tarball)另行做了「安装后启动并完成绑定/对话/重连」的实测