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/scripts/doctor.sh CHANGED
@@ -37,210 +37,26 @@ get_config() { grep "^$1=" "$CONFIG_FILE" 2>/dev/null | head -1 | cut -d= -f2- |
37
37
 
38
38
  # --- Read runtime setting ---
39
39
  SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)"
40
- CTI_RUNTIME=$(get_config CTI_RUNTIME)
41
- CTI_RUNTIME="${CTI_RUNTIME:-claude}"
42
- echo "Runtime: $CTI_RUNTIME"
43
- echo ""
44
-
45
- # --- Claude CLI available (claude/auto modes) ---
46
- if [ "$CTI_RUNTIME" = "claude" ] || [ "$CTI_RUNTIME" = "auto" ]; then
47
- # Resolve CLI path matching the daemon's checkCliCompatibility logic:
48
- # - Version >= 2.x AND all required flags present
49
- # - Skip candidates that fail either check (same as resolveClaudeCliPath)
50
- CLAUDE_PATH=""
51
- CLAUDE_VER=""
52
- CLAUDE_COMPAT=1
53
- REQUIRED_FLAGS="output-format input-format permission-mode setting-sources"
54
-
55
- # Helper: check if a candidate passes both version and flags checks.
56
- # Sets CLAUDE_PATH/CLAUDE_VER/CLAUDE_COMPAT on success.
57
- try_candidate() {
58
- local cand="$1"
59
- [ -x "$cand" ] || return 1
60
- local ver
61
- ver=$("$cand" --version 2>/dev/null || true)
62
- [ -z "$ver" ] && return 1
63
- local major
64
- major=$(echo "$ver" | sed -E -n 's/^[^0-9]*([0-9]+)\..*/\1/p' | head -1)
65
- if [ -z "$major" ] || ! [ "$major" -ge 2 ] 2>/dev/null; then
66
- echo " (skipping $cand — version $ver is too old, need >= 2.x)"
67
- return 1
68
- fi
69
- # Version OK — check flags
70
- local help_text
71
- help_text=$("$cand" --help 2>&1 || true)
72
- for flag in $REQUIRED_FLAGS; do
73
- if ! echo "$help_text" | grep -q "$flag"; then
74
- echo " (skipping $cand — version $ver OK but missing --$flag)"
75
- return 1
76
- fi
77
- done
78
- # Fully compatible
79
- CLAUDE_PATH="$cand"
80
- CLAUDE_VER="$ver"
81
- CLAUDE_COMPAT=0
82
- return 0
83
- }
84
-
85
- # 1. Explicit env var — if set, daemon uses it unconditionally (no fallback).
86
- # Doctor must mirror this: report on this path only, never scan further.
87
- CTI_EXE=$(get_config CTI_CLAUDE_CODE_EXECUTABLE 2>/dev/null || true)
88
- if [ -n "$CTI_EXE" ]; then
89
- if [ -x "$CTI_EXE" ]; then
90
- if ! try_candidate "$CTI_EXE"; then
91
- # Explicit path is set but incompatible — daemon WILL use it and fail.
92
- # Report it as the selected CLI so the user sees the real problem.
93
- CLAUDE_PATH="$CTI_EXE"
94
- CLAUDE_VER=$("$CTI_EXE" --version 2>/dev/null || echo "unknown")
95
- # CLAUDE_COMPAT stays 1 (incompatible) — checks below will report failure
96
- fi
97
- else
98
- CLAUDE_PATH="$CTI_EXE"
99
- CLAUDE_VER="(not executable)"
100
- fi
101
- fi
102
-
103
- # 2. All PATH candidates (only if no explicit env var was set)
104
- if [ -z "$CTI_EXE" ] && [ -z "$CLAUDE_PATH" ]; then
105
- ALL_CLAUDES=$(which -a claude 2>/dev/null || true)
106
- for cand in $ALL_CLAUDES; do
107
- try_candidate "$cand" && break
108
- done
109
- fi
110
-
111
- # 3. Well-known locations (only if no explicit env var was set)
112
- if [ -z "$CTI_EXE" ] && [ -z "$CLAUDE_PATH" ]; then
113
- for cand in \
114
- "$HOME/.claude/local/claude" \
115
- "$HOME/.local/bin/claude" \
116
- "/usr/local/bin/claude" \
117
- "/opt/homebrew/bin/claude" \
118
- "$HOME/.npm-global/bin/claude"; do
119
- try_candidate "$cand" && break
120
- done
121
- fi
122
-
123
- if [ -n "$CLAUDE_PATH" ] && [ "$CLAUDE_COMPAT" = "0" ]; then
124
- check "Claude CLI compatible (${CLAUDE_VER} at ${CLAUDE_PATH})" 0
125
- elif [ -n "$CLAUDE_PATH" ]; then
126
- # Path found but incompatible (too old, missing flags, or not executable)
127
- check "Claude CLI compatible (${CLAUDE_VER} at ${CLAUDE_PATH} — incompatible, see above)" 1
128
- else
129
- if [ "$CTI_RUNTIME" = "claude" ]; then
130
- check "Claude CLI available (not found in PATH or common locations)" 1
131
- else
132
- check "Claude CLI available (not found — will use Codex fallback)" 0
133
- fi
134
- fi
135
-
136
- # --- Claude CLI authenticated ---
137
- # Skip this check if third-party API credentials are configured in config.env.
138
- # In that mode the bridge authenticates via ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN,
139
- # not via `claude auth login`, so a missing interactive login is expected and harmless.
140
- HAS_THIRD_PARTY_AUTH=false
141
- if [ -f "$CONFIG_FILE" ] && grep -qE "^ANTHROPIC_(API_KEY|AUTH_TOKEN)=" "$CONFIG_FILE" 2>/dev/null; then
142
- HAS_THIRD_PARTY_AUTH=true
143
- fi
144
- if [ -n "$CLAUDE_PATH" ] && [ "$CLAUDE_COMPAT" = "0" ]; then
145
- if [ "$HAS_THIRD_PARTY_AUTH" = "true" ]; then
146
- check "Claude CLI auth (skipped — using third-party API credentials from config.env)" 0
147
- else
148
- AUTH_OUT=$("$CLAUDE_PATH" auth status 2>&1 || true)
149
- if echo "$AUTH_OUT" | grep -qiE 'loggedIn.*true|logged.in'; then
150
- check "Claude CLI authenticated" 0
151
- else
152
- check "Claude CLI authenticated (run 'claude auth login')" 1
153
- fi
154
- fi
155
- fi
156
-
157
- # --- ANTHROPIC_* env reachability ---
158
- # Check whether ANTHROPIC_* vars are configured in config.env.
159
- # This is what matters for the daemon — the current shell env is irrelevant
160
- # because on macOS the daemon runs under launchd with only plist env vars.
161
- HAS_ANTHROPIC_CONFIG=false
162
- if [ -f "$CONFIG_FILE" ]; then
163
- if grep -q "^ANTHROPIC_" "$CONFIG_FILE" 2>/dev/null; then
164
- HAS_ANTHROPIC_CONFIG=true
165
- fi
166
- fi
167
- if [ "$HAS_ANTHROPIC_CONFIG" = "true" ]; then
168
- check "ANTHROPIC_* vars in config.env (third-party API provider)" 0
169
-
170
- PLIST_FILE="$HOME/Library/LaunchAgents/com.codex-to-im.bridge.plist"
171
-
172
- # On macOS, verify the launchd plist also has the vars
173
- if [ "$(uname -s)" = "Darwin" ] && [ -f "$PLIST_FILE" ]; then
174
- if grep -q "ANTHROPIC_" "$PLIST_FILE" 2>/dev/null; then
175
- check "ANTHROPIC_* vars in launchd plist" 0
176
- else
177
- check "ANTHROPIC_* vars in launchd plist (NOT present — restart bridge to regenerate plist)" 1
178
- fi
179
- fi
180
-
181
- # If bridge is running, verify the LIVE process has the vars.
182
- # The plist may be correct on disk but if the daemon hasn't been
183
- # restarted since the plist was regenerated, it still runs with the
184
- # old environment.
185
- BRIDGE_PID=$(cat "$PID_FILE" 2>/dev/null || true)
186
- if [ -n "$BRIDGE_PID" ] && kill -0 "$BRIDGE_PID" 2>/dev/null; then
187
- # ps eww shows the process environment on macOS/Linux
188
- PROC_ENV=$(ps eww -p "$BRIDGE_PID" 2>/dev/null || true)
189
- if echo "$PROC_ENV" | grep -q "ANTHROPIC_"; then
190
- check "Running bridge process has ANTHROPIC_* env vars" 0
191
- else
192
- check "Running bridge process has ANTHROPIC_* env vars (NOT in process env — restart the bridge)" 1
193
- fi
194
- fi
195
- else
196
- check "ANTHROPIC_* vars in config.env (not set — OK if using default Anthropic auth)" 0
197
- fi
198
-
199
- # --- SDK cli.js resolvable ---
200
- SDK_CLI=""
201
- for candidate in \
202
- "$SKILL_DIR/node_modules/@anthropic-ai/claude-agent-sdk/cli.js" \
203
- "$SKILL_DIR/node_modules/@anthropic-ai/claude-agent-sdk/dist/cli.js"; do
204
- if [ -f "$candidate" ]; then
205
- SDK_CLI="$candidate"
206
- break
207
- fi
208
- done
209
- if [ -n "$SDK_CLI" ]; then
210
- check "Claude SDK cli.js exists ($SDK_CLI)" 0
211
- else
212
- if [ "$CTI_RUNTIME" = "claude" ]; then
213
- check "Claude SDK cli.js exists (not found — run 'npm install' in $SKILL_DIR)" 1
214
- else
215
- check "Claude SDK cli.js exists (not found — OK for auto/codex mode)" 0
216
- fi
217
- fi
218
- fi
219
-
220
- # --- Codex checks (codex/auto modes) ---
221
- if [ "$CTI_RUNTIME" = "codex" ] || [ "$CTI_RUNTIME" = "auto" ]; then
222
- if command -v codex &>/dev/null; then
223
- CODEX_VER=$(codex --version 2>/dev/null || echo "unknown")
224
- check "Codex CLI available (${CODEX_VER})" 0
225
- else
226
- if [ "$CTI_RUNTIME" = "codex" ]; then
227
- check "Codex CLI available (not found in PATH)" 1
228
- else
229
- check "Codex CLI available (not found — will use Claude)" 0
230
- fi
231
- fi
232
-
233
- # Check @openai/codex-sdk
234
- CODEX_SDK="$SKILL_DIR/node_modules/@openai/codex-sdk"
235
- if [ -d "$CODEX_SDK" ]; then
236
- check "@openai/codex-sdk installed" 0
237
- else
238
- if [ "$CTI_RUNTIME" = "codex" ]; then
239
- check "@openai/codex-sdk installed (not found — run 'npm install' in $SKILL_DIR)" 1
240
- else
241
- check "@openai/codex-sdk installed (not found — OK for auto/claude mode)" 0
242
- fi
243
- fi
40
+ CTI_RUNTIME=$(get_config CTI_RUNTIME)
41
+ CTI_RUNTIME="codex"
42
+ echo "Runtime: $CTI_RUNTIME"
43
+ echo ""
44
+
45
+ # --- Codex checks ---
46
+ if command -v codex &>/dev/null; then
47
+ CODEX_VER=$(codex --version 2>/dev/null || echo "unknown")
48
+ check "Codex CLI available (${CODEX_VER})" 0
49
+ else
50
+ check "Codex CLI available (not found in PATH)" 1
51
+ fi
52
+
53
+ # Check @openai/codex-sdk
54
+ CODEX_SDK="$SKILL_DIR/node_modules/@openai/codex-sdk"
55
+ if [ -d "$CODEX_SDK" ]; then
56
+ check "@openai/codex-sdk installed" 0
57
+ else
58
+ check "@openai/codex-sdk installed (not found — run 'npm install' in $SKILL_DIR)" 1
59
+ fi
244
60
 
