@tunnelbox/dsh-tunnelbox 0.1.10 → 0.1.16
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 +128 -128
- package/README.zh-CN.md +128 -128
- package/dist/index.mjs +68 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,128 +1,128 @@
|
|
|
1
|
-
# @tunnelbox/dsh-tunnelbox
|
|
2
|
-
|
|
3
|
-
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
4
|
-
|
|
5
|
-
**Official website:** [www.tunnelbox.top](https://www.tunnelbox.top)
|
|
6
|
-
|
|
7
|
-
**tunnelbox DeepSeek Harness (dsh) plugin:** run dsh on your computer and drive it from your phone — agents, sessions, tools, approvals, abort. It runs **inside the dsh (Cordis) process** and dials **out** to a relay only (no public IP, no port forwarding).
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
Phone app ──WSS──► relay ──WSS──► this plugin (inside dsh) ──ctx.agents/session/approval──► DeepSeek Harness
|
|
11
|
-
(dsh --profile tunnelbox)
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Quick start (install → run → pair → use)
|
|
15
|
-
|
|
16
|
-
Follow these steps once on a computer that has DeepSeek Harness installed.
|
|
17
|
-
|
|
18
|
-
### Step 0 — Prepare your phone
|
|
19
|
-
|
|
20
|
-
Install the tunnelbox App (Android & iOS) from the official website: **https://www.tunnelbox.top**
|
|
21
|
-
|
|
22
|
-
- Sign in / create an account when prompted.
|
|
23
|
-
|
|
24
|
-
### Step 1 — Install the plugin into a dsh profile
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
dsh plugin --profile tunnelbox add @tunnelbox/dsh-tunnelbox
|
|
28
|
-
dsh --profile tunnelbox --dump-config # optional: confirm the tunnelbox-dsh bundle layer
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Step 2 — Run dsh with the profile
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
dsh --profile tunnelbox
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
dsh starts the harness plus this plugin, which connects to the relay and prints a **pairing QR code + pairing code** in the terminal. Credentials are read automatically from `$DSH_HOME/.credentials.yaml` (default `~/.dsh/`).
|
|
38
|
-
|
|
39
|
-
### Step 3 — Pair with your phone
|
|
40
|
-
|
|
41
|
-
In the phone app tap **Scan to pair** and scan the QR (or type the pairing code manually). The code is single-use and valid for about 10 minutes.
|
|
42
|
-
|
|
43
|
-
- Once bound, later starts print "connected account — open the app and pick this computer" and do not refresh the code. To unbind, see the app settings.
|
|
44
|
-
|
|
45
|
-
### Step 4 — Use it from your phone
|
|
46
|
-
|
|
47
|
-
In the app, open this computer and you can start agents/sessions, send messages, watch streaming output, approve tool requests, answer structured questions, and abort a running session.
|
|
48
|
-
|
|
49
|
-
## Configuration
|
|
50
|
-
|
|
51
|
-
The plugin is configured through the profile's `cordis.yml` (fields below) or env vars.
|
|
52
|
-
|
|
53
|
-
| Field / env | Default | Description |
|
|
54
|
-
|---|---|---|
|
|
55
|
-
| `relayUrl` / `TUNNELBOX_RELAY_URL` | built-in default | tunnelbox relay address |
|
|
56
|
-
| `provider` | `deepseek-official` | LLM provider |
|
|
57
|
-
| `model` | `deepseek-v4-flash` | Model |
|
|
58
|
-
| `cwd` | `process.cwd()` | Agent working directory (sessions persist per-workspace) |
|
|
59
|
-
| `DSH_PERMISSION_MODE` | - | `danger-full-access` = full access (approval never prompts on the phone) |
|
|
60
|
-
|
|
61
|
-
Example profile overlay (`cordis.patch.yml`):
|
|
62
|
-
|
|
63
|
-
```yaml
|
|
64
|
-
- id: tunnelbox-dsh
|
|
65
|
-
config:
|
|
66
|
-
relayUrl: 'wss://chat.example.com'
|
|
67
|
-
model: 'deepseek-v4-flash'
|
|
68
|
-
cwd: 'D:/workspace/project'
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Capabilities
|
|
72
|
-
|
|
73
|
-
| Capability | Value | Notes |
|
|
74
|
-
|---|---|---|
|
|
75
|
-
| streaming | ✅ | dsh session events → live deltas |
|
|
76
|
-
| thinking | ✅ | `reasoning-delta` → thinking parts |
|
|
77
|
-
| permission | ✅ | dsh approval requests → phone approval card (timeout = fail-closed deny) |
|
|
78
|
-
| commands | ✅ | `/new`, `/help` |
|
|
79
|
-
| abort | ✅ | `agent.cancel` → phone stop button |
|
|
80
|
-
| questions | ✅ | `ask_user_question` tool → structured phone question card |
|
|
81
|
-
|
|
82
|
-
## Approvals & security
|
|
83
|
-
|
|
84
|
-
- Approval policy is governed by dsh's `approval` / `sandbox-policy` (default `workspace-write` + ask). With both the dsh web UI and your phone present, approvals/questions show on both — whoever answers first decides (the other side is cancelled automatically).
|
|
85
|
-
- `DSH_PERMISSION_MODE=danger-full-access` fully disables prompts (approval policy becomes `never`; no phone card).
|
|
86
|
-
- Don't expose sensitive project directories to an untrusted phone.
|
|
87
|
-
|
|
88
|
-
## Running multiple instances
|
|
89
|
-
|
|
90
|
-
Each `dsh --profile <name>` is an independent process, naturally isolated (own cwd/model/tools/approval policy):
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
DSH_HOME=~/.dsh-a dsh --profile tunnelbox --patch ./a.patch.yml # project A + workspace-write
|
|
94
|
-
DSH_HOME=~/.dsh-b DSH_PERMISSION_MODE=danger-full-access dsh --profile tunnelbox --patch ./b.patch.yml
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Each instance appears separately on the phone by `type=dsh` + its own agentID.
|
|
98
|
-
|
|
99
|
-
## Multilingual
|
|
100
|
-
|
|
101
|
-
User-visible output supports 8 languages (`zh-CN` / `zh-TW` / `en-US` / `ja-JP` / `ko-KR` / `fr-FR` / `de-DE` / `es-ES`). Resolution order: `TUNNELBOX_LANG` > saved `remote-state.dsh.json.lang` > system locale > `en-US`.
|
|
102
|
-
|
|
103
|
-
## Troubleshooting
|
|
104
|
-
|
|
105
|
-
| Problem | Fix |
|
|
106
|
-
|---|---|
|
|
107
|
-
| No QR / pairing code on screen | Restart dsh; the plugin prints it at startup |
|
|
108
|
-
| Plugin layer missing in the profile | `dsh plugin --profile tunnelbox add @tunnelbox/dsh-tunnelbox`, then `--dump-config` |
|
|
109
|
-
| Phone asks for credentials/relay mismatch | Confirm `relayUrl` / `TUNNELBOX_RELAY_URL`; check `~/.tunnelbox/tunnelbox.log` |
|
|
110
|
-
| Use your own relay | Set `relayUrl` in the profile config or `TUNNELBOX_RELAY_URL` |
|
|
111
|
-
|
|
112
|
-
## State files
|
|
113
|
-
|
|
114
|
-
- `~/.tunnelbox/remote-state.dsh.json` — agentID / relay / bound state / language
|
|
115
|
-
- `~/.tunnelbox/remote-pairing.json` — latest pairing info
|
|
116
|
-
- `~/.tunnelbox/tunnelbox.log` — plugin log
|
|
117
|
-
|
|
118
|
-
## Uninstall
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
dsh plugin --profile tunnelbox remove @tunnelbox/dsh-tunnelbox
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Remove `~/.tunnelbox` (all adapters' shared state) only if you no longer use any tunnelbox adapter.
|
|
125
|
-
|
|
126
|
-
## Development
|
|
127
|
-
|
|
128
|
-
Implementation details (protocol mapping, source layout, design decisions, untested items) are kept in the source repository as `DEV.md` next to this package, plus the protocol spec under the repo's `docs/`.
|
|
1
|
+
# @tunnelbox/dsh-tunnelbox
|
|
2
|
+
|
|
3
|
+
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
**Official website:** [www.tunnelbox.top](https://www.tunnelbox.top)
|
|
6
|
+
|
|
7
|
+
**tunnelbox DeepSeek Harness (dsh) plugin:** run dsh on your computer and drive it from your phone — agents, sessions, tools, approvals, abort. It runs **inside the dsh (Cordis) process** and dials **out** to a relay only (no public IP, no port forwarding).
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Phone app ──WSS──► relay ──WSS──► this plugin (inside dsh) ──ctx.agents/session/approval──► DeepSeek Harness
|
|
11
|
+
(dsh --profile tunnelbox)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick start (install → run → pair → use)
|
|
15
|
+
|
|
16
|
+
Follow these steps once on a computer that has DeepSeek Harness installed.
|
|
17
|
+
|
|
18
|
+
### Step 0 — Prepare your phone
|
|
19
|
+
|
|
20
|
+
Install the tunnelbox App (Android & iOS) from the official website: **https://www.tunnelbox.top**
|
|
21
|
+
|
|
22
|
+
- Sign in / create an account when prompted.
|
|
23
|
+
|
|
24
|
+
### Step 1 — Install the plugin into a dsh profile
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
dsh plugin --profile tunnelbox add @tunnelbox/dsh-tunnelbox
|
|
28
|
+
dsh --profile tunnelbox --dump-config # optional: confirm the tunnelbox-dsh bundle layer
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Step 2 — Run dsh with the profile
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
dsh --profile tunnelbox
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
dsh starts the harness plus this plugin, which connects to the relay and prints a **pairing QR code + pairing code** in the terminal. Credentials are read automatically from `$DSH_HOME/.credentials.yaml` (default `~/.dsh/`).
|
|
38
|
+
|
|
39
|
+
### Step 3 — Pair with your phone
|
|
40
|
+
|
|
41
|
+
In the phone app tap **Scan to pair** and scan the QR (or type the pairing code manually). The code is single-use and valid for about 10 minutes.
|
|
42
|
+
|
|
43
|
+
- Once bound, later starts print "connected account — open the app and pick this computer" and do not refresh the code. To unbind, see the app settings.
|
|
44
|
+
|
|
45
|
+
### Step 4 — Use it from your phone
|
|
46
|
+
|
|
47
|
+
In the app, open this computer and you can start agents/sessions, send messages, watch streaming output, approve tool requests, answer structured questions, and abort a running session.
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
|
|
51
|
+
The plugin is configured through the profile's `cordis.yml` (fields below) or env vars.
|
|
52
|
+
|
|
53
|
+
| Field / env | Default | Description |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `relayUrl` / `TUNNELBOX_RELAY_URL` | built-in default | tunnelbox relay address |
|
|
56
|
+
| `provider` | `deepseek-official` | LLM provider |
|
|
57
|
+
| `model` | `deepseek-v4-flash` | Model |
|
|
58
|
+
| `cwd` | `process.cwd()` | Agent working directory (sessions persist per-workspace) |
|
|
59
|
+
| `DSH_PERMISSION_MODE` | - | `danger-full-access` = full access (approval never prompts on the phone) |
|
|
60
|
+
|
|
61
|
+
Example profile overlay (`cordis.patch.yml`):
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
- id: tunnelbox-dsh
|
|
65
|
+
config:
|
|
66
|
+
relayUrl: 'wss://chat.example.com'
|
|
67
|
+
model: 'deepseek-v4-flash'
|
|
68
|
+
cwd: 'D:/workspace/project'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Capabilities
|
|
72
|
+
|
|
73
|
+
| Capability | Value | Notes |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| streaming | ✅ | dsh session events → live deltas |
|
|
76
|
+
| thinking | ✅ | `reasoning-delta` → thinking parts |
|
|
77
|
+
| permission | ✅ | dsh approval requests → phone approval card (timeout = fail-closed deny) |
|
|
78
|
+
| commands | ✅ | `/new`, `/help` |
|
|
79
|
+
| abort | ✅ | `agent.cancel` → phone stop button |
|
|
80
|
+
| questions | ✅ | `ask_user_question` tool → structured phone question card |
|
|
81
|
+
|
|
82
|
+
## Approvals & security
|
|
83
|
+
|
|
84
|
+
- Approval policy is governed by dsh's `approval` / `sandbox-policy` (default `workspace-write` + ask). With both the dsh web UI and your phone present, approvals/questions show on both — whoever answers first decides (the other side is cancelled automatically).
|
|
85
|
+
- `DSH_PERMISSION_MODE=danger-full-access` fully disables prompts (approval policy becomes `never`; no phone card).
|
|
86
|
+
- Don't expose sensitive project directories to an untrusted phone.
|
|
87
|
+
|
|
88
|
+
## Running multiple instances
|
|
89
|
+
|
|
90
|
+
Each `dsh --profile <name>` is an independent process, naturally isolated (own cwd/model/tools/approval policy):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
DSH_HOME=~/.dsh-a dsh --profile tunnelbox --patch ./a.patch.yml # project A + workspace-write
|
|
94
|
+
DSH_HOME=~/.dsh-b DSH_PERMISSION_MODE=danger-full-access dsh --profile tunnelbox --patch ./b.patch.yml
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Each instance appears separately on the phone by `type=dsh` + its own agentID.
|
|
98
|
+
|
|
99
|
+
## Multilingual
|
|
100
|
+
|
|
101
|
+
User-visible output supports 8 languages (`zh-CN` / `zh-TW` / `en-US` / `ja-JP` / `ko-KR` / `fr-FR` / `de-DE` / `es-ES`). Resolution order: `TUNNELBOX_LANG` > saved `remote-state.dsh.json.lang` > system locale > `en-US`.
|
|
102
|
+
|
|
103
|
+
## Troubleshooting
|
|
104
|
+
|
|
105
|
+
| Problem | Fix |
|
|
106
|
+
|---|---|
|
|
107
|
+
| No QR / pairing code on screen | Restart dsh; the plugin prints it at startup |
|
|
108
|
+
| Plugin layer missing in the profile | `dsh plugin --profile tunnelbox add @tunnelbox/dsh-tunnelbox`, then `--dump-config` |
|
|
109
|
+
| Phone asks for credentials/relay mismatch | Confirm `relayUrl` / `TUNNELBOX_RELAY_URL`; check `~/.tunnelbox/tunnelbox.log` |
|
|
110
|
+
| Use your own relay | Set `relayUrl` in the profile config or `TUNNELBOX_RELAY_URL` |
|
|
111
|
+
|
|
112
|
+
## State files
|
|
113
|
+
|
|
114
|
+
- `~/.tunnelbox/remote-state.dsh.json` — agentID / relay / bound state / language
|
|
115
|
+
- `~/.tunnelbox/remote-pairing.json` — latest pairing info
|
|
116
|
+
- `~/.tunnelbox/tunnelbox.log` — plugin log
|
|
117
|
+
|
|
118
|
+
## Uninstall
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
dsh plugin --profile tunnelbox remove @tunnelbox/dsh-tunnelbox
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Remove `~/.tunnelbox` (all adapters' shared state) only if you no longer use any tunnelbox adapter.
|
|
125
|
+
|
|
126
|
+
## Development
|
|
127
|
+
|
|
128
|
+
Implementation details (protocol mapping, source layout, design decisions, untested items) are kept in the source repository as `DEV.md` next to this package, plus the protocol spec under the repo's `docs/`.
|
package/README.zh-CN.md
CHANGED
|
@@ -1,128 +1,128 @@
|
|
|
1
|
-
# @tunnelbox/dsh-tunnelbox
|
|
2
|
-
|
|
3
|
-
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
4
|
-
|
|
5
|
-
**官网:** [www.tunnelbox.top](https://www.tunnelbox.top)
|
|
6
|
-
|
|
7
|
-
**tunnelbox DeepSeek Harness(dsh)原生 Cordis 插件**:在电脑上运行 dsh,用手机远程驱动完整的 DeepSeek Harness——agent / session / 工具 / 审批 / 中止。它跑在 **dsh(Cordis)进程内**,只向中继发出站连接(无需公网 IP / 端口映射)。
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
手机 App ──WSS──► relay ──WSS──► 本插件(dsh 进程内) ──ctx.agents/session/approval──► DeepSeek Harness
|
|
11
|
-
(dsh --profile tunnelbox)
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## 快速上手(安装 → 运行 → 配对 → 使用)
|
|
15
|
-
|
|
16
|
-
在装有 DeepSeek Harness 的电脑上,按以下步骤操作一次即可。
|
|
17
|
-
|
|
18
|
-
### 第 0 步 — 准备手机
|
|
19
|
-
|
|
20
|
-
在官网下载并安装 tunnelbox App(Android / iOS 均已上架):**https://www.tunnelbox.top**
|
|
21
|
-
|
|
22
|
-
- 按提示登录/注册账号。
|
|
23
|
-
|
|
24
|
-
### 第 1 步 — 安装插件到 dsh profile
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
dsh plugin --profile tunnelbox add @tunnelbox/dsh-tunnelbox
|
|
28
|
-
dsh --profile tunnelbox --dump-config # 可选:确认已含 tunnelbox-dsh 插件层
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### 第 2 步 — 用该 profile 运行 dsh
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
dsh --profile tunnelbox
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
dsh 启动 harness 与本插件,插件连接中继并在终端打印**配对二维码 + 配对码**。凭证自动读取 `$DSH_HOME/.credentials.yaml`(默认 `~/.dsh/`)。
|
|
38
|
-
|
|
39
|
-
### 第 3 步 — 与手机配对
|
|
40
|
-
|
|
41
|
-
在手机 App 点「扫一扫配对」,扫描二维码(或手动输入配对码)。配对码一次性有效,约 10 分钟。
|
|
42
|
-
|
|
43
|
-
- 绑定后,之后的启动会打印「已绑定账号,从手机「我的电脑」直接连接」,不再刷新码;换手机需先在 App 设置解绑。
|
|
44
|
-
|
|
45
|
-
### 第 4 步 — 在手机上使用
|
|
46
|
-
|
|
47
|
-
在 App 里打开这台电脑,即可启动 agent/会话、发消息、看流式输出、审批工具请求、回答结构化提问、中止运行中的会话。
|
|
48
|
-
|
|
49
|
-
## 配置
|
|
50
|
-
|
|
51
|
-
插件经 profile 的 `cordis.yml`(下列字段)或环境变量配置。
|
|
52
|
-
|
|
53
|
-
| 字段 / 环境变量 | 默认 | 说明 |
|
|
54
|
-
|---|---|---|
|
|
55
|
-
| `relayUrl` / `TUNNELBOX_RELAY_URL` | 构建注入默认 | tunnelbox 中继地址 |
|
|
56
|
-
| `provider` | `deepseek-official` | LLM provider |
|
|
57
|
-
| `model` | `deepseek-v4-flash` | 模型 |
|
|
58
|
-
| `cwd` | `process.cwd()` | agent 工作目录(会话按工作区分目录持久化) |
|
|
59
|
-
| `DSH_PERMISSION_MODE` | - | `danger-full-access` = 全放开(审批不再弹手机卡) |
|
|
60
|
-
|
|
61
|
-
profile overlay 示例(cordis.patch.yml):
|
|
62
|
-
|
|
63
|
-
```yaml
|
|
64
|
-
- id: tunnelbox-dsh
|
|
65
|
-
config:
|
|
66
|
-
relayUrl: 'wss://chat.example.com'
|
|
67
|
-
model: 'deepseek-v4-flash'
|
|
68
|
-
cwd: 'D:/workspace/project'
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## 能力位
|
|
72
|
-
|
|
73
|
-
| 能力 | 值 | 说明 |
|
|
74
|
-
|---|---|---|
|
|
75
|
-
| streaming | ✅ | dsh 会话事件 → 实时增量 |
|
|
76
|
-
| thinking | ✅ | `reasoning-delta` → thinking 部件 |
|
|
77
|
-
| permission | ✅ | dsh 审批请求 → 手机审批卡(超时 fail-closed 拒绝) |
|
|
78
|
-
| commands | ✅ | `/new`、`/help` |
|
|
79
|
-
| abort | ✅ | `agent.cancel` → 前端「停止」 |
|
|
80
|
-
| questions | ✅ | `ask_user_question` 工具 → 手机结构化提问卡 |
|
|
81
|
-
|
|
82
|
-
## 审批与安全
|
|
83
|
-
|
|
84
|
-
- 审批策略由 dsh 的 `approval` / `sandbox-policy` 决定(默认 `workspace-write` + ask)。当 dsh web UI 与手机同时在时,审批/提问两端同显——**谁先答谁得**,另一端自动取消。
|
|
85
|
-
- `DSH_PERMISSION_MODE=danger-full-access` 完全关闭弹卡(approval policy 变 `never`,手机不再显示审批卡)。
|
|
86
|
-
- 请勿把敏感工程目录暴露给不受信手机。
|
|
87
|
-
|
|
88
|
-
## 多实例隔离
|
|
89
|
-
|
|
90
|
-
每个 `dsh --profile <name>` 是独立进程,天然隔离(各自 cwd/模型/工具集/审批策略):
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
DSH_HOME=~/.dsh-a dsh --profile tunnelbox --patch ./a.patch.yml # 工程 A + workspace-write
|
|
94
|
-
DSH_HOME=~/.dsh-b DSH_PERMISSION_MODE=danger-full-access dsh --profile tunnelbox --patch ./b.patch.yml
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
手机端每个实例按 `type=dsh` + 独立 agentID 区分。
|
|
98
|
-
|
|
99
|
-
## 多语言
|
|
100
|
-
|
|
101
|
-
用户可见输出支持 8 种语言(`zh-CN` / `zh-TW` / `en-US` / `ja-JP` / `ko-KR` / `fr-FR` / `de-DE` / `es-ES`)。解析顺序:`TUNNELBOX_LANG` > `remote-state.dsh.json` 的 `lang` > 系统 locale > 默认 `en-US`。
|
|
102
|
-
|
|
103
|
-
## 故障排查
|
|
104
|
-
|
|
105
|
-
| 问题 | 解决 |
|
|
106
|
-
|---|---|
|
|
107
|
-
| 没有二维码/配对码 | 重启 dsh;插件启动时会打印 |
|
|
108
|
-
| profile 里没有插件层 | `dsh plugin --profile tunnelbox add @tunnelbox/dsh-tunnelbox`,再 `--dump-config` |
|
|
109
|
-
| 手机连不上/中继不符 | 确认 `relayUrl` / `TUNNELBOX_RELAY_URL`;查看 `~/.tunnelbox/tunnelbox.log` |
|
|
110
|
-
| 使用自建中继 | 在 profile 配置设 `relayUrl`,或设 `TUNNELBOX_RELAY_URL` |
|
|
111
|
-
|
|
112
|
-
## 状态文件
|
|
113
|
-
|
|
114
|
-
- `~/.tunnelbox/remote-state.dsh.json` — agentID / 中继地址 / 绑定状态 / 语言
|
|
115
|
-
- `~/.tunnelbox/remote-pairing.json` — 最新配对信息
|
|
116
|
-
- `~/.tunnelbox/tunnelbox.log` — 插件日志
|
|
117
|
-
|
|
118
|
-
## 卸载
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
dsh plugin --profile tunnelbox remove @tunnelbox/dsh-tunnelbox
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
仅当不再使用任何 tunnelbox 适配器时,才删除 `~/.tunnelbox`(各适配器共享状态)。
|
|
125
|
-
|
|
126
|
-
## 开发
|
|
127
|
-
|
|
128
|
-
实现细节(协议映射、源码结构、决策记录、待实测项)保存在源码仓库中本包旁的 `DEV.md` 与仓库 `docs/` 下。
|
|
1
|
+
# @tunnelbox/dsh-tunnelbox
|
|
2
|
+
|
|
3
|
+
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
**官网:** [www.tunnelbox.top](https://www.tunnelbox.top)
|
|
6
|
+
|
|
7
|
+
**tunnelbox DeepSeek Harness(dsh)原生 Cordis 插件**:在电脑上运行 dsh,用手机远程驱动完整的 DeepSeek Harness——agent / session / 工具 / 审批 / 中止。它跑在 **dsh(Cordis)进程内**,只向中继发出站连接(无需公网 IP / 端口映射)。
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
手机 App ──WSS──► relay ──WSS──► 本插件(dsh 进程内) ──ctx.agents/session/approval──► DeepSeek Harness
|
|
11
|
+
(dsh --profile tunnelbox)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 快速上手(安装 → 运行 → 配对 → 使用)
|
|
15
|
+
|
|
16
|
+
在装有 DeepSeek Harness 的电脑上,按以下步骤操作一次即可。
|
|
17
|
+
|
|
18
|
+
### 第 0 步 — 准备手机
|
|
19
|
+
|
|
20
|
+
在官网下载并安装 tunnelbox App(Android / iOS 均已上架):**https://www.tunnelbox.top**
|
|
21
|
+
|
|
22
|
+
- 按提示登录/注册账号。
|
|
23
|
+
|
|
24
|
+
### 第 1 步 — 安装插件到 dsh profile
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
dsh plugin --profile tunnelbox add @tunnelbox/dsh-tunnelbox
|
|
28
|
+
dsh --profile tunnelbox --dump-config # 可选:确认已含 tunnelbox-dsh 插件层
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 第 2 步 — 用该 profile 运行 dsh
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
dsh --profile tunnelbox
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
dsh 启动 harness 与本插件,插件连接中继并在终端打印**配对二维码 + 配对码**。凭证自动读取 `$DSH_HOME/.credentials.yaml`(默认 `~/.dsh/`)。
|
|
38
|
+
|
|
39
|
+
### 第 3 步 — 与手机配对
|
|
40
|
+
|
|
41
|
+
在手机 App 点「扫一扫配对」,扫描二维码(或手动输入配对码)。配对码一次性有效,约 10 分钟。
|
|
42
|
+
|
|
43
|
+
- 绑定后,之后的启动会打印「已绑定账号,从手机「我的电脑」直接连接」,不再刷新码;换手机需先在 App 设置解绑。
|
|
44
|
+
|
|
45
|
+
### 第 4 步 — 在手机上使用
|
|
46
|
+
|
|
47
|
+
在 App 里打开这台电脑,即可启动 agent/会话、发消息、看流式输出、审批工具请求、回答结构化提问、中止运行中的会话。
|
|
48
|
+
|
|
49
|
+
## 配置
|
|
50
|
+
|
|
51
|
+
插件经 profile 的 `cordis.yml`(下列字段)或环境变量配置。
|
|
52
|
+
|
|
53
|
+
| 字段 / 环境变量 | 默认 | 说明 |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `relayUrl` / `TUNNELBOX_RELAY_URL` | 构建注入默认 | tunnelbox 中继地址 |
|
|
56
|
+
| `provider` | `deepseek-official` | LLM provider |
|
|
57
|
+
| `model` | `deepseek-v4-flash` | 模型 |
|
|
58
|
+
| `cwd` | `process.cwd()` | agent 工作目录(会话按工作区分目录持久化) |
|
|
59
|
+
| `DSH_PERMISSION_MODE` | - | `danger-full-access` = 全放开(审批不再弹手机卡) |
|
|
60
|
+
|
|
61
|
+
profile overlay 示例(cordis.patch.yml):
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
- id: tunnelbox-dsh
|
|
65
|
+
config:
|
|
66
|
+
relayUrl: 'wss://chat.example.com'
|
|
67
|
+
model: 'deepseek-v4-flash'
|
|
68
|
+
cwd: 'D:/workspace/project'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 能力位
|
|
72
|
+
|
|
73
|
+
| 能力 | 值 | 说明 |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| streaming | ✅ | dsh 会话事件 → 实时增量 |
|
|
76
|
+
| thinking | ✅ | `reasoning-delta` → thinking 部件 |
|
|
77
|
+
| permission | ✅ | dsh 审批请求 → 手机审批卡(超时 fail-closed 拒绝) |
|
|
78
|
+
| commands | ✅ | `/new`、`/help` |
|
|
79
|
+
| abort | ✅ | `agent.cancel` → 前端「停止」 |
|
|
80
|
+
| questions | ✅ | `ask_user_question` 工具 → 手机结构化提问卡 |
|
|
81
|
+
|
|
82
|
+
## 审批与安全
|
|
83
|
+
|
|
84
|
+
- 审批策略由 dsh 的 `approval` / `sandbox-policy` 决定(默认 `workspace-write` + ask)。当 dsh web UI 与手机同时在时,审批/提问两端同显——**谁先答谁得**,另一端自动取消。
|
|
85
|
+
- `DSH_PERMISSION_MODE=danger-full-access` 完全关闭弹卡(approval policy 变 `never`,手机不再显示审批卡)。
|
|
86
|
+
- 请勿把敏感工程目录暴露给不受信手机。
|
|
87
|
+
|
|
88
|
+
## 多实例隔离
|
|
89
|
+
|
|
90
|
+
每个 `dsh --profile <name>` 是独立进程,天然隔离(各自 cwd/模型/工具集/审批策略):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
DSH_HOME=~/.dsh-a dsh --profile tunnelbox --patch ./a.patch.yml # 工程 A + workspace-write
|
|
94
|
+
DSH_HOME=~/.dsh-b DSH_PERMISSION_MODE=danger-full-access dsh --profile tunnelbox --patch ./b.patch.yml
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
手机端每个实例按 `type=dsh` + 独立 agentID 区分。
|
|
98
|
+
|
|
99
|
+
## 多语言
|
|
100
|
+
|
|
101
|
+
用户可见输出支持 8 种语言(`zh-CN` / `zh-TW` / `en-US` / `ja-JP` / `ko-KR` / `fr-FR` / `de-DE` / `es-ES`)。解析顺序:`TUNNELBOX_LANG` > `remote-state.dsh.json` 的 `lang` > 系统 locale > 默认 `en-US`。
|
|
102
|
+
|
|
103
|
+
## 故障排查
|
|
104
|
+
|
|
105
|
+
| 问题 | 解决 |
|
|
106
|
+
|---|---|
|
|
107
|
+
| 没有二维码/配对码 | 重启 dsh;插件启动时会打印 |
|
|
108
|
+
| profile 里没有插件层 | `dsh plugin --profile tunnelbox add @tunnelbox/dsh-tunnelbox`,再 `--dump-config` |
|
|
109
|
+
| 手机连不上/中继不符 | 确认 `relayUrl` / `TUNNELBOX_RELAY_URL`;查看 `~/.tunnelbox/tunnelbox.log` |
|
|
110
|
+
| 使用自建中继 | 在 profile 配置设 `relayUrl`,或设 `TUNNELBOX_RELAY_URL` |
|
|
111
|
+
|
|
112
|
+
## 状态文件
|
|
113
|
+
|
|
114
|
+
- `~/.tunnelbox/remote-state.dsh.json` — agentID / 中继地址 / 绑定状态 / 语言
|
|
115
|
+
- `~/.tunnelbox/remote-pairing.json` — 最新配对信息
|
|
116
|
+
- `~/.tunnelbox/tunnelbox.log` — 插件日志
|
|
117
|
+
|
|
118
|
+
## 卸载
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
dsh plugin --profile tunnelbox remove @tunnelbox/dsh-tunnelbox
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
仅当不再使用任何 tunnelbox 适配器时,才删除 `~/.tunnelbox`(各适配器共享状态)。
|
|
125
|
+
|
|
126
|
+
## 开发
|
|
127
|
+
|
|
128
|
+
实现细节(协议映射、源码结构、决策记录、待实测项)保存在源码仓库中本包旁的 `DEV.md` 与仓库 `docs/` 下。
|
package/dist/index.mjs
CHANGED
|
@@ -17,6 +17,8 @@ function envelope(type, payload, id) {
|
|
|
17
17
|
}
|
|
18
18
|
var BASE_DELAY = 1e3;
|
|
19
19
|
var MAX_DELAY = 15e3;
|
|
20
|
+
var KEEPALIVE_INTERVAL_MS = 15e3;
|
|
21
|
+
var KEEPALIVE_TIMEOUT_MS = 25e3;
|
|
20
22
|
var RelayClient = class {
|
|
21
23
|
ws = null;
|
|
22
24
|
url = "";
|
|
@@ -26,6 +28,11 @@ var RelayClient = class {
|
|
|
26
28
|
retry = 0;
|
|
27
29
|
stopped = false;
|
|
28
30
|
connected = false;
|
|
31
|
+
reconnectScheduled = false;
|
|
32
|
+
/** 保活心跳定时器(onopen 启动 / onclose 停止) */
|
|
33
|
+
keepaliveTimer = null;
|
|
34
|
+
/** 最近一次收到服务端帧的时间(含心跳回执 pong),用于静默断流检测 */
|
|
35
|
+
lastInbound = 0;
|
|
29
36
|
get isConnected() {
|
|
30
37
|
return this.connected;
|
|
31
38
|
}
|
|
@@ -35,6 +42,8 @@ var RelayClient = class {
|
|
|
35
42
|
this.handlers = handlers;
|
|
36
43
|
this.stopped = false;
|
|
37
44
|
this.retry = 0;
|
|
45
|
+
this.reconnectScheduled = false;
|
|
46
|
+
this.stopKeepalive();
|
|
38
47
|
this.open();
|
|
39
48
|
}
|
|
40
49
|
send(env) {
|
|
@@ -50,6 +59,8 @@ var RelayClient = class {
|
|
|
50
59
|
}
|
|
51
60
|
close() {
|
|
52
61
|
this.stopped = true;
|
|
62
|
+
this.reconnectScheduled = false;
|
|
63
|
+
this.stopKeepalive();
|
|
53
64
|
if (this.timer) clearTimeout(this.timer);
|
|
54
65
|
this.timer = null;
|
|
55
66
|
if (this.ws) {
|
|
@@ -69,11 +80,14 @@ var RelayClient = class {
|
|
|
69
80
|
ws.onopen = () => {
|
|
70
81
|
this.connected = true;
|
|
71
82
|
this.retry = 0;
|
|
83
|
+
this.startKeepalive();
|
|
72
84
|
this.handlers?.onOpen();
|
|
73
85
|
};
|
|
74
86
|
ws.onmessage = (ev) => {
|
|
87
|
+
this.lastInbound = Date.now();
|
|
75
88
|
try {
|
|
76
89
|
const msg = JSON.parse(String(ev.data));
|
|
90
|
+
if (msg.type === "pong") return;
|
|
77
91
|
this.handlers?.onMessage(msg);
|
|
78
92
|
} catch {
|
|
79
93
|
}
|
|
@@ -82,6 +96,7 @@ var RelayClient = class {
|
|
|
82
96
|
ws.onclose = () => {
|
|
83
97
|
this.connected = false;
|
|
84
98
|
this.ws = null;
|
|
99
|
+
this.stopKeepalive();
|
|
85
100
|
this.handlers?.onClose();
|
|
86
101
|
this.scheduleReconnect();
|
|
87
102
|
};
|
|
@@ -91,10 +106,52 @@ var RelayClient = class {
|
|
|
91
106
|
}
|
|
92
107
|
}
|
|
93
108
|
scheduleReconnect() {
|
|
94
|
-
if (this.stopped) return;
|
|
109
|
+
if (this.stopped || this.reconnectScheduled) return;
|
|
110
|
+
this.reconnectScheduled = true;
|
|
95
111
|
const delay = Math.min(BASE_DELAY * 2 ** this.retry, MAX_DELAY);
|
|
96
112
|
this.retry++;
|
|
97
|
-
this.timer = setTimeout(() =>
|
|
113
|
+
this.timer = setTimeout(() => {
|
|
114
|
+
this.reconnectScheduled = false;
|
|
115
|
+
this.open();
|
|
116
|
+
}, delay);
|
|
117
|
+
}
|
|
118
|
+
/** 启动保活心跳:每周期发 ping,长时间收不到任何帧则判定断流主动重连。 */
|
|
119
|
+
startKeepalive() {
|
|
120
|
+
this.stopKeepalive();
|
|
121
|
+
this.lastInbound = Date.now();
|
|
122
|
+
this.keepaliveTimer = setInterval(() => {
|
|
123
|
+
if (!this.connected || !this.ws) return;
|
|
124
|
+
const now = Date.now();
|
|
125
|
+
if (now - this.lastInbound > KEEPALIVE_TIMEOUT_MS) {
|
|
126
|
+
this.forceReconnect();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
this.ws.send(JSON.stringify({ type: "ping", payload: {}, ts: now }));
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
}, KEEPALIVE_INTERVAL_MS);
|
|
134
|
+
}
|
|
135
|
+
stopKeepalive() {
|
|
136
|
+
if (this.keepaliveTimer !== null) {
|
|
137
|
+
clearInterval(this.keepaliveTimer);
|
|
138
|
+
this.keepaliveTimer = null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** 判定连接已死:关闭当前 socket 并调度重连(沿用指数退避,onclose 去重)。 */
|
|
142
|
+
forceReconnect() {
|
|
143
|
+
if (this.stopped) return;
|
|
144
|
+
this.connected = false;
|
|
145
|
+
this.stopKeepalive();
|
|
146
|
+
const w = this.ws;
|
|
147
|
+
this.ws = null;
|
|
148
|
+
if (w) {
|
|
149
|
+
try {
|
|
150
|
+
w.close();
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
this.scheduleReconnect();
|
|
98
155
|
}
|
|
99
156
|
};
|
|
100
157
|
var zh_CN_default = {
|
|
@@ -113,6 +170,7 @@ var zh_CN_default = {
|
|
|
113
170
|
"agent.log.pendingResent": "session.pending: \u8865\u53D1 {session} \u79EF\u538B\u8BF7\u6C42 {count} \u6761",
|
|
114
171
|
"agent.log.unhandledType": "\u672A\u5904\u7406\u7684\u6D88\u606F\u7C7B\u578B: {type}",
|
|
115
172
|
"events.log.fwdPermission": "\u8F6C\u53D1\u6743\u9650\u8BF7\u6C42\u5230\u624B\u673A (id={id} tool={tool} {version})",
|
|
173
|
+
"events.log.sessionDeleted": "\u8F6C\u53D1 session.deleted \u5230\u624B\u673A (session={session})",
|
|
116
174
|
"events.log.permissionReplied": "opencode \u56DE\u6267 permission.replied (id={id} {response})",
|
|
117
175
|
"events.log.questionRejected": "opencode \u56DE\u6267 question.rejected (id={id})",
|
|
118
176
|
"events.log.questionReplied": "opencode \u56DE\u6267 question.replied (id={id})",
|
|
@@ -278,6 +336,7 @@ var zh_TW_default = {
|
|
|
278
336
|
"agent.log.pendingResent": "session.pending: \u88DC\u767C {session} \u7A4D\u58D3\u8ACB\u6C42 {count} \u689D",
|
|
279
337
|
"agent.log.unhandledType": "\u672A\u8655\u7406\u7684\u8A0A\u606F\u985E\u578B: {type}",
|
|
280
338
|
"events.log.fwdPermission": "\u8F49\u767C\u6B0A\u9650\u8ACB\u6C42\u5230\u624B\u6A5F (id={id} tool={tool} {version})",
|
|
339
|
+
"events.log.sessionDeleted": "\u8F49\u767C session.deleted \u5230\u624B\u6A5F (session={session})",
|
|
281
340
|
"events.log.permissionReplied": "opencode \u56DE\u57F7 permission.replied (id={id} {response})",
|
|
282
341
|
"events.log.questionRejected": "opencode \u56DE\u57F7 question.rejected (id={id})",
|
|
283
342
|
"events.log.questionReplied": "opencode \u56DE\u57F7 question.replied (id={id})",
|
|
@@ -443,6 +502,7 @@ var en_US_default = {
|
|
|
443
502
|
"agent.log.pendingResent": "session.pending: resent {count} pending request(s) for {session}",
|
|
444
503
|
"agent.log.unhandledType": "Unhandled message type: {type}",
|
|
445
504
|
"events.log.fwdPermission": "Forwarded permission request to phone (id={id} tool={tool} {version})",
|
|
505
|
+
"events.log.sessionDeleted": "Forwarded session.deleted to phone (session={session})",
|
|
446
506
|
"events.log.permissionReplied": "opencode acked permission.replied (id={id} {response})",
|
|
447
507
|
"events.log.questionRejected": "opencode acked question.rejected (id={id})",
|
|
448
508
|
"events.log.questionReplied": "opencode acked question.replied (id={id})",
|
|
@@ -608,6 +668,7 @@ var ja_JP_default = {
|
|
|
608
668
|
"agent.log.pendingResent": "session.pending: {session} \u306E\u4FDD\u7559\u30EA\u30AF\u30A8\u30B9\u30C8 {count} \u4EF6\u3092\u518D\u9001",
|
|
609
669
|
"agent.log.unhandledType": "\u672A\u51E6\u7406\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u30BF\u30A4\u30D7: {type}",
|
|
610
670
|
"events.log.fwdPermission": "\u6A29\u9650\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u643A\u5E2F\u3078\u8EE2\u9001 (id={id} tool={tool} {version})",
|
|
671
|
+
"events.log.sessionDeleted": "session.deleted \u3092\u643A\u5E2F\u3078\u8EE2\u9001 (session={session})",
|
|
611
672
|
"events.log.permissionReplied": "opencode \u5FDC\u7B54 permission.replied (id={id} {response})",
|
|
612
673
|
"events.log.questionRejected": "opencode \u5FDC\u7B54 question.rejected (id={id})",
|
|
613
674
|
"events.log.questionReplied": "opencode \u5FDC\u7B54 question.replied (id={id})",
|
|
@@ -773,6 +834,7 @@ var ko_KR_default = {
|
|
|
773
834
|
"agent.log.pendingResent": "session.pending: {session} \uBCF4\uB958 \uC694\uCCAD {count}\uAC74 \uC7AC\uC804\uC1A1",
|
|
774
835
|
"agent.log.unhandledType": "\uCC98\uB9AC\uB418\uC9C0 \uC54A\uC740 \uBA54\uC2DC\uC9C0 \uC720\uD615: {type}",
|
|
775
836
|
"events.log.fwdPermission": "\uAD8C\uD55C \uC694\uCCAD\uC744 \uD734\uB300\uD3F0\uC73C\uB85C \uC804\uB2EC (id={id} tool={tool} {version})",
|
|
837
|
+
"events.log.sessionDeleted": "session.deleted\uB97C \uD734\uB300\uD3F0\uC73C\uB85C \uC804\uB2EC (session={session})",
|
|
776
838
|
"events.log.permissionReplied": "opencode \uC751\uB2F5 permission.replied (id={id} {response})",
|
|
777
839
|
"events.log.questionRejected": "opencode \uC751\uB2F5 question.rejected (id={id})",
|
|
778
840
|
"events.log.questionReplied": "opencode \uC751\uB2F5 question.replied (id={id})",
|
|
@@ -938,6 +1000,7 @@ var fr_FR_default = {
|
|
|
938
1000
|
"agent.log.pendingResent": "session.pending : renvoi de {count} demande(s) en attente pour {session}",
|
|
939
1001
|
"agent.log.unhandledType": "Type de message non g\xE9r\xE9 : {type}",
|
|
940
1002
|
"events.log.fwdPermission": "Demande d'autorisation transmise au t\xE9l\xE9phone (id={id} tool={tool} {version})",
|
|
1003
|
+
"events.log.sessionDeleted": "session.deleted transmise au t\xE9l\xE9phone (session={session})",
|
|
941
1004
|
"events.log.permissionReplied": "opencode a accus\xE9 permission.replied (id={id} {response})",
|
|
942
1005
|
"events.log.questionRejected": "opencode a accus\xE9 question.rejected (id={id})",
|
|
943
1006
|
"events.log.questionReplied": "opencode a accus\xE9 question.replied (id={id})",
|
|
@@ -1103,6 +1166,7 @@ var de_DE_default = {
|
|
|
1103
1166
|
"agent.log.pendingResent": "session.pending: {count} ausstehende Anfrage(n) f\xFCr {session} erneut gesendet",
|
|
1104
1167
|
"agent.log.unhandledType": "Nicht behandelter Nachrichtentyp: {type}",
|
|
1105
1168
|
"events.log.fwdPermission": "Berechtigungsanfrage an Telefon weitergeleitet (id={id} tool={tool} {version})",
|
|
1169
|
+
"events.log.sessionDeleted": "session.deleted an Telefon weitergeleitet (session={session})",
|
|
1106
1170
|
"events.log.permissionReplied": "opencode quittierte permission.replied (id={id} {response})",
|
|
1107
1171
|
"events.log.questionRejected": "opencode quittierte question.rejected (id={id})",
|
|
1108
1172
|
"events.log.questionReplied": "opencode quittierte question.replied (id={id})",
|
|
@@ -1268,6 +1332,7 @@ var es_ES_default = {
|
|
|
1268
1332
|
"agent.log.pendingResent": "session.pending: reenviadas {count} solicitud(es) pendientes para {session}",
|
|
1269
1333
|
"agent.log.unhandledType": "Tipo de mensaje no gestionado: {type}",
|
|
1270
1334
|
"events.log.fwdPermission": "Solicitud de permiso reenviada al tel\xE9fono (id={id} tool={tool} {version})",
|
|
1335
|
+
"events.log.sessionDeleted": "session.deleted reenviada al tel\xE9fono (session={session})",
|
|
1271
1336
|
"events.log.permissionReplied": "opencode confirm\xF3 permission.replied (id={id} {response})",
|
|
1272
1337
|
"events.log.questionRejected": "opencode confirm\xF3 question.rejected (id={id})",
|
|
1273
1338
|
"events.log.questionReplied": "opencode confirm\xF3 question.replied (id={id})",
|
|
@@ -2049,7 +2114,7 @@ function findDir(dir, name2) {
|
|
|
2049
2114
|
}
|
|
2050
2115
|
|
|
2051
2116
|
// src/bridge.ts
|
|
2052
|
-
var VERSION = true ? "0.1.
|
|
2117
|
+
var VERSION = true ? "0.1.16" : "0.0.0-dev";
|
|
2053
2118
|
var AGENT_TYPE = "dsh";
|
|
2054
2119
|
var APPROVAL_TIMEOUT_MS = 12e4;
|
|
2055
2120
|
var ADAPTER_COMMANDS = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tunnelbox/dsh-tunnelbox",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "tunnelbox 的 dsh 原生 Cordis 插件:手机远程驱动 DeepSeek Harness(agent/session/tools/审批/中止)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.mjs",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@deepseek-ai/schemastery": "^3.18.1"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@tunnelbox/core": "0.1.
|
|
39
|
+
"@tunnelbox/core": "0.1.16",
|
|
40
40
|
"@types/node": "^22.0.0",
|
|
41
41
|
"esbuild": "^0.24.0",
|
|
42
42
|
"typescript": "^5.4.5"
|