chatccc 0.2.198 → 0.2.200

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.
Files changed (49) hide show
  1. package/README.md +1 -1
  2. package/agent-prompts/claude_specific.md +45 -45
  3. package/agent-prompts/codex_specific.md +2 -2
  4. package/im-skills/feishu-skill/receive-send-file.md +63 -63
  5. package/im-skills/feishu-skill/receive-send-image.md +24 -24
  6. package/im-skills/feishu-skill/skill.md +3 -3
  7. package/im-skills/wechat-file-skill/receive-send-file.md +38 -38
  8. package/im-skills/wechat-file-skill/send-file.mjs +83 -83
  9. package/im-skills/wechat-file-skill/skill.md +10 -10
  10. package/im-skills/wechat-image-skill/skill.md +10 -10
  11. package/im-skills/wechat-video-skill/receive-send-video.md +38 -38
  12. package/im-skills/wechat-video-skill/send-video.mjs +79 -79
  13. package/im-skills/wechat-video-skill/skill.md +10 -10
  14. package/package.json +1 -1
  15. package/scripts/postinstall-sharp-check.mjs +58 -58
  16. package/src/__tests__/agent-delegate-task-rpc.test.ts +165 -165
  17. package/src/__tests__/card-plain-text.test.ts +5 -5
  18. package/src/__tests__/cardkit.test.ts +60 -60
  19. package/src/__tests__/cards.test.ts +1 -1
  20. package/src/__tests__/claude-adapter.test.ts +592 -592
  21. package/src/__tests__/codex-reset-actions.test.ts +146 -146
  22. package/src/__tests__/cursor-adapter.test.ts +66 -7
  23. package/src/__tests__/feishu-api.test.ts +60 -60
  24. package/src/__tests__/feishu-avatar.test.ts +47 -5
  25. package/src/__tests__/feishu-platform.test.ts +22 -22
  26. package/src/__tests__/format-message.test.ts +47 -47
  27. package/src/__tests__/orchestrator.test.ts +27 -2
  28. package/src/__tests__/privacy.test.ts +198 -198
  29. package/src/__tests__/shared-prefix.test.ts +36 -36
  30. package/src/__tests__/stream-state.test.ts +42 -42
  31. package/src/adapters/claude-session-meta-store.ts +120 -120
  32. package/src/adapters/cursor-adapter.ts +39 -6
  33. package/src/adapters/resource-monitor.ts +140 -140
  34. package/src/agent-delegate-task-rpc.ts +153 -153
  35. package/src/agent-delegate-task.ts +81 -81
  36. package/src/agent-stop-stuck.ts +129 -129
  37. package/src/cards.ts +1 -1
  38. package/src/codex-reset-actions.ts +184 -184
  39. package/src/feishu-api.ts +41 -18
  40. package/src/feishu-platform.ts +20 -20
  41. package/src/format-message.ts +293 -293
  42. package/src/litellm-proxy.ts +374 -374
  43. package/src/orchestrator.ts +4 -4
  44. package/src/privacy.ts +118 -118
  45. package/src/session-chat-binding.ts +6 -6
  46. package/src/session-name.ts +8 -8
  47. package/src/shared-prefix.ts +29 -29
  48. package/src/sim-platform.ts +20 -20
  49. package/src/turn-cards.ts +117 -117
@@ -1,39 +1,39 @@
1
- # Receiving & Sending Videos (WeChat)
2
-
3
- ## Receive Videos
4
-
5
- Videos 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>.mp4
10
- ```
11
-
12
- You can read the video file at that path to understand what the user sent.
13
-
14
- ## Send Videos
15
-
16
- ### Script (recommended)
17
- ```bash
18
- node "{{wechat_send_video_script}}" --path "<absolute video 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 video 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, videoBuffer, "video.mp4", "caption");
30
- ```
31
-
32
- ### Rules
33
-
34
- - Save or choose a local video file first.
35
- - Use an absolute local path.
36
- - Supported formats: .mp4, .mov, .avi, .mkv, .webm, .flv.
37
- - Max video size: 100MB.
38
- - Only send a video when the user asked for one or when it materially helps the answer.
1
+ # Receiving & Sending Videos (WeChat)
2
+
3
+ ## Receive Videos
4
+
5
+ Videos 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>.mp4
10
+ ```
11
+
12
+ You can read the video file at that path to understand what the user sent.
13
+
14
+ ## Send Videos
15
+
16
+ ### Script (recommended)
17
+ ```bash
18
+ node "{{wechat_send_video_script}}" --path "<absolute video 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 video 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, videoBuffer, "video.mp4", "caption");
30
+ ```
31
+
32
+ ### Rules
33
+
34
+ - Save or choose a local video file first.
35
+ - Use an absolute local path.
36
+ - Supported formats: .mp4, .mov, .avi, .mkv, .webm, .flv.
37
+ - Max video size: 100MB.
38
+ - Only send a video when the user asked for one or when it materially helps the answer.
39
39
  - **Claw 限制**: 视频发送也计入微信 claw 连发计数,连续 10 条未回复会截断。
