chatccc 0.2.196 → 0.2.198

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 (53) hide show
  1. package/agent-prompts/cursor_specific.md +13 -13
  2. package/bin/cccagent.mjs +17 -17
  3. package/config.sample.json +27 -27
  4. package/package.json +2 -1
  5. package/src/__tests__/agent-reload-config-rpc.test.ts +99 -0
  6. package/src/__tests__/builtin-chat-session.test.ts +277 -181
  7. package/src/__tests__/builtin-cli-json.test.ts +39 -39
  8. package/src/__tests__/builtin-config.test.ts +33 -33
  9. package/src/__tests__/builtin-context.test.ts +163 -163
  10. package/src/__tests__/builtin-file-tools.test.ts +224 -196
  11. package/src/__tests__/builtin-session-select.test.ts +116 -116
  12. package/src/__tests__/builtin-sigint.test.ts +56 -56
  13. package/src/__tests__/cards.test.ts +109 -109
  14. package/src/__tests__/ccc-adapter.test.ts +114 -113
  15. package/src/__tests__/chatgpt-subscription-rpc.test.ts +89 -89
  16. package/src/__tests__/chatgpt-subscription.test.ts +135 -135
  17. package/src/__tests__/chrome-devtools-guard.test.ts +165 -165
  18. package/src/__tests__/claude-raw-stream-log.test.ts +87 -0
  19. package/src/__tests__/codex-raw-stream-log.test.ts +163 -0
  20. package/src/__tests__/config-reload.test.ts +10 -10
  21. package/src/__tests__/config-sample.test.ts +18 -18
  22. package/src/__tests__/cursor-adapter.test.ts +167 -113
  23. package/src/__tests__/feishu-avatar.test.ts +40 -40
  24. package/src/__tests__/jsonl-stream.test.ts +79 -0
  25. package/src/__tests__/orchestrator.test.ts +181 -154
  26. package/src/__tests__/raw-stream-log.test.ts +106 -106
  27. package/src/__tests__/session.test.ts +40 -40
  28. package/src/__tests__/sim-platform.test.ts +12 -12
  29. package/src/__tests__/web-ui.test.ts +209 -209
  30. package/src/adapters/ccc-adapter.ts +121 -119
  31. package/src/adapters/claude-adapter.ts +603 -566
  32. package/src/adapters/codex-adapter.ts +65 -52
  33. package/src/adapters/cursor-adapter.ts +269 -276
  34. package/src/adapters/jsonl-stream.ts +157 -0
  35. package/src/adapters/raw-stream-log.ts +124 -124
  36. package/src/agent-reload-config-rpc.ts +34 -0
  37. package/src/builtin/cli.ts +473 -461
  38. package/src/builtin/context.ts +323 -323
  39. package/src/builtin/file-tools.ts +1072 -915
  40. package/src/builtin/index.ts +404 -353
  41. package/src/builtin/session-select.ts +48 -48
  42. package/src/builtin/sigint.ts +50 -50
  43. package/src/cards.ts +195 -195
  44. package/src/chatgpt-subscription-rpc.ts +27 -27
  45. package/src/chatgpt-subscription.ts +299 -299
  46. package/src/chrome-devtools-guard.ts +318 -318
  47. package/src/config.ts +125 -125
  48. package/src/feishu-api.ts +49 -49
  49. package/src/index.ts +8 -13
  50. package/src/orchestrator.ts +166 -145
  51. package/src/runtime-reload.ts +34 -0
  52. package/src/session.ts +141 -141
  53. package/src/web-ui.ts +205 -205
@@ -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);
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatccc",
3
- "version": "0.2.196",
3
+ "version": "0.2.198",
4
4
  "description": "Feishu bot bridge for Claude Code",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -36,6 +36,7 @@
36
36
  "demo:permission-check": "tsx demo/permission_check.ts",
37
37
  "demo:claude-hi": "tsx demo/claude_say_hi.ts",
38
38
  "demo:codex-hi": "tsx demo/codex_say_hi.ts",
