chatccc 0.2.226 → 0.2.228

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/.agents/skills/create-chatccc-feishu-app/SKILL.md +85 -85
  2. package/.claude/skills/create-chatccc-feishu-app/SKILL.md +85 -85
  3. package/.cursor/skills/create-chatccc-feishu-app/SKILL.md +85 -85
  4. package/README.md +90 -90
  5. package/package.json +1 -1
  6. package/src/__tests__/agent-activity.test.ts +76 -76
  7. package/src/__tests__/builtin-chat-session.test.ts +350 -350
  8. package/src/__tests__/builtin-config.test.ts +26 -26
  9. package/src/__tests__/builtin-context.test.ts +163 -163
  10. package/src/__tests__/builtin-file-tools.test.ts +275 -275
  11. package/src/__tests__/builtin-permissions.test.ts +211 -211
  12. package/src/__tests__/builtin-session-select.test.ts +116 -116
  13. package/src/__tests__/builtin-skills.test.ts +252 -141
  14. package/src/__tests__/builtin-web-tools.test.ts +220 -0
  15. package/src/__tests__/card-action-routing.test.ts +18 -18
  16. package/src/__tests__/ccc-adapter.test.ts +136 -136
  17. package/src/__tests__/claude-adapter.test.ts +614 -614
  18. package/src/__tests__/codex-adapter.test.ts +58 -58
  19. package/src/__tests__/codex-raw-stream-log.test.ts +170 -170
  20. package/src/__tests__/cursor-adapter.test.ts +268 -268
  21. package/src/__tests__/feishu-avatar.test.ts +164 -164
  22. package/src/__tests__/feishu-message-ingress.test.ts +138 -138
  23. package/src/__tests__/package-files.test.ts +24 -24
  24. package/src/__tests__/progress-reducer.test.ts +110 -110
  25. package/src/__tests__/response-stall.test.ts +49 -49
  26. package/src/__tests__/sim-platform.test.ts +16 -16
  27. package/src/__tests__/startup-lifecycle.test.ts +231 -231
  28. package/src/__tests__/stop-session.test.ts +34 -34
  29. package/src/__tests__/terminal-renderer.test.ts +247 -247
  30. package/src/__tests__/update-command-guard.test.ts +144 -144
  31. package/src/__tests__/web-ui.test.ts +326 -326
  32. package/src/adapters/adapter-interface.ts +18 -18
  33. package/src/adapters/ccc-adapter.ts +131 -131
  34. package/src/adapters/claude-adapter.ts +620 -620
  35. package/src/adapters/codex-adapter.ts +426 -426
  36. package/src/adapters/cursor-adapter.ts +681 -681
  37. package/src/agent-activity.ts +170 -170
  38. package/src/agent-delegate-task.ts +91 -91
  39. package/src/builtin/cli.ts +61 -2
  40. package/src/builtin/config.ts +84 -84
  41. package/src/builtin/context.ts +323 -323
  42. package/src/builtin/file-log.ts +38 -38
  43. package/src/builtin/file-tools.ts +37 -0
  44. package/src/builtin/index.ts +44 -24
  45. package/src/builtin/proc-tree-kill.ts +61 -61
  46. package/src/builtin/progress/cards-helpers.ts +76 -76
  47. package/src/builtin/progress/reducer.ts +108 -108
  48. package/src/builtin/progress/terminal-renderer.ts +294 -294
  49. package/src/builtin/progress/view.ts +77 -77
  50. package/src/builtin/raw-stream-log.ts +124 -124
  51. package/src/builtin/session-select.ts +48 -48
  52. package/src/builtin/skills.ts +190 -108
  53. package/src/builtin/web-tools.ts +313 -0
  54. package/src/card-action-routing.ts +14 -14
  55. package/src/feishu-api.ts +193 -193
  56. package/src/feishu-message-ingress.ts +195 -195
  57. package/src/index.ts +306 -306
  58. package/src/orchestrator.ts +2388 -2388
  59. package/src/platform-adapter.ts +6 -6
  60. package/src/progress/reducer.ts +108 -108
  61. package/src/progress/terminal-renderer.ts +294 -294
  62. package/src/progress/view.ts +77 -77
  63. package/src/response-stall.ts +28 -28
  64. package/src/session-chat-binding.ts +82 -82
  65. package/src/startup-lifecycle.ts +250 -250
  66. package/src/stream-state.ts +18 -18
  67. package/src/update-command-guard.ts +165 -165
