dsh-plugin-dshm 0.1.0 → 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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
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
+
3
14
  ## 0.1.0 — 2026-10-28
4
15
 
5
16
  Initial DSHM bridge release for DeepSeek Harness 0.2.1-rc.3.
package/README.md CHANGED
@@ -8,9 +8,10 @@ your paired device over your local network or your own VPN.
8
8
 
9
9
  ## Requirements and compatibility
10
10
 
11
- - DeepSeek Harness **0.2.1-rc.3**, the exact currently supported `engines.dsh`
12
- value. DSH is a Developer Preview; a newer version is not automatically
13
- compatible.
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.
14
15
  - A running DSH desktop app or `dsh web` on your computer, and a compatible DSHM
15
16
  iPhone/iPad build. This npm package does not install the iOS app.
16
17
  - Node 24 or later in the DSH runtime, and `openssl` on its PATH for the initial
@@ -19,9 +20,10 @@ your paired device over your local network or your own VPN.
19
20
  connected VPN such as Tailscale.
20
21
 
21
22
  The bridge has been exercised with DSH 0.2.1-rc.3 on macOS, including the desktop
22
- app and isolated `dsh web`. Windows is an intended platform, but its native
23
- runtime/firewall checklist is still pending; do not treat the macOS tests as
24
- Windows verification. Physical-phone network acceptance is also separate from
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
25
27
  the local test-client and Simulator results. Mainland China is outside the v1
26
28
  release scope; mainland network reachability is not claimed.
27
29
 
@@ -190,8 +192,10 @@ credentials/session directories. Uninstall does not remove your DSH sessions.
190
192
 
191
193
  ## New DSH release checklist (maintainers)
192
194
 
193
- 1. Keep `engines.dsh` at the currently verified version while testing. Review
194
- upstream DSH changes, especially the projection APIs and bundle loader.
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.
195
199
  2. Install the candidate DSH runtime through its normal distribution and run
196
200
  `pnpm -C bridge test:integration` against it in the isolated `.dsh-test` home.
197
201
  Review the explicit runtime version guard in `bridge/src/projection/native.ts`
@@ -203,7 +207,7 @@ credentials/session directories. Uninstall does not remove your DSH sessions.
203
207
  3. Run `pnpm -C bridge test`, `pnpm -C protocol validate` and
204
208
  `pnpm -C protocol gen:check`. Fix compatibility changes only inside the
205
209
  appropriate boundary and review the results.
206
- 4. **Only after the real-DSH suite passes**, widen `engines.dsh` to the explicit
210
+ 4. **Only after the real-DSH suite passes**, finalize `engines.dsh` as the explicit
207
211
  tested versions/range. Never assume an entire future minor release is safe.
208
212
  Update the tested range in `tools/release-plugin/check-release.mjs` with the
209
213
  recorded evidence, keeping it aligned with the runtime compatibility guard.
package/README.zh-CN.md CHANGED
@@ -7,8 +7,10 @@
7
7
 
8
8
  ## 环境与兼容性
9
9
 
10
- - DeepSeek Harness **0.2.1-rc.3**,这是当前 `engines.dsh` 声明的精确版本。
11
- DSH 仍处于 Developer Preview 阶段,不能假定新版本自动兼容。
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
+ 不会自动视为兼容。
12
14
  - 电脑正在运行 DSH 桌面应用或 `dsh web`,手机或平板已安装兼容的 DSHM
13
15
  构建版本。这个 npm 包不会安装 iOS 应用。
14
16
  - DSH 运行环境使用 Node 24 或更新版本,且 PATH 中有 `openssl`,供首次
@@ -16,8 +18,9 @@
16
18
  - 两台设备之间能够直接通信,或已连接到你自己的 Tailscale 等 VPN。
17
19
 
18
20
  目前已在 macOS 上使用 DSH 0.2.1-rc.3 验证桌面应用及隔离的 `dsh web`。
19
- Windows 是计划支持的平台,但原生运行和防火墙验证清单尚未完成;macOS
20
- 通过的测试不能代替 Windows 验证。真实手机的网络测试也与本地测试客户端、
21
+ 插件 0.1.1 还在真实 DSH 0.2.1-rc.5 的隔离 `dsh web` 中通过了审批、重连、
22
+ 文件传输、路径限制及重启测试。新的 0.1.1 / rc.5 组合仍需 Windows 原生验证;
23
+ macOS 通过的测试不能代替 Windows 验证。真实手机的网络测试也与本地测试客户端、
21
24
  Simulator 的结果分别记录。v1 不包含中国大陆市场,也不声明已验证大陆网络可达性。
