botmux 2.25.1 → 2.27.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.en.md +48 -46
- package/README.md +47 -46
- package/dist/adapters/backend/session-backend-selector.d.ts +11 -0
- package/dist/adapters/backend/session-backend-selector.d.ts.map +1 -0
- package/dist/adapters/backend/session-backend-selector.js +26 -0
- package/dist/adapters/backend/session-backend-selector.js.map +1 -0
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +55 -15
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +163 -21
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +90 -14
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/cli.js +259 -40
- package/dist/cli.js.map +1 -1
- package/dist/setup/bots-store.d.ts +3 -0
- package/dist/setup/bots-store.d.ts.map +1 -0
- package/dist/setup/bots-store.js +24 -0
- package/dist/setup/bots-store.js.map +1 -0
- package/dist/setup/lark-scopes.json +301 -0
- package/dist/setup/register-app.d.ts +46 -0
- package/dist/setup/register-app.d.ts.map +1 -0
- package/dist/setup/register-app.js +87 -0
- package/dist/setup/register-app.js.map +1 -0
- package/dist/setup/verify-permissions.d.ts +115 -0
- package/dist/setup/verify-permissions.d.ts.map +1 -0
- package/dist/setup/verify-permissions.js +207 -0
- package/dist/setup/verify-permissions.js.map +1 -0
- package/dist/utils/screenshot-renderer.d.ts.map +1 -1
- package/dist/utils/screenshot-renderer.js +63 -26
- package/dist/utils/screenshot-renderer.js.map +1 -1
- package/dist/utils/terminal-renderer.d.ts +16 -0
- package/dist/utils/terminal-renderer.d.ts.map +1 -1
- package/dist/utils/terminal-renderer.js +35 -21
- package/dist/utils/terminal-renderer.js.map +1 -1
- package/dist/utils/transient-snapshot.d.ts +28 -0
- package/dist/utils/transient-snapshot.d.ts.map +1 -0
- package/dist/utils/transient-snapshot.js +96 -0
- package/dist/utils/transient-snapshot.js.map +1 -0
- package/dist/worker.js +94 -31
- package/dist/worker.js.map +1 -1
- package/package.json +5 -3
package/README.en.md
CHANGED
|
@@ -71,78 +71,71 @@ Compared to OpenClaw-style approaches built on Agent SDKs:
|
|
|
71
71
|
|
|
72
72
|
## 5-Minute Setup
|
|
73
73
|
|
|
74
|
+
> 💡 **TL;DR**: run `botmux setup` and pick "scan-to-create" to finish Steps 1+2 in one shot (the official `@larksuiteoapi/node-sdk` device flow gives you the AppID/AppSecret). PersonalAgent apps come with event subscriptions and bot capability pre-configured, so only Step 4 (permissions) + Step 5 (optional redirect URL) + Step 6 (publish) require browser clicks; the setup wizard writes a JSON file with a one-line clipboard copy command and prints deep-links to each remaining step.
|
|
75
|
+
|
|
74
76
|
### Step 1: Create a Lark App
|
|
75
77
|
|
|
76
|
-
|
|
78
|
+
**Recommended**: `botmux setup` → pick "1) Scan-to-create app". Scan with the Lark mobile app and the AppID/AppSecret are persisted automatically; no manual browser navigation. Falls back to manual paste on cancel/timeout/network error.
|
|
79
|
+
|
|
80
|
+
> ⚠️ **Currently only Feishu (feishu.cn) tenants are supported.** If scan detects a Lark international (larksuite.com) tenant, setup aborts — the daemon runtime (Lark Client/WSClient/event-dispatcher) hasn't been wired up for the `larksuite.com` domain yet, so accepting Lark credentials would land users in a half-working state. A follow-up PR will add full Lark support.
|
|
81
|
+
|
|
82
|
+
**Manual**: go to the [Lark Open Platform](https://open.larkoffice.com/app) and click "Create Custom App".
|
|
77
83
|
|
|
78
84
|

|
|
79
85
|
|
|
80
86
|
### Step 2: Get Credentials
|
|
81
87
|
|
|
88
|
+
> The scan-to-create path completes this step automatically; skip to Step 3.
|
|
89
|
+
|
|
82
90
|
Open the app details page → "Credentials & Basic Info", and copy the **App ID** and **App Secret**.
|
|
83
91
|
|
|
84
92
|

|
|
85
93
|
|
|
86
|
-
### Step 3:
|
|
87
|
-
|
|
88
|
-
Go to "Permissions & Scopes" → "Batch Import/Export", and paste the following JSON to import all permissions at once:
|
|
89
|
-
|
|
90
|
-

|
|
91
|
-
|
|
92
|
-
<details>
|
|
93
|
-
<summary>Click to expand batch import JSON</summary>
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
{
|
|
97
|
-
"scopes": {
|
|
98
|
-
"tenant": [
|
|
99
|
-
"contact:user.base:readonly",
|
|
100
|
-
"contact:user.id:readonly",
|
|
101
|
-
"im:chat:read",
|
|
102
|
-
"im:chat.members:bot_access",
|
|
103
|
-
"im:chat.members:read",
|
|
104
|
-
"im:message",
|
|
105
|
-
"im:message:readonly",
|
|
106
|
-
"im:message:send_as_bot",
|
|
107
|
-
"im:message:update",
|
|
108
|
-
"im:message.group_at_msg",
|
|
109
|
-
"im:message.group_at_msg:readonly",
|
|
110
|
-
"im:message.group_msg",
|
|
111
|
-
"im:message.p2p_msg:readonly",
|
|
112
|
-
"im:message.reactions:write_only",
|
|
113
|
-
"im:resource"
|
|
114
|
-
]
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
</details>
|
|
119
|
-
|
|
120
|
-
### Step 4: Install & Start botmux
|
|
94
|
+
### Step 3: Install & Start botmux
|
|
121
95
|
|
|
122
96
|
```bash
|
|
123
97
|
# Install
|
|
124
98
|
npm install -g botmux
|
|
125
99
|
|
|
126
|
-
# Interactive setup —
|
|
100
|
+
# Interactive setup — pick "1) Scan-to-create app" or "2) Paste AppID/Secret manually".
|
|
101
|
+
# Credentials are validated with a tenant_access_token call before bots.json is written.
|
|
102
|
+
# At the end of setup the wizard writes the full scope JSON to ~/.botmux/lark-scopes.json
|
|
103
|
+
# and prints a one-line clipboard copy command for your platform.
|
|
127
104
|
botmux setup
|
|
128
105
|
|
|
129
|
-
# Start (
|
|
106
|
+
# Start (if you ever need to verify the event subscription, Lark requires the daemon to be running so it can detect the WebSocket connection)
|
|
107
|
+
# Re-validates credentials before forking workers; missing scopes only WARN, do not block the daemon.
|
|
130
108
|
botmux start
|
|
131
109
|
```
|
|
132
110
|
|
|
133
|
-
### Step
|
|
111
|
+
### Step 4: Add Permissions
|
|
134
112
|
|
|
135
|
-
|
|
113
|
+
Run the copy-to-clipboard command setup printed, then go to "Permissions & Scopes" → "Batch Import/Export" and paste. Submit for review — visibility "only me" auto-approves.
|
|
136
114
|
|
|
137
|
-
|
|
115
|
+

|
|
138
116
|
|
|
139
|
-
|
|
117
|
+
The full JSON lives at `~/.botmux/lark-scopes.json` (also tracked in-repo at [src/setup/lark-scopes.json](src/setup/lark-scopes.json), kept in sync with the internal wiki, covers ~290 tenant + user scopes).
|
|
140
118
|
|
|
141
|
-
|
|
119
|
+
```bash
|
|
120
|
+
# macOS
|
|
121
|
+
cat ~/.botmux/lark-scopes.json | pbcopy
|
|
122
|
+
# Linux X
|
|
123
|
+
cat ~/.botmux/lark-scopes.json | xclip -selection clipboard
|
|
124
|
+
# Wayland
|
|
125
|
+
cat ~/.botmux/lark-scopes.json | wl-copy
|
|
126
|
+
```
|
|
142
127
|
|
|
143
|
-
|
|
128
|
+
> Scan-created PersonalAgent apps have `im.message.receive_v1` + `card.action.trigger` subscribed and the bot capability enabled out of the box, per botmux maintainer testing. Lark hasn't documented this as stable behavior, so **if the bot receives no messages at all after setup**, see "Step 8: Troubleshoot — bot not receiving messages" below for a manual fallback.
|
|
144
129
|
|
|
145
|
-
|
|
130
|
+
### Step 5: Add Redirect URL (optional)
|
|
131
|
+
|
|
132
|
+
If you plan to use `/login` inside Lark to let botmux act on your behalf for docs / calendar / wiki / sheets, add a redirect URL under "Security Settings" → "Redirect URL":
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
http://127.0.0.1:9768/callback
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Skip this step if you only need bot messaging.
|
|
146
139
|
|
|
147
140
|
### Step 6: Publish the App
|
|
148
141
|
|
|
@@ -158,7 +151,16 @@ Go to "Version Management & Release", click "Create Version" and publish. Set av
|
|
|
158
151
|
|
|
159
152
|

|
|
160
153
|
|
|
161
|
-
### Step 8:
|
|
154
|
+
### Step 8: Troubleshoot — bot not receiving messages (fallback)
|
|
155
|
+
|
|
156
|
+
PersonalAgent apps come with event subscriptions and bot capability pre-configured; in normal cases you don't touch this. If the bot **receives no messages at all** after setup (not even DMs), verify these two settings:
|
|
157
|
+
|
|
158
|
+
- **Event subscription**: Open Platform → your app → Events & Callbacks → should be subscribed to `im.message.receive_v1` + `card.action.trigger`. If missing, add them manually. Subscription mode must be "Receive via persistent connection" (WebSocket), and the botmux daemon must be running.
|
|
159
|
+
- **Bot capability**: Open Platform → your app → Features → Bot should be enabled (it is by default). Adjust name/avatar if needed.
|
|
160
|
+
|
|
161
|
+
After verifying, restart: `botmux restart`.
|
|
162
|
+
|
|
163
|
+
### Step 9: Enable Boot-time Autostart (recommended)
|
|
162
164
|
|
|
163
165
|
Once the bot is sending and receiving messages cleanly, run:
|
|
164
166
|
|
package/README.md
CHANGED
|
@@ -173,78 +173,70 @@ CLI 进入 botmux 会话时自动获得 `~/.botmux/bin` 在 PATH 中,以及一
|
|
|
173
173
|
|
|
174
174
|
## 5 分钟快速接入
|
|
175
175
|
|
|
176
|
+
> 💡 **TL;DR**:跑 `botmux setup` 选「扫码建应用」一步完成 Step 1+2(拿 AppID/AppSecret)。PersonalAgent 应用建出来时事件订阅和 bot 能力都已默认配好,只剩 Step 4 权限申请 + Step 5(按需)重定向 URL + Step 6 发版三步要在浏览器手动点;setup 完成后会自动写 JSON 文件 + 打印一键复制命令 + 各步骤的深链。
|
|
177
|
+
|
|
176
178
|
### Step 1: 创建飞书应用
|
|
177
179
|
|
|
178
|
-
|
|
180
|
+
**推荐路径**:`botmux setup` 选「1) 扫码建应用」,飞书扫码完成后自动落盘 AppID/AppSecret,无需手动浏览器创建。底层走 `@larksuiteoapi/node-sdk` 的官方 device flow。
|
|
181
|
+
|
|
182
|
+
> ⚠️ **目前仅支持飞书 (feishu.cn) 租户**。扫码检测到 Lark 国际版 (larksuite.com) 会中止 setup —— daemon runtime (Lark Client/WSClient/event-dispatcher 等) 需要一并接入 lark 域,会在单独 PR 跟进。
|
|
183
|
+
|
|
184
|
+
**手动路径**:打开 [飞书开放平台](https://open.larkoffice.com/app),点击「创建企业自建应用」。
|
|
179
185
|
|
|
180
186
|

|
|
181
187
|
|
|
182
188
|
### Step 2: 获取凭证
|
|
183
189
|
|
|
190
|
+
> 扫码路径自动完成此步,可直接跳到 Step 3。
|
|
191
|
+
|
|
184
192
|
进入应用详情 →「凭证与基础信息」,复制 **App ID** 和 **App Secret**。
|
|
185
193
|
|
|
186
194
|

|
|
187
195
|
|
|
188
|
-
### Step 3:
|
|
189
|
-
|
|
190
|
-
进入「权限管理」→「批量导入/导出权限」,粘贴以下 JSON 一次性导入所有权限:
|
|
191
|
-
|
|
192
|
-

|
|
193
|
-
|
|
194
|
-
<details>
|
|
195
|
-
<summary>点击展开批量导入 JSON</summary>
|
|
196
|
-
|
|
197
|
-
```json
|
|
198
|
-
{
|
|
199
|
-
"scopes": {
|
|
200
|
-
"tenant": [
|
|
201
|
-
"contact:user.base:readonly",
|
|
202
|
-
"contact:user.id:readonly",
|
|
203
|
-
"im:chat:read",
|
|
204
|
-
"im:chat.members:bot_access",
|
|
205
|
-
"im:chat.members:read",
|
|
206
|
-
"im:message",
|
|
207
|
-
"im:message:readonly",
|
|
208
|
-
"im:message:send_as_bot",
|
|
209
|
-
"im:message:update",
|
|
210
|
-
"im:message.group_at_msg",
|
|
211
|
-
"im:message.group_at_msg:readonly",
|
|
212
|
-
"im:message.group_msg",
|
|
213
|
-
"im:message.p2p_msg:readonly",
|
|
214
|
-
"im:message.reactions:write_only",
|
|
215
|
-
"im:resource"
|
|
216
|
-
]
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
</details>
|
|
221
|
-
|
|
222
|
-
### Step 4: 安装 & 启动 botmux
|
|
196
|
+
### Step 3: 安装 & 启动 botmux
|
|
223
197
|
|
|
224
198
|
```bash
|
|
225
199
|
# 安装
|
|
226
200
|
npm install -g botmux
|
|
227
201
|
|
|
228
|
-
# 交互式配置 —
|
|
202
|
+
# 交互式配置 — 选「1) 扫码建应用」或「2) 手动粘 AppID/Secret」
|
|
203
|
+
# 凭证拿到后自动取一次 tenant_access_token 校验,通过才落盘 bots.json
|
|
204
|
+
# setup 末尾会把完整权限 JSON 写到 ~/.botmux/lark-scopes.json 并打印一键复制命令
|
|
229
205
|
botmux setup
|
|
230
206
|
|
|
231
|
-
#
|
|
207
|
+
# 启动(如果之后需要确认事件订阅,飞书后台会要求 daemon 已在跑才能识别长连接)
|
|
208
|
+
# start 前再校验一次凭证;权限未配齐不会阻塞 daemon,只 WARN
|
|
232
209
|
botmux start
|
|
233
210
|
```
|
|
234
211
|
|
|
235
|
-
### Step
|
|
212
|
+
### Step 4: 添加权限
|
|
236
213
|
|
|
237
|
-
|
|
214
|
+
setup 完成后,按 terminal 提示的一键复制命令把权限 JSON 复制到剪贴板,进入「权限管理」→「批量导入/导出权限」粘贴 → 提交审批。可用性范围选「仅自己可见」会自动通过:
|
|
238
215
|
|
|
239
|
-
|
|
216
|
+

|
|
240
217
|
|
|
241
|
-
|
|
218
|
+
完整 JSON 已经写到 `~/.botmux/lark-scopes.json`,源仓库版本在 [src/setup/lark-scopes.json](src/setup/lark-scopes.json)(与本仓库内部 wiki 文档同步,覆盖 tenant + user 双套域 ≈ 290 项)。
|
|
242
219
|
|
|
243
|
-
|
|
220
|
+
```bash
|
|
221
|
+
# macOS
|
|
222
|
+
cat ~/.botmux/lark-scopes.json | pbcopy
|
|
223
|
+
# Linux X
|
|
224
|
+
cat ~/.botmux/lark-scopes.json | xclip -selection clipboard
|
|
225
|
+
# Wayland
|
|
226
|
+
cat ~/.botmux/lark-scopes.json | wl-copy
|
|
227
|
+
```
|
|
244
228
|
|
|
245
|
-
|
|
229
|
+
> 扫码建出来的 PersonalAgent 应用,botmux 维护者实测默认已订阅 `im.message.receive_v1` + `card.action.trigger` 并开通 bot 能力,所以主线流程不再要求手动配。但飞书没在公开文档里承诺这是稳定行为,**如果配好后机器人完全收不到消息**,参见下方「Step 8: 机器人收不到消息时的自查」。
|
|
246
230
|
|
|
247
|
-
|
|
231
|
+
### Step 5: 添加重定向 URL(按需)
|
|
232
|
+
|
|
233
|
+
如果之后要在飞书里 `/login` 让 botmux 以你的身份调云文档/日历/Wiki 等 API,进入「安全设置」→「重定向 URL」填入:
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
http://127.0.0.1:9768/callback
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
只用 bot 收发消息的话这一步可以跳过。
|
|
248
240
|
|
|
249
241
|
### Step 6: 发版
|
|
250
242
|
|
|
@@ -260,7 +252,16 @@ botmux start
|
|
|
260
252
|
|
|
261
253
|

|
|
262
254
|
|
|
263
|
-
### Step 8:
|
|
255
|
+
### Step 8: 机器人收不到消息时的自查(fallback)
|
|
256
|
+
|
|
257
|
+
PersonalAgent 默认配好事件订阅 + bot 能力,正常情况下不用动。如果按上面步骤走完 bot **完全收不到任何消息**(连私聊都不回),分别确认这两项:
|
|
258
|
+
|
|
259
|
+
- **事件订阅**:开放平台 → 你的应用 → 事件与回调 → 应当订阅 `im.message.receive_v1` + `card.action.trigger`(默认已订阅,如缺失就手动添加)。订阅方式必须是「使用长连接接收事件」(WebSocket),且 botmux daemon 已经在跑。
|
|
260
|
+
- **机器人能力**:开放平台 → 你的应用 → 应用功能 → 机器人 应当已开通(默认开通),名字/头像可以改。
|
|
261
|
+
|
|
262
|
+
确认后重启 daemon:`botmux restart`。
|
|
263
|
+
|
|
264
|
+
### Step 9: 开机自启(推荐)
|
|
264
265
|
|
|
265
266
|
确认机器人能正常收发消息之后,跑一次:
|
|
266
267
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SessionBackend } from './types.js';
|
|
2
|
+
export interface SelectedSessionBackend {
|
|
3
|
+
backend: SessionBackend;
|
|
4
|
+
isTmuxMode: boolean;
|
|
5
|
+
isPipeMode: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function selectSessionBackend(opts: {
|
|
8
|
+
sessionId: string;
|
|
9
|
+
useTmux: boolean;
|
|
10
|
+
}): SelectedSessionBackend;
|
|
11
|
+
//# sourceMappingURL=session-backend-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-backend-selector.d.ts","sourceRoot":"","sources":["../../../src/adapters/backend/session-backend-selector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,sBAAsB,CAuB1G"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PtyBackend } from './pty-backend.js';
|
|
2
|
+
import { TmuxBackend } from './tmux-backend.js';
|
|
3
|
+
import { TmuxPipeBackend } from './tmux-pipe-backend.js';
|
|
4
|
+
export function selectSessionBackend(opts) {
|
|
5
|
+
if (!opts.useTmux) {
|
|
6
|
+
return {
|
|
7
|
+
backend: new PtyBackend(),
|
|
8
|
+
isTmuxMode: false,
|
|
9
|
+
isPipeMode: false,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const sessionName = TmuxBackend.sessionName(opts.sessionId);
|
|
13
|
+
if (TmuxBackend.hasSession(sessionName)) {
|
|
14
|
+
return {
|
|
15
|
+
backend: new TmuxPipeBackend(sessionName, { ownsSession: true, isReattach: true }),
|
|
16
|
+
isTmuxMode: true,
|
|
17
|
+
isPipeMode: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
backend: new TmuxPipeBackend(sessionName, { createSession: true, ownsSession: true }),
|
|
22
|
+
isTmuxMode: true,
|
|
23
|
+
isPipeMode: true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=session-backend-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-backend-selector.js","sourceRoot":"","sources":["../../../src/adapters/backend/session-backend-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AASzD,MAAM,UAAU,oBAAoB,CAAC,IAA6C;IAChF,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO;YACL,OAAO,EAAE,IAAI,UAAU,EAAE;YACzB,UAAU,EAAE,KAAK;YACjB,UAAU,EAAE,KAAK;SAClB,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5D,IAAI,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACxC,OAAO;YACL,OAAO,EAAE,IAAI,eAAe,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;YAClF,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,EAAE,IAAI,eAAe,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QACrF,UAAU,EAAE,IAAI;QAChB,UAAU,EAAE,IAAI;KACjB,CAAC;AACJ,CAAC"}
|
|
@@ -4,22 +4,42 @@ import type { SessionBackend, SpawnOpts } from './types.js';
|
|
|
4
4
|
* to xterm.js (which treats bare LF as "down one row, keep column"). */
|
|
5
5
|
export declare function normaliseCaptureLineEndings(s: string): string;
|
|
6
6
|
export declare class TmuxPipeBackend implements SessionBackend {
|
|
7
|
-
/** Real tmux pane address (e.g. "0:2.0"). */
|
|
7
|
+
/** Real tmux pane address (e.g. "0:2.0") or botmux session name (bmx-*). */
|
|
8
8
|
private readonly paneTarget;
|
|
9
9
|
private readonly fifoPath;
|
|
10
10
|
private readStream;
|
|
11
11
|
private readonly dataCbs;
|
|
12
12
|
private readonly exitCbs;
|
|
13
|
+
private lifecycleTimer;
|
|
13
14
|
private cols;
|
|
14
15
|
private rows;
|
|
15
16
|
private exited;
|
|
16
17
|
/** Set after pipe-pane subscription is active so kill() knows to cancel it. */
|
|
17
18
|
private pipeAttached;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
private readonly createSession;
|
|
20
|
+
private readonly ownsSession;
|
|
21
|
+
private readonly _isReattach;
|
|
22
|
+
/** Claude Code session JSONL path — set by worker for claude-code sessions so
|
|
23
|
+
* the claude-code adapter can verify paste+Enter submissions via file growth. */
|
|
24
|
+
claudeJsonlPath?: string;
|
|
25
|
+
/** PID of the spawned Claude Code child — used by the claude-code adapter to
|
|
26
|
+
* follow Claude's authoritative session id via ~/.claude/sessions/<pid>.json. */
|
|
27
|
+
cliPid?: number;
|
|
28
|
+
/** Working directory the CLI was spawned in — cross-checked against the pid
|
|
29
|
+
* file's cwd field so a recycled PID can't mislead the resolver. */
|
|
30
|
+
cliCwd?: string;
|
|
31
|
+
/** Whether this backend re-attached to an existing bmx-* tmux session
|
|
32
|
+
* (rather than creating a new detached one). Mirrors TmuxBackend.isReattach
|
|
33
|
+
* so the worker can branch on reattach behaviour without a private-cast. */
|
|
34
|
+
get isReattach(): boolean;
|
|
35
|
+
constructor(paneTarget: string, opts?: {
|
|
36
|
+
createSession?: boolean;
|
|
37
|
+
ownsSession?: boolean;
|
|
38
|
+
isReattach?: boolean;
|
|
39
|
+
});
|
|
40
|
+
/** spawn() sets up the pipe-pane subscription + fifo reader. In managed
|
|
41
|
+
* mode it first creates a detached bmx-* tmux session that runs the CLI. */
|
|
42
|
+
spawn(bin: string, args: string[], opts: SpawnOpts): void;
|
|
23
43
|
write(data: string): void;
|
|
24
44
|
sendText(text: string): void;
|
|
25
45
|
sendSpecialKeys(...keys: string[]): void;
|
|
@@ -34,20 +54,40 @@ export declare class TmuxPipeBackend implements SessionBackend {
|
|
|
34
54
|
destroySession(): void;
|
|
35
55
|
getChildPid(): number | null;
|
|
36
56
|
getAttachInfo(): null;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
57
|
+
private startLifecycleWatcher;
|
|
58
|
+
private stopLifecycleWatcher;
|
|
59
|
+
private handlePaneExit;
|
|
60
|
+
private createDetachedSession;
|
|
61
|
+
private applySessionOptions;
|
|
62
|
+
/** Snapshot the full pane history WITH ANSI escapes (`-S - -E -`).
|
|
63
|
+
*
|
|
64
|
+
* Used by web reattach so a brand-new web client sees the whole prior
|
|
65
|
+
* conversation. For the screenshot / screen_update fast path use
|
|
66
|
+
* `captureViewport()` instead — that one only returns the visible pane
|
|
67
|
+
* and is safe to seed a transient xterm-headless with.
|
|
41
68
|
*
|
|
42
69
|
* IMPORTANT: tmux capture-pane separates rows with bare `\n`, no `\r`.
|
|
43
70
|
* xterm.js (and any VT100-compliant emulator) treats a bare LF as
|
|
44
71
|
* "move down one row, keep column" — every captured line lands further
|
|
45
|
-
* to the right than the previous one
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* itself doesn't need this fix — applications write proper `\r\n` (and
|
|
49
|
-
* Claude Code uses cursor-positioning instead of bare LF anyway). */
|
|
72
|
+
* to the right than the previous one. Normalising every `\n` to `\r\n`
|
|
73
|
+
* makes the snapshot render correctly. The live pipe-pane stream itself
|
|
74
|
+
* doesn't need this fix — applications write proper `\r\n`. */
|
|
50
75
|
captureCurrentScreen(): string;
|
|
76
|
+
/** Snapshot ONLY the currently visible pane (no scrollback). Equivalent to
|
|
77
|
+
* `tmux capture-pane` with no `-S`/`-E` flags, which defaults to the
|
|
78
|
+
* viewport. This is the right input for a transient xterm-headless seed:
|
|
79
|
+
* the snapshot row count matches the transient terminal's row count, so
|
|
80
|
+
* no normal-buffer scroll happens and the rendered screenshot lines up
|
|
81
|
+
* with what the user is seeing in the web terminal right now. */
|
|
82
|
+
captureViewport(): string;
|
|
83
|
+
private captureWithBounds;
|
|
84
|
+
/** Current real tmux pane dimensions. Drives transient-renderer sizing so
|
|
85
|
+
* the screenshot canvas matches whatever the web client resized the pane
|
|
86
|
+
* to. Returns null if tmux can't be queried (pane gone, server gone). */
|
|
87
|
+
getPaneSize(): {
|
|
88
|
+
cols: number;
|
|
89
|
+
rows: number;
|
|
90
|
+
} | null;
|
|
51
91
|
/** Cheap probe: is the adopted pane currently in the alternate screen
|
|
52
92
|
* buffer? Used by captureCurrentScreen to decide whether the snapshot
|
|
53
93
|
* needs an alt-buffer-enter prefix for correct rendering. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tmux-pipe-backend.d.ts","sourceRoot":"","sources":["../../../src/adapters/backend/tmux-pipe-backend.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"tmux-pipe-backend.d.ts","sourceRoot":"","sources":["../../../src/adapters/backend/tmux-pipe-backend.ts"],"names":[],"mappings":"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"}
|