39
+ "demo:codex-app-server-approval": "tsx demo/codex-app-server-approval/approval_demo.ts",
39
40
  "demo:ilink-echo": "tsx demo/ilink_echo_probe.ts",
40
41
  "claude-proxy": "tsx src/litellm-proxy.ts",
41
42
  "test": "vitest run",
@@ -0,0 +1,99 @@
1
+ import { Readable } from "node:stream";
2
+ import { describe, expect, it, vi } from "vitest";
3
+
4
+ import {
5
+ AGENT_RELOAD_CONFIG_PATH,
6
+ handleAgentReloadConfigRequest,
7
+ } from "../agent-reload-config-rpc.ts";
8
+
9
+ function request(path = AGENT_RELOAD_CONFIG_PATH, method = "POST"): Readable & {
10
+ url?: string;
11
+ method?: string;
12
+ headers: Record<string, string>;
13
+ } {
14
+ const req = Readable.from([]) as Readable & {
15
+ url?: string;
16
+ method?: string;
17
+ headers: Record<string, string>;
18
+ };
19
+ req.url = path;
20
+ req.method = method;
21
+ req.headers = {};
22
+ return req;
23
+ }
24
+
25
+ function response() {
26
+ const res = {
27
+ statusCode: 0,
28
+ headers: {} as Record<string, string>,
29
+ body: "",
30
+ writeHead(status: number, headers: Record<string, string>) {
31
+ this.statusCode = status;
32
+ this.headers = headers;
33
+ return this;
34
+ },
35
+ end(chunk?: string) {
36
+ this.body += chunk ?? "";
37
+ return this;
38
+ },
39
+ };
40
+ return res;
41
+ }
42
+
43
+ describe("agent reload config RPC", () => {
44
+ it("reloads runtime config for POST requests", async () => {
45
+ const reload = vi.fn(async () => ({
46
+ configPath: "C:\\Users\\me\\.chatccc\\config.json",
47
+ defaultAgent: "codex" as const,
48
+ reloadedAt: "2026-07-02T05:00:00.000Z",
49
+ }));
50
+ const res = response();
51
+
52
+ await expect(handleAgentReloadConfigRequest(request() as never, res as never, reload)).resolves.toBe(true);
53
+
54
+ expect(reload).toHaveBeenCalledWith("agent-reload-api");
55
+ expect(res.statusCode).toBe(200);
56
+ expect(JSON.parse(res.body)).toEqual({
57
+ ok: true,
58
+ configPath: "C:\\Users\\me\\.chatccc\\config.json",
59
+ defaultAgent: "codex",
60
+ reloadedAt: "2026-07-02T05:00:00.000Z",
61
+ });
62
+ });
63
+
64
+ it("rejects non-POST requests without reloading", async () => {
65
+ const reload = vi.fn();
66
+ const res = response();
67
+
68
+ await expect(handleAgentReloadConfigRequest(request(AGENT_RELOAD_CONFIG_PATH, "GET") as never, res as never, reload)).resolves.toBe(true);
69
+
70
+ expect(reload).not.toHaveBeenCalled();
71
+ expect(res.statusCode).toBe(405);
72
+ expect(JSON.parse(res.body)).toMatchObject({ ok: false, error: "Method not allowed" });
73
+ });
74
+
75
+ it("does not handle other paths", async () => {
76
+ const res = response();
77
+
78
+ await expect(handleAgentReloadConfigRequest(request("/api/other") as never, res as never, vi.fn())).resolves.toBe(false);
79
+
80
+ expect(res.body).toBe("");
81
+ });
82
+
83
+ it("returns a visible error when reload fails", async () => {
84
+ const res = response();
85
+
86
+ await expect(
87
+ handleAgentReloadConfigRequest(
88
+ request() as never,
89
+ res as never,
90
+ vi.fn(async () => {
91
+ throw new Error("bad config");
92
+ }),
93
+ ),
94
+ ).resolves.toBe(true);
95
+
96
+ expect(res.statusCode).toBe(500);
97
+ expect(JSON.parse(res.body)).toEqual({ ok: false, error: "bad config" });
98
+ });
99
+ });