codex-to-im 1.0.41 → 1.0.43

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-to-im",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "Installable Codex-to-IM bridge with local setup UI and background service",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/zhangle1987/codex-to-im#readme",
@@ -40,10 +40,8 @@
40
40
  "prepublishOnly": "npm run typecheck && npm run build"
41
41
  },
42
42
  "dependencies": {
43
- "@anthropic-ai/claude-agent-sdk": "^0.2.62",
44
43
  "@larksuiteoapi/node-sdk": "^1.59.0",
45
- "@openai/codex-sdk": "^0.122.0",
46
- "discord.js": "^14.25.1",
44
+ "@openai/codex-sdk": "^0.124.0",
47
45
  "markdown-it": "^14.1.1",
48
46
  "qrcode": "^1.5.4",
49
47
  "ws": "^8.18.0"
@@ -4,97 +4,6 @@ Detailed step-by-step guides for each IM platform. Referenced by the `setup` and
4
4
 
5
5
  ---
6
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
7
  ## Feishu / Lark
99
8
 
100
9
  ### App ID and App Secret
@@ -138,11 +47,11 @@ Enter comma-separated IDs. Leave empty to allow all servers the bot is in.
138
47
  }
139
48
  ```
140
49
 
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.
50
+ 4. Click **"Save"** to apply all permissions
51
+
52
+ If the batch import UI is not available, add each scope manually via the search box.
53
+
54
+ > **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
55
 
147
56
  **Step B — Enable the bot**
148
57
 
@@ -161,9 +70,9 @@ If the batch import UI is not available, add each scope manually via the search
161
70
 
162
71
  > 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
72
 
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.
73
+ **Step D — Start the bridge service**
74
+
75
+ Start the bridge from the local `codex-to-im` workbench. This establishes the WebSocket long connection that Feishu needs to detect.
167
76
 
168
77
  **Step E — Configure Events & Callbacks (long connection)**
169
78
 
@@ -192,21 +101,21 @@ If you already have a Feishu app configured, you need to:
192
101
  - `im:message:update` — Real-time card content updates
193
102
  - `im:message.reactions:read`, `im:message.reactions:write_only` — Typing indicator
194
103
  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
104
+ 3. **Start (or restart) the bridge** — Start it from the local `codex-to-im` workbench so the WebSocket connection is active
196
105
  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
106
  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`.
107
+ 6. **Restart the bridge** — Stop and start it again from the local `codex-to-im` workbench to pick up the new capabilities
108
+
109
+ ### Current Feishu streaming behavior with Codex runtime
110
+
111
+ Even after the Feishu permissions are correct, the current `codex` runtime does **not** guarantee token-by-token text streaming into the Feishu card.
112
+
113
+ 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:
114
+
115
+ - early `Thinking` / tool progress updates
116
+ - final response text written into the card at completion
117
+
118
+ 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
119
 
211
120
  ### Domain (optional)
212
121
 
@@ -222,37 +131,6 @@ Leave empty to allow all users who can message the bot.
222
131
 
223
132
  ---
224
133
 
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
134
  ## Weixin / 微信
257
135
 
258
136
  > 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.
@@ -261,28 +139,28 @@ If you don't have the openid yet, leave this field empty. You can add it later v
261
139
 
262
140
  Weixin does **not** use a static bot token in `config.env`.
263
141
 
264
- Instead, run the local QR helper from the local app directory:
142
+ Instead, run the local QR helper from the local app directory:
143
+
144
+ - Repo checkout or app install:
145
+
146
+ ```bash
147
+ cd /path/to/codex-to-im
148
+ npm run weixin:login
149
+ ```
265
150
 
266
- - Repo checkout or app install:
267
-
268
- ```bash
269
- cd /path/to/codex-to-im
270
- npm run weixin:login
271
- ```
272
-
273
- If you are running from a checked-out repo, use that repo's `codex-to-im` directory.
151
+ If you are running from a checked-out repo, use that repo's `codex-to-im` directory.
274
152
 
275
153
  What happens next:
276
154
 
277
155
  1. The helper requests a fresh WeChat QR code
278
156
  2. It writes a local HTML file to:
279
- `~/.codex-to-im/runtime/weixin-login.html`
157
+ `~/.codex-to-im/runtime/weixin-login.html`
280
158
  3. It tries to open that HTML file in your default browser automatically
281
159
  4. You scan the QR code with the WeChat app and confirm on your phone
282
160
  5. On success, the helper stores the linked account in:
283
- `~/.codex-to-im/data/weixin-accounts.json`
161
+ `~/.codex-to-im/data/weixin-accounts.json`
284
162
 
285
- The filename stays plural for backward compatibility. Multiple linked Weixin accounts can coexist in the same store.
163
+ The filename stays plural for backward compatibility. Multiple linked Weixin accounts can coexist in the same store.
286
164
 
287
165
  If the browser does not open automatically, open the HTML file manually.
