@tunnelbox/cursor 0.1.9 → 0.1.11
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 +127 -127
- package/README.zh-CN.md +127 -127
- package/dist/index.mjs +69 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
# @tunnelbox/cursor
|
|
2
|
-
|
|
3
|
-
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
4
|
-
|
|
5
|
-
**Official website:** [www.tunnelbox.top](https://www.tunnelbox.top)
|
|
6
|
-
|
|
7
|
-
**tunnelbox Cursor adapter (standalone daemon):** drive the Cursor agent on your computer from your phone — sessions, streaming, abort, delete. It drives the Cursor CLI headless mode and dials **out** to a relay only (no public IP, no port forwarding).
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
Phone app ──WSS──► relay ──WSS──► tunnelbox-cursor (this adapter)
|
|
11
|
-
└─ agent -p --output-format stream-json --stream-partial-output
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Quick start (install → run → pair → use)
|
|
15
|
-
|
|
16
|
-
Follow these steps once on a computer that has Cursor CLI installed and signed in.
|
|
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 adapter on your computer
|
|
25
|
-
|
|
26
|
-
Prerequisites: Node.js ≥ 22, and **Cursor CLI** installed & configured (`agent -p "hello"` works). Headless mode bills against your Cursor plan.
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm install -g @tunnelbox/cursor
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Step 2 — Run it
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
tunnelbox-cursor
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
On first start the adapter connects to the relay and prints a **pairing QR code + pairing code** in the terminal.
|
|
39
|
-
|
|
40
|
-
### Step 3 — Pair with your phone
|
|
41
|
-
|
|
42
|
-
In the phone app tap **Scan to pair** and scan the terminal QR code (or type the pairing code manually). The code is single-use and valid for about 10 minutes.
|
|
43
|
-
|
|
44
|
-
- Once bound, the adapter prints "connected account — open the app and pick this computer" on later starts and does not refresh the code.
|
|
45
|
-
- Want a fresh code any time? Run `tunnelbox-cursor --pair`.
|
|
46
|
-
|
|
47
|
-
### Step 4 — Use it from your phone
|
|
48
|
-
|
|
49
|
-
In the app, open this computer and you can start new sessions, send messages, watch streaming output, and abort a running session.
|
|
50
|
-
|
|
51
|
-
## Configuration
|
|
52
|
-
|
|
53
|
-
| Env var | Default | Description |
|
|
54
|
-
|---|---|---|
|
|
55
|
-
| `TUNNELBOX_RELAY_URL` | saved relay URL | Relay address |
|
|
56
|
-
| `TUNNELBOX_CWD` | `process.cwd()` | Default workspace (agent runs there) |
|
|
57
|
-
| `TUNNELBOX_CURSOR_MODE` | `agent` | `agent` / `plan` / `ask` (`--mode`) |
|
|
58
|
-
| `TUNNELBOX_CURSOR_MODEL` | Cursor default | `--model` |
|
|
59
|
-
| `TUNNELBOX_CURSOR_FORCE` | off | Add `--force`: allow direct file edits (no confirmation) |
|
|
60
|
-
| `TUNNELBOX_CURSOR_YOLO` | off | Add `--yolo` (broader permissions — dangerous) |
|
|
61
|
-
| `TUNNELBOX_CURSOR_SANDBOX` | `enabled` | `--sandbox enabled/disabled` |
|
|
62
|
-
| `TUNNELBOX_CURSOR_BIN` | `agent` | Cursor CLI executable name / absolute path |
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
TUNNELBOX_RELAY_URL=wss://chat.example.com TUNNELBOX_CURSOR_MODE=plan tunnelbox-cursor
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Capabilities
|
|
69
|
-
|
|
70
|
-
| Capability | Value | Notes |
|
|
71
|
-
|---|---|---|
|
|
72
|
-
| streaming | ✅ | stream-json: assistant delta lines → live deltas |
|
|
73
|
-
| thinking | ❌ | Cursor suppresses thinking in print mode (headless has no reasoning stream) |
|
|
74
|
-
| permission | ❌ | Cursor's hooks target IDE / Cmd+K / Cloud agents; headless `agent -p` has no external approval channel — **no phone approval**. Gating is decided by `--force/--yolo` + `--sandbox` + `permissions` allow/deny |
|
|
75
|
-
| commands | ✅ | `/new`, `/help` |
|
|
76
|
-
| abort | ✅ | kill subprocess (SIGTERM → SIGKILL) |
|
|
77
|
-
| workspaces | ✅ | session `cwd` |
|
|
78
|
-
|
|
79
|
-
## Permissions & approvals (official constraints)
|
|
80
|
-
|
|
81
|
-
- Cursor official hooks can `allow/deny/ask`, but they serve **IDE / Cmd+K / Cloud agents**; the docs do not state that local headless `agent -p` loads hooks, and there is no relay channel to await a phone decision.
|
|
82
|
-
- Therefore `capability.permission=false`: **phone approval is not available for Cursor headless**. Gating comes from `permissions.allow/deny` (`~/.cursor/cli-config.json` or `<project>/.cursor/cli.json`) + `--force/--yolo` + `--sandbox`.
|
|
83
|
-
- Defaults are safe: no `--force` (agent only proposes, doesn't edit) and `--sandbox=enabled`.
|
|
84
|
-
|
|
85
|
-
## Sessions
|
|
86
|
-
|
|
87
|
-
- Sessions are local mirrors (`~/.tunnelbox/cursor-sessions/<uuid>/`): each streamed part/user message is written immediately for list/history/delete.
|
|
88
|
-
- Continuation: the adapter tries to capture the Cursor chat id (`meta.resumeId`) from the stream and resumes with `--resume=<id>`; if it can't be captured, each session is an independent Q&A (limited context continuity).
|
|
89
|
-
- State file: `~/.tunnelbox/remote-state.cursor.json`.
|
|
90
|
-
|
|
91
|
-
## Security notes
|
|
92
|
-
|
|
93
|
-
- By default no `--force` is passed (the agent doesn't edit files, it only proposes) and `--sandbox=enabled` is on.
|
|
94
|
-
- To actually change code you must explicitly set `TUNNELBOX_CURSOR_FORCE=1`. Don't enable yolo in untrusted directories.
|
|
95
|
-
- Don't expose sensitive projects to an untrusted phone.
|
|
96
|
-
|
|
97
|
-
## Multilingual
|
|
98
|
-
|
|
99
|
-
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.cursor.json.lang` > system locale > `en-US`.
|
|
100
|
-
|
|
101
|
-
## Troubleshooting
|
|
102
|
-
|
|
103
|
-
| Problem | Fix |
|
|
104
|
-
|---|---|
|
|
105
|
-
| No QR / pairing code on screen | Run `tunnelbox-cursor --pair` to print a fresh one |
|
|
106
|
-
| Need to pair a different phone | Unbind in the app settings, then run with `--pair` again |
|
|
107
|
-
| Already bound but phone doesn't connect | Confirm both use the same relay; check `~/.tunnelbox/tunnelbox.log` |
|
|
108
|
-
| Use your own relay | Start with `TUNNELBOX_RELAY_URL=wss://<your-relay>` |
|
|
109
|
-
|
|
110
|
-
## State files
|
|
111
|
-
|
|
112
|
-
- `~/.tunnelbox/remote-state.cursor.json` — agentID / relay / bound state / language
|
|
113
|
-
- `~/.tunnelbox/cursor-sessions/` — local session mirrors
|
|
114
|
-
- `~/.tunnelbox/remote-pairing.cursor.txt` + `remote-pairing.json` — latest pairing info
|
|
115
|
-
- `~/.tunnelbox/tunnelbox.log` — adapter log
|
|
116
|
-
|
|
117
|
-
## Uninstall
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
npm uninstall -g @tunnelbox/cursor
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Remove `~/.tunnelbox` (all adapters' shared state) only if you no longer use any tunnelbox adapter.
|
|
124
|
-
|
|
125
|
-
## Development
|
|
126
|
-
|
|
127
|
-
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/cursor
|
|
2
|
+
|
|
3
|
+
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
**Official website:** [www.tunnelbox.top](https://www.tunnelbox.top)
|
|
6
|
+
|
|
7
|
+
**tunnelbox Cursor adapter (standalone daemon):** drive the Cursor agent on your computer from your phone — sessions, streaming, abort, delete. It drives the Cursor CLI headless mode and dials **out** to a relay only (no public IP, no port forwarding).
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Phone app ──WSS──► relay ──WSS──► tunnelbox-cursor (this adapter)
|
|
11
|
+
└─ agent -p --output-format stream-json --stream-partial-output
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick start (install → run → pair → use)
|
|
15
|
+
|
|
16
|
+
Follow these steps once on a computer that has Cursor CLI installed and signed in.
|
|
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 adapter on your computer
|
|
25
|
+
|
|
26
|
+
Prerequisites: Node.js ≥ 22, and **Cursor CLI** installed & configured (`agent -p "hello"` works). Headless mode bills against your Cursor plan.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install -g @tunnelbox/cursor
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Step 2 — Run it
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
tunnelbox-cursor
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
On first start the adapter connects to the relay and prints a **pairing QR code + pairing code** in the terminal.
|
|
39
|
+
|
|
40
|
+
### Step 3 — Pair with your phone
|
|
41
|
+
|
|
42
|
+
In the phone app tap **Scan to pair** and scan the terminal QR code (or type the pairing code manually). The code is single-use and valid for about 10 minutes.
|
|
43
|
+
|
|
44
|
+
- Once bound, the adapter prints "connected account — open the app and pick this computer" on later starts and does not refresh the code.
|
|
45
|
+
- Want a fresh code any time? Run `tunnelbox-cursor --pair`.
|
|
46
|
+
|
|
47
|
+
### Step 4 — Use it from your phone
|
|
48
|
+
|
|
49
|
+
In the app, open this computer and you can start new sessions, send messages, watch streaming output, and abort a running session.
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
| Env var | Default | Description |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `TUNNELBOX_RELAY_URL` | saved relay URL | Relay address |
|
|
56
|
+
| `TUNNELBOX_CWD` | `process.cwd()` | Default workspace (agent runs there) |
|
|
57
|
+
| `TUNNELBOX_CURSOR_MODE` | `agent` | `agent` / `plan` / `ask` (`--mode`) |
|
|
58
|
+
| `TUNNELBOX_CURSOR_MODEL` | Cursor default | `--model` |
|
|
59
|
+
| `TUNNELBOX_CURSOR_FORCE` | off | Add `--force`: allow direct file edits (no confirmation) |
|
|
60
|
+
| `TUNNELBOX_CURSOR_YOLO` | off | Add `--yolo` (broader permissions — dangerous) |
|
|
61
|
+
| `TUNNELBOX_CURSOR_SANDBOX` | `enabled` | `--sandbox enabled/disabled` |
|
|
62
|
+
| `TUNNELBOX_CURSOR_BIN` | `agent` | Cursor CLI executable name / absolute path |
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
TUNNELBOX_RELAY_URL=wss://chat.example.com TUNNELBOX_CURSOR_MODE=plan tunnelbox-cursor
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Capabilities
|
|
69
|
+
|
|
70
|
+
| Capability | Value | Notes |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| streaming | ✅ | stream-json: assistant delta lines → live deltas |
|
|
73
|
+
| thinking | ❌ | Cursor suppresses thinking in print mode (headless has no reasoning stream) |
|
|
74
|
+
| permission | ❌ | Cursor's hooks target IDE / Cmd+K / Cloud agents; headless `agent -p` has no external approval channel — **no phone approval**. Gating is decided by `--force/--yolo` + `--sandbox` + `permissions` allow/deny |
|
|
75
|
+
| commands | ✅ | `/new`, `/help` |
|
|
76
|
+
| abort | ✅ | kill subprocess (SIGTERM → SIGKILL) |
|
|
77
|
+
| workspaces | ✅ | session `cwd` |
|
|
78
|
+
|
|
79
|
+
## Permissions & approvals (official constraints)
|
|
80
|
+
|
|
81
|
+
- Cursor official hooks can `allow/deny/ask`, but they serve **IDE / Cmd+K / Cloud agents**; the docs do not state that local headless `agent -p` loads hooks, and there is no relay channel to await a phone decision.
|
|
82
|
+
- Therefore `capability.permission=false`: **phone approval is not available for Cursor headless**. Gating comes from `permissions.allow/deny` (`~/.cursor/cli-config.json` or `<project>/.cursor/cli.json`) + `--force/--yolo` + `--sandbox`.
|
|
83
|
+
- Defaults are safe: no `--force` (agent only proposes, doesn't edit) and `--sandbox=enabled`.
|
|
84
|
+
|
|
85
|
+
## Sessions
|
|
86
|
+
|
|
87
|
+
- Sessions are local mirrors (`~/.tunnelbox/cursor-sessions/<uuid>/`): each streamed part/user message is written immediately for list/history/delete.
|
|
88
|
+
- Continuation: the adapter tries to capture the Cursor chat id (`meta.resumeId`) from the stream and resumes with `--resume=<id>`; if it can't be captured, each session is an independent Q&A (limited context continuity).
|
|
89
|
+
- State file: `~/.tunnelbox/remote-state.cursor.json`.
|
|
90
|
+
|
|
91
|
+
## Security notes
|
|
92
|
+
|
|
93
|
+
- By default no `--force` is passed (the agent doesn't edit files, it only proposes) and `--sandbox=enabled` is on.
|
|
94
|
+
- To actually change code you must explicitly set `TUNNELBOX_CURSOR_FORCE=1`. Don't enable yolo in untrusted directories.
|
|
95
|
+
- Don't expose sensitive projects to an untrusted phone.
|
|
96
|
+
|
|
97
|
+
## Multilingual
|
|
98
|
+
|
|
99
|
+
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.cursor.json.lang` > system locale > `en-US`.
|
|
100
|
+
|
|
101
|
+
## Troubleshooting
|
|
102
|
+
|
|
103
|
+
| Problem | Fix |
|
|
104
|
+
|---|---|
|
|
105
|
+
| No QR / pairing code on screen | Run `tunnelbox-cursor --pair` to print a fresh one |
|
|
106
|
+
| Need to pair a different phone | Unbind in the app settings, then run with `--pair` again |
|
|
107
|
+
| Already bound but phone doesn't connect | Confirm both use the same relay; check `~/.tunnelbox/tunnelbox.log` |
|
|
108
|
+
| Use your own relay | Start with `TUNNELBOX_RELAY_URL=wss://<your-relay>` |
|
|
109
|
+
|
|
110
|
+
## State files
|
|
111
|
+
|
|
112
|
+
- `~/.tunnelbox/remote-state.cursor.json` — agentID / relay / bound state / language
|
|
113
|
+
- `~/.tunnelbox/cursor-sessions/` — local session mirrors
|
|
114
|
+
- `~/.tunnelbox/remote-pairing.cursor.txt` + `remote-pairing.json` — latest pairing info
|
|
115
|
+
- `~/.tunnelbox/tunnelbox.log` — adapter log
|
|
116
|
+
|
|
117
|
+
## Uninstall
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm uninstall -g @tunnelbox/cursor
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Remove `~/.tunnelbox` (all adapters' shared state) only if you no longer use any tunnelbox adapter.
|
|
124
|
+
|
|
125
|
+
## Development
|
|
126
|
+
|
|
127
|
+
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,127 +1,127 @@
|
|
|
1
|
-
# @tunnelbox/cursor
|
|
2
|
-
|
|
3
|
-
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
4
|
-
|
|
5
|
-
**官网:** [www.tunnelbox.top](https://www.tunnelbox.top)
|
|
6
|
-
|
|
7
|
-
**tunnelbox Cursor 适配器(独立进程)**:用手机远程驱动电脑上的 Cursor agent——会话 / 流式 / 中止 / 删除。它驱动 Cursor CLI 的 headless 模式,只向中继发出站连接(无需公网 IP / 端口映射)。
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
手机 App ──WSS──► relay ──WSS──► tunnelbox-cursor(本适配器)
|
|
11
|
-
└─ agent -p --output-format stream-json --stream-partial-output
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## 快速上手(安装 → 运行 → 配对 → 使用)
|
|
15
|
-
|
|
16
|
-
在装有 Cursor CLI 并已配置的电脑上,按以下步骤操作一次即可。
|
|
17
|
-
|
|
18
|
-
### 第 0 步 — 准备手机
|
|
19
|
-
|
|
20
|
-
在官网下载并安装 tunnelbox App(Android / iOS 均已上架):**https://www.tunnelbox.top**
|
|
21
|
-
|
|
22
|
-
- 按提示登录/注册账号。
|
|
23
|
-
|
|
24
|
-
### 第 1 步 — 电脑上安装适配器
|
|
25
|
-
|
|
26
|
-
前置条件:Node.js ≥ 22,且本机已安装并登录 **Cursor CLI**(`agent -p "hello"` 可正常输出)。headless 走 Cursor 计费,需在你的套餐计划内。
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm install -g @tunnelbox/cursor
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### 第 2 步 — 运行
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
tunnelbox-cursor
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
首次启动会连接中继,并在终端打印**配对二维码 + 配对码**。
|
|
39
|
-
|
|
40
|
-
### 第 3 步 — 与手机配对
|
|
41
|
-
|
|
42
|
-
在手机 App 点「扫一扫配对」,扫描终端二维码(或手动输入配对码)。配对码一次性有效,约 10 分钟。
|
|
43
|
-
|
|
44
|
-
- 绑定后再次启动会打印「已绑定账号,从手机「我的电脑」直接连接」,不再刷新码;
|
|
45
|
-
- 随时需要新码:运行 `tunnelbox-cursor --pair`。
|
|
46
|
-
|
|
47
|
-
### 第 4 步 — 在手机上使用
|
|
48
|
-
|
|
49
|
-
在 App 里打开这台电脑,即可新建会话、发消息、看流式输出、中止运行中的会话。
|
|
50
|
-
|
|
51
|
-
## 配置
|
|
52
|
-
|
|
53
|
-
| 环境变量 | 默认 | 说明 |
|
|
54
|
-
|---|---|---|
|
|
55
|
-
| `TUNNELBOX_RELAY_URL` | state 保存的地址 | 中继地址 |
|
|
56
|
-
| `TUNNELBOX_CWD` | `process.cwd()` | 默认工作区(agent 在该目录跑) |
|
|
57
|
-
| `TUNNELBOX_CURSOR_MODE` | `agent` | `agent` / `plan` / `ask`(`--mode`) |
|
|
58
|
-
| `TUNNELBOX_CURSOR_MODEL` | Cursor 默认 | `--model` |
|
|
59
|
-
| `TUNNELBOX_CURSOR_FORCE` | 关 | 加 `--force`:允许直接改文件(无确认) |
|
|
60
|
-
| `TUNNELBOX_CURSOR_YOLO` | 关 | 加 `--yolo`(更强放行,危险,慎用) |
|
|
61
|
-
| `TUNNELBOX_CURSOR_SANDBOX` | `enabled` | `--sandbox enabled/disabled` |
|
|
62
|
-
| `TUNNELBOX_CURSOR_BIN` | `agent` | Cursor CLI 可执行名/绝对路径 |
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
TUNNELBOX_RELAY_URL=wss://chat.example.com TUNNELBOX_CURSOR_MODE=plan tunnelbox-cursor
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## 能力位
|
|
69
|
-
|
|
70
|
-
| 能力 | 值 | 说明 |
|
|
71
|
-
|---|---|---|
|
|
72
|
-
| streaming | ✅ | stream-json:assistant 增量行 → 实时增量 |
|
|
73
|
-
| thinking | ❌ | Cursor 在 print 模式**抑制思考流**,headless 拿不到推理流 |
|
|
74
|
-
| permission | ❌ | Cursor hooks 面向 IDE / Cmd+K / Cloud agents;headless `agent -p` **无外部审批中继通道** → 无手机审批。放行由 `--force/--yolo` + `--sandbox` + `permissions` allow/deny 决定 |
|
|
75
|
-
| commands | ✅ | `/new`、`/help` |
|
|
76
|
-
| abort | ✅ | kill 子进程(SIGTERM → SIGKILL) |
|
|
77
|
-
| workspaces | ✅ | 会话 `cwd` |
|
|
78
|
-
|
|
79
|
-
## 审批与权限(官方口径)
|
|
80
|
-
|
|
81
|
-
- Cursor 官方 hooks 可 `allow/deny/ask`,但面向 **IDE / Cmd+K / Cloud agents**;文档未说明 headless `agent -p` 会加载 hooks,也没有"等待手机决定后回填"的中继通道。
|
|
82
|
-
- 因此 **`capability.permission=false`**:Cursor headless **不支持手机审批**。放行由 `permissions.allow/deny`(`~/.cursor/cli-config.json` 或 `<项目>/.cursor/cli.json`)+ `--force/--yolo` + `--sandbox` 决定。
|
|
83
|
-
- 默认安全:不传 `--force`(agent 只出方案不改文件),并开启 `--sandbox=enabled`。
|
|
84
|
-
|
|
85
|
-
## 会话模型
|
|
86
|
-
|
|
87
|
-
- 会话 = 本地镜像(`~/.tunnelbox/cursor-sessions/<uuid>/`):每个流式部件/用户消息即时落盘,供列表/历史/删除。
|
|
88
|
-
- 续聊:尽力从流中采集 Cursor chat id(`meta.resumeId`)→ 用 `--resume=<id>`;采集不到则该会话为独立问答(连续上下文受限)。
|
|
89
|
-
- 状态文件:`~/.tunnelbox/remote-state.cursor.json`。
|
|
90
|
-
|
|
91
|
-
## 安全说明
|
|
92
|
-
|
|
93
|
-
- 默认不传 `--force`(agent 不改文件、只出方案),并开 `--sandbox=enabled`;
|
|
94
|
-
- 要实际改代码需显式 `TUNNELBOX_CURSOR_FORCE=1`;请勿在不受信目录启用 yolo;
|
|
95
|
-
- 请勿把敏感工程目录暴露给不受信手机。
|
|
96
|
-
|
|
97
|
-
## 多语言
|
|
98
|
-
|
|
99
|
-
用户可见输出支持 8 种语言(`zh-CN` / `zh-TW` / `en-US` / `ja-JP` / `ko-KR` / `fr-FR` / `de-DE` / `es-ES`)。解析顺序:`TUNNELBOX_LANG` > `remote-state.cursor.json` 的 `lang` > 系统 locale > 默认 `en-US`。
|
|
100
|
-
|
|
101
|
-
## 故障排查
|
|
102
|
-
|
|
103
|
-
| 问题 | 解决 |
|
|
104
|
-
|---|---|
|
|
105
|
-
| 终端没有二维码/配对码 | 运行 `tunnelbox-cursor --pair` 打印新码 |
|
|
106
|
-
| 需要换手机配对 | 在 App 设置里解绑,再带 `--pair` 运行 |
|
|
107
|
-
| 已绑定但手机连不上 | 确认两端同一中继;查看 `~/.tunnelbox/tunnelbox.log` |
|
|
108
|
-
| 使用自建中继 | 启动时带 `TUNNELBOX_RELAY_URL=wss://<你的中继>` |
|
|
109
|
-
|
|
110
|
-
## 状态文件
|
|
111
|
-
|
|
112
|
-
- `~/.tunnelbox/remote-state.cursor.json` — agentID / 中继地址 / 绑定状态 / 语言
|
|
113
|
-
- `~/.tunnelbox/cursor-sessions/` — 本地会话镜像
|
|
114
|
-
- `~/.tunnelbox/remote-pairing.cursor.txt` + `remote-pairing.json` — 最新配对信息
|
|
115
|
-
- `~/.tunnelbox/tunnelbox.log` — 适配器日志
|
|
116
|
-
|
|
117
|
-
## 卸载
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
npm uninstall -g @tunnelbox/cursor
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
仅当不再使用任何 tunnelbox 适配器时,才删除 `~/.tunnelbox`(各适配器共享状态)。
|
|
124
|
-
|
|
125
|
-
## 开发
|
|
126
|
-
|
|
127
|
-
实现细节(协议映射、源码结构、决策记录、待实测项)保存在源码仓库中本包旁的 `DEV.md` 与仓库 `docs/` 下。
|
|
1
|
+
# @tunnelbox/cursor
|
|
2
|
+
|
|
3
|
+
[English](README.md) · [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
**官网:** [www.tunnelbox.top](https://www.tunnelbox.top)
|
|
6
|
+
|
|
7
|
+
**tunnelbox Cursor 适配器(独立进程)**:用手机远程驱动电脑上的 Cursor agent——会话 / 流式 / 中止 / 删除。它驱动 Cursor CLI 的 headless 模式,只向中继发出站连接(无需公网 IP / 端口映射)。
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
手机 App ──WSS──► relay ──WSS──► tunnelbox-cursor(本适配器)
|
|
11
|
+
└─ agent -p --output-format stream-json --stream-partial-output
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## 快速上手(安装 → 运行 → 配对 → 使用)
|
|
15
|
+
|
|
16
|
+
在装有 Cursor CLI 并已配置的电脑上,按以下步骤操作一次即可。
|
|
17
|
+
|
|
18
|
+
### 第 0 步 — 准备手机
|
|
19
|
+
|
|
20
|
+
在官网下载并安装 tunnelbox App(Android / iOS 均已上架):**https://www.tunnelbox.top**
|
|
21
|
+
|
|
22
|
+
- 按提示登录/注册账号。
|
|
23
|
+
|
|
24
|
+
### 第 1 步 — 电脑上安装适配器
|
|
25
|
+
|
|
26
|
+
前置条件:Node.js ≥ 22,且本机已安装并登录 **Cursor CLI**(`agent -p "hello"` 可正常输出)。headless 走 Cursor 计费,需在你的套餐计划内。
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install -g @tunnelbox/cursor
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 第 2 步 — 运行
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
tunnelbox-cursor
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
首次启动会连接中继,并在终端打印**配对二维码 + 配对码**。
|
|
39
|
+
|
|
40
|
+
### 第 3 步 — 与手机配对
|
|
41
|
+
|
|
42
|
+
在手机 App 点「扫一扫配对」,扫描终端二维码(或手动输入配对码)。配对码一次性有效,约 10 分钟。
|
|
43
|
+
|
|
44
|
+
- 绑定后再次启动会打印「已绑定账号,从手机「我的电脑」直接连接」,不再刷新码;
|
|
45
|
+
- 随时需要新码:运行 `tunnelbox-cursor --pair`。
|
|
46
|
+
|
|
47
|
+
### 第 4 步 — 在手机上使用
|
|
48
|
+
|
|
49
|
+
在 App 里打开这台电脑,即可新建会话、发消息、看流式输出、中止运行中的会话。
|
|
50
|
+
|
|
51
|
+
## 配置
|
|
52
|
+
|
|
53
|
+
| 环境变量 | 默认 | 说明 |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `TUNNELBOX_RELAY_URL` | state 保存的地址 | 中继地址 |
|
|
56
|
+
| `TUNNELBOX_CWD` | `process.cwd()` | 默认工作区(agent 在该目录跑) |
|
|
57
|
+
| `TUNNELBOX_CURSOR_MODE` | `agent` | `agent` / `plan` / `ask`(`--mode`) |
|
|
58
|
+
| `TUNNELBOX_CURSOR_MODEL` | Cursor 默认 | `--model` |
|
|
59
|
+
| `TUNNELBOX_CURSOR_FORCE` | 关 | 加 `--force`:允许直接改文件(无确认) |
|
|
60
|
+
| `TUNNELBOX_CURSOR_YOLO` | 关 | 加 `--yolo`(更强放行,危险,慎用) |
|
|
61
|
+
| `TUNNELBOX_CURSOR_SANDBOX` | `enabled` | `--sandbox enabled/disabled` |
|
|
62
|
+
| `TUNNELBOX_CURSOR_BIN` | `agent` | Cursor CLI 可执行名/绝对路径 |
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
TUNNELBOX_RELAY_URL=wss://chat.example.com TUNNELBOX_CURSOR_MODE=plan tunnelbox-cursor
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 能力位
|
|
69
|
+
|
|
70
|
+
| 能力 | 值 | 说明 |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| streaming | ✅ | stream-json:assistant 增量行 → 实时增量 |
|
|
73
|
+
| thinking | ❌ | Cursor 在 print 模式**抑制思考流**,headless 拿不到推理流 |
|
|
74
|
+
| permission | ❌ | Cursor hooks 面向 IDE / Cmd+K / Cloud agents;headless `agent -p` **无外部审批中继通道** → 无手机审批。放行由 `--force/--yolo` + `--sandbox` + `permissions` allow/deny 决定 |
|
|
75
|
+
| commands | ✅ | `/new`、`/help` |
|
|
76
|
+
| abort | ✅ | kill 子进程(SIGTERM → SIGKILL) |
|
|
77
|
+
| workspaces | ✅ | 会话 `cwd` |
|
|
78
|
+
|
|
79
|
+
## 审批与权限(官方口径)
|
|
80
|
+
|
|
81
|
+
- Cursor 官方 hooks 可 `allow/deny/ask`,但面向 **IDE / Cmd+K / Cloud agents**;文档未说明 headless `agent -p` 会加载 hooks,也没有"等待手机决定后回填"的中继通道。
|
|
82
|
+
- 因此 **`capability.permission=false`**:Cursor headless **不支持手机审批**。放行由 `permissions.allow/deny`(`~/.cursor/cli-config.json` 或 `<项目>/.cursor/cli.json`)+ `--force/--yolo` + `--sandbox` 决定。
|
|
83
|
+
- 默认安全:不传 `--force`(agent 只出方案不改文件),并开启 `--sandbox=enabled`。
|
|
84
|
+
|
|
85
|
+
## 会话模型
|
|
86
|
+
|
|
87
|
+
- 会话 = 本地镜像(`~/.tunnelbox/cursor-sessions/<uuid>/`):每个流式部件/用户消息即时落盘,供列表/历史/删除。
|
|
88
|
+
- 续聊:尽力从流中采集 Cursor chat id(`meta.resumeId`)→ 用 `--resume=<id>`;采集不到则该会话为独立问答(连续上下文受限)。
|
|
89
|
+
- 状态文件:`~/.tunnelbox/remote-state.cursor.json`。
|
|
90
|
+
|
|
91
|
+
## 安全说明
|
|
92
|
+
|
|
93
|
+
- 默认不传 `--force`(agent 不改文件、只出方案),并开 `--sandbox=enabled`;
|
|
94
|
+
- 要实际改代码需显式 `TUNNELBOX_CURSOR_FORCE=1`;请勿在不受信目录启用 yolo;
|
|
95
|
+
- 请勿把敏感工程目录暴露给不受信手机。
|
|
96
|
+
|
|
97
|
+
## 多语言
|
|
98
|
+
|
|
99
|
+
用户可见输出支持 8 种语言(`zh-CN` / `zh-TW` / `en-US` / `ja-JP` / `ko-KR` / `fr-FR` / `de-DE` / `es-ES`)。解析顺序:`TUNNELBOX_LANG` > `remote-state.cursor.json` 的 `lang` > 系统 locale > 默认 `en-US`。
|
|
100
|
+
|
|
101
|
+
## 故障排查
|
|
102
|
+
|
|
103
|
+
| 问题 | 解决 |
|
|
104
|
+
|---|---|
|
|
105
|
+
| 终端没有二维码/配对码 | 运行 `tunnelbox-cursor --pair` 打印新码 |
|
|
106
|
+
| 需要换手机配对 | 在 App 设置里解绑,再带 `--pair` 运行 |
|
|
107
|
+
| 已绑定但手机连不上 | 确认两端同一中继;查看 `~/.tunnelbox/tunnelbox.log` |
|
|
108
|
+
| 使用自建中继 | 启动时带 `TUNNELBOX_RELAY_URL=wss://<你的中继>` |
|
|
109
|
+
|
|
110
|
+
## 状态文件
|
|
111
|
+
|
|
112
|
+
- `~/.tunnelbox/remote-state.cursor.json` — agentID / 中继地址 / 绑定状态 / 语言
|
|
113
|
+
- `~/.tunnelbox/cursor-sessions/` — 本地会话镜像
|
|
114
|
+
- `~/.tunnelbox/remote-pairing.cursor.txt` + `remote-pairing.json` — 最新配对信息
|
|
115
|
+
- `~/.tunnelbox/tunnelbox.log` — 适配器日志
|
|
116
|
+
|
|
117
|
+
## 卸载
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm uninstall -g @tunnelbox/cursor
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
仅当不再使用任何 tunnelbox 适配器时,才删除 `~/.tunnelbox`(各适配器共享状态)。
|
|
124
|
+
|
|
125
|
+
## 开发
|
|
126
|
+
|
|
127
|
+
实现细节(协议映射、源码结构、决策记录、待实测项)保存在源码仓库中本包旁的 `DEV.md` 与仓库 `docs/` 下。
|
package/dist/index.mjs
CHANGED
|
@@ -20,6 +20,8 @@ function envelope(type, payload, id) {
|
|
|
20
20
|
}
|
|
21
21
|
var BASE_DELAY = 1e3;
|
|
22
22
|
var MAX_DELAY = 15e3;
|
|
23
|
+
var KEEPALIVE_INTERVAL_MS = 15e3;
|
|
24
|
+
var KEEPALIVE_TIMEOUT_MS = 25e3;
|
|
23
25
|
var RelayClient = class {
|
|
24
26
|
ws = null;
|
|
25
27
|
url = "";
|
|
@@ -29,6 +31,11 @@ var RelayClient = class {
|
|
|
29
31
|
retry = 0;
|
|
30
32
|
stopped = false;
|
|
31
33
|
connected = false;
|
|
34
|
+
reconnectScheduled = false;
|
|
35
|
+
/** 保活心跳定时器(onopen 启动 / onclose 停止) */
|
|
36
|
+
keepaliveTimer = null;
|
|
37
|
+
/** 最近一次收到服务端帧的时间(含心跳回执 pong),用于静默断流检测 */
|
|
38
|
+
lastInbound = 0;
|
|
32
39
|
get isConnected() {
|
|
33
40
|
return this.connected;
|
|
34
41
|
}
|
|
@@ -38,6 +45,8 @@ var RelayClient = class {
|
|
|
38
45
|
this.handlers = handlers;
|
|
39
46
|
this.stopped = false;
|
|
40
47
|
this.retry = 0;
|
|
48
|
+
this.reconnectScheduled = false;
|
|
49
|
+
this.stopKeepalive();
|
|
41
50
|
this.open();
|
|
42
51
|
}
|
|
43
52
|
send(env) {
|
|
@@ -53,6 +62,8 @@ var RelayClient = class {
|
|
|
53
62
|
}
|
|
54
63
|
close() {
|
|
55
64
|
this.stopped = true;
|
|
65
|
+
this.reconnectScheduled = false;
|
|
66
|
+
this.stopKeepalive();
|
|
56
67
|
if (this.timer) clearTimeout(this.timer);
|
|
57
68
|
this.timer = null;
|
|
58
69
|
if (this.ws) {
|
|
@@ -72,11 +83,14 @@ var RelayClient = class {
|
|
|
72
83
|
ws.onopen = () => {
|
|
73
84
|
this.connected = true;
|
|
74
85
|
this.retry = 0;
|
|
86
|
+
this.startKeepalive();
|
|
75
87
|
this.handlers?.onOpen();
|
|
76
88
|
};
|
|
77
89
|
ws.onmessage = (ev) => {
|
|
90
|
+
this.lastInbound = Date.now();
|
|
78
91
|
try {
|
|
79
92
|
const msg = JSON.parse(String(ev.data));
|
|
93
|
+
if (msg.type === "pong") return;
|
|
80
94
|
this.handlers?.onMessage(msg);
|
|
81
95
|
} catch {
|
|
82
96
|
}
|
|
@@ -85,6 +99,7 @@ var RelayClient = class {
|
|
|
85
99
|
ws.onclose = () => {
|
|
86
100
|
this.connected = false;
|
|
87
101
|
this.ws = null;
|
|
102
|
+
this.stopKeepalive();
|
|
88
103
|
this.handlers?.onClose();
|
|
89
104
|
this.scheduleReconnect();
|
|
90
105
|
};
|
|
@@ -94,10 +109,52 @@ var RelayClient = class {
|
|
|
94
109
|
}
|
|
95
110
|
}
|
|
96
111
|
scheduleReconnect() {
|
|
97
|
-
if (this.stopped) return;
|
|
112
|
+
if (this.stopped || this.reconnectScheduled) return;
|
|
113
|
+
this.reconnectScheduled = true;
|
|
98
114
|
const delay = Math.min(BASE_DELAY * 2 ** this.retry, MAX_DELAY);
|
|
99
115
|
this.retry++;
|
|
100
|
-
this.timer = setTimeout(() =>
|
|
116
|
+
this.timer = setTimeout(() => {
|
|
117
|
+
this.reconnectScheduled = false;
|
|
118
|
+
this.open();
|
|
119
|
+
}, delay);
|
|
120
|
+
}
|
|
121
|
+
/** 启动保活心跳:每周期发 ping,长时间收不到任何帧则判定断流主动重连。 */
|
|
122
|
+
startKeepalive() {
|
|
123
|
+
this.stopKeepalive();
|
|
124
|
+
this.lastInbound = Date.now();
|
|
125
|
+
this.keepaliveTimer = setInterval(() => {
|
|
126
|
+
if (!this.connected || !this.ws) return;
|
|
127
|
+
const now = Date.now();
|
|
128
|
+
if (now - this.lastInbound > KEEPALIVE_TIMEOUT_MS) {
|
|
129
|
+
this.forceReconnect();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
this.ws.send(JSON.stringify({ type: "ping", payload: {}, ts: now }));
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
}, KEEPALIVE_INTERVAL_MS);
|
|
137
|
+
}
|
|
138
|
+
stopKeepalive() {
|
|
139
|
+
if (this.keepaliveTimer !== null) {
|
|
140
|
+
clearInterval(this.keepaliveTimer);
|
|
141
|
+
this.keepaliveTimer = null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** 判定连接已死:关闭当前 socket 并调度重连(沿用指数退避,onclose 去重)。 */
|
|
145
|
+
forceReconnect() {
|
|
146
|
+
if (this.stopped) return;
|
|
147
|
+
this.connected = false;
|
|
148
|
+
this.stopKeepalive();
|
|
149
|
+
const w = this.ws;
|
|
150
|
+
this.ws = null;
|
|
151
|
+
if (w) {
|
|
152
|
+
try {
|
|
153
|
+
w.close();
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
this.scheduleReconnect();
|
|
101
158
|
}
|
|
102
159
|
};
|
|
103
160
|
var zh_CN_default = {
|
|
@@ -116,6 +173,7 @@ var zh_CN_default = {
|
|
|
116
173
|
"agent.log.pendingResent": "session.pending: \u8865\u53D1 {session} \u79EF\u538B\u8BF7\u6C42 {count} \u6761",
|
|
117
174
|
"agent.log.unhandledType": "\u672A\u5904\u7406\u7684\u6D88\u606F\u7C7B\u578B: {type}",
|
|
118
175
|
"events.log.fwdPermission": "\u8F6C\u53D1\u6743\u9650\u8BF7\u6C42\u5230\u624B\u673A (id={id} tool={tool} {version})",
|
|
176
|
+
"events.log.sessionDeleted": "\u8F6C\u53D1 session.deleted \u5230\u624B\u673A (session={session})",
|
|
119
177
|
"events.log.permissionReplied": "opencode \u56DE\u6267 permission.replied (id={id} {response})",
|
|
120
178
|
"events.log.questionRejected": "opencode \u56DE\u6267 question.rejected (id={id})",
|
|
121
179
|
"events.log.questionReplied": "opencode \u56DE\u6267 question.replied (id={id})",
|
|
@@ -281,6 +339,7 @@ var zh_TW_default = {
|
|
|
281
339
|
"agent.log.pendingResent": "session.pending: \u88DC\u767C {session} \u7A4D\u58D3\u8ACB\u6C42 {count} \u689D",
|
|
282
340
|
"agent.log.unhandledType": "\u672A\u8655\u7406\u7684\u8A0A\u606F\u985E\u578B: {type}",
|
|
283
341
|
"events.log.fwdPermission": "\u8F49\u767C\u6B0A\u9650\u8ACB\u6C42\u5230\u624B\u6A5F (id={id} tool={tool} {version})",
|
|
342
|
+
"events.log.sessionDeleted": "\u8F49\u767C session.deleted \u5230\u624B\u6A5F (session={session})",
|
|
284
343
|
"events.log.permissionReplied": "opencode \u56DE\u57F7 permission.replied (id={id} {response})",
|
|
285
344
|
"events.log.questionRejected": "opencode \u56DE\u57F7 question.rejected (id={id})",
|
|
286
345
|
"events.log.questionReplied": "opencode \u56DE\u57F7 question.replied (id={id})",
|
|
@@ -446,6 +505,7 @@ var en_US_default = {
|
|
|
446
505
|
"agent.log.pendingResent": "session.pending: resent {count} pending request(s) for {session}",
|
|
447
506
|
"agent.log.unhandledType": "Unhandled message type: {type}",
|
|
448
507
|
"events.log.fwdPermission": "Forwarded permission request to phone (id={id} tool={tool} {version})",
|
|
508
|
+
"events.log.sessionDeleted": "Forwarded session.deleted to phone (session={session})",
|
|
449
509
|
"events.log.permissionReplied": "opencode acked permission.replied (id={id} {response})",
|
|
450
510
|
"events.log.questionRejected": "opencode acked question.rejected (id={id})",
|
|
451
511
|
"events.log.questionReplied": "opencode acked question.replied (id={id})",
|
|
@@ -611,6 +671,7 @@ var ja_JP_default = {
|
|
|
611
671
|
"agent.log.pendingResent": "session.pending: {session} \u306E\u4FDD\u7559\u30EA\u30AF\u30A8\u30B9\u30C8 {count} \u4EF6\u3092\u518D\u9001",
|
|
612
672
|
"agent.log.unhandledType": "\u672A\u51E6\u7406\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u30BF\u30A4\u30D7: {type}",
|
|
613
673
|
"events.log.fwdPermission": "\u6A29\u9650\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u643A\u5E2F\u3078\u8EE2\u9001 (id={id} tool={tool} {version})",
|
|
674
|
+
"events.log.sessionDeleted": "session.deleted \u3092\u643A\u5E2F\u3078\u8EE2\u9001 (session={session})",
|
|
614
675
|
"events.log.permissionReplied": "opencode \u5FDC\u7B54 permission.replied (id={id} {response})",
|
|
615
676
|
"events.log.questionRejected": "opencode \u5FDC\u7B54 question.rejected (id={id})",
|
|
616
677
|
"events.log.questionReplied": "opencode \u5FDC\u7B54 question.replied (id={id})",
|
|
@@ -776,6 +837,7 @@ var ko_KR_default = {
|
|
|
776
837
|
"agent.log.pendingResent": "session.pending: {session} \uBCF4\uB958 \uC694\uCCAD {count}\uAC74 \uC7AC\uC804\uC1A1",
|
|
777
838
|
"agent.log.unhandledType": "\uCC98\uB9AC\uB418\uC9C0 \uC54A\uC740 \uBA54\uC2DC\uC9C0 \uC720\uD615: {type}",
|
|
778
839
|
"events.log.fwdPermission": "\uAD8C\uD55C \uC694\uCCAD\uC744 \uD734\uB300\uD3F0\uC73C\uB85C \uC804\uB2EC (id={id} tool={tool} {version})",
|
|
840
|
+
"events.log.sessionDeleted": "session.deleted\uB97C \uD734\uB300\uD3F0\uC73C\uB85C \uC804\uB2EC (session={session})",
|
|
779
841
|
"events.log.permissionReplied": "opencode \uC751\uB2F5 permission.replied (id={id} {response})",
|
|
780
842
|
"events.log.questionRejected": "opencode \uC751\uB2F5 question.rejected (id={id})",
|
|
781
843
|
"events.log.questionReplied": "opencode \uC751\uB2F5 question.replied (id={id})",
|
|
@@ -941,6 +1003,7 @@ var fr_FR_default = {
|
|
|
941
1003
|
"agent.log.pendingResent": "session.pending : renvoi de {count} demande(s) en attente pour {session}",
|
|
942
1004
|
"agent.log.unhandledType": "Type de message non g\xE9r\xE9 : {type}",
|
|
943
1005
|
"events.log.fwdPermission": "Demande d'autorisation transmise au t\xE9l\xE9phone (id={id} tool={tool} {version})",
|
|
1006
|
+
"events.log.sessionDeleted": "session.deleted transmise au t\xE9l\xE9phone (session={session})",
|
|
944
1007
|
"events.log.permissionReplied": "opencode a accus\xE9 permission.replied (id={id} {response})",
|
|
945
1008
|
"events.log.questionRejected": "opencode a accus\xE9 question.rejected (id={id})",
|
|
946
1009
|
"events.log.questionReplied": "opencode a accus\xE9 question.replied (id={id})",
|
|
@@ -1106,6 +1169,7 @@ var de_DE_default = {
|
|
|
1106
1169
|
"agent.log.pendingResent": "session.pending: {count} ausstehende Anfrage(n) f\xFCr {session} erneut gesendet",
|
|
1107
1170
|
"agent.log.unhandledType": "Nicht behandelter Nachrichtentyp: {type}",
|
|
1108
1171
|
"events.log.fwdPermission": "Berechtigungsanfrage an Telefon weitergeleitet (id={id} tool={tool} {version})",
|
|
1172
|
+
"events.log.sessionDeleted": "session.deleted an Telefon weitergeleitet (session={session})",
|
|
1109
1173
|
"events.log.permissionReplied": "opencode quittierte permission.replied (id={id} {response})",
|
|
1110
1174
|
"events.log.questionRejected": "opencode quittierte question.rejected (id={id})",
|
|
1111
1175
|
"events.log.questionReplied": "opencode quittierte question.replied (id={id})",
|
|
@@ -1271,6 +1335,7 @@ var es_ES_default = {
|
|
|
1271
1335
|
"agent.log.pendingResent": "session.pending: reenviadas {count} solicitud(es) pendientes para {session}",
|
|
1272
1336
|
"agent.log.unhandledType": "Tipo de mensaje no gestionado: {type}",
|
|
1273
1337
|
"events.log.fwdPermission": "Solicitud de permiso reenviada al tel\xE9fono (id={id} tool={tool} {version})",
|
|
1338
|
+
"events.log.sessionDeleted": "session.deleted reenviada al tel\xE9fono (session={session})",
|
|
1274
1339
|
"events.log.permissionReplied": "opencode confirm\xF3 permission.replied (id={id} {response})",
|
|
1275
1340
|
"events.log.questionRejected": "opencode confirm\xF3 question.rejected (id={id})",
|
|
1276
1341
|
"events.log.questionReplied": "opencode confirm\xF3 question.replied (id={id})",
|
|
@@ -1585,7 +1650,7 @@ async function printPairing(code, type, name, lang) {
|
|
|
1585
1650
|
console.log(" " + tt("qr.fileWritten", { path: file }));
|
|
1586
1651
|
console.log("");
|
|
1587
1652
|
}
|
|
1588
|
-
var DEFAULT_PAGE_SIZE =
|
|
1653
|
+
var DEFAULT_PAGE_SIZE = 20;
|
|
1589
1654
|
var MAX_PART_TEXT = 16e3;
|
|
1590
1655
|
var MAX_PART_ARGS = 4e3;
|
|
1591
1656
|
var MAX_PAGE_BYTES = 15e5;
|
|
@@ -2033,7 +2098,7 @@ async function removeSession(sessionID) {
|
|
|
2033
2098
|
}
|
|
2034
2099
|
|
|
2035
2100
|
// src/bridge.ts
|
|
2036
|
-
var VERSION = true ? "0.1.
|
|
2101
|
+
var VERSION = true ? "0.1.11" : "0.0.0-dev";
|
|
2037
2102
|
var AGENT_TYPE = "cursor";
|
|
2038
2103
|
var ADAPTER_COMMANDS = [
|
|
2039
2104
|
{ name: "new", description: "\u65B0\u5EFA\u4F1A\u8BDD" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tunnelbox/cursor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "tunnelbox 的 Cursor 适配器(C 类/B2 头less):手机远程驱动本机 Cursor CLI(agent -p stream-json,会话/流式/中止/删除)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.mjs",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"qrcode": "^1.5.3"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@tunnelbox/core": "0.1.
|
|
34
|
+
"@tunnelbox/core": "0.1.11",
|
|
35
35
|
"@types/node": "^22.0.0",
|
|
36
36
|
"@types/qrcode": "^1.5.5",
|
|
37
37
|
"esbuild": "^0.24.0",
|