codex-to-im 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/LICENSE +21 -0
- package/README.md +163 -0
- package/README_CN.md +161 -0
- package/SECURITY.md +38 -0
- package/SKILL.md +79 -0
- package/config.env.example +106 -0
- package/dist/cli.mjs +182 -0
- package/dist/daemon.mjs +206122 -0
- package/dist/ui-server.mjs +7725 -0
- package/docs/codex-to-im-prd.md +424 -0
- package/docs/codex-to-im-shared-thread-design.md +572 -0
- package/docs/install-windows.md +287 -0
- package/package.json +55 -0
- package/references/setup-guides.md +329 -0
- package/references/token-validation.md +44 -0
- package/references/troubleshooting.md +88 -0
- package/references/usage.md +46 -0
- package/scripts/build.js +36 -0
- package/scripts/daemon.ps1 +16 -0
- package/scripts/daemon.sh +225 -0
- package/scripts/doctor.ps1 +27 -0
- package/scripts/doctor.sh +450 -0
- package/scripts/install-codex.sh +65 -0
- package/scripts/run-tests.js +44 -0
- package/scripts/supervisor-linux.sh +49 -0
- package/scripts/supervisor-macos.sh +154 -0
- package/scripts/supervisor-windows.ps1 +481 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# Codex-to-IM Windows 安装说明
|
|
2
|
+
|
|
3
|
+
## 1. 当前部署方案
|
|
4
|
+
|
|
5
|
+
`codex-to-im` 当前采用的是 **单 npm 包 + 本地 Web 工作台 + 本地后台 bridge** 的部署方案。
|
|
6
|
+
|
|
7
|
+
补充说明:当前版本不是从零开始的新工程,而是在以下两个已有项目基础上整理和改造而来:
|
|
8
|
+
|
|
9
|
+
- `Claude-to-IM`
|
|
10
|
+
- `Claude-to-IM-skill`
|
|
11
|
+
|
|
12
|
+
核心形态如下:
|
|
13
|
+
|
|
14
|
+
- 分发物:`codex-to-im` npm 包
|
|
15
|
+
- 启动入口:全局命令 `codex-to-im`
|
|
16
|
+
- 本地界面:优先 `http://127.0.0.1:4781`,被占用时自动切换到可用端口
|
|
17
|
+
- 后台进程:
|
|
18
|
+
- `dist/ui-server.mjs` 负责本地工作台
|
|
19
|
+
- `dist/daemon.mjs` 负责 bridge
|
|
20
|
+
- 运行方式:本地 Node.js detached 子进程,不依赖当前命令窗口常驻
|
|
21
|
+
- 配置目录:`%USERPROFILE%\\.codex-to-im\\`
|
|
22
|
+
- 兼容目录:如果机器上已有旧数据,会回落到 `%USERPROFILE%\\.claude-to-im\\`
|
|
23
|
+
- 可选增强:可安装一层轻量 Codex 集成到 `%USERPROFILE%\\.codex\\skills\\codex-to-im`
|
|
24
|
+
|
|
25
|
+
这意味着当前推荐的部署方式不是“clone 仓库后让用户手动跑脚本”,而是:
|
|
26
|
+
|
|
27
|
+
1. 发布一个已经构建好的 npm 包
|
|
28
|
+
2. 在目标 Windows 主机全局安装
|
|
29
|
+
3. 运行 `codex-to-im`
|
|
30
|
+
4. 在浏览器里完成配置、测试和启动
|
|
31
|
+
|
|
32
|
+
## 2. 适用前提
|
|
33
|
+
|
|
34
|
+
下面这份说明按 **Windows 主机** 写。
|
|
35
|
+
|
|
36
|
+
默认假设:
|
|
37
|
+
|
|
38
|
+
- 目标机是 Windows 10 / 11
|
|
39
|
+
- 目标机已经安装 Node.js 20+
|
|
40
|
+
- 目标机使用同一个 Windows 用户来运行 Codex 和 `codex-to-im`
|
|
41
|
+
- 飞书应用、微信账号等平台侧信息已经准备好
|
|
42
|
+
|
|
43
|
+
## 3. 安装前准备
|
|
44
|
+
|
|
45
|
+
目标机至少需要这些前置条件:
|
|
46
|
+
|
|
47
|
+
### 3.1 安装 Node.js
|
|
48
|
+
|
|
49
|
+
要求:
|
|
50
|
+
|
|
51
|
+
- Node.js >= 20
|
|
52
|
+
|
|
53
|
+
建议安装完成后检查:
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
node -v
|
|
57
|
+
npm -v
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 3.2 安装并登录 Codex
|
|
61
|
+
|
|
62
|
+
如果你希望 bridge 接管和继续 Codex 会话,目标机必须在 **同一个 Windows 用户** 下完成 Codex 登录。
|
|
63
|
+
|
|
64
|
+
建议至少满足以下之一:
|
|
65
|
+
|
|
66
|
+
- 已安装并使用过 Codex Windows App
|
|
67
|
+
- 已安装 Codex CLI 并完成认证
|
|
68
|
+
|
|
69
|
+
建议显式安装 Codex CLI:
|
|
70
|
+
|
|
71
|
+
```powershell
|
|
72
|
+
npm install -g @openai/codex
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
然后完成登录:
|
|
76
|
+
|
|
77
|
+
```powershell
|
|
78
|
+
codex auth login
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 4. 目标机安装方式
|
|
82
|
+
|
|
83
|
+
### 4.1 推荐:从 npm 全局安装
|
|
84
|
+
|
|
85
|
+
如果包已经发布到 npm:
|
|
86
|
+
|
|
87
|
+
```powershell
|
|
88
|
+
npm install -g codex-to-im
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
安装完成后,直接启动:
|
|
92
|
+
|
|
93
|
+
```powershell
|
|
94
|
+
codex-to-im
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 4.2 备用:从源码安装
|
|
98
|
+
|
|
99
|
+
如果还没有正式发布 npm 包,可以在目标机直接用源码:
|
|
100
|
+
|
|
101
|
+
```powershell
|
|
102
|
+
git clone <your-repo-url> D:\codex\codex-to-im
|
|
103
|
+
cd D:\codex\codex-to-im
|
|
104
|
+
npm install
|
|
105
|
+
npm run build
|
|
106
|
+
node dist\cli.mjs open
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
如果希望源码安装后也能直接使用 `codex-to-im` 命令,可以再执行:
|
|
110
|
+
|
|
111
|
+
```powershell
|
|
112
|
+
npm link
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 5. 首次启动
|
|
116
|
+
|
|
117
|
+
首次启动命令:
|
|
118
|
+
|
|
119
|
+
```powershell
|
|
120
|
+
codex-to-im
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
当前行为是:
|
|
124
|
+
|
|
125
|
+
1. 拉起本地 UI 服务
|
|
126
|
+
2. 在后台运行 `ui-server`
|
|
127
|
+
3. 自动打开浏览器到本地工作台
|
|
128
|
+
|
|
129
|
+
默认地址:
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
http://127.0.0.1:4781
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
如果 `4781` 已被占用,程序会自动查找一个可用端口,并在启动时把实际地址打印到命令行。
|
|
136
|
+
|
|
137
|
+
如果之后忘记了当前 Web 地址,可以执行:
|
|
138
|
+
|
|
139
|
+
```powershell
|
|
140
|
+
codex-to-im url
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## 6. 在目标机上的首次配置
|
|
144
|
+
|
|
145
|
+
进入本地工作台后,按这个顺序做:
|
|
146
|
+
|
|
147
|
+
1. 选择 `Runtime`
|
|
148
|
+
- 推荐:`codex`
|
|
149
|
+
2. 设置默认工作目录
|
|
150
|
+
3. 设置 `/history` 默认返回条数(可选)
|
|
151
|
+
4. 如果目标目录不是 Codex 已信任的 Git 仓库,可勾选“允许在未信任 Git 目录运行 Codex”
|
|
152
|
+
5. 勾选要启用的通道
|
|
153
|
+
- 飞书:勾选 `启用飞书`
|
|
154
|
+
- 微信:勾选 `启用微信`
|
|
155
|
+
6. 飞书场景下填写:
|
|
156
|
+
- `App ID`
|
|
157
|
+
- `App Secret`
|
|
158
|
+
- `Domain`
|
|
159
|
+
- `Allowed Users` 可选
|
|
160
|
+
- `启用飞书流式响应卡片` 可选
|
|
161
|
+
7. 微信场景下点击:
|
|
162
|
+
- `开始微信扫码`
|
|
163
|
+
8. 点击测试
|
|
164
|
+
- 飞书:`测试飞书凭据`
|
|
165
|
+
- Codex:`测试 Codex`
|
|
166
|
+
9. 点击:
|
|
167
|
+
- `启动 Bridge`
|
|
168
|
+
|
|
169
|
+
说明:
|
|
170
|
+
|
|
171
|
+
- 飞书流式响应卡片依赖飞书应用侧具备可更新卡片 / CardKit 相关能力。
|
|
172
|
+
- 当前至少需要并发布这些权限:
|
|
173
|
+
- `cardkit:card:write`
|
|
174
|
+
- `cardkit:card:read`
|
|
175
|
+
- `im:message:update`
|
|
176
|
+
- 如果这些权限没有开通,桥接仍然可以工作,但会回退到最终结果消息。
|
|
177
|
+
- 缺权限时,`logs\\bridge.log` 里通常会出现 `99991672` 和 `cardkit:card:write`。
|
|
178
|
+
- 另外,当前 `codex` runtime 下正文通常不是逐字流式输出;更常见的效果是先显示 `Thinking / Tool Progress`,正文在回答完成时一次性落到卡片里。
|
|
179
|
+
- IM 里发送 `/history` 可以查看当前会话最近 N 条消息,N 由“基础配置”中的返回条数控制。
|
|
180
|
+
|
|
181
|
+
## 7. 目标机上的目录说明
|
|
182
|
+
|
|
183
|
+
当前版本主要使用这些目录:
|
|
184
|
+
|
|
185
|
+
### 7.1 新目录
|
|
186
|
+
|
|
187
|
+
```text
|
|
188
|
+
%USERPROFILE%\.codex-to-im\
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
其中主要文件有:
|
|
192
|
+
|
|
193
|
+
- `config.env`
|
|
194
|
+
- `logs\bridge.log`
|
|
195
|
+
- `logs\ui-server.out.log`
|
|
196
|
+
- `runtime\status.json`
|
|
197
|
+
- `runtime\ui-server.json`
|
|
198
|
+
|
|
199
|
+
### 7.2 旧目录兼容
|
|
200
|
+
|
|
201
|
+
如果目标机上已经存在旧安装数据,程序会自动回落到:
|
|
202
|
+
|
|
203
|
+
```text
|
|
204
|
+
%USERPROFILE%\.claude-to-im\
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
所以安装或排查时,需要先确认当前实际使用的是哪一个 home 目录。
|
|
208
|
+
|
|
209
|
+
## 8. 可选 Codex 集成
|
|
210
|
+
|
|
211
|
+
这一步不是必须的。
|
|
212
|
+
|
|
213
|
+
只有在你希望:
|
|
214
|
+
|
|
215
|
+
- 从 Codex 里直接打开 `codex-to-im`
|
|
216
|
+
- 或保留“共享当前会话到飞书”的轻入口
|
|
217
|
+
|
|
218
|
+
时,才需要安装。
|
|
219
|
+
|
|
220
|
+
当前可以通过本地工作台里的按钮安装到:
|
|
221
|
+
|
|
222
|
+
```text
|
|
223
|
+
%USERPROFILE%\.codex\skills\codex-to-im
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
安装后,它只保留两个动作:
|
|
227
|
+
|
|
228
|
+
- `open codex-to-im`
|
|
229
|
+
- `share current session to Feishu`
|
|
230
|
+
|
|
231
|
+
## 9. 安装给别的主机时的建议
|
|
232
|
+
|
|
233
|
+
### 9.1 飞书
|
|
234
|
+
|
|
235
|
+
如果是同一个飞书应用,只需要在目标机重新填写:
|
|
236
|
+
|
|
237
|
+
- App ID
|
|
238
|
+
- App Secret
|
|
239
|
+
- Domain
|
|
240
|
+
- Allowed Users(如需)
|
|
241
|
+
|
|
242
|
+
不需要复制源码里的任何配置文件。
|
|
243
|
+
|
|
244
|
+
### 9.2 微信
|
|
245
|
+
|
|
246
|
+
微信建议在 **目标机重新扫码**,不要直接复制旧机器上的登录状态文件。
|
|
247
|
+
|
|
248
|
+
### 9.3 多台机器
|
|
249
|
+
|
|
250
|
+
如果你要给多台 Windows 机器部署,推荐流程是:
|
|
251
|
+
|
|
252
|
+
1. 在发布机完成 `npm run build`
|
|
253
|
+
2. 发布 npm 包
|
|
254
|
+
3. 每台目标机执行 `npm install -g codex-to-im`
|
|
255
|
+
4. 每台机器各自完成本地登录、配置和通道测试
|
|
256
|
+
|
|
257
|
+
## 10. 当前限制
|
|
258
|
+
|
|
259
|
+
当前版本有几个需要提前说明的点:
|
|
260
|
+
|
|
261
|
+
- 默认不是 Windows Service,而是本地 detached 进程
|
|
262
|
+
- 机器重启后,不会自动恢复,需要再次运行 `codex-to-im`
|
|
263
|
+
- 可选 Codex 集成不是主安装路径
|
|
264
|
+
- 当前主路径是“本地工作台 + IM 配置 + Bridge 启动”
|
|
265
|
+
|
|
266
|
+
## 11. 发布方注意事项
|
|
267
|
+
|
|
268
|
+
如果你要把这个包发布到 npm,当前实现要求:
|
|
269
|
+
|
|
270
|
+
1. 先在发布前执行:
|
|
271
|
+
|
|
272
|
+
```powershell
|
|
273
|
+
npm run build
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
2. 确保发布包中包含:
|
|
277
|
+
|
|
278
|
+
- `dist/cli.mjs`
|
|
279
|
+
- `dist/ui-server.mjs`
|
|
280
|
+
- `dist/daemon.mjs`
|
|
281
|
+
|
|
282
|
+
原因是当前包没有 `postinstall` 或 `prepare` 来在目标机自动构建。
|
|
283
|
+
|
|
284
|
+
也就是说:
|
|
285
|
+
|
|
286
|
+
- **发布到 npm 时应发布预构建产物**
|
|
287
|
+
- **目标机安装时不应依赖本地构建**
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codex-to-im",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Installable Codex-to-IM bridge with local setup UI and background service",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/",
|
|
9
|
+
"docs/",
|
|
10
|
+
"references/",
|
|
11
|
+
"scripts/",
|
|
12
|
+
"LICENSE",
|
|
13
|
+
"README.md",
|
|
14
|
+
"README_CN.md",
|
|
15
|
+
"SECURITY.md",
|
|
16
|
+
"SKILL.md",
|
|
17
|
+
"config.env.example"
|
|
18
|
+
],
|
|
19
|
+
"bin": {
|
|
20
|
+
"codex-to-im": "dist/cli.mjs"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "node scripts/build.js",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"dev": "tsx src/main.ts",
|
|
26
|
+
"dev:ui": "tsx src/ui-server.ts",
|
|
27
|
+
"open": "node dist/cli.mjs open",
|
|
28
|
+
"weixin:login": "node --import tsx src/weixin-login.ts",
|
|
29
|
+
"test": "node scripts/run-tests.js",
|
|
30
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@anthropic-ai/claude-agent-sdk": "^0.2.62",
|
|
34
|
+
"@larksuiteoapi/node-sdk": "^1.59.0",
|
|
35
|
+
"discord.js": "^14.25.1",
|
|
36
|
+
"markdown-it": "^14.1.1",
|
|
37
|
+
"qrcode": "^1.5.4"
|
|
38
|
+
,
|
|
39
|
+
"ws": "^8.18.0"
|
|
40
|
+
},
|
|
41
|
+
"optionalDependencies": {
|
|
42
|
+
"@openai/codex-sdk": "^0.110.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/markdown-it": "^14.1.2",
|
|
46
|
+
"@types/node": "^22",
|
|
47
|
+
"@types/ws": "^8.5.0",
|
|
48
|
+
"esbuild": "^0.25.0",
|
|
49
|
+
"tsx": "^4.21.0",
|
|
50
|
+
"typescript": "^5"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=20"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# Platform Setup Guides
|
|
2
|
+
|
|
3
|
+
Detailed step-by-step guides for each IM platform. Referenced by the `setup` and `reconfigure` subcommands.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Telegram
|
|
8
|
+
|
|
9
|
+
### Bot Token
|
|
10
|
+
|
|
11
|
+
**How to get a Telegram Bot Token:**
|
|
12
|
+
1. Open Telegram and search for `@BotFather`
|
|
13
|
+
2. Send `/newbot` to create a new bot
|
|
14
|
+
3. Follow the prompts: choose a display name and a username (must end in `bot`)
|
|
15
|
+
4. BotFather will reply with a token like `7823456789:AAF-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
|
16
|
+
5. Copy the full token and paste it here
|
|
17
|
+
|
|
18
|
+
**Recommended bot settings** (send these commands to @BotFather):
|
|
19
|
+
- `/setprivacy` → choose your bot → `Disable` (so the bot can read group messages, only needed for group use)
|
|
20
|
+
- `/setcommands` → set commands like `new - Start new session`, `mode - Switch mode`
|
|
21
|
+
|
|
22
|
+
Token format: `数字:字母数字字符串` (e.g. `7823456789:AAF-xxx...xxx`)
|
|
23
|
+
|
|
24
|
+
### Chat ID
|
|
25
|
+
|
|
26
|
+
**How to get your Telegram Chat ID:**
|
|
27
|
+
1. Start a chat with your bot (search for the bot's username and click **Start**)
|
|
28
|
+
2. Send any message to the bot (e.g. "hello")
|
|
29
|
+
3. Open this URL in your browser (replace `YOUR_BOT_TOKEN` with your actual bot token):
|
|
30
|
+
`https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates`
|
|
31
|
+
4. In the JSON response, find `"chat":{"id":123456789,...}` — that number is your Chat ID
|
|
32
|
+
5. For group chats, the Chat ID is a negative number (e.g. `-1001234567890`)
|
|
33
|
+
|
|
34
|
+
**Why this matters:** The bot uses Chat ID for authorization. If neither Chat ID nor Allowed User IDs are configured, the bot will reject all incoming messages.
|
|
35
|
+
|
|
36
|
+
### Allowed User IDs (optional)
|
|
37
|
+
|
|
38
|
+
**How to find your Telegram User ID:**
|
|
39
|
+
1. Search for `@userinfobot` on Telegram and start a chat
|
|
40
|
+
2. It will reply with your User ID (a number like `123456789`)
|
|
41
|
+
3. Alternatively, forward a message from yourself to `@userinfobot`
|
|
42
|
+
|
|
43
|
+
Enter comma-separated IDs to restrict access (recommended for security).
|
|
44
|
+
Leave empty to allow anyone who can message the bot.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Discord
|
|
49
|
+
|
|
50
|
+
### Bot Token
|
|
51
|
+
|
|
52
|
+
**How to create a Discord Bot and get the token:**
|
|
53
|
+
1. Go to https://discord.com/developers/applications
|
|
54
|
+
2. Click **"New Application"** → give it a name → click **"Create"**
|
|
55
|
+
3. Go to the **"Bot"** tab on the left sidebar
|
|
56
|
+
4. Click **"Reset Token"** → copy the token (you can only see it once!)
|
|
57
|
+
|
|
58
|
+
**Required bot settings (on the Bot tab):**
|
|
59
|
+
- Under **Privileged Gateway Intents**, enable:
|
|
60
|
+
- ✅ **Message Content Intent** (required to read message text)
|
|
61
|
+
|
|
62
|
+
**Invite the bot to your server:**
|
|
63
|
+
1. Go to the **"OAuth2"** tab → **"URL Generator"**
|
|
64
|
+
2. Under **Scopes**, check: `bot`
|
|
65
|
+
3. Under **Bot Permissions**, check: `Send Messages`, `Read Message History`, `View Channels`
|
|
66
|
+
4. Copy the generated URL at the bottom and open it in your browser
|
|
67
|
+
5. Select the server and click **"Authorize"**
|
|
68
|
+
|
|
69
|
+
Token format: a long base64-like string (e.g. `MTIzNDU2Nzg5.Gxxxxx.xxxxxxxxxxxxxxxxxxxxxxxx`)
|
|
70
|
+
|
|
71
|
+
### Allowed User IDs
|
|
72
|
+
|
|
73
|
+
**How to find Discord User IDs:**
|
|
74
|
+
1. In Discord, go to Settings → Advanced → enable **Developer Mode**
|
|
75
|
+
2. Right-click on any user → **"Copy User ID"**
|
|
76
|
+
|
|
77
|
+
Enter comma-separated IDs.
|
|
78
|
+
|
|
79
|
+
**Why this matters:** The bot uses a default-deny policy. If neither Allowed User IDs nor Allowed Channel IDs are configured, the bot will silently reject all incoming messages. You must set at least one.
|
|
80
|
+
|
|
81
|
+
### Allowed Channel IDs (optional)
|
|
82
|
+
|
|
83
|
+
**How to find Discord Channel IDs:**
|
|
84
|
+
1. With Developer Mode enabled, right-click on any channel → **"Copy Channel ID"**
|
|
85
|
+
|
|
86
|
+
Enter comma-separated IDs to restrict the bot to specific channels.
|
|
87
|
+
Leave empty to allow all channels the bot can see.
|
|
88
|
+
|
|
89
|
+
### Allowed Guild (Server) IDs (optional)
|
|
90
|
+
|
|
91
|
+
**How to find Discord Server IDs:**
|
|
92
|
+
1. With Developer Mode enabled, right-click on the server icon → **"Copy Server ID"**
|
|
93
|
+
|
|
94
|
+
Enter comma-separated IDs. Leave empty to allow all servers the bot is in.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Feishu / Lark
|
|
99
|
+
|
|
100
|
+
### App ID and App Secret
|
|
101
|
+
|
|
102
|
+
**How to create a Feishu/Lark app and get credentials:**
|
|
103
|
+
1. Go to Feishu: https://open.feishu.cn/app or Lark: https://open.larksuite.com/app
|
|
104
|
+
2. Click **"Create Custom App"**
|
|
105
|
+
3. Fill in the app name and description → click **"Create"**
|
|
106
|
+
4. On the app's **"Credentials & Basic Info"** page, find:
|
|
107
|
+
- **App ID** (like `cli_xxxxxxxxxx`)
|
|
108
|
+
- **App Secret** (click to reveal, like `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`)
|
|
109
|
+
|
|
110
|
+
### Phase 1: Permissions + Bot capability
|
|
111
|
+
|
|
112
|
+
> Complete Phase 1 and publish before moving to Phase 2. Feishu requires a published version for permissions to take effect, and the bridge service needs active permissions to establish its WebSocket connection.
|
|
113
|
+
|
|
114
|
+
**Step A — Batch-add required permissions**
|
|
115
|
+
|
|
116
|
+
1. On the app page, go to **"Permissions & Scopes"**
|
|
117
|
+
2. Use **batch configuration** (click **"Batch switch to configure by dependency"** or find the JSON editor)
|
|
118
|
+
3. Paste the following JSON (required for streaming cards and interactive buttons):
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"scopes": {
|
|
123
|
+
"tenant": [
|
|
124
|
+
"im:message:send_as_bot",
|
|
125
|
+
"im:message:readonly",
|
|
126
|
+
"im:message.p2p_msg:readonly",
|
|
127
|
+
"im:message.group_at_msg:readonly",
|
|
128
|
+
"im:message:update",
|
|
129
|
+
"im:message.reactions:read",
|
|
130
|
+
"im:message.reactions:write_only",
|
|
131
|
+
"im:chat:read",
|
|
132
|
+
"im:resource",
|
|
133
|
+
"cardkit:card:write",
|
|
134
|
+
"cardkit:card:read"
|
|
135
|
+
],
|
|
136
|
+
"user": []
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
4. Click **"Save"** to apply all permissions
|
|
142
|
+
|
|
143
|
+
If the batch import UI is not available, add each scope manually via the search box.
|
|
144
|
+
|
|
145
|
+
> **Important:** If `cardkit:card:write` is missing, enabling Feishu streaming in the local workbench will not work. The bridge will log Feishu error `99991672` and fall back to a normal final-result message.
|
|
146
|
+
|
|
147
|
+
**Step B — Enable the bot**
|
|
148
|
+
|
|
149
|
+
1. Go to **"Add Features"** → enable **"Bot"**
|
|
150
|
+
2. Set the bot name and description
|
|
151
|
+
|
|
152
|
+
**Step C — First publish (makes permissions + bot effective)**
|
|
153
|
+
|
|
154
|
+
1. Go to **"Version Management & Release"** → click **"Create Version"**
|
|
155
|
+
2. Fill in version `1.0.0` and a description → click **"Save"** → **"Submit for Review"**
|
|
156
|
+
3. Admin approves in **Feishu Admin Console** → **App Review** (self-approve if you are the admin)
|
|
157
|
+
|
|
158
|
+
**The bot will NOT work until this version is approved.**
|
|
159
|
+
|
|
160
|
+
### Phase 2: Event subscription (requires running bridge)
|
|
161
|
+
|
|
162
|
+
> The bridge service must be running before configuring events. Feishu validates the WebSocket connection when saving event subscription — if the bridge is not running, you'll get "未检测到应用连接信息" (connection not detected) error.
|
|
163
|
+
|
|
164
|
+
**Step D — Start the bridge service**
|
|
165
|
+
|
|
166
|
+
Start the bridge from the local `codex-to-im` workbench. This establishes the WebSocket long connection that Feishu needs to detect.
|
|
167
|
+
|
|
168
|
+
**Step E — Configure Events & Callbacks (long connection)**
|
|
169
|
+
|
|
170
|
+
1. Go to **"Events & Callbacks"** in the left sidebar
|
|
171
|
+
2. Under **"Event Dispatch Method"**, select **"Long Connection"** (长连接 / WebSocket mode)
|
|
172
|
+
3. Click **"Add Event"** and add:
|
|
173
|
+
- `im.message.receive_v1` — Receive messages
|
|
174
|
+
4. Click **"Add Callback"** and add:
|
|
175
|
+
- `card.action.trigger` — Card interaction callback (for permission approval buttons)
|
|
176
|
+
5. Click **"Save"**
|
|
177
|
+
|
|
178
|
+
**Step F — Second publish (makes event subscription effective)**
|
|
179
|
+
|
|
180
|
+
1. Go to **"Version Management & Release"** → click **"Create Version"**
|
|
181
|
+
2. Fill in version `1.1.0` → **"Save"** → **"Submit for Review"** → Admin approves
|
|
182
|
+
3. After approval, the bot can receive and respond to messages
|
|
183
|
+
|
|
184
|
+
> **Ongoing rule:** Any change to permissions, events, or capabilities requires a new version publish + admin approval.
|
|
185
|
+
|
|
186
|
+
### Upgrading from a previous version
|
|
187
|
+
|
|
188
|
+
If you already have a Feishu app configured, you need to:
|
|
189
|
+
|
|
190
|
+
1. **Add new permissions**: Go to Permissions & Scopes, add these scopes:
|
|
191
|
+
- `cardkit:card:write`, `cardkit:card:read` — Streaming cards
|
|
192
|
+
- `im:message:update` — Real-time card content updates
|
|
193
|
+
- `im:message.reactions:read`, `im:message.reactions:write_only` — Typing indicator
|
|
194
|
+
2. **Publish a new version** — Permission changes only take effect after a new version is approved
|
|
195
|
+
3. **Start (or restart) the bridge** — Start it from the local `codex-to-im` workbench so the WebSocket connection is active
|
|
196
|
+
4. **Add callback**: Go to Events & Callbacks, add `card.action.trigger` callback (card interaction for permission buttons). This step requires the bridge to be running — Feishu validates the WebSocket connection when saving.
|
|
197
|
+
5. **Publish again** — The new callback requires another version publish + admin approval
|
|
198
|
+
6. **Restart the bridge** — Stop and start it again from the local `codex-to-im` workbench to pick up the new capabilities
|
|
199
|
+
|
|
200
|
+
### Current Feishu streaming behavior with Codex runtime
|
|
201
|
+
|
|
202
|
+
Even after the Feishu permissions are correct, the current `codex` runtime does **not** guarantee token-by-token text streaming into the Feishu card.
|
|
203
|
+
|
|
204
|
+
As of **2026-03-24**, the `Codex CLI / SDK` event stream typically emits assistant text when the `agent_message` item completes, rather than as token deltas. In practice, Feishu streaming cards are best understood as:
|
|
205
|
+
|
|
206
|
+
- early `Thinking` / tool progress updates
|
|
207
|
+
- final response text written into the card at completion
|
|
208
|
+
|
|
209
|
+
So if you see the final answer appear all at once after the card was created successfully, that is currently expected behavior with `codex`.
|
|
210
|
+
|
|
211
|
+
### Domain (optional)
|
|
212
|
+
|
|
213
|
+
Default: `https://open.feishu.cn`
|
|
214
|
+
Use `https://open.larksuite.com` for Lark (international version).
|
|
215
|
+
Leave empty to use the default Feishu domain.
|
|
216
|
+
|
|
217
|
+
### Allowed User IDs (optional)
|
|
218
|
+
|
|
219
|
+
Feishu user IDs (open_id format like `ou_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`).
|
|
220
|
+
You can find them in the Feishu Admin Console under user profiles.
|
|
221
|
+
Leave empty to allow all users who can message the bot.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## QQ
|
|
226
|
+
|
|
227
|
+
> **Note:** QQ first version only supports **C2C private chat** (sandbox access). Group chat and channel are not supported yet.
|
|
228
|
+
|
|
229
|
+
### App ID and App Secret (required)
|
|
230
|
+
|
|
231
|
+
**How to get QQ Bot credentials:**
|
|
232
|
+
1. Go to https://q.qq.com/qqbot/openclaw
|
|
233
|
+
2. Log in and enter the QQ Bot / OpenClaw management page
|
|
234
|
+
3. Create a new QQ Bot or select an existing one
|
|
235
|
+
4. Find **App ID** and **App Secret** on the bot's credential page
|
|
236
|
+
5. Copy both values
|
|
237
|
+
|
|
238
|
+
These are the only two required fields for QQ.
|
|
239
|
+
|
|
240
|
+
### Sandbox private chat setup
|
|
241
|
+
|
|
242
|
+
1. In the QQ Bot management page, configure sandbox access
|
|
243
|
+
2. Scan the QR code with QQ to add the bot as a friend
|
|
244
|
+
3. Send a message to the bot via QQ private chat to start using it
|
|
245
|
+
|
|
246
|
+
### Allowed User OpenIDs (optional)
|
|
247
|
+
|
|
248
|
+
**Important:** The value is `user_openid`, NOT QQ number.
|
|
249
|
+
|
|
250
|
+
`user_openid` is an opaque identifier assigned by the QQ Bot platform to each user. You can obtain it from the bot's message logs after a user sends a message to the bot.
|
|
251
|
+
|
|
252
|
+
If you don't have the openid yet, leave this field empty. You can add it later via `reconfigure`.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Weixin / 微信
|
|
257
|
+
|
|
258
|
+
> Risk note: this integration follows the same OpenClaw-style WeChat plugin protocol used by CodePilot. Because it connects a non-OpenClaw product to WeChat, there may be account risk. Use with caution.
|
|
259
|
+
|
|
260
|
+
### QR login flow
|
|
261
|
+
|
|
262
|
+
Weixin does **not** use a static bot token in `config.env`.
|
|
263
|
+
|
|
264
|
+
Instead, run the local QR helper from the local app directory or optional Codex integration directory:
|
|
265
|
+
|
|
266
|
+
- Repo checkout or app install:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
cd /path/to/codex-to-im
|
|
270
|
+
npm run weixin:login
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
- Optional Codex integration install:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
cd ~/.codex/skills/codex-to-im
|
|
277
|
+
npm run weixin:login
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
If you are running from a checked-out repo, use that repo's `codex-to-im` directory.
|
|
281
|
+
|
|
282
|
+
What happens next:
|
|
283
|
+
|
|
284
|
+
1. The helper requests a fresh WeChat QR code
|
|
285
|
+
2. It writes a local HTML file to:
|
|
286
|
+
`~/.codex-to-im/runtime/weixin-login.html`
|
|
287
|
+
3. It tries to open that HTML file in your default browser automatically
|
|
288
|
+
4. You scan the QR code with the WeChat app and confirm on your phone
|
|
289
|
+
5. On success, the helper stores the linked account in:
|
|
290
|
+
`~/.codex-to-im/data/weixin-accounts.json`
|
|
291
|
+
|
|
292
|
+
The filename stays plural for backward compatibility, but Weixin currently runs in single-account mode.
|
|
293
|
+
|
|
294
|
+
If the browser does not open automatically, open the HTML file manually.
|
|
295
|
+
|
|
296
|
+
### Replacing the linked Weixin account
|
|
297
|
+
|
|
298
|
+
Run the helper again:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
cd <skill-dir>
|
|
302
|
+
npm run weixin:login
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Each successful scan replaces the previously linked Weixin account. Only the most recent account is kept locally and used by the bridge.
|
|
306
|
+
|
|
307
|
+
### Optional config
|
|
308
|
+
|
|
309
|
+
Most users should leave these unset:
|
|
310
|
+
|
|
311
|
+
- `CTI_WEIXIN_BASE_URL`
|
|
312
|
+
- `CTI_WEIXIN_CDN_BASE_URL`
|
|
313
|
+
- `CTI_WEIXIN_MEDIA_ENABLED`
|
|
314
|
+
|
|
315
|
+
Defaults:
|
|
316
|
+
|
|
317
|
+
- Base URL: `https://ilinkai.weixin.qq.com`
|
|
318
|
+
- CDN Base URL: `https://novac2c.cdn.weixin.qq.com/c2c`
|
|
319
|
+
- Media: disabled by default in CLI setups; when enabled, inbound images/files/videos are downloaded and forwarded as attachments
|
|
320
|
+
|
|
321
|
+
### Voice message behavior
|
|
322
|
+
|
|
323
|
+
Weixin voice messages are handled differently from image/file/video media:
|
|
324
|
+
|
|
325
|
+
- If WeChat includes built-in speech-to-text text in `voice_item.text`, the bridge forwards that text as the user message.
|
|
326
|
+
- If WeChat does **not** include a transcript, the bridge returns a user-visible error asking the sender to enable WeChat voice transcription and resend.
|
|
327
|
+
- The bridge does **not** download, decrypt, or transcribe raw voice audio on its own.
|
|
328
|
+
|
|
329
|
+
This rule applies in both Claude Code and Codex runtimes.
|