dsh-notch 0.3.1 → 0.3.6

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 (102) hide show
  1. package/README.en.md +58 -47
  2. package/README.md +60 -55
  3. package/cordis.patch.yml +3 -0
  4. package/desktop/README.md +29 -0
  5. package/desktop/notch-lifecycle.mjs +120 -0
  6. package/desktop/restart-probe.mjs +61 -0
  7. package/docs/desktop-017rc2.md +23 -0
  8. package/docs/elastic-edge-dock.md +127 -0
  9. package/docs/motion-audit.md +1 -1
  10. package/docs/releases/v0.3.2.md +38 -0
  11. package/docs/releases/v0.3.3.md +9 -0
  12. package/docs/subagent-compatibility.md +51 -0
  13. package/docs/verification/elastic-algorithm-timing.json +337 -0
  14. package/docs/verification/elastic-attention.json +44 -0
  15. package/docs/verification/elastic-frame-timing.json +240 -0
  16. package/docs/verification/elastic-tension.json +59 -0
  17. package/docs/verification/elastic-tip-taper.json +181 -0
  18. package/dshx.yml +2 -0
  19. package/lib/client.js +112 -0
  20. package/lib/client.js.map +1 -0
  21. package/lib/index.mjs +990 -0
  22. package/lib/index.mjs.map +1 -0
  23. package/package.json +66 -10
  24. package/src/board.ts +178 -35
  25. package/src/client/index.ts +104 -0
  26. package/src/dsh-notch.ts +19 -2
  27. package/src/http.ts +17 -2
  28. package/src/session-state.ts +15 -1
  29. package/src/store.ts +3 -3
  30. package/src/types.ts +3 -0
  31. package/BASELINE.md +0 -13
  32. package/DESIGN.md +0 -34
  33. package/cordis.yml +0 -5
  34. package/macos/Package.swift +0 -17
  35. package/macos/STATUS-MOTION.md +0 -49
  36. package/macos/Sources/Client.swift +0 -139
  37. package/macos/Sources/IdleRobot.swift +0 -423
  38. package/macos/Sources/NotchMarkdown.swift +0 -266
  39. package/macos/Sources/Panel.swift +0 -153
  40. package/macos/Sources/Resources/Idle/balance.json +0 -1
  41. package/macos/Sources/Resources/Idle/blink.json +0 -1
  42. package/macos/Sources/Resources/Idle/cube-in.json +0 -1
  43. package/macos/Sources/Resources/Idle/dance.json +0 -1
  44. package/macos/Sources/Resources/Idle/hop.json +0 -1
  45. package/macos/Sources/Resources/Idle/nod.json +0 -1
  46. package/macos/Sources/Resources/Idle/satellite-in.json +0 -1
  47. package/macos/Sources/Resources/Idle/satellite-out.json +0 -1
  48. package/macos/Sources/Resources/Idle/scan.json +0 -1
  49. package/macos/Sources/Resources/Idle/sleep.json +0 -1
  50. package/macos/Sources/Resources/Idle/sneeze.json +0 -1
  51. package/macos/Sources/Resources/Idle/stretch.json +0 -1
  52. package/macos/Sources/Resources/Idle/tilt.json +0 -1
  53. package/macos/Sources/ReviewStudio.swift +0 -337
  54. package/macos/Sources/RootView.swift +0 -1093
  55. package/macos/Sources/StatusOrbit.swift +0 -642
  56. package/macos/Sources/main.swift +0 -153
  57. package/macos/Tests/ExpandedHeightProbe.swift +0 -108
  58. package/macos/Tests/GeometryProbe.swift +0 -98
  59. package/macos/Tests/IdleProbe.swift +0 -294
  60. package/macos/Tests/MotionProbe.swift +0 -106
  61. package/macos/Tests/OutcomeProbe.swift +0 -133
  62. package/macos/Tests/ScrollbarProbe.swift +0 -91
  63. package/macos/Tests/expanded-height.sh +0 -13
  64. package/macos/Tests/geometry.sh +0 -14
  65. package/macos/Tests/idle.sh +0 -14
  66. package/macos/Tests/motion.sh +0 -14
  67. package/macos/Tests/outcome.sh +0 -14
  68. package/macos/Tests/scrollbar.sh +0 -13
  69. package/tests/answer-lifecycle.test.mjs +0 -23
  70. package/tests/board.test.mjs +0 -7
  71. package/tests/browse-sync.test.mjs +0 -20
  72. package/tests/mirror.test.mjs +0 -4
  73. package/tests/peer-range.test.mjs +0 -21
  74. package/tests/session-state.test.mjs +0 -54
  75. package/tests/unread-hold.test.mjs +0 -90
  76. package/tools/desktop-shell/README.md +0 -56
  77. package/tools/desktop-shell/child-log.mjs +0 -6
  78. package/tools/desktop-shell/child-log.test.mjs +0 -14
  79. package/tools/desktop-shell/package-recovery.py +0 -78
  80. package/tools/desktop-shell/recovery-probe.cjs +0 -50
  81. package/tools/desktop-shell/renderer-recovery.mjs +0 -95
  82. package/tools/desktop-shell/renderer-recovery.test.mjs +0 -24
  83. package/tools/diagnostics/completion-watch.py +0 -101
  84. package/tools/diagnostics/completion-watch.test.py +0 -17
  85. package/tools/diagnostics/renderer-diagnostics.mjs +0 -56
  86. package/tools/diagnostics/renderer-diagnostics.test.mjs +0 -32
  87. package/tools/idle/LICENSE.open-bot-motion +0 -21
  88. package/tools/idle/export.mjs +0 -40
  89. package/tools/idle/index.html +0 -4
  90. package/tools/idle/motions.js +0 -83
  91. package/tools/idle/original.js +0 -1673
  92. package/tools/idle/renderer.js +0 -1673
  93. package/tools/recording/Client.swift +0 -76
  94. package/tools/recording/DemoCatalog.swift +0 -174
  95. package/tools/recording/README.md +0 -23
  96. package/tools/recording/build.sh +0 -41
  97. package/tools/recording/main.swift +0 -100
  98. package/tools/review/ReviewStudio.swift +0 -236
  99. package/tools/review/audit.sh +0 -19
  100. package/tools/review/build.sh +0 -7
  101. package/tools/review/main.swift +0 -158
  102. package/tools/review/render-audit.swift +0 -32
package/README.en.md CHANGED
@@ -8,70 +8,57 @@ Installation has two parts: a **Host plugin inside DSH** that supplies session s
8
8
 
