dsh-deeppilot 0.9.9 → 0.9.11

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/COMPATIBILITY.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # Compatibility
2
2
 
3
- This branch targets exactly **five DSH releases**: `0.2.0-rc.2`, which the npm
4
- `latest` channel points at; `0.2.1-alpha.3`, `0.2.1-alpha.4`, and
5
- `0.2.1-alpha.5`, which the `alpha` channel has pointed at in turn; and
6
- `0.2.1-rc.2`, which the `next` channel points at. All five are
3
+ This branch targets exactly **six DSH releases**: `0.2.0-rc.2`; the `alpha`
4
+ channel releases `0.2.1-alpha.3`, `0.2.1-alpha.4`, and `0.2.1-alpha.5`; and the
5
+ `next` channel releases `0.2.1-rc.2` and `0.2.1-rc.3`. The npm channels have
6
+ moved since: `latest` now points at `0.2.1-rc.2`, promoted from `next`, and
7
+ `next` at `0.2.1-rc.3`. All six are
7
8
  named in both `engines.dsh` and `peerDependencies`; no other version is accepted.
8
9
  DSH evaluates that declaration before composing a profile — on every start, not
9
10
  only on install — so a newly published DSH release deactivates this plugin until
@@ -21,9 +22,10 @@ recorded in the release memory.
21
22
  | Component | Current contract | Evidence |
22
23
  |---|---|---|
23
24
  | Node.js | 22 or newer | Package engine and CI |
24
- | DSH CLI and Host API | `engines.dsh` and `peerDependencies` both name `0.2.0-rc.2 \|\| 0.2.1-alpha.3 \|\| 0.2.1-alpha.4 \|\| 0.2.1-alpha.5 \|\| 0.2.1-rc.2` (dev pins `0.2.0-rc.2`) | Peer metadata, source typecheck, unit tests, bundle build, and config schema projection against a real 0.2.0-rc.2 CLI, plus isolated composes and live phone-protocol runs with the published 0.2.1-alpha.2, 0.2.1-alpha.3, and 0.2.1-alpha.4 CLIs, an isolated 0.2.1-alpha.5 host where this plugin now composes, starts, and answers `/phone/health` with 200 on its own LAN listener, and a pre-widening 0.2.1-rc.2 host run where the unchanged declaration is refused at compose time (audits below) |
25
+ | DSH CLI and Host API | `engines.dsh` and `peerDependencies` both name `0.2.0-rc.2 \|\| 0.2.1-alpha.3 \|\| 0.2.1-alpha.4 \|\| 0.2.1-alpha.5 \|\| 0.2.1-rc.2 \|\| 0.2.1-rc.3` (dev pins `0.2.0-rc.2`) | Peer metadata, source typecheck, unit tests, bundle build, and config schema projection against a real 0.2.0-rc.2 CLI, plus isolated composes and live phone-protocol runs with the published 0.2.1-alpha.2, 0.2.1-alpha.3, and 0.2.1-alpha.4 CLIs, an isolated 0.2.1-alpha.5 host where this plugin now composes, starts, and answers `/phone/health` with 200 on its own LAN listener, a pre-widening 0.2.1-rc.2 host run where the unchanged declaration is refused at compose time, and an isolated 0.2.1-rc.3 host where the widened declaration composes, starts, and answers `/phone/health` with 200 (audits below) |
25
26
  | iOS bridge | DeepPilot protocol v2 | Bridge protocol tests; device behavior must be checked with the running Host and app |
26
27
  | Remote access | Tailscale Funnel on ports 443, 8443, or 10000 | Helper and supervisor tests |
28
+ | Funnel helper platforms | macOS 13 Ventura or later, Linux, and Windows, each on amd64/arm64; built with Go 1.27, which dropped macOS 12 | CI starts the committed helper on a native runner for each of the six targets (`helper-smoke`); no runner covers macOS 13 itself |
27
29
 
28
30
  ## DSH interfaces used here
29
31
 
@@ -73,6 +75,77 @@ carries the old top-level `debug: true` is accepted but that value is ignored:
73
75
  verbose logging must be turned on again from the settings page. No other config
74
76
  field changed shape, and the old key is not read anywhere in this version.
75
77
 
