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
@@ -0,0 +1,634 @@
1
+ /**
2
+ * DeepCCC terminal REPL and JSONL streaming entrypoint — 同步自 ChatCCC
3
+ *
4
+ * Usage:
5
+ * node bin/deepccc.mjs
6
+ * node bin/deepccc.mjs --model deepseek-v4-pro
7
+ * node bin/deepccc.mjs --stream-json --prompt "hello"
8
+ *
9
+ * 交互模式(TTY)下,单轮回复渲染为固定"过程区块":状态行 + 折叠工具行 +
10
+ * 原地更新正文,不再滚屏刷 JSON;完成/停止/异常后定型留在屏幕上。
11
+ * 非 TTY(管道/CI)或 --plain 回退为纯文本流式输出;--stream-json 机器接口不变。
12
+ */
13
+ import * as readline from "node:readline";
14
+ import process from "node:process";
15
+ import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
16
+ import { homedir } from "node:os";
17
+ import { join, resolve as resolvePath } from "node:path";
18
+ import { fileURLToPath } from "node:url";
19
+ import { listBuiltinContextSessions } from "./context.js";
20
+ import { resolveBuiltinSession } from "./session-select.js";
21
+ import { createCtrlCState } from "./sigint.js";
22
+ import { buildSkillTemplate } from "./skills.js";
23
+ import { reduceProgress } from "./progress/reducer.js";
24
+ import { TerminalProgressRenderer } from "./progress/terminal-renderer.js";
25
+ import { progressView } from "./progress/view.js";
26
+ import { defaultLogDir, setupFileLogging } from "./file-log.js";
27
+ function parsePositiveIntegerOption(name, value) {
28
+ const parsed = Number(value);
29
+ if (!Number.isInteger(parsed) || parsed <= 0) {
30
+ throw new Error(`${name} must be a positive integer`);
31
+ }
32
+ return parsed;
33
+ }
34
+ function parseProviderOption(value) {
35
+ const normalized = value.trim().toLowerCase();
36
+ if (normalized === "openai" || normalized === "anthropic")
37
+ return normalized;
38
+ throw new Error(`--provider must be "openai" or "anthropic", received: ${value}`);
39
+ }
40
+ function parseArgs(argv = process.argv.slice(2)) {
41
+ const config = {};
42
+ const options = {};
43
+ let listSessions = false;
44
+ let resume;
45
+ let help = false;
46
+ let streamJson = false;
47
+ let prompt = null;
48
+ let plain = false;
49
+ for (let i = 0; i < argv.length; i++) {
50
+ const arg = argv[i];
51
+ const next = argv[i + 1];
52
+ if (arg === "--provider" && next !== undefined) {
53
+ config.provider = parseProviderOption(next);
54
+ i++;
55
+ }
56
+ else if (arg === "--model" && next !== undefined) {
57
+ config.model = next;
58
+ i++;
59
+ }
60
+ else if (arg === "--effort" && next !== undefined) {
61
+ config.effort = next;
62
+ i++;
63
+ }
64
+ else if (arg === "--base-url" && next !== undefined) {
65
+ config.baseURL = next;
66
+ i++;
67
+ }
68
+ else if (arg === "--api-key" && next !== undefined) {
69
+ config.apiKey = next;
70
+ i++;
71
+ }
72
+ else if (arg === "--cwd" && next !== undefined) {
73
+ options.cwd = next;
74
+ i++;
75
+ }
76
+ else if (arg === "--max-steps" && next !== undefined) {
77
+ options.maxSteps = parsePositiveIntegerOption("--max-steps", next);
78
+ i++;
79
+ }
80
+ else if (arg === "--resume") {
81
+ if (next !== undefined && !next.startsWith("--")) {
82
+ resume = next;
83
+ i++;
84
+ }
85
+ else {
86
+ resume = true;
87
+ }
88
+ }
89
+ else if (arg === "--list-sessions") {
90
+ listSessions = true;
91
+ }
92
+ else if (arg === "--stream-json") {
93
+ streamJson = true;
94
+ }
95
+ else if (arg === "--prompt" && next !== undefined) {
96
+ prompt = next;
97
+ i++;
98
+ }
99
+ else if (arg === "--plain") {
100
+ plain = true;
101
+ }
102
+ else if (arg === "--dangerously-bypass-permissions") {
103
+ // 仅保留一个 bypass 入口(对齐 chatccc 调 claude/codex 的 bypass 模式)
104
+ options.permissionMode = "bypass";
105
+ }
106
+ else if (arg === "--help" || arg === "-h") {
107
+ help = true;
108
+ }
109
+ }
110
+ return { config, options, listSessions, resume, help, streamJson, prompt, plain };
111
+ }
112
+ async function loadRuntime() {
113
+ const [{ ChatSession }, { config: appConfig }] = await Promise.all([
114
+ import("./index.js"),
115
+ import("./config.js"),
116
+ ]);
117
+ return { ChatSession, appConfig };
118
+ }
119
+ function printHelp(appConfig) {
120
+ console.log([
121
+ "DeepCCC terminal agent",
122
+ "",
123
+ "Usage: deepccc [options]",
124
+ "",
125
+ "Options:",
126
+ ` --provider <name> API protocol: openai or anthropic (current default ${appConfig.provider})`,
127
+ ` --model <name> Model name (current default ${appConfig.model})`,
128
+ ` --effort <level> Reasoning effort: none/minimal/low/medium/high/xhigh/max (overrides config.effort)`,
129
+ ` --base-url <url> Provider API base URL (current default ${appConfig.baseURL})`,
130
+ " --api-key <key> API key",
131
+ " --cwd <path> Working directory",
132
+ " --max-steps <n> Optional tool-step limit. Omit for no step limit",
133
+ " --resume [id] Resume latest cwd session, or the explicit session id",
134
+ " --list-sessions List saved sessions and exit",
135
+ " --stream-json One-shot mode: write JSONL events to stdout",
136
+ " --prompt <text> Prompt text for --stream-json",
137
+ " --plain Force plain streaming output (no progress block renderer)",
138
+ " --dangerously-bypass-permissions Skip all permission prompts (aligns with chatccc's bypass mode)",
139
+ " --help, -h Show help",
140
+ "",
141
+ "Permissions:",
142
+ " Default mode asks before high-risk commands (rm -rf, git push --force, ...).",
143
+ " Answer y = allow once, a = allow always (saved to ~/.deepccc/allow.json),",
144
+ " n = deny, g = allow all for this session. Read-only tools and normal file",
145
+ " edits never prompt. In non-interactive mode (--stream-json) high-risk",
146
+ " commands are denied unless --dangerously-bypass-permissions is passed.",
147
+ "",
148
+ "Default config source:",
149
+ " ~/.deepccc/config.json, DEEPCCC_* environment variables, or DEEPSEEK_* aliases",
150
+ "",
151
+ ].join("\n"));
152
+ }
153
+ function formatTime(ms) {
154
+ return new Date(ms).toLocaleString();
155
+ }
156
+ function printSessions(streamJson = false) {
157
+ const sessions = listBuiltinContextSessions();
158
+ if (streamJson) {
159
+ writeJsonLine({
160
+ type: "sessions",
161
+ sessions: sessions.map((session) => ({
162
+ session_id: session.sessionId,
163
+ turns: session.totalMessages,
164
+ compacted_messages: session.compactedMessages,
165
+ has_summary: session.hasSummary,
166
+ updated_at: session.updatedAt,
167
+ cwd: session.cwd,
168
+ })),
169
+ });
170
+ return;
171
+ }
172
+ if (sessions.length === 0) {
173
+ console.log("No saved DeepCCC sessions");
174
+ return;
175
+ }
176
+ for (const session of sessions) {
177
+ const summary = session.hasSummary ? " summary=yes" : "";
178
+ const cwd = session.cwd ? ` cwd=${session.cwd}` : "";
179
+ console.log(`${session.sessionId} turns=${session.totalMessages} compacted=${session.compactedMessages}${summary} updated=${formatTime(session.updatedAt)}${cwd}`);
180
+ }
181
+ }
182
+ function stringifyConsoleArg(value) {
183
+ if (typeof value === "string")
184
+ return value;
185
+ if (value instanceof Error)
186
+ return value.stack ?? value.message;
187
+ try {
188
+ return JSON.stringify(value);
189
+ }
190
+ catch {
191
+ return String(value);
192
+ }
193
+ }
194
+ function redirectConsoleLogsToStderr() {
195
+ const write = (...args) => {
196
+ process.stderr.write(`${args.map(stringifyConsoleArg).join(" ")}\n`);
197
+ };
198
+ console.log = write;
199
+ console.info = write;
200
+ console.warn = write;
201
+ }
202
+ function writeJsonLine(event) {
203
+ process.stdout.write(`${JSON.stringify(event)}\n`);
204
+ }
205
+ function streamJsonEvent(event) {
206
+ if (event.type === "status") {
207
+ writeJsonLine({
208
+ type: "status",
209
+ phase: event.phase,
210
+ });
211
+ }
212
+ else if (event.type === "text") {
213
+ writeJsonLine({
214
+ type: "text_delta",
215
+ text: event.text,
216
+ accumulated: event.accumulated,
217
+ });
218
+ }
219
+ else if (event.type === "compact") {
220
+ writeJsonLine({
221
+ type: "compact",
222
+ compacted_messages: event.compactedMessages,
223
+ });
224
+ }
225
+ else if (event.type === "tool_use") {
226
+ writeJsonLine({
227
+ type: "tool_call",
228
+ id: event.id,
229
+ name: event.name,
230
+ input: event.input,
231
+ });
232
+ }
233
+ else if (event.type === "tool_result") {
234
+ writeJsonLine({
235
+ type: "tool_result",
236
+ tool_call_id: event.tool_use_id,
237
+ name: event.name,
238
+ content: event.content,
239
+ is_error: event.is_error,
240
+ });
241
+ }
242
+ else if (event.type === "done") {
243
+ writeJsonLine({
244
+ type: "done",
245
+ text: event.text,
246
+ });
247
+ }
248
+ else if (event.type === "error") {
249
+ writeJsonLine({
250
+ type: "error",
251
+ message: event.message,
252
+ });
253
+ }
254
+ }
255
+ async function readPromptFromStdin() {
256
+ const chunks = [];
257
+ for await (const chunk of process.stdin) {
258
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
259
+ }
260
+ return Buffer.concat(chunks).toString("utf8");
261
+ }
262
+ async function runStreamJson(args) {
263
+ redirectConsoleLogsToStderr();
264
+ if (args.listSessions) {
265
+ printSessions(true);
266
+ return 0;
267
+ }
268
+ const prompt = args.prompt ?? (!process.stdin.isTTY ? await readPromptFromStdin() : "");
269
+ if (!prompt.trim()) {
270
+ writeJsonLine({ type: "error", message: "--stream-json requires --prompt <text> or stdin input" });
271
+ return 1;
272
+ }
273
+ let runtime;
274
+ try {
275
+ runtime = await loadRuntime();
276
+ }
277
+ catch (err) {
278
+ writeJsonLine({ type: "error", message: err.message });
279
+ return 1;
280
+ }
281
+ const cwd = resolvePath(args.options.cwd ?? process.cwd());
282
+ let resolvedSession;
283
+ try {
284
+ resolvedSession = resolveBuiltinSession({ cwd, resume: args.resume });
285
+ }
286
+ catch (err) {
287
+ writeJsonLine({ type: "error", message: err.message });
288
+ return 1;
289
+ }
290
+ let session;
291
+ try {
292
+ session = new runtime.ChatSession(args.config, {
293
+ ...args.options,
294
+ cwd,
295
+ persist: true,
296
+ sessionId: resolvedSession.sessionId,
297
+ });
298
+ }
299
+ catch (err) {
300
+ writeJsonLine({ type: "error", message: err.message });
301
+ return 1;
302
+ }
303
+ writeJsonLine({
304
+ type: "start",
305
+ session_id: resolvedSession.sessionId,
306
+ mode: resolvedSession.mode,
307
+ cwd,
308
+ model: args.config.model ?? runtime.appConfig.model,
309
+ });
310
+ try {
311
+ for await (const event of session.chat(prompt)) {
312
+ streamJsonEvent(event);
313
+ }
314
+ return 0;
315
+ }
316
+ catch (err) {
317
+ writeJsonLine({ type: "error", message: err.message });
318
+ return 1;
319
+ }
320
+ }
321
+ const C = {
322
+ reset: "\x1b[0m",
323
+ dim: "\x1b[2m",
324
+ green: "\x1b[32m",
325
+ yellow: "\x1b[33m",
326
+ };
327
+ /**
328
+ * 交互模式下渲染器独占终端 stdout:普通日志只写日志文件、不回显到终端,
329
+ * 避免生成过程中任何 console 输出混入过程区块、破坏行数计数(导致重绘
330
+ * 上移不足、把上方历史内容"吃掉")。错误提示(console.error)保留回显。
331
+ */
332
+ function muteConsoleLogToFile(logPath) {
333
+ const writeFile = (level, args) => {
334
+ try {
335
+ const text = args
336
+ .map((a) => typeof a === "string" ? a
337
+ : a instanceof Error ? (a.stack ?? a.message)
338
+ : JSON.stringify(a))
339
+ .join(" ");
340
+ appendFileSync(logPath, `[${new Date().toISOString()}] [${level}] ${text}\n`, "utf8");
341
+ }
342
+ catch {
343
+ // 日志系统自身失败不影响主流程
344
+ }
345
+ };
346
+ console.log = (...args) => writeFile("LOG", args);
347
+ console.info = (...args) => writeFile("INFO", args);
348
+ console.warn = (...args) => writeFile("WARN", args);
349
+ }
350
+ async function runRepl(args) {
351
+ const { ChatSession, appConfig } = await loadRuntime();
352
+ const cwd = resolvePath(args.options.cwd ?? process.cwd());
353
+ let resolvedSession;
354
+ try {
355
+ resolvedSession = resolveBuiltinSession({ cwd, resume: args.resume });
356
+ }
357
+ catch (err) {
358
+ console.error(`${C.yellow}${err.message}${C.reset}`);
359
+ process.exit(1);
360
+ }
361
+ console.log(`${C.dim}DeepCCC agent${C.reset}`);
362
+ console.log(`${C.dim}Provider: ${args.config.provider ?? appConfig.provider}${C.reset}`);
363
+ console.log(`${C.dim}Model: ${args.config.model ?? appConfig.model}${C.reset}`);
364
+ console.log(`${C.dim}Directory: ${cwd}${C.reset}`);
365
+ console.log(`${C.dim}Session: ${resolvedSession.sessionId} (${resolvedSession.mode === "new" ? "new" : "resumed"})${C.reset}`);
366
+ console.log(`${C.dim}Type a message to chat. Double Ctrl+C interrupts generation or exits. Type exit to quit.${C.reset}`);
367
+ console.log("");
368
+ // 交互渲染模式下 console 输出只写日志文件、不回显到终端(渲染器独占 stdout,
369
+ // 避免生成中日志混入区块破坏行数)。--plain 无渲染器,不需要静音。
370
+ if (process.stdout.isTTY === true && !args.plain) {
371
+ muteConsoleLogToFile(setupFileLogging(defaultLogDir(), "index").logPath);
372
+ }
373
+ const rl = readline.createInterface({
374
+ input: process.stdin,
375
+ output: process.stdout,
376
+ prompt: `${C.green}>${C.reset} `,
377
+ });
378
+ // 权限交互:暂停过程区块渲染(恢复光标)→ readline 提问 → 恢复渲染。
379
+ // activeRenderer/activeView 由每轮 line 处理器维护,resolver 只在工具
380
+ // 执行期间被调用,此时当前轮的区块正处于运行中。
381
+ let activeRenderer = null;
382
+ let activeView = null;
383
+ const permissionResolver = async (request) => {
384
+ const renderer = activeRenderer;
385
+ const view = activeView;
386
+ if (renderer)
387
+ renderer.dispose();
388
+ process.stdout.write(`\n${C.yellow}⚠️ 高危操作需要确认${C.reset}\n`);
389
+ process.stdout.write(`${C.dim}${request.detail}${C.reset}\n`);
390
+ const answer = await new Promise((resolve) => {
391
+ rl.question(`${C.green}允许一次(y) / 永远允许(a) / 拒绝(n) / 本会话允许所有(g) >${C.reset} `, resolve);
392
+ });
393
+ if (renderer && view)
394
+ renderer.begin(view);
395
+ const v = answer.trim().toLowerCase();
396
+ if (v === "y")
397
+ return "allow";
398
+ if (v === "a")
399
+ return "allow-always";
400
+ if (v === "g")
401
+ return "allow-session";
402
+ return "deny";
403
+ };
404
+ let session;
405
+ try {
406
+ session = new ChatSession(args.config, {
407
+ ...args.options,
408
+ cwd,
409
+ persist: true,
410
+ sessionId: resolvedSession.sessionId,
411
+ permissionResolver,
412
+ });
413
+ }
414
+ catch (err) {
415
+ console.error(`${C.yellow}${err.message}${C.reset}`);
416
+ process.exit(1);
417
+ }
418
+ let currentAbort = null;
419
+ const ctrlCState = createCtrlCState();
420
+ rl.prompt();
421
+ rl.on("line", async (line) => {
422
+ ctrlCState.reset();
423
+ const input = line.trim();
424
+ if (!input) {
425
+ rl.prompt();
426
+ return;
427
+ }
428
+ if (input === "exit") {
429
+ process.stdout.write(`${C.dim}bye${C.reset}\n`);
430
+ rl.close();
431
+ return;
432
+ }
433
+ if (input === "/clear") {
434
+ session.reset();
435
+ process.stdout.write(`${C.dim}session cleared${C.reset}\n`);
436
+ rl.prompt();
437
+ return;
438
+ }
439
+ if (input === "/history") {
440
+ process.stdout.write(`${C.dim}${session.turnCount} conversation turns${C.reset}\n`);
441
+ rl.prompt();
442
+ return;
443
+ }
444
+ if (input === "/sessions") {
445
+ printSessions();
446
+ rl.prompt();
447
+ return;
448
+ }
449
+ currentAbort = new AbortController();
450
+ const signal = currentAbort.signal;
451
+ // TTY 下用"过程区块"(飞书过程卡片的终端形态):固定区域原地更新、
452
+ // 工具调用折叠为单行;非 TTY(管道/CI)或 --plain 回退为纯文本流式输出。
453
+ const useTerminalBlock = process.stdout.isTTY === true && !args.plain;
454
+ const renderer = useTerminalBlock ? new TerminalProgressRenderer() : null;
455
+ let view = null;
456
+ if (renderer) {
457
+ view = progressView({ headerTitle: "生成中..." });
458
+ activeRenderer = renderer;
459
+ activeView = view;
460
+ // 先回行首换行再 begin:让过程区块从输入行下方开始,避免首帧 \r\x1b[2K
461
+ // 清掉用户刚输入的问题行(历史文本不被刷掉)。\r\n 兼容 readline
462
+ // 行提交后光标仍停在输入行行尾的情况。
463
+ process.stdout.write("\r\n");
464
+ renderer.begin(view);
465
+ }
466
+ let rendererEnded = false;
467
+ try {
468
+ let lastAccumulated = "";
469
+ for await (const event of session.chat(input, signal)) {
470
+ if (renderer && view) {
471
+ view = reduceProgress(view, event);
472
+ if (event.type === "text" || event.type === "compact" || event.type === "status") {
473
+ renderer.render(view);
474
+ }
475
+ else {
476
+ renderer.flush();
477
+ }
478
+ }
479
+ else if (event.type === "status") {
480
+ console.log(`${C.dim}[${event.phase === "compacting" ? "compacting context" : "generating reply"}]${C.reset}`);
481
+ }
482
+ else if (event.type === "text") {
483
+ const newText = event.accumulated.slice(lastAccumulated.length);
484
+ process.stdout.write(newText);
485
+ lastAccumulated = event.accumulated;
486
+ }
487
+ else if (event.type === "done") {
488
+ if (lastAccumulated)
489
+ console.log("");
490
+ console.log(`${C.dim}[done]${C.reset}`);
491
+ }
492
+ else if (event.type === "compact") {
493
+ console.log(`${C.dim}[context compacted: ${event.compactedMessages} old messages]${C.reset}`);
494
+ }
495
+ else if (event.type === "tool_use") {
496
+ console.log(`\n${C.dim}[tool] ${event.name} ${stringifyConsoleArg(event.input)}${C.reset}`);
497
+ }
498
+ else if (event.type === "tool_result") {
499
+ const status = event.is_error ? "error" : "ok";
500
+ console.log(`${C.dim}[tool result] ${event.name ?? event.tool_use_id} ${status}${C.reset}`);
501
+ }
502
+ else if (event.type === "error") {
503
+ console.log(`\n${C.yellow}[error] ${event.message}${C.reset}`);
504
+ }
505
+ }
506
+ }
507
+ catch (err) {
508
+ if (renderer && view) {
509
+ const aborted = err instanceof Error && err.name === "AbortError";
510
+ view = progressView({ ...view, status: aborted ? "stopped" : "error", showStop: false });
511
+ renderer.end(view);
512
+ rendererEnded = true;
513
+ process.stdout.write("\n");
514
+ }
515
+ console.error(`\n${C.yellow}[error] ${err.message}${C.reset}`);
516
+ }
517
+ finally {
518
+ activeRenderer = null;
519
+ activeView = null;
520
+ if (renderer && view && !rendererEnded) {
521
+ // 定型终态区块(完成/已停止/异常结束)留在屏幕上,恢复光标
522
+ renderer.end(view);
523
+ process.stdout.write("\n");
524
+ }
525
+ currentAbort = null;
526
+ ctrlCState.reset();
527
+ }
528
+ rl.prompt();
529
+ });
530
+ rl.on("SIGINT", () => {
531
+ const action = ctrlCState.press(currentAbort !== null);
532
+ if (action === "exit") {
533
+ console.error(`\n${C.dim}bye${C.reset}`);
534
+ rl.close();
535
+ return;
536
+ }
537
+ if (action === "interrupt") {
538
+ console.error(`\n${C.yellow}[interrupting...]${C.reset}`);
539
+ currentAbort?.abort();
540
+ currentAbort = null;
541
+ return;
542
+ }
543
+ if (action === "arm-interrupt") {
544
+ console.error(`\n${C.dim}Press Ctrl+C again to interrupt current response${C.reset}`);
545
+ return;
546
+ }
547
+ if (action === "arm-exit") {
548
+ console.error(`\n${C.dim}Press Ctrl+C again to exit, or type exit${C.reset}`);
549
+ rl.prompt();
550
+ }
551
+ });
552
+ rl.on("close", () => {
553
+ process.stdout.write("\n");
554
+ process.exit(0);
555
+ });
556
+ }
557
+ /**
558
+ * skill create 子命令:deepccc skill create <name> [--scope global|project] [--description "..."]
559
+ * 默认创建为全局技能(~/.deepccc/skills/<name>/SKILL.md,Codex 结构);
560
+ * --scope project 创建为项目技能(<cwd>/.deepccc/skills/<name>/SKILL.md)。
561
+ * 新技能在下一次对话自动生效(技能索引每次 chat() 前重扫)。
562
+ */
563
+ function runSkillCreate(argv) {
564
+ const positional = argv.filter((a) => !a.startsWith("--"));
565
+ const name = positional[0];
566
+ if (!name) {
567
+ console.error("usage: deepccc skill create <name> [--scope global|project] [--description \"...\"]");
568
+ process.exit(1);
569
+ }
570
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name)) {
571
+ console.error(`invalid skill name: ${name}(允许字母/数字/._-,不能以 . 或 - 开头)`);
572
+ process.exit(1);
573
+ }
574
+ const scopeIdx = argv.indexOf("--scope");
575
+ const scope = scopeIdx !== -1 && argv[scopeIdx + 1] === "project" ? "project" : "global";
576
+ const descIdx = argv.indexOf("--description");
577
+ const description = descIdx !== -1 ? (argv[descIdx + 1] ?? "") : "";
578
+ const base = scope === "project"
579
+ ? join(process.cwd(), ".deepccc", "skills")
580
+ : join(homedir(), ".deepccc", "skills");
581
+ const skillPath = join(base, name, "SKILL.md");
582
+ if (existsSync(skillPath)) {
583
+ console.error(`skill already exists: ${skillPath}`);
584
+ process.exit(1);
585
+ }
586
+ try {
587
+ mkdirSync(join(base, name), { recursive: true });
588
+ writeFileSync(skillPath, buildSkillTemplate(name, description), "utf8");
589
+ }
590
+ catch (err) {
591
+ console.error(`failed to create skill: ${err.message}`);
592
+ process.exit(1);
593
+ }
594
+ console.log(`created skill: ${skillPath}`);
595
+ console.log(`scope: ${scope === "project" ? "project(仅当前项目生效)" : "global(所有项目生效)"}`);
596
+ if (description)
597
+ console.log(`description: ${description}`);
598
+ console.log("hot reload: 下一次对话自动生效,无需重启");
599
+ }
600
+ async function main() {
601
+ // skill create 子命令:deepccc skill create <name> [--scope global|project] [--description "..."]
602
+ // 默认创建在全局 ~/.deepccc/skills(Codex 目录结构),--scope project 创建到 <cwd>/.deepccc/skills。
603
+ if (process.argv[2] === "skill" && process.argv[3] === "create") {
604
+ runSkillCreate(process.argv.slice(4));
605
+ return;
606
+ }
607
+ const args = parseArgs();
608
+ if (args.streamJson) {
609
+ const code = await runStreamJson(args);
610
+ process.exitCode = code;
611
+ return;
612
+ }
613
+ if (args.help) {
614
+ const { appConfig } = await loadRuntime();
615
+ printHelp(appConfig);
616
+ return;
617
+ }
618
+ if (args.listSessions) {
619
+ printSessions();
620
+ return;
621
+ }
622
+ await runRepl(args);
623
+ }
624
+ function isDirectCliInvocation() {
625
+ const current = resolvePath(fileURLToPath(import.meta.url));
626
+ const invoked = process.argv[1] ? resolvePath(process.argv[1]) : "";
627
+ return current === invoked;
628
+ }
629
+ if (isDirectCliInvocation()) {
630
+ main().catch((err) => {
631
+ console.error(`${C.yellow}startup failed: ${err.message}${C.reset}`);
632
+ process.exit(1);
633
+ });
634
+ }