@gehennawu/dsh-service 1.9.9 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.1-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.2-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
 
@@ -196,9 +196,10 @@ Under **Plugins → Plugin configuration**, twelve host-level switches: **Health
196
196
 
197
197
  - Off by default; active only below a 1024 px viewport (phones / narrow windows), desktops unaffected
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
+ - The official Plugins panel header never wraps its text on phones: when "title + intro" and "refresh / Add plugin" no longer fit one row, the whole toolbar drops to a second row flush right, keeping the intro and the button label each on a single line; this also fixes the old drawer-button clearance rule that rewrote this page header's vertical/right padding (it used to squeeze the intro into two lines with an orphan character and wrap the "Add plugin" label inside its pill)
199
200
  - 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
201
  - 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
202
+ - 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
203
  - 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
204
  - 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
205
  - 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,12 +301,32 @@ Key contracts:
300
301
 
301
302
  ## ⚡ Installation
302
303
 
304
+ ### Option 1: DSH plugin manager (graphical, recommended)
305
+
306
+ 1. Open the **Plugins** page in the left sidebar.
307
+ 2. Click the **+ Add plugin** button in the top-right corner.
308
+ 3. In the dialog, fill in **one of the three** source forms (the same field accepts all three, and the hint below it follows what you type):
309
+ - **npm package name (recommended)**: `@gehennawu/dsh-service`;
310
+ - **GitHub repository URL**: `https://github.com/gehennawu/dsh-service` (public repository, no token needed; the shorthand `github:gehennawu/dsh-service` works too);
311
+ - **Local plugin directory**: an absolute path on this machine, e.g. `/path/to/dsh-service` (for your own or pre-downloaded plugins).
312
+ 4. Pick the **install source** for your network: the default **official npm registry**, or the **China mainland mirror** if fetching from npm is restricted there (it affects package-name installs only; GitHub URLs and local directories are unaffected).
313
+ 5. Click **Install** and wait for the official layer to add the package to the current profile (the dialog reports progress and the result).
314
+ 6. The plugin then appears under **Installed**. The host half takes effect after the DSH process restarts; the client half applies on a page refresh.
315
+ - On Web: use this plugin's **Service Control → Restart**, or send `/restart` in a conversation;
316
+ - 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).
317
+
318
+ > Tip: all three forms go through the official installation path — no manual profile edits; entering a GitHub URL in the dialog is equivalent to the `github:` prefix on the command line.
319
+
320
+ ### Option 2: Command line
321
+
303
322
  | Method | Command |
304
323
  | --- | --- |
305
324
  | npm (recommended) | `dsh plugin --profile web add @gehennawu/dsh-service` |
306
325
  | GitHub | `dsh plugin --profile web add github:gehennawu/dsh-service` |
307
326
  | Local development | `dsh plugin --profile web add link:/path/to/dsh-service` |
308
327
 
328
+ The command line uses the default npm / pnpm registry; if you need a mirror, point npm / pnpm's registry at one the usual way first, then run the command above.
329
+
309
330
  Restart DSH Web after installing or updating:
310
331
 
