codebuff 1.0.245 → 1.0.246
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/package.json +1 -1
- package/dist/background-process-manager.d.ts +0 -50
- package/dist/background-process-manager.js +0 -359
- package/dist/background-process-manager.js.map +0 -1
- package/dist/browser-runner.d.ts +0 -35
- package/dist/browser-runner.js +0 -680
- package/dist/browser-runner.js.map +0 -1
- package/dist/chat-storage.d.ts +0 -2
- package/dist/chat-storage.js +0 -93
- package/dist/chat-storage.js.map +0 -1
- package/dist/checkpoints/checkpoint-manager.d.ts +0 -94
- package/dist/checkpoints/checkpoint-manager.js +0 -280
- package/dist/checkpoints/checkpoint-manager.js.map +0 -1
- package/dist/checkpoints/file-manager.d.ts +0 -72
- package/dist/checkpoints/file-manager.js +0 -311
- package/dist/checkpoints/file-manager.js.map +0 -1
- package/dist/cli-handlers/api-key.d.ts +0 -25
- package/dist/cli-handlers/api-key.js +0 -66
- package/dist/cli-handlers/api-key.js.map +0 -1
- package/dist/cli-handlers/checkpoint.d.ts +0 -18
- package/dist/cli-handlers/checkpoint.js +0 -195
- package/dist/cli-handlers/checkpoint.js.map +0 -1
- package/dist/cli-handlers/diff.d.ts +0 -2
- package/dist/cli-handlers/diff.js +0 -31
- package/dist/cli-handlers/diff.js.map +0 -1
- package/dist/cli-handlers/easter-egg.d.ts +0 -1
- package/dist/cli-handlers/easter-egg.js +0 -126
- package/dist/cli-handlers/easter-egg.js.map +0 -1
- package/dist/cli-handlers/inititalization-flow.d.ts +0 -1
- package/dist/cli-handlers/inititalization-flow.js +0 -24
- package/dist/cli-handlers/inititalization-flow.js.map +0 -1
- package/dist/cli.d.ts +0 -44
- package/dist/cli.js +0 -478
- package/dist/cli.js.map +0 -1
- package/dist/client.d.ts +0 -157
- package/dist/client.js +0 -836
- package/dist/client.js.map +0 -1
- package/dist/config.d.ts +0 -4
- package/dist/config.js +0 -12
- package/dist/config.js.map +0 -1
- package/dist/create-template-project.d.ts +0 -1
- package/dist/create-template-project.js +0 -107
- package/dist/create-template-project.js.map +0 -1
- package/dist/credentials.d.ts +0 -4
- package/dist/credentials.js +0 -38
- package/dist/credentials.js.map +0 -1
- package/dist/dev-process-manager.d.ts +0 -10
- package/dist/dev-process-manager.js +0 -54
- package/dist/dev-process-manager.js.map +0 -1
- package/dist/fingerprint.d.ts +0 -1
- package/dist/fingerprint.js +0 -48
- package/dist/fingerprint.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -117
- package/dist/index.js.map +0 -1
- package/dist/menu.d.ts +0 -3
- package/dist/menu.js +0 -126
- package/dist/menu.js.map +0 -1
- package/dist/project-files.d.ts +0 -114
- package/dist/project-files.js +0 -513
- package/dist/project-files.js.map +0 -1
- package/dist/startup-process-handler.d.ts +0 -2
- package/dist/startup-process-handler.js +0 -21
- package/dist/startup-process-handler.js.map +0 -1
- package/dist/tool-handlers.d.ts +0 -28
- package/dist/tool-handlers.js +0 -240
- package/dist/tool-handlers.js.map +0 -1
- package/dist/types.d.ts +0 -15
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/update-codebuff.d.ts +0 -1
- package/dist/update-codebuff.js +0 -160
- package/dist/update-codebuff.js.map +0 -1
- package/dist/utils/__tests__/background-process-manager.test.d.ts +0 -1
- package/dist/utils/__tests__/background-process-manager.test.js +0 -289
- package/dist/utils/__tests__/background-process-manager.test.js.map +0 -1
- package/dist/utils/__tests__/tool-renderers.test.d.ts +0 -1
- package/dist/utils/__tests__/tool-renderers.test.js +0 -51
- package/dist/utils/__tests__/tool-renderers.test.js.map +0 -1
- package/dist/utils/__tests__/xml-stream-parser.test.d.ts +0 -1
- package/dist/utils/__tests__/xml-stream-parser.test.js +0 -229
- package/dist/utils/__tests__/xml-stream-parser.test.js.map +0 -1
- package/dist/utils/analytics.d.ts +0 -6
- package/dist/utils/analytics.js +0 -59
- package/dist/utils/analytics.js.map +0 -1
- package/dist/utils/detect-shell.d.ts +0 -1
- package/dist/utils/detect-shell.js +0 -60
- package/dist/utils/detect-shell.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -21
- package/dist/utils/logger.js +0 -105
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/spinner.d.ts +0 -11
- package/dist/utils/spinner.js +0 -87
- package/dist/utils/spinner.js.map +0 -1
- package/dist/utils/system-info.d.ts +0 -8
- package/dist/utils/system-info.js +0 -22
- package/dist/utils/system-info.js.map +0 -1
- package/dist/utils/terminal.d.ts +0 -41
- package/dist/utils/terminal.js +0 -467
- package/dist/utils/terminal.js.map +0 -1
- package/dist/utils/tool-renderers.d.ts +0 -16
- package/dist/utils/tool-renderers.js +0 -145
- package/dist/utils/tool-renderers.js.map +0 -1
- package/dist/utils/xml-stream-parser.d.ts +0 -9
- package/dist/utils/xml-stream-parser.js +0 -128
- package/dist/utils/xml-stream-parser.js.map +0 -1
- package/dist/web-scraper.d.ts +0 -3
- package/dist/web-scraper.js +0 -57
- package/dist/web-scraper.js.map +0 -1
- package/dist/workers/checkpoint-worker.d.ts +0 -1
- package/dist/workers/checkpoint-worker.js +0 -48
- package/dist/workers/checkpoint-worker.js.map +0 -1
- package/dist/workers/project-context.d.ts +0 -1
- package/dist/workers/project-context.js +0 -17
- package/dist/workers/project-context.js.map +0 -1
package/dist/client.js
DELETED
|
@@ -1,836 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.Client = void 0;
|
|
7
|
-
const child_process_1 = require("child_process");
|
|
8
|
-
const fs_1 = require("fs");
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const actions_1 = require("./common/actions");
|
|
11
|
-
const constants_1 = require("./common/api-keys/constants");
|
|
12
|
-
const constants_2 = require("./common/constants");
|
|
13
|
-
const analytics_events_1 = require("./common/constants/analytics-events");
|
|
14
|
-
const constants_3 = require("./common/json-config/constants");
|
|
15
|
-
const agent_state_1 = require("./common/types/agent-state");
|
|
16
|
-
const array_1 = require("./common/util/array");
|
|
17
|
-
const string_1 = require("./common/util/string");
|
|
18
|
-
const websocket_client_1 = require("./common/websockets/websocket-client");
|
|
19
|
-
const picocolors_1 = require("picocolors");
|
|
20
|
-
const ts_pattern_1 = require("ts-pattern");
|
|
21
|
-
const zod_1 = require("zod");
|
|
22
|
-
const background_process_manager_1 = require("./background-process-manager");
|
|
23
|
-
const browser_runner_1 = require("./browser-runner");
|
|
24
|
-
const chat_storage_1 = require("./chat-storage");
|
|
25
|
-
const checkpoint_manager_1 = require("./checkpoints/checkpoint-manager");
|
|
26
|
-
const config_1 = require("./config");
|
|
27
|
-
const credentials_1 = require("./credentials");
|
|
28
|
-
const fingerprint_1 = require("./fingerprint");
|
|
29
|
-
const menu_1 = require("./menu");
|
|
30
|
-
const project_files_1 = require("./project-files");
|
|
31
|
-
const tool_handlers_1 = require("./tool-handlers");
|
|
32
|
-
const analytics_1 = require("./utils/analytics");
|
|
33
|
-
const logger_1 = require("./utils/logger");
|
|
34
|
-
const spinner_1 = require("./utils/spinner");
|
|
35
|
-
const tool_renderers_1 = require("./utils/tool-renderers");
|
|
36
|
-
const xml_stream_parser_1 = require("./utils/xml-stream-parser");
|
|
37
|
-
const web_scraper_1 = require("./web-scraper");
|
|
38
|
-
const LOW_BALANCE_THRESHOLD = 100;
|
|
39
|
-
const WARNING_CONFIG = {
|
|
40
|
-
[constants_2.UserState.LOGGED_OUT]: {
|
|
41
|
-
message: () => `Type "login" to unlock full access and get free credits!`,
|
|
42
|
-
threshold: 100,
|
|
43
|
-
},
|
|
44
|
-
[constants_2.UserState.DEPLETED]: {
|
|
45
|
-
message: () => [
|
|
46
|
-
(0, picocolors_1.red)(`\n❌ You have used all your credits.`),
|
|
47
|
-
`Visit ${(0, picocolors_1.bold)((0, picocolors_1.blue)(config_1.websiteUrl + '/usage'))} to add more credits and continue coding.`,
|
|
48
|
-
].join('\n'),
|
|
49
|
-
threshold: 100,
|
|
50
|
-
},
|
|
51
|
-
[constants_2.UserState.CRITICAL]: {
|
|
52
|
-
message: (credits) => [
|
|
53
|
-
(0, picocolors_1.yellow)(`\n🪫 Only ${(0, picocolors_1.bold)((0, string_1.pluralize)(credits, 'credit'))} remaining!`),
|
|
54
|
-
(0, picocolors_1.yellow)(`Visit ${(0, picocolors_1.bold)(config_1.websiteUrl + '/usage')} to add more credits.`),
|
|
55
|
-
].join('\n'),
|
|
56
|
-
threshold: 85,
|
|
57
|
-
},
|
|
58
|
-
[constants_2.UserState.ATTENTION_NEEDED]: {
|
|
59
|
-
message: (credits) => [
|
|
60
|
-
(0, picocolors_1.yellow)(`\n⚠️ ${(0, picocolors_1.bold)((0, string_1.pluralize)(credits, 'credit'))} remaining. Consider topping up soon.`),
|
|
61
|
-
].join('\n'),
|
|
62
|
-
threshold: 75,
|
|
63
|
-
},
|
|
64
|
-
[constants_2.UserState.GOOD_STANDING]: {
|
|
65
|
-
message: () => '',
|
|
66
|
-
threshold: 0,
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
class Client {
|
|
70
|
-
webSocket;
|
|
71
|
-
freshPrompt;
|
|
72
|
-
reconnectWhenNextIdle;
|
|
73
|
-
fingerprintId;
|
|
74
|
-
costMode;
|
|
75
|
-
hadFileChanges = false;
|
|
76
|
-
git;
|
|
77
|
-
rl;
|
|
78
|
-
responseComplete = false;
|
|
79
|
-
responseBuffer = '';
|
|
80
|
-
oneTimeFlags = Object.fromEntries(constants_2.ONE_TIME_LABELS.map((tag) => [tag, false]));
|
|
81
|
-
usageData = {
|
|
82
|
-
usage: 0,
|
|
83
|
-
remainingBalance: null,
|
|
84
|
-
balanceBreakdown: undefined,
|
|
85
|
-
next_quota_reset: null,
|
|
86
|
-
};
|
|
87
|
-
pendingTopUpMessageAmount = 0;
|
|
88
|
-
fileContext;
|
|
89
|
-
lastChanges = [];
|
|
90
|
-
agentState;
|
|
91
|
-
originalFileVersions = {};
|
|
92
|
-
creditsByPromptId = {};
|
|
93
|
-
user;
|
|
94
|
-
lastWarnedPct = 0;
|
|
95
|
-
storedApiKeyTypes = [];
|
|
96
|
-
lastToolResults = [];
|
|
97
|
-
model;
|
|
98
|
-
constructor({ websocketUrl, onWebSocketError, onWebSocketReconnect, freshPrompt, reconnectWhenNextIdle, costMode, git, rl, model, }) {
|
|
99
|
-
this.costMode = costMode;
|
|
100
|
-
this.model = model;
|
|
101
|
-
this.git = git;
|
|
102
|
-
this.webSocket = new websocket_client_1.APIRealtimeClient(websocketUrl, onWebSocketError, onWebSocketReconnect);
|
|
103
|
-
this.user = this.getUser();
|
|
104
|
-
this.initFingerprintId();
|
|
105
|
-
this.freshPrompt = freshPrompt;
|
|
106
|
-
this.reconnectWhenNextIdle = reconnectWhenNextIdle;
|
|
107
|
-
this.rl = rl;
|
|
108
|
-
logger_1.logger.info({ eventId: analytics_events_1.AnalyticsEvent.APP_LAUNCHED }, 'App launched');
|
|
109
|
-
}
|
|
110
|
-
async exit() {
|
|
111
|
-
if (browser_runner_1.activeBrowserRunner) {
|
|
112
|
-
browser_runner_1.activeBrowserRunner.shutdown();
|
|
113
|
-
}
|
|
114
|
-
process.exit(0);
|
|
115
|
-
}
|
|
116
|
-
initAgentState(projectFileContext) {
|
|
117
|
-
this.agentState = (0, agent_state_1.getInitialAgentState)(projectFileContext);
|
|
118
|
-
this.fileContext = projectFileContext;
|
|
119
|
-
}
|
|
120
|
-
initFingerprintId() {
|
|
121
|
-
if (!this.fingerprintId) {
|
|
122
|
-
this.fingerprintId = this.user?.fingerprintId ?? (0, fingerprint_1.calculateFingerprint)();
|
|
123
|
-
}
|
|
124
|
-
return this.fingerprintId;
|
|
125
|
-
}
|
|
126
|
-
getUser() {
|
|
127
|
-
if (!(0, fs_1.existsSync)(credentials_1.CREDENTIALS_PATH)) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
const credentialsFile = (0, fs_1.readFileSync)(credentials_1.CREDENTIALS_PATH, 'utf8');
|
|
131
|
-
const user = (0, credentials_1.userFromJson)(credentialsFile);
|
|
132
|
-
if (user) {
|
|
133
|
-
(0, analytics_1.identifyUser)(user.id, {
|
|
134
|
-
email: user.email,
|
|
135
|
-
name: user.name,
|
|
136
|
-
fingerprintId: this.fingerprintId,
|
|
137
|
-
});
|
|
138
|
-
logger_1.loggerContext.userId = user.id;
|
|
139
|
-
logger_1.loggerContext.userEmail = user.email;
|
|
140
|
-
logger_1.loggerContext.fingerprintId = user.fingerprintId;
|
|
141
|
-
}
|
|
142
|
-
return user;
|
|
143
|
-
}
|
|
144
|
-
async connect() {
|
|
145
|
-
await this.webSocket.connect();
|
|
146
|
-
this.setupSubscriptions();
|
|
147
|
-
await this.fetchStoredApiKeyTypes();
|
|
148
|
-
}
|
|
149
|
-
async fetchStoredApiKeyTypes() {
|
|
150
|
-
if (!this.user || !this.user.authToken) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
// const TIMEOUT_MS = 5_000
|
|
154
|
-
// try {
|
|
155
|
-
// const timeoutPromise = new Promise<Response>((_, reject) => {
|
|
156
|
-
// setTimeout(() => reject(new Error('Request timed out')), TIMEOUT_MS)
|
|
157
|
-
// })
|
|
158
|
-
// const fetchPromise = fetch(
|
|
159
|
-
// `${process.env.NEXT_PUBLIC_APP_URL}/api/api-keys`,
|
|
160
|
-
// {
|
|
161
|
-
// method: 'GET',
|
|
162
|
-
// headers: {
|
|
163
|
-
// 'Content-Type': 'application/json',
|
|
164
|
-
// Cookie: `next-auth.session-token=${this.user.authToken}`,
|
|
165
|
-
// Authorization: `Bearer ${this.user.authToken}`,
|
|
166
|
-
// },
|
|
167
|
-
// }
|
|
168
|
-
// )
|
|
169
|
-
// const response = await Promise.race([fetchPromise, timeoutPromise])
|
|
170
|
-
// if (response.ok) {
|
|
171
|
-
// const { keyTypes } = await response.json()
|
|
172
|
-
// this.storedApiKeyTypes = keyTypes as ApiKeyType[]
|
|
173
|
-
// } else {
|
|
174
|
-
// this.storedApiKeyTypes = []
|
|
175
|
-
// }
|
|
176
|
-
// } catch (error) {
|
|
177
|
-
// if (process.env.NODE_ENV !== 'production') {
|
|
178
|
-
// console.error(
|
|
179
|
-
// 'Error fetching stored API key types (is there something else on port 3000?):',
|
|
180
|
-
// error
|
|
181
|
-
// )
|
|
182
|
-
// }
|
|
183
|
-
// this.storedApiKeyTypes = []
|
|
184
|
-
// }
|
|
185
|
-
this.storedApiKeyTypes = [];
|
|
186
|
-
}
|
|
187
|
-
async handleAddApiKey(keyType, apiKey) {
|
|
188
|
-
if (!this.user || !this.user.authToken) {
|
|
189
|
-
console.log((0, picocolors_1.yellow)("Please log in first using 'login'."));
|
|
190
|
-
this.freshPrompt();
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
const readableKeyType = constants_1.READABLE_NAME[keyType];
|
|
194
|
-
spinner_1.Spinner.get().start();
|
|
195
|
-
try {
|
|
196
|
-
const response = await fetch(`${process.env.NEXT_PUBLIC_APP_URL}/api/api-keys`, {
|
|
197
|
-
method: 'POST',
|
|
198
|
-
headers: {
|
|
199
|
-
'Content-Type': 'application/json',
|
|
200
|
-
Cookie: `next-auth.session-token=${this.user.authToken}`,
|
|
201
|
-
},
|
|
202
|
-
body: JSON.stringify({
|
|
203
|
-
keyType,
|
|
204
|
-
apiKey,
|
|
205
|
-
authToken: this.user.authToken,
|
|
206
|
-
}),
|
|
207
|
-
});
|
|
208
|
-
spinner_1.Spinner.get().stop();
|
|
209
|
-
const respJson = await response.json();
|
|
210
|
-
if (response.ok) {
|
|
211
|
-
console.log((0, picocolors_1.green)(`Successfully added ${readableKeyType} API key.`));
|
|
212
|
-
if (!this.storedApiKeyTypes.includes(keyType)) {
|
|
213
|
-
this.storedApiKeyTypes.push(keyType);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
throw new Error(respJson.message);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
catch (e) {
|
|
221
|
-
spinner_1.Spinner.get().stop();
|
|
222
|
-
const error = e;
|
|
223
|
-
console.error((0, picocolors_1.red)('Error adding API key: ' + error.message));
|
|
224
|
-
}
|
|
225
|
-
finally {
|
|
226
|
-
this.freshPrompt();
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
async handleReferralCode(referralCode) {
|
|
230
|
-
if (this.user) {
|
|
231
|
-
try {
|
|
232
|
-
const redeemReferralResp = await fetch(`${process.env.NEXT_PUBLIC_APP_URL}/api/referrals`, {
|
|
233
|
-
method: 'POST',
|
|
234
|
-
headers: {
|
|
235
|
-
'Content-Type': 'application/json',
|
|
236
|
-
Cookie: `next-auth.session-token=${this.user.authToken};`,
|
|
237
|
-
},
|
|
238
|
-
body: JSON.stringify({
|
|
239
|
-
referralCode,
|
|
240
|
-
authToken: this.user.authToken,
|
|
241
|
-
}),
|
|
242
|
-
});
|
|
243
|
-
const respJson = await redeemReferralResp.json();
|
|
244
|
-
if (redeemReferralResp.ok) {
|
|
245
|
-
console.log([
|
|
246
|
-
(0, picocolors_1.green)(`Noice, you've earned an extra ${respJson.credits_redeemed} credits!`),
|
|
247
|
-
`(pssst: you can also refer new users and earn ${constants_2.CREDITS_REFERRAL_BONUS} credits for each referral at: ${process.env.NEXT_PUBLIC_APP_URL}/referrals)`,
|
|
248
|
-
].join('\n'));
|
|
249
|
-
this.getUsage();
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
throw new Error(respJson.error);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
catch (e) {
|
|
256
|
-
const error = e;
|
|
257
|
-
console.error((0, picocolors_1.red)('Error: ' + error.message));
|
|
258
|
-
this.freshPrompt();
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
await this.login(referralCode);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
async logout() {
|
|
266
|
-
if (this.user) {
|
|
267
|
-
try {
|
|
268
|
-
const response = await fetch(`${config_1.websiteUrl}/api/auth/cli/logout`, {
|
|
269
|
-
method: 'POST',
|
|
270
|
-
headers: { 'Content-Type': 'application/json' },
|
|
271
|
-
body: JSON.stringify({
|
|
272
|
-
authToken: this.user.authToken,
|
|
273
|
-
userId: this.user.id,
|
|
274
|
-
fingerprintId: this.user.fingerprintId,
|
|
275
|
-
fingerprintHash: this.user.fingerprintHash,
|
|
276
|
-
}),
|
|
277
|
-
});
|
|
278
|
-
if (!response.ok) {
|
|
279
|
-
const error = await response.text();
|
|
280
|
-
console.error((0, picocolors_1.red)('Failed to log out: ' + error));
|
|
281
|
-
}
|
|
282
|
-
try {
|
|
283
|
-
(0, fs_1.unlinkSync)(credentials_1.CREDENTIALS_PATH);
|
|
284
|
-
console.log(`You (${this.user.name}) have been logged out.`);
|
|
285
|
-
this.user = undefined;
|
|
286
|
-
this.pendingTopUpMessageAmount = 0;
|
|
287
|
-
this.usageData = {
|
|
288
|
-
usage: 0,
|
|
289
|
-
remainingBalance: null,
|
|
290
|
-
balanceBreakdown: undefined,
|
|
291
|
-
next_quota_reset: null,
|
|
292
|
-
};
|
|
293
|
-
this.oneTimeFlags = Object.fromEntries(constants_2.ONE_TIME_LABELS.map((tag) => [tag, false]));
|
|
294
|
-
}
|
|
295
|
-
catch (error) {
|
|
296
|
-
console.error('Error removing credentials file:', error);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
console.error('Error during logout:', error);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
async login(referralCode) {
|
|
305
|
-
if (this.user) {
|
|
306
|
-
console.log(`You are currently logged in as ${this.user.name}. Please enter "logout" first if you want to login as a different user.`);
|
|
307
|
-
this.freshPrompt();
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
try {
|
|
311
|
-
const response = await fetch(`${config_1.websiteUrl}/api/auth/cli/code`, {
|
|
312
|
-
method: 'POST',
|
|
313
|
-
headers: { 'Content-Type': 'application/json' },
|
|
314
|
-
body: JSON.stringify({
|
|
315
|
-
fingerprintId: await this.fingerprintId,
|
|
316
|
-
referralCode,
|
|
317
|
-
}),
|
|
318
|
-
});
|
|
319
|
-
if (!response.ok) {
|
|
320
|
-
const error = await response.text();
|
|
321
|
-
console.error((0, picocolors_1.red)('Login code request failed: ' + error));
|
|
322
|
-
this.freshPrompt();
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
const { loginUrl, fingerprintHash, expiresAt } = await response.json();
|
|
326
|
-
const responseToUser = [
|
|
327
|
-
'\n',
|
|
328
|
-
`Press ${(0, picocolors_1.blue)('ENTER')} to open your browser and finish logging in...`,
|
|
329
|
-
];
|
|
330
|
-
console.log(responseToUser.join('\n'));
|
|
331
|
-
let shouldRequestLogin = true;
|
|
332
|
-
this.rl.once('line', () => {
|
|
333
|
-
if (shouldRequestLogin) {
|
|
334
|
-
(0, child_process_1.spawn)(`open ${loginUrl}`, { shell: true });
|
|
335
|
-
console.log("Opened a browser window to log you in! If it doesn't open automatically, you can click this link:");
|
|
336
|
-
console.log();
|
|
337
|
-
console.log((0, picocolors_1.blue)((0, picocolors_1.bold)((0, picocolors_1.underline)(loginUrl))));
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
const initialTime = Date.now();
|
|
341
|
-
const pollInterval = setInterval(async () => {
|
|
342
|
-
if (Date.now() - initialTime > 5 * 60 * 1000 && shouldRequestLogin) {
|
|
343
|
-
shouldRequestLogin = false;
|
|
344
|
-
console.log('Unable to login. Please try again by typing "login" in the terminal.');
|
|
345
|
-
this.freshPrompt();
|
|
346
|
-
clearInterval(pollInterval);
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
if (!shouldRequestLogin) {
|
|
350
|
-
clearInterval(pollInterval);
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
try {
|
|
354
|
-
const fingerprintId = await this.fingerprintId;
|
|
355
|
-
const statusResponse = await fetch(`${config_1.websiteUrl}/api/auth/cli/status?fingerprintId=${fingerprintId}&fingerprintHash=${fingerprintHash}&expiresAt=${expiresAt}`);
|
|
356
|
-
if (!statusResponse.ok) {
|
|
357
|
-
if (statusResponse.status !== 401) {
|
|
358
|
-
// Ignore 401s during polling
|
|
359
|
-
console.error('Error checking login status:', await statusResponse.text());
|
|
360
|
-
}
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
const { user, message } = await statusResponse.json();
|
|
364
|
-
if (user) {
|
|
365
|
-
shouldRequestLogin = false;
|
|
366
|
-
this.user = user;
|
|
367
|
-
(0, analytics_1.identifyUser)(user.id, {
|
|
368
|
-
email: user.email,
|
|
369
|
-
name: user.name,
|
|
370
|
-
fingerprintId: fingerprintId,
|
|
371
|
-
});
|
|
372
|
-
logger_1.loggerContext.userId = user.id;
|
|
373
|
-
logger_1.loggerContext.userEmail = user.email;
|
|
374
|
-
logger_1.loggerContext.fingerprintId = fingerprintId;
|
|
375
|
-
logger_1.logger.info({
|
|
376
|
-
eventId: analytics_events_1.AnalyticsEvent.LOGIN,
|
|
377
|
-
}, 'login');
|
|
378
|
-
const credentialsPathDir = path_1.default.dirname(credentials_1.CREDENTIALS_PATH);
|
|
379
|
-
(0, fs_1.mkdirSync)(credentialsPathDir, { recursive: true });
|
|
380
|
-
(0, fs_1.writeFileSync)(credentials_1.CREDENTIALS_PATH, JSON.stringify({ default: user }));
|
|
381
|
-
const referralLink = `${process.env.NEXT_PUBLIC_APP_URL}/referrals`;
|
|
382
|
-
const responseToUser = [
|
|
383
|
-
'Authentication successful! 🎉',
|
|
384
|
-
(0, picocolors_1.bold)(`Hey there, ${user.name}.`),
|
|
385
|
-
`Refer new users and earn ${constants_2.CREDITS_REFERRAL_BONUS} credits per month: ${(0, picocolors_1.blueBright)(referralLink)}`,
|
|
386
|
-
];
|
|
387
|
-
console.log('\n' + responseToUser.join('\n'));
|
|
388
|
-
this.lastWarnedPct = 0;
|
|
389
|
-
this.oneTimeFlags = Object.fromEntries(constants_2.ONE_TIME_LABELS.map((tag) => [tag, false]));
|
|
390
|
-
(0, menu_1.displayGreeting)(this.costMode, null);
|
|
391
|
-
clearInterval(pollInterval);
|
|
392
|
-
this.freshPrompt();
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
catch (error) {
|
|
396
|
-
console.error('Error checking login status:', error);
|
|
397
|
-
}
|
|
398
|
-
}, 5000);
|
|
399
|
-
}
|
|
400
|
-
catch (error) {
|
|
401
|
-
console.error('Error during login:', error);
|
|
402
|
-
this.freshPrompt();
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
setUsage(usageData) {
|
|
406
|
-
this.usageData = usageData;
|
|
407
|
-
}
|
|
408
|
-
reconnect() {
|
|
409
|
-
this.webSocket.forceReconnect();
|
|
410
|
-
}
|
|
411
|
-
setupSubscriptions() {
|
|
412
|
-
this.webSocket.subscribe('action-error', (action) => {
|
|
413
|
-
if (action.error === 'Insufficient credits') {
|
|
414
|
-
console.error(['', (0, picocolors_1.red)(`Error: ${action.message}`)].join('\n'));
|
|
415
|
-
console.error(`Visit ${(0, picocolors_1.blue)((0, picocolors_1.bold)(process.env.NEXT_PUBLIC_APP_URL + '/usage'))} to add credits.`);
|
|
416
|
-
}
|
|
417
|
-
else if (action.error === 'Auto top-up disabled') {
|
|
418
|
-
console.error(['', (0, picocolors_1.red)(`Error: ${action.message}`)].join('\n'));
|
|
419
|
-
console.error((0, picocolors_1.yellow)(`Visit ${(0, picocolors_1.blue)((0, picocolors_1.bold)(process.env.NEXT_PUBLIC_APP_URL + '/usage'))} to update your payment settings.`));
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
console.error(['', (0, picocolors_1.red)(`Error: ${action.message}`)].join('\n'));
|
|
423
|
-
}
|
|
424
|
-
this.freshPrompt();
|
|
425
|
-
return;
|
|
426
|
-
});
|
|
427
|
-
this.webSocket.subscribe('read-files', (a) => {
|
|
428
|
-
const { filePaths, requestId } = a;
|
|
429
|
-
const files = (0, project_files_1.getFiles)(filePaths);
|
|
430
|
-
this.webSocket.sendAction({
|
|
431
|
-
type: 'read-files-response',
|
|
432
|
-
files,
|
|
433
|
-
requestId,
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
this.webSocket.subscribe('npm-version-status', (action) => {
|
|
437
|
-
const { isUpToDate } = action;
|
|
438
|
-
if (!isUpToDate) {
|
|
439
|
-
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`));
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
this.webSocket.subscribe('message-cost-response', (action) => {
|
|
443
|
-
const parsedAction = actions_1.MessageCostResponseSchema.safeParse(action);
|
|
444
|
-
if (!parsedAction.success)
|
|
445
|
-
return;
|
|
446
|
-
const response = parsedAction.data;
|
|
447
|
-
// Store credits used for this prompt
|
|
448
|
-
if (!this.creditsByPromptId[response.promptId]) {
|
|
449
|
-
this.creditsByPromptId[response.promptId] = [];
|
|
450
|
-
}
|
|
451
|
-
this.creditsByPromptId[response.promptId].push(response.credits);
|
|
452
|
-
});
|
|
453
|
-
this.webSocket.subscribe('usage-response', (action) => {
|
|
454
|
-
const parsedAction = actions_1.UsageReponseSchema.safeParse(action);
|
|
455
|
-
if (!parsedAction.success) {
|
|
456
|
-
console.error((0, picocolors_1.red)('Received invalid usage data from server:'), parsedAction.error.errors);
|
|
457
|
-
return;
|
|
458
|
-
}
|
|
459
|
-
this.setUsage(parsedAction.data);
|
|
460
|
-
// Store auto-topup amount if present, to be displayed when returning control to user
|
|
461
|
-
if (parsedAction.data.autoTopupAdded) {
|
|
462
|
-
this.pendingTopUpMessageAmount += parsedAction.data.autoTopupAdded;
|
|
463
|
-
}
|
|
464
|
-
// Only show warning if the response is complete
|
|
465
|
-
if (this.responseComplete) {
|
|
466
|
-
this.showUsageWarning();
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
// Used to handle server restarts gracefully
|
|
470
|
-
this.webSocket.subscribe('request-reconnect', () => {
|
|
471
|
-
this.reconnectWhenNextIdle();
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
showUsageWarning() {
|
|
475
|
-
// Determine user state based on login status and credit balance
|
|
476
|
-
const state = (0, ts_pattern_1.match)({
|
|
477
|
-
isLoggedIn: !!this.user,
|
|
478
|
-
credits: this.usageData.remainingBalance,
|
|
479
|
-
})
|
|
480
|
-
.with({ isLoggedIn: false }, () => constants_2.UserState.LOGGED_OUT)
|
|
481
|
-
.with({ credits: ts_pattern_1.P.number.gte(100) }, () => constants_2.UserState.GOOD_STANDING)
|
|
482
|
-
.with({ credits: ts_pattern_1.P.number.gte(20) }, () => constants_2.UserState.ATTENTION_NEEDED)
|
|
483
|
-
.with({ credits: ts_pattern_1.P.number.gte(1) }, () => constants_2.UserState.CRITICAL)
|
|
484
|
-
.otherwise(() => constants_2.UserState.DEPLETED);
|
|
485
|
-
const config = WARNING_CONFIG[state];
|
|
486
|
-
// Reset warning percentage if in good standing
|
|
487
|
-
if (state === constants_2.UserState.GOOD_STANDING) {
|
|
488
|
-
this.lastWarnedPct = 0;
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
// Show warning if we haven't warned at this threshold yet
|
|
492
|
-
if (this.lastWarnedPct < config.threshold &&
|
|
493
|
-
this.usageData.remainingBalance) {
|
|
494
|
-
const message = config.message(this.usageData.remainingBalance);
|
|
495
|
-
console.warn(message);
|
|
496
|
-
this.lastWarnedPct = config.threshold;
|
|
497
|
-
this.freshPrompt();
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
async generateCommitMessage(stagedChanges) {
|
|
501
|
-
return new Promise(async (resolve, reject) => {
|
|
502
|
-
const unsubscribe = this.webSocket.subscribe('commit-message-response', (action) => {
|
|
503
|
-
unsubscribe();
|
|
504
|
-
resolve(action.commitMessage);
|
|
505
|
-
});
|
|
506
|
-
this.webSocket.sendAction({
|
|
507
|
-
type: 'generate-commit-message',
|
|
508
|
-
fingerprintId: await this.fingerprintId,
|
|
509
|
-
authToken: this.user?.authToken,
|
|
510
|
-
stagedChanges,
|
|
511
|
-
});
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
async sendUserInput(prompt) {
|
|
515
|
-
if (!this.agentState) {
|
|
516
|
-
throw new Error('Agent state not initialized');
|
|
517
|
-
}
|
|
518
|
-
const userInputId = `mc-input-` + Math.random().toString(36).substring(2, 15);
|
|
519
|
-
logger_1.loggerContext.clientRequestId = userInputId;
|
|
520
|
-
const { responsePromise, stopResponse } = this.subscribeToResponse((chunk) => {
|
|
521
|
-
spinner_1.Spinner.get().stop();
|
|
522
|
-
this.displayChunk(chunk);
|
|
523
|
-
}, userInputId, () => {
|
|
524
|
-
spinner_1.Spinner.get().stop();
|
|
525
|
-
this.displayChunk((0, picocolors_1.green)((0, picocolors_1.underline)('\nCodebuff') + ':') + ' ');
|
|
526
|
-
}, prompt);
|
|
527
|
-
const urls = (0, web_scraper_1.parseUrlsFromContent)(prompt);
|
|
528
|
-
const scrapedBlocks = await (0, web_scraper_1.getScrapedContentBlocks)(urls);
|
|
529
|
-
const scrapedContent = scrapedBlocks.length > 0 ? scrapedBlocks.join('\n\n') + '\n\n' : '';
|
|
530
|
-
// Append process updates to existing tool results
|
|
531
|
-
const toolResults = (0, array_1.buildArray)(...(this.lastToolResults || []), ...(0, background_process_manager_1.getBackgroundProcessUpdates)(), scrapedContent && {
|
|
532
|
-
id: 'scraped-content',
|
|
533
|
-
name: 'web-scraper',
|
|
534
|
-
result: scrapedContent,
|
|
535
|
-
});
|
|
536
|
-
spinner_1.Spinner.get().start();
|
|
537
|
-
this.webSocket.sendAction({
|
|
538
|
-
type: 'prompt',
|
|
539
|
-
promptId: userInputId,
|
|
540
|
-
prompt,
|
|
541
|
-
agentState: this.agentState,
|
|
542
|
-
toolResults,
|
|
543
|
-
fingerprintId: await this.fingerprintId,
|
|
544
|
-
authToken: this.user?.authToken,
|
|
545
|
-
costMode: this.costMode,
|
|
546
|
-
model: this.model,
|
|
547
|
-
});
|
|
548
|
-
return {
|
|
549
|
-
responsePromise,
|
|
550
|
-
stopResponse,
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* Shrinks all instances of more than 2 newlines in a row.
|
|
555
|
-
* Note: don't start or end colored text with newlines
|
|
556
|
-
* @param chunk chunk to display
|
|
557
|
-
*/
|
|
558
|
-
displayChunk(chunk) {
|
|
559
|
-
// Process chunk to limit consecutive newlines
|
|
560
|
-
const combinedContent = this.responseBuffer + chunk;
|
|
561
|
-
const processedContent = combinedContent.replace(/\n{3,}/g, '\n\n');
|
|
562
|
-
const processedChunk = processedContent.slice(this.responseBuffer.length);
|
|
563
|
-
this.responseBuffer = processedContent;
|
|
564
|
-
process.stdout.write(processedChunk);
|
|
565
|
-
}
|
|
566
|
-
subscribeToResponse(onChunk, userInputId, onStreamStart, prompt) {
|
|
567
|
-
const rawChunkBuffer = [];
|
|
568
|
-
this.responseBuffer = '';
|
|
569
|
-
let streamStarted = false;
|
|
570
|
-
let responseStopped = false;
|
|
571
|
-
let resolveResponse;
|
|
572
|
-
let rejectResponse;
|
|
573
|
-
let unsubscribeChunks;
|
|
574
|
-
let unsubscribeComplete;
|
|
575
|
-
const responsePromise = new Promise((resolve, reject) => {
|
|
576
|
-
resolveResponse = resolve;
|
|
577
|
-
rejectResponse = reject;
|
|
578
|
-
});
|
|
579
|
-
const stopResponse = () => {
|
|
580
|
-
responseStopped = true;
|
|
581
|
-
unsubscribeChunks();
|
|
582
|
-
unsubscribeComplete();
|
|
583
|
-
const additionalMessages = [
|
|
584
|
-
{ role: 'user', content: prompt },
|
|
585
|
-
{
|
|
586
|
-
role: 'user',
|
|
587
|
-
content: `<system><assistant_message>${rawChunkBuffer.join('')}</assistant_message>[RESPONSE_CANCELED_BY_USER]</system>`,
|
|
588
|
-
},
|
|
589
|
-
];
|
|
590
|
-
// Update the agent state with just the assistant's response
|
|
591
|
-
const { messageHistory } = this.agentState;
|
|
592
|
-
const newMessages = [...messageHistory, ...additionalMessages];
|
|
593
|
-
this.agentState = {
|
|
594
|
-
...this.agentState,
|
|
595
|
-
messageHistory: newMessages,
|
|
596
|
-
};
|
|
597
|
-
(0, chat_storage_1.setMessages)(newMessages);
|
|
598
|
-
resolveResponse({
|
|
599
|
-
type: 'prompt-response',
|
|
600
|
-
promptId: userInputId,
|
|
601
|
-
agentState: this.agentState,
|
|
602
|
-
toolCalls: [],
|
|
603
|
-
toolResults: [],
|
|
604
|
-
wasStoppedByUser: true,
|
|
605
|
-
});
|
|
606
|
-
};
|
|
607
|
-
const xmlStreamParser = (0, xml_stream_parser_1.createXMLStreamParser)(tool_renderers_1.toolRenderers, (chunk) => {
|
|
608
|
-
onChunk(chunk);
|
|
609
|
-
});
|
|
610
|
-
unsubscribeChunks = this.webSocket.subscribe('response-chunk', (a) => {
|
|
611
|
-
if (a.userInputId !== userInputId)
|
|
612
|
-
return;
|
|
613
|
-
const { chunk } = a;
|
|
614
|
-
rawChunkBuffer.push(chunk);
|
|
615
|
-
const trimmed = chunk.trim();
|
|
616
|
-
for (const tag of constants_2.ONE_TIME_TAGS) {
|
|
617
|
-
if (trimmed.startsWith(`<${tag}>`) && trimmed.endsWith(`</${tag}>`)) {
|
|
618
|
-
if (this.oneTimeFlags[tag]) {
|
|
619
|
-
return;
|
|
620
|
-
}
|
|
621
|
-
spinner_1.Spinner.get().stop();
|
|
622
|
-
const warningMessage = trimmed
|
|
623
|
-
.replace(`<${tag}>`, '')
|
|
624
|
-
.replace(`</${tag}>`, '');
|
|
625
|
-
this.displayChunk((0, picocolors_1.yellow)(`\n\n${warningMessage}\n\n`));
|
|
626
|
-
this.oneTimeFlags[tag] = true;
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
if (chunk && chunk.trim()) {
|
|
631
|
-
if (!streamStarted && chunk.trim()) {
|
|
632
|
-
streamStarted = true;
|
|
633
|
-
onStreamStart();
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
try {
|
|
637
|
-
xmlStreamParser.write(chunk, 'utf8');
|
|
638
|
-
}
|
|
639
|
-
catch (e) {
|
|
640
|
-
// console.error('Error writing chunk', e)
|
|
641
|
-
}
|
|
642
|
-
});
|
|
643
|
-
unsubscribeComplete = this.webSocket.subscribe('prompt-response', async (action) => {
|
|
644
|
-
const parsedAction = actions_1.PromptResponseSchema.safeParse(action);
|
|
645
|
-
if (!parsedAction.success)
|
|
646
|
-
return;
|
|
647
|
-
if (action.promptId !== userInputId)
|
|
648
|
-
return;
|
|
649
|
-
const a = parsedAction.data;
|
|
650
|
-
let isComplete = false;
|
|
651
|
-
spinner_1.Spinner.get().stop();
|
|
652
|
-
this.agentState = a.agentState;
|
|
653
|
-
const toolResults = [...a.toolResults];
|
|
654
|
-
for (const toolCall of a.toolCalls) {
|
|
655
|
-
try {
|
|
656
|
-
if (toolCall.name === 'end_turn') {
|
|
657
|
-
this.responseComplete = true;
|
|
658
|
-
isComplete = true;
|
|
659
|
-
continue;
|
|
660
|
-
}
|
|
661
|
-
if (toolCall.name === 'write_file') {
|
|
662
|
-
// Save lastChanges for `diff` command
|
|
663
|
-
this.lastChanges.push(actions_1.FileChangeSchema.parse(toolCall.parameters));
|
|
664
|
-
this.hadFileChanges = true;
|
|
665
|
-
}
|
|
666
|
-
if (toolCall.name === 'run_terminal_command' &&
|
|
667
|
-
toolCall.parameters.mode === 'user') {
|
|
668
|
-
// Special case: when terminal command is run it as a user command, then no need to reprompt assistant.
|
|
669
|
-
this.responseComplete = true;
|
|
670
|
-
isComplete = true;
|
|
671
|
-
}
|
|
672
|
-
if (toolCall.name === 'run_terminal_command' &&
|
|
673
|
-
toolCall.parameters.mode === 'assistant' &&
|
|
674
|
-
toolCall.parameters.process_type === 'BACKGROUND') {
|
|
675
|
-
this.oneTimeFlags[constants_2.SHOULD_ASK_CONFIG] = true;
|
|
676
|
-
}
|
|
677
|
-
if (toolCall.name === 'run_terminal_command') {
|
|
678
|
-
this.displayChunk('\n\n');
|
|
679
|
-
this.responseBuffer = '\n';
|
|
680
|
-
}
|
|
681
|
-
const toolResult = await (0, tool_handlers_1.handleToolCall)(toolCall, (0, project_files_1.getProjectRoot)());
|
|
682
|
-
toolResults.push(toolResult);
|
|
683
|
-
}
|
|
684
|
-
catch (error) {
|
|
685
|
-
this.displayChunk('\n\n' +
|
|
686
|
-
(0, picocolors_1.red)(`Error parsing tool call ${toolCall.name}:\n${error}`) +
|
|
687
|
-
'\n\n');
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
this.displayChunk('\n\n');
|
|
691
|
-
// If we had any file changes, update the project context
|
|
692
|
-
if (this.hadFileChanges) {
|
|
693
|
-
this.fileContext = await (0, project_files_1.getProjectFileContext)((0, project_files_1.getProjectRoot)(), {});
|
|
694
|
-
}
|
|
695
|
-
if (!isComplete) {
|
|
696
|
-
// Append process updates to existing tool results
|
|
697
|
-
toolResults.push(...(0, background_process_manager_1.getBackgroundProcessUpdates)());
|
|
698
|
-
// Continue the prompt with the tool results.
|
|
699
|
-
this.webSocket.sendAction({
|
|
700
|
-
type: 'prompt',
|
|
701
|
-
promptId: userInputId,
|
|
702
|
-
prompt: undefined,
|
|
703
|
-
agentState: this.agentState,
|
|
704
|
-
toolResults,
|
|
705
|
-
fingerprintId: await this.fingerprintId,
|
|
706
|
-
authToken: this.user?.authToken,
|
|
707
|
-
costMode: this.costMode,
|
|
708
|
-
model: this.model,
|
|
709
|
-
});
|
|
710
|
-
return;
|
|
711
|
-
}
|
|
712
|
-
this.lastToolResults = toolResults;
|
|
713
|
-
xmlStreamParser.end();
|
|
714
|
-
askConfig: if (this.oneTimeFlags[constants_2.SHOULD_ASK_CONFIG] &&
|
|
715
|
-
!this.oneTimeFlags[constants_2.ASKED_CONFIG]) {
|
|
716
|
-
this.oneTimeFlags[constants_2.ASKED_CONFIG] = true;
|
|
717
|
-
if ((0, fs_1.existsSync)(path_1.default.join((0, project_files_1.getProjectRoot)(), constants_3.codebuffConfigFile))) {
|
|
718
|
-
break askConfig;
|
|
719
|
-
}
|
|
720
|
-
this.displayChunk('\n\n' +
|
|
721
|
-
(0, picocolors_1.yellow)(`✨ Recommended: run the 'init' command in order to create a configuration file!
|
|
722
|
-
|
|
723
|
-
If you would like background processes (like this one) to run automatically whenever Codebuff starts, creating a ${constants_3.codebuffConfigFile} config file can improve your workflow.
|
|
724
|
-
Go to https://www.codebuff.com/config for more information.`) +
|
|
725
|
-
'\n\n');
|
|
726
|
-
}
|
|
727
|
-
if (this.agentState) {
|
|
728
|
-
(0, chat_storage_1.setMessages)(this.agentState.messageHistory);
|
|
729
|
-
}
|
|
730
|
-
// Show total credits used for this prompt if significant
|
|
731
|
-
const credits = this.creditsByPromptId[userInputId]?.reduce((a, b) => a + b, 0) ?? 0;
|
|
732
|
-
if (credits >= constants_2.REQUEST_CREDIT_SHOW_THRESHOLD) {
|
|
733
|
-
this.displayChunk(`\n\n${(0, string_1.pluralize)(credits, 'credit')} used for this request.\n`);
|
|
734
|
-
}
|
|
735
|
-
if (this.hadFileChanges) {
|
|
736
|
-
let checkpointAddendum = '';
|
|
737
|
-
try {
|
|
738
|
-
checkpointAddendum = ` or "checkpoint ${checkpoint_manager_1.checkpointManager.getLatestCheckpoint().id}" to revert`;
|
|
739
|
-
}
|
|
740
|
-
catch (error) {
|
|
741
|
-
// No latest checkpoint, don't show addendum
|
|
742
|
-
}
|
|
743
|
-
this.displayChunk(`\n\nComplete! Type "diff" to review changes${checkpointAddendum}.\n\n`);
|
|
744
|
-
this.hadFileChanges = false;
|
|
745
|
-
this.freshPrompt();
|
|
746
|
-
}
|
|
747
|
-
unsubscribeChunks();
|
|
748
|
-
unsubscribeComplete();
|
|
749
|
-
resolveResponse({ ...a, wasStoppedByUser: false });
|
|
750
|
-
});
|
|
751
|
-
// Reset flags at the start of each response
|
|
752
|
-
this.responseComplete = false;
|
|
753
|
-
return {
|
|
754
|
-
responsePromise,
|
|
755
|
-
stopResponse,
|
|
756
|
-
};
|
|
757
|
-
}
|
|
758
|
-
async getUsage() {
|
|
759
|
-
try {
|
|
760
|
-
const response = await fetch(`${config_1.backendUrl}/api/usage`, {
|
|
761
|
-
method: 'POST',
|
|
762
|
-
headers: {
|
|
763
|
-
'Content-Type': 'application/json',
|
|
764
|
-
},
|
|
765
|
-
body: JSON.stringify({
|
|
766
|
-
fingerprintId: await this.fingerprintId,
|
|
767
|
-
authToken: this.user?.authToken,
|
|
768
|
-
}),
|
|
769
|
-
});
|
|
770
|
-
const data = await response.json();
|
|
771
|
-
// Use zod schema to validate response
|
|
772
|
-
const parsedResponse = actions_1.UsageReponseSchema.parse(data);
|
|
773
|
-
if (data.type === 'action-error') {
|
|
774
|
-
console.error((0, picocolors_1.red)(data.message));
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
|
-
this.setUsage(parsedResponse);
|
|
778
|
-
const usageLink = `${config_1.websiteUrl}/usage`;
|
|
779
|
-
const remainingColor = this.usageData.remainingBalance === null
|
|
780
|
-
? picocolors_1.yellow
|
|
781
|
-
: this.usageData.remainingBalance <= 0
|
|
782
|
-
? picocolors_1.red
|
|
783
|
-
: this.usageData.remainingBalance <= LOW_BALANCE_THRESHOLD
|
|
784
|
-
? picocolors_1.red
|
|
785
|
-
: picocolors_1.green;
|
|
786
|
-
const totalCreditsUsedThisSession = Object.values(this.creditsByPromptId)
|
|
787
|
-
.flat()
|
|
788
|
-
.reduce((sum, credits) => sum + credits, 0);
|
|
789
|
-
console.log(`Session usage: ${totalCreditsUsedThisSession.toLocaleString()}${this.usageData.remainingBalance !== null
|
|
790
|
-
? `. Credits Remaining: ${remainingColor(this.usageData.remainingBalance.toLocaleString())}`
|
|
791
|
-
: '.'}`);
|
|
792
|
-
if (this.usageData.next_quota_reset) {
|
|
793
|
-
const resetDate = new Date(this.usageData.next_quota_reset);
|
|
794
|
-
const today = new Date();
|
|
795
|
-
const isToday = resetDate.toDateString() === today.toDateString();
|
|
796
|
-
const dateDisplay = isToday
|
|
797
|
-
? resetDate.toLocaleString() // Show full date and time for today
|
|
798
|
-
: resetDate.toLocaleDateString(); // Just show date otherwise
|
|
799
|
-
console.log(`Free credits will renew on ${dateDisplay}. Details: ${(0, picocolors_1.underline)((0, picocolors_1.blue)(usageLink))}`);
|
|
800
|
-
}
|
|
801
|
-
this.showUsageWarning();
|
|
802
|
-
}
|
|
803
|
-
catch (error) {
|
|
804
|
-
console.error((0, picocolors_1.red)(`Error checking usage: Please reach out to ${process.env.NEXT_PUBLIC_SUPPORT_EMAIL} for help.`));
|
|
805
|
-
// Check if it's a ZodError for more specific feedback
|
|
806
|
-
if (error instanceof zod_1.z.ZodError) {
|
|
807
|
-
console.error((0, picocolors_1.red)('Data validation failed:'), error.errors);
|
|
808
|
-
}
|
|
809
|
-
else {
|
|
810
|
-
console.error(error);
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
finally {
|
|
814
|
-
this.freshPrompt();
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
async warmContextCache() {
|
|
818
|
-
const fileContext = await (0, project_files_1.getProjectFileContext)((0, project_files_1.getProjectRoot)(), {});
|
|
819
|
-
this.webSocket.subscribe('init-response', (a) => {
|
|
820
|
-
const parsedAction = actions_1.InitResponseSchema.safeParse(a);
|
|
821
|
-
if (!parsedAction.success)
|
|
822
|
-
return;
|
|
823
|
-
// Set initial usage data from the init response
|
|
824
|
-
this.setUsage(parsedAction.data);
|
|
825
|
-
});
|
|
826
|
-
this.webSocket.sendAction({
|
|
827
|
-
type: 'init',
|
|
828
|
-
fingerprintId: await this.fingerprintId,
|
|
829
|
-
authToken: this.user?.authToken,
|
|
830
|
-
fileContext,
|
|
831
|
-
});
|
|
832
|
-
await this.fetchStoredApiKeyTypes();
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
exports.Client = Client;
|
|
836
|
-
//# sourceMappingURL=client.js.map
|