78
+ ## 0.2.1-rc.3 audit outcome
79
+
80
+ The artifact-level audit of `dsh-v0.2.1-rc.3` (published to the npm registry
81
+ 2026-10-23T07:54:30Z, the `next` channel release; `latest` points at `0.2.1-rc.2`)
82
+ against `dsh-v0.2.1-rc.2` found **no change that reaches this plugin's call
83
+ surface**. Nineteen packages were compared as whole trees rather than by `lib/`
84
+ alone — eighteen from the two installed trees plus
85
+ `@deepseek-ai/dsh-client-ui-slots` (the seventh declared `dsh-*` peer, absent from
86
+ both trees) through its registry tarball:
87
+
88
+ - **Fourteen packages differ only in `package.json`** — version and dependency
89
+ specs — so every file those hosts read at runtime is byte-identical.
90
+ - **Three packages carry one non-`package.json` change each** — `dsh-api-remotes`,
91
+ `dsh-api-session-controller`, and `dsh-web-app` — detailed below.
92
+ - **`cordis 4.0.5` and `schemastery 3.18.5` are byte-identical including
93
+ `package.json`**, so the vendor peer ranges need no widening again.
94
+ - **The tree gains one package**: `rc.2` ships 306 packages and `rc.3` 307; the
95
+ addition is `@deepseek-ai/dsh-client-ui-entry-customization@0.2.1-rc.3`, the
96
+ bundle behind the More menus. This plugin neither references it nor depends on
97
+ it through its own patch.
98
+
99
+ Of 3,302 shared files, 3,275 are byte-identical and 20 differ: 16 `package.json`
100
+ files, the three code/config files above, and the `dsh-client-ui-slots`
101
+ `package.json`. Across 274 analysed modules **no export symbol is added or
102
+ removed** (18 entry modules compared), so every earlier fix still holds
103
+ unchanged. The manifest delta over 19 packages covers 585 paths — 17 version
104
+ bumps and 568 dependency-spec moves, **zero structural differences** — with no
105
+ package added or removed by dependency resolution.
106
+
107
+ **The one file outside `package.json` that could reach this plugin's patch layer
108
+ is additive.** `@deepseek-ai/dsh-web-app/cordis.patch.yml` gained one hunk that
109
+ inserts the `ui-entry-customization` bundle (the More menus named in the rc.3
110
+ release notes). The patch anchor this plugin targets, `id: directory-picker`, is
111
+ byte-identical on both sides at the same offsets, and neither the new package
112
+ name nor `entry-customization` appears in this plugin's `cordis.patch.yml` or
113
+ `package.json`, so the change cannot reach any patch this plugin applies.
114
+
115
+ The other two non-`package.json` files are equally out of reach:
116
+ `@deepseek-ai/dsh-api-remotes/lib/client.js` only widens the client telemetry
117
+ event schema (`is_new_session`, `agent_preset`, and the More-menu and
118
+ agent-preset switch events), which this plugin neither emits nor validates, and
119
+ `@deepseek-ai/dsh-api-session-controller`'s
120
+ `lib/types/client/sessions/service.d.ts` changes a doc comment only.
121
+
122
+ The activation verdict repeats the rc.2 shape: rc.3 also reads `engines.dsh`
123
+ alone. Before the widening, the published rc.3 evaluator refused `0.2.1-rc.3`
124
+ with a single `engines.dsh` requirement and `exempted: false`, and a real rc.3
125
+ CLI reproduced the refusal at compose time (`skipping profile bundle
126
+ "dsh-deeppilot"`) while the host itself still booted and served its web port.
127
+ After the widening, the same evaluator admits exactly `0.2.1-rc.3` and adds no
128
+ other acceptance: the five earlier hosts stay admitted, and `0.2.1-rc.1`,
129
+ `0.2.1-rc.3.1`, `0.2.1-rc.30`, `0.2.1-RC.3`, `0.2.1`, `0.2.1-rc.2.1`, `0.2.0`,
130
+ `0.3.0`, and `1.0.0` remain refused. Deleting `engines.dsh` from a copy of the
131
+ manifest falls back to the ten peers and still admits the same six hosts, so the
132
+ short-circuit is unchanged.
133
+
134
+ **The positive half is complete this time.** An isolated `0.2.1-rc.3` host — its
135
+ own `DSH_HOME`, the plugin linked from this working tree, and no other plugin —
136
+ composes the plugin into the tree, starts it, and answers `/phone/health` with
137
+ 200 on the plugin's own LAN listener (`serverVersion` `0.9.10`, protocol v2),
138
+ while the isolated home gains the plugin's data directory. The same profile run
139
+ with the declaration unchanged shows the skip line instead and no listener,
140
+ which is what makes the pair discriminative.
141
+
142
+ Evidence: `.rc3-verify/AUDIT.md` and `.rc3-verify/CHANGE_SURFACE.md` with the raw
143
+ logs under `.rc3-verify/logs/`, the evaluator reproduction in
144
+ `.rc3-verify/evaluator-repro.out.json`, the acceptance matrix in
145
+ `.rc3-verify/matrix.out.json`, the export-symbol diff in
146
+ `.rc3-verify/export-symbol-diff.out.json`, and the host run in
147
+ `.rc3-verify/HOST-BOOT.md`.
148
+
76
149
  ## 0.2.1-rc.2 audit outcome
77
150
 
78
151
  The artifact-level audit of `dsh-v0.2.1-rc.2` against `dsh-v0.2.1-alpha.5` found