311
332
  ```sh
@@ -318,7 +339,7 @@ Open DSH Web Settings and select **Service Control**.
318
339
 
319
340
  The plugin only sends an exit signal; it does not start the process again. Without a process manager, restart stops DSH Web.
320
341
 
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.
342
+ 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
343
 
323
344
  ### Docker Compose
324
345
 
@@ -350,11 +371,15 @@ pm2 start "dsh web --host 127.0.0.1" --name dsh-web
350
371
  | Linux + Docker Compose | Supported | Supported with a restart policy | Verified |
351
372
  | Linux + systemd / pm2 | Expected to work | Managed externally | Not separately tested |
352
373
  | macOS / Windows + pm2 or similar | Not blocked by the code | Managed externally | Not tested |
374
+ | DSH Desktop (Windows, Electron) | Supported | Owned by the desktop app | Verified (real host, 2026-09-28) |
375
+ | DSH Desktop (macOS / Linux, Electron) | Not blocked by the code | Owned by the desktop app | Not verified |
353
376
  | Direct `dsh web` execution | Supported | Not supported | Expected behavior |
354
377
 
355
378
  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
379
 
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.
380
+ **DSH compatibility statement**: adapted to DSH `0.2.0-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.2.0-rc.2`; source-level and artifact-level reviews of 0.2.0-rc.2 (187 commits) confirmed that the upstream Client Inspect hang defect is officially fixed, and the official model selection popup group heading migration to MenuGroup (`data-menu-group-heading`) has been backward-compatibly adapted with a dual selector; all other 20 existing seams (18 byte-identical), key package artifacts, CSS class anchors, and theme tokens show zero removals 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.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.
381
+
382
+ **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
383
 
359
384
  ## 🔒 Security design
360
385
 
@@ -381,6 +406,12 @@ The plugin only sends an exit signal; a process manager brings it back (see "Aut
381
406
  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
407
  </details>
383
408
 
409
+ <details>
410
+ <summary><strong>Why do task notifications not appear on DSH Desktop?</strong></summary>
411
+
412
+ 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.
413
+ </details>
414
+
384
415
  <details>
385
416
  <summary><strong>A quota card shows "credential missing"?</strong></summary>
386
417
 
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.1-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.2-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
 
@@ -211,9 +211,10 @@ DSH Web 服务控制与运维插件:安全重启、版本管理与一键升级
211
211
 
212
212
  - 默认关闭;仅在视口 <1024px(手机竖屏 / 窄窗口)生效,桌面完全无感
213
213
  - 侧栏变抽屉、详情列移动端隐藏(对齐官方窄屏语义)、模态变全屏面板、设置左列导航变顶部横滑
214
+ - 官方插件面板页(「插件」)顶部手机端不折行:标题+简介与「刷新/添加插件」放不下时工具栏整体落到第二行右缘,简介与按钮文案各自单行;同时修掉抽屉钮让位内边距连带改写该页头部纵向/右侧内边距的旧写法(曾把「安装、启用和配置插件」挤成两行、「添加插件」按钮内文案折两行溢出胶囊)
214
215
  - 模型选择按钮在手机上收成图标(≤480px,与官方窄容器同形态;481px 以上仍显示模型名与推理等级)——插件移动端把中列拉宽,官方 `@container (width<=360px)` 那条收起规则在 428~440px 机型上永远不会触发,故显式对齐官方窄容器形态
215
216
  - 统计条(输入框下方「轮/步/tok/s | tok/缓存命中」)在手机上**保持一行、居中且不歪**:收紧这一行自身的左右内边距(官方 32px→2px)与列间距换出可用宽度,两枚统计交给官方 `justify-content` 居中排开——≥~420px 视口零截断,更窄视口按比例各让一点(远少于官方的固定截断),不换行、不横向滚动;同时兼容老版本 DSH(0.1.5-rc.2 上这条行是整行宽,早期实现的子项 `flex-grow` 会把两枚统计整组推到左边,现已改为不生长)(桌面不受影响)
216
- - 会话顶栏手机端重排(≤560px):标题行只留**标题 + 模式芯片**(芯片右靠贴住「…」钮,标题基本完整可见),「N 个子代理」与「N 个后台任务运行中」两枚计数芯片泊到「对话/轨迹」标签行右缘成一对(标签间距 36→20,点芯片本体仍开各自菜单);官方 crumbs 放不下时的**拦腰硬裁**彻底消除,561px 以上与桌面保持官方原布局
217
+ - 会话顶栏手机端重排(≤560px):标题行只留**标题 + 模式芯片**(芯片右靠贴住「…」钮,标题基本完整可见),「N 个子代理」与「N 个后台任务运行中」两枚计数芯片泊到「对话/轨迹」标签行右缘成一对(标签间距 36→20,点芯片本体仍开各自菜单);官方 crumbs 放不下时的**拦腰硬裁**彻底消除,561px 以上与桌面保持官方原布局。DSH 0.1.7-rc.1 起官方给模式芯片加了 `@container (width<=540px)` 隐藏(容器是标题行,约合 606px 视口),手机上曾整片消失——本插件在整个移动端带内覆盖回可见(390px 以上标题仍完整不裁,仅 320~375px 档标题略带省略号)
217
218
  - Agent Team 弹窗手机端不越屏(<1024px):官方 Agent Team 面板自带左锚(`left:0`),挂在头部右侧动作槽上会整体右移出屏(实测 320~1023px 越出 112~352px)。移动端把会话头部设为定位上下文、面板改**右锚 16px** 并按 `100vw − 32px` 封顶,两缘各留 16px;桌面 ≥1024px 官方几何逐字不变
218
219
  - 滑动沉浸:会话内下滑自动收起头部与输入框全屏阅读(收起时让出输入框占位,正文真正铺满整屏;回显时若仍停在会话末尾会自动对齐到底),上滑 / 点「回到底部」浮钮 / 聚焦输入框即恢复(无额外悬浮钮);已经停在会话末尾时往回一点即回显(不再等满阈值),点回底后停留位置会补一次贴底对齐;流式贴底、锚点跳转等程序化滚动绝不误触发
219
220
  - 滑动开合抽屉:双抽屉关闭时,横移主导的右滑任意位置打开侧栏抽屉、左滑任意位置打开官方右侧栏(DSH 0.1.5+,未就绪时该方向无效);开启后反向横滑任意位置关闭;从屏幕边缘起滑额外享有浏览器手势接管的补完加成,编辑器等真横滚区内的滑动不误触发
@@ -302,12 +303,32 @@ flowchart TB
302
303
 
303
304
  ## ⚡ 安装
304
305
 
306
+ ### 方式一:DSH 插件管理页(图形界面,推荐)
307
+
308
+ 1. 打开左侧边栏的「**插件**」页。
309
+ 2. 点右上角的「**+ 添加插件**」按钮。
310
+ 3. 在弹窗里按来源**三选一**填写(同一个输入框接受三种形式,底部提示会随填写内容变化):
311
+ - **npm 包名(推荐)**:`@gehennawu/dsh-service`;
312
+ - **GitHub 仓库地址**:`https://github.com/gehennawu/dsh-service`(公开仓库,无需令牌;`github:gehennawu/dsh-service` 简写同样可用);
313
+ - **本地插件目录**:本机上的绝对路径,例如 `/path/to/dsh-service`(自研或已下载的插件)。
314
+ 4. 「**安装源**」按网络情况选择:默认「**npm 官方源**」;国内网络拉取受限时可选「**中国大陆镜像源**」(影响走包名安装时的拉取源,GitHub 地址与本地目录不受其影响)。
315
+ 5. 点「**安装**」,等待官方把包装进当前 profile(弹窗底部会给出进度与结果)。
316
+ 6. 装好后本插件出现在「**已安装**」分组里。宿主半要等 DSH 进程重启才生效,客户端半刷新页面即生效。
317
+ - 在 Web 上:用本插件的「**服务控制 → 重启**」,或在对话里发 `/restart`;
318
+ - 在 DSH Desktop 上:请退出应用后重新打开(桌面端由应用自身托管进程,本插件不会自行退出)。
319
+
320
+ > 提示:三种形式都走官方安装链路,无需手动改 profile 文件;图形界面填 GitHub 地址与命令行 `github:` 前缀等价。
321
+
322
+ ### 方式二:命令行
323
+
305
324
  | 方式 | 命令 |