288
166
 
@@ -319,4 +197,4 @@ Weixin voice messages are handled differently from image/file/video media:
319
197
  - If WeChat does **not** include a transcript, the bridge returns a user-visible error asking the sender to enable WeChat voice transcription and resend.
320
198
  - The bridge does **not** download, decrypt, or transcribe raw voice audio on its own.
321
199
 
322
- This rule applies in both Claude Code and Codex runtimes.
200
+ This rule applies to the Codex runtime.
@@ -1,44 +1,28 @@
1
- # Token Validation Commands
2
-
3
- After writing config.env, validate each enabled platform's credentials to catch typos and configuration errors early.
4
-
5
- ## Telegram
6
-
7
- ```bash
8
- curl -s "https://api.telegram.org/bot${TOKEN}/getMe"
9
- ```
10
- Expected: response contains `"ok":true`. If not, the Bot Token is invalid — re-check with @BotFather.
11
-
12
- ## Discord
13
-
14
- Verify token format matches: `[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+`
15
-
16
- A format mismatch means the token was copied incorrectly from the Discord Developer Portal.
17
-
18
- ## Feishu / Lark
19
-
20
- ```bash
21
- curl -s -X POST "${DOMAIN}/open-apis/auth/v3/tenant_access_token/internal" \
22
- -H "Content-Type: application/json" \
23
- -d '{"app_id":"...","app_secret":"..."}'
24
- ```
25
- Expected: response contains `"code":0`. If not, check that App ID and App Secret match the Feishu Developer Console.
26
-
27
- ## QQ
28
-
29
- Step 1 — Get access token:
30
- ```bash
31
- curl -s -X POST "https://bots.qq.com/app/getAppAccessToken" \
32
- -H "Content-Type: application/json" \
33
- -d '{"appId":"...","clientSecret":"..."}'
34
- ```
35
- Expected: response contains `access_token`.
36
-
37
- Step 2 — Verify gateway connectivity:
38
- ```bash
39
- curl -s "https://api.sgroup.qq.com/gateway" \
40
- -H "Authorization: QQBot <access_token>"
41
- ```
42
- Expected: response contains a gateway URL.
43
-
44
- If either step fails, verify the App ID and App Secret from https://q.qq.com.
1
+ # Token Validation Commands
2
+
3
+ After writing `config.env`, validate each enabled platform's credentials to catch typos and configuration errors early.
4
+
5
+ ## Feishu / Lark
6
+
7
+ ```bash
8
+ curl -s -X POST "${DOMAIN}/open-apis/auth/v3/tenant_access_token/internal" \
9
+ -H "Content-Type: application/json" \
10
+ -d '{"app_id":"...","app_secret":"..."}'
11
+ ```
12
+
13
+ Expected: response contains `"code":0`. If not, check that App ID, App Secret, and site/domain match the Feishu Developer Console.
14
+
15
+ ## Weixin
16
+
17
+ Weixin uses the local linked-account store instead of a bot token. Validate it with:
18
+
19
+ ```bash
20
+ codex-to-im status
21
+ ```
22
+
23
+ If no linked account is available, run:
24
+
25
+ ```bash
26
+ cd /path/to/codex-to-im
27
+ npm run weixin:login
28
+ ```
@@ -8,7 +8,7 @@
8
8
 
9
9
  1. Run the local doctor script or inspect the workbench logs to identify the issue
10
10
  2. Check that Node.js >= 20 is installed: `node --version`
11
- 3. Check that Claude Code CLI is available: `claude --version`
11
+ 3. Check that Codex CLI is available: `codex --version`
12
12
  4. Verify config exists: `ls -la ~/.codex-to-im/config.env`
13
13
  5. Check logs for startup errors in `~/.codex-to-im/logs/`
14
14
 
@@ -23,12 +23,11 @@
23
23
 
24
24
  **Steps**:
25
25
 
26
- 1. Verify the bot token is valid with the local workbench test tools or doctor script
27
- 2. Check allowed user IDs in config -- if set, only listed users can interact
28
- 3. For Telegram: ensure you've sent `/start` to the bot first
29
- 4. For Discord: verify the bot has been invited to the server with message read permissions
30
- 5. For Feishu: confirm the app has been approved and event subscriptions are configured
31
- 6. Check recent logs for incoming message events under `~/.codex-to-im/logs/`
26
+ 1. Verify the channel credentials with the local workbench test tools or doctor script
27
+ 2. Check allowed user IDs in config -- if set, only listed users can interact
28
+ 3. For Feishu: confirm the app has been approved and event subscriptions are configured
29
+ 4. For Weixin: confirm the linked account is logged in and assigned to the channel instance
30
+ 5. Check recent logs for incoming message events under `~/.codex-to-im/logs/`
32
31
 
33
32
  ## Feishu streaming cards not working
34
33
 
@@ -52,12 +51,12 @@
52
51
 
53
52
  ## Permission timeout