package/README.md CHANGED
@@ -32,19 +32,23 @@ Host on your own computer and does not replace or modify the DSH Web UI.
32
32
 
33
33
  ## Install from npm
34
34
 
35
- This source checkout targets Node.js 22+ and the five DSH releases it has been
36
- audited against — `0.2.0-rc.2` (the `latest` channel), the `alpha` channel
37
- releases `0.2.1-alpha.3`, `0.2.1-alpha.4`, and `0.2.1-alpha.5`, and `0.2.1-rc.2`
38
- (the `next` channel) — with a `web` profile. DSH checks a plugin's declared
35
+ This source checkout targets Node.js 22+ and the six DSH releases it has been
36
+ audited against — `0.2.0-rc.2`, the `alpha` channel releases `0.2.1-alpha.3`,
37
+ `0.2.1-alpha.4`, and `0.2.1-alpha.5`, and the two `next` channel releases it has
38
+ admitted in turn, `0.2.1-rc.2` and `0.2.1-rc.3` — with a `web` profile. (The
39
+ npm channels move: `latest` now points at `0.2.1-rc.2`, which was promoted
40
+ from `next`, and `next` at `0.2.1-rc.3`.) DSH checks a plugin's declared
39
41
  requirements before composing a profile, on every start rather than only on
40
42
  install, so any other host version refuses to activate this plugin. From DSH
41
43
  `0.2.1-alpha.4` on, that check reads `engines.dsh` and ignores
42
44
  `peerDependencies`; older hosts know only the peer range, so both name the same
43
- five releases. The package includes Funnel helpers
45
+ six releases. The package includes Funnel helpers
44
46
  for macOS, Linux, and Windows on amd64/arm64; trusted-LAN mode does not require
45
- the helper.
47
+ the helper. The helper is built with Go 1.27, which requires **macOS 13 Ventura
48
+ or later**: on macOS 12 and earlier, Funnel mode cannot start, while
49
+ trusted-LAN mode keeps working.
46
50
 
47
- The current working tree names exactly those five versions in `engines.dsh` and
51
+ The current working tree names exactly those six versions in `engines.dsh` and
48
52
  `peerDependencies` and is built/typechecked against `0.2.0-rc.2`. A previously
49
53
  published plugin package may still carry its own older compatibility
50
54
  declaration until a release is made from this tree.
package/README.zh-CN.md CHANGED
@@ -30,17 +30,20 @@
30
30
 
31
31
  ## 从 npm 安装
32
32
 
33
- 当前源码面向 Node.js 22+ 与带 `web` profile 的**五个已审计 DSH 版本**:
34
- `0.2.0-rc.2`(`latest` 通道)、`alpha` 通道的 `0.2.1-alpha.3`、
35
- `0.2.1-alpha.4` 与 `0.2.1-alpha.5`,以及 `0.2.1-rc.2`(`next` 通道)。
33
+ 当前源码面向 Node.js 22+ 与带 `web` profile 的**六个已审计 DSH 版本**:
34
+ `0.2.0-rc.2`、`alpha` 通道的 `0.2.1-alpha.3`、
35
+ `0.2.1-alpha.4` 与 `0.2.1-alpha.5`,以及先后两版 `next` 通道的
36
+ `0.2.1-rc.2` 与 `0.2.1-rc.3`(npm 通道会移动:`latest` 现指向由 `next` 转正的
37
+ `0.2.1-rc.2`,`next` 指向 `0.2.1-rc.3`)。
36
38
  DSH 在组合 profile 前会校验插件声明的
37
39
  兼容要求,且**每次启动都会校验**(不只是安装时),因此其他宿主版本会拒绝
38
40
  激活本插件。从 DSH `0.2.1-alpha.4` 起,该校验只读 `engines.dsh` 并忽略
39
- `peerDependencies`;更早的宿主只认 peer 范围,因此两处列出同一组五个版本。
41
+ `peerDependencies`;更早的宿主只认 peer 范围,因此两处列出同一组六个版本。
40
42
  npm 包内置 macOS、Linux、Windows 的 amd64/arm64 Funnel helper;可信局域网
41
- 模式不依赖 helper。
43
+ 模式不依赖 helper。helper 用 Go 1.27 编译,要求 **macOS 13 Ventura 或更高版本**:
44
+ macOS 12 及更早版本无法启动 Funnel 模式,可信局域网模式不受影响。
42
45
 
43
- 当前工作树的 `engines.dsh` 与 `peerDependencies` 精确列出这五个版本,构建与
46
+ 当前工作树的 `engines.dsh` 与 `peerDependencies` 精确列出这六个版本,构建与
44
47
  类型检查针对 `0.2.0-rc.2`。从此工作树发布新版本前,已发布的旧插件包仍可能