306
325
  | --- | --- |
307
326
  | npm(推荐) | `dsh plugin --profile web add @gehennawu/dsh-service` |
308
327
  | GitHub | `dsh plugin --profile web add github:gehennawu/dsh-service` |
309
328
  | 本地开发 | `dsh plugin --profile web add link:/path/to/dsh-service` |
310
329
 
330
+ 命令行走 npm / pnpm 的默认源;需要镜像时,请先按 npm / pnpm 的常规做法把 registry 指到镜像站,再执行上面的命令。
331
+
311
332
  安装或更新后重启 DSH Web:
312
333
 
313
334
  ```sh
@@ -320,7 +341,7 @@ dsh web
320
341
 
321
342
  插件只发送退出信号,不负责拉起进程;没有进程管理器时重启会直接停止 DSH Web。
322
343
 
323
- 插件以被动信号(环境变量、`/.dockerenv`、`/proc/1/cgroup`、终端 TTY)判断进程管理器:检测到 Docker/systemd/pm2/supervisord/Kubernetes 时照常自动重启;都没有且 stdin/stdout 为交互终端时视为「疑似手动启动」——健康诊断黄色标注、一键升级改为保持运行并提示手动重启。启发式无法覆盖输出重定向、NSSM/WinSW 等场景,可用 `DSH_SERVICE_RUNTIME_ENV=managed|manual` 显式声明。
344
+ 插件以被动信号(环境变量、`/.dockerenv`、`/proc/1/cgroup`、终端 TTY)判断进程管理器:检测到 Docker/systemd/pm2/supervisord/Kubernetes 时照常自动重启;都没有且 stdin/stdout 为交互终端时视为「疑似手动启动」——健康诊断黄色标注、一键升级改为保持运行并提示手动重启。启发式无法覆盖输出重定向、NSSM/WinSW 等场景,可用 `DSH_SERVICE_RUNTIME_ENV=managed|manual|desktop` 显式声明。
324
345
 
325
346
  ### Docker Compose
326
347
 
@@ -352,11 +373,15 @@ pm2 start "dsh web --host 127.0.0.1" --name dsh-web
352
373
  | Linux + Docker Compose | 支持 | 配置 restart policy 后支持 | 已验证 |
353
374
  | Linux + systemd / pm2 | 预期支持 | 由进程管理器负责 | 未单独验证 |
354
375
  | macOS / Windows + pm2 等 | 代码未限制 | 由进程管理器负责 | 未验证 |
376
+ | DSH Desktop(Windows,Electron) | 支持 | 由桌面应用负责 | 已验证(2026-09-28 真机) |
377
+ | DSH Desktop(macOS / Linux,Electron) | 代码未限制 | 由桌面应用负责 | 未验证 |
355
378
  | 直接运行 `dsh web` | 支持 | 不支持 | 预期行为 |
356
379
 
357
380
  运行要求:Node.js `>=22`,DSH Web 能加载 Host 与 Client 两半插件。更新检查需访问 `registry.npmjs.org`;网络失败不影响其他功能。
358
381
 
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` 区间判定兼容性(该字段是唯一的支持口径声明)。
382
+ **DSH 适配口径**:已适配 DSH `0.2.0-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.2.0-rc.2`;0.2.0-rc.2 源码级与产物级审查(187 commits)确认 Client Inspect 挂起缺陷已正式修复,官方模型选择弹窗分组标题重构为 MenuGroup(`data-menu-group-heading`)已通过双选选择器完成向下兼容适配;其余 20 条既有接缝 18 条字节级相同、关键官方包产物逐字节相同、CSS 类锚点与主题令牌经产物 grep 定案零删除;rc.1 起新增的插件版本兼容门禁只读取 `peerDependencies`(本插件无该声明,不受门禁约束),并已在 DSH `0.2.0-rc.2` 真机挂载运行。设置面、persistence/布局 seam 均按运行时能力探测走双形态,旧宿主上针对新结构的适配项天然不生效(纯展示,无功能损失)。注意:升级后写入的会话日志无法被旧版 DSH 读取,**备份不可跨版本降级恢复**。插件市场按 `package.json` 的 `engines.dsh` 区间判定兼容性(该字段是唯一的支持口径声明)。
383
+
384
+ **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
385
 
