chatccc 0.2.200 → 0.2.202
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 +17 -15
- package/agent-prompts/claude_specific.md +45 -45
- package/agent-prompts/codex_specific.md +2 -2
- package/agent-prompts/cursor_specific.md +13 -13
- package/bin/cccagent.mjs +17 -17
- package/config.sample.json +27 -27
- package/im-skills/feishu-skill/receive-send-file.md +63 -63
- package/im-skills/feishu-skill/receive-send-image.md +24 -24
- package/im-skills/feishu-skill/skill.md +3 -3
- package/im-skills/wechat-file-skill/receive-send-file.md +38 -38
- package/im-skills/wechat-file-skill/send-file.mjs +83 -83
- package/im-skills/wechat-file-skill/skill.md +10 -10
- package/im-skills/wechat-image-skill/skill.md +10 -10
- package/im-skills/wechat-video-skill/receive-send-video.md +38 -38
- package/im-skills/wechat-video-skill/send-video.mjs +79 -79
- package/im-skills/wechat-video-skill/skill.md +10 -10
- package/package.json +1 -1
- package/scripts/postinstall-sharp-check.mjs +58 -58
- package/src/__tests__/agent-delegate-task-rpc.test.ts +165 -165
- package/src/__tests__/agent-reload-config-rpc.test.ts +99 -99
- package/src/__tests__/builtin-chat-session.test.ts +277 -277
- package/src/__tests__/builtin-cli-json.test.ts +39 -39
- package/src/__tests__/builtin-config.test.ts +33 -33
- package/src/__tests__/builtin-context.test.ts +163 -163
- package/src/__tests__/builtin-file-tools.test.ts +224 -224
- package/src/__tests__/builtin-session-select.test.ts +116 -116
- package/src/__tests__/builtin-sigint.test.ts +56 -56
- package/src/__tests__/card-plain-text.test.ts +5 -5
- package/src/__tests__/cardkit.test.ts +60 -60
- package/src/__tests__/cards.test.ts +133 -122
- package/src/__tests__/ccc-adapter.test.ts +114 -114
- package/src/__tests__/chatgpt-subscription-rpc.test.ts +89 -89
- package/src/__tests__/chatgpt-subscription.test.ts +135 -135
- package/src/__tests__/chrome-devtools-guard.test.ts +165 -165
- package/src/__tests__/claude-adapter.test.ts +592 -592
- package/src/__tests__/claude-raw-stream-log.test.ts +87 -87
- package/src/__tests__/codex-raw-stream-log.test.ts +163 -163
- package/src/__tests__/codex-reset-actions.test.ts +146 -146
- package/src/__tests__/config-reload.test.ts +10 -10
- package/src/__tests__/config-sample.test.ts +18 -18
- package/src/__tests__/cursor-adapter.test.ts +226 -226
- package/src/__tests__/feishu-api.test.ts +60 -60
- package/src/__tests__/feishu-avatar.test.ts +90 -90
- package/src/__tests__/feishu-platform.test.ts +22 -22
- package/src/__tests__/format-message.test.ts +47 -47
- package/src/__tests__/jsonl-stream.test.ts +79 -79
- package/src/__tests__/orchestrator.test.ts +464 -301
- package/src/__tests__/privacy.test.ts +198 -198
- package/src/__tests__/raw-stream-log.test.ts +106 -106
- package/src/__tests__/session.test.ts +46 -44
- package/src/__tests__/shared-prefix.test.ts +36 -36
- package/src/__tests__/sim-platform.test.ts +12 -12
- package/src/__tests__/stream-state.test.ts +42 -42
- package/src/__tests__/web-ui.test.ts +209 -209
- package/src/adapters/ccc-adapter.ts +121 -121
- package/src/adapters/claude-adapter.ts +603 -603
- package/src/adapters/claude-session-meta-store.ts +120 -120
- package/src/adapters/codex-adapter.ts +380 -380
- package/src/adapters/cursor-adapter.ts +673 -673
- package/src/adapters/jsonl-stream.ts +157 -157
- package/src/adapters/raw-stream-log.ts +124 -124
- package/src/adapters/resource-monitor.ts +140 -140
- package/src/agent-delegate-task-rpc.ts +153 -153
- package/src/agent-delegate-task.ts +81 -81
- package/src/agent-reload-config-rpc.ts +34 -34
- package/src/agent-stop-stuck.ts +129 -129
- package/src/builtin/cli.ts +473 -473
- package/src/builtin/context.ts +323 -323
- package/src/builtin/file-tools.ts +1072 -1072
- package/src/builtin/index.ts +404 -404
- package/src/builtin/session-select.ts +48 -48
- package/src/builtin/sigint.ts +50 -50
- package/src/cards.ts +222 -210
- package/src/chatgpt-subscription-rpc.ts +27 -27
- package/src/chatgpt-subscription.ts +299 -299
- package/src/chrome-devtools-guard.ts +318 -318
- package/src/codex-reset-actions.ts +184 -184
- package/src/config.ts +125 -125
- package/src/feishu-api.ts +118 -118
- package/src/feishu-platform.ts +20 -20
- package/src/format-message.ts +293 -293
- package/src/litellm-proxy.ts +374 -374
- package/src/orchestrator.ts +348 -329
- package/src/privacy.ts +118 -118
- package/src/runtime-reload.ts +34 -34
- package/src/session-chat-binding.ts +6 -6
- package/src/session-name.ts +8 -8
- package/src/session.ts +177 -169
- package/src/shared-prefix.ts +29 -29
- package/src/sim-platform.ts +20 -20
- package/src/turn-cards.ts +117 -117
- package/src/web-ui.ts +205 -205
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
ChatCCC 把本地 AI 编程工具接入即时通讯软件。你可以在手机上发消息,让 Claude Code、Cursor Agent 或 Codex 继续写代码、查问题、跑命令;不用一直守在电脑前。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
飞书是推荐入口:直接私聊机器人即可持续使用同一个专属会话,需要并行任务时再用 `/new` 创建独立会话群;卡片能流式更新,体验完整。微信 iLink 更适合快速试用或临时使用:扫码即可接入,但只能走私聊文本模式。
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<img src="images/img_readme_messages.jpg" alt="飞书会话列表" width="220" align="top" />
|
|
@@ -19,7 +19,7 @@ ChatCCC 把本地 AI 编程工具接入即时通讯软件。你可以在手机
|
|
|
19
19
|
## 为什么用 ChatCCC
|
|
20
20
|
|
|
21
21
|
- **手机上也能用 AI 编程工具**:在飞书或微信发消息,就像在终端给 Agent 下指令。
|
|
22
|
-
-
|
|
22
|
+
- **飞书体验更完整**:私聊可持续对话,`/new` 创建的一群一会话支持多任务并行,CardKit 卡片可流式更新。
|
|
23
23
|
- **微信接入更轻**:不用创建飞书应用,启动后扫码即可在微信私聊里使用。
|
|
24
24
|
- **多 Agent 切换**:`/new` 使用默认 Agent,也可以用 `/new claude`、`/new cursor`、`/new codex` 指定工具。
|
|
25
25
|
- **群里能跑 git**:`/git status`、`/git pull`、`/git log` 会在当前会话工作目录执行,并把输出发回聊天窗口。
|
|
@@ -29,7 +29,7 @@ ChatCCC 把本地 AI 编程工具接入即时通讯软件。你可以在手机
|
|
|
29
29
|
| 项目 | 飞书(推荐) | 微信 iLink |
|
|
30
30
|
| --- | --- | --- |
|
|
31
31
|
| 使用场景 | 长期主力使用 | 快速试用、临时远程控制 |
|
|
32
|
-
| 会话形态 |
|
|
32
|
+
| 会话形态 | 私聊固定专属会话;`/new` 创建一群一会话 | 私聊,一对一 |
|
|
33
33
|
| 消息展示 | CardKit 卡片,流式更新 | 纯文本,增量推送 |
|
|
34
34
|
| `/new` | 自动创建新群并绑定新会话 | 在当前私聊里创建新会话 |
|
|
35
35
|
| 多会话并行 | 直接切换不同群 | 支持并行,使用切换指令后未完成的任务会继续在后台进行,但不如飞书直观方便 |
|
|
@@ -164,9 +164,11 @@ npm run dev
|
|
|
164
164
|
|
|
165
165
|
### 2. 即时通讯软件配置
|
|
166
166
|
|
|
167
|
-
#### 飞书(推荐)
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
#### 飞书(推荐)
|
|
168
|
+
|
|
169
|
+
如果 Chrome 已登录飞书开放平台,也可以让 Codex、Claude 或 Cursor 使用项目内的 [`create-chatccc-feishu-app`](.agents/skills/create-chatccc-feishu-app/SKILL.md) Skill,通过 Chrome DevTools/CDP 自动创建并配置机器人(默认 CDP 端口为 `15166`)。创建应用、开通权限和正式发布属于外部变更,执行前仍需明确确认;不要把 App Secret 写入对话或仓库。
|
|
170
|
+
|
|
171
|
+
1. 打开 [飞书开放平台](https://open.feishu.cn),创建一个**企业自建应用**。
|
|
170
172
|
2. 在「应用功能」里开启**机器人**能力。
|
|
171
173
|
3. 在「权限管理」里开通 `im:` 和 `cardkit:` 前缀下的相关权限:
|
|
172
174
|
|
|
@@ -324,7 +326,7 @@ Codex 的默认模型和推理强度可继续由 `~/.codex/config.toml` 管理
|
|
|
324
326
|
|
|
325
327
|
### 5. 开始使用
|
|
326
328
|
|
|
327
|
-
**飞书:**
|
|
329
|
+
**飞书:** 找到机器人后直接发送普通消息,即可在当前私聊中创建并持续使用专属 AI 会话;私聊工作目录固定为运行 ChatCCC 的系统账号用户目录。需要独立任务时,发送 `/new`、`/new claude`、`/new cursor` 或 `/new codex`,机器人会另外创建会话群,原私聊会话不受影响。
|
|
328
330
|
|
|
329
331
|
**微信:** 扫码登录后,在机器人私聊里发送 `/new` 或指定 Agent 的 `/new ...` 命令即可开始。功能与飞书基本一致,但展示为纯文本。
|
|
330
332
|
|
|
@@ -332,19 +334,19 @@ Codex 的默认模型和推理强度可继续由 `~/.codex/config.toml` 管理
|
|
|
332
334
|
|
|
333
335
|
| 指令 | 作用 |
|
|
334
336
|
| --- | --- |
|
|
335
|
-
| `/new` | 使用默认 Agent
|
|
336
|
-
| `/new claude` | 创建 Claude Code
|
|
337
|
-
| `/new cursor` | 创建 Cursor
|
|
338
|
-
| `/new codex` | 创建 Codex
|
|
339
|
-
| `/newh` |
|
|
337
|
+
| `/new` | 使用默认 Agent 创建新会话;飞书中会创建新群 |
|
|
338
|
+
| `/new claude` | 创建 Claude Code 会话;飞书中会创建新群 |
|
|
339
|
+
| `/new cursor` | 创建 Cursor 会话;飞书中会创建新群 |
|
|
340
|
+
| `/new codex` | 创建 Codex 会话;飞书中会创建新群 |
|
|
341
|
+
| `/newh` | 在当前聊天原地重置会话;群聊保留工作目录,飞书私聊固定使用系统用户目录 |
|
|
340
342
|
| `/model` | 查看或切换当前会话的模型 |
|
|
341
343
|
| `/stop` | 停止当前回复 |
|
|
342
344
|
| `/cancel` | 取消当前会话里排队等待处理的消息 |
|
|
343
345
|
| `/state` | 查看当前会话状态 |
|
|
344
|
-
| `/cd` |
|
|
346
|
+
| `/cd` | 查看或设置后续新建会话的默认工作目录,不改变当前会话;飞书私聊自身始终使用系统用户目录 |
|
|
345
347
|
| `/sessions` | 查看所有会话状态 |
|
|
346
|
-
| `/session <数字>` | 将当前群聊切换到 `/sessions`
|
|
347
|
-
| `/usage` | 查看当前会话对应 Agent 的用量;Codex 按接口实际返回显示 5h/7天窗口(缺失窗口不显示),若 Chrome CDP 可用且 ChatGPT 已登录,会额外显示订阅到期时间;Cursor 显示当前周期用量 |
|
|
348
|
+
| `/session <数字>` | 将当前群聊切换到 `/sessions` 列表中的指定会话;飞书私聊不支持切换 |
|
|
349
|
+
| `/usage` | 查看当前会话对应 Agent 的用量;Codex 按接口实际返回显示 5h/7天窗口(缺失窗口不显示),若 Chrome CDP 可用且 ChatGPT 已登录,会额外显示订阅到期时间;Cursor 显示当前周期用量 |
|
|
348
350
|
| `/git <子命令>` | 在当前会话工作目录执行 `git ...` 并回传输出 |
|
|
349
351
|
| `/abd<内容>` | 去掉 `/abd` 前缀后把内容发给 Agent,并在消息末尾追加第一性原理需求澄清提示 |
|
|
350
352
|
| `/plan <内容>` | 只读计划模式:仅允许读文件和 stop-stuck-loop 请求,不执行任何写操作 |
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
## 重复成功命令保护
|
|
2
|
-
|
|
3
|
-
通过 Claude Agent SDK 在本项目中工作时,重复成功的 shell 命令是完成信号,不应继续使用工具。
|
|
4
|
-
|
|
5
|
-
以下条件**全部**满足时,视为相同命令:
|
|
6
|
-
- 命令文本基本相同
|
|
7
|
-
- 工作目录相同
|
|
8
|
-
- 任务目标未变
|
|
9
|
-
- 没有新的用户输入改变任务
|
|
10
|
-
- 没有新的错误输出需要重新处理
|
|
11
|
-
|
|
12
|
-
同一命令**连续成功两次**后,停止调用工具,直接给出最终回复。不要"再验证一次"。
|
|
13
|
-
|
|
14
|
-
此规则适用于所有工具调用。
|
|
15
|
-
|
|
16
|
-
## 硬停止规则
|
|
17
|
-
|
|
18
|
-
同一命令在本项目中**不得成功执行三次**。若连续两次成功,第三次必须是最终回复。
|
|
19
|
-
|
|
20
|
-
## 卡住自检
|
|
21
|
-
|
|
22
|
-
如果你感觉任务已经完成,但发现自己陷入了循环(反复调用相同工具、输出 "stuck in a loop" 等),**立即**调用以下接口。
|
|
23
|
-
|
|
24
|
-
**重要:必须用 heredoc 写临时文件再 curl,禁止在命令行参数中直接写中文 JSON。** Windows 下命令行参数传中文会变成 `?` 乱码。
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
cat > /tmp/stop_ccc.json << 'STOPJSON'
|
|
28
|
-
{"session_id": "{{session_id}}", "final_reply": "<你给用户的最终回复,总结已完成的工作和结果>"}
|
|
29
|
-
STOPJSON
|
|
30
|
-
curl -s -X POST {{stop_stuck_url}} -H "Content-Type: application/json" -d @/tmp/stop_ccc.json
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
final_reply 注意事项:
|
|
34
|
-
- 把 `<...>` 占位符替换为你的实际回复,不要包含双引号 `"` 和反斜杠 `\`
|
|
35
|
-
- 不要包含换行,用空格代替
|
|
36
|
-
- 保持简短(1-2 句话)
|
|
37
|
-
|
|
38
|
-
调用后停止所有工具调用,直接输出最终回复即可。
|
|
39
|
-
|
|
40
|
-
## 禁止 PushNotification
|
|
41
|
-
|
|
42
|
-
**不要调用 PushNotification 工具。** 如果你认为当前会话已经完成任务需要结束,直接调用上述 stop-stuck-loop 接口,不要使用 PushNotification。
|
|
43
|
-
|
|
44
|
-
## 计划/问答模式权限规则
|
|
45
|
-
|
|
1
|
+
## 重复成功命令保护
|
|
2
|
+
|
|
3
|
+
通过 Claude Agent SDK 在本项目中工作时,重复成功的 shell 命令是完成信号,不应继续使用工具。
|
|
4
|
+
|
|
5
|
+
以下条件**全部**满足时,视为相同命令:
|
|
6
|
+
- 命令文本基本相同
|
|
7
|
+
- 工作目录相同
|
|
8
|
+
- 任务目标未变
|
|
9
|
+
- 没有新的用户输入改变任务
|
|
10
|
+
- 没有新的错误输出需要重新处理
|
|
11
|
+
|
|
12
|
+
同一命令**连续成功两次**后,停止调用工具,直接给出最终回复。不要"再验证一次"。
|
|
13
|
+
|
|
14
|
+
此规则适用于所有工具调用。
|
|
15
|
+
|
|
16
|
+
## 硬停止规则
|
|
17
|
+
|
|
18
|
+
同一命令在本项目中**不得成功执行三次**。若连续两次成功,第三次必须是最终回复。
|
|
19
|
+
|
|
20
|
+
## 卡住自检
|
|
21
|
+
|
|
22
|
+
如果你感觉任务已经完成,但发现自己陷入了循环(反复调用相同工具、输出 "stuck in a loop" 等),**立即**调用以下接口。
|
|
23
|
+
|
|
24
|
+
**重要:必须用 heredoc 写临时文件再 curl,禁止在命令行参数中直接写中文 JSON。** Windows 下命令行参数传中文会变成 `?` 乱码。
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cat > /tmp/stop_ccc.json << 'STOPJSON'
|
|
28
|
+
{"session_id": "{{session_id}}", "final_reply": "<你给用户的最终回复,总结已完成的工作和结果>"}
|
|
29
|
+
STOPJSON
|
|
30
|
+
curl -s -X POST {{stop_stuck_url}} -H "Content-Type: application/json" -d @/tmp/stop_ccc.json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
final_reply 注意事项:
|
|
34
|
+
- 把 `<...>` 占位符替换为你的实际回复,不要包含双引号 `"` 和反斜杠 `\`
|
|
35
|
+
- 不要包含换行,用空格代替
|
|
36
|
+
- 保持简短(1-2 句话)
|
|
37
|
+
|
|
38
|
+
调用后停止所有工具调用,直接输出最终回复即可。
|
|
39
|
+
|
|
40
|
+
## 禁止 PushNotification
|
|
41
|
+
|
|
42
|
+
**不要调用 PushNotification 工具。** 如果你认为当前会话已经完成任务需要结束,直接调用上述 stop-stuck-loop 接口,不要使用 PushNotification。
|
|
43
|
+
|
|
44
|
+
## 计划/问答模式权限规则
|
|
45
|
+
|
|
46
46
|
如果用户消息以 `/plan` 或 `/ask` 开头,说明当前处于只读模式。**遇到任何需要用户同意的权限请求时,不要向用户申请权限,立即调用 stop-stuck-loop 接口提前结束本轮会话。**
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
## 计划/问答模式权限规则
|
|
2
|
-
|
|
1
|
+
## 计划/问答模式权限规则
|
|
2
|
+
|
|
3
3
|
如果用户消息以 `/plan` 或 `/ask` 开头,说明当前处于只读模式。**遇到任何需要用户同意的权限请求时,不要向用户申请权限,立即调用 stop-stuck-loop 接口提前结束本轮会话。**
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
## 计划/问答模式权限规则
|
|
2
|
-
|
|
3
|
-
如果用户消息以 `/plan` 或 `/ask` 开头,说明当前处于只读模式。**遇到任何需要用户同意的权限请求时,不要向用户申请权限,立即调用 stop-stuck-loop 接口提前结束本轮会话。**
|
|
4
|
-
|
|
5
|
-
## 用户问题澄清规则
|
|
6
|
-
|
|
7
|
-
当需要在开始实现前向用户确认问题、让用户做选择,或用户要求“从第一性原理出发挖掘真实需求 / 判断需求是否合理 / 开始实现前有什么问题要问我”时,**不要调用 `AskQuestion`、多选表单或任何结构化选择工具**。
|
|
8
|
-
|
|
9
|
-
必须直接用普通文本回复用户:
|
|
10
|
-
|
|
11
|
-
- 先简要说明你理解到的真实需求和你对合理性的判断。
|
|
12
|
-
- 再列出需要用户确认的问题;如果有推荐选项,就用文本说明“我建议 X,原因是 Y”。
|
|
13
|
-
- 问题数量尽量少,只问会影响实现边界、风险或不可逆决策的问题。
|
|
1
|
+
## 计划/问答模式权限规则
|
|
2
|
+
|
|
3
|
+
如果用户消息以 `/plan` 或 `/ask` 开头,说明当前处于只读模式。**遇到任何需要用户同意的权限请求时,不要向用户申请权限,立即调用 stop-stuck-loop 接口提前结束本轮会话。**
|
|
4
|
+
|
|
5
|
+
## 用户问题澄清规则
|
|
6
|
+
|
|
7
|
+
当需要在开始实现前向用户确认问题、让用户做选择,或用户要求“从第一性原理出发挖掘真实需求 / 判断需求是否合理 / 开始实现前有什么问题要问我”时,**不要调用 `AskQuestion`、多选表单或任何结构化选择工具**。
|
|
8
|
+
|
|
9
|
+
必须直接用普通文本回复用户:
|
|
10
|
+
|
|
11
|
+
- 先简要说明你理解到的真实需求和你对合理性的判断。
|
|
12
|
+
- 再列出需要用户确认的问题;如果有推荐选项,就用文本说明“我建议 X,原因是 Y”。
|
|
13
|
+
- 问题数量尽量少,只问会影响实现边界、风险或不可逆决策的问题。
|
|
14
14
|
- 不要把这些问题放进工具调用参数里,也不要只在卡片/工具结果中呈现。
|
package/bin/cccagent.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { createRequire } from "node:module";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
5
|
-
|
|
6
|
-
const require = createRequire(import.meta.url);
|
|
7
|
-
const pkgRoot = dirname(require.resolve("../package.json"));
|
|
8
|
-
const cliTs = join(pkgRoot, "src", "builtin", "cli.ts");
|
|
9
|
-
const tsxCli = require.resolve("tsx/cli");
|
|
10
|
-
|
|
11
|
-
const result = spawnSync(process.execPath, [tsxCli, cliTs, ...process.argv.slice(2)], {
|
|
12
|
-
stdio: "inherit",
|
|
13
|
-
cwd: process.cwd(),
|
|
14
|
-
env: process.env,
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
process.exit(result.status === null ? 1 : result.status);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const pkgRoot = dirname(require.resolve("../package.json"));
|
|
8
|
+
const cliTs = join(pkgRoot, "src", "builtin", "cli.ts");
|
|
9
|
+
const tsxCli = require.resolve("tsx/cli");
|
|
10
|
+
|
|
11
|
+
const result = spawnSync(process.execPath, [tsxCli, cliTs, ...process.argv.slice(2)], {
|
|
12
|
+
stdio: "inherit",
|
|
13
|
+
cwd: process.cwd(),
|
|
14
|
+
env: process.env,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
process.exit(result.status === null ? 1 : result.status);
|
package/config.sample.json
CHANGED
|
@@ -28,19 +28,19 @@
|
|
|
28
28
|
"retentionDays": 7,
|
|
29
29
|
"keepCompleted": false
|
|
30
30
|
},
|
|
31
|
-
"codex": {
|
|
32
|
-
"enabled": false,
|
|
33
|
-
"maxBytesPerTurn": 52428800,
|
|
34
|
-
"retentionDays": 7,
|
|
35
|
-
"keepCompleted": false
|
|
36
|
-
},
|
|
37
|
-
"ccc": {
|
|
38
|
-
"enabled": false,
|
|
39
|
-
"maxBytesPerTurn": 52428800,
|
|
40
|
-
"retentionDays": 7,
|
|
41
|
-
"keepCompleted": false
|
|
42
|
-
}
|
|
43
|
-
},
|
|
31
|
+
"codex": {
|
|
32
|
+
"enabled": false,
|
|
33
|
+
"maxBytesPerTurn": 52428800,
|
|
34
|
+
"retentionDays": 7,
|
|
35
|
+
"keepCompleted": false
|
|
36
|
+
},
|
|
37
|
+
"ccc": {
|
|
38
|
+
"enabled": false,
|
|
39
|
+
"maxBytesPerTurn": 52428800,
|
|
40
|
+
"retentionDays": 7,
|
|
41
|
+
"keepCompleted": false
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
44
|
"claude": {
|
|
45
45
|
"enabled": false,
|
|
46
46
|
"defaultAgent": true,
|
|
@@ -60,17 +60,17 @@
|
|
|
60
60
|
"avatarBatteryMode": "apiPercent",
|
|
61
61
|
"onDemandMonthlyBudget": 1000
|
|
62
62
|
},
|
|
63
|
-
"codex": {
|
|
64
|
-
"enabled": false,
|
|
65
|
-
"defaultAgent": false,
|
|
66
|
-
"path": "",
|
|
67
|
-
"model": "",
|
|
68
|
-
"alternativeModel": "",
|
|
69
|
-
"effort": ""
|
|
70
|
-
},
|
|
71
|
-
"ccc": {
|
|
72
|
-
"DEEPSEEK_API_KEY": "",
|
|
73
|
-
"DEEPSEEK_BASE_URL": "https://api.deepseek.com/v1",
|
|
74
|
-
"model": "deepseek-v4-pro"
|
|
75
|
-
}
|
|
76
|
-
}
|
|
63
|
+
"codex": {
|
|
64
|
+
"enabled": false,
|
|
65
|
+
"defaultAgent": false,
|
|
66
|
+
"path": "",
|
|
67
|
+
"model": "",
|
|
68
|
+
"alternativeModel": "",
|
|
69
|
+
"effort": ""
|
|
70
|
+
},
|
|
71
|
+
"ccc": {
|
|
72
|
+
"DEEPSEEK_API_KEY": "",
|
|
73
|
+
"DEEPSEEK_BASE_URL": "https://api.deepseek.com/v1",
|
|
74
|
+
"model": "deepseek-v4-pro"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
# Sending & Downloading Files/Videos
|
|
2
|
-
|
|
3
|
-
## Send Files or Videos
|
|
4
|
-
|
|
5
|
-
Videos are sent as regular files (not media), which looks cleaner in Feishu.
|
|
6
|
-
|
|
7
|
-
**Use the node script below. Do NOT use curl or raw HTTP — the script correctly handles errors and exits non-zero on failure.**
|
|
8
|
-
|
|
9
|
-
### Script
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
node "{{send_file_script}}" --url "{{send_file_url}}" --session-id "{{session_id}}" --path "<absolute file path>" --caption "<optional caption>"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
### Rules
|
|
16
|
-
|
|
17
|
-
- Use the node script above — never curl or raw HTTP.
|
|
18
|
-
- Save or choose a local file first.
|
|
19
|
-
- Use an absolute local path.
|
|
20
|
-
- Max file size: 30MB.
|
|
21
|
-
- Supported formats: .mp4 .mov .avi .mkv .webm .flv .mp3 .wav .ogg .aac .m4a .pdf .doc .docx .xls .xlsx .csv .ppt .pptx .txt .zip .tar .gz.
|
|
22
|
-
- Only send a file/video when the user asked for one or when it materially helps the answer.
|
|
23
|
-
- **If the script fails (non-zero exit), read stderr for the error. Do NOT retry with the same path. Either fix the problem (wrong extension, missing file, etc.) or tell the user what the error was. Never retry more than once.**
|
|
24
|
-
|
|
25
|
-
### Video Compression (when file > 30MB)
|
|
26
|
-
|
|
27
|
-
If the video exceeds 30MB, compress it with ffmpeg before sending.
|
|
28
|
-
|
|
29
|
-
**Ensure ffmpeg is available** (install if missing):
|
|
30
|
-
|
|
31
|
-
| OS | Install command |
|
|
32
|
-
|----|----------------|
|
|
33
|
-
| macOS | `brew install ffmpeg` |
|
|
34
|
-
| Linux (Debian/Ubuntu) | `sudo apt install ffmpeg` |
|
|
35
|
-
| Linux (RHEL/Fedora) | `sudo dnf install ffmpeg` |
|
|
36
|
-
| Windows | `winget install Gyan.FFmpeg` |
|
|
37
|
-
|
|
38
|
-
**Two-pass compression** (target ~28MB for 30s video, adjust `b:v` for other durations):
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
ffmpeg -y -i "<input>" -c:v libx264 -b:v <bitrate>k -pass 1 -f mp4 NUL
|
|
42
|
-
ffmpeg -y -i "<input>" -c:v libx264 -b:v <bitrate>k -pass 2 -c:a aac -b:a 128k "<output>"
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Bitrate formula: `bitrate = 28 × 8 × 1000 ÷ duration_seconds - 128` (target ~28MB, safe under 30MB).
|
|
46
|
-
On Windows replace `NUL` with `NUL` (same); on Linux/macOS use `/dev/null`.
|
|
47
|
-
|
|
48
|
-
If the compressed file still exceeds 30MB, explain to the user that automatic compression wasn't enough and suggest they manually trim or re-encode the source.
|
|
49
|
-
|
|
50
|
-
## Download Files or Videos
|
|
51
|
-
|
|
52
|
-
When the user sends a file or video to the bot, the message contains `message_id` and `file_key`. Download it with:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
node "{{download_video_script}}" --message-id <message_id> --file-key <file_key> --name <file_name>
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
If only `chat_id` and `file_key` are available:
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
node "{{download_video_script}}" --chat-id <chat_id> --file-key <file_key> --name <file_name>
|
|
62
|
-
```
|
|
63
|
-
|
|
1
|
+
# Sending & Downloading Files/Videos
|
|
2
|
+
|
|
3
|
+
## Send Files or Videos
|
|
4
|
+
|
|
5
|
+
Videos are sent as regular files (not media), which looks cleaner in Feishu.
|
|
6
|
+
|
|
7
|
+
**Use the node script below. Do NOT use curl or raw HTTP — the script correctly handles errors and exits non-zero on failure.**
|
|
8
|
+
|
|
9
|
+
### Script
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
node "{{send_file_script}}" --url "{{send_file_url}}" --session-id "{{session_id}}" --path "<absolute file path>" --caption "<optional caption>"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Rules
|
|
16
|
+
|
|
17
|
+
- Use the node script above — never curl or raw HTTP.
|
|
18
|
+
- Save or choose a local file first.
|
|
19
|
+
- Use an absolute local path.
|
|
20
|
+
- Max file size: 30MB.
|
|
21
|
+
- Supported formats: .mp4 .mov .avi .mkv .webm .flv .mp3 .wav .ogg .aac .m4a .pdf .doc .docx .xls .xlsx .csv .ppt .pptx .txt .zip .tar .gz.
|
|
22
|
+
- Only send a file/video when the user asked for one or when it materially helps the answer.
|
|
23
|
+
- **If the script fails (non-zero exit), read stderr for the error. Do NOT retry with the same path. Either fix the problem (wrong extension, missing file, etc.) or tell the user what the error was. Never retry more than once.**
|
|
24
|
+
|
|
25
|
+
### Video Compression (when file > 30MB)
|
|
26
|
+
|
|
27
|
+
If the video exceeds 30MB, compress it with ffmpeg before sending.
|
|
28
|
+
|
|
29
|
+
**Ensure ffmpeg is available** (install if missing):
|
|
30
|
+
|
|
31
|
+
| OS | Install command |
|
|
32
|
+
|----|----------------|
|
|
33
|
+
| macOS | `brew install ffmpeg` |
|
|
34
|
+
| Linux (Debian/Ubuntu) | `sudo apt install ffmpeg` |
|
|
35
|
+
| Linux (RHEL/Fedora) | `sudo dnf install ffmpeg` |
|
|
36
|
+
| Windows | `winget install Gyan.FFmpeg` |
|
|
37
|
+
|
|
38
|
+
**Two-pass compression** (target ~28MB for 30s video, adjust `b:v` for other durations):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ffmpeg -y -i "<input>" -c:v libx264 -b:v <bitrate>k -pass 1 -f mp4 NUL
|
|
42
|
+
ffmpeg -y -i "<input>" -c:v libx264 -b:v <bitrate>k -pass 2 -c:a aac -b:a 128k "<output>"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Bitrate formula: `bitrate = 28 × 8 × 1000 ÷ duration_seconds - 128` (target ~28MB, safe under 30MB).
|
|
46
|
+
On Windows replace `NUL` with `NUL` (same); on Linux/macOS use `/dev/null`.
|
|
47
|
+
|
|
48
|
+
If the compressed file still exceeds 30MB, explain to the user that automatic compression wasn't enough and suggest they manually trim or re-encode the source.
|
|
49
|
+
|
|
50
|
+
## Download Files or Videos
|
|
51
|
+
|
|
52
|
+
When the user sends a file or video to the bot, the message contains `message_id` and `file_key`. Download it with:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
node "{{download_video_script}}" --message-id <message_id> --file-key <file_key> --name <file_name>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If only `chat_id` and `file_key` are available:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node "{{download_video_script}}" --chat-id <chat_id> --file-key <file_key> --name <file_name>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
64
|
Downloads are saved under `~/.chatccc/videos/downloads/`.
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
# Sending & Receiving Images
|
|
2
|
-
|
|
3
|
-
## Send Images
|
|
4
|
-
|
|
5
|
-
**Use the node script below. Do NOT use curl or raw HTTP — the script correctly handles errors and exits non-zero on failure.**
|
|
6
|
-
|
|
7
|
-
### Script
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
node "{{send_image_script}}" --url "{{send_image_url}}" --session-id "{{session_id}}" --path "<absolute image path>" --caption "<optional caption>"
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
### Rules
|
|
14
|
-
|
|
15
|
-
- Use the node script above — never curl or raw HTTP.
|
|
16
|
-
- Save or choose a local image file first.
|
|
17
|
-
- Use an absolute local path.
|
|
18
|
-
- Supported formats: .png, .jpg, .jpeg, .webp, .gif, .bmp.
|
|
19
|
-
- Max image size: 10MB.
|
|
20
|
-
- Only send an image when the user asked for one or when it materially helps the answer.
|
|
21
|
-
- **If the script fails (non-zero exit), read stderr for the error. Do NOT retry with the same path. Either fix the problem (wrong extension, missing file, etc.) or tell the user what the error was. Never retry more than once.**
|
|
22
|
-
|
|
23
|
-
## Receive Images
|
|
24
|
-
|
|
1
|
+
# Sending & Receiving Images
|
|
2
|
+
|
|
3
|
+
## Send Images
|
|
4
|
+
|
|
5
|
+
**Use the node script below. Do NOT use curl or raw HTTP — the script correctly handles errors and exits non-zero on failure.**
|
|
6
|
+
|
|
7
|
+
### Script
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node "{{send_image_script}}" --url "{{send_image_url}}" --session-id "{{session_id}}" --path "<absolute image path>" --caption "<optional caption>"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Rules
|
|
14
|
+
|
|
15
|
+
- Use the node script above — never curl or raw HTTP.
|
|
16
|
+
- Save or choose a local image file first.
|
|
17
|
+
- Use an absolute local path.
|
|
18
|
+
- Supported formats: .png, .jpg, .jpeg, .webp, .gif, .bmp.
|
|
19
|
+
- Max image size: 10MB.
|
|
20
|
+
- Only send an image when the user asked for one or when it materially helps the answer.
|
|
21
|
+
- **If the script fails (non-zero exit), read stderr for the error. Do NOT retry with the same path. Either fix the problem (wrong extension, missing file, etc.) or tell the user what the error was. Never retry more than once.**
|
|
22
|
+
|
|
23
|
+
## Receive Images
|
|
24
|
+
|
|
25
25
|
Images sent to the bot are automatically downloaded to `~/.chatccc/images/downloads/`. The message contains an `image_key` that maps to the cached file.
|
|
@@ -7,6 +7,6 @@ Current working directory: {{cwd}}
|
|
|
7
7
|
|
|
8
8
|
Use local endpoints instead of calling Feishu Open Platform directly.
|
|
9
9
|
|
|
10
|
-
- **Send images**: POST `{{send_image_url}}` with `{"session_id":"{{session_id}}","path":"<absolute path>","caption":"<optional>"}` — read `{{im_skills_cache_dir}}/feishu-skill/receive-send-image.md`
|
|
11
|
-
- **Send files/videos**: POST `{{send_file_url}}` with `{"session_id":"{{session_id}}","path":"<absolute path>","caption":"<optional>"}` — read `{{im_skills_cache_dir}}/feishu-skill/receive-send-file.md`
|
|
12
|
-
- **Delegate a task to a new agent conversation**: POST `{{delegate_task_url}}` with `{"tool":"codex|claude|cursor","cwd":"<absolute working directory>","open_id":"<Feishu user open_id>","prompt":"<first task>"}`. Use `open_ids` for multiple users. This uses the normal ChatCCC prompt flow, so project prompt injection and IM skills still apply.
|
|
10
|
+
- **Send images**: POST `{{send_image_url}}` with `{"session_id":"{{session_id}}","path":"<absolute path>","caption":"<optional>"}` — read `{{im_skills_cache_dir}}/feishu-skill/receive-send-image.md`
|
|
11
|
+
- **Send files/videos**: POST `{{send_file_url}}` with `{"session_id":"{{session_id}}","path":"<absolute path>","caption":"<optional>"}` — read `{{im_skills_cache_dir}}/feishu-skill/receive-send-file.md`
|
|
12
|
+
- **Delegate a task to a new agent conversation**: POST `{{delegate_task_url}}` with `{"tool":"codex|claude|cursor","cwd":"<absolute working directory>","open_id":"<Feishu user open_id>","prompt":"<first task>"}`. Use `open_ids` for multiple users. This uses the normal ChatCCC prompt flow, so project prompt injection and IM skills still apply.
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
# Receiving & Sending Files (WeChat)
|
|
2
|
-
|
|
3
|
-
## Receive Files
|
|
4
|
-
|
|
5
|
-
Files sent to the bot are **automatically downloaded** to `~/.chatccc/images/downloads/` with the `wx_` filename prefix.
|
|
6
|
-
|
|
7
|
-
The message text you receive will include the downloaded path in the format:
|
|
8
|
-
```
|
|
9
|
-
[文件] C:\Users\<用户名>\.chatccc\images\downloads\wx_<key>_<filename>
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
You can read the file at that path to understand what the user sent.
|
|
13
|
-
|
|
14
|
-
## Send Files
|
|
15
|
-
|
|
16
|
-
### Script (recommended)
|
|
17
|
-
```bash
|
|
18
|
-
node "{{wechat_send_file_script}}" --path "<absolute file path>" --caption "<optional caption>"
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
The script reads the current WeChat session's auth token, chat ID, and context token from `~/.chatccc/state/ilink-auth.json`, then sends the file to the most recent chat.
|
|
22
|
-
|
|
23
|
-
### Direct usage in test scripts
|
|
24
|
-
|
|
25
|
-
The underlying SDK call is:
|
|
26
|
-
```ts
|
|
27
|
-
import { Client as OpenIlinkWire } from "@openilink/openilink-sdk-node";
|
|
28
|
-
const wire = new OpenIlinkWire(token, { base_url: baseUrl });
|
|
29
|
-
await wire.sendMediaFile(chatId, contextToken, fileBuffer, "filename.pdf", "caption");
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Rules
|
|
33
|
-
|
|
34
|
-
- Save or choose a local file first.
|
|
35
|
-
- Use an absolute local path.
|
|
36
|
-
- Supported formats: .pdf, .doc, .docx, .xls, .xlsx, .csv, .ppt, .pptx, .txt, .zip, .tar, .gz, .rar, .7z, .mp3, .wav, .ogg, .aac, .m4a.
|
|
37
|
-
- Max file size: 100MB.
|
|
38
|
-
- Only send a file when the user asked for one or when it materially helps the answer.
|
|
1
|
+
# Receiving & Sending Files (WeChat)
|
|
2
|
+
|
|
3
|
+
## Receive Files
|
|
4
|
+
|
|
5
|
+
Files sent to the bot are **automatically downloaded** to `~/.chatccc/images/downloads/` with the `wx_` filename prefix.
|
|
6
|
+
|
|
7
|
+
The message text you receive will include the downloaded path in the format:
|
|
8
|
+
```
|
|
9
|
+
[文件] C:\Users\<用户名>\.chatccc\images\downloads\wx_<key>_<filename>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
You can read the file at that path to understand what the user sent.
|
|
13
|
+
|
|
14
|
+
## Send Files
|
|
15
|
+
|
|
16
|
+
### Script (recommended)
|
|
17
|
+
```bash
|
|
18
|
+
node "{{wechat_send_file_script}}" --path "<absolute file path>" --caption "<optional caption>"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The script reads the current WeChat session's auth token, chat ID, and context token from `~/.chatccc/state/ilink-auth.json`, then sends the file to the most recent chat.
|
|
22
|
+
|
|
23
|
+
### Direct usage in test scripts
|
|
24
|
+
|
|
25
|
+
The underlying SDK call is:
|
|
26
|
+
```ts
|
|
27
|
+
import { Client as OpenIlinkWire } from "@openilink/openilink-sdk-node";
|
|
28
|
+
const wire = new OpenIlinkWire(token, { base_url: baseUrl });
|
|
29
|
+
await wire.sendMediaFile(chatId, contextToken, fileBuffer, "filename.pdf", "caption");
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Rules
|
|
33
|
+
|
|
34
|
+
- Save or choose a local file first.
|
|
35
|
+
- Use an absolute local path.
|
|
36
|
+
- Supported formats: .pdf, .doc, .docx, .xls, .xlsx, .csv, .ppt, .pptx, .txt, .zip, .tar, .gz, .rar, .7z, .mp3, .wav, .ogg, .aac, .m4a.
|
|
37
|
+
- Max file size: 100MB.
|
|
38
|
+
- Only send a file when the user asked for one or when it materially helps the answer.
|
|
39
39
|
- **Claw 限制**: 文件发送也计入微信 claw 连发计数,连续 10 条未回复会截断。
|