45
48
  带有各自旧的兼容声明。
46
49
 
package/bin/SHA256SUMS CHANGED
@@ -1,6 +1,6 @@
1
- 4e83f82d5c623115d121f58264ca84706e5fc935dadc0747b37ae886d102dc6a ./darwin-amd64/dsh-deeppilot-tunnel
2
- 7707999a5b745d11afeb4ab1868c85680e4ff5567202d97015d72d810817a134 ./darwin-arm64/dsh-deeppilot-tunnel
3
- 8a83351568cb223854efbe8f54ca9a403fc2b152382d4e7c952d372b0b0cb3e9 ./linux-amd64/dsh-deeppilot-tunnel
4
- dfa4eb4dd50b386aadf40d9767ac0df8151308b620fa395d0a560498f01eb0cb ./linux-arm64/dsh-deeppilot-tunnel
5
- 9c734ea42bc6dd5763930991db52f910d5138e9b12df0e826d6964ceb271e215 ./windows-amd64/dsh-deeppilot-tunnel.exe
6
- e7db4a0e62f04266d97a5bad38e1a21961474440e7231fd5b24980053589faa0 ./windows-arm64/dsh-deeppilot-tunnel.exe
1
+ 0e49860ffd7b6fd9ba5918481cbfa2fc0a788f0c16d500de69a162d31451d526 ./darwin-amd64/dsh-deeppilot-tunnel
2
+ 16e0b6235cb097401dc52840f11c0dcf405925d23449934cdfea93ec89c071e9 ./darwin-arm64/dsh-deeppilot-tunnel
3
+ ed3d60db2da2f3c17a5f7d04834faf4623a955ecc48a3aa0497c3903df8a2bce ./linux-amd64/dsh-deeppilot-tunnel
4
+ b5e85cd9f9f928f4204cfc15067588d1c3dcdc683a5f5b85759d5454bce2110e ./linux-arm64/dsh-deeppilot-tunnel
5
+ 836126376d0da12abc6bafb3ed163138436f812b201bd254eb1c7cae3f8a34c7 ./windows-amd64/dsh-deeppilot-tunnel.exe
6
+ 6b74d0f4b73f9f53b01829a84abd178c17a64950c1e9949b8fae15ef274fb99f ./windows-arm64/dsh-deeppilot-tunnel.exe
@@ -3,7 +3,97 @@
3
3
  > This is the durable audit record for DeepPilot's public DSH plugin. Re-audit
4
4
  > the next DSH release instead of assuming that an rc upgrade is runtime-safe.
5
5
 
