thatgfsj-code 0.2.1 → 0.2.2
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/CHANGELOG.md +131 -0
- package/DEVELOPMENT.md +286 -0
- package/README.md +131 -30
- package/dist/core/ai-engine.d.ts +17 -0
- package/dist/core/ai-engine.d.ts.map +1 -1
- package/dist/core/ai-engine.js +23 -7
- package/dist/core/ai-engine.js.map +1 -1
- package/dist/index.js +18 -27
- package/dist/index.js.map +1 -1
- package/dist/repl/input.d.ts +8 -0
- package/dist/repl/input.d.ts.map +1 -1
- package/dist/repl/input.js +12 -0
- package/dist/repl/input.js.map +1 -1
- package/dist/repl/loop.d.ts +56 -0
- package/dist/repl/loop.d.ts.map +1 -1
- package/dist/repl/loop.js +333 -4
- package/dist/repl/loop.js.map +1 -1
- package/dist/repl/output.d.ts.map +1 -1
- package/dist/repl/output.js +3 -1
- package/dist/repl/output.js.map +1 -1
- package/dist/repl/welcome.js +1 -1
- package/dist/repl/welcome.js.map +1 -1
- package/docs/API_KEY_GUIDE.md +6 -0
- package/docs/FAQ.md +25 -3
- package/package.json +35 -3
- package/.patches/0001-fix-repl-replace-readline-with-inquirer-input-for-ke.patch +0 -279
- package/.patches/0002-fix-repl-stream-AI-output-directly-to-stdout-so-term.patch +0 -564
- package/.patches/0003-fix-session-break-the-hallucination-loop-in-assistan.patch +0 -194
- package/.patches/0004-chore-release-bump-version-to-0.2.1.patch +0 -24
- package/ROADMAP.md +0 -107
- package/src/agent/core.ts +0 -179
- package/src/agent/index.ts +0 -8
- package/src/agent/intent.ts +0 -181
- package/src/agent/streaming.ts +0 -132
- package/src/core/ai-engine.ts +0 -437
- package/src/core/cli.ts +0 -171
- package/src/core/config.ts +0 -147
- package/src/core/context-compactor.ts +0 -245
- package/src/core/hooks.ts +0 -196
- package/src/core/permissions.ts +0 -308
- package/src/core/session.ts +0 -165
- package/src/core/skills.ts +0 -208
- package/src/core/state.ts +0 -120
- package/src/core/subagent.ts +0 -195
- package/src/core/system-prompt.ts +0 -163
- package/src/core/tool-registry.ts +0 -157
- package/src/core/types.ts +0 -280
- package/src/index.ts +0 -544
- package/src/mcp/client.ts +0 -330
- package/src/repl/index.ts +0 -8
- package/src/repl/input.ts +0 -139
- package/src/repl/loop.ts +0 -280
- package/src/repl/output.ts +0 -222
- package/src/repl/welcome.ts +0 -296
- package/src/tools/file.ts +0 -117
- package/src/tools/git.ts +0 -132
- package/src/tools/index.ts +0 -48
- package/src/tools/search.ts +0 -263
- package/src/tools/shell.ts +0 -181
- package/src/utils/diff-preview.ts +0 -202
- package/src/utils/index.ts +0 -8
- package/src/utils/memory.ts +0 -223
- package/src/utils/project-context.ts +0 -207
- package/tsconfig.json +0 -19
package/src/repl/loop.ts
DELETED
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* REPL Loop
|
|
3
|
-
* Main interactive loop with streaming support
|
|
4
|
-
*
|
|
5
|
-
* S07-fix:
|
|
6
|
-
* - 输入端换用 REPLInput (基于 @inquirer/input),支持方向键/小键盘
|
|
7
|
-
* - 流式输出保留完整内容(用户可滚动终端查看历史),不跳顶不刷屏
|
|
8
|
-
* - Ctrl+C 行为:有未提交内容=>清空当前输入;空输入两次=>退出
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import chalk from 'chalk';
|
|
12
|
-
import { REPLInput, type PromptResult } from './input.js';
|
|
13
|
-
import { REPLOutput } from './output.js';
|
|
14
|
-
import { AIEngine } from '../core/ai-engine.js';
|
|
15
|
-
import { SessionManager } from '../core/session.js';
|
|
16
|
-
import { ConfigManager } from '../core/config.js';
|
|
17
|
-
import { SystemPromptBuilder } from '../core/system-prompt.js';
|
|
18
|
-
import { getBuiltInTools } from '../tools/index.js';
|
|
19
|
-
|
|
20
|
-
export class REPLLoop {
|
|
21
|
-
private input: REPLInput;
|
|
22
|
-
private output: REPLOutput;
|
|
23
|
-
private ai: AIEngine | null = null;
|
|
24
|
-
private session: SessionManager | null = null;
|
|
25
|
-
private running: boolean = false;
|
|
26
|
-
// Used to abort an in-flight AI stream when the user presses Ctrl+C twice
|
|
27
|
-
private streamAbort: AbortController | null = null;
|
|
28
|
-
|
|
29
|
-
constructor() {
|
|
30
|
-
this.input = new REPLInput();
|
|
31
|
-
this.output = new REPLOutput();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Initialize the REPL
|
|
36
|
-
* S04: Use SystemPromptBuilder for dynamic prompt construction
|
|
37
|
-
*/
|
|
38
|
-
async init(): Promise<void> {
|
|
39
|
-
const config = await ConfigManager.load();
|
|
40
|
-
|
|
41
|
-
this.ai = new AIEngine(config);
|
|
42
|
-
|
|
43
|
-
const builtInTools = getBuiltInTools();
|
|
44
|
-
for (const tool of builtInTools) {
|
|
45
|
-
this.ai!.registerTool(tool);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
this.session = new SessionManager();
|
|
49
|
-
|
|
50
|
-
const promptBuilder = new SystemPromptBuilder({
|
|
51
|
-
cwd: process.cwd(),
|
|
52
|
-
tools: builtInTools,
|
|
53
|
-
permissionMode: 'ask'
|
|
54
|
-
});
|
|
55
|
-
const systemPrompt = promptBuilder.build();
|
|
56
|
-
|
|
57
|
-
this.session.addMessage('system', systemPrompt);
|
|
58
|
-
|
|
59
|
-
this.running = true;
|
|
60
|
-
|
|
61
|
-
// 全局 SIGINT 处理:第一次按下 abort 当前 AI stream,第二次退出 REPL
|
|
62
|
-
process.on('SIGINT', () => {
|
|
63
|
-
if (this.streamAbort) {
|
|
64
|
-
this.streamAbort.abort();
|
|
65
|
-
this.streamAbort = null;
|
|
66
|
-
this.output.stopSpinner();
|
|
67
|
-
this.output.printWarning('\n⏹ Generation cancelled (Ctrl+C again to exit)');
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
// 没有在生成:交给 REPLInput 处理(它会检测是否要退出)
|
|
71
|
-
this.output.printWarning('\n(press Ctrl+C again on an empty prompt to exit)');
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Start the REPL loop
|
|
77
|
-
*/
|
|
78
|
-
async start(): Promise<void> {
|
|
79
|
-
await this.init();
|
|
80
|
-
|
|
81
|
-
this.output.clear();
|
|
82
|
-
this.output.printBanner();
|
|
83
|
-
this.output.printInfo('\nType "help" for available commands\n');
|
|
84
|
-
this.output.printDivider();
|
|
85
|
-
|
|
86
|
-
while (this.running) {
|
|
87
|
-
let result: PromptResult;
|
|
88
|
-
try {
|
|
89
|
-
result = await this.input.prompt();
|
|
90
|
-
} catch (err: any) {
|
|
91
|
-
this.output.printError(err?.message ?? String(err));
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (result.kind === 'cancelled') {
|
|
96
|
-
if (this.input.shouldExitOnCancel()) {
|
|
97
|
-
this.output.printInfo('\n👋 Goodbye!');
|
|
98
|
-
this.running = false;
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
101
|
-
// 继续让用户输入
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// input layer 自动重置 cancel 计数,无需手动调
|
|
106
|
-
|
|
107
|
-
const userInput = result.value;
|
|
108
|
-
if (!userInput) continue;
|
|
109
|
-
|
|
110
|
-
const handled = await this.handleCommand(userInput);
|
|
111
|
-
if (handled) continue;
|
|
112
|
-
|
|
113
|
-
await this.processInput(userInput);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// 清理全局监听
|
|
117
|
-
process.removeAllListeners('SIGINT');
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Handle built-in commands
|
|
122
|
-
*/
|
|
123
|
-
private async handleCommand(input: string): Promise<boolean> {
|
|
124
|
-
const cmd = input.toLowerCase().trim();
|
|
125
|
-
|
|
126
|
-
switch (cmd) {
|
|
127
|
-
case 'exit':
|
|
128
|
-
case 'quit':
|
|
129
|
-
case '\\x03':
|
|
130
|
-
this.output.printInfo('\n👋 Goodbye!');
|
|
131
|
-
this.running = false;
|
|
132
|
-
return true;
|
|
133
|
-
|
|
134
|
-
case 'clear':
|
|
135
|
-
this.output.clear();
|
|
136
|
-
this.output.printBanner();
|
|
137
|
-
return true;
|
|
138
|
-
|
|
139
|
-
case 'context':
|
|
140
|
-
this.showContext();
|
|
141
|
-
return true;
|
|
142
|
-
|
|
143
|
-
case 'history':
|
|
144
|
-
this.showHistory();
|
|
145
|
-
return true;
|
|
146
|
-
|
|
147
|
-
case 'tools':
|
|
148
|
-
this.showTools();
|
|
149
|
-
return true;
|
|
150
|
-
|
|
151
|
-
case 'help':
|
|
152
|
-
this.output.printHelp();
|
|
153
|
-
return true;
|
|
154
|
-
|
|
155
|
-
case 'models':
|
|
156
|
-
case 'providers':
|
|
157
|
-
this.showProviders();
|
|
158
|
-
return true;
|
|
159
|
-
|
|
160
|
-
default:
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Process user input with AI (S01: streaming, no prompt reset)
|
|
167
|
-
*
|
|
168
|
-
* 关键修复:
|
|
169
|
-
* - 不再调用 rl.question,所以不会 reset 终端
|
|
170
|
-
* - chunk 直接 process.stdout.write,完整保留所有输出,用户可滚动查看
|
|
171
|
-
* - spinner 在第一个 chunk 到达时停止,然后正常流式
|
|
172
|
-
*/
|
|
173
|
-
private async processInput(input: string): Promise<void> {
|
|
174
|
-
if (!this.ai || !this.session) {
|
|
175
|
-
this.output.printError('AI not initialized');
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
this.session.addMessage('user', input);
|
|
180
|
-
|
|
181
|
-
// 视觉提示用户:AI 开始工作,但不阻塞,可滚动
|
|
182
|
-
this.output.printInfo(chalk.gray('🤖 Thinking...\n'));
|
|
183
|
-
|
|
184
|
-
let fullResponse = '';
|
|
185
|
-
let firstChunk = true;
|
|
186
|
-
this.streamAbort = new AbortController();
|
|
187
|
-
|
|
188
|
-
try {
|
|
189
|
-
const stream = (this.ai as any).chatStream(this.session.getMessages());
|
|
190
|
-
for await (const chunk of stream) {
|
|
191
|
-
if (firstChunk) {
|
|
192
|
-
// 第一个 chunk 到来,把 "Thinking..." 那行通过 ANSI 清除
|
|
193
|
-
// 但不能清光——只把光标移到下一行的开头即可,内容自然出现在前面
|
|
194
|
-
firstChunk = false;
|
|
195
|
-
}
|
|
196
|
-
// 关键:直接 stdout.write,允许任意长度、可滚动
|
|
197
|
-
process.stdout.write(chunk);
|
|
198
|
-
fullResponse += chunk;
|
|
199
|
-
|
|
200
|
-
if (this.streamAbort.signal.aborted) break;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
console.log(); // 流结束换行
|
|
204
|
-
} catch (error: any) {
|
|
205
|
-
if (error?.name === 'AbortError' || this.streamAbort.signal.aborted) {
|
|
206
|
-
console.log();
|
|
207
|
-
this.output.printWarning('[cancelled]');
|
|
208
|
-
} else {
|
|
209
|
-
this.output.printError(error.message);
|
|
210
|
-
}
|
|
211
|
-
} finally {
|
|
212
|
-
this.streamAbort = null;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const accepted = this.session.addMessage('assistant', fullResponse);
|
|
216
|
-
if (!accepted) {
|
|
217
|
-
this.output.printWarning(
|
|
218
|
-
chalk.yellow(
|
|
219
|
-
`⚠️ 上轮回复包含 "[已中断]" 等污染标记,已自动丢弃以避免循环。本次回复不会基于它继续;请重说你的问题。\n` +
|
|
220
|
-
`(本次会话已累计过滤 ${this.session.getDroppedCount()} 条污染消息)`
|
|
221
|
-
)
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
this.session.truncate(20);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
private showContext(): void {
|
|
228
|
-
const cwd = process.cwd();
|
|
229
|
-
this.output.printHeader('📁 Project Context');
|
|
230
|
-
this.output.printInfo(`Working directory: ${cwd}`);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
private showHistory(): void {
|
|
234
|
-
const items = this.input.getHistory();
|
|
235
|
-
this.output.printHeader('📜 Command History');
|
|
236
|
-
if (items.length === 0) {
|
|
237
|
-
this.output.printInfo('(no history yet)');
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
items.forEach((h, i) => this.output.printInfo(` ${i + 1}. ${h}`));
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
private showTools(): void {
|
|
244
|
-
this.output.printHeader('🔧 Available Tools');
|
|
245
|
-
this.output.printInfo(' file - File operations (read, write, list, delete)');
|
|
246
|
-
this.output.printInfo(' shell - Execute shell commands');
|
|
247
|
-
this.output.printInfo(' git - Git operations (coming soon)');
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
private showProviders(): void {
|
|
251
|
-
this.output.printHeader('🌐 Available Providers');
|
|
252
|
-
this.output.printInfo(' siliconflow - 硅基流动 (default)');
|
|
253
|
-
this.output.printInfo(' minimax - MiniMax M2.5');
|
|
254
|
-
this.output.printInfo(' openai - OpenAI GPT');
|
|
255
|
-
this.output.printInfo(' anthropic - Anthropic Claude');
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Stop the REPL
|
|
260
|
-
*/
|
|
261
|
-
stop(): void {
|
|
262
|
-
this.running = false;
|
|
263
|
-
if (this.streamAbort) {
|
|
264
|
-
this.streamAbort.abort();
|
|
265
|
-
this.streamAbort = null;
|
|
266
|
-
}
|
|
267
|
-
this.output.stopStreaming();
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Handle interrupt (Ctrl+C) while streaming
|
|
272
|
-
*/
|
|
273
|
-
interrupt(): void {
|
|
274
|
-
if (this.streamAbort) {
|
|
275
|
-
this.streamAbort.abort();
|
|
276
|
-
this.streamAbort = null;
|
|
277
|
-
}
|
|
278
|
-
this.output.stopStreaming();
|
|
279
|
-
}
|
|
280
|
-
}
|
package/src/repl/output.ts
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* REPL Output Handler
|
|
3
|
-
* Handles streaming output, colors, and formatting
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import ora, { Ora } from 'ora';
|
|
8
|
-
|
|
9
|
-
export class REPLOutput {
|
|
10
|
-
private spinner: Ora | null = null;
|
|
11
|
-
private isStreaming: boolean = false;
|
|
12
|
-
|
|
13
|
-
// Color schemes
|
|
14
|
-
readonly colors = {
|
|
15
|
-
user: chalk.cyan,
|
|
16
|
-
assistant: chalk.green,
|
|
17
|
-
system: chalk.yellow,
|
|
18
|
-
error: chalk.red,
|
|
19
|
-
warning: chalk.yellow,
|
|
20
|
-
info: chalk.gray,
|
|
21
|
-
code: chalk.bgBlack,
|
|
22
|
-
success: chalk.green,
|
|
23
|
-
tool: chalk.magenta,
|
|
24
|
-
diff: {
|
|
25
|
-
add: chalk.green,
|
|
26
|
-
remove: chalk.red,
|
|
27
|
-
header: chalk.blue
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Print user input
|
|
33
|
-
*/
|
|
34
|
-
printUser(input: string): void {
|
|
35
|
-
console.log(this.colors.user('\n👤 ') + input);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Print assistant response
|
|
40
|
-
*/
|
|
41
|
-
printAssistant(content: string): void {
|
|
42
|
-
console.log(this.colors.assistant('\n🤖 ') + content);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Print tool execution
|
|
47
|
-
*/
|
|
48
|
-
printTool(name: string, result: string): void {
|
|
49
|
-
console.log(this.colors.tool(`\n🔧 Tool: ${name}`));
|
|
50
|
-
console.log(this.colors.info(result));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Print error
|
|
55
|
-
*/
|
|
56
|
-
printError(error: string): void {
|
|
57
|
-
console.error(this.colors.error(`\n❌ Error: ${error}`));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Print warning
|
|
62
|
-
*/
|
|
63
|
-
printWarning(warning: string): void {
|
|
64
|
-
console.warn(this.colors.warning(`\n⚠️ ${warning}`));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Print success
|
|
69
|
-
*/
|
|
70
|
-
printSuccess(message: string): void {
|
|
71
|
-
console.log(this.colors.success(`\n✅ ${message}`));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Print info
|
|
76
|
-
*/
|
|
77
|
-
printInfo(message: string): void {
|
|
78
|
-
console.log(this.colors.info(message));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Print code block
|
|
83
|
-
*/
|
|
84
|
-
printCode(code: string, language: string = ''): void {
|
|
85
|
-
console.log(chalk.bgBlack.gray('```' + language));
|
|
86
|
-
console.log(chalk.bgBlack(code));
|
|
87
|
-
console.log(chalk.bgBlack.gray('```'));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Start spinner
|
|
92
|
-
*/
|
|
93
|
-
startSpinner(text: string): void {
|
|
94
|
-
this.spinner = ora({
|
|
95
|
-
text,
|
|
96
|
-
color: 'cyan',
|
|
97
|
-
spinner: 'dots'
|
|
98
|
-
}).start();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Update spinner text
|
|
103
|
-
*/
|
|
104
|
-
updateSpinner(text: string): void {
|
|
105
|
-
if (this.spinner) {
|
|
106
|
-
this.spinner.text = text;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Stop spinner with success
|
|
112
|
-
*/
|
|
113
|
-
stopSpinnerSuccess(text?: string): void {
|
|
114
|
-
if (this.spinner) {
|
|
115
|
-
this.spinner.succeed(text || this.spinner.text);
|
|
116
|
-
this.spinner = null;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Stop spinner with error
|
|
122
|
-
*/
|
|
123
|
-
stopSpinnerError(text?: string): void {
|
|
124
|
-
if (this.spinner) {
|
|
125
|
-
this.spinner.fail(text || this.spinner.text);
|
|
126
|
-
this.spinner = null;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Stop spinner
|
|
132
|
-
*/
|
|
133
|
-
stopSpinner(): void {
|
|
134
|
-
if (this.spinner) {
|
|
135
|
-
this.spinner.stop();
|
|
136
|
-
this.spinner = null;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Print divider
|
|
142
|
-
*/
|
|
143
|
-
printDivider(char: string = '─', length: number = 40): void {
|
|
144
|
-
console.log(chalk.gray(char.repeat(length)));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Print header
|
|
149
|
-
*/
|
|
150
|
-
printHeader(text: string): void {
|
|
151
|
-
this.printDivider();
|
|
152
|
-
console.log(chalk.cyan(text));
|
|
153
|
-
this.printDivider();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Print with typewriter effect (streaming)
|
|
158
|
-
*/
|
|
159
|
-
async printTypewriter(text: string, delay: number = 20): Promise<void> {
|
|
160
|
-
this.isStreaming = true;
|
|
161
|
-
|
|
162
|
-
process.stdout.write(chalk.green('\n🤖 '));
|
|
163
|
-
|
|
164
|
-
for (let i = 0; i < text.length; i++) {
|
|
165
|
-
if (!this.isStreaming) {
|
|
166
|
-
// User interrupted, print rest immediately
|
|
167
|
-
process.stdout.write(text.slice(i));
|
|
168
|
-
break;
|
|
169
|
-
}
|
|
170
|
-
process.stdout.write(text[i]);
|
|
171
|
-
await new Promise(r => setTimeout(r, delay));
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
process.stdout.write('\n');
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Stop streaming (for Ctrl+C)
|
|
179
|
-
*/
|
|
180
|
-
stopStreaming(): void {
|
|
181
|
-
this.isStreaming = false;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Clear screen
|
|
186
|
-
*/
|
|
187
|
-
clear(): void {
|
|
188
|
-
console.clear();
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Print banner
|
|
193
|
-
*/
|
|
194
|
-
printBanner(): void {
|
|
195
|
-
console.log(chalk.cyan(`
|
|
196
|
-
╔═══════════════════════════════════════╗
|
|
197
|
-
║ 🤖 Thatgfsj Code v0.2.0 ║
|
|
198
|
-
║ Claude Code Style REPL ║
|
|
199
|
-
╚═══════════════════════════════════════╝
|
|
200
|
-
`));
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Print help
|
|
205
|
-
*/
|
|
206
|
-
printHelp(): void {
|
|
207
|
-
console.log(`
|
|
208
|
-
${chalk.cyan('Commands:')}
|
|
209
|
-
${chalk.gray('exit, Ctrl+C')} - Exit the REPL
|
|
210
|
-
${chalk.gray('clear')} - Clear screen
|
|
211
|
-
${chalk.gray('context')} - Show project context
|
|
212
|
-
${chalk.gray('history')} - Show command history
|
|
213
|
-
${chalk.gray('tools')} - List available tools
|
|
214
|
-
${chalk.gray('help')} - Show this help
|
|
215
|
-
|
|
216
|
-
${chalk.cyan('Tips:')}
|
|
217
|
-
• Use ${chalk.gray('\\')} at end for multiline input
|
|
218
|
-
• Use ${chalk.gray('↑/↓')} for command history
|
|
219
|
-
• Use ${chalk.gray('Tab')} for auto-complete
|
|
220
|
-
`);
|
|
221
|
-
}
|
|
222
|
-
}
|