dsh-plugin-dshm 0.0.0-stage → 0.1.1

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.
Files changed (82) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +232 -2
  4. package/README.zh-CN.md +194 -0
  5. package/cordis.patch.yml +7 -0
  6. package/lib/auth/signature.d.ts +4 -0
  7. package/lib/auth/signature.js +24 -0
  8. package/lib/cli/index.d.ts +4 -0
  9. package/lib/cli/index.js +41 -0
  10. package/lib/client.js +419 -0
  11. package/lib/config.d.ts +10 -0
  12. package/lib/config.js +27 -0
  13. package/lib/discovery/advertiser.d.ts +45 -0
  14. package/lib/discovery/advertiser.js +141 -0
  15. package/lib/discovery/interfaces.d.ts +5 -0
  16. package/lib/discovery/interfaces.js +24 -0
  17. package/lib/errors.d.ts +5 -0
  18. package/lib/errors.js +10 -0
  19. package/lib/host/local.d.ts +5 -0
  20. package/lib/host/local.js +122 -0
  21. package/lib/host/tailscale.d.ts +43 -0
  22. package/lib/host/tailscale.js +137 -0
  23. package/lib/host/types.d.ts +40 -0
  24. package/lib/host/types.js +1 -0
  25. package/lib/index.d.ts +30 -0
  26. package/lib/index.js +98 -0
  27. package/lib/methods/index.d.ts +9 -0
  28. package/lib/methods/index.js +206 -0
  29. package/lib/pairing/state.d.ts +26 -0
  30. package/lib/pairing/state.js +89 -0
  31. package/lib/pairing/window.d.ts +18 -0
  32. package/lib/pairing/window.js +57 -0
  33. package/lib/projection/client.d.mts +2 -0
  34. package/lib/projection/client.mjs +11 -0
  35. package/lib/projection/compatibility.d.mts +2 -0
  36. package/lib/projection/compatibility.mjs +4 -0
  37. package/lib/projection/files.d.ts +33 -0
  38. package/lib/projection/files.js +278 -0
  39. package/lib/projection/fold-recording.d.mts +50 -0
  40. package/lib/projection/fold-recording.mjs +440 -0
  41. package/lib/projection/host.d.ts +6 -0
  42. package/lib/projection/host.js +86 -0
  43. package/lib/projection/ids.d.mts +1 -0
  44. package/lib/projection/ids.mjs +1 -0
  45. package/lib/projection/index.d.ts +2 -0
  46. package/lib/projection/index.js +2 -0
  47. package/lib/projection/interactions.d.ts +10 -0
  48. package/lib/projection/interactions.js +73 -0
  49. package/lib/projection/native.d.ts +115 -0
  50. package/lib/projection/native.js +915 -0
  51. package/lib/protocol/THIRD_PARTY_LICENSES.txt +135 -0
  52. package/lib/protocol/dmp.d.ts +402 -0
  53. package/lib/protocol/dmp.js +1 -0
  54. package/lib/protocol/schema/dmp-v1/common.schema.json +88 -0
  55. package/lib/protocol/schema/dmp-v1/events.schema.json +107 -0
  56. package/lib/protocol/schema/dmp-v1/frames.schema.json +280 -0
  57. package/lib/protocol/schema/dmp-v1/methods.schema.json +584 -0
  58. package/lib/protocol/schema/dmp-v1/models.schema.json +674 -0
  59. package/lib/protocol/scripts/contract.mjs +8106 -0
  60. package/lib/push/controller.d.ts +64 -0
  61. package/lib/push/controller.js +290 -0
  62. package/lib/push/observer.d.ts +51 -0
  63. package/lib/push/observer.js +266 -0
  64. package/lib/push/payload.d.ts +15 -0
  65. package/lib/push/payload.js +18 -0
  66. package/lib/push/store.d.ts +17 -0
  67. package/lib/push/store.js +75 -0
  68. package/lib/server/index.d.ts +30 -0
  69. package/lib/server/index.js +500 -0
  70. package/lib/server/rate-limit.d.ts +7 -0
  71. package/lib/server/rate-limit.js +19 -0
  72. package/lib/server/uploads.d.ts +21 -0
  73. package/lib/server/uploads.js +74 -0
  74. package/lib/types.d.ts +92 -0
  75. package/lib/types.js +1 -0
  76. package/lib/ui/card.d.mts +3 -0
  77. package/lib/ui/card.mjs +59 -0
  78. package/lib/ui/copy.d.mts +146 -0
  79. package/lib/ui/copy.mjs +106 -0
  80. package/lib/ui/remote-setup.d.mts +81 -0
  81. package/lib/ui/remote-setup.mjs +75 -0
  82. package/package.json +67 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## 0.1.1 — Unreleased