@@ -1,80 +1,80 @@
1
- #!/usr/bin/env node
2
- import { existsSync, readFileSync, statSync } from "node:fs";
3
- import { basename, extname, join } from "node:path";
4
- import { homedir } from "node:os";
5
-
6
- import { Client as OpenIlinkWire } from "@openilink/openilink-sdk-node";
7
-
8
- const ILINK_AUTH_PATH = join(homedir(), ".chatccc", "state", "ilink-auth.json");
9
- const MAX_VIDEO_BYTES = 100 * 1024 * 1024;
10
- const ALLOWED_EXTS = new Set([".mp4", ".mov", ".avi", ".mkv", ".webm", ".flv"]);
11
-
12
- function parseArgs(argv) {
13
- const result = {};
14
- for (let i = 0; i < argv.length; i++) {
15
- const key = argv[i];
16
- if (!key.startsWith("--")) continue;
17
- const value = argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[++i] : "true";
18
- result[key.slice(2)] = value;
19
- }
20
- return result;
21
- }
22
-
23
- function usage() {
24
- console.error(`Usage:
25
- node ${basename(process.argv[1])} --path <absolute video path> [--caption <text>]`);
26
- }
27
-
28
- async function main() {
29
- const args = parseArgs(process.argv.slice(2));
30
- const videoPath = args.path;
31
- const caption = args.caption || "";
32
-
33
- if (!videoPath) {
34
- usage();
35
- process.exit(1);
36
- }
37
-
38
- const ext = extname(videoPath).toLowerCase();
39
- if (!ALLOWED_EXTS.has(ext)) {
40
- console.error(`Unsupported video extension: ${ext || "(none)"}`);
41
- process.exit(1);
42
- }
43
-
44
- const st = statSync(videoPath);
45
- if (!st.isFile()) {
46
- console.error("Video path is not a file");
47
- process.exit(1);
48
- }
49
- if (st.size > MAX_VIDEO_BYTES) {
50
- console.error("Video file exceeds 100MB limit");
51
- process.exit(1);
52
- }
53
-
54
- if (!existsSync(ILINK_AUTH_PATH)) {
55
- console.error(`Auth snapshot not found: ${ILINK_AUTH_PATH}`);
56
- console.error("Make sure the WeChat iLink platform is logged in.");
57
- process.exit(1);
58
- }
59
-
60
- const snap = JSON.parse(readFileSync(ILINK_AUTH_PATH, "utf8"));
61
- if (!snap.token || !snap.lastChatId || !snap.contextToken) {
62
- console.error("Auth snapshot missing token, lastChatId, or contextToken.");
63
- process.exit(1);
64
- }
65
-
66
- const videoData = readFileSync(videoPath);
67
- const fileName = basename(videoPath);
68
-
69
- const wire = new OpenIlinkWire(snap.token, {
70
- base_url: snap.baseUrl,
71
- });
72
-
73
- await wire.sendMediaFile(snap.lastChatId, snap.contextToken, videoData, fileName, caption);
74
- console.log(JSON.stringify({ ok: true, sentTo: 1 }));
75
- }
76
-
77
- main().catch((err) => {
78
- console.error(err instanceof Error ? err.message : String(err));
79
- process.exit(1);
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync, statSync } from "node:fs";
3
+ import { basename, extname, join } from "node:path";
4
+ import { homedir } from "node:os";
5
+
6
+ import { Client as OpenIlinkWire } from "@openilink/openilink-sdk-node";
7
+
8
+ const ILINK_AUTH_PATH = join(homedir(), ".chatccc", "state", "ilink-auth.json");
9
+ const MAX_VIDEO_BYTES = 100 * 1024 * 1024;
10
+ const ALLOWED_EXTS = new Set([".mp4", ".mov", ".avi", ".mkv", ".webm", ".flv"]);
11
+
12
+ function parseArgs(argv) {
13
+ const result = {};
14
+ for (let i = 0; i < argv.length; i++) {
15
+ const key = argv[i];
16
+ if (!key.startsWith("--")) continue;
17
+ const value = argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[++i] : "true";
18
+ result[key.slice(2)] = value;
19
+ }
20
+ return result;
21
+ }
22
+
23
+ function usage() {
24
+ console.error(`Usage:
25
+ node ${basename(process.argv[1])} --path <absolute video path> [--caption <text>]`);
26
+ }
27
+
28
+ async function main() {
29
+ const args = parseArgs(process.argv.slice(2));
30
+ const videoPath = args.path;
31
+ const caption = args.caption || "";
32
+
33
+ if (!videoPath) {
34
+ usage();
35
+ process.exit(1);
36
+ }
37
+
38
+ const ext = extname(videoPath).toLowerCase();
39
+ if (!ALLOWED_EXTS.has(ext)) {
40
+ console.error(`Unsupported video extension: ${ext || "(none)"}`);
41
+ process.exit(1);
42
+ }
43
+
44
+ const st = statSync(videoPath);
45
+ if (!st.isFile()) {
46
+ console.error("Video path is not a file");
47
+ process.exit(1);
48
+ }
49
+ if (st.size > MAX_VIDEO_BYTES) {
50
+ console.error("Video file exceeds 100MB limit");
51
+ process.exit(1);
52
+ }
53
+
54
+ if (!existsSync(ILINK_AUTH_PATH)) {
55
+ console.error(`Auth snapshot not found: ${ILINK_AUTH_PATH}`);
56
+ console.error("Make sure the WeChat iLink platform is logged in.");
57
+ process.exit(1);
58
+ }
59
+
60
+ const snap = JSON.parse(readFileSync(ILINK_AUTH_PATH, "utf8"));
61
+ if (!snap.token || !snap.lastChatId || !snap.contextToken) {
62
+ console.error("Auth snapshot missing token, lastChatId, or contextToken.");
63
+ process.exit(1);
64
+ }
65
+
66
+ const videoData = readFileSync(videoPath);
67
+ const fileName = basename(videoPath);
68
+
69
+ const wire = new OpenIlinkWire(snap.token, {
70
+ base_url: snap.baseUrl,
71
+ });
72
+
73
+ await wire.sendMediaFile(snap.lastChatId, snap.contextToken, videoData, fileName, caption);
74
+ console.log(JSON.stringify({ ok: true, sentTo: 1 }));
75
+ }
76
+
77
+ main().catch((err) => {
78
+ console.error(err instanceof Error ? err.message : String(err));
79
+ process.exit(1);
80
80
  });
@@ -1,11 +1,11 @@
1
- ---
2
- name: wechat-video-skill
3
- description: WeChat iLink local skills for sending and receiving videos.
4
- ---
5
-
6
- Current working directory: {{cwd}}
7
-
8
- WeChat videos are handled through the iLink SDK. The local server does NOT have HTTP RPC endpoints for WeChat; use the helper scripts below instead.
9
-
10
- - **Receive videos**: Videos sent to the bot are automatically downloaded to `~/.chatccc/images/downloads/` with the filename prefix `wx_`. The message text will include the local path as `[视频] <absolute path>` — read `{{im_skills_cache_dir}}/wechat-video-skill/receive-send-video.md`
1
+ ---
2
+ name: wechat-video-skill
3
+ description: WeChat iLink local skills for sending and receiving videos.
4
+ ---
5
+
6
+ Current working directory: {{cwd}}
7
+
8
+ WeChat videos are handled through the iLink SDK. The local server does NOT have HTTP RPC endpoints for WeChat; use the helper scripts below instead.
9
+
10
+ - **Receive videos**: Videos sent to the bot are automatically downloaded to `~/.chatccc/images/downloads/` with the filename prefix `wx_`. The message text will include the local path as `[视频] <absolute path>` — read `{{im_skills_cache_dir}}/wechat-video-skill/receive-send-video.md`
11
11
  - **Send videos**: Use the send-video helper script — read `{{im_skills_cache_dir}}/wechat-video-skill/receive-send-video.md`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatccc",
3
- "version": "0.2.198",
3
+ "version": "0.2.200",
4
4
  "description": "Feishu bot bridge for Claude Code",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -1,59 +1,59 @@
1
- // postinstall 检测 sharp 原生模块是否可用(常见于 Linux 缺少 libvips)
2
- import { createRequire } from "node:module";
3
-
4
- const require = createRequire(import.meta.url);
5
- let ok = false;
6
-
7
- try {
8
- require("sharp");
9
- ok = true;
10
- } catch (err) {
11
- const msg = err.message;
12
- const platform = process.platform;
13
-
14
- console.warn("");
15
- console.warn("============================================================");
16
- console.warn(" ChatCCC: sharp 图像处理模块检测失败");
17
- console.warn("============================================================");
18
-
19
- if (platform === "linux") {
20
- if (msg.includes("libvips") || msg.includes("vips") || msg.includes("libglib")) {
21
- console.warn(" 原因:系统缺少 libvips 图像处理库。");
22
- console.warn("");
23
- console.warn(" 请先安装 libvips 然后重建 sharp:");
24
- console.warn("");
25
- console.warn(" Debian / Ubuntu:");
26
- console.warn(" sudo apt install libvips-dev");
27
- console.warn("");
28
- console.warn(" CentOS / RHEL / Fedora:");
29
- console.warn(" sudo yum install vips-devel");
30
- console.warn("");
31
- console.warn(" Alpine:");
32
- console.warn(" sudo apk add vips-dev");
33
- console.warn("");
34
- console.warn(" 安装 libvips 后重建 sharp:");
35
- console.warn(" npm install -g chatccc --force");
36
- } else if (msg.includes("Cannot find module")) {
37
- console.warn(" 原因:sharp 模块未成功安装。");
38
- console.warn("");
39
- console.warn(" 请尝试重建(可能需要先安装 libvips):");
40
- console.warn(" npm install -g chatccc --force");
41
- } else {
42
- console.warn(" 错误详情:", msg);
43
- }
44
- } else {
45
- console.warn(" 错误详情:", msg);
46
- console.warn(" 平台:", platform);
47
- console.warn(" 请尝试:npm install -g chatccc --force");
48
- }
49
-
50
- console.warn("");
51
- console.warn(" 缺少 sharp 不影响消息收发,但群聊头像状态指示");
52
- console.warn(" (运行中/空闲/新建)将不会更新。");
53
- console.warn("============================================================");
54
- console.warn("");
55
- }
56
-
57
- if (!ok && process.env.npm_config_verbose) {
58
- process.exitCode = 0; // 永远不阻塞安装
1
+ // postinstall 检测 sharp 原生模块是否可用(常见于 Linux 缺少 libvips)
2
+ import { createRequire } from "node:module";
3
+
4
+ const require = createRequire(import.meta.url);
5
+ let ok = false;
6
+
7
+ try {
8
+ require("sharp");
9
+ ok = true;
10
+ } catch (err) {
11
+ const msg = err.message;
12
+ const platform = process.platform;
13
+
14
+ console.warn("");
15
+ console.warn("============================================================");
16
+ console.warn(" ChatCCC: sharp 图像处理模块检测失败");
17
+ console.warn("============================================================");
18
+
19
+ if (platform === "linux") {
20
+ if (msg.includes("libvips") || msg.includes("vips") || msg.includes("libglib")) {
21
+ console.warn(" 原因:系统缺少 libvips 图像处理库。");
22
+ console.warn("");
23
+ console.warn(" 请先安装 libvips 然后重建 sharp:");
24
+ console.warn("");
25
+ console.warn(" Debian / Ubuntu:");
26
+ console.warn(" sudo apt install libvips-dev");
27
+ console.warn("");
28
+ console.warn(" CentOS / RHEL / Fedora:");
29
+ console.warn(" sudo yum install vips-devel");
30
+ console.warn("");
31
+ console.warn(" Alpine:");
32
+ console.warn(" sudo apk add vips-dev");
33
+ console.warn("");
34
+ console.warn(" 安装 libvips 后重建 sharp:");
35
+ console.warn(" npm install -g chatccc --force");
36
+ } else if (msg.includes("Cannot find module")) {
37
+ console.warn(" 原因:sharp 模块未成功安装。");
38
+ console.warn("");
39
+ console.warn(" 请尝试重建(可能需要先安装 libvips):");
40
+ console.warn(" npm install -g chatccc --force");
41
+ } else {
42
+ console.warn(" 错误详情:", msg);
43
+ }
44
+ } else {
45
+ console.warn(" 错误详情:", msg);
46
+ console.warn(" 平台:", platform);
47
+ console.warn(" 请尝试:npm install -g chatccc --force");
48
+ }
49
+
50
+ console.warn("");
51
+ console.warn(" 缺少 sharp 不影响消息收发,但群聊头像状态指示");
52
+ console.warn(" (运行中/空闲/新建)将不会更新。");
53
+ console.warn("============================================================");
54
+ console.warn("");
55
+ }
56
+
57
+ if (!ok && process.env.npm_config_verbose) {
58
+ process.exitCode = 0; // 永远不阻塞安装
59
59
  }