chatccc 0.2.16 → 0.2.18
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 +105 -111
- package/bin/chatccc.mjs +2 -14
- package/config.sample.json +26 -0
- package/images/avatars/status_busy.png +0 -0
- package/images/avatars/status_idle.png +0 -0
- package/images/avatars/status_new.png +0 -0
- package/images/img_readme_0.jpg +0 -0
- package/images/img_readme_1.jpg +0 -0
- package/images/img_readme_callback.png +0 -0
- package/images/img_readme_event.png +0 -0
- package/images/img_readme_permission.png +0 -0
- package/package.json +13 -12
- package/src/__tests__/cards.test.ts +3 -3
- package/src/__tests__/claude-adapter.test.ts +301 -10
- package/src/__tests__/config-reload.test.ts +171 -0
- package/src/__tests__/config.test.ts +259 -2
- package/src/__tests__/crash-logging.test.ts +210 -0
- package/src/__tests__/session.test.ts +2 -2
- package/src/__tests__/web-ui.test.ts +178 -0
- package/src/adapters/claude-adapter.ts +57 -8
- package/src/adapters/codex-adapter.ts +294 -293
- package/src/adapters/cursor-adapter.ts +1 -1
- package/src/config-utils.ts +177 -0
- package/src/config.ts +412 -178
- package/src/exit-banner.ts +12 -2
- package/src/feishu-api.ts +4 -15
- package/src/index.ts +178 -64
- package/src/session.ts +27 -12
- package/src/shared.ts +189 -16
- package/src/web-ui.ts +1591 -0
- package/.env.example +0 -44
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ ChatCCC 把 Claude Code、Cursor Agent、Codex (OpenAI) 接入了飞书群聊:
|
|
|
27
27
|
## 为什么选 ChatCCC
|
|
28
28
|
|
|
29
29
|
- **一群一会话,心智最简单** —— `/new` 直接建一个新飞书群,群本身就是 AI 会话上下文。换会话就是换群,没有 thread / 子话题概念,手机端切换最直观
|
|
30
|
-
- **零配置成本** ——
|
|
30
|
+
- **零配置成本** —— 单一 `config.json`,没有 TOML 也没有零散环境变量。`npm i -g chatccc` 后**任意目录**直接 `chatccc` 就跑,首次启动自动弹出本地 Web 配置向导
|
|
31
31
|
- **群里能跑 git** —— `/git status`、`/git pull`、`/git log` 在飞书群里直接执行 stdout/stderr 回发,不用回电脑
|
|
32
32
|
- **代码极简易改** —— 纯 TypeScript 实现,核心只有 20 多个文件,统一 `ToolAdapter` 接口屏蔽 Claude / Cursor / Codex 差异,看得懂、改得动
|
|
33
33
|
|
|
@@ -43,21 +43,17 @@ ChatCCC 把 Claude Code、Cursor Agent、Codex (OpenAI) 接入了飞书群聊:
|
|
|
43
43
|
npm install -g chatccc
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
要求 Node.js >= 20
|
|
46
|
+
要求 Node.js >= 20。安装完成后,**在任意目录**直接启动即可:
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
cd /path/to/your/project # Windows 示例: cd D:\code\ChatCCC
|
|
50
49
|
chatccc
|
|
51
50
|
```
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
> ChatCCC 的所有数据(`config.json`、`logs/`、`state/`)都保存在 npm 包安装目录下,与你当前终端所在目录无关。**不需要先 `cd` 到任何特定目录。**
|
|
54
53
|
|
|
55
|
-
|
|
54
|
+
首次启动时若 `config.json` 还没有有效凭证,会自动起一个本地 Web 配置向导(默认 `http://127.0.0.1:18080`),用浏览器把飞书 App ID / App Secret 等填进去,保存即开始运行。
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
cd /path/to/your/project
|
|
59
|
-
npx tsx --env-file=.env src/index.ts
|
|
60
|
-
```
|
|
56
|
+
> 已在运行的实例,启动完成后控制台底部 banner 也会打印「配置面板」地址,随时可以打开浏览器查看状态、修改配置(多数改动无需重启即可生效)。停止 / 重启请通过页面顶部按钮或终端 `Ctrl+C`,**面板上不再提供"启动"按钮**——服务停止后页面随进程退出,需要回到终端重新执行 `chatccc`。
|
|
61
57
|
|
|
62
58
|
#### 从源码安装
|
|
63
59
|
|
|
@@ -68,7 +64,7 @@ npm install
|
|
|
68
64
|
npm run dev
|
|
69
65
|
```
|
|
70
66
|
|
|
71
|
-
启动后机器人通过 WebSocket
|
|
67
|
+
启动后机器人通过 WebSocket 连接飞书服务器,日志会写入仓库根目录下的 `logs/`。
|
|
72
68
|
|
|
73
69
|
#### Cursor Agent CLI(使用 Cursor 会话时需要)
|
|
74
70
|
|
|
@@ -102,19 +98,25 @@ agent --version
|
|
|
102
98
|
cursor-agent --version
|
|
103
99
|
```
|
|
104
100
|
|
|
105
|
-
ChatCCC
|
|
101
|
+
ChatCCC 启动时会按以下顺序确定 Cursor Agent CLI:
|
|
106
102
|
|
|
107
|
-
1.
|
|
103
|
+
1. `config.json` 中的 `cursor.path` 指定的路径(若已配置)
|
|
108
104
|
2. Windows 上 Cursor IDE 默认安装位置 `%LOCALAPPDATA%\cursor-agent\agent.cmd`(自动识别)
|
|
109
105
|
3. PATH 中的 `agent` 命令
|
|
110
106
|
|
|
111
|
-
|
|
107
|
+
> 首次启动 ChatCCC 时,如果 `config.json` 不存在,会从 `config.sample.json` 复制一份并**立即探测一次** Cursor / Codex CLI 的绝对路径,命中就写入 `cursor.path` / `codex.path`,无须手动编辑。
|
|
112
108
|
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
若想强制使用某个非默认的可执行文件(例如 `cursor-agent` 而不是 `agent`),可在 `config.json` 中显式指定:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"cursor": {
|
|
114
|
+
"path": "/path/to/agent"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
115
117
|
```
|
|
116
118
|
|
|
117
|
-
>
|
|
119
|
+
> 旧版字段 `cursor.command` 仍可读取(启动时会打印一次 warning 提示改名),新配置请统一使用 `cursor.path`。
|
|
118
120
|
|
|
119
121
|
> **说明**:只使用 Claude Code(`/new claude` 或 `/new`)的用户无需安装 Cursor CLI。
|
|
120
122
|
|
|
@@ -138,21 +140,23 @@ codex login
|
|
|
138
140
|
codex --version
|
|
139
141
|
```
|
|
140
142
|
|
|
141
|
-
Codex 会话的模型和努力程度由 `config.toml`(`~/.codex/config.toml
|
|
142
|
-
|
|
143
|
-
```env
|
|
144
|
-
# 不设置或设为 default 时由 codex config.toml 决定
|
|
145
|
-
CHATCCC_CODEX_MODEL=default
|
|
143
|
+
Codex 会话的模型和努力程度由 `config.toml`(`~/.codex/config.toml`)决定,也可在 `config.json` 中显式覆盖:
|
|
146
144
|
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"codex": {
|
|
148
|
+
"path": "",
|
|
149
|
+
"model": "",
|
|
150
|
+
"effort": ""
|
|
151
|
+
}
|
|
152
|
+
}
|
|
149
153
|
```
|
|
150
154
|
|
|
151
|
-
|
|
155
|
+
- `codex.path`:留空时直接调用 PATH 中的 `codex`;可填绝对路径指向自定义可执行文件(首次创建 `config.json` 时会自动探测并填入)
|
|
156
|
+
- `codex.model`:留空时由 `~/.codex/config.toml` 决定
|
|
157
|
+
- `codex.effort`:留空时由 `~/.codex/config.toml` 决定(通过 `-c model_reasoning_effort` 传递)
|
|
152
158
|
|
|
153
|
-
|
|
154
|
-
CHATCCC_CODEX_COMMAND=/path/to/codex
|
|
155
|
-
```
|
|
159
|
+
> 旧版字段 `codex.command` 仍可读取(启动时会打印一次 warning 提示改名),新配置请统一使用 `codex.path`。
|
|
156
160
|
|
|
157
161
|
> **说明**:只使用 Claude Code 或 Cursor 的用户无需安装 Codex CLI。
|
|
158
162
|
|
|
@@ -162,7 +166,7 @@ CHATCCC_CODEX_COMMAND=/path/to/codex
|
|
|
162
166
|
|
|
163
167
|
> **第一步:添加机器人(千万别忘!)**
|
|
164
168
|
>
|
|
165
|
-
>
|
|
169
|
+
> 创建应用后,立刻在「应用功能」中开启「机器人」能力。没有机器人,就根本找不到哪里和这个机器人对话,整个 ChatCCC 无法工作。
|
|
166
170
|
|
|
167
171
|
**权限配置(重要)**(在「权限管理」中按前缀搜索,**将以下两类前缀开头的权限全部开通**):
|
|
168
172
|
|
|
@@ -191,103 +195,93 @@ CHATCCC_CODEX_COMMAND=/path/to/codex
|
|
|
191
195
|
|
|
192
196
|
在飞书应用详情页的「凭证与基础信息」中,复制 **App ID** 和 **App Secret**。
|
|
193
197
|
|
|
194
|
-
### 4.
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
# Codex 会话使用的模型;不设置或设为 default 时由 codex config.toml 决定
|
|
234
|
-
CHATCCC_CODEX_MODEL=default
|
|
235
|
-
|
|
236
|
-
# Codex 会话的努力程度(low/medium/high);不设置或设为 default 时由 codex config.toml 决定
|
|
237
|
-
CHATCCC_CODEX_EFFORT=default
|
|
238
|
-
|
|
239
|
-
# 也可指定自定义 Codex 可执行文件路径
|
|
240
|
-
# CHATCCC_CODEX_COMMAND=/path/to/codex
|
|
198
|
+
### 4. 配置 `config.json`
|
|
199
|
+
|
|
200
|
+
ChatCCC 的所有运行参数都集中在包根目录的 `config.json`。
|
|
201
|
+
|
|
202
|
+
#### 推荐:用 Web 配置向导(首次启动自动弹出)
|
|
203
|
+
|
|
204
|
+
第一次运行 `chatccc` 时,如果 `config.json` 还没有有效凭证,会自动起一个本地 Web 服务(默认 `http://127.0.0.1:18080`)。在浏览器里把上一步拿到的 **App ID** / **App Secret** 等填进去,保存即写入 `config.json`,进程立即继续启动飞书 WebSocket。
|
|
205
|
+
|
|
206
|
+
#### 备选:手动编辑 `config.json`
|
|
207
|
+
|
|
208
|
+
`config.json` 不存在时,ChatCCC 会从 `config.sample.json` 复制一份,结构如下:
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"feishu": {
|
|
213
|
+
"appId": "cli_xxxxxxxxxxxx",
|
|
214
|
+
"appSecret": "xxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
215
|
+
},
|
|
216
|
+
"port": 18080,
|
|
217
|
+
"gitTimeoutSeconds": 180,
|
|
218
|
+
"claude": {
|
|
219
|
+
"enabled": false,
|
|
220
|
+
"model": "",
|
|
221
|
+
"effort": "",
|
|
222
|
+
"apiKey": "",
|
|
223
|
+
"baseUrl": ""
|
|
224
|
+
},
|
|
225
|
+
"cursor": {
|
|
226
|
+
"enabled": false,
|
|
227
|
+
"path": "",
|
|
228
|
+
"model": ""
|
|
229
|
+
},
|
|
230
|
+
"codex": {
|
|
231
|
+
"enabled": false,
|
|
232
|
+
"path": "",
|
|
233
|
+
"model": "",
|
|
234
|
+
"effort": ""
|
|
235
|
+
}
|
|
236
|
+
}
|
|
241
237
|
```
|
|
242
238
|
|
|
243
|
-
|
|
239
|
+
各字段含义:
|
|
244
240
|
|
|
245
|
-
|
|
241
|
+
| 字段 | 必填 | 说明 |
|
|
242
|
+
| --- | --- | --- |
|
|
243
|
+
| `feishu.appId` / `feishu.appSecret` | 是 | 飞书应用「凭证与基础信息」中的 App ID / App Secret |
|
|
244
|
+
| `port` | 否 | 本地 WebSocket 中继 + Web 向导监听端口,默认 `18080`;同机多实例时改成不同值即可 |
|
|
245
|
+
| `gitTimeoutSeconds` | 否 | `/git` 命令在会话工作目录执行时的单次超时秒数,默认 `180`,允许范围 `1–3600`,超时会被 `SIGKILL` 强制终止 |
|
|
246
|
+
| `claude.enabled` / `cursor.enabled` / `codex.enabled` | 否 | 是否启用对应 AI Agent;Web 向导/管理页只展示 `enabled: true` 的 agent 卡片。字段缺省时按「任一配置字段非空」自动判定(向后兼容) |
|
|
247
|
+
| `claude.model` | 否 | Claude Code 会话使用的模型;留空(`""` / 全空白)→ 不向 SDK 传 `model`,由 SDK / 服务商默认决定 |
|
|
248
|
+
| `claude.effort` | 否 | Claude 思考深度(如 `low` / `medium` / `high` / `max`);留空 → 不向 SDK 传 `effort` |
|
|
249
|
+
| `claude.apiKey` | 否 | 第三方 Anthropic 兼容网关的 API 密钥;**官方 Claude 用户保持 `""` 即可**,详见下文「第三方 API」一节 |
|
|
250
|
+
| `claude.baseUrl` | 否 | 第三方 Anthropic 兼容网关的 base URL(例如 `https://api.deepseek.com/anthropic`);**官方 Claude 用户保持 `""` 即可** |
|
|
251
|
+
| `cursor.model` | 否 | Cursor 会话使用的模型 ID(如 `claude-opus-4-7-max`);留空时不传 `--model`,可用 `agent --list-models` 查看支持的模型 |
|
|
252
|
+
| `codex.model` | 否 | Codex 会话使用的模型;留空时由 `~/.codex/config.toml` 决定 |
|
|
253
|
+
| `codex.effort` | 否 | Codex 努力程度(`low` / `medium` / `high`);留空时由 `~/.codex/config.toml` 决定 |
|
|
246
254
|
|
|
247
|
-
|
|
255
|
+
> `claude.model` / `claude.effort` 的旧值 `"default"` 仍兼容,启动时会按留空处理并打印一次 warning,请尽快改成 `""`。
|
|
248
256
|
|
|
249
|
-
`
|
|
257
|
+
> `cursor.path` / `codex.path` 由首次启动时的自动探测填入,一般无需手动修改。
|
|
250
258
|
|
|
251
|
-
|
|
259
|
+
#### 第三方 API(如 DeepSeek):填 `claude.apiKey` 与 `claude.baseUrl`
|
|
252
260
|
|
|
253
|
-
|
|
254
|
-
| ------ | ---- |
|
|
255
|
-
| `ANTHROPIC_API_KEY` | 在服务商控制台获取的 **API 密钥**,填入本环境变量。Anthropic 兼容网关普遍使用该名称;若服务商文档要求使用其它环境变量名,以文档为准。 |
|
|
256
|
-
| `ANTHROPIC_BASE_URL` | 兼容 Anthropic API 的 base URL,例如 DeepSeek:`https://api.deepseek.com/anthropic` |
|
|
261
|
+
若你通过 **Anthropic 兼容网关**(例如 DeepSeek 的 `/anthropic` 端点)调用模型,需要把网关凭证填到 `config.json` 的 `claude.apiKey` 与 `claude.baseUrl`。**官方 Claude 用户**(本机已通过 `claude` CLI 完成 OAuth 登录)保持这两项 `""` 即可,无需任何额外配置。
|
|
257
262
|
|
|
258
|
-
|
|
263
|
+
两条等价的填写路径:
|
|
259
264
|
|
|
260
|
-
|
|
265
|
+
**1. Web 配置向导(推荐)**
|
|
261
266
|
|
|
262
|
-
|
|
267
|
+
打开 `http://127.0.0.1:18080`(首次启动自动弹出,已在运行的实例也可手动访问),在「Claude Agent」一节顶部把「API 来源」从 **官方 API(Anthropic 直连)** 切换到 **第三方 API(自定义网关)**——切换后会出现 API Key / Base URL 两个输入框,填进去保存即可。**切回官方模式后保存,已填的密钥会被自动清空**,不会残留在 `config.json` 中。
|
|
263
268
|
|
|
264
|
-
|
|
265
|
-
[Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", "https://api.deepseek.com/anthropic", "User")
|
|
266
|
-
[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "你的_API_密钥", "User")
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
也可在 **系统属性 → 环境变量** 中手动添加。Linux / macOS 可将 `export` 写入 `~/.bashrc`、`~/.zshrc` 等,或使用 systemd、`launchctl` 等按你的部署方式注入。
|
|
270
|
-
|
|
271
|
-
> **说明**:项目根目录的 `.env` 若通过 `tsx --env-file=.env` 加载,其中的变量会进入 Node 进程环境,**多数情况下**会随进程继承给 SDK 子进程;但各家网关与 Claude Code 版本组合较多,**仍推荐**将 **`ANTHROPIC_API_KEY`** 与 **`ANTHROPIC_BASE_URL`** 放在系统/用户环境变量中,与 `settings.json` 形成双保险,避免仅依赖 `.claude/settings.json` 时在 SDK 场景下踩坑。
|
|
269
|
+
**2. 直接编辑 `config.json`**
|
|
272
270
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"claude": {
|
|
274
|
+
"model": "",
|
|
275
|
+
"effort": "",
|
|
276
|
+
"apiKey": "你的_API_密钥",
|
|
277
|
+
"baseUrl": "https://api.deepseek.com/anthropic"
|
|
278
|
+
}
|
|
279
|
+
}
|
|
281
280
|
```
|
|
282
281
|
|
|
283
|
-
|
|
282
|
+
> ChatCCC 不会把这两个值写入主进程的环境变量;它们仅在调用 Claude Agent SDK 时被注入到 SDK 拉起的子进程,跟主进程 env 完全隔离。两项留空 / 缺失时,子进程沿用主进程默认的鉴权行为(即官方 Claude 的 OAuth)。
|
|
284
283
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
```env
|
|
288
|
-
# 调高到 600 秒,适合 git fsck、git gc 等耗时操作
|
|
289
|
-
CHATCCC_GIT_TIMEOUT_SECONDS=600
|
|
290
|
-
```
|
|
284
|
+
> 所有运行参数(端口、`/git` 超时、各 AI 工具模型 / 路径等)都在第 4 节展示的 `config.json` 里配置,不再使用 `CHATCCC_*` 环境变量。多实例共存只需在每个实例的 `config.json` 里把 `port` 设为不同值即可(例如 `18080` / `18081`),ChatCCC 启动时会自动清理各自端口上的旧进程。
|
|
291
285
|
|
|
292
286
|
> **权限说明**:目前 ChatCCC 以 `bypassPermissions` 模式运行,即跳过所有权限确认、允许所有操作。后续会考虑引入细粒度权限控制,让你可以按需放行特定操作。
|
|
293
287
|
|
|
@@ -311,7 +305,7 @@ CHATCCC_GIT_TIMEOUT_SECONDS=600
|
|
|
311
305
|
| `/cd` | 查看/切换工作目录 |
|
|
312
306
|
| `/sessions` | 查看所有会话状态 |
|
|
313
307
|
| `/forget` | 重置当前会话(创建新 Session,保留工作目录,同一群内继续) |
|
|
314
|
-
| `/git <子命令>` | 在**当前会话工作目录**执行 `git ...` 并把 stdout/stderr 回发到群里(仅会话群内可用,超时见 `
|
|
308
|
+
| `/git <子命令>` | 在**当前会话工作目录**执行 `git ...` 并把 stdout/stderr 回发到群里(仅会话群内可用,超时见 `config.json` 的 `gitTimeoutSeconds` 字段) |
|
|
315
309
|
| `/restart` | 重启机器人进程 |
|
|
316
310
|
|
|
317
311
|
|
package/bin/chatccc.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
4
3
|
import { createRequire } from "node:module";
|
|
5
4
|
import { dirname, join } from "node:path";
|
|
6
5
|
|
|
@@ -10,18 +9,7 @@ const pkgRoot = dirname(require.resolve("../package.json"));
|
|
|
10
9
|
const indexTs = join(pkgRoot, "src", "index.ts");
|
|
11
10
|
const tsxCli = require.resolve("tsx/cli");
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
const envFile = join(process.cwd(), ".env");
|
|
15
|
-
if (!existsSync(envFile)) {
|
|
16
|
-
console.error(`[chatccc] 当前目录下未找到 .env,不会自动加载环境变量: ${envFile}`);
|
|
17
|
-
console.error(" 将只使用系统/用户环境变量。若未设置 CHATCCC_APP_ID / CHATCCC_APP_SECRET,启动会失败。");
|
|
18
|
-
console.error(" 建议: cd 到项目根目录,复制 .env.example 为 .env 并填写后再运行 chatccc。\n");
|
|
19
|
-
}
|
|
20
|
-
const tsxArgs = existsSync(envFile)
|
|
21
|
-
? [tsxCli, "--env-file", envFile, indexTs, ...process.argv.slice(2)]
|
|
22
|
-
: [tsxCli, indexTs, ...process.argv.slice(2)];
|
|
23
|
-
|
|
24
|
-
const result = spawnSync(process.execPath, tsxArgs, {
|
|
12
|
+
const result = spawnSync(process.execPath, [tsxCli, indexTs, ...process.argv.slice(2)], {
|
|
25
13
|
stdio: "inherit",
|
|
26
14
|
cwd: process.cwd(),
|
|
27
15
|
env: process.env,
|
|
@@ -33,4 +21,4 @@ if (code !== 0) {
|
|
|
33
21
|
console.error("chatccc 子进程已结束,服务没有在后台运行。");
|
|
34
22
|
}
|
|
35
23
|
|
|
36
|
-
process.exit(code);
|
|
24
|
+
process.exit(code);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"feishu": {
|
|
3
|
+
"appId": "",
|
|
4
|
+
"appSecret": ""
|
|
5
|
+
},
|
|
6
|
+
"port": 18080,
|
|
7
|
+
"gitTimeoutSeconds": 180,
|
|
8
|
+
"claude": {
|
|
9
|
+
"enabled": false,
|
|
10
|
+
"model": "",
|
|
11
|
+
"effort": "",
|
|
12
|
+
"apiKey": "",
|
|
13
|
+
"baseUrl": ""
|
|
14
|
+
},
|
|
15
|
+
"cursor": {
|
|
16
|
+
"enabled": false,
|
|
17
|
+
"path": "",
|
|
18
|
+
"model": ""
|
|
19
|
+
},
|
|
20
|
+
"codex": {
|
|
21
|
+
"enabled": false,
|
|
22
|
+
"path": "",
|
|
23
|
+
"model": "",
|
|
24
|
+
"effort": ""
|
|
25
|
+
}
|
|
26
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chatccc",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.18",
|
|
4
4
|
"description": "Feishu bot bridge for Claude Code",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -11,21 +11,22 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"src/",
|
|
13
13
|
"bin/",
|
|
14
|
+
"images/",
|
|
14
15
|
"package.json",
|
|
15
16
|
"README.md",
|
|
16
|
-
".
|
|
17
|
+
"config.sample.json"
|
|
17
18
|
],
|
|
18
19
|
"scripts": {
|
|
19
|
-
"dev": "tsx
|
|
20
|
-
"chatccc": "tsx
|
|
21
|
-
"start": "tsx
|
|
22
|
-
"demo:bot-test": "tsx
|
|
23
|
-
"demo:bot-test:local": "tsx
|
|
24
|
-
"demo:create-group": "tsx
|
|
25
|
-
"demo:create-group:local": "tsx
|
|
26
|
-
"demo:permission-check": "tsx
|
|
27
|
-
"demo:claude-hi": "tsx
|
|
28
|
-
"demo:codex-hi": "tsx
|
|
20
|
+
"dev": "tsx src/index.ts",
|
|
21
|
+
"chatccc": "tsx src/index.ts",
|
|
22
|
+
"start": "tsx src/index.ts",
|
|
23
|
+
"demo:bot-test": "tsx demo/bot_test.ts",
|
|
24
|
+
"demo:bot-test:local": "tsx demo/bot_test.ts --local",
|
|
25
|
+
"demo:create-group": "tsx src/index.ts",
|
|
26
|
+
"demo:create-group:local": "tsx src/index.ts --local",
|
|
27
|
+
"demo:permission-check": "tsx demo/permission_check.ts",
|
|
28
|
+
"demo:claude-hi": "tsx demo/claude_say_hi.ts",
|
|
29
|
+
"demo:codex-hi": "tsx demo/codex_say_hi.ts",
|
|
29
30
|
"test": "vitest run",
|
|
30
31
|
"test:watch": "vitest"
|
|
31
32
|
},
|
|
@@ -338,8 +338,8 @@ describe("buildSessionsCard", () => {
|
|
|
338
338
|
|
|
339
339
|
it("separates Claude Code and Cursor sessions", () => {
|
|
340
340
|
const card = buildSessionsCard([
|
|
341
|
-
{ sessionId: "c1", active: false, turnCount: 1, elapsedSeconds: null, model: "
|
|
342
|
-
{ sessionId: "c2", active: false, turnCount: 2, elapsedSeconds: null, model: "
|
|
341
|
+
{ sessionId: "c1", active: false, turnCount: 1, elapsedSeconds: null, model: "(留空)", tool: "claude" },
|
|
342
|
+
{ sessionId: "c2", active: false, turnCount: 2, elapsedSeconds: null, model: "claude-opus-4-7-max", tool: "cursor" },
|
|
343
343
|
]);
|
|
344
344
|
const parsed = JSON.parse(card);
|
|
345
345
|
const content: string = parsed.elements[0].text.content;
|
|
@@ -349,7 +349,7 @@ describe("buildSessionsCard", () => {
|
|
|
349
349
|
|
|
350
350
|
it("omits Cursor section when no Cursor sessions", () => {
|
|
351
351
|
const card = buildSessionsCard([
|
|
352
|
-
{ sessionId: "c1", active: false, turnCount: 1, elapsedSeconds: null, model: "
|
|
352
|
+
{ sessionId: "c1", active: false, turnCount: 1, elapsedSeconds: null, model: "(留空)", tool: "claude" },
|
|
353
353
|
]);
|
|
354
354
|
const parsed = JSON.parse(card);
|
|
355
355
|
const content: string = parsed.elements[0].text.content;
|