codecane 1.0.156 → 1.0.171
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/browser-runner.d.ts +2 -0
- package/dist/browser-runner.js +210 -135
- package/dist/browser-runner.js.map +1 -1
- package/dist/chat-storage.d.ts +1 -1
- package/dist/chat-storage.js +35 -31
- package/dist/chat-storage.js.map +1 -1
- package/dist/checkpoints.d.ts +64 -0
- package/dist/checkpoints.js +147 -0
- package/dist/checkpoints.js.map +1 -0
- package/dist/cli.d.ts +22 -16
- package/dist/cli.js +472 -367
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +178 -25
- package/dist/client.js +252 -198
- package/dist/client.js.map +1 -1
- package/dist/code-map/tsconfig.tsbuildinfo +1 -1
- package/dist/common/actions.d.ts +2083 -443
- package/dist/common/actions.js +31 -78
- package/dist/common/actions.js.map +1 -1
- package/dist/common/browser-actions.d.ts +221 -141
- package/dist/common/browser-actions.js +25 -12
- package/dist/common/browser-actions.js.map +1 -1
- package/dist/common/constants/tools.d.ts +3 -0
- package/dist/common/constants/tools.js +24 -0
- package/dist/common/constants/tools.js.map +1 -0
- package/dist/common/constants.d.ts +14 -8
- package/dist/common/constants.js +7 -6
- package/dist/common/constants.js.map +1 -1
- package/dist/common/message-image-handling.d.ts +41 -0
- package/dist/common/message-image-handling.js +57 -0
- package/dist/common/message-image-handling.js.map +1 -0
- package/dist/common/project-file-tree.js +7 -7
- package/dist/common/project-file-tree.js.map +1 -1
- package/dist/common/types/agent-state.d.ts +461 -0
- package/dist/common/types/agent-state.js +30 -0
- package/dist/common/types/agent-state.js.map +1 -0
- package/dist/common/types/message.d.ts +311 -0
- package/dist/common/types/message.js +54 -0
- package/dist/common/types/message.js.map +1 -0
- package/dist/common/types/tools.d.ts +5 -0
- package/dist/common/types/tools.js +3 -0
- package/dist/common/types/tools.js.map +1 -0
- package/dist/common/util/__tests__/messages.test.js +70 -0
- package/dist/common/util/__tests__/messages.test.js.map +1 -0
- package/dist/common/util/changes.js +3 -3
- package/dist/common/util/changes.js.map +1 -1
- package/dist/common/util/credentials.d.ts +4 -4
- package/dist/common/util/file.d.ts +6 -2
- package/dist/common/util/file.js +30 -27
- package/dist/common/util/file.js.map +1 -1
- package/dist/common/util/git.js +1 -1
- package/dist/common/util/git.js.map +1 -1
- package/dist/common/util/lru-cache.d.ts +9 -0
- package/dist/common/util/lru-cache.js +42 -0
- package/dist/common/util/lru-cache.js.map +1 -0
- package/dist/common/util/messages.d.ts +6 -0
- package/dist/common/util/messages.js +22 -0
- package/dist/common/util/messages.js.map +1 -0
- package/dist/common/util/min-heap.d.ts +15 -0
- package/dist/common/util/min-heap.js +73 -0
- package/dist/common/util/min-heap.js.map +1 -0
- package/dist/common/util/process-stream.d.ts +8 -0
- package/dist/common/util/process-stream.js +102 -0
- package/dist/common/util/process-stream.js.map +1 -0
- package/dist/common/util/promise.d.ts +8 -0
- package/dist/common/util/promise.js +25 -2
- package/dist/common/util/promise.js.map +1 -1
- package/dist/common/util/string.d.ts +31 -0
- package/dist/common/util/string.js +71 -1
- package/dist/common/util/string.js.map +1 -1
- package/dist/common/websockets/websocket-schema.d.ts +3920 -938
- package/dist/config.d.ts +1 -0
- package/dist/config.js +3 -2
- package/dist/config.js.map +1 -1
- package/dist/credentials.d.ts +1 -0
- package/dist/credentials.js +7 -3
- package/dist/credentials.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/menu.js +16 -12
- package/dist/menu.js.map +1 -1
- package/dist/project-files.d.ts +40 -2
- package/dist/project-files.js +95 -17
- package/dist/project-files.js.map +1 -1
- package/dist/tool-handlers.d.ts +22 -7
- package/dist/tool-handlers.js +110 -43
- package/dist/tool-handlers.js.map +1 -1
- package/dist/utils/logger.d.ts +1 -0
- package/dist/utils/logger.js +46 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/process-xml-chunks.d.ts +37 -0
- package/dist/utils/process-xml-chunks.js +247 -0
- package/dist/utils/process-xml-chunks.js.map +1 -0
- package/dist/utils/spinner.d.ts +11 -0
- package/dist/utils/spinner.js +87 -0
- package/dist/utils/spinner.js.map +1 -0
- package/dist/utils/terminal.d.ts +3 -3
- package/dist/utils/terminal.js +23 -24
- package/dist/utils/terminal.js.map +1 -1
- package/dist/web-scraper.d.ts +1 -1
- package/dist/web-scraper.js +11 -7
- package/dist/web-scraper.js.map +1 -1
- package/package.json +3 -4
- package/dist/__tests__/browser-runner.test.js +0 -15
- package/dist/__tests__/browser-runner.test.js.map +0 -1
- /package/dist/{__tests__/browser-runner.test.d.ts → common/util/__tests__/messages.test.d.ts} +0 -0
package/dist/cli.js
CHANGED
|
@@ -24,35 +24,24 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.CLI = void 0;
|
|
27
|
-
const
|
|
28
|
-
const project_file_tree_1 = require("./common/project-file-tree");
|
|
29
|
-
const changes_1 = require("./common/util/changes");
|
|
30
|
-
const readline = __importStar(require("readline"));
|
|
31
|
-
const picocolors_1 = require("picocolors");
|
|
27
|
+
const fs = __importStar(require("fs"));
|
|
32
28
|
const path_1 = require("path");
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
process.stdout.write(line + '\n');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
const config_1 = require("./config");
|
|
29
|
+
const picocolors_1 = require("picocolors");
|
|
30
|
+
const readline = __importStar(require("readline"));
|
|
31
|
+
const constants_1 = require("./common/constants");
|
|
32
|
+
const project_file_tree_1 = require("./common/project-file-tree");
|
|
33
|
+
const file_1 = require("./common/util/file");
|
|
34
|
+
const string_1 = require("./common/util/string");
|
|
45
35
|
const chat_storage_1 = require("./chat-storage");
|
|
36
|
+
const checkpoints_1 = require("./checkpoints");
|
|
46
37
|
const client_1 = require("./client");
|
|
38
|
+
const config_1 = require("./config");
|
|
47
39
|
const menu_1 = require("./menu");
|
|
48
40
|
const project_files_1 = require("./project-files");
|
|
49
41
|
const tool_handlers_1 = require("./tool-handlers");
|
|
42
|
+
const spinner_1 = require("./utils/spinner");
|
|
50
43
|
const terminal_1 = require("./utils/terminal");
|
|
51
|
-
const constants_1 = require("./common/constants");
|
|
52
|
-
const file_1 = require("./common/util/file");
|
|
53
44
|
const web_scraper_1 = require("./web-scraper");
|
|
54
|
-
const git_1 = require("./common/util/git");
|
|
55
|
-
const string_1 = require("./common/util/string");
|
|
56
45
|
class CLI {
|
|
57
46
|
client;
|
|
58
47
|
chatStorage;
|
|
@@ -62,8 +51,6 @@ class CLI {
|
|
|
62
51
|
rl;
|
|
63
52
|
isReceivingResponse = false;
|
|
64
53
|
stopResponse = null;
|
|
65
|
-
loadingInterval = null;
|
|
66
|
-
lastChanges = [];
|
|
67
54
|
lastSigintTime = 0;
|
|
68
55
|
lastInputTime = 0;
|
|
69
56
|
consecutiveFastInputs = 0;
|
|
@@ -73,375 +60,223 @@ class CLI {
|
|
|
73
60
|
this.git = git;
|
|
74
61
|
this.costMode = costMode;
|
|
75
62
|
this.chatStorage = new chat_storage_1.ChatStorage();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this.restoreCursor();
|
|
79
|
-
process.exit(0);
|
|
80
|
-
});
|
|
81
|
-
this.rl = readline.createInterface({
|
|
82
|
-
input: process.stdin,
|
|
83
|
-
output: process.stdout,
|
|
84
|
-
historySize: 1000,
|
|
85
|
-
terminal: true,
|
|
86
|
-
completer: (line) => {
|
|
87
|
-
if (!this.client.fileContext?.fileTree)
|
|
88
|
-
return [[], line];
|
|
89
|
-
const tokenNames = Object.values(this.client.fileContext.fileTokenScores).flatMap((o) => Object.keys(o));
|
|
90
|
-
const paths = (0, project_file_tree_1.getAllFilePaths)(this.client.fileContext.fileTree);
|
|
91
|
-
const lastWord = line.split(' ').pop() || '';
|
|
92
|
-
const matchingTokens = [...tokenNames, ...paths].filter((token) => token.startsWith(lastWord) || token.includes('/' + lastWord));
|
|
93
|
-
if (matchingTokens.length > 1) {
|
|
94
|
-
// Find common characters after lastWord
|
|
95
|
-
const suffixes = matchingTokens.map((token) => {
|
|
96
|
-
const index = token.indexOf(lastWord);
|
|
97
|
-
return token.slice(index + lastWord.length);
|
|
98
|
-
});
|
|
99
|
-
let commonPrefix = '';
|
|
100
|
-
const firstSuffix = suffixes[0];
|
|
101
|
-
for (let i = 0; i < firstSuffix.length; i++) {
|
|
102
|
-
const char = firstSuffix[i];
|
|
103
|
-
if (suffixes.every((suffix) => suffix[i] === char)) {
|
|
104
|
-
commonPrefix += char;
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (commonPrefix) {
|
|
111
|
-
// Match the common prefix
|
|
112
|
-
return [[lastWord + commonPrefix], lastWord];
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return [matchingTokens, lastWord];
|
|
116
|
-
},
|
|
117
|
-
});
|
|
63
|
+
this.setupSignalHandlers();
|
|
64
|
+
this.initReadlineInterface();
|
|
118
65
|
this.client = new client_1.Client(config_1.websocketUrl, this.chatStorage, this.onWebSocketError.bind(this), this.onWebSocketReconnect.bind(this), this.returnControlToUser.bind(this), this.costMode, this.git, this.rl);
|
|
119
66
|
this.readyPromise = Promise.all([
|
|
120
67
|
readyPromise.then((results) => {
|
|
121
68
|
const [_, fileContext] = results;
|
|
122
|
-
this.client.
|
|
69
|
+
this.client.initAgentState(fileContext);
|
|
123
70
|
return this.client.warmContextCache();
|
|
124
71
|
}),
|
|
125
72
|
this.client.connect(),
|
|
126
73
|
]);
|
|
127
74
|
this.setPrompt();
|
|
128
|
-
|
|
129
|
-
|
|
75
|
+
}
|
|
76
|
+
setupSignalHandlers() {
|
|
77
|
+
process.on('exit', () => spinner_1.Spinner.get().restoreCursor());
|
|
78
|
+
process.on('SIGTERM', () => {
|
|
79
|
+
spinner_1.Spinner.get().restoreCursor();
|
|
80
|
+
process.exit(0);
|
|
130
81
|
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
82
|
+
process.on('SIGTSTP', () => this.handleExit());
|
|
83
|
+
}
|
|
84
|
+
initReadlineInterface() {
|
|
85
|
+
this.rl = readline.createInterface({
|
|
86
|
+
input: process.stdin,
|
|
87
|
+
output: process.stdout,
|
|
88
|
+
historySize: 1000,
|
|
89
|
+
terminal: true,
|
|
90
|
+
completer: this.completer.bind(this),
|
|
91
|
+
});
|
|
92
|
+
this.rl.on('line', (line) => this.handleLine(line));
|
|
93
|
+
this.rl.on('SIGINT', () => this.handleSigint());
|
|
94
|
+
this.rl.on('close', () => this.handleExit());
|
|
95
|
+
process.stdin.on('keypress', (str, key) => this.handleKeyPress(str, key));
|
|
96
|
+
}
|
|
97
|
+
completer(line) {
|
|
98
|
+
if (!this.client.fileContext?.fileTree)
|
|
99
|
+
return [[], line];
|
|
100
|
+
const tokenNames = Object.values(this.client.fileContext.fileTokenScores).flatMap((o) => Object.keys(o));
|
|
101
|
+
const paths = (0, project_file_tree_1.getAllFilePaths)(this.client.fileContext.fileTree);
|
|
102
|
+
const lastWord = line.split(' ').pop() || '';
|
|
103
|
+
const lastWordLower = lastWord.toLowerCase();
|
|
104
|
+
const matchingTokens = [...tokenNames, ...paths].filter((token) => token.toLowerCase().startsWith(lastWordLower) ||
|
|
105
|
+
token.toLowerCase().includes('/' + lastWordLower));
|
|
106
|
+
if (matchingTokens.length > 1) {
|
|
107
|
+
const suffixes = matchingTokens.map((token) => {
|
|
108
|
+
const index = token.toLowerCase().indexOf(lastWordLower);
|
|
109
|
+
return token.slice(index + lastWord.length);
|
|
110
|
+
});
|
|
111
|
+
let commonPrefix = '';
|
|
112
|
+
const firstSuffix = suffixes[0];
|
|
113
|
+
for (let i = 0; i < firstSuffix.length; i++) {
|
|
114
|
+
const char = firstSuffix[i];
|
|
115
|
+
if (suffixes.every((suffix) => suffix[i] === char)) {
|
|
116
|
+
commonPrefix += char;
|
|
148
117
|
}
|
|
149
118
|
else {
|
|
150
|
-
|
|
151
|
-
console.log('\nPress Ctrl-C again to exit');
|
|
152
|
-
this.rl.prompt();
|
|
119
|
+
break;
|
|
153
120
|
}
|
|
154
121
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this.handleExit();
|
|
158
|
-
});
|
|
159
|
-
process.on('SIGTSTP', () => {
|
|
160
|
-
// Exit on Ctrl+Z
|
|
161
|
-
this.handleExit();
|
|
162
|
-
});
|
|
163
|
-
process.stdin.on('keypress', (str, key) => {
|
|
164
|
-
if (key.name === 'escape') {
|
|
165
|
-
this.handleEscKey();
|
|
166
|
-
}
|
|
167
|
-
// Make double spaces into newlines
|
|
168
|
-
if (!this.isPasting &&
|
|
169
|
-
str === ' ' &&
|
|
170
|
-
'_refreshLine' in this.rl &&
|
|
171
|
-
'line' in this.rl &&
|
|
172
|
-
'cursor' in this.rl) {
|
|
173
|
-
const rl = this.rl;
|
|
174
|
-
const { cursor, line } = rl;
|
|
175
|
-
const prevTwoChars = cursor > 1 ? line.slice(cursor - 2, cursor) : '';
|
|
176
|
-
if (prevTwoChars === ' ') {
|
|
177
|
-
rl.line = line.slice(0, cursor - 2) + '\n\n' + line.slice(cursor);
|
|
178
|
-
rl._refreshLine();
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
this.detectPasting();
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
returnControlToUser() {
|
|
185
|
-
this.rl.prompt();
|
|
186
|
-
this.isReceivingResponse = false;
|
|
187
|
-
if (this.stopResponse) {
|
|
188
|
-
this.stopResponse();
|
|
189
|
-
}
|
|
190
|
-
this.stopLoadingAnimation();
|
|
191
|
-
}
|
|
192
|
-
onWebSocketError() {
|
|
193
|
-
this.stopLoadingAnimation();
|
|
194
|
-
this.isReceivingResponse = false;
|
|
195
|
-
if (this.stopResponse) {
|
|
196
|
-
this.stopResponse();
|
|
197
|
-
this.stopResponse = null;
|
|
198
|
-
}
|
|
199
|
-
console.error((0, picocolors_1.yellow)('\nCould not connect. Retrying...'));
|
|
200
|
-
}
|
|
201
|
-
onWebSocketReconnect() {
|
|
202
|
-
console.log((0, picocolors_1.green)('\nReconnected!'));
|
|
203
|
-
this.returnControlToUser();
|
|
204
|
-
}
|
|
205
|
-
detectPasting() {
|
|
206
|
-
const currentTime = Date.now();
|
|
207
|
-
const timeDiff = currentTime - this.lastInputTime;
|
|
208
|
-
if (timeDiff < 10) {
|
|
209
|
-
this.consecutiveFastInputs++;
|
|
210
|
-
if (this.consecutiveFastInputs >= 2) {
|
|
211
|
-
this.isPasting = true;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
this.consecutiveFastInputs = 0;
|
|
216
|
-
if (this.isPasting) {
|
|
217
|
-
this.isPasting = false;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
this.lastInputTime = currentTime;
|
|
221
|
-
}
|
|
222
|
-
handleInput(line) {
|
|
223
|
-
this.detectPasting();
|
|
224
|
-
if (this.isPasting) {
|
|
225
|
-
this.pastedContent += line + '\n';
|
|
226
|
-
}
|
|
227
|
-
else if (!this.isReceivingResponse) {
|
|
228
|
-
if (this.pastedContent) {
|
|
229
|
-
this.handleUserInput((this.pastedContent + line).trim());
|
|
230
|
-
this.pastedContent = '';
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
this.handleUserInput(line.trim());
|
|
122
|
+
if (commonPrefix) {
|
|
123
|
+
return [[lastWord + commonPrefix], lastWord];
|
|
234
124
|
}
|
|
235
125
|
}
|
|
126
|
+
return [matchingTokens, lastWord];
|
|
236
127
|
}
|
|
237
128
|
setPrompt() {
|
|
238
|
-
this.rl.setPrompt((0, picocolors_1.green)(`${(0, path_1.parse)((0, project_files_1.getProjectRoot)()).base} > `));
|
|
129
|
+
this.rl.setPrompt((0, picocolors_1.green)(`${(0, path_1.parse)((0, project_files_1.getProjectRoot)()).base} ${checkpoints_1.checkpointManager.getNextId()} > `));
|
|
130
|
+
}
|
|
131
|
+
promptWithCheckpointNumber() {
|
|
132
|
+
this.setPrompt();
|
|
133
|
+
this.rl.prompt();
|
|
239
134
|
}
|
|
240
135
|
async printInitialPrompt(initialInput) {
|
|
241
136
|
if (this.client.user) {
|
|
242
137
|
(0, menu_1.displayGreeting)(this.costMode, this.client.user.name);
|
|
243
138
|
}
|
|
244
139
|
else {
|
|
245
|
-
console.log(`Welcome to Codebuff!
|
|
140
|
+
console.log(`Welcome to Codebuff! Give us a sec to get your account set up...`);
|
|
246
141
|
await this.client.login();
|
|
247
142
|
return;
|
|
248
143
|
}
|
|
249
|
-
this.
|
|
144
|
+
this.promptWithCheckpointNumber();
|
|
250
145
|
if (initialInput) {
|
|
251
146
|
process.stdout.write(initialInput + '\n');
|
|
252
147
|
this.handleUserInput(initialInput);
|
|
253
148
|
}
|
|
254
149
|
}
|
|
255
|
-
|
|
256
|
-
this.
|
|
257
|
-
this.
|
|
258
|
-
}
|
|
259
|
-
handleRedo() {
|
|
260
|
-
this.navigateFileVersion('redo');
|
|
261
|
-
this.rl.prompt();
|
|
262
|
-
}
|
|
263
|
-
navigateFileVersion(direction) {
|
|
264
|
-
const currentVersion = this.chatStorage.getCurrentVersion();
|
|
265
|
-
const filePaths = Object.keys(currentVersion ? currentVersion.files : {});
|
|
266
|
-
const currentFiles = (0, project_files_1.getExistingFiles)(filePaths);
|
|
267
|
-
this.chatStorage.saveCurrentFileState(currentFiles);
|
|
268
|
-
const navigated = this.chatStorage.navigateVersion(direction);
|
|
269
|
-
if (navigated) {
|
|
270
|
-
console.log(direction === 'undo'
|
|
271
|
-
? (0, picocolors_1.green)('Undo last change')
|
|
272
|
-
: (0, picocolors_1.green)('Redo last change'));
|
|
273
|
-
const files = this.applyAndDisplayCurrentFileVersion();
|
|
274
|
-
console.log((0, picocolors_1.green)('Loaded files:'), (0, picocolors_1.green)(Object.keys(files).join(', ')));
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
console.log((0, picocolors_1.green)(`No more ${direction === 'undo' ? 'undo' : 'redo'}s`));
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
handleStopResponse() {
|
|
281
|
-
console.log((0, picocolors_1.yellow)('\n[Response stopped by user]'));
|
|
282
|
-
this.isReceivingResponse = false;
|
|
283
|
-
if (this.stopResponse) {
|
|
284
|
-
this.stopResponse();
|
|
285
|
-
}
|
|
286
|
-
this.stopLoadingAnimation();
|
|
287
|
-
this.restoreCursor();
|
|
150
|
+
async printDiff() {
|
|
151
|
+
this.handleDiff();
|
|
152
|
+
this.promptWithCheckpointNumber();
|
|
288
153
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
handleExit() {
|
|
294
|
-
this.restoreCursor();
|
|
295
|
-
console.log('\n\n');
|
|
296
|
-
console.log(`${(0, string_1.pluralize)(this.client.sessionCreditsUsed, 'credit')} used this session.`);
|
|
297
|
-
if (!!this.client.limit &&
|
|
298
|
-
!!this.client.usage &&
|
|
299
|
-
!!this.client.nextQuotaReset) {
|
|
300
|
-
const daysUntilReset = Math.max(0, Math.floor((this.client.nextQuotaReset.getTime() - Date.now()) /
|
|
301
|
-
(1000 * 60 * 60 * 24)));
|
|
302
|
-
console.log(`${Math.max(0, this.client.limit - this.client.usage)} / ${this.client.limit} credits remaining. Renews in ${(0, string_1.pluralize)(daysUntilReset, 'day')}.`);
|
|
303
|
-
}
|
|
304
|
-
console.log((0, picocolors_1.green)('Codebuff out!'));
|
|
305
|
-
process.exit(0);
|
|
306
|
-
}
|
|
307
|
-
handleEscKey() {
|
|
308
|
-
if (this.isReceivingResponse) {
|
|
309
|
-
this.handleStopResponse();
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
applyAndDisplayCurrentFileVersion() {
|
|
313
|
-
const currentVersion = this.chatStorage.getCurrentVersion();
|
|
314
|
-
if (currentVersion) {
|
|
315
|
-
(0, project_files_1.setFiles)(currentVersion.files);
|
|
316
|
-
return currentVersion.files;
|
|
317
|
-
}
|
|
318
|
-
return {};
|
|
319
|
-
}
|
|
320
|
-
startLoadingAnimation() {
|
|
321
|
-
const chars = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
322
|
-
let i = 0;
|
|
323
|
-
// Hide cursor while spinner is active
|
|
324
|
-
process.stdout.write('\u001B[?25l');
|
|
325
|
-
this.loadingInterval = setInterval(() => {
|
|
326
|
-
rewriteLine((0, picocolors_1.green)(`${chars[i]} Thinking...`));
|
|
327
|
-
i = (i + 1) % chars.length;
|
|
328
|
-
}, 100);
|
|
329
|
-
}
|
|
330
|
-
stopLoadingAnimation() {
|
|
331
|
-
if (this.loadingInterval) {
|
|
332
|
-
clearInterval(this.loadingInterval);
|
|
333
|
-
this.loadingInterval = null;
|
|
334
|
-
rewriteLine(''); // Clear the spinner line
|
|
335
|
-
this.restoreCursor(); // Show cursor after spinner stops
|
|
154
|
+
async handleLine(line) {
|
|
155
|
+
this.detectPasting();
|
|
156
|
+
if (this.isPasting) {
|
|
157
|
+
this.pastedContent += line + '\n';
|
|
336
158
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
return commitMessage;
|
|
159
|
+
else if (!this.isReceivingResponse) {
|
|
160
|
+
if (this.pastedContent) {
|
|
161
|
+
await this.handleUserInput((this.pastedContent + line).trim());
|
|
162
|
+
this.pastedContent = '';
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
await this.handleUserInput(line.trim());
|
|
166
|
+
}
|
|
346
167
|
}
|
|
347
|
-
return undefined;
|
|
348
|
-
}
|
|
349
|
-
handleDiff() {
|
|
350
|
-
if (this.lastChanges.length === 0) {
|
|
351
|
-
console.log((0, picocolors_1.yellow)('No changes found in the last assistant response.'));
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
this.lastChanges.forEach((change) => {
|
|
355
|
-
console.log('-', change.filePath);
|
|
356
|
-
const lines = change.content
|
|
357
|
-
.split('\n')
|
|
358
|
-
.map((line) => (change.type === 'file' ? '+' + line : line));
|
|
359
|
-
lines.forEach((line) => {
|
|
360
|
-
if (line.startsWith('+')) {
|
|
361
|
-
console.log((0, picocolors_1.green)(line));
|
|
362
|
-
}
|
|
363
|
-
else if (line.startsWith('-')) {
|
|
364
|
-
console.log((0, picocolors_1.red)(line));
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
console.log(line);
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
});
|
|
371
168
|
}
|
|
372
169
|
async handleUserInput(userInput) {
|
|
373
170
|
if (!userInput)
|
|
374
171
|
return;
|
|
375
172
|
userInput = userInput.trim();
|
|
376
|
-
|
|
173
|
+
if (await this.processCommand(userInput)) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
await this.forwardUserInput(userInput);
|
|
177
|
+
}
|
|
178
|
+
async beforeProcessCommand(userInput) {
|
|
179
|
+
await this.readyPromise;
|
|
180
|
+
// Save the current agent state
|
|
181
|
+
checkpoints_1.checkpointManager.addCheckpoint(this.client.agentState, userInput);
|
|
182
|
+
}
|
|
183
|
+
async processCommand(userInput) {
|
|
184
|
+
await this.beforeProcessCommand(userInput);
|
|
377
185
|
if (userInput === 'help' || userInput === 'h') {
|
|
378
186
|
(0, menu_1.displayMenu)();
|
|
379
|
-
this.
|
|
380
|
-
return;
|
|
187
|
+
this.promptWithCheckpointNumber();
|
|
188
|
+
return true;
|
|
381
189
|
}
|
|
382
190
|
if (userInput === 'login' || userInput === 'signin') {
|
|
383
191
|
await this.client.login();
|
|
384
|
-
return;
|
|
192
|
+
return true;
|
|
385
193
|
}
|
|
386
|
-
|
|
194
|
+
if (userInput === 'logout' || userInput === 'signout') {
|
|
387
195
|
await this.client.logout();
|
|
388
|
-
this.
|
|
389
|
-
return;
|
|
196
|
+
this.promptWithCheckpointNumber();
|
|
197
|
+
return true;
|
|
390
198
|
}
|
|
391
|
-
|
|
199
|
+
if (userInput.startsWith('ref-')) {
|
|
392
200
|
await this.client.handleReferralCode(userInput.trim());
|
|
393
|
-
return;
|
|
201
|
+
return true;
|
|
394
202
|
}
|
|
395
|
-
|
|
203
|
+
if (userInput === 'usage' || userInput === 'credits') {
|
|
396
204
|
this.client.getUsage();
|
|
397
|
-
return;
|
|
205
|
+
return true;
|
|
398
206
|
}
|
|
399
|
-
|
|
207
|
+
if (userInput === 'undo' || userInput === 'u') {
|
|
400
208
|
this.handleUndo();
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
else if (userInput === 'redo' || userInput === 'r') {
|
|
404
|
-
this.handleRedo();
|
|
405
|
-
return;
|
|
209
|
+
return true;
|
|
406
210
|
}
|
|
407
|
-
|
|
408
|
-
userInput === 'exit' ||
|
|
409
|
-
userInput === 'q') {
|
|
211
|
+
if (userInput === 'quit' || userInput === 'exit' || userInput === 'q') {
|
|
410
212
|
this.handleExit();
|
|
411
|
-
return;
|
|
213
|
+
return true;
|
|
412
214
|
}
|
|
413
|
-
|
|
414
|
-
userInput === 'doff' ||
|
|
415
|
-
userInput === 'dif' ||
|
|
416
|
-
userInput === 'iff' ||
|
|
417
|
-
userInput === 'd') {
|
|
215
|
+
if (['diff', 'doff', 'dif', 'iff', 'd'].includes(userInput)) {
|
|
418
216
|
this.handleDiff();
|
|
419
|
-
this.
|
|
420
|
-
return;
|
|
217
|
+
this.promptWithCheckpointNumber();
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
if (userInput === 'uuddlrlrba' ||
|
|
221
|
+
userInput === 'konami' ||
|
|
222
|
+
userInput === 'codebuffy') {
|
|
223
|
+
this.showEasterEgg();
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
// Checkpoint commands
|
|
227
|
+
if (userInput === 'checkpoint list' || userInput === 'checkpoints') {
|
|
228
|
+
this.handleCheckpoints();
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
const checkpointDetailMatch = userInput.match(/^checkpoint\s+(\d+)$/);
|
|
232
|
+
if (checkpointDetailMatch) {
|
|
233
|
+
const id = parseInt(checkpointDetailMatch[1], 10);
|
|
234
|
+
this.handleCheckpointDetail(id);
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
const restoreMatch = userInput.match(/^restore\s+(\d+)$/);
|
|
238
|
+
if (restoreMatch) {
|
|
239
|
+
const id = parseInt(restoreMatch[1], 10);
|
|
240
|
+
this.handleRestoreCheckpoint(id);
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
if (userInput === 'checkpoint clear') {
|
|
244
|
+
this.handleClearCheckpoints();
|
|
245
|
+
return true;
|
|
421
246
|
}
|
|
422
247
|
const runPrefix = '/run ';
|
|
248
|
+
const bangPrefix = '!';
|
|
423
249
|
const hasRunPrefix = userInput.startsWith(runPrefix);
|
|
250
|
+
const hasBangPrefix = userInput.startsWith(bangPrefix);
|
|
424
251
|
if (hasRunPrefix ||
|
|
425
|
-
|
|
252
|
+
hasBangPrefix ||
|
|
253
|
+
(!constants_1.SKIPPED_TERMINAL_COMMANDS.some((cmd) => userInput.toLowerCase().startsWith(cmd)) &&
|
|
426
254
|
!userInput.includes('error ') &&
|
|
427
255
|
!userInput.includes("'") &&
|
|
428
256
|
userInput.split(' ').length <= 5)) {
|
|
429
|
-
|
|
430
|
-
|
|
257
|
+
let commandToRun = userInput;
|
|
258
|
+
if (hasRunPrefix) {
|
|
259
|
+
commandToRun = userInput.replace(runPrefix, '');
|
|
260
|
+
}
|
|
261
|
+
else if (hasBangPrefix) {
|
|
262
|
+
commandToRun = userInput.replace(bangPrefix, '');
|
|
263
|
+
}
|
|
264
|
+
const { result, stdout } = await (0, tool_handlers_1.handleRunTerminalCommand)({ command: commandToRun }, 'user', 'user', (0, project_files_1.getProjectRoot)());
|
|
431
265
|
if (result !== 'command not found') {
|
|
432
|
-
this.
|
|
433
|
-
|
|
434
|
-
return;
|
|
266
|
+
this.promptWithCheckpointNumber();
|
|
267
|
+
return true;
|
|
435
268
|
}
|
|
436
|
-
else if (hasRunPrefix) {
|
|
269
|
+
else if (hasRunPrefix || hasBangPrefix) {
|
|
437
270
|
process.stdout.write(stdout);
|
|
438
|
-
this.
|
|
439
|
-
|
|
440
|
-
return;
|
|
271
|
+
this.promptWithCheckpointNumber();
|
|
272
|
+
return true;
|
|
441
273
|
}
|
|
442
274
|
}
|
|
443
|
-
|
|
444
|
-
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
async forwardUserInput(userInput) {
|
|
278
|
+
spinner_1.Spinner.get().start();
|
|
279
|
+
this.client.lastChanges = [];
|
|
445
280
|
const currentChat = this.chatStorage.getCurrentChat();
|
|
446
281
|
const { fileVersions } = currentChat;
|
|
447
282
|
const currentFileVersion = fileVersions[fileVersions.length - 1]?.files ?? {};
|
|
@@ -466,60 +301,330 @@ class CLI {
|
|
|
466
301
|
};
|
|
467
302
|
this.chatStorage.addMessage(currentChat, newMessage);
|
|
468
303
|
this.isReceivingResponse = true;
|
|
469
|
-
const {
|
|
304
|
+
const { responsePromise, stopResponse } = await this.client.sendUserInput(userInput);
|
|
305
|
+
this.stopResponse = stopResponse;
|
|
306
|
+
await responsePromise;
|
|
307
|
+
this.stopResponse = null;
|
|
470
308
|
this.isReceivingResponse = false;
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
309
|
+
spinner_1.Spinner.get().stop();
|
|
310
|
+
if (this.client.lastRequestCredits >= constants_1.REQUEST_CREDIT_SHOW_THRESHOLD) {
|
|
311
|
+
console.log(`\n${(0, string_1.pluralize)(this.client.lastRequestCredits, 'credit')} used for this request.`);
|
|
312
|
+
}
|
|
313
|
+
this.client.showUsageWarning();
|
|
314
|
+
console.log();
|
|
315
|
+
this.promptWithCheckpointNumber();
|
|
316
|
+
}
|
|
317
|
+
returnControlToUser() {
|
|
318
|
+
this.promptWithCheckpointNumber();
|
|
319
|
+
this.isReceivingResponse = false;
|
|
320
|
+
if (this.stopResponse) {
|
|
321
|
+
this.stopResponse();
|
|
322
|
+
}
|
|
323
|
+
spinner_1.Spinner.get().stop();
|
|
324
|
+
}
|
|
325
|
+
onWebSocketError() {
|
|
326
|
+
spinner_1.Spinner.get().stop();
|
|
327
|
+
this.isReceivingResponse = false;
|
|
328
|
+
if (this.stopResponse) {
|
|
329
|
+
this.stopResponse();
|
|
330
|
+
this.stopResponse = null;
|
|
331
|
+
}
|
|
332
|
+
console.error((0, picocolors_1.yellow)('\nCould not connect. Retrying...'));
|
|
333
|
+
}
|
|
334
|
+
onWebSocketReconnect() {
|
|
335
|
+
console.log((0, picocolors_1.green)('\nReconnected!'));
|
|
336
|
+
this.returnControlToUser();
|
|
337
|
+
}
|
|
338
|
+
handleUndo() {
|
|
339
|
+
// Get previous checkpoint number (not including undo command)
|
|
340
|
+
const checkpointId = checkpoints_1.checkpointManager.getLatestCheckpoint().id - 1;
|
|
341
|
+
if (checkpointId < 1) {
|
|
342
|
+
console.log((0, picocolors_1.red)('Nothing to undo.'));
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
this.restoreAgentStateAndFiles(checkpoints_1.checkpointManager.getCheckpoint(checkpointId));
|
|
346
|
+
console.log((0, picocolors_1.green)(`Restored to checkpoint #${checkpointId}.`));
|
|
347
|
+
this.promptWithCheckpointNumber();
|
|
348
|
+
}
|
|
349
|
+
handleKeyPress(str, key) {
|
|
350
|
+
if (key.name === 'escape') {
|
|
351
|
+
this.handleEscKey();
|
|
352
|
+
}
|
|
353
|
+
if (!this.isPasting &&
|
|
354
|
+
str === ' ' &&
|
|
355
|
+
'_refreshLine' in this.rl &&
|
|
356
|
+
'line' in this.rl &&
|
|
357
|
+
'cursor' in this.rl) {
|
|
358
|
+
const rlAny = this.rl;
|
|
359
|
+
const { cursor, line } = rlAny;
|
|
360
|
+
const prevTwoChars = cursor > 1 ? line.slice(cursor - 2, cursor) : '';
|
|
361
|
+
if (prevTwoChars === ' ') {
|
|
362
|
+
rlAny.line = line.slice(0, cursor - 2) + '\n\n' + line.slice(cursor);
|
|
363
|
+
rlAny._refreshLine();
|
|
480
364
|
}
|
|
481
365
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
366
|
+
this.detectPasting();
|
|
367
|
+
}
|
|
368
|
+
handleSigint() {
|
|
369
|
+
if ((0, terminal_1.isCommandRunning)()) {
|
|
370
|
+
(0, terminal_1.resetShell)((0, project_files_1.getProjectRoot)());
|
|
485
371
|
}
|
|
486
|
-
|
|
487
|
-
|
|
372
|
+
if ('line' in this.rl) {
|
|
373
|
+
;
|
|
374
|
+
this.rl.line = '';
|
|
488
375
|
}
|
|
489
|
-
|
|
490
|
-
|
|
376
|
+
if (this.isReceivingResponse) {
|
|
377
|
+
this.handleStopResponse();
|
|
491
378
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
379
|
+
else {
|
|
380
|
+
const now = Date.now();
|
|
381
|
+
if (now - this.lastSigintTime < 5000) {
|
|
382
|
+
this.handleExit();
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
this.lastSigintTime = now;
|
|
386
|
+
console.log('\nPress Ctrl-C again to exit');
|
|
387
|
+
this.promptWithCheckpointNumber();
|
|
495
388
|
}
|
|
496
|
-
console.log('Complete! Type "diff" to see the changes made.');
|
|
497
|
-
this.client.showUsageWarning();
|
|
498
389
|
}
|
|
499
|
-
console.log();
|
|
500
|
-
this.lastChanges = allChanges;
|
|
501
|
-
const assistantMessage = {
|
|
502
|
-
role: 'assistant',
|
|
503
|
-
content: response,
|
|
504
|
-
};
|
|
505
|
-
this.chatStorage.addMessage(this.chatStorage.getCurrentChat(), assistantMessage);
|
|
506
|
-
const updatedFiles = (0, project_files_1.getExistingFiles)(allFilesChanged);
|
|
507
|
-
this.chatStorage.addNewFileState(updatedFiles);
|
|
508
|
-
this.rl.prompt();
|
|
509
390
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
391
|
+
handleEscKey() {
|
|
392
|
+
if (this.isReceivingResponse) {
|
|
393
|
+
this.handleStopResponse();
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
handleStopResponse() {
|
|
397
|
+
console.log((0, picocolors_1.yellow)('\n[Response stopped by user]'));
|
|
398
|
+
this.isReceivingResponse = false;
|
|
399
|
+
if (this.stopResponse) {
|
|
400
|
+
this.stopResponse();
|
|
401
|
+
}
|
|
402
|
+
spinner_1.Spinner.get().stop();
|
|
403
|
+
}
|
|
404
|
+
async showEasterEgg() {
|
|
405
|
+
const text = 'codebuffy';
|
|
406
|
+
// Utility: clear the terminal screen
|
|
407
|
+
function clearScreen() {
|
|
408
|
+
process.stdout.write('\u001b[2J\u001b[0;0H');
|
|
409
|
+
}
|
|
410
|
+
const termWidth = process.stdout.columns;
|
|
411
|
+
const termHeight = process.stdout.rows;
|
|
412
|
+
const baselineWidth = 80;
|
|
413
|
+
const baselineHeight = 24;
|
|
414
|
+
const scaleFactor = Math.min(termWidth / baselineWidth, termHeight / baselineHeight);
|
|
415
|
+
// Utility: Generate a set of points tracing a "C" shape using an arc.
|
|
416
|
+
function generateCPath(cx, cy, r, steps) {
|
|
417
|
+
const points = [];
|
|
418
|
+
// A typical "C" opens to the right: from 45° to 315° (in radians)
|
|
419
|
+
const startAngle = Math.PI / 4;
|
|
420
|
+
const endAngle = (7 * Math.PI) / 4;
|
|
421
|
+
const angleStep = (endAngle - startAngle) / steps;
|
|
422
|
+
for (let i = 0; i <= steps; i++) {
|
|
423
|
+
const angle = startAngle + i * angleStep;
|
|
424
|
+
const x = Math.floor(cx + r * Math.cos(angle));
|
|
425
|
+
const y = Math.floor(cy + r * Math.sin(angle));
|
|
426
|
+
points.push({ x, y });
|
|
427
|
+
}
|
|
428
|
+
return points;
|
|
429
|
+
}
|
|
430
|
+
// Utility: Generate points along a quadratic Bézier curve.
|
|
431
|
+
function quadraticBezier(P0, P1, P2, steps) {
|
|
432
|
+
const points = [];
|
|
433
|
+
for (let i = 0; i <= steps; i++) {
|
|
434
|
+
const t = i / steps;
|
|
435
|
+
const x = Math.round((1 - t) ** 2 * P0.x + 2 * (1 - t) * t * P1.x + t ** 2 * P2.x);
|
|
436
|
+
const y = Math.round((1 - t) ** 2 * P0.y + 2 * (1 - t) * t * P1.y + t ** 2 * P2.y);
|
|
437
|
+
points.push({ x, y });
|
|
438
|
+
}
|
|
439
|
+
return points;
|
|
440
|
+
}
|
|
441
|
+
// Generate a vertical line from startY to endY at a given x.
|
|
442
|
+
function generateVerticalLine(x, startY, endY) {
|
|
443
|
+
const points = [];
|
|
444
|
+
const step = startY < endY ? 1 : -1;
|
|
445
|
+
for (let y = startY; y !== endY; y += step) {
|
|
446
|
+
points.push({ x, y });
|
|
447
|
+
}
|
|
448
|
+
points.push({ x, y: endY });
|
|
449
|
+
return points;
|
|
450
|
+
}
|
|
451
|
+
// Generate a path approximating a B shape using two quadratic Bézier curves
|
|
452
|
+
// for the rounded bubbles, and then closing the shape with a vertical spine.
|
|
453
|
+
function generateBPath(bX, bYTop, bYBottom, bWidth, bGap, stepsPerCurve) {
|
|
454
|
+
let points = [];
|
|
455
|
+
const middle = Math.floor((bYTop + bYBottom) / 2);
|
|
456
|
+
// Upper bubble: from top-left (spine) out then back to the spine at the middle.
|
|
457
|
+
const upperStart = { x: bX, y: bYTop };
|
|
458
|
+
const upperControl = {
|
|
459
|
+
x: bX + bWidth + bGap - 10,
|
|
460
|
+
y: Math.floor((bYTop + middle) / 2),
|
|
461
|
+
};
|
|
462
|
+
const upperEnd = { x: bX, y: middle };
|
|
463
|
+
const upperCurve = quadraticBezier(upperStart, upperControl, upperEnd, stepsPerCurve);
|
|
464
|
+
// Lower bubble: from the middle to the bottom.
|
|
465
|
+
const lowerStart = { x: bX, y: middle };
|
|
466
|
+
const lowerControl = {
|
|
467
|
+
x: bX + bWidth + bGap,
|
|
468
|
+
y: Math.floor((middle + bYBottom) / 2),
|
|
469
|
+
};
|
|
470
|
+
const lowerEnd = { x: bX, y: bYBottom };
|
|
471
|
+
const lowerCurve = quadraticBezier(lowerStart, lowerControl, lowerEnd, stepsPerCurve);
|
|
472
|
+
// Combine the curves.
|
|
473
|
+
points = points.concat(upperCurve, lowerCurve);
|
|
474
|
+
// Add a vertical line from the bottom of the B back up to the top.
|
|
475
|
+
const closingLine = generateVerticalLine(bX, bYBottom, bYTop);
|
|
476
|
+
points = points.concat(closingLine);
|
|
477
|
+
return points;
|
|
478
|
+
}
|
|
479
|
+
// Dynamically scale parameters for the shapes.
|
|
480
|
+
// Use Math.max to ensure values don't get too small.
|
|
481
|
+
const cCenterX = Math.floor(termWidth * 0.3);
|
|
482
|
+
const cCenterY = Math.floor(termHeight / 2);
|
|
483
|
+
const cRadius = Math.max(2, Math.floor(8 * scaleFactor));
|
|
484
|
+
const cSteps = Math.max(10, Math.floor(30 * scaleFactor));
|
|
485
|
+
const bX = Math.floor(termWidth * 0.55);
|
|
486
|
+
const bYTop = Math.floor(termHeight / 2 - 7 * scaleFactor);
|
|
487
|
+
const bYBottom = Math.floor(termHeight / 2 + 7 * scaleFactor);
|
|
488
|
+
const bWidth = Math.max(2, Math.floor(8 * scaleFactor));
|
|
489
|
+
const bGap = Math.max(1, Math.floor(35 * scaleFactor));
|
|
490
|
+
const bStepsPerCurve = Math.max(10, Math.floor(20 * scaleFactor));
|
|
491
|
+
// Generate the paths.
|
|
492
|
+
const fullPath = [
|
|
493
|
+
...generateCPath(cCenterX, cCenterY, cRadius, cSteps),
|
|
494
|
+
...generateBPath(bX, bYTop, bYBottom, bWidth, bGap, bStepsPerCurve),
|
|
495
|
+
];
|
|
496
|
+
// Array of picocolors functions for random colors.
|
|
497
|
+
const colors = [picocolors_1.red, picocolors_1.green, picocolors_1.yellow, picocolors_1.blue, picocolors_1.magenta, picocolors_1.cyan];
|
|
498
|
+
function getRandomColor() {
|
|
499
|
+
return colors[Math.floor(Math.random() * colors.length)];
|
|
500
|
+
}
|
|
501
|
+
// Animation state: index into the fullPath.
|
|
502
|
+
let index = 0;
|
|
503
|
+
let completedCycle = false;
|
|
504
|
+
// Main animation function
|
|
505
|
+
function animate() {
|
|
506
|
+
if (index >= fullPath.length) {
|
|
507
|
+
completedCycle = true;
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
const { x, y } = fullPath[index];
|
|
511
|
+
const cursorPosition = `\u001b[${y + 1};${x + 1}H`;
|
|
512
|
+
process.stdout.write(cursorPosition + getRandomColor()(text));
|
|
513
|
+
index++;
|
|
514
|
+
}
|
|
515
|
+
clearScreen();
|
|
516
|
+
const interval = setInterval(() => {
|
|
517
|
+
animate();
|
|
518
|
+
if (completedCycle) {
|
|
519
|
+
clearInterval(interval);
|
|
520
|
+
clearScreen();
|
|
521
|
+
this.returnControlToUser();
|
|
522
|
+
}
|
|
523
|
+
}, 100);
|
|
524
|
+
}
|
|
525
|
+
handleExit() {
|
|
526
|
+
spinner_1.Spinner.get().restoreCursor();
|
|
527
|
+
console.log('\n\n');
|
|
528
|
+
console.log(`${(0, string_1.pluralize)(this.client.sessionCreditsUsed, 'credit')} used this session.`);
|
|
529
|
+
if (this.client.limit && this.client.usage && this.client.nextQuotaReset) {
|
|
530
|
+
const daysUntilReset = Math.max(0, Math.floor((this.client.nextQuotaReset.getTime() - Date.now()) /
|
|
531
|
+
(1000 * 60 * 60 * 24)));
|
|
532
|
+
console.log(`${Math.max(0, this.client.limit - this.client.usage)} / ${this.client.limit} credits remaining. Renews in ${(0, string_1.pluralize)(daysUntilReset, 'day')}.`);
|
|
533
|
+
}
|
|
534
|
+
console.log((0, picocolors_1.green)('Codebuff out!'));
|
|
535
|
+
process.exit(0);
|
|
536
|
+
}
|
|
537
|
+
detectPasting() {
|
|
538
|
+
const currentTime = Date.now();
|
|
539
|
+
const timeDiff = currentTime - this.lastInputTime;
|
|
540
|
+
if (timeDiff < 10) {
|
|
541
|
+
this.consecutiveFastInputs++;
|
|
542
|
+
if (this.consecutiveFastInputs >= 2) {
|
|
543
|
+
this.isPasting = true;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
this.consecutiveFastInputs = 0;
|
|
548
|
+
if (this.isPasting) {
|
|
549
|
+
this.isPasting = false;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
this.lastInputTime = currentTime;
|
|
553
|
+
}
|
|
554
|
+
handleDiff() {
|
|
555
|
+
if (this.client.lastChanges.length === 0) {
|
|
556
|
+
console.log((0, picocolors_1.yellow)('No changes found in the last assistant response.'));
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
this.client.lastChanges.forEach((change) => {
|
|
560
|
+
console.log((0, picocolors_1.bold)(`___${change.path}___`));
|
|
561
|
+
const lines = change.content
|
|
562
|
+
.split('\n')
|
|
563
|
+
.map((line) => (change.type === 'file' ? '+' + line : line));
|
|
564
|
+
lines.forEach((line) => {
|
|
565
|
+
if (line.startsWith('+')) {
|
|
566
|
+
console.log((0, picocolors_1.green)(line));
|
|
567
|
+
}
|
|
568
|
+
else if (line.startsWith('-')) {
|
|
569
|
+
console.log((0, picocolors_1.red)(line));
|
|
570
|
+
}
|
|
571
|
+
else if (line.startsWith('@@')) {
|
|
572
|
+
console.log((0, picocolors_1.cyan)(line));
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
console.log(line);
|
|
576
|
+
}
|
|
577
|
+
});
|
|
517
578
|
});
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
579
|
+
}
|
|
580
|
+
// Checkpoint command handlers
|
|
581
|
+
handleCheckpoints() {
|
|
582
|
+
console.log(checkpoints_1.checkpointManager.getCheckpointsAsString());
|
|
583
|
+
this.promptWithCheckpointNumber();
|
|
584
|
+
}
|
|
585
|
+
handleCheckpointDetail(id) {
|
|
586
|
+
const checkpoint = checkpoints_1.checkpointManager.getCheckpoint(id);
|
|
587
|
+
if (!checkpoint) {
|
|
588
|
+
console.log((0, picocolors_1.red)(`Checkpoint #${id} not found.`));
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
console.log(checkpoints_1.checkpointManager.getCheckpointDetails(id));
|
|
592
|
+
}
|
|
593
|
+
this.promptWithCheckpointNumber();
|
|
594
|
+
}
|
|
595
|
+
async handleRestoreCheckpoint(id) {
|
|
596
|
+
const checkpoint = checkpoints_1.checkpointManager.getCheckpoint(id);
|
|
597
|
+
if (!checkpoint) {
|
|
598
|
+
console.log((0, picocolors_1.red)(`Checkpoint #${id} not found.`));
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
this.restoreAgentStateAndFiles(checkpoint);
|
|
602
|
+
console.log((0, picocolors_1.green)(`Restored to checkpoint #${id}.`));
|
|
603
|
+
// Insert the original user input that created this checkpoint
|
|
604
|
+
this.promptWithCheckpointNumber();
|
|
605
|
+
this.rl.write(checkpoint.userInput);
|
|
606
|
+
}
|
|
607
|
+
restoreAgentStateAndFiles(checkpoint) {
|
|
608
|
+
// Restore the agentState
|
|
609
|
+
this.client.agentState = JSON.parse(checkpoint.agentStateString);
|
|
610
|
+
// Restore file state
|
|
611
|
+
const toChange = {
|
|
612
|
+
...this.client.originalFileVersions,
|
|
613
|
+
...checkpoint.fileVersions,
|
|
614
|
+
};
|
|
615
|
+
for (const [filePath, fileContents] of Object.entries(toChange)) {
|
|
616
|
+
if (fileContents === null) {
|
|
617
|
+
// delete file
|
|
618
|
+
fs.unlinkSync(filePath);
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
fs.writeFileSync(filePath, fileContents);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
async handleClearCheckpoints() {
|
|
626
|
+
checkpoints_1.checkpointManager.clearCheckpoints();
|
|
627
|
+
this.promptWithCheckpointNumber();
|
|
523
628
|
}
|
|
524
629
|
}
|
|
525
630
|
exports.CLI = CLI;
|