@wu529778790/open-im 1.10.5 → 1.10.6-beta.1

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/README.md CHANGED
@@ -62,29 +62,33 @@ Session state is stored in **`~/.open-im/data/sessions.json`** (per user, not IM
62
62
 
63
63
  ### Per-platform AI
64
64
 
65
- Default: root **`aiCommand`**. Override with **`platforms.<name>.aiCommand`**:
65
+ Set **`platforms.<name>.aiCommand`** per channel (`claude` / `codex` / `codebuddy`). If unset, the process **`AI_COMMAND`** env var is used when present; otherwise it defaults to **`claude`**.
66
66
 
67
67
  ```json
68
68
  {
69
- "aiCommand": "claude",
70
69
  "platforms": {
71
- "telegram": { "enabled": true, "aiCommand": "codex" }
70
+ "telegram": { "enabled": true, "aiCommand": "codex", "botToken": "..." }
72
71
  }
73
72
  }
74
73
  ```
75
74
 
76
75
  ### Claude (Agent SDK)
77
76
 
78
- No local `claude` binary required. Credentials: env → **`config.json`** `env` → **`~/.claude/settings.json`**.
77
+ No local `claude` binary required. Credentials: env → **`config.json`** **`tools.claude.env`** → **`~/.claude/settings.json`** (dashboard saves API fields here).
79
78
 
80
79
  Third-party / compatible API example:
81
80
 
82
81
  ```json
83
82
  {
84
- "env": {
85
- "ANTHROPIC_AUTH_TOKEN": "your-token",
86
- "ANTHROPIC_BASE_URL": "https://your-api-endpoint",
87
- "ANTHROPIC_MODEL": "glm-4.7"
83
+ "tools": {
84
+ "claude": {
85
+ "workDir": "/path/to/project",
86
+ "env": {
87
+ "ANTHROPIC_AUTH_TOKEN": "your-token",
88
+ "ANTHROPIC_BASE_URL": "https://your-api-endpoint",
89
+ "ANTHROPIC_MODEL": "glm-4.7"
90
+ }
91
+ }
88
92
  }
89
93
  }
90
94
  ```
@@ -100,12 +104,11 @@ codebuddy login
100
104
 
101
105
  ```json
102
106
  {
103
- "aiCommand": "claude",
104
107
  "tools": {
105
108
  "claude": { "workDir": "/path/to/project", "skipPermissions": true, "timeoutMs": 600000 }
106
109
  },
107
110
  "platforms": {
108
- "telegram": { "enabled": true, "botToken": "YOUR_TELEGRAM_BOT_TOKEN" }
111
+ "telegram": { "enabled": true, "aiCommand": "claude", "botToken": "YOUR_TELEGRAM_BOT_TOKEN" }
109
112
  }
110
113
  }
111
114
  ```
@@ -114,7 +117,7 @@ Add Feishu, QQ, WeCom, DingTalk, WorkBuddy under **`platforms`** as needed. Run
114
117
 
115
118
  ### Environment variables
116
119
 
117
- Use **`config.json`** or environment variables; the dashboard exposes common options. Typical keys: **`ANTHROPIC_*`**, **`TELEGRAM_BOT_TOKEN`**, **`OPEN_IM_WEB_PORT`**, **`OPEN_IM_WEB_HOST`**, plus platform-specific `*_APP_ID`, `*_SECRET`, `WORKBUDDY_*`, etc.
120
+ Use **`config.json`** (platforms, `tools.*`, etc.) or environment variables; the dashboard exposes common options. Typical keys: **`ANTHROPIC_*`** (shell or **`tools.claude.env`**), **`TELEGRAM_BOT_TOKEN`**, **`OPEN_IM_WEB_PORT`**, **`OPEN_IM_WEB_HOST`**, plus platform-specific `*_APP_ID`, `*_SECRET`, `WORKBUDDY_*`, etc. The root-level **`config.json` `env`** field is no longer read.
118
121
 
119
122
  ### Privacy
120
123
 
package/README.zh-CN.md CHANGED
@@ -62,29 +62,33 @@ npx @wu529778790/open-im start
62
62
 
63
63
  ### 按平台指定 AI
64
64
 
65
- 根级 **`aiCommand`** 为默认;用 **`platforms.<name>.aiCommand`** 覆盖:
65
+ 在每个已启用渠道上设置 **`platforms.<name>.aiCommand`**(`claude` / `codex` / `codebuddy`)。若未设置,会尝试进程环境变量 **`AI_COMMAND`**;再否则默认为 **`claude`**。
66
66
 
67
67
  ```json
68
68
  {
69
- "aiCommand": "claude",
70
69
  "platforms": {
71
- "telegram": { "enabled": true, "aiCommand": "codex" }
70
+ "telegram": { "enabled": true, "aiCommand": "codex", "botToken": "..." }
72
71
  }
73
72
  }
74
73
  ```
75
74
 
76
75
  ### Claude(Agent SDK)
77
76
 
78
- 无需本地 `claude` 可执行文件。凭证顺序:环境变量 → **`config.json`** 的 **`env`** → **`~/.claude/settings.json`**。
77
+ 无需本地 `claude` 可执行文件。凭证顺序:环境变量 → **`config.json`** 的 **`tools.claude.env`** → **`~/.claude/settings.json`**(控制台保存的 API 配置写入后者)。
79
78
 
80
79
  第三方兼容接口示例:
81
80
 
82
81
  ```json
83
82
  {
84
- "env": {
85
- "ANTHROPIC_AUTH_TOKEN": "your-token",
86
- "ANTHROPIC_BASE_URL": "https://your-api-endpoint",
87
- "ANTHROPIC_MODEL": "glm-4.7"
83
+ "tools": {
84
+ "claude": {
85
+ "workDir": "/path/to/project",
86
+ "env": {
87
+ "ANTHROPIC_AUTH_TOKEN": "your-token",
88
+ "ANTHROPIC_BASE_URL": "https://your-api-endpoint",
89
+ "ANTHROPIC_MODEL": "glm-4.7"
90
+ }
91
+ }
88
92
  }
89
93
  }
90
94
  ```
@@ -100,12 +104,11 @@ codebuddy login
100
104
 
101
105
  ```json
102
106
  {
103
- "aiCommand": "claude",
104
107
  "tools": {
105
108
  "claude": { "workDir": "/path/to/project", "skipPermissions": true, "timeoutMs": 600000 }
106
109
  },
107
110
  "platforms": {
108
- "telegram": { "enabled": true, "botToken": "YOUR_TELEGRAM_BOT_TOKEN" }
111
+ "telegram": { "enabled": true, "aiCommand": "claude", "botToken": "YOUR_TELEGRAM_BOT_TOKEN" }
109
112
  }
110
113
  }
111
114
  ```
@@ -114,7 +117,7 @@ codebuddy login
114
117
 
115
118
  ### 环境变量
116
119
 
117
- 可在 **`config.json`** 或环境变量中设置;控制台会展示常用项。常见:**`ANTHROPIC_*`**、**`TELEGRAM_BOT_TOKEN`**、**`OPEN_IM_WEB_PORT`**、**`OPEN_IM_WEB_HOST`**,以及各平台的 `*_APP_ID`、`*_SECRET`、`WORKBUDDY_*` 等。
120
+ 可在 **`config.json`**(平台与 `tools.*` 等)或环境变量中设置;控制台会展示常用项。常见:**`ANTHROPIC_*`**(shell 或 **`tools.claude.env`**)、**`TELEGRAM_BOT_TOKEN`**、**`OPEN_IM_WEB_PORT`**、**`OPEN_IM_WEB_HOST`**,以及各平台的 `*_APP_ID`、`*_SECRET`、`WORKBUDDY_*` 等。根级 **`config.json` `env`** 已不再使用。
118
121
 
119
122
  ### 隐私
120
123
 
@@ -37,7 +37,7 @@ export class CodexAdapter {
37
37
  onError: (err) => {
38
38
  const msg = typeof err === "string" ? err : String(err);
39
39
  const friendly = msg.includes("Authentication") || msg.includes("login")
40
- ? "Codex 需要先登录。请在终端运行 codex login,或在 ~/.open-im/config.json env 中添加 OPENAI_API_KEY。"
40
+ ? "Codex 需要先登录。请在终端运行 codex login,或在 shell export OPENAI_API_KEY。"
41
41
  : msg.includes("stream disconnected") ||
42
42
  msg.includes("error sending request") ||
43
43
  msg.includes("Connection refused") ||
@@ -2,6 +2,7 @@ import { execFileSync, spawn } from 'node:child_process';
2
2
  import { accessSync, constants } from 'node:fs';
3
3
  import { isAbsolute, join } from 'node:path';
4
4
  import { createLogger } from '../logger.js';
5
+ import { processEnvForNonClaudeCliChild } from '../config/file-io.js';
5
6
  const log = createLogger('CodeBuddyCli');
6
7
  export function buildCodeBuddyArgs(prompt, sessionId, options) {
7
8
  const args = ['--print', '--output-format', 'stream-json'];
@@ -164,11 +165,7 @@ export function runCodeBuddy(cliPath, prompt, sessionId, workDir, callbacks, opt
164
165
  ...options,
165
166
  permissionMode: normalizePermissionMode(options?.permissionMode),
166
167
  });
167
- const env = {};
168
- for (const [key, value] of Object.entries(process.env)) {
169
- if (value !== undefined)
170
- env[key] = value;
171
- }
168
+ const env = processEnvForNonClaudeCliChild();
172
169
  if (process.platform === 'win32') {
173
170
  env.LANG = env.LANG || 'C.UTF-8';
174
171
  env.LC_ALL = env.LC_ALL || 'C.UTF-8';
@@ -6,6 +6,7 @@ import { existsSync, readFileSync } from 'node:fs';
6
6
  import { dirname, join } from 'node:path';
7
7
  import { createInterface } from 'node:readline';
8
8
  import { createLogger } from '../logger.js';
9
+ import { processEnvForNonClaudeCliChild } from '../config/file-io.js';
9
10
  const log = createLogger('CodexCli');
10
11
  const windowsCodexLaunchCache = new Map();
11
12
  const SUPPORTED_IMAGE_EXTENSIONS = new Set([
@@ -161,11 +162,7 @@ function resolveWindowsCodexLaunch(cliPath, args) {
161
162
  }
162
163
  export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options) {
163
164
  const args = buildCodexArgs(prompt, sessionId, workDir, options);
164
- const env = {};
165
- for (const [k, v] of Object.entries(process.env)) {
166
- if (v !== undefined)
167
- env[k] = v;
168
- }
165
+ const env = processEnvForNonClaudeCliChild();
169
166
  if (options?.chatId)
170
167
  env.CC_IM_CHAT_ID = options.chatId;
171
168
  if (options?.hookPort)
@@ -3,6 +3,10 @@ export declare const CONFIG_PATH: string;
3
3
  export declare const CODEX_AUTH_PATHS: string[];
4
4
  /** Claude 认证相关的环境变量 key 列表 */
5
5
  export declare const CLAUDE_AUTH_ENV_KEYS: readonly ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "CLAUDE_CODE_OAUTH_TOKEN", "ANTHROPIC_BASE_URL", "ANTHROPIC_MODEL"];
6
+ /**
7
+ * 供非 Claude CLI 子进程使用的环境:拷贝当前 process.env,并移除 Anthropic/Claude 专用项。
8
+ */
9
+ export declare function processEnvForNonClaudeCliChild(): Record<string, string>;
6
10
  export declare function loadFileConfig(): FileConfig;
7
11
  export declare function saveFileConfig(raw: FileConfig): void;
8
12
  export declare function getClaudeConfigHome(): string;
@@ -13,7 +17,8 @@ export declare function hasCodexAuth(): boolean;
13
17
  export declare function parseCommaSeparated(value: string): string[];
14
18
  /**
15
19
  * 将最新的 Claude 认证环境变量按优先级合并到 process.env。
16
- * 优先级:shell 环境变量 > tools.claude.env(config.json) > ~/.claude/settings.json
17
- * 启动时调用一次;cc switch 后再次调用即可生效。
20
+ * 优先级:shell 环境变量 > ~/.open-im/config.json 的 tools.claude.env >
21
+ * 本机 Claude 配置(~/.claude/settings.json,与 Claude Code 共用)。
22
+ * 多数用户只维护本机 settings;每次创建 Claude SDK 会话前调用,本机文件变更后下次会话即生效。
18
23
  */
19
24
  export declare function refreshClaudeEnvToProcess(): void;
@@ -24,6 +24,29 @@ export const CLAUDE_AUTH_ENV_KEYS = [
24
24
  'ANTHROPIC_BASE_URL',
25
25
  'ANTHROPIC_MODEL',
26
26
  ];
27
+ /**
28
+ * 不应传入 Codex / CodeBuddy 等子进程的环境变量。
29
+ * Claude 适配器会通过 refreshClaudeEnvToProcess 把这些写入 process.env;
30
+ * 若原样拷贝给 CLI 子进程,可能导致错误使用 ANTHROPIC_BASE_URL 等「访问地址」。
31
+ */
32
+ const NON_CLAUDE_CLI_STRIP_KEYS = new Set([
33
+ ...CLAUDE_AUTH_ENV_KEYS,
34
+ 'ANTHROPIC_DEFAULT_HAIKU_MODEL',
35
+ 'ANTHROPIC_DEFAULT_SONNET_MODEL',
36
+ 'ANTHROPIC_DEFAULT_OPUS_MODEL',
37
+ ]);
38
+ /**
39
+ * 供非 Claude CLI 子进程使用的环境:拷贝当前 process.env,并移除 Anthropic/Claude 专用项。
40
+ */
41
+ export function processEnvForNonClaudeCliChild() {
42
+ const env = {};
43
+ for (const [k, v] of Object.entries(process.env)) {
44
+ if (v === undefined || NON_CLAUDE_CLI_STRIP_KEYS.has(k))
45
+ continue;
46
+ env[k] = v;
47
+ }
48
+ return env;
49
+ }
27
50
  // Config cache with mtime tracking
28
51
  let cachedConfig = null;
29
52
  let cachedClaudeEnv = null;
@@ -109,39 +132,61 @@ export function saveFileConfig(raw) {
109
132
  export function getClaudeConfigHome() {
110
133
  return process.env.HOME || process.env.USERPROFILE || homedir();
111
134
  }
135
+ function claudeSettingsJsonPath(home) {
136
+ return join(home, '.claude', 'settings.json');
137
+ }
138
+ /**
139
+ * 从单个 Claude settings JSON 根对象解析 env(与 Claude Code 行为对齐)。
140
+ * - `env` 对象内字段优先于根上同名认证键
141
+ * - 根上可存在 ANTHROPIC_* / CLAUDE_CODE_OAUTH_TOKEN(部分用户或旧版会写在顶层)
142
+ */
143
+ function extractAuthEnvFromClaudeSettingsRoot(raw) {
144
+ const out = {};
145
+ for (const key of CLAUDE_AUTH_ENV_KEYS) {
146
+ const v = raw[key];
147
+ if (v != null && typeof v === 'string' && v.length > 0) {
148
+ out[key] = v;
149
+ }
150
+ }
151
+ const env = raw.env;
152
+ if (env && typeof env === 'object' && !Array.isArray(env)) {
153
+ for (const [k, v] of Object.entries(env)) {
154
+ if (v != null && typeof k === 'string') {
155
+ out[k] = String(v);
156
+ }
157
+ }
158
+ }
159
+ return out;
160
+ }
112
161
  export function loadClaudeSettingsEnv() {
113
162
  const home = getClaudeConfigHome();
114
- const paths = [
115
- join(home, '.claude', 'settings.json'),
116
- join(home, '.claude.json'),
117
- ];
118
- for (const p of paths) {
119
- try {
120
- if (existsSync(p)) {
121
- const stats = statSync(p);
122
- const currentMtime = stats.mtimeMs;
123
- if (cachedClaudeEnv && cachedClaudeEnv.mtime === currentMtime && cachedClaudeEnv.env) {
124
- return cachedClaudeEnv.env;
125
- }
126
- const raw = JSON.parse(readFileSync(p, 'utf-8'));
127
- const env = raw?.env;
128
- if (env && typeof env === 'object') {
129
- const result = {};
130
- for (const [k, v] of Object.entries(env)) {
131
- if (v != null && typeof k === 'string') {
132
- result[k] = String(v);
133
- }
134
- }
135
- cachedClaudeEnv = { env: result, mtime: currentMtime };
136
- return result;
137
- }
138
- }
163
+ const p = claudeSettingsJsonPath(home);
164
+ let fingerprint = '';
165
+ try {
166
+ if (existsSync(p)) {
167
+ fingerprint = `${p}:${statSync(p).mtimeMs}`;
139
168
  }
140
- catch {
141
- /* file not found or parse error, try next path */
169
+ }
170
+ catch {
171
+ /* ignore */
172
+ }
173
+ if (cachedClaudeEnv && cachedClaudeEnv.fingerprint === fingerprint) {
174
+ return cachedClaudeEnv.env;
175
+ }
176
+ let merged = {};
177
+ try {
178
+ if (existsSync(p)) {
179
+ const raw = JSON.parse(readFileSync(p, 'utf-8'));
180
+ if (raw && typeof raw === 'object') {
181
+ merged = extractAuthEnvFromClaudeSettingsRoot(raw);
182
+ }
142
183
  }
143
184
  }
144
- return {};
185
+ catch {
186
+ /* 文件损坏或不可读 */
187
+ }
188
+ cachedClaudeEnv = { env: merged, fingerprint };
189
+ return merged;
145
190
  }
146
191
  export function saveClaudeSettingsEnv(env) {
147
192
  const home = getClaudeConfigHome();
@@ -191,8 +236,9 @@ export function parseCommaSeparated(value) {
191
236
  }
192
237
  /**
193
238
  * 将最新的 Claude 认证环境变量按优先级合并到 process.env。
194
- * 优先级:shell 环境变量 > tools.claude.env(config.json) > ~/.claude/settings.json
195
- * 启动时调用一次;cc switch 后再次调用即可生效。
239
+ * 优先级:shell 环境变量 > ~/.open-im/config.json 的 tools.claude.env >
240
+ * 本机 Claude 配置(~/.claude/settings.json,与 Claude Code 共用)。
241
+ * 多数用户只维护本机 settings;每次创建 Claude SDK 会话前调用,本机文件变更后下次会话即生效。
196
242
  */
197
243
  export function refreshClaudeEnvToProcess() {
198
244
  const file = loadFileConfig();
@@ -21,7 +21,6 @@ export interface Config {
21
21
  weworkAllowedUserIds: string[];
22
22
  dingtalkAllowedUserIds: string[];
23
23
  workbuddyAllowedUserIds: string[];
24
- aiCommand: AiCommand;
25
24
  codexCliPath: string;
26
25
  codebuddyCliPath: string;
27
26
  /** Claude 访问 API 的代理(如 http://127.0.0.1:7890) */
@@ -182,7 +181,7 @@ export interface FileConfig {
182
181
  dingtalk?: FilePlatformDingtalk;
183
182
  workbuddy?: FilePlatformWorkBuddy;
184
183
  };
185
- env?: Record<string, string>;
184
+ /** @deprecated 仅旧配置兼容;运行时以各 platforms.*.aiCommand 为准 */
186
185
  aiCommand?: string;
187
186
  tools?: {
188
187
  claude?: FileToolClaude;
@@ -86,7 +86,8 @@ export declare const PAGE_TEXTS: {
86
86
  readonly optional: "Optional";
87
87
  readonly commaSeparatedIds: "Comma-separated IDs";
88
88
  readonly aiTitle: "AI Tooling";
89
- readonly aiHint: "Pick the default tool first. Claude SDK keys: sidebar Config files → ~/.claude/settings.json. Codex / CodeBuddy need a CLI path here.";
89
+ readonly aiHint: "Claude SDK keys: sidebar Config files → ~/.claude/settings.json. Set which AI each platform uses under Platforms above. Codex / CodeBuddy need a CLI path in the panels below when any platform uses them.";
90
+ readonly aiPerPlatformHint: "Which AI to use is configured per platform in the Platforms section (default: claude). This section sets shared paths, proxy, and logs.";
90
91
  readonly claudeNote: "Claude credentials are still read from environment variables or ~/.claude/settings.json. This page manages local bridge config, not Claude account auth.";
91
92
  readonly aiCommonTitle: "Shared defaults";
92
93
  readonly aiCommonHint: "Choose the default AI tool first. Tool-specific fields are shown below.";
@@ -99,6 +100,8 @@ export declare const PAGE_TEXTS: {
99
100
  readonly codexCli: "Codex CLI path";
100
101
  readonly codebuddyCli: "CodeBuddy CLI path";
101
102
  readonly codexProxy: "Codex proxy";
103
+ readonly codexApiKey: "OPENAI_API_KEY";
104
+ readonly codexApiKeyTip: "Set the OpenAI API key used by Codex. You can also edit the auth file below.";
102
105
  readonly claudeConfigPath: "Config file location";
103
106
  readonly claudeAuthToken: "ANTHROPIC_AUTH_TOKEN";
104
107
  readonly claudeBaseUrl: "ANTHROPIC_BASE_URL";
@@ -129,8 +132,9 @@ export declare const PAGE_TEXTS: {
129
132
  readonly configEditorTitle: "Config Editor";
130
133
  readonly configEditorHint: "Edit ~/.open-im/config.json directly";
131
134
  readonly claudeSettingsLabel: "~/.claude/settings.json";
135
+ readonly codexSettingsLabel: "~/.codex/auth.json";
136
+ readonly codexSettingsCardHint: "Codex CLI auth (OPENAI_API_KEY etc.). Set API access here, or use the OPENAI_API_KEY field in the Codex tool tab.";
132
137
  readonly configJson: "~/.open-im/config.json";
133
- readonly configJsonHint: "Edit the configuration JSON. Changes will be saved when you click \"Save Config\" in the Service section.";
134
138
  readonly formatJson: "Format";
135
139
  readonly resetJson: "Reset";
136
140
  readonly saveBtn: "Save";
@@ -235,7 +239,8 @@ export declare const PAGE_TEXTS: {
235
239
  readonly optional: "可选";
236
240
  readonly commaSeparatedIds: "多个 ID 用逗号分隔";
237
241
  readonly aiTitle: "AI 工具配置";
238
- readonly aiHint: "先选默认 AI。Claude SDK:左侧栏「配置文件」→ ~/.claude/settings.jsonCodex / CodeBuddy 在此填 CLI 路径。";
242
+ readonly aiHint: "Claude SDK:左侧栏「配置文件」→ ~/.claude/settings.json。各渠道用哪个 AI 在上方「平台」里分别设置。若任一平台选 Codex/CodeBuddy,再在下方填对应 CLI 路径。";
243
+ readonly aiPerPlatformHint: "每个平台的 AI 工具在上方「平台」中配置(默认 claude)。本区域设置共用路径、代理与日志。";
239
244
  readonly claudeNote: "Claude 凭证仍然从环境变量或 ~/.claude/settings.json 读取。这个页面只管理本地桥接配置,不负责 Claude 账号登录。";
240
245
  readonly aiCommonTitle: "公共默认配置";
241
246
  readonly aiCommonHint: "先选择默认 AI 工具,下方再显示对应的工具专属配置。";
@@ -248,6 +253,8 @@ export declare const PAGE_TEXTS: {
248
253
  readonly codexCli: "Codex CLI 路径";
249
254
  readonly codebuddyCli: "CodeBuddy CLI 路径";
250
255
  readonly codexProxy: "Codex 代理";
256
+ readonly codexApiKey: "OPENAI_API_KEY";
257
+ readonly codexApiKeyTip: "设置 Codex 使用的 OpenAI API Key。也可以在下方编辑 auth 文件。";
251
258
  readonly claudeConfigPath: "配置文件位置";
252
259
  readonly claudeProxy: "代理(可选)";
253
260
  readonly hookPort: "Hook 端口";
@@ -275,6 +282,8 @@ export declare const PAGE_TEXTS: {
275
282
  readonly configEditorTitle: "JSON 配置编辑器";
276
283
  readonly configEditorHint: "直接编辑 ~/.open-im/config.json";
277
284
  readonly claudeSettingsLabel: "~/.claude/settings.json";
285
+ readonly codexSettingsLabel: "~/.codex/auth.json";
286
+ readonly codexSettingsCardHint: "Codex CLI 认证信息(OPENAI_API_KEY 等)。在此配置 API 访问,或在 Codex 工具标签页填写 OPENAI_API_KEY。";
278
287
  readonly configJson: "~/.open-im/config.json";
279
288
  readonly configJsonHint: "编辑配置 JSON。点击服务区的“保存配置”按钮后侘存更改。";
280
289
  readonly formatJson: "格式化";
@@ -86,7 +86,8 @@ export const PAGE_TEXTS = {
86
86
  optional: "Optional",
87
87
  commaSeparatedIds: "Comma-separated IDs",
88
88
  aiTitle: "AI Tooling",
89
- aiHint: "Pick the default tool first. Claude SDK keys: sidebar Config files → ~/.claude/settings.json. Codex / CodeBuddy need a CLI path here.",
89
+ aiHint: "Claude SDK keys: sidebar Config files → ~/.claude/settings.json. Set which AI each platform uses under Platforms above. Codex / CodeBuddy need a CLI path in the panels below when any platform uses them.",
90
+ aiPerPlatformHint: "Which AI to use is configured per platform in the Platforms section (default: claude). This section sets shared paths, proxy, and logs.",
90
91
  claudeNote: "Claude credentials are still read from environment variables or ~/.claude/settings.json. This page manages local bridge config, not Claude account auth.",
91
92
  aiCommonTitle: "Shared defaults",
92
93
  aiCommonHint: "Choose the default AI tool first. Tool-specific fields are shown below.",
@@ -99,6 +100,8 @@ export const PAGE_TEXTS = {
99
100
  codexCli: "Codex CLI path",
100
101
  codebuddyCli: "CodeBuddy CLI path",
101
102
  codexProxy: "Codex proxy",
103
+ codexApiKey: "OPENAI_API_KEY",
104
+ codexApiKeyTip: "Set the OpenAI API key used by Codex. You can also edit the auth file below.",
102
105
  claudeConfigPath: "Config file location",
103
106
  claudeAuthToken: "ANTHROPIC_AUTH_TOKEN",
104
107
  claudeBaseUrl: "ANTHROPIC_BASE_URL",
@@ -129,8 +132,9 @@ export const PAGE_TEXTS = {
129
132
  configEditorTitle: "Config Editor",
130
133
  configEditorHint: "Edit ~/.open-im/config.json directly",
131
134
  claudeSettingsLabel: "~/.claude/settings.json",
135
+ codexSettingsLabel: "~/.codex/auth.json",
136
+ codexSettingsCardHint: "Codex CLI auth (OPENAI_API_KEY etc.). Set API access here, or use the OPENAI_API_KEY field in the Codex tool tab.",
132
137
  configJson: "~/.open-im/config.json",
133
- configJsonHint: "Edit the configuration JSON. Changes will be saved when you click \"Save Config\" in the Service section.",
134
138
  formatJson: "Format",
135
139
  resetJson: "Reset",
136
140
  saveBtn: "Save",
@@ -235,7 +239,8 @@ export const PAGE_TEXTS = {
235
239
  optional: "\u53ef\u9009",
236
240
  commaSeparatedIds: "\u591a\u4e2a ID \u7528\u9017\u53f7\u5206\u9694",
237
241
  aiTitle: "AI \u5de5\u5177\u914d\u7f6e",
238
- aiHint: "\u5148\u9009\u9ed8\u8ba4 AI\u3002Claude SDK\uff1a\u5de6\u4fa7\u680f\u300c\u914d\u7f6e\u6587\u4ef6\u300d\u2192 ~/.claude/settings.json\u3002Codex / CodeBuddy \u5728\u6b64\u586b CLI \u8def\u5f84\u3002",
242
+ aiHint: "Claude SDK\uff1a\u5de6\u4fa7\u680f\u300c\u914d\u7f6e\u6587\u4ef6\u300d\u2192 ~/.claude/settings.json\u3002\u5404\u6e20\u9053\u7528\u54ea\u4e2a AI \u5728\u4e0a\u65b9\u300c\u5e73\u53f0\u300d\u91cc\u5206\u522b\u8bbe\u7f6e\u3002\u82e5\u4efb\u4e00\u5e73\u53f0\u9009 Codex/CodeBuddy\uff0c\u518d\u5728\u4e0b\u65b9\u586b\u5bf9\u5e94 CLI \u8def\u5f84\u3002",
243
+ aiPerPlatformHint: "\u6bcf\u4e2a\u5e73\u53f0\u7684 AI \u5de5\u5177\u5728\u4e0a\u65b9\u300c\u5e73\u53f0\u300d\u4e2d\u914d\u7f6e\uff08\u9ed8\u8ba4 claude\uff09\u3002\u672c\u533a\u57df\u8bbe\u7f6e\u5171\u7528\u8def\u5f84\u3001\u4ee3\u7406\u4e0e\u65e5\u5fd7\u3002",
239
244
  claudeNote: "Claude \u51ed\u8bc1\u4ecd\u7136\u4ece\u73af\u5883\u53d8\u91cf\u6216 ~/.claude/settings.json \u8bfb\u53d6\u3002\u8fd9\u4e2a\u9875\u9762\u53ea\u7ba1\u7406\u672c\u5730\u6865\u63a5\u914d\u7f6e\uff0c\u4e0d\u8d1f\u8d23 Claude \u8d26\u53f7\u767b\u5f55\u3002",
240
245
  aiCommonTitle: "\u516c\u5171\u9ed8\u8ba4\u914d\u7f6e",
241
246
  aiCommonHint: "\u5148\u9009\u62e9\u9ed8\u8ba4 AI \u5de5\u5177\uff0c\u4e0b\u65b9\u518d\u663e\u793a\u5bf9\u5e94\u7684\u5de5\u5177\u4e13\u5c5e\u914d\u7f6e\u3002",
@@ -248,6 +253,8 @@ export const PAGE_TEXTS = {
248
253
  codexCli: "Codex CLI \u8def\u5f84",
249
254
  codebuddyCli: "CodeBuddy CLI \u8def\u5f84",
250
255
  codexProxy: "Codex \u4ee3\u7406",
256
+ codexApiKey: "OPENAI_API_KEY",
257
+ codexApiKeyTip: "\u8bbe\u7f6e Codex \u4f7f\u7528\u7684 OpenAI API Key\u3002\u4e5f\u53ef\u4ee5\u5728\u4e0b\u65b9\u7f16\u8f91 auth \u6587\u4ef6\u3002",
251
258
  claudeConfigPath: "\u914d\u7f6e\u6587\u4ef6\u4f4d\u7f6e",
252
259
  claudeProxy: "\u4ee3\u7406\uff08\u53ef\u9009\uff09",
253
260
  hookPort: "Hook \u7aef\u53e3",
@@ -275,6 +282,8 @@ export const PAGE_TEXTS = {
275
282
  configEditorTitle: "JSON \u914d\u7f6e\u7f16\u8f91\u5668",
276
283
  configEditorHint: "\u76f4\u63a5\u7f16\u8f91 ~/.open-im/config.json",
277
284
  claudeSettingsLabel: "~/.claude/settings.json",
285
+ codexSettingsLabel: "~/.codex/auth.json",
286
+ codexSettingsCardHint: "Codex CLI \u8ba4\u8bc1\u4fe1\u606f\uff08OPENAI_API_KEY \u7b49\uff09\u3002\u5728\u6b64\u914d\u7f6e API \u8bbf\u95ee\uff0c\u6216\u5728 Codex \u5de5\u5177\u6807\u7b7e\u9875\u586b\u5199 OPENAI_API_KEY\u3002",
278
287
  configJson: "~/.open-im/config.json",
279
288
  configJsonHint: "\u7f16\u8f91\u914d\u7f6e JSON\u3002\u70b9\u51fb\u670d\u52a1\u533a\u7684\u201c\u4fdd\u5b58\u914d\u7f6e\u201d\u6309\u94ae\u540e\u4f98\u5b58\u66f4\u6539\u3002",
280
289
  formatJson: "\u683c\u5f0f\u5316",