chatccc 0.2.226 → 0.2.227

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 (64) 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 +185 -74
  14. package/src/__tests__/card-action-routing.test.ts +18 -18
  15. package/src/__tests__/ccc-adapter.test.ts +136 -136
  16. package/src/__tests__/claude-adapter.test.ts +614 -614
  17. package/src/__tests__/codex-adapter.test.ts +58 -58
  18. package/src/__tests__/codex-raw-stream-log.test.ts +170 -170
  19. package/src/__tests__/cursor-adapter.test.ts +268 -268
  20. package/src/__tests__/feishu-avatar.test.ts +164 -164
  21. package/src/__tests__/feishu-message-ingress.test.ts +138 -138
  22. package/src/__tests__/package-files.test.ts +24 -24
  23. package/src/__tests__/progress-reducer.test.ts +110 -110
  24. package/src/__tests__/response-stall.test.ts +49 -49
  25. package/src/__tests__/sim-platform.test.ts +16 -16
  26. package/src/__tests__/startup-lifecycle.test.ts +231 -231
  27. package/src/__tests__/stop-session.test.ts +34 -34
  28. package/src/__tests__/terminal-renderer.test.ts +247 -247
  29. package/src/__tests__/update-command-guard.test.ts +144 -144
  30. package/src/__tests__/web-ui.test.ts +326 -326
  31. package/src/adapters/adapter-interface.ts +18 -18
  32. package/src/adapters/ccc-adapter.ts +131 -131
  33. package/src/adapters/claude-adapter.ts +620 -620
  34. package/src/adapters/codex-adapter.ts +426 -426
  35. package/src/adapters/cursor-adapter.ts +681 -681
  36. package/src/agent-activity.ts +170 -170
  37. package/src/agent-delegate-task.ts +91 -91
  38. package/src/builtin/cli.ts +61 -2
  39. package/src/builtin/config.ts +84 -84
  40. package/src/builtin/context.ts +323 -323
  41. package/src/builtin/file-log.ts +38 -38
  42. package/src/builtin/index.ts +44 -24
  43. package/src/builtin/proc-tree-kill.ts +61 -61
  44. package/src/builtin/progress/cards-helpers.ts +76 -76
  45. package/src/builtin/progress/reducer.ts +108 -108
  46. package/src/builtin/progress/terminal-renderer.ts +294 -294
  47. package/src/builtin/progress/view.ts +77 -77
  48. package/src/builtin/raw-stream-log.ts +124 -124
  49. package/src/builtin/session-select.ts +48 -48
  50. package/src/builtin/skills.ts +126 -44
  51. package/src/card-action-routing.ts +14 -14
  52. package/src/feishu-api.ts +193 -193
  53. package/src/feishu-message-ingress.ts +195 -195
  54. package/src/index.ts +306 -306
  55. package/src/orchestrator.ts +2388 -2388
  56. package/src/platform-adapter.ts +6 -6
  57. package/src/progress/reducer.ts +108 -108
  58. package/src/progress/terminal-renderer.ts +294 -294
  59. package/src/progress/view.ts +77 -77
  60. package/src/response-stall.ts +28 -28
  61. package/src/session-chat-binding.ts +82 -82
  62. package/src/startup-lifecycle.ts +250 -250
  63. package/src/stream-state.ts +18 -18
  64. 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
+ }