@@ -87,17 +87,17 @@ export type UnifiedBlock =
87
87
  // UnifiedStreamMessage — 一次 SDK/CLI 事件对应的归一化消息
88
88
  // ---------------------------------------------------------------------------
89
89
 
90
- export interface UnifiedStreamMessage {
91
- type: "assistant" | "user" | "system";
92
- blocks: UnifiedBlock[];
93
- /**
94
- * 适配器确认本事件代表一条完整、权威的最终回复,而不是流式文本片段。
95
- *
96
- * response-stall 终止与最终事件可能在同一事件循环边界竞态;只有该标记
97
- * 为 true 时,上层才允许把已经触发的超时改判为正常完成。
98
- */
99
- isFinalResponse?: boolean;
100
- }
90
+ export interface UnifiedStreamMessage {
91
+ type: "assistant" | "user" | "system";
92
+ blocks: UnifiedBlock[];
93
+ /**
94
+ * 适配器确认本事件代表一条完整、权威的最终回复,而不是流式文本片段。
95
+ *
96
+ * response-stall 终止与最终事件可能在同一事件循环边界竞态;只有该标记
97
+ * 为 true 时,上层才允许把已经触发的超时改判为正常完成。
98
+ */
99
+ isFinalResponse?: boolean;
100
+ }
101
101
 
102
102
  // ---------------------------------------------------------------------------
103
103
  // CreateSessionResult
