chatccc 0.2.94 → 0.2.95
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.
- package/im-skills/wechat-file-skill/receive-send-file.md +38 -38
- package/im-skills/wechat-file-skill/send-file.mjs +83 -83
- package/im-skills/wechat-file-skill/skill.md +10 -10
- package/im-skills/wechat-image-skill/skill.md +10 -10
- package/im-skills/wechat-video-skill/receive-send-video.md +38 -38
- package/im-skills/wechat-video-skill/send-video.mjs +79 -79
- package/im-skills/wechat-video-skill/skill.md +10 -10
- package/package.json +1 -1
- package/scripts/postinstall-sharp-check.mjs +58 -58
- package/src/__tests__/session.test.ts +91 -1
- package/src/__tests__/stream-state.test.ts +42 -42
- package/src/adapters/adapter-interface.ts +13 -0
- package/src/adapters/codex-adapter.ts +4 -0
- package/src/adapters/cursor-adapter.ts +4 -0
- package/src/builtin/cli.ts +196 -196
- package/src/builtin/index.ts +166 -166
- package/src/session-chat-binding.ts +9 -0
- package/src/session.ts +148 -12
- package/src/stream-state.ts +33 -33
- package/src/turn-cards.ts +117 -117
package/src/builtin/cli.ts
CHANGED
|
@@ -1,197 +1,197 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* builtin/cli.ts — ChatCCC 内置 Agent 终端 REPL
|
|
3
|
-
*
|
|
4
|
-
* 用法:
|
|
5
|
-
* npx tsx src/builtin/cli.ts
|
|
6
|
-
* npx tsx src/builtin/cli.ts --model deepseek-chat
|
|
7
|
-
* npx tsx src/builtin/cli.ts --cwd /path/to/project
|
|
8
|
-
*
|
|
9
|
-
* 环境变量:
|
|
10
|
-
* DEEPSEEK_API_KEY — DeepSeek API Key(必需)
|
|
11
|
-
* DEEPSEEK_BASE_URL — API 地址(可选,默认 https://api.deepseek.com/v1)
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import * as readline from "node:readline";
|
|
15
|
-
import * as process from "node:process";
|
|
16
|
-
import { ChatSession, type ChatSessionConfig, type ChatSessionOptions } from "./index.js";
|
|
17
|
-
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
// 命令行参数解析
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
|
|
22
|
-
function parseArgs(): { config: ChatSessionConfig; options: ChatSessionOptions } {
|
|
23
|
-
const args = process.argv.slice(2);
|
|
24
|
-
const config: ChatSessionConfig = {};
|
|
25
|
-
const options: ChatSessionOptions = {};
|
|
26
|
-
|
|
27
|
-
for (let i = 0; i < args.length; i++) {
|
|
28
|
-
const arg = args[i];
|
|
29
|
-
const next = args[i + 1];
|
|
30
|
-
if (arg === "--model" && next) {
|
|
31
|
-
config.model = next;
|
|
32
|
-
i++;
|
|
33
|
-
} else if (arg === "--base-url" && next) {
|
|
34
|
-
config.baseURL = next;
|
|
35
|
-
i++;
|
|
36
|
-
} else if (arg === "--api-key" && next) {
|
|
37
|
-
config.apiKey = next;
|
|
38
|
-
i++;
|
|
39
|
-
} else if (arg === "--cwd" && next) {
|
|
40
|
-
options.cwd = next;
|
|
41
|
-
i++;
|
|
42
|
-
} else if (arg === "--help" || arg === "-h") {
|
|
43
|
-
printHelp();
|
|
44
|
-
process.exit(0);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return { config, options };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function printHelp(): void {
|
|
52
|
-
console.log([
|
|
53
|
-
"ChatCCC 内置 Agent 终端 REPL",
|
|
54
|
-
"",
|
|
55
|
-
"用法: npx tsx src/builtin/cli.ts [选项]",
|
|
56
|
-
"",
|
|
57
|
-
"选项:",
|
|
58
|
-
" --model <name> 模型名称(默认 deepseek-chat)",
|
|
59
|
-
" --base-url <url> API 地址(默认 https://api.deepseek.com/v1)",
|
|
60
|
-
" --api-key <key> API Key(默认读 DEEPSEEK_API_KEY 环境变量)",
|
|
61
|
-
" --cwd <path> 工作目录",
|
|
62
|
-
" --help, -h 显示帮助",
|
|
63
|
-
"",
|
|
64
|
-
"环境变量:",
|
|
65
|
-
" DEEPSEEK_API_KEY DeepSeek API Key",
|
|
66
|
-
" DEEPSEEK_BASE_URL API 地址",
|
|
67
|
-
"",
|
|
68
|
-
].join("\n"));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ---------------------------------------------------------------------------
|
|
72
|
-
// ANSI 颜色
|
|
73
|
-
// ---------------------------------------------------------------------------
|
|
74
|
-
|
|
75
|
-
const C = {
|
|
76
|
-
reset: "\x1b[0m",
|
|
77
|
-
dim: "\x1b[2m",
|
|
78
|
-
green: "\x1b[32m",
|
|
79
|
-
cyan: "\x1b[36m",
|
|
80
|
-
yellow: "\x1b[33m",
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// ---------------------------------------------------------------------------
|
|
84
|
-
// 主程序
|
|
85
|
-
// ---------------------------------------------------------------------------
|
|
86
|
-
|
|
87
|
-
async function main(): Promise<void> {
|
|
88
|
-
const { config, options } = parseArgs();
|
|
89
|
-
|
|
90
|
-
// 环境变量回退
|
|
91
|
-
if (!config.baseURL) config.baseURL = process.env.DEEPSEEK_BASE_URL;
|
|
92
|
-
if (!config.apiKey) config.apiKey = process.env.DEEPSEEK_API_KEY;
|
|
93
|
-
|
|
94
|
-
console.log(`${C.dim}ChatCCC 内置 Agent 原型${C.reset}`);
|
|
95
|
-
console.log(`${C.dim}模型: ${config.model ?? "deepseek-chat"}${C.reset}`);
|
|
96
|
-
if (options.cwd) {
|
|
97
|
-
console.log(`${C.dim}目录: ${options.cwd}${C.reset}`);
|
|
98
|
-
}
|
|
99
|
-
console.log(`${C.dim}输入消息开始对话,Ctrl+C 中断当前回复,/exit 退出${C.reset}`);
|
|
100
|
-
console.log("");
|
|
101
|
-
|
|
102
|
-
let session: ChatSession;
|
|
103
|
-
try {
|
|
104
|
-
session = new ChatSession(config, options);
|
|
105
|
-
} catch (err) {
|
|
106
|
-
console.error(`${C.yellow}${(err as Error).message}${C.reset}`);
|
|
107
|
-
process.exit(1);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const rl = readline.createInterface({
|
|
111
|
-
input: process.stdin,
|
|
112
|
-
output: process.stdout,
|
|
113
|
-
prompt: `${C.green}>${C.reset} `,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
// 用于中断当前 LLM 调用的 AbortController
|
|
117
|
-
let currentAbort: AbortController | null = null;
|
|
118
|
-
|
|
119
|
-
rl.prompt();
|
|
120
|
-
|
|
121
|
-
rl.on("line", async (line: string) => {
|
|
122
|
-
const input = line.trim();
|
|
123
|
-
if (!input) {
|
|
124
|
-
rl.prompt();
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// 特殊命令
|
|
129
|
-
if (input === "/exit" || input === "/quit") {
|
|
130
|
-
console.log(`${C.dim}再见${C.reset}`);
|
|
131
|
-
rl.close();
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (input === "/clear") {
|
|
136
|
-
session.reset();
|
|
137
|
-
console.log(`${C.dim}会话已重置${C.reset}`);
|
|
138
|
-
rl.prompt();
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (input === "/history") {
|
|
143
|
-
console.log(`${C.dim}共 ${session.turnCount} 轮对话${C.reset}`);
|
|
144
|
-
rl.prompt();
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// 发送消息
|
|
149
|
-
currentAbort = new AbortController();
|
|
150
|
-
const signal = currentAbort.signal;
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
let lastAccumulated = "";
|
|
154
|
-
for await (const event of session.chat(input, signal)) {
|
|
155
|
-
if (event.type === "text") {
|
|
156
|
-
// 增量输出(仅在首次和行首时不换行)
|
|
157
|
-
const newText = event.accumulated.slice(lastAccumulated.length);
|
|
158
|
-
process.stdout.write(newText);
|
|
159
|
-
lastAccumulated = event.accumulated;
|
|
160
|
-
} else if (event.type === "done") {
|
|
161
|
-
if (lastAccumulated) console.log("");
|
|
162
|
-
console.log(`${C.dim}[完成]${C.reset}`);
|
|
163
|
-
} else if (event.type === "error") {
|
|
164
|
-
console.log(`\n${C.yellow}[错误] ${event.message}${C.reset}`);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
} catch (err) {
|
|
168
|
-
console.log(`\n${C.yellow}[错误] ${(err as Error).message}${C.reset}`);
|
|
169
|
-
} finally {
|
|
170
|
-
currentAbort = null;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
rl.prompt();
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// Ctrl+C → 中断当前 LLM 调用(不退出程序)
|
|
177
|
-
rl.on("SIGINT", () => {
|
|
178
|
-
if (currentAbort) {
|
|
179
|
-
console.log(`\n${C.yellow}[中断中...]${C.reset}`);
|
|
180
|
-
currentAbort.abort();
|
|
181
|
-
currentAbort = null;
|
|
182
|
-
} else {
|
|
183
|
-
console.log(`\n${C.dim}输入 /exit 退出${C.reset}`);
|
|
184
|
-
rl.prompt();
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
rl.on("close", () => {
|
|
189
|
-
console.log("");
|
|
190
|
-
process.exit(0);
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
main().catch((err) => {
|
|
195
|
-
console.error(`${C.yellow}启动失败: ${(err as Error).message}${C.reset}`);
|
|
196
|
-
process.exit(1);
|
|
1
|
+
/**
|
|
2
|
+
* builtin/cli.ts — ChatCCC 内置 Agent 终端 REPL
|
|
3
|
+
*
|
|
4
|
+
* 用法:
|
|
5
|
+
* npx tsx src/builtin/cli.ts
|
|
6
|
+
* npx tsx src/builtin/cli.ts --model deepseek-chat
|
|
7
|
+
* npx tsx src/builtin/cli.ts --cwd /path/to/project
|
|
8
|
+
*
|
|
9
|
+
* 环境变量:
|
|
10
|
+
* DEEPSEEK_API_KEY — DeepSeek API Key(必需)
|
|
11
|
+
* DEEPSEEK_BASE_URL — API 地址(可选,默认 https://api.deepseek.com/v1)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import * as readline from "node:readline";
|
|
15
|
+
import * as process from "node:process";
|
|
16
|
+
import { ChatSession, type ChatSessionConfig, type ChatSessionOptions } from "./index.js";
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// 命令行参数解析
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
function parseArgs(): { config: ChatSessionConfig; options: ChatSessionOptions } {
|
|
23
|
+
const args = process.argv.slice(2);
|
|
24
|
+
const config: ChatSessionConfig = {};
|
|
25
|
+
const options: ChatSessionOptions = {};
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < args.length; i++) {
|
|
28
|
+
const arg = args[i];
|
|
29
|
+
const next = args[i + 1];
|
|
30
|
+
if (arg === "--model" && next) {
|
|
31
|
+
config.model = next;
|
|
32
|
+
i++;
|
|
33
|
+
} else if (arg === "--base-url" && next) {
|
|
34
|
+
config.baseURL = next;
|
|
35
|
+
i++;
|
|
36
|
+
} else if (arg === "--api-key" && next) {
|
|
37
|
+
config.apiKey = next;
|
|
38
|
+
i++;
|
|
39
|
+
} else if (arg === "--cwd" && next) {
|
|
40
|
+
options.cwd = next;
|
|
41
|
+
i++;
|
|
42
|
+
} else if (arg === "--help" || arg === "-h") {
|
|
43
|
+
printHelp();
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { config, options };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function printHelp(): void {
|
|
52
|
+
console.log([
|
|
53
|
+
"ChatCCC 内置 Agent 终端 REPL",
|
|
54
|
+
"",
|
|
55
|
+
"用法: npx tsx src/builtin/cli.ts [选项]",
|
|
56
|
+
"",
|
|
57
|
+
"选项:",
|
|
58
|
+
" --model <name> 模型名称(默认 deepseek-chat)",
|
|
59
|
+
" --base-url <url> API 地址(默认 https://api.deepseek.com/v1)",
|
|
60
|
+
" --api-key <key> API Key(默认读 DEEPSEEK_API_KEY 环境变量)",
|
|
61
|
+
" --cwd <path> 工作目录",
|
|
62
|
+
" --help, -h 显示帮助",
|
|
63
|
+
"",
|
|
64
|
+
"环境变量:",
|
|
65
|
+
" DEEPSEEK_API_KEY DeepSeek API Key",
|
|
66
|
+
" DEEPSEEK_BASE_URL API 地址",
|
|
67
|
+
"",
|
|
68
|
+
].join("\n"));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// ANSI 颜色
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
const C = {
|
|
76
|
+
reset: "\x1b[0m",
|
|
77
|
+
dim: "\x1b[2m",
|
|
78
|
+
green: "\x1b[32m",
|
|
79
|
+
cyan: "\x1b[36m",
|
|
80
|
+
yellow: "\x1b[33m",
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// 主程序
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
async function main(): Promise<void> {
|
|
88
|
+
const { config, options } = parseArgs();
|
|
89
|
+
|
|
90
|
+
// 环境变量回退
|
|
91
|
+
if (!config.baseURL) config.baseURL = process.env.DEEPSEEK_BASE_URL;
|
|
92
|
+
if (!config.apiKey) config.apiKey = process.env.DEEPSEEK_API_KEY;
|
|
93
|
+
|
|
94
|
+
console.log(`${C.dim}ChatCCC 内置 Agent 原型${C.reset}`);
|
|
95
|
+
console.log(`${C.dim}模型: ${config.model ?? "deepseek-chat"}${C.reset}`);
|
|
96
|
+
if (options.cwd) {
|
|
97
|
+
console.log(`${C.dim}目录: ${options.cwd}${C.reset}`);
|
|
98
|
+
}
|
|
99
|
+
console.log(`${C.dim}输入消息开始对话,Ctrl+C 中断当前回复,/exit 退出${C.reset}`);
|
|
100
|
+
console.log("");
|
|
101
|
+
|
|
102
|
+
let session: ChatSession;
|
|
103
|
+
try {
|
|
104
|
+
session = new ChatSession(config, options);
|
|
105
|
+
} catch (err) {
|
|
106
|
+
console.error(`${C.yellow}${(err as Error).message}${C.reset}`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const rl = readline.createInterface({
|
|
111
|
+
input: process.stdin,
|
|
112
|
+
output: process.stdout,
|
|
113
|
+
prompt: `${C.green}>${C.reset} `,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// 用于中断当前 LLM 调用的 AbortController
|
|
117
|
+
let currentAbort: AbortController | null = null;
|
|
118
|
+
|
|
119
|
+
rl.prompt();
|
|
120
|
+
|
|
121
|
+
rl.on("line", async (line: string) => {
|
|
122
|
+
const input = line.trim();
|
|
123
|
+
if (!input) {
|
|
124
|
+
rl.prompt();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 特殊命令
|
|
129
|
+
if (input === "/exit" || input === "/quit") {
|
|
130
|
+
console.log(`${C.dim}再见${C.reset}`);
|
|
131
|
+
rl.close();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (input === "/clear") {
|
|
136
|
+
session.reset();
|
|
137
|
+
console.log(`${C.dim}会话已重置${C.reset}`);
|
|
138
|
+
rl.prompt();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (input === "/history") {
|
|
143
|
+
console.log(`${C.dim}共 ${session.turnCount} 轮对话${C.reset}`);
|
|
144
|
+
rl.prompt();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 发送消息
|
|
149
|
+
currentAbort = new AbortController();
|
|
150
|
+
const signal = currentAbort.signal;
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
let lastAccumulated = "";
|
|
154
|
+
for await (const event of session.chat(input, signal)) {
|
|
155
|
+
if (event.type === "text") {
|
|
156
|
+
// 增量输出(仅在首次和行首时不换行)
|
|
157
|
+
const newText = event.accumulated.slice(lastAccumulated.length);
|
|
158
|
+
process.stdout.write(newText);
|
|
159
|
+
lastAccumulated = event.accumulated;
|
|
160
|
+
} else if (event.type === "done") {
|
|
161
|
+
if (lastAccumulated) console.log("");
|
|
162
|
+
console.log(`${C.dim}[完成]${C.reset}`);
|
|
163
|
+
} else if (event.type === "error") {
|
|
164
|
+
console.log(`\n${C.yellow}[错误] ${event.message}${C.reset}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch (err) {
|
|
168
|
+
console.log(`\n${C.yellow}[错误] ${(err as Error).message}${C.reset}`);
|
|
169
|
+
} finally {
|
|
170
|
+
currentAbort = null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
rl.prompt();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Ctrl+C → 中断当前 LLM 调用(不退出程序)
|
|
177
|
+
rl.on("SIGINT", () => {
|
|
178
|
+
if (currentAbort) {
|
|
179
|
+
console.log(`\n${C.yellow}[中断中...]${C.reset}`);
|
|
180
|
+
currentAbort.abort();
|
|
181
|
+
currentAbort = null;
|
|
182
|
+
} else {
|
|
183
|
+
console.log(`\n${C.dim}输入 /exit 退出${C.reset}`);
|
|
184
|
+
rl.prompt();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
rl.on("close", () => {
|
|
189
|
+
console.log("");
|
|
190
|
+
process.exit(0);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
main().catch((err) => {
|
|
195
|
+
console.error(`${C.yellow}启动失败: ${(err as Error).message}${C.reset}`);
|
|
196
|
+
process.exit(1);
|
|
197
197
|
});
|