@wu529778790/open-im 1.6.7 → 1.6.8-alpha.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/README.md +6 -13
- package/README.zh-CN.md +6 -13
- package/dist/adapters/registry.js +0 -6
- package/dist/commands/handler.js +5 -7
- package/dist/config-web-page-i18n.d.ts +0 -8
- package/dist/config-web-page-i18n.js +0 -8
- package/dist/config-web-page-script.js +2 -14
- package/dist/config-web-page-template.js +0 -28
- package/dist/config-web-page.test.js +1 -1
- package/dist/config-web.js +0 -16
- package/dist/config-web.test.js +0 -30
- package/dist/config.d.ts +1 -18
- package/dist/config.js +6 -140
- package/dist/config.test.js +4 -36
- package/dist/dingtalk/client.d.ts +2 -0
- package/dist/dingtalk/client.js +41 -2
- package/dist/dingtalk/message-sender.test.js +3 -3
- package/dist/feishu/card-builder.d.ts +1 -1
- package/dist/index.js +32 -32
- package/dist/session/session-manager.d.ts +2 -2
- package/dist/session/session-manager.js +6 -6
- package/dist/setup.js +2 -9
- package/dist/shared/ai-task.js +27 -13
- package/dist/shared/message-title.test.js +1 -1
- package/dist/shared/utils.js +0 -1
- package/dist/wework/message-sender.js +11 -1
- package/package.json +2 -2
- package/dist/adapters/cursor-adapter.d.ts +0 -11
- package/dist/adapters/cursor-adapter.js +0 -60
- package/dist/cursor/cli-runner.d.ts +0 -36
- package/dist/cursor/cli-runner.js +0 -328
- package/dist/cursor/cli-runner.test.d.ts +0 -1
- package/dist/cursor/cli-runner.test.js +0 -94
package/README.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
[中文](./README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
Multi-platform IM bridge for AI CLI tools. Connect Telegram, Feishu, WeCom, DingTalk, QQ, and WeChat to Claude Code, Codex,
|
|
5
|
+
Multi-platform IM bridge for AI CLI tools. Connect Telegram, Feishu, WeCom, DingTalk, QQ, and WeChat to Claude Code, Codex, and CodeBuddy so you can use your coding assistant remotely from a phone or chat window.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- Multi-platform support: Telegram, Feishu, WeCom, DingTalk, QQ, and WeChat (experimental), with multiple platforms enabled at the same time
|
|
10
|
-
- Multiple AI tools: Claude, Codex,
|
|
10
|
+
- Multiple AI tools: Claude, Codex, and CodeBuddy
|
|
11
11
|
- Per-platform AI routing: each IM platform can use a different AI tool, with `aiCommand` as the global default and `platforms.<name>.aiCommand` as the override
|
|
12
12
|
- Streaming replies: relay AI output and tool execution progress in real time (DingTalk streaming is not fully supported yet)
|
|
13
13
|
- Graphical configuration page and CLI setup flow
|
|
@@ -84,7 +84,7 @@ Example:
|
|
|
84
84
|
},
|
|
85
85
|
"feishu": {
|
|
86
86
|
"enabled": true,
|
|
87
|
-
"aiCommand": "
|
|
87
|
+
"aiCommand": "codex"
|
|
88
88
|
},
|
|
89
89
|
"qq": {
|
|
90
90
|
"enabled": true,
|
|
@@ -94,7 +94,7 @@ Example:
|
|
|
94
94
|
}
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
In that setup, Telegram uses Codex, Feishu uses
|
|
97
|
+
In that setup, Telegram uses Codex, Feishu uses Codex, QQ uses CodeBuddy, and any platform without its own `aiCommand` continues using Claude.
|
|
98
98
|
|
|
99
99
|
### Claude
|
|
100
100
|
|
|
@@ -151,10 +151,6 @@ The following is valid JSON and can be saved directly as `~/.open-im/config.json
|
|
|
151
151
|
"skipPermissions": true,
|
|
152
152
|
"timeoutMs": 600000
|
|
153
153
|
},
|
|
154
|
-
"cursor": {
|
|
155
|
-
"cliPath": "agent",
|
|
156
|
-
"skipPermissions": true
|
|
157
|
-
},
|
|
158
154
|
"codex": {
|
|
159
155
|
"cliPath": "codex",
|
|
160
156
|
"workDir": "D:/coding/open-im",
|
|
@@ -177,7 +173,7 @@ The following is valid JSON and can be saved directly as `~/.open-im/config.json
|
|
|
177
173
|
},
|
|
178
174
|
"feishu": {
|
|
179
175
|
"enabled": false,
|
|
180
|
-
"aiCommand": "
|
|
176
|
+
"aiCommand": "codex",
|
|
181
177
|
"allowedUserIds": [],
|
|
182
178
|
"appId": "YOUR_FEISHU_APP_ID",
|
|
183
179
|
"appSecret": "YOUR_FEISHU_APP_SECRET"
|
|
@@ -219,14 +215,13 @@ The following is valid JSON and can be saved directly as `~/.open-im/config.json
|
|
|
219
215
|
|
|
220
216
|
| Variable | Description |
|
|
221
217
|
| ---- | ---- |
|
|
222
|
-
| `AI_COMMAND` | Select `claude`, `codex`,
|
|
218
|
+
| `AI_COMMAND` | Select `claude`, `codex`, or `codebuddy` |
|
|
223
219
|
| `CLAUDE_WORK_DIR` | Default session working directory |
|
|
224
220
|
| `LOG_DIR` | Log directory |
|
|
225
221
|
| `LOG_LEVEL` | Log level |
|
|
226
222
|
| `HOOK_PORT` | Permission service port |
|
|
227
223
|
| `CODEX_PROXY` | Proxy used by Codex to access `chatgpt.com` |
|
|
228
224
|
| `OPENAI_API_KEY` | Codex API key, can replace `codex login` |
|
|
229
|
-
| `CURSOR_API_KEY` | Cursor API key, can replace `agent login` |
|
|
230
225
|
| `CODEBUDDY_CLI_PATH` | Override CodeBuddy CLI path |
|
|
231
226
|
| `CODEBUDDY_TIMEOUT_MS` | Override CodeBuddy timeout |
|
|
232
227
|
| `CODEBUDDY_SKIP_PERMISSIONS` | Override CodeBuddy skip-permissions behavior |
|
|
@@ -304,8 +299,6 @@ DingTalk AI card templates are already compatible with the official "Search Resu
|
|
|
304
299
|
|
|
305
300
|
**DingTalk has no streaming updates**: when `prepare` fails, the app falls back to plain text replies. In custom bot or regular group scenarios, neither the AI assistant API nor the interactive card API is available, so only single plain text replies are supported.
|
|
306
301
|
|
|
307
|
-
**Cursor shows `Authentication required`**: run `agent login` first, or set `CURSOR_API_KEY` in `env`.
|
|
308
|
-
|
|
309
302
|
**Codex shows `stream disconnected` or `error sending request`**: `chatgpt.com` is not reachable. Configure `tools.codex.proxy` or set `CODEX_PROXY`.
|
|
310
303
|
|
|
311
304
|
**CodeBuddy prompts for login**: run `codebuddy login` first. `open-im` does not read CodeBuddy login state from `~/.open-im/config.json`.
|
package/README.zh-CN.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
[English](./README.md)
|
|
4
4
|
|
|
5
|
-
多平台 IM 桥接工具,把 Telegram、飞书、企业微信、钉钉、QQ、微信接到 AI CLI 工具(Claude Code、Codex、
|
|
5
|
+
多平台 IM 桥接工具,把 Telegram、飞书、企业微信、钉钉、QQ、微信接到 AI CLI 工具(Claude Code、Codex、CodeBuddy),方便在手机或聊天窗口里远程使用 AI 编程助手。
|
|
6
6
|
|
|
7
7
|
## 功能特性
|
|
8
8
|
|
|
9
9
|
- 多平台:支持 Telegram、飞书、企业微信、钉钉、QQ、微信(测试中),可同时启用
|
|
10
|
-
- 多 AI 工具:支持 Claude、Codex、
|
|
10
|
+
- 多 AI 工具:支持 Claude、Codex、CodeBuddy
|
|
11
11
|
- 按平台分配 AI:根级 `aiCommand` 作为默认值,`platforms.<name>.aiCommand` 可为不同 IM 单独指定 AI 工具
|
|
12
12
|
- 流式输出:实时回传 AI 回复与工具执行进度(目前钉钉暂未实现流式传输)
|
|
13
13
|
- 图形化配置页面 / CLI 配置引导
|
|
@@ -84,7 +84,7 @@ open-im start
|
|
|
84
84
|
},
|
|
85
85
|
"feishu": {
|
|
86
86
|
"enabled": true,
|
|
87
|
-
"aiCommand": "
|
|
87
|
+
"aiCommand": "codex"
|
|
88
88
|
},
|
|
89
89
|
"qq": {
|
|
90
90
|
"enabled": true,
|
|
@@ -94,7 +94,7 @@ open-im start
|
|
|
94
94
|
}
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
这个配置下,Telegram 会走 Codex,飞书会走
|
|
97
|
+
这个配置下,Telegram 会走 Codex,飞书会走 Codex,QQ 会走 CodeBuddy,其他未单独指定 `aiCommand` 的平台仍然使用 Claude。
|
|
98
98
|
|
|
99
99
|
### Claude
|
|
100
100
|
|
|
@@ -151,10 +151,6 @@ codebuddy login
|
|
|
151
151
|
"skipPermissions": true,
|
|
152
152
|
"timeoutMs": 600000
|
|
153
153
|
},
|
|
154
|
-
"cursor": {
|
|
155
|
-
"cliPath": "agent",
|
|
156
|
-
"skipPermissions": true
|
|
157
|
-
},
|
|
158
154
|
"codex": {
|
|
159
155
|
"cliPath": "codex",
|
|
160
156
|
"workDir": "D:/coding/open-im",
|
|
@@ -177,7 +173,7 @@ codebuddy login
|
|
|
177
173
|
},
|
|
178
174
|
"feishu": {
|
|
179
175
|
"enabled": false,
|
|
180
|
-
"aiCommand": "
|
|
176
|
+
"aiCommand": "codex",
|
|
181
177
|
"allowedUserIds": [],
|
|
182
178
|
"appId": "YOUR_FEISHU_APP_ID",
|
|
183
179
|
"appSecret": "YOUR_FEISHU_APP_SECRET"
|
|
@@ -219,14 +215,13 @@ codebuddy login
|
|
|
219
215
|
|
|
220
216
|
| 变量 | 说明 |
|
|
221
217
|
| ---- | ---- |
|
|
222
|
-
| `AI_COMMAND` | 选择 `claude` / `codex` / `
|
|
218
|
+
| `AI_COMMAND` | 选择 `claude` / `codex` / `codebuddy` |
|
|
223
219
|
| `CLAUDE_WORK_DIR` | 默认会话目录 |
|
|
224
220
|
| `LOG_DIR` | 日志目录 |
|
|
225
221
|
| `LOG_LEVEL` | 日志级别 |
|
|
226
222
|
| `HOOK_PORT` | 权限服务端口 |
|
|
227
223
|
| `CODEX_PROXY` | Codex 访问 `chatgpt.com` 的代理 |
|
|
228
224
|
| `OPENAI_API_KEY` | Codex API Key,可替代 `codex login` |
|
|
229
|
-
| `CURSOR_API_KEY` | Cursor API Key,可替代 `agent login` |
|
|
230
225
|
| `CODEBUDDY_CLI_PATH` | 覆盖 CodeBuddy CLI 路径 |
|
|
231
226
|
| `CODEBUDDY_TIMEOUT_MS` | 覆盖 CodeBuddy 超时 |
|
|
232
227
|
| `CODEBUDDY_SKIP_PERMISSIONS` | 覆盖 CodeBuddy 的跳过权限确认行为 |
|
|
@@ -304,8 +299,6 @@ codebuddy login
|
|
|
304
299
|
|
|
305
300
|
**钉钉没有流式更新**:`prepare` 失败时 fallback 为普通文本回复。自定义机器人/普通群场景下,AI 助理和互动卡片 API 均不可用,仅支持单条文本回复。
|
|
306
301
|
|
|
307
|
-
**Cursor 报 `Authentication required`**:先执行 `agent login`,或在 `env` 中设置 `CURSOR_API_KEY`。
|
|
308
|
-
|
|
309
302
|
**Codex 报 `stream disconnected` / `error sending request`**:无法访问 `chatgpt.com`,请配置 `tools.codex.proxy` 或环境变量 `CODEX_PROXY`。
|
|
310
303
|
|
|
311
304
|
**CodeBuddy 提示需要登录**:先执行 `codebuddy login`。`open-im` 不会从 `~/.open-im/config.json` 读取 CodeBuddy 的登录态。
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getConfiguredAiCommands } from '../config.js';
|
|
2
2
|
import { ClaudeAdapter } from './claude-adapter.js';
|
|
3
3
|
import { ClaudeSDKAdapter } from './claude-sdk-adapter.js';
|
|
4
|
-
import { CursorAdapter } from './cursor-adapter.js';
|
|
5
4
|
import { CodexAdapter } from './codex-adapter.js';
|
|
6
5
|
import { CodeBuddyAdapter } from './codebuddy-adapter.js';
|
|
7
6
|
const adapters = new Map();
|
|
@@ -22,11 +21,6 @@ export function initAdapters(config) {
|
|
|
22
21
|
}
|
|
23
22
|
continue;
|
|
24
23
|
}
|
|
25
|
-
if (aiCommand === 'cursor') {
|
|
26
|
-
console.log('Cursor CLI adapter enabled');
|
|
27
|
-
adapters.set('cursor', new CursorAdapter(config.cursorCliPath));
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
24
|
if (aiCommand === 'codex') {
|
|
31
25
|
console.log('Codex CLI adapter enabled');
|
|
32
26
|
adapters.set('codex', new CodexAdapter(config.codexCliPath));
|
package/dist/commands/handler.js
CHANGED
|
@@ -172,13 +172,11 @@ export class CommandHandler {
|
|
|
172
172
|
return true;
|
|
173
173
|
}
|
|
174
174
|
getAiVersion(aiCommand) {
|
|
175
|
-
const cmd = aiCommand === '
|
|
176
|
-
? this.deps.config.
|
|
177
|
-
: aiCommand === '
|
|
178
|
-
? this.deps.config.
|
|
179
|
-
:
|
|
180
|
-
? this.deps.config.codebuddyCliPath
|
|
181
|
-
: this.deps.config.claudeCliPath;
|
|
175
|
+
const cmd = aiCommand === 'codex'
|
|
176
|
+
? this.deps.config.codexCliPath
|
|
177
|
+
: aiCommand === 'codebuddy'
|
|
178
|
+
? this.deps.config.codebuddyCliPath
|
|
179
|
+
: this.deps.config.claudeCliPath;
|
|
182
180
|
return new Promise((resolve) => {
|
|
183
181
|
execFile(cmd, ['--version'], { timeout: 5000 }, (err, stdout) => {
|
|
184
182
|
resolve(err ? '未知' : (stdout?.toString().trim() || '未知'));
|
|
@@ -85,7 +85,6 @@ export declare const PAGE_TEXTS: {
|
|
|
85
85
|
readonly aiTool: "Default AI tool";
|
|
86
86
|
readonly workDir: "Default work directory";
|
|
87
87
|
readonly claudeCli: "Claude CLI path";
|
|
88
|
-
readonly cursorCli: "Cursor CLI path";
|
|
89
88
|
readonly codexCli: "Codex CLI path";
|
|
90
89
|
readonly codebuddyCli: "CodeBuddy CLI path";
|
|
91
90
|
readonly codexProxy: "Codex proxy";
|
|
@@ -96,10 +95,7 @@ export declare const PAGE_TEXTS: {
|
|
|
96
95
|
readonly claudeModel: "ANTHROPIC_MODEL";
|
|
97
96
|
readonly claudeProxy: "Proxy (optional)";
|
|
98
97
|
readonly codexTimeout: "Codex timeout (ms)";
|
|
99
|
-
readonly cursorTimeout: "Cursor timeout (ms)";
|
|
100
|
-
readonly cursorModel: "Model (e.g. auto)";
|
|
101
98
|
readonly codebuddyTimeout: "CodeBuddy timeout (ms)";
|
|
102
|
-
readonly cursorProxy: "Proxy (optional)";
|
|
103
99
|
readonly hookPort: "Hook port";
|
|
104
100
|
readonly logLevel: "Log level";
|
|
105
101
|
readonly logLevelDefault: "default (app default)";
|
|
@@ -206,7 +202,6 @@ export declare const PAGE_TEXTS: {
|
|
|
206
202
|
readonly aiTool: "默认 AI 工具";
|
|
207
203
|
readonly workDir: "默认工作目录";
|
|
208
204
|
readonly claudeCli: "Claude CLI 路径";
|
|
209
|
-
readonly cursorCli: "Cursor CLI 路径";
|
|
210
205
|
readonly codexCli: "Codex CLI 路径";
|
|
211
206
|
readonly codebuddyCli: "CodeBuddy CLI 路径";
|
|
212
207
|
readonly codexProxy: "Codex 代理";
|
|
@@ -217,10 +212,7 @@ export declare const PAGE_TEXTS: {
|
|
|
217
212
|
readonly claudeModel: "ANTHROPIC_MODEL";
|
|
218
213
|
readonly claudeProxy: "代理(可选)";
|
|
219
214
|
readonly codexTimeout: "Codex 超时(毫秒)";
|
|
220
|
-
readonly cursorTimeout: "Cursor 超时(毫秒)";
|
|
221
|
-
readonly cursorModel: "模型(如 auto)";
|
|
222
215
|
readonly codebuddyTimeout: "CodeBuddy 超时(毫秒)";
|
|
223
|
-
readonly cursorProxy: "代理(可选)";
|
|
224
216
|
readonly hookPort: "Hook 端口";
|
|
225
217
|
readonly logLevel: "日志级别";
|
|
226
218
|
readonly logLevelDefault: "default(程序默认)";
|
|
@@ -85,7 +85,6 @@ export const PAGE_TEXTS = {
|
|
|
85
85
|
aiTool: "Default AI tool",
|
|
86
86
|
workDir: "Default work directory",
|
|
87
87
|
claudeCli: "Claude CLI path",
|
|
88
|
-
cursorCli: "Cursor CLI path",
|
|
89
88
|
codexCli: "Codex CLI path",
|
|
90
89
|
codebuddyCli: "CodeBuddy CLI path",
|
|
91
90
|
codexProxy: "Codex proxy",
|
|
@@ -96,10 +95,7 @@ export const PAGE_TEXTS = {
|
|
|
96
95
|
claudeModel: "ANTHROPIC_MODEL",
|
|
97
96
|
claudeProxy: "Proxy (optional)",
|
|
98
97
|
codexTimeout: "Codex timeout (ms)",
|
|
99
|
-
cursorTimeout: "Cursor timeout (ms)",
|
|
100
|
-
cursorModel: "Model (e.g. auto)",
|
|
101
98
|
codebuddyTimeout: "CodeBuddy timeout (ms)",
|
|
102
|
-
cursorProxy: "Proxy (optional)",
|
|
103
99
|
hookPort: "Hook port",
|
|
104
100
|
logLevel: "Log level",
|
|
105
101
|
logLevelDefault: "default (app default)",
|
|
@@ -206,7 +202,6 @@ export const PAGE_TEXTS = {
|
|
|
206
202
|
aiTool: "\u9ed8\u8ba4 AI \u5de5\u5177",
|
|
207
203
|
workDir: "\u9ed8\u8ba4\u5de5\u4f5c\u76ee\u5f55",
|
|
208
204
|
claudeCli: "Claude CLI \u8def\u5f84",
|
|
209
|
-
cursorCli: "Cursor CLI \u8def\u5f84",
|
|
210
205
|
codexCli: "Codex CLI \u8def\u5f84",
|
|
211
206
|
codebuddyCli: "CodeBuddy CLI \u8def\u5f84",
|
|
212
207
|
codexProxy: "Codex \u4ee3\u7406",
|
|
@@ -217,10 +212,7 @@ export const PAGE_TEXTS = {
|
|
|
217
212
|
claudeModel: "ANTHROPIC_MODEL",
|
|
218
213
|
claudeProxy: "\u4ee3\u7406\uff08\u53ef\u9009\uff09",
|
|
219
214
|
codexTimeout: "Codex \u8d85\u65f6\uff08\u6beb\u79d2\uff09",
|
|
220
|
-
cursorTimeout: "Cursor \u8d85\u65f6\uff08\u6beb\u79d2\uff09",
|
|
221
|
-
cursorModel: "模型(如 auto)",
|
|
222
215
|
codebuddyTimeout: "CodeBuddy \u8d85\u65f6\uff08\u6beb\u79d2\uff09",
|
|
223
|
-
cursorProxy: "\u4ee3\u7406\uff08\u53ef\u9009\uff09",
|
|
224
216
|
hookPort: "Hook \u7aef\u53e3",
|
|
225
217
|
logLevel: "\u65e5\u5fd7\u7ea7\u522b",
|
|
226
218
|
logLevelDefault: "default\uff08\u7a0b\u5e8f\u9ed8\u8ba4\uff09",
|
|
@@ -6,11 +6,11 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
6
6
|
{ key: "dingtalk", label: "DingTalk", fields: ["aiCommand", "clientId", "clientSecret", "cardTemplateId", "allowedUserIds"], testFields: ["clientId", "clientSecret"], requiredFields: ["clientId", "clientSecret"] },
|
|
7
7
|
];
|
|
8
8
|
const platformKeys = platformDefinitions.map((platform) => platform.key);
|
|
9
|
-
const aiTools = ["claude", "codex", "
|
|
9
|
+
const aiTools = ["claude", "codex", "codebuddy"];
|
|
10
10
|
const STORAGE_KEY_LANG = "open-im-web-lang";
|
|
11
11
|
const STORAGE_KEY_DARK_MODE = "open-im-web-dark-mode";
|
|
12
12
|
const POLLING_INTERVAL = 10000;
|
|
13
|
-
const toolLabels = { claude: "Claude", codex: "Codex",
|
|
13
|
+
const toolLabels = { claude: "Claude", codex: "Codex", codebuddy: "CodeBuddy" };
|
|
14
14
|
|
|
15
15
|
// Dark mode handling
|
|
16
16
|
const getSystemDarkMode = () => window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
@@ -209,10 +209,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
209
209
|
{ id: "ai-codexCliPath-label", key: "codexCli" },
|
|
210
210
|
{ id: "ai-codexTimeoutMs-label", key: "codexTimeout" },
|
|
211
211
|
{ id: "ai-codexProxy-label", key: "codexProxy" },
|
|
212
|
-
{ id: "ai-cursorCliPath-label", key: "cursorCli" },
|
|
213
|
-
{ id: "ai-cursorModel-label", key: "cursorModel" },
|
|
214
|
-
{ id: "ai-cursorTimeoutMs-label", key: "cursorTimeout" },
|
|
215
|
-
{ id: "ai-cursorProxy-label", key: "cursorProxy" },
|
|
216
212
|
{ id: "ai-codebuddyCliPath-label", key: "codebuddyCli" },
|
|
217
213
|
{ id: "ai-codebuddyTimeoutMs-label", key: "codebuddyTimeout" },
|
|
218
214
|
{ id: "ai-hookPort-label", key: "hookPort" },
|
|
@@ -424,10 +420,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
424
420
|
{ id: "ai-codexCliPath", key: "codexCliPath" },
|
|
425
421
|
{ id: "ai-codexTimeoutMs", key: "codexTimeoutMs" },
|
|
426
422
|
{ id: "ai-codexProxy", key: "codexProxy" },
|
|
427
|
-
{ id: "ai-cursorCliPath", key: "cursorCliPath" },
|
|
428
|
-
{ id: "ai-cursorModel", key: "cursorModel" },
|
|
429
|
-
{ id: "ai-cursorTimeoutMs", key: "cursorTimeoutMs" },
|
|
430
|
-
{ id: "ai-cursorProxy", key: "cursorProxy" },
|
|
431
423
|
{ id: "ai-codebuddyCliPath", key: "codebuddyCliPath" },
|
|
432
424
|
{ id: "ai-codebuddyTimeoutMs", key: "codebuddyTimeoutMs" },
|
|
433
425
|
{ id: "ai-hookPort", key: "hookPort" },
|
|
@@ -672,10 +664,6 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
672
664
|
codebuddyTimeoutMs: getNumber("ai-codebuddyTimeoutMs"),
|
|
673
665
|
codexCliPath: getValue("ai-codexCliPath"),
|
|
674
666
|
codexProxy: getValue("ai-codexProxy"),
|
|
675
|
-
cursorCliPath: getValue("ai-cursorCliPath"),
|
|
676
|
-
cursorModel: getValue("ai-cursorModel"),
|
|
677
|
-
cursorTimeoutMs: getNumber("ai-cursorTimeoutMs"),
|
|
678
|
-
cursorProxy: getValue("ai-cursorProxy"),
|
|
679
667
|
codebuddyCliPath: getValue("ai-codebuddyCliPath"),
|
|
680
668
|
hookPort: getNumber("ai-hookPort"),
|
|
681
669
|
logLevel: getValue("ai-logLevel"),
|
|
@@ -875,7 +875,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
875
875
|
<option value="">(default)</option>
|
|
876
876
|
<option value="claude">claude</option>
|
|
877
877
|
<option value="codex">codex</option>
|
|
878
|
-
<option value="cursor">cursor</option>
|
|
879
878
|
<option value="codebuddy">codebuddy</option>
|
|
880
879
|
</select>
|
|
881
880
|
</div>
|
|
@@ -918,7 +917,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
918
917
|
<option value="">(default)</option>
|
|
919
918
|
<option value="claude">claude</option>
|
|
920
919
|
<option value="codex">codex</option>
|
|
921
|
-
<option value="cursor">cursor</option>
|
|
922
920
|
<option value="codebuddy">codebuddy</option>
|
|
923
921
|
</select>
|
|
924
922
|
</div>
|
|
@@ -960,7 +958,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
960
958
|
<option value="">(default)</option>
|
|
961
959
|
<option value="claude">claude</option>
|
|
962
960
|
<option value="codex">codex</option>
|
|
963
|
-
<option value="cursor">cursor</option>
|
|
964
961
|
<option value="codebuddy">codebuddy</option>
|
|
965
962
|
</select>
|
|
966
963
|
</div>
|
|
@@ -1002,7 +999,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
1002
999
|
<option value="">(default)</option>
|
|
1003
1000
|
<option value="claude">claude</option>
|
|
1004
1001
|
<option value="codex">codex</option>
|
|
1005
|
-
<option value="cursor">cursor</option>
|
|
1006
1002
|
<option value="codebuddy">codebuddy</option>
|
|
1007
1003
|
</select>
|
|
1008
1004
|
</div>
|
|
@@ -1048,7 +1044,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
1048
1044
|
<option value="">(default)</option>
|
|
1049
1045
|
<option value="claude">claude</option>
|
|
1050
1046
|
<option value="codex">codex</option>
|
|
1051
|
-
<option value="cursor">cursor</option>
|
|
1052
1047
|
<option value="codebuddy">codebuddy</option>
|
|
1053
1048
|
</select>
|
|
1054
1049
|
</div>
|
|
@@ -1084,7 +1079,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
1084
1079
|
<select id="ai-aiCommand" class="form-select">
|
|
1085
1080
|
<option value="claude">claude</option>
|
|
1086
1081
|
<option value="codex">codex</option>
|
|
1087
|
-
<option value="cursor">cursor</option>
|
|
1088
1082
|
<option value="codebuddy">codebuddy</option>
|
|
1089
1083
|
</select>
|
|
1090
1084
|
</div>
|
|
@@ -1114,7 +1108,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
1114
1108
|
<div class="tabs" id="aiToolSwitcher">
|
|
1115
1109
|
<button class="tab active" data-tool="claude" type="button">Claude</button>
|
|
1116
1110
|
<button class="tab" data-tool="codex" type="button">Codex</button>
|
|
1117
|
-
<button class="tab" data-tool="cursor" type="button">Cursor</button>
|
|
1118
1111
|
<button class="tab" data-tool="codebuddy" type="button">CodeBuddy</button>
|
|
1119
1112
|
</div>
|
|
1120
1113
|
</div>
|
|
@@ -1170,27 +1163,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
1170
1163
|
</div>
|
|
1171
1164
|
</div>
|
|
1172
1165
|
|
|
1173
|
-
<div id="ai-tool-cursor" class="ai-tool-panel" data-tool-panel="cursor">
|
|
1174
|
-
<div class="form-group">
|
|
1175
|
-
<label class="form-label" id="ai-cursorCliPath-label">CLI Path</label>
|
|
1176
|
-
<input id="ai-cursorCliPath" class="form-input mono" type="text" />
|
|
1177
|
-
</div>
|
|
1178
|
-
<div class="form-group">
|
|
1179
|
-
<label class="form-label" id="ai-cursorModel-label">Model</label>
|
|
1180
|
-
<input id="ai-cursorModel" class="form-input mono" type="text" placeholder="auto" />
|
|
1181
|
-
<div class="form-hint" id="ai-cursorModel-hint">如 auto、Claude 4 Sonnet 等,agent --list-models 查看</div>
|
|
1182
|
-
</div>
|
|
1183
|
-
<div class="form-group">
|
|
1184
|
-
<label class="form-label" id="ai-cursorTimeoutMs-label">Timeout (ms)</label>
|
|
1185
|
-
<input id="ai-cursorTimeoutMs" class="form-input" type="number" min="1" />
|
|
1186
|
-
</div>
|
|
1187
|
-
<div class="form-group">
|
|
1188
|
-
<label class="form-label" id="ai-cursorProxy-label">Proxy (optional)</label>
|
|
1189
|
-
<input id="ai-cursorProxy" class="form-input mono" type="text" />
|
|
1190
|
-
<div class="form-hint" id="ai-cursorProxy-hint">HTTP proxy for API requests (e.g., http://127.0.0.1:7890)</div>
|
|
1191
|
-
</div>
|
|
1192
|
-
</div>
|
|
1193
|
-
|
|
1194
1166
|
<div id="ai-tool-codebuddy" class="ai-tool-panel" data-tool-panel="codebuddy">
|
|
1195
1167
|
<div class="form-group">
|
|
1196
1168
|
<label class="form-label" id="ai-codebuddyCliPath-label">CLI Path</label>
|
|
@@ -38,7 +38,7 @@ describe("config web page assembly", () => {
|
|
|
38
38
|
const toolListMatch = PAGE_SCRIPT.match(/const aiTools = \[([^\]]+)\]/);
|
|
39
39
|
expect(toolListMatch).toBeTruthy();
|
|
40
40
|
const tools = Array.from((toolListMatch?.[1] ?? "").matchAll(/"([^"]+)"/g), (match) => match[1]);
|
|
41
|
-
expect(tools).toEqual(["claude", "codex", "
|
|
41
|
+
expect(tools).toEqual(["claude", "codex", "codebuddy"]);
|
|
42
42
|
for (const tool of tools) {
|
|
43
43
|
expect(PAGE_HTML).toContain(`data-tool="${tool}"`);
|
|
44
44
|
expect(PAGE_HTML).toContain(`data-tool-panel="${tool}"`);
|
package/dist/config-web.js
CHANGED
|
@@ -143,14 +143,10 @@ function buildInitialPayload(file) {
|
|
|
143
143
|
claudeModel: file.tools?.claude?.model ?? claudeEnv.ANTHROPIC_MODEL ?? "",
|
|
144
144
|
claudeProxy: file.tools?.claude?.proxy ?? "",
|
|
145
145
|
codexTimeoutMs: file.tools?.codex?.timeoutMs ?? 600000,
|
|
146
|
-
cursorTimeoutMs: file.tools?.cursor?.timeoutMs ?? 600000,
|
|
147
146
|
codebuddyTimeoutMs: file.tools?.codebuddy?.timeoutMs ?? 600000,
|
|
148
|
-
cursorCliPath: file.tools?.cursor?.cliPath ?? "cursor",
|
|
149
|
-
cursorModel: file.tools?.cursor?.model ?? "auto",
|
|
150
147
|
codexCliPath: file.tools?.codex?.cliPath ?? "codex",
|
|
151
148
|
codebuddyCliPath: file.tools?.codebuddy?.cliPath ?? "codebuddy",
|
|
152
149
|
codexProxy: file.tools?.codex?.proxy ?? "",
|
|
153
|
-
cursorProxy: file.tools?.cursor?.proxy ?? "",
|
|
154
150
|
defaultPermissionMode: file.defaultPermissionMode ?? "ask",
|
|
155
151
|
hookPort: file.hookPort ?? 35801,
|
|
156
152
|
logDir: file.logDir ?? "",
|
|
@@ -188,8 +184,6 @@ function validatePayload(payload) {
|
|
|
188
184
|
errors.push("Claude timeout must be positive.");
|
|
189
185
|
if (!Number.isFinite(payload.ai.codexTimeoutMs) || payload.ai.codexTimeoutMs <= 0)
|
|
190
186
|
errors.push("Codex timeout must be positive.");
|
|
191
|
-
if (!Number.isFinite(payload.ai.cursorTimeoutMs) || payload.ai.cursorTimeoutMs <= 0)
|
|
192
|
-
errors.push("Cursor timeout must be positive.");
|
|
193
187
|
if (!Number.isFinite(payload.ai.codebuddyTimeoutMs) || payload.ai.codebuddyTimeoutMs <= 0)
|
|
194
188
|
errors.push("CodeBuddy timeout must be positive.");
|
|
195
189
|
if (!Number.isFinite(payload.ai.hookPort) || payload.ai.hookPort <= 0)
|
|
@@ -271,14 +265,12 @@ function createProbeConfig(values) {
|
|
|
271
265
|
dingtalkAllowedUserIds: [],
|
|
272
266
|
aiCommand: "claude",
|
|
273
267
|
claudeCliPath: "claude",
|
|
274
|
-
cursorCliPath: "cursor",
|
|
275
268
|
codexCliPath: "codex",
|
|
276
269
|
claudeWorkDir: process.cwd(),
|
|
277
270
|
claudeSkipPermissions: true,
|
|
278
271
|
defaultPermissionMode: "ask",
|
|
279
272
|
claudeTimeoutMs: 600000,
|
|
280
273
|
codexTimeoutMs: 600000,
|
|
281
|
-
cursorTimeoutMs: 600000,
|
|
282
274
|
codebuddyTimeoutMs: 600000,
|
|
283
275
|
hookPort: 35801,
|
|
284
276
|
logDir: "",
|
|
@@ -422,14 +414,6 @@ function toFileConfig(payload, existing) {
|
|
|
422
414
|
proxy: clean(payload.ai.claudeProxy),
|
|
423
415
|
// model is now saved to ~/.claude/settings.json as ANTHROPIC_MODEL
|
|
424
416
|
},
|
|
425
|
-
cursor: {
|
|
426
|
-
...existing.tools?.cursor,
|
|
427
|
-
cliPath: clean(payload.ai.cursorCliPath) ?? "cursor",
|
|
428
|
-
skipPermissions: existing.tools?.cursor?.skipPermissions ?? payload.ai.claudeSkipPermissions,
|
|
429
|
-
proxy: clean(payload.ai.cursorProxy),
|
|
430
|
-
timeoutMs: payload.ai.cursorTimeoutMs,
|
|
431
|
-
model: clean(payload.ai.cursorModel),
|
|
432
|
-
},
|
|
433
417
|
codex: {
|
|
434
418
|
...existing.tools?.codex,
|
|
435
419
|
cliPath: clean(payload.ai.codexCliPath) ?? "codex",
|
package/dist/config-web.test.js
CHANGED
|
@@ -55,33 +55,3 @@ describe("getHealthPlatformSnapshot", () => {
|
|
|
55
55
|
expect(snapshot.qq.message).toContain("configured");
|
|
56
56
|
});
|
|
57
57
|
});
|
|
58
|
-
describe("Cursor web config defaults", () => {
|
|
59
|
-
it("surfaces cursor as the default CLI path in initial config", async () => {
|
|
60
|
-
vi.resetModules();
|
|
61
|
-
const { startWebConfigServer } = await import("./config-web.js");
|
|
62
|
-
const server = await startWebConfigServer({ mode: "init", cwd: process.cwd(), persistent: true });
|
|
63
|
-
if (!server.url) {
|
|
64
|
-
await server.close();
|
|
65
|
-
throw new Error("Web config server failed to bind (url empty)");
|
|
66
|
-
}
|
|
67
|
-
// 使用原生 fetch(可能被 testPlatformConfig 的 vi.fn 覆盖),改用 http.get
|
|
68
|
-
const { get } = await import("node:http");
|
|
69
|
-
const body = await new Promise((resolve, reject) => {
|
|
70
|
-
get(`${server.url}/api/config`, (res) => {
|
|
71
|
-
let data = "";
|
|
72
|
-
res.on("data", (chunk) => { data += chunk; });
|
|
73
|
-
res.on("end", () => {
|
|
74
|
-
try {
|
|
75
|
-
resolve(JSON.parse(data));
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
78
|
-
reject(e);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}).on("error", reject);
|
|
82
|
-
});
|
|
83
|
-
await server.close();
|
|
84
|
-
// 无显式配置时为 cursor;Windows 下可能解析为安装路径
|
|
85
|
-
expect(body?.payload?.ai?.cursorCliPath === "cursor" || body?.payload?.ai?.cursorCliPath?.endsWith("cursor.cmd")).toBe(true);
|
|
86
|
-
});
|
|
87
|
-
});
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { LogLevel } from './logger.js';
|
|
2
2
|
export type Platform = 'dingtalk' | 'feishu' | 'qq' | 'telegram' | 'wechat' | 'wework';
|
|
3
|
-
export type AiCommand = 'claude' | 'codex' | '
|
|
3
|
+
export type AiCommand = 'claude' | 'codex' | 'codebuddy';
|
|
4
4
|
export interface Config {
|
|
5
5
|
enabledPlatforms: Platform[];
|
|
6
6
|
telegramBotToken?: string;
|
|
@@ -31,23 +31,17 @@ export interface Config {
|
|
|
31
31
|
dingtalkAllowedUserIds: string[];
|
|
32
32
|
aiCommand: AiCommand;
|
|
33
33
|
claudeCliPath: string;
|
|
34
|
-
cursorCliPath: string;
|
|
35
34
|
codexCliPath: string;
|
|
36
35
|
codebuddyCliPath: string;
|
|
37
36
|
/** Codex 访问 chatgpt.com 的代理(如 http://127.0.0.1:7890) */
|
|
38
37
|
codexProxy?: string;
|
|
39
|
-
/** Cursor 访问 API 的代理(如 http://127.0.0.1:7890,CLI 非官方支持) */
|
|
40
|
-
cursorProxy?: string;
|
|
41
38
|
claudeTimeoutMs: number;
|
|
42
39
|
codexTimeoutMs: number;
|
|
43
|
-
cursorTimeoutMs: number;
|
|
44
40
|
codebuddyTimeoutMs: number;
|
|
45
41
|
claudeWorkDir: string;
|
|
46
42
|
claudeSkipPermissions: boolean;
|
|
47
43
|
defaultPermissionMode: 'ask' | 'accept-edits' | 'plan' | 'yolo';
|
|
48
44
|
claudeModel?: string;
|
|
49
|
-
/** Cursor 专用模型,如 auto(自动选择)、Claude 4 Sonnet 等 */
|
|
50
|
-
cursorModel?: string;
|
|
51
45
|
hookPort: number;
|
|
52
46
|
logDir: string;
|
|
53
47
|
logLevel: LogLevel;
|
|
@@ -152,16 +146,6 @@ export interface FileToolClaude {
|
|
|
152
146
|
model?: string;
|
|
153
147
|
proxy?: string;
|
|
154
148
|
}
|
|
155
|
-
export interface FileToolCursor {
|
|
156
|
-
cliPath?: string;
|
|
157
|
-
/** 是否跳过权限确认(默认 true,与 tools.claude 共用权限服务器) */
|
|
158
|
-
skipPermissions?: boolean;
|
|
159
|
-
/** HTTP/HTTPS 代理(CLI 非官方支持,部分环境可能生效) */
|
|
160
|
-
proxy?: string;
|
|
161
|
-
timeoutMs?: number;
|
|
162
|
-
/** 模型名,如 auto、Claude 4 Sonnet、gpt-5.2 等,见 agent --list-models */
|
|
163
|
-
model?: string;
|
|
164
|
-
}
|
|
165
149
|
export interface FileToolCodex {
|
|
166
150
|
cliPath?: string;
|
|
167
151
|
workDir?: string;
|
|
@@ -194,7 +178,6 @@ export interface FileConfig {
|
|
|
194
178
|
aiCommand?: string;
|
|
195
179
|
tools?: {
|
|
196
180
|
claude?: FileToolClaude;
|
|
197
|
-
cursor?: FileToolCursor;
|
|
198
181
|
codex?: FileToolCodex;
|
|
199
182
|
codebuddy?: FileToolCodeBuddy;
|
|
200
183
|
};
|