@@ -152,12 +152,12 @@ export interface ToolAdapter {
152
152
  /** 群描述中会话 ID 的前缀,如 "Claude Session:" */
153
153
  readonly sessionDescPrefix: string;
154
154
 
155
- /**
156
- * 创建新会话,返回会话 ID。
157
- * 适配器内部需处理后台流消费(静默消费 stream 中除 init 外的所有事件)。
158
- * signal 用于上层在长期收不到 init 事件时终止底层 SDK/CLI。
159
- */
160
- createSession(cwd: string, signal?: AbortSignal): Promise<CreateSessionResult>;
155
+ /**
156
+ * 创建新会话,返回会话 ID。
157
+ * 适配器内部需处理后台流消费(静默消费 stream 中除 init 外的所有事件)。
158
+ * signal 用于上层在长期收不到 init 事件时终止底层 SDK/CLI。
159
+ */
160
+ createSession(cwd: string, signal?: AbortSignal): Promise<CreateSessionResult>;
161
161
 
162
162
  /**
163
163
  * 向已有会话发送提示文本,返回归一化消息的异步迭代器。
@@ -202,4 +202,4 @@ export function parseUserCommand(userText: string): UserCommand {
202
202
  if (original.startsWith("/plan")) return { original, mode: "plan" };
203
203
  if (original.startsWith("/ask")) return { original, mode: "ask" };
204
204
  return { original, mode: null };
205
- }
205
+ }
@@ -1,131 +1,131 @@
1
- import { ChatSession, type ChatSessionConfig, type ChatSessionOptions } from "../builtin/index.ts";
2
- import {
3
- getBuiltinContextSession,
4
- newBuiltinSessionId,
5
- normalizeBuiltinSessionId,
6
- } from "../builtin/context.ts";
7
- import { config, CCC_SESSION_PREFIX } from "../config.ts";
8
- import type {
9
- CreateSessionResult,
10
- SessionInfo,
11
- ToolAdapter,
12
- ToolPromptOptions,
13
- UnifiedStreamMessage,
14
- } from "./adapter-interface.ts";
15
-
16
- export interface CccAdapterOptions extends ChatSessionConfig {
17
- contextDir?: string;
18
- compactAtTokens?: number;
19
- keepRecentMessages?: number;
20
- maxSteps?: number;
21
- }
22
-
23
- function toChatSessionOptions(
24
- sessionId: string,
25
- cwd: string,
26
- options: CccAdapterOptions,
27
- ): ChatSessionOptions {
28
- return {
29
- cwd,
30
- persist: true,
31
- sessionId,
32
- contextDir: options.contextDir,
33
- compactAtTokens: options.compactAtTokens,
34
- keepRecentMessages: options.keepRecentMessages,
35
- maxSteps: options.maxSteps,
36
- // chatccc 无终端可交互,且对齐 claude/codex 适配器的 bypass 模式:
37
- // 高危命令不询问,全部放行(与独立 deepccc CLI 的 ask 模式不同)
38
- permissionMode: "bypass",
39
- };
40
- }
41
-
42
- export function createCccAdapter(options: CccAdapterOptions = {}): ToolAdapter {
43
- const chatConfig: ChatSessionConfig = {
44
- ...(options.apiKey !== undefined ? { apiKey: options.apiKey } : {}),
45
- ...(options.baseURL !== undefined ? { baseURL: options.baseURL } : {}),
46
- ...(options.model !== undefined ? { model: options.model } : {}),
47
- ...(options.effort !== undefined ? { effort: options.effort } : {}),
48
- };
49
-
50
- return {
51
- displayName: "CCC Agent",
52
- sessionDescPrefix: CCC_SESSION_PREFIX,
53
-
54
- async createSession(cwd: string): Promise<CreateSessionResult> {
55
- const sessionId = newBuiltinSessionId();
56
- const session = new ChatSession(
57
- chatConfig,
58
- toChatSessionOptions(sessionId, cwd, options),
59
- );
60
- session.reset();
61
- return { sessionId };
62
- },
63
-
64
- async *prompt(
65
- sessionId: string,
66
- userText: string,
67
- cwd: string,
68
- signal?: AbortSignal,
69
- _promptOptions?: ToolPromptOptions,
70
- ): AsyncIterable<UnifiedStreamMessage> {
71
- const normalizedSessionId = normalizeBuiltinSessionId(sessionId);
72
- const session = new ChatSession(
73
- chatConfig,
74
- toChatSessionOptions(normalizedSessionId, cwd, options),
75
- );
76
-
77
- for await (const event of session.chat(userText, signal)) {
78
- if (event.type === "text") {
79
- yield {
80
- type: "assistant",
81
- blocks: [{ type: "text", text: event.text }],
82
- };
83
- } else if (event.type === "tool_use") {
84
- yield {
85
- type: "assistant",
86
- blocks: [{
87
- type: "tool_use",
88
- id: event.id,
89
- name: event.name,
90
- input: event.input,
91
- }],
92
- };
93
- } else if (event.type === "tool_result") {
94
- yield {
95
- type: "assistant",
96
- blocks: [{
97
- type: "tool_result",
98
- tool_use_id: event.tool_use_id,
99
- content: event.content,
100
- is_error: event.is_error,
101
- }],
102
- };
103
- } else if (event.type === "done" && !signal?.aborted) {
104
- yield {
105
- type: "assistant",
106
- blocks: [],
107
- isFinalResponse: true,
108
- };
109
- } else if (event.type === "error") {
110
- throw new Error(event.message);
111
- }
112
- }
113
- },
114
-
115
- async getSessionInfo(sessionId: string): Promise<SessionInfo | undefined> {
116
- const normalizedSessionId = normalizeBuiltinSessionId(sessionId);
117
- const info = getBuiltinContextSession(normalizedSessionId, options.contextDir);
118
- if (!info) return undefined;
119
- return {
120
- sessionId: info.sessionId,
121
- cwd: info.cwd,
122
- lastModified: info.updatedAt,
123
- model: options.model ?? config.ccc.model,
124
- };
125
- },
126
-
127
- async closeSession(_sessionId: string): Promise<void> {
128
- // ChatSession uses one request-scoped stream per prompt. AbortSignal handles cancellation.
129
- },
130
- };
131
- }
1
+ import { ChatSession, type ChatSessionConfig, type ChatSessionOptions } from "../builtin/index.ts";
2
+ import {
3
+ getBuiltinContextSession,
4
+ newBuiltinSessionId,
5
+ normalizeBuiltinSessionId,
6
+ } from "../builtin/context.ts";
7
+ import { config, CCC_SESSION_PREFIX } from "../config.ts";
8
+ import type {
9
+ CreateSessionResult,
10
+ SessionInfo,
11
+ ToolAdapter,
12
+ ToolPromptOptions,
13
+ UnifiedStreamMessage,
14
+ } from "./adapter-interface.ts";
15
+
16
+ export interface CccAdapterOptions extends ChatSessionConfig {
17
+ contextDir?: string;
18
+ compactAtTokens?: number;
19
+ keepRecentMessages?: number;
20
+ maxSteps?: number;
21
+ }
22
+
23
+ function toChatSessionOptions(
24
+ sessionId: string,
25
+ cwd: string,
26
+ options: CccAdapterOptions,
27
+ ): ChatSessionOptions {
28
+ return {
29
+ cwd,
30
+ persist: true,
31
+ sessionId,
32
+ contextDir: options.contextDir,
33
+ compactAtTokens: options.compactAtTokens,
34
+ keepRecentMessages: options.keepRecentMessages,
35
+ maxSteps: options.maxSteps,
36
+ // chatccc 无终端可交互,且对齐 claude/codex 适配器的 bypass 模式:
37
+ // 高危命令不询问,全部放行(与独立 deepccc CLI 的 ask 模式不同)
38
+ permissionMode: "bypass",
39
+ };
40
+ }
41
+
42
+ export function createCccAdapter(options: CccAdapterOptions = {}): ToolAdapter {
43
+ const chatConfig: ChatSessionConfig = {
44
+ ...(options.apiKey !== undefined ? { apiKey: options.apiKey } : {}),
45
+ ...(options.baseURL !== undefined ? { baseURL: options.baseURL } : {}),
46
+ ...(options.model !== undefined ? { model: options.model } : {}),
47
+ ...(options.effort !== undefined ? { effort: options.effort } : {}),
48
+ };
49
+
50
+ return {
51
+ displayName: "CCC Agent",
52
+ sessionDescPrefix: CCC_SESSION_PREFIX,
53
+
54
+ async createSession(cwd: string): Promise<CreateSessionResult> {
55
+ const sessionId = newBuiltinSessionId();
56
+ const session = new ChatSession(
57
+ chatConfig,
58
+ toChatSessionOptions(sessionId, cwd, options),
59
+ );
60
+ session.reset();
61
+ return { sessionId };
62
+ },
63
+
64
+ async *prompt(
65
+ sessionId: string,
66
+ userText: string,
67
+ cwd: string,
68
+ signal?: AbortSignal,
69
+ _promptOptions?: ToolPromptOptions,
70
+ ): AsyncIterable<UnifiedStreamMessage> {
71
+ const normalizedSessionId = normalizeBuiltinSessionId(sessionId);
72
+ const session = new ChatSession(
73
+ chatConfig,
74
+ toChatSessionOptions(normalizedSessionId, cwd, options),
75
+ );
76
+
77
+ for await (const event of session.chat(userText, signal)) {
78
+ if (event.type === "text") {
79
+ yield {
80
+ type: "assistant",
81
+ blocks: [{ type: "text", text: event.text }],
82
+ };
83
+ } else if (event.type === "tool_use") {
84
+ yield {
85
+ type: "assistant",
86
+ blocks: [{
87
+ type: "tool_use",
88
+ id: event.id,
89
+ name: event.name,
90
+ input: event.input,
91
+ }],
92
+ };
93
+ } else if (event.type === "tool_result") {
94
+ yield {
95
+ type: "assistant",
96
+ blocks: [{
97
+ type: "tool_result",
98
+ tool_use_id: event.tool_use_id,
99
+ content: event.content,
100
+ is_error: event.is_error,
101
+ }],
102
+ };
103
+ } else if (event.type === "done" && !signal?.aborted) {
104
+ yield {
105
+ type: "assistant",
106
+ blocks: [],
107
+ isFinalResponse: true,
108
+ };
109
+ } else if (event.type === "error") {
110
+ throw new Error(event.message);
111
+ }
112
+ }
113
+ },
114
+
115
+ async getSessionInfo(sessionId: string): Promise<SessionInfo | undefined> {
116
+ const normalizedSessionId = normalizeBuiltinSessionId(sessionId);
117
+ const info = getBuiltinContextSession(normalizedSessionId, options.contextDir);
118
+ if (!info) return undefined;
119
+ return {
120
+ sessionId: info.sessionId,
121
+ cwd: info.cwd,
122
+ lastModified: info.updatedAt,
123
+ model: options.model ?? config.ccc.model,
124
+ };
125
+ },
126
+
127
+ async closeSession(_sessionId: string): Promise<void> {
128
+ // ChatSession uses one request-scoped stream per prompt. AbortSignal handles cancellation.
129
+ },
130
+ };
131
+ }