chatccc 0.2.235 → 0.2.236

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 CHANGED
@@ -230,7 +230,7 @@ CCC Agent 是 ChatCCC 内置的编程 Agent,不需要额外安装 CLI,开箱
230
230
 
231
231
  #### Claude Code
232
232
 
233
- ChatCCC 通过 Anthropic Claude Agent SDK 调用 Claude Code 能力。SDK 引擎(含 Claude Code CLI 原生二进制,约 220MB)**按需下载**:在首次配置向导或 Web 管理页的「Claude Code」卡片点「安装引擎」,页面会显示下载进度条,完成后即可使用。**只有启用 Claude Code 的用户才需要下载**,不使用 Claude Code 的安装不包含该引擎,chatccc 主包体积保持精简。
233
+ ChatCCC 通过 Anthropic Claude Agent SDK 调用 Claude Code 能力。SDK 引擎(含 Claude Code CLI 原生二进制,约 220MB)**按需下载**:在首次配置向导或 Web 管理页的「Claude Code」卡片点「安装 Claude Code SDK」(开关从关闭切到打开时也会弹出安装确认),页面会显示下载进度条,完成后即可使用。**只有启用 Claude Code 的用户才需要下载**,不使用 Claude Code 的安装不包含该引擎,chatccc 主包体积保持精简。
234
234
 
235
235
  SDK 始终使用其内置的 Claude Code CLI(档位 b),不依赖用户自行安装的 `claude` 命令。本机完成 Claude Code 登录后即可使用(SDK 复用 `~/.claude` 登录态);同时支持官方和第三方 Anthropic 兼容 API:使用官方服务无需额外配置,使用第三方 API 则填写 `claude.apiKey` 和 `claude.baseUrl`。`claude.model`、`claude.subagentModel`、`claude.effort`、`claude.apiKey`、`claude.baseUrl` 均为选填;`claude.maxTurn` 控制每次对话的最大轮数(默认 0,即无限制)。填写后会把对应配置传给 Claude Agent SDK;留空则以 `~/.claude/settings.json` 为准。
236
236
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatccc",
3
- "version": "0.2.235",
3
+ "version": "0.2.236",
4
4
  "description": "Feishu bot bridge for Claude Code",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -59,7 +59,6 @@
59
59
  "ws": "^8.18.0"
60
60
  },
