dsh-whale-link 0.0.1 → 0.16.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Liming Xie
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,33 +1,205 @@
1
- # dsh-whale-link
1
+ # WhaleLink for DSH
2
2
 
3
- **Name reservation package.** This package currently exists only to reserve the
4
- `dsh-whale-link` name on npm.
3
+ **Other languages**: [简体中文](README.zh.md)
5
4
 
6
- ## Status
5
+ ## What is WhaleLink
6
+
7
+ WhaleLink (鲸语通) is a **voice assistant**: talk to your agents instead of typing, and have the replies read aloud. Your agent goes where you go.
8
+
9
+ - **Speak to type.** Say a sentence and it becomes text in the input box; segments accumulate and can be edited before sending — no mode switching. Choose system recognition or offline on-device recognition, so your voice never leaves the device.
10
+ - **Read aloud.** Replies are read automatically; voice and speed are yours to set, so you can listen while doing something else.
11
+ - **One place for every host.** Every joined host lives in the same list — no addresses or ports to remember, one entry point however many hosts you have.
12
+ - **LAN-direct first.** On the same network it connects directly, for lower latency and less data; elsewhere it falls back to encrypted relay automatically — no config juggling.
13
+ - **Reachable from anywhere.** The host opens an outbound tunnel that traverses NAT and firewalls (outbound only), so your phone can reach your machine on any network.
14
+
15
+ ## What this plugin is
16
+
17
+ `dsh-whale-link` is the **DSH desktop plugin** for WhaleLink — the "join" half: it connects the computer running DSH to WhaleLink (a **WhaleLink** section appears in DSH's Settings). Once joined, that computer shows up in your WhaleLink **host list** alongside your other hosts, and you open it from the app or a browser. Voice input and read-aloud come from the WhaleLink app, not from this plugin.
18
+
19
+ ## Features
20
+
21
+ - **A panel, not a terminal.** Join, disconnect, revoke and status all live in **Settings → WhaleLink**.
22
+ - **Two ways to join.** Paste the one-time auth token from WhaleLink's web portal, or scan a QR code with the WhaleLink app.
23
+ - **Pause without losing the binding.** *Disconnect* stops the tunnel and keeps the token; *Revoke* clears the local binding and asks WhaleLink to revoke the host.
24
+ - **Optional access code.** A lock that belongs to you alone: anyone reaching this host — including the service operator — must enter it. On/off at any time.
25
+ - **Diagnostics & repair.** See which process holds the tunnel, which other copies of the plugin are installed on this machine, and clear a stale lock.
26
+ - **Directory picking works remotely.** The plugin pins DSH's directory picker to the **in-app browser**, because a remote browser can never reach a native OS dialog on the host's screen.
27
+
28
+ ## Requirements
7
29
 
8
30
  | | |
9
31
  |---|---|
10
- | Implementation | ❌ not here — the working plugin is [`dsh-web-remote`](../web-remote) |
11
- | Installable | ❌ not yet — `index.js` deliberately throws |
12
- | Purpose | reserve the branded name so it can be used later |
32
+ | DSH | **DSH Desktop**, or a command-line DSH (`dsh web`) with plugin support |
33
+ | Server | The hosted WhaleLink service (the panel pre-fills `https://rdsh.cn`), or a service you deploy yourself — see [remote-dsh](https://github.com/floatinghotpot/remote-dsh) |
34
+ | `pnpm` | Only needed if you install through DSH's **Plugins** screen |
35
+
36
+ ## Install
37
+
38
+ Two ways; pick the one that matches how you run DSH.
39
+
40
+ ### A. DSH Desktop
41
+
42
+ In **DSH Desktop**: **Plugins** → **Add plugin** → enter `dsh-whale-link`.
43
+
44
+ **⚠️ After installing, restart DSH.** Installing or upgrading can make the plugin page report an error such as "directory picker is already registered". Why:
45
+
46
+ 1. DSH's directory picker is a single service (`directoryPicker`) with exactly two implementations: `native` (an OS dialog on the host) and `browse` (browsing inside the page).
47
+ 2. The `native` dialog is drawn on the host's screen — a remote user on a phone or in a browser can neither see nor click it, so directory picking does not exist for remote sessions.
48
+ 3. The `auto` chooser resolves to `native` on a desktop build (display present, loopback bind, not SSH), so the plugin must replace it with `browse` at boot — and that replacement can only come from a patch layer, not from a live apply.
49
+
50
+ **Quit and reopen DSH**: the plugin pins the picker back to `browse`, the error disappears, and remote sessions can pick directories again.
51
+
52
+ ### B. Command line / cloud server / embedded Linux (prefer launching DSH with remote-dsh)
53
+
54
+ If DSH runs on a cloud server or an embedded Linux box such as a Raspberry Pi, **prefer launching and supervising DSH with [`remote-dsh`](https://github.com/floatinghotpot/remote-dsh)'s `rdsh`** instead of installing this plugin: `rdsh` starts DSH for you and can run as a system service — start on boot, restart on failure.
55
+
56
+ ```bash
57
+ npm install -g remote-dsh
58
+ rdsh join https://rdsh.cn # paste the one-time auth token from WhaleLink's web portal
59
+ rdsh serve # foreground: rdsh starts and supervises dsh web
60
+ rdsh service install # systemd (Linux) / launchd (macOS): start on boot, restart on failure
61
+ ```
62
+
63
+ - Start on boot **without a login**: `sudo loginctl enable-linger $USER` (user services otherwise run only while logged in).
64
+ - Status and logs: `rdsh service status`, `journalctl --user -u rdsh-join -f`.
65
+
66
+ If you do want the plugin in the command-line form (managing DSH yourself), install it into the profile and start DSH yourself:
67
+
68
+ ```bash
69
+ dsh plugin --profile <name> add dsh-whale-link
70
+ dsh --profile <name> # same as: dsh <name>
71
+ ```
72
+
73
+ > One tunnel, one owner: while `rdsh` runs, the plugin panel shows "Managed by another instance on this machine" and stays read-only. Pick one; do not run both.
74
+
75
+ ## Usage
76
+
77
+ ### 1. Join this computer
78
+
79
+ **Recommended: scan with the WhaleLink app.**
80
+
81
+ 1. In DSH open **Settings → WhaleLink** and click **Scan to connect**;
82
+ 2. In the WhaleLink app, open the host list, go to **Remote Agents** → **Scan to add**, and scan the QR code;
83
+ 3. When the panel shows **Connected**, the host is in your host list.
84
+
85
+ **Or join with a token** (handier when you only have the computer):
86
+
87
+ 1. On WhaleLink's web portal choose **Add host** and copy the **server URL** and the **auth token** it shows (shown once);
88
+ 2. Open **Settings → WhaleLink**. The server URL is pre-filled; change it only for your own deployment;
89
+ 3. Paste the **auth token**, optionally set **this host's name**, and click **Connect**.
90
+
91
+ The token is stored on this machine after the first join, so you will not paste it again.
92
+
93
+ ### 2. Reach it from anywhere
94
+
95
+ **The WhaleLink app is the recommended way**: sign in and tap this host in the host list — your phone is the entry point, and every host sits in the same list.
96
+
97
+ On a computer you can also **use a browser**: open WhaleLink's web portal, sign in, and tap this host in the host list. The app and the portal show the same host list.
98
+
99
+ ### 3. Nothing to do day to day
100
+
101
+ Once joined, there is **nothing to operate**: every time DSH starts, the plugin joins and reconnects automatically; a dropped tunnel recovers by itself, and the panel status is always live.
102
+
103
+ Only reach for the panel to pause or unbind:
104
+
105
+ | Action | Effect |
106
+ |---|---|
107
+ | **Disconnect** | Pauses this connection and keeps config and auth; click **Connect** or start DSH again to resume. (The LAN listener keeps serving your network.) |
108
+ | **Revoke** | Unbinds completely: removes the local binding and token and asks WhaleLink to revoke this host (best effort; a failure is reported in the panel); the panel returns to *Not joined*. |
109
+
110
+ ### Panel status
111
+
112
+ | Status | Meaning |
113
+ |---|---|
114
+ | Not joined | Never joined, or revoked |
115
+ | Connecting… / Reconnecting… | Establishing the tunnel, or auto-recovering after a drop |
116
+ | Connected | Reachable from outside right now |
117
+ | Disconnected (config kept) | Joined before, currently paused |
118
+ | Managed by another instance on this machine | The `rdsh` CLI or another DSH runs the tunnel; the panel is read-only |
119
+
120
+ ## Where your data lives
121
+
122
+ Everything is kept under `~/.rdsh/` (override the host config path with `RDSH_CONFIG`):
123
+
124
+ | Path | Contents |
125
+ |---|---|
126
+ | `host.json` | Host config (`mode`, `hub`, `name`, access code, compatibility flag) |
127
+ | `join-<host>[-<port>].token` | Persisted host token (`0600`) |
128
+ | `e2ee-key.json` | Host end-to-end encryption key pair (`0600`) |
129
+ | `direct-secret` | Per-host secret for LAN-direct tickets (`0600`) |
130
+ | `join.lock` | Which process currently runs the tunnel (`0600`) |
131
+ | `device-id` | Stable per-device identifier (`0600`) |
132
+ | `rdsh-meta.json` | Reported device kind and component versions |
133
+
134
+ Deleting these is the same as "never joined", but prefer **Revoke** — it also asks WhaleLink to revoke the host.
135
+
136
+ ## How it works
13
137
 
14
- ## Background
138
+ - **Server half** runs in DSH's **plugin host process** (a Cordis function plugin): in DSH Desktop that is the desktop app's main process, and in the command-line form it is the `dsh web` process — the plugin and DSH's server are the same process, and no extra process is started. It opens an **outbound** tunnel to WhaleLink through [`rdsh-gateway`](https://www.npmjs.com/package/rdsh-gateway) and forwards traffic to the local DSH web server (`127.0.0.1:<webServer.port>`). No inbound public port is opened.
139
+ - **LAN direct** listens on a separate local port (default `8442`) while joined. It is gated by a one-time ticket signed with a per-host secret; the optional access code is an additional layer.
140
+ - **Browser half** is a hand-written `window.__ModuleLoader__` module that registers the **Settings → WhaleLink** section and talks to the server half over the plugin's own `/remote-access` RPC route.
141
+ - **End-to-end encryption** is carried by the tunnel: the relay forwards ciphertext and cannot read sessions or files.
15
142
 
16
- The remote-access plugin is published as **`dsh-web-remote`** (a descriptive
17
- name). **`dsh-whale-link`** is the branded name for the same product. Both
18
- names should be kept available and published together in the future, so this
19
- placeholder reserves the name before someone else takes it.
143
+ ## Migrating from the old name `dsh-web-remote`
20
144
 
21
- ## Options under discussion
145
+ This plugin used to be called **`dsh-web-remote`**; it is now **`dsh-whale-link`**. They are one plugin with one implementation and **must not be installed into the same DSH profile**:
22
146
 
23
- Once the loading strategy is settled, this package will become one of:
147
+ - both patches disable `directory-picker` and insert a `directory-picker-browse` row, which the loader rejects as `duplicate loader entry id` (duplicate `directoryPicker` service) — **DSH will not start**;
148
+ - both expose the same `/remote-access` RPC route and compete for the same machine-level `~/.rdsh/join.lock`.
149
+
150
+ **If you have the old package installed, remove it first, then install the new one:**
151
+
152
+ ```bash
153
+ dsh plugin --profile <name> remove dsh-web-remote
154
+ dsh plugin --profile <name> add dsh-whale-link
155
+ ```
156
+
157
+ You can also uninstall and install from DSH Desktop's plugin screens. **Restart DSH** afterwards.
158
+
159
+ **No re-joining needed.** The host config and auth token live in `~/.rdsh/`, independent of the package name; after switching packages the existing host joins automatically, and the panel status and access code are preserved.
160
+
161
+ ## Security notes
162
+
163
+ - **Only your account gets in.** Joining does not open a door: a host is reachable only by the account that owns it.
164
+ - **Transport is encrypted end to end.** The relay sees connection metadata, not your conversations or files.
165
+ - **A local lock you control.** The optional access code is verified on this host, so even the service operator cannot get past it.
166
+ - **Revoke leaves nothing behind.** *Revoke* removes the local binding and token and asks WhaleLink to revoke the host.
167
+ - The plugin opens no inbound public port. The tunnel runs only while joined; the LAN listener keeps serving your local network while the host stays in join mode (ticket-gated, and code-gated when an access code is set).
168
+
169
+ ## Related project
170
+
171
+ [**remote-dsh**](https://github.com/floatinghotpot/remote-dsh) (code name `rdsh`) is the open-source project behind this system, MIT licensed and public on GitHub:
172
+
173
+ - **Connection platform**: `rdsh-hub` (accounts, host registration and routing, with a built-in relay) + `rdsh-portal` (the web portal);
174
+ - **Host-side gateway**: the `rdsh` command line — the one that turns DSH into a resident service on servers and embedded devices (see Install B);
175
+ - **Protocols and public API**: the tunnel protocol and public API docs, for third-party clients;
176
+ - `rdsh-gateway`, which this plugin depends on, is published from there.
177
+
178
+ Start there if you want to deploy the service yourself, or avoid the hosted service.
179
+
180
+ ## Development
181
+
182
+ Requires **Node.js ≥ 22** and **pnpm ≥ 9**.
183
+
184
+ ```bash
185
+ pnpm install
186
+ pnpm build # tsc, strict
187
+ pnpm test # node --test
188
+ ```
189
+
190
+ | Path | Contents |
191
+ |---|---|
192
+ | `src/index.ts` | Server half: tunnel lifecycle, direct listener, RPC dispatch |
193
+ | `src/rpc-route.ts` | The `/remote-access` prefix route and its envelope |
194
+ | `src/lock-diagnostics.ts` | Lock-holder classification and install scanning |
195
+ | `client.js` | Browser half: the Settings section |
196
+ | `cordis.patch.yml` | Bundle patch: mounts the plugin row and pins the directory picker |
197
+ | `locale/` | `meta.title` / `meta.description` / `meta.detail` for the DSH plugin pages |
198
+ | `docs/` | Plugin detail page body (English `DETAIL.md` / Chinese `DETAIL.zh.md`) |
199
+ | `icon.svg` | Plugin icon |
24
200
 
25
- - **(a) Thin wrapper** — keep the implementation in `dsh-web-remote` and have
26
- this package re-export it (`export * from "dsh-web-remote"` plus its own
27
- `cordis.patch.yml`). No duplicated code; recommended.
28
- - **(b) Full package** — move the implementation here.
201
+ Runtime dependency: `rdsh-gateway` — the host-side tunnel implementation, published from [remote-dsh](https://github.com/floatinghotpot/remote-dsh). The exact version is pinned in [package.json](package.json); no range is used.
29
202
 
30
- ## Do not install yet
203
+ ## License
31
204
 
32
- `dsh plugin add dsh-whale-link` will fail until one of the options above is
33
- implemented. Use `dsh-web-remote` in the meantime.
205
+ Code is released under the **MIT License** — see [LICENSE](LICENSE). The **WhaleLink / 鲸语通** name and logo are brand assets and are **not** covered by the MIT grant — see [NOTICE](NOTICE).
package/README.zh.md ADDED
@@ -0,0 +1,205 @@
1
+ # WhaleLink(鲸语通)DSH 插件
2
+
3
+ **其他语言**:[English](README.md)
4
+
5
+ ## 鲸语通是什么
6
+
7
+ 鲸语通(WhaleLink)是**语音助手**——用语音和智能体沟通,无需打字,回复可以直接念出来。让智能体随身而行。
8
+
9
+ - **说话就是输入法。** 说一句话,文字直接写进输入框;可多段累积、编辑后再发送,不用切换模式。可选系统识别或离线本地识别,声音不出本机。
10
+ - **朗读回复。** 智能体的回复自动朗读,音色、语速随心调,边走边听、不必盯屏。
11
+ - **一处管理所有主机。** 接入的主机都在同一个列表里,不用记一堆地址和端口——主机再多也只有一个入口。
12
+ - **内网直连优先。** 同一网络下优先直连,延迟更低、更省流量;不在同一网络时自动走加密中转,不用来回改配置。
13
+ - **随时随地访问。** 主机主动建立出站隧道,穿透 NAT 与防火墙(只出不进),手机在任何网络下都能安全连回自己的机器。
14
+
15
+ ## 这个插件是什么
16
+
17
+ `dsh-whale-link` 是鲸语通的 **DSH 桌面端插件**——负责「接入」这一半:把运行 DSH 的这台电脑接进鲸语通(DSH 的「设置」里会多出一个 **WhaleLink** 面板)。接入之后,这台电脑就出现在鲸语通的**主机列表**里,和你的其他主机一起集中管理;用手机或浏览器都能点进去。语音输入与朗读由鲸语通 App 提供,不在本插件内。
18
+
19
+ ## 功能
20
+
21
+ - **在面板里完成,不用命令行。** 接入、断开、注销、状态,都在 **设置 → WhaleLink**。
22
+ - **两种接入方式。** 粘贴鲸语通网页版给出的一次性授权令牌,或用「鲸语通」App 扫码。
23
+ - **暂停不丢绑定。**「断开」只停隧道、保留令牌;「注销」清掉本地绑定并请求鲸语通吊销这台主机。
24
+ - **可选访问口令。** 只有你知道的一层锁:任何人(包括服务提供方)要进入这台主机都得先输对口令。随时开启/关闭。
25
+ - **诊断与修复。** 能看到是谁占着隧道、本机还装了哪些份插件,以及清掉残留锁。
26
+ - **远程也能选目录。** 插件把 DSH 的目录选择器固定为**浏览器内**形态——远端浏览器永远够不到宿主屏幕上的原生系统对话框。
27
+
28
+ ## 环境要求
29
+
30
+ | | |
31
+ |---|---|
32
+ | DSH | **DSH Desktop**,或支持插件、命令行启动的 DSH(`dsh web`) |
33
+ | 服务器 | 鲸语通托管服务(面板已预填 `https://rdsh.cn`),或你自己部署的服务——见 [remote-dsh](https://github.com/floatinghotpot/remote-dsh) |
34
+ | `pnpm` | 仅当通过 DSH 的**插件**界面安装时需要 |
35
+
36
+ ## 安装
37
+
38
+ 两种形态,按你跑 DSH 的方式选一条。
39
+
40
+ ### A. DSH Desktop(桌面版)
41
+
42
+ 在 **DSH Desktop** 里:**插件** → **添加插件** → 输入 `dsh-whale-link`。
43
+
44
+ **⚠️ 安装后,请重启 DSH。** 安装或升级后,插件页可能显示「目录选择器已注册」之类的异常。原因是:
45
+
46
+ 1. DSH 的目录选择器是一个单例服务(`directoryPicker`),只有两种实现:`native`(弹宿主 OS 对话框)和 `browse`(在页面里浏览)。
47
+ 2. `native` 的对话框画在宿主屏幕上——远端用户在自己手机/浏览器里根本看不见、也点不到,选目录这个功能对远端等于没有。
48
+ 3. `auto` 选择器默认会在桌面版选 `native`(有显示器、loopback、非 SSH),所以插件必须在启动时把它替换成 `browse`;而替换只能靠 patch 层,热应用来不及。
49
+
50
+ **完全退出并重新打开 DSH 后**,插件会把选择器重新固定为 `browse`,异常消失,远端即可选目录。
51
+
52
+ ### B. 命令行 / 云服务器 / 嵌入式 Linux(推荐用 remote-dsh 启动 DSH)
53
+
54
+ 如果 DSH 跑在云服务器、或树莓派这类嵌入式 Linux 上,**更推荐直接用 [`remote-dsh`](https://github.com/floatinghotpot/remote-dsh) 的 `rdsh` 来启动并托管 DSH**,而不是装这个插件:`rdsh` 会把 DSH 拉起来、并可以作为系统服务常驻,开机自启、崩溃自动重启。
55
+
56
+ ```bash
57
+ npm install -g remote-dsh
58
+ rdsh join https://rdsh.cn # 按提示粘贴鲸语通网页版给出的一次性授权令牌
59
+ rdsh serve # 前台运行:rdsh 自动拉起并托管 dsh web
60
+ rdsh service install # 装成服务:systemd(Linux)/ launchd(macOS),开机自启、崩溃自动重启
61
+ ```
62
+
63
+ - 想让**开机免登录**也自启:`sudo loginctl enable-linger $USER`(用户级服务默认只在登录期间运行)。
64
+ - 状态与日志:`rdsh service status`、`journalctl --user -u rdsh-join -f`。
65
+
66
+ 如果你确实要在命令行形态下用这个插件(自己管理 DSH 进程),那就装到目标 profile 后自行启动:
67
+
68
+ ```bash
69
+ dsh plugin --profile <name> add dsh-whale-link
70
+ dsh --profile <name> # 启动该 profile(等价写法:dsh <name>)
71
+ ```
72
+
73
+ > 同一条隧道只能有一个托管者:`rdsh` 正在跑时,插件面板会显示「已接入(由本机其它实例托管)」并保持只读。二选一,不要两边同时开。
74
+
75
+ ## 使用
76
+
77
+ ### 1. 接入本机
78
+
79
+ **推荐:用「鲸语通」App 扫码接入。**
80
+
81
+ 1. 在 DSH 里打开 **设置 → WhaleLink**,点「**扫码接入**」;
82
+ 2. 用「鲸语通」App 打开「地址列表」,在「远程智能体」一节点「**扫码添加**」,扫面板上的二维码;
83
+ 3. 面板显示「已连接」即完成,这台主机已出现在你的主机列表里。
84
+
85
+ **也可以用令牌接入**(手上只有电脑时更方便):
86
+
87
+ 1. 在鲸语通网页版「添加主机」,复制页面给出的**服务器地址**与**授权令牌**(只显示一次);
88
+ 2. 打开 **设置 → WhaleLink**。服务器地址已预填,只有自建服务才需要改;
89
+ 3. 粘贴**授权令牌**,可填**主机名称**,点「**接入**」。
90
+
91
+ 接入成功后令牌会存在本机,以后再接入不必重新粘贴。
92
+
93
+ ### 2. 从任何地方访问它
94
+
95
+ **推荐用「鲸语通」App**:登录后,在主机列表里点这台主机——手机就是你的入口,再多主机也都在同一个列表里。
96
+
97
+ 在电脑上也可以**直接用浏览器**:打开鲸语通网页版,登录,在主机列表里点这台主机。App 和网页版看到的是同一份主机列表。
98
+
99
+ ### 3. 平时不用管
100
+
101
+ 绑定并连上之后,就**不需要再做任何操作**:每次 DSH 启动,插件会自动接入、自动重连;中途掉线也会自己恢复,面板状态始终是实时的。
102
+
103
+ 只有需要暂停或解绑时,才去面板点一下:
104
+
105
+ | 操作 | 效果 |
106
+ |---|---|
107
+ | **断开** | 暂停这次连接,配置与授权保留;点「接入」或下次启动 DSH 会自动恢复。(内网直连口仍继续服务本网段。) |
108
+ | **注销** | 彻底解绑:删除本地绑定与令牌,并请求鲸语通吊销这台主机(尽力而为,失败会在面板提示);面板回到「未接入」。 |
109
+
110
+ ### 面板状态
111
+
112
+ | 状态 | 含义 |
113
+ |---|---|
114
+ | 未接入 | 从未接入,或已注销 |
115
+ | 连接中…/断线重连… | 正在建立隧道,或掉线后自动恢复 |
116
+ | 已连接 | 此刻可从外网访问 |
117
+ | 未接入(已断开,配置保留) | 曾接入过,当前暂停 |
118
+ | 已接入(由本机其它实例托管) | 本机的 `rdsh` CLI 或另一个 DSH 在用隧道,面板只读 |
119
+
120
+ ## 数据存在哪
121
+
122
+ 全部在 `~/.rdsh/` 下(host 配置路径可用 `RDSH_CONFIG` 覆盖):
123
+
124
+ | 路径 | 内容 |
125
+ |---|---|
126
+ | `host.json` | 主机配置(`mode`、`hub`、`name`、访问口令、兼容开关) |
127
+ | `join-<host>[-<port>].token` | 持久化的 host 令牌(`0600`) |
128
+ | `e2ee-key.json` | 主机端端到端加密密钥对(`0600`) |
129
+ | `direct-secret` | 内网直连票据的 per-host 密钥(`0600`) |
130
+ | `join.lock` | 当前哪个进程在跑隧道(`0600`) |
131
+ | `device-id` | 稳定的设备标识(`0600`) |
132
+ | `rdsh-meta.json` | 上报的设备类型与组件版本 |
133
+
134
+ 删掉这些文件等同于“从未接入”,但推荐用「注销」——它还会请求鲸语通吊销主机。
135
+
136
+ ## 工作原理
137
+
138
+ - **服务端半**跑在 DSH 的**插件宿主进程**里(Cordis 函数插件):DSH Desktop 就是桌面应用的主进程,命令行形态是 `dsh web` 的进程——插件和 DSH 的服务端本来就同一个进程,不需要另起进程。它通过 [`rdsh-gateway`](https://www.npmjs.com/package/rdsh-gateway) 向鲸语通服务建立**出站**隧道,并把流量转发给本机的 DSH Web 服务(`127.0.0.1:<webServer.port>`)。不在公网开任何入站端口。
139
+ - **内网直连**在接入期间额外监听一个本机端口(默认 `8442`),由 per-host 密钥签名的**一次性票据**把守;访问口令是可选的额外一层。
140
+ - **浏览器半**是手写的 `window.__ModuleLoader__` 模块,注册 **设置 → WhaleLink** 分区,并通过插件自己的 `/remote-access` RPC 路由与服务端半通信。
141
+ - **端到端加密**由隧道承载:中转只转发密文,读不到会话内容与文件。
142
+
143
+ ## ⚠️ 从旧名字 `dsh-web-remote` 迁移
144
+
145
+ 这个插件以前叫 **`dsh-web-remote`**,现在统一为 **`dsh-whale-link`**。两者是同一个插件、同一套实现,**不能装进同一个 DSH profile**:
146
+
147
+ - 两份 patch 都会禁用 `directory-picker` 并插入 `directory-picker-browse` 行,loader 会判定 `duplicate loader entry id`(`directoryPicker` 服务重复)——**DSH 无法启动**;
148
+ - 两者暴露同一个 `/remote-access` RPC 路由,并争抢同一把机器级 `~/.rdsh/join.lock`。
149
+
150
+ **已经装了旧包的,先卸旧的,再装新的:**
151
+
152
+ ```bash
153
+ dsh plugin --profile <name> remove dsh-web-remote
154
+ dsh plugin --profile <name> add dsh-whale-link
155
+ ```
156
+
157
+ DSH Desktop 里也可以直接在插件界面卸载旧的、安装新的。装完**重启 DSH**。
158
+
159
+ **不用重新接入。** 主机配置与授权令牌都在 `~/.rdsh/` 下,跟包名无关;换包后原来的主机仍会自动接入,面板状态和访问口令也都保留。
160
+
161
+ ## 安全说明
162
+
163
+ - **只有你的账号进得来。** 接入不是“开门”:一台主机只对它所属的账号可达。
164
+ - **传输端到端加密。** 中转只看到连接元数据,看不到你的对话与文件。
165
+ - **本机还有你的一把锁。** 可选访问口令在本机校验,连服务运营方也绕不过去。
166
+ - **注销即清空。**「注销」删除本地绑定与令牌,并请求鲸语通吊销主机。
167
+ - 插件不开公网入站端口。隧道只在接入期间运行;内网直连口在主机保持 join 模式期间继续服务本网段(受票据把守,设了口令时还要过口令)。
168
+
169
+ ## 相关项目
170
+
171
+ [**remote-dsh**](https://github.com/floatinghotpot/remote-dsh)(代码名 `rdsh`)是本套系统的开源项目,MIT 协议,在 GitHub 上公开:
172
+
173
+ - **连接平台**:`rdsh-hub`(账号、主机注册与路由,含内置中转)+ `rdsh-portal`(网页版);
174
+ - **主机侧网关**:`rdsh` 命令行——在服务器 / 嵌入式设备上把 DSH 做成常驻服务用的就是它(见「安装」B);
175
+ - **协议与对外 API**:隧道协议和对外 API 文档,供第三方接入;
176
+ - 本插件依赖的 `rdsh-gateway` 也由它发布。
177
+
178
+ 想自己部署服务、或不想使用托管服务时,从那里开始。
179
+
180
+ ## 开发
181
+
182
+ 需要 **Node.js ≥ 22** 与 **pnpm ≥ 9**。
183
+
184
+ ```bash
185
+ pnpm install
186
+ pnpm build # tsc(strict)
187
+ pnpm test # node --test
188
+ ```
189
+
190
+ | 路径 | 内容 |
191
+ |---|---|
192
+ | `src/index.ts` | 服务端半:隧道生命周期、直连口、RPC 分发 |
193
+ | `src/rpc-route.ts` | `/remote-access` 前缀路由与其信封 |
194
+ | `src/lock-diagnostics.ts` | 锁持有者分类、本机安装扫描 |
195
+ | `client.js` | 浏览器半:设置分区 |
196
+ | `cordis.patch.yml` | Bundle patch:挂载插件行并固定目录选择器 |
197
+ | `locale/` | DSH 插件页面的 `meta.title` / `meta.description` / `meta.detail` |
198
+ | `docs/` | 插件详情页正文(中文 `DETAIL.zh.md` / 英文 `DETAIL.md`) |
199
+ | `icon.svg` | 插件图标 |
200
+
201
+ 运行时依赖:`rdsh-gateway`——主机侧隧道实现,由 [remote-dsh](https://github.com/floatinghotpot/remote-dsh) 发布。具体版本以 [package.json](package.json) 为准(精确钉死,不用范围)。
202
+
203
+ ## 许可
204
+
205
+ 代码以 **MIT** 许可发布——见 [LICENSE](LICENSE)。**WhaleLink / 鲸语通**名称与 logo 属品牌资产,**不在** MIT 授权范围内——见 [NOTICE](NOTICE)。