@gehennawu/dsh-service 1.9.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -9,9 +9,9 @@
9
9
  <em>DeepSeek Harness (DSH) Web 服务控制与运维插件。</em>
10
10
  </p>
11
11
 
12
- [![Version](https://img.shields.io/badge/version-1.9.9-3b82f6.svg?style=flat-square)](package.json)
12
+ [![Version](https://img.shields.io/badge/version-2.0.0-3b82f6.svg?style=flat-square)](package.json)
13
13
  [![License: MIT](https://img.shields.io/badge/License-MIT-10b981.svg?style=flat-square)](LICENSE)
14
- [![DSH Compatibility](https://img.shields.io/badge/DSH-%E2%89%A50.1.1--rc.2%20%C2%B7%20compatible%20with%200.1.7--rc.2-6366f1.svg?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)
14
+ [![DSH Compatibility](https://img.shields.io/badge/DSH-%E2%89%A50.1.1--rc.2%20%C2%B7%20compatible%20with%200.2.0--rc.1-6366f1.svg?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)
15
15
  [![Cordis](https://img.shields.io/badge/Cordis-v4.x-f59e0b.svg?style=flat-square)](https://cordis.moe/)
16
16
  [![Platform](https://img.shields.io/badge/platform-DSH%20Web-ec4899.svg?style=flat-square)](https://github.com/gehennawu/dsh-service)
17
17
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/gehennawu/dsh-service/issues)
@@ -74,7 +74,7 @@ Under **Plugins → Plugin configuration**, twelve host-level switches: **Health
74
74
 
75
75
  - Shows the current DSH and plugin versions, linking to GitHub Releases
76
76
  - Automatically checks npm **stable + preview** (latest / next dist-tags)
77
- - "What's new" sits right after the current version number and is always available: it opens the notes for **the version you are running**; when a new version exists, the status text ("New version: x.y.z") is clickable and expands **the new version's** release info. Either way the host fetches the body from the GitHub Releases API and the client renders it in place (plain Markdown — no iframe, no navigation), with the version number, publish date and a pre-release tag; a missing Release or a failed read each get their own message; clicking anywhere outside the version card or pressing Escape closes it. Both rows lay their version number and "What's new" button out on **one shared set of columns**, with the version number right-aligned so that the gap before the button is fixed — they line up **regardless of version-number length**, since a longer version only widens the whole column instead of knocking one row out of place
77
+ - "What's new" sits right after the current version number and is always available: it opens the notes for **the version you are running**; when a new version exists, the status text ("New version: x.y.z") is clickable and expands **the new version's** release info. Either way the host fetches the body from the GitHub Releases API and the client renders it in place (plain Markdown — no iframe, no navigation), with the version number, publish date and a pre-release tag; a missing Release or a failed read each get their own message; clicking anywhere outside the version card or pressing Escape closes it. Both rows lay their version number and "What's new" button out on **one shared set of columns**, with the version number right-aligned so that the gap before the button is fixed — they line up **regardless of version-number length**, since a longer version only widens the whole column instead of knocking one row out of place; narrow containers (phones and narrow settings panels) keep the same alignment — the version number absorbs the row's slack and right-aligns, so both rows still share their column edges
78
78
  - One-click upgrade with automatic restart; when no process manager is detected, it confirms the consequences first, keeps running, and shows manual-restart instructions
79
79
  - Between the upgrade landing and the process restart (common in a manual-launch environment) the version row reads "Installed X — restart to take effect" and the upgrade button is withdrawn; reopening the panel or refreshing the page keeps that state until the process is restarted
80
80
 
@@ -198,7 +198,7 @@ Under **Plugins → Plugin configuration**, twelve host-level switches: **Health
198
198
  - Sidebar becomes a drawer, details column is hidden on mobile (matching the official narrow-screen behavior), modals become full-screen panels, settings left nav a horizontal top strip
199
199
  - The model picker collapses to an icon on phones (≤480 px, mirroring the official narrow-container form; from 481 px up it still shows the model name and reasoning effort) — the plugin's mobile layout widens the composer column, so the official `@container (width<=360px)` collapse rule never fires on 428~440 px devices; this aligns with the official narrow-container form explicitly
200
200
  - The stats line under the composer ("turns/steps · tok/s | tok · cache hit") **stays on one line, centred and straight** on phones: this row's own horizontal padding is tightened (official 32 px → 2 px) along with its gaps to free up width, and the official `justify-content` centres both chips — zero truncation from ~420 px up, proportionally less text cut than the official fixed truncation below that, with no wrapping and no horizontal scrolling; this also works on older DSH (on 0.1.5-rc.2 the row spans the full width, where the earlier sub-item `flex-grow` pushed both chips as a group to the left — they no longer grow) (desktops unaffected)
201
- - The session header is re-flowed on phones (≤560 px): the title row keeps only the **title + preset chip** (the chip hugs the "…" button on the right, the title stays nearly fully visible), while the "N subagents" and "N background jobs running" counter chips park as a pair on the right of the Conversation/Trajectory tab row (tab gap 36→20, tapping a chip still opens its menu); the official crumbs **hard-clip** is eliminated, and layouts ≥561 px keep the official flow
201
+ - The session header is re-flowed on phones (≤560 px): the title row keeps only the **title + preset chip** (the chip hugs the "…" button on the right, the title stays nearly fully visible), while the "N subagents" and "N background jobs running" counter chips park as a pair on the right of the Conversation/Trajectory tab row (tab gap 36→20, tapping a chip still opens its menu); the official crumbs **hard-clip** is eliminated, and layouts ≥561 px keep the official flow. From DSH 0.1.7-rc.1 the official preset label hides itself via `@container (width<=540px)` (the container is the title row, roughly viewports up to 606 px), so the mode chip vanished on every phone; the plugin overrides that back to visible across the whole mobile range (from 390 px up the title stays untruncated, only 320–375 px trade away 15–70 px of title as an ellipsis)
202
202
  - The Agent Team panel stays on screen on phones (<1024 px): the official panel is left-anchored (`left:0`), so sitting in the header's right-hand action slot pushes it off the right edge (measured 112–352 px past the viewport at 320–1023 px). On mobile the session header becomes the positioning context and the panel is re-anchored to the **right with a 16 px inset** and capped at `100vw − 32px`, leaving 16 px on each side; desktop ≥1024 px keeps the official geometry byte-for-byte
203
203
  - Scroll immersion: inside a conversation, swiping down auto-hides the header and composer for full-screen reading (the composer also yields its layout space so the transcript really fills the screen; on reveal, if you are still at the end of the conversation it re-aligns to the bottom). Swipe up, tapping the official "Back to bottom" button, or focusing the composer brings them back (no extra floating button); already sitting at the end of the conversation, a single small backward nudge reveals it right away (no full threshold needed), and after a back-to-bottom tap the resting position gets one extra bottom snap. Programmatic scrolling (streaming pinning, anchor jumps) never triggers it
204
204
  - Swipeable drawers: with both drawers closed, a horizontally dominant swipe rightward anywhere opens the sidebar drawer and a swipe leftward anywhere opens the official right sidebar (DSH 0.1.5+; stays inert when unavailable); once open, a swipe in the reverse direction anywhere closes them. Swipes starting at the screen edge additionally benefit from stolen-gesture completion for browser edge navigation, and horizontal scrolling inside editors never misfires
@@ -300,6 +300,20 @@ Key contracts:
300
300
 
301
301
  ## ⚡ Installation
302
302
 
303
+ ### Option 1: DSH plugin manager (graphical, recommended)
304
+
305
+ 1. Open the **Plugins** page in the left sidebar.
306
+ 2. Click the **+ Add plugin** button in the top-right corner.
307
+ 3. In the dialog, enter `@gehennawu/dsh-service` in the **Package name** field and leave the source at the default **official npm registry**.
308
+ 4. Click **Install** and wait for the official layer to add the package to the current profile (the dialog reports progress and the result).
309
+ 5. The plugin then appears under **Installed**. The host half takes effect after the DSH process restarts; the client half applies on a page refresh.
310
+ - On Web: use this plugin's **Service Control → Restart**, or send `/restart` in a conversation;
311
+ - On DSH Desktop: quit the app and open it again (the desktop app owns the host process, so this plugin never exits it on its own).
312
+
313
+ > Tip: the plugin manager's Install button uses the official npm registry and the official installation path — no command line and no manual profile edits.
314
+
315
+ ### Option 2: Command line
316
+
303
317
  | Method | Command |
304
318
  | --- | --- |
305
319
  | npm (recommended) | `dsh plugin --profile web add @gehennawu/dsh-service` |
@@ -318,7 +332,7 @@ Open DSH Web Settings and select **Service Control**.
318
332
 
319
333
  The plugin only sends an exit signal; it does not start the process again. Without a process manager, restart stops DSH Web.
320
334
 
321
- The plugin passively detects a process manager (environment variables, `/.dockerenv`, `/proc/1/cgroup`, terminal TTY): with Docker/systemd/pm2/supervisord/Kubernetes detected it restarts as usual; when nothing is detected and stdin/stdout are an interactive terminal, it treats the launch as manual — flagged in Health diagnostics and switching one-click upgrade to keep running with manual-restart instructions. Heuristics cannot cover redirected output or wrappers such as NSSM/WinSW; declare `DSH_SERVICE_RUNTIME_ENV=managed|manual` explicitly.
335
+ The plugin passively detects a process manager (environment variables, `/.dockerenv`, `/proc/1/cgroup`, terminal TTY): with Docker/systemd/pm2/supervisord/Kubernetes detected it restarts as usual; when nothing is detected and stdin/stdout are an interactive terminal, it treats the launch as manual — flagged in Health diagnostics and switching one-click upgrade to keep running with manual-restart instructions. Heuristics cannot cover redirected output or wrappers such as NSSM/WinSW; declare `DSH_SERVICE_RUNTIME_ENV=managed|manual|desktop` explicitly.
322
336
 
323
337
  ### Docker Compose
324
338
 
@@ -350,11 +364,15 @@ pm2 start "dsh web --host 127.0.0.1" --name dsh-web
350
364
  | Linux + Docker Compose | Supported | Supported with a restart policy | Verified |
351
365
  | Linux + systemd / pm2 | Expected to work | Managed externally | Not separately tested |
352
366
  | macOS / Windows + pm2 or similar | Not blocked by the code | Managed externally | Not tested |
367
+ | DSH Desktop (Windows, Electron) | Supported | Owned by the desktop app | Verified (real host, 2026-09-28) |
368
+ | DSH Desktop (macOS / Linux, Electron) | Not blocked by the code | Owned by the desktop app | Not verified |
353
369
  | Direct `dsh web` execution | Supported | Not supported | Expected behavior |
354
370
 
355
371
  Requirements: Node.js `>=22`, and a DSH Web installation capable of loading both Host and Client plugin halves. Update checks require access to `registry.npmjs.org`; network failures do not affect other features.
356
372
 
357
- **DSH compatibility statement**: adapted to DSH `0.1.7-rc.2` — session format V4 (V3 logs are migrated by the official layer into a `session.v4.jsonl.zstd` generation file on first read, with the old `session.v3.jsonl.zstd` retained per the format catalog's policy; the detail view automatically archives system events), the `SettingsForms` configuration surface (plugin config now lives in the Profile's `cordis.patch.yml` with hot updates over `loader/volatile-update`, while the legacy `settings.register` remains authoritative on 0.1.5/0.1.6 so the two never cross-contaminate on a shared host), and all existing V3 adaptation (the `system/message` history, the handle-based sessionPersistence, the official right sidebar, the object-shaped turn-process), plus dual-hash compatibility for mobile bottom-row triggers, subagent turn-tail list-slot adaptive compatibility, `plugins.bundle.config` slot injection, and session-detail open fallback through `uiWorkspace`. Older DSH releases (`>=0.1.1-rc.2`) remain supported. The declared range now extends through `0.1.7-rc.2`; source-level and artifact-level reviews of rc.2 (346 commits) found no new breakage, and CSS hash stems have zero drift across artifact grep; the plugin-version compatibility gate introduced in rc.1 reads only `peerDependencies` (this plugin declares none, so the gate does not apply); real-host mounting on DSH `0.1.7-rc.2` is operational. The settings surface and the persistence/layout seams all run in dual shapes detected from runtime capabilities, and adaptation items that target newer structures are naturally inert on older hosts (cosmetic only, no functional loss). Note: sessions written after upgrading cannot be read by older DSH releases — **backups do not restore across a version downgrade**. The plugin marketplace judges compatibility from the `engines.dsh` range in `package.json`, which is the single declaration of the supported range.
373
+ **DSH compatibility statement**: adapted to DSH `0.2.0-rc.1` — session format V4 (V3 logs are migrated by the official layer into a `session.v4.jsonl.zstd` generation file on first read, with the old `session.v3.jsonl.zstd` retained per the format catalog's policy; the detail view automatically archives system events), the `SettingsForms` configuration surface (plugin config now lives in the Profile's `cordis.patch.yml` with hot updates over `loader/volatile-update`, while the legacy `settings.register` remains authoritative on 0.1.5/0.1.6 so the two never cross-contaminate on a shared host), and all existing V3 adaptation (the `system/message` history, the handle-based sessionPersistence, the official right sidebar, the object-shaped turn-process), plus dual-hash compatibility for mobile bottom-row triggers, subagent turn-tail list-slot adaptive compatibility, `plugins.bundle.config` slot injection, and session-detail open fallback through `uiWorkspace`. Older DSH releases (`>=0.1.1-rc.2`) remain supported. The declared range now extends through `0.2.0-rc.1`; source-level and artifact-level reviews of 0.2.0-rc.1 (261 commits) found no new breakage — 17 of 20 existing seams are byte-identical, key official package artifacts are byte-identical, and CSS class anchors and theme tokens show zero drift across artifact grep; the plugin-version compatibility gate introduced in rc.1 reads only `peerDependencies` (this plugin declares none, so the gate does not apply); real-host mounting on DSH `0.2.0-rc.1` is operational. The settings surface and the persistence/layout seams all run in dual shapes detected from runtime capabilities, and adaptation items that target newer structures are naturally inert on older hosts (cosmetic only, no functional loss). Note: sessions written after upgrading cannot be read by older DSH releases — **backups do not restore across a version downgrade**. The plugin marketplace judges compatibility from the `engines.dsh` range in `package.json`, which is the single declaration of the supported range.
374
+
375
+ **DSH Desktop (Electron) statement**: the desktop app reuses the same Web frontend and the same client plugin graph (`platform: web`), so the plugin loads as usual and almost everything works unchanged; only "restart" and "one-click upgrade" differ in meaning. The host is owned by the desktop app, so **restart never calls `process.exit(42)`** there (the shell treats any non-zero exit as a host crash, shows a native failure dialog and does not relaunch it; there is no official programmatic restart RPC) — the Restart button, the `/restart` command and the post-restore restart all guide the user to quit and reopen the desktop app instead; **one-click upgrade is greyed out on the desktop** and points at the app's own plugin manager (the bundled CLI cannot boot or mutate `profiles/desktop`, so the upgrade endpoint short-circuits with `desktop-managed-upgrade` and spawns nothing); the Health diagnostics "Runtime environment" row reads "Managed by DSH Desktop (Electron)". The signal is `process.versions.electron` inside the host process (measured on the real Windows desktop build: `44.0.0`, with `ELECTRON_RUN_AS_NODE=1` and non-TTY stdio); non-Electron desktop wrappers can declare `DSH_SERVICE_RUNTIME_ENV=desktop`. Task notifications **do work on the desktop app** (the permission is granted and a real system notification has been observed); the only boundary is that **clicking a notification cannot bring the window back** (closing the window hides it and `dshDesktop` exposes no window API — use the tray). macOS / Linux desktop builds are not verified.
358
376
 
359
377
  ## 🔒 Security design
360
378
 
@@ -381,6 +399,12 @@ The plugin only sends an exit signal; a process manager brings it back (see "Aut
381
399
  It is the "likely manual terminal launch" detection — no process manager found. If it is actually managed by NSSM/WinSW or output redirection, declare `DSH_SERVICE_RUNTIME_ENV=managed` to clear it.
382
400
  </details>
383
401
 
402
+ <details>
403
+ <summary><strong>Why do task notifications not appear on DSH Desktop?</strong></summary>
404
+
405
+ Check two things first: (1) the **master notification switch** under "Configuration → Notifications" must actually be on — it defaults to off and only turns on after you click "Enable notifications" and the system grants permission (if you only see the "Enable notifications" button, permission has not been granted yet); (2) the session must really go from running to finished, and it must not be a subagent session. System notifications themselves do work on the desktop app: Windows "Settings → System → Notifications" registers an `electron.app.DeepSeek Harness` entry, and a real "task complete" toast has been observed on the actual machine. The only known boundary is that **clicking the notification does not bring the window back** — closing the window hides it and the current desktop bridge exposes no window API; use the system tray instead.
406
+ </details>
407
+
384
408
  <details>
385
409
  <summary><strong>A quota card shows "credential missing"?</strong></summary>
386
410
 
package/README.md CHANGED
@@ -9,9 +9,9 @@
9
9
  <em>A service-control &amp; operations plugin for DeepSeek Harness (DSH) Web.</em>
10
10
  </p>
11
11
 
12
- [![Version](https://img.shields.io/badge/version-1.9.9-3b82f6.svg?style=flat-square)](package.json)
12
+ [![Version](https://img.shields.io/badge/version-2.0.0-3b82f6.svg?style=flat-square)](package.json)
13
13
  [![License: MIT](https://img.shields.io/badge/License-MIT-10b981.svg?style=flat-square)](LICENSE)
14
- [![DSH Compatibility](https://img.shields.io/badge/DSH-%E2%89%A50.1.1--rc.2%20%C2%B7%20%E5%B7%B2%E9%80%82%E9%85%8D%200.1.7--rc.2-6366f1.svg?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)
14
+ [![DSH Compatibility](https://img.shields.io/badge/DSH-%E2%89%A50.1.1--rc.2%20%C2%B7%20%E5%B7%B2%E9%80%82%E9%85%8D%200.2.0--rc.1-6366f1.svg?style=flat-square)](https://github.com/deepseek-ai/deepseek-harness)
15
15
  [![Cordis](https://img.shields.io/badge/Cordis-v4.x-f59e0b.svg?style=flat-square)](https://cordis.moe/)
16
16
  [![Platform](https://img.shields.io/badge/platform-DSH%20Web-ec4899.svg?style=flat-square)](https://github.com/gehennawu/dsh-service)
17
17
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/gehennawu/dsh-service/issues)
@@ -74,7 +74,7 @@ DSH Web 服务控制与运维插件:安全重启、版本管理与一键升级
74
74
 
75
75
  - 显示当前 DSH 与插件版本,链接 GitHub Releases
76
76
  - 自动检查 npm **正式版 + 预览版**(latest / next 双 tag)
77
- - 「本次更新内容」入口跟在当前版本号之后且常驻:点开读**当前这一版**的更新说明;有新版本时状态文本「有新版本:x.y.z」整体可点,展开**新版**的 release 信息。正文一律由宿主从 GitHub Releases API 取回后就地渲染(纯 Markdown,不嵌 iframe、不跳转),带版本号、发布日期与预发布标记;未建 Release 或读取失败各有明确提示;点版本卡以外的任意位置或按 Esc 即关闭。两行的版本号与「本次更新内容」入口按钮按同一套列对齐,版本号右对齐使它与入口按钮的间距固定,**与版本号长度无关**——长短版本号只把整列一起推宽,不会让某一行错位
77
+ - 「本次更新内容」入口跟在当前版本号之后且常驻:点开读**当前这一版**的更新说明;有新版本时状态文本「有新版本:x.y.z」整体可点,展开**新版**的 release 信息。正文一律由宿主从 GitHub Releases API 取回后就地渲染(纯 Markdown,不嵌 iframe、不跳转),带版本号、发布日期与预发布标记;未建 Release 或读取失败各有明确提示;点版本卡以外的任意位置或按 Esc 即关闭。两行的版本号与「本次更新内容」入口按钮按同一套列对齐,版本号右对齐使它与入口按钮的间距固定,**与版本号长度无关**——长短版本号只把整列一起推宽,不会让某一行错位;窄容器(手机与窄设置面板)沿用同一对齐——版本号吃掉行内余量并右对齐,两行的版本号与入口按钮仍各自同列
78
78
  - 一键升级,完成后自动重启;未检测到进程管理器时先确认后果,保持运行并提示手动重启
79
79
  - 升级落地但进程尚未重启期间(手动启动环境尤为常见),版本行改示「已安装 X,重启后生效」并收起升级按钮,重开面板或刷新页面状态依旧;重启进程后恢复常态
80
80
 
@@ -213,7 +213,7 @@ DSH Web 服务控制与运维插件:安全重启、版本管理与一键升级
213
213
  - 侧栏变抽屉、详情列移动端隐藏(对齐官方窄屏语义)、模态变全屏面板、设置左列导航变顶部横滑
214
214
  - 模型选择按钮在手机上收成图标(≤480px,与官方窄容器同形态;481px 以上仍显示模型名与推理等级)——插件移动端把中列拉宽,官方 `@container (width<=360px)` 那条收起规则在 428~440px 机型上永远不会触发,故显式对齐官方窄容器形态
215
215
  - 统计条(输入框下方「轮/步/tok/s | tok/缓存命中」)在手机上**保持一行、居中且不歪**:收紧这一行自身的左右内边距(官方 32px→2px)与列间距换出可用宽度,两枚统计交给官方 `justify-content` 居中排开——≥~420px 视口零截断,更窄视口按比例各让一点(远少于官方的固定截断),不换行、不横向滚动;同时兼容老版本 DSH(0.1.5-rc.2 上这条行是整行宽,早期实现的子项 `flex-grow` 会把两枚统计整组推到左边,现已改为不生长)(桌面不受影响)
216
- - 会话顶栏手机端重排(≤560px):标题行只留**标题 + 模式芯片**(芯片右靠贴住「…」钮,标题基本完整可见),「N 个子代理」与「N 个后台任务运行中」两枚计数芯片泊到「对话/轨迹」标签行右缘成一对(标签间距 36→20,点芯片本体仍开各自菜单);官方 crumbs 放不下时的**拦腰硬裁**彻底消除,561px 以上与桌面保持官方原布局
216
+ - 会话顶栏手机端重排(≤560px):标题行只留**标题 + 模式芯片**(芯片右靠贴住「…」钮,标题基本完整可见),「N 个子代理」与「N 个后台任务运行中」两枚计数芯片泊到「对话/轨迹」标签行右缘成一对(标签间距 36→20,点芯片本体仍开各自菜单);官方 crumbs 放不下时的**拦腰硬裁**彻底消除,561px 以上与桌面保持官方原布局。DSH 0.1.7-rc.1 起官方给模式芯片加了 `@container (width<=540px)` 隐藏(容器是标题行,约合 606px 视口),手机上曾整片消失——本插件在整个移动端带内覆盖回可见(390px 以上标题仍完整不裁,仅 320~375px 档标题略带省略号)
217
217
  - Agent Team 弹窗手机端不越屏(<1024px):官方 Agent Team 面板自带左锚(`left:0`),挂在头部右侧动作槽上会整体右移出屏(实测 320~1023px 越出 112~352px)。移动端把会话头部设为定位上下文、面板改**右锚 16px** 并按 `100vw − 32px` 封顶,两缘各留 16px;桌面 ≥1024px 官方几何逐字不变
218
218
  - 滑动沉浸:会话内下滑自动收起头部与输入框全屏阅读(收起时让出输入框占位,正文真正铺满整屏;回显时若仍停在会话末尾会自动对齐到底),上滑 / 点「回到底部」浮钮 / 聚焦输入框即恢复(无额外悬浮钮);已经停在会话末尾时往回一点即回显(不再等满阈值),点回底后停留位置会补一次贴底对齐;流式贴底、锚点跳转等程序化滚动绝不误触发
219
219
  - 滑动开合抽屉:双抽屉关闭时,横移主导的右滑任意位置打开侧栏抽屉、左滑任意位置打开官方右侧栏(DSH 0.1.5+,未就绪时该方向无效);开启后反向横滑任意位置关闭;从屏幕边缘起滑额外享有浏览器手势接管的补完加成,编辑器等真横滚区内的滑动不误触发
@@ -302,6 +302,20 @@ flowchart TB
302
302
 
303
303
  ## ⚡ 安装
304
304
 
305
+ ### 方式一:DSH 插件管理页(图形界面,推荐)
306
+
307
+ 1. 打开左侧边栏的「**插件**」页。
308
+ 2. 点右上角的「**+ 添加插件**」按钮。
309
+ 3. 在弹出的对话框里,把 `@gehennawu/dsh-service` 填进「**包名**」输入框;「**安装源**」保持默认的「npm 官方源」。
310
+ 4. 点「**安装**」,等待官方把包装进当前 profile(对话框底部会给出进度与结果)。
311
+ 5. 装好后本插件出现在「**已安装**」分组里。宿主半要等 DSH 进程重启才生效,客户端半刷新页面即生效。
312
+ - 在 Web 上:用本插件的「**服务控制 → 重启**」,或在对话里发 `/restart`;
313
+ - 在 DSH Desktop 上:请退出应用后重新打开(桌面端由应用自身托管进程,本插件不会自行退出)。
314
+
315
+ > 提示:插件管理页的「安装」按钮走官方 npm 源与官方安装链路,无需命令行、无需手动改 profile 文件。
316
+
317
+ ### 方式二:命令行
318
+
305
319
  | 方式 | 命令 |
306
320
  | --- | --- |
307
321
  | npm(推荐) | `dsh plugin --profile web add @gehennawu/dsh-service` |
@@ -320,7 +334,7 @@ dsh web
320
334
 
321
335
  插件只发送退出信号,不负责拉起进程;没有进程管理器时重启会直接停止 DSH Web。
322
336
 
323
- 插件以被动信号(环境变量、`/.dockerenv`、`/proc/1/cgroup`、终端 TTY)判断进程管理器:检测到 Docker/systemd/pm2/supervisord/Kubernetes 时照常自动重启;都没有且 stdin/stdout 为交互终端时视为「疑似手动启动」——健康诊断黄色标注、一键升级改为保持运行并提示手动重启。启发式无法覆盖输出重定向、NSSM/WinSW 等场景,可用 `DSH_SERVICE_RUNTIME_ENV=managed|manual` 显式声明。
337
+ 插件以被动信号(环境变量、`/.dockerenv`、`/proc/1/cgroup`、终端 TTY)判断进程管理器:检测到 Docker/systemd/pm2/supervisord/Kubernetes 时照常自动重启;都没有且 stdin/stdout 为交互终端时视为「疑似手动启动」——健康诊断黄色标注、一键升级改为保持运行并提示手动重启。启发式无法覆盖输出重定向、NSSM/WinSW 等场景,可用 `DSH_SERVICE_RUNTIME_ENV=managed|manual|desktop` 显式声明。
324
338
 
325
339
  ### Docker Compose
326
340
 
@@ -352,11 +366,15 @@ pm2 start "dsh web --host 127.0.0.1" --name dsh-web
352
366
  | Linux + Docker Compose | 支持 | 配置 restart policy 后支持 | 已验证 |
353
367
  | Linux + systemd / pm2 | 预期支持 | 由进程管理器负责 | 未单独验证 |
354
368
  | macOS / Windows + pm2 等 | 代码未限制 | 由进程管理器负责 | 未验证 |
369
+ | DSH Desktop(Windows,Electron) | 支持 | 由桌面应用负责 | 已验证(2026-09-28 真机) |
370
+ | DSH Desktop(macOS / Linux,Electron) | 代码未限制 | 由桌面应用负责 | 未验证 |
355
371
  | 直接运行 `dsh web` | 支持 | 不支持 | 预期行为 |
356
372
 
357
373
  运行要求:Node.js `>=22`,DSH Web 能加载 Host 与 Client 两半插件。更新检查需访问 `registry.npmjs.org`;网络失败不影响其他功能。
358
374
 
359
- **DSH 适配口径**:已适配 DSH `0.1.7-rc.2`——会话格式 V4(V3 日志首读时由官方迁移为 `session.v4.jsonl.zstd` 代际文件,旧 `session.v3.jsonl.zstd` 按格式目录策略保留;详情视图自动归档系统事件)、`SettingsForms` 配置面(插件配置改由 Profile 的 `cordis.patch.yml` 承载,热更新走 `loader/volatile-update`;旧的 `settings.register` 在 0.1.5/0.1.6 上仍是权威来源,装在同一宿主上两者互不串台)、会话格式 V3 既有适配全部保留(`system/message` 入史、sessionPersistence handle 化、官方右栏、turn-process 对象化)、移动端底行触发钮双哈希兼容、子代理回合尾模型行 list 槽位自适应兼容、`plugins.bundle.config` 槽位注入、会话详情打开接入 `uiWorkspace` 降级链路。旧版 DSH(`>=0.1.1-rc.2`)保持兼容。支持区间扩展到 `0.1.7-rc.2`;rc.2 源码级与产物级审查(346 commits)未发现新增破坏面,CSS 哈希词干经产物 grep 定案零漂移;rc.1 起新增的插件版本兼容门禁只读取 `peerDependencies`(本插件无该声明,不受门禁约束),并已在 DSH `0.1.7-rc.2` 真机挂载运行。设置面、persistence/布局 seam 均按运行时能力探测走双形态,旧宿主上针对新结构的适配项天然不生效(纯展示,无功能损失)。注意:升级后写入的会话日志无法被旧版 DSH 读取,**备份不可跨版本降级恢复**。插件市场按 `package.json` 的 `engines.dsh` 区间判定兼容性(该字段是唯一的支持口径声明)。
375
+ **DSH 适配口径**:已适配 DSH `0.2.0-rc.1`——会话格式 V4(V3 日志首读时由官方迁移为 `session.v4.jsonl.zstd` 代际文件,旧 `session.v3.jsonl.zstd` 按格式目录策略保留;详情视图自动归档系统事件)、`SettingsForms` 配置面(插件配置改由 Profile 的 `cordis.patch.yml` 承载,热更新走 `loader/volatile-update`;旧的 `settings.register` 在 0.1.5/0.1.6 上仍是权威来源,装在同一宿主上两者互不串台)、会话格式 V3 既有适配全部保留(`system/message` 入史、sessionPersistence handle 化、官方右栏、turn-process 对象化)、移动端底行触发钮双哈希兼容、子代理回合尾模型行 list 槽位自适应兼容、`plugins.bundle.config` 槽位注入、会话详情打开接入 `uiWorkspace` 降级链路。旧版 DSH(`>=0.1.1-rc.2`)保持兼容。支持区间扩展到 `0.2.0-rc.1`;0.2.0-rc.1 源码级与产物级审查(261 commits)未发现新增破坏面——20 条既有接缝 17 条字节级相同、关键官方包产物逐字节相同、CSS 类锚点与主题令牌经产物 grep 定案零漂移;rc.1 起新增的插件版本兼容门禁只读取 `peerDependencies`(本插件无该声明,不受门禁约束),并已在 DSH `0.2.0-rc.1` 真机挂载运行。设置面、persistence/布局 seam 均按运行时能力探测走双形态,旧宿主上针对新结构的适配项天然不生效(纯展示,无功能损失)。注意:升级后写入的会话日志无法被旧版 DSH 读取,**备份不可跨版本降级恢复**。插件市场按 `package.json` 的 `engines.dsh` 区间判定兼容性(该字段是唯一的支持口径声明)。
376
+
377
+ **DSH 桌面端(DSH Desktop / Electron)口径**:桌面端复用同一份 Web 前端与同一张客户端插件图(`platform: web`),插件照常加载,绝大多数功能原样可用;语义不同的只有「重启」与「一键升级」。宿主由桌面应用托管,**重启一律不再 `process.exit(42)`**(桌面壳把任何非 0 退出判为 Host 崩溃,会弹原生「启动失败」对话框且不会自动重拉,官方也没有可编程重启 RPC)——「重启」按钮、对话里的 `/restart` 与备份恢复后的重启统一改为提示「请在桌面端退出应用后重新打开」;**一键升级在桌面端置灰**并指向应用自带的插件管理页(桌面端 CLI 不能启动/改写 `profiles/desktop`,升级端点直接短路返回 `desktop-managed-upgrade`,不产生任何 subprocess);健康诊断的「运行环境」行显示「由桌面端托管(Electron)」。判据是宿主进程内的 `process.versions.electron`(Windows 桌面版真机实测 `44.0.0`,同进程 `ELECTRON_RUN_AS_NODE=1`、stdin/stdout 均非 TTY);非 Electron 的桌面封装可用 `DSH_SERVICE_RUNTIME_ENV=desktop` 显式声明。任务通知在桌面端**可用**(权限 granted,真机已收到系统通知);唯一的边界是**点击通知唤不回窗口**(桌面端关窗=隐藏窗口,`dshDesktop` 无窗口 API,请用托盘唤回)。macOS / Linux 桌面端未验证。
360
378
 
361
379
  ## 🔒 安全设计
362
380
 
@@ -383,6 +401,12 @@ pm2 start "dsh web --host 127.0.0.1" --name dsh-web
383
401
  这是「疑似终端手动启动」的检测结果,说明当前没有检测到进程管理器。若实际由 NSSM/WinSW 或输出重定向等场景托管,可用 `DSH_SERVICE_RUNTIME_ENV=managed` 显式声明消除。
384
402
  </details>
385
403
 
404
+ <details>
405
+ <summary><strong>桌面端(DSH Desktop)收不到任务通知?</strong></summary>
406
+
407
+ 先确认两件事:① 「配置 → 通知」里的**通知总开关**必须真正打开——它默认关闭,只有点过「开启通知」且系统授予权限后才会置为开启(若只看到「开启通知」按钮,说明权限还没授予);② 会话必须真的从「运行中」变为结束,且不是子代理会话。系统通知在桌面端本身是可用的:Windows「设置 → 系统 → 通知」里会为应用建立一条 `electron.app.DeepSeek Harness` 记录(真机实测会弹出「任务完成」通知)。唯一已知边界是**点击通知不会把窗口唤回**——桌面端关窗=隐藏窗口,当前桌面桥面没有窗口显示 API,请用系统托盘唤回窗口。
408
+ </details>
409
+
386
410
  <details>
387
411
  <summary><strong>额度卡片显示「凭据未配置」?</strong></summary>
388
412
 
@@ -705,7 +705,9 @@ export function createBackupIntegrity(options) {
705
705
  throw domainError('restore-failed')
706
706
  }
707
707
 
708
- const manual = runtimeEnv?.manualStartLikely === true
708
+ // 桌面端(electronShell)与终端手动启动同理:没有东西会把 Host 拉起来,恢复完成后不调度
709
+ // exit(42)(桌面端退出会被壳判为崩溃并弹原生恢复对话框),改由客户端示「重启应用」指引。
710
+ const manual = runtimeEnv?.manualStartLikely === true || runtimeEnv?.electronShell === true
709
711
  if (!manual) scheduleRestart()
710
712
  return {
711
713
  restoredFrom: plan.source.name,