61
61
  "devDependencies": {
62
- "@anthropic-ai/claude-agent-sdk": "0.2.133",
63
62
  "@types/node": "^20.0.0",
64
63
  "@types/qrcode-terminal": "^0.12.2",
65
64
  "@types/ws": "^8.18.1",
@@ -1,96 +1,96 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
-
3
- const resumeSessionMock = vi.hoisted(() => vi.fn());
4
- const createRawStreamLogMock = vi.hoisted(() => vi.fn());
5
- const rawLogWriteLineMock = vi.hoisted(() => vi.fn());
6
- const rawLogCloseMock = vi.hoisted(() => vi.fn());
7
-
8
- // 注意:SDK 已从 chatccc 依赖中移除,改为按需安装 + 动态 import(变量路径),
9
- // vi.mock 无法拦截;这里通过 __setClaudeSdkModuleForTest 注入假 SDK 模块。
10
-
11
- vi.mock("../adapters/raw-stream-log.ts", () => ({
12
- createRawStreamLog: createRawStreamLogMock,
13
- }));
14
-
15
- import { config } from "../config.ts";
16
- import {
17
- __setClaudeSdkModuleForTest,
18
- createClaudeAdapter,
19
- } from "../adapters/claude-adapter.ts";
20
-
21
- const originalRawStreamLogs = structuredClone(config.rawStreamLogs);
22
-
23
- async function collect(iterable: AsyncIterable<unknown>): Promise<unknown[]> {
24
- const events: unknown[] = [];
25
- for await (const event of iterable) events.push(event);
26
- return events;
27
- }
28
-
29
- beforeEach(() => {
30
- __setClaudeSdkModuleForTest({
31
- getSessionInfo: vi.fn(),
32
- unstable_v2_createSession: vi.fn(),
33
- unstable_v2_resumeSession: resumeSessionMock,
34
- });
35
- });
36
-
37
- afterEach(() => {
38
- __setClaudeSdkModuleForTest(null);
39
- resumeSessionMock.mockReset();
40
- createRawStreamLogMock.mockReset();
41
- rawLogWriteLineMock.mockReset();
42
- rawLogCloseMock.mockReset();
43
- config.rawStreamLogs = structuredClone(originalRawStreamLogs);
44
- });
45
-
46
- describe("Claude raw stream logs", () => {
47
- it("writes raw Claude SDK stream messages when enabled", async () => {
48
- const rawMessages = [
49
- { type: "system", subtype: "init", session_id: "sid-raw", cwd: "F:/project", model: "claude-test" },
50
- { type: "assistant", message: { content: [{ type: "text", text: "hello" }] } },
51
- ];
52
- const session = {
53
- send: vi.fn(async () => {}),
54
- stream: async function* () {
55
- for (const msg of rawMessages) yield msg;
56
- },
57
- close: vi.fn(),
58
- };
59
- resumeSessionMock.mockReturnValueOnce(session);
60
- createRawStreamLogMock.mockResolvedValueOnce({
61
- filePath: "claude.jsonl.gz",
62
- writeLine: rawLogWriteLineMock,
63
- close: rawLogCloseMock,
64
- });
65
- config.rawStreamLogs.claude = {
66
- enabled: true,
67
- maxBytesPerTurn: 4096,
68
- retentionDays: 5,
69
- keepCompleted: false,
70
- };
71
-
72
- const adapter = createClaudeAdapter({
73
- model: "claude-test",
74
- effort: "high",
75
- isEmpty: (value) => value.trim() === "",
76
- });
77
- const events = await collect(adapter.prompt("sid-raw", "hi", "F:/project"));
78
-
79
- expect(createRawStreamLogMock).toHaveBeenCalledWith(expect.objectContaining({
80
- enabled: true,
81
- tool: "claude",
82
- sessionId: "sid-raw",
83
- label: "prompt",
84
- maxBytesPerTurn: 4096,
85
- retentionDays: 5,
86
- }));
87
- expect(rawLogWriteLineMock).toHaveBeenNthCalledWith(1, JSON.stringify(rawMessages[0]));
88
- expect(rawLogWriteLineMock).toHaveBeenNthCalledWith(2, JSON.stringify(rawMessages[1]));
89
- expect(rawLogCloseMock).toHaveBeenCalledWith({ keep: false });
90
- expect(session.close).toHaveBeenCalledOnce();
91
- expect(events).toContainEqual({
92
- type: "assistant",
93
- blocks: [{ type: "text", text: "hello" }],
94
- });
95
- });
96
- });
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+
3
+ const resumeSessionMock = vi.hoisted(() => vi.fn());
4
+ const createRawStreamLogMock = vi.hoisted(() => vi.fn());
5
+ const rawLogWriteLineMock = vi.hoisted(() => vi.fn());
6
+ const rawLogCloseMock = vi.hoisted(() => vi.fn());
7
+
8
+ // 注意:SDK 已从 chatccc 依赖中移除,改为按需安装 + 动态 import(变量路径),
9
+ // vi.mock 无法拦截;这里通过 __setClaudeSdkModuleForTest 注入假 SDK 模块。
10
+
11
+ vi.mock("../adapters/raw-stream-log.ts", () => ({
12
+ createRawStreamLog: createRawStreamLogMock,
13
+ }));
14
+
15
+ import { config } from "../config.ts";
16
+ import {
17
+ __setClaudeSdkModuleForTest,
18
+ createClaudeAdapter,
19
+ } from "../adapters/claude-adapter.ts";
20
+
21
+ const originalRawStreamLogs = structuredClone(config.rawStreamLogs);
22
+
23
+ async function collect(iterable: AsyncIterable<unknown>): Promise<unknown[]> {
24
+ const events: unknown[] = [];
25
+ for await (const event of iterable) events.push(event);
26
+ return events;
27
+ }
28
+
29
+ beforeEach(() => {
30
+ __setClaudeSdkModuleForTest({
31
+ getSessionInfo: vi.fn(),
32
+ unstable_v2_createSession: vi.fn(),
33
+ unstable_v2_resumeSession: resumeSessionMock,
34
+ });
35
+ });
36
+
37
+ afterEach(() => {
38
+ __setClaudeSdkModuleForTest(null);
39
+ resumeSessionMock.mockReset();
40
+ createRawStreamLogMock.mockReset();
41
+ rawLogWriteLineMock.mockReset();
42
+ rawLogCloseMock.mockReset();
43
+ config.rawStreamLogs = structuredClone(originalRawStreamLogs);
44
+ });
45
+
46
+ describe("Claude raw stream logs", () => {
47
+ it("writes raw Claude SDK stream messages when enabled", async () => {
48
+ const rawMessages = [
49
+ { type: "system", subtype: "init", session_id: "sid-raw", cwd: "F:/project", model: "claude-test" },
50
+ { type: "assistant", message: { content: [{ type: "text", text: "hello" }] } },
51
+ ];
52
+ const session = {
53
+ send: vi.fn(async () => {}),
54
+ stream: async function* () {
55
+ for (const msg of rawMessages) yield msg;
56
+ },
57
+ close: vi.fn(),
58
+ };
59
+ resumeSessionMock.mockReturnValueOnce(session);
60
+ createRawStreamLogMock.mockResolvedValueOnce({
61
+ filePath: "claude.jsonl.gz",
62
+ writeLine: rawLogWriteLineMock,
63
+ close: rawLogCloseMock,
64
+ });
65
+ config.rawStreamLogs.claude = {
66
+ enabled: true,
67
+ maxBytesPerTurn: 4096,
68
+ retentionDays: 5,
69
+ keepCompleted: false,
70
+ };
71
+
72
+ const adapter = createClaudeAdapter({
73
+ model: "claude-test",
74
+ effort: "high",
75
+ isEmpty: (value) => value.trim() === "",
76
+ });
77
+ const events = await collect(adapter.prompt("sid-raw", "hi", "F:/project"));
78
+
79
+ expect(createRawStreamLogMock).toHaveBeenCalledWith(expect.objectContaining({
80
+ enabled: true,
81
+ tool: "claude",
82
+ sessionId: "sid-raw",
83
+ label: "prompt",
84
+ maxBytesPerTurn: 4096,
85
+ retentionDays: 5,
86
+ }));
87
+ expect(rawLogWriteLineMock).toHaveBeenNthCalledWith(1, JSON.stringify(rawMessages[0]));
88
+ expect(rawLogWriteLineMock).toHaveBeenNthCalledWith(2, JSON.stringify(rawMessages[1]));
89
+ expect(rawLogCloseMock).toHaveBeenCalledWith({ keep: false });
90
+ expect(session.close).toHaveBeenCalledOnce();
91
+ expect(events).toContainEqual({
92
+ type: "assistant",
93
+ blocks: [{ type: "text", text: "hello" }],
94
+ });
95
+ });
96
+ });