cloving 0.3.12 → 0.3.13
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/cloving_gpt/index.js +1 -1
- package/dist/commands/config.js +2 -2
- package/dist/managers/BlockManager.js +20 -7
- package/dist/managers/ChatManager.js +41 -19
- package/dist/managers/CodeManager.js +13 -11
- package/dist/managers/DocsManager.js +2 -0
- package/dist/managers/InitManager.js +18 -5
- package/dist/managers/ProxyManager.js +19 -2
- package/dist/managers/StreamManager.js +44 -27
- package/dist/package.json +1 -1
- package/dist/utils/prompts/CODEGEN_INSTRUCTIONS.md +8 -7
- package/dist/utils/string_utils.js +10 -5
- package/package.json +1 -1
|
@@ -32,7 +32,7 @@ class ClovingGPT {
|
|
|
32
32
|
const { provider, model, config: modelConfig } = primaryModel;
|
|
33
33
|
this.apiKey = modelConfig.apiKey;
|
|
34
34
|
this.temperature = options.temperature || modelConfig.temperature || 0.2;
|
|
35
|
-
this.silent = options.silent || modelConfig.silent;
|
|
35
|
+
this.silent = options.silent || modelConfig.silent || false;
|
|
36
36
|
this.stream = options.stream || false;
|
|
37
37
|
this.timeout = options.timeout || 60000; // Default timeout of 60 seconds
|
|
38
38
|
switch (provider) {
|
package/dist/commands/config.js
CHANGED
|
@@ -89,14 +89,14 @@ const config = async () => {
|
|
|
89
89
|
*/
|
|
90
90
|
const review = await (0, prompts_1.confirm)({
|
|
91
91
|
message: `Do you want to review all prompts before they are sent to ${selectedModel}?`,
|
|
92
|
-
default:
|
|
92
|
+
default: false,
|
|
93
93
|
});
|
|
94
94
|
/**
|
|
95
95
|
* Prompts the user to decide if they trust the selected model with sensitive information.
|
|
96
96
|
*/
|
|
97
97
|
const trust = await (0, prompts_1.confirm)({
|
|
98
98
|
message: `Do you trust ${selectedModel} with sensitive information?`,
|
|
99
|
-
default:
|
|
99
|
+
default: true,
|
|
100
100
|
});
|
|
101
101
|
/**
|
|
102
102
|
* Prompts the user to enter the temperature setting for the selected model.
|
|
@@ -24,14 +24,19 @@ class BlockManager extends events_1.EventEmitter {
|
|
|
24
24
|
this.buffer = '';
|
|
25
25
|
}
|
|
26
26
|
// if content has multiple \n``` in the string, then we need to split it up
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
const codeBlockRegex = /\n```[\s\S]*?\n```/g;
|
|
28
|
+
const codeBlocks = content.match(codeBlockRegex);
|
|
29
|
+
if (codeBlocks) {
|
|
30
|
+
let lastIndex = 0;
|
|
31
|
+
for (const block of codeBlocks) {
|
|
32
|
+
const index = content.indexOf(block, lastIndex);
|
|
33
|
+
this.processCodeBlocks(content.slice(lastIndex, index));
|
|
34
|
+
this.processCodeBlocks(block);
|
|
35
|
+
lastIndex = index + block.length;
|
|
32
36
|
}
|
|
37
|
+
this.processCodeBlocks(content.slice(lastIndex));
|
|
33
38
|
}
|
|
34
|
-
|
|
39
|
+
else {
|
|
35
40
|
this.processCodeBlocks(content);
|
|
36
41
|
}
|
|
37
42
|
}
|
|
@@ -95,7 +100,15 @@ class BlockManager extends events_1.EventEmitter {
|
|
|
95
100
|
*/
|
|
96
101
|
parseCodeBuffer() {
|
|
97
102
|
const results = (0, string_utils_1.extractCurrentNewBlocks)(this.codeBuffer);
|
|
98
|
-
|
|
103
|
+
if (results.length === 0) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
const block = results[0];
|
|
107
|
+
if (!block.currentContent || !block.newContent) {
|
|
108
|
+
console.warn('Incomplete code block detected. Skipping.');
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
return block;
|
|
99
112
|
}
|
|
100
113
|
clearBuffer() {
|
|
101
114
|
this.buffer = '';
|
|
@@ -11,6 +11,7 @@ const child_process_1 = require("child_process");
|
|
|
11
11
|
const CommitManager_1 = __importDefault(require("./CommitManager"));
|
|
12
12
|
const ReviewManager_1 = __importDefault(require("./ReviewManager"));
|
|
13
13
|
const string_utils_1 = require("../utils/string_utils");
|
|
14
|
+
const config_utils_1 = require("../utils/config_utils");
|
|
14
15
|
const prompt_utils_1 = require("../utils/prompt_utils");
|
|
15
16
|
const prompts_1 = require("../utils/prompts");
|
|
16
17
|
const StreamManager_1 = __importDefault(require("./StreamManager"));
|
|
@@ -39,7 +40,7 @@ class ChatManager extends StreamManager_1.default {
|
|
|
39
40
|
this.multilineInput = '';
|
|
40
41
|
this.isMultilineMode = false;
|
|
41
42
|
this.isSilent = false;
|
|
42
|
-
this.isSilent = options.silent || false;
|
|
43
|
+
this.isSilent = options.silent || (0, config_utils_1.getConfig)(options).globalSilent || false;
|
|
43
44
|
options.stream = true;
|
|
44
45
|
options.silent = true;
|
|
45
46
|
this.rl = readline_1.default.createInterface({
|
|
@@ -98,6 +99,15 @@ class ChatManager extends StreamManager_1.default {
|
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
101
|
const trimmedLine = line.trim();
|
|
102
|
+
if (this.isPastedCode(trimmedLine)) {
|
|
103
|
+
console.log('Detected pasted code. Processing as multiline input...');
|
|
104
|
+
this.multilineInput = trimmedLine;
|
|
105
|
+
this.isMultilineMode = true;
|
|
106
|
+
await this.handleCommand(this.multilineInput);
|
|
107
|
+
this.multilineInput = '';
|
|
108
|
+
this.isMultilineMode = false;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
101
111
|
if (this.handleMultilineInput(trimmedLine)) {
|
|
102
112
|
return;
|
|
103
113
|
}
|
|
@@ -133,6 +143,10 @@ class ChatManager extends StreamManager_1.default {
|
|
|
133
143
|
}
|
|
134
144
|
return false;
|
|
135
145
|
}
|
|
146
|
+
isPastedCode(line) {
|
|
147
|
+
// Check if the line contains multiple lines (indicating a paste)
|
|
148
|
+
return line.includes('\n') || line.length > 100;
|
|
149
|
+
}
|
|
136
150
|
handleExitCommand(command) {
|
|
137
151
|
if (command.toLowerCase() === 'exit') {
|
|
138
152
|
this.rl.close();
|
|
@@ -178,6 +192,11 @@ class ChatManager extends StreamManager_1.default {
|
|
|
178
192
|
if (matchingCommand) {
|
|
179
193
|
command = matchingCommand.split(' ')[0]; // Use only the command part without arguments
|
|
180
194
|
}
|
|
195
|
+
else {
|
|
196
|
+
console.log(`No matching command found for '${command}'. Processing as user input.`);
|
|
197
|
+
await this.processUserInput(command);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
181
200
|
}
|
|
182
201
|
switch (command) {
|
|
183
202
|
case 'help':
|
|
@@ -438,7 +457,7 @@ class ChatManager extends StreamManager_1.default {
|
|
|
438
457
|
try {
|
|
439
458
|
await this.refreshContext();
|
|
440
459
|
this.addUserPrompt(this.generatePrompt(input));
|
|
441
|
-
if (!this.
|
|
460
|
+
if (!this.gpt.silent) {
|
|
442
461
|
const fullPrompt = this.chatHistory
|
|
443
462
|
.map((m) => {
|
|
444
463
|
const content = m.content
|
|
@@ -461,25 +480,11 @@ class ChatManager extends StreamManager_1.default {
|
|
|
461
480
|
// Review the prompt using the REPL
|
|
462
481
|
const tokenCount = Math.ceil(fullPrompt.length / 4).toLocaleString();
|
|
463
482
|
console.log(`${colors_1.default.yellow.bold('INFORMATION')} The generated prompt is approximately ${tokenCount} tokens long. Would you like to review the prompt before sending it? ${colors_1.default.gray('(Y/n)')}`);
|
|
464
|
-
const reviewPrompt = await
|
|
465
|
-
this.rl.question(colors_1.default.green.bold('cloving> '), (answer) => {
|
|
466
|
-
resolve(answer.trim().toLowerCase());
|
|
467
|
-
});
|
|
468
|
-
});
|
|
483
|
+
const reviewPrompt = await this.askQuestion('cloving> ');
|
|
469
484
|
if (reviewPrompt.startsWith('y') || reviewPrompt === '') {
|
|
470
|
-
|
|
471
|
-
const promptParts = fullPrompt.split('\n```');
|
|
472
|
-
const highlightedPrompt = promptParts
|
|
473
|
-
.map((part, index) => index % 2 === 1 ? (0, cli_highlight_1.default)(part, { language: 'typescript' }) : part)
|
|
474
|
-
.join('\n```');
|
|
475
|
-
console.log(highlightedPrompt);
|
|
476
|
-
console.log(colors_1.default.gray.bold('\n---------------------- PROMPT END ----------------------\n'));
|
|
485
|
+
this.reviewPrompt(fullPrompt);
|
|
477
486
|
console.log(`Do you want to proceed with this prompt? ${colors_1.default.gray('(Y/n)')}`);
|
|
478
|
-
const confirmPrompt = await
|
|
479
|
-
this.rl.question(colors_1.default.green.bold('cloving> '), (answer) => {
|
|
480
|
-
resolve(answer.trim().toLowerCase());
|
|
481
|
-
});
|
|
482
|
-
});
|
|
487
|
+
const confirmPrompt = await this.askQuestion('cloving> ');
|
|
483
488
|
if (!confirmPrompt.startsWith('y') && confirmPrompt !== '') {
|
|
484
489
|
console.log('Operation cancelled by user.');
|
|
485
490
|
this.isProcessing = false;
|
|
@@ -498,9 +503,26 @@ class ChatManager extends StreamManager_1.default {
|
|
|
498
503
|
this.handleError(err);
|
|
499
504
|
}
|
|
500
505
|
}
|
|
506
|
+
askQuestion(prompt) {
|
|
507
|
+
return new Promise((resolve) => {
|
|
508
|
+
this.rl.question(colors_1.default.green.bold(prompt), (answer) => {
|
|
509
|
+
resolve(answer.trim().toLowerCase());
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
reviewPrompt(fullPrompt) {
|
|
514
|
+
console.log(colors_1.default.gray.bold('\n---------------------- PROMPT START ----------------------\n'));
|
|
515
|
+
const promptParts = fullPrompt.split('\n```');
|
|
516
|
+
const highlightedPrompt = promptParts
|
|
517
|
+
.map((part, index) => (index % 2 === 1 ? (0, cli_highlight_1.default)(part, { language: 'typescript' }) : part))
|
|
518
|
+
.join('\n```');
|
|
519
|
+
console.log(highlightedPrompt);
|
|
520
|
+
console.log(colors_1.default.gray.bold('\n---------------------- PROMPT END ----------------------\n'));
|
|
521
|
+
}
|
|
501
522
|
async finalizeResponse() {
|
|
502
523
|
this.addAssistantResponse(this.responseString);
|
|
503
524
|
this.isProcessing = false;
|
|
525
|
+
process.stdout.write('\b'.repeat(100));
|
|
504
526
|
if (this.responseString !== '') {
|
|
505
527
|
const currentNewBlocks = (0, string_utils_1.extractCurrentNewBlocks)(this.responseString);
|
|
506
528
|
const [canApply, summary] = await (0, string_utils_1.checkBlocksApplicability)(currentNewBlocks);
|
|
@@ -162,22 +162,24 @@ Please briefly explain how the code works in this.`;
|
|
|
162
162
|
const currentNewBlocks = (0, string_utils_1.extractCurrentNewBlocks)(this.responseString);
|
|
163
163
|
const [canApply, summary] = await (0, string_utils_1.checkBlocksApplicability)(currentNewBlocks);
|
|
164
164
|
if (!canApply) {
|
|
165
|
-
|
|
166
|
-
console.log(`\n\n${summary}\n\n${colors_1.default.yellow.bold('WARNING')} Some of the provided code blocks could not be automatically applied. Retrying (Attempt ${this.retryCount + 1}/${this.maxRetries})...\n`);
|
|
167
|
-
this.retryCount++;
|
|
168
|
-
this.generateCode(`${prompts_2.CODEGEN_COULDNT_APPLY}\n\n${summary}`);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
console.log(`\n\n${colors_1.default.red.bold('ERROR')} Failed to generate a diff that could be cleanly applied after ${this.maxRetries} attempts. Please review the changes manually and try again.\n`);
|
|
173
|
-
this.retryCount = 0; // Reset the retry count for future attempts
|
|
174
|
-
}
|
|
165
|
+
await this.handleUnapplicableBlocks(summary);
|
|
175
166
|
}
|
|
176
167
|
else {
|
|
177
168
|
this.retryCount = 0; // Reset the retry count on successful application
|
|
178
169
|
}
|
|
179
170
|
}
|
|
180
|
-
this.handleUserAction(this.responseString);
|
|
171
|
+
await this.handleUserAction(this.responseString);
|
|
172
|
+
}
|
|
173
|
+
async handleUnapplicableBlocks(summary) {
|
|
174
|
+
if (this.retryCount < this.maxRetries) {
|
|
175
|
+
console.log(`\n\n${summary}\n\n${colors_1.default.yellow.bold('WARNING')} Some of the provided code blocks could not be automatically applied. Retrying (Attempt ${this.retryCount + 1}/${this.maxRetries})...\n`);
|
|
176
|
+
this.retryCount++;
|
|
177
|
+
await this.generateCode(`${prompts_2.CODEGEN_COULDNT_APPLY}\n\n${summary}`);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
console.log(`\n\n${colors_1.default.red.bold('ERROR')} Failed to generate a diff that could be cleanly applied after ${this.maxRetries} attempts. Please review the changes manually and try again.\n`);
|
|
181
|
+
this.retryCount = 0; // Reset the retry count for future attempts
|
|
182
|
+
}
|
|
181
183
|
}
|
|
182
184
|
}
|
|
183
185
|
exports.default = CodeManager;
|
|
@@ -182,15 +182,28 @@ ${JSON.stringify(projectDetails, null, 2)}`;
|
|
|
182
182
|
}
|
|
183
183
|
const clovingJson = JSON.parse(cleanAiChatResponse);
|
|
184
184
|
const directoriesToCheck = [
|
|
185
|
-
...clovingJson.languages.map((language) =>
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
...clovingJson.languages.map((language) => ({
|
|
186
|
+
type: 'Language',
|
|
187
|
+
name: language.name,
|
|
188
|
+
directory: language.directory,
|
|
189
|
+
})),
|
|
190
|
+
...clovingJson.frameworks.map((framework) => ({
|
|
191
|
+
type: 'Framework',
|
|
192
|
+
name: framework.name,
|
|
193
|
+
directory: framework.directory,
|
|
194
|
+
})),
|
|
195
|
+
...clovingJson.testingFrameworks.map((testingFramework) => ({
|
|
196
|
+
type: 'Testing Framework',
|
|
197
|
+
name: testingFramework.name,
|
|
198
|
+
directory: testingFramework.directory,
|
|
199
|
+
})),
|
|
188
200
|
];
|
|
189
|
-
const missingDirectories = directoriesToCheck.filter((
|
|
201
|
+
const missingDirectories = directoriesToCheck.filter((item) => !fs_1.default.existsSync(item.directory));
|
|
190
202
|
if (missingDirectories.length > 0) {
|
|
203
|
+
const missingDirMessages = missingDirectories.map((item) => `${item.type} ${colors_1.default.bold(item.name)}: ${colors_1.default.red.bold(item.directory)}`);
|
|
191
204
|
return [
|
|
192
205
|
false,
|
|
193
|
-
`${colors_1.default.red.bold('ERROR:')} The following directories were not found
|
|
206
|
+
`${colors_1.default.red.bold('ERROR:')} The following directories were not found:\n${missingDirMessages.join('\n')}`,
|
|
194
207
|
];
|
|
195
208
|
}
|
|
196
209
|
return [true, ''];
|
|
@@ -73,7 +73,17 @@ class ProxyManager {
|
|
|
73
73
|
async handleChatCompletions(req, res) {
|
|
74
74
|
try {
|
|
75
75
|
const { messages, stream } = req.body;
|
|
76
|
-
|
|
76
|
+
if (!Array.isArray(messages)) {
|
|
77
|
+
return res.status(400).json({ error: 'Invalid request body: messages must be an array' });
|
|
78
|
+
}
|
|
79
|
+
const content = messages
|
|
80
|
+
.map((message) => {
|
|
81
|
+
if (typeof message !== 'object' || typeof message.content !== 'string') {
|
|
82
|
+
throw new Error('Invalid message format');
|
|
83
|
+
}
|
|
84
|
+
return message.content;
|
|
85
|
+
})
|
|
86
|
+
.join('\n\n');
|
|
77
87
|
const contextFileContents = Object.keys(this.contextFiles)
|
|
78
88
|
.map((file) => `### Contents of ${file}\n\n${this.contextFiles[file]}\n\n`)
|
|
79
89
|
.join('\n');
|
|
@@ -99,7 +109,14 @@ ${content}`;
|
|
|
99
109
|
}
|
|
100
110
|
catch (error) {
|
|
101
111
|
console.error('Error processing request:', error);
|
|
102
|
-
|
|
112
|
+
if (error instanceof Error && error.message === 'Invalid message format') {
|
|
113
|
+
res.status(400).json({
|
|
114
|
+
error: 'Invalid request body: each message must have a content property of type string',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
119
|
+
}
|
|
103
120
|
}
|
|
104
121
|
}
|
|
105
122
|
async handleStreamResponse(prompt, res) {
|
|
@@ -142,17 +142,23 @@ class StreamManager extends events_1.EventEmitter {
|
|
|
142
142
|
* @param {CurrentNewBlock} currentNewBlock - The current and new content of the code block.
|
|
143
143
|
*/
|
|
144
144
|
displayCurrentNewBlock(currentNewBlock) {
|
|
145
|
+
const language = currentNewBlock.language.split('\n')[0];
|
|
146
|
+
process.stdout.write(colors_1.default.gray.bold(`\`\`\`${language} \n`));
|
|
147
|
+
process.stdout.write(colors_1.default.gray.bold(`<<<<<<< CURRENT ${currentNewBlock.filePath}\n`));
|
|
145
148
|
try {
|
|
146
|
-
process.stdout.write(
|
|
147
|
-
process.stdout.write(colors_1.default.gray.bold(`<<<<<<< CURRENT ${currentNewBlock.filePath}\n`));
|
|
148
|
-
process.stdout.write((0, cli_highlight_1.default)(currentNewBlock.currentContent, { language: currentNewBlock.language }));
|
|
149
|
-
process.stdout.write(colors_1.default.gray.bold('\n=======\n'));
|
|
150
|
-
process.stdout.write((0, cli_highlight_1.default)(currentNewBlock.newContent, { language: currentNewBlock.language }));
|
|
151
|
-
process.stdout.write(colors_1.default.gray.bold('\n>>>>>>> NEW\n```'));
|
|
149
|
+
process.stdout.write((0, cli_highlight_1.default)(currentNewBlock.currentContent, { language }));
|
|
152
150
|
}
|
|
153
151
|
catch (error) {
|
|
154
|
-
|
|
152
|
+
process.stdout.write(currentNewBlock.currentContent);
|
|
155
153
|
}
|
|
154
|
+
process.stdout.write(colors_1.default.gray.bold('\n=======\n'));
|
|
155
|
+
try {
|
|
156
|
+
process.stdout.write((0, cli_highlight_1.default)(currentNewBlock.newContent, { language }));
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
process.stdout.write(currentNewBlock.newContent);
|
|
160
|
+
}
|
|
161
|
+
process.stdout.write(colors_1.default.gray.bold('\n>>>>>>> NEW\n```'));
|
|
156
162
|
}
|
|
157
163
|
/**
|
|
158
164
|
* Displays a raw code block.
|
|
@@ -235,27 +241,38 @@ class StreamManager extends events_1.EventEmitter {
|
|
|
235
241
|
* @returns {Promise<void>}
|
|
236
242
|
*/
|
|
237
243
|
async loadContextFiles() {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
try {
|
|
245
|
+
const config = (0, config_utils_1.getClovingConfig)();
|
|
246
|
+
const primaryLanguage = config.languages.find((lang) => lang.primary);
|
|
247
|
+
const defaultDirectory = primaryLanguage ? primaryLanguage.directory : '.';
|
|
248
|
+
const testingDirectories = config.testingFrameworks?.map((framework) => framework.directory) || [];
|
|
249
|
+
const testingDirectory = testingDirectories[0];
|
|
250
|
+
let files = this.options.files || [defaultDirectory, testingDirectory].filter(Boolean);
|
|
251
|
+
if (files.length > 0) {
|
|
252
|
+
console.log(`\nBuilding AI prompt context...\n`);
|
|
253
|
+
}
|
|
254
|
+
for (const file of files) {
|
|
255
|
+
// Skip if the file is not a string
|
|
256
|
+
if (!file)
|
|
257
|
+
continue;
|
|
258
|
+
try {
|
|
259
|
+
const previousCount = Object.keys(this.contextFiles).length;
|
|
260
|
+
this.contextFiles = await (0, prompt_utils_2.addFileOrDirectoryToContext)(file, this.contextFiles, this.options);
|
|
261
|
+
const newCount = Object.keys(this.contextFiles).length;
|
|
262
|
+
const addedCount = newCount - previousCount;
|
|
263
|
+
const totalTokens = this.calculateTotalTokens();
|
|
264
|
+
console.log(colors_1.default.cyan(`📁 Loaded context from: ${colors_1.default.bold(file)}`));
|
|
265
|
+
console.log(colors_1.default.green(` ✅ Added ${addedCount} file(s) to context`));
|
|
266
|
+
console.log(colors_1.default.yellow(` 📊 Total tokens in context: ${totalTokens.toLocaleString()}\n`));
|
|
267
|
+
}
|
|
268
|
+
catch (fileError) {
|
|
269
|
+
console.error(colors_1.default.red(`Error loading context from ${file}:`), fileError);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
246
272
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
continue;
|
|
251
|
-
const previousCount = Object.keys(this.contextFiles).length;
|
|
252
|
-
this.contextFiles = await (0, prompt_utils_2.addFileOrDirectoryToContext)(file, this.contextFiles, this.options);
|
|
253
|
-
const newCount = Object.keys(this.contextFiles).length;
|
|
254
|
-
const addedCount = newCount - previousCount;
|
|
255
|
-
const totalTokens = this.calculateTotalTokens();
|
|
256
|
-
console.log(colors_1.default.cyan(`📁 Loaded context from: ${colors_1.default.bold(file)}`));
|
|
257
|
-
console.log(colors_1.default.green(` ✅ Added ${addedCount} file(s) to context`));
|
|
258
|
-
console.log(colors_1.default.yellow(` 📊 Total tokens in context: ${totalTokens.toLocaleString()}\n`));
|
|
273
|
+
catch (error) {
|
|
274
|
+
console.error(colors_1.default.red('Error loading context files:'), error);
|
|
275
|
+
throw new Error('Failed to load context files');
|
|
259
276
|
}
|
|
260
277
|
}
|
|
261
278
|
calculateTotalTokens() {
|
package/dist/package.json
CHANGED
|
@@ -19,18 +19,19 @@
|
|
|
19
19
|
|
|
20
20
|
## *CURRENT/NEW* Block Format
|
|
21
21
|
|
|
22
|
-
1. **Start a block with a one line description of change
|
|
23
|
-
|
|
22
|
+
1. **Start a block with a one line description of change followed by three backticks and the language name like this:**
|
|
23
|
+
About to add documentation to the `UserService` class.
|
|
24
|
+
|
|
24
25
|
```typescript
|
|
25
|
-
2. **Next line: seven <, CURRENT, and the file path
|
|
26
|
+
2. **Next line: seven <, CURRENT, and the file path like this:**
|
|
26
27
|
<<<<<<< CURRENT path/to/file.ts
|
|
27
|
-
3. **Include the exact existing code to be changed, this section should always have some code characters in it, not just spaces or tabs
|
|
28
|
-
4. **Divide with seven
|
|
28
|
+
3. **Include the exact existing code to be changed, this section should always have some code characters in it, not just spaces or tabs.**
|
|
29
|
+
4. **Divide with seven = like this:**
|
|
29
30
|
=======
|
|
30
31
|
5. **Add the new code.**
|
|
31
|
-
6. **End with seven > and NEW
|
|
32
|
+
6. **End with seven > and NEW like this:**
|
|
32
33
|
>>>>>>> NEW
|
|
33
|
-
7. **Close the block with three backticks
|
|
34
|
+
7. **Close the block with three backticks like this:**
|
|
34
35
|
```
|
|
35
36
|
|
|
36
37
|
## Don't Invent Code That Isn't Provided in Context
|
|
@@ -474,10 +474,18 @@ const checkBlocksApplicability = async (blocks) => {
|
|
|
474
474
|
for (const [index, block] of blocks.entries()) {
|
|
475
475
|
const filePath = path_1.default.resolve(block.filePath);
|
|
476
476
|
let fileContent = await readFileContent(filePath);
|
|
477
|
-
if (
|
|
477
|
+
if (block.newContent.trim() === '') {
|
|
478
|
+
allApplicable = false;
|
|
479
|
+
summary.push(`[${index + 1}] ${colors_1.default.red.bold(block.filePath)} ${colors_1.default.red.bold('cannot be applied: New content is empty')}`);
|
|
480
|
+
}
|
|
481
|
+
else if (fileContent === '') {
|
|
478
482
|
summary.push(`[${index + 1}] ${colors_1.default.green.bold(block.filePath)} can be ${colors_1.default.green.bold('created')}`);
|
|
479
483
|
}
|
|
480
|
-
else if (block.currentContent.trim()
|
|
484
|
+
else if (block.currentContent.trim() === '') {
|
|
485
|
+
allApplicable = false;
|
|
486
|
+
summary.push(`[${index + 1}] ${colors_1.default.red.bold(block.filePath)} ${colors_1.default.red.bold(`cannot be applied: File '${block.filePath}' already exists`)}`);
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
481
489
|
const { matchingLines } = await analyzeBlockContent(block, fileContent);
|
|
482
490
|
if (matchingLines.length === 0) {
|
|
483
491
|
allApplicable = false;
|
|
@@ -491,9 +499,6 @@ const checkBlocksApplicability = async (blocks) => {
|
|
|
491
499
|
summary.push(`[${index + 1}] ${colors_1.default.green.bold(block.filePath)} can be ${colors_1.default.yellow.bold('updated')}`);
|
|
492
500
|
}
|
|
493
501
|
}
|
|
494
|
-
else {
|
|
495
|
-
summary.push(`[${index + 1}] ${colors_1.default.green.bold(block.filePath)} can be ${colors_1.default.yellow.bold('updated')}`);
|
|
496
|
-
}
|
|
497
502
|
}
|
|
498
503
|
return [allApplicable, summary.join('\n')];
|
|
499
504
|
};
|