chatccc 0.2.62 → 0.2.64

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 (35) hide show
  1. package/config.sample.json +2 -3
  2. package/im-skills/feishu-skill/download-video.mjs +10 -17
  3. package/im-skills/wechat-file-skill/receive-send-file.md +39 -0
  4. package/im-skills/wechat-file-skill/send-file.mjs +84 -0
  5. package/im-skills/wechat-file-skill/skill.md +11 -0
  6. package/im-skills/{wechat-skill → wechat-image-skill}/receive-send-image.md +39 -39
  7. package/im-skills/{wechat-skill → wechat-image-skill}/send-image.mjs +84 -80
  8. package/im-skills/{wechat-skill → wechat-image-skill}/skill.md +11 -11
  9. package/im-skills/wechat-video-skill/receive-send-video.md +39 -0
  10. package/im-skills/wechat-video-skill/send-video.mjs +80 -0
  11. package/im-skills/wechat-video-skill/skill.md +11 -0
  12. package/package.json +59 -59
  13. package/src/__tests__/agent-platform-routing.test.ts +26 -0
  14. package/src/__tests__/claude-adapter.test.ts +48 -48
  15. package/src/__tests__/config-reload.test.ts +14 -14
  16. package/src/__tests__/config-sample.test.ts +22 -22
  17. package/src/__tests__/im-skills.test.ts +112 -3
  18. package/src/__tests__/orchestrator.test.ts +1 -1
  19. package/src/__tests__/privacy.test.ts +142 -142
  20. package/src/__tests__/simplify.test.ts +282 -282
  21. package/src/__tests__/web-ui.test.ts +23 -23
  22. package/src/__tests__/wechat-platform.test.ts +65 -0
  23. package/src/adapters/claude-adapter.ts +40 -40
  24. package/src/agent-file-rpc.ts +19 -4
  25. package/src/agent-image-rpc.ts +19 -4
  26. package/src/agent-platform-routing.ts +28 -0
  27. package/src/config.ts +2 -24
  28. package/src/im-skills.ts +9 -0
  29. package/src/index.ts +11 -6
  30. package/src/orchestrator.ts +2 -2
  31. package/src/privacy.ts +67 -67
  32. package/src/session.ts +21 -5
  33. package/src/simplify.ts +119 -119
  34. package/src/web-ui.ts +3 -26
  35. package/src/wechat-platform.ts +170 -30
