dsh-any-agent 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,62 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.3] — 2026-11-08
11
+
12
+ ### Added
13
+
14
+ - **English interface for `watch` and `dashboard`.** Both follow the system
15
+ language (`DSH_MCP_LANG`, then `LC_ALL` / `LC_MESSAGES` / `LANG`, then the OS
16
+ locale) and take `--lang zh|en`; the dashboard also has a switch in its corner
17
+ and remembers the choice.
18
+ - **`dashboard --open`** launches the page in the default browser.
19
+ - **MCP Registry listing.** `server.json` and `mcpName` in `package.json`; the
20
+ release workflow publishes to the official MCP Registry after npm, logging in
21
+ with GitHub OIDC and running a pinned, cosign-verified `mcp-publisher`.
22
+ `check:release` keeps `server.json` in step with `package.json`.
23
+ - **Community files**: `CONTRIBUTING.md`, issue forms (bug report asks for
24
+ `dsh_doctor` output), a pull request checklist, and Dependabot for GitHub
25
+ Actions and `video/`.
26
+ - README: CI badge and dashboard screenshots; the website gets the promo video.
27
+ - `docs/en/live-view-design.md` (the design was Chinese-only).
28
+ - **`dsh_doctor` checks the live event stream.** A new `live` check reports the
29
+ level, whether the live directory is writable, how many conversations it holds,
30
+ its size and when the last event was written — so "why is `watch` empty?" has
31
+ an answer. Problems are warnings, not failures: the live view never affects a run.
32
+ - **Release automation.** `release.yml` now builds the GitHub Release notes from
33
+ the version's CHANGELOG section (`scripts/release-notes.mjs`, with the install
34
+ command and a compare link) instead of GitHub's one-line generated notes, and
35
+ updates the notes of an existing Release on re-run. A second job publishes to
36
+ npm from CI with **provenance via npm Trusted Publishing** (no `NPM_TOKEN`),
37
+ after checking the tag matches `package.json` and running the release gate; it
38
+ skips versions already on npm. Needs a one-time Trusted Publisher setup on
39
+ npmjs.com — see `docs/en/release.md`.
40
+ - **`SECURITY.md`**: how to report a vulnerability privately, supported versions,
41
+ and what is in and out of scope.
42
+
43
+ ### Changed
44
+
45
+ - Website: the observability card and a new FAQ entry cover `watch` / `dashboard`
46
+ and token usage; the GUI FAQ now points to them as the lock-free way to follow
47
+ progress.
48
+ - **Smaller npm package** (935 KB → about 370 KB packed): maintainer scripts,
49
+ images and the archived `DESIGN.md` are no longer shipped; `docs/zh` and
50
+ `docs/en` still are. `package-check` now fails if repo-only paths come back.
51
+ - `DESIGN.md` is marked as an archived early draft, with links to the current docs.
52
+ - Dashboard "Files" panel lists only files actually read or written, not the
53
+ directories searched by `grep` / `glob`.
54
+
55
+ ### Fixed
56
+
57
+ - Running some offline suites on their own (`node test/dispatch-tools.mjs`, …)
58
+ wrote live events into the real `~/.dsh/.dsh-any-agent/live`, where they showed
59
+ up in `watch` / `dashboard`. They now use a temporary live directory
60
+ (`test/live-sandbox.mjs`), as `npm test` already did.
61
+ - `check:release` treated a version's CHANGELOG section as non-empty whenever any
62
+ later version followed it; it now checks the section itself, that release notes
63
+ can be built from it, and the compare links at the bottom. The `[Unreleased]`
64
+ link and the missing `[0.6.1]` / `[0.6.2]` links were corrected.
65
+
10
66
  ## [0.6.2] — 2026-11-08
11
67
 
12
68
  ### Added