245
61
  # Check Codex auth: any of CTI_CODEX_API_KEY / CODEX_API_KEY / OPENAI_API_KEY,
246
62
  # or `codex auth status` showing logged-in (interactive login).
@@ -253,18 +69,13 @@ if [ "$CTI_RUNTIME" = "codex" ] || [ "$CTI_RUNTIME" = "auto" ]; then
253
69
  CODEX_AUTH=0
254
70
  fi
255
71
  fi
256
- if [ "$CODEX_AUTH" = "0" ]; then
257
- check "Codex auth available (API key or login)" 0
258
- else
259
- if [ "$CTI_RUNTIME" = "codex" ]; then
260
- check "Codex auth available (set OPENAI_API_KEY or run 'codex auth login')" 1
261
- else
262
- check "Codex auth available (not found — needed only for Codex fallback)" 0
263
- fi
264
- fi
265
- fi
266
-
267
- # --- dist/daemon.mjs freshness ---
72
+ if [ "$CODEX_AUTH" = "0" ]; then
73
+ check "Codex auth available (API key or login)" 0
74
+ else
75
+ check "Codex auth available (set OPENAI_API_KEY or run 'codex auth login')" 1
76
+ fi
77
+
78
+ # --- dist/daemon.mjs freshness ---
268
79
  DAEMON_MJS="$SKILL_DIR/dist/daemon.mjs"