361
386
  ## 🔒 安全设计
362
387
 
@@ -383,6 +408,12 @@ pm2 start "dsh web --host 127.0.0.1" --name dsh-web
383
408
  这是「疑似终端手动启动」的检测结果,说明当前没有检测到进程管理器。若实际由 NSSM/WinSW 或输出重定向等场景托管,可用 `DSH_SERVICE_RUNTIME_ENV=managed` 显式声明消除。
384
409
  </details>
385
410
 
411
+ <details>
412
+ <summary><strong>桌面端(DSH Desktop)收不到任务通知?</strong></summary>
413
+
414
+ 先确认两件事:① 「配置 → 通知」里的**通知总开关**必须真正打开——它默认关闭,只有点过「开启通知」且系统授予权限后才会置为开启(若只看到「开启通知」按钮,说明权限还没授予);② 会话必须真的从「运行中」变为结束,且不是子代理会话。系统通知在桌面端本身是可用的:Windows「设置 → 系统 → 通知」里会为应用建立一条 `electron.app.DeepSeek Harness` 记录(真机实测会弹出「任务完成」通知)。唯一已知边界是**点击通知不会把窗口唤回**——桌面端关窗=隐藏窗口,当前桌面桥面没有窗口显示 API,请用系统托盘唤回窗口。
415
+ </details>
416
+
386
417
  <details>
387
418
  <summary><strong>额度卡片显示「凭据未配置」?</strong></summary>
388
419
 
@@ -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,