chatccc 0.2.190 → 0.2.191

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 (67) hide show
  1. package/agent-prompts/claude_specific.md +45 -45
  2. package/agent-prompts/codex_specific.md +2 -2
  3. package/agent-prompts/cursor_specific.md +13 -13
  4. package/config.sample.json +14 -14
  5. package/im-skills/feishu-skill/receive-send-file.md +63 -63
  6. package/im-skills/feishu-skill/receive-send-image.md +24 -24
  7. package/im-skills/feishu-skill/skill.md +3 -3
  8. package/im-skills/wechat-file-skill/receive-send-file.md +38 -38
  9. package/im-skills/wechat-file-skill/send-file.mjs +83 -83
  10. package/im-skills/wechat-file-skill/skill.md +10 -10
  11. package/im-skills/wechat-image-skill/skill.md +10 -10
  12. package/im-skills/wechat-video-skill/receive-send-video.md +38 -38
  13. package/im-skills/wechat-video-skill/send-video.mjs +79 -79
  14. package/im-skills/wechat-video-skill/skill.md +10 -10
  15. package/package.json +1 -1
  16. package/scripts/postinstall-sharp-check.mjs +58 -58
  17. package/src/__tests__/agent-delegate-task-rpc.test.ts +165 -165
  18. package/src/__tests__/builtin-config.test.ts +33 -33
  19. package/src/__tests__/card-plain-text.test.ts +5 -5
  20. package/src/__tests__/cardkit.test.ts +60 -60
  21. package/src/__tests__/cards.test.ts +77 -77
  22. package/src/__tests__/chatgpt-subscription-rpc.test.ts +89 -89
  23. package/src/__tests__/chatgpt-subscription.test.ts +135 -135
  24. package/src/__tests__/chrome-devtools-guard.test.ts +165 -165
  25. package/src/__tests__/claude-adapter.test.ts +592 -592
  26. package/src/__tests__/codex-reset-actions.test.ts +146 -146
  27. package/src/__tests__/config-reload.test.ts +4 -4
  28. package/src/__tests__/config-sample.test.ts +17 -17
  29. package/src/__tests__/feishu-api.test.ts +60 -60
  30. package/src/__tests__/feishu-platform.test.ts +22 -22
  31. package/src/__tests__/format-message.test.ts +47 -47
  32. package/src/__tests__/orchestrator.test.ts +120 -120
  33. package/src/__tests__/privacy.test.ts +198 -198
  34. package/src/__tests__/raw-stream-log.test.ts +106 -106
  35. package/src/__tests__/session.test.ts +17 -17
  36. package/src/__tests__/shared-prefix.test.ts +36 -36
  37. package/src/__tests__/stream-state.test.ts +42 -42
  38. package/src/__tests__/web-ui.test.ts +209 -209
  39. package/src/adapters/claude-adapter.ts +566 -566
  40. package/src/adapters/claude-session-meta-store.ts +120 -120
  41. package/src/adapters/codex-adapter.ts +30 -30
  42. package/src/adapters/cursor-adapter.ts +46 -46
  43. package/src/adapters/raw-stream-log.ts +124 -124
  44. package/src/adapters/resource-monitor.ts +140 -140
  45. package/src/agent-delegate-task-rpc.ts +153 -153
  46. package/src/agent-delegate-task.ts +81 -81
  47. package/src/agent-stop-stuck.ts +129 -129
  48. package/src/builtin/cli.ts +204 -189
  49. package/src/builtin/index.ts +170 -170
  50. package/src/cards.ts +137 -137
  51. package/src/chatgpt-subscription-rpc.ts +27 -27
  52. package/src/chatgpt-subscription.ts +299 -299
  53. package/src/chrome-devtools-guard.ts +318 -318
  54. package/src/codex-reset-actions.ts +184 -184
  55. package/src/config.ts +86 -86
  56. package/src/feishu-platform.ts +20 -20
  57. package/src/format-message.ts +293 -293
  58. package/src/litellm-proxy.ts +374 -374
  59. package/src/orchestrator.ts +143 -143
  60. package/src/privacy.ts +118 -118
  61. package/src/session-chat-binding.ts +6 -6
  62. package/src/session-name.ts +8 -8
  63. package/src/session.ts +98 -98
  64. package/src/shared-prefix.ts +29 -29
  65. package/src/sim-platform.ts +20 -20
  66. package/src/turn-cards.ts +117 -117
  67. package/src/web-ui.ts +205 -205