269
80
  if [ -f "$DAEMON_MJS" ]; then
270
81
  STALE_SRC=$(find "$SKILL_DIR/src" -name '*.ts' -newer "$DAEMON_MJS" 2>/dev/null | head -1)
@@ -295,25 +106,10 @@ if [ -f "$CONFIG_FILE" ]; then
295
106
  fi
296
107
 
297
108
  # --- Load config for channel checks ---
298
- if [ -f "$CONFIG_FILE" ]; then
299
- CTI_CHANNELS=$(get_config CTI_ENABLED_CHANNELS)
300
-
301
- # --- Telegram ---
302
- if echo "$CTI_CHANNELS" | grep -q telegram; then
303
- TG_TOKEN=$(get_config CTI_TG_BOT_TOKEN)
304
- if [ -n "$TG_TOKEN" ]; then
305
- TG_RESULT=$(curl -s --max-time 5 "https://api.telegram.org/bot${TG_TOKEN}/getMe" 2>/dev/null || echo '{"ok":false}')
306
- if echo "$TG_RESULT" | grep -q '"ok":true'; then
307
- check "Telegram bot token is valid" 0
308
- else
309
- check "Telegram bot token is valid (getMe failed)" 1
310
- fi
311
- else
312
- check "Telegram bot token configured" 1
313
- fi
314
- fi
315
-
316
- # --- Feishu ---
109
+ if [ -f "$CONFIG_FILE" ]; then
110
+ CTI_CHANNELS=$(get_config CTI_ENABLED_CHANNELS)
111
+
112
+ # --- Feishu ---
317
113
  if echo "$CTI_CHANNELS" | grep -q feishu; then
