chatccc 0.2.252 → 0.2.254

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 (296) hide show
  1. package/README.md +10 -1
  2. package/bin/cccagent.mjs +12 -3
  3. package/bin/chatccc.mjs +15 -6
  4. package/config.sample.json +2 -1
  5. package/deepccc-agent/README.md +40 -35
  6. package/deepccc-agent/os-prompts/darwin.md +8 -8
  7. package/deepccc-agent/os-prompts/linux.md +8 -8
  8. package/deepccc-agent/os-prompts/win32.md +11 -11
  9. package/deepccc-agent/package.json +65 -65
  10. package/dist/deepccc-agent/src/cli.js +634 -0
  11. package/dist/deepccc-agent/src/config.js +81 -0
  12. package/dist/deepccc-agent/src/context.js +348 -0
  13. package/dist/deepccc-agent/src/file-log.js +34 -0
  14. package/dist/deepccc-agent/src/file-tools.js +1208 -0
  15. package/dist/deepccc-agent/src/index.js +601 -0
  16. package/dist/deepccc-agent/src/permissions.js +170 -0
  17. package/dist/deepccc-agent/src/privacy.js +124 -0
  18. package/dist/deepccc-agent/src/proc-tree-kill.js +60 -0
  19. package/dist/deepccc-agent/src/progress/cards-helpers.js +70 -0
  20. package/dist/deepccc-agent/src/progress/reducer.js +102 -0
  21. package/dist/deepccc-agent/src/progress/terminal-renderer.js +264 -0
  22. package/dist/deepccc-agent/src/progress/view.js +30 -0
  23. package/dist/deepccc-agent/src/raw-stream-log.js +106 -0
  24. package/dist/deepccc-agent/src/session-search.js +276 -0
  25. package/dist/deepccc-agent/src/session-select.js +23 -0
  26. package/dist/deepccc-agent/src/sigint.js +26 -0
  27. package/dist/deepccc-agent/src/skills.js +178 -0
  28. package/dist/deepccc-agent/src/web-tools.js +246 -0
  29. package/dist/src/adapters/adapter-interface.js +19 -0
  30. package/dist/src/adapters/ccc-adapter.js +112 -0
  31. package/dist/src/adapters/claude-adapter.js +497 -0
  32. package/dist/src/adapters/claude-session-meta-store.js +92 -0
  33. package/dist/src/adapters/codex-adapter.js +279 -0
  34. package/dist/src/adapters/codex-session-meta-store.js +94 -0
  35. package/dist/src/adapters/cursor-adapter.js +491 -0
  36. package/dist/src/adapters/cursor-session-meta-store.js +116 -0
  37. package/dist/src/adapters/jsonl-stream.js +104 -0
  38. package/{src/adapters/proc-tree-kill.ts → dist/src/adapters/proc-tree-kill.js} +94 -97
  39. package/dist/src/adapters/raw-stream-log.js +106 -0
  40. package/dist/src/adapters/resource-monitor.js +113 -0
  41. package/dist/src/agent-activity.js +133 -0
  42. package/dist/src/agent-delegate-task-rpc.js +129 -0
  43. package/dist/src/agent-delegate-task.js +48 -0
  44. package/dist/src/agent-file-rpc.js +152 -0
  45. package/dist/src/agent-image-rpc.js +148 -0
  46. package/dist/src/agent-platform-routing.js +13 -0
  47. package/dist/src/agent-reload-config-rpc.js +23 -0
  48. package/dist/src/agent-rpc-body.js +87 -0
  49. package/dist/src/agent-stop-stuck.js +110 -0
  50. package/dist/src/agent-team/application/board-service.js +142 -0
  51. package/dist/src/agent-team/application/main-agent-service.js +151 -0
  52. package/dist/src/agent-team/domain/board.js +69 -0
  53. package/dist/src/agent-team/http/board-routes.js +213 -0
  54. package/dist/src/agent-team/infrastructure/filesystem-browser.js +112 -0
  55. package/dist/src/agent-team/infrastructure/main-agent-session-runtime.js +30 -0
  56. package/dist/src/agent-team/main-agent-bootstrap.js +15 -0
  57. package/dist/src/agent-team/repositories/board-repository.js +10 -0
  58. package/dist/src/agent-team/repositories/feishu-p2p-contact-store.js +64 -0
  59. package/dist/src/agent-team/repositories/json-board-repository.js +209 -0
  60. package/dist/src/agent-team/repositories/main-agent-binding-repository.js +84 -0
  61. package/dist/src/agent-team/sync/board-sync-adapter.js +1 -0
  62. package/dist/src/agent-team/web/agent-team-page.js +219 -0
  63. package/dist/src/agent-tool.js +10 -0
  64. package/dist/src/card-action-routing.js +7 -0
  65. package/dist/src/card-plain-text.js +101 -0
  66. package/dist/src/cardkit.js +158 -0
  67. package/dist/src/cards.js +573 -0
  68. package/dist/src/chatgpt-subscription-rpc.js +18 -0
  69. package/dist/src/chatgpt-subscription.js +199 -0
  70. package/dist/src/chrome-devtools-guard.js +238 -0
  71. package/dist/src/claude-sdk-installer.js +249 -0
  72. package/dist/src/codex-reset-actions.js +143 -0
  73. package/dist/src/config-utils.js +149 -0
  74. package/dist/src/config.js +808 -0
  75. package/dist/src/cursor-usage.js +77 -0
  76. package/dist/src/exit-banner.js +28 -0
  77. package/dist/src/feishu-api.js +1404 -0
  78. package/dist/src/feishu-message-ingress.js +137 -0
  79. package/dist/src/feishu-platform.js +97 -0
  80. package/dist/src/format-message.js +252 -0
  81. package/dist/src/git-command.js +155 -0
  82. package/dist/src/im-skills.js +121 -0
  83. package/dist/src/index.js +835 -0
  84. package/dist/src/litellm-proxy.js +300 -0
  85. package/dist/src/orchestrator.js +2096 -0
  86. package/dist/src/package-root.js +26 -0
  87. package/dist/src/platform-adapter.js +7 -0
  88. package/dist/src/platform-startup.js +6 -0
  89. package/dist/src/privacy.js +100 -0
  90. package/dist/src/progress/reducer.js +102 -0
  91. package/dist/src/progress/terminal-renderer.js +264 -0
  92. package/dist/src/progress/view.js +30 -0
  93. package/dist/src/response-stall.js +14 -0
  94. package/dist/src/runtime-entry.js +13 -0
  95. package/dist/src/runtime-reload.js +19 -0
  96. package/dist/src/session-chat-binding.js +183 -0
  97. package/dist/src/session-name.js +7 -0
  98. package/dist/src/session.js +2147 -0
  99. package/dist/src/shared-prefix.js +16 -0
  100. package/dist/src/shared.js +493 -0
  101. package/dist/src/sim-agent.js +105 -0
  102. package/dist/src/sim-platform.js +142 -0
  103. package/dist/src/sim-store.js +231 -0
  104. package/dist/src/simplify.js +99 -0
  105. package/dist/src/startup-lifecycle.js +209 -0
  106. package/dist/src/stream-state.js +141 -0
  107. package/dist/src/terminal-error.js +100 -0
  108. package/dist/src/trace.js +50 -0
  109. package/dist/src/turn-cards.js +92 -0
  110. package/dist/src/update-command-guard.js +114 -0
  111. package/{src/web-ui.ts → dist/src/web-ui.js} +753 -839
  112. package/dist/src/wechat-platform.js +545 -0
  113. package/package.json +76 -74
  114. package/deepccc-agent/LICENSE +0 -201
  115. package/deepccc-agent/bin/deepccc.mjs +0 -26
  116. package/deepccc-agent/docs/cache-hit-rate-1.jpg +0 -0
  117. package/deepccc-agent/docs/cache-hit-rate-2.jpg +0 -0
  118. package/deepccc-agent/package-lock.json +0 -2027
  119. package/deepccc-agent/src/__tests__/chat-session.test.ts +0 -877
  120. package/deepccc-agent/src/__tests__/cli-json.test.ts +0 -49
  121. package/deepccc-agent/src/__tests__/config.test.ts +0 -34
  122. package/deepccc-agent/src/__tests__/context.test.ts +0 -341
  123. package/deepccc-agent/src/__tests__/file-tools.test.ts +0 -240
  124. package/deepccc-agent/src/__tests__/permissions.test.ts +0 -199
  125. package/deepccc-agent/src/__tests__/privacy.test.ts +0 -318
  126. package/deepccc-agent/src/__tests__/progress-reducer.test.ts +0 -121
  127. package/deepccc-agent/src/__tests__/session-search.test.ts +0 -262
  128. package/deepccc-agent/src/__tests__/session-select.test.ts +0 -116
  129. package/deepccc-agent/src/__tests__/sigint.test.ts +0 -56
  130. package/deepccc-agent/src/__tests__/skills.test.ts +0 -284
  131. package/deepccc-agent/src/__tests__/terminal-renderer.test.ts +0 -247
  132. package/deepccc-agent/src/__tests__/web-tools.test.ts +0 -220
  133. package/deepccc-agent/src/cli.ts +0 -682
  134. package/deepccc-agent/src/config.ts +0 -101
  135. package/deepccc-agent/src/context.ts +0 -465
  136. package/deepccc-agent/src/file-log.ts +0 -38
  137. package/deepccc-agent/src/file-tools.ts +0 -1493
  138. package/deepccc-agent/src/index.ts +0 -710
  139. package/deepccc-agent/src/permissions.ts +0 -226
  140. package/deepccc-agent/src/privacy.ts +0 -141
  141. package/deepccc-agent/src/proc-tree-kill.ts +0 -61
  142. package/deepccc-agent/src/progress/cards-helpers.ts +0 -76
  143. package/deepccc-agent/src/progress/reducer.ts +0 -113
  144. package/deepccc-agent/src/progress/terminal-renderer.ts +0 -294
  145. package/deepccc-agent/src/progress/view.ts +0 -77
  146. package/deepccc-agent/src/raw-stream-log.ts +0 -124
  147. package/deepccc-agent/src/session-search.ts +0 -370
  148. package/deepccc-agent/src/session-select.ts +0 -48
  149. package/deepccc-agent/src/sigint.ts +0 -50
  150. package/deepccc-agent/src/skills.ts +0 -205
  151. package/deepccc-agent/src/web-tools.ts +0 -313
  152. package/deepccc-agent/tsconfig.build.json +0 -13
  153. package/deepccc-agent/tsconfig.json +0 -13
  154. package/deepccc-agent/vitest.config.ts +0 -7
  155. package/src/__tests__/adapter-interface.test.ts +0 -152
  156. package/src/__tests__/agent-activity.test.ts +0 -86
  157. package/src/__tests__/agent-delegate-task-rpc.test.ts +0 -165
  158. package/src/__tests__/agent-image-rpc.test.ts +0 -34
  159. package/src/__tests__/agent-platform-routing.test.ts +0 -26
  160. package/src/__tests__/agent-reload-config-rpc.test.ts +0 -99
  161. package/src/__tests__/agent-rpc-body.test.ts +0 -42
  162. package/src/__tests__/builtin-chat-session.test.ts +0 -532
  163. package/src/__tests__/builtin-cli-json.test.ts +0 -39
  164. package/src/__tests__/builtin-config.test.ts +0 -26
  165. package/src/__tests__/builtin-context.test.ts +0 -319
  166. package/src/__tests__/builtin-file-tools.test.ts +0 -240
  167. package/src/__tests__/builtin-permissions.test.ts +0 -219
  168. package/src/__tests__/builtin-session-search.test.ts +0 -262
  169. package/src/__tests__/builtin-session-select.test.ts +0 -116
  170. package/src/__tests__/builtin-sigint.test.ts +0 -56
  171. package/src/__tests__/builtin-skills.test.ts +0 -284
  172. package/src/__tests__/builtin-web-tools.test.ts +0 -220
  173. package/src/__tests__/card-action-routing.test.ts +0 -18
  174. package/src/__tests__/card-plain-text.test.ts +0 -45
  175. package/src/__tests__/cardkit.test.ts +0 -60
  176. package/src/__tests__/cards.test.ts +0 -607
  177. package/src/__tests__/ccc-adapter.test.ts +0 -194
  178. package/src/__tests__/chatgpt-subscription-rpc.test.ts +0 -89
  179. package/src/__tests__/chatgpt-subscription.test.ts +0 -135
  180. package/src/__tests__/chrome-devtools-guard.test.ts +0 -165
  181. package/src/__tests__/claude-adapter.test.ts +0 -614
  182. package/src/__tests__/claude-raw-stream-log.test.ts +0 -96
  183. package/src/__tests__/claude-sdk-installer.test.ts +0 -285
  184. package/src/__tests__/codex-adapter.test.ts +0 -331
  185. package/src/__tests__/codex-raw-stream-log.test.ts +0 -170
  186. package/src/__tests__/codex-reset-actions.test.ts +0 -146
  187. package/src/__tests__/config-reload.test.ts +0 -284
  188. package/src/__tests__/config-sample.test.ts +0 -97
  189. package/src/__tests__/config-utils.test.ts +0 -40
  190. package/src/__tests__/config.test.ts +0 -395
  191. package/src/__tests__/crash-logging.test.ts +0 -360
  192. package/src/__tests__/cursor-adapter.test.ts +0 -890
  193. package/src/__tests__/cursor-session-meta-store.test.ts +0 -212
  194. package/src/__tests__/feishu-api.test.ts +0 -60
  195. package/src/__tests__/feishu-avatar.test.ts +0 -504
  196. package/src/__tests__/feishu-message-ingress.test.ts +0 -138
  197. package/src/__tests__/feishu-platform.test.ts +0 -75
  198. package/src/__tests__/fixtures/codex_simple_text.jsonl +0 -4
  199. package/src/__tests__/fixtures/codex_with_tool.jsonl +0 -6
  200. package/src/__tests__/fixtures/cursor_partial_only.jsonl +0 -5
  201. package/src/__tests__/fixtures/cursor_partial_with_final.jsonl +0 -13
  202. package/src/__tests__/fixtures/cursor_with_tool_call.jsonl +0 -12
  203. package/src/__tests__/format-message.test.ts +0 -316
  204. package/src/__tests__/git-command.test.ts +0 -288
  205. package/src/__tests__/im-skills.test.ts +0 -125
  206. package/src/__tests__/jsonl-stream.test.ts +0 -79
  207. package/src/__tests__/orchestrator.test.ts +0 -1268
  208. package/src/__tests__/package-files.test.ts +0 -24
  209. package/src/__tests__/platform-startup.test.ts +0 -19
  210. package/src/__tests__/privacy.test.ts +0 -198
  211. package/src/__tests__/proc-tree-kill.test.ts +0 -108
  212. package/src/__tests__/progress-reducer.test.ts +0 -121
  213. package/src/__tests__/raw-stream-log.test.ts +0 -106
  214. package/src/__tests__/response-stall.test.ts +0 -49
  215. package/src/__tests__/restart.test.ts +0 -232
  216. package/src/__tests__/session-ccc-config.test.ts +0 -66
  217. package/src/__tests__/session.test.ts +0 -3004
  218. package/src/__tests__/shared-prefix.test.ts +0 -36
  219. package/src/__tests__/sim-agent.test.ts +0 -174
  220. package/src/__tests__/sim-platform.test.ts +0 -93
  221. package/src/__tests__/sim-store.test.ts +0 -214
  222. package/src/__tests__/simplify.test.ts +0 -283
  223. package/src/__tests__/startup-lifecycle.test.ts +0 -231
  224. package/src/__tests__/stop-session.test.ts +0 -162
  225. package/src/__tests__/stream-state.test.ts +0 -164
  226. package/src/__tests__/terminal-error.test.ts +0 -54
  227. package/src/__tests__/terminal-renderer.test.ts +0 -247
  228. package/src/__tests__/update-command-guard.test.ts +0 -144
  229. package/src/__tests__/web-ui.test.ts +0 -438
  230. package/src/__tests__/wechat-platform.test.ts +0 -111
  231. package/src/adapters/adapter-interface.ts +0 -217
  232. package/src/adapters/ccc-adapter.ts +0 -150
  233. package/src/adapters/claude-adapter.ts +0 -673
  234. package/src/adapters/claude-session-meta-store.ts +0 -120
  235. package/src/adapters/codex-adapter.ts +0 -426
  236. package/src/adapters/codex-session-meta-store.ts +0 -131
  237. package/src/adapters/cursor-adapter.ts +0 -681
  238. package/src/adapters/cursor-session-meta-store.ts +0 -154
  239. package/src/adapters/jsonl-stream.ts +0 -157
  240. package/src/adapters/raw-stream-log.ts +0 -124
  241. package/src/adapters/resource-monitor.ts +0 -141
  242. package/src/agent-activity.ts +0 -175
  243. package/src/agent-delegate-task-rpc.ts +0 -153
  244. package/src/agent-delegate-task.ts +0 -91
  245. package/src/agent-file-rpc.ts +0 -172
  246. package/src/agent-image-rpc.ts +0 -168
  247. package/src/agent-platform-routing.ts +0 -28
  248. package/src/agent-reload-config-rpc.ts +0 -34
  249. package/src/agent-rpc-body.ts +0 -92
  250. package/src/agent-stop-stuck.ts +0 -129
  251. package/src/card-action-routing.ts +0 -14
  252. package/src/card-plain-text.ts +0 -108
  253. package/src/cardkit.ts +0 -179
  254. package/src/cards.ts +0 -684
  255. package/src/chatgpt-subscription-rpc.ts +0 -27
  256. package/src/chatgpt-subscription.ts +0 -299
  257. package/src/chrome-devtools-guard.ts +0 -318
  258. package/src/claude-sdk-installer.ts +0 -324
  259. package/src/codex-reset-actions.ts +0 -184
  260. package/src/config-utils.ts +0 -211
  261. package/src/config.ts +0 -1063
  262. package/src/cursor-usage.ts +0 -128
  263. package/src/exit-banner.ts +0 -33
  264. package/src/feishu-api.ts +0 -1616
  265. package/src/feishu-message-ingress.ts +0 -195
  266. package/src/feishu-platform.ts +0 -159
  267. package/src/format-message.ts +0 -293
  268. package/src/git-command.ts +0 -202
  269. package/src/im-skills.ts +0 -149
  270. package/src/index.ts +0 -1089
  271. package/src/litellm-proxy.ts +0 -374
  272. package/src/orchestrator.ts +0 -2543
  273. package/src/platform-adapter.ts +0 -70
  274. package/src/platform-startup.ts +0 -16
  275. package/src/privacy.ts +0 -118
  276. package/src/progress/reducer.ts +0 -113
  277. package/src/progress/terminal-renderer.ts +0 -294
  278. package/src/progress/view.ts +0 -77
  279. package/src/response-stall.ts +0 -28
  280. package/src/runtime-reload.ts +0 -34
  281. package/src/session-chat-binding.ts +0 -292
  282. package/src/session-name.ts +0 -8
  283. package/src/session.ts +0 -2659
  284. package/src/shared-prefix.ts +0 -29
  285. package/src/shared.ts +0 -552
  286. package/src/sim-agent.ts +0 -167
  287. package/src/sim-platform.ts +0 -177
  288. package/src/sim-store.ts +0 -317
  289. package/src/simplify.ts +0 -120
  290. package/src/startup-lifecycle.ts +0 -250
  291. package/src/stream-state.ts +0 -177
  292. package/src/terminal-error.ts +0 -129
  293. package/src/trace.ts +0 -51
  294. package/src/turn-cards.ts +0 -118
  295. package/src/update-command-guard.ts +0 -165
  296. package/src/wechat-platform.ts +0 -680