9
9
  ## Installation
10
10
 
11
- ### Requirements
11
+ **DSH Notch 0.3.4 supports official DeepSeek Harness `0.2.0-rc.2`.** Install `dsh-notch@0.3.4` and `dsh-notch-focus@0.1.2` from npm. The native macOS helper remains version 0.3.3 and is included in the release below. This release changes npm packaging and installation instructions; its runtime code matches 0.3.3.
12
12
 
13
- - macOS 14 or later.
14
- - DeepSeek Harness `0.1.7-rc.1`. This package peers `@deepseek-ai/dsh` and the `@deepseek-ai/dsh-*` packages it imports at `>=0.1.7-rc.1 <0.1.8`.
15
- - A working local DSH Web Host, with `dsh`, `pnpm`, and `git` available in your terminal.
16
- - Swift 6 or later through Command Line Tools. Check with `swift --version`; use `xcode-select --install` if the developer tools are missing.
13
+ ### 1. Download the release
17
14
 
18
- These instructions use the default `web` profile and `~/.dsh`. For a custom `DSH_HOME`, run plugin installation with that same environment and edit that Home's profile in step 2.
15
+ Download from [v0.3.4](https://github.com/aa2246740/dsh-notch/releases/tag/v0.3.4):
19
16
 
20
- ### 1. Download and install the Host plugin
17
+ | File | Purpose |
18
+ | --- | --- |
19
+ | `dsh-notch-0.3.4.tgz` | Host plugin for status, questions, and native connectivity |
20
+ | `dsh-notch-focus-0.1.2.tgz` | Client companion for navigation and reading acknowledgements |
21
+ | `dsh-notch-0.3.3-macos-arm64.tar.gz` | Native executable and robot resources; macOS 14+, Apple Silicon |
22
+ | `SHA256SUMS` | Place beside the downloads and run `shasum -a 256 -c SHA256SUMS` |
21
23
 
22
- ```sh
23
- git clone https://github.com/aa2246740/dsh-notch.git
24
- cd dsh-notch
25
- dsh plugin --profile web add "$PWD"
26
- ```
24
+ Prebuilt packages do not require Swift or DSHX. Other architectures require a source build and are not covered by this binary release.
27
25
 
28
- This links the local package into DSH's Web profile. Keep the checkout: it is also where you build the native application.
26
+ ### 2. Install both plugin packages
29
27
 
30
- The warning `declares no dsh.bundle — installed as a plain dependency` is expected for this package. **Continue with step 2 to activate it.** The current package has no automatic bundle registration, so `plugin add` alone does not start Notch.
28
+ **Official Desktop:** enter `dsh-notch@0.3.4` and `dsh-notch-focus@0.1.2` through the app's Plugins page, enable them, follow the app's loading instructions, then reopen the page. The app owns the Desktop profile.
31
29
 
32
- If you run DSH from source without a global `dsh` command, run this from the Harness checkout, then return to the Notch checkout:
30
+ **Web:** use the same `DSH_HOME` as the running Host, then run from your download directory:
33
31
 
34
32
  ```sh
35
- pnpm dsh plugin --profile web add /absolute/path/to/dsh-notch
33
+ dsh plugin --profile web add dsh-notch@0.3.4
34
+ dsh plugin --profile web add dsh-notch-focus@0.1.2
36
35
  ```
37
36
 
38
- ### 2. Activate the plugin in DSH
39
-
40
- Append this item to the YAML list in `~/.dsh/profiles/web/cordis.patch.yml`. Create the file if absent. **Keep existing configuration, and add this ID only once.**
41
-
42
- ```yaml
43
- - insert:
44
- - id: dsh-notch
45
- name: dsh-notch
46
- ```
37
+ Both packages declare official `dsh.bundle.patch` entries. Follow the plugin manager's loading guidance and reopen the page. Do not add a second manual insert. Update existing entries when migrating older installations so a Bundle and an old manual patch do not mount the same plugin twice.
47
38
 
48
- `name: dsh-notch` resolves the profile dependency from step 1. Do not copy the repository's `cordis.yml` directly into this location; its relative paths serve a different purpose.
39
+ A loaded Host writes `$DSH_HOME/dsh-notch/runtime.json`. This is a private connection file managed by the plugin; do not fill it in or share it. Check Host loading errors if it is absent.
49
40
 
50
- The standard Web profile watches this file and loads the plugin after saving. If DSH is not running yet, start it using your usual launcher. Successful loading emits `[my-plugins/dsh-notch] loaded` in the Host log and creates `~/.dsh/dsh-notch/runtime.json`.
51
-
52
- The plugin manages this private connection file automatically. Do not fill it in manually or paste its contents into a chat. If it is absent, resolve YAML, module-resolution, or missing-service errors in the Host before continuing.
53
-
54
- ### 3. Build and start the real Notch
55
-
56
- From the Notch checkout:
41
+ ### 3. Extract and start the native helper
57
42
 
58
43
  ```sh
59
- swift build --package-path macos -c release
60
- macos/.build/release/dsh-notch --verify-idle-resources
61
- macos/.build/release/dsh-notch
44
+ tar -xzf dsh-notch-0.3.3-macos-arm64.tar.gz
45
+ cd dsh-notch-0.3.3-macos-arm64
46
+ ./dsh-notch --verify-idle-resources
47
+ ./dsh-notch
62
48
  ```
63
49
 
64
- The resource check should print `IDLE_RESOURCES=10/10`. The last command starts the application connected to real DSH sessions. Keep this terminal open during the first run.
50
+ The resource check should print `IDLE_RESOURCES=10/10`. Keep the terminal open for the first run. If a desktop launcher already manages a Notch helper, update that executable instead. Always keep `dsh-notch` and `DshNotch_DshNotch.bundle` together when moving them. A custom `DSH_HOME` must match the Host's Home.
65
51
 
66
- If your DSH.app already manages a Notch helper, update that copy instead of starting a duplicate. When moving the executable or integrating it into a desktop shell, keep `dsh-notch` and `DshNotch_DshNotch.bundle` from the same build together in the destination directory, then relaunch the helper. Installing the Host plugin does not configure login startup or replace a desktop shell's existing executable.
52
+ Optionally set the Host plugin's `helperPath` configuration to the absolute path of the extracted executable and follow the app's plugin loading guidance. The Host then supervises that helper; do not also start another copy manually.
67
53
 
68
- ### 4. Confirm it works
54
+ ### 4. Confirm synchronization
69
55
 
70
- - With no active work or unread results, the robot appears at the screen edge.
71
- - Existing running sessions produce a blue count; questions and results produce their corresponding states.
72
- - Clicking a session opens it in DSH. When a question appears, answer it directly in Notch.
56
+ - Running primary sessions show a blue count; completions, failures, and questions show their corresponding states.
57
+ - Clicking a Notch session opens the matching conversation in DSH.
58
+ - Opening a completed session in foreground DSH clears that result from Notch. Running tasks remain visible.
59
+ - Reading all results returns Notch to the idle robot.
73
60
 
74
- Use existing sessions for these checks; a new model task is unnecessary. Seeing the robot alone does not prove Host connectivity: confirm that real session state updates too.
61
+ The native helper exits with its Host. Temporary request failures do not close it. Closing only the window keeps it alive if the Host still runs. See [desktop helper ownership](desktop/README.md) for lifecycle integration.
75
62
 
76
63
  ## Usage
77
64
 
@@ -84,9 +71,17 @@ Use existing sessions for these checks; a new model task is unnecessary. Seeing
84
71
  | Click an option | Submit that choice; follow the panel for multiple questions or selections |
85
72
  | Click the question title | Open the full conversation in DSH |
86
73
  | Read all results | Return to the idle robot |
74
+ | Drag and release Notch | Hide it elastically at the screen edge; drag it out again to restore |
75
+ | New completion, failure, or decision while hidden | Bounce back to the normal compact view; repeated polls of the same event do not reveal it again |
76
+
77
+ Ordinary running-state and size updates keep a hidden Notch tucked away. An attention event received during a drag waits until release. Screen work-area changes, including a right-side macOS Dock, do not move the hidden cap away from the physical display edge.
87
78
 
88
79
  The interface uses native AppKit, SwiftUI, and Canvas. Animation itself never calls a model. The panel grows with content, scrolls at the screen-height cap, and respects Reduced Motion.
89
80
 
81
+ Counts represent user conversations. Workflow workers and nested subagents belong to their owning conversation; they do not add separate running, success, or failure indicators. A background worker keeps its owner running, while result indicators come from the owner's final outcome. Child questions appear on the owner's yellow indicator and answers return to the original requester, with multiple questions handled in order. User-created forks remain independent conversations.
82
+
83
+ External Codex, Claude Code, ACP, and DSH SDK children registered as official background jobs also keep their owner active. Observation never consumes job completion notices. The [dsh-notch-focus companion](companions/dsh-notch-focus/README.md) handles browser navigation and cold-session mirroring; existing installations can keep their current directory. See the [source compatibility audit](docs/subagent-compatibility.md) for entry paths, cancellation, resumption, and verification limits.
84
+
90
85
  ## Troubleshooting
91
86
 
92
87
  | Symptom | Check |
@@ -98,16 +93,28 @@ The interface uses native AppKit, SwiftUI, and Canvas. Animation itself never ca
98
93
  | Two Notches | Check for both a manually started and a desktop-shell-managed copy. |
99
94
  | Old behavior after updating source | Rebuild and replace the executable actually running; `git pull` does not replace an existing native process. |
100
95
 
101
- The Host plugin requires `sessions`, `webServer`, `approval`, `userQuestions`, and `agents`. It targets a local DSH Web Host on the same Mac. Native foregrounding looks for a DSH.app with bundle ID `local.dsh.desktop`; other desktop shells need an adapter. Successful package installation alone does not certify multiple Homes, remote Hosts, or every DSH version.
96
+ The Host plugin requires `sessions`, `webServer`, `approval`, `userQuestions`, and `agents`. It targets a local DSH Web Host on the same Mac. Native foregrounding prefers official `com.deepseek.dsh` and retains compatibility with `local.dsh.desktop`. Successful package installation alone does not certify multiple Homes, remote Hosts, or every DSH version.
102
97
 
103
98
  ## Updates and development
104
99
 
105
100
  After updating source, rebuild the native helper. Native-only changes require updating and relaunching Notch. Changes under `src/` also require the appropriate Host module activation.
106
101
 
107
- Maintainers using [dshx](https://github.com/aa2246740/dsh-external-plugin-devkit) can inspect `dshx activation-plan dsh-notch --change artifact` or `--change server`, according to the changed surface. Initial activation above uses a watched patch; restarting the whole Host does not replace a missing installation step.
102
+ Maintainers using [dshx](https://github.com/aa2246740/dsh-external-plugin-devkit) can inspect `dshx activation-plan dsh-notch --change artifact` or `--change server`, according to the changed surface. Package synchronization and live activation are separate checks.
103
+
104
+ Source builds require Node.js 24 and Swift 6 / Command Line Tools:
105
+
106
+ ```sh
107
+ npm ci --ignore-scripts --legacy-peer-deps
108
+ npm run build
109
+ npm run build:macos
110
+ ```
111
+
112
+ See the [companion README](companions/dsh-notch-focus/README.md) for its DSHX 0.9.2 build against a `dsh-v0.2.0-rc.2` checkout. Release consumers do not need DSHX.
113
+
114
+ Development checks:
108
115
 
109
116
  ```sh
110
- npm ci
117
+ npm ci --ignore-scripts --legacy-peer-deps
111
118
  npm test
112
119
  npm run test:outcome
113
120
  npm run test:motion
@@ -118,6 +125,8 @@ npm run test:idle
118
125
  npm run build:macos
119
126
  ```
120
127
 
128
+ Try the elastic edge-hiding gesture in the [standalone native preview](tools/elastic-preview/README.md), built with `npm run build:elastic-preview`. It uses local fixtures, makes no model requests, and does not replace an installed Notch.
129
+
121
130
  ### Optional recording demo
122
131
 
123
132
  For animation review and video recording, separate from plugin installation:
@@ -129,8 +138,10 @@ open "dist/DSH Notch Demo.app"
129
138
 
130
139
  The demo contains 36 bilingual scenes driven by local fixtures. It does not connect to DSH. See the [demo controls](tools/recording/README.md).
131
140
 
132
- More: [motion contracts](macos/STATUS-MOTION.md), [design notes](DESIGN.md), [0.3.0 changes](docs/releases/v0.3.0.md), and [optional desktop-shell diagnostics](tools/desktop-shell/README.md).
141
+ More: [motion contracts](macos/STATUS-MOTION.md), [design notes](DESIGN.md), [0.3.3 changes](docs/releases/v0.3.3.md), [0.3.2 changes](docs/releases/v0.3.2.md), [0.3.0 changes](docs/releases/v0.3.0.md), and [optional desktop-shell diagnostics](tools/desktop-shell/README.md).
133
142
 
134
143
  ## License
135
144
 
136
145
  [MIT](LICENSE). Robot resources derive from [OpenBotMotion](https://github.com/aa2246740/open-bot-motion); its original [MIT notice](tools/idle/LICENSE.open-bot-motion) is retained. This is a community-maintained DSH plugin.
146
+
147
+ See the [Desktop 0.1.7-rc.2 verification record](docs/desktop-017rc2.md). `DSH_NOTCH_RUNTIME_FILE` selects the connection only. Use explicit `--demo` or `--elastic-preview` modes for offline presentation.
package/README.md CHANGED
@@ -8,77 +8,57 @@
8
8
 
9
9
  ## 安装
10
10
 
11
- ### 准备条件
11
+ **DSH Notch 0.3.4 支持官方 DeepSeek Harness `0.2.0-rc.2`。** 从 npm 安装 `dsh-notch@0.3.4` 和 `dsh-notch-focus@0.1.2`。原生 macOS 程序继续使用 0.3.3,包含在下面的发布页中。本次只调整 npm 打包和安装说明,运行代码与 0.3.3 相同。
12
12
 
13
- - macOS 14 或更新版本。
14
- - DeepSeek Harness `0.1.7-rc.1`。本包对 `@deepseek-ai/dsh` 与所用 `@deepseek-ai/dsh-*` 的 peer 是 `>=0.1.7-rc.1 <0.1.8`。
15
- - 本机已有正常运行的 DSH Web Host;终端能使用 `dsh`、`pnpm` 和 `git`。
16
- - Swift 6 或更新版本的 Command Line Tools。用 `swift --version` 检查;没有开发工具时先运行 `xcode-select --install`。
13
+ ### 1. 下载发布包
17
14
 
18
- 以下以默认的 `web` profile、`~/.dsh` 为例。若你的 DSH 使用自定义 `DSH_HOME`,插件安装命令必须使用同一环境,第二步也要编辑该 Home 下的 profile 文件。
15
+ 从 [v0.3.4 Release](https://github.com/aa2246740/dsh-notch/releases/tag/v0.3.4) 下载:
19
16
 
20
- ### 1. 下载并安装 Host 插件
21
-
22
- ```sh
23
- git clone https://github.com/aa2246740/dsh-notch.git
24
- cd dsh-notch
25
- dsh plugin --profile web add "$PWD"
26
- ```
17
+ | 文件 | 用途 |
18
+ | --- | --- |
19
+ | `dsh-notch-0.3.4.tgz` | Host 插件,提供状态、问题和原生程序连接 |
20
+ | `dsh-notch-focus-0.1.2.tgz` | 客户端同步助手,负责双向会话跳转与已读同步 |
21
+ | `dsh-notch-0.3.3-macos-arm64.tar.gz` | macOS 14+、Apple Silicon 原生程序及机器人资源 |
22
+ | `SHA256SUMS` | 下载校验;与上述文件放在同一目录后执行 `shasum -a 256 -c SHA256SUMS` |
27
23
 
28
- 这条命令把本地插件目录链接到 DSH 的 Web profile。请保留这个目录,后面还要在这里构建 Notch。
24
+ 预编译包无需 Swift 或 DSHX。其他架构需从源码构建,尚未提供验收过的预编译包。
29
25
 
30
- 如果看到 `declares no dsh.bundle — installed as a plain dependency`,这是当前包的预期提示:**包已经装入,继续第二步把插件加入运行配置。** 当前版本没有声明自动挂载的 bundle,单独执行 `plugin add` 还不会显示 Notch。
26
+ ### 2. 在 DSH 安装两个插件包
31
27
 
32
- <details>
33
- <summary>从 Harness 源码运行,没有全局 dsh 命令?</summary>
28
+ **官方 Desktop:** 在应用内插件管理页分别输入 `dsh-notch@0.3.4` 和 `dsh-notch-focus@0.1.2`,确认都已启用,按应用提示完成加载,再重新打开页面。Desktop profile 由应用管理。
34
29
 
35
- 在 Harness checkout 里运行它自己的 CLI,使用刚下载插件的绝对路径:
30
+ **Web:** 对运行中的 Host 使用相同的 `DSH_HOME`,在下载目录执行:
36
31
 
37
32
  ```sh
38
- pnpm dsh plugin --profile web add /absolute/path/to/dsh-notch
39
- ```
40
-
41
- 然后回到 `dsh-notch` 目录继续下面的步骤。
42
-
43
- </details>
44
-
45
- ### 2. 在 DSH 中激活插件
46
-
47
- 打开 `~/.dsh/profiles/web/cordis.patch.yml`,在现有 YAML 列表中追加下面这一项。文件不存在时可新建;**保留已有配置,同一个 `id` 只添加一次**。
48
-
49
- ```yaml
50
- - insert:
51
- - id: dsh-notch
52
- name: dsh-notch
33
+ dsh plugin --profile web add dsh-notch@0.3.4
34
+ dsh plugin --profile web add dsh-notch-focus@0.1.2
53
35
  ```
54
36
 
55
- 这里的 `name: dsh-notch` 从第一步安装的 profile 依赖中解析。不要直接复制仓库内的 `cordis.yml`:里面的相对路径用途不同。
56
-
57
- 标准 Web profile 会监听这份配置并热加载插件。若 DSH 正在运行,保存后等它加载即可;尚未启动 DSH 时,用你原来的启动入口启动它。成功后,Host 日志会出现 `[my-plugins/dsh-notch] loaded`,并生成 `~/.dsh/dsh-notch/runtime.json`。
58
-
59
- 该文件包含 Notch 的本机连接信息,由插件自动管理,不需要手动填写或把内容发给 Agent。如果没有生成,先检查 Host 是否报 YAML、模块解析或缺少服务的错误,再继续第三步。
37
+ 两个包都声明了官方 `dsh.bundle.patch`。按插件管理器的提示加载,并重新打开页面;不要再手工追加同名 `insert`。已有安装应更新原条目,避免 Bundle 与旧手动配置重复挂载。
60
38
 
61
- ### 3. 构建并启动正式 Notch
39
+ Host 加载后生成 `$DSH_HOME/dsh-notch/runtime.json`。这是插件管理的私有连接文件,不需要填写或分享。找不到它时,先检查 Host 插件的加载错误。
62
40
 
63
- 在刚下载的 `dsh-notch` 目录执行:
41
+ ### 3. 解压并启动原生程序
64
42
 
65
43
  ```sh
66
- swift build --package-path macos -c release
67
- macos/.build/release/dsh-notch --verify-idle-resources
68
- macos/.build/release/dsh-notch
44
+ tar -xzf dsh-notch-0.3.3-macos-arm64.tar.gz
45
+ cd dsh-notch-0.3.3-macos-arm64
46
+ ./dsh-notch --verify-idle-resources
47
+ ./dsh-notch
69
48
  ```
70
49
 
71
- 资源检查应输出 `IDLE_RESOURCES=10/10`。最后一条命令启动连接真实 DSH 会话的 Notch;首次启动时保持这个终端窗口打开。
50
+ 资源检查应输出 `IDLE_RESOURCES=10/10`。首次运行请保持终端打开;如果已有桌面启动器管理 Notch,更新它使用的那份程序即可。移动时始终把 `dsh-notch` 和 `DshNotch_DshNotch.bundle` 放在一起。使用自定义 `DSH_HOME` 时,原生程序和 Host 必须指向同一 Home。
72
51
 
73
- 如果你使用的 DSH.app 已经在管理一份 Notch,只更新那份程序,避免同时启动两个。移动程序或接入 App 壳时,要把 `dsh-notch` 和同一构建目录的 `DshNotch_DshNotch.bundle` 一起放到目标目录,再重新启动 Notch 程序。单独安装 Host 插件不会自动配置登录启动,也不会替换某个 App 壳里的旧程序。
52
+ 可在 Host 插件配置中把 `helperPath` 设为已解压的 `dsh-notch` 的绝对路径,让插件随 Host 管理辅助进程;配置后按应用的插件加载提示生效。请勿同时手工启动另一份。
74
53
 
75
- ### 4. 确认安装成功
54
+ ### 4. 确认同步正常
76
55
 
77
- - 没有活跃任务和未读结果时,屏幕边缘出现机器人。
78
- - 已有会话运行时出现蓝色计数;完成、失败或等待决定时显示对应状态。
79
- - 点击会话能回到 DSH;出现问题时可以直接在 Notch 里选择回答。
56
+ - 正在运行的主会话显示蓝色计数;完成、失败或等待回答显示对应状态。
57
+ - 点击 Notch 的会话,DSH 打开对应对话。
58
+ - 在 DSH 前台打开已完成的会话,Notch 清除该条未读状态;仍在运行的任务继续保留。
59
+ - 全部结果读完后,Notch 回到机器人待机。
80
60
 
81
- 可以用已有会话检查,不必为了测试新开一个模型任务。仅出现机器人还不能证明已经连接 Host;还要确认真实会话状态能同步。
61
+ Notch 跟随连接文件中的 Host 进程退出。临时请求失败不会让它退出;只关闭窗口而 Host 仍在后台运行时,它会继续显示任务。[桌面托管说明](desktop/README.md)介绍了辅助程序的退出与快速重启联动。
82
62
 
83
63
  ## 使用
84
64
 
@@ -91,9 +71,17 @@ macos/.build/release/dsh-notch
91
71
  | 点击问题选项 | 直接提交该选项;多选或多题按面板提示完成 |
92
72
  | 点击问题标题 | 回到 DSH 查看完整上下文 |
93
73
  | 全部结果读完 | 回到机器人待机 |
74
+ | 拖动 Notch 后松手 | 弹性收纳到屏幕边缘;再拖出即可恢复 |
75
+ | 隐藏时出现新完成、错误或待审批问题 | 自动弹回正常紧凑状态;同一提醒不会因轮询反复弹出 |
76
+
77
+ 隐藏状态下,普通运行和尺寸更新不打扰你。鼠标正在拖动时收到新提醒,会先保持跟手,等松手再恢复。右侧系统 Dock 或显示工作区变化不会改变 Notch 对物理屏幕边缘的定位。
94
78
 
95
79
  Notch 使用原生 AppKit / SwiftUI / Canvas 渲染。动画本身不调用模型。窗口随内容展开,达到屏幕高度上限后滚动;系统开启“减少动态效果”时呈现静态状态。
96
80
 
81
+ 计数以用户的主对话为单位:workflow 和普通子代理(包括嵌套子代理)归到所属主对话,不会各自增加蓝色数字或生成完成、失败灯。后台子代理仍在工作时,主任务继续显示运行中;结果灯以主对话的最终结果为准。子代理需要你回答的问题会显示在主任务的黄色状态下,回答送回原请求,多个问题依次处理。用户手动 fork 出来的对话仍独立计数。
82
+
83
+ 外部 Codex、Claude Code、ACP、DSH SDK 子代理转入官方后台任务后,也会归到所属主对话。Notch 只读取状态,不消费后台任务的完成通知。浏览器跳转和未加载会话的同步由 [dsh-notch-focus 助手](companions/dsh-notch-focus/README.md)提供;已有安装保留原目录更新即可。入口、取消与恢复路径的检查范围见[源码兼容性审计](docs/subagent-compatibility.md)。
84
+
97
85
  ## 常见安装问题
98
86
 
99
87
  | 现象 | 检查位置 |
@@ -105,28 +93,43 @@ Notch 使用原生 AppKit / SwiftUI / Canvas 渲染。动画本身不调用模
105
93
  | 屏幕上出现两个 Notch | 检查是否同时启动了手动版本和 App 壳管理的版本,只保留预期的那一份。 |
106
94
  | 更新源码后仍是旧效果 | 重新构建,并更新实际运行的可执行文件;只 `git pull` 不会替换已启动的原生进程。 |
107
95
 
108
- 当前 Host 插件依赖 `sessions`、`webServer`、`approval`、`userQuestions`、`agents` 服务,面向同一台 Mac 上的 DSH Web Host。原生界面的会话跳转会唤起 bundle ID 为 `local.dsh.desktop` 的 DSH.app;其他 App 壳的前台唤起需要适配。多 Home、远程 Host 和各版本 DSH 的兼容性不能只凭安装成功判断。
96
+ 若状态灯叠影、点击后才恢复,可按发生时间查看 `~/.dsh/dsh-notch/presentation.jsonl`。日志只记录计数、动画阶段、布局和进程编号,不记录对话正文、标题或认证信息;达到 256 KiB 后轮换,只保留当前和上一份。刷新时会检查过期的转场并补做收尾,菜单交互期间也继续推进状态与布局计时器。
97
+
98
+ 当前 Host 插件依赖 `sessions`、`webServer`、`approval`、`userQuestions`、`agents` 服务,面向同一台 Mac 上的 DSH Web Host。原生界面的会话跳转优先唤起官方 `com.deepseek.dsh` 桌面版,并保留旧 `local.dsh.desktop` 壳的兼容。多 Home、远程 Host 和各版本 DSH 的兼容性不能只凭安装成功判断。
109
99
 
110
100
  ## 更新与开发
111
101
 
112
- 更新已安装的源码后,重新构建原生程序。只改原生界面时,更新并重新启动 Notch 即可;若改了 `src/` 下的 Host 插件代码,还需要对应的服务端热加载。
102
+ 更新已安装的源码后,重新构建原生程序。只改原生界面时,更新并重新启动 Notch 即可;若改了 `src/` 下的 Host 插件代码,先 `npm run build` 更新 `lib/index.mjs`,再做对应的服务端热加载。
103
+
104
+ 使用 [dshx](https://github.com/aa2246740/dsh-external-plugin-devkit) 的维护者可先执行 `dshx activation-plan dsh-notch --change artifact` 或 `--change server`,按实际修改范围更新。激活要匹配实际 Host 和挂载方式,不能把复制原生二进制当作 Host 模块热更新。
105
+
106
+ 从源码构建 Host 和原生程序需要 Node.js 24、Swift 6 / Command Line Tools:
113
107
 
114
- 使用 [dshx](https://github.com/aa2246740/dsh-external-plugin-devkit) 的维护者可先执行 `dshx activation-plan dsh-notch --change artifact` 或 `--change server`,按实际修改范围更新。安装文档中的首次配置属于 watched patch,不能用重启整个 Host 代替缺失的安装步骤。
108
+ ```sh
109
+ npm ci --ignore-scripts --legacy-peer-deps
110
+ npm run build
111
+ npm run build:macos
112
+ ```
113
+
114
+ 同步助手的源码构建需要 DSHX 0.9.2 和已备好依赖的 `dsh-v0.2.0-rc.2` Harness checkout;步骤见[助手说明](companions/dsh-notch-focus/README.md)。预编译发布包不需要这些开发工具。
115
115
 
116
116
  开发检查:
117
117
 
118
118
  ```sh
119
- npm ci
119
+ npm ci --ignore-scripts --legacy-peer-deps
120
120
  npm test
121
121
  npm run test:outcome
122
122
  npm run test:motion
123
123
  npm run test:geometry
124
124
  npm run test:scrollbar
125
125
  npm run test:expanded-height
126
+ npm run test:host-lifetime
126
127
  npm run test:idle
127
128
  npm run build:macos
128
129
  ```
129
130
 
131
+ 弹性收纳交互可在 [独立原生预览](tools/elastic-preview/README.md) 中试用;运行 `npm run build:elastic-preview` 构建,不连接 DSH、不调用模型,也不替换当前安装。
132
+
130
133
  ### 录屏 Demo(可选)
131
134
 
132
135
  用于开发、检查动画或录制演示视频,**不属于插件安装步骤**:
@@ -138,8 +141,10 @@ open "dist/DSH Notch Demo.app"
138
141
 
139
142
  Demo 提供 36 个中英双语场景,使用本地假任务,不连接 DSH。录屏控制与快捷键见 [Demo 文档](tools/recording/README.md)。
140
143
 
141
- 更多:[动效说明](macos/STATUS-MOTION.md) · [设计说明](DESIGN.md) · [0.3.0 更新记录](docs/releases/v0.3.0.md) · [可选 App 壳诊断](tools/desktop-shell/README.md)。
144
+ 更多:[动效说明](macos/STATUS-MOTION.md) · [设计说明](DESIGN.md) · [0.3.3 更新记录](docs/releases/v0.3.3.md) · [0.3.2 更新记录](docs/releases/v0.3.2.md) · [0.3.0 更新记录](docs/releases/v0.3.0.md) · [可选 App 壳诊断](tools/desktop-shell/README.md)。
142
145
 
143
146
  ## 许可
144
147
 
145
148
  [MIT](LICENSE)。机器人资源基于 [OpenBotMotion](https://github.com/aa2246740/open-bot-motion),保留了原始 [MIT 许可声明](tools/idle/LICENSE.open-bot-motion)。这是社区维护的 DSH 插件。
149
+
150
+ 官方桌面版的原生启动适配与验证见 [0.1.7-rc.2 验证记录](docs/desktop-017rc2.md)。`DSH_NOTCH_RUNTIME_FILE` 只指定连接文件,绝不触发演示偏移;演示使用显式的 `--demo` 或 `--elastic-preview` 入口。
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: dsh-notch
3
+ name: dsh-notch
@@ -0,0 +1,29 @@
1
+ # Desktop helper ownership
2
+
3
+ `notch-lifecycle.mjs` is a small Node/Electron integration for desktop shells that launch the native helper. It owns both a helper it spawns and an existing helper adopted from a PID file. It verifies the executable and process start time, retries if the adopted helper exits during startup, and closes the owned helper on application quit.
4
+
5
+ ```js
6
+ import { superviseNotch } from './notch-lifecycle.mjs'
7
+
8
+ let notch
9
+ app.on('before-quit', () => notch?.stop())
10
+ // After the authenticated Host has finished starting:
11
+ notch = superviseNotch({ bin: absoluteHelperPath, pidPath: helperPIDPath, log })
12
+ ```
13
+
14
+ Register quit cleanup before awaiting Host startup. If the app quits while startup is pending, cancel/terminate its own starting Host and do not start Notch afterwards. Do not terminate an unrelated Host to manage Notch.
15
+
16
+ An external native updater should create `${pidPath}.updating` before stopping the old helper, replace the binary/resources, start and verify the new helper, publish its PID, then remove the marker in a `finally` block. The marker expires after 60 seconds if an updater crashes. This prevents the shell's recovery from racing the updater.
17
+
18
+ The native helper also watches its Host independently. Actual process exit closes it without a deliberate grace delay; HTTP timeouts do not. A process that has already committed to exiting is replaced by the desktop supervisor rather than treated as a usable helper forever.
19
+
20
+ Validation:
21
+
22
+ ```sh
23
+ npm test
24
+ swift build --package-path macos -c release
25
+ python3 macos/Tests/helper-lifetime.py
26
+ node desktop/restart-probe.mjs
27
+ ```
28
+
29
+ The native probes use disposable local owner processes and isolated runtime files. They never start DSH or invoke a model.
@@ -0,0 +1,120 @@
1
+ import { spawn, execFileSync } from 'node:child_process'
2
+ import { readFileSync, mkdirSync, writeFileSync, renameSync, unlinkSync, statSync } from 'node:fs'
3
+ import { dirname, resolve } from 'node:path'
4
+
5
+ /** PID alone is not ownership: require both executable and process start time. */
6
+ export function processIdentity(pid) {
7
+ if (!Number.isSafeInteger(pid) || pid <= 1) return { state: 'dead' }
8
+ try {
9
+ const text = execFileSync('/bin/ps', ['-p', String(pid), '-o', 'lstart=', '-o', 'comm='],
10
+ { encoding: 'utf8', env: { ...process.env, LC_ALL: 'C' }, timeout: 1000 }).trim()
11
+ const match = /^(.{24})\s+(.+)$/.exec(text)
12
+ if (match) return { state: 'alive', stamp: match[1], command: match[2] }
13
+ } catch {}
14
+ try { process.kill(pid, 0) } catch (error) {
15
+ if (error.code === 'ESRCH') return { state: 'dead' }
16
+ }
17
+ return { state: 'unknown' }
18
+ }
19
+
20
+ export function processLiveness(pid) {
21
+ if (!Number.isSafeInteger(pid) || pid <= 1) return 'dead'
22
+ try { process.kill(pid, 0); return 'alive' } catch (error) {
23
+ return error.code === 'ESRCH' ? 'dead' : 'unknown'
24
+ }
25
+ }
26
+
27
+ /** The desktop owns an adopted helper too. If it exits during adoption, retry. */
28
+ export function superviseNotch({ bin, pidPath, log, interval = 250, env = process.env,
29
+ probe = processIdentity, alive = processLiveness, launch = spawn, signal = process.kill.bind(process) }) {
30
+ let current, pending, timer, stopped = false
31
+ const starts = []
32
+ const note = text => log.write(`[notch] ${text}\n`)
33
+ const storedPID = () => {
34
+ try { return Number(readFileSync(pidPath, 'utf8').trim()) } catch { return 0 }
35
+ }
36
+ const owned = pid => {
37
+ const identity = probe(pid)
38
+ return identity.state === 'alive' && resolve(identity.command) === resolve(bin)
39
+ ? { pid, ...identity, checkedAt: Date.now() } : undefined
40
+ }
41
+ const schedule = () => {
42
+ clearTimeout(timer)
43
+ if (!stopped) { timer = setTimeout(reconcile, interval); timer.unref?.() }
44
+ }
45
+ function reconcile() {
46
+ if (stopped) return
47
+ if (pending) { schedule(); return }
48
+ // External installers hold this short lease while replacing executable + PID.
49
+ // A crashed installer cannot disable recovery indefinitely.
50
+ try {
51
+ if (Date.now() - statSync(`${pidPath}.updating`).mtimeMs < 60000) { schedule(); return }
52
+ } catch {}
53
+ if (current) {
54
+ const state = alive(current.pid)
55
+ if (state === 'unknown' || (state === 'alive' && Date.now() - current.checkedAt < 5000)) {
56
+ schedule(); return
57
+ }
58
+ const live = probe(current.pid)
59
+ if (live.state === 'unknown' || (live.state === 'alive' && live.stamp === current.stamp && live.command === current.command)) {
60
+ current.checkedAt = Date.now()
61
+ schedule(); return
62
+ }
63
+ current = undefined
64
+ }
65
+ const pid = storedPID()
66
+ const identity = probe(pid)
67
+ if (identity.state === 'unknown') { schedule(); return }
68
+ current = owned(pid)
69
+ if (current) { note(`adopt ${current.pid}`); schedule(); return }
70
+ while (starts.length && Date.now() - starts[0] > 10000) starts.shift()
71
+ if (starts.length >= 3) { note('helper repeatedly exited; retry paused'); stopped = true; return }
72
+ starts.push(Date.now())
73
+ const child = launch(bin, [], { stdio: ['ignore', 'pipe', 'pipe'], detached: false, env })
74
+ pending = child
75
+ child.stdout?.pipe(log, { end: false })
76
+ child.stderr?.pipe(log, { end: false })
77
+ child.once('spawn', () => {
78
+ if (pending !== child) return
79
+ pending = undefined
80
+ if (stopped) { child.kill('SIGTERM'); return }
81
+ current = owned(child.pid)
82
+ // A successful spawn still must be attributable before touching its PID file.
83
+ if (!current) { child.kill('SIGTERM'); schedule(); return }
84
+ mkdirSync(dirname(pidPath), { recursive: true })
85
+ const stage = `${pidPath}.${process.pid}.tmp`
86
+ writeFileSync(stage, `${child.pid}\n`)
87
+ renameSync(stage, pidPath)
88
+ note(`spawn ${child.pid}`)
89
+ schedule()
90
+ })
91
+ child.once('error', error => { if (pending === child) pending = undefined; note(`spawn error: ${error.message}`); schedule() })
92
+ child.once('exit', () => {
93
+ if (pending === child) pending = undefined
94
+ if (current?.pid === child.pid) current = undefined
95
+ schedule()
96
+ })
97
+ schedule()
98
+ }
99
+ const stop = () => {
100
+ stopped = true
101
+ clearTimeout(timer)
102
+ pending?.kill('SIGTERM')
103
+ // A native hot replacement may have updated the file since the last check.
104
+ const candidates = [current, owned(storedPID())].filter(Boolean)
105
+ const seen = new Set()
106
+ for (const item of candidates) {
107
+ if (seen.has(item.pid)) continue
108
+ seen.add(item.pid)
109
+ const live = owned(item.pid)
110
+ if (!live || live.stamp !== item.stamp) continue
111
+ try { signal(item.pid, 'SIGTERM'); note(`stop ${item.pid}`) } catch (error) {
112
+ if (error.code !== 'ESRCH') note(`stop failed: ${error.message}`)
113
+ }
114
+ if (storedPID() === item.pid) { try { unlinkSync(pidPath) } catch {} }
115
+ }
116
+ current = undefined
117
+ }
118
+ reconcile()
119
+ return { get pid() { return current?.pid ?? pending?.pid }, stop, kill: stop }
120
+ }
@@ -0,0 +1,61 @@
1
+ // Real native helper + disposable sleep processes; never starts DSH or calls a model.
2
+ import assert from 'node:assert/strict'
3
+ import { spawn } from 'node:child_process'
4
+ import { once } from 'node:events'
5
+ import { mkdtempSync, writeFileSync, rmSync, readFileSync } from 'node:fs'
6
+ import { tmpdir } from 'node:os'
7
+ import { join } from 'node:path'
8
+ import { fileURLToPath } from 'node:url'
9
+ import { Writable } from 'node:stream'
10
+ import { superviseNotch, processIdentity } from './notch-lifecycle.mjs'
11
+
12
+ const bin = fileURLToPath(new URL('../macos/.build/release/dsh-notch', import.meta.url))
13
+ const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
14
+ const logs = new Writable({ write(_chunk, _encoding, callback) { callback() } })
15
+ const running = child => child.exitCode === null && child.signalCode === null
16
+ async function owner() {
17
+ const child = spawn('/bin/sleep', ['60']); await once(child, 'spawn'); return child
18
+ }
19
+ async function stop(child) {
20
+ if (!child || !running(child)) return
21
+ const exited = once(child, 'exit'); child.kill('SIGTERM'); await exited
22
+ }
23
+
24
+ for (const gap of [0, 50, 1200]) {
25
+ const root = mkdtempSync(join(tmpdir(), 'notch-restart-'))
26
+ const runtime = join(root, 'runtime.json'), pidPath = join(root, 'helper.pid')
27
+ const children = []
28
+ let first, second, manager
29
+ const writeOwner = child => writeFileSync(runtime, JSON.stringify({ pid: child.pid,
30
+ writtenAt: Date.now(), origin: 'http://127.0.0.1:9', token: 'offline-test' }))
31
+ const launch = (file, args, options) => {
32
+ const child = spawn(file, args, { ...options, env: { ...process.env, DSH_NOTCH_RUNTIME_FILE: runtime } })
33
+ children.push(child); return child
34
+ }
35
+ try {
36
+ first = await owner(); writeOwner(first)
37
+ const old = launch(bin, [], { stdio: 'ignore', detached: true }); await once(old, 'spawn')
38
+ writeFileSync(pidPath, String(old.pid))
39
+ await delay(800)
40
+ assert.equal(processIdentity(old.pid).command, bin)
41
+ await stop(first)
42
+ await delay(gap)
43
+ second = await owner(); writeOwner(second)
44
+ manager = superviseNotch({ bin, pidPath, launch, log: logs, interval: 25 })
45
+ await delay(900)
46
+ const live = children.filter(running)
47
+ assert.equal(live.length, 1, `gap ${gap}: exactly one helper expected`)
48
+ assert.equal(manager.pid, live[0].pid)
49
+ assert.equal(Number(readFileSync(pidPath, 'utf8')), live[0].pid)
50
+ const start = performance.now()
51
+ manager.stop()
52
+ while (children.some(running) && performance.now() - start < 1000) await delay(10)
53
+ assert.equal(children.filter(running).length, 0, 'quit must also close an adopted helper')
54
+ console.log(`PASS restart gap=${gap}ms: one live helper; quit ${(performance.now() - start).toFixed(0)}ms`)
55
+ } finally {
56
+ manager?.stop()
57
+ await Promise.all(children.map(stop))
58
+ await stop(first); await stop(second)
59
+ rmSync(root, { recursive: true, force: true })
60
+ }
61
+ }
@@ -0,0 +1,23 @@
1
+ # 官方桌面版 0.1.7-rc.2 适配
2
+
3
+ 本分支保留 `ff78f13` 的完整弹性拖拽、左端变细、隐藏贴边和关注事件弹回,合入 `e79bbf1` 的 RC2 兼容分支,并保存当前本地桌面部署已经采用的 Home 路径、原生辅助程序托管、后台子任务及桌面唤起适配。
4
+
5
+ ## 本次故障
6
+
7
+ 正式 Host 给辅助程序传入 `DSH_NOTCH_RUNTIME_FILE`,用于指定连接文件。旧原生入口却用同一个变量判断“演示”,把窗口向内移动 360 pt,并让决策面板忽略自动折叠。现在连接选择与显示行为完全分开:正式入口始终以物理屏幕右边缘为锚点,离线演示只走已有显式入口。
8
+
9
+ ## 验证
10
+
11
+ - `npm run test:desktop-launch` 使用真正的 `AppDelegate` 和离线连接文件,检查原生窗口边界:旧入口测得 360 pt 间隙,修复后为 0 pt。测试不连接真实 Host,不调用模型。
12
+ - `npm run test:edge-dock` 通过,覆盖二维拖动、连续形变、原形裁切、回弹打断、重要事件恢复和减少动态效果。
13
+ - `npm test`:61/61 通过,包含 RC2 的 `jobs.list(agent.id)`、`job.owner` 和主任务归属。每个测试进程使用临时 `DSH_HOME`,防止继承真实 Home 写入已读状态。
14
+ - Release 原生构建与 Host 预编译构建通过;`dshx check` 检查源入口通过,热替换文件集合同时声明实际加载的 `lib/index.mjs` 与源码及辅助模块。
15
+ - 原生预览实操完成斜向拖动收纳、运行更新保持隐藏、完成后完整弹回。
16
+
17
+ ## 部署边界
18
+
19
+ 本次运行中需要改变的只有用户目录里的原生辅助程序。当前 Host 已经加载 RC2 适配的 Host 插件,服务器部分不需要再激活。更新采用辅助程序自己的短更新租约、哈希与进程身份检查、备份和原子替换;由现有托管器拉起唯一新辅助进程。官方应用包、Host 进程、profile 配置及真实任务均不修改。
20
+
21
+ 当前 DSHX 外部 CLI 的 desktop `activation-plan` 能分类为 artifact,但离线 profile 合成需要 Creator+ 发出的短时能力,返回 `DESKTOP_PROFILE_BRIDGE_REQUIRED`。本次不绕过此限制、不伪造票据、不执行 Host 插件激活;原生辅助程序的独立更新与运行验证单独记录。以后若改 Host 模块,仍需满足对应激活流程。
22
+
23
+ 正式验收区分源代码、构建、安装哈希、唯一进程、Host 快照和 GUI 操作。独立预览不等于向正式会话注入事件,算法测试不等于实屏帧率保证。