@wu529778790/open-im 1.10.9-beta.8 → 1.11.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 +23 -67
- package/README.zh-CN.md +20 -64
- package/dist/adapters/claude-sdk-adapter.d.ts +0 -5
- package/dist/adapters/claude-sdk-adapter.js +24 -42
- package/dist/adapters/opencode-adapter.d.ts +10 -0
- package/dist/adapters/opencode-adapter.js +45 -0
- package/dist/adapters/registry.js +5 -0
- package/dist/channels/capabilities.js +5 -0
- package/dist/clawbot/client.d.ts +14 -0
- package/dist/clawbot/client.js +303 -0
- package/dist/clawbot/event-handler.d.ts +12 -0
- package/dist/clawbot/event-handler.js +85 -0
- package/dist/clawbot/message-sender.d.ts +18 -0
- package/dist/clawbot/message-sender.js +118 -0
- package/dist/clawbot/qr-login.d.ts +29 -0
- package/dist/clawbot/qr-login.js +120 -0
- package/dist/clawbot/types.d.ts +104 -0
- package/dist/clawbot/types.js +7 -0
- package/dist/codebuddy/cli-runner.d.ts +0 -1
- package/dist/codebuddy/cli-runner.js +1 -1
- package/dist/commands/handler.js +3 -5
- package/dist/config/types.d.ts +23 -2
- package/dist/config-web-page-i18n.d.ts +24 -2
- package/dist/config-web-page-i18n.js +24 -2
- package/dist/config-web.d.ts +0 -1
- package/dist/config-web.js +86 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +41 -2
- package/dist/constants.d.ts +6 -0
- package/dist/constants.js +6 -0
- package/dist/feishu/cardkit-manager.d.ts +0 -1
- package/dist/feishu/cardkit-manager.js +1 -1
- package/dist/feishu/message-sender.d.ts +0 -2
- package/dist/feishu/message-sender.js +1 -1
- package/dist/index.js +17 -0
- package/dist/opencode/cli-runner.d.ts +32 -0
- package/dist/opencode/cli-runner.js +161 -0
- package/dist/session/session-manager.d.ts +1 -1
- package/dist/setup.d.ts +0 -7
- package/dist/setup.js +128 -8
- package/dist/shared/active-chats.d.ts +8 -2
- package/dist/shared/active-chats.js +18 -0
- package/dist/shared/utils.d.ts +0 -2
- package/dist/shared/utils.js +1 -1
- package/dist/telegram/client.d.ts +0 -1
- package/dist/telegram/client.js +1 -1
- package/dist/wework/types.d.ts +0 -16
- package/dist/workbuddy/client.d.ts +0 -3
- package/dist/workbuddy/client.js +2 -2
- package/dist/workbuddy/message-sender.d.ts +0 -4
- package/dist/workbuddy/message-sender.js +1 -1
- package/dist/workbuddy/types.d.ts +0 -12
- package/package.json +1 -1
- package/web/dist/assets/index-BaLTMeeF.js +57 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-B-oVSMUp.js +0 -57
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**English** · [中文](./README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
Multi-platform IM bridge for AI CLI tools. Connect Telegram, Feishu, WeCom, DingTalk, QQ, and WeChat (
|
|
5
|
+
Multi-platform IM bridge for AI CLI tools. Connect Telegram, Feishu, WeCom, DingTalk, QQ, WeChat (WorkBuddy), and WeChat (ClawBot) to Claude Code, Codex, and CodeBuddy — use your AI coding assistant from any phone or chat window.
|
|
6
6
|
|
|
7
7
|
## Architecture
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ Multi-platform IM bridge for AI CLI tools. Connect Telegram, Feishu, WeCom, Ding
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **
|
|
13
|
+
- **Seven IM platforms** — Telegram, Feishu, WeCom, DingTalk, QQ, WorkBuddy, ClawBot
|
|
14
14
|
- **Three AI backends** — Claude (Agent SDK), Codex, CodeBuddy (per-platform override supported)
|
|
15
15
|
- **Streaming, media, sessions** — live output where supported; `/new` for a fresh AI session
|
|
16
16
|
- **Web UI** — dashboard bundled in the package; default **`http://127.0.0.1:39282`**
|
|
@@ -42,16 +42,6 @@ Config: **`~/.open-im/config.json`**
|
|
|
42
42
|
|
|
43
43
|
After `start`, the CLI prints the dashboard URL (default **`http://127.0.0.1:39282`**).
|
|
44
44
|
|
|
45
|
-
## Git co-authors
|
|
46
|
-
|
|
47
|
-
`Co-authored-by` is appended by default on AI-driven commits. **Disable:** set **`OPEN_IM_GIT_COAUTHOR=0`** in the environment and restart the bridge.
|
|
48
|
-
|
|
49
|
-
## Web dashboard
|
|
50
|
-
|
|
51
|
-
`open-im start` and `open-im dashboard` serve the built-in SPA and **`/api/*`** on **`OPEN_IM_WEB_PORT`** (default **39282**). Open **`http://127.0.0.1:39282`** in a browser (same origin as the API). Override the displayed URL with **`OPEN_IM_PUBLIC_WEB_URL`** if behind a proxy.
|
|
52
|
-
|
|
53
|
-
**Remote / LAN:** `export OPEN_IM_WEB_HOST=0.0.0.0` — first access from another host may show a one-time login link. Optional: **`OPEN_IM_ALLOW_REMOTE_API`**, **`OPEN_IM_CORS_ORIGINS`**.
|
|
54
|
-
|
|
55
45
|
## Chat commands
|
|
56
46
|
|
|
57
47
|
| Command | Description |
|
|
@@ -64,15 +54,13 @@ After `start`, the CLI prints the dashboard URL (default **`http://127.0.0.1:392
|
|
|
64
54
|
| `/cd` / `/pwd` | Working directory |
|
|
65
55
|
| `/allow` / `/y`, `/deny` / `/n` | Permission prompts |
|
|
66
56
|
|
|
67
|
-
Session state is stored in **`~/.open-im/data/sessions.json`** (per user, not IM chat logs).
|
|
68
|
-
|
|
69
57
|
## Session continuity
|
|
70
58
|
|
|
71
|
-
open-im and Claude Code CLI share the same session storage.
|
|
59
|
+
open-im and Claude Code CLI share the same session storage. In the same directory, you can seamlessly switch between phone and computer.
|
|
72
60
|
|
|
73
|
-
**Phone → Computer:** open-im
|
|
61
|
+
**Phone → Computer:** open-im auto-resumes the latest CLI session — no configuration needed.
|
|
74
62
|
|
|
75
|
-
**Computer → Phone:** use `claude --continue` (or `claude -c`) to pick up the conversation
|
|
63
|
+
**Computer → Phone:** use `claude --continue` (or `claude -c`) to pick up the phone conversation.
|
|
76
64
|
|
|
77
65
|
```
|
|
78
66
|
# On computer
|
|
@@ -85,33 +73,35 @@ cd /my-project && claude # work as usual, then Ctrl+C
|
|
|
85
73
|
claude -c # continues the phone conversation
|
|
86
74
|
```
|
|
87
75
|
|
|
88
|
-
>
|
|
76
|
+
> Only one side can be active at a time. Exit the CLI before sending messages from the phone, and vice versa.
|
|
89
77
|
|
|
90
|
-
##
|
|
78
|
+
## Git co-authors
|
|
91
79
|
|
|
92
|
-
|
|
80
|
+
`Co-authored-by` is appended by default on AI-driven commits. **Disable:** set **`OPEN_IM_GIT_COAUTHOR=0`** in the environment and restart the bridge.
|
|
93
81
|
|
|
94
|
-
|
|
82
|
+
## Minimal config
|
|
95
83
|
|
|
96
84
|
```json
|
|
97
85
|
{
|
|
86
|
+
"tools": {
|
|
87
|
+
"claude": { "workDir": "/path/to/project", "skipPermissions": true, "timeoutMs": 600000 }
|
|
88
|
+
},
|
|
98
89
|
"platforms": {
|
|
99
|
-
"telegram": { "enabled": true, "
|
|
90
|
+
"telegram": { "enabled": true, "botToken": "YOUR_TELEGRAM_BOT_TOKEN" }
|
|
100
91
|
}
|
|
101
92
|
}
|
|
102
93
|
```
|
|
103
94
|
|
|
104
|
-
|
|
95
|
+
Add other platforms under **`platforms`** as needed. Run **`open-im init`** for a full template.
|
|
105
96
|
|
|
106
|
-
|
|
97
|
+
### Claude (Agent SDK)
|
|
107
98
|
|
|
108
|
-
Third-party / compatible API
|
|
99
|
+
No local `claude` binary required. Third-party / compatible API:
|
|
109
100
|
|
|
110
101
|
```json
|
|
111
102
|
{
|
|
112
103
|
"tools": {
|
|
113
104
|
"claude": {
|
|
114
|
-
"workDir": "/path/to/project",
|
|
115
105
|
"env": {
|
|
116
106
|
"ANTHROPIC_AUTH_TOKEN": "your-token",
|
|
117
107
|
"ANTHROPIC_BASE_URL": "https://your-api-endpoint",
|
|
@@ -122,59 +112,25 @@ Third-party / compatible API example:
|
|
|
122
112
|
}
|
|
123
113
|
```
|
|
124
114
|
|
|
125
|
-
###
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
npm install -g @tencent-ai/codebuddy-code
|
|
129
|
-
codebuddy login
|
|
130
|
-
```
|
|
115
|
+
### Per-platform AI
|
|
131
116
|
|
|
132
|
-
|
|
117
|
+
Set **`platforms.<name>.aiCommand`** (`claude` / `codex` / `codebuddy`) per channel. Default: `claude`.
|
|
133
118
|
|
|
134
|
-
|
|
135
|
-
{
|
|
136
|
-
"tools": {
|
|
137
|
-
"claude": { "workDir": "/path/to/project", "skipPermissions": true, "timeoutMs": 600000 }
|
|
138
|
-
},
|
|
139
|
-
"platforms": {
|
|
140
|
-
"telegram": { "enabled": true, "aiCommand": "claude", "botToken": "YOUR_TELEGRAM_BOT_TOKEN" }
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
```
|
|
119
|
+
### Web dashboard
|
|
144
120
|
|
|
145
|
-
|
|
121
|
+
`open-im start` serves the built-in SPA and **`/api/*`** on **`OPEN_IM_WEB_PORT`** (default **39282**). For LAN access: `export OPEN_IM_WEB_HOST=0.0.0.0`.
|
|
146
122
|
|
|
147
123
|
### Environment variables
|
|
148
124
|
|
|
149
|
-
|
|
125
|
+
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.
|
|
150
126
|
|
|
151
127
|
### Privacy
|
|
152
128
|
|
|
153
129
|
**Anonymous** usage information may be collected to improve reliability (no chat or prompt content). To disable: **`OPEN_IM_TELEMETRY=false`** or **`"telemetry": { "enabled": false }`** in **`config.json`**.
|
|
154
130
|
|
|
155
|
-
|
|
131
|
+
## Platform setup & troubleshooting
|
|
156
132
|
|
|
157
|
-
|
|
158
|
-
| --- | --- |
|
|
159
|
-
| Telegram | [@BotFather](https://t.me/BotFather) |
|
|
160
|
-
| Feishu | [Open Platform](https://open.feishu.cn/) |
|
|
161
|
-
| QQ | [QQ Open Platform](https://bot.q.qq.com/) |
|
|
162
|
-
| DingTalk | Open Platform — bot **Stream Mode**; optional **`cardTemplateId`** for AI assistant cards |
|
|
163
|
-
| WeCom | [Admin](https://work.weixin.qq.com/) |
|
|
164
|
-
| WeChat | **`open-im init`** → WorkBuddy OAuth |
|
|
165
|
-
|
|
166
|
-
## Troubleshooting
|
|
167
|
-
|
|
168
|
-
| Issue | What to try |
|
|
169
|
-
| --- | --- |
|
|
170
|
-
| Telegram / network | `proxy` or **`TELEGRAM_PROXY`** |
|
|
171
|
-
| QQ | Check **`QQ_BOT_APPID`** / **`QQ_BOT_SECRET`**; update if duplicate replies |
|
|
172
|
-
| Feishu cards | **`/mode ask`** or **`/mode yolo`** without card callbacks |
|
|
173
|
-
| WeCom | Send the bot a message first |
|
|
174
|
-
| DingTalk | Stream Mode + credentials; custom bots may be text-only |
|
|
175
|
-
| Codex disconnect | **`CODEX_PROXY`** or **`tools.codex.proxy`** |
|
|
176
|
-
| CodeBuddy login | **`codebuddy login`** |
|
|
177
|
-
| WorkBuddy | Re-run **`open-im init`** (tokens expire) |
|
|
133
|
+
See **[docs/platforms.md](./docs/platforms.md)** for detailed per-platform configuration, credential setup, and troubleshooting.
|
|
178
134
|
|
|
179
135
|
## License
|
|
180
136
|
|
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](./README.md) · **中文**
|
|
4
4
|
|
|
5
|
-
多平台 IM 桥接:把 Telegram、飞书、企业微信、钉钉、QQ、微信(WorkBuddy)接到 Claude Code、Codex、CodeBuddy,在手机或聊天里使用 AI 编程助手。
|
|
5
|
+
多平台 IM 桥接:把 Telegram、飞书、企业微信、钉钉、QQ、微信(WorkBuddy)、微信(ClawBot)接到 Claude Code、Codex、CodeBuddy,在手机或聊天里使用 AI 编程助手。
|
|
6
6
|
|
|
7
7
|
## 架构
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
## 功能特性
|
|
12
12
|
|
|
13
|
-
-
|
|
13
|
+
- **七个 IM 平台** — Telegram、飞书、企业微信、钉钉、QQ、WorkBuddy、ClawBot
|
|
14
14
|
- **三种 AI 后端** — Claude(Agent SDK)、Codex、CodeBuddy(可按平台覆盖)
|
|
15
15
|
- **流式、多媒体、会话** — 视平台能力;`/new` 开启新 AI 会话
|
|
16
16
|
- **Web 控制台** — 随包内置,默认 **`http://127.0.0.1:39282`**
|
|
@@ -42,16 +42,6 @@ npx @wu529778790/open-im start
|
|
|
42
42
|
|
|
43
43
|
`start` 后会提示控制台地址(默认 **`http://127.0.0.1:39282`**)。
|
|
44
44
|
|
|
45
|
-
## Git 共同作者
|
|
46
|
-
|
|
47
|
-
默认在 AI 发起的提交里追加 `Co-authored-by`。**关闭**:设置环境变量 **`OPEN_IM_GIT_COAUTHOR=0`** 并重启桥接。
|
|
48
|
-
|
|
49
|
-
## Web 控制台
|
|
50
|
-
|
|
51
|
-
`open-im start` / `open-im dashboard` 在 **`OPEN_IM_WEB_PORT`**(默认 **39282**)提供内置页面与 **`/api/*`**。浏览器打开 **`http://127.0.0.1:39282`** 即可(与 API 同源)。反向代理时可设 **`OPEN_IM_PUBLIC_WEB_URL`**。
|
|
52
|
-
|
|
53
|
-
**局域网 / 远程:** `export OPEN_IM_WEB_HOST=0.0.0.0` — 首次外网访问可能需一次性登录链接。可选 **`OPEN_IM_ALLOW_REMOTE_API`**、**`OPEN_IM_CORS_ORIGINS`**。
|
|
54
|
-
|
|
55
45
|
## IM 内命令
|
|
56
46
|
|
|
57
47
|
| 命令 | 说明 |
|
|
@@ -64,8 +54,6 @@ npx @wu529778790/open-im start
|
|
|
64
54
|
| `/cd` / `/pwd` | 工作目录 |
|
|
65
55
|
| `/allow` / `/y`、`/deny` / `/n` | 权限确认 |
|
|
66
56
|
|
|
67
|
-
会话状态保存在 **`~/.open-im/data/sessions.json`**(按用户,与 IM 聊天记录无关)。
|
|
68
|
-
|
|
69
57
|
## 会话接力
|
|
70
58
|
|
|
71
59
|
open-im 和 Claude Code CLI 共享同一份 session 存储。在同一个目录下,手机和电脑可以无缝切换。
|
|
@@ -85,33 +73,35 @@ cd /my-project && claude # 正常工作,退出时 Ctrl+C
|
|
|
85
73
|
claude -c # 接上手机端的对话
|
|
86
74
|
```
|
|
87
75
|
|
|
88
|
-
>
|
|
76
|
+
> 同一时刻只能有一端活跃。从手机发消息前先退出 CLI,反之亦然。
|
|
89
77
|
|
|
90
|
-
##
|
|
78
|
+
## Git 共同作者
|
|
91
79
|
|
|
92
|
-
|
|
80
|
+
默认在 AI 发起的提交里追加 `Co-authored-by`。**关闭**:设置环境变量 **`OPEN_IM_GIT_COAUTHOR=0`** 并重启桥接。
|
|
93
81
|
|
|
94
|
-
|
|
82
|
+
## 最小配置
|
|
95
83
|
|
|
96
84
|
```json
|
|
97
85
|
{
|
|
86
|
+
"tools": {
|
|
87
|
+
"claude": { "workDir": "/path/to/project", "skipPermissions": true, "timeoutMs": 600000 }
|
|
88
|
+
},
|
|
98
89
|
"platforms": {
|
|
99
|
-
"telegram": { "enabled": true, "
|
|
90
|
+
"telegram": { "enabled": true, "botToken": "YOUR_TELEGRAM_BOT_TOKEN" }
|
|
100
91
|
}
|
|
101
92
|
}
|
|
102
93
|
```
|
|
103
94
|
|
|
104
|
-
|
|
95
|
+
在 **`platforms`** 下按需补充其他平台。完整模板请用 **`open-im init`**。
|
|
105
96
|
|
|
106
|
-
|
|
97
|
+
### Claude(Agent SDK)
|
|
107
98
|
|
|
108
|
-
|
|
99
|
+
无需本地 `claude` 可执行文件。第三方兼容接口示例:
|
|
109
100
|
|
|
110
101
|
```json
|
|
111
102
|
{
|
|
112
103
|
"tools": {
|
|
113
104
|
"claude": {
|
|
114
|
-
"workDir": "/path/to/project",
|
|
115
105
|
"env": {
|
|
116
106
|
"ANTHROPIC_AUTH_TOKEN": "your-token",
|
|
117
107
|
"ANTHROPIC_BASE_URL": "https://your-api-endpoint",
|
|
@@ -122,59 +112,25 @@ claude -c # 接上手机端的对话
|
|
|
122
112
|
}
|
|
123
113
|
```
|
|
124
114
|
|
|
125
|
-
###
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
npm install -g @tencent-ai/codebuddy-code
|
|
129
|
-
codebuddy login
|
|
130
|
-
```
|
|
115
|
+
### 按平台指定 AI
|
|
131
116
|
|
|
132
|
-
|
|
117
|
+
在每个平台上设置 **`platforms.<name>.aiCommand`**(`claude` / `codex` / `codebuddy`)。默认 `claude`。
|
|
133
118
|
|
|
134
|
-
|
|
135
|
-
{
|
|
136
|
-
"tools": {
|
|
137
|
-
"claude": { "workDir": "/path/to/project", "skipPermissions": true, "timeoutMs": 600000 }
|
|
138
|
-
},
|
|
139
|
-
"platforms": {
|
|
140
|
-
"telegram": { "enabled": true, "aiCommand": "claude", "botToken": "YOUR_TELEGRAM_BOT_TOKEN" }
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
```
|
|
119
|
+
### Web 控制台
|
|
144
120
|
|
|
145
|
-
|
|
121
|
+
`open-im start` 在 **`OPEN_IM_WEB_PORT`**(默认 **39282**)提供内置页面与 **`/api/*`**。局域网访问:`export OPEN_IM_WEB_HOST=0.0.0.0`。
|
|
146
122
|
|
|
147
123
|
### 环境变量
|
|
148
124
|
|
|
149
|
-
|
|
125
|
+
常见:**`ANTHROPIC_*`**(shell 或 **`tools.claude.env`**)、**`TELEGRAM_BOT_TOKEN`**、**`OPEN_IM_WEB_PORT`**、**`OPEN_IM_WEB_HOST`**,以及各平台的 `*_APP_ID`、`*_SECRET`、`WORKBUDDY_*` 等。
|
|
150
126
|
|
|
151
127
|
### 隐私
|
|
152
128
|
|
|
153
129
|
为改进稳定性,可能记录**匿名**运行信息(不含聊天或 prompt 内容)。若需关闭:环境变量 **`OPEN_IM_TELEMETRY=false`**,或 **`config.json`** 中 **`"telemetry": { "enabled": false }`**。
|
|
154
130
|
|
|
155
|
-
|
|
131
|
+
## 平台配置与故障排除
|
|
156
132
|
|
|
157
|
-
|
|
158
|
-
| --- | --- |
|
|
159
|
-
| Telegram | [@BotFather](https://t.me/BotFather) |
|
|
160
|
-
| 飞书 | [开放平台](https://open.feishu.cn/) |
|
|
161
|
-
| QQ | [QQ 开放平台](https://bot.q.qq.com/) |
|
|
162
|
-
| 钉钉 | 开放平台创建应用,机器人开 **Stream Mode**;可选 **`cardTemplateId`** 走 AI 助理卡片 |
|
|
163
|
-
| 企业微信 | [管理后台](https://work.weixin.qq.com/) |
|
|
164
|
-
| 微信 | **`open-im init`** → WorkBuddy OAuth |
|
|
165
|
-
|
|
166
|
-
## 故障排除
|
|
167
|
-
|
|
168
|
-
| 现象 | 处理 |
|
|
169
|
-
| --- | --- |
|
|
170
|
-
| Telegram / 网络 | 配置 `proxy` 或 **`TELEGRAM_PROXY`** |
|
|
171
|
-
| QQ | 核对 **`QQ_BOT_APPID`**、**`QQ_BOT_SECRET`**;重复回复请升级版本 |
|
|
172
|
-
| 飞书卡片 | 未配回调时用 **`/mode ask`** 或 **`/mode yolo`** |
|
|
173
|
-
| 企业微信 | 先给机器人发一条消息 |
|
|
174
|
-
| 钉钉 | 开启 Stream Mode;自定义机器人可能仅纯文本 |
|
|
175
|
-
| Codex 断流 | **`CODEX_PROXY`** 或 **`tools.codex.proxy`** |
|
|
176
|
-
| CodeBuddy 登录 | **`codebuddy login`** |
|
|
177
|
-
| WorkBuddy / 微信 | 重跑 **`open-im init`**(Token 会过期) |
|
|
133
|
+
详见 **[docs/platforms.zh-CN.md](./docs/platforms.zh-CN.md)**。
|
|
178
134
|
|
|
179
135
|
## License
|
|
180
136
|
|
|
@@ -9,11 +9,6 @@
|
|
|
9
9
|
* 认证:ANTHROPIC_API_KEY 或 CLAUDE_CODE_OAUTH_TOKEN
|
|
10
10
|
*/
|
|
11
11
|
import type { ToolAdapter, RunCallbacks, RunOptions, RunHandle } from './tool-adapter.interface.js';
|
|
12
|
-
/**
|
|
13
|
-
* 标记某个 workDir 下的用户显式执行了 /new,下次创建会话时跳过 auto-resume。
|
|
14
|
-
* 由命令处理器在 /new 时调用。
|
|
15
|
-
*/
|
|
16
|
-
export declare function markSkipAutoResume(workDir: string): void;
|
|
17
12
|
interface ClaudeSessionMeta {
|
|
18
13
|
sessionId: string;
|
|
19
14
|
mtime: number;
|
|
@@ -72,8 +72,9 @@ function workDirToProjectPath(workDir) {
|
|
|
72
72
|
function isCliSessionActive(sessionId, sessionFilePath) {
|
|
73
73
|
try {
|
|
74
74
|
// macOS/Linux: 用 ps 搜索包含该 sessionId 的 claude 进程
|
|
75
|
+
// 排除 open-im 自己的 SDK 子进程(路径含 claude-agent-sdk),只匹配用户交互式 CLI
|
|
75
76
|
// -F 固定字符串匹配,避免正则意外;-- 防止 sessionId 被误认为 flag
|
|
76
|
-
const result = execSync(`ps -axo pid,command 2>/dev/null | grep -v grep | grep "claude" | grep -F -- "${sessionId}" || true`, { encoding: 'utf-8', timeout: 3000 });
|
|
77
|
+
const result = execSync(`ps -axo pid,command 2>/dev/null | grep -v grep | grep "claude" | grep -v "claude-agent-sdk" | grep -F -- "${sessionId}" || true`, { encoding: 'utf-8', timeout: 3000 });
|
|
77
78
|
if (result.trim().length === 0)
|
|
78
79
|
return false;
|
|
79
80
|
// 进程存在,但可能只是 idle 在终端等输入。检查文件 mtime:
|
|
@@ -97,14 +98,6 @@ function isCliSessionActive(sessionId, sessionFilePath) {
|
|
|
97
98
|
return false;
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
|
-
/**
|
|
101
|
-
* 标记某个 workDir 下的用户显式执行了 /new,下次创建会话时跳过 auto-resume。
|
|
102
|
-
* 由命令处理器在 /new 时调用。
|
|
103
|
-
*/
|
|
104
|
-
export function markSkipAutoResume(workDir) {
|
|
105
|
-
skipAutoResumeFor.add(workDir);
|
|
106
|
-
log.info(`Marked skip auto-resume for workDir: ${workDir}`);
|
|
107
|
-
}
|
|
108
101
|
/**
|
|
109
102
|
* 扫描 ~/.claude/projects/<encoded-path>/ 找到最新的 CLI session。
|
|
110
103
|
* 只返回 JSONL 文件(排除子目录如 subagents/),按修改时间倒序。
|
|
@@ -187,9 +180,6 @@ function validateSessionFile(filePath, expectedSessionId) {
|
|
|
187
180
|
// 存储所有活跃的 SDKSession 对象,key 为 sessionId
|
|
188
181
|
// 使用 Map 而不是 Set,因为我们需要通过 sessionId 获取 session
|
|
189
182
|
const activeSessions = new Map();
|
|
190
|
-
// 用户显式执行 /new 后标记跳过 auto-resume,避免立即接回旧 CLI session
|
|
191
|
-
// key 格式: `${workDir}\0${sessionIdPrefix}`(用 workDir 区分不同项目目录)
|
|
192
|
-
const skipAutoResumeFor = new Set();
|
|
193
183
|
// 记录每个 session 创建/恢复时的 workDir,防止跨 workDir 复用已固定 cwd 的子进程
|
|
194
184
|
const sessionWorkDirs = new Map();
|
|
195
185
|
// 存储正在进行的流式迭代器,用于中断
|
|
@@ -390,39 +380,31 @@ async function getOrCreateSession(sessionId, workDir, model, permissionMode, onS
|
|
|
390
380
|
// 没有指定 sessionId 时,尝试自动恢复 Claude Code CLI 的最新 session
|
|
391
381
|
// 实现手机/电脑无缝切换:同目录下默认共享同一个对话
|
|
392
382
|
if (!sessionId) {
|
|
393
|
-
|
|
394
|
-
if (
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
log.info(`
|
|
383
|
+
const latest = findLatestClaudeSession(workDir);
|
|
384
|
+
if (latest) {
|
|
385
|
+
// 检测 CLI 是否正在使用该 session(用于日志,不阻止 resume)
|
|
386
|
+
const cliActive = isCliSessionActive(latest.sessionId, latest.filePath);
|
|
387
|
+
if (cliActive) {
|
|
388
|
+
log.info(`CLI is actively using session ${latest.sessionId}, attempting resume anyway (SDK handles concurrency)`);
|
|
389
|
+
}
|
|
390
|
+
// 验证文件内容一致性
|
|
391
|
+
if (validateSessionFile(latest.filePath, latest.sessionId)) {
|
|
392
|
+
try {
|
|
393
|
+
log.info(`Auto-resuming latest CLI session: ${latest.sessionId}${cliActive ? ' (CLI active)' : ''}`);
|
|
394
|
+
session = unstable_v2_resumeSession(latest.sessionId, sessionOptions);
|
|
395
|
+
activeSessions.set(latest.sessionId, session);
|
|
396
|
+
sessionWorkDirs.set(latest.sessionId, workDir);
|
|
397
|
+
sessionLastUsed.set(latest.sessionId, Date.now());
|
|
398
|
+
log.info(`Successfully auto-resumed CLI session: ${latest.sessionId}`);
|
|
399
|
+
return { session, sessionId: latest.sessionId };
|
|
404
400
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
if (validateSessionFile(latest.filePath, latest.sessionId)) {
|
|
408
|
-
try {
|
|
409
|
-
log.info(`Auto-resuming latest CLI session: ${latest.sessionId}`);
|
|
410
|
-
session = unstable_v2_resumeSession(latest.sessionId, sessionOptions);
|
|
411
|
-
activeSessions.set(latest.sessionId, session);
|
|
412
|
-
sessionWorkDirs.set(latest.sessionId, workDir);
|
|
413
|
-
sessionLastUsed.set(latest.sessionId, Date.now());
|
|
414
|
-
log.info(`Successfully auto-resumed CLI session: ${latest.sessionId}`);
|
|
415
|
-
return { session, sessionId: latest.sessionId };
|
|
416
|
-
}
|
|
417
|
-
catch (err) {
|
|
418
|
-
log.warn(`Failed to auto-resume CLI session ${latest.sessionId}, skipping auto-resume: ${err}`);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
log.warn(`Session file validation failed for ${latest.sessionId}, skipping`);
|
|
423
|
-
}
|
|
401
|
+
catch (err) {
|
|
402
|
+
log.warn(`Failed to auto-resume CLI session ${latest.sessionId}, creating new one: ${err}`);
|
|
424
403
|
}
|
|
425
404
|
}
|
|
405
|
+
else {
|
|
406
|
+
log.warn(`Session file validation failed for ${latest.sessionId}, skipping`);
|
|
407
|
+
}
|
|
426
408
|
}
|
|
427
409
|
}
|
|
428
410
|
// 创建新会话
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode Adapter — run tasks through OpenCode CLI (`opencode run`)
|
|
3
|
+
*/
|
|
4
|
+
import type { RunCallbacks, RunHandle, RunOptions, ToolAdapter } from './tool-adapter.interface.js';
|
|
5
|
+
export declare class OpenCodeAdapter implements ToolAdapter {
|
|
6
|
+
private cliPath;
|
|
7
|
+
readonly toolId = "opencode";
|
|
8
|
+
constructor(cliPath: string);
|
|
9
|
+
run(prompt: string, sessionId: string | undefined, workDir: string, callbacks: RunCallbacks, options?: RunOptions): RunHandle;
|
|
10
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode Adapter — run tasks through OpenCode CLI (`opencode run`)
|
|
3
|
+
*/
|
|
4
|
+
import { runOpenCode } from '../opencode/cli-runner.js';
|
|
5
|
+
export class OpenCodeAdapter {
|
|
6
|
+
cliPath;
|
|
7
|
+
toolId = 'opencode';
|
|
8
|
+
constructor(cliPath) {
|
|
9
|
+
this.cliPath = cliPath;
|
|
10
|
+
}
|
|
11
|
+
run(prompt, sessionId, workDir, callbacks, options) {
|
|
12
|
+
return runOpenCode(this.cliPath, prompt, sessionId, workDir, {
|
|
13
|
+
onText: callbacks.onText,
|
|
14
|
+
onThinking: callbacks.onThinking,
|
|
15
|
+
onToolUse: callbacks.onToolUse,
|
|
16
|
+
onComplete: (raw) => {
|
|
17
|
+
const result = {
|
|
18
|
+
success: raw.success,
|
|
19
|
+
result: raw.result,
|
|
20
|
+
accumulated: raw.accumulated,
|
|
21
|
+
cost: raw.cost,
|
|
22
|
+
durationMs: raw.durationMs,
|
|
23
|
+
model: raw.model,
|
|
24
|
+
numTurns: raw.numTurns,
|
|
25
|
+
toolStats: raw.toolStats,
|
|
26
|
+
};
|
|
27
|
+
callbacks.onComplete(result);
|
|
28
|
+
},
|
|
29
|
+
onError: (err) => {
|
|
30
|
+
const msg = typeof err === 'string' ? err : String(err);
|
|
31
|
+
const friendly = msg.includes('session not found') ||
|
|
32
|
+
msg.includes('Session not found') ||
|
|
33
|
+
msg.includes('no sessions found')
|
|
34
|
+
? 'OpenCode 会话已失效,旧 session 已清理。请直接重试当前请求。'
|
|
35
|
+
: msg;
|
|
36
|
+
callbacks.onError(friendly);
|
|
37
|
+
},
|
|
38
|
+
onSessionId: callbacks.onSessionId,
|
|
39
|
+
onSessionInvalid: callbacks.onSessionInvalid,
|
|
40
|
+
}, {
|
|
41
|
+
skipPermissions: options?.skipPermissions,
|
|
42
|
+
model: options?.model,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -2,6 +2,7 @@ import { getConfiguredAiCommands } from '../config.js';
|
|
|
2
2
|
import { ClaudeSDKAdapter, configureClaudeSdkSessionIdle } from './claude-sdk-adapter.js';
|
|
3
3
|
import { CodexAdapter } from './codex-adapter.js';
|
|
4
4
|
import { CodeBuddyAdapter } from './codebuddy-adapter.js';
|
|
5
|
+
import { OpenCodeAdapter } from './opencode-adapter.js';
|
|
5
6
|
import { createLogger } from '../logger.js';
|
|
6
7
|
import { destroyAllLiveChildren } from '../shared/process-kill.js';
|
|
7
8
|
const log = createLogger('Registry');
|
|
@@ -24,6 +25,10 @@ export function initAdapters(config) {
|
|
|
24
25
|
log.info('CodeBuddy CLI adapter enabled');
|
|
25
26
|
adapters.set('codebuddy', new CodeBuddyAdapter(config.codebuddyCliPath));
|
|
26
27
|
}
|
|
28
|
+
if (aiCommand === 'opencode') {
|
|
29
|
+
log.info('OpenCode CLI adapter enabled');
|
|
30
|
+
adapters.set('opencode', new OpenCodeAdapter(config.opencodeCliPath));
|
|
31
|
+
}
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
export function getAdapter(aiCommand) {
|
|
@@ -5,6 +5,7 @@ const PLATFORM_LABELS = {
|
|
|
5
5
|
wework: "企业微信",
|
|
6
6
|
dingtalk: "钉钉",
|
|
7
7
|
workbuddy: "WorkBuddy",
|
|
8
|
+
clawbot: "ClawBot",
|
|
8
9
|
};
|
|
9
10
|
export const CHANNEL_CAPABILITIES = {
|
|
10
11
|
telegram: {
|
|
@@ -31,6 +32,10 @@ export const CHANNEL_CAPABILITIES = {
|
|
|
31
32
|
inbound: { text: "native", image: "none", file: "none", voice: "none", video: "none" },
|
|
32
33
|
outbound: { streamEdit: "none", streamPush: "none", image: "none", card: "none", typing: "none" },
|
|
33
34
|
},
|
|
35
|
+
clawbot: {
|
|
36
|
+
inbound: { text: "native", image: "none", file: "none", voice: "none", video: "none" },
|
|
37
|
+
outbound: { streamEdit: "none", streamPush: "none", image: "none", card: "none", typing: "none" },
|
|
38
|
+
},
|
|
34
39
|
};
|
|
35
40
|
function listPreferredPlatforms(kind) {
|
|
36
41
|
return Object.entries(CHANNEL_CAPABILITIES)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClawBot Client - WeChat iLink Bot API long-polling client
|
|
3
|
+
*
|
|
4
|
+
* Uses the official iLink protocol: POST + JSON body + Bearer token auth.
|
|
5
|
+
* Receives messages via long-polling ilink/bot/getupdates and dispatches
|
|
6
|
+
* them to the event handler.
|
|
7
|
+
*
|
|
8
|
+
* Reference: @tencent-weixin/openclaw-weixin, cc-wechat, claude-code-wechat-channel
|
|
9
|
+
*/
|
|
10
|
+
import type { Config } from '../config.js';
|
|
11
|
+
import type { ClawBotState } from './types.js';
|
|
12
|
+
export declare function getChannelState(): ClawBotState;
|
|
13
|
+
export declare function initClawbot(config: Config, eventHandler: (chatId: string, msgId: string, content: string) => Promise<void>, onStateChange?: (state: ClawBotState) => void): Promise<void>;
|
|
14
|
+
export declare function stopClawbot(): void;
|