cloving 0.3.12 → 0.3.14
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/index.js +0 -0
- package/dist/managers/BlockManager.js +20 -7
- package/dist/managers/ChatManager.js +40 -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
- package/dist/abstract_gpt/index.js +0 -55
- package/dist/cloving_gpt/adapters/Adapter.js +0 -2
- package/dist/cloving_gpt/adapters/gpt4all.js +0 -29
- package/dist/commands/analyze.js +0 -47
- package/dist/commands/check.js +0 -7
- package/dist/commands/commit.js +0 -44
- package/dist/commands/describe.js +0 -235
- package/dist/commands/generate/documentation.js +0 -11
- package/dist/commands/generate/fizzbuzz.js +0 -35
- package/dist/commands/generate/init.js +0 -15
- package/dist/commands/generate/sh.js +0 -95
- package/dist/commands/project/build.js +0 -88
- package/dist/commands/project/complete.js +0 -12
- package/dist/commands/project/init.js +0 -82
- package/dist/commands/project/plan.js +0 -108
- package/dist/commands/review.js +0 -50
- package/dist/commands/unit_tests.js +0 -150
- package/dist/commands/update.js +0 -7
- package/dist/file2.js +0 -4
- package/dist/managers/DocumentationManager.js +0 -114
- package/dist/managers/src/managers/ProxyManager.js +0 -1
- package/dist/newfile.js +0 -2
- package/dist/utils/command_utils.js +0 -384
- package/dist/utils/gitUtils.js +0 -42
- package/dist/utils/modelUtils.js +0 -7
|
@@ -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.
|
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -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,14 @@ class ChatManager extends StreamManager_1.default {
|
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
101
|
const trimmedLine = line.trim();
|
|
102
|
+
if (this.isPastedCode(trimmedLine)) {
|
|
103
|
+
this.multilineInput = trimmedLine;
|
|
104
|
+
this.isMultilineMode = true;
|
|
105
|
+
await this.handleCommand(this.multilineInput);
|
|
106
|
+
this.multilineInput = '';
|
|
107
|
+
this.isMultilineMode = false;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
101
110
|
if (this.handleMultilineInput(trimmedLine)) {
|
|
102
111
|
return;
|
|
103
112
|
}
|
|
@@ -133,6 +142,10 @@ class ChatManager extends StreamManager_1.default {
|
|
|
133
142
|
}
|
|
134
143
|
return false;
|
|
135
144
|
}
|
|
145
|
+
isPastedCode(line) {
|
|
146
|
+
// Check if the line contains multiple lines (indicating a paste)
|
|
147
|
+
return line.includes('\n') || line.length > 100;
|
|
148
|
+
}
|
|
136
149
|
handleExitCommand(command) {
|
|
137
150
|
if (command.toLowerCase() === 'exit') {
|
|
138
151
|
this.rl.close();
|
|
@@ -178,6 +191,11 @@ class ChatManager extends StreamManager_1.default {
|
|
|
178
191
|
if (matchingCommand) {
|
|
179
192
|
command = matchingCommand.split(' ')[0]; // Use only the command part without arguments
|
|
180
193
|
}
|
|
194
|
+
else {
|
|
195
|
+
console.log(`No matching command found for '${command}'. Processing as user input.`);
|
|
196
|
+
await this.processUserInput(command);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
181
199
|
}
|
|
182
200
|
switch (command) {
|
|
183
201
|
case 'help':
|
|
@@ -438,7 +456,7 @@ class ChatManager extends StreamManager_1.default {
|
|
|
438
456
|
try {
|
|
439
457
|
await this.refreshContext();
|
|
440
458
|
this.addUserPrompt(this.generatePrompt(input));
|
|
441
|
-
if (!this.
|
|
459
|
+
if (!this.gpt.silent) {
|
|
442
460
|
const fullPrompt = this.chatHistory
|
|
443
461
|
.map((m) => {
|
|
444
462
|
const content = m.content
|
|
@@ -461,25 +479,11 @@ class ChatManager extends StreamManager_1.default {
|
|
|
461
479
|
// Review the prompt using the REPL
|
|
462
480
|
const tokenCount = Math.ceil(fullPrompt.length / 4).toLocaleString();
|
|
463
481
|
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
|
-
});
|
|
482
|
+
const reviewPrompt = await this.askQuestion('cloving> ');
|
|
469
483
|
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'));
|
|
484
|
+
this.reviewPrompt(fullPrompt);
|
|
477
485
|
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
|
-
});
|
|
486
|
+
const confirmPrompt = await this.askQuestion('cloving> ');
|
|
483
487
|
if (!confirmPrompt.startsWith('y') && confirmPrompt !== '') {
|
|
484
488
|
console.log('Operation cancelled by user.');
|
|
485
489
|
this.isProcessing = false;
|
|
@@ -498,9 +502,26 @@ class ChatManager extends StreamManager_1.default {
|
|
|
498
502
|
this.handleError(err);
|
|
499
503
|
}
|
|
500
504
|
}
|
|
505
|
+
askQuestion(prompt) {
|
|
506
|
+
return new Promise((resolve) => {
|
|
507
|
+
this.rl.question(colors_1.default.green.bold(prompt), (answer) => {
|
|
508
|
+
resolve(answer.trim().toLowerCase());
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
reviewPrompt(fullPrompt) {
|
|
513
|
+
console.log(colors_1.default.gray.bold('\n---------------------- PROMPT START ----------------------\n'));
|
|
514
|
+
const promptParts = fullPrompt.split('\n```');
|
|
515
|
+
const highlightedPrompt = promptParts
|
|
516
|
+
.map((part, index) => (index % 2 === 1 ? (0, cli_highlight_1.default)(part, { language: 'typescript' }) : part))
|
|
517
|
+
.join('\n```');
|
|
518
|
+
console.log(highlightedPrompt);
|
|
519
|
+
console.log(colors_1.default.gray.bold('\n---------------------- PROMPT END ----------------------\n'));
|
|
520
|
+
}
|
|
501
521
|
async finalizeResponse() {
|
|
502
522
|
this.addAssistantResponse(this.responseString);
|
|
503
523
|
this.isProcessing = false;
|
|
524
|
+
process.stdout.write('\b'.repeat(100));
|
|
504
525
|
if (this.responseString !== '') {
|
|
505
526
|
const currentNewBlocks = (0, string_utils_1.extractCurrentNewBlocks)(this.responseString);
|
|
506
527
|
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
|
};
|
package/package.json
CHANGED
|
@@ -1,55 +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
|
-
const axios_1 = __importDefault(require("axios"));
|
|
7
|
-
class AbstractGPT {
|
|
8
|
-
constructor() {
|
|
9
|
-
const clovingModel = process.env.CLOVING_MODEL;
|
|
10
|
-
this.apiKey = process.env.CLOVING_API_KEY || '';
|
|
11
|
-
if (!clovingModel || !this.apiKey) {
|
|
12
|
-
throw new Error("CLOVING_MODEL and CLOVING_API_KEY environment variables must be set");
|
|
13
|
-
}
|
|
14
|
-
const [provider, model] = clovingModel.split(':');
|
|
15
|
-
this.provider = provider;
|
|
16
|
-
this.model = model;
|
|
17
|
-
}
|
|
18
|
-
getEndpoint() {
|
|
19
|
-
switch (this.provider) {
|
|
20
|
-
case 'openai':
|
|
21
|
-
return `https://api.openai.com/v1/engines/${this.model}/completions`;
|
|
22
|
-
case 'claude':
|
|
23
|
-
return `https://api.anthropic.com/v1/claude/${this.model}`;
|
|
24
|
-
case 'gpt4all':
|
|
25
|
-
return `https://api.gpt4all.io/v1/models/${this.model}/completions`;
|
|
26
|
-
default:
|
|
27
|
-
throw new Error(`Unsupported provider: ${this.provider}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
async generateText(request) {
|
|
31
|
-
const endpoint = this.getEndpoint();
|
|
32
|
-
const response = await axios_1.default.post(endpoint, {
|
|
33
|
-
model: this.model,
|
|
34
|
-
prompt: request.prompt,
|
|
35
|
-
max_tokens: request.maxTokens || 100,
|
|
36
|
-
temperature: request.temperature || 0.7
|
|
37
|
-
}, {
|
|
38
|
-
headers: {
|
|
39
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
40
|
-
'Content-Type': 'application/json'
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
switch (this.provider) {
|
|
44
|
-
case 'openai':
|
|
45
|
-
return response.data.choices[0].text;
|
|
46
|
-
case 'claude':
|
|
47
|
-
return response.data.completion;
|
|
48
|
-
case 'gpt4all':
|
|
49
|
-
return response.data.text;
|
|
50
|
-
default:
|
|
51
|
-
throw new Error(`Unsupported provider: ${this.provider}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
exports.default = AbstractGPT;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GPT4AllAdapter = void 0;
|
|
4
|
-
class GPT4AllAdapter {
|
|
5
|
-
constructor(model) {
|
|
6
|
-
this.model = model;
|
|
7
|
-
}
|
|
8
|
-
getEndpoint() {
|
|
9
|
-
return `https://api.gpt4all.io/v1/models/${this.model}/completions`;
|
|
10
|
-
}
|
|
11
|
-
getHeaders(apiKey) {
|
|
12
|
-
return {
|
|
13
|
-
'Authorization': `Bearer ${apiKey}`,
|
|
14
|
-
'Content-Type': 'application/json'
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
getPayload(request) {
|
|
18
|
-
return {
|
|
19
|
-
model: this.model,
|
|
20
|
-
prompt: request.prompt,
|
|
21
|
-
max_tokens: request.maxTokens,
|
|
22
|
-
temperature: request.temperature || 0.7
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
extractResponse(data) {
|
|
26
|
-
return data.text;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
exports.GPT4AllAdapter = GPT4AllAdapter;
|
package/dist/commands/analyze.js
DELETED
|
@@ -1,47 +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
|
-
const readline_1 = __importDefault(require("readline"));
|
|
7
|
-
const child_process_1 = require("child_process");
|
|
8
|
-
const git_utils_1 = require("../utils/git_utils");
|
|
9
|
-
const model_utils_1 = require("../utils/model_utils");
|
|
10
|
-
const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
|
|
11
|
-
const analyze = async () => {
|
|
12
|
-
try {
|
|
13
|
-
// Define the prompt for analysis
|
|
14
|
-
const gitDiff = await (0, git_utils_1.getGitDiff)();
|
|
15
|
-
const model = (0, model_utils_1.getModel)();
|
|
16
|
-
const prompt = `Explain why the change is being made and document a description of these changes.
|
|
17
|
-
Also list any bugs in the new code as well as recommended fixes for those bugs with code examples.
|
|
18
|
-
|
|
19
|
-
${gitDiff}`;
|
|
20
|
-
// Instantiate ClovingGPT and get the analysis
|
|
21
|
-
const gpt = new cloving_gpt_1.default();
|
|
22
|
-
const analysis = await gpt.generateText({ prompt });
|
|
23
|
-
// Print the analysis to the console
|
|
24
|
-
console.log(analysis);
|
|
25
|
-
// Prompt the user to copy the analysis to the clipboard
|
|
26
|
-
const rl = readline_1.default.createInterface({
|
|
27
|
-
input: process.stdin,
|
|
28
|
-
output: process.stdout
|
|
29
|
-
});
|
|
30
|
-
rl.question('Do you want to copy the analysis to the clipboard? [Y/n] ', (answer) => {
|
|
31
|
-
if (answer.toLowerCase() === 'y' || answer === '') {
|
|
32
|
-
try {
|
|
33
|
-
(0, child_process_1.execFileSync)('pbcopy', { input: analysis });
|
|
34
|
-
console.log('Analysis copied to clipboard');
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
console.error('Error: pbcopy command not found. Unable to copy to clipboard.');
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
rl.close();
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
console.error('Error during analysis:', error.message);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
exports.default = analyze;
|