22
25
 
23
26
  ## 在 DSH 中安装
@@ -158,8 +161,9 @@ APNs 已经接收的通知无法撤回。终端输出仍仅供查看;桥接插
158
161
 
159
162
  ## 新 DSH 版本发布检查清单(维护者)
160
163
 
161
- 1. 测试期间保持当前已验证的 `engines.dsh` 值不变,先阅读上游改动,尤其是
162
- projection 接口和插件加载器的变化。
164
+ 1. 先阅读上游改动,尤其是 projection 接口和插件加载器。在尚未发布的候选包中,
165
+ 同步更新显式运行时允许列表及 `engines.dsh`,以便通过 DSH 安装并进行隔离
166
+ 验证。以下测试通过前,不发布该包,也不对外声明支持新版本。
163
167
  2. 通过 DSH 的正常发布渠道安装候选运行时,在隔离的 `.dsh-test` home 中对
164
168
  **该候选版本**运行 `pnpm -C bridge test:integration`。兼容性改动必须同时
165
169
  审查 `bridge/src/projection/native.ts` 中的显式运行时版本保护;只改包元数据
@@ -168,7 +172,7 @@ APNs 已经接收的通知无法撤回。终端输出仍仅供查看;桥接插
168
172
  记录实际版本和结果;声明新的 Windows 组合已支持前,完成 Windows 清单。
169
173
  3. 运行 `pnpm -C bridge test`、`pnpm -C protocol validate` 和
170
174
  `pnpm -C protocol gen:check`。在正确的架构边界内修复兼容性问题并审查结果。
171
- 4. **只有真实 DSH 集成测试通过后**,才把 `engines.dsh` 扩大到明确验证过的
175
+ 4. **只有真实 DSH 集成测试通过后**,才最终确定 `engines.dsh` 中明确验证过的
172
176
  版本或范围。不要假定未来整个小版本都兼容。根据实际验证记录,更新
173
177
  `tools/release-plugin/check-release.mjs` 中的已测试范围,并与运行时版本保护
174
178
  保持一致。从 `bridge/package.json`
@@ -0,0 +1,2 @@
1
+ export const supportedDSHVersions: readonly string[];
2
+ export function supportsDSH(version: any): boolean;
@@ -0,0 +1,4 @@
1
+ // Enumerate verified carriers; a future prerelease is not implicitly compatible.
2
+ // Keep package metadata and the release gate aligned with the native test receipt.
3
+ export const supportedDSHVersions = Object.freeze(['0.2.1-rc.3', '0.2.1-rc.5']);
4
+ export const supportsDSH = version => supportedDSHVersions.includes(version);
@@ -87,6 +87,7 @@ export declare class LivePeer implements ProjectionPeer {
87
87
  private accept;
88
88
  private waitForProjection;
89
89
  private expireMissingInteractions;
90
+ private warnUnidentifiedInteraction;
90
91
  private interactionsReady;
91
92
  private loadChanges;
92
93
  private acceptNative;
@@ -5,6 +5,7 @@ import { dirname, resolve } from 'node:path';
5
5
  import { homedir } from 'node:os';
6
6
  import { createProjectionFold } from './fold-recording.mjs';
7
7
  import { FileProjection } from './files.js';
8
+ import { supportsDSH } from './compatibility.mjs';
8
9
  import { interactionIdentity, expectedInteractionIds } from './interactions.js';
9
10
  const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
10
11
  const array = (value) => Array.isArray(value) ? value : [];
@@ -82,7 +83,7 @@ export function createProjectionHost(context) {
82
83
  }
83
84
  catch { /* The bundle may not run under a DSH CLI carrier. */ }
84
85
  }
85
- const status = version === '0.2.1-rc.3' ? 'ok' : 'incompatible';
86
+ const status = supportsDSH(version) ? 'ok' : 'incompatible';
86
87
  const diagnostics = { createdPeers: 0, disposedPeers: 0, activePeers: 0 };
87
88
  const peers = new Set();
88
89
  const attachments = new Map();
