@alia-codea/cli 1.0.0 → 2.0.0
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/dist/index.js +1362 -491
- package/package.json +5 -5
- package/src/app.tsx +281 -0
- package/src/commands/auth.ts +149 -20
- package/src/commands/repl.ts +11 -299
- package/src/commands/run.ts +103 -126
- package/src/commands/sessions.ts +5 -6
- package/src/components/ApprovalPrompt.tsx +60 -0
- package/src/components/Header.tsx +39 -0
- package/src/components/InputBar.tsx +36 -0
- package/src/components/MessageList.tsx +81 -0
- package/src/components/ThinkingIndicator.tsx +28 -0
- package/src/components/ToolCallCard.tsx +68 -0
- package/src/index.ts +31 -11
- package/src/tools/executor.ts +140 -14
- package/src/tools/patch.ts +167 -0
- package/src/utils/api.ts +22 -3
- package/src/utils/approval.ts +31 -0
- package/src/utils/context.ts +65 -4
- package/src/utils/conversation.ts +141 -0
- package/dist/api-X2G5QROW.js +0 -10
- package/dist/chunk-SVPL4GNV.js +0 -230
- package/dist/index.d.ts +0 -1
- package/src/utils/ui.ts +0 -153
package/src/commands/repl.ts
CHANGED
|
@@ -1,309 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { executeTool, formatToolCall } from '../tools/executor.js';
|
|
6
|
-
import {
|
|
7
|
-
printBanner,
|
|
8
|
-
printTips,
|
|
9
|
-
printPrompt,
|
|
10
|
-
printToolExecution,
|
|
11
|
-
printToolResult,
|
|
12
|
-
showThinkingStatus,
|
|
13
|
-
hideThinkingStatus,
|
|
14
|
-
printStatusBar,
|
|
15
|
-
printAssistantPrefix,
|
|
16
|
-
printError,
|
|
17
|
-
printInfo
|
|
18
|
-
} from '../utils/ui.js';
|
|
19
|
-
import { buildSystemMessage, getCodebaseContext } from '../utils/context.js';
|
|
20
|
-
|
|
21
|
-
interface Message {
|
|
22
|
-
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
23
|
-
content: string;
|
|
24
|
-
tool_calls?: any[];
|
|
25
|
-
tool_call_id?: string;
|
|
26
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from 'ink';
|
|
3
|
+
import { App, AppOptions } from '../app.js';
|
|
4
|
+
import { ApprovalMode } from '../utils/approval.js';
|
|
27
5
|
|
|
28
6
|
interface ReplOptions {
|
|
29
7
|
model: string;
|
|
30
8
|
context: boolean;
|
|
9
|
+
approvalMode?: string;
|
|
31
10
|
}
|
|
32
11
|
|
|
33
12
|
export async function startRepl(options: ReplOptions): Promise<void> {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const maxContext = 128000;
|
|
39
|
-
|
|
40
|
-
// Print welcome UI
|
|
41
|
-
printTips();
|
|
42
|
-
|
|
43
|
-
// Get initial codebase context
|
|
44
|
-
let codebaseContext = '';
|
|
45
|
-
if (options.context !== false) {
|
|
46
|
-
printInfo('Analyzing codebase...');
|
|
47
|
-
codebaseContext = await getCodebaseContext();
|
|
48
|
-
if (codebaseContext) {
|
|
49
|
-
printInfo(`Loaded context from ${codebaseContext.split('\n').length} files`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Setup readline
|
|
54
|
-
const rl = readline.createInterface({
|
|
55
|
-
input: process.stdin,
|
|
56
|
-
output: process.stdout,
|
|
57
|
-
terminal: true
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Handle Ctrl+C
|
|
61
|
-
rl.on('SIGINT', () => {
|
|
62
|
-
if (isProcessing) {
|
|
63
|
-
isProcessing = false;
|
|
64
|
-
hideThinkingStatus();
|
|
65
|
-
console.log(chalk.yellow('\nCancelled.'));
|
|
66
|
-
printPrompt();
|
|
67
|
-
} else {
|
|
68
|
-
console.log(chalk.gray('\nGoodbye!'));
|
|
69
|
-
process.exit(0);
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const askQuestion = (): void => {
|
|
74
|
-
printPrompt();
|
|
75
|
-
rl.question('', async (input) => {
|
|
76
|
-
const trimmed = input.trim();
|
|
77
|
-
|
|
78
|
-
if (!trimmed) {
|
|
79
|
-
askQuestion();
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Handle slash commands
|
|
84
|
-
if (trimmed.startsWith('/')) {
|
|
85
|
-
await handleSlashCommand(trimmed, messages, session, options);
|
|
86
|
-
askQuestion();
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Add user message
|
|
91
|
-
messages.push({ role: 'user', content: trimmed });
|
|
92
|
-
isProcessing = true;
|
|
93
|
-
|
|
94
|
-
// Build system message
|
|
95
|
-
const systemMessage = buildSystemMessage(options.model, codebaseContext);
|
|
96
|
-
|
|
97
|
-
// Process conversation with tool loop
|
|
98
|
-
await processConversation(messages, systemMessage, options.model, () => isProcessing);
|
|
99
|
-
|
|
100
|
-
isProcessing = false;
|
|
101
|
-
|
|
102
|
-
// Update session
|
|
103
|
-
session.messages = messages.map(m => ({ role: m.role, content: m.content }));
|
|
104
|
-
session.title = messages[0]?.content.slice(0, 50) || 'New conversation';
|
|
105
|
-
session.updatedAt = Date.now();
|
|
106
|
-
saveSession(session);
|
|
107
|
-
|
|
108
|
-
// Update context usage estimate
|
|
109
|
-
contextUsed = Math.min(95, Math.floor(messages.reduce((acc, m) => acc + m.content.length, 0) / maxContext * 100));
|
|
110
|
-
|
|
111
|
-
// Print status bar
|
|
112
|
-
printStatusBar(process.cwd(), getModelDisplayName(options.model), 100 - contextUsed);
|
|
113
|
-
|
|
114
|
-
askQuestion();
|
|
115
|
-
});
|
|
13
|
+
const appOptions: AppOptions = {
|
|
14
|
+
model: options.model,
|
|
15
|
+
approvalMode: (options.approvalMode as ApprovalMode) || 'suggest',
|
|
16
|
+
context: options.context,
|
|
116
17
|
};
|
|
117
18
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
async function processConversation(
|
|
122
|
-
messages: Message[],
|
|
123
|
-
systemMessage: string,
|
|
124
|
-
model: string,
|
|
125
|
-
isActive: () => boolean
|
|
126
|
-
): Promise<void> {
|
|
127
|
-
while (isActive()) {
|
|
128
|
-
console.log();
|
|
129
|
-
printAssistantPrefix();
|
|
130
|
-
|
|
131
|
-
let fullContent = '';
|
|
132
|
-
let toolCalls: any[] | undefined;
|
|
133
|
-
|
|
134
|
-
showThinkingStatus('Thinking');
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
await streamChat(messages, systemMessage, model, {
|
|
138
|
-
onContent: (content) => {
|
|
139
|
-
if (!isActive()) return;
|
|
140
|
-
hideThinkingStatus();
|
|
141
|
-
process.stdout.write(content);
|
|
142
|
-
fullContent += content;
|
|
143
|
-
},
|
|
144
|
-
onToolCall: (tc) => {
|
|
145
|
-
// Tool calls are accumulated
|
|
146
|
-
},
|
|
147
|
-
onDone: (content, tcs) => {
|
|
148
|
-
hideThinkingStatus();
|
|
149
|
-
toolCalls = tcs;
|
|
150
|
-
},
|
|
151
|
-
onError: (error) => {
|
|
152
|
-
hideThinkingStatus();
|
|
153
|
-
printError(error.message);
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
} catch (error: any) {
|
|
157
|
-
hideThinkingStatus();
|
|
158
|
-
printError(error.message);
|
|
159
|
-
break;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (!isActive()) break;
|
|
163
|
-
|
|
164
|
-
// Handle tool calls
|
|
165
|
-
if (toolCalls && toolCalls.length > 0) {
|
|
166
|
-
// Add assistant message with tool calls
|
|
167
|
-
messages.push({
|
|
168
|
-
role: 'assistant',
|
|
169
|
-
content: fullContent,
|
|
170
|
-
tool_calls: toolCalls
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
if (fullContent) {
|
|
174
|
-
console.log(); // New line after content
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Execute each tool
|
|
178
|
-
for (const tc of toolCalls) {
|
|
179
|
-
if (!isActive()) break;
|
|
180
|
-
|
|
181
|
-
const args = JSON.parse(tc.function.arguments);
|
|
182
|
-
printToolExecution(tc.function.name, formatToolArgs(tc.function.name, args));
|
|
183
|
-
|
|
184
|
-
showThinkingStatus(`Executing ${tc.function.name}`);
|
|
185
|
-
const result = await executeTool(tc.function.name, args);
|
|
186
|
-
hideThinkingStatus();
|
|
187
|
-
|
|
188
|
-
printToolResult(result.success, result.result);
|
|
189
|
-
|
|
190
|
-
// Add tool result
|
|
191
|
-
messages.push({
|
|
192
|
-
role: 'tool',
|
|
193
|
-
tool_call_id: tc.id,
|
|
194
|
-
content: result.result
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Continue loop for next response
|
|
199
|
-
continue;
|
|
200
|
-
} else {
|
|
201
|
-
// No tool calls, conversation turn complete
|
|
202
|
-
if (fullContent) {
|
|
203
|
-
messages.push({ role: 'assistant', content: fullContent });
|
|
204
|
-
console.log(); // New line after response
|
|
205
|
-
}
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
async function handleSlashCommand(
|
|
212
|
-
command: string,
|
|
213
|
-
messages: Message[],
|
|
214
|
-
session: any,
|
|
215
|
-
options: ReplOptions
|
|
216
|
-
): Promise<void> {
|
|
217
|
-
const [cmd, ...args] = command.slice(1).split(' ');
|
|
218
|
-
|
|
219
|
-
switch (cmd.toLowerCase()) {
|
|
220
|
-
case 'help':
|
|
221
|
-
console.log();
|
|
222
|
-
console.log(chalk.bold('Available commands:'));
|
|
223
|
-
console.log(chalk.cyan(' /help') + chalk.gray(' - Show this help'));
|
|
224
|
-
console.log(chalk.cyan(' /clear') + chalk.gray(' - Clear conversation'));
|
|
225
|
-
console.log(chalk.cyan(' /model') + chalk.gray(' - Switch model'));
|
|
226
|
-
console.log(chalk.cyan(' /context') + chalk.gray(' - Show current context'));
|
|
227
|
-
console.log(chalk.cyan(' /save') + chalk.gray(' - Save conversation'));
|
|
228
|
-
console.log(chalk.cyan(' /exit') + chalk.gray(' - Exit Codea'));
|
|
229
|
-
console.log();
|
|
230
|
-
break;
|
|
231
|
-
|
|
232
|
-
case 'clear':
|
|
233
|
-
messages.length = 0;
|
|
234
|
-
console.log(chalk.green('Conversation cleared.'));
|
|
235
|
-
break;
|
|
236
|
-
|
|
237
|
-
case 'model':
|
|
238
|
-
const modelArg = args[0];
|
|
239
|
-
if (modelArg) {
|
|
240
|
-
options.model = modelArg.startsWith('alia-') ? modelArg : `alia-v1-${modelArg}`;
|
|
241
|
-
console.log(chalk.green(`Model switched to ${options.model}`));
|
|
242
|
-
} else {
|
|
243
|
-
console.log(chalk.gray('Current model: ') + chalk.cyan(options.model));
|
|
244
|
-
try {
|
|
245
|
-
const { fetchModels } = await import('../utils/api.js');
|
|
246
|
-
const apiModels = await fetchModels();
|
|
247
|
-
if (apiModels.length > 0) {
|
|
248
|
-
console.log(chalk.gray('Available models:'));
|
|
249
|
-
for (const m of apiModels) {
|
|
250
|
-
console.log(chalk.gray(' ') + chalk.cyan(m.id) + chalk.gray(` - ${m.name}`));
|
|
251
|
-
}
|
|
252
|
-
} else {
|
|
253
|
-
console.log(chalk.gray('Available: codea, codea-pro, codea-thinking'));
|
|
254
|
-
}
|
|
255
|
-
} catch {
|
|
256
|
-
console.log(chalk.gray('Available: codea, codea-pro, codea-thinking'));
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
break;
|
|
260
|
-
|
|
261
|
-
case 'context':
|
|
262
|
-
console.log(chalk.gray(`Messages in context: ${messages.length}`));
|
|
263
|
-
console.log(chalk.gray(`Working directory: ${process.cwd()}`));
|
|
264
|
-
break;
|
|
265
|
-
|
|
266
|
-
case 'save':
|
|
267
|
-
session.messages = messages.map(m => ({ role: m.role, content: m.content }));
|
|
268
|
-
session.updatedAt = Date.now();
|
|
269
|
-
saveSession(session);
|
|
270
|
-
console.log(chalk.green('Conversation saved.'));
|
|
271
|
-
break;
|
|
272
|
-
|
|
273
|
-
case 'exit':
|
|
274
|
-
case 'quit':
|
|
275
|
-
console.log(chalk.gray('Goodbye!'));
|
|
276
|
-
process.exit(0);
|
|
277
|
-
break;
|
|
278
|
-
|
|
279
|
-
default:
|
|
280
|
-
console.log(chalk.yellow(`Unknown command: /${cmd}`));
|
|
281
|
-
console.log(chalk.gray('Type /help for available commands.'));
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function formatToolArgs(name: string, args: Record<string, any>): string {
|
|
286
|
-
switch (name) {
|
|
287
|
-
case 'read_file':
|
|
288
|
-
case 'write_file':
|
|
289
|
-
case 'edit_file':
|
|
290
|
-
return args.path || '';
|
|
291
|
-
case 'list_files':
|
|
292
|
-
return args.path || '.';
|
|
293
|
-
case 'search_files':
|
|
294
|
-
return `"${args.pattern}" in ${args.path || '.'}`;
|
|
295
|
-
case 'run_command':
|
|
296
|
-
return args.command || '';
|
|
297
|
-
default:
|
|
298
|
-
return JSON.stringify(args).slice(0, 50);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function getModelDisplayName(model: string): string {
|
|
303
|
-
const names: Record<string, string> = {
|
|
304
|
-
'alia-v1-codea': 'codea',
|
|
305
|
-
'alia-v1-pro': 'codea-pro',
|
|
306
|
-
'alia-v1-thinking': 'codea-thinking'
|
|
307
|
-
};
|
|
308
|
-
return names[model] || model;
|
|
19
|
+
const { waitUntilExit } = render(React.createElement(App, { options: appOptions }));
|
|
20
|
+
await waitUntilExit();
|
|
309
21
|
}
|
package/src/commands/run.ts
CHANGED
|
@@ -1,33 +1,28 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
printToolExecution,
|
|
8
|
-
printToolResult,
|
|
9
|
-
showThinkingStatus,
|
|
10
|
-
hideThinkingStatus,
|
|
11
|
-
printAssistantPrefix,
|
|
12
|
-
printError,
|
|
13
|
-
printInfo
|
|
14
|
-
} from '../utils/ui.js';
|
|
15
|
-
|
|
16
|
-
interface Message {
|
|
17
|
-
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
18
|
-
content: string;
|
|
19
|
-
tool_calls?: any[];
|
|
20
|
-
tool_call_id?: string;
|
|
21
|
-
}
|
|
2
|
+
import { buildSystemMessage, getCodebaseContext, loadProjectInstructions } from '../utils/context.js';
|
|
3
|
+
import { processConversation, Message, ToolExecution } from '../utils/conversation.js';
|
|
4
|
+
import { ApprovalMode } from '../utils/approval.js';
|
|
5
|
+
import * as readline from 'readline';
|
|
22
6
|
|
|
23
7
|
interface RunOptions {
|
|
24
8
|
model: string;
|
|
25
9
|
yes: boolean;
|
|
26
10
|
context: boolean;
|
|
11
|
+
approvalMode?: string;
|
|
12
|
+
quiet?: boolean;
|
|
13
|
+
json?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface JsonOutput {
|
|
17
|
+
model: string;
|
|
18
|
+
prompt: string;
|
|
19
|
+
response: string;
|
|
20
|
+
tool_calls: Array<{ tool: string; args: Record<string, any>; result: string; success: boolean }>;
|
|
27
21
|
}
|
|
28
22
|
|
|
29
23
|
export async function runPrompt(prompt: string, options: RunOptions): Promise<void> {
|
|
30
24
|
const messages: Message[] = [];
|
|
25
|
+
const toolResults: JsonOutput['tool_calls'] = [];
|
|
31
26
|
|
|
32
27
|
// Get codebase context
|
|
33
28
|
let codebaseContext = '';
|
|
@@ -35,136 +30,118 @@ export async function runPrompt(prompt: string, options: RunOptions): Promise<vo
|
|
|
35
30
|
codebaseContext = await getCodebaseContext();
|
|
36
31
|
}
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
messages.push({ role: 'user', content: prompt });
|
|
40
|
-
|
|
41
|
-
// Build system message
|
|
42
|
-
const systemMessage = buildSystemMessage(options.model, codebaseContext);
|
|
43
|
-
|
|
44
|
-
// Process with tool loop
|
|
45
|
-
await processConversation(messages, systemMessage, options.model, options.yes);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function processConversation(
|
|
49
|
-
messages: Message[],
|
|
50
|
-
systemMessage: string,
|
|
51
|
-
model: string,
|
|
52
|
-
autoApprove: boolean
|
|
53
|
-
): Promise<void> {
|
|
54
|
-
let continueProcessing = true;
|
|
55
|
-
|
|
56
|
-
while (continueProcessing) {
|
|
57
|
-
printAssistantPrefix();
|
|
58
|
-
|
|
59
|
-
let fullContent = '';
|
|
60
|
-
let toolCalls: any[] | undefined;
|
|
61
|
-
|
|
62
|
-
showThinkingStatus('Thinking');
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
await streamChat(messages, systemMessage, model, {
|
|
66
|
-
onContent: (content) => {
|
|
67
|
-
hideThinkingStatus();
|
|
68
|
-
process.stdout.write(content);
|
|
69
|
-
fullContent += content;
|
|
70
|
-
},
|
|
71
|
-
onToolCall: () => {},
|
|
72
|
-
onDone: (content, tcs) => {
|
|
73
|
-
hideThinkingStatus();
|
|
74
|
-
toolCalls = tcs;
|
|
75
|
-
},
|
|
76
|
-
onError: (error) => {
|
|
77
|
-
hideThinkingStatus();
|
|
78
|
-
printError(error.message);
|
|
79
|
-
continueProcessing = false;
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
} catch (error: any) {
|
|
83
|
-
hideThinkingStatus();
|
|
84
|
-
printError(error.message);
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Handle tool calls
|
|
89
|
-
if (toolCalls && toolCalls.length > 0) {
|
|
90
|
-
messages.push({
|
|
91
|
-
role: 'assistant',
|
|
92
|
-
content: fullContent,
|
|
93
|
-
tool_calls: toolCalls
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
if (fullContent) console.log();
|
|
33
|
+
const instructions = await loadProjectInstructions();
|
|
97
34
|
|
|
98
|
-
|
|
99
|
-
const args = JSON.parse(tc.function.arguments);
|
|
100
|
-
|
|
101
|
-
// Check if we need approval for file writes
|
|
102
|
-
const isDestructive = ['write_file', 'edit_file', 'run_command'].includes(tc.function.name);
|
|
103
|
-
|
|
104
|
-
if (isDestructive && !autoApprove) {
|
|
105
|
-
console.log();
|
|
106
|
-
console.log(chalk.yellow('⚠ ') + chalk.bold('Approval required:'));
|
|
107
|
-
console.log(formatToolCall(tc.function.name, args));
|
|
108
|
-
console.log();
|
|
35
|
+
messages.push({ role: 'user', content: prompt });
|
|
109
36
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
37
|
+
const systemMessage = buildSystemMessage(options.model, codebaseContext, instructions);
|
|
38
|
+
|
|
39
|
+
const approvalMode: ApprovalMode = options.yes
|
|
40
|
+
? 'full-auto'
|
|
41
|
+
: (options.approvalMode as ApprovalMode) || 'suggest';
|
|
42
|
+
|
|
43
|
+
let fullResponse = '';
|
|
44
|
+
|
|
45
|
+
await processConversation({
|
|
46
|
+
messages,
|
|
47
|
+
systemMessage,
|
|
48
|
+
model: options.model,
|
|
49
|
+
approvalMode,
|
|
50
|
+
isActive: () => true,
|
|
51
|
+
requestApproval: async (execution) => {
|
|
52
|
+
if (options.quiet || options.json) return false;
|
|
53
|
+
return askApproval(execution);
|
|
54
|
+
},
|
|
55
|
+
onEvent: (event) => {
|
|
56
|
+
switch (event.type) {
|
|
57
|
+
case 'thinking':
|
|
58
|
+
if (!options.quiet && !options.json) {
|
|
59
|
+
process.stdout.write(chalk.magenta('✦ '));
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
case 'content':
|
|
63
|
+
fullResponse += event.text;
|
|
64
|
+
if (!options.quiet && !options.json) {
|
|
65
|
+
process.stdout.write(event.text);
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
case 'tool_start':
|
|
69
|
+
if (!options.quiet && !options.json) {
|
|
70
|
+
console.log();
|
|
71
|
+
console.log(chalk.cyan(' → ') + chalk.bold(event.execution.tool) + ' ' + chalk.gray(formatArgs(event.execution)));
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
case 'tool_done':
|
|
75
|
+
if (event.execution.result !== undefined) {
|
|
76
|
+
toolResults.push({
|
|
77
|
+
tool: event.execution.tool,
|
|
78
|
+
args: event.execution.args,
|
|
79
|
+
result: event.execution.result,
|
|
80
|
+
success: event.execution.success ?? false,
|
|
116
81
|
});
|
|
117
|
-
continue;
|
|
118
82
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
83
|
+
if (!options.quiet && !options.json) {
|
|
84
|
+
const icon = event.execution.success ? chalk.green(' ✓') : chalk.red(' ✗');
|
|
85
|
+
const preview = (event.execution.result || '').slice(0, 100).replace(/\n/g, ' ');
|
|
86
|
+
console.log(`${icon} ${chalk.gray(preview)}`);
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
case 'done':
|
|
90
|
+
if (!options.quiet && !options.json) {
|
|
91
|
+
console.log();
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case 'error':
|
|
95
|
+
if (!options.json) {
|
|
96
|
+
console.error(chalk.red('Error: ') + event.message);
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
134
99
|
}
|
|
100
|
+
},
|
|
101
|
+
});
|
|
135
102
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
103
|
+
if (options.json) {
|
|
104
|
+
const output: JsonOutput = {
|
|
105
|
+
model: options.model,
|
|
106
|
+
prompt,
|
|
107
|
+
response: fullResponse,
|
|
108
|
+
tool_calls: toolResults,
|
|
109
|
+
};
|
|
110
|
+
console.log(JSON.stringify(output, null, 2));
|
|
111
|
+
} else if (options.quiet) {
|
|
112
|
+
if (fullResponse) {
|
|
113
|
+
console.log(fullResponse);
|
|
143
114
|
}
|
|
144
115
|
}
|
|
145
116
|
}
|
|
146
117
|
|
|
147
|
-
async function askApproval(): Promise<boolean> {
|
|
148
|
-
const readline = await import('readline');
|
|
118
|
+
async function askApproval(execution: ToolExecution): Promise<boolean> {
|
|
149
119
|
const rl = readline.createInterface({
|
|
150
120
|
input: process.stdin,
|
|
151
|
-
output: process.stdout
|
|
121
|
+
output: process.stdout,
|
|
152
122
|
});
|
|
153
123
|
|
|
124
|
+
const desc = formatArgs(execution);
|
|
125
|
+
console.log();
|
|
126
|
+
console.log(chalk.yellow('⚠ ') + chalk.bold(execution.tool) + ' ' + desc);
|
|
127
|
+
|
|
154
128
|
return new Promise((resolve) => {
|
|
155
|
-
rl.question(chalk.cyan('Allow? [y/N] '), (answer) => {
|
|
129
|
+
rl.question(chalk.cyan(' Allow? [y/N] '), (answer) => {
|
|
156
130
|
rl.close();
|
|
157
131
|
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
158
132
|
});
|
|
159
133
|
});
|
|
160
134
|
}
|
|
161
135
|
|
|
162
|
-
function
|
|
163
|
-
|
|
136
|
+
function formatArgs(execution: ToolExecution): string {
|
|
137
|
+
const { tool, args } = execution;
|
|
138
|
+
switch (tool) {
|
|
164
139
|
case 'read_file':
|
|
165
140
|
case 'write_file':
|
|
166
141
|
case 'edit_file':
|
|
167
142
|
return args.path || '';
|
|
143
|
+
case 'apply_patch':
|
|
144
|
+
return 'applying patch...';
|
|
168
145
|
case 'list_files':
|
|
169
146
|
return args.path || '.';
|
|
170
147
|
case 'search_files':
|
|
@@ -172,6 +149,6 @@ function formatToolArgs(name: string, args: Record<string, any>): string {
|
|
|
172
149
|
case 'run_command':
|
|
173
150
|
return args.command || '';
|
|
174
151
|
default:
|
|
175
|
-
return JSON.stringify(args).slice(0,
|
|
152
|
+
return JSON.stringify(args).slice(0, 60);
|
|
176
153
|
}
|
|
177
154
|
}
|
package/src/commands/sessions.ts
CHANGED
|
@@ -2,13 +2,12 @@ import chalk from 'chalk';
|
|
|
2
2
|
import * as readline from 'readline';
|
|
3
3
|
import { getSessions, getSession, config } from '../utils/config.js';
|
|
4
4
|
import { startRepl } from './repl.js';
|
|
5
|
-
import { printBanner, printError, printInfo } from '../utils/ui.js';
|
|
6
5
|
|
|
7
6
|
export async function listSessions(): Promise<void> {
|
|
8
7
|
const sessions = getSessions();
|
|
9
8
|
|
|
10
9
|
if (sessions.length === 0) {
|
|
11
|
-
|
|
10
|
+
console.log(chalk.blue('ℹ ') + 'No saved sessions found.');
|
|
12
11
|
console.log(chalk.gray('Start a new session with: ') + chalk.cyan('codea'));
|
|
13
12
|
return;
|
|
14
13
|
}
|
|
@@ -38,7 +37,7 @@ export async function resumeSession(sessionId?: string): Promise<void> {
|
|
|
38
37
|
const sessions = getSessions();
|
|
39
38
|
|
|
40
39
|
if (sessions.length === 0) {
|
|
41
|
-
|
|
40
|
+
console.log(chalk.blue('ℹ ') + 'No saved sessions found.');
|
|
42
41
|
return;
|
|
43
42
|
}
|
|
44
43
|
|
|
@@ -54,7 +53,7 @@ export async function resumeSession(sessionId?: string): Promise<void> {
|
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
if (!selectedSession) {
|
|
57
|
-
|
|
56
|
+
console.log(chalk.red('✗ Error: ') + `Session not found: ${sessionId}`);
|
|
58
57
|
return;
|
|
59
58
|
}
|
|
60
59
|
} else {
|
|
@@ -82,7 +81,7 @@ export async function resumeSession(sessionId?: string): Promise<void> {
|
|
|
82
81
|
|
|
83
82
|
const index = parseInt(answer) - 1;
|
|
84
83
|
if (isNaN(index) || index < 0 || index >= sessions.length) {
|
|
85
|
-
|
|
84
|
+
console.log(chalk.red('✗ Error: ') + 'Invalid selection.');
|
|
86
85
|
resolve();
|
|
87
86
|
return;
|
|
88
87
|
}
|
|
@@ -99,7 +98,7 @@ export async function resumeSession(sessionId?: string): Promise<void> {
|
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
async function startRestoredSession(session: any): Promise<void> {
|
|
102
|
-
|
|
101
|
+
console.log(chalk.blue('ℹ ') + `Resuming: ${session.title}`);
|
|
103
102
|
console.log();
|
|
104
103
|
|
|
105
104
|
// Display previous messages
|