318
114
  FS_APP_ID=$(get_config CTI_FEISHU_APP_ID)
319
115
  FS_SECRET=$(get_config CTI_FEISHU_APP_SECRET)
@@ -337,51 +133,10 @@ if [ -f "$CONFIG_FILE" ]; then
337
133
  fi
338
134
  else
339
135
  check "Feishu app credentials configured" 1
340
- fi
341
- fi
342
-
343
- # --- QQ ---
344
- if echo "$CTI_CHANNELS" | grep -q qq; then
345
- QQ_APP_ID=$(get_config CTI_QQ_APP_ID)
346
- QQ_APP_SECRET=$(get_config CTI_QQ_APP_SECRET)
347
- if [ -n "$QQ_APP_ID" ] && [ -n "$QQ_APP_SECRET" ]; then
348
- QQ_TOKEN_RESULT=$(curl -s --max-time 10 -X POST "https://bots.qq.com/app/getAppAccessToken" \
349
- -H "Content-Type: application/json" \
350
- -d "{\"appId\":\"${QQ_APP_ID}\",\"clientSecret\":\"${QQ_APP_SECRET}\"}" 2>/dev/null || echo '{}')
351
- QQ_ACCESS_TOKEN=$(echo "$QQ_TOKEN_RESULT" | sed -n 's/.*"access_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
352
- if [ -n "$QQ_ACCESS_TOKEN" ]; then
353
- check "QQ app credentials are valid (access_token obtained)" 0
354
- # Verify gateway availability
355
- QQ_GW_RESULT=$(curl -s --max-time 10 "https://api.sgroup.qq.com/gateway" \
356
- -H "Authorization: QQBot ${QQ_ACCESS_TOKEN}" 2>/dev/null || echo '{}')
357
- if echo "$QQ_GW_RESULT" | grep -q '"url"'; then
358
- check "QQ gateway is reachable" 0
359
- else
360
- check "QQ gateway is reachable (GET /gateway failed)" 1
361
- fi
362
- else
363
- check "QQ app credentials are valid (getAppAccessToken failed)" 1
364
- fi
365
- else
366
- check "QQ app credentials configured" 1
367
- fi
368
- fi
369
-
370
- # --- Discord ---
371
- if echo "$CTI_CHANNELS" | grep -q discord; then
372
- DC_TOKEN=$(get_config CTI_DISCORD_BOT_TOKEN)
373
- if [ -n "$DC_TOKEN" ]; then
374
- if echo "${DC_TOKEN}" | grep -qE '^[A-Za-z0-9_-]{20,}\.'; then
375
- check "Discord bot token format" 0
376
- else
377
- check "Discord bot token format (does not match expected pattern)" 1
378
- fi
379
- else
380
- check "Discord bot token configured" 1
381
- fi
382
- fi
383
-
384
- # --- Weixin ---
136
+ fi
137
+ fi
138
+
139
+ # --- Weixin ---
385
140
  if echo "$CTI_CHANNELS" | grep -q weixin; then
386
141
  WX_ACCOUNTS_FILE="$CTI_HOME/data/weixin-accounts.json"
387
142
  if [ -f "$WX_ACCOUNTS_FILE" ]; then
@@ -28,34 +28,15 @@ build_env_dict() {
28
28
  ;; esac
29
29
  done < <(env)
30
30
 
31
- # Forward runtime-specific API keys
32
- local runtime
33
- runtime=$(grep "^CTI_RUNTIME=" "$CTI_HOME/config.env" 2>/dev/null | head -1 | cut -d= -f2- | tr -d "'" | tr -d '"' || true)
34
- runtime="${runtime:-claude}"
35
-
36
- case "$runtime" in
37
- codex|auto)
38
- for var in OPENAI_API_KEY CODEX_API_KEY CTI_CODEX_API_KEY CTI_CODEX_BASE_URL; do
39
- local val="${!var:-}"
40
- [ -z "$val" ] && continue
41
- dict+="${indent}<key>${var}</key>\n${indent}<string>${val}</string>\n"
42
- done
43
- ;;
44
- esac
45
- case "$runtime" in
46
- claude|auto)
47
- # Auto-forward all ANTHROPIC_* env vars (sourced from config.env by daemon.sh).
48
- # Third-party API providers need these to reach the CLI subprocess.
49
- while IFS='=' read -r name val; do
50
- case "$name" in ANTHROPIC_*)
51
- dict+="${indent}<key>${name}</key>\n${indent}<string>${val}</string>\n"
52
- ;; esac
53
- done < <(env)
54
- ;;
55
- esac
56
-
57
- echo -e "$dict"
58
- }
31
+ # Forward Codex/OpenAI credentials used by the Codex runtime.
32
+ for var in OPENAI_API_KEY CODEX_API_KEY CTI_CODEX_API_KEY CTI_CODEX_BASE_URL; do
33
+ local val="${!var:-}"
34
+ [ -z "$val" ] && continue
35
+ dict+="${indent}<key>${var}</key>\n${indent}<string>${val}</string>\n"
36
+ done
37
+
38
+ echo -e "$dict"
39
+ }
59
40
 
60
41
  generate_plist() {
61
42
  local node_path