dsh-plugin-tether 0.1.12 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  本文件记录面向用户的变化。每个版本的这一节会原样作为该版本 Release 的说明。
4
4
 
5
+ ## 0.1.14
6
+
7
+ ### 修复
8
+
9
+ - **Android 本地模式:每一轮对话都失败,报 `EACCES: permission denied, link ...`**([#9](https://github.com/zexadev/dsh-tether/issues/9))。Android 系统的 SELinux 策略禁止普通 App 创建硬链接,与机型、ROM、系统版本无关;dsh 新会话首次落盘用的正是硬链接,所以 0.1.13 的本地模式在任何手机上都新建不了会话,发送图片也会以 `ATTACHMENT_WRITE_FAILED` 失败。现在本地模式内置的 dsh 在硬链接被拒时改为「写一份副本并落盘 → 确认目标不存在 → 原子改名」,文件仍然完整出现、不会覆盖已有会话。升级后第一次进入本地模式会重新解压运行时(约 9 秒)。远程模式(连电脑)不受影响。
10
+
11
+ ## 0.1.13
12
+
13
+ ### 新增
14
+
15
+ - **Android 本地模式:没电脑也能用,DSH 直接跑在手机上**。同一个 App 两种模式:有电脑连电脑(原有能力),没电脑在「主机」页点「在本机运行」。Node 24 与 dsh `0.1.2-rc.1` 的完整依赖树打在 `arm64` APK 里,首次启动离线解压(实测 9 秒),之后每次约 2 秒;没有配对、没有远端,会话和设置只存在手机里,与连电脑时的状态完全分开;运行期间挂一条常驻通知(前台服务),退后台、锁屏不被系统收掉,进程被杀后下次打开自动重起。手机上的 dsh 同样带窄屏适配。只有 `arm64` 包带本地模式(约 71 MB,其余包约 32 MB);iOS 沙箱不允许子进程,没有这个入口。手机上没有 bash 与完整 coreutils,依赖 shell 的工具用不全。
16
+ - 顶栏常驻「主机」按钮,任何模式下都能回到主机页。
17
+
18
+ ### 变更
19
+
20
+ - 插件 `peerDependencies` 加入 dsh `0.1.5` 版本族;`0.1.2-rc.1` 与 `0.1.5-alpha.1` 已在隔离环境实测(patch、cookie 兑换、路由栅栏、侧栏注入、经代理流的手机链路)。实测 pnpm 在 peer 范围不含当前版本族时照常安装且无警告,该声明只记录已验证范围。
21
+ - 插件新增 `config.sidecar: false`:只做界面适配,不找也不起 sidecar;供手机本地模式使用。
22
+ - README、网页与包描述改为如实表述:直连优先,打不通才退回 relay,relay 只见密文;不再写「不经过任何服务器」。
5
23
  ## 0.1.12
6
24
 
7
25
  ### 修复
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  <h1 align="center">DSH Tether</h1>
2
2
 
3
3
  <p align="center">
4
- <strong>Use the DeepSeek Harness on your dev machine, from your phone.</strong><br>
5
- Across networks, peer to peer, through no server at all.<br>
6
- No relay to configure, no shared Wi-Fi, no Linux on your phone.
4
+ <strong>DSH in your pocket: connect to your machine when you have one, run it on the phone when you don't.</strong><br>
5
+ Remote: across networks, peer to peer, no server to set up, no shared Wi-Fi — if hole-punching fails it falls back to a relay that sees only ciphertext.<br>
6
+ Local (Android): the DeepSeek Harness runs on the phone itself — install and go, no Termux, no commands.
7
7
  </p>
8
8
 
9
9
  <p align="center"><sub>An independent community project. Not affiliated with, partnered with, authorised by, or endorsed by DeepSeek.<br>No DeepSeek employee or upstream DeepSeek Harness team member is involved in this repository.<br><a href="README.zh.md">中文</a> · English</sub></p>
10
10
 
11
11
  <p align="center">
12
- <img src="assets/banner.jpg" alt="Phone tethered directly to a dev machine — no server in between" width="100%">
12
+ <img src="assets/banner.jpg" alt="Phone tethered directly to a dev machine" width="100%">
13
13
  </p>
14
14
 
15
15
  <p align="center">
@@ -17,7 +17,7 @@
17
17
  <a href="../../releases"><img src="https://img.shields.io/github/downloads/zexadev/dsh-tether/total?style=flat&label=downloads&color=4D6BFE" alt="Downloads"></a>
18
18
  <a href="../../stargazers"><img src="https://img.shields.io/github/stars/zexadev/dsh-tether?style=flat&label=%E2%98%85&color=08C" alt="Stars"></a>
19
19
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat" alt="MIT"></a>
20
- <img src="https://img.shields.io/badge/dsh-0.1.0--rc.7%20%7C%20rc.8%20%7C%200.1.2--alpha-4D6BFE?style=flat" alt="dsh 0.1.0-rc.7 | rc.8 | 0.1.2-alpha">
20
+ <img src="https://img.shields.io/badge/dsh-0.1.0--rc.7%20%7C%20rc.8%20%7C%200.1.2%20%7C%200.1.5--alpha-4D6BFE?style=flat" alt="dsh 0.1.0-rc.7 | rc.8 | 0.1.2 | 0.1.5-alpha">
21
21
  <img src="https://img.shields.io/badge/Android-4493F8?style=flat" alt="Android">
22
22
  <img src="https://img.shields.io/badge/iOS-beta-8E8E93?style=flat" alt="iOS beta">
23
23
  <a href="https://www.dsh.so/artifact/dsh-tether"><img src="https://www.dsh.so/badge/dsh-tether.svg" alt="dsh.so security scan"></a>
@@ -32,6 +32,8 @@
32
32
 
33
33
  DSH Tether carries the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) web interface to your phone over a direct peer-to-peer connection. The agent keeps running on the machine your code lives on, and the phone gets DSH's own full interface — conversations, tool calls, approvals and settings, not a reimplementation of them. Pair once with a 6-digit code; after that the two ends find each other whatever network they are on.
34
34
 
35
+ When there is no machine around, the same app can run DSH on the phone itself (Android) — see [Local mode](#local-mode-no-machine-needed-android).
36
+
35
37
  ## The case it solves
36
38
 
37
39
  **You are not on your machine's network, and you do not want a server in the middle.**
@@ -40,17 +42,28 @@ Reaching your own dev machine from a phone usually asks for one of two things: b
40
42
 
41
43
  If you only use your phone on the same Wi-Fi as your machine, you don't need any of this — a LAN setup is simpler.
42
44
 
45
+ ### Compared with ds-harness-remote
46
+
47
+ The project most often compared with this one is [liguobao/ds-harness-remote](https://github.com/liguobao/ds-harness-remote). Going by both READMEs:
48
+
49
+ | | DSH Tether | ds-harness-remote |
50
+ | --- | --- | --- |
51
+ | Connection | Direct first (iroh hole-punching), relay only as fallback and it sees ciphertext only; no account, no server to run | Sign in to its service, then LAN → P2P → TURN → Relay in turn; a self-hosted relay is supported |
52
+ | No machine around | Android local mode: DSH runs on the phone | — |
53
+ | Clients | Android, iOS (beta) | PC, Android, Web; no native iOS app |
54
+ | License | MIT | No license file in the repository |
55
+
43
56
  ## Download and install
44
57
 
45
58
  | Where | Download | How |
46
59
  | --- | --- | --- |
47
60
  | Machine | — | `dsh plugin --profile web add dsh-plugin-tether` |
48
- | Phone | `dsh-tether-<version>-arm64.apk` from the [Release](../../releases/latest) | Signed — install it directly |
61
+ | Phone | `dsh-tether-<version>-arm64.apk` from the [Release](../../releases/latest) | Signed — install it directly; local mode included |
49
62
  | Phone (iOS) | `dsh-tether-<version>-ios-unsigned.ipa` from the [Release](../../releases/latest) | **Beta**, unsigned — sign it yourself |
50
63
 
51
64
  The plugin carries a small Rust sidecar that owns the iroh connection, shipped as one package per platform; installing pulls only the one matching your system, with nothing to choose.
52
65
 
53
- The phone build is split by CPU architecture. **Any Android phone from the last decade takes `arm64`**; `arm` is for 32-bit legacy devices, and `x86` / `x86_64` are for emulators and ChromeOS. Picking the wrong one simply gets refused at install time.
66
+ The phone build is split by CPU architecture. **Any Android phone from the last decade takes `arm64`**; `arm` is for 32-bit legacy devices, and `x86` / `x86_64` are for emulators and ChromeOS. Picking the wrong one simply gets refused at install time. Only the `arm64` build carries the local-mode runtime; the other three have no such entry.
54
67
 
55
68
  The iOS build is **beta**: this project has no Mac, so the package is only ever built in CI and has never run on a real device. You sign it yourself with AltStore, Sideloadly or similar (a free Apple ID expires after 7 days). Please open an issue if you hit anything.
56
69
 
@@ -70,6 +83,19 @@ On the phone, open DSH Tether → **Add computer** → paste that whole line →
70
83
 
71
84
  From then on the app connects by itself when you open it.
72
85
 
86
+ ## Local mode: no machine needed (Android)
87
+
88
+ Open the app → **Hosts** in the top bar → **Run on this phone**. The first start unpacks the runtime first (about 9 seconds measured); after that the DSH interface appears in about 2 seconds. Enter an API key in Settings and start talking.
89
+
90
+ - **Install and go**: no Termux, no terminal, no commands, no root. Node 24 and the full dependency tree of dsh `0.1.2-rc.1` ship inside the APK and unpack offline on first start; after that only model API calls need the network.
91
+ - **No pairing**: dsh is on this phone, there is no remote end. Sessions, settings and workspaces live only on the phone and are entirely separate from what you see when connected to a machine; switching back and forth touches neither.
92
+ - **Stays up**: while running there is a persistent notification (a foreground service), so backgrounding or locking the screen does not get the process reclaimed. If the process is killed anyway, the next launch restarts it; sessions are already on disk.
93
+ - **Versioned with the app**: the bundled dsh upgrades with the app; currently `0.1.2-rc.1`.
94
+ - Only the `arm64` APK carries local mode; iOS forbids child processes, so the iOS build has no such entry.
95
+ - The phone has no bash and no full coreutils, so shell-dependent tools are incomplete; chat and file read/write are unaffected.
96
+
97
+ The Termux route still works if you prefer it: install dsh and this plugin inside Termux (it picks the `android-arm64` sidecar package automatically), then pair to it in remote mode — the phone is just another "machine". There is no guided setup for that path; it simply keeps working.
98
+
73
99
  ## Features
74
100
 
75
101
  <table>
@@ -102,13 +128,15 @@ From then on the app connects by itself when you open it.
102
128
  - Traffic is end-to-end encrypted by iroh (QUIC/TLS). When hole-punching succeeds it touches no third party; when it falls back, the relay only carries ciphertext it cannot read.
103
129
  - The plugin's own two HTTP routes apply the same browser-trust rules dsh applies to `/api`: the `Host` must be a loopback authority, an explicit cross-site marker is refused, and an attached `Origin` must match the Host. Cross-site requests from a malicious page and DNS-rebinding attempts both get a 403.
104
130
  - **Known limit**: those rules stop a browser from being used as a confused deputy; they do **not** stop a local process. A local process presents a loopback `Host`, so it can mint a pairing code and pair itself as a "phone" — meaning **an attacker who can already run code on your dev machine can turn that into long-term access**. Don't run this plugin on a machine where you run untrusted code.
131
+ - **The phone side has a limit too**: the local proxy the app starts listens on 127.0.0.1 only, but any other app on the phone can connect to it and gets the full dsh interface; the port is derived from the host, so it is easier to find than a random one. Untrusted apps on the phone, or an unlocked phone in someone else's hands, amount to exposing the dev machine.
105
132
 
106
133
  ## Known limitations
107
134
 
108
135
  - The iOS build is beta: built only in CI, never run on a real device, and you sign it yourself. Android is the one verified on real hardware.
109
136
  - The app connects when you open it and holds no background connection — Android's doze would not let it anyway.
110
137
  - The interface on the phone is DSH's own; the narrow-screen fit comes from minimal injected styles, so a dsh layout change may need a follow-up here.
111
- - Verified against dsh **`0.1.0-rc.7`**, **`0.1.0-rc.8`** and **`0.1.2-alpha`**. dsh is in developer preview — check this line before assuming a newer dsh works. The browser authentication dsh introduced in 0.1.2-alpha is handled entirely on the machine side; the phone app needs no update for it.
138
+ - Local mode exists only in the `arm64` build, never on iOS; the phone lacks bash and a full coreutils, so shell-dependent tools are incomplete. The `arm64` APK is about 71 MB because of the bundled runtime; the others are about 32 MB.
139
+ - Verified against dsh **`0.1.0-rc.7`**, **`0.1.0-rc.8`**, **`0.1.2`** (alpha and rc.1) and **`0.1.5-alpha.1`**. dsh is in developer preview — check this line before assuming a newer dsh works. The browser authentication dsh introduced in 0.1.2-alpha is handled entirely on the machine side; the phone app needs no update for it.
112
140
 
113
141
  ## What has been verified
114
142
 
@@ -116,6 +144,8 @@ Direct cross-network connection is the whole point of the project, so here is th
116
144
 
117
145
  Pairing (including a wrong code being refused), approval delivery, and switching between saved machines were all verified on a real device. **The relay fallback has not yet been triggered on a real network.**
118
146
 
147
+ Local mode was verified on a Redmi running Android 16: a fresh install reaches a working interface in 9.1 seconds (runtime unpacking included) and later starts take 2.1 seconds; the node process survives 30 seconds in the background; force-stopping the app and reopening it restores local mode automatically.
148
+
119
149
  ## Relationship to DeepSeek Harness
120
150
 
121
151
  <p align="center"><img src="assets/dsh-mark.svg" height="36" alt="DeepSeek Harness"></p>
package/README.zh.md CHANGED
@@ -1,15 +1,15 @@
1
1
  <h1 align="center">DSH Tether</h1>
2
2
 
3
3
  <p align="center">
4
- <strong>在手机上用你开发机里的 DeepSeek Harness。</strong><br>
5
- 跨网络,点对点直连,中间不经过任何服务器。<br>
6
- 不用配中转,不用同一个 WiFi,不用在手机上装 Linux。
4
+ <strong>DSH 随身:有电脑连电脑,没电脑本地跑。</strong><br>
5
+ 连电脑:跨网络点对点打洞直连,不用架任何服务器,不用同一个 WiFi;打不通才退回 relay,relay 只见密文。<br>
6
+ 本地跑(Android):DeepSeek Harness 直接在手机上运行,装完即用,不装 Termux 不敲命令。
7
7
  </p>
8
8
 
9
9
  <p align="center"><sub>独立的社区开源项目,与深度求索不存在隶属、合作、授权或背书关系。<br>本仓库无深度求索员工或 DeepSeek Harness 上游官方团队成员参与。<br>中文 · <a href="README.md">English</a></sub></p>
10
10
 
11
11
  <p align="center">
12
- <img src="assets/banner.jpg" alt="手机与开发机直接相连,中间没有服务器" width="100%">
12
+ <img src="assets/banner.jpg" alt="手机与开发机直接相连" width="100%">
13
13
  </p>
14
14
 
15
15
  <p align="center">
@@ -17,7 +17,7 @@
17
17
  <a href="../../releases"><img src="https://img.shields.io/github/downloads/zexadev/dsh-tether/total?style=flat&label=downloads&color=4D6BFE" alt="下载量"></a>
18
18
  <a href="../../stargazers"><img src="https://img.shields.io/github/stars/zexadev/dsh-tether?style=flat&label=%E2%98%85&color=08C" alt="Stars"></a>
19
19
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat" alt="MIT"></a>
20
- <img src="https://img.shields.io/badge/dsh-0.1.0--rc.7%20%7C%20rc.8%20%7C%200.1.2--alpha-4D6BFE?style=flat" alt="dsh 0.1.0-rc.7 | rc.8 | 0.1.2-alpha">
20
+ <img src="https://img.shields.io/badge/dsh-0.1.0--rc.7%20%7C%20rc.8%20%7C%200.1.2%20%7C%200.1.5--alpha-4D6BFE?style=flat" alt="dsh 0.1.0-rc.7 | rc.8 | 0.1.2 | 0.1.5-alpha">
21
21
  <img src="https://img.shields.io/badge/Android-4493F8?style=flat" alt="Android">
22
22
  <img src="https://img.shields.io/badge/iOS-%E6%B5%8B%E8%AF%95%E7%89%88-8E8E93?style=flat" alt="iOS 测试版">
23
23
  <a href="https://www.dsh.so/artifact/dsh-tether"><img src="https://www.dsh.so/badge/dsh-tether.svg" alt="dsh.so 安全扫描"></a>
@@ -32,6 +32,8 @@
32
32
 
33
33
  DSH Tether 把 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 的 Web 界面通过点对点直连带到手机上。agent 依旧跑在你代码所在的那台电脑,手机拿到的是 DSH 自己的完整界面——会话、工具调用、审批、设置全都在,不是另做一套。用 6 位码配对一次,之后两端在哪个网络都能互相找到。
34
34
 
35
+ 手边没有电脑时,同一个 App 还能在手机本地把 DSH 跑起来(Android),见[本地模式](#本地模式没电脑也能用android)。
36
+
35
37
  ## 它解决什么
36
38
 
37
39
  **你不在电脑那个网络里,又不想中间有一台服务器。**
@@ -40,17 +42,28 @@ DSH Tether 把 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harnes
40
42
 
41
43
  如果你只在和电脑同一个 WiFi 下用手机,你并不需要这些——局域网方案更简单。
42
44
 
45
+ ### 与 ds-harness-remote 的区别
46
+
47
+ 同类里最常被拿来比的是 [liguobao/ds-harness-remote](https://github.com/liguobao/ds-harness-remote)。按两边的 README 对照:
48
+
49
+ | | DSH Tether | ds-harness-remote |
50
+ | --- | --- | --- |
51
+ | 建链 | 直连优先(iroh 打洞),失败才退回 relay,relay 只见密文;不用账号,不用架服务器 | 登录其服务后建链,LAN → P2P → TURN → Relay 逐级回退,也可自建 relay |
52
+ | 没电脑时 | Android 本地模式,DSH 跑在手机上 | — |
53
+ | 客户端 | Android、iOS(测试版) | PC、Android、Web,无 iOS 原生 App |
54
+ | 许可证 | MIT | 仓库未附许可证 |
55
+
43
56
  ## 下载与安装
44
57
 
45
58
  | 装在哪 | 下载 | 安装方式 |
46
59
  | --- | --- | --- |
47
60
  | 电脑 | — | `dsh plugin --profile web add dsh-plugin-tether` |
48
- | 手机 | [Release](../../releases/latest) 里的 `dsh-tether-<版本>-arm64.apk` | 已签名,直接安装 |
61
+ | 手机 | [Release](../../releases/latest) 里的 `dsh-tether-<版本>-arm64.apk` | 已签名,直接安装;内置本地模式 |
49
62
  | 手机(iOS) | [Release](../../releases/latest) 里的 `dsh-tether-<版本>-ios-unsigned.ipa` | **测试版**,未签名,需自签 |
50
63
 
51
64
  插件带一个 Rust 写的 sidecar 负责 iroh 连接,按平台拆成独立子包;安装时只会下载与你系统匹配的那一个,不用手动选。
52
65
 
53
- 手机端按 CPU 架构分了四个包,**近十年的安卓手机都选 `arm64`**;`arm` 给 32 位老设备,`x86` / `x86_64` 给模拟器和 ChromeOS。装错了系统会直接拒绝安装,不会装出问题。
66
+ 手机端按 CPU 架构分了四个包,**近十年的安卓手机都选 `arm64`**;`arm` 给 32 位老设备,`x86` / `x86_64` 给模拟器和 ChromeOS。装错了系统会直接拒绝安装,不会装出问题。只有 `arm64` 包带本地模式的运行时,其余三个包没有这个入口。
54
67
 
55
68
  iOS 版是**测试版**:本项目没有 Mac,该包只在 CI 上构建过,从未在真机上运行。需要用 AltStore、Sideloadly 一类工具自行签名(免费 Apple ID 签的应用 7 天过期)。遇到问题请提 issue。
56
69
 
@@ -70,6 +83,19 @@ dsh plugin --profile web add .
70
83
 
71
84
  之后每次打开 App 自动连上,不用再配对。
72
85
 
86
+ ## 本地模式:没电脑也能用(Android)
87
+
88
+ 打开 App → 顶栏「主机」→ **在本机运行**。第一次要先解压运行时(实测约 9 秒),之后每次约 2 秒出现 dsh 的界面;在设置里填上 API Key 就能对话。
89
+
90
+ - **装完即用**:不装 Termux、不开终端、不敲命令、不要 root。Node 24 与 dsh `0.1.2-rc.1` 的完整依赖树打在 APK 里,首次启动离线解压;之后只有调用模型 API 才需要网络。
91
+ - **没有配对**:dsh 就在这台手机上,没有远端。会话、设置、工作区只存在手机里,和连电脑时看到的完全是两套,来回切换互不影响。
92
+ - **常驻**:运行期间有一条常驻通知(前台服务),退后台、锁屏不会被系统收掉;进程真被杀了,下次打开 App 自动重起,会话已落盘不丢。
93
+ - **版本随 App 走**:内置的 dsh 随 App 升级一起升,当前内置 `0.1.2-rc.1`。
94
+ - 只有 `arm64` 的 APK 带本地模式;iOS 的沙箱不允许子进程,iOS 版没有这个入口。
95
+ - 手机上没有 bash 和完整的 coreutils,依赖 shell 的工具用不全;对话、文件读写不受影响。
96
+
97
+ 想走 Termux 的老路也行:在 Termux 里装好 dsh 和本插件(会自动选到 `android-arm64` 的 sidecar 子包),再用远程模式配对连接——手机自己也是一台「电脑」。这条路不做引导,只是仍然能用。
98
+
73
99
  ## 主要功能
74
100
 
75
101
  <table>
@@ -102,13 +128,15 @@ dsh plugin --profile web add .
102
128
  - 流量由 iroh 端到端加密(QUIC/TLS)。打洞成功时不经过任何第三方;退回 relay 时,relay 上过的也只是它读不懂的密文。
103
129
  - 插件自己那两条 HTTP 路由套了与 dsh `/api` 同一套浏览器信任判据:Host 必须是回环权威,跨站标记一律拒,带 Origin 时必须与 Host 同源。恶意网页的跨站请求和 DNS 重绑定都会拿到 403。
104
130
  - **已知边界**:上面那套判据防的是浏览器被当枪使,**挡不住本机进程**。本机进程的 Host 就是回环,能取到一个配对码,进而把自己配成一台「手机」。也就是说,**已经能在你开发机上执行代码的攻击者,可以借此拿到长期访问权**。若你的机器上会跑不受信任的代码,别用这个插件。
131
+ - **手机侧同样有边界**:App 在手机上起的本地代理只监听 127.0.0.1,但手机上其他 App 一样连得上,连上拿到的就是完整 dsh 界面;端口按主机派生固定,比随机端口更容易被找到。手机上装着不受信任的 App,或手机没锁屏落到别人手里,等同于开发机暴露。
105
132
 
106
133
  ## 已知限制
107
134
 
108
135
  - iOS 版是测试版:只在 CI 上构建,从未在真机运行过,且需要自行签名。安卓版是经过真机验证的那一个。
109
136
  - App 打开时才连接,不在后台常驻——Android 的 doze 也留不住它。
110
137
  - 手机上的界面是 DSH 自己的,窄屏适配靠注入的最小样式完成;dsh 改版式时可能需要跟进。
111
- - 已针对 dsh **`0.1.0-rc.7`**、**`0.1.0-rc.8`** 与 **`0.1.2-alpha`** 验证。dsh 处于 developer preview,换更新的 dsh 之前先看这一行。dsh 0.1.2-alpha 引入的浏览器认证完全在电脑侧处理,手机 App 无需更新。
138
+ - 本地模式只有 `arm64` 包有,iOS 没有;手机上没有 bash 与完整 coreutils,依赖 shell 的工具用不全。arm64 包因内置运行时约 71 MB,其余包约 32 MB。
139
+ - 已针对 dsh **`0.1.0-rc.7`**、**`0.1.0-rc.8`**、**`0.1.2`**(alpha 与 rc.1)与 **`0.1.5-alpha.1`** 验证。dsh 处于 developer preview,换更新的 dsh 之前先看这一行。dsh 0.1.2-alpha 引入的浏览器认证完全在电脑侧处理,手机 App 无需更新。
112
140
 
113
141
  ## 验证过什么
114
142
 
@@ -123,6 +151,8 @@ dsh plugin --profile web add .
123
151
 
124
152
  配对(含错码被拒)、审批送达、多设备切换都在真机上验证过。**打洞失败退回 relay 这条路径,尚未在真实网络下触发过。**
125
153
 
154
+ 本地模式在 Redmi(Android 16)真机验证:全新安装后首次启动到界面出现 9.1 秒(含解压运行时),之后启动 2.1 秒;退后台 30 秒 node 进程仍在;强杀 App 后重开自动恢复到本地模式。
155
+
126
156
  ## 与 DeepSeek Harness 的关系
127
157
 
128
158
  <p align="center"><img src="assets/dsh-mark.svg" height="36" alt="DeepSeek Harness"></p>
package/index.js CHANGED
@@ -86,11 +86,53 @@ function refuse(res) {
86
86
  res.end('forbidden')
87
87
  }
88
88
 
89
+ /** 与 sidecar 无关的部分:窄屏适配注入,以及手机上看配置文件的路由 */
90
+ function applyUi(ctx) {
91
+ ctx.effect(() => ctx.webServer.tapIndex(injectNarrowScreenCss))
92
+
93
+ // 「打开配置文件」在宿主机桌面开编辑器,手机上按了毫无反应。这条路由把同一份
94
+ // 文件的内容原样交给手机自己渲染。路径由 Host 侧的 settings.documentPath 决定,
95
+ // 不接受客户端传路径——否则就成了任意文件读取。
96
+ ctx.effect(() => ctx.webServer.register({
97
+ kind: 'exact',
98
+ path: CONFIG_DOCUMENT_PATH,
99
+ handler: async (req, res) => {
100
+ if (!isTrustedRequest(req)) return refuse(res)
101
+ const path = await ctx.settings.prepareDocument()
102
+ if (path === undefined) {
103
+ res.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' })
104
+ res.end('当前的设置存储不是本地文件,没有可查看的配置文件')
105
+ return
106
+ }
107
+ let text
108
+ try {
109
+ text = await readFile(path, 'utf8')
110
+ } catch (error) {
111
+ res.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' })
112
+ res.end(`读不到配置文件 ${path}: ${String(error)}`)
113
+ return
114
+ }
115
+ res.writeHead(200, {
116
+ 'content-type': 'application/json; charset=utf-8',
117
+ 'cache-control': 'no-store',
118
+ })
119
+ res.end(JSON.stringify({ path, text }))
120
+ },
121
+ }))
122
+ }
123
+
89
124
  /**
90
125
  * @param {import('@deepseek-ai/cordis').Context} ctx
91
- * @param {{hostBinary?: string, pair?: boolean}} [config]
126
+ * @param {{hostBinary?: string, pair?: boolean, sidecar?: boolean}} [config]
92
127
  */
93
128
  function apply(ctx, config = {}) {
129
+ // 手机 App 的本地模式:dsh 就跑在手机上,没有远端也没有配对,只要窄屏适配与
130
+ // 目录选择器替换(patch 里那两条)。侧栏底部的按钮在 iframe 里照样出现,它把
131
+ // 「打开主机页」交给外层 App,与远程模式一致。
132
+ if (config.sidecar === false) {
133
+ applyUi(ctx)
134
+ return
135
+ }
94
136
  const binary = config.hostBinary ?? resolveHostBinary()
95
137
  if (binary === undefined || !existsSync(binary)) {
96
138
  throw new Error(
@@ -185,7 +227,7 @@ function apply(ctx, config = {}) {
185
227
  }
186
228
  })
187
229
 
188
- ctx.effect(() => ctx.webServer.tapIndex(injectNarrowScreenCss))
230
+ applyUi(ctx)
189
231
 
190
232
  // dsh 0.1.2-alpha 起浏览器界面要求认证:进程启动 token 经 GET /?token= 换成
191
233
  // HMAC 签名 cookie,index 与 /api 无 cookie 一律 401。cookie 是 SameSite=Strict
@@ -225,36 +267,6 @@ function apply(ctx, config = {}) {
225
267
  connCtx.effect(() => () => clearInterval(timer))
226
268
  })
227
269
 
228
- // 「打开配置文件」在宿主机桌面开编辑器,手机上按了毫无反应。这条路由把同一份
229
- // 文件的内容原样交给手机自己渲染。路径由 Host 侧的 settings.documentPath 决定,
230
- // 不接受客户端传路径——否则就成了任意文件读取。
231
- ctx.effect(() => ctx.webServer.register({
232
- kind: 'exact',
233
- path: CONFIG_DOCUMENT_PATH,
234
- handler: async (req, res) => {
235
- if (!isTrustedRequest(req)) return refuse(res)
236
- const path = await ctx.settings.prepareDocument()
237
- if (path === undefined) {
238
- res.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' })
239
- res.end('当前的设置存储不是本地文件,没有可查看的配置文件')
240
- return
241
- }
242
- let text
243
- try {
244
- text = await readFile(path, 'utf8')
245
- } catch (error) {
246
- res.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' })
247
- res.end(`读不到配置文件 ${path}: ${String(error)}`)
248
- return
249
- }
250
- res.writeHead(200, {
251
- 'content-type': 'application/json; charset=utf-8',
252
- 'cache-control': 'no-store',
253
- })
254
- res.end(JSON.stringify({ path, text }))
255
- },
256
- }))
257
-
258
270
  // 配对窗口只在白名单为空时自动开一次;换手机、加第二台设备都得能再开一个,
259
271
  // 否则用户只能去手工删 paired.json。这条路由就是那个开关。
260
272
  ctx.effect(() => ctx.webServer.register({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-plugin-tether",
3
- "version": "0.1.12",
4
- "description": "Mobile client for the DeepSeek Harness — use the dsh on your dev machine from your Android or iOS phone, remotely across networks, peer-to-peer with no server in between (iroh)",
3
+ "version": "0.1.14",
4
+ "description": "Mobile client for the DeepSeek Harness — use the dsh on your dev machine from your Android or iOS phone, remotely across networks, peer-to-peer over iroh with no server to set up (falls back to a relay that only sees ciphertext)",
5
5
  "keywords": [
6
6
  "dsh",
7
7
  "dsh-plugin",
@@ -39,22 +39,26 @@
39
39
  "dsh": {
40
40
  "bundle": {
41
41
  "patch": "./cordis.patch.yml"
42
+ },
43
+ "androidRuntime": {
44
+ "node": "24.18.0",
45
+ "dsh": "0.1.2-rc.1"
42
46
  }
43
47
  },
44
48
  "peerDependencies": {
45
- "@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.7 <0.1.1-0 || >=0.1.2-alpha.0 <0.1.3-0",
46
- "@deepseek-ai/dsh-user-approval": ">=0.1.0-rc.7 <0.1.1-0 || >=0.1.2-alpha.0 <0.1.3-0"
49
+ "@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.7 <0.1.1-0 || >=0.1.2-alpha.0 <0.1.3-0 || >=0.1.5-alpha.0 <0.1.6-0",
50
+ "@deepseek-ai/dsh-user-approval": ">=0.1.0-rc.7 <0.1.1-0 || >=0.1.2-alpha.0 <0.1.3-0 || >=0.1.5-alpha.0 <0.1.6-0"
47
51
  },
48
52
  "peerDependenciesMeta": {
49
53
  "@deepseek-ai/dsh-host-webserver": { "optional": true },
50
54
  "@deepseek-ai/dsh-user-approval": { "optional": true }
51
55
  },
52
56
  "optionalDependencies": {
53
- "dsh-tether-host-android-arm64": "0.1.12",
54
- "dsh-tether-host-darwin-arm64": "0.1.12",
55
- "dsh-tether-host-darwin-x64": "0.1.12",
56
- "dsh-tether-host-linux-arm64": "0.1.12",
57
- "dsh-tether-host-linux-x64": "0.1.12",
58
- "dsh-tether-host-win32-x64": "0.1.12"
57
+ "dsh-tether-host-android-arm64": "0.1.14",
58
+ "dsh-tether-host-darwin-arm64": "0.1.14",
59
+ "dsh-tether-host-darwin-x64": "0.1.14",
60
+ "dsh-tether-host-linux-arm64": "0.1.14",
61
+ "dsh-tether-host-linux-x64": "0.1.14",
62
+ "dsh-tether-host-win32-x64": "0.1.14"
59
63
  }
60
64
  }