@@ -259,7 +260,8 @@ export class LivePeer {
259
260
  const state = await this.ensure(sessionId);
260
261
  const request = object(frame.request);
261
262
  const nativeId = string(frame.eventId);
262
- state.identifying.add(nativeId);
263
+ const kind = frame.event === 'approval/request' ? 'approval' : 'question';
264
+ state.identifying.set(nativeId, kind);
263
265
  let identity;
264
266
  try {
265
267
  identity = await this.waitForProjection(state, () => interactionIdentity(sessionId, string(frame.event), request, state.records));
@@ -274,7 +276,7 @@ export class LivePeer {
274
276
  }
275
277
  if (!identity) {
276
278
  this.expireMissingInteractions(state);
277
- this.accept(state, { source: 'interaction-warning', frame: { kind: frame.event === 'approval/request' ? 'approval' : 'question', status: this.summary(this.nativeSummaries.get(sessionId) ?? { sessionId }).status }, atMs: 0 });
279
+ this.warnUnidentifiedInteraction(state, kind);
278
280
  return;
279
281
  }
280
282
  const { id, callId } = identity;
@@ -405,13 +407,23 @@ export class LivePeer {
405
407
  if (ids.length)
406
408
  this.accept(state, { source: 'interaction-expire', frame: { ids, status: this.summary(this.nativeSummaries.get(state.id) ?? { sessionId: state.id }).status }, atMs: 0 });
407
409
  }
410
+ warnUnidentifiedInteraction(state, kind) {
411
+ this.accept(state, { source: 'interaction-warning', frame: { kind, status: this.summary(this.nativeSummaries.get(state.id) ?? { sessionId: state.id }).status }, atMs: 0 });
412
+ }
408
413
  async interactionsReady(state, signal, deadline = Date.now() + 2000) {
409
414
  const ready = await this.waitForProjection(state, () => state.followReady && !state.identifying.size &&
410
415
  expectedInteractionIds(state.id, state.records).every(id => this.deliveries.has(id) || state.expiredInteractions.has(id)) ? true : undefined, signal, deadline);
411
416
  // A durable audit can outlive its native waterfall after a crash. Keep the
412
417
  // session readable, but never present an unanswerable row as live.
413
- if (!ready)
418
+ if (!ready) {
414
419
  this.expireMissingInteractions(state);
420
+ // The read deadline can settle before the correlation callback. Publish
421
+ // the fallback now so its snapshot cannot retain stale running state or
422
+ // omit the warning. The later callback may still identify a valid delivery.
423
+ const kind = state.identifying.values().next().value;
424
+ if (kind)
425
+ this.warnUnidentifiedInteraction(state, kind);
426
+ }
415
427
  }
416
428
  async loadChanges(state, seq) {
417
429
  const url = new URL('http://localhost/api/changes.summary');
@@ -458,7 +470,7 @@ export class LivePeer {
458
470
  if (!native)
459
471
  throw fault('not-found');
460
472
  const metadata = { live: true, scenario: 'live', sessionId: id, title: null, recordedAt: iso(native.updatedAt), summary: this.summary(native), cwd: native.cwd };
461
- const state = { id, metadata, fold: createProjectionFold(metadata), records: [], nativeSeq: -1, listeners: new Set(), ready: Promise.resolve(), followReady: false, cancel: new AbortController(), changed: new Set(), identifying: new Set(), expiredInteractions: new Set() };
473
+ const state = { id, metadata, fold: createProjectionFold(metadata), records: [], nativeSeq: -1, listeners: new Set(), ready: Promise.resolve(), followReady: false, cancel: new AbortController(), changed: new Set(), identifying: new Map(), expiredInteractions: new Set() };
462
474
  this.lifetime.signal.addEventListener('abort', () => state.cancel.abort(), { once: true });
463
475
  this.sessions.set(id, state);
464
476
  state.ready = this.startStream('session/follow', { request: { address: { kind: 'session', sessionId: id }, assistantStream: true, maxMessages: 200 } }, async (frame) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-dshm",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Pair your iPhone or iPad with DeepSeek Harness over a private, authenticated connection",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
  ],
32
32
  "engines": {
33
33
  "node": ">=24",
34
- "dsh": "0.2.1-rc.3"
34
+ "dsh": "0.2.1-rc.3 || 0.2.1-rc.5"
35
35
  },
36
36
  "dsh": {
37
37
  "bundle": {