4
+
5
+ - Support DSH 0.2.1-rc.5 (npm latest verified 2026-10-30), retaining exact
6
+ support for 0.2.1-rc.3. Other prereleases and future versions remain blocked.
7
+ - Include the previously verified task-032 interaction-status correction:
8
+ concurrent read/correlation timeouts publish the native running/idle fallback
9
+ and its warning before returning a session snapshot.
10
+ - Native macOS integration covers approvals/questions, reconnects, transfers,
11
+ path policy and restart. Windows verification of this new combination is
12
+ pending; no new Windows compatibility result is claimed.
13
+
14
+ ## 0.1.0 — 2026-10-28
15
+
16
+ Initial DSHM bridge release for DeepSeek Harness 0.2.1-rc.3.
17
+
18
+ - Pair an iPhone or iPad using a short-lived code and pinned TLS; authenticate
19
+ paired devices and revoke access from the DSH settings card.
20
+ - Follow sessions, send prompts, answer approvals/questions and transfer files
21
+ over a reachable private network or the user's own VPN.
22
+ - English and Simplified Chinese settings card with optional Tailscale setup
23
+ guidance under “Not on the same Wi-Fi / 不在同一 Wi-Fi”.
24
+ - Optional encrypted push sender; proxy deployment and real-device notification
25
+ delivery are separate from this package's local verification.
26
+ - MIT license and a separate plugin-only public source repository. The iOS app,
27
+ private development history and push-proxy source are not part of this release.
28
+
29
+ Fresh-install and remote-phone acceptance of the new Tailscale setup helper
30
+ remain pending. Earlier Windows LAN/remote tests used the previous package.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DSHM contributors
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,3 +1,233 @@
1
- # Temporary Holding Version
1
+ # DSHM bridge
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [简体中文](README.zh-CN.md)
4
+
5
+ Control DeepSeek Harness sessions on your computer from the DSHM app on your
6
+ iPhone or iPad. The agent keeps running on your computer; the bridge connects
7
+ your paired device over your local network or your own VPN.
8
+
9
+ ## Requirements and compatibility
10
+
11
+ - DeepSeek Harness **0.2.1-rc.3 or 0.2.1-rc.5**. Plugin 0.1.1 adds support for
12
+ **0.2.1-rc.5**, the npm `latest` release verified on 2026-10-30. These are
13
+ exact tested versions; other releases, including the separate 0.2.2 alpha
14
+ channel, are not automatically compatible.
15
+ - A running DSH desktop app or `dsh web` on your computer, and a compatible DSHM
16
+ iPhone/iPad build. This npm package does not install the iOS app.
17
+ - Node 24 or later in the DSH runtime, and `openssl` on its PATH for the initial
18
+ local TLS certificate.
19
+ - Both devices on a network that permits direct communication, or on your own
20
+ connected VPN such as Tailscale.
21
+
22
+ The bridge has been exercised with DSH 0.2.1-rc.3 on macOS, including the desktop
23
+ app and isolated `dsh web`. Plugin 0.1.1 is also tested against real DSH
24
+ 0.2.1-rc.5 in isolated `dsh web`, including approvals, reconnects, file transfers,
25
+ path restrictions and restart. The new 0.1.1 / rc.5 combination still needs a
26
+ Windows native check; macOS results do not substitute for Windows verification. Physical-phone network acceptance is also separate from
27
+ the local test-client and Simulator results. Mainland China is outside the v1
28
+ release scope; mainland network reachability is not claimed.
29
+
30
+ ## Install in DSH
31
+
32
+ 1. Open the **Plugins** page in the DSH instance you want to control.
33
+ 2. Install this package spec using the page's package installation control:
34
+
35
+ ```text
36
+ dsh-plugin-dshm
37
+ ```
38
+
39
+ 3. Let DSH's plugin manager install the bundle and dependencies. Restart DSH
40
+ when requested, then open **Settings → DSHM**.
41
+
42
+ Use DSH's plugin manager rather than editing its profile files or copying files
43
+ into the installed application. The plugin is installed into the selected DSH
44
+ profile; installing it into one profile does not enable every other profile.
45
+
46
+ DSH 0.2.1 installs packages by name from npm; there is no central DSH plugin
47
+ market. No DSHM custom plugin index is published for this release.
48
+
49
+ ## Pair your device
50
+
51
+ ### Guided remote setup
52
+
53
+ Phone not on the same Wi-Fi as this computer? Use Tailscale. On the same Wi-Fi,
54
+ nothing else is needed. Open **Settings → DSHM → Not on the same Wi-Fi**.
55
+ The optional helper checks the official Tailscale app on Windows/macOS, links
56
+ to its official installer instructions, and can open the installed app on the
57
+ DSH host. Complete installation, system approvals and browser sign-in yourself.
58
+ If viewing DSH from another computer, install Tailscale on the **DSH host**.
59
+ The plugin does not embed a VPN, install software automatically, or change
60
+ Tailscale accounts, DNS, routes, exit nodes, firewall or proxy settings.
61
+
62
+ Install Tailscale on your iPhone/iPad, sign in to the same personal account,
63
+ and connect both ends. For organization accounts, both devices must belong to
64
+ the same permitted tailnet; account sign-in does not override access policy.
65
+ Then select **Pair for remote access** and scan the fresh QR in DSHM. An older
66
+ LAN-only pairing does not automatically acquire the new VPN address: forget
67
+ the old computer in DSHM, revoke its old device entry on the host, and pair again.
68
+ An active earlier QR is replaced when you explicitly create the fresh one.
69
+
70
+ The card distinguishes PC readiness from **Phone connected over Tailscale**.
71
+ Test with your phone on cellular or a different Wi-Fi.
72
+ **Pair a device** remains available for ordinary LAN use without Tailscale.
73
+ Missing software, canceled installation, sign-out and unavailable status checks
74
+ do not disable local pairing. Removing this plugin leaves Tailscale installed.
75
+ Fresh-install and remote-phone acceptance of this helper remain pending.
76
+ Earlier Windows LAN/remote tests used the previous package.
77
+
78
+ The helper reads local Tailscale state only while setup is open or when you
79
+ request remote pairing. It returns connection state and local VPN addresses,
80
+ not account identities, login links or peer inventories. Tailscale is a separate
81
+ service with its own account and privacy terms; DSHM's pinned TLS remains in use
82
+ over that VPN.
83
+
84
+ ### Local pairing
85
+
86
+ 1. Keep DSH running. On the computer, open **Settings → DSHM → Pair a device**.
87
+ 2. In DSHM on your iPhone or iPad, add a computer and scan the displayed QR code.
88
+ 3. Allow local-network access when prompted. The computer's DSHM card should
89
+ show your device as **Connected**.
90
+
91
+ The QR code is private, single use and valid for five minutes. Do not share it
92
+ or include it in screenshots or support reports. **Cancel pairing** closes the
93
+ window; if it expires, start a new one. Pair only devices you trust: paired
94
+ devices can view sessions and files, send prompts and answer tool approvals.
95
+
96
+ To disconnect a lost or unwanted device, use **Settings → DSHM → Revoke**, then
97
+ confirm **Revoke device**. This closes its active connection and prevents that
98
+ pairing from reconnecting. Pair again if you later want to restore access.
99
+
100
+ ## Network setup
101
+
102
+ - **macOS:** allow **DeepSeek Harness** in **System Settings → Privacy & Security
103
+ → Local Network**. If you run `dsh web` in Terminal or another terminal app,
104
+ allow that app too. DSHM on iOS also needs Local Network permission.
105
+ - **Windows:** if Windows Firewall asks about the DSH host process, allow it on
106
+ your trusted **Private networks**. Keep **Public networks** disabled. The
107
+ bridge does not change firewall rules for you; Windows runtime verification
108
+ remains pending.
109
+ - **Wi-Fi:** start with the same trusted home/work Wi-Fi. Guest networks,
110
+ hotspots and router client isolation may prevent devices from reaching each
111
+ other even when both have internet access.
112
+ - **Proxies and VPNs:** enable **bypass LAN/local networks** on both devices, or
113
+ temporarily turn the interfering proxy off to check the route. Keep LAN and
114
+ the chosen VPN's device addresses reachable; a rule that routes all traffic
115
+ through a proxy can prevent pairing.
116
+ - **Not on the same Wi-Fi:** connect both devices to the same Tailscale network (or
117
+ another VPN you control) and permit traffic between them. Keep the computer
118
+ awake and DSH running. DSHM does not provide a cloud relay for session traffic. Bonjour may
119
+ not cross a VPN; pair while both devices can reach an address included by the
120
+ computer.
121
+
122
+ The bridge normally listens on TCP **47390** on private/LAN and Tailscale
123
+ addresses. It uses a separate listener from DSH's Web UI. Do not expose that
124
+ port by router port forwarding or change DSH's Web server to a public bind.
125
+ Bonjour discovery uses the local network. If discovery sees your computer but
126
+ connection fails, check permissions, VPN/proxy bypass and client isolation first.
127
+
128
+ ## What is sent, and where
129
+
130
+ The bridge sends session messages, tool results, approvals, selected files and
131
+ declared deliverables to your authenticated, paired device over pinned TLS.
132
+ Prompts, answers and attachments from that device go back to DSH on your
133
+ computer. The bridge runs no cloud agent and has no analytics service or relay
134
+ for session traffic. It does not read or forward DSH's provider-credential store.
135
+ DSH itself still contacts the model providers and tools you configured, under
136
+ their own settings.
137
+
138
+ On the LAN, Bonjour announces the bridge's host identity/version and private
139
+ addresses for discovery. Local bridge identity and pairing records stay under
140
+ `$DSH_HOME/dshm/` (`~/.dsh/dshm/` with the default DSH home); private files should
141
+ never be pasted into issues. Installing a package or using a remote plugin
142
+ index makes DSH contact the package registry/index host.
143
+
144
+ **Optional push notifications use a separate proxy and Apple Push Notification
145
+ service (APNs).** Without a configured `pushProxyUrl`, the bridge makes no push
146
+ network requests and does not advertise push support. Configuring a URL enables
147
+ periodic health checks; push support is advertised only while the proxy is
148
+ reachable and the bridge's session observer is working. This package includes the bridge sender; the proxy and app are separate. iOS push registration,
149
+ the Notification Service Extension and real locked-phone delivery remain
150
+ separate work; they have not been verified by the local backend tests.
151
+
152
+ For push registration, the app sends its APNs device token and sandbox/production
153
+ environment to the selected HTTPS proxy. The proxy stores that routing mapping
154
+ and encrypts its authentication secret under a separate wrapping key. The app
155
+ shares the returned registration and a separate notification-content key with
156
+ the paired bridge over DMP. The bridge stores these keys and preferences in its
157
+ private `$DSH_HOME/dshm/push.json` file (mode 0600). The APNs provider key stays
158
+ only in the proxy's secret configuration; it is never supplied to the bridge.
159
+
160
+ When notifications are configured and registered, the bridge sends the proxy
161
+ an encrypted session title and short event summary, plus an opaque push ID,
162
+ event category, grouping ID and request signature. The proxy forwards the
163
+ ciphertext and a generic fallback alert to APNs. The proxy and APNs do not
164
+ receive the notification-content key or decrypted title/summary; routing
165
+ metadata, timing and payload size remain visible, and the proxy receives the
166
+ client IP at the network layer. The application logs counters only and stores
167
+ hashed IP quota buckets. Push does not upload files or full transcripts, and
168
+ an authenticated live connection suppresses sends to that device.
169
+
170
+ Unregistering notifications or revoking a device removes its local push
171
+ registration before a best-effort request to delete the proxy mapping. If the
172
+ proxy is unreachable, remote deletion is not confirmed; uninstalling the
173
+ package alone does not delete a remote mapping. Alerts already accepted by
174
+ APNs cannot be recalled. Terminal output remains read-only; the bridge does
175
+ not provide an interactive remote terminal.
176
+
177
+ ## Remove the bridge
178
+
179
+ 1. In **Settings → DSHM**, revoke devices you no longer want to authorize.
180
+ 2. Open **Plugins**, find `dsh-plugin-dshm`, and remove it from the active
181
+ profile through DSH's plugin manager. Repeat for any other profile where you
182
+ installed it, including an optional `dshm` CLI profile.
183
+ 3. Restart the affected DSH host when requested. The DSHM settings card and its
184
+ listener should be gone from that host.
185
+
186
+ Uninstalling the package is separate from deleting its private identity and
187
+ pairing state. Preserve `$DSH_HOME/dshm/` if you intend to reinstall. If you
188
+ deliberately choose a full reset, stop every DSH host using that home first and
189
+ remove only the bridge's `dshm` state directory; existing devices will need to
190
+ forget the old host and pair again. Do not delete the whole DSH home or its
191
+ credentials/session directories. Uninstall does not remove your DSH sessions.
192
+
193
+ ## New DSH release checklist (maintainers)
194
+
195
+ 1. Review upstream DSH changes, especially the projection APIs and bundle
196
+ loader. In an unpublished candidate, update the explicit runtime allowlist
197
+ and `engines.dsh` together so DSH can install it for isolated verification.
198
+ Do not publish or claim support before the following tests pass.
199
+ 2. Install the candidate DSH runtime through its normal distribution and run
200
+ `pnpm -C bridge test:integration` against it in the isolated `.dsh-test` home.
201
+ Review the explicit runtime version guard in `bridge/src/projection/native.ts`
202
+ as part of the compatibility change; changing package metadata alone does
203
+ not enable a new runtime. Adapt the test carrier path if needed; do not
204
+ bypass a failure or test against the old runtime while claiming the new one. Record the
205
+ actual DSH version and results. Complete the Windows checklist before
206
+ claiming a newly supported Windows combination.
207
+ 3. Run `pnpm -C bridge test`, `pnpm -C protocol validate` and
208
+ `pnpm -C protocol gen:check`. Fix compatibility changes only inside the
209
+ appropriate boundary and review the results.
210
+ 4. **Only after the real-DSH suite passes**, finalize `engines.dsh` as the explicit
211
+ tested versions/range. Never assume an entire future minor release is safe.
212
+ Update the tested range in `tools/release-plugin/check-release.mjs` with the
213
+ recorded evidence, keeping it aligned with the runtime compatibility guard.
214
+ Regenerate and validate the plugin index from `bridge/package.json`, keeping
215
+ its compatibility field identical.
216
+ 5. Bump the bridge version, update these READMEs, inspect `npm pack --dry-run`,
217
+ and install/boot the exact tarball through the isolated plugin manager.
218
+ 6. Audit the exact release tarball and record its SHA-256 before publication.
219
+ The owner signs in to npm and publishes that audited tarball with lifecycle
220
+ scripts disabled. Verify installation by name through DSH's plugin manager
221
+ in an isolated profile. Never publish a replacement over an existing version.
222
+
223
+ The public repository is a plugin-only source snapshot. Shared protocol source,
224
+ fixtures and integration tools remain in the private development repository;
225
+ monorepo build/test commands above require that maintainer checkout. The npm
226
+ package includes its protocol runtime and dependency license notices, so users
227
+ do not need those development sources. No private monorepo history, iOS app or
228
+ push-proxy source is included in the public repository.
229
+
230
+ Licensed under [MIT](LICENSE). See [CHANGELOG](CHANGELOG.md) for release changes.
231
+
232
+ [Source](https://github.com/JeremyCruzFang/dsh-plugin-dshm) ·
233
+ [Issues](https://github.com/JeremyCruzFang/dsh-plugin-dshm/issues)
@@ -0,0 +1,194 @@
1
+ # DSHM 桥接插件
2
+
3
+ [English](README.md)
4
+
5
+ 通过 iPhone 或 iPad 上的 DSHM,查看和控制电脑里的 DeepSeek Harness 会话。
6
+ 智能体仍在你的电脑上运行;手机通过局域网或你自己的 VPN 连接桥接插件。
7
+
8
+ ## 环境与兼容性
9
+
10
+ - DeepSeek Harness **0.2.1-rc.3 或 0.2.1-rc.5**。插件 0.1.1 新增对
11
+ **0.2.1-rc.5** 的支持,这是 2026-10-30 验证的 npm `latest` 版本。
12
+ 仅支持这些已测试的精确版本;其他版本(包括独立的 0.2.2 alpha 通道)
13
+ 不会自动视为兼容。
14
+ - 电脑正在运行 DSH 桌面应用或 `dsh web`,手机或平板已安装兼容的 DSHM
15
+ 构建版本。这个 npm 包不会安装 iOS 应用。
16
+ - DSH 运行环境使用 Node 24 或更新版本,且 PATH 中有 `openssl`,供首次
17
+ 创建本地 TLS 证书使用。
18
+ - 两台设备之间能够直接通信,或已连接到你自己的 Tailscale 等 VPN。
19
+
20
+ 目前已在 macOS 上使用 DSH 0.2.1-rc.3 验证桌面应用及隔离的 `dsh web`。
21
+ 插件 0.1.1 还在真实 DSH 0.2.1-rc.5 的隔离 `dsh web` 中通过了审批、重连、
22
+ 文件传输、路径限制及重启测试。新的 0.1.1 / rc.5 组合仍需 Windows 原生验证;
23
+ macOS 通过的测试不能代替 Windows 验证。真实手机的网络测试也与本地测试客户端、
24
+ Simulator 的结果分别记录。v1 不包含中国大陆市场,也不声明已验证大陆网络可达性。
25
+
26
+ ## 在 DSH 中安装
27
+
28
+ 1. 在需要远程控制的 DSH 实例中打开 **Plugins(插件)** 页面。
29
+ 2. 使用页面上的包安装入口,输入以下包名:
30
+
31
+ ```text
32
+ dsh-plugin-dshm
33
+ ```
34
+
35
+ 3. 让 DSH 插件管理器安装插件及依赖。按提示重启 DSH,然后打开
36
+ **Settings(设置)→ DSHM**。
37
+
38
+ 请使用 DSH 插件管理器,不要手动修改配置文件,也不要把文件复制进已安装的
39
+ DSH 应用目录。安装只作用于所选的 DSH profile,不会自动启用其他 profile。
40
+
41
+ DSH 0.2.1 通过包名从 npm 安装插件,没有中央插件市场。本版本未发布 DSHM
42
+ 自定义插件索引。
43
+
44
+ ## 配对手机或平板
45
+
46
+ 1. 保持 DSH 运行。在电脑上打开 **Settings → DSHM → Pair a device(配对设备)**。
47
+ 2. 在 iPhone 或 iPad 的 DSHM 中添加电脑,扫描显示的二维码。
48
+ 3. 出现提示时允许本地网络访问。电脑上的 DSHM 设置卡片应显示该设备为
49
+ **Connected(已连接)**。
50
+
51
+ 二维码只能使用一次,五分钟后过期。它包含临时配对凭据,请勿转发,也不要
52
+ 放进截图或问题报告。点击 **Cancel pairing(取消配对)** 可以提前关闭;过期
53
+ 后重新开始配对即可。只配对你信任的设备:已配对设备可以查看会话和文件、
54
+ 发送提示词、回答工具审批。
55
+
56
+ 手机丢失或不再需要访问时,在 **Settings → DSHM** 中点击该设备的
57
+ **Revoke(撤销)**,再确认 **Revoke device(撤销设备)**。插件会关闭其当前
58
+ 连接,并阻止旧配对重新连接。以后需要恢复访问时,可以重新配对。
59
+
60
+ ## 网络设置
61
+
62
+ ### 引导设置远程连接
63
+
64
+ 手机和这台电脑不在同一 Wi-Fi?使用 Tailscale。在同一 Wi-Fi 下无需其他设置。
65
+ 打开 **Settings → DSHM → 不在同一 Wi-Fi**。这个可选向导检查 Windows/
66
+ macOS 上的官方 Tailscale 程序,提供官方安装说明,并可打开 DSH 宿主电脑上的
67
+ Tailscale。安装、系统授权和浏览器登录由你亲自完成。如果从另一台电脑打开
68
+ DSH Web UI,请把 Tailscale 安装在 **运行 DSH 的电脑** 上。
69
+
70
+ 手机安装 Tailscale,使用同一个个人账号登录,并连接两端。组织账号需确保
71
+ 两台设备处于同一且允许通信的 tailnet;登录相同账号不会绕过组织访问策略。
72
+ 连接后点 **Pair for remote access**,在 DSHM 扫描新二维码。旧的仅局域网配对
73
+ 不会自动获得新 VPN 地址:先在 DSHM 忘记旧电脑,在宿主撤销旧设备条目,再
74
+ 重新配对。主动生成新二维码会替换尚未使用的旧二维码。
75
+
76
+ 向导区分“电脑已就绪”和“设备已通过 Tailscale 连接”。请让手机使用蜂窝网络
77
+ 或其他 Wi-Fi 进行测试。**Pair a device** 始终保留局域网配对入口,无须
78
+ 安装 Tailscale。取消安装、未登录或状态检查失败都不会关闭局域网配对。
79
+
80
+ 插件不会自动安装 VPN,不修改 Tailscale 账号、DNS、路由、出口节点、防火墙
81
+ 或代理设置,也不收集登录凭据。卸载插件会保留已安装的 Tailscale。新向导的全新安装及
82
+ 远程手机验收尚未完成;此前 Windows 局域网/远程测试使用旧版包,不能代替
83
+ 新向导验收。
84
+
85
+ - **macOS:** 在 **系统设置 → 隐私与安全性 → 本地网络** 中允许
86
+ **DeepSeek Harness**。如果通过终端运行 `dsh web`,也要允许相应的终端
87
+ 应用。iOS 上的 DSHM 同样需要“本地网络”权限。
88
+ - **Windows:** Windows 防火墙询问 DSH 宿主程序的联网权限时,允许你信任的
89
+ **专用网络(Private networks)**,保持 **公用网络(Public networks)**
90
+ 禁用。桥接插件不会替你修改防火墙规则;Windows 的运行验证仍待完成。
91
+ - **Wi-Fi:** 建议先让两台设备连接同一个可信的家庭或办公 Wi-Fi。访客网络、
92
+ 手机热点或路由器的客户端隔离功能,可能让设备都能上网却无法互相连接。
93
+ - **代理和 VPN:** 在两台设备上开启 **绕过局域网/本地网络(bypass LAN)**,
94
+ 或暂时关闭影响连接的代理以检查路由。局域网地址和所用 VPN 的设备地址都
95
+ 必须可达;把全部流量送入代理的规则可能阻止配对。
96
+ - **不在同一 Wi-Fi:** 让电脑和手机加入同一个 Tailscale 网络或你管理的其他 VPN,
97
+ 并允许两台设备之间通信。电脑需要保持唤醒,DSH 需要保持运行。DSHM 没有
98
+ 自营会话流量中继。Bonjour 发现通常不会穿过 VPN;配对时应确保手机能够
99
+ 连接电脑提供的某个地址。
100
+
101
+ 桥接插件默认在局域网/私有地址及 Tailscale 地址的 TCP **47390** 端口监听,
102
+ 与 DSH Web UI 使用不同的监听端口。不要为它设置路由器公网端口转发,也不要
103
+ 把 DSH Web 服务改成公网监听。Bonjour 使用本地网络;如果能够发现电脑却
104
+ 连接不上,先检查权限、代理/VPN 绕过设置及客户端隔离。
105
+
106
+ ## 数据会发送到哪里
107
+
108
+ 只有打开远程设置或请求远程配对时,向导才读取本机 Tailscale 状态;返回连接
109
+ 状态和本机 VPN 地址,不返回账号身份、登录链接或其他设备清单。Tailscale 是
110
+ 独立服务,有自己的账号和隐私条款;DSHM 在 VPN 上仍使用固定证书的 TLS。
111
+
112
+ 桥接插件通过固定证书的 TLS 连接,把会话消息、工具结果、审批、所选文件及
113
+ 已声明的交付文件发送给经过认证的已配对设备。手机发送的提示词、回答和附件
114
+ 会交给电脑上的 DSH。桥接插件不运行云端智能体,也不使用分析服务或 DSHM
115
+ 会话流量中继;它不会读取或转发 DSH 的模型服务凭据存储。DSH 本身仍会按照你
116
+ 自己的配置连接模型服务和工具,遵循这些服务的设置。
117
+
118
+ Bonjour 会在局域网内公布桥接宿主的标识、协议版本和私有网络地址,供发现
119
+ 使用。本地桥接身份和配对记录保存在 `$DSH_HOME/dshm/`,使用默认 DSH home
120
+ 时为 `~/.dsh/dshm/`。请勿把其中的私有文件粘贴到问题报告。安装插件或使用
121
+ 远程索引时,DSH 会访问相应的包仓库和索引服务器。
122
+
123
+ **可选的推送通知经过独立代理及 Apple 推送通知服务(APNs)。** 未配置
124
+ `pushProxyUrl` 时,桥接插件不会发起推送网络请求,也不会声明支持推送。
125
+ 配置地址后会定期检查代理健康状态;只有代理可达且会话观察功能正常时,才
126
+ 声明支持推送。本软件包包含桥接发送端,代理及应用另行提供。iOS 推送注册、
127
+ 通知服务扩展及真实锁屏手机的通知送达仍是独立工作,本地后端测试不代表
128
+ 这些环节已经验证。
129
+
130
+ 注册推送时,应用将 APNs 设备令牌及沙盒/生产环境标识发送给所选的 HTTPS
131
+ 代理。代理保存这份路由映射,以及用独立包装密钥加密的认证密钥。应用通过
132
+ DMP 将返回的注册信息和另一把通知内容密钥交给已配对的桥接插件。桥接插件
133
+ 把这些密钥和偏好保存在私有的 `$DSH_HOME/dshm/push.json`(权限 0600)中。
134
+ APNs 提供方密钥只存在代理的密钥配置中,不会交给桥接插件。
135
+
136
+ 配置并完成注册后,桥接插件会把加密的会话标题、简短事件摘要,以及不透明
137
+ 推送 ID、事件类别、分组 ID 和请求签名发送给代理。代理将密文和通用备用
138
+ 提示转交 APNs。代理及 APNs 都不会收到通知内容密钥,也无法直接读取解密后
139
+ 的标题/摘要;路由元数据、时间和载荷大小仍然可见,代理在网络层也会收到
140
+ 客户端 IP。应用仅记录计数,并保存用于限流的 IP 哈希。推送不会上传文件或
141
+ 完整会话记录;设备保持已认证的实时连接时,不会向该设备发送推送。
142
+
143
+ 取消推送注册或撤销设备会先删除本地推送注册,再尽力请求代理删除相应映射。
144
+ 代理不可达时,无法确认远端删除成功;仅卸载软件包不会删除远端映射。
145
+ APNs 已经接收的通知无法撤回。终端输出仍仅供查看;桥接插件不提供可交互的
146
+ 远程终端。
147
+
148
+ ## 卸载
149
+
150
+ 1. 在 **Settings → DSHM** 中撤销不再需要授权的设备。
151
+ 2. 打开 **Plugins**,找到 `dsh-plugin-dshm`,通过 DSH 插件管理器从当前
152
+ profile 中移除。如果其他 profile 也安装过,包括可选的 `dshm` CLI
153
+ profile,请分别移除。
154
+ 3. 按提示重启受影响的 DSH 宿主。该宿主的 DSHM 设置卡片和监听端口应已消失。
155
+
156
+ 卸载软件包与删除私有身份、配对记录是两件事。如果打算重新安装,请保留
157
+ `$DSH_HOME/dshm/`。如果你明确选择完整重置,应先停止所有使用该 home 的 DSH
158
+ 宿主,然后仅删除桥接插件的 `dshm` 状态目录;已有设备需要忘记旧电脑并重新
159
+ 配对。不要删除整个 DSH home,也不要删除模型服务凭据或会话目录。卸载桥接
160
+ 插件不会删除 DSH 会话。
161
+
162
+ ## 新 DSH 版本发布检查清单(维护者)
163
+
164
+ 1. 先阅读上游改动,尤其是 projection 接口和插件加载器。在尚未发布的候选包中,
165
+ 同步更新显式运行时允许列表及 `engines.dsh`,以便通过 DSH 安装并进行隔离
166
+ 验证。以下测试通过前,不发布该包,也不对外声明支持新版本。
167
+ 2. 通过 DSH 的正常发布渠道安装候选运行时,在隔离的 `.dsh-test` home 中对
168
+ **该候选版本**运行 `pnpm -C bridge test:integration`。兼容性改动必须同时
169
+ 审查 `bridge/src/projection/native.ts` 中的显式运行时版本保护;只改包元数据
170
+ 不会启用新运行时。必要时调整测试宿主路径,但不要跳过失败,也不要用旧
171
+ 运行时的结果冒充新版本验证。
172
+ 记录实际版本和结果;声明新的 Windows 组合已支持前,完成 Windows 清单。
173
+ 3. 运行 `pnpm -C bridge test`、`pnpm -C protocol validate` 和
174
+ `pnpm -C protocol gen:check`。在正确的架构边界内修复兼容性问题并审查结果。
175
+ 4. **只有真实 DSH 集成测试通过后**,才最终确定 `engines.dsh` 中明确验证过的
176
+ 版本或范围。不要假定未来整个小版本都兼容。根据实际验证记录,更新
177
+ `tools/release-plugin/check-release.mjs` 中的已测试范围,并与运行时版本保护
178
+ 保持一致。从 `bridge/package.json`
179
+ 重新生成并验证插件索引,保证两处兼容性字段一致。
180
+ 5. 提升插件版本,更新中英文 README,检查 `npm pack --dry-run`,并通过隔离
181
+ profile 的插件管理器安装和启动准备发布的同一个 tarball。
182
+ 6. 发布前审计准备发布的同一个 tarball,记录 SHA-256。所有者亲自登录 npm,
183
+ 禁用生命周期脚本后发布该文件。通过隔离 profile 的 DSH 插件管理器验证按名
184
+ 安装。已经发布的版本不能通过覆盖来修复。
185
+
186
+ 公开仓库仅保存插件源码快照。共用协议源码、fixtures 及集成工具保留在私有
187
+ 开发仓库中;上述 monorepo 构建和测试命令需要维护者的开发检出。npm 包已包含
188
+ 协议运行时和依赖许可证,用户不需要这些开发源码。公开仓库不包含私有仓库
189
+ 历史、iOS 应用或推送代理源码。
190
+
191
+ 采用 [MIT 许可证](LICENSE)。版本改动见 [CHANGELOG](CHANGELOG.md)。
192
+
193
+ [项目源码](https://github.com/JeremyCruzFang/dsh-plugin-dshm) ·
194
+ [问题反馈](https://github.com/JeremyCruzFang/dsh-plugin-dshm/issues)
@@ -0,0 +1,7 @@
1
+ - insert:
2
+ - id: dshm-bridge
3
+ name: dsh-plugin-dshm
4
+ disabled: !!js "ctx.get('profileContext')?.name === 'dshm'"
5
+ - id: dshm-cli
6
+ name: dsh-plugin-dshm/cli
7
+ disabled: !!js "ctx.get('profileContext')?.name !== 'dshm'"
@@ -0,0 +1,4 @@
1
+ import crypto from 'node:crypto';
2
+ export declare const authMessage: (nonce: string, hostId: string, fingerprint: string) => Buffer;
3
+ export declare function publicKeyFromSpki(value: string): crypto.KeyObject;
4
+ export declare function verifySignature(publicKey: string, nonce: string, hostId: string, fingerprint: string, signature: string): boolean;
@@ -0,0 +1,24 @@
1
+ import crypto from 'node:crypto';
2
+ export const authMessage = (nonce, hostId, fingerprint) => Buffer.concat([
3
+ Buffer.from('dshm-auth-v1'), Buffer.from(nonce, 'base64url'), Buffer.from(hostId), Buffer.from(fingerprint),
4
+ ]);
5
+ export function publicKeyFromSpki(value) {
6
+ const bytes = Buffer.from(value, 'base64');
7
+ if (bytes.toString('base64') !== value || bytes.length > 256)
8
+ throw new Error('Invalid public key encoding');
9
+ const key = crypto.createPublicKey({ key: bytes, type: 'spki', format: 'der' });
10
+ if (key.asymmetricKeyType !== 'ec' || key.asymmetricKeyDetails?.namedCurve !== 'prime256v1')
11
+ throw new Error('P-256 key required');
12
+ return key;
13
+ }
14
+ export function verifySignature(publicKey, nonce, hostId, fingerprint, signature) {
15
+ try {
16
+ const bytes = Buffer.from(signature, 'base64');
17
+ if (bytes.toString('base64') !== signature || bytes.length > 80)
18
+ return false;
19
+ return crypto.verify('sha256', authMessage(nonce, hostId, fingerprint), { key: publicKeyFromSpki(publicKey), dsaEncoding: 'der' }, bytes);
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
@@ -0,0 +1,4 @@
1
+ export declare const name = "dshm-cli";
2
+ export declare const inject: string[];
3
+ export declare function run(args: readonly string[]): Promise<number>;
4
+ export declare function apply(context: unknown): void;
@@ -0,0 +1,41 @@
1
+ import QRCode from 'qrcode';
2
+ import { parseConfig } from '../config.js';
3
+ import { localRequest } from '../host/local.js';
4
+ import { installCli, cliInject } from '../projection/host.js';
5
+ export const name = 'dshm-cli';
6
+ export const inject = cliInject;
7
+ export async function run(args) {
8
+ const directory = parseConfig(undefined).stateDir;
9
+ const [command, id, ...extra] = args;
10
+ if (extra.length || !['pair', 'devices', 'revoke', 'status'].includes(command ?? '') || (command === 'revoke' ? !id : id !== undefined)) {
11
+ console.error('Usage: dsh dshm pair | devices | revoke <id> | status');
12
+ return 2;
13
+ }
14
+ try {
15
+ if (command === 'pair') {
16
+ const value = await localRequest(directory, 'POST', '/pair', {});
17
+ console.log(await QRCode.toString(value.url, { type: 'terminal', small: true }));
18
+ console.log(`Pairing expires at ${value.expiresAt}. One use. Keep this QR private.`);
19
+ }
20
+ else if (command === 'devices') {
21
+ const { devices } = await localRequest(directory, 'GET', '/devices');
22
+ console.log(JSON.stringify(devices, null, 2));
23
+ }
24
+ else if (command === 'revoke') {
25
+ const result = await localRequest(directory, 'POST', '/revoke', { deviceId: id });
26
+ if (!result.revoked) {
27
+ console.error('Device not found');
28
+ return 1;
29
+ }
30
+ console.log('Device revoked');
31
+ }
32
+ else
33
+ console.log(JSON.stringify(await localRequest(directory, 'GET', '/status'), null, 2));
34
+ return 0;
35
+ }
36
+ catch {
37
+ console.error('DSHM bridge is unavailable in this DSH_HOME. Start the host profile first.');
38
+ return 1;
39
+ }
40
+ }
41
+ export function apply(context) { installCli(context, run); }