package/src/sim-agent.ts DELETED
@@ -1,167 +0,0 @@
1
- /**
2
- * sim-agent.ts — SimAgent: 模拟飞书用户的编程接口
3
- *
4
- * SimAgent 代表一个模拟飞书用户,提供纯代码 API:
5
- * - sendMessage(): 发送消息给 bot
6
- * - on("message"): 订阅 bot 和其他人的回复
7
- * - on("invited_to_group"): 当被拉入群时收到通知
8
- * - waitForReply(): Promise 模式等待 bot 回复
9
- * - getMessages(): 查看会话历史消息
10
- *
11
- * 不依赖 UI,进程内直接调用,适合用于自动化测试和 Agent 编程。
12
- */
13
-
14
- import { simStore, dispatchMessage, SIM_DEFAULT_CHAT_ID } from "./sim-store.ts";
15
- import type { SimAccount, SimMessage } from "./sim-store.ts";
16
-
17
- // ---------------------------------------------------------------------------
18
- // 类型
19
- // ---------------------------------------------------------------------------
20
-
21
- export type MessageEventCallback = (chatId: string, msg: SimMessage) => void;
22
- export type InvitedToGroupCallback = (chatId: string, userId: string) => void;
23
-
24
- export interface SimAgent {
25
- /** 绑定的用户 ID */
26
- userId: string;
27
-
28
- /** 绑定的账户信息 */
29
- account: SimAccount;
30
-
31
- /**
32
- * 发送文本消息。
33
- * chatId 默认 sim_default;p2p 私聊需指定。
34
- */
35
- sendMessage(chatId: string, text: string): Promise<void>;
36
-
37
- /** 创建与 bot 的私聊,返回 p2p chatId */
38
- createP2pWithBot(): string;
39
-
40
- /** 获取用户在指定会话中的消息历史 */
41
- getMessages(chatId: string): SimMessage[];
42
-
43
- /** 获取用户所属的所有会话 */
44
- listChats(): { id: string; name: string; type: "p2p" | "group" }[];
45
-
46
- // ---- 事件订阅 ----
47
- /** 订阅消息事件(所有该用户所在群的消息) */
48
- on(event: "message", handler: MessageEventCallback): void;
49
- /** 订阅被拉入群事件 */
50
- on(event: "invited_to_group", handler: InvitedToGroupCallback): void;
51
- /** 取消订阅 */
52
- off(event: string, handler: (...args: any[]) => void): void;
53
-
54
- // ---- Promise 模式 ----
55
- /**
56
- * 等待指定会话的下一条 bot 回复。
57
- * 超时返回 null(默认 30 秒)。
58
- */
59
- waitForReply(chatId: string, timeoutMs?: number): Promise<SimMessage | null>;
60
- }
61
-
62
- // ---------------------------------------------------------------------------
63
- // 实现
64
- // ---------------------------------------------------------------------------
65
-
66
- export function createSimAgent(userId: string): SimAgent {
67
- const account = simStore.getAccount(userId);
68
- if (!account) throw new Error(`Account "${userId}" not found. Register it in simStore first.`);
69
- if (account.kind !== "user") throw new Error(`Account "${userId}" is not a user account.`);
70
-
71
- // 确保用户有至少一个会话(bot 私聊自动创建)
72
- simStore.createP2pChat(userId);
73
-
74
- function onEvent(event: "message", handler: MessageEventCallback): void;
75
- function onEvent(event: "invited_to_group", handler: InvitedToGroupCallback): void;
76
- function onEvent(
77
- event: "message" | "invited_to_group",
78
- handler: MessageEventCallback | InvitedToGroupCallback,
79
- ): void {
80
- if (event === "message") {
81
- const messageHandler = handler as MessageEventCallback;
82
- const filteredHandler = (payload: { chatId: string; message: SimMessage }) => {
83
- // 只推送给该用户所在群的消息
84
- const chat = simStore.getChat(payload.chatId);
85
- if (chat && chat.memberIds.includes(userId)) {
86
- messageHandler(payload.chatId, payload.message);
87
- }
88
- };
89
- // 保存映射以便 off 能移除
90
- (handler as any).__filtered = filteredHandler;
91
- simStore.on("message", filteredHandler);
92
- } else {
93
- const invitedHandler = handler as InvitedToGroupCallback;
94
- const filteredHandler = (payload: { chatId: string; userId: string }) => {
95
- if (payload.userId === userId) {
96
- invitedHandler(payload.chatId, payload.userId);
97
- }
98
- };
99
- (handler as any).__filtered = filteredHandler;
100
- simStore.on("member_added", filteredHandler);
101
- }
102
- }
103
-
104
- function offEvent(event: string, handler: (...args: any[]) => void): void {
105
- const filtered = (handler as any).__filtered;
106
- if (event === "message" && filtered) {
107
- simStore.off("message", filtered);
108
- } else if (event === "invited_to_group" && filtered) {
109
- simStore.off("member_added", filtered);
110
- }
111
- }
112
-
113
- const agent: SimAgent = {
114
- userId,
115
- account,
116
-
117
- async sendMessage(chatId, text) {
118
- const chat = simStore.getChat(chatId);
119
- if (!chat) throw new Error(`Chat "${chatId}" not found`);
120
- if (!chat.memberIds.includes(userId)) {
121
- throw new Error(`User "${userId}" is not a member of chat "${chatId}"`);
122
- }
123
- await dispatchMessage(text, chatId, userId, chat.type === "p2p" ? "p2p" : "group");
124
- },
125
-
126
- createP2pWithBot() {
127
- const chat = simStore.createP2pChat(userId);
128
- return chat.id;
129
- },
130
-
131
- getMessages(chatId) {
132
- return simStore.getMessages(chatId, userId);
133
- },
134
-
135
- listChats() {
136
- return simStore.getChatsForUser(userId).map((c) => ({
137
- id: c.id,
138
- name: c.name,
139
- type: c.type,
140
- }));
141
- },
142
-
143
- on: onEvent,
144
-
145
- off: offEvent,
146
-
147
- waitForReply(chatId, timeoutMs = 30000) {
148
- return new Promise((resolve) => {
149
- const timer = setTimeout(() => {
150
- agent.off("message", onMessage);
151
- resolve(null);
152
- }, timeoutMs);
153
-
154
- const onMessage = (cid: string, msg: SimMessage) => {
155
- if (cid === chatId && msg.senderId === "bot") {
156
- clearTimeout(timer);
157
- agent.off("message", onMessage);
158
- resolve(msg);
159
- }
160
- };
161
- agent.on("message", onMessage);
162
- });
163
- },
164
- };
165
-
166
- return agent;
167
- }
@@ -1,177 +0,0 @@
1
- /**
2
- * sim-platform.ts — SimulatedPlatform: 零飞书依赖的本地模拟实现
3
- *
4
- * 所有飞书 API 调用都由本地 SimStore 替代:
5
- * - 消息通过 SimStore 写入内存 + JSONL + 事件推送
6
- * - 群聊/账户信息由 SimStore 统一管理
7
- * - createGroupChat 生成 "sim_<uuid>" 格式的 chat_id
8
- *
9
- * 纯函数(extractSessionInfo / formatDelayNotice / reportPermissionResults)
10
- * 直接从 feishu-api.ts re-export,不重新实现。
11
- */
12
-
13
- import { join } from "node:path";
14
-
15
- import {
16
- extractSessionInfo as realExtractSessionInfo,
17
- extractSessionId as realExtractSessionId,
18
- formatDelayNotice as realFormatDelayNotice,
19
- reportPermissionResults as realReportPermissionResults,
20
- } from "./feishu-api.ts";
21
- import type { FeishuPlatform } from "./feishu-platform.ts";
22
- import { simStore } from "./sim-store.ts";
23
-
24
- // ---------------------------------------------------------------------------
25
- // 持久化路径
26
- // ---------------------------------------------------------------------------
27
-
28
- import { homedir } from "node:os";
29
- const SIM_DIR = join(homedir(), ".chatccc", "sim");
30
-
31
- // ---------------------------------------------------------------------------
32
- // 工具函数
33
- // ---------------------------------------------------------------------------
34
-
35
- function ts(): string {
36
- return new Date().toISOString().replace("T", " ").slice(0, 19);
37
- }
38
-
39
- // ---------------------------------------------------------------------------
40
- // SimulatedPlatform
41
- // ---------------------------------------------------------------------------
42
-
43
- export const SimulatedPlatform: FeishuPlatform = {
44
- // ---- 认证 ----
45
- async getTenantAccessToken() {
46
- return "sim_token";
47
- },
48
-
49
- // ---- 消息发送:委托给 simStore ----
50
- async sendTextReply(_token, chatId, text) {
51
- console.log(`[${ts()}] [SIM:SEND] text → ${chatId}: ${text.slice(0, 80)}`);
52
- simStore.sendReply(chatId, "text", text);
53
- return true;
54
- },
55
-
56
- async sendCardReply(_token, chatId, title, content, _template) {
57
- console.log(`[${ts()}] [SIM:SEND] card → ${chatId}: [${title}]`);
58
- const text = `**[${title}]**\n${content}`;
59
- simStore.sendReply(chatId, "card", text);
60
- return true;
61
- },
62
-
63
- async sendImageReply(_token, chatId, imagePath) {
64
- console.log(`[${ts()}] [SIM:SEND] image → ${chatId}: ${imagePath}`);
65
- simStore.sendReply(chatId, "image", imagePath);
66
- return true;
67
- },
68
-
69
- async sendFileReply(_token, chatId, filePath) {
70
- console.log(`[${ts()}] [SIM:SEND] file → ${chatId}: ${filePath}`);
71
- simStore.sendReply(chatId, "file", filePath);
72
- return true;
73
- },
74
-
75
- async sendRawCard(_token, chatId, cardJson) {
76
- console.log(`[${ts()}] [SIM:SEND] raw_card → ${chatId}: ${cardJson.slice(0, 80)}...`);
77
- simStore.sendReply(chatId, "raw_card", cardJson.slice(0, 500));
78
- return true;
79
- },
80
-
81
- async sendPostMessage(_token, chatId, title, postContent) {
82
- console.log(`[${ts()}] [SIM:SEND] post → ${chatId}: title="${title}" paragraphs=${postContent.length}`);
83
- simStore.sendReply(chatId, "post", `[${title}] ${postContent.length} paragraphs`);
84
- return true;
85
- },
86
-
87
- // ---- 消息管理 ----
88
- async addReaction(_token, _messageId, _emojiType) {
89
- // 模拟模式不需要表情回应
90
- },
91
-
92
- async recallMessage(_token, _messageId) {
93
- return true;
94
- },
95
-
96
- async updateCardMessage(_token, _messageId, content) {
97
- // 模拟模式:记录卡片更新到控制台(无 chatId,不写入消息历史)
98
- console.log(`[${ts()}] [SIM:CARD] update: msgId=${_messageId} preview=${content.slice(0, 80)}`);
99
- return true;
100
- },
101
-
102
- // ---- 群聊管理 ----
103
- async createGroupChat(_token, name, userIds) {
104
- const chat = simStore.createGroupChat(name, userIds);
105
- console.log(`[${ts()}] [SIM:CHAT] created: ${chat.id} name="${name}" members=${userIds.length}`);
106
- return chat.id;
107
- },
108
-
109
- async updateChatInfo(_token, chatId, name, description) {
110
- simStore.updateChatInfo(chatId, name, description);
111
- console.log(`[${ts()}] [SIM:CHAT] updated: ${chatId} name="${name}"`);
112
- },
113
-
114
- async getChatInfo(_token, chatId) {
115
- const chat = simStore.getChat(chatId);
116
- if (!chat) throw new Error(`[99999] chat not found: ${chatId}`);
117
- return { name: chat.name, description: chat.description };
118
- },
119
-
120
- async disbandChat(_token, chatId) {
121
- simStore.disbandChat(chatId);
122
- console.log(`[${ts()}] [SIM:CHAT] disbanded: ${chatId}`);
123
- },
124
-
125
- // ---- 头像 ----
126
- async setChatAvatar(_token, _chatId, _tool, _status) {
127
- // 模拟模式不需要头像
128
- },
129
-
130
- async getCodexUsageSummary() {
131
- return {
132
- fiveHour: { usedPercent: 0, remainingPercent: 100, resetAtEpochSeconds: null, resetAfterSeconds: null },
133
- weekly: { usedPercent: 0, remainingPercent: 100, resetAtEpochSeconds: null, resetAfterSeconds: null },
134
- rateLimitResetCreditsAvailable: null,
135
- rateLimitResetCredits: null,
136
- };
137
- },
138
-
139
- async consumeCodexRateLimitResetCredit(_redeemRequestId) {
140
- return { code: "no_credit" as const, windowsReset: 0 };
141
- },
142
-
143
- // ---- 图片下载 ----
144
- async getOrDownloadImage(_token, _messageId, fileKey) {
145
- return join(SIM_DIR, "images", fileKey);
146
- },
147
-
148
- // ---- 权限验证 ----
149
- async verifyAllPermissions(_token) {
150
- return [
151
- { scope: "im:chat", description: "模拟", ok: true, detail: "模拟模式跳过" },
152
- { scope: "im:message:send_as_bot", description: "模拟", ok: true, detail: "模拟模式跳过" },
153
- { scope: "im:message:reaction", description: "模拟", ok: true, detail: "模拟模式跳过" },
154
- { scope: "im:message", description: "模拟", ok: true, detail: "模拟模式跳过" },
155
- { scope: "cardkit:card", description: "模拟", ok: true, detail: "模拟模式跳过" },
156
- ];
157
- },
158
-
159
- // ---- 纯函数:直接从真实实现 re-export ----
160
- extractSessionInfo: realExtractSessionInfo,
161
- extractSessionId: realExtractSessionId,
162
- formatDelayNotice: realFormatDelayNotice,
163
- reportPermissionResults: realReportPermissionResults,
164
-
165
- // ---- 其他 ----
166
- async sendRestartCard(_token) {
167
- // 模拟模式不需要重启通知
168
- },
169
-
170
- async getMergeForwardMessages(_token, _messageId) {
171
- // 模拟模式没有真实 API,返回空数组让调用方降级到 preview
172
- return [];
173
- },
174
- };
175
-
176
- /** 模拟模式下的默认 chat_id(重新导出以保持向后兼容) */
177
- export { SIM_DEFAULT_CHAT_ID } from "./sim-store.ts";
package/src/sim-store.ts DELETED
@@ -1,317 +0,0 @@
1
- /**
2
- * sim-store.ts — 模拟飞书环境的状态管理核心
3
- *
4
- * SimStore 是一个单例的 EventEmitter,管理所有模拟状态:
5
- * - 账户(bot + 多个用户)
6
- * - 会话(群聊 + 私聊)
7
- * - 消息历史(内存 + JSONL 持久化)
8
- *
9
- * 同时暴露 setMessageHandler / dispatchMessage,让 SimAgent 进程内触发
10
- * handleCommand 而无需通过 HTTP。
11
- */
12
-
13
- import { randomUUID } from "node:crypto";
14
- import { appendFile, mkdir } from "node:fs/promises";
15
- import { homedir } from "node:os";
16
- import { join } from "node:path";
17
- import { EventEmitter } from "node:events";
18
-
19
- // ---------------------------------------------------------------------------
20
- // 类型定义
21
- // ---------------------------------------------------------------------------
22
-
23
- export interface SimAccount {
24
- id: string; // "bot" | "sim_user_001" | "alice"
25
- kind: "bot" | "user";
26
- name: string;
27
- }
28
-
29
- export interface SimMessage {
30
- id: string; // UUID
31
- chatId: string;
32
- senderId: string; // SimAccount.id
33
- type: "text" | "card" | "image" | "file" | "raw_card" | "post" | "system";
34
- content: string; // 文本内容或 JSON 字符串
35
- timestamp: number;
36
- }
37
-
38
- export interface SimChat {
39
- id: string; // "sim_default" | "sim_<uuid8>" | "p2p_alice_bot"
40
- type: "group" | "p2p";
41
- name: string;
42
- description: string;
43
- memberIds: string[]; // 所有成员,第一个是创建者
44
- messages: SimMessage[]; // 消息历史(按时间排序)
45
- }
46
-
47
- /** handleCommand 的回调签名 */
48
- export type MessageHandler = (
49
- text: string,
50
- chatId: string,
51
- openId: string,
52
- timestamp: number,
53
- chatType: string,
54
- traceId?: string,
55
- ) => Promise<void>;
56
-
57
- // ---------------------------------------------------------------------------
58
- // 持久化路径
59
- // ---------------------------------------------------------------------------
60
-
61
- const SIM_DIR = join(homedir(), ".chatccc", "sim");
62
- const MESSAGES_FILE = join(SIM_DIR, "messages.jsonl");
63
-
64
- async function ensureDir(): Promise<void> {
65
- await mkdir(SIM_DIR, { recursive: true });
66
- }
67
-
68
- async function appendJsonl(line: Record<string, unknown>): Promise<void> {
69
- await ensureDir();
70
- await appendFile(MESSAGES_FILE, JSON.stringify(line) + "\n", "utf-8");
71
- }
72
-
73
- // ---------------------------------------------------------------------------
74
- // SimStore
75
- // ---------------------------------------------------------------------------
76
-
77
- export class SimStore extends EventEmitter {
78
- accounts = new Map<string, SimAccount>();
79
- chats = new Map<string, SimChat>();
80
-
81
- // ---- 初始化 ----
82
-
83
- constructor() {
84
- super();
85
- this._initDefaults();
86
- }
87
-
88
- private _initDefaults(): void {
89
- // 注册 bot 账户
90
- this.accounts.set("bot", { id: "bot", kind: "bot", name: "ChatCCC" });
91
-
92
- // 注册默认用户
93
- this.accounts.set("sim_user_001", { id: "sim_user_001", kind: "user", name: "Developer" });
94
-
95
- // 创建默认群聊
96
- const defaultChatId = "sim_default";
97
- this.chats.set(defaultChatId, {
98
- id: defaultChatId,
99
- type: "group",
100
- name: "默认模拟会话",
101
- description: "",
102
- memberIds: ["bot", "sim_user_001"],
103
- messages: [],
104
- });
105
- }
106
-
107
- // ---- 账户管理 ----
108
-
109
- registerAccount(account: SimAccount): void {
110
- if (this.accounts.has(account.id)) {
111
- throw new Error(`Account "${account.id}" already exists`);
112
- }
113
- this.accounts.set(account.id, account);
114
- }
115
-
116
- getAccount(id: string): SimAccount | undefined {
117
- return this.accounts.get(id);
118
- }
119
-
120
- // ---- 会话管理 ----
121
-
122
- createGroupChat(name: string, memberIds: string[]): SimChat {
123
- const chatId = `sim_${randomUUID().slice(0, 8)}`;
124
- // bot 始终是成员
125
- const allMembers = ["bot", ...memberIds.filter((id) => id !== "bot")];
126
- const chat: SimChat = {
127
- id: chatId,
128
- type: "group",
129
- name,
130
- description: "",
131
- memberIds: allMembers,
132
- messages: [],
133
- };
134
- this.chats.set(chatId, chat);
135
-
136
- // 通知被拉入群的用户
137
- for (const uid of memberIds) {
138
- this.emit("member_added", { chatId, userId: uid });
139
- }
140
- this.emit("chat_created", { chat });
141
-
142
- return chat;
143
- }
144
-
145
- createP2pChat(userId: string): SimChat {
146
- // p2p 命名规则:p2p_<userId>_bot
147
- const chatId = `p2p_${userId}_bot`;
148
- const existing = this.chats.get(chatId);
149
- if (existing) return existing;
150
-
151
- const user = this.accounts.get(userId);
152
- const chat: SimChat = {
153
- id: chatId,
154
- type: "p2p",
155
- name: user ? `${user.name} 的私聊` : `私聊`,
156
- description: "",
157
- memberIds: ["bot", userId],
158
- messages: [],
159
- };
160
- this.chats.set(chatId, chat);
161
- this.emit("chat_created", { chat });
162
- return chat;
163
- }
164
-
165
- getChat(chatId: string): SimChat | undefined {
166
- return this.chats.get(chatId);
167
- }
168
-
169
- getChatsForUser(userId: string): SimChat[] {
170
- return [...this.chats.values()].filter((c) => c.memberIds.includes(userId));
171
- }
172
-
173
- addMember(chatId: string, userId: string): void {
174
- const chat = this.chats.get(chatId);
175
- if (!chat) throw new Error(`Chat not found: ${chatId}`);
176
- if (!chat.memberIds.includes(userId)) {
177
- chat.memberIds.push(userId);
178
- this.emit("member_added", { chatId, userId });
179
- }
180
- }
181
-
182
- updateChatInfo(chatId: string, name: string, description: string): void {
183
- const chat = this.chats.get(chatId);
184
- if (chat) {
185
- chat.name = name;
186
- chat.description = description;
187
- } else {
188
- // 模拟模式下机器人可能尝试更新不存在的群(比如从旧状态恢复),兼容处理
189
- this.chats.set(chatId, {
190
- id: chatId,
191
- type: "group",
192
- name,
193
- description,
194
- memberIds: ["bot", "sim_user_001"],
195
- messages: [],
196
- });
197
- }
198
- }
199
-
200
- disbandChat(chatId: string): void {
201
- this.chats.delete(chatId);
202
- }
203
-
204
- // ---- 消息管理 ----
205
-
206
- /** 任何参与者发送消息 */
207
- recordMessage(
208
- chatId: string,
209
- senderId: string,
210
- type: SimMessage["type"],
211
- content: string,
212
- ): SimMessage {
213
- const chat = this.chats.get(chatId);
214
- if (!chat) throw new Error(`Chat not found: ${chatId}`);
215
-
216
- const msg: SimMessage = {
217
- id: randomUUID(),
218
- chatId,
219
- senderId,
220
- type,
221
- content,
222
- timestamp: Date.now(),
223
- };
224
- chat.messages.push(msg);
225
-
226
- // 写 JSONL
227
- appendJsonl({
228
- direction: senderId === "bot" ? "send" : "recv",
229
- chat_id: chatId,
230
- sender_id: senderId,
231
- msg_type: type,
232
- content,
233
- timestamp: msg.timestamp,
234
- }).catch(() => {});
235
-
236
- // 通知所有订阅者
237
- this.emit("message", { chatId, message: msg });
238
-
239
- return msg;
240
- }
241
-
242
- /** bot 发送回复——即使 chat 不存在也记录(兼容未知 chat) */
243
- sendReply(chatId: string, type: SimMessage["type"], content: string): SimMessage {
244
- const msg: SimMessage = {
245
- id: randomUUID(),
246
- chatId,
247
- senderId: "bot",
248
- type,
249
- content,
250
- timestamp: Date.now(),
251
- };
252
-
253
- // 如果 chat 存在,追加到消息历史
254
- const chat = this.chats.get(chatId);
255
- if (chat) {
256
- chat.messages.push(msg);
257
- }
258
-
259
- // 写 JSONL
260
- appendJsonl({
261
- direction: "send",
262
- chat_id: chatId,
263
- msg_type: type,
264
- content,
265
- timestamp: msg.timestamp,
266
- }).catch(() => {});
267
-
268
- // 通知订阅者
269
- this.emit("message", { chatId, message: msg });
270
-
271
- return msg;
272
- }
273
-
274
- /** 获取指定会话的消息 */
275
- getMessages(chatId: string, requesterId: string): SimMessage[] {
276
- const chat = this.chats.get(chatId);
277
- if (!chat) return [];
278
- // 只有成员能看消息
279
- if (!chat.memberIds.includes(requesterId)) return [];
280
- return chat.messages;
281
- }
282
-
283
- /** 重置所有状态(测试用) */
284
- reset(): void {
285
- this.accounts.clear();
286
- this.chats.clear();
287
- this.removeAllListeners();
288
- this._initDefaults();
289
- }
290
- }
291
-
292
- // ---------------------------------------------------------------------------
293
- // 单例 + 消息分发
294
- // ---------------------------------------------------------------------------
295
-
296
- export const simStore = new SimStore();
297
-
298
- export const SIM_DEFAULT_CHAT_ID = "sim_default";
299
-
300
- let _messageHandler: MessageHandler | null = null;
301
-
302
- /** 注册 handleCommand 回调(由 index.ts 在模拟模式启动时调用) */
303
- export function setMessageHandler(handler: MessageHandler): void {
304
- _messageHandler = handler;
305
- }
306
-
307
- /** 模拟用户发送消息 → 记录消息 + 触发 bot 处理 */
308
- export async function dispatchMessage(
309
- text: string,
310
- chatId: string,
311
- openId: string,
312
- chatType: string,
313
- ): Promise<void> {
314
- if (!_messageHandler) throw new Error("Message handler not registered — is simulate mode running?");
315
- simStore.recordMessage(chatId, openId, "text", text);
316
- await _messageHandler(text, chatId, openId, Date.now(), chatType);
317
- }