@@ -1,143 +1,143 @@
1
- import { describe, it, expect, beforeEach, afterEach, afterAll, vi } from "vitest";
2
- import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
-
6
- // 在 import privacy 之前 mock config,让 USER_DATA_DIR 指向临时目录
7
- const TEST_DATA_DIR = await mkdtemp(join(tmpdir(), "chatccc-privacy-test-"));
8
- vi.mock("../config.ts", async () => {
9
- const actual = await vi.importActual<typeof import("../config.ts")>("../config.ts");
10
- return {
11
- ...actual,
12
- USER_DATA_DIR: TEST_DATA_DIR,
13
- ts: () => "test-ts",
14
- };
15
- });
16
-
17
- let applyPrivacy: (text: string) => string;
18
- let reloadPrivacyRules: () => void;
19
- let getPrivacyRules: () => Record<string, string>;
20
-
21
- beforeEach(async () => {
22
- vi.resetModules();
23
- // 清理临时目录中的 privacy.json
24
- try {
25
- await rm(join(TEST_DATA_DIR, "privacy.json"), { force: true });
26
- } catch {}
27
- const mod = await import("../privacy.ts");
28
- applyPrivacy = mod.applyPrivacy;
29
- reloadPrivacyRules = mod.reloadPrivacyRules;
30
- getPrivacyRules = mod.getPrivacyRules;
31
- });
32
-
33
- afterEach(async () => {
34
- try {
35
- await rm(join(TEST_DATA_DIR, "privacy.json"), { force: true });
36
- } catch {}
37
- });
38
-
39
- afterAll(async () => {
40
- try {
41
- await rm(TEST_DATA_DIR, { recursive: true, force: true });
42
- } catch {}
43
- });
44
-
45
- describe("applyPrivacy", () => {
46
- it("无 privacy.json 时返回原文", () => {
47
- reloadPrivacyRules();
48
- expect(applyPrivacy("hello weizhangjian")).toBe("hello weizhangjian");
49
- });
50
-
51
- it("privacy.json 存在时按规则替换", async () => {
52
- await writeFile(
53
- join(TEST_DATA_DIR, "privacy.json"),
54
- JSON.stringify({ weizhangjian: "wzj", secret: "***" }),
55
- "utf-8",
56
- );
57
- reloadPrivacyRules();
58
-
59
- expect(applyPrivacy("hello weizhangjian")).toBe("hello wzj");
60
- expect(applyPrivacy("my secret is safe")).toBe("my *** is safe");
61
- expect(applyPrivacy("weizhangjian and secret")).toBe("wzj and ***");
62
- });
63
-
64
- it("多规则替换多次出现", async () => {
65
- await writeFile(
66
- join(TEST_DATA_DIR, "privacy.json"),
67
- JSON.stringify({ a: "A", b: "B" }),
68
- "utf-8",
69
- );
70
- reloadPrivacyRules();
71
-
72
- expect(applyPrivacy("a b a b")).toBe("A B A B");
73
- });
74
-
75
- it("空文本直接返回", async () => {
76
- await writeFile(
77
- join(TEST_DATA_DIR, "privacy.json"),
78
- JSON.stringify({ x: "y" }),
79
- "utf-8",
80
- );
81
- reloadPrivacyRules();
82
-
83
- expect(applyPrivacy("")).toBe("");
84
- });
85
-
86
- it("规则中的特殊字符不会被当作正则", async () => {
87
- await writeFile(
88
- join(TEST_DATA_DIR, "privacy.json"),
89
- JSON.stringify({ "a.b": "X", "(test)": "Y", "*star": "Z" }),
90
- "utf-8",
91
- );
92
- reloadPrivacyRules();
93
-
94
- expect(applyPrivacy("hello a.b world")).toBe("hello X world");
95
- expect(applyPrivacy("text (test) here")).toBe("text Y here");
96
- expect(applyPrivacy("a *star shines")).toBe("a Z shines");
97
- });
98
-
99
- it("reloadPrivacyRules 强制重新加载", async () => {
100
- await writeFile(
101
- join(TEST_DATA_DIR, "privacy.json"),
102
- JSON.stringify({ old: "OLD" }),
103
- "utf-8",
104
- );
105
- reloadPrivacyRules();
106
-
107
- expect(applyPrivacy("old")).toBe("OLD");
108
- expect(getPrivacyRules()).toEqual({ old: "OLD" });
109
-
110
- // 变更磁盘内容后 reload
111
- await writeFile(
112
- join(TEST_DATA_DIR, "privacy.json"),
113
- JSON.stringify({ new: "NEW" }),
114
- "utf-8",
115
- );
116
- reloadPrivacyRules();
117
-
118
- expect(applyPrivacy("new")).toBe("NEW");
119
- expect(getPrivacyRules()).toEqual({ new: "NEW" });
120
- });
121
-
122
- it("格式错误的 JSON 不抛异常,返回原文", async () => {
123
- await writeFile(
124
- join(TEST_DATA_DIR, "privacy.json"),
125
- "not json",
126
- "utf-8",
127
- );
128
- reloadPrivacyRules();
129
-
130
- expect(applyPrivacy("hello")).toBe("hello");
131
- });
132
-
133
- it("数组格式的 JSON 不抛异常,返回原文", async () => {
134
- await writeFile(
135
- join(TEST_DATA_DIR, "privacy.json"),
136
- JSON.stringify(["a", "b"]),
137
- "utf-8",
138
- );
139
- reloadPrivacyRules();
140
-
141
- expect(applyPrivacy("hello")).toBe("hello");
142
- });
1
+ import { describe, it, expect, beforeEach, afterEach, afterAll, vi } from "vitest";
2
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+
6
+ // 在 import privacy 之前 mock config,让 USER_DATA_DIR 指向临时目录
7
+ const TEST_DATA_DIR = await mkdtemp(join(tmpdir(), "chatccc-privacy-test-"));
8
+ vi.mock("../config.ts", async () => {
9
+ const actual = await vi.importActual<typeof import("../config.ts")>("../config.ts");
10
+ return {
11
+ ...actual,
12
+ USER_DATA_DIR: TEST_DATA_DIR,
13
+ ts: () => "test-ts",
14
+ };
15
+ });
16
+
17
+ let applyPrivacy: (text: string) => string;
18
+ let reloadPrivacyRules: () => void;
19
+ let getPrivacyRules: () => Record<string, string>;
20
+
21
+ beforeEach(async () => {
22
+ vi.resetModules();
23
+ // 清理临时目录中的 privacy.json
24
+ try {
25
+ await rm(join(TEST_DATA_DIR, "privacy.json"), { force: true });
26
+ } catch {}
27
+ const mod = await import("../privacy.ts");
28
+ applyPrivacy = mod.applyPrivacy;
29
+ reloadPrivacyRules = mod.reloadPrivacyRules;
30
+ getPrivacyRules = mod.getPrivacyRules;
31
+ });
32
+
33
+ afterEach(async () => {
34
+ try {
35
+ await rm(join(TEST_DATA_DIR, "privacy.json"), { force: true });
36
+ } catch {}
37
+ });
38
+
39
+ afterAll(async () => {
40
+ try {
41
+ await rm(TEST_DATA_DIR, { recursive: true, force: true });
42
+ } catch {}
43
+ });
44
+
45
+ describe("applyPrivacy", () => {
46
+ it("无 privacy.json 时返回原文", () => {
47
+ reloadPrivacyRules();
48
+ expect(applyPrivacy("hello weizhangjian")).toBe("hello weizhangjian");
49
+ });
50
+
51
+ it("privacy.json 存在时按规则替换", async () => {
52
+ await writeFile(
53
+ join(TEST_DATA_DIR, "privacy.json"),
54
+ JSON.stringify({ weizhangjian: "wzj", secret: "***" }),
55
+ "utf-8",
56
+ );
57
+ reloadPrivacyRules();
58
+
59
+ expect(applyPrivacy("hello weizhangjian")).toBe("hello wzj");
60
+ expect(applyPrivacy("my secret is safe")).toBe("my *** is safe");
61
+ expect(applyPrivacy("weizhangjian and secret")).toBe("wzj and ***");
62
+ });
63
+
64
+ it("多规则替换多次出现", async () => {
65
+ await writeFile(
66
+ join(TEST_DATA_DIR, "privacy.json"),
67
+ JSON.stringify({ a: "A", b: "B" }),
68
+ "utf-8",
69
+ );
70
+ reloadPrivacyRules();
71
+
72
+ expect(applyPrivacy("a b a b")).toBe("A B A B");
73
+ });
74
+
75
+ it("空文本直接返回", async () => {
76
+ await writeFile(
77
+ join(TEST_DATA_DIR, "privacy.json"),
78
+ JSON.stringify({ x: "y" }),
79
+ "utf-8",
80
+ );
81
+ reloadPrivacyRules();
82
+
83
+ expect(applyPrivacy("")).toBe("");
84
+ });
85
+
86
+ it("规则中的特殊字符不会被当作正则", async () => {
87
+ await writeFile(
88
+ join(TEST_DATA_DIR, "privacy.json"),
89
+ JSON.stringify({ "a.b": "X", "(test)": "Y", "*star": "Z" }),
90
+ "utf-8",
91
+ );
92
+ reloadPrivacyRules();
93
+
94
+ expect(applyPrivacy("hello a.b world")).toBe("hello X world");
95
+ expect(applyPrivacy("text (test) here")).toBe("text Y here");
96
+ expect(applyPrivacy("a *star shines")).toBe("a Z shines");
97
+ });
98
+
99
+ it("reloadPrivacyRules 强制重新加载", async () => {
100
+ await writeFile(
101
+ join(TEST_DATA_DIR, "privacy.json"),
102
+ JSON.stringify({ old: "OLD" }),
103
+ "utf-8",
104
+ );
105
+ reloadPrivacyRules();
106
+
107
+ expect(applyPrivacy("old")).toBe("OLD");
108
+ expect(getPrivacyRules()).toEqual({ old: "OLD" });
109
+
110
+ // 变更磁盘内容后 reload
111
+ await writeFile(
112
+ join(TEST_DATA_DIR, "privacy.json"),
113
+ JSON.stringify({ new: "NEW" }),
114
+ "utf-8",
115
+ );
116
+ reloadPrivacyRules();
117
+
118
+ expect(applyPrivacy("new")).toBe("NEW");
119
+ expect(getPrivacyRules()).toEqual({ new: "NEW" });
120
+ });
121
+
122
+ it("格式错误的 JSON 不抛异常,返回原文", async () => {
123
+ await writeFile(
124
+ join(TEST_DATA_DIR, "privacy.json"),
125
+ "not json",
126
+ "utf-8",
127
+ );
128
+ reloadPrivacyRules();
129
+
130
+ expect(applyPrivacy("hello")).toBe("hello");
131
+ });
132
+
133
+ it("数组格式的 JSON 不抛异常,返回原文", async () => {
134
+ await writeFile(
135
+ join(TEST_DATA_DIR, "privacy.json"),
136
+ JSON.stringify(["a", "b"]),
137
+ "utf-8",
138
+ );
139
+ reloadPrivacyRules();
140
+
141
+ expect(applyPrivacy("hello")).toBe("hello");
142
+ });
143
143
  });