6
- ## Current decision — `dsh-v0.2.1-rc.2`
6
+ ## Current decision — `dsh-v0.2.1-rc.3`
7
+
8
+ - **Audited release:** `dsh-v0.2.1-rc.3`, published to the npm registry
9
+ 2026-10-23T07:54:30Z (GitHub Release 2026-10-23T15:26:39Z), and the **`next`**
10
+ channel release — `next` moved from `0.2.1-rc.2` to it, so this is the second
11
+ consecutive rc on that line to enter the supported list, each on its own audit.
12
+ It is **not** `latest`: the registry currently reads `latest = 0.2.1-rc.2`
13
+ (rc.2, promoted from `next`) and `alpha = 0.2.1-alpha.5`. This audit therefore also
14
+ corrected the older channel attribution that called `0.2.0-rc.2` the `latest`
15
+ channel in `AGENTS.md` and both READMEs — the list of six admitted hosts is
16
+ unchanged by that correction, only its description.
17
+ - **Comparison baseline:** `dsh-v0.2.1-rc.2` (the previous audited tag).
18
+ - **Plugin runtime verdict: no break, and no `src/` change was needed.**
19
+ Nineteen packages were compared **as whole trees, not by `lib/` alone** —
20
+ eighteen from the two installed trees plus `dsh-client-ui-slots` (the seventh
21
+ declared `dsh-*` peer, absent from both) through its registry tarball. Fourteen
22
+ differ only in `package.json`, three carry one further file each, and
23
+ `cordis 4.0.5` / `schemastery 3.18.5` are byte-identical including
24
+ `package.json`. Of 3,302 shared files, 3,275 are byte-identical and 20 differ.
25
+ The tree count moves 306 → 307 with the new
26
+ `@deepseek-ai/dsh-client-ui-entry-customization@0.2.1-rc.3`, the More-menu bundle
27
+ the web-app patch now references; this plugin neither references it nor depends
28
+ on it. Across 274 modules **no export symbol is added or removed** (18 entry
29
+ modules compared), so every earlier fix still holds unchanged. The manifest
30
+ delta over 19 packages covers 585 paths — 17 version bumps and 568
31
+ dependency-spec moves — with **zero structural differences**.
32
+ - **The three non-`package.json` files are additive or comment-only.**
33
+ `@deepseek-ai/dsh-api-remotes/lib/client.js` widens the client telemetry event
34
+ schema (`is_new_session`, `agent_preset`, and the More-menu / agent-preset
35
+ switch events), data this plugin neither emits nor validates.
36
+ `@deepseek-ai/dsh-api-session-controller`'s
37
+ `lib/types/client/sessions/service.d.ts` changes a doc comment only.
38
+ `@deepseek-ai/dsh-web-app/cordis.patch.yml` gains one hunk inserting the
39
+ `ui-entry-customization` bundle (the More menus named in the rc.3 release
40
+ notes); the patch anchor this plugin targets, `id: directory-picker`, is
41
+ byte-identical on both sides at the same offsets, and neither the new package
42
+ name nor `entry-customization` appears in this plugin's `cordis.patch.yml` or
43
+ `package.json`.
44
+ - **Activation verdict: the new release is admitted by both declarations, and the
45
+ earlier rc stays out.** rc.3, like rc.2, reads a declared `engines.dsh` alone,
46
+ so before the widening its refusal reported a **single** `engines.dsh`
47
+ requirement and `exempted: false` — no profile exemption file exists on this
48
+ machine — and a real rc.3 CLI reproduced it (`skipping profile bundle
49
+ "dsh-deeppilot"`) while the host itself still booted and served its web port.
50
+ Widening admits `0.2.1-rc.3` and nothing else: `0.2.1-rc.1` was never audited as
51
+ its own host, so it stays refused, as do `0.2.1-rc.3.1`, `0.2.1-rc.30`,
52
+ `0.2.1-RC.3`, `0.2.1`, `0.2.1-rc.2.1`, `0.2.0`, `0.3.0`, and `1.0.0`. Deleting
53
+ `engines.dsh` from a copy of the manifest falls back to the ten peers and admits
54
+ the same six hosts, so the short-circuit is unchanged.
55
+ - **Evidence: the published artifacts, the published evaluator, and a real rc.3
56
+ CLI run — all taken before any declaration changed.**
57
+ - **Change surface:** `.rc3-verify/CHANGE_SURFACE.md` and
58
+ `.rc3-verify/AUDIT.md`, with raw logs under `.rc3-verify/logs/`
59
+ (`master-table.txt`, `file-hash-compare.txt`, `diff-rq.all.txt`,
60
+ `patch-anchor-check.stdout.txt`), plus `tree-compare.out.json` (the
61
+ 16-package whole-tree comparison), `export-symbol-diff.out.json` (274
62
+ modules, zero surface deltas), `pkg-manifest-delta.out.json` (585 paths, all
63
+ version or dependency-spec values) and `patch-anchor-check.out.json` (the one
64
+ patch-file change and its anchor).
65
+ - **Activation decision, reproduced against rc.3's own published evaluator
66
+ before any edit:** `.rc3-verify/evaluator-repro.out.json` shows the unchanged
67
+ manifest refused with one `engines.dsh` requirement and `exempted: false`, and
68
+ the worktree manifest admitted; `.rc3-verify/matrix.out.json` projects the
69
+ widening over 15 candidates — before accepted 5, after accepted 6, **newly
70
+ accepted exactly `0.2.1-rc.3`, newly rejected 0**.
71
+ - **Real CLI refusal and real CLI load.** The refusal was captured from the
72
+ installed rc.3 CLI before the declaration changed; after the widening the same
73
+ CLI composes the plugin (`--dump-config`, exit 0, no skip line).
74
+ - **Positive load verified this time.** An isolated `0.2.1-rc.3` host — its own
75
+ `DSH_HOME` in a one-off scratch directory (since deleted), the plugin linked
76
+ from this working tree, and no other plugin — composed the plugin into the
77
+ tree, started it, and answered `https://127.0.0.1:3098/phone/health` with `200`:
78
+ `{"ok":true,"enabled":true,"protocolVersion":2,"serverVersion":"0.9.10","dataPlane":true}`
79
+ while the isolated home gained `deeppilot/host-id` and `deeppilot/lan-tls/`.
80
+ Evidence: `.rc3-verify/HOST-BOOT.md` (written after the audit directory was
81
+ handed over) with the raw log and probe output beside it.
82
+ - **Check set run (nothing published).** `npm test` (609 pass, 0 fail),
83
+ `typecheck`, `build` (committed `lib/` unchanged), `check:config-schema`, and
84
+ `smoke:helper` (darwin-arm64). One environment note carries forward: the
85
+ default npm cache on this machine holds root-owned files, so the
86
+ `check:config-schema` script's `npx` invocation fails with `EPERM` until
87
+ `npm_config_cache` points at a writable directory; with that variable set the
88
+ check passes. No `npm ci`, no commit, no push, no tag, and no npm publish: the
89
+ release is prepared but not shipped.
90
+ - **Not covered / limits.** No real iPhone run, no Funnel end-to-end, no
91
+ model-backed turn against this host. `npm ci` and the helper-matrix rebuild
92
+ steps were skipped because no helper, dependency, or source input changed; CI
93
+ rebuilds the matrix and fails on any `bin/` drift. The widening is a metadata
94
+ and documentation change only.
95
+
96
+ ### Previous decision — `dsh-v0.2.1-rc.2`
7
97
 
