@zxh126/pi-qqbot 2.4.1 → 2.6.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/CHANGELOG.md +41 -0
- package/LICENSE +21 -21
- package/README.md +12 -8
- package/approver.ts +2 -2
- package/billing.ts +579 -579
- package/constants.ts +2 -0
- package/docs/README.zh-CN.md +11 -8
- package/docs/accounts.md +88 -88
- package/index.ts +131 -20
- package/lock.ts +237 -237
- package/logger.ts +58 -58
- package/package.json +2 -2
- package/progress.ts +176 -176
- package/qq/api.ts +17 -0
- package/qq/auth.ts +35 -35
- package/qq/gateway.ts +20 -3
- package/qq/keyboard.ts +141 -0
- package/queue.ts +120 -120
- package/redact.ts +136 -136
- package/selfupdate.ts +212 -212
- package/slash.ts +3 -2
- package/stream-buffer.ts +22 -22
- package/util/chunk.ts +107 -42
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,47 @@
|
|
|
3
3
|
本文件记录 pi-qqbot 的版本变更。格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
|
4
4
|
版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
|
|
5
5
|
|
|
6
|
+
## [2.6.0] - 2026-11-01
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **审批与单选列表支持内联按钮**:审批卡片附带「✅ 允许一次 / ❌ 拒绝 / 🚀 以后都同意」按钮
|
|
11
|
+
(强制审批工具只有前两个);/tree、/fork、/resume 与模型选择列表附带选项按钮(2 列、最多 5 行,
|
|
12
|
+
label 超 10 字符截断,正文仍保留完整列表)。按钮只在 markdown 回复(`markdownReply=true`)时附带。
|
|
13
|
+
- **`INTERACTION_CREATE` 事件链路**:网关新增 `1<<26` 意图订阅与互动事件分发;`QQApi.acknowledgeInteraction`
|
|
14
|
+
在 5 秒窗口内 `PUT /interactions/{id}` 回应(命中 ACK 0,过期/越权/越界 ACK 3 重复操作)。
|
|
15
|
+
- **`qq/keyboard.ts`**:键盘构建与 `button_data` 编解码(顶层 `t` 字段路由 approval / pick)。
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- `QQApi.sendC2C` 的 `SendOptions.keyboard` 只随 markdown 消息发送;markdown 失败回退纯文本时自动丢弃键盘。
|
|
20
|
+
- `replyTo` / `bridgeReply` 增加可选 `keyboard` 透传;选择按钮点击复用「回复编号」的 `/qq pick` 派发路径,
|
|
21
|
+
审批按钮点击复用 `Approver.confirm` / `allowAll`,文本回复(同意/拒绝 N、编号)全部保留为兜底。
|
|
22
|
+
|
|
23
|
+
### Compatibility
|
|
24
|
+
|
|
25
|
+
- `markdownReply=false` 时行为与之前完全一致(键盘不附带、纯文本回复)。
|
|
26
|
+
- 自定义按钮需 QQ 开放平台「内邀开通」;未开通时按钮不渲染,编号/文本回复不受影响。
|
|
27
|
+
|
|
28
|
+
## [2.5.0] - 2026-11-01
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- **`markdownReply` 配置生效**:置 `true` 后回复统一走 QQ markdown 消息(`msg_type=2`),GFM 表格、
|
|
33
|
+
代码块等由 QQ 客户端渲染。此前该配置只被解析、从未被消费。发送失败(如无 markdown 权限)由
|
|
34
|
+
`qq/api.ts` 自动回退纯文本,行为安全。
|
|
35
|
+
- **`util/chunk.ts` 切分器防拆表格**:`splitText` 把 GFM 表格整块保留(表格行先入缓冲、遇到非表格行
|
|
36
|
+
再整块提交),代码块边界不作切分点;长回复不再出现被拦腰截断的破表。
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- 回复格式由 `state.cfg.markdownReply` 决定:`replyTo` 的 `format` 默认值改为 `auto`,最终答案、
|
|
41
|
+
错误通知、审批提示与各回执统一生效;仍可显式传 `"text"` 强制纯文本。
|
|
42
|
+
|
|
43
|
+
### Compatibility
|
|
44
|
+
|
|
45
|
+
- `markdownReply` 默认仍为 `false`,未开启时行为与之前完全一致。
|
|
46
|
+
|
|
6
47
|
## [2.4.1] - 2026-11-01
|
|
7
48
|
|
|
8
49
|
### Added
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 pi-qqbot contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pi-qqbot contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -12,9 +12,9 @@ Bridge the **[Pi](https://pi.dev) coding agent** into QQ private (C2C) chats: se
|
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Chat-driven agent** | QQ private messages are fed into the current pi session; the assistant's answer is sent back to QQ (long replies are split automatically). |
|
|
14
14
|
| **Message queue** | While a task is running, further QQ messages are **queued** instead of rejected; each one starts automatically as soon as the current run settles. `/cancel` is the exception — it acts immediately and clears the queue. |
|
|
15
|
-
| **Remote approval** | Before pi runs `bash` / `powershell` / `write` / `edit` — or any tool annotated `destructiveHint` — the bot asks in QQ first. |
|
|
15
|
+
| **Remote approval** | Before pi runs `bash` / `powershell` / `write` / `edit` — or any tool annotated `destructiveHint` — the bot asks in QQ first. With `markdownReply: true` the card carries inline buttons; text replies work either way. |
|
|
16
16
|
| **Remote-context notice** | The first QQ message of a session is really handed to pi (loading the extension or chatting locally in the TUI adds nothing), then the bot tells it the conversation comes from a remote QQ user and that the machine may be locked: desktop screenshots / screen OCR / UI automation / headed browsers are off by default, images must be rendered off-screen and sent with `qq_send_file`. Re-injected after context compaction. |
|
|
17
|
-
| **Session-scoped "always allow"** |
|
|
17
|
+
| **Session-scoped "always allow"** | Tap 🚀 以后都同意 on the approval card (or reply 「以后都同意」) and every approval request in the **current session** is auto-approved, including the one already waiting. |
|
|
18
18
|
| **Single-instance lock** | Only one pi process hosts the QQ gateway; the others stand by and take over automatically when the host exits. |
|
|
19
19
|
| **Cancel a running task** | Send `/cancel` (or 「取消」/「停止」) and the current run is aborted immediately — the QQ reply, the pending tool calls, the half-written answer and the pending queue are all cleaned up. |
|
|
20
20
|
| **Slash-command routing** | QQ messages starting with `/` are routed: pi extension commands, prompt templates and `/skill:name` are dispatched to pi; a set of pi built-ins (`/reload`, `/new`, `/compact`, `/session`, `/name`, `/model`, `/thinking`, `/quit`) is taken over; host-only commands are answered instead of being fed to the model. |
|
|
@@ -90,7 +90,7 @@ Then create `~/.pi/agent/pi-qqbot.json`:
|
|
|
90
90
|
| `appId` / `appSecret` | required | Credentials of your QQ Open Platform bot |
|
|
91
91
|
| `sandbox` | `false` | Set `true` while the bot is not yet published (sandbox environment) |
|
|
92
92
|
| `allowlist` | `[]` | openid allowlist; empty means no restriction |
|
|
93
|
-
| `markdownReply` | `false` | QQ
|
|
93
|
+
| `markdownReply` | `false` | Reply with QQ markdown messages (msg_type=2) so GFM tables render; approval and selection lists then carry inline buttons (custom keyboards need platform enablement). Needs the bot's markdown permission; falls back to plain text on send failure |
|
|
94
94
|
| `streaming` | `false` | Reserved, streaming is not enabled in v1 |
|
|
95
95
|
| `approve.tools` | `["bash","powershell","write","edit"]` | Tools that require approval; tools annotated `destructiveHint` are always gated too |
|
|
96
96
|
| `approve.remember` | `true` | Remember the decision per tool inside the session (no more prompts for that tool) |
|
|
@@ -255,10 +255,10 @@ Any message that starts with `/` is routed before it can become a chat prompt:
|
|
|
255
255
|
| `/name [name]` | get or set the session name | `commands.allowSession` |
|
|
256
256
|
| `/model [provider/model]` | list available models or switch | `commands.allowSession` |
|
|
257
257
|
| `/thinking [level]` | get or set the thinking level | `commands.allowSession` |
|
|
258
|
-
| `/tree` | list branch points (numbered), answer with a number to jump there | `commands.allowSession` |
|
|
259
|
-
| `/fork` | list earlier user messages (numbered), answer with a number to fork from it | `commands.allowSession` |
|
|
258
|
+
| `/tree` | list branch points (numbered), answer with a number or tap the button to jump there | `commands.allowSession` |
|
|
259
|
+
| `/fork` | list earlier user messages (numbered), answer with a number or tap the button to fork from it | `commands.allowSession` |
|
|
260
260
|
| `/clone` | duplicate the current session at its current leaf | `commands.allowSession` |
|
|
261
|
-
| `/resume` | list the project's other sessions (numbered), answer with a number to switch | `commands.allowSession` |
|
|
261
|
+
| `/resume` | list the project's other sessions (numbered), answer with a number or tap the button to switch | `commands.allowSession` |
|
|
262
262
|
| `/quit` | shuts the host pi down | `commands.allowQuit` (default **false**) |
|
|
263
263
|
| `/update` | updates pi-qqbot from npm (`pi update`) and reloads itself — see [Self-update](#self-update-from-qq) | `commands.allowUpdate` (default **false**) |
|
|
264
264
|
|
|
@@ -297,7 +297,7 @@ Guards:
|
|
|
297
297
|
- Prompt templates and `/skill:name` start an agent run, so while a task is in progress they are
|
|
298
298
|
**queued** like ordinary messages (see [Queueing while busy](#queueing-while-busy)). Extension commands
|
|
299
299
|
that manage their own LLM interaction still run immediately.
|
|
300
|
-
- Selection commands (`/tree`, `/fork`, `/resume`) answer with a numbered list of at most 10 entries, scoped to
|
|
300
|
+
- Selection commands (`/tree`, `/fork`, `/resume`) answer with a numbered list of at most 10 entries (with tap-to-select buttons when `markdownReply` is on), scoped to
|
|
301
301
|
the user who asked and valid for 10 minutes. The next bare number from that user executes the choice; anything
|
|
302
302
|
else (or 「取消」) abandons it. A number without a pending list is ordinary chat.
|
|
303
303
|
- `/reload` is off by default: it restarts the bot, and if the new code fails to load the bot stays
|
|
@@ -481,7 +481,11 @@ This is pi's own update path, not a re-implementation: `npm view @zxh126/pi-qqbo
|
|
|
481
481
|
要本会话内全部放行,回复「以后都同意」(可用「取消自动同意」关闭)。
|
|
482
482
|
```
|
|
483
483
|
|
|
484
|
-
|
|
484
|
+
With `markdownReply: true` the card carries ✅ 允许一次 / ❌ 拒绝 / 🚀 以后都同意 buttons — tapping one
|
|
485
|
+
is the same as replying. Strict tools (`qq_send_file`) show only the first two buttons. Text replies keep
|
|
486
|
+
working either way.
|
|
487
|
+
|
|
488
|
+
Reply vocabulary (approval keywords are Chinese, with English aliases; the card buttons are the faster path when they are shown):
|
|
485
489
|
|
|
486
490
|
| Intent | Reply |
|
|
487
491
|
|---|---|
|
package/approver.ts
CHANGED
|
@@ -99,8 +99,8 @@ export class Approver {
|
|
|
99
99
|
render(seq: number, opts: { strict?: boolean } = {}): string {
|
|
100
100
|
const item = this.pending.get(seq);
|
|
101
101
|
const hint = opts.strict
|
|
102
|
-
?
|
|
103
|
-
:
|
|
102
|
+
? `点下方按钮,或回「同意 ${seq}」/「拒绝 ${seq}」,需单独确认。`
|
|
103
|
+
: `点下方按钮,或回「同意 ${seq}」/「拒绝 ${seq}」;想全部放行回「以后都同意」。`;
|
|
104
104
|
return [`[审批 #${seq}] ${item?.summary ?? ""}`, hint].join("\n");
|
|
105
105
|
}
|
|
106
106
|
|