dsh-baton-mcp 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,7 +37,7 @@ Codex and Claude take turns in the same Harness session, and every message is la
37
37
  ## Quick start
38
38
 
39
39
  <p align="center">
40
- <img src="./assets/readme/install.svg" width="100%" alt="Step 1: run npx -y dsh-baton-mcp setup. Step 2: in Harness open Plugins, Add plugin, paste, Install, Enable now. Step 3: in a new chat, ask for dsh_list_workspaces">
40
+ <img src="./assets/readme/install.svg" width="100%" alt="Step 1: run npx -y dsh-baton-mcp setup. Step 2: in Harness open Plugins, Add plugin, enter dsh-baton-host from the npm registry, Install, Enable now. Step 3: in a new chat, ask for dsh_list_workspaces">
41
41
  </p>
42
42
 
43
43
  Requires DeepSeek Harness ≥ 0.2.1-rc.2 (signed in), Node.js ≥ 22.15. On Windows, see [WINDOWS.md](WINDOWS.md).
@@ -50,9 +50,9 @@ npx -y dsh-baton-mcp setup
50
50
 
51
51
  dsh-baton has no dependencies. `setup` copies itself to `~/.dsh-baton/app`, a folder that stays put (npx's cache does not), and registers the MCP server once, user-wide, for Claude Code and Codex: every new conversation, in any folder, has the `dsh_*` tools. It writes `~/.claude.json` and `~/.codex/config.toml` directly (a backup of each is kept as `*.bak-dsh-baton`), so it also works when only the desktop apps are installed and `claude` / `codex` are not on your `PATH`. Running it again is safe.
52
52
 
53
- **2. Paste in Harness.** `setup` copies the plugin folder path to your clipboard:
53
+ **2. Add the plugin in Harness**, by its npm package name (`setup` copies it to your clipboard):
54
54
 
55
- **Plugins** (插件) → **Add plugin** (添加插件) → paste → **Install** (安装) → **Enable now** (立即启用)
55
+ **Plugins** (插件) → **Add plugin** (添加插件) → registry **Official npm registry** → `dsh-baton-host` → **Install** (安装) → **Enable now** (立即启用)
56
56
 
57
57
  **3. Check.** Start a **new** conversation in Claude Code or Codex and ask it to call `dsh_list_workspaces`. It lists your Harness workspaces.
58
58
 
@@ -63,13 +63,18 @@ dsh-baton has no dependencies. `setup` copies itself to `~/.dsh-baton/app`, a fo
63
63
  - **Codex** waits inside `dsh_wait`, up to 270 s per call, just under its 300 s tool timeout. An unfinished wait returns only the state, so Codex calls again without summarising. Codex gets no `wait_command`: its terminal cannot wake it, so it would poll.
64
64
  - Codex asks you to approve MCP tool calls: approve the `dsh-baton` tools. For unattended `codex exec` runs, add `--approve-for-me`.
65
65
 
66
- **Updating:** run `npx -y dsh-baton-mcp@latest setup` again, then restart Harness to load plugin changes; new conversations pick up MCP server changes.
66
+ **Updating:** the MCP server and the plugin update separately, and both carry the same version.
67
+ - MCP server: `npx -y dsh-baton-mcp@latest setup`. New conversations use it.
68
+ - Plugin: Harness offers an update button only for its own official plugins, so for this one: Plugins → dsh-baton-host → **Uninstall**, then **Add plugin** → `dsh-baton-host` again.
69
+ - `setup` says when the two are out of step, and so does the first tool call that notices it.
67
70
 
68
- **Removing:** `npx -y dsh-baton-mcp setup --remove`, then Harness → Plugins → dsh-baton-host → Uninstall, then `setup --remove` once more to delete `~/.dsh-baton/app`.
71
+ **Removing:** Harness → Plugins → dsh-baton-host → **Uninstall**, and `npx -y dsh-baton-mcp setup --remove`. That removes the MCP entries and `~/.dsh-baton/app`; run records stay in `~/.dsh-baton` until you delete it.
69
72
 
70
- **Upgrading from dsh-bridge**: run `setup` as above. It replaces the old `dsh-bridge` MCP entries; in Harness, uninstall `dsh-bridge-host`, then add the new path. `DSH_BRIDGE_*` variables and an existing `~/.dsh-bridge` folder keep working for now. Tools get a new prefix (`mcp__dsh-baton__…`), so update any permission allowlists.
73
+ **Upgrading from dsh-bridge**: run `setup` as above. It replaces the old `dsh-bridge` MCP entries; in Harness, uninstall `dsh-bridge-host`, then add `dsh-baton-host` as in step 2. `DSH_BRIDGE_*` variables and an existing `~/.dsh-bridge` folder keep working for now. Tools get a new prefix (`mcp__dsh-baton__…`), so update any permission allowlists.
71
74
 
72
- **From source** (to follow `main` or to change the code): `git clone https://github.com/JialaoLiu/dsh-baton.git` and `node dsh-baton/src/cli.mjs setup`. setup then registers the clone itself; update with `git pull`.
75
+ **Installed from a local folder before 0.4?** Earlier versions had you paste `~/.dsh-baton/app/host`. That still works, but it does not update with npm: uninstall it and add `dsh-baton-host` by name. `setup` points this out.
76
+
77
+ **From source** (to follow `main` or to change the code): `git clone https://github.com/JialaoLiu/dsh-baton.git` and `node dsh-baton/src/cli.mjs setup`. setup then registers the clone itself and has you add the plugin from the clone's `host` folder (Add plugin → paste the path it copies), so plugin changes run before they are published; update with `git pull`.
73
78
 
74
79
  <details>
75
80
  <summary>Manual registration and the Claude desktop app</summary>
package/README.zh-CN.md CHANGED
@@ -37,7 +37,7 @@ Codex 和 Claude 轮流往同一个 Harness 对话发消息,每条都标明是
37
37
  ## 快速上手
38
38
 
39
39
  <p align="center">
40
- <img src="./assets/readme/zh/install.svg" width="100%" alt="第一步:运行 npx -y dsh-baton-mcp setup。第二步:Harness → 插件 → 添加插件 → 粘贴 → 安装 → 立即启用。第三步:新开对话,让它调用 dsh_list_workspaces">
40
+ <img src="./assets/readme/zh/install.svg" width="100%" alt="第一步:运行 npx -y dsh-baton-mcp setup。第二步:Harness → 插件 → 添加插件 → 从 npm 输入 dsh-baton-host → 安装 → 立即启用。第三步:新开对话,让它调用 dsh_list_workspaces">
41
41
  </p>
42
42
 
43
43
  需要:DeepSeek Harness ≥ 0.2.1-rc.2 并已登录;Node.js ≥ 22.15。Windows 见 [WINDOWS.md](WINDOWS.md)。
@@ -50,9 +50,9 @@ npx -y dsh-baton-mcp setup
50
50
 
51
51
  dsh-baton 没有任何依赖。`setup` 会把自己复制到 `~/.dsh-baton/app` 这个固定的文件夹(npx 的缓存目录会变),然后在用户级别给 Claude Code 和 Codex 注册一次 MCP 服务器:之后在任何文件夹新开的对话都有 `dsh_*` 工具。它直接写 `~/.claude.json` 和 `~/.codex/config.toml`(各留一份 `*.bak-dsh-baton` 备份),所以只装了桌面应用、`claude` / `codex` 不在 `PATH` 里也能用。重复运行也没问题。
52
52
 
53
- **2. 在 Harness 里粘贴。**`setup` 已经把插件文件夹路径复制到剪贴板:
53
+ **2. 在 Harness 里按包名添加插件**(`setup` 已经把包名复制到剪贴板):
54
54
 
55
- **插件** → **添加插件** → 粘贴 → **安装** → **立即启用**
55
+ **插件** → **添加插件** → 来源选 **Official npm registry** → 输入 `dsh-baton-host` → **安装** → **立即启用**
56
56
 
57
57
  **3. 检查。**在 Claude Code 或 Codex 里**新开**一个对话,让它调用 `dsh_list_workspaces`,应该会列出你的 Harness 工作区。
58
58
 
@@ -63,13 +63,18 @@ dsh-baton 没有任何依赖。`setup` 会把自己复制到 `~/.dsh-baton/app`
63
63
  - **Codex** 在 `dsh_wait` 里等待,每次最多 270 秒,刚好低于它 300 秒的工具超时。没做完时只返回状态,Codex 会直接再调用,不会去总结进度。Codex 不会收到 `wait_command`:它的终端无法在命令结束时唤醒它,只能轮询。
64
64
  - Codex 调用 MCP 工具时会请你批准,批准 `dsh-baton` 的工具即可;无人值守的 `codex exec` 加上 `--approve-for-me`。
65
65
 
66
- **更新:** 再运行一次 `npx -y dsh-baton-mcp@latest setup`,然后重启 Harness 以加载插件改动;新开的对话会用上 MCP 服务器的改动。
66
+ **更新:** MCP 服务器和插件分开更新,两者版本号相同。
67
+ - MCP 服务器:`npx -y dsh-baton-mcp@latest setup`,新开的对话就会用上。
68
+ - 插件:Harness 只给官方插件提供"更新"按钮,所以这个插件要:插件 → dsh-baton-host → **卸载**,再**添加插件** → `dsh-baton-host`。
69
+ - 两边版本对不上时,`setup` 会提示,第一次发现不一致的工具调用也会提示。
67
70
 
68
- **卸载:** `npx -y dsh-baton-mcp setup --remove`,再到 Harness → 插件 → dsh-baton-host → 卸载,最后再运行一次 `setup --remove` 删除 `~/.dsh-baton/app`。
71
+ **卸载:** Harness → 插件 → dsh-baton-host → **卸载**,再运行 `npx -y dsh-baton-mcp setup --remove`。它会删掉 MCP 注册和 `~/.dsh-baton/app`;运行记录留在 `~/.dsh-baton`,不需要的话自己删掉。
69
72
 
70
- **从 dsh-bridge 升级:**照上面运行 `setup`。它会替换掉旧的 `dsh-bridge` MCP 注册;在 Harness 里先卸载 `dsh-bridge-host`,再添加新路径。`DSH_BRIDGE_*` 环境变量和已有的 `~/.dsh-bridge` 文件夹暂时继续可用。工具前缀变成 `mcp__dsh-baton__…`,权限白名单里写了旧前缀的要改一下。
73
+ **从 dsh-bridge 升级:**照上面运行 `setup`。它会替换掉旧的 `dsh-bridge` MCP 注册;在 Harness 里先卸载 `dsh-bridge-host`,再按第 2 步添加 `dsh-baton-host`。`DSH_BRIDGE_*` 环境变量和已有的 `~/.dsh-bridge` 文件夹暂时继续可用。工具前缀变成 `mcp__dsh-baton__…`,权限白名单里写了旧前缀的要改一下。
71
74
 
72
- **从源码安装**(想跟进 `main` 或改代码):`git clone https://github.com/JialaoLiu/dsh-baton.git`,再运行 `node dsh-baton/src/cli.mjs setup`。这时 setup 注册的就是克隆目录本身,更新用 `git pull`。
75
+ **0.4 之前从本地文件夹装的插件:**旧版本让你粘贴 `~/.dsh-baton/app/host`。这样装的仍然能用,但不会跟着 npm 更新:卸载它,再按包名添加 `dsh-baton-host`。`setup` 会提示这一点。
76
+
77
+ **从源码安装**(想跟进 `main` 或改代码):`git clone https://github.com/JialaoLiu/dsh-baton.git`,再运行 `node dsh-baton/src/cli.mjs setup`。这时 setup 注册的就是克隆目录本身,插件也从克隆目录的 `host` 文件夹添加(添加插件 → 粘贴它复制的路径),这样插件改动在发布前就能跑起来;更新用 `git pull`。
73
78
 
74
79
  <details>
75
80
  <summary>手动注册与 Claude 桌面应用</summary>
package/WINDOWS.md CHANGED
@@ -26,17 +26,19 @@ Requires DeepSeek Harness ≥ 0.2.1-rc.2 and Node.js ≥ 22.15. In PowerShell:
26
26
  npx -y dsh-baton-mcp setup
27
27
  ```
28
28
 
29
- `setup` copies itself to `%USERPROFILE%\.dsh-baton\app` (npx's cache is not a stable place) and registers the MCP server once, user-wide, for Claude Code (`%USERPROFILE%\.claude.json`) and Codex (`%USERPROFILE%\.codex\config.toml`), with the absolute path of `node`. It edits the files directly, so it works with the desktop apps alone: their `claude.exe` / `codex.exe` are usually not on `PATH`. It also copies the plugin path to the clipboard.
29
+ `setup` copies itself to `%USERPROFILE%\.dsh-baton\app` (npx's cache is not a stable place) and registers the MCP server once, user-wide, for Claude Code (`%USERPROFILE%\.claude.json`) and Codex (`%USERPROFILE%\.codex\config.toml`), with the absolute path of `node`. It edits the files directly, so it works with the desktop apps alone: their `claude.exe` / `codex.exe` are usually not on `PATH`. It also copies the plugin's package name to the clipboard.
30
30
 
31
- Then, in Harness: **Plugins / 插件** → **Add plugin / 添加插件** → paste the path it copied (`%USERPROFILE%\.dsh-baton\app\host`) → **Install / 安装** → **Enable now / 立即启用**. The pipe appears right away (see [Verify](#verify)); if it does not, restart Harness.
31
+ Then, in Harness: **Plugins / 插件** → **Add plugin / 添加插件** → registry **Official npm registry** → `dsh-baton-host` → **Install / 安装** → **Enable now / 立即启用**. The pipe appears right away (see [Verify](#verify)); if it does not, restart Harness.
32
32
 
33
33
  Nothing else to configure: Claude Code waits for a run in the background (Git Bash runs the `wait_command` that `dsh_send` returns), and Codex waits up to 270 s per `dsh_wait` call, under its 300 s tool timeout. Approve the `dsh-baton` tools when Codex asks; for unattended `codex exec`, add `--approve-for-me`.
34
34
 
35
- Remove: `npx -y dsh-baton-mcp setup --remove`, then Harness → Plugins → dsh-baton-host → Uninstall, then `setup --remove` once more to delete the app folder.
35
+ Update: `npx -y dsh-baton-mcp@latest setup` for the MCP server; for the plugin, Harness → Plugins → dsh-baton-host → Uninstall, then Add plugin → `dsh-baton-host` again (Harness has no update button for non-official plugins).
36
36
 
37
- Upgrading from dsh-bridge: `setup` replaces the old MCP entries and reuses an existing `%USERPROFILE%\.dsh-bridge` (the app then goes to `.dsh-bridge\app`). Uninstall `dsh-bridge-host` in Harness, then add the path `setup` copied. With the hoisted profile layout, uninstalling may leave a `node_modules\dsh-bridge-host` link behind in `%USERPROFILE%\.dsh\profiles\desktop`; `setup --remove` deletes such a leftover link (old or new name) once the profile no longer lists the plugin.
37
+ Remove: Harness → Plugins → dsh-baton-host → Uninstall, and `npx -y dsh-baton-mcp setup --remove`.
38
38
 
39
- From source instead: `git clone https://github.com/JialaoLiu/dsh-baton.git C:\dev\dsh-baton` and `node C:\dev\dsh-baton\src\cli.mjs setup`; the plugin path is then `C:\dev\dsh-baton\host`.
39
+ Upgrading from dsh-bridge: `setup` replaces the old MCP entries and reuses an existing `%USERPROFILE%\.dsh-bridge` (the app then goes to `.dsh-bridge\app`). Uninstall `dsh-bridge-host` in Harness, then add `dsh-baton-host` by name. A plugin added earlier from `.dsh-baton\app\host` (0.3) also works, but `setup` suggests swapping it for the npm package, which is the one that gets updates. With the hoisted profile layout, uninstalling may leave a `node_modules\dsh-bridge-host` link behind in `%USERPROFILE%\.dsh\profiles\desktop`; `setup --remove` deletes such a leftover link (old or new name) once the profile no longer lists the plugin.
40
+
41
+ From source instead: `git clone https://github.com/JialaoLiu/dsh-baton.git C:\dev\dsh-baton` and `node C:\dev\dsh-baton\src\cli.mjs setup`; setup then has you add the plugin from `C:\dev\dsh-baton\host` (Add plugin → paste the path it copies).
40
42
 
41
43
  ### If the Plugins page cannot uninstall or install it
42
44
 
@@ -107,7 +109,7 @@ The suite runs on Windows with named pipes. Two POSIX-only checks are skipped: f
107
109
 
108
110
  - **套接字改为命名管道。** Windows 上 Node 不能监听 Unix 套接字文件,所以同一路径被映射成按用户区分的命名管道 `\\.\pipe\dsh-baton-<哈希>`。插件和 MCP 两边算法一致,`DSH_BATON_SOCKET` 仍然可用,Harness 退出后管道自动消失。
109
111
  - **headless 用 Harness 自带的 CLI。** Harness ≥ 0.2.1 自带 `resources\runtime\cli\bin\dsh.cmd`;更早的版本只有打包在 `app.asar` 里的 CLI,由 Harness 自己的 exe 以 Node 模式运行。会按顺序自动查找:`DSH_BIN`、`PATH` 里的 `dsh`、默认安装位置,以及注册表里的自定义安装目录。
110
- - **插件用 Harness 插件页安装。** 插件 → 添加插件 → 粘贴 `%USERPROFILE%\.dsh-baton\app\host` → 安装 → 立即启用(`setup` 已把路径复制到剪贴板)。
112
+ - **插件用 Harness 插件页按包名安装。** 插件 → 添加插件 → 来源选 Official npm registry → 输入 `dsh-baton-host` → 安装 → 立即启用(`setup` 已把包名复制到剪贴板)。更新插件要先卸载再重新添加,Harness 只给官方插件提供更新按钮。
111
113
  - **一条命令注册 MCP。** `npx -y dsh-baton-mcp setup` 把自己复制到 `%USERPROFILE%\.dsh-baton\app`,再直接写 Claude Code 和 Codex 的用户级配置(用 `node` 的绝对路径),桌面版的 `claude` / `codex` 不在 `PATH` 里也没关系。之后新开对话就有 `dsh_*` 工具;Codex 每次最多等 270 秒,不用再配超时。
112
114
  - **插件页卸不掉或装不上时**(`ERR_PNPM_UNEXPECTED_STORE`,或提示"该插件已安装"):是旧版 Harness 装 profile 时用了另一个 pnpm store。一次性修好:从菜单退出 Harness,把 `%USERPROFILE%\.dsh\profiles\desktop\node_modules` 改名备份,用 Harness 自带的 pnpm 运行 `install --frozen-lockfile`(不加 `--store-dir`;`$app` 改成你的安装目录,比如 `E:\Software\DeepSeek Harness`),再启动 Harness,插件页的卸载和添加就正常了;如果插件被关掉了,记得重新打开。
113
115
  - **headless 需要独立凭据。** 要么登录账户,要么设置 `DEEPSEEK_API_KEY`。桌面版里保存的 Key,headless CLI 读不到。
package/host/README.md CHANGED
@@ -1,14 +1,16 @@
1
1
  # dsh-baton-host
2
2
 
3
- DeepSeek Harness plugin for [dsh-baton](../README.md). It runs inside the Harness host (desktop app or `dsh web`) and serves a local, owner-only Unix socket (`~/.dsh-baton/host.sock`; a per-user named pipe on Windows, see [WINDOWS.md](../WINDOWS.md)). Through it, an MCP client can list and create workspaces, create sessions, continue a specific session, and wait for its turn to finish. All of this goes through Harness's own session controller, so the messages show up live in the Harness UI.
3
+ DeepSeek Harness plugin for [dsh-baton](https://github.com/JialaoLiu/dsh-baton#readme). It runs inside the Harness host (desktop app or `dsh web`) and serves a local, owner-only Unix socket (`~/.dsh-baton/host.sock`; a per-user named pipe on Windows, see [WINDOWS.md](https://github.com/JialaoLiu/dsh-baton/blob/main/WINDOWS.md)). Through it, an MCP client can list and create workspaces, create sessions, continue a specific session, and wait for its turn to finish. All of this goes through Harness's own session controller, so the messages show up live in the Harness UI.
4
4
 
5
- DeepSeek Harness 插件,配合 [dsh-baton](../README.zh-CN.md) 使用。它运行在 Harness 内部,只开一个当前用户才能访问的本地套接字,让 MCP 客户端能新建工作区和对话、续接指定对话、等待任务完成。所有操作都走 Harness 官方会话服务,界面实时可见。
5
+ DeepSeek Harness 插件,配合 [dsh-baton](https://github.com/JialaoLiu/dsh-baton/blob/main/README.zh-CN.md) 使用。它运行在 Harness 内部,只开一个当前用户才能访问的本地套接字,让 MCP 客户端能新建工作区和对话、续接指定对话、等待任务完成。所有操作都走 Harness 官方会话服务,界面实时可见。
6
6
 
7
7
  ## Install / 安装
8
8
 
9
- Harness → Plugins / 插件 → Add plugin / 添加插件 → `dsh-baton-host` → Install / 安装 → Enable now / 立即应用
9
+ Harness → Plugins / 插件 → Add plugin / 添加插件 → registry Official npm registry → `dsh-baton-host` → Install / 安装 → Enable now / 立即启用
10
10
 
11
- Then connect the MCP server / 然后接入 MCP 服务器: see [dsh-baton](../README.md).
11
+ Update / 更新: uninstall, then add it again / 先卸载再重新添加. Keep it on the same version as `dsh-baton-mcp` / 版本与 `dsh-baton-mcp` 保持一致.
12
+
13
+ Then connect the MCP server / 然后接入 MCP 服务器: see [dsh-baton](https://github.com/JialaoLiu/dsh-baton#readme).
12
14
 
13
15
  ## Socket protocol / 套接字协议
14
16
 
package/host/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-baton-host",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "DeepSeek Harness plugin for dsh-baton: takes the baton from Claude Code or Codex over a local, owner-only control socket, runs it in a specific session through the host's own session controller, and hands the result back when the turn is done.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -53,5 +53,8 @@
53
53
  "url": "git+https://github.com/JialaoLiu/dsh-baton.git",
54
54
  "directory": "host"
55
55
  },
56
- "homepage": "https://github.com/JialaoLiu/dsh-baton#readme"
56
+ "homepage": "https://github.com/JialaoLiu/dsh-baton#readme",
57
+ "scripts": {
58
+ "prepublishOnly": "node ../scripts/version.mjs"
59
+ }
57
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-baton-mcp",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Pass the baton from Claude Code, Codex or any MCP client to a local DeepSeek Harness: an MCP server that hands off tasks, continues a specific session, shows the run live in Harness and hands the result back when it is done.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,7 +35,8 @@
35
35
  "license": "MIT",
36
36
  "scripts": {
37
37
  "test": "node --test --test-concurrency=1 tests/*.test.mjs",
38
- "test:live": "node tests/live.mjs"
38
+ "test:live": "node tests/live.mjs",
39
+ "prepublishOnly": "node scripts/version.mjs"
39
40
  },
40
41
  "repository": {
41
42
  "type": "git",
package/src/core.mjs CHANGED
@@ -164,6 +164,8 @@ export async function hostAvailable() {
164
164
  }
165
165
  }
166
166
 
167
+ export const hostVersionSeen = () => hostVersion
168
+
167
169
  // The plugin and the MCP server update separately (Harness and npx), so they can drift.
168
170
  // A different major.minor gets a note asking to update the older side; patch releases mix.
169
171
  const minorOf = (v) => String(v).split('.').slice(0, 2).join('.')
package/src/setup.mjs CHANGED
@@ -5,7 +5,7 @@ import fs from 'node:fs'
5
5
  import os from 'node:os'
6
6
  import path from 'node:path'
7
7
  import { execFileSync } from 'node:child_process'
8
- import { ROOT, config, hostAvailable } from './core.mjs'
8
+ import { ROOT, config, hostAvailable, hostVersionSeen as versionOfHost, versionWarning } from './core.mjs'
9
9
 
10
10
  const NAME = 'dsh-baton'
11
11
  // The name before the rename: setup removes its entries so the tools are not listed twice.
@@ -110,6 +110,38 @@ export function cleanStalePluginLinks(profile = path.join(config.dshHome, 'profi
110
110
  return { removed, failed }
111
111
  }
112
112
 
113
+ // What setup says about the Harness plugin. The plugin is installed in Harness by its npm
114
+ // package name; a checkout of this repo (setup run from a git clone) is the exception and
115
+ // links its own host folder, so plugin changes can be tried before they are published.
116
+ export function pluginSteps({ current, old }, running, hostDir, fromSource = fs.existsSync(path.join(ROOT, '.git'))) {
117
+ const isLink = (spec) => /^(link|file):/.test(spec ?? '')
118
+ const ok = fromSource ? pluginFrom(current, hostDir) : current && !isLink(current)
119
+ if (ok && !old && running) {
120
+ const warning = versionWarning(running)
121
+ return warning ? ['Harness plugin: running, but out of step.', ` ${warning}`] : [`Harness plugin: running (${running}).`]
122
+ }
123
+ const steps = ['Last step, in DeepSeek Harness:']
124
+ // The plugin was renamed: Harness cannot load the old entry once its folder holds the new name.
125
+ if (old) steps.push(' The plugin is installed under its old name: first Plugins (插件) → dsh-bridge-host → Uninstall (卸载).')
126
+ if (current && !ok) {
127
+ steps.push(isLink(current)
128
+ ? ` The plugin installed now comes from a local folder (${current.replace(/^(link|file):/, '')}): first Plugins (插件) → dsh-baton-host → Uninstall (卸载).`
129
+ : ' The plugin installed now comes from npm, not this checkout: first Plugins (插件) → dsh-baton-host → Uninstall (卸载).')
130
+ }
131
+ if (ok && !old) return ['Harness plugin: installed but not answering. Open Harness and check that dsh-baton-host is switched on in Plugins (插件).']
132
+ if (fromSource) {
133
+ const copied = copyToClipboard(hostDir)
134
+ steps.push(` Plugins (插件) → Add plugin (添加插件) → paste ${copied ? 'the path (already copied)' : 'this path'}: ${hostDir}`)
135
+ } else {
136
+ const copied = copyToClipboard(PLUGIN)
137
+ steps.push(` Plugins (插件) → Add plugin (添加插件) → registry: Official npm registry → package: ${PLUGIN}${copied ? ' (already copied)' : ''}`)
138
+ }
139
+ steps.push(' → Install (安装) → Enable now (立即启用)')
140
+ return steps
141
+ }
142
+
143
+ const PLUGIN = 'dsh-baton-host'
144
+
113
145
  const pluginFrom = (source, hostDir) => source === `link:${hostDir}` || source === `link:${hostDir.split(path.sep).join('/')}`
114
146
 
115
147
  // The node to register: the one on PATH when it is this same binary, since that path
@@ -190,21 +222,6 @@ export async function setup({ remove = false } = {}) {
190
222
  }
191
223
  lines.push('', 'MCP server registered user-wide: new conversations in Claude Code and Codex have the dsh_* tools.')
192
224
 
193
- const hostDir = path.join(root, 'host')
194
- const { current: source, old } = installedPlugins()
195
- const fromHere = pluginFrom(source, hostDir)
196
- const running = await hostAvailable()
197
- if (running && !old && (fromHere || !source)) {
198
- lines.push('', 'Harness plugin: running.')
199
- } else {
200
- const copied = copyToClipboard(hostDir)
201
- lines.push('', 'Last step, in DeepSeek Harness:')
202
- // The plugin was renamed: Harness cannot load the old entry once its folder holds the new name.
203
- if (old) lines.push(' The plugin is installed under its old name: first Plugins (插件) → dsh-bridge-host → Uninstall (卸载).')
204
- if (source && !fromHere) lines.push(` The plugin installed now comes from another folder (${source}): first Plugins (插件) → dsh-baton-host → Uninstall (卸载).`)
205
- lines.push(
206
- ` Plugins (插件) → Add plugin (添加插件) → paste ${copied ? 'the path (already copied)' : 'this path'}: ${hostDir}`,
207
- ' → Install (安装) → Enable now (立即启用)')
208
- }
225
+ lines.push('', ...pluginSteps(installedPlugins(), await hostAvailable() ? versionOfHost() : null, path.join(root, 'host')))
209
226
  return lines.join('\n')
210
227
  }