8
98
  - **Audited release:** `dsh-v0.2.1-rc.2`, published 2026-10-17T08:36:31.655Z. It is
9
99
  **not** `latest`: `latest` still points at `0.2.0-rc.2`, and `alpha` still points
@@ -115,6 +205,33 @@
115
205
  `200` and `serverVersion: "0.9.8"`; the GitHub Release was made public only after
116
206
  that install verification. The same release shipped the mobile skills, host
117
207
  commands, and catalog-cache work recorded below.
208
+ - **Published as 0.9.9 on 2026-10-21.** The annotated tag `v0.9.9` dereferences to
209
+ `feee5c5854cd598af7b7827c53ddffdec3199573` on `main`, with CI and CodeQL green on
210
+ that commit. The DSH compatibility declaration did not change (the same five
211
+ audited hosts). The first CI run on the release commit failed in the helper job:
212
+ `govulncheck` reported GO-2026-6809 in Go 1.26.9's `crypto/x509`, reachable
213
+ through `http.Server.Serve`; the helper moved to Go 1.26.10 and the
214
+ `build-helpers` workflow refreshed all six binaries (PR #30, six `go1.26.10`
215
+ binaries, `bin/SHA256SUMS` 6/6) before the tag was cut. `publish.yml` ran on the
216
+ tag (run `39612245054`): the upload and provenance steps succeeded, but its last
217
+ step (registry verification) exhausted its 24 retries with `HTTP 404` — the
218
+ registry-visibility delay already seen in 0.9.5 and 0.9.6, not an upload failure.
219
+ Checked by hand instead: `npm view --prefer-online` gives `latest: 0.9.9` with a
220
+ `https://slsa.dev/provenance/v1` attestation whose `gitCommit` is that commit and
221
+ whose workflow ref is `refs/tags/v0.9.9`; the published tarball's SHA1
222
+ `bfea9ade6be9eb07f209e0e76f5ea20326dc0ddb` and its SHA512 match the registry and
223
+ the attestation subject; it holds 68 entries (the pre-publication pack count) and
224
+ every packaged file compared byte-identically with the verified tree. A clean
225
+ isolated `DSH_HOME` then installed `dsh-deeppilot@0.9.9` from npm on a real
226
+ `0.2.1-rc.2` host (`dsh web --no-open --port 0`) and `/phone/health` answered `200`
227
+ with `serverVersion: "0.9.9"`, `protocolVersion: 2` and the data plane active.
228
+ The first start attempt failed because DSH's own web server could not bind
229
+ `127.0.0.1:3080`, which another running DSH instance held; that is an environment
230
+ conflict, not a plugin fault, and the plugin's own listener had come up. The
231
+ GitHub Release was made public only after that install verification. The release
232
+ ships connection-failure diagnostics, the `failed` Live Activity phase, the
233
+ optional `toolName` / `detail` approval fields and `mutable-content`; it must run
234
+ against a Relay that already accepts them.
118
235
 
119
236
  ### Previous decision — `dsh-v0.2.1-alpha.5`
120
237
 
@@ -117,6 +117,25 @@
117
117
  3098 的 `/phone/health` 返回 200 且 `serverVersion` 为 `0.9.8`;GitHub Release
118
118
  在这一步通过后才公开并标记 Latest。
119
119
 