@@ -1,165 +1,165 @@
1
- import { describe, expect, it, vi } from "vitest";
2
- import { spawn } from "node:child_process";
3
-
4
- import {
5
- ensureChromeCdpRunning,
6
- ensureChatcccPageOpen,
7
- isChromeCdpHealthy,
8
- probeChromeCdp,
9
- resolveChromeExecutable,
10
- resolveChromeUserDataDir,
11
- } from "../chrome-devtools-guard.ts";
12
-
13
- describe("Chrome CDP guard", () => {
14
- it("treats /json/version with Browser as healthy", async () => {
15
- const fetchImpl = vi.fn(async () =>
16
- new Response(JSON.stringify({ Browser: "Chrome/144.0.0.0" }), { status: 200 }),
17
- ) as unknown as typeof fetch;
18
-
19
- await expect(isChromeCdpHealthy(15166, { fetchImpl })).resolves.toBe(true);
20
- });
21
-
22
- it("does not spawn Chrome when the CDP endpoint is already healthy", async () => {
23
- const fetchImpl = vi.fn(async () =>
24
- new Response(JSON.stringify({ webSocketDebuggerUrl: "ws://127.0.0.1:15166/devtools/browser/1" }), { status: 200 }),
25
- ) as unknown as typeof fetch;
26
- const spawnImpl = vi.fn() as unknown as typeof spawn;
27
-
28
- await expect(
29
- ensureChromeCdpRunning(
30
- { enabled: true, port: 15166, chromePath: "C:/Chrome/chrome.exe" },
31
- { fetchImpl, spawnImpl },
32
- ),
33
- ).resolves.toEqual({ ok: true, started: false, port: 15166 });
34
- expect(spawnImpl).not.toHaveBeenCalled();
35
- });
36
-
37
- it("spawns Chrome with a dedicated profile when the endpoint is unhealthy", async () => {
38
- const fetchImpl = vi.fn()
39
- .mockRejectedValueOnce(new Error("ECONNREFUSED"))
40
- .mockResolvedValue(new Response(JSON.stringify({ Browser: "Chrome/144.0.0.0" }), { status: 200 })) as unknown as typeof fetch;
41
- const unref = vi.fn();
42
- const spawnImpl = vi.fn(() => ({ unref })) as unknown as typeof spawn;
43
- const mkdirSyncImpl = vi.fn();
44
-
45
- await expect(
46
- ensureChromeCdpRunning(
47
- { enabled: true, port: 15166, chromePath: "C:/Chrome/chrome.exe" },
48
- {
49
- fetchImpl,
50
- spawnImpl,
51
- mkdirSyncImpl: mkdirSyncImpl as never,
52
- existsSyncImpl: vi.fn(() => true),
53
- env: { LOCALAPPDATA: "C:/Users/me/AppData/Local" },
54
- },
55
- ),
56
- ).resolves.toEqual({ ok: true, started: true, port: 15166 });
57
-
58
- expect(mkdirSyncImpl).toHaveBeenCalledWith("C:\\Users\\me\\AppData\\Local\\chatccc\\chrome-cdp-15166", { recursive: true });
59
- expect(spawnImpl).toHaveBeenCalledWith(
60
- "C:/Chrome/chrome.exe",
61
- expect.arrayContaining([
62
- "--remote-debugging-address=127.0.0.1",
63
- "--remote-debugging-port=15166",
64
- "--user-data-dir=C:\\Users\\me\\AppData\\Local\\chatccc\\chrome-cdp-15166",
65
- "--new-window",
66
- "about:blank",
67
- ]),
68
- expect.objectContaining({ detached: true, stdio: "ignore", windowsHide: true }),
69
- );
70
- expect(unref).toHaveBeenCalled();
71
- });
72
-
73
- it("does not spawn Chrome when the port is occupied by a non-CDP service", async () => {
74
- const fetchImpl = vi.fn(async () => new Response("not found", { status: 404 })) as unknown as typeof fetch;
75
- const spawnImpl = vi.fn() as unknown as typeof spawn;
76
-
77
- await expect(probeChromeCdp(15166, { fetchImpl })).resolves.toBe("occupied");
78
- await expect(
79
- ensureChromeCdpRunning(
80
- { enabled: true, port: 15166, chromePath: "C:/Chrome/chrome.exe" },
81
- { fetchImpl, spawnImpl },
82
- ),
83
- ).resolves.toMatchObject({
84
- ok: false,
85
- started: false,
86
- port: 15166,
87
- error: expect.stringContaining("not a healthy Chrome CDP endpoint"),
88
- });
89
- expect(spawnImpl).not.toHaveBeenCalled();
90
- });
91
-
92
- it("reports a clear error when Chrome cannot be found", async () => {
93
- const fetchImpl = vi.fn(async () => { throw new Error("ECONNREFUSED"); }) as unknown as typeof fetch;
94
-
95
- await expect(
96
- ensureChromeCdpRunning(
97
- { enabled: true, port: 15166, chromePath: "" },
98
- {
99
- fetchImpl,
100
- existsSyncImpl: vi.fn(() => false),
101
- platform: "win32",
102
- env: {},
103
- },
104
- ),
105
- ).resolves.toMatchObject({
106
- ok: false,
107
- started: false,
108
- port: 15166,
109
- error: expect.stringContaining("Cannot find chrome executable"),
110
- });
111
- });
112
-
113
- it("resolves explicit and default Chrome paths", () => {
114
- expect(resolveChromeExecutable("C:/Chrome/chrome.exe", { existsSyncImpl: vi.fn(() => true) })).toBe("C:/Chrome/chrome.exe");
115
- expect(resolveChromeExecutable("", {
116
- existsSyncImpl: vi.fn((p: unknown) => String(p).endsWith("Google\\Chrome\\Application\\chrome.exe")),
117
- platform: "win32",
118
- env: { ProgramFiles: "C:/Program Files" },
119
- })).toBe("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe");
120
- });
121
-
122
- it("uses LocalAppData for the Chrome CDP user data directory", () => {
123
- expect(resolveChromeUserDataDir(15166, { LOCALAPPDATA: "C:/Users/me/AppData/Local" }))
124
- .toBe("C:\\Users\\me\\AppData\\Local\\chatccc\\chrome-cdp-15166");
125
- });
126
-
127
- it("opens the configured ChatCCC page when no localhost or loopback page is present", async () => {
128
- const fetchImpl = vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
129
- const url = String(input);
130
- if (url === "http://127.0.0.1:15166/json/list") {
131
- return new Response(JSON.stringify([
132
- { id: "chatgpt", type: "page", url: "https://chatgpt.com/", webSocketDebuggerUrl: "ws://page" },
133
- ]), { status: 200 });
134
- }
135
- if (url === "http://127.0.0.1:15166/json/new?http%3A%2F%2Flocalhost%3A18081%2F") {
136
- expect(init?.method).toBe("PUT");
137
- return new Response(JSON.stringify({ id: "chatccc" }), { status: 200 });
138
- }
139
- throw new Error(`unexpected fetch ${url}`);
140
- }) as unknown as typeof fetch;
141
-
142
- await expect(ensureChatcccPageOpen(15166, 18081, { fetchImpl })).resolves.toEqual({
143
- ok: true,
144
- opened: true,
145
- });
146
- });
147
-
148
- it("does not open another ChatCCC page when localhost or 127.0.0.1 is already present", async () => {
149
- const fetchImpl = vi.fn(async (input: string | URL | Request) => {
150
- const url = String(input);
151
- if (url === "http://127.0.0.1:15166/json/list") {
152
- return new Response(JSON.stringify([
153
- { id: "chatccc", type: "page", url: "http://127.0.0.1:18080/", webSocketDebuggerUrl: "ws://page" },
154
- ]), { status: 200 });
155
- }
156
- throw new Error(`unexpected fetch ${url}`);
157
- }) as unknown as typeof fetch;
158
-
159
- await expect(ensureChatcccPageOpen(15166, 18080, { fetchImpl })).resolves.toEqual({
160
- ok: true,
161
- opened: false,
162
- });
163
- expect(fetchImpl).toHaveBeenCalledTimes(1);
164
- });
165
- });
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { spawn } from "node:child_process";
3
+
4
+ import {
5
+ ensureChromeCdpRunning,
6
+ ensureChatcccPageOpen,
7
+ isChromeCdpHealthy,
8
+ probeChromeCdp,
9
+ resolveChromeExecutable,
10
+ resolveChromeUserDataDir,
11
+ } from "../chrome-devtools-guard.ts";
12
+
13
+ describe("Chrome CDP guard", () => {
14
+ it("treats /json/version with Browser as healthy", async () => {
15
+ const fetchImpl = vi.fn(async () =>
16
+ new Response(JSON.stringify({ Browser: "Chrome/144.0.0.0" }), { status: 200 }),
17
+ ) as unknown as typeof fetch;
18
+
19
+ await expect(isChromeCdpHealthy(15166, { fetchImpl })).resolves.toBe(true);
20
+ });
21
+
22
+ it("does not spawn Chrome when the CDP endpoint is already healthy", async () => {
23
+ const fetchImpl = vi.fn(async () =>
24
+ new Response(JSON.stringify({ webSocketDebuggerUrl: "ws://127.0.0.1:15166/devtools/browser/1" }), { status: 200 }),
25
+ ) as unknown as typeof fetch;
26
+ const spawnImpl = vi.fn() as unknown as typeof spawn;
27
+
28
+ await expect(
29
+ ensureChromeCdpRunning(
30
+ { enabled: true, port: 15166, chromePath: "C:/Chrome/chrome.exe" },
31
+ { fetchImpl, spawnImpl },
32
+ ),
33
+ ).resolves.toEqual({ ok: true, started: false, port: 15166 });
34
+ expect(spawnImpl).not.toHaveBeenCalled();
35
+ });
36
+
37
+ it("spawns Chrome with a dedicated profile when the endpoint is unhealthy", async () => {
38
+ const fetchImpl = vi.fn()
39
+ .mockRejectedValueOnce(new Error("ECONNREFUSED"))
40
+ .mockResolvedValue(new Response(JSON.stringify({ Browser: "Chrome/144.0.0.0" }), { status: 200 })) as unknown as typeof fetch;
41
+ const unref = vi.fn();
42
+ const spawnImpl = vi.fn(() => ({ unref })) as unknown as typeof spawn;
43
+ const mkdirSyncImpl = vi.fn();
44
+
45
+ await expect(
46
+ ensureChromeCdpRunning(
47
+ { enabled: true, port: 15166, chromePath: "C:/Chrome/chrome.exe" },
48
+ {
49
+ fetchImpl,
50
+ spawnImpl,
51
+ mkdirSyncImpl: mkdirSyncImpl as never,
52
+ existsSyncImpl: vi.fn(() => true),
53
+ env: { LOCALAPPDATA: "C:/Users/me/AppData/Local" },
54
+ },
55
+ ),
56
+ ).resolves.toEqual({ ok: true, started: true, port: 15166 });
57
+
58
+ expect(mkdirSyncImpl).toHaveBeenCalledWith("C:\\Users\\me\\AppData\\Local\\chatccc\\chrome-cdp-15166", { recursive: true });
59
+ expect(spawnImpl).toHaveBeenCalledWith(
60
+ "C:/Chrome/chrome.exe",
61
+ expect.arrayContaining([
62
+ "--remote-debugging-address=127.0.0.1",
63
+ "--remote-debugging-port=15166",
64
+ "--user-data-dir=C:\\Users\\me\\AppData\\Local\\chatccc\\chrome-cdp-15166",
65
+ "--new-window",
66
+ "about:blank",
67
+ ]),
68
+ expect.objectContaining({ detached: true, stdio: "ignore", windowsHide: true }),
69
+ );
70
+ expect(unref).toHaveBeenCalled();
71
+ });
72
+
73
+ it("does not spawn Chrome when the port is occupied by a non-CDP service", async () => {
74
+ const fetchImpl = vi.fn(async () => new Response("not found", { status: 404 })) as unknown as typeof fetch;
75
+ const spawnImpl = vi.fn() as unknown as typeof spawn;
76
+
77
+ await expect(probeChromeCdp(15166, { fetchImpl })).resolves.toBe("occupied");
78
+ await expect(
79
+ ensureChromeCdpRunning(
80
+ { enabled: true, port: 15166, chromePath: "C:/Chrome/chrome.exe" },
81
+ { fetchImpl, spawnImpl },
82
+ ),
83
+ ).resolves.toMatchObject({
84
+ ok: false,
85
+ started: false,
86
+ port: 15166,
87
+ error: expect.stringContaining("not a healthy Chrome CDP endpoint"),
88
+ });
89
+ expect(spawnImpl).not.toHaveBeenCalled();
90
+ });
91
+
92
+ it("reports a clear error when Chrome cannot be found", async () => {
93
+ const fetchImpl = vi.fn(async () => { throw new Error("ECONNREFUSED"); }) as unknown as typeof fetch;
94
+
95
+ await expect(
96
+ ensureChromeCdpRunning(
97
+ { enabled: true, port: 15166, chromePath: "" },
98
+ {
99
+ fetchImpl,
100
+ existsSyncImpl: vi.fn(() => false),
101
+ platform: "win32",
102
+ env: {},
103
+ },
104
+ ),
105
+ ).resolves.toMatchObject({
106
+ ok: false,
107
+ started: false,
108
+ port: 15166,
109
+ error: expect.stringContaining("Cannot find chrome executable"),
110
+ });
111
+ });
112
+
113
+ it("resolves explicit and default Chrome paths", () => {
114
+ expect(resolveChromeExecutable("C:/Chrome/chrome.exe", { existsSyncImpl: vi.fn(() => true) })).toBe("C:/Chrome/chrome.exe");
115
+ expect(resolveChromeExecutable("", {
116
+ existsSyncImpl: vi.fn((p: unknown) => String(p).endsWith("Google\\Chrome\\Application\\chrome.exe")),
117
+ platform: "win32",
118
+ env: { ProgramFiles: "C:/Program Files" },
119
+ })).toBe("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe");
120
+ });
121
+
122
+ it("uses LocalAppData for the Chrome CDP user data directory", () => {
123
+ expect(resolveChromeUserDataDir(15166, { LOCALAPPDATA: "C:/Users/me/AppData/Local" }))
124
+ .toBe("C:\\Users\\me\\AppData\\Local\\chatccc\\chrome-cdp-15166");
125
+ });
126
+
127
+ it("opens the configured ChatCCC page when no localhost or loopback page is present", async () => {
128
+ const fetchImpl = vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
129
+ const url = String(input);
130
+ if (url === "http://127.0.0.1:15166/json/list") {
131
+ return new Response(JSON.stringify([
132
+ { id: "chatgpt", type: "page", url: "https://chatgpt.com/", webSocketDebuggerUrl: "ws://page" },
133
+ ]), { status: 200 });
134
+ }
135
+ if (url === "http://127.0.0.1:15166/json/new?http%3A%2F%2Flocalhost%3A18081%2F") {
136
+ expect(init?.method).toBe("PUT");
137
+ return new Response(JSON.stringify({ id: "chatccc" }), { status: 200 });
138
+ }
139
+ throw new Error(`unexpected fetch ${url}`);
140
+ }) as unknown as typeof fetch;
141
+
142
+ await expect(ensureChatcccPageOpen(15166, 18081, { fetchImpl })).resolves.toEqual({
143
+ ok: true,
144
+ opened: true,
145
+ });
146
+ });
147
+
148
+ it("does not open another ChatCCC page when localhost or 127.0.0.1 is already present", async () => {
149
+ const fetchImpl = vi.fn(async (input: string | URL | Request) => {
150
+ const url = String(input);
151
+ if (url === "http://127.0.0.1:15166/json/list") {
152
+ return new Response(JSON.stringify([
153
+ { id: "chatccc", type: "page", url: "http://127.0.0.1:18080/", webSocketDebuggerUrl: "ws://page" },
154
+ ]), { status: 200 });
155
+ }
156
+ throw new Error(`unexpected fetch ${url}`);
157
+ }) as unknown as typeof fetch;
158
+
159
+ await expect(ensureChatcccPageOpen(15166, 18080, { fetchImpl })).resolves.toEqual({
160
+ ok: true,
161
+ opened: false,
162
+ });
163
+ expect(fetchImpl).toHaveBeenCalledTimes(1);
164
+ });
165
+ });