@@ -1189,7 +1245,10 @@ First public release, published to npm as [`dsh-any-agent`](https://www.npmjs.co
1189
1245
  profiles, sessions and client configs. The product name changed; the on-disk
1190
1246
  contract did not. See the README FAQ.
1191
1247
 
1192
- [Unreleased]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.6.0...HEAD
1248
+ [Unreleased]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.6.3...HEAD
1249
+ [0.6.3]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.6.2...v0.6.3
1250
+ [0.6.2]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.6.1...v0.6.2
1251
+ [0.6.1]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.6.0...v0.6.1
1193
1252
  [0.6.0]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.5.2...v0.6.0
1194
1253
  [0.5.2]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.5.1...v0.5.2
1195
1254
  [0.5.1]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.5.0...v0.5.1
package/README.md CHANGED
@@ -10,12 +10,13 @@
10
10
  [![node](https://img.shields.io/node/v/dsh-any-agent.svg?style=flat-square)](https://nodejs.org)
11
11
  [![license](https://img.shields.io/npm/l/dsh-any-agent.svg?style=flat-square)](LICENSE)
12
12
  [![dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg?style=flat-square)](package.json)
13
+ [![tests](https://img.shields.io/github/actions/workflow/status/xmtlzzz/dsh-any-agent/tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/xmtlzzz/dsh-any-agent/actions/workflows/tests.yml)
13
14
 
14
- [Website](https://dsh-any-agent.xmtlz.dev/) · [Quick start](#quick-start) · [Features](#-why-its-different) · [Tools](#-tools) · [Usage notes](USAGE-NOTES.en.md) · [Changelog](CHANGELOG.md)
15
+ [Website](https://dsh-any-agent.xmtlz.dev/) · [Quick start](#quick-start) · [Features](#-why-its-different) · [Tools](#-tools) · [Live view](#-live-view-see-what-the-dispatched-work-is-doing) · [Usage notes](USAGE-NOTES.en.md) · [Changelog](CHANGELOG.md)
15
16
 
16
17
  </div>
17
18
 
18
- 🧪 0.5.2 offline suite green, including the workspace-change detection fix and visible auto-approvals · 🔌 MCP over stdio · 📦 Zero dependencies · 📜 MIT
19
+ 🧪 0.6.2 offline suite green · 👀 new live call-chain view (`watch` / `dashboard`, with token usage) · 🔌 MCP over stdio · 📦 Zero dependencies · 📜 MIT
19
20
 
20
21
  An MCP server that drives DeepSeek Harness as a **long-lived coding agent**. Hand it a goal, let it write code and run scripts, steer it mid-flight, and collect the result when you are ready.
21
22
 
@@ -28,7 +29,8 @@ You already have a coding agent in your editor. What you do **not** have is one
28
29
  - **hand a multi-hour job to another agent and walk away** — then collect the result when it's done;
29
30
  - **keep the job alive across restarts** of your editor, your session, your machine's idle reap;
30
31
  - **cut in mid-flight** when it's going the wrong way, without destroying the work;
31
- - **run several of them at once** and switch between them.
32
+ - **run several of them at once** and switch between them;
33
+ - **see what it is doing** without asking the agent — which tools it called, which approvals went through, how many tokens it spent.
32
34
 
33
35
  DSH (DeepSeek Harness) can do all of that — it has file/shell tools, skills, subagents and workflows — but it is a GUI-first application. Its own `sdk` profile exposes only 3 requests and can't resume, cancel, or answer approvals.
34
36
 
@@ -44,6 +46,7 @@ DSH (DeepSeek Harness) can do all of that — it has file/shell tools, skills, s
44
46
  | 🗣️ **You are never stuck waiting** | Steer a conversation mid-flight — **interject** to stop and redirect (~100 ms to reach idle, measured over four cancelled turns), or **queue** a remark for after the current turn. Interrupting never damages the conversation. |
45
47
  | 📡 **Completion notification, not polling** | Long tasks return instantly with a `run_id`; when the turn ends, a **sentinel file** is written atomically so a background task in *your* host wakes you. No polling, no occupied turn. |
46
48
  | 🪟 **Many conversations at once** | `dsh_list(only_running)` shows what's live; `dsh_read` gives cursor-based incremental output. Cycle between them like windows. |
49
+ | 👀 **You can see it yourself** | `dsh-any-agent watch` (terminal) or `dsh-any-agent dashboard` (local read-only web page) lays dispatched work out as a call chain — client → conversation → run → tool calls / approvals — with per-run tokens and context-window use, updating while the run is going. Separate processes, never touch the write lock, and show work from every client together. |
47
50
  | 🧠 **Reasoning hidden by default** | You get "thought for N chars / M seconds" statistics instead of context-burning prose — and it is never logged, never written to disk. |
48
51
  | 🤫 **Silent by default** | Not one byte on stderr, so nothing pollutes your host's logs. stdout carries the protocol and nothing else. |
49
52
  | 🧩 **Capabilities compose** | DSH can mount its own MCP servers (IDA Pro, browsers, your internal tooling), so this is a bridge to a whole toolbox. |
@@ -60,7 +63,7 @@ from DSH's tool surface is proxied, duplicated or preloaded.
60
63
  |---|---|
61
64
  | File I/O, shell, search, editing | Session identity and cross-crash resume |
62
65
  | Skills, subagents, Agent Teams, task board | Async dispatch, receipts, completion sentinels |
63
- | Model routing, sandbox, approval policy | Incremental read, interject, interrupt |
66
+ | Model routing, sandbox, approval policy | Incremental read, interject, interrupt, live call-chain view |
64
67
  | Memory/context/compaction | Approval bridge, write-lock governance, queue, inbox |
65
68
  | worktrees (the agent creates them with git) | Setup, status, doctor, audit |
66
69
 
@@ -98,6 +101,10 @@ dsh-any-agent-setup --yes
98
101
 
99
102
  The second command previews the changes; `--yes` applies them. Reconnect your client's MCP server, then ask your agent to start a DSH conversation in your project, dispatch a task, and collect the result. The [dispatch workflow](#-workflow-dispatch-then-collect-later) shows the tool sequence.
100
103
 
104
+ > **Want to see it first?** Watch the [54-second promo](https://dsh-any-agent.xmtlz.dev/en/#video) — dispatch, interject, the sentinel landing and the caller's review, with the terminal replayed from a real run:
105
+ >
106
+ > <a href="https://dsh-any-agent.xmtlz.dev/en/#video"><img src="https://raw.githubusercontent.com/xmtlzzz/dsh-any-agent/main/website/src/media/promo-poster.jpg" width="560" alt="▶ Play the dsh-any-agent promo (54 seconds)"></a>
107
+
101
108
  > **Before your first task:** read the [Usage Notes](USAGE-NOTES.en.md), especially the model-config and external-MCP permission boundaries. External MCP tools bypass DSH's sandbox. For a fresh machine, follow the [migration guide](USAGE-MIGRATION.en.md).
102
109
 
103
110
  <details>
@@ -105,7 +112,7 @@ The second command previews the changes; `--yes` applies them. Reconnect your cl
105
112
 
106
113
  - **Quick start** — [Install and connect](#quick-start) · [Changelog](CHANGELOG.md)
107
114
  - **Start here** — [The problem](#-the-problem-this-solves) · [Why it's different](#-why-its-different) · [Why not just wrap the DSH CLI](#-why-not-just-wrap-the-dsh-cli) · [Requirements](#-requirements) · [Setup](#-setup)
108
- - **Using it** — [Tools](#-tools) · [Dispatch then collect](#-workflow-dispatch-then-collect-later) · [Completion notifications](#-workflow-get-notified-on-completion-no-polling) · [Many conversations](#-workflow-many-conversations-at-once)
115
+ - **Using it** — [Tools](#-tools) · [Live view](#-live-view-see-what-the-dispatched-work-is-doing) · [Dispatch then collect](#-workflow-dispatch-then-collect-later) · [Completion notifications](#-workflow-get-notified-on-completion-no-polling) · [Many conversations](#-workflow-many-conversations-at-once)
109
116
  - **Behavior** — [Permissions](#-permissions) · [Reasoning](#-reasoning-hidden-by-default) · [Logging and privacy](#-logging-and-privacy) · [Workspace & GUI](#-workspace-visibility-in-the-dsh-gui)
110
117
  - **Hard parts** — [The write lock](#-the-write-lock-one-writer-per-conversation-at-a-time)
111
118
  - **Reference** — [Environment](#-environment-variables) · [Tests](#-tests) · [Known limitations](#-known-limitations) · [Why the old profile name?](#-why-is-the-profile-still-called-dsh-mcp)
@@ -132,12 +139,46 @@ The second command previews the changes; `--yes` applies them. Reconnect your cl
132
139
  | `dsh_queue` | Inspect/modify the session queue: `list` / `remove` / `update` / `promote` (created by `dsh_send(queue=true)`, memory only) |
133
140
  | `dsh_doctor` | Read-only health check: DSH version, profile, state/dir writability, orphan locks, sessions and RSS, effective config |
134
141
 
142
+ ## 👀 Live view: see what the dispatched work is doing
143
+
144
+ The tools above are for the **calling agent**. **You**, sitting at the client, usually see one `dsh_send` and nothing else. Since 0.6.1 the server writes each conversation's activity to a local event stream, so you can watch the call chain **without going through the agent**:
145
+
146
+ ```text
147
+ claude-code pid 8328
148
+ └─ e896d16a temperature module running · total 278k/17k · context 3%
149
+ ├─ ✓ run-…-1 [send] · done · 1m24s · 8 tools · 69k↑ 4.1k↓ tok
150
+ └─ ▶ run-…-2 [queue] · running · 156k↑ 12k↓ tok
151
+ ✓ read temp.js 13ms
152
+ ✓ edit temp.js 18ms
153
+ ◆ approval auto-allow ⚠ danger-full-access node --test
154
+ ▶ pwsh node --test
155
+ ```
156
+
157
+ ```bash
158
+ dsh-any-agent watch
159
+ ```
160
+
161
+ ```bash
162
+ dsh-any-agent dashboard --open
163
+ ```
164
+
165
+ <img src="https://raw.githubusercontent.com/xmtlzzz/dsh-any-agent/main/docs/images/dashboard.en.png" width="100%" alt="dsh-any-agent dashboard: conversations grouped by client on the left, the run timeline with a timing bar per tool call in the middle, overview, token usage, tools and files on the right (sample data)">
166
+
167
+ - **`watch`**: the call chain in your terminal, redrawn in place like `top` (no scrolling spam). `watch <conversation id prefix>` follows one conversation; `--once` prints once and exits.
168
+ - **`dashboard`**: a local read-only web page; `--open` launches it in your default browser. Left: conversations grouped by client. Middle: the run timeline, with a timing bar per tool call and approvals/escalations highlighted. Right: overview, tool breakdown, files touched, approvals, and **token usage** (input / output / cache hit, context window, per-turn chart).
169
+ - **English / 中文**: follows your system language by default; pass `--lang en|zh` to choose, or switch from the page's top-right corner.
170
+ - **Doesn't disturb running work**: both are separate processes that only read event files — they never touch the write lock or DSH. Use them to watch progress, and **don't open MCP-driven conversations in the DSH GUI** (that takes the write lock; see [usage notes 3.10](USAGE-NOTES.en.md)).
171
+ - **Safety and privacy**: the dashboard binds `127.0.0.1` only, its URL carries a one-time token, it checks the Host header, and it has no control that changes state. Command, path and prompt previews are redacted first; **reasoning is never written at any level**. `DSH_MCP_LIVE=meta` keeps only tool names and status; `off` disables it.
172
+
173
+ > Details in [Usage · side view](docs/en/usage.md); event format and design trade-offs in the [live view design](docs/en/live-view-design.md).
174
+
135
175
  ## 📚 Documentation map
136
176
 
137
177
  | Document | Contents |
138
178
  |---|---|
139
179
  | [Setup](docs/en/install.md) | Requirements, profile bootstrap, 9 MCP clients |
140
- | [Usage](docs/en/usage.md) | Dispatch/collect, sentinels, many conversations, reasoning |
180
+ | [Usage](docs/en/usage.md) | Dispatch/collect, sentinels, many conversations, live view, reasoning |
181
+ | [Live view design](docs/en/live-view-design.md) | Event stream format, `watch` / `dashboard`, token source, privacy trade-offs |
141
182
  | [Team mode](docs/en/team.md) | Default behavior, how to disable (per client), verify and revert |
142
183
  | [Permissions & privacy](docs/en/security.md) | Tiers, approvals, GUI visibility, logging |
143
184
  | [Write lock](docs/en/locking.md) | Four holder classes, takeover, GUI contention |
package/README.zh.md CHANGED
@@ -10,12 +10,13 @@
10
10
  [![node](https://img.shields.io/node/v/dsh-any-agent.svg?style=flat-square)](https://nodejs.org)
11
11
  [![license](https://img.shields.io/npm/l/dsh-any-agent.svg?style=flat-square)](LICENSE)
12
12
  [![dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg?style=flat-square)](package.json)
13
+ [![tests](https://img.shields.io/github/actions/workflow/status/xmtlzzz/dsh-any-agent/tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/xmtlzzz/dsh-any-agent/actions/workflows/tests.yml)
13
14
 
14
- [官网](https://dsh-any-agent.xmtlz.dev/) · [快速开始](#快速开始) · [主要优势](#-主要优势) · [工具](#-工具) · [使用注意事项](USAGE-NOTES.md) · [更新日志](CHANGELOG.md)
15
+ [官网](https://dsh-any-agent.xmtlz.dev/) · [快速开始](#快速开始) · [主要优势](#-主要优势) · [工具](#-工具) · [实时查看](#-实时查看派出去的活在干什么) · [使用注意事项](USAGE-NOTES.md) · [更新日志](CHANGELOG.md)
15
16
 
16
17
  </div>
17
18
 
18
- 🧪 0.5.2 本机离线套件全绿,含工作区变化检测修复、自动放行审批可见 · 🔌 MCP over stdio · 📦 零依赖 · 📜 MIT
19
+ 🧪 0.6.2 本机离线套件全绿 · 👀 新增实时调用链视图(`watch` / `dashboard`,含 token 用量)· 🔌 MCP over stdio · 📦 零依赖 · 📜 MIT
19
20
 
20
21
  一个 MCP 服务端,把 DeepSeek Harness 当作**长驻的编码 agent** 来驱动。开个会话、扔个目标,它自己写代码、跑脚本、派子代理;你随时能看、能插话、能回头验收。
21
22
 
@@ -28,7 +29,8 @@
28
29
  - **把几小时的长活交给它,然后走开** —— 回头再来收结果;
29
30
  - **跨重启不丢** —— 编辑器重启、会话断开、机器空闲回收,任务都还在;
30
31
  - **跑偏时能中途插话** —— 改口、打断,而不毁掉已经做的工作;
31
- - **同时跑好几个**,像切窗口一样轮流盯。
32
+ - **同时跑好几个**,像切窗口一样轮流盯;
33
+ - **看得见它在干什么** —— 不用问 agent,自己就能看到它调了哪些工具、批了哪些审批、花了多少 token。
32
34
 
33
35
  DSH(DeepSeek Harness)本身**全都能做** —— 它有文件/shell 工具、技能、子代理、workflow —— 但它是个 GUI 优先的应用。它自带的 `sdk` profile 只暴露 3 个请求,不能 resume、不能 cancel、不能应答审批。
34
36
 
@@ -44,6 +46,7 @@ DSH(DeepSeek Harness)本身**全都能做** —— 它有文件/shell 工具
44
46
  | 🗣️ **不用傻等** | 回合跑偏了能**插话改口**(约 100ms 收敛到 idle,四次打断实测),或**排队**等这轮跑完再说;打断后会话不损坏。 |
45
47
  | 📡 **跑完自动通知** | 长任务 `wait=false` 立刻返回 `run_id`;回合结束时**原子写出哨兵文件**,用你宿主的后台任务等它即可。不轮询、不占轮次。 |
46
48
  | 🪟 **多会话并发** | `dsh_list(only_running)` 看谁在跑,`dsh_read` 游标式增量读——像切窗口一样轮流盯。 |
49
+ | 👀 **你自己就能看见** | `dsh-any-agent watch`(终端)或 `dsh-any-agent dashboard`(本地只读网页)把派出去的活展开成调用链:客户端 → 会话 → 回合 → 工具调用 / 审批,带每回合 token 与上下文占用,回合进行中实时更新。独立进程、不碰写锁,所有客户端派的活一起看。 |
47
50
  | 🧠 **灰色思考默认隐藏** | 只给"想了 N 字 / M 秒"的统计,不烧上下文;**本服务不写日志、不落盘**(DSH 自己的会话日志仍含思考,见“日志与隐私”)。 |
48
51
  | 🤫 **默认完全静默** | 一个字节都不输出,不污染宿主日志;stdout 只走协议。 |
49
52
  | 🧩 **能力可叠加** | DSH 自己还能挂别的 MCP(IDA Pro、浏览器、内部工具)——这是一座通往整个工具箱的桥。 |
@@ -59,7 +62,7 @@ DSH(DeepSeek Harness)本身**全都能做** —— 它有文件/shell 工具
59
62
  |---|---|
60
63
  | 文件读写、shell、搜索、编辑 | 会话身份与跨崩溃 resume |
61
64
  | 技能、子代理、Agent Teams、任务板 | 异步派活、收据、完成哨兵 |
62
- | 模型路由、沙箱、审批策略 | 增量读、插话、中断 |
65
+ | 模型路由、沙箱、审批策略 | 增量读、插话、中断、实时调用链视图 |
63
66
  | 记忆/上下文/压缩 | 审批桥、写锁治理、队列、收件箱 |
64
67
  | worktree(agent 自己用 git 建) | 安装、状态、体检、审计 |
65
68
 
@@ -93,14 +96,18 @@ dsh-any-agent-setup --yes
93
96
 
94
97
  > **第一次派活前:** 先读[使用注意事项](USAGE-NOTES.md),尤其是模型配置与外部 MCP 的权限边界。**外部 MCP 工具的副作用不受 DSH 沙箱约束。** 新机器部署可按[迁移指引](USAGE-MIGRATION.md)逐步操作。
95
98
 
96
- > **想先看效果?** `npm run demo` 是一条能跑通的 5 分钟路径:派活 → 中途插话两次 → 脚本自己复核产物(连 `node --test` 都替你跑)。不想花 token 就先 `npm run demo -- --replay`。见 [5 分钟案例](docs/zh/demo.md)。
99
+ > **想先看效果?** 先看 [54 秒宣传片](https://dsh-any-agent.xmtlz.dev/#video)(派活、插话、哨兵落地、调用方复核,终端画面回放自一次真实运行):
100
+ >
101
+ > <a href="https://dsh-any-agent.xmtlz.dev/#video"><img src="https://raw.githubusercontent.com/xmtlzzz/dsh-any-agent/main/website/src/media/promo-poster.jpg" width="560" alt="▶ 播放 dsh-any-agent 宣传片(54 秒)"></a>
102
+ >
103
+ > 再自己跑一遍:`npm run demo` 是一条能跑通的 5 分钟路径:派活 → 中途插话两次 → 脚本自己复核产物(连 `node --test` 都替你跑)。不想花 token 就先 `npm run demo -- --replay`。见 [5 分钟案例](docs/zh/demo.md)。
97
104
 
98
105
  <details>
99
106
  <summary>展开完整目录</summary>
100
107
 
101
108
  - **快速开始** —— [安装并连接](#快速开始) · [更新日志](CHANGELOG.md)
102
109
  - **先看这里** —— [解决什么问题](#-解决什么问题) · [主要优势](#-主要优势) · [为什么不是包一层](#-为什么不是直接把-dsh-包一层) · [前置要求](#-前置要求) · [安装配置](#-安装配置)
103
- - **怎么用** —— [工具](#-工具) · [先派活回头验收](#-用法先派活回头再验收) · [跑完自动通知](#-用法跑完自动通知不轮询) · [多会话并发](#-用法同时控制多个会话)
110
+ - **怎么用** —— [工具](#-工具) · [实时查看](#-实时查看派出去的活在干什么) · [先派活回头验收](#-用法先派活回头再验收) · [跑完自动通知](#-用法跑完自动通知不轮询) · [多会话并发](#-用法同时控制多个会话)
104
111
  - **行为** —— [权限](#-权限) · [思考内容](#-思考内容默认隐藏) · [日志与隐私](#-日志与隐私) · [工作区与 GUI](#-会话在-dsh-gui-里的可见性)
105
112
  - **难点** —— [写锁](#-写锁一个会话同一时刻只有一个写者)
106
113
  - **参考** —— [环境变量](#-环境变量) · [测试](#-测试) · [已知限制](#-已知限制) · [为什么还叫旧 profile 名?](#-为什么-profile-还叫-dsh-mcp)
@@ -127,13 +134,47 @@ dsh-any-agent-setup --yes
127
134
  | `dsh_queue` | 查看/修改会话队列:`list` / `remove` / `update` / `promote`(队列由 `dsh_send(queue=true)` 产生,仅内存) |
128
135
  | `dsh_doctor` | 只读体检:DSH 版本、profile、状态/目录可写、孤儿锁、会话与 RSS、生效配置 |
129
136
 
137
+ ## 👀 实时查看:派出去的活在干什么
138
+
139
+ 上面的工具是给**调用方 agent** 用的。坐在客户端前的**你**,通常只看到一次 `dsh_send`。0.6.1 起,服务会把每个会话的活动写成本地事件流,你可以**不经过 agent** 直接看调用链:
140
+
141
+ ```text
142
+ claude-code pid 8328
143
+ └─ e896d16a 温度换算小模块 运行中 · 累计 278k/17k · 上下文 3%
144
+ ├─ ✓ run-…-1 [send] · done · 1m24s · 8 工具 · 69k↑ 4.1k↓ tok
145
+ └─ ▶ run-…-2 [queue] · running · 156k↑ 12k↓ tok
146
+ ✓ read temp.js 13ms
147
+ ✓ edit temp.js 18ms
148
+ ◆ 审批 auto-allow ⚠ danger-full-access node --test
149
+ ▶ pwsh node --test
150
+ ```
151
+
152
+ ```bash
153
+ dsh-any-agent watch
154
+ ```
155
+
156
+ ```bash
157
+ dsh-any-agent dashboard --open
158
+ ```
159
+
160
+ <img src="https://raw.githubusercontent.com/xmtlzzz/dsh-any-agent/main/docs/images/dashboard.zh.png" width="100%" alt="dsh-any-agent dashboard:左栏按客户端分组的会话,中间是回合时间线与每次工具调用的时间条,右栏是概览、Token 消耗、工具分布与涉及文件(示例数据)">
161
+
162
+ - **`watch`**:终端里原地刷新的调用链(同 `top`,不刷屏)。`watch <会话id前缀>` 只看一个会话,`--once` 打印一次就退出。
163
+ - **`dashboard`**:本地只读网页,`--open` 直接用默认浏览器打开。左栏按客户端分组列出会话;中间是回合时间线,每次工具调用带一根时间条,审批与提权高亮;右栏是概览、工具分布、涉及文件、审批,以及 **Token 消耗**(输入 / 输出 / 缓存命中、上下文窗口、每回合用量)。
164
+ - **中文 / English**:界面默认跟随系统语言,`--lang zh|en` 可指定;网页右上角也能随时切换。
165
+ - **不打扰正在跑的活**:两者都是独立进程,只读事件文件,不碰写锁、不连 DSH。想看进度就用它们,**别在 DSH GUI 里点开 MCP 驱动的会话**(那会抢走写锁,见[使用注意事项 3.10](USAGE-NOTES.md))。
166
+ - **安全与隐私**:dashboard 只监听 `127.0.0.1`,地址带一次性 token 并校验 Host 头,没有任何能改变状态的按钮。事件里的命令、路径、prompt 预览都先脱敏;**思考内容任何级别都不写**。`DSH_MCP_LIVE=meta` 只记工具名与状态,`off` 完全关闭。
167
+
168
+ > 详细说明见 [工具与用法 · 旁路查看](docs/zh/usage.md),事件格式与设计取舍见 [实时查看设计](docs/zh/live-view-design.md)。
169
+
130
170
  ## 📚 文档地图
131
171
 
132
172
  | 文档 | 内容 |
133
173
  |---|---|
134
174
  | [安装与配置](docs/zh/install.md) | 前置要求、profile 引导、9 个客户端注册 |
135
175
  | [5 分钟案例](docs/zh/demo.md) | 一条能跑通的端到端路径:派活、插话、自己复核 |
136
- | [工具与用法](docs/zh/usage.md) | 派活/验收、哨兵、多会话、思考内容 |
176
+ | [工具与用法](docs/zh/usage.md) | 派活/验收、哨兵、多会话、实时查看、思考内容 |
177
+ | [实时查看设计](docs/zh/live-view-design.md) | 事件流格式、`watch` / `dashboard`、token 来源、隐私取舍 |
137
178
  | [团队模式](docs/zh/team.md) | 默认行为、关闭步骤(各客户端)、验证与回退 |
138
179
  | [权限与隐私](docs/zh/security.md) | 权限档、审批、GUI 可见性、日志 |
139
180
  | [写锁](docs/zh/locking.md) | 四类持有者、takeover、GUI 竞争 |
package/SECURITY.md ADDED
@@ -0,0 +1,46 @@
1
+ # Security policy · 安全策略
2
+
3
+ ## Reporting a vulnerability · 报告漏洞
4
+
5
+ **Please do not open a public issue for security problems.** Report privately through GitHub:
6
+ **[Security → Report a vulnerability](https://github.com/xmtlzzz/dsh-any-agent/security/advisories/new)**.
7
+
8
+ 请**不要**在公开 issue 里报告安全问题,通过 GitHub 私下报告:仓库页面 **Security → Report a vulnerability**(链接见上)。
9
+
10
+ Please include · 请尽量附上:
11
+
12
+ - the dsh-any-agent version (`dsh-any-agent --version`) and DSH version (from `dsh_doctor`) · 版本号;
13
+ - the permission tier and `on_approval` of the session involved · 会话的权限档与审批策略;
14
+ - minimal steps or a proof of concept, and what you expected instead · 最小复现步骤与预期行为。
15
+
16
+ This is a small, volunteer-maintained project. Reports are acknowledged on a best-effort basis, usually within a week; fixes for confirmed issues ship as a patch release with a CHANGELOG entry crediting the reporter (unless you prefer otherwise).
17
+
18
+ 这是个人维护的小项目:会尽力在一周内回复;确认的问题会以补丁版本修复,并在 CHANGELOG 里致谢(如不希望署名请说明)。
19
+
20
+ ## Supported versions · 支持的版本
21
+
22
+ Only the **latest minor release line** (currently `0.6.x`) receives security fixes. Upgrade with `npm install -g dsh-any-agent@latest`.
23
+
24
+ 只有**最新的次版本线**(目前是 `0.6.x`)会收到安全修复。
25
+
26
+ ## In scope · 属于本项目的安全问题
27
+
28
+ dsh-any-agent sits between an MCP client and DeepSeek Harness. Issues in what *this server* promises are in scope, for example:
29
+
30
+ - **Permission tiers**: a `read-only` session that can write, or an approval from a read-only session that gets allowed; `danger-full-access` reachable without `DSH_MCP_ALLOW_FULL_ACCESS=1`.
31
+ - **Path handling**: a `conversation_id` / `run_id` / `cwd` that escapes its directory (traversal into sentinel, review, lock, tombstone or live-event paths); a writable `cwd` at a filesystem root or home directory.
32
+ - **Disk hygiene**: reasoning text written to this server's own files (sentinels, reviews, live events, registry, logs) without `DSH_MCP_SENTINEL_INCLUDE_REASONING=1`; credentials that survive redaction in sentinels, approval context or live-event previews.
33
+ - **Write-lock handling**: `dsh_takeover` killing a process it could not prove it owns (the GUI, an unrelated process).
34
+ - **Client configuration**: `dsh-any-agent-setup` / `restore` changing entries other than its own, or losing a user's config without a backup.
35
+ - **Live dashboard**: reaching it without the one-time token, from a non-loopback address, or with a foreign `Host` header; any request that changes state; script injection through event content.
36
+
37
+ ## Out of scope · 不属于本项目
38
+
39
+ - **DeepSeek Harness itself** (its sandbox, model behaviour, its own session logs, which do contain reasoning) — report to the DSH project.
40
+ - **Side effects of external MCP tools** that DSH is configured to use — they are not constrained by DSH's sandbox; see the usage notes.
41
+ - **Documented behaviour**: under `on_approval=auto-allow`, DSH may request and be granted `sandbox_permissions: danger-full-access`. This is the documented default and is reported on every result (`auto_escalations_total`); use `on_approval=ask` to gate it.
42
+ - Anything that requires an attacker who can already write to your `~/.dsh` directory or run code as your user.
43
+
44
+ ## More · 更多
45
+
46
+ How permissions, approvals, logging and the live view behave: [docs/en/security.md](docs/en/security.md) · [docs/zh/security.md](docs/zh/security.md).
package/USAGE-NOTES.en.md CHANGED
@@ -40,6 +40,8 @@ Practical gotchas and trade-offs you *will* hit when letting Claude / Codex driv
40
40
 
41
41
  **2.6 Sentinel files consume disk.** They are a *latch*: written once and kept so a late waiter never misses one, so they don't vanish on their own. The service **prunes sentinels older than 7 days at startup** (`DSH_MCP_SENTINEL_TTL_MS`, `0` disables); have your waiter `rm` after consuming. Sentinels **contain no reasoning** — `result.thinking` is stripped and a boolean `thinking_omitted` is always present. They also carry usage and **credential-redacted tool inputs**, so treat them as sensitive files.
42
42
 
43
+ **2.7 Watch tokens in the dashboard instead of waiting for the bill (since 0.6.2).** Run `dsh-any-agent dashboard` (or `watch`): each run's input / output / cache read-write tokens update **while the run is going**, and the side column's token panel adds cache-hit rate, context-window use and a per-turn chart. A sudden drop in cache hits, or one turn far above the others, is your cue to look at what it is doing and whether to interject. The numbers come from DSH's own session record (`tokenUsage` / `contextPressure` in the projection cache) — this server reads them rather than estimating. Session totals include runs from before the live view existed; until DSH has written them the panel shows no data.
44
+
43
45
  ## 3. Concurrency and lifecycle
44
46
 
45
47
  **3.1 One turn per conversation at a time.** ACP rejects concurrent prompts: `a prompt is already in flight for this session`. To redirect, use `dsh_interject` (`interject` = stop and redirect, `queue` = speak after the current turn); to stop, `dsh_interrupt`.
@@ -60,9 +62,9 @@ Practical gotchas and trade-offs you *will* hit when letting Claude / Codex driv
60
62
 
61
63
  **3.9 ★★ The silent privilege-escalation trap (the most dangerous pitfall here).** Symptom: `dsh_start(permission: 'read-only')` **returns** `"read-only"` while the session actually runs with **full access** — you think you are analysing a sample in a sandbox and you are not. Cause: if the profile sets `defaultPreset`, `dsh-permission-presets` applies it **at session creation** to the sandbox mode and approval policy, **overriding** the mode `dsh-base` derived from `DSH_PERMISSION_MODE`; pinning `danger-full-access` therefore escalates every session. Correct form: **define the presets but do not write `defaultPreset`**. The plugin then falls back to its inferred default (matching a preset by the sandbox + approval pair), and `dsh-base`'s rule — `mode = DSH_PERMISSION_MODE ?? 'workspace-write'`, `policy = (mode === 'danger-full-access') ? 'never' : 'ask'` — lines up with the three tiers exactly, so **each session's real tier is decided by the env passed at spawn time**. `profile-example/cordis.patch.yml` already does it this way. How to verify: **do not trust the tool's return value** (that is exactly what used to lie) — read **the session's own record** (`permissions.preset` / `sandboxMode` in the projection cache). `test/permission.mjs` does precisely that, checking all three tiers and that their recorded values differ. One more caveat: the tier is fixed at **`dsh_start`**; DSH is designed so that **a resumed session keeps its recorded permission**, so changing the `permission` argument later will not alter an existing conversation — create a new one to change tiers.
62
64
 
63
- **3.10 ★★ Peeking at progress in the web UI takes the write lock away (measured A/B).** Method: have a **separate process** attempt `session/resume` on the same conversation — success means the lock is free, failure (`already owned`) means somebody is writing. That is the only way to see past our own registration table. Result: with the conversation only in the MCP's hands it is **free** (probed twice); the moment you **open** it in the web UI it becomes **held** (`already owned by an active write handle`), and since the only MCP server present had **no child processes**, the holder is the `dsh web` process. Precise wording: **reading content, searching and listing are unaffected** (the lease docs say readers proceed freely), but **the act of opening a conversation in the GUI** takes a write handle — it is not "only sending a message". This is the typical cause of "the task finished and the caller cannot get back in": the MCP dispatches and holds the lock, you open the conversation to watch progress, the GUI takes the lock, and when the task ends the caller's resume is refused. Correct habit: **do not click a running conversation open in the GUI.** To watch progress use **`dsh_read`** (the MCP tool, cursor-based incremental reads) or wait for the sentinel file; if you really want the GUI view, `dsh_release` first (which interrupts a running turn, so it only fits the gaps between tasks).
65
+ **3.10 ★★ Peeking at progress in the web UI takes the write lock away (measured A/B).** Method: have a **separate process** attempt `session/resume` on the same conversation — success means the lock is free, failure (`already owned`) means somebody is writing. That is the only way to see past our own registration table. Result: with the conversation only in the MCP's hands it is **free** (probed twice); the moment you **open** it in the web UI it becomes **held** (`already owned by an active write handle`), and since the only MCP server present had **no child processes**, the holder is the `dsh web` process. Precise wording: **reading content, searching and listing are unaffected** (the lease docs say readers proceed freely), but **the act of opening a conversation in the GUI** takes a write handle — it is not "only sending a message". This is the typical cause of "the task finished and the caller cannot get back in": the MCP dispatches and holds the lock, you open the conversation to watch progress, the GUI takes the lock, and when the task ends the caller's resume is refused. Correct habit: **do not click a running conversation open in the GUI.** To watch progress yourself, use **`dsh-any-agent watch`** (terminal) or **`dsh-any-agent dashboard`** (local read-only web page, since 0.6.1): they only read the event files this server writes, **never touch the write lock**, and show tool calls, approvals and tokens live. For the agent, use **`dsh_read`** (the MCP tool, cursor-based incremental reads) or wait for the sentinel file. If you really want the GUI view, `dsh_release` first (which interrupts a running turn, so it only fits the gaps between tasks).
64
66
 
65
- **3.11 ★★ Opening it once hands the conversation to the GUI permanently (measured; harsher than 3.10).** Measured: you open the conversation in the web UI (the GUI takes the lock), then **switch away to another conversation**, then we probe again — **the lock is still held**. So `dsh web` does **not** release it when you navigate away: **once opened, that conversation belongs to the GUI for the entire lifetime of the web process**, and the MCP cannot touch it again until you **restart `dsh web`**. That is why it is "always": it is not taken on every peek, it is taken once and stays taken — so from then on every retry fails until the GUI restarts. Practical advice: (1) never open a conversation the MCP drives, not even once — seeing its title in the list is fine; (2) to read content, have the agent call `dsh_read` and paste the output to you; (3) if you already opened it, **restart `dsh web`** — switching away in the UI does nothing.
67
+ **3.11 ★★ Opening it once hands the conversation to the GUI permanently (measured; harsher than 3.10).** Measured: you open the conversation in the web UI (the GUI takes the lock), then **switch away to another conversation**, then we probe again — **the lock is still held**. So `dsh web` does **not** release it when you navigate away: **once opened, that conversation belongs to the GUI for the entire lifetime of the web process**, and the MCP cannot touch it again until you **restart `dsh web`**. That is why it is "always": it is not taken on every peek, it is taken once and stays taken — so from then on every retry fails until the GUI restarts. Practical advice: (1) never open a conversation the MCP drives, not even once — seeing its title in the list is fine; (2) to follow progress, run `dsh-any-agent watch` or `dsh-any-agent dashboard` yourself (no lock involved); to read the full text, have the agent call `dsh_read` and paste the output to you; (3) if you already opened it, **restart `dsh web`** — switching away in the UI does nothing.
66
68
 
67
69
  **3.12 ★★ The lossless answer: keep the MCP holding the lock (`DSH_MCP_IDLE_TTL_MS=0`).** The full causal chain, all measured: with a non-zero TTL, a task finishes, the conversation sits idle past that TTL, **idle reaping kills the child and frees the write lock**, you happen to open that conversation in the web UI right then, **the GUI takes the lock and never returns it** (navigating away ✗, waiting ✗, **archiving ✗** — verified that the archive really landed), and from then on every MCP resume fails. That is "the caller can never get back in after a task". The fix: **`DSH_MCP_IDLE_TTL_MS=0` is now the default** (never reap), so the MCP keeps holding the write lock. Then opening it in the GUI **opens it read-only and you can still read it** (measured: the turns and answers are visible), and probing from a separate instance confirms **the holder is still this server's own PID with a fresh heartbeat** — the lock was never taken. **Neither side is harmed**: you keep visibility, while the MCP's turns keep running and later calls reconnect normally. Zero data loss, zero duplication, zero extra disk. The cost, measured: **300–480 MB per live conversation** (two cold starts of a single active conversation added 476 MB and 295 MB; roughly linear, so ten conversations reach 3–5 GB). It will not blow up, but it is real. Three ways to control it: ★ **on by default — `DSH_MCP_MAX_LIVE=8`**: over the cap, the **least recently used** process is reaped (a running turn is never reaped), giving "**bounded memory, locks kept where it matters**" ✓; **after a batch of work — `dsh_release(all=true)`** frees every **idle** conversation, dropping memory ✓ and it is lossless (the logs are on disk, everything resumes on demand ✓); busy turns are skipped by default — pass `force=true` to interrupt them too; or set `DSH_MCP_IDLE_TTL_MS` to a millisecond value (at the cost of the lock being takeable ✗). In one line: reaping saves memory but hands the lock away; not reaping spends memory to buy "never silently locked out". Your data is never at risk either way: a GUI-pinned conversation is intact, and the MCP resumes it normally once `dsh web` restarts — what you lose is only immediate usability, not content.
68
70
 
@@ -108,6 +110,8 @@ Practical gotchas and trade-offs you *will* hit when letting Claude / Codex driv
108
110
 
109
111
  **7.3 Be careful with `DSH_MCP_LOG_STDERR=1`** — it forwards DSH's raw stderr, which may contain reasoning. Local debugging only.
110
112
 
113
+ **7.4 What the live event stream holds (since 0.6.1).** `watch` / `dashboard` read `$DSH_HOME/.dsh-any-agent/live/<conversation_id>/events.jsonl`. With the default `DSH_MCP_LIVE=detail` there is one line per dispatch, tool call (on status change), approval, run end and token update, with **redacted** short previews of commands, paths and prompts — no more than the sentinels already hold. **Reasoning has no place in the event format and is never written at any level.** Set `meta` to keep only tool names, status, timing, approval kinds and token counts, or `off` to write nothing. Event files share the sentinels' 7-day TTL and are deleted by `dsh_release(forget=true)`. The dashboard binds `127.0.0.1` only, its URL carries a one-time token, and it exposes nothing that changes state.
114
+
111
115
  ## 8. Troubleshooting
112
116
 
113
117
  | Error | Meaning | Fix |
package/USAGE-NOTES.md CHANGED
@@ -76,6 +76,11 @@
76
76
  - **原因**:哨兵是**闩锁**——写一次并保留,晚到的等待方才能不漏,所以它不会自己消失。
77
77
  - **对策**:服务**启动时会清掉超过 7 天的**(`DSH_MCP_SENTINEL_TTL_MS` 调,`0` 关闭)。等待任务消费后顺手 `rm` 更干净。哨兵**不含思考内容**(`result.thinking` 被剥掉,并始终给出布尔 `thinking_omitted`);它还会包含用量与**已按审批规则脱敏的工具输入**,仍应按敏感文件对待。
78
78
 
79
+ ### 2.7 用 dashboard 盯 token,比事后看账单早(0.6.2 起)
80
+ - **现象**:一个回合烧了多少 token,以前只能等结束后看 `dsh_get` 的用量,或者事后看账单。
81
+ - **做法**:开 `dsh-any-agent dashboard`(或 `watch`)。每个回合的输入 / 输出 / 缓存读写在**回合进行中**就会更新,右栏"Token 消耗"面板还有缓存命中率、上下文窗口占用和每回合用量图。缓存命中率突然掉下来、或某一轮远高于其它轮,就是该看看它在干什么、要不要插话的时候。
82
+ - **数字从哪来**:DSH 自己的会话记录(投影缓存里的 `tokenUsage` / `contextPressure`),本服务只是读出来,不自己估算。会话累计包含 live 之前的回合;DSH 还没写入时面板显示"暂无数据"。
83
+
79
84
  ---
80
85
 
81
86
  ## 三、并发与会话管理
@@ -152,7 +157,7 @@
152
157
  - **结果**:会话只在 MCP 手里时 → **【空】**(连测两次);你在 web 里**点开**它之后 → **【被占用】**(`already owned by an active write handle`)。当时唯一的 MCP 服务**没有任何子进程**,所以持有者就是 `dsh web` 进程。
153
158
  - **准确表述**:**读内容 / 搜索 / 列目录不受影响**(租约文档明说 "readers ... proceed freely"),但**"在 GUI 里打开一个会话"这个动作本身**要为可写取句柄 → **占锁**。不是"发消息才占"。
154
159
  - **这就是"任务跑完后调用方接不回去"的典型成因**:CC 派活(MCP 持锁)→ 你去 web 看进度 → GUI 抢走锁 → 任务结束后 CC 想 resume 回去就被拒。
155
- - **正确姿势**:运行中的会话**别在 GUI 里点开**。看进度用 **`dsh_read`**(MCP 工具,游标增量读)或等哨兵文件;真要在 GUI 里看,先 `dsh_release` 交还(但那会中断正在跑的回合,只适合任务间隙)。
160
+ - **正确姿势**:运行中的会话**别在 GUI 里点开**。你自己想看进度,用 **`dsh-any-agent watch`**(终端)或 **`dsh-any-agent dashboard`**(本地只读网页,0.6.1 起):它们只读本服务写的事件文件,**完全不碰写锁**,工具调用、审批、token 都能实时看到。让 agent 看,用 **`dsh_read`**(MCP 工具,游标增量读)或等哨兵文件。真要在 GUI 里看,先 `dsh_release` 交还(但那会中断正在跑的回合,只适合任务间隙)。
156
161
 
157
162
  ### 3.11 ★★ "点开过一次"是把会话永久交给 GUI(实测,比 3.10 更硬)
158
163
  - **实测**:你在 web 里点开那条会话(锁被 GUI 拿走)→ 你**切走到别的会话** → 再探测 → **锁仍然被占用** ✗
@@ -160,7 +165,7 @@
160
165
  - **为什么这解释了"总是"**:不是每次看进度都被抢,而是**抢一次就永久生效** —— 之后 CC 无论怎么重试都接不回去,直到你重启 GUI。
161
166
  - **给你的操作建议**:
162
167
  1. MCP 驱动的会话,**一次都别点开**(列表里能看见它,看标题就行);
163
- 2. 要看内容 → 让 agent 调 `dsh_read`,把输出贴给你;
168
+ 2. 要看进度 → 自己开 `dsh-any-agent watch` 或 `dsh-any-agent dashboard`(不碰锁);要看完整正文 → 让 agent 调 `dsh_read`,把输出贴给你;
164
169
  3. 已经点开过了 → **重启 `dsh web`** 才能真正把锁还回来(界面上切走没用)。
165
170
 
166
171
  ### 3.12 ★★ 无损解法:让 MCP 一直握着锁(`DSH_MCP_IDLE_TTL_MS=0`)
@@ -250,6 +255,9 @@
250
255
  ### 7.3 `DSH_MCP_LOG_STDERR=1` 要谨慎
251
256
  它会转发 DSH 子进程的原始 stderr,**其中可能包含思考内容**。只在本地排障时临时开。
252
257
 
258
+ ### 7.4 live 事件流里有什么(0.6.1 起)
259
+ `watch` / `dashboard` 读的是 `$DSH_HOME/.dsh-any-agent/live/<会话id>/events.jsonl`。默认 `DSH_MCP_LIVE=detail`:每次派活、工具调用(状态变化时)、审批、回合结束和 token 用量各一行,带**脱敏后的**命令、路径、prompt 短预览——暴露面不超过哨兵。**思考内容在事件格式里没有位置,任何级别都不写。** 想少记就设 `meta`(只有工具名、状态、计时、审批类型、token 计数),不要就设 `off`。事件文件和哨兵同一个 7 天 TTL,`dsh_release(forget=true)` 会一并删掉。dashboard 只监听 `127.0.0.1`,地址带一次性 token,没有任何能改变状态的接口。
260
+
253
261
  ---
254
262
 
255
263
  ## 八、故障速查
@@ -40,7 +40,8 @@ if (argv.includes('--help') || argv.includes('-h')) {
40
40
  ' dsh-any-agent team on|off enable/disable Agent Teams (writes settings.json)\n' +
41
41
  ' dsh-any-agent team status show the effective team mode\n' +
42
42
  ' dsh-any-agent watch [conv] live call chain of dispatched runs in this terminal\n' +
43
- ' dsh-any-agent dashboard same, as a read-only local web page (127.0.0.1 + token)\n' +
43
+ ' dsh-any-agent dashboard same, as a read-only local web page (127.0.0.1 + token);\n' +
44
+ ' --open launches it in your browser\n' +
44
45
  ' dsh-any-agent --version print the version and exit\n' +
45
46
  ' dsh-any-agent --help this text\n\n' +
46
47
  'Register it with your client:\n' +
@@ -38,6 +38,18 @@ DSH ships two programmable entry points. The `sdk` profile looks simpler, but it
38
38
 
39
39
  **Process model.** A conversation's identity is its `sessionId`; the process is a disposable carrier. Since 0.5.0, sessions with the same `(cwd, permission)` share one ACP process by default (`src/host.mjs`): DSH's ACP server accepts multiple sessions per connection, each with its own Agent, but the sandbox root and approval policy are **process-wide**, so grouping can only follow those two. The win: the second session costs ≈300 ms instead of a ≈4 s cold start, and memory is paid once per group. The price: if that one process dies, every in-flight turn in the group dies with it (the conversations themselves are intact and resume on the next call) — which is why `dsh_takeover` refuses to kill a shared process without `force`. Set `DSH_MCP_SHARED_PROCESS=0` for one process per conversation.
40
40
 
41
+ **Live view (since 0.6.1).** The server is a stdio child of each MCP client, so there may be several instances whose memory does not overlap, and none of them has a port. The live view therefore goes through files rather than a socket: while dispatching, each instance appends the conversation's activity — runs, tool calls, approvals, token usage — to `<state dir>/live/<conversation_id>/events.jsonl`. The write lock already guarantees one writer per conversation, so one file per conversation needs no extra locking. `dsh-any-agent watch` and `dsh-any-agent dashboard` are separate read-only processes that tail those files, so they see work from every client and every instance at once, survive server restarts, and never touch the write lock or DSH:
42
+
43
+ ```
44
+ MCP clients ─▶ dsh-any-agent (one per client) ──append──▶ live/<id>/events.jsonl
45
+ │ tail (read-only)
46
+ ┌──────────────┴──────────────┐
47
+ dsh-any-agent watch dsh-any-agent dashboard
48
+ (terminal, in place) (127.0.0.1 + token, SSE)
49
+ ```
50
+
51
+ Token numbers are read from DSH's own projection cache (`tokenUsage` / `contextPressure`), which DSH updates after every model step. Design notes: [live view design](live-view-design.md).
52
+
41
53
  **MCP compatibility.** The server uses only `initialize`, `ping`, `tools/list` and `tools/call`. It has also been verified with a bare-bones client that negotiates an older protocol version and never sends `notifications/initialized`.
42
54
 
43
55
  </details>
package/docs/en/limits.md CHANGED
@@ -11,6 +11,12 @@
11
11
  7. **`session/list` returns only `{sessionId, cwd}` and excludes already-open sessions** — titles are filled in by this server from DSH's projection cache.
12
12
  8. **Memory (measured 300–480 MB per live process)** — since 0.5.0 sessions with the same `(cwd, permission)` **share one ACP process by default**, so that cost is once per group rather than once per conversation; combined with the 0.4.0 defaults (**10-minute idle reaping + `MAX_LIVE=4`**) the worst case is ≈1.2–1.9 GB. `keep_alive=true` sessions are exempt from idle reaping (at the cost of staying resident). You can also: ① cap by measured RSS with `DSH_MCP_MAX_RSS_MB`; ② cap the child heap with `DSH_MCP_CHILD_MAX_OLD_SPACE_MB`. To drop to zero right after a batch of work: **`dsh_release(all=true)`** ✓ (releases idle conversations; busy turns are skipped and keep running — pass `force=true` to interrupt them too. Everything resumes on demand).
13
13
  9. **A shared process takes its group down with it** — the default shared host puts sessions with the same `(cwd, permission)` on one PID. Sessions do not interfere with each other (each has its own Agent and context), but **if the process crashes or is killed, every in-flight turn in the group dies at once** (error sentinels are written and waiters wake up; each session resumes on its next call — the conversation itself is intact). Hence: ① `dsh_takeover` requires `force=true` to kill such a process, and lists the other sessions riding on it; ② for strict isolation (untrusted samples, mutually untrusted tasks) set `DSH_MCP_SHARED_PROCESS=0`; ③ different workspaces or permission tiers still get separate processes — that follows from `dsh-base`'s process-wide sandbox and approval config, not a choice.
14
+ 10. **Live view (`watch` / `dashboard`) boundaries** —
15
+ ① **local only**: events are written to this machine's `$DSH_HOME/.dsh-any-agent/live/`, so remote or cloud sessions are not visible;
16
+ ② **read-only**: you cannot approve, interject or interrupt from the page — use the MCP tools (`dsh_approval_decide` / `dsh_interject` / `dsh_interrupt`);
17
+ ③ **only tool calls reported over ACP are visible**: whether a DSH subagent's internal calls are reported is up to DSH, and this server does not infer them;
18
+ ④ **token numbers come from DSH's session record**: before DSH writes them the panel shows no data, and session totals include runs from before the live view;
19
+ ⑤ **no backfill**: runs before 0.6.1 have no call chain, and runs before 0.6.2 have no token data.
14
20
 
15
21
  ## ❓ Why is the profile still called `dsh-mcp`?
16
22