@foxden-app/foxclaw 0.2.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/.env.example +36 -0
- package/LICENSE +22 -0
- package/README.md +244 -0
- package/README_EN.md +244 -0
- package/dist/channels/bridge_messaging_router.d.ts +27 -0
- package/dist/channels/bridge_messaging_router.js +85 -0
- package/dist/channels/telegram/telegram_channel_adapter.d.ts +12 -0
- package/dist/channels/telegram/telegram_channel_adapter.js +21 -0
- package/dist/channels/telegram/telegram_messaging_port.d.ts +25 -0
- package/dist/channels/telegram/telegram_messaging_port.js +51 -0
- package/dist/channels/weixin/account_store.d.ts +15 -0
- package/dist/channels/weixin/account_store.js +54 -0
- package/dist/channels/weixin/ilink/aes_ecb.d.ts +3 -0
- package/dist/channels/weixin/ilink/aes_ecb.js +12 -0
- package/dist/channels/weixin/ilink/api.d.ts +44 -0
- package/dist/channels/weixin/ilink/api.js +187 -0
- package/dist/channels/weixin/ilink/cdn_upload.d.ts +11 -0
- package/dist/channels/weixin/ilink/cdn_upload.js +60 -0
- package/dist/channels/weixin/ilink/cdn_url.d.ts +7 -0
- package/dist/channels/weixin/ilink/cdn_url.js +7 -0
- package/dist/channels/weixin/ilink/constants.d.ts +7 -0
- package/dist/channels/weixin/ilink/constants.js +27 -0
- package/dist/channels/weixin/ilink/context.d.ts +13 -0
- package/dist/channels/weixin/ilink/context.js +13 -0
- package/dist/channels/weixin/ilink/login_qr.d.ts +34 -0
- package/dist/channels/weixin/ilink/login_qr.js +233 -0
- package/dist/channels/weixin/ilink/media_image.d.ts +11 -0
- package/dist/channels/weixin/ilink/media_image.js +44 -0
- package/dist/channels/weixin/ilink/mime.d.ts +3 -0
- package/dist/channels/weixin/ilink/mime.js +36 -0
- package/dist/channels/weixin/ilink/pic_decrypt.d.ts +2 -0
- package/dist/channels/weixin/ilink/pic_decrypt.js +56 -0
- package/dist/channels/weixin/ilink/random.d.ts +2 -0
- package/dist/channels/weixin/ilink/random.js +7 -0
- package/dist/channels/weixin/ilink/redact.d.ts +4 -0
- package/dist/channels/weixin/ilink/redact.js +34 -0
- package/dist/channels/weixin/ilink/runtime_attach.d.ts +3 -0
- package/dist/channels/weixin/ilink/runtime_attach.js +13 -0
- package/dist/channels/weixin/ilink/send.d.ts +21 -0
- package/dist/channels/weixin/ilink/send.js +108 -0
- package/dist/channels/weixin/ilink/session_guard.d.ts +6 -0
- package/dist/channels/weixin/ilink/session_guard.js +39 -0
- package/dist/channels/weixin/ilink/types.d.ts +155 -0
- package/dist/channels/weixin/ilink/types.js +10 -0
- package/dist/channels/weixin/ilink/upload.d.ts +15 -0
- package/dist/channels/weixin/ilink/upload.js +75 -0
- package/dist/channels/weixin/sync_buf_store.d.ts +3 -0
- package/dist/channels/weixin/sync_buf_store.js +19 -0
- package/dist/channels/weixin/weixin_channel_adapter.d.ts +18 -0
- package/dist/channels/weixin/weixin_channel_adapter.js +273 -0
- package/dist/channels/weixin/weixin_messaging_port.d.ts +29 -0
- package/dist/channels/weixin/weixin_messaging_port.js +113 -0
- package/dist/codex_app/client.d.ts +176 -0
- package/dist/codex_app/client.js +1230 -0
- package/dist/codex_app/deeplink.d.ts +7 -0
- package/dist/codex_app/deeplink.js +29 -0
- package/dist/codex_app/local_usage.d.ts +16 -0
- package/dist/codex_app/local_usage.js +123 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.js +131 -0
- package/dist/controller/access.d.ts +11 -0
- package/dist/controller/access.js +33 -0
- package/dist/controller/activity.d.ts +62 -0
- package/dist/controller/activity.js +330 -0
- package/dist/controller/commands.d.ts +6 -0
- package/dist/controller/commands.js +17 -0
- package/dist/controller/controller.d.ts +326 -0
- package/dist/controller/controller.js +7503 -0
- package/dist/controller/observer.d.ts +16 -0
- package/dist/controller/observer.js +98 -0
- package/dist/controller/presentation.d.ts +80 -0
- package/dist/controller/presentation.js +568 -0
- package/dist/controller/service_tier.d.ts +9 -0
- package/dist/controller/service_tier.js +32 -0
- package/dist/controller/session_observer.d.ts +22 -0
- package/dist/controller/session_observer.js +259 -0
- package/dist/controller/status.d.ts +10 -0
- package/dist/controller/status.js +28 -0
- package/dist/core/bridge_scope.d.ts +18 -0
- package/dist/core/bridge_scope.js +46 -0
- package/dist/core/channel_port.d.ts +15 -0
- package/dist/core/channel_port.js +1 -0
- package/dist/i18n.d.ts +1108 -0
- package/dist/i18n.js +1154 -0
- package/dist/lock.d.ts +7 -0
- package/dist/lock.js +80 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +57 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +236 -0
- package/dist/runtime.d.ts +3 -0
- package/dist/runtime.js +14 -0
- package/dist/store/database.d.ts +79 -0
- package/dist/store/database.js +489 -0
- package/dist/store/migrate_bridge_scope.d.ts +6 -0
- package/dist/store/migrate_bridge_scope.js +59 -0
- package/dist/telegram/addressing.d.ts +33 -0
- package/dist/telegram/addressing.js +57 -0
- package/dist/telegram/api.d.ts +14 -0
- package/dist/telegram/api.js +89 -0
- package/dist/telegram/gateway.d.ts +76 -0
- package/dist/telegram/gateway.js +383 -0
- package/dist/telegram/media.d.ts +34 -0
- package/dist/telegram/media.js +180 -0
- package/dist/telegram/rendering.d.ts +10 -0
- package/dist/telegram/rendering.js +21 -0
- package/dist/telegram/scope.d.ts +6 -0
- package/dist/telegram/scope.js +24 -0
- package/dist/telegram/text.d.ts +7 -0
- package/dist/telegram/text.js +47 -0
- package/dist/types.d.ts +343 -0
- package/dist/types.js +1 -0
- package/docs/agent-assisted-install.md +84 -0
- package/docs/install-for-beginners.md +287 -0
- package/docs/troubleshooting.md +239 -0
- package/package.json +62 -0
- package/scripts/doctor.sh +3 -0
- package/scripts/launchd/install.sh +54 -0
- package/scripts/status.sh +3 -0
- package/scripts/systemd/install.sh +83 -0
- package/scripts/systemd/uninstall.sh +15 -0
- package/skills/foxclaw/SKILL.md +167 -0
- package/skills/foxclaw/agents/openai.yaml +4 -0
- package/skills/foxclaw/references/telegram-setup.md +93 -0
- package/skills/foxclaw/scripts/bootstrap_host.py +350 -0
- package/skills/foxclaw/scripts/bootstrap_remote.py +67 -0
package/.env.example
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Required: one bot token per device
|
|
2
|
+
TG_BOT_TOKEN=<telegram_bot_token>
|
|
3
|
+
|
|
4
|
+
# Required: only this Telegram user can control the bridge
|
|
5
|
+
TG_ALLOWED_USER_ID=<telegram_user_id>
|
|
6
|
+
|
|
7
|
+
# Optional: set this to allow a specific group/supergroup
|
|
8
|
+
TG_ALLOWED_CHAT_ID=
|
|
9
|
+
|
|
10
|
+
# Optional: set this to make one topic the default conversation scope
|
|
11
|
+
# Leave empty to use the whole allowed group as the default scope
|
|
12
|
+
TG_ALLOWED_TOPIC_ID=
|
|
13
|
+
|
|
14
|
+
# Optional Codex Desktop bridge settings
|
|
15
|
+
CODEX_APP_AUTOLAUNCH=true
|
|
16
|
+
CODEX_APP_LAUNCH_CMD=codex app
|
|
17
|
+
# Optional: persist the managed app-server pid/port and collect its stdout/stderr
|
|
18
|
+
CODEX_APP_SERVER_STATE_PATH=
|
|
19
|
+
CODEX_APP_SERVER_LOG_PATH=
|
|
20
|
+
CODEX_APP_SYNC_ON_OPEN=true
|
|
21
|
+
CODEX_APP_SYNC_ON_TURN_COMPLETE=false
|
|
22
|
+
STORE_PATH=
|
|
23
|
+
LOG_LEVEL=info
|
|
24
|
+
DEFAULT_CWD=/absolute/path/to/workspace
|
|
25
|
+
DEFAULT_APPROVAL_POLICY=on-request
|
|
26
|
+
DEFAULT_SANDBOX_MODE=workspace-write
|
|
27
|
+
TELEGRAM_POLL_INTERVAL_MS=1200
|
|
28
|
+
TELEGRAM_PREVIEW_THROTTLE_MS=800
|
|
29
|
+
THREAD_LIST_LIMIT=10
|
|
30
|
+
CODEX_CLI_BIN=/absolute/path/to/codex
|
|
31
|
+
|
|
32
|
+
# Weixin (iLink): run `npm run weixin-login` once, then enable:
|
|
33
|
+
# WX_ENABLED=true
|
|
34
|
+
# Comma-separated iLink user ids allowed to chat (see account JSON linkedIlinkUserId)
|
|
35
|
+
# WX_ALLOWED_ILINK_USER_IDS=
|
|
36
|
+
# Optional: WEIXIN_ACCOUNTS_DIR, WEIXIN_SYNC_BUF_DIR, WEIXIN_MEDIA_DIR, WX_ILINK_ROUTE_TAG
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gan Xing
|
|
4
|
+
Copyright (c) 2026 Foxden App contributors
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
中文 | [English](./README_EN.md)
|
|
2
|
+
|
|
3
|
+
# FoxClaw
|
|
4
|
+
|
|
5
|
+
FoxClaw 是 Foxden agents 的本地执行爪。
|
|
6
|
+
|
|
7
|
+
它运行在你自己的电脑上,让受信任的 Telegram 或微信聊天可以控制本机 Codex 环境。你不需要公网服务器:FoxClaw 通过本地 `codex app-server` 与 Codex 通信,把审批留在你的电脑上,并把工作会话发送回手机。
|
|
8
|
+
|
|
9
|
+
## 从这里开始
|
|
10
|
+
|
|
11
|
+
- 已经有 Codex、OpenClaw、QwenPaw、Hermes、OpenCode 或 Kimi CLI 这类能操作 shell 的 agent?优先使用 [Agent 辅助安装](./docs/agent-assisted-install.md),这是推荐路径。
|
|
12
|
+
- 不熟悉 Node、Telegram 机器人或 Codex CLI?使用 [新手安装指南](./docs/install-for-beginners.md)。
|
|
13
|
+
- 已经熟悉 Git、Node 和 `.env` 文件?可以直接使用下面的快速设置。
|
|
14
|
+
- 遇到问题?查看 [故障排查](./docs/troubleshooting.md)。
|
|
15
|
+
|
|
16
|
+
如果你希望做到这些,FoxClaw 会很适合:
|
|
17
|
+
|
|
18
|
+
- 在手机上使用 Codex,同时不把自己的电脑暴露到公网
|
|
19
|
+
- 将代码、shell 访问、认证、审批和运行数据都保留在自己的机器上
|
|
20
|
+
- 让一个受信任的 Telegram 用户作为远程操作者
|
|
21
|
+
|
|
22
|
+
最小安装只需要一个 Telegram bot token、你的 Telegram 数字用户 ID、Node.js 24,以及一份已经登录的 `codex` CLI。首次安装通常需要 10-20 分钟。
|
|
23
|
+
|
|
24
|
+
30 秒产品示例:FoxClaw 运行后,向你的 Telegram 机器人发送 `List files in DEFAULT_CWD`。FoxClaw 会让本地 Codex 检查你电脑上的那个目录,并把答案发回 Telegram。
|
|
25
|
+
|
|
26
|
+
## 环境要求
|
|
27
|
+
|
|
28
|
+
- macOS 或 Linux,并且有可用的 `codex` CLI
|
|
29
|
+
- 主机上的 Codex 已完成认证
|
|
30
|
+
- Node.js 24+
|
|
31
|
+
- 来自 `@BotFather` 的 Telegram bot token
|
|
32
|
+
- 你的 Telegram 数字用户 ID
|
|
33
|
+
|
|
34
|
+
## 快速设置
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/foxden-app/foxclaw.git
|
|
38
|
+
cd foxclaw
|
|
39
|
+
npm install
|
|
40
|
+
cp .env.example .env
|
|
41
|
+
$EDITOR .env
|
|
42
|
+
npm run build
|
|
43
|
+
npm run doctor
|
|
44
|
+
npm run serve
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
运行 `doctor` 或 `serve` 前先编辑 `.env`。私聊模式的最小配置:
|
|
48
|
+
|
|
49
|
+
```dotenv
|
|
50
|
+
TG_BOT_TOKEN=123456:telegram-token
|
|
51
|
+
TG_ALLOWED_USER_ID=123456789
|
|
52
|
+
DEFAULT_CWD=/absolute/path/to/workspace
|
|
53
|
+
DEFAULT_APPROVAL_POLICY=on-request
|
|
54
|
+
DEFAULT_SANDBOX_MODE=workspace-write
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
FoxClaw 只接受来自 `TG_ALLOWED_USER_ID` 的消息。把机器人放进群组并不会让每个群成员都能使用它。
|
|
58
|
+
|
|
59
|
+
<details>
|
|
60
|
+
<summary>FoxClaw 运行后可以做什么</summary>
|
|
61
|
+
|
|
62
|
+
- 允许一个 Telegram 用户通过私聊、群组和话题控制
|
|
63
|
+
- 可选的微信/iLink 通道,复用同一套桥接核心
|
|
64
|
+
- 使用 `/threads`、`/open`、`/new`、`/where` 和 `/interrupt` 进行稳定的聊天到线程绑定
|
|
65
|
+
- 从手机控制线程生命周期:重命名、归档、取消归档、fork、回滚、compact、review 和 diff
|
|
66
|
+
- 面向单个聊天的设置面板:模型、reasoning effort、Fast service tier、access preset、Agent/Plan 模式和 active-turn 行为
|
|
67
|
+
- Codex 账户控制:`/account`、`/quota`、`/login_device`、`/login_cancel`、`/auth add <name>`,以及带保护的 `/logout confirm`
|
|
68
|
+
- 当某个认证触发用量限制时,在本地 `auth.json_*` 候选之间自动切换 Codex 认证
|
|
69
|
+
- 针对命令、文件变更和细粒度权限审批的内联按钮
|
|
70
|
+
- 针对工具在 turn 中提出的结构化问题显示 MCP elicitation 卡片
|
|
71
|
+
- Skills、MCP、hooks、plugins、apps、feature flags、config、requirements 和 provider diagnostics
|
|
72
|
+
- 使用 SQLite 持久化绑定、offset、审批、待处理输入提示和审计日志
|
|
73
|
+
- 单实例进程锁,避免同一个 bot token 上出现重复 Telegram polling
|
|
74
|
+
|
|
75
|
+
</details>
|
|
76
|
+
|
|
77
|
+
## 作为服务安装
|
|
78
|
+
|
|
79
|
+
Linux 用户级 systemd:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm run install-systemd
|
|
83
|
+
systemctl --user status foxclaw.service
|
|
84
|
+
journalctl --user -u foxclaw.service -f
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
macOS launchd:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
./scripts/launchd/install.sh
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
默认运行时文件存储在 `~/.foxclaw`:
|
|
94
|
+
|
|
95
|
+
- store:`~/.foxclaw/data/bridge.sqlite`
|
|
96
|
+
- bridge log:`~/.foxclaw/logs/service.log`
|
|
97
|
+
- status:`~/.foxclaw/runtime/status.json`
|
|
98
|
+
- app-server state:`~/.foxclaw/runtime/codex-app-server.json`
|
|
99
|
+
- app-server log:`~/.foxclaw/logs/codex-app-server.log`
|
|
100
|
+
|
|
101
|
+
可以用 `STORE_PATH`、`LOCK_PATH`、`CODEX_APP_SERVER_STATE_PATH` 和 `CODEX_APP_SERVER_LOG_PATH` 覆盖 store、lock 和 app-server 路径。
|
|
102
|
+
|
|
103
|
+
## 从 telegram-codex-app-bridge 迁移
|
|
104
|
+
|
|
105
|
+
FoxClaw 最初 fork 自 `Gan-Xing/telegram-codex-app-bridge`,并继续以 MIT License 分发。
|
|
106
|
+
|
|
107
|
+
升级已有本地安装时:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
systemctl --user disable --now telegram-codex-app-bridge.service 2>/dev/null || true
|
|
111
|
+
test -e ~/.foxclaw || cp -a ~/.telegram-codex-app-bridge ~/.foxclaw
|
|
112
|
+
npm run install-systemd
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
如果使用 launchd 安装,先卸载旧 plist(如存在):
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
launchctl unload ~/Library/LaunchAgents/com.ganxing.telegram-codex-app-bridge.plist 2>/dev/null || true
|
|
119
|
+
./scripts/launchd/install.sh
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
旧运行时目录不会被自动读取。如果你想保留现有绑定、缓存线程列表、审批和状态数据,请手动复制一次。
|
|
123
|
+
|
|
124
|
+
## Telegram 设置
|
|
125
|
+
|
|
126
|
+
1. 使用 `@BotFather` 创建机器人,并把 token 填入 `TG_BOT_TOKEN`。
|
|
127
|
+
2. 获取你的 Telegram 数字用户 ID,并填入 `TG_ALLOWED_USER_ID`。
|
|
128
|
+
3. 使用 `npm run serve` 或服务安装器启动 FoxClaw。
|
|
129
|
+
4. 打开与机器人的私聊并发送 `/help`。
|
|
130
|
+
|
|
131
|
+
可选的群组/话题配置:
|
|
132
|
+
|
|
133
|
+
```dotenv
|
|
134
|
+
TG_ALLOWED_CHAT_ID=-1001234567890
|
|
135
|
+
TG_ALLOWED_TOPIC_ID=42
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- 留空 `TG_ALLOWED_CHAT_ID` 表示使用私聊模式。
|
|
139
|
+
- 只设置 `TG_ALLOWED_CHAT_ID` 时,允许一个群组作为默认会话范围。
|
|
140
|
+
- 同时设置 `TG_ALLOWED_CHAT_ID` 和 `TG_ALLOWED_TOPIC_ID` 时,绑定一个话题作为默认范围。
|
|
141
|
+
- 即使配置了群组,`TG_ALLOWED_USER_ID` 仍然可以继续使用私聊。
|
|
142
|
+
|
|
143
|
+
查找群组和话题 ID:
|
|
144
|
+
|
|
145
|
+
1. 停止 FoxClaw。
|
|
146
|
+
2. 在目标群组或话题中发送一条消息。
|
|
147
|
+
3. 打开 `https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates`。
|
|
148
|
+
4. 读取 `message.chat.id` 作为 `TG_ALLOWED_CHAT_ID`。
|
|
149
|
+
5. 读取 `message.message_thread_id` 作为 `TG_ALLOWED_TOPIC_ID`。
|
|
150
|
+
|
|
151
|
+
如果 FoxClaw 还在运行,它可能会在你检查前消费掉该 update。
|
|
152
|
+
|
|
153
|
+
## Telegram 群组检查清单
|
|
154
|
+
|
|
155
|
+
对于群组或超级群里的自然语言消息:
|
|
156
|
+
|
|
157
|
+
1. 将机器人加入目标群组。
|
|
158
|
+
2. 在 `@BotFather` 中禁用机器人的 `privacy mode`。
|
|
159
|
+
3. 将机器人提升为该群管理员。
|
|
160
|
+
4. 如果是在加入群组后才修改隐私模式,请移除并重新加入机器人。
|
|
161
|
+
|
|
162
|
+
即使 privacy mode 阻止普通消息,`/status@botname` 这样的显式命令也可能正常工作,所以请用一条普通消息验证群组设置。
|
|
163
|
+
|
|
164
|
+
## Codex App-Server 生命周期
|
|
165
|
+
|
|
166
|
+
默认配置:
|
|
167
|
+
|
|
168
|
+
```dotenv
|
|
169
|
+
CODEX_APP_AUTOLAUNCH=true
|
|
170
|
+
CODEX_APP_LAUNCH_CMD=codex app
|
|
171
|
+
CODEX_APP_SERVER_STATE_PATH=
|
|
172
|
+
CODEX_APP_SERVER_LOG_PATH=
|
|
173
|
+
CODEX_APP_SYNC_ON_OPEN=true
|
|
174
|
+
CODEX_APP_SYNC_ON_TURN_COMPLETE=false
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
FoxClaw 会把 `codex app-server` 启动为一个由 bridge 管理的 detached 进程,并记录它的 pid 和端口。重启时,如果记录的 app-server 进程仍然存活,FoxClaw 会重新连接;否则会启动一个新进程。`/auth_reload` 和认证切换会重启托管的 app-server,从而重新加载当前 `auth.json`。
|
|
178
|
+
|
|
179
|
+
正常安装不需要固定的 Codex app-server 端口。
|
|
180
|
+
|
|
181
|
+
## 命令
|
|
182
|
+
|
|
183
|
+
- `/help`
|
|
184
|
+
- `/setup` 打开统一偏好设置面板
|
|
185
|
+
- `/fast <on|off|toggle>`
|
|
186
|
+
- `/active <steer|queue>`
|
|
187
|
+
- `/status`、`/account`、`/quota`
|
|
188
|
+
- `/quota_nudge <credits|usage_limit> confirm`
|
|
189
|
+
- `/login_device`、`/login_cancel [id]`、`/logout confirm`
|
|
190
|
+
- `/auth [list|use <n>|enable <n>|disable <n>|reload|add <name>]`
|
|
191
|
+
- `/threads [query]`、`/threads archived`、`/open <n>`
|
|
192
|
+
- `/goal [objective|pause|resume|done|budget <tokens|off>|clear confirm]`
|
|
193
|
+
- `/history [limit]`、`/files <query>`、`/remote`
|
|
194
|
+
- `/new [cwd]`
|
|
195
|
+
- `/steer <message>`、`/takeover <message>`、`/queue <message>`
|
|
196
|
+
- `/review [base <branch>|commit <sha>|custom <instructions>]`
|
|
197
|
+
- `/diff`、`/fork [name]`、`/undo [n]`、`/rollback [n]`
|
|
198
|
+
- `/rename <name>`、`/compact`、`/archive`、`/unarchive <n>`
|
|
199
|
+
- `/skills [query]`、`/skill <name>`、`/skill_enable <name>`、`/skill_disable <name>`
|
|
200
|
+
- `/loaded`、`/hooks`、`/plugins [query]`、`/apps [reload]`、`/features`、`/config`、`/requirements`、`/provider`
|
|
201
|
+
- `/mcp`、`/mcp_reload`、`/mcp_login <server>`、`/mcp_resource <server> <uri>`
|
|
202
|
+
- `/models`、`/model`、`/effort`、`/permissions`、`/access`、`/mode`、`/plan` 和 `/agent`
|
|
203
|
+
- `/reveal`、`/where`、`/interrupt`
|
|
204
|
+
|
|
205
|
+
普通文本会发送到当前线程;如果当前没有绑定线程,则创建一个新线程。
|
|
206
|
+
|
|
207
|
+
## 微信/iLink
|
|
208
|
+
|
|
209
|
+
微信支持是可选的,默认关闭:
|
|
210
|
+
|
|
211
|
+
```dotenv
|
|
212
|
+
WX_ENABLED=true
|
|
213
|
+
WX_ALLOWED_ILINK_USER_IDS=
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
构建后运行一次二维码登录助手:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
npm run weixin-login
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
微信运行时文件默认存储在 `~/.foxclaw/weixin`。
|
|
223
|
+
|
|
224
|
+
## Codex Skill
|
|
225
|
+
|
|
226
|
+
本仓库内置一个 Codex skill:[`skills/foxclaw`](./skills/foxclaw)。当你想让 Codex 在本机或另一台 Mac 上通过 SSH bootstrap FoxClaw、写入 `.env`、构建、运行 doctor、安装 launchd,并指导首次消息验证时,可以使用它。
|
|
227
|
+
|
|
228
|
+
## 故障排查
|
|
229
|
+
|
|
230
|
+
`doctor` 失败、Telegram 没有回复、服务日志、重启行为和迁移问题,请查看 [故障排查](./docs/troubleshooting.md)。
|
|
231
|
+
|
|
232
|
+
## 运维命令
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
npm run build
|
|
236
|
+
npm run doctor
|
|
237
|
+
npm run status
|
|
238
|
+
npm run install-systemd
|
|
239
|
+
npm run uninstall-systemd
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## 贡献
|
|
243
|
+
|
|
244
|
+
欢迎在 `https://github.com/foxden-app/foxclaw` 提交 issue 和 PR。
|
package/README_EN.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
[中文](./README.md) | English
|
|
2
|
+
|
|
3
|
+
# FoxClaw
|
|
4
|
+
|
|
5
|
+
FoxClaw is the local execution claw for Foxden agents.
|
|
6
|
+
|
|
7
|
+
It runs on your own computer and lets a trusted Telegram or Weixin chat control your local Codex environment. You do not need a public server: FoxClaw talks to Codex over local `codex app-server`, keeps approvals on your machine, and sends the working conversation back to your phone.
|
|
8
|
+
|
|
9
|
+
## Start Here
|
|
10
|
+
|
|
11
|
+
- Already have a shell-capable agent such as Codex, OpenClaw, QwenPaw, Hermes, OpenCode, or Kimi CLI? Use the [Agent-Assisted Install](./docs/agent-assisted-install.md) first. This is the recommended path.
|
|
12
|
+
- New to Node, Telegram bots, or Codex CLI? Use the [Beginner Install Guide](./docs/install-for-beginners.md).
|
|
13
|
+
- Already comfortable with Git, Node, and `.env` files? Use the quick setup below.
|
|
14
|
+
- Something failed? Check [Troubleshooting](./docs/troubleshooting.md).
|
|
15
|
+
|
|
16
|
+
FoxClaw is a good fit if you want to:
|
|
17
|
+
|
|
18
|
+
- use Codex from your phone without exposing your computer to the public internet
|
|
19
|
+
- keep code, shell access, auth, approvals, and runtime data on your own machine
|
|
20
|
+
- use one trusted Telegram user as the remote operator
|
|
21
|
+
|
|
22
|
+
The minimum install needs only a Telegram bot token, your numeric Telegram user id, Node.js 24, and a logged-in `codex` CLI. A first install usually takes 10-20 minutes.
|
|
23
|
+
|
|
24
|
+
30-second product example: after FoxClaw is running, send `List files in DEFAULT_CWD` to your Telegram bot. FoxClaw asks local Codex to inspect that folder on your computer and sends the answer back to Telegram.
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- macOS or Linux with a working `codex` CLI
|
|
29
|
+
- Codex authenticated on the host machine
|
|
30
|
+
- Node.js 24+
|
|
31
|
+
- A Telegram bot token from `@BotFather`
|
|
32
|
+
- Your Telegram numeric user id
|
|
33
|
+
|
|
34
|
+
## Quick Setup
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/foxden-app/foxclaw.git
|
|
38
|
+
cd foxclaw
|
|
39
|
+
npm install
|
|
40
|
+
cp .env.example .env
|
|
41
|
+
$EDITOR .env
|
|
42
|
+
npm run build
|
|
43
|
+
npm run doctor
|
|
44
|
+
npm run serve
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Edit `.env` before running `doctor` or `serve`. Minimum private-chat config:
|
|
48
|
+
|
|
49
|
+
```dotenv
|
|
50
|
+
TG_BOT_TOKEN=123456:telegram-token
|
|
51
|
+
TG_ALLOWED_USER_ID=123456789
|
|
52
|
+
DEFAULT_CWD=/absolute/path/to/workspace
|
|
53
|
+
DEFAULT_APPROVAL_POLICY=on-request
|
|
54
|
+
DEFAULT_SANDBOX_MODE=workspace-write
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
FoxClaw accepts messages only from `TG_ALLOWED_USER_ID`. Putting the bot in a group does not make it available to every group member.
|
|
58
|
+
|
|
59
|
+
<details>
|
|
60
|
+
<summary>What FoxClaw can do after it is running</summary>
|
|
61
|
+
|
|
62
|
+
- Telegram private chat, group, and topic control for one allowed Telegram user
|
|
63
|
+
- Optional Weixin/iLink channel for the same bridge core
|
|
64
|
+
- Sticky chat-to-thread binding with `/threads`, `/open`, `/new`, `/where`, and `/interrupt`
|
|
65
|
+
- Thread lifecycle controls from mobile: rename, archive, unarchive, fork, rollback, compact, review, and diff
|
|
66
|
+
- Chat-scoped setup panel for model, reasoning effort, Fast service tier, access preset, Agent/Plan mode, and active-turn behavior
|
|
67
|
+
- Codex account controls with `/account`, `/quota`, `/login_device`, `/login_cancel`, `/auth add <name>`, and guarded `/logout confirm`
|
|
68
|
+
- Automatic local Codex auth rotation across `auth.json_*` candidates when a usage-limit auth fails
|
|
69
|
+
- Inline approval buttons for command, file-change, and granular permission approvals
|
|
70
|
+
- MCP elicitation cards for structured questions raised by tools during a turn
|
|
71
|
+
- Skills, MCP, hooks, plugins, apps, feature flags, config, requirements, and provider diagnostics
|
|
72
|
+
- SQLite persistence for bindings, offsets, approvals, pending input prompts, and audit logs
|
|
73
|
+
- Single-instance process lock to prevent duplicate Telegram polling on the same bot token
|
|
74
|
+
|
|
75
|
+
</details>
|
|
76
|
+
|
|
77
|
+
## Installing As A Service
|
|
78
|
+
|
|
79
|
+
Linux user systemd:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm run install-systemd
|
|
83
|
+
systemctl --user status foxclaw.service
|
|
84
|
+
journalctl --user -u foxclaw.service -f
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
macOS launchd:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
./scripts/launchd/install.sh
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Default runtime files are stored under `~/.foxclaw`:
|
|
94
|
+
|
|
95
|
+
- store: `~/.foxclaw/data/bridge.sqlite`
|
|
96
|
+
- bridge log: `~/.foxclaw/logs/service.log`
|
|
97
|
+
- status: `~/.foxclaw/runtime/status.json`
|
|
98
|
+
- app-server state: `~/.foxclaw/runtime/codex-app-server.json`
|
|
99
|
+
- app-server log: `~/.foxclaw/logs/codex-app-server.log`
|
|
100
|
+
|
|
101
|
+
Override the store, lock, and app-server paths with `STORE_PATH`, `LOCK_PATH`, `CODEX_APP_SERVER_STATE_PATH`, and `CODEX_APP_SERVER_LOG_PATH`.
|
|
102
|
+
|
|
103
|
+
## Migrating From telegram-codex-app-bridge
|
|
104
|
+
|
|
105
|
+
FoxClaw was originally forked from `Gan-Xing/telegram-codex-app-bridge` and remains distributed under the MIT License.
|
|
106
|
+
|
|
107
|
+
When upgrading an existing local install:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
systemctl --user disable --now telegram-codex-app-bridge.service 2>/dev/null || true
|
|
111
|
+
test -e ~/.foxclaw || cp -a ~/.telegram-codex-app-bridge ~/.foxclaw
|
|
112
|
+
npm run install-systemd
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
For launchd installs, unload the old plist if present:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
launchctl unload ~/Library/LaunchAgents/com.ganxing.telegram-codex-app-bridge.plist 2>/dev/null || true
|
|
119
|
+
./scripts/launchd/install.sh
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The old runtime directory is not read automatically. Copy it once if you want to keep existing bindings, cached thread lists, approvals, and status data.
|
|
123
|
+
|
|
124
|
+
## Telegram Setup
|
|
125
|
+
|
|
126
|
+
1. Create a bot with `@BotFather` and copy the token into `TG_BOT_TOKEN`.
|
|
127
|
+
2. Get your Telegram numeric user id and place it into `TG_ALLOWED_USER_ID`.
|
|
128
|
+
3. Start FoxClaw with `npm run serve` or the service installer.
|
|
129
|
+
4. Open a private chat with the bot and send `/help`.
|
|
130
|
+
|
|
131
|
+
Optional group/topic config:
|
|
132
|
+
|
|
133
|
+
```dotenv
|
|
134
|
+
TG_ALLOWED_CHAT_ID=-1001234567890
|
|
135
|
+
TG_ALLOWED_TOPIC_ID=42
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- Leave `TG_ALLOWED_CHAT_ID` empty for private-chat mode.
|
|
139
|
+
- Set `TG_ALLOWED_CHAT_ID` only to allow one group as the default conversation scope.
|
|
140
|
+
- Set both `TG_ALLOWED_CHAT_ID` and `TG_ALLOWED_TOPIC_ID` to bind one topic as the default scope.
|
|
141
|
+
- Private chat remains available for `TG_ALLOWED_USER_ID` even when a group is configured.
|
|
142
|
+
|
|
143
|
+
To discover group and topic ids:
|
|
144
|
+
|
|
145
|
+
1. Stop FoxClaw.
|
|
146
|
+
2. Send a message in the target group or topic.
|
|
147
|
+
3. Open `https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates`.
|
|
148
|
+
4. Read `message.chat.id` as `TG_ALLOWED_CHAT_ID`.
|
|
149
|
+
5. Read `message.message_thread_id` as `TG_ALLOWED_TOPIC_ID`.
|
|
150
|
+
|
|
151
|
+
If FoxClaw is still running, it may consume the update before you inspect it.
|
|
152
|
+
|
|
153
|
+
## Telegram Group Checklist
|
|
154
|
+
|
|
155
|
+
For natural-language messages in a group or supergroup:
|
|
156
|
+
|
|
157
|
+
1. Add the bot to the target group.
|
|
158
|
+
2. Disable the bot's `privacy mode` in `@BotFather`.
|
|
159
|
+
3. Promote the bot to administrator in that group.
|
|
160
|
+
4. If privacy mode was changed after adding the bot, remove and re-add the bot.
|
|
161
|
+
|
|
162
|
+
Explicit commands such as `/status@botname` can work even when privacy mode blocks normal messages, so use a plain message to verify group setup.
|
|
163
|
+
|
|
164
|
+
## Codex App-Server Lifecycle
|
|
165
|
+
|
|
166
|
+
By default:
|
|
167
|
+
|
|
168
|
+
```dotenv
|
|
169
|
+
CODEX_APP_AUTOLAUNCH=true
|
|
170
|
+
CODEX_APP_LAUNCH_CMD=codex app
|
|
171
|
+
CODEX_APP_SERVER_STATE_PATH=
|
|
172
|
+
CODEX_APP_SERVER_LOG_PATH=
|
|
173
|
+
CODEX_APP_SYNC_ON_OPEN=true
|
|
174
|
+
CODEX_APP_SYNC_ON_TURN_COMPLETE=false
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
FoxClaw starts `codex app-server` as a detached, bridge-managed process and records its pid and port. On restart, it reconnects to the recorded app-server if that process is still alive; otherwise it starts a new one. `/auth_reload` and auth switching restart the managed app-server so the current `auth.json` is reloaded.
|
|
178
|
+
|
|
179
|
+
No static Codex app-server port is required in normal installs.
|
|
180
|
+
|
|
181
|
+
## Commands
|
|
182
|
+
|
|
183
|
+
- `/help`
|
|
184
|
+
- `/setup` opens the unified preference panel
|
|
185
|
+
- `/fast <on|off|toggle>`
|
|
186
|
+
- `/active <steer|queue>`
|
|
187
|
+
- `/status`, `/account`, `/quota`
|
|
188
|
+
- `/quota_nudge <credits|usage_limit> confirm`
|
|
189
|
+
- `/login_device`, `/login_cancel [id]`, `/logout confirm`
|
|
190
|
+
- `/auth [list|use <n>|enable <n>|disable <n>|reload|add <name>]`
|
|
191
|
+
- `/threads [query]`, `/threads archived`, `/open <n>`
|
|
192
|
+
- `/goal [objective|pause|resume|done|budget <tokens|off>|clear confirm]`
|
|
193
|
+
- `/history [limit]`, `/files <query>`, `/remote`
|
|
194
|
+
- `/new [cwd]`
|
|
195
|
+
- `/steer <message>`, `/takeover <message>`, `/queue <message>`
|
|
196
|
+
- `/review [base <branch>|commit <sha>|custom <instructions>]`
|
|
197
|
+
- `/diff`, `/fork [name]`, `/undo [n]`, `/rollback [n]`
|
|
198
|
+
- `/rename <name>`, `/compact`, `/archive`, `/unarchive <n>`
|
|
199
|
+
- `/skills [query]`, `/skill <name>`, `/skill_enable <name>`, `/skill_disable <name>`
|
|
200
|
+
- `/loaded`, `/hooks`, `/plugins [query]`, `/apps [reload]`, `/features`, `/config`, `/requirements`, `/provider`
|
|
201
|
+
- `/mcp`, `/mcp_reload`, `/mcp_login <server>`, `/mcp_resource <server> <uri>`
|
|
202
|
+
- `/models`, `/model`, `/effort`, `/permissions`, `/access`, `/mode`, `/plan`, and `/agent`
|
|
203
|
+
- `/reveal`, `/where`, `/interrupt`
|
|
204
|
+
|
|
205
|
+
Plain text sends to the current thread, or creates a new one if none is bound.
|
|
206
|
+
|
|
207
|
+
## Weixin/iLink
|
|
208
|
+
|
|
209
|
+
Weixin support is optional and disabled by default:
|
|
210
|
+
|
|
211
|
+
```dotenv
|
|
212
|
+
WX_ENABLED=true
|
|
213
|
+
WX_ALLOWED_ILINK_USER_IDS=
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Run the QR login helper once after building:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
npm run weixin-login
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Weixin runtime files default to `~/.foxclaw/weixin`.
|
|
223
|
+
|
|
224
|
+
## Codex Skill
|
|
225
|
+
|
|
226
|
+
This repo ships a Codex skill at [`skills/foxclaw`](./skills/foxclaw). Use it when you want Codex to bootstrap FoxClaw locally or on another Mac over SSH, write `.env`, build, run doctor, install launchd, and guide first-message validation.
|
|
227
|
+
|
|
228
|
+
## Troubleshooting
|
|
229
|
+
|
|
230
|
+
See [Troubleshooting](./docs/troubleshooting.md) for `doctor` failures, Telegram no-reply cases, service logs, reboot behavior, and migration issues.
|
|
231
|
+
|
|
232
|
+
## Operations
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
npm run build
|
|
236
|
+
npm run doctor
|
|
237
|
+
npm run status
|
|
238
|
+
npm run install-systemd
|
|
239
|
+
npm run uninstall-systemd
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Contributing
|
|
243
|
+
|
|
244
|
+
Issues and PRs are welcome at `https://github.com/foxden-app/foxclaw`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TelegramRemoteFile } from '../telegram/api.js';
|
|
2
|
+
import type { InlineKeyboard, TelegramMessagingPort } from './telegram/telegram_messaging_port.js';
|
|
3
|
+
import type { WeixinMessagingPort } from './weixin/weixin_messaging_port.js';
|
|
4
|
+
/**
|
|
5
|
+
* Routes outbound calls by `scopeId` prefix: {@link BRIDGE_SCOPE_WEIXIN_PREFIX} vs Telegram.
|
|
6
|
+
* Telegram-only surfaces (callbacks, Bot API files) always use the Telegram port.
|
|
7
|
+
*/
|
|
8
|
+
export declare class BridgeMessagingRouter {
|
|
9
|
+
private readonly telegram;
|
|
10
|
+
private readonly weixin;
|
|
11
|
+
constructor(telegram: TelegramMessagingPort, weixin: WeixinMessagingPort | null);
|
|
12
|
+
get hasWeixinTransport(): boolean;
|
|
13
|
+
private isWeixinScope;
|
|
14
|
+
canSendToScope(scopeId: string): boolean;
|
|
15
|
+
private requireWeixinTransport;
|
|
16
|
+
sendPlain(scopeId: string, text: string, keyboard?: InlineKeyboard): Promise<number>;
|
|
17
|
+
sendHtml(scopeId: string, text: string, keyboard?: InlineKeyboard): Promise<number>;
|
|
18
|
+
editPlain(scopeId: string, messageId: number, text: string, keyboard?: InlineKeyboard): Promise<void>;
|
|
19
|
+
editHtml(scopeId: string, messageId: number, text: string, keyboard?: InlineKeyboard): Promise<void>;
|
|
20
|
+
deleteMessage(scopeId: string, messageId: number): Promise<void>;
|
|
21
|
+
sendTypingInScope(scopeId: string): Promise<void>;
|
|
22
|
+
clearInlineKeyboard(scopeId: string, messageId: number): Promise<void>;
|
|
23
|
+
sendDraft(scopeId: string, draftId: number, text: string): Promise<void>;
|
|
24
|
+
answerCallback(callbackQueryId: string, text: string): Promise<void>;
|
|
25
|
+
getFile(fileId: string): Promise<TelegramRemoteFile>;
|
|
26
|
+
downloadResolvedFile(remoteFilePath: string, destinationPath: string): Promise<number>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { BRIDGE_SCOPE_WEIXIN_PREFIX } from '../core/bridge_scope.js';
|
|
2
|
+
/**
|
|
3
|
+
* Routes outbound calls by `scopeId` prefix: {@link BRIDGE_SCOPE_WEIXIN_PREFIX} vs Telegram.
|
|
4
|
+
* Telegram-only surfaces (callbacks, Bot API files) always use the Telegram port.
|
|
5
|
+
*/
|
|
6
|
+
export class BridgeMessagingRouter {
|
|
7
|
+
telegram;
|
|
8
|
+
weixin;
|
|
9
|
+
constructor(telegram, weixin) {
|
|
10
|
+
this.telegram = telegram;
|
|
11
|
+
this.weixin = weixin;
|
|
12
|
+
}
|
|
13
|
+
get hasWeixinTransport() {
|
|
14
|
+
return this.weixin !== null;
|
|
15
|
+
}
|
|
16
|
+
isWeixinScope(scopeId) {
|
|
17
|
+
return scopeId.startsWith(BRIDGE_SCOPE_WEIXIN_PREFIX);
|
|
18
|
+
}
|
|
19
|
+
canSendToScope(scopeId) {
|
|
20
|
+
return !this.isWeixinScope(scopeId) || this.weixin !== null;
|
|
21
|
+
}
|
|
22
|
+
requireWeixinTransport(scopeId) {
|
|
23
|
+
if (!this.weixin) {
|
|
24
|
+
throw new Error(`Weixin channel is disabled for scope ${scopeId}`);
|
|
25
|
+
}
|
|
26
|
+
return this.weixin;
|
|
27
|
+
}
|
|
28
|
+
sendPlain(scopeId, text, keyboard) {
|
|
29
|
+
if (this.isWeixinScope(scopeId)) {
|
|
30
|
+
return this.requireWeixinTransport(scopeId).sendPlain(scopeId, text, keyboard);
|
|
31
|
+
}
|
|
32
|
+
return this.telegram.sendPlain(scopeId, text, keyboard);
|
|
33
|
+
}
|
|
34
|
+
sendHtml(scopeId, text, keyboard) {
|
|
35
|
+
if (this.isWeixinScope(scopeId)) {
|
|
36
|
+
return this.requireWeixinTransport(scopeId).sendHtml(scopeId, text, keyboard);
|
|
37
|
+
}
|
|
38
|
+
return this.telegram.sendHtml(scopeId, text, keyboard);
|
|
39
|
+
}
|
|
40
|
+
editPlain(scopeId, messageId, text, keyboard) {
|
|
41
|
+
if (this.isWeixinScope(scopeId)) {
|
|
42
|
+
return this.requireWeixinTransport(scopeId).editPlain(scopeId, messageId, text, keyboard);
|
|
43
|
+
}
|
|
44
|
+
return this.telegram.editPlain(scopeId, messageId, text, keyboard);
|
|
45
|
+
}
|
|
46
|
+
editHtml(scopeId, messageId, text, keyboard) {
|
|
47
|
+
if (this.isWeixinScope(scopeId)) {
|
|
48
|
+
return this.requireWeixinTransport(scopeId).editHtml(scopeId, messageId, text, keyboard);
|
|
49
|
+
}
|
|
50
|
+
return this.telegram.editHtml(scopeId, messageId, text, keyboard);
|
|
51
|
+
}
|
|
52
|
+
deleteMessage(scopeId, messageId) {
|
|
53
|
+
if (this.isWeixinScope(scopeId)) {
|
|
54
|
+
return this.requireWeixinTransport(scopeId).deleteMessage(scopeId, messageId);
|
|
55
|
+
}
|
|
56
|
+
return this.telegram.deleteMessage(scopeId, messageId);
|
|
57
|
+
}
|
|
58
|
+
sendTypingInScope(scopeId) {
|
|
59
|
+
if (this.isWeixinScope(scopeId)) {
|
|
60
|
+
return this.requireWeixinTransport(scopeId).sendTypingInScope(scopeId);
|
|
61
|
+
}
|
|
62
|
+
return this.telegram.sendTypingInScope(scopeId);
|
|
63
|
+
}
|
|
64
|
+
clearInlineKeyboard(scopeId, messageId) {
|
|
65
|
+
if (this.isWeixinScope(scopeId)) {
|
|
66
|
+
return this.requireWeixinTransport(scopeId).clearInlineKeyboard(scopeId, messageId);
|
|
67
|
+
}
|
|
68
|
+
return this.telegram.clearInlineKeyboard(scopeId, messageId);
|
|
69
|
+
}
|
|
70
|
+
sendDraft(scopeId, draftId, text) {
|
|
71
|
+
if (this.isWeixinScope(scopeId)) {
|
|
72
|
+
return this.requireWeixinTransport(scopeId).sendDraft(scopeId, draftId, text);
|
|
73
|
+
}
|
|
74
|
+
return this.telegram.sendDraft(scopeId, draftId, text);
|
|
75
|
+
}
|
|
76
|
+
answerCallback(callbackQueryId, text) {
|
|
77
|
+
return this.telegram.answerCallback(callbackQueryId, text);
|
|
78
|
+
}
|
|
79
|
+
getFile(fileId) {
|
|
80
|
+
return this.telegram.getFile(fileId);
|
|
81
|
+
}
|
|
82
|
+
downloadResolvedFile(remoteFilePath, destinationPath) {
|
|
83
|
+
return this.telegram.downloadResolvedFile(remoteFilePath, destinationPath);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BridgeSessionCore } from '../../controller/controller.js';
|
|
2
|
+
/**
|
|
3
|
+
* Telegram channel: inbound subscription + transport startup ordering for {@link BridgeSessionCore}.
|
|
4
|
+
* Additional channels (e.g. Weixin) can compose the same core with their own adapters.
|
|
5
|
+
*/
|
|
6
|
+
export declare class TelegramChannelAdapter {
|
|
7
|
+
private readonly core;
|
|
8
|
+
constructor(core: BridgeSessionCore);
|
|
9
|
+
start(): Promise<void>;
|
|
10
|
+
stop(): Promise<void>;
|
|
11
|
+
get sessionCore(): BridgeSessionCore;
|
|
12
|
+
}
|