54
53
 
55
- **Symptoms**: Claude Code session starts but times out waiting for tool approval.
54
+ **Symptoms**: Codex session starts but times out waiting for tool approval.
56
55
 
57
56
  **Steps**:
58
57
 
59
- 1. The bridge runs Claude Code in non-interactive mode; ensure your Claude Code configuration allows the necessary tools
60
- 2. Consider using `--allowedTools` in your configuration to pre-approve common tools
58
+ 1. The bridge runs Codex through the SDK/CLI; ensure the configured sandbox and approval policy match the requested task
59
+ 2. Use the IM permission prompt to approve the requested tool, or adjust Codex approval settings if you expect unattended execution
61
60
  3. Check network connectivity if the timeout occurs during API calls
62
61
 
63
62
  ## High memory usage
@@ -71,7 +70,7 @@
71
70
  ```
72
71
  Stop the bridge, then start it again from the local workbench
73
72
  ```
74
- 3. If the issue persists, check how many concurrent sessions are active -- each Claude Code session consumes memory
73
+ 3. If the issue persists, check how many concurrent sessions are active -- each Codex session consumes memory
75
74
  4. Review logs for error loops that may cause memory leaks
76
75
 
77
76
  ## Stale PID file
package/scripts/build.js CHANGED
@@ -6,17 +6,12 @@ const common = {
6
6
  format: 'esm',
7
7
  target: 'node20',
8
8
  external: [
9
- // SDK must stay external — it spawns a CLI subprocess and resolves
10
- // dist/cli.js relative to its own package location. Bundling it
11
- // breaks that path resolution.
12
- '@anthropic-ai/claude-agent-sdk',
13
9
  '@openai/codex-sdk',
14
10
  // Keep large IM SDKs external so global/local npm installs resolve them
15
11
  // from node_modules instead of inflating daemon.mjs.
16
12
  '@larksuiteoapi/node-sdk',
17
- 'discord.js',
18
- // discord.js optional native deps
19
- 'bufferutil', 'utf-8-validate', 'zlib-sync', 'erlpack',
13
+ // ws optional native deps
14
+ 'bufferutil', 'utf-8-validate',
20
15
  // Node.js built-ins
21
16
  'fs', 'path', 'os', 'crypto', 'http', 'https', 'net', 'tls',
22
17
  'stream', 'events', 'url', 'util', 'child_process', 'worker_threads',
package/scripts/daemon.sh CHANGED
@@ -38,34 +38,16 @@ ensure_built() {
38
38
  }
39
39
 
40
40
  # Clean environment for subprocess isolation.
41
- clean_env() {
42
- unset CLAUDECODE 2>/dev/null || true
43
-
44
- local runtime
45
- runtime=$(grep "^CTI_RUNTIME=" "$CTI_HOME/config.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d "'" | tr -d '"' || true)
46
- runtime="${runtime:-claude}"
47
-
48
- local mode="${CTI_ENV_ISOLATION:-inherit}"
49
- if [ "$mode" = "strict" ]; then
50
- case "$runtime" in
51
- codex)
52
- while IFS='=' read -r name _; do
53
- case "$name" in ANTHROPIC_*) unset "$name" 2>/dev/null || true ;; esac
54
- done < <(env)
55
- ;;
56
- claude)
57
- # Keep ANTHROPIC_* (from config.env) — needed for third-party API providers.
58
- # Strip OPENAI_* to avoid cross-runtime leakage.
59
- while IFS='=' read -r name _; do
60
- case "$name" in OPENAI_*) unset "$name" 2>/dev/null || true ;; esac
61
- done < <(env)
62
- ;;
63
- auto)
64
- # Keep both ANTHROPIC_* and OPENAI_* for auto mode
65
- ;;
66
- esac
67
- fi
68
- }
41
+ clean_env() {
42
+ unset CLAUDECODE 2>/dev/null || true
43
+
44
+ local mode="${CTI_ENV_ISOLATION:-inherit}"
45
+ if [ "$mode" = "strict" ]; then
46
+ while IFS='=' read -r name _; do
47
+ case "$name" in ANTHROPIC_*) unset "$name" 2>/dev/null || true ;; esac
48
+ done < <(env)
49
+ fi
50
+ }
69
51
 
70
52
  read_pid() {
71
53
  [ -f "$PID_FILE" ] && cat "$PID_FILE" 2>/dev/null || echo ""
@@ -133,8 +115,7 @@ case "${1:-help}" in
133
115
  exit 1
134
116
  fi
135
117
 
136
- # Source config.env BEFORE clean_env so that CTI_ANTHROPIC_PASSTHROUGH
137
- # and other CTI_* flags are available when clean_env checks them.
118
+ # Source config.env BEFORE clean_env so CTI_* flags are available.
138
119
  [ -f "$CTI_HOME/config.env" ] && set -a && source "$CTI_HOME/config.env" && set +a
139
120
 
140
121
  clean_env