120
+ 9. `0.9.9` 的实际发布结果(2026-10-21):附注标签 `v0.9.9` 指向
121
+ `feee5c5854cd598af7b7827c53ddffdec3199573`,该提交的 CI 与 CodeQL 均为绿。发布
122
+ 提交的首次 CI 曾因 helper 的 `govulncheck` 报 GO-2026-6809(Go 1.26.9 的
123
+ `crypto/x509`,调用链可达)而失败,处理方式是 helper 升到 Go 1.26.10,由
124
+ `build-helpers` 工作流重建六个二进制并合并刷新 PR(#30),之后才打标签。
125
+ `publish.yml` 在该标签上运行(运行号 `39612245054`):**上传与来源证明步骤成功,
126
+ 但最后的核对步骤在 24 次重试后仍抛 `读取 npm 发布信息失败(HTTP 404)`,整次运行
127
+ 结论为失败**——与 `0.9.5`、`0.9.6` 同一形态,说明 `0.9.7` 放宽的约 7 分钟窗口并非
128
+ 总是足够,注册表元数据的可见性延迟仍会超出它。事后人工核验:
129
+ `npm view --prefer-online` 得到 `latest = 0.9.9`;来源证明类型为
130
+ `https://slsa.dev/provenance/v1`,`gitCommit` 正是该提交,工作流引用为
131
+ `refs/tags/v0.9.9`;压缩包 SHA1 `bfea9ade6be9eb07f209e0e76f5ea20326dc0ddb` 与 SHA512
132
+ 同注册表和来源证明主体一致,共 68 个条目,包内每个文件与已验证的工作树逐字节相同。
133
+ 随后在全新隔离 `DSH_HOME` 中从 npm 安装 `dsh-deeppilot@0.9.9`,在真实
134
+ `0.2.1-rc.2` 宿主上用 `dsh web --no-open --port 0` 启动,`/phone/health` 返回 200,
135
+ `serverVersion` 为 `0.9.9`;首次启动因另一个正在运行的 DSH 占用了宿主自己的 3080
136
+ 端口而失败,属环境冲突,不是插件问题。GitHub Release 在这一步通过后才公开并标记
137
+ Latest。是否再放宽核对窗口,留待下次发布前决定,本次未改工作流。
138
+
120
139
  ## 五、官方资料
121
140
 
122
141
  1. [npm 可信发布配置与限制](https://docs.npmjs.com/trusted-publishers/)
package/lib/index.d.ts CHANGED
@@ -971,7 +971,11 @@ declare class HostBridge {
971
971
  * push failures must never block or break the WS data plane.
972
972
  */
973
973
  private fanOutPush;
974
- /** Remember the latest assistant text so notifications can quote it. */
974
+ /**
975
+ * Remember the latest assistant text so notifications can quote it. 存完整原文:
976
+ * 按字符数截尾会从链接地址中间切开(横幅只剩 URL 编码的路径),段落选择与
977
+ * Markdown 清洗统一留到 emitNotify。条目随 sessions.list / 归档清理。
978
+ */
975
979
  private captureAssistantText;
976
980
  /**
977
981
  * Replay buffered pushes after the given cursor; false when the gap is
package/lib/index.js CHANGED
@@ -5838,6 +5838,50 @@ function scheduleMutationCodec(persistValues) {
5838
5838
  };
5839
5839
  }
5840
5840
  //#endregion
5841
+ //#region src/notification-text.ts
5842
+ /**
5843
+ * 通知正文的纯文本投影。
5844
+ *
5845
+ * 为什么需要:s2c.notify 与 APNs 的 body 是"可直接展示"的文本(PROTOCOL §6),
5846
+ * 客户端不得改写;而来源(助手回复、审批原因、提问)都是 Host 给的 Markdown。
5847
+ * 直接截原文会把链接地址、URL 编码的中文路径、代码块符号带进锁屏横幅,
5848
+ * 所以 Bridge 出站前在这里统一转成纯文本。
5849
+ *
5850
+ * 只做"去标记、留可读文字",不追求完整 Markdown 语义;任何无法识别的写法原样保留。
5851
+ */
5852
+ /** 把 Markdown 拆成段落并逐段转为单行纯文本;清洗后为空的段落被丢弃。 */
5853
+ function notificationParagraphs(markdown) {
5854
+ return stripCodeFences(markdown.replace(/\r\n?/g, "\n")).split(/\n[ \t]*\n/).map(plainParagraph).filter((paragraph) => paragraph.length > 0);
5855
+ }
5856
+ /**
5857
+ * 通知正文:`last` 取最后一个非空段落(任务完成 / 异常结束——回复结尾通常是结论),
5858
+ * `all` 把全部段落合成一行(审批原因、提问原文)。长度上限由调用方负责。
5859
+ */
5860
+ function notificationPlainText(markdown, pick) {
5861
+ const paragraphs = notificationParagraphs(markdown);
5862
+ return pick === "last" ? paragraphs.at(-1) ?? "" : paragraphs.join(" ");
5863
+ }
5864
+ /** 围栏代码块整体丢弃:横幅里放不下代码,留一半反而更难读。未闭合的围栏丢到文末。 */
5865
+ function stripCodeFences(text) {
5866
+ return text.replace(/^[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?(?:^[ \t]*\1[ \t]*$|(?![\s\S]))/gm, "\n");
5867
+ }
5868
+ function plainParagraph(paragraph) {
5869
+ return decodePercentRuns(stripInline(paragraph.split("\n").filter((line) => !(line.includes("|") && line.includes("-") && /^[\s|:-]+$/.test(line))).filter((line) => !/^\s*([*_-])(\s*\1){2,}\s*$/.test(line)).map((line) => line.replace(/^\s*(>\s?)+/, "").replace(/^\s*#{1,6}\s+/, "").replace(/^\s*([-*+]|\d+[.)])\s+(\[[ xX]\]\s+)?/, "").replace(/^\s*\|(.*?)\|?\s*$/, (_row, cells) => cells.replace(/\s*\|\s*/g, " "))).join(" "))).replace(/\s+/g, " ").trim();
5870
+ }
5871
+ function stripInline(text) {
5872
+ return text.replace(/!\[[^\]]*\]\((?:[^()]|\([^()]*\))*\)/g, "").replace(/\[([^\]]+)\]\((?:[^()]|\([^()]*\))*\)/g, "$1").replace(/\[([^\]]+)\]\[[^\]]*\]/g, "$1").replace(/<((?:https?|mailto):[^>\s]+)>/g, "$1").replace(/<\/?[A-Za-z][^>]*>/g, "").replace(/(`+)([^`]+?)\1/g, "$2").replace(/(\*\*|__|~~)(?=\S)([\s\S]*?\S)\1/g, "$2").replace(/(^|[^\w*])\*(?=\S)([^*\n]*?\S)\*(?![\w*])/g, "$1$2").replace(/(^|[^\w])_(?=\S)([^_\n]*?\S)_(?!\w)/g, "$1$2");
5873
+ }
5874
+ /** 正文里残留的 %E6%8F%90 这类编码串解码成原字符;解不开(非法 UTF-8)就保持原样。 */
5875
+ function decodePercentRuns(text) {
5876
+ return text.replace(/(?:%[0-9A-Fa-f]{2})+/g, (run) => {
5877
+ try {
5878
+ return decodeURIComponent(run);
5879
+ } catch {
5880
+ return run;
5881
+ }
5882
+ });
5883
+ }
5884
+ //#endregion
5841
5885
  //#region src/host-api.ts
5842
5886
  /**
5843
5887
  * Subagent sessions are host-internal workers of a parent conversation.
@@ -6020,8 +6064,10 @@ var HostBridge = class {
6020
6064
  * PROTOCOL §6 + §7), then fan the same payload out to offline devices
6021
6065
  * holding an APNs token. */
6022
6066
  emitNotify(args) {
6023
- if ((args.category === "turn.completed" || args.category === "session.error") && this.subagentSessionIds.has(args.sessionId)) return;
6024
- const body = args.body.length > 120 ? args.body.slice(0, 119) + "…" : args.body;
6067
+ const turnEnd = args.category === "turn.completed" || args.category === "session.error";
6068
+ if (turnEnd && this.subagentSessionIds.has(args.sessionId)) return;
6069
+ const plain = notificationPlainText(args.body, turnEnd ? "last" : "all") || (args.fallbackBody ?? "");
6070
+ const body = plain.length > 120 ? plain.slice(0, 119) + "…" : plain;
6025
6071
  const approvalExtras = args.category === "approval.required" && args.toolName ? {
6026
6072
  toolName: args.toolName.slice(0, 80),
6027
6073
  ...args.detail ? { detail: args.detail.slice(0, 600) } : {}
@@ -6049,12 +6095,12 @@ var HostBridge = class {
6049
6095
  if (this.subagentSessionIds.has(sessionId)) return;
6050
6096
  const row = this.summaries.get(sessionId);
6051
6097
  const title = ok ? "任务完成" : "任务异常结束";
6052
- const body = this.lastAssistantText.get(sessionId) ?? row?.title ?? "";
6053
6098
  this.emitNotify({
6054
6099
  sessionId,
6055
6100
  category: ok ? "turn.completed" : "session.error",
6056
6101
  title,
6057
- body,
6102
+ body: this.lastAssistantText.get(sessionId) ?? "",
6103
+ fallbackBody: row?.title ?? "",
6058
6104
  notificationId: "n-" + (this.cursor + 1)
6059
6105
  });
6060
6106
  }
@@ -6067,11 +6113,15 @@ var HostBridge = class {
6067
6113
  this.pushOutlet?.fanOut(notification);
6068
6114
  } catch {}
6069
6115
  }
6070
- /** Remember the latest assistant text so notifications can quote it. */
6116
+ /**
6117
+ * Remember the latest assistant text so notifications can quote it. 存完整原文:
6118
+ * 按字符数截尾会从链接地址中间切开(横幅只剩 URL 编码的路径),段落选择与
6119
+ * Markdown 清洗统一留到 emitNotify。条目随 sessions.list / 归档清理。
6120
+ */
6071
6121
  captureAssistantText(sessionId, event) {
6072
6122
  if (event.type !== "assistant/message") return;
6073
6123
  const text = messageText(event.data).trim();
6074
- if (text.length > 0) this.lastAssistantText.set(sessionId, text.slice(-160));
6124
+ if (text.length > 0) this.lastAssistantText.set(sessionId, text);
6075
6125
  }
6076
6126
  /**
6077
6127
  * Replay buffered pushes after the given cursor; false when the gap is