dsh-any-agent 0.3.7 → 0.3.8
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 +29 -2
- package/DESIGN.md +9 -1
- package/README.md +10 -6
- package/README.zh.md +8 -5
- package/USAGE-MIGRATION.en.md +160 -0
- package/package.json +3 -1
- package/src/workspace.mjs +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
Post-0.3.
|
|
10
|
+
Post-0.3.8 hardening.
|
|
11
|
+
|
|
12
|
+
## [0.3.8] — 2026-11-02
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- `npm test` now works without a local DSH: smoke still checks handshake and
|
|
17
|
+
the tool table, then skips session-dependent sections instead of failing, so
|
|
18
|
+
all offline suites run. `npm run test:all` is the explicit full-suite entry.
|
|
19
|
+
- Added the `model-suites` workflow for a self-hosted runner with DSH and
|
|
20
|
+
provider credentials; hosted runners print an explicit skip.
|
|
21
|
+
- Added an English `USAGE-MIGRATION.en.md` and linked it from the English
|
|
22
|
+
README and `/en/` install section.
|
|
23
|
+
|
|
24
|
+
### Testing
|
|
25
|
+
|
|
26
|
+
- Removed the remaining always-true `check(..., true)` assertions; cleanup
|
|
27
|
+
checks now assert actual release/forget results or timeout state.
|
|
28
|
+
- `prune` runs with an isolated `DSH_HOME` so it cannot touch real tombstones.
|
|
29
|
+
- Added 8 static accessibility tests for both locales (28 website tests total
|
|
30
|
+
counting the existing site/release/demo suites).
|
|
31
|
+
- `readHeaderAsync` now uses `StringDecoder` for multi-byte UTF-8 boundaries.
|
|
32
|
+
|
|
33
|
+
### Website
|
|
34
|
+
|
|
35
|
+
- `robots.txt` now mirrors the complete Cloudflare Managed crawler list, not
|
|
36
|
+
just the four most common bots.
|
|
11
37
|
|
|
12
38
|
## [0.3.7] — 2026-11-02
|
|
13
39
|
|
|
@@ -670,7 +696,8 @@ First public release, published to npm as [`dsh-any-agent`](https://www.npmjs.co
|
|
|
670
696
|
profiles, sessions and client configs. The product name changed; the on-disk
|
|
671
697
|
contract did not. See the README FAQ.
|
|
672
698
|
|
|
673
|
-
[Unreleased]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.3.
|
|
699
|
+
[Unreleased]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.3.8...HEAD
|
|
700
|
+
[0.3.8]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.3.7...v0.3.8
|
|
674
701
|
[0.3.7]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.3.6...v0.3.7
|
|
675
702
|
[0.3.6]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.3.5...v0.3.6
|
|
676
703
|
[0.3.5]: https://github.com/xmtlzzz/dsh-any-agent/compare/v0.3.4...v0.3.5
|
package/DESIGN.md
CHANGED
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
> 目标:做一个 MCP Server,让 **Codex / Claude Code** 能调用 **DeepSeek Harness (DSH)** 当"外包工程师"——写代码、搭脚手架、跑任务,并且 DSH 自己还能挂它自己的 MCP。
|
|
4
4
|
>
|
|
5
|
-
> 本文只谈**功能与接口**,不写实现代码;其中 M2/M3 工具(`dsh_rename` 等)是分期计划,不是当前 0.3.
|
|
5
|
+
> 本文只谈**功能与接口**,不写实现代码;其中 M2/M3 工具(`dsh_rename` 等)是分期计划,不是当前 0.3.8 的缺失功能。技术判断最初基于 DSH 0.1.7-rc.2,当前验证基线是 **DSH 0.2.1-rc.5**(见 §2 证据)。
|
|
6
|
+
|
|
7
|
+
## 当前实现状态(0.3.8)
|
|
8
|
+
|
|
9
|
+
当前对外暴露 11 个工具,均已实现并有回归:
|
|
10
|
+
|
|
11
|
+
`dsh_start`、`dsh_send`、`dsh_list`、`dsh_read`、`dsh_get`、`dsh_interject`、`dsh_interrupt`、`dsh_release`、`dsh_takeover`、`dsh_approval_decide`、`dsh_status`
|
|
12
|
+
|
|
13
|
+
本文后续出现的 `dsh_resume`、`dsh_rename`、`dsh_delete`、`dsh_transcript`、`dsh_diff`、`dsh_doctor` 等属于 M2/M3 路线图,**不是当前版本的缺失**。当前版本的能力边界以 README 的 Known limitations 与 USAGE-NOTES 为准。
|
|
6
14
|
|
|
7
15
|
---
|
|
8
16
|
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
|
-
🧪 815 checks green on 0.3.
|
|
18
|
+
🧪 815 checks green on 0.3.8 on this machine (851 when all nine client fixtures exist); 519 of them are in the client-registration suites (555 with all fixtures) · 🔌 MCP over stdio · 📦 Zero dependencies · 📜 MIT
|
|
19
19
|
|
|
20
20
|
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
21
|
|
|
@@ -33,7 +33,7 @@ dsh-any-agent-setup --yes
|
|
|
33
33
|
|
|
34
34
|
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.
|
|
35
35
|
|
|
36
|
-
> **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.md).
|
|
36
|
+
> **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).
|
|
37
37
|
|
|
38
38
|
<details>
|
|
39
39
|
<summary>Full contents</summary>
|
|
@@ -550,11 +550,15 @@ Silent by default — **not one byte is written**.
|
|
|
550
550
|
## 🧪 Tests
|
|
551
551
|
|
|
552
552
|
```bash
|
|
553
|
-
|
|
554
|
-
|
|
553
|
+
npm test # offline suites; smoke skips DSH sections if no DSH
|
|
554
|
+
npm run test:all # offline + model-backed suites (needs DSH/provider)
|
|
555
555
|
node test/cleanup.mjs # suite teardown on its own (test-created dirs only; --dry-run to preview)
|
|
556
556
|
```
|
|
557
557
|
|
|
558
|
+
Model-backed suites are not part of the hosted CI matrix (they need a real DSH
|
|
559
|
+
install and provider credentials). Run them locally, or dispatch the
|
|
560
|
+
`model-suites` workflow with a self-hosted runner that has DSH configured.
|
|
561
|
+
|
|
558
562
|
The suite **cleans up after itself**: `run.mjs` always ends with `cleanup.mjs`, which removes sessions and workspace registrations whose cwd is **a test-created directory** (`tmpdir()/dsh-any-agent-*` or `Desktop/dsh-any-agent-test-*`). Real project sessions — including projects under `%TEMP%` — and your live state directory are never touched. To remove `Desktop/dsh-any-agent-test-*` artifacts explicitly, run `node bin/dsh-any-agent-workspaces.mjs --purge-test-sessions`.
|
|
559
563
|
|
|
560
564
|
| Suite | Checks | Covers |
|
|
@@ -595,11 +599,11 @@ The suite **cleans up after itself**: `run.mjs` always ends with `cleanup.mjs`,
|
|
|
595
599
|
| `list` | 13 | **the cost of `dsh_list`** (measured): a default call with the on-disk probe takes ~1 s (it spawns a DSH process) while **repeated calls hit a cache and drop to single-digit milliseconds**; `only_running=true` and `include_closed=false` **skip the probe** with equivalent semantics (unopened on-disk sessions are simply excluded) |
|
|
596
600
|
| `reasoning-check` | 8 | **reasoning visibility**: `reasoning=hide` returns no thinking body but non-zero stats; `reasoning=full` returns the text and the rendered section |
|
|
597
601
|
|
|
598
|
-
**`node test/run.mjs` runs 815 checks on a machine with five client fixtures (851 with all nine)** — smoke 29 + 786 offline checks (822 with nine). Every suite exited 0 on 0.3.
|
|
602
|
+
**`node test/run.mjs` runs 815 checks on a machine with five client fixtures (851 with all nine)** — smoke 29 + 786 offline checks (822 with nine). Every suite exited 0 on 0.3.8; none needs a provider (smoke skips its session-creation sections when DSH is absent).
|
|
599
603
|
|
|
600
604
|
That is **519 assertions in the client-registration suites alone** (`setup` 41, `removal-scope` 24, `config-safety` 406, `real-configs` 48; 555 with all nine fixtures), which is where the 0.3 work actually is.
|
|
601
605
|
|
|
602
|
-
The model-backed suites (`smoke` 29, `boundary` 46, `integration` 30, `async` 16, `sentinel` 36, `timeout` 38, `lock` 79, `cycle` 36, `concurrency` 31, `capability` 22, `workspace-effect` 24, `acceptance` 36, `multi` 19, `permission` 11, `list` 13, `reasoning-check` 8) total 474 and were last measured in full on 0.3.
|
|
606
|
+
The model-backed suites (`smoke` 29, `boundary` 46, `integration` 30, `async` 16, `sentinel` 36, `timeout` 38, `lock` 79, `cycle` 36, `concurrency` 31, `capability` 22, `workspace-effect` 24, `acceptance` 36, `multi` 19, `permission` 11, `list` 13, `reasoning-check` 8) total 474 and were last measured in full on 0.3.8 — they need a working provider, so re-run them yourself before trusting a release: `node test/run.mjs --all`. `acceptance` now **skips explicitly** when the DSH profile has no IDA MCP (`mcp__ida__*`).
|
|
603
607
|
|
|
604
608
|
> Three different totals are intentional: `node test/run.mjs` (815/851), the CI offline job (786/822, no smoke), and the model-backed set (474 nominal). Counts are the numbers each suite prints itself; don't use one number for a different runner.
|
|
605
609
|
|
package/README.zh.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
|
-
🧪 0.3.
|
|
18
|
+
🧪 0.3.8 本机 815 项检查全绿(九种客户端配置齐全时 851 项;其中 519 项属于客户端注册器套件,齐全时 555 项) · 🔌 MCP over stdio · 📦 零依赖 · 📜 MIT
|
|
19
19
|
|
|
20
20
|
一个 MCP 服务端,把 DeepSeek Harness 当作**长驻的编码 agent** 来驱动。开个会话、扔个目标,它自己写代码、跑脚本、派子代理;你随时能看、能插话、能回头验收。
|
|
21
21
|
|
|
@@ -565,11 +565,14 @@ node bin/dsh-any-agent-workspaces.mjs --purge-test-sessions # 删测试会话
|
|
|
565
565
|
## 🧪 测试
|
|
566
566
|
|
|
567
567
|
```bash
|
|
568
|
-
|
|
569
|
-
|
|
568
|
+
npm test # 全部离线套件;没有 DSH 时 smoke 自动跳过会话段
|
|
569
|
+
npm run test:all # 离线 + 需要模型的套件(需要 DSH/provider)
|
|
570
570
|
node test/cleanup.mjs # 单独跑收尾清理(只清测试自己造的目录;--dry-run 可预演)
|
|
571
571
|
```
|
|
572
572
|
|
|
573
|
+
模型套件不在 GitHub 托管 CI 里(需要真实 DSH、provider 与凭据)。在本机跑,
|
|
574
|
+
或用 `model-suites` workflow 指定一台装好 DSH 的 self-hosted runner。
|
|
575
|
+
|
|
573
576
|
测试套件**会自己收尾**:`run.mjs` 结束时必定执行 `cleanup.mjs`,它只清理 cwd 在**测试自己造的目录**(`tmpdir()/dsh-any-agent-*` 或桌面 `dsh-any-agent-test-*`)里的会话与工作区登记。**用户在 `%TEMP%` 里自己的真实项目、以及你的状态目录都不会被碰**。要连桌面测试目录一起清,可显式跑 `node bin/dsh-any-agent-workspaces.mjs --purge-test-sessions`。
|
|
574
577
|
|
|
575
578
|
| 套件 | 检查数 | 覆盖 |
|
|
@@ -610,11 +613,11 @@ node test/cleanup.mjs # 单独跑收尾清理(只清测试自己造的目
|
|
|
610
613
|
| `list` | 13 | **`dsh_list` 的开销**(实测驱动):含磁盘探测的默认调用约 1 秒(要 spawn 一个 DSH 进程),**连续调用命中缓存降到个位数毫秒**;`only_running=true` 与 `include_closed=false` **跳过探测**且语义等价(不把磁盘上的未打开会话算进来) |
|
|
611
614
|
| `reasoning-check` | 8 | **思考可见性**:`reasoning=hide` 不返回思考正文但统计非零;`reasoning=full` 返回正文且渲染出思考段 |
|
|
612
615
|
|
|
613
|
-
**`node test/run.mjs` 在本机 5/9 客户端配置时跑 815 项(九种齐全时 851 项)** —— smoke 29 + 离线套件 786 项(九种齐全时 822 项)。0.3.
|
|
616
|
+
**`node test/run.mjs` 在本机 5/9 客户端配置时跑 815 项(九种齐全时 851 项)** —— smoke 29 + 离线套件 786 项(九种齐全时 822 项)。0.3.8 上全部退出码 0;都不需要 provider(没有 DSH 时 smoke 自动跳过建会话段)。
|
|
614
617
|
|
|
615
618
|
其中 **519 项属于客户端注册器套件**(`setup` 41、`removal-scope` 24、`config-safety` 406、`real-configs` 48;九种齐全时 555 项)—— 0.3 的活其实都在这里。
|
|
616
619
|
|
|
617
|
-
需要模型的套件(`smoke` 29、`boundary` 46、`integration` 30、`async` 16、`sentinel` 36、`timeout` 38、`lock` 79、`cycle` 36、`concurrency` 31、`capability` 22、`workspace-effect` 24、`acceptance` 36、`multi` 19、`permission` 11、`list` 13、`reasoning-check` 8)合计 474 项,**最近一次完整实测在 0.3.
|
|
620
|
+
需要模型的套件(`smoke` 29、`boundary` 46、`integration` 30、`async` 16、`sentinel` 36、`timeout` 38、`lock` 79、`cycle` 36、`concurrency` 31、`capability` 22、`workspace-effect` 24、`acceptance` 36、`multi` 19、`permission` 11、`list` 13、`reasoning-check` 8)合计 474 项,**最近一次完整实测在 0.3.8** —— 它们要可用 provider,发版前请自己重跑一遍:`node test/run.mjs --all`。`acceptance` 在没有 IDA MCP(`mcp__ida__*`)时会明确 **skip**。
|
|
618
621
|
|
|
619
622
|
> 三个总数是刻意分开的:`node test/run.mjs`(815/851)、CI 离线 job(786/822,不含 smoke)、需要模型的集合(名义 474)。数字取各套件自己打印的汇总,不在这里手抄;不要把一个数字套到另一个 runner 上。
|
|
620
623
|
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Moving to a new machine / first-time setup (English)
|
|
2
|
+
|
|
3
|
+
This is the short English version of `USAGE-MIGRATION.md`. It covers a fresh
|
|
4
|
+
install, registering the MCP server with your client, and the checks worth
|
|
5
|
+
doing before you trust it with real work.
|
|
6
|
+
|
|
7
|
+
## 1. Prerequisites
|
|
8
|
+
|
|
9
|
+
| Item | Requirement |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Node.js | **≥ 22.15** (`zstdDecompressSync` is required) |
|
|
12
|
+
| DSH | DeepSeek Harness installed and able to answer a normal chat turn |
|
|
13
|
+
| Provider | A model route configured in DSH, with credentials available through `~/.dsh/.credentials.yaml` or environment variables |
|
|
14
|
+
|
|
15
|
+
> The order matters. This server does **not** ship a provider or credentials.
|
|
16
|
+
> On first start it copies the model route from an existing DSH profile. If DSH
|
|
17
|
+
> itself is not configured, the first call fails with a provider error.
|
|
18
|
+
|
|
19
|
+
## 2. Install and register
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g dsh-any-agent
|
|
23
|
+
|
|
24
|
+
# Preview only: reads configs, writes nothing
|
|
25
|
+
dsh-any-agent-setup
|
|
26
|
+
|
|
27
|
+
# Apply
|
|
28
|
+
dsh-any-agent-setup --yes
|
|
29
|
+
|
|
30
|
+
# Limit to some clients, or choose a permission tier
|
|
31
|
+
dsh-any-agent-setup --yes --only cursor,zed
|
|
32
|
+
dsh-any-agent-setup --yes --permission workspace-write
|
|
33
|
+
|
|
34
|
+
# Remove only this server's entry
|
|
35
|
+
dsh-any-agent-setup --remove --yes
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Supported clients: **Claude Code, Claude Desktop, Codex, Cursor, Windsurf,
|
|
39
|
+
Zed, Gemini CLI, opencode, VS Code**. Clients that are not installed are
|
|
40
|
+
reported as skipped, not failed.
|
|
41
|
+
|
|
42
|
+
The writer is deliberately conservative:
|
|
43
|
+
|
|
44
|
+
- preview mode never writes and never starts a child process;
|
|
45
|
+
- every changed file is backed up as `<file>.bak-dsh-<stamp>`;
|
|
46
|
+
- JSON/JSONC/TOML edits are text-level and only touch the
|
|
47
|
+
`dsh-any-agent` entry (indentation, key order, CRLF, BOM and comments are
|
|
48
|
+
preserved);
|
|
49
|
+
- malformed or read-only configs are refused rather than overwritten;
|
|
50
|
+
- a second `--yes` is a no-op;
|
|
51
|
+
- `setup` does **not** invoke client CLIs such as `claude mcp get` (that can
|
|
52
|
+
make Claude Code rewrite `~/.claude.json`).
|
|
53
|
+
|
|
54
|
+
## 3. Manual configuration (optional)
|
|
55
|
+
|
|
56
|
+
If your client is not covered by setup, add a stdio MCP server. For example:
|
|
57
|
+
|
|
58
|
+
Codex `~/.codex/config.toml`:
|
|
59
|
+
|
|
60
|
+
```toml
|
|
61
|
+
[mcp_servers.dsh-any-agent]
|
|
62
|
+
command = "dsh-any-agent"
|
|
63
|
+
args = []
|
|
64
|
+
startup_timeout_sec = 20.0
|
|
65
|
+
tool_timeout_sec = 120.0
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Generic JSON client:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"mcpServers": {
|
|
73
|
+
"dsh-any-agent": {
|
|
74
|
+
"command": "dsh-any-agent",
|
|
75
|
+
"args": []
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`setup --yes` writes the absolute node path, the entry file, and
|
|
82
|
+
`DSH_MCP_PERMISSION` / `DSH_MCP_LOG`; the examples above assume
|
|
83
|
+
`dsh-any-agent` is on `PATH`.
|
|
84
|
+
|
|
85
|
+
## 4. First start and profile bootstrap
|
|
86
|
+
|
|
87
|
+
On first start the server creates `~/.dsh/profiles/dsh-mcp/` and copies the
|
|
88
|
+
model route from an existing DSH profile (`home` → `desktop` → `web` →
|
|
89
|
+
`headless` → `acp`, first usable one). It uses a built-in zero-dependency YAML
|
|
90
|
+
subset parser, so no extra npm package is needed.
|
|
91
|
+
|
|
92
|
+
What is copied: `apiKeyEnv`, `baseURL`, `api`, `models`, reasoning metadata.
|
|
93
|
+
What is stripped: literal API keys, nested `headers`, and URL userinfo. The
|
|
94
|
+
generated profile includes the three permission presets but **never**
|
|
95
|
+
`defaultPreset` (that would override the permission tier at session creation).
|
|
96
|
+
|
|
97
|
+
Credentials remain in DSH's own credential store; this project never owns them.
|
|
98
|
+
Set `DSH_MCP_BOOTSTRAP=0` to disable profile writing entirely, or
|
|
99
|
+
`DSH_MCP_ROUTE_SOURCE=<profile>` / `__home__` to pin the route source.
|
|
100
|
+
|
|
101
|
+
## 5. Permission tiers
|
|
102
|
+
|
|
103
|
+
| Tier | Meaning |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `read-only` | DSH's sandbox is read-only; approvals are forced to `auto-deny` |
|
|
106
|
+
| `workspace-write` | Writes are limited to the workspace by DSH's sandbox |
|
|
107
|
+
| `danger-full-access` | No workspace sandbox |
|
|
108
|
+
|
|
109
|
+
The server's raw default is `danger-full-access` when `DSH_MCP_PERMISSION` is
|
|
110
|
+
not set; `setup` writes `workspace-write` into the client config. Out-of-
|
|
111
|
+
workspace approval requests default to `auto-allow`; pass `on_approval=ask`
|
|
112
|
+
when creating a session if you want `dsh_approval_decide` to adjudicate them.
|
|
113
|
+
|
|
114
|
+
`read-only` is a hard boundary at this layer: `read-only + auto-allow/ask` is
|
|
115
|
+
rejected, and the server reads back the session's recorded permission tier
|
|
116
|
+
after create/resume. External MCP tools mounted in DSH are outside DSH's
|
|
117
|
+
sandbox; read `USAGE-NOTES.en.md` before using them with untrusted data.
|
|
118
|
+
|
|
119
|
+
## 6. Verify
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
dsh-any-agent --version
|
|
123
|
+
dsh-any-agent-setup --help
|
|
124
|
+
dsh-any-agent-setup # preview should show your clients
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
In the client, ask the agent to call `dsh_start` with a small project
|
|
128
|
+
directory, then `dsh_send` a short prompt and `dsh_get` the result. If the
|
|
129
|
+
client cannot see the server, restart the client after setup.
|
|
130
|
+
|
|
131
|
+
## 7. Common problems
|
|
132
|
+
|
|
133
|
+
- **`DSH CLI entry not found`** — set `DSH_BIN` to
|
|
134
|
+
`.../node_modules/@deepseek-ai/dsh/lib/bin.js`, or install DSH in a location
|
|
135
|
+
the server can discover.
|
|
136
|
+
- **`no adapter registered for provider` / no API key** — DSH itself is not
|
|
137
|
+
configured, or the profile route was not copied. Open DSH once, configure a
|
|
138
|
+
model, then restart the MCP server.
|
|
139
|
+
- **`session ... is already owned by an active write handle`** — the session
|
|
140
|
+
is held by another process (often the DSH GUI). Use `dsh_status` to see
|
|
141
|
+
`lock_holder`; use `dsh_release` on the other instance or `dsh_takeover`
|
|
142
|
+
when the holder is a stale dsh-any-agent process. Never kill a GUI process.
|
|
143
|
+
- **Nothing happens when waiting for completion** — use the returned
|
|
144
|
+
`sentinel_file`; a turn that is interrupted by a process exit may not land
|
|
145
|
+
one. Inspect the workspace and re-dispatch.
|
|
146
|
+
- **Old state after upgrading** — the registry moved from
|
|
147
|
+
`<repo>/.state/conversations.json` to
|
|
148
|
+
`$DSH_HOME/.dsh-any-agent/conversations.json`; the first 0.3.x start
|
|
149
|
+
migrates it automatically. Use `DSH_MCP_STATE` to override.
|
|
150
|
+
|
|
151
|
+
## 8. Upgrade / rollback
|
|
152
|
+
|
|
153
|
+
`npm install -g dsh-any-agent@latest` upgrades the server. Client configs are
|
|
154
|
+
not rewritten by an upgrade; run `dsh-any-agent-setup` again only if you want
|
|
155
|
+
to refresh the entry or permission env. `dsh-any-agent-restore` can restore a
|
|
156
|
+
client config from a `.bak-dsh-*` backup.
|
|
157
|
+
|
|
158
|
+
For the full Chinese guide, environment-variable reference, write-lock
|
|
159
|
+
measurements and website deployment notes, see `USAGE-MIGRATION.md`,
|
|
160
|
+
`README.md` and `USAGE-NOTES.en.md`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-any-agent",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Drive DeepSeek Harness (DSH) as a long-lived coding agent from any MCP client — Claude Code, Claude Desktop, Codex, Cursor, Windsurf, Zed, Gemini CLI, opencode, VS Code. Resume-aware, interruptible, approval-capable, and it only ever touches the one config entry it owns.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"USAGE-NOTES.en.md",
|
|
37
37
|
"USAGE-NOTES.md",
|
|
38
38
|
"USAGE-MIGRATION.md",
|
|
39
|
+
"USAGE-MIGRATION.en.md",
|
|
39
40
|
"CHANGELOG.md",
|
|
40
41
|
"LICENSE",
|
|
41
42
|
"DESIGN.md",
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
"start": "node ./bin/dsh-any-agent.mjs",
|
|
46
47
|
"setup": "node ./bin/setup.mjs",
|
|
47
48
|
"test": "node ./test/run.mjs",
|
|
49
|
+
"test:all": "node ./test/run.mjs --all",
|
|
48
50
|
"test:smoke": "node ./test/smoke.mjs",
|
|
49
51
|
"test:guards": "node ./test/guards.mjs",
|
|
50
52
|
"test:prune": "node ./test/prune.mjs",
|
package/src/workspace.mjs
CHANGED
|
@@ -19,6 +19,7 @@ import { copyFileSync, createReadStream, readFileSync, writeFileSync, existsSync
|
|
|
19
19
|
import { randomUUID } from 'node:crypto';
|
|
20
20
|
import { basename, dirname, isAbsolute, join, relative, sep } from 'node:path';
|
|
21
21
|
import { tmpdir } from 'node:os';
|
|
22
|
+
import { StringDecoder } from 'node:string_decoder';
|
|
22
23
|
import { createZstdDecompress, zstdDecompressSync } from 'node:zlib';
|
|
23
24
|
import { DSH_HOME, REGISTER_WORKSPACE } from './config.mjs';
|
|
24
25
|
|
|
@@ -245,6 +246,7 @@ export async function readHeaderAsync(file, { timeoutMs = 5000, maxHeaderBytes =
|
|
|
245
246
|
let settled = false;
|
|
246
247
|
let buf = '';
|
|
247
248
|
let timer = null;
|
|
249
|
+
const decoder = new StringDecoder('utf8');
|
|
248
250
|
const rs = createReadStream(file);
|
|
249
251
|
const zs = createZstdDecompress();
|
|
250
252
|
const finish = (value) => {
|
|
@@ -268,12 +270,15 @@ export async function readHeaderAsync(file, { timeoutMs = 5000, maxHeaderBytes =
|
|
|
268
270
|
rs.on('error', () => finish(null));
|
|
269
271
|
zs.on('error', () => finish(null));
|
|
270
272
|
zs.on('data', (chunk) => {
|
|
271
|
-
|
|
273
|
+
// 用 StringDecoder 处理跨 chunk 的多字节 UTF-8(中文/emoji 路径),
|
|
274
|
+
// 避免 chunk.toString() 把字符截成乱码。
|
|
275
|
+
buf += decoder.write(chunk);
|
|
272
276
|
const nl = buf.search(/\r?\n/);
|
|
273
277
|
if (nl >= 0) parseLine(buf.slice(0, nl));
|
|
274
278
|
else if (buf.length > maxHeaderBytes) finish(null);
|
|
275
279
|
});
|
|
276
280
|
zs.on('end', () => {
|
|
281
|
+
buf += decoder.end();
|
|
277
282
|
const line = buf.split(/\r?\n/).find(Boolean);
|
|
278
283
|
if (line) parseLine(line);
|
|
279
284
|
else finish(null);
|