pi-courier 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +363 -0
- package/README.zh-CN.md +362 -0
- package/deploy/pi-msg-bridge.service +26 -0
- package/deploy/pi-msg-bridge.user.service +37 -0
- package/dist/auth/challenge-auth.d.ts +76 -0
- package/dist/auth/challenge-auth.d.ts.map +1 -0
- package/dist/auth/challenge-auth.js +337 -0
- package/dist/auth/challenge-auth.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +265 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +49 -0
- package/dist/config.js.map +1 -0
- package/dist/formatting.d.ts +22 -0
- package/dist/formatting.d.ts.map +1 -0
- package/dist/formatting.js +74 -0
- package/dist/formatting.js.map +1 -0
- package/dist/lock.d.ts +3 -0
- package/dist/lock.d.ts.map +1 -0
- package/dist/lock.js +75 -0
- package/dist/lock.js.map +1 -0
- package/dist/rpc/command-map.d.ts +19 -0
- package/dist/rpc/command-map.d.ts.map +1 -0
- package/dist/rpc/command-map.js +191 -0
- package/dist/rpc/command-map.js.map +1 -0
- package/dist/rpc/message-router.d.ts +30 -0
- package/dist/rpc/message-router.d.ts.map +1 -0
- package/dist/rpc/message-router.js +110 -0
- package/dist/rpc/message-router.js.map +1 -0
- package/dist/rpc/pi-rpc.d.ts +79 -0
- package/dist/rpc/pi-rpc.d.ts.map +1 -0
- package/dist/rpc/pi-rpc.js +199 -0
- package/dist/rpc/pi-rpc.js.map +1 -0
- package/dist/setup.d.ts +10 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +159 -0
- package/dist/setup.js.map +1 -0
- package/dist/standalone.d.ts +13 -0
- package/dist/standalone.d.ts.map +1 -0
- package/dist/standalone.js +184 -0
- package/dist/standalone.js.map +1 -0
- package/dist/transports/discord.d.ts +33 -0
- package/dist/transports/discord.d.ts.map +1 -0
- package/dist/transports/discord.js +216 -0
- package/dist/transports/discord.js.map +1 -0
- package/dist/transports/interface.d.ts +42 -0
- package/dist/transports/interface.d.ts.map +1 -0
- package/dist/transports/interface.js +2 -0
- package/dist/transports/interface.js.map +1 -0
- package/dist/transports/manager.d.ts +54 -0
- package/dist/transports/manager.d.ts.map +1 -0
- package/dist/transports/manager.js +98 -0
- package/dist/transports/manager.js.map +1 -0
- package/dist/transports/matrix-utils.d.ts +31 -0
- package/dist/transports/matrix-utils.d.ts.map +1 -0
- package/dist/transports/matrix-utils.js +99 -0
- package/dist/transports/matrix-utils.js.map +1 -0
- package/dist/transports/matrix-utils.test.d.ts +2 -0
- package/dist/transports/matrix-utils.test.d.ts.map +1 -0
- package/dist/transports/matrix-utils.test.js +246 -0
- package/dist/transports/matrix-utils.test.js.map +1 -0
- package/dist/transports/matrix.d.ts +34 -0
- package/dist/transports/matrix.d.ts.map +1 -0
- package/dist/transports/matrix.js +240 -0
- package/dist/transports/matrix.js.map +1 -0
- package/dist/transports/slack.d.ts +31 -0
- package/dist/transports/slack.d.ts.map +1 -0
- package/dist/transports/slack.js +203 -0
- package/dist/transports/slack.js.map +1 -0
- package/dist/transports/telegram.d.ts +38 -0
- package/dist/transports/telegram.d.ts.map +1 -0
- package/dist/transports/telegram.js +167 -0
- package/dist/transports/telegram.js.map +1 -0
- package/dist/transports/whatsapp.d.ts +31 -0
- package/dist/transports/whatsapp.d.ts.map +1 -0
- package/dist/transports/whatsapp.js +235 -0
- package/dist/transports/whatsapp.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/extensions/index.ts +42 -0
- package/package.json +71 -0
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
# pi-courier
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
通过 **Matrix** 远程操控 [pi coding agent](https://pi.dev),slash 命令、技能、提示词模板在聊天客户端里完整可用。
|
|
6
|
+
|
|
7
|
+
与传统的 pi 扩展模式不同,本项目通过 [RPC 协议](https://pi.dev/docs/latest/rpc)驱动 pi,因此 **messenger 里可以直接执行 slash 命令**(`/new`、`/compact`、`/model`、`/skill:name`、提示词模板、扩展命令)—— 这是扩展模式做不到的,因为 pi 的 `sendUserMessage()` 刻意跳过了命令解析。
|
|
8
|
+
|
|
9
|
+
> **上游来源**:本项目改造自 [tintinweb/pi-messenger-bridge](https://github.com/tintinweb/pi-messenger-bridge) —— Matrix 传输层与挑战码认证来自上游;基于 RPC 的独立架构、slash 命令映射、CLI 与配置向导为本项目新增。
|
|
10
|
+
|
|
11
|
+
## 特性
|
|
12
|
+
|
|
13
|
+
- 📱 Matrix 传输(支持 E2EE)、6 位验证码挑战认证
|
|
14
|
+
- 🎛️ slash 命令全支持:`/new`、`/compact`、`/model`、`/thinking`、`/bash`、`/reload` 等
|
|
15
|
+
- 🧩 技能与提示词模板透传:`/skill:名称`、`/模板名` 直接生效
|
|
16
|
+
- 💾 会话持久化:pi 会话存磁盘,重启自动恢复
|
|
17
|
+
- 🔄 `/reload` 重启 pi 进程:装新插件、改配置后一条命令生效,会话无损
|
|
18
|
+
- 🔌 不打包 pi:作为 pi 的伴侣程序独立部署,通过 RPC 连接系统安装的 pi,pi 独立升级
|
|
19
|
+
- 🧭 一条命令搞定: `pi-courier setup` 配置向导、`pi-courier enable` 开机自启、`pi-courier update` 自更新
|
|
20
|
+
|
|
21
|
+
## 架构
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Messenger ──> pi-courier (dist/standalone.js) ──> pi --mode rpc(系统安装)
|
|
25
|
+
Messenger <── 回复 <────────────────────────── <── agent 事件流(stdout JSONL)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- pi-courier 负责 spawn 并管理 `pi --mode rpc` 子进程
|
|
29
|
+
- 会话持久化到 `~/.pi/agent/sessions`,重启自动恢复
|
|
30
|
+
- systemd 只需托管 pi-courier 一个服务
|
|
31
|
+
|
|
32
|
+
## 环境要求
|
|
33
|
+
|
|
34
|
+
| 组件 | 要求 | 检查命令 |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| Node.js | **>= 20**(实测 24.x) | `node --version` |
|
|
37
|
+
| pi | **>= 0.83,全局安装**(项目不打包) | `pi --version` |
|
|
38
|
+
| 网络 | 能访问 homeserver 与 LLM provider 端点 | — |
|
|
39
|
+
|
|
40
|
+
**先装 pi**(bridge 是 pi 的伴侣程序,通过 RPC 协议连接系统安装的 pi):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install -g @earendil-works/pi-coding-agent
|
|
44
|
+
pi --version
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
> 使用 nvm 的注意:每次新终端先 `source ~/.nvm/nvm.sh`(或按你的 nvm 初始化方式),并确认 `pi` 在 PATH 中(`which pi`)。
|
|
48
|
+
|
|
49
|
+
## 安装
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/Hi-Barry/pi-courier.git
|
|
53
|
+
cd pi-courier
|
|
54
|
+
npm install
|
|
55
|
+
npm link # 把 `pi-courier` 命令全局化,之后任何目录都能用
|
|
56
|
+
npm run build
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**重要:不要加 `--ignore-scripts`**。Matrix 的 E2EE 加密库(`@matrix-org/matrix-sdk-crypto-nodejs`)的原生二进制由 postinstall 脚本下载。若你的 npm 配置了 allow-scripts 拦截导致安装后报 `Cannot find module '@matrix-org/matrix-sdk-crypto-nodejs-linux-x64-gnu'`,手动补下载:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cd node_modules/@matrix-org/matrix-sdk-crypto-nodejs
|
|
63
|
+
node download-lib.js
|
|
64
|
+
cd ../..
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
构建成功标志:出现 `dist/standalone.js`。
|
|
68
|
+
|
|
69
|
+
## 配置
|
|
70
|
+
|
|
71
|
+
### pi 的 LLM provider(`~/.pi/agent/`)
|
|
72
|
+
|
|
73
|
+
**a) models.json** — 模型元数据。推荐从 models.dev 提取(字段完整正确),以 opencode-go 为例:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
curl -s https://models.dev/api.json -o /tmp/modelsdev.json
|
|
77
|
+
python3 -c "
|
|
78
|
+
import json, os
|
|
79
|
+
md = json.load(open('/tmp/modelsdev.json')) # 顶层直接是 provider 字典
|
|
80
|
+
out = {'providers': {'opencode-go': md['opencode-go']}}
|
|
81
|
+
json.dump(out, open(os.path.expanduser('~/.pi/agent/models.json'), 'w'), indent=2)
|
|
82
|
+
"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**b) auth.json** — API key(权限 600):
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"opencode-go": { "type": "api_key", "key": "sk-你的密钥" }
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**c) settings.json** — 默认 provider 与模型:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"defaultProvider": "opencode-go",
|
|
98
|
+
"defaultModel": "deepseek-v4-flash"
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
> 字段名是 `defaultProvider` / `defaultModel`(不是 `provider` / `model`)。
|
|
103
|
+
|
|
104
|
+
验证配置(在 pi-courier 项目目录内执行):
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
node --input-type=module -e "
|
|
108
|
+
import { RpcClient } from '@earendil-works/pi-coding-agent';
|
|
109
|
+
import { fileURLToPath } from 'node:url';
|
|
110
|
+
import path from 'node:path';
|
|
111
|
+
const entry = fileURLToPath(import.meta.resolve('@earendil-works/pi-coding-agent'));
|
|
112
|
+
const c = new RpcClient({ cliPath: path.join(path.dirname(entry), 'cli.js') });
|
|
113
|
+
await c.start();
|
|
114
|
+
console.log('可用模型数:', (await c.getAvailableModels()).length);
|
|
115
|
+
console.log('当前模型:', (await c.getState()).model?.id);
|
|
116
|
+
await c.stop();
|
|
117
|
+
"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 配置 messenger(Matrix 为例)
|
|
121
|
+
|
|
122
|
+
**方式一(推荐):首次运行配置向导**
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pi-courier setup
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
按提示依次输入:平台 → homeserver URL → token(用户名密码登录或粘贴已有 token)→ 信任用户 MXID → 是否启用 E2EE → pi 工作目录。向导会验证 token 并自动写入 `~/.pi/msg-bridge.json`。
|
|
129
|
+
|
|
130
|
+
**方式二:手动编辑 `~/.pi/msg-bridge.json`**(权限 600):
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"matrix": {
|
|
135
|
+
"homeserverUrl": "https://你的homeserver",
|
|
136
|
+
"accessToken": "syt_你的token",
|
|
137
|
+
"encryption": true
|
|
138
|
+
},
|
|
139
|
+
"auth": {
|
|
140
|
+
"trustedUsers": ["matrix:@你的账号:你的homeserver域名"],
|
|
141
|
+
"adminUserId": "matrix:@你的账号:你的homeserver域名"
|
|
142
|
+
},
|
|
143
|
+
"workdir": "/path/to/pi/workdir",
|
|
144
|
+
"autoConnect": true,
|
|
145
|
+
"debug": true
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
- `accessToken` 获取:`POST /_matrix/client/v3/login`(密码登录)或 Element 设置页
|
|
150
|
+
- `trustedUsers` / `adminUserId` 格式:`<transport>:<完整userId>`,Matrix 的 userId 是完整 MXID(如 `@barry:matrix.example.com`)
|
|
151
|
+
- `workdir`:pi 的工作目录(不存在会自动创建);`pi-courier run --workdir <目录>` 可覆盖
|
|
152
|
+
- `sessionDir` / `cliPath`:可选覆盖(默认:pi 的会话目录、`which pi` 定位 CLI)
|
|
153
|
+
- `encryption: true` 用于加密房间;普通房间保持 true 也可用
|
|
154
|
+
- 环境变量替代:`PI_MATRIX_HOMESERVER` / `PI_MATRIX_ACCESS_TOKEN`
|
|
155
|
+
|
|
156
|
+
## 使用
|
|
157
|
+
|
|
158
|
+
全部操作走一个命令:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
pi-courier setup 首次运行配置向导(Matrix 账号、信任用户、工作目录)
|
|
162
|
+
pi-courier run 前台运行(工作目录从配置读,--workdir 可覆盖)
|
|
163
|
+
pi-courier enable 安装用户级 systemd 服务并开机自启、立即启动
|
|
164
|
+
pi-courier start 启动服务
|
|
165
|
+
pi-courier stop 停止服务
|
|
166
|
+
pi-courier restart 重启服务
|
|
167
|
+
pi-courier status 查看服务状态与最近日志
|
|
168
|
+
pi-courier logs 跟踪服务日志(Ctrl+C 退出)
|
|
169
|
+
pi-courier disable 卸载服务(停止 + 取消自启 + 删除 unit 文件)
|
|
170
|
+
pi-courier update 更新本项目(git pull + 安装依赖 + 重新构建)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
典型首次部署:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
pi-courier setup # 按提示配置(或手动编辑 ~/.pi/msg-bridge.json)
|
|
177
|
+
pi-courier enable # 开机自启,以当前用户运行
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
前台快速测试:`pi-courier run`(Ctrl+C 停止)。旧的 `node dist/standalone.js --workdir ...` 方式仍然可用。
|
|
181
|
+
|
|
182
|
+
**启动成功的标志日志:**
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
✅ Matrix connected as @bot:你的homeserver (2 rooms, E2EE enabled)
|
|
186
|
+
✅ pi RPC connected (model: deepseek-v4-flash, session: 019f...)
|
|
187
|
+
🚀 msg-bridge standalone ready. Waiting for messages...
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 命令一览(DM 中直接发送)
|
|
191
|
+
|
|
192
|
+
**Pi 命令(映射到 RPC):**
|
|
193
|
+
|
|
194
|
+
| 命令 | 说明 |
|
|
195
|
+
|---|---|
|
|
196
|
+
| `/new` `/clear` | 新会话 |
|
|
197
|
+
| `/compact [说明]` | 压缩上下文 |
|
|
198
|
+
| `/model` / `/model <provider/id>` | 查看 / 切换模型 |
|
|
199
|
+
| `/models` | 列出可用模型 |
|
|
200
|
+
| `/thinking [level]` | 查看 / 设置思考级别 |
|
|
201
|
+
| `/session` `/cost` | 会话统计与费用 |
|
|
202
|
+
| `/status` | 当前模型与状态 |
|
|
203
|
+
| `/name <名字>` | 会话命名 |
|
|
204
|
+
| `/export [路径]` | 导出会话 HTML |
|
|
205
|
+
| `/bash <命令>` | 执行 shell 命令(写入上下文) |
|
|
206
|
+
| `/abort` | 中止当前操作 |
|
|
207
|
+
| `/reload` | 重启 pi 进程(装插件 / 改配置后使用) |
|
|
208
|
+
| `/help` | 完整帮助 |
|
|
209
|
+
|
|
210
|
+
**Bridge 管理命令:** `/trusted`、`/revoke <userId>`、`/channels`、`/enable <chatId> <mode>`、`/disable <chatId>`、`/toggletools`
|
|
211
|
+
|
|
212
|
+
**透传:** 其他 `/` 开头的命令直接交给 pi(扩展命令、`/skill:名称`、提示词模板由 pi 展开);普通文本 = 正常对话。
|
|
213
|
+
|
|
214
|
+
### 首次使用:认证
|
|
215
|
+
|
|
216
|
+
1. 你的账号给 bot 账号发第一条 DM
|
|
217
|
+
2. bridge 终端(或 `journalctl --user -u pi-msg-bridge -f`)会打印 6 位验证码
|
|
218
|
+
3. 把验证码发回给 bot → 成为 trusted user(第一个 trusted 用户自动成为 admin)
|
|
219
|
+
|
|
220
|
+
已在 `msg-bridge.json` 的 `auth.trustedUsers` 里预置的账号跳过此步骤。
|
|
221
|
+
|
|
222
|
+
## systemd 部署(开机自启)
|
|
223
|
+
|
|
224
|
+
**用户级(推荐,无需 sudo):**
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
pi-courier enable
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
一条命令搞定 —— 自动写入 `~/.config/systemd/user/pi-msg-bridge.service`(使用绝对 node 路径和配置的工作目录)、启用开机自启并立即启动。彻底无人值守(注销后继续运行)执行一次:`sudo loginctl enable-linger $USER`。
|
|
231
|
+
|
|
232
|
+
常用命令:`pi-courier status`、`pi-courier logs`、`pi-courier stop`、`pi-courier start`(或 `systemctl --user restart pi-msg-bridge`)。
|
|
233
|
+
|
|
234
|
+
**系统级(需要 sudo):** 复制 `deploy/pi-msg-bridge.service` 到 `/etc/systemd/system/`,按注释修改三处必改项(`User`、`WorkingDirectory`、`NVM_DIR`),再 `sudo systemctl enable --now pi-msg-bridge`。
|
|
235
|
+
|
|
236
|
+
## 升级 pi
|
|
237
|
+
|
|
238
|
+
pi 由系统独立管理,升级只需全局更新,bridge 无需任何改动:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
npm install -g @earendil-works/pi-coding-agent@latest
|
|
242
|
+
pi --version
|
|
243
|
+
pi-courier restart # 或: systemctl --user restart pi-msg-bridge
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
bridge 通过 `which pi` 始终连接系统最新版 pi。仅当 pi 的 RPC 协议发生破坏性变更时才需要改 bridge 代码(协议为文档化稳定接口,从未破坏性变更)。
|
|
247
|
+
|
|
248
|
+
## FAQ(常见问题)
|
|
249
|
+
|
|
250
|
+
### 安装与部署
|
|
251
|
+
|
|
252
|
+
**Q: `git clone` 报 404?**
|
|
253
|
+
A: 仓库地址写错。用 `https://github.com/Hi-Barry/pi-courier.git`(或直接 `npm install -g pi-courier` 安装)。
|
|
254
|
+
|
|
255
|
+
**Q: `npm install` 卡住 / 只有 20-60 kB/s?**
|
|
256
|
+
A: 涉及两个下载,要分开配代理:
|
|
257
|
+
- npm registry 的包 → 配 npm 代理:`npm config set proxy http://...` 和 `npm config set https-proxy http://...`
|
|
258
|
+
- 21MB 的 E2EE 原生库(由 matrix-sdk-crypto-nodejs 从 GitHub Releases 下载)→ **不走 npm 代理**,需先 `export https_proxy=http://...` `export http_proxy=http://...` 再安装(想永久生效写进 `~/.bashrc`)
|
|
259
|
+
|
|
260
|
+
**Q: 报 `Cannot find module '@matrix-org/matrix-sdk-crypto-nodejs-linux-x64-gnu'`?**
|
|
261
|
+
A: 原生二进制没下载成功(postinstall 被拦或中断)。手动补(必要时先设置代理环境变量):
|
|
262
|
+
```bash
|
|
263
|
+
cd node_modules/@matrix-org/matrix-sdk-crypto-nodejs
|
|
264
|
+
node download-lib.js
|
|
265
|
+
cd ../..
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Q: `npm install -g pi-courier` 报 EEXIST?**
|
|
269
|
+
A: 之前 `npm link` 过,bin 冲突。先清理:
|
|
270
|
+
```bash
|
|
271
|
+
npm unlink -g pi-courier
|
|
272
|
+
rm -f ~/.nvm/versions/node/v24.18.1/bin/pi-courier
|
|
273
|
+
npm install -g pi-courier
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Q: `npm link` 后 `pi-courier` 命令找不到?**
|
|
277
|
+
A: link 在 `npm run build` 之前执行,`dist/cli.js` 还不存在。build 后重新 `npm link`(或直接改用 npm 安装)。
|
|
278
|
+
|
|
279
|
+
**Q: systemd 服务反复重启循环?**
|
|
280
|
+
A: pi 子进程崩溃,几乎都是 **Node 版本不匹配**:bridge 通过 PATH 找 node 启动 pi,systemd 默认 PATH 可能命中系统 node(如 v20),而 pi 的 undici 与 Node 20 不兼容(报 `webidl.util.markAsUncloneable is not a function`)。修复:`source ~/.nvm/nvm.sh` 后重新 `pi-courier enable`(0.1.2+ 会自动把 `Environment=PATH=<nvm bin 优先>` 写进 unit)。**全机统一用一个 Node 版本(nvm v24)**,别和系统 node 混用。
|
|
281
|
+
|
|
282
|
+
### 配置
|
|
283
|
+
|
|
284
|
+
**Q: 启动日志显示 `model: unknown`?**
|
|
285
|
+
A: pi 的 provider 没配置。检查 `~/.pi/agent/` 三个文件:`models.json`(模型元数据)、`auth.json`(API key,权限 600)、`settings.json`(`defaultProvider` / `defaultModel` —— 注意字段名是这两个,不是 provider/model)。
|
|
286
|
+
|
|
287
|
+
**Q: `getAvailableModels` 为空?**
|
|
288
|
+
A: `models.json` 格式错误。用配置章节的 models.dev 提取命令重新生成。
|
|
289
|
+
|
|
290
|
+
**Q: 启动报 `no transports configured`?**
|
|
291
|
+
A: bridge 配置为空。运行 `pi-courier setup` 生成 `~/.pi/msg-bridge.json`,或检查 `PI_*` 环境变量。
|
|
292
|
+
|
|
293
|
+
**Q: setup 向导里出现奇怪的 `DeprecationWarning: util._extend`?**
|
|
294
|
+
A: 传输层依赖的已知噪音,0.1.0 起已过滤。更新 pi-courier 后仍看到就说明版本太旧。
|
|
295
|
+
|
|
296
|
+
### 消息与加密
|
|
297
|
+
|
|
298
|
+
**Q: 日志大量 `Decryption error`?**
|
|
299
|
+
A: 历史消息无法解密(新设备没有旧密钥)。**正常**,不影响新消息。
|
|
300
|
+
|
|
301
|
+
**Q: 加密房间:发消息没回复 / 新消息解不开?**
|
|
302
|
+
A: bot 的新设备没拿到你客户端的房间密钥。处理:
|
|
303
|
+
- Element(网页:设置 → 安全与隐私 → 加密):确保 **"仅向已验证设备共享密钥"未勾选**,然后在房间里发一条消息
|
|
304
|
+
- bot 账号没有交叉签名,"用户验证"显示不可用是正常的;最省心的可靠方案:**直接用非加密房间**(新建房间时不要勾选加密,把 bot 拉进来)。bridge 配置 `encryption: true` 也照常处理非加密房间。
|
|
305
|
+
|
|
306
|
+
**Q: 启动报 `M_BAD_JSON: Provided device_id in device_keys does not match...`?**
|
|
307
|
+
A: 加密存储里是旧设备身份,而 access token 属于新设备(重新登录过)。删掉存储重启:
|
|
308
|
+
```bash
|
|
309
|
+
rm -rf ~/.pi/msg-bridge-matrix-crypto
|
|
310
|
+
pi-courier restart
|
|
311
|
+
```
|
|
312
|
+
**以后每次重跑 setup / 换 token,都顺手删一次这个目录。**
|
|
313
|
+
|
|
314
|
+
**Q: Matrix 连接失败(homeserver/token 错误)?**
|
|
315
|
+
A: 验证 token:`curl -H "Authorization: Bearer <token>" https://homeserver/_matrix/client/v3/account/whoami`。
|
|
316
|
+
|
|
317
|
+
**Q: 第一次给 bot 发消息要 6 位验证码?**
|
|
318
|
+
A: 这是 challenge 认证 —— 把验证码回复给 bot 即成为 trusted user(第一个 trusted 用户自动成为 admin)。已在 `auth.trustedUsers` 里的用户跳过此步骤。
|
|
319
|
+
|
|
320
|
+
**Q: 消息完全没有回复?**
|
|
321
|
+
A: 按顺序排查:(1) `pi-courier status` / 日志 —— Matrix 连上了吗?有没有 Decryption error(加密房间)?(2) pi RPC 连上了吗?(3) 模型调用本身 —— 用 curl 直接测 provider 端点,排除网络/密钥问题。
|
|
322
|
+
|
|
323
|
+
### 运行与维护
|
|
324
|
+
|
|
325
|
+
**Q: `pi RPC did not become ready`?**
|
|
326
|
+
A: pi 子进程启动失败。手动跑它看真实报错:
|
|
327
|
+
```bash
|
|
328
|
+
node node_modules/@earendil-works/pi-coding-agent/dist/cli.js --mode rpc
|
|
329
|
+
```
|
|
330
|
+
常见原因:Node 版本不匹配(见上面重启循环)、provider 配置错误、无法访问 provider 端点。
|
|
331
|
+
|
|
332
|
+
**Q: 重启后对话上下文丢了?**
|
|
333
|
+
A: 0.1.1 起 bridge 会给 pi 传 `--continue`(等价 `pi -c`),按 workdir 恢复最近会话。升级并重启即可;`/new` 开新会话,下次重启恢复的是新会话。
|
|
334
|
+
|
|
335
|
+
**Q: Element(网页客户端)拦截 `/` 开头的消息?**
|
|
336
|
+
A: 用 `//` 转义发送字面文本(如 `//compact` 会发出 `/compact`)。
|
|
337
|
+
|
|
338
|
+
**Q: 代理环境有什么讲究?**
|
|
339
|
+
A: npm registry → `npm config set proxy/https-proxy`;GitHub 下载与 bridge 运行 → `export https_proxy` / `http_proxy`(systemd 里加进 EnvironmentFile)。
|
|
340
|
+
|
|
341
|
+
## 使用提示
|
|
342
|
+
|
|
343
|
+
- **Element 客户端**:`/` 开头的消息会被客户端当作命令拦截,要发送字面文本用 `//` 转义(如 `//compact` 会发送 `/compact`)
|
|
344
|
+
- **代理环境**:设置 `HTTP_PROXY` / `HTTPS_PROXY` 环境变量(systemd 用 EnvironmentFile)
|
|
345
|
+
- **群聊**:需先 `/enable <roomId> all` 启用;DM 无需配置
|
|
346
|
+
|
|
347
|
+
## 开发
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
npm run build # 编译
|
|
351
|
+
npm run typecheck # 类型检查
|
|
352
|
+
npm run test # 单元测试(vitest)
|
|
353
|
+
npm run lint # biome lint
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
完整的开发历程 —— 调研、设计决策、真实部署中踩过的每一个坑 —— 见 [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md)。
|
|
357
|
+
|
|
358
|
+
## License
|
|
359
|
+
|
|
360
|
+
MIT
|
|
361
|
+
|
|
362
|
+
上游:[tintinweb/pi-messenger-bridge](https://github.com/tintinweb/pi-messenger-bridge)(MIT)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=pi-remote (messengers -> pi RPC)
|
|
3
|
+
# The bridge spawns `pi --mode rpc` itself as a child process, so only this
|
|
4
|
+
# one unit is needed. pi sessions persist to disk and are resumed on restart.
|
|
5
|
+
After=network-online.target
|
|
6
|
+
Wants=network-online.target
|
|
7
|
+
|
|
8
|
+
[Service]
|
|
9
|
+
Type=simple
|
|
10
|
+
# Adjust User/WorkingDirectory to your setup.
|
|
11
|
+
# WorkingDirectory is where the agent works (bash tool, project context).
|
|
12
|
+
User=hermes
|
|
13
|
+
WorkingDirectory=/home/hermes/Projects/pi-remote
|
|
14
|
+
Environment=NVM_DIR=/home/hermes/.nvm
|
|
15
|
+
# Optional: PI_MATRIX_HOMESERVER / PI_MATRIX_ACCESS_TOKEN etc. can live here
|
|
16
|
+
# instead of ~/.pi/msg-bridge.json
|
|
17
|
+
EnvironmentFile=-/etc/pi-bridge.env
|
|
18
|
+
ExecStart=/bin/bash -lc 'source "$NVM_DIR/nvm.sh" && exec node dist/standalone.js --workdir /home/hermes/Projects'
|
|
19
|
+
Restart=on-failure
|
|
20
|
+
RestartSec=5
|
|
21
|
+
# Basic hardening
|
|
22
|
+
NoNewPrivileges=true
|
|
23
|
+
PrivateTmp=true
|
|
24
|
+
|
|
25
|
+
[Install]
|
|
26
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# User-level systemd unit — no sudo required.
|
|
2
|
+
#
|
|
3
|
+
# Install:
|
|
4
|
+
# mkdir -p ~/.config/systemd/user
|
|
5
|
+
# cp deploy/pi-msg-bridge.user.service ~/.config/systemd/user/pi-msg-bridge.service
|
|
6
|
+
# systemctl --user daemon-reload
|
|
7
|
+
# systemctl --user enable --now pi-msg-bridge
|
|
8
|
+
#
|
|
9
|
+
# To keep running after you log out (fully headless):
|
|
10
|
+
# sudo loginctl enable-linger $USER
|
|
11
|
+
#
|
|
12
|
+
# Logs: journalctl --user -u pi-msg-bridge -f
|
|
13
|
+
|
|
14
|
+
[Unit]
|
|
15
|
+
Description=pi-remote (messengers -> pi RPC)
|
|
16
|
+
# The bridge spawns `pi --mode rpc` itself as a child process, so only this
|
|
17
|
+
# one unit is needed. pi sessions persist to disk and are resumed on restart.
|
|
18
|
+
After=default.target
|
|
19
|
+
|
|
20
|
+
[Service]
|
|
21
|
+
Type=simple
|
|
22
|
+
# WorkingDirectory is where the agent works (bash tool, project context).
|
|
23
|
+
# Change to your project dir.
|
|
24
|
+
WorkingDirectory=%h/Projects/pi-remote
|
|
25
|
+
Environment=NVM_DIR=%h/.nvm
|
|
26
|
+
# Optional: PI_MATRIX_HOMESERVER / PI_MATRIX_ACCESS_TOKEN etc. can live here
|
|
27
|
+
# instead of ~/.pi/msg-bridge.json
|
|
28
|
+
EnvironmentFile=-%h/.config/pi-bridge.env
|
|
29
|
+
ExecStart=/bin/bash -lc 'source "$NVM_DIR/nvm.sh" && exec node dist/standalone.js --workdir %h/Projects'
|
|
30
|
+
Restart=on-failure
|
|
31
|
+
RestartSec=5
|
|
32
|
+
# Basic hardening
|
|
33
|
+
NoNewPrivileges=true
|
|
34
|
+
PrivateTmp=true
|
|
35
|
+
|
|
36
|
+
[Install]
|
|
37
|
+
WantedBy=default.target
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Challenge-based authentication for remote messengers
|
|
3
|
+
* Ported from vscode-chonky-remote-pilot
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Manages authentication via 6-digit challenge codes and trusted users
|
|
7
|
+
*/
|
|
8
|
+
export declare class ChallengeAuth {
|
|
9
|
+
private onShowCode;
|
|
10
|
+
private onNotify;
|
|
11
|
+
private onSendMessage?;
|
|
12
|
+
private onSaveAuth?;
|
|
13
|
+
private challenges;
|
|
14
|
+
private trustedUsers;
|
|
15
|
+
private channelAuth;
|
|
16
|
+
private blockedUsers;
|
|
17
|
+
private adminUserId?;
|
|
18
|
+
constructor(onShowCode: (code: string, username: string) => void, onNotify: (message: string, level?: "info" | "warning" | "error") => void, onSendMessage?: ((chatId: string, message: string) => Promise<void>) | undefined, onSaveAuth?: (() => void) | undefined);
|
|
19
|
+
/**
|
|
20
|
+
* Initialize auth state from config
|
|
21
|
+
*/
|
|
22
|
+
loadFromConfig(config: {
|
|
23
|
+
trustedUsers?: string[];
|
|
24
|
+
adminUserId?: string;
|
|
25
|
+
channels?: Record<string, {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
mode: "all" | "mentions" | "trusted-only";
|
|
28
|
+
}>;
|
|
29
|
+
}): void;
|
|
30
|
+
/**
|
|
31
|
+
* Export auth state for config persistence
|
|
32
|
+
*/
|
|
33
|
+
exportConfig(): {
|
|
34
|
+
trustedUsers: string[];
|
|
35
|
+
adminUserId?: string;
|
|
36
|
+
channels: Record<string, {
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
mode: "all" | "mentions" | "trusted-only";
|
|
39
|
+
}>;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Check if a user is authorized to send messages
|
|
43
|
+
* Handles challenge creation, validation, and channel authorization
|
|
44
|
+
*/
|
|
45
|
+
checkAuthorization(userId: string, chatId: string, username: string, isGroupChat: boolean, wasMentioned: boolean, sendMessage?: (chatId: string, message: string) => Promise<void>, transport?: string): Promise<boolean>;
|
|
46
|
+
/**
|
|
47
|
+
* Initiate or validate a challenge
|
|
48
|
+
*/
|
|
49
|
+
private initiateChallenge;
|
|
50
|
+
/**
|
|
51
|
+
* Handle admin commands in DM
|
|
52
|
+
* Returns true if command was handled
|
|
53
|
+
*/
|
|
54
|
+
handleAdminCommand(text: string, _chatId: string, userId: string, sendMessage: (text: string) => Promise<void>, transport?: string): Promise<boolean>;
|
|
55
|
+
/**
|
|
56
|
+
* Validate a challenge code entered by the user
|
|
57
|
+
*/
|
|
58
|
+
private validateChallenge;
|
|
59
|
+
/**
|
|
60
|
+
* Generate a random 6-digit code
|
|
61
|
+
*/
|
|
62
|
+
private generateCode;
|
|
63
|
+
/**
|
|
64
|
+
* Get help text for admin commands
|
|
65
|
+
*/
|
|
66
|
+
private getHelpText;
|
|
67
|
+
/**
|
|
68
|
+
* Get current stats with detailed user info
|
|
69
|
+
*/
|
|
70
|
+
getStats(): {
|
|
71
|
+
trustedUsers: number;
|
|
72
|
+
channels: number;
|
|
73
|
+
usersByTransport: Record<string, string[]>;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=challenge-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"challenge-auth.d.ts","sourceRoot":"","sources":["../../src/auth/challenge-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkBH;;GAEG;AACH,qBAAa,aAAa;IAQtB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,aAAa,CAAC;IACtB,OAAO,CAAC,UAAU,CAAC;IAVrB,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,WAAW,CAAC,CAAS;gBAGnB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,EACpD,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,KAAK,IAAI,EACzE,aAAa,CAAC,GAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,aAAA,EAClE,UAAU,CAAC,GAAE,MAAM,IAAI,aAAA;IAGjC;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE;QACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,IAAI,EAAE,KAAK,GAAG,UAAU,GAAG,cAAc,CAAA;SAAE,CAAC,CAAC;KAC5F,GAAG,IAAI;IAYR;;OAEG;IACH,YAAY,IAAI;QACd,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,IAAI,EAAE,KAAK,GAAG,UAAU,GAAG,cAAc,CAAA;SAAE,CAAC,CAAC;KAC3F;IAQD;;;OAGG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,OAAO,EACpB,YAAY,EAAE,OAAO,EACrB,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EAChE,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC;IAyDnB;;OAEG;YACW,iBAAiB;IAkD/B;;;OAGG;IACG,kBAAkB,CACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EAC5C,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC;IAkHnB;;OAEG;YACW,iBAAiB;IAyC/B;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAmBnB;;OAEG;IACH,QAAQ,IAAI;QACV,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;KAC5C;CAmBF"}
|