besh 0.1.0__tar.gz
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.
- besh-0.1.0/.gitignore +4 -0
- besh-0.1.0/LICENSE.txt +9 -0
- besh-0.1.0/PKG-INFO +244 -0
- besh-0.1.0/README.md +217 -0
- besh-0.1.0/pyproject.toml +82 -0
- besh-0.1.0/src/besh/__about__.py +4 -0
- besh-0.1.0/src/besh/__init__.py +18 -0
- besh-0.1.0/src/besh/__main__.py +9 -0
- besh-0.1.0/src/besh/beacon.py +767 -0
- besh-0.1.0/src/besh/cli.py +754 -0
- besh-0.1.0/src/besh/client.py +119 -0
- besh-0.1.0/src/besh/serve.py +191 -0
- besh-0.1.0/src/besh/skills/besh/SKILL.md +102 -0
- besh-0.1.0/src/besh/storage.py +193 -0
- besh-0.1.0/src/besh/store.py +281 -0
- besh-0.1.0/src/besh/target.py +34 -0
- besh-0.1.0/src/besh/util.py +152 -0
- besh-0.1.0/src/besh/worker.py +574 -0
- besh-0.1.0/src/besh/www/index.html +719 -0
- besh-0.1.0/tests/__init__.py +3 -0
- besh-0.1.0/tests/fake_worker.py +178 -0
- besh-0.1.0/tests/test_beacon.py +227 -0
- besh-0.1.0/tests/test_store.py +132 -0
- besh-0.1.0/tests/test_util.py +85 -0
- besh-0.1.0/tests/test_worker.py +181 -0
besh-0.1.0/.gitignore
ADDED
besh-0.1.0/LICENSE.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026-present cqian-cs <cqian.cs@qq.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
besh-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: besh
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Beacon Shell:让 Agent 把计算任务交给闲置算力(手机 Termux / 云 IDE / 云 Notebook)
|
|
5
|
+
Project-URL: Documentation, https://github.com/cqian-cs/besh#readme
|
|
6
|
+
Project-URL: Issues, https://github.com/cqian-cs/besh/issues
|
|
7
|
+
Project-URL: Source, https://github.com/cqian-cs/besh
|
|
8
|
+
Author-email: cqian-cs <cqian.cs@qq.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE.txt
|
|
11
|
+
Keywords: agent,beacon,rclone,remote,tmux,worker
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: aiofiles>=22.1
|
|
20
|
+
Requires-Dist: aiohttp>=3.8
|
|
21
|
+
Requires-Dist: orjson>=3.6
|
|
22
|
+
Requires-Dist: sqless>=5.0.1
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'test'
|
|
25
|
+
Requires-Dist: pytest>=7.0; extra == 'test'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Beacon Shell (besh)
|
|
29
|
+
|
|
30
|
+
**把闲置算力变成 AI Agent 可远程操作的工人。**
|
|
31
|
+
|
|
32
|
+
闲置算力随处可见:手机 Termux、免费的云 IDE、云 Notebook……但它们大多没有公网 IP,没法通过 SSH 远程操作。
|
|
33
|
+
|
|
34
|
+
besh 用一个"信标 + 工人"的架构解决这个问题:只要闲置终端能访问外网,就能反向连接信标、领取命令、回传结果——你(或你的 AI Agent)则可以像操作 tmux 一样操作散落在各处的机器。
|
|
35
|
+
|
|
36
|
+
```mermaid
|
|
37
|
+
flowchart TB
|
|
38
|
+
UR["人类"]
|
|
39
|
+
AG["AI Agent"]
|
|
40
|
+
RC["本地电脑<br>besh run -t 工人ID:窗口名 命令"]
|
|
41
|
+
BE["公网服务器<br>besh serve"]
|
|
42
|
+
|
|
43
|
+
UR -- CLI --> RC
|
|
44
|
+
UR -- Web --> BE
|
|
45
|
+
AG -- CLI --> RC -- API --> BE
|
|
46
|
+
AG -- MCP --> BE
|
|
47
|
+
|
|
48
|
+
BE <-- "轮询取命令 <br> 回传屏幕 / 结果" --> W1["闲置算力<br>besh worker 工人ID"]
|
|
49
|
+
BE <-- "轮询取命令 <br> 回传屏幕 / 结果" --> W2["闲置算力<br>besh worker 工人ID"]
|
|
50
|
+
|
|
51
|
+
W1 -.->|"rclone 定时备份"| R2[("对象存储<br>Cloudflare R2")]
|
|
52
|
+
W2 -.->|"rclone 定时备份"| R2
|
|
53
|
+
|
|
54
|
+
classDef purple fill:#ede9fe,stroke:#7c3aed,color:#1e293b
|
|
55
|
+
classDef blue fill:#dbeafe,stroke:#2563eb,color:#1e293b
|
|
56
|
+
classDef green fill:#d1fae5,stroke:#059669,color:#1e293b
|
|
57
|
+
classDef amber fill:#fef3c7,stroke:#d97706,color:#1e293b
|
|
58
|
+
|
|
59
|
+
class RC,AG,UR purple
|
|
60
|
+
class BE blue
|
|
61
|
+
class W1,W2 green
|
|
62
|
+
class R2 amber
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 四个角色
|
|
66
|
+
|
|
67
|
+
| 角色 | 运行位置 | 职责 |
|
|
68
|
+
|------|----------|------|
|
|
69
|
+
| 信标 | 有公网 IP 的服务器 | 中转命令、记录状态、提供 Web 界面与 MCP 接口 |
|
|
70
|
+
| 工人 | 任意闲置终端(无公网 IP) | 轮询信标领命令,在 tmux 窗口里执行,定时备份工作目录 |
|
|
71
|
+
| 遥控器 | 本地电脑 | 类似 tmux 的命令行,把 session 换成工人 ID,可同时操作多台 |
|
|
72
|
+
| 对象存储 | Cloudflare R2 | 备份工人工作目录(工人是临时的,随时会释放) |
|
|
73
|
+
|
|
74
|
+
## 安装
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pip install besh
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
要求 Python ≥ 3.10。工人机器上还需要安装 [tmux](https://github.com/tmux/tmux)。
|
|
81
|
+
|
|
82
|
+
## 快速开始
|
|
83
|
+
|
|
84
|
+
### 1. 启动信标(云服务器)
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
export besh_secret=CHANGE_TO_YOUR_PASSWORD
|
|
88
|
+
besh serve
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
启动时会生成自包含的 `besh_beacon.py`(主程序)和 `www/index.html`(Web 界面),数据存放在 `./db/`。默认监听 `12242` 端口,输出类似:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
工人连接 : export besh_url=http://<HOST>:12242?secret=xxx
|
|
95
|
+
浏览器 : http://<HOST>:12242/?secret=xxx
|
|
96
|
+
MCP : http://<HOST>:12242/mcp (Authorization: Bearer xxx)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 2. 接入工人(闲置终端)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
export besh_url=http://BEACON-HOST:12242?secret=CHANGE_TO_YOUR_PASSWORD
|
|
103
|
+
besh worker WORKER_ID
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- 会创建 `./WORKER_ID` 作为工作目录,后续所有命令都在这个目录里执行
|
|
107
|
+
- 通过 tmux 启动 `besh_worker` 会话(创建窗口、执行命令)和 `besh_sync` 会话(定时把工作目录同步到对象存储)
|
|
108
|
+
|
|
109
|
+
### 3. 远程操作(本地电脑)
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
export besh_url=http://BEACON-HOST:12242?secret=CHANGE_TO_YOUR_PASSWORD
|
|
113
|
+
|
|
114
|
+
# 列出所有工人(ls / list-sessions / list-workers 等价)
|
|
115
|
+
besh ls
|
|
116
|
+
|
|
117
|
+
# 列出某工人的所有窗口
|
|
118
|
+
besh list-windows -t WORKER_ID
|
|
119
|
+
|
|
120
|
+
# 查看窗口内容(同 tmux capture-pane)
|
|
121
|
+
besh capture-pane -t WORKER_ID:WINDOW_NAME -p -S -50
|
|
122
|
+
|
|
123
|
+
# 发送按键(窗口不存在会自动创建)
|
|
124
|
+
besh send-keys -t WORKER_ID:WINDOW_NAME "ls -l" Enter
|
|
125
|
+
|
|
126
|
+
# 发送按键,-l 按字面处理(不展开变量)
|
|
127
|
+
besh send-keys -t WORKER_ID:WINDOW_NAME -l 'echo "Hello $USER"'
|
|
128
|
+
|
|
129
|
+
# 执行一条命令并打印输出(体验类似 ssh host cmd)
|
|
130
|
+
besh run -t WORKER_ID "uname -a"
|
|
131
|
+
|
|
132
|
+
# 跑长任务:先输入不等待,稍后等它执行完(窗口回到提示符)
|
|
133
|
+
besh type -t WORKER_ID:WINDOW_NAME "python train.py"
|
|
134
|
+
besh wait -t WORKER_ID:WINDOW_NAME
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 对象存储(Cloudflare R2)
|
|
138
|
+
|
|
139
|
+
信标带宽贵、网速慢,不适合备份工作目录;[Cloudflare R2](https://developers.cloudflare.com/r2/) 免费 10GB 且网速快,所以用它。工人工作目录备份在 `cf:besh/YYYY-MM-DD/WORKER_ID/*`。
|
|
140
|
+
|
|
141
|
+
1. 开通 Cloudflare R2,创建存储桶 `besh`
|
|
142
|
+
2. 在信标与工人机器上安装 [rclone](https://rclone.org/install/):
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
sudo -v ; curl https://rclone.org/install.sh | sudo bash
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
3. 配置 rclone 环境变量访问 R2:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
export RCLONE_CONFIG_CF_TYPE=s3
|
|
152
|
+
export RCLONE_CONFIG_CF_PROVIDER=Cloudflare
|
|
153
|
+
export RCLONE_CONFIG_CF_ACCESS_KEY_ID=
|
|
154
|
+
export RCLONE_CONFIG_CF_SECRET_ACCESS_KEY=
|
|
155
|
+
export RCLONE_CONFIG_CF_ENDPOINT=
|
|
156
|
+
export RCLONE_CONFIG_CF_REGION=auto
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
配置好后,遥控器即可管理备份:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
besh backup -t WORKER_ID # 立刻备份(不等定时任务)
|
|
163
|
+
besh restore -t WORKER_ID # 从最新备份恢复工作目录
|
|
164
|
+
besh files -t WORKER_ID # 列出对象存储里的备份文件
|
|
165
|
+
besh download / besh upload / besh rm # 下载 / 上传 / 删除文件
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Web 操作界面
|
|
169
|
+
|
|
170
|
+
浏览器打开 `http://BEACON-HOST:12242?secret=xxx`:
|
|
171
|
+
|
|
172
|
+
- 每个工人的实时状态(主机名、工作目录、窗口列表、在线状态)
|
|
173
|
+
- 完善的 WebShell:实时屏幕、输入框、`^C` / `^D` / `Tab` / `↑` / `↓` / `Esc` 按键助手
|
|
174
|
+
- 基于对象存储的文件上传 / 下载 / 直链分享
|
|
175
|
+
|
|
176
|
+
## AI Agent 接入
|
|
177
|
+
|
|
178
|
+
besh 为 AI Agent 提供两条通道,任选其一:
|
|
179
|
+
|
|
180
|
+
**MCP**(信标内置):
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
besh mcp # 打印 MCP 客户端配置
|
|
184
|
+
besh mcp --write ~/.workbuddy/mcp.json # 直接写入客户端配置
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**CLI 技能**(把 besh 命令教给 Agent):
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
besh skill # 打印 SKILL.md
|
|
191
|
+
besh skill --install ~/.workbuddy/skills/ # 安装为 Agent 技能
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## 命令一览
|
|
195
|
+
|
|
196
|
+
| 命令 | 说明 |
|
|
197
|
+
|------|------|
|
|
198
|
+
| `besh serve` | 在当前目录启动信标 |
|
|
199
|
+
| `besh worker ID` | 以工人身份接入信标 |
|
|
200
|
+
| `besh ls` | 列出所有工人 |
|
|
201
|
+
| `besh list-windows -t ID` | 列出工人的窗口 |
|
|
202
|
+
| `besh capture-pane -t ID:WIN` | 查看窗口内容 |
|
|
203
|
+
| `besh send-keys -t ID:WIN …` | 向窗口发送按键 |
|
|
204
|
+
| `besh type -t ID:WIN TEXT` | 输入文本(可选回车),Agent 友好 |
|
|
205
|
+
| `besh run -t ID:WIN CMD` | 执行命令并打印输出 |
|
|
206
|
+
| `besh new-window` / `kill-window` | 新建 / 关闭窗口 |
|
|
207
|
+
| `besh kill-worker -t ID` | 让工人退出(tmux 会话一并关闭) |
|
|
208
|
+
| `besh wait -t ID:WIN` | 等待窗口回到提示符(命令执行完毕) |
|
|
209
|
+
| `besh wait CMD_ID` | 等待某条异步命令的回执 |
|
|
210
|
+
| `besh history` / `besh info` | 命令历史 / 工人详情 |
|
|
211
|
+
| `besh files` / `download` / `upload` / `rm` | 管理对象存储里的文件 |
|
|
212
|
+
| `besh backup` / `restore` | 备份 / 恢复工作目录 |
|
|
213
|
+
| `besh mcp` / `besh skill` | 生成 MCP / Agent 技能配置 |
|
|
214
|
+
|
|
215
|
+
环境变量:`besh_url`(信标地址)、`besh_secret`(密钥)。也可以用 `-u` / `--secret` 参数临时指定,或 `--json` 输出 JSON。
|
|
216
|
+
|
|
217
|
+
## 可靠性设计
|
|
218
|
+
|
|
219
|
+
- **命令不丢**:命令入队即落盘(sqlite)。信标重启后,pending 和已投递未回执的命令都会重新排队;工人侧用执行记录去重,最坏情况重复执行一次(at-least-once)。
|
|
220
|
+
- **屏幕秒回**:工人定期把各窗口屏幕快照推给信标缓存,`capture-pane` 无需等待。
|
|
221
|
+
- **投递超时重排**:命令投递后 120 秒无回执,自动重新排队(工人可能已重启)。
|
|
222
|
+
- **安全模型**:单一密钥认证(信标侧);工人本身处在容器 / 虚拟机内,不提供额外的安全隔离。
|
|
223
|
+
|
|
224
|
+
## 实现细节
|
|
225
|
+
|
|
226
|
+
1. 信标基于 [sqless](https://github.com/cqian-cs/sqless) 框架(简易单用户认证 + sqlite 数据库 + 函数转 API + 函数转 MCP)。`besh serve` 会在当前路径通过 `sqless --app besh_beacon.py` 生成服务端代码。
|
|
227
|
+
2. 工人内部跑两个 tmux 会话:`besh_worker`(窗口与命令执行)和 `besh_sync`(定时 rclone 备份)。
|
|
228
|
+
3. 遥控器客户端只依赖 Python 标准库。
|
|
229
|
+
|
|
230
|
+
## 开发
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
git clone https://github.com/cqian-cs/besh
|
|
234
|
+
cd besh
|
|
235
|
+
pip install -e . --no-build-isolation
|
|
236
|
+
pip install -e ".[test]"
|
|
237
|
+
pytest
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
测试包含 55 个单元/集成测试;`tests/fake_worker.py` 提供不依赖 tmux 的假工人,可用于本地联调。
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
MIT © [cqian-cs](https://github.com/cqian-cs)
|
besh-0.1.0/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Beacon Shell (besh)
|
|
2
|
+
|
|
3
|
+
**把闲置算力变成 AI Agent 可远程操作的工人。**
|
|
4
|
+
|
|
5
|
+
闲置算力随处可见:手机 Termux、免费的云 IDE、云 Notebook……但它们大多没有公网 IP,没法通过 SSH 远程操作。
|
|
6
|
+
|
|
7
|
+
besh 用一个"信标 + 工人"的架构解决这个问题:只要闲置终端能访问外网,就能反向连接信标、领取命令、回传结果——你(或你的 AI Agent)则可以像操作 tmux 一样操作散落在各处的机器。
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
flowchart TB
|
|
11
|
+
UR["人类"]
|
|
12
|
+
AG["AI Agent"]
|
|
13
|
+
RC["本地电脑<br>besh run -t 工人ID:窗口名 命令"]
|
|
14
|
+
BE["公网服务器<br>besh serve"]
|
|
15
|
+
|
|
16
|
+
UR -- CLI --> RC
|
|
17
|
+
UR -- Web --> BE
|
|
18
|
+
AG -- CLI --> RC -- API --> BE
|
|
19
|
+
AG -- MCP --> BE
|
|
20
|
+
|
|
21
|
+
BE <-- "轮询取命令 <br> 回传屏幕 / 结果" --> W1["闲置算力<br>besh worker 工人ID"]
|
|
22
|
+
BE <-- "轮询取命令 <br> 回传屏幕 / 结果" --> W2["闲置算力<br>besh worker 工人ID"]
|
|
23
|
+
|
|
24
|
+
W1 -.->|"rclone 定时备份"| R2[("对象存储<br>Cloudflare R2")]
|
|
25
|
+
W2 -.->|"rclone 定时备份"| R2
|
|
26
|
+
|
|
27
|
+
classDef purple fill:#ede9fe,stroke:#7c3aed,color:#1e293b
|
|
28
|
+
classDef blue fill:#dbeafe,stroke:#2563eb,color:#1e293b
|
|
29
|
+
classDef green fill:#d1fae5,stroke:#059669,color:#1e293b
|
|
30
|
+
classDef amber fill:#fef3c7,stroke:#d97706,color:#1e293b
|
|
31
|
+
|
|
32
|
+
class RC,AG,UR purple
|
|
33
|
+
class BE blue
|
|
34
|
+
class W1,W2 green
|
|
35
|
+
class R2 amber
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 四个角色
|
|
39
|
+
|
|
40
|
+
| 角色 | 运行位置 | 职责 |
|
|
41
|
+
|------|----------|------|
|
|
42
|
+
| 信标 | 有公网 IP 的服务器 | 中转命令、记录状态、提供 Web 界面与 MCP 接口 |
|
|
43
|
+
| 工人 | 任意闲置终端(无公网 IP) | 轮询信标领命令,在 tmux 窗口里执行,定时备份工作目录 |
|
|
44
|
+
| 遥控器 | 本地电脑 | 类似 tmux 的命令行,把 session 换成工人 ID,可同时操作多台 |
|
|
45
|
+
| 对象存储 | Cloudflare R2 | 备份工人工作目录(工人是临时的,随时会释放) |
|
|
46
|
+
|
|
47
|
+
## 安装
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install besh
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
要求 Python ≥ 3.10。工人机器上还需要安装 [tmux](https://github.com/tmux/tmux)。
|
|
54
|
+
|
|
55
|
+
## 快速开始
|
|
56
|
+
|
|
57
|
+
### 1. 启动信标(云服务器)
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
export besh_secret=CHANGE_TO_YOUR_PASSWORD
|
|
61
|
+
besh serve
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
启动时会生成自包含的 `besh_beacon.py`(主程序)和 `www/index.html`(Web 界面),数据存放在 `./db/`。默认监听 `12242` 端口,输出类似:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
工人连接 : export besh_url=http://<HOST>:12242?secret=xxx
|
|
68
|
+
浏览器 : http://<HOST>:12242/?secret=xxx
|
|
69
|
+
MCP : http://<HOST>:12242/mcp (Authorization: Bearer xxx)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. 接入工人(闲置终端)
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
export besh_url=http://BEACON-HOST:12242?secret=CHANGE_TO_YOUR_PASSWORD
|
|
76
|
+
besh worker WORKER_ID
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- 会创建 `./WORKER_ID` 作为工作目录,后续所有命令都在这个目录里执行
|
|
80
|
+
- 通过 tmux 启动 `besh_worker` 会话(创建窗口、执行命令)和 `besh_sync` 会话(定时把工作目录同步到对象存储)
|
|
81
|
+
|
|
82
|
+
### 3. 远程操作(本地电脑)
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
export besh_url=http://BEACON-HOST:12242?secret=CHANGE_TO_YOUR_PASSWORD
|
|
86
|
+
|
|
87
|
+
# 列出所有工人(ls / list-sessions / list-workers 等价)
|
|
88
|
+
besh ls
|
|
89
|
+
|
|
90
|
+
# 列出某工人的所有窗口
|
|
91
|
+
besh list-windows -t WORKER_ID
|
|
92
|
+
|
|
93
|
+
# 查看窗口内容(同 tmux capture-pane)
|
|
94
|
+
besh capture-pane -t WORKER_ID:WINDOW_NAME -p -S -50
|
|
95
|
+
|
|
96
|
+
# 发送按键(窗口不存在会自动创建)
|
|
97
|
+
besh send-keys -t WORKER_ID:WINDOW_NAME "ls -l" Enter
|
|
98
|
+
|
|
99
|
+
# 发送按键,-l 按字面处理(不展开变量)
|
|
100
|
+
besh send-keys -t WORKER_ID:WINDOW_NAME -l 'echo "Hello $USER"'
|
|
101
|
+
|
|
102
|
+
# 执行一条命令并打印输出(体验类似 ssh host cmd)
|
|
103
|
+
besh run -t WORKER_ID "uname -a"
|
|
104
|
+
|
|
105
|
+
# 跑长任务:先输入不等待,稍后等它执行完(窗口回到提示符)
|
|
106
|
+
besh type -t WORKER_ID:WINDOW_NAME "python train.py"
|
|
107
|
+
besh wait -t WORKER_ID:WINDOW_NAME
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 对象存储(Cloudflare R2)
|
|
111
|
+
|
|
112
|
+
信标带宽贵、网速慢,不适合备份工作目录;[Cloudflare R2](https://developers.cloudflare.com/r2/) 免费 10GB 且网速快,所以用它。工人工作目录备份在 `cf:besh/YYYY-MM-DD/WORKER_ID/*`。
|
|
113
|
+
|
|
114
|
+
1. 开通 Cloudflare R2,创建存储桶 `besh`
|
|
115
|
+
2. 在信标与工人机器上安装 [rclone](https://rclone.org/install/):
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
sudo -v ; curl https://rclone.org/install.sh | sudo bash
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
3. 配置 rclone 环境变量访问 R2:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
export RCLONE_CONFIG_CF_TYPE=s3
|
|
125
|
+
export RCLONE_CONFIG_CF_PROVIDER=Cloudflare
|
|
126
|
+
export RCLONE_CONFIG_CF_ACCESS_KEY_ID=
|
|
127
|
+
export RCLONE_CONFIG_CF_SECRET_ACCESS_KEY=
|
|
128
|
+
export RCLONE_CONFIG_CF_ENDPOINT=
|
|
129
|
+
export RCLONE_CONFIG_CF_REGION=auto
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
配置好后,遥控器即可管理备份:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
besh backup -t WORKER_ID # 立刻备份(不等定时任务)
|
|
136
|
+
besh restore -t WORKER_ID # 从最新备份恢复工作目录
|
|
137
|
+
besh files -t WORKER_ID # 列出对象存储里的备份文件
|
|
138
|
+
besh download / besh upload / besh rm # 下载 / 上传 / 删除文件
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Web 操作界面
|
|
142
|
+
|
|
143
|
+
浏览器打开 `http://BEACON-HOST:12242?secret=xxx`:
|
|
144
|
+
|
|
145
|
+
- 每个工人的实时状态(主机名、工作目录、窗口列表、在线状态)
|
|
146
|
+
- 完善的 WebShell:实时屏幕、输入框、`^C` / `^D` / `Tab` / `↑` / `↓` / `Esc` 按键助手
|
|
147
|
+
- 基于对象存储的文件上传 / 下载 / 直链分享
|
|
148
|
+
|
|
149
|
+
## AI Agent 接入
|
|
150
|
+
|
|
151
|
+
besh 为 AI Agent 提供两条通道,任选其一:
|
|
152
|
+
|
|
153
|
+
**MCP**(信标内置):
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
besh mcp # 打印 MCP 客户端配置
|
|
157
|
+
besh mcp --write ~/.workbuddy/mcp.json # 直接写入客户端配置
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**CLI 技能**(把 besh 命令教给 Agent):
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
besh skill # 打印 SKILL.md
|
|
164
|
+
besh skill --install ~/.workbuddy/skills/ # 安装为 Agent 技能
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 命令一览
|
|
168
|
+
|
|
169
|
+
| 命令 | 说明 |
|
|
170
|
+
|------|------|
|
|
171
|
+
| `besh serve` | 在当前目录启动信标 |
|
|
172
|
+
| `besh worker ID` | 以工人身份接入信标 |
|
|
173
|
+
| `besh ls` | 列出所有工人 |
|
|
174
|
+
| `besh list-windows -t ID` | 列出工人的窗口 |
|
|
175
|
+
| `besh capture-pane -t ID:WIN` | 查看窗口内容 |
|
|
176
|
+
| `besh send-keys -t ID:WIN …` | 向窗口发送按键 |
|
|
177
|
+
| `besh type -t ID:WIN TEXT` | 输入文本(可选回车),Agent 友好 |
|
|
178
|
+
| `besh run -t ID:WIN CMD` | 执行命令并打印输出 |
|
|
179
|
+
| `besh new-window` / `kill-window` | 新建 / 关闭窗口 |
|
|
180
|
+
| `besh kill-worker -t ID` | 让工人退出(tmux 会话一并关闭) |
|
|
181
|
+
| `besh wait -t ID:WIN` | 等待窗口回到提示符(命令执行完毕) |
|
|
182
|
+
| `besh wait CMD_ID` | 等待某条异步命令的回执 |
|
|
183
|
+
| `besh history` / `besh info` | 命令历史 / 工人详情 |
|
|
184
|
+
| `besh files` / `download` / `upload` / `rm` | 管理对象存储里的文件 |
|
|
185
|
+
| `besh backup` / `restore` | 备份 / 恢复工作目录 |
|
|
186
|
+
| `besh mcp` / `besh skill` | 生成 MCP / Agent 技能配置 |
|
|
187
|
+
|
|
188
|
+
环境变量:`besh_url`(信标地址)、`besh_secret`(密钥)。也可以用 `-u` / `--secret` 参数临时指定,或 `--json` 输出 JSON。
|
|
189
|
+
|
|
190
|
+
## 可靠性设计
|
|
191
|
+
|
|
192
|
+
- **命令不丢**:命令入队即落盘(sqlite)。信标重启后,pending 和已投递未回执的命令都会重新排队;工人侧用执行记录去重,最坏情况重复执行一次(at-least-once)。
|
|
193
|
+
- **屏幕秒回**:工人定期把各窗口屏幕快照推给信标缓存,`capture-pane` 无需等待。
|
|
194
|
+
- **投递超时重排**:命令投递后 120 秒无回执,自动重新排队(工人可能已重启)。
|
|
195
|
+
- **安全模型**:单一密钥认证(信标侧);工人本身处在容器 / 虚拟机内,不提供额外的安全隔离。
|
|
196
|
+
|
|
197
|
+
## 实现细节
|
|
198
|
+
|
|
199
|
+
1. 信标基于 [sqless](https://github.com/cqian-cs/sqless) 框架(简易单用户认证 + sqlite 数据库 + 函数转 API + 函数转 MCP)。`besh serve` 会在当前路径通过 `sqless --app besh_beacon.py` 生成服务端代码。
|
|
200
|
+
2. 工人内部跑两个 tmux 会话:`besh_worker`(窗口与命令执行)和 `besh_sync`(定时 rclone 备份)。
|
|
201
|
+
3. 遥控器客户端只依赖 Python 标准库。
|
|
202
|
+
|
|
203
|
+
## 开发
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
git clone https://github.com/cqian-cs/besh
|
|
207
|
+
cd besh
|
|
208
|
+
pip install -e . --no-build-isolation
|
|
209
|
+
pip install -e ".[test]"
|
|
210
|
+
pytest
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
测试包含 55 个单元/集成测试;`tests/fake_worker.py` 提供不依赖 tmux 的假工人,可用于本地联调。
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
MIT © [cqian-cs](https://github.com/cqian-cs)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "besh"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Beacon Shell:让 Agent 把计算任务交给闲置算力(手机 Termux / 云 IDE / 云 Notebook)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
keywords = ["tmux", "remote", "agent", "beacon", "worker", "rclone"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "cqian-cs", email = "cqian.cs@qq.com" },
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Programming Language :: Python",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"sqless>=5.0.1",
|
|
26
|
+
"aiohttp>=3.8",
|
|
27
|
+
"aiofiles>=22.1",
|
|
28
|
+
"orjson>=3.6",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
besh = "besh.cli:main"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Documentation = "https://github.com/cqian-cs/besh#readme"
|
|
36
|
+
Issues = "https://github.com/cqian-cs/besh/issues"
|
|
37
|
+
Source = "https://github.com/cqian-cs/besh"
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
test = ["pytest>=7.0", "pytest-asyncio>=0.21"]
|
|
41
|
+
|
|
42
|
+
[tool.hatch.version]
|
|
43
|
+
path = "src/besh/__about__.py"
|
|
44
|
+
|
|
45
|
+
[tool.hatch.build.targets.wheel]
|
|
46
|
+
packages = ["src/besh"]
|
|
47
|
+
core-metadata-version = "2.4"
|
|
48
|
+
|
|
49
|
+
[tool.hatch.build.targets.sdist]
|
|
50
|
+
include = ["src/besh", "tests", "README.md"]
|
|
51
|
+
core-metadata-version = "2.4"
|
|
52
|
+
|
|
53
|
+
[tool.hatch.envs.types]
|
|
54
|
+
extra-dependencies = [
|
|
55
|
+
"mypy>=1.0.0",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[tool.hatch.envs.types.scripts]
|
|
59
|
+
check = "mypy --install-types --non-interactive {args:src/besh tests}"
|
|
60
|
+
|
|
61
|
+
[tool.pytest.ini_options]
|
|
62
|
+
testpaths = ["tests"]
|
|
63
|
+
filterwarnings = ["ignore::DeprecationWarning"]
|
|
64
|
+
|
|
65
|
+
[tool.coverage.run]
|
|
66
|
+
source_pkgs = ["besh", "tests"]
|
|
67
|
+
branch = true
|
|
68
|
+
parallel = true
|
|
69
|
+
omit = [
|
|
70
|
+
"src/besh/__about__.py",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[tool.coverage.paths]
|
|
74
|
+
besh = ["src/besh", "*/besh/src/besh"]
|
|
75
|
+
tests = ["tests", "*/besh/tests"]
|
|
76
|
+
|
|
77
|
+
[tool.coverage.report]
|
|
78
|
+
exclude_lines = [
|
|
79
|
+
"no cov",
|
|
80
|
+
"if __name__ == .__main__.:",
|
|
81
|
+
"if TYPE_CHECKING:",
|
|
82
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026-present cqian-cs <cqian.cs@qq.com>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
"""besh - Beacon Shell.
|
|
5
|
+
|
|
6
|
+
把闲置算力(手机 Termux、免费云 IDE、云 NoteBook)变成可远程操作的工人。
|
|
7
|
+
|
|
8
|
+
四个角色:
|
|
9
|
+
|
|
10
|
+
* 信标(beacon)—— 有公网 IP 的服务器,中转命令、记录状态、提供 Web 界面与 MCP。
|
|
11
|
+
* 工人(worker)—— 任意终端,向信标轮询命令并交给 tmux 执行。
|
|
12
|
+
* 遥控器(controller)—— 本地电脑,用 tmux 风格的命令行操作多个工人。
|
|
13
|
+
* 对象存储(R2)—— 备份工人的工作目录。
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from .__about__ import __version__
|
|
17
|
+
|
|
18
|
+
__all__ = ["__version__"]
|