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/client.js
CHANGED
|
@@ -27,32 +27,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.Client = void 0;
|
|
30
|
+
const child_process_1 = require("child_process");
|
|
31
|
+
const fs = __importStar(require("fs"));
|
|
32
|
+
const path_1 = __importDefault(require("path"));
|
|
30
33
|
const picocolors_1 = require("picocolors");
|
|
34
|
+
const ts_pattern_1 = require("ts-pattern");
|
|
35
|
+
const actions_1 = require("./common/actions");
|
|
36
|
+
const constants_1 = require("./common/constants");
|
|
37
|
+
const agent_state_1 = require("./common/types/agent-state");
|
|
31
38
|
const websocket_client_1 = require("./common/websockets/websocket-client");
|
|
32
|
-
const project_files_1 = require("./project-files");
|
|
33
39
|
const browser_runner_1 = require("./browser-runner");
|
|
34
|
-
const
|
|
40
|
+
const checkpoints_1 = require("./checkpoints");
|
|
41
|
+
const config_1 = require("./config");
|
|
35
42
|
const credentials_1 = require("./credentials");
|
|
36
|
-
const actions_1 = require("./common/actions");
|
|
37
|
-
const tool_handlers_1 = require("./tool-handlers");
|
|
38
|
-
const constants_1 = require("./common/constants");
|
|
39
|
-
const lodash_1 = require("lodash");
|
|
40
|
-
const path_1 = __importDefault(require("path"));
|
|
41
|
-
const fs = __importStar(require("fs"));
|
|
42
|
-
const ts_pattern_1 = require("ts-pattern");
|
|
43
43
|
const fingerprint_1 = require("./fingerprint");
|
|
44
|
-
const git_1 = require("./common/util/git");
|
|
45
44
|
const menu_1 = require("./menu");
|
|
46
|
-
const
|
|
45
|
+
const project_files_1 = require("./project-files");
|
|
46
|
+
const tool_handlers_1 = require("./tool-handlers");
|
|
47
|
+
const spinner_1 = require("./utils/spinner");
|
|
48
|
+
const process_xml_chunks_1 = require("./utils/process-xml-chunks");
|
|
47
49
|
class Client {
|
|
48
50
|
webSocket;
|
|
49
51
|
chatStorage;
|
|
50
|
-
currentUserInputId;
|
|
51
52
|
returnControlToUser;
|
|
52
53
|
fingerprintId;
|
|
53
54
|
costMode;
|
|
54
55
|
fileVersions = [];
|
|
55
56
|
fileContext;
|
|
57
|
+
lastChanges = [];
|
|
58
|
+
agentState;
|
|
59
|
+
originalFileVersions = {};
|
|
56
60
|
user;
|
|
57
61
|
lastWarnedPct = 0;
|
|
58
62
|
usage = 0;
|
|
@@ -61,7 +65,7 @@ class Client {
|
|
|
61
65
|
lastRequestCredits = 0;
|
|
62
66
|
sessionCreditsUsed = 0;
|
|
63
67
|
nextQuotaReset = null;
|
|
64
|
-
|
|
68
|
+
hadFileChanges = false;
|
|
65
69
|
git;
|
|
66
70
|
rl;
|
|
67
71
|
constructor(websocketUrl, chatStorage, onWebSocketError, onWebSocketReconnect, returnControlToUser, costMode, git, rl) {
|
|
@@ -73,16 +77,15 @@ class Client {
|
|
|
73
77
|
this.getFingerprintId();
|
|
74
78
|
this.returnControlToUser = returnControlToUser;
|
|
75
79
|
this.rl = rl;
|
|
76
|
-
this.browserRunner = new browser_runner_1.BrowserRunner();
|
|
77
80
|
}
|
|
78
81
|
async exit() {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
await this.browserRunner.shutdown();
|
|
82
|
+
if (browser_runner_1.activeBrowserRunner) {
|
|
83
|
+
browser_runner_1.activeBrowserRunner.shutdown();
|
|
82
84
|
}
|
|
83
85
|
process.exit(0);
|
|
84
86
|
}
|
|
85
|
-
|
|
87
|
+
initAgentState(projectFileContext) {
|
|
88
|
+
this.agentState = (0, agent_state_1.getInitialAgentState)(projectFileContext);
|
|
86
89
|
const { knowledgeFiles } = projectFileContext;
|
|
87
90
|
this.fileContext = projectFileContext;
|
|
88
91
|
this.fileVersions = [
|
|
@@ -114,7 +117,6 @@ class Client {
|
|
|
114
117
|
}
|
|
115
118
|
async handleReferralCode(referralCode) {
|
|
116
119
|
if (this.user) {
|
|
117
|
-
// User is logged in, so attempt to redeem referral code directly
|
|
118
120
|
try {
|
|
119
121
|
const redeemReferralResp = await fetch(`${process.env.NEXT_PUBLIC_APP_URL}/api/referrals`, {
|
|
120
122
|
method: 'POST',
|
|
@@ -151,29 +153,122 @@ class Client {
|
|
|
151
153
|
}
|
|
152
154
|
async logout() {
|
|
153
155
|
if (this.user) {
|
|
154
|
-
// If there was an existing user, clear their existing state
|
|
155
|
-
this.webSocket.sendAction({
|
|
156
|
-
type: 'clear-auth-token',
|
|
157
|
-
authToken: this.user.authToken,
|
|
158
|
-
userId: this.user.id,
|
|
159
|
-
fingerprintId: this.user.fingerprintId,
|
|
160
|
-
fingerprintHash: this.user.fingerprintHash,
|
|
161
|
-
});
|
|
162
|
-
// attempt to delete credentials file
|
|
163
156
|
try {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
157
|
+
const response = await fetch(`${config_1.backendUrl}/api/auth/cli/logout`, {
|
|
158
|
+
method: 'POST',
|
|
159
|
+
headers: { 'Content-Type': 'application/json' },
|
|
160
|
+
body: JSON.stringify({
|
|
161
|
+
authToken: this.user.authToken,
|
|
162
|
+
userId: this.user.id,
|
|
163
|
+
fingerprintId: this.user.fingerprintId,
|
|
164
|
+
fingerprintHash: this.user.fingerprintHash,
|
|
165
|
+
}),
|
|
166
|
+
});
|
|
167
|
+
if (!response.ok) {
|
|
168
|
+
const error = await response.text();
|
|
169
|
+
console.error((0, picocolors_1.red)('Failed to log out: ' + error));
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
fs.unlinkSync(credentials_1.CREDENTIALS_PATH);
|
|
173
|
+
console.log(`You (${this.user.name}) have been logged out.`);
|
|
174
|
+
this.user = undefined;
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
console.error('Error removing credentials file:', error);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.error('Error during logout:', error);
|
|
167
182
|
}
|
|
168
|
-
catch (error) { }
|
|
169
183
|
}
|
|
170
184
|
}
|
|
171
185
|
async login(referralCode) {
|
|
172
|
-
this.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
186
|
+
if (this.user) {
|
|
187
|
+
console.log(`You are currently logged in as ${this.user.name}. Please enter "logout" first if you want to login as a different user.`);
|
|
188
|
+
this.returnControlToUser();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
const response = await fetch(`${config_1.backendUrl}/api/auth/cli/code`, {
|
|
193
|
+
method: 'POST',
|
|
194
|
+
headers: { 'Content-Type': 'application/json' },
|
|
195
|
+
body: JSON.stringify({
|
|
196
|
+
fingerprintId: await this.getFingerprintId(),
|
|
197
|
+
referralCode,
|
|
198
|
+
}),
|
|
199
|
+
});
|
|
200
|
+
if (!response.ok) {
|
|
201
|
+
const error = await response.text();
|
|
202
|
+
console.error((0, picocolors_1.red)('Login code request failed: ' + error));
|
|
203
|
+
this.returnControlToUser();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const { loginUrl, fingerprintHash } = await response.json();
|
|
207
|
+
const responseToUser = [
|
|
208
|
+
'\n',
|
|
209
|
+
`Press ${(0, picocolors_1.blue)('ENTER')} to open your browser and finish logging in...`,
|
|
210
|
+
];
|
|
211
|
+
console.log(responseToUser.join('\n'));
|
|
212
|
+
let shouldRequestLogin = true;
|
|
213
|
+
this.rl.once('line', () => {
|
|
214
|
+
if (shouldRequestLogin) {
|
|
215
|
+
(0, child_process_1.spawn)(`open ${loginUrl}`, { shell: true });
|
|
216
|
+
console.log('Done. If nothing happened, copy and paste this link into your browser:');
|
|
217
|
+
console.log();
|
|
218
|
+
console.log((0, picocolors_1.blue)((0, picocolors_1.bold)((0, picocolors_1.underline)(loginUrl))));
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
const initialTime = Date.now();
|
|
222
|
+
const pollInterval = setInterval(async () => {
|
|
223
|
+
if (Date.now() - initialTime > 5 * 60 * 1000 && shouldRequestLogin) {
|
|
224
|
+
shouldRequestLogin = false;
|
|
225
|
+
console.log('Unable to login. Please try again by typing "login" in the terminal.');
|
|
226
|
+
this.returnControlToUser();
|
|
227
|
+
clearInterval(pollInterval);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (!shouldRequestLogin) {
|
|
231
|
+
clearInterval(pollInterval);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const statusResponse = await fetch(`${config_1.backendUrl}/api/auth/cli/status?fingerprintId=${await this.getFingerprintId()}&fingerprintHash=${fingerprintHash}`);
|
|
236
|
+
if (!statusResponse.ok) {
|
|
237
|
+
if (statusResponse.status !== 401) {
|
|
238
|
+
// Ignore 401s during polling
|
|
239
|
+
console.error('Error checking login status:', await statusResponse.text());
|
|
240
|
+
}
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const { user, message } = await statusResponse.json();
|
|
244
|
+
if (user) {
|
|
245
|
+
shouldRequestLogin = false;
|
|
246
|
+
this.user = user;
|
|
247
|
+
const credentialsPathDir = path_1.default.dirname(credentials_1.CREDENTIALS_PATH);
|
|
248
|
+
fs.mkdirSync(credentialsPathDir, { recursive: true });
|
|
249
|
+
fs.writeFileSync(credentials_1.CREDENTIALS_PATH, JSON.stringify({ default: user }));
|
|
250
|
+
const referralLink = `${process.env.NEXT_PUBLIC_APP_URL}/referrals`;
|
|
251
|
+
const responseToUser = [
|
|
252
|
+
'Authentication successful! 🎉',
|
|
253
|
+
(0, picocolors_1.bold)(`Hey there, ${user.name}.`),
|
|
254
|
+
`Refer new users and earn ${constants_1.CREDITS_REFERRAL_BONUS} credits per month for each of them: ${(0, picocolors_1.blueBright)(referralLink)}`,
|
|
255
|
+
];
|
|
256
|
+
console.log('\n' + responseToUser.join('\n'));
|
|
257
|
+
this.lastWarnedPct = 0;
|
|
258
|
+
(0, menu_1.displayGreeting)(this.costMode, null);
|
|
259
|
+
clearInterval(pollInterval);
|
|
260
|
+
this.returnControlToUser();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
console.error('Error checking login status:', error);
|
|
265
|
+
}
|
|
266
|
+
}, 5000);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
console.error('Error during login:', error);
|
|
270
|
+
this.returnControlToUser();
|
|
271
|
+
}
|
|
177
272
|
}
|
|
178
273
|
setUsage({ usage, limit, subscription_active, next_quota_reset, referralLink, session_credits_used, }) {
|
|
179
274
|
this.usage = usage;
|
|
@@ -192,59 +287,13 @@ class Client {
|
|
|
192
287
|
this.returnControlToUser();
|
|
193
288
|
return;
|
|
194
289
|
});
|
|
195
|
-
this.webSocket.subscribe('tool-call', async (a) => {
|
|
196
|
-
const { response, changes, changesAlreadyApplied, data, userInputId, addedFileVersions, resetFileVersions, } = a;
|
|
197
|
-
if (userInputId !== this.currentUserInputId) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (resetFileVersions) {
|
|
201
|
-
this.fileVersions = [addedFileVersions];
|
|
202
|
-
}
|
|
203
|
-
else {
|
|
204
|
-
this.fileVersions.push(addedFileVersions);
|
|
205
|
-
}
|
|
206
|
-
const filesChanged = (0, lodash_1.uniq)(changes.map((change) => change.filePath));
|
|
207
|
-
this.chatStorage.saveFilesChanged(filesChanged);
|
|
208
|
-
// Stage files about to be changed if flag was set
|
|
209
|
-
if (this.git === 'stage' && changes.length > 0) {
|
|
210
|
-
const didStage = (0, git_1.stagePatches)((0, project_files_1.getProjectRoot)(), changes);
|
|
211
|
-
if (didStage) {
|
|
212
|
-
console.log((0, picocolors_1.green)('\nStaged previous changes'));
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
(0, changes_1.applyChanges)((0, project_files_1.getProjectRoot)(), changes);
|
|
216
|
-
const { id, name, input } = data;
|
|
217
|
-
const currentChat = this.chatStorage.getCurrentChat();
|
|
218
|
-
const messages = currentChat.messages;
|
|
219
|
-
if (messages[messages.length - 1].role === 'assistant') {
|
|
220
|
-
// Probably the last response from the assistant was cancelled and added immediately.
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
const assistantMessage = {
|
|
224
|
-
role: 'assistant',
|
|
225
|
-
content: response,
|
|
226
|
-
};
|
|
227
|
-
this.chatStorage.addMessage(this.chatStorage.getCurrentChat(), assistantMessage);
|
|
228
|
-
const handler = tool_handlers_1.toolHandlers[name];
|
|
229
|
-
if (handler) {
|
|
230
|
-
const content = await handler(input, id);
|
|
231
|
-
const toolResultMessage = {
|
|
232
|
-
role: 'user',
|
|
233
|
-
content: `${constants_1.TOOL_RESULT_MARKER}\n${content}`,
|
|
234
|
-
};
|
|
235
|
-
this.chatStorage.addMessage(this.chatStorage.getCurrentChat(), toolResultMessage);
|
|
236
|
-
await this.sendUserInput([...changesAlreadyApplied, ...changes], userInputId);
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
console.error(`No handler found for tool: ${name}`);
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
290
|
this.webSocket.subscribe('read-files', (a) => {
|
|
243
|
-
const { filePaths } = a;
|
|
291
|
+
const { filePaths, requestId } = a;
|
|
244
292
|
const files = (0, project_files_1.getFiles)(filePaths);
|
|
245
293
|
this.webSocket.sendAction({
|
|
246
294
|
type: 'read-files-response',
|
|
247
295
|
files,
|
|
296
|
+
requestId,
|
|
248
297
|
});
|
|
249
298
|
});
|
|
250
299
|
this.webSocket.subscribe('npm-version-status', (action) => {
|
|
@@ -253,100 +302,38 @@ class Client {
|
|
|
253
302
|
console.warn((0, picocolors_1.yellow)(`\nThere's a new version of Codebuff! Please update to ensure proper functionality.\nUpdate now by running: npm install -g codebuff`));
|
|
254
303
|
}
|
|
255
304
|
});
|
|
256
|
-
let shouldRequestLogin = true;
|
|
257
|
-
this.webSocket.subscribe('login-code-response', async ({ loginUrl, fingerprintHash }) => {
|
|
258
|
-
const responseToUser = [
|
|
259
|
-
'\n',
|
|
260
|
-
'Press Enter to open the browser or visit:\n',
|
|
261
|
-
(0, picocolors_1.bold)((0, picocolors_1.underline)((0, picocolors_1.blueBright)(loginUrl))),
|
|
262
|
-
];
|
|
263
|
-
console.log(responseToUser.join('\n'));
|
|
264
|
-
this.rl.on('line', () => {
|
|
265
|
-
if (shouldRequestLogin) {
|
|
266
|
-
(0, child_process_1.spawn)(`open ${loginUrl}`, {
|
|
267
|
-
shell: true,
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
// call backend every few seconds to check if user has been created yet, using our fingerprintId, for up to 5 minutes
|
|
272
|
-
const initialTime = Date.now();
|
|
273
|
-
const handler = setInterval(async () => {
|
|
274
|
-
if (Date.now() - initialTime > 60 * 1000 && shouldRequestLogin) {
|
|
275
|
-
shouldRequestLogin = false;
|
|
276
|
-
console.log('Unable to login. Please try again by typing "login" in the terminal.');
|
|
277
|
-
clearInterval(handler);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
if (!shouldRequestLogin) {
|
|
281
|
-
clearInterval(handler);
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
this.webSocket.sendAction({
|
|
285
|
-
type: 'login-status-request',
|
|
286
|
-
fingerprintId: await this.getFingerprintId(),
|
|
287
|
-
fingerprintHash,
|
|
288
|
-
});
|
|
289
|
-
}, 5000);
|
|
290
|
-
});
|
|
291
|
-
this.webSocket.subscribe('auth-result', async (action) => {
|
|
292
|
-
shouldRequestLogin = false;
|
|
293
|
-
if (action.user) {
|
|
294
|
-
await this.logout(); // remove existing user, if it exists
|
|
295
|
-
this.user = action.user;
|
|
296
|
-
// Store in config file
|
|
297
|
-
const credentialsPathDir = path_1.default.dirname(credentials_1.CREDENTIALS_PATH);
|
|
298
|
-
fs.mkdirSync(credentialsPathDir, { recursive: true });
|
|
299
|
-
fs.writeFileSync(credentials_1.CREDENTIALS_PATH, JSON.stringify({ default: action.user }));
|
|
300
|
-
const referralLink = `${process.env.NEXT_PUBLIC_APP_URL}/referrals`;
|
|
301
|
-
const responseToUser = [
|
|
302
|
-
'Authentication successful! 🎉',
|
|
303
|
-
(0, picocolors_1.bold)(`Hey there, ${action.user.name}.`),
|
|
304
|
-
`Refer new users and earn ${constants_1.CREDITS_REFERRAL_BONUS} credits per month for each of them: ${(0, picocolors_1.blueBright)(referralLink)}`,
|
|
305
|
-
];
|
|
306
|
-
console.log('\n' + responseToUser.join('\n'));
|
|
307
|
-
this.lastWarnedPct = 0;
|
|
308
|
-
(0, menu_1.displayGreeting)(this.costMode, null);
|
|
309
|
-
this.returnControlToUser();
|
|
310
|
-
// this.getUsage()
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
console.warn(`Authentication failed: ${action.message}. Please try again in a few minutes or contact support at ${process.env.NEXT_PUBLIC_SUPPORT_EMAIL}.`);
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
305
|
this.webSocket.subscribe('usage-response', (action) => {
|
|
306
|
+
this.returnControlToUser();
|
|
317
307
|
const parsedAction = actions_1.UsageReponseSchema.safeParse(action);
|
|
318
308
|
if (!parsedAction.success)
|
|
319
309
|
return;
|
|
320
310
|
const a = parsedAction.data;
|
|
321
|
-
console.log(
|
|
311
|
+
console.log();
|
|
312
|
+
console.log((0, picocolors_1.green)((0, picocolors_1.underline)(`Codebuff usage:`)), `${a.usage} / ${a.limit} credits`);
|
|
322
313
|
this.setUsage(a);
|
|
323
|
-
this.
|
|
314
|
+
this.showUsageWarning(a.referralLink);
|
|
324
315
|
});
|
|
325
316
|
}
|
|
326
317
|
showUsageWarning(referralLink) {
|
|
327
318
|
const errorCopy = [
|
|
328
319
|
this.user
|
|
329
|
-
? (0, picocolors_1.
|
|
320
|
+
? `Visit ${(0, picocolors_1.blue)((0, picocolors_1.bold)(process.env.NEXT_PUBLIC_APP_URL + '/pricing'))} to upgrade – or refer a new user and earn ${constants_1.CREDITS_REFERRAL_BONUS} credits per month: ${(0, picocolors_1.blue)((0, picocolors_1.bold)(referralLink))}`
|
|
330
321
|
: (0, picocolors_1.green)('Type "login" below to sign up and get more credits!'),
|
|
331
|
-
referralLink
|
|
332
|
-
? (0, picocolors_1.green)(`Refer friends by sharing this link and you'll ${(0, picocolors_1.bold)(`each earn ${constants_1.CREDITS_REFERRAL_BONUS} credits per month`)}: ${referralLink}`)
|
|
333
|
-
: '',
|
|
334
322
|
].join('\n');
|
|
335
323
|
const pct = (0, ts_pattern_1.match)(Math.floor((this.usage / this.limit) * 100))
|
|
336
324
|
.with(ts_pattern_1.P.number.gte(100), () => 100)
|
|
337
325
|
.with(ts_pattern_1.P.number.gte(75), () => 75)
|
|
338
326
|
.otherwise(() => 0);
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (this.subscription_active) {
|
|
327
|
+
if (pct >= 100) {
|
|
328
|
+
this.lastWarnedPct = 100;
|
|
329
|
+
if (!this.subscription_active) {
|
|
330
|
+
console.error([(0, picocolors_1.red)('You have reached your monthly usage limit.'), errorCopy].join('\n'));
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (this.subscription_active && this.lastWarnedPct < 100) {
|
|
342
334
|
console.warn((0, picocolors_1.yellow)(`You have exceeded your monthly quota, but feel free to keep using Codebuff! We'll continue to charge you for the overage until your next billing cycle. See ${process.env.NEXT_PUBLIC_APP_URL}/usage for more details.`));
|
|
343
|
-
this.lastWarnedPct = 100;
|
|
344
335
|
return;
|
|
345
336
|
}
|
|
346
|
-
console.error([(0, picocolors_1.red)('You have reached your monthly usage limit.'), errorCopy].join('\n'));
|
|
347
|
-
this.returnControlToUser();
|
|
348
|
-
this.lastWarnedPct = 100;
|
|
349
|
-
return;
|
|
350
337
|
}
|
|
351
338
|
if (pct > 0 && pct > this.lastWarnedPct) {
|
|
352
339
|
console.warn([
|
|
@@ -371,47 +358,69 @@ class Client {
|
|
|
371
358
|
});
|
|
372
359
|
});
|
|
373
360
|
}
|
|
374
|
-
async sendUserInput(
|
|
375
|
-
this.
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
const
|
|
380
|
-
|
|
361
|
+
async sendUserInput(prompt) {
|
|
362
|
+
if (!this.agentState) {
|
|
363
|
+
throw new Error('Agent state not initialized');
|
|
364
|
+
}
|
|
365
|
+
const userInputId = `mc-input-` + Math.random().toString(36).substring(2, 15);
|
|
366
|
+
const { responsePromise, stopResponse } = this.subscribeToResponse((chunk) => {
|
|
367
|
+
spinner_1.Spinner.get().stop();
|
|
368
|
+
process.stdout.write(chunk);
|
|
369
|
+
}, userInputId, () => {
|
|
370
|
+
spinner_1.Spinner.get().stop();
|
|
371
|
+
process.stdout.write((0, picocolors_1.green)((0, picocolors_1.underline)('\nCodebuff') + ':') + ' ');
|
|
372
|
+
}, prompt);
|
|
373
|
+
spinner_1.Spinner.get().start();
|
|
381
374
|
this.webSocket.sendAction({
|
|
382
|
-
type: '
|
|
383
|
-
userInputId,
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
375
|
+
type: 'prompt',
|
|
376
|
+
promptId: userInputId,
|
|
377
|
+
prompt,
|
|
378
|
+
agentState: this.agentState,
|
|
379
|
+
toolResults: [],
|
|
387
380
|
fingerprintId: await this.getFingerprintId(),
|
|
388
381
|
authToken: this.user?.authToken,
|
|
389
382
|
costMode: this.costMode,
|
|
390
383
|
});
|
|
384
|
+
return {
|
|
385
|
+
responsePromise,
|
|
386
|
+
stopResponse,
|
|
387
|
+
};
|
|
391
388
|
}
|
|
392
|
-
subscribeToResponse(onChunk, userInputId, onStreamStart) {
|
|
389
|
+
subscribeToResponse(onChunk, userInputId, onStreamStart, prompt) {
|
|
393
390
|
let responseBuffer = '';
|
|
391
|
+
let streamStarted = false;
|
|
394
392
|
let resolveResponse;
|
|
395
393
|
let rejectResponse;
|
|
396
394
|
let unsubscribeChunks;
|
|
397
395
|
let unsubscribeComplete;
|
|
398
|
-
|
|
396
|
+
// Initialize XML processor with default handlers
|
|
397
|
+
const xmlProcessor = new process_xml_chunks_1.XmlStreamProcessor(process_xml_chunks_1.defaultTagHandlers);
|
|
399
398
|
const responsePromise = new Promise((resolve, reject) => {
|
|
400
399
|
resolveResponse = resolve;
|
|
401
400
|
rejectResponse = reject;
|
|
402
401
|
});
|
|
403
402
|
const stopResponse = () => {
|
|
404
|
-
this.currentUserInputId = undefined;
|
|
405
403
|
unsubscribeChunks();
|
|
406
404
|
unsubscribeComplete();
|
|
405
|
+
// Update the agent state with your prompt and partial response.
|
|
406
|
+
const { messageHistory } = this.agentState;
|
|
407
|
+
this.agentState = {
|
|
408
|
+
...this.agentState,
|
|
409
|
+
messageHistory: [
|
|
410
|
+
...messageHistory,
|
|
411
|
+
{ role: 'user', content: prompt },
|
|
412
|
+
{
|
|
413
|
+
role: 'assistant',
|
|
414
|
+
content: responseBuffer + '[RESPONSE_CANCELED_BY_USER]',
|
|
415
|
+
},
|
|
416
|
+
],
|
|
417
|
+
};
|
|
407
418
|
resolveResponse({
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
resetFileVersions: false,
|
|
414
|
-
type: 'response-complete',
|
|
419
|
+
type: 'prompt-response',
|
|
420
|
+
promptId: userInputId,
|
|
421
|
+
agentState: this.agentState,
|
|
422
|
+
toolCalls: [],
|
|
423
|
+
toolResults: [],
|
|
415
424
|
wasStoppedByUser: true,
|
|
416
425
|
});
|
|
417
426
|
};
|
|
@@ -419,28 +428,74 @@ class Client {
|
|
|
419
428
|
if (a.userInputId !== userInputId)
|
|
420
429
|
return;
|
|
421
430
|
const { chunk } = a;
|
|
422
|
-
|
|
423
|
-
streamStarted = true;
|
|
424
|
-
onStreamStart();
|
|
425
|
-
}
|
|
431
|
+
// Add the chunk to the response buffer
|
|
426
432
|
responseBuffer += chunk;
|
|
427
|
-
|
|
433
|
+
// Process the entire responseBuffer through our XML processor
|
|
434
|
+
const output = chunk; // TODO: figure out xml parsing: xmlProcessor.process(chunk)
|
|
435
|
+
if (output && output.trim()) {
|
|
436
|
+
if (!streamStarted && chunk.trim()) {
|
|
437
|
+
streamStarted = true;
|
|
438
|
+
onStreamStart();
|
|
439
|
+
}
|
|
440
|
+
onChunk(output);
|
|
441
|
+
}
|
|
428
442
|
});
|
|
429
|
-
unsubscribeComplete = this.webSocket.subscribe('response
|
|
430
|
-
const parsedAction = actions_1.
|
|
431
|
-
if (!parsedAction.success || action.
|
|
443
|
+
unsubscribeComplete = this.webSocket.subscribe('prompt-response', async (action) => {
|
|
444
|
+
const parsedAction = actions_1.PromptResponseSchema.safeParse(action);
|
|
445
|
+
if (!parsedAction.success || action.promptId !== userInputId)
|
|
432
446
|
return;
|
|
433
447
|
const a = parsedAction.data;
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
448
|
+
this.agentState = a.agentState;
|
|
449
|
+
spinner_1.Spinner.get().stop();
|
|
450
|
+
let isComplete = false;
|
|
451
|
+
const toolResults = [...a.toolResults];
|
|
452
|
+
for (const toolCall of a.toolCalls) {
|
|
453
|
+
if (toolCall.name === 'end_turn') {
|
|
454
|
+
isComplete = true;
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
if (toolCall.name === 'write_file') {
|
|
458
|
+
// Save the file contents before writing
|
|
459
|
+
const { path: filePath } = toolCall.parameters;
|
|
460
|
+
if (filePath !== undefined) {
|
|
461
|
+
const fullPath = path_1.default.join((0, project_files_1.getProjectRoot)(), filePath);
|
|
462
|
+
if (!(fullPath in this.originalFileVersions)) {
|
|
463
|
+
this.originalFileVersions[fullPath] = fs.existsSync(fullPath)
|
|
464
|
+
? fs.readFileSync(fullPath, 'utf8')
|
|
465
|
+
: null;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
this.lastChanges.push(actions_1.FileChangeSchema.parse(toolCall.parameters));
|
|
469
|
+
this.hadFileChanges = true;
|
|
470
|
+
}
|
|
471
|
+
const toolResult = await (0, tool_handlers_1.handleToolCall)(toolCall, (0, project_files_1.getProjectRoot)());
|
|
472
|
+
toolResults.push(toolResult);
|
|
473
|
+
}
|
|
474
|
+
if (!isComplete) {
|
|
475
|
+
spinner_1.Spinner.get().start();
|
|
476
|
+
// Continue the prompt with the tool results.
|
|
477
|
+
this.webSocket.sendAction({
|
|
478
|
+
type: 'prompt',
|
|
479
|
+
promptId: userInputId,
|
|
480
|
+
prompt: undefined,
|
|
481
|
+
agentState: this.agentState,
|
|
482
|
+
toolResults,
|
|
483
|
+
fingerprintId: await this.getFingerprintId(),
|
|
484
|
+
authToken: this.user?.authToken,
|
|
485
|
+
costMode: this.costMode,
|
|
486
|
+
});
|
|
487
|
+
return;
|
|
438
488
|
}
|
|
439
|
-
|
|
440
|
-
|
|
489
|
+
if (this.hadFileChanges) {
|
|
490
|
+
const latestCheckpointId = checkpoints_1.checkpointManager.getLatestCheckpoint().id;
|
|
491
|
+
console.log(`\nComplete! Type "diff" to review changes or "restore ${latestCheckpointId}" to revert.`);
|
|
492
|
+
this.hadFileChanges = false;
|
|
441
493
|
}
|
|
494
|
+
// Reset the XML processor state when the stream is complete
|
|
495
|
+
xmlProcessor.reset();
|
|
496
|
+
unsubscribeChunks();
|
|
497
|
+
unsubscribeComplete();
|
|
442
498
|
resolveResponse({ ...a, wasStoppedByUser: false });
|
|
443
|
-
this.currentUserInputId = undefined;
|
|
444
499
|
if (!a.usage ||
|
|
445
500
|
!a.next_quota_reset ||
|
|
446
501
|
a.subscription_active === undefined ||
|
|
@@ -454,7 +509,7 @@ class Client {
|
|
|
454
509
|
next_quota_reset: a.next_quota_reset,
|
|
455
510
|
session_credits_used: a.session_credits_used ?? 0,
|
|
456
511
|
});
|
|
457
|
-
|
|
512
|
+
this.showUsageWarning(a.referralLink);
|
|
458
513
|
if (this.limit !== a.limit) {
|
|
459
514
|
this.lastWarnedPct = 0;
|
|
460
515
|
}
|
|
@@ -473,7 +528,6 @@ class Client {
|
|
|
473
528
|
}
|
|
474
529
|
async warmContextCache() {
|
|
475
530
|
const fileContext = await (0, project_files_1.getProjectFileContext)((0, project_files_1.getProjectRoot)(), {}, this.fileVersions);
|
|
476
|
-
// Don't wait for response anymore.
|
|
477
531
|
this.webSocket.subscribe('init-response', (a) => {
|
|
478
532
|
const parsedAction = actions_1.InitResponseSchema.safeParse(a);
|
|
479
533
|
if (!parsedAction.success)
|