cloving 0.3.7 → 0.3.9
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.
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const events_1 = require("events");
|
|
4
|
+
const string_utils_1 = require("../utils/string_utils");
|
|
4
5
|
// Passes through string chunks, looking for code blocks, when it finds one, it starts buffering until it finds the end of the block
|
|
5
6
|
// Then it emits the code block and clears the buffer and continues
|
|
6
7
|
class BlockManager extends events_1.EventEmitter {
|
|
@@ -13,8 +14,7 @@ class BlockManager extends events_1.EventEmitter {
|
|
|
13
14
|
}
|
|
14
15
|
// add content to the buffer, watching for code blocks along the way
|
|
15
16
|
addContent(content) {
|
|
16
|
-
|
|
17
|
-
if (content.includes('`')) {
|
|
17
|
+
if (content.includes('`') || content.includes('\n')) {
|
|
18
18
|
this.isWaitingForContent = true;
|
|
19
19
|
this.buffer += content;
|
|
20
20
|
return;
|
|
@@ -23,13 +23,13 @@ class BlockManager extends events_1.EventEmitter {
|
|
|
23
23
|
content = this.buffer + content;
|
|
24
24
|
this.buffer = '';
|
|
25
25
|
}
|
|
26
|
+
this.processCodeBlocks(content);
|
|
27
|
+
}
|
|
28
|
+
processCodeBlocks(content) {
|
|
26
29
|
const codeBlockMarker = '\n```';
|
|
27
30
|
let markerIndex = content.indexOf(codeBlockMarker);
|
|
28
|
-
if (content.startsWith('```'))
|
|
29
|
-
markerIndex = 0;
|
|
30
31
|
if (markerIndex !== -1) {
|
|
31
32
|
if (this.isBufferingCode) {
|
|
32
|
-
// End of code block
|
|
33
33
|
this.codeBuffer += content.slice(0, markerIndex + codeBlockMarker.length);
|
|
34
34
|
const rest = content.slice(markerIndex + codeBlockMarker.length);
|
|
35
35
|
this.emit('endGeneratingCode');
|
|
@@ -37,7 +37,6 @@ class BlockManager extends events_1.EventEmitter {
|
|
|
37
37
|
this.emit('content', rest);
|
|
38
38
|
}
|
|
39
39
|
else {
|
|
40
|
-
// Start of code block
|
|
41
40
|
this.emitBuffer(content.slice(0, markerIndex));
|
|
42
41
|
this.codeBuffer = content.slice(markerIndex);
|
|
43
42
|
this.emit('startGeneratingCode');
|
|
@@ -45,7 +44,6 @@ class BlockManager extends events_1.EventEmitter {
|
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
else {
|
|
48
|
-
// No code block marker found
|
|
49
47
|
if (this.isBufferingCode) {
|
|
50
48
|
this.codeBuffer += content;
|
|
51
49
|
}
|
|
@@ -66,22 +64,17 @@ class BlockManager extends events_1.EventEmitter {
|
|
|
66
64
|
}
|
|
67
65
|
emitCodeBlock() {
|
|
68
66
|
if (this.codeBuffer.length > 0) {
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
const { language, currentStart, newEnd, currentCode, newCode } = codeParts;
|
|
67
|
+
const currentNewBlock = this.parseCodeBuffer();
|
|
68
|
+
if (currentNewBlock) {
|
|
72
69
|
this.emit('codeBlock', {
|
|
73
|
-
|
|
74
|
-
currentStart,
|
|
75
|
-
newEnd,
|
|
76
|
-
currentCode,
|
|
77
|
-
newCode,
|
|
70
|
+
currentNewBlock,
|
|
78
71
|
raw: this.codeBuffer,
|
|
79
72
|
});
|
|
80
73
|
this.emit('content', this.buffer);
|
|
81
74
|
this.clearBuffer();
|
|
82
75
|
}
|
|
83
76
|
else {
|
|
84
|
-
this.emit('
|
|
77
|
+
this.emit('codeBlock', this.codeBuffer);
|
|
85
78
|
this.clearBuffer();
|
|
86
79
|
}
|
|
87
80
|
}
|
|
@@ -93,27 +86,12 @@ class BlockManager extends events_1.EventEmitter {
|
|
|
93
86
|
* current start index, divider index, and new end index. It then extracts the current code and new code
|
|
94
87
|
* from the buffer based on these indices.
|
|
95
88
|
*
|
|
96
|
-
* @return {
|
|
89
|
+
* @return {CurrentNewBlock | null}
|
|
97
90
|
* An object containing the language, current start, new end, current code, and new code.
|
|
98
91
|
*/
|
|
99
92
|
parseCodeBuffer() {
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
const currentStartIndex = lines.findIndex((line) => line.startsWith('<<<<<<< CURRENT'));
|
|
103
|
-
const dividerIndex = lines.findIndex((line) => line === '=======');
|
|
104
|
-
const newEndIndex = lines.findIndex((line) => line.startsWith('>>>>>>> NEW'));
|
|
105
|
-
if (currentStartIndex === -1 || dividerIndex === -1 || newEndIndex === -1) {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
const currentCode = lines.slice(currentStartIndex + 1, dividerIndex).join('\n');
|
|
109
|
-
const newCode = lines.slice(dividerIndex + 1, newEndIndex).join('\n');
|
|
110
|
-
return {
|
|
111
|
-
language,
|
|
112
|
-
currentStart: lines[currentStartIndex],
|
|
113
|
-
newEnd: lines[newEndIndex],
|
|
114
|
-
currentCode,
|
|
115
|
-
newCode,
|
|
116
|
-
};
|
|
93
|
+
const results = (0, string_utils_1.extractCurrentNewBlocks)(this.codeBuffer);
|
|
94
|
+
return results[0];
|
|
117
95
|
}
|
|
118
96
|
clearBuffer() {
|
|
119
97
|
this.buffer = '';
|
|
@@ -621,12 +621,26 @@ class ChatManager {
|
|
|
621
621
|
accumulatedContent += content;
|
|
622
622
|
});
|
|
623
623
|
this.blockManager.on('codeBlock', (codeBlock) => {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
624
|
+
const { currentNewBlock } = codeBlock;
|
|
625
|
+
if (currentNewBlock?.currentContent && currentNewBlock?.newContent) {
|
|
626
|
+
// Current/New format
|
|
627
|
+
process.stdout.write(colors_1.default.gray.bold(`\`\`\`${currentNewBlock.language} \n`));
|
|
628
|
+
process.stdout.write(colors_1.default.gray.bold(`<<<<<<< CURRENT ${currentNewBlock.filePath}\n`));
|
|
629
|
+
process.stdout.write((0, cli_highlight_1.default)(currentNewBlock.currentContent, { language: currentNewBlock.language }));
|
|
630
|
+
process.stdout.write(colors_1.default.gray.bold('\n=======\n'));
|
|
631
|
+
process.stdout.write((0, cli_highlight_1.default)(currentNewBlock.newContent, { language: currentNewBlock.language }));
|
|
632
|
+
process.stdout.write(colors_1.default.gray.bold('\n>>>>>>> NEW\n```'));
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
if (codeBlock.raw) {
|
|
636
|
+
// Raw format
|
|
637
|
+
process.stdout.write(` \n`);
|
|
638
|
+
process.stdout.write((0, cli_highlight_1.default)(codeBlock.raw));
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
process.stdout.write(` \n`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
630
644
|
accumulatedContent += codeBlock.raw;
|
|
631
645
|
});
|
|
632
646
|
// Handle content chunks from the ChunkManager
|
package/dist/package.json
CHANGED
|
@@ -36,7 +36,7 @@ exports.CODEGEN_INSTRUCTIONS = `## AI Code Generation Instructions
|
|
|
36
36
|
\`\`\`typescript
|
|
37
37
|
2. **Next line: seven <, CURRENT, and the file path.**
|
|
38
38
|
<<<<<<< CURRENT path/to/file.ts
|
|
39
|
-
3. **Include the exact existing code to be changed.**
|
|
39
|
+
3. **Include the exact existing code to be changed, this section should never be just spaces or tabs unless it is a new file.**
|
|
40
40
|
4. **Divide with seven =.**
|
|
41
41
|
=======
|
|
42
42
|
5. **Add the new code.**
|
|
@@ -7,9 +7,10 @@ exports.checkBlocksApplicability = exports.applyAndSaveCurrentNewBlocks = export
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const colors_1 = __importDefault(require("colors"));
|
|
10
|
-
const BLOCK_START = '\n
|
|
10
|
+
const BLOCK_START = '\n```';
|
|
11
|
+
const BLOCK_CURRENT = '\n<<<<<<< CURRENT';
|
|
11
12
|
const BLOCK_DIVIDER = '\n=======';
|
|
12
|
-
const BLOCK_END = '\n>>>>>>> NEW';
|
|
13
|
+
const BLOCK_END = '\n>>>>>>> NEW\n```';
|
|
13
14
|
// Function to estimate token count
|
|
14
15
|
const estimateTokens = async (text) => {
|
|
15
16
|
const charCount = text.length;
|
|
@@ -65,6 +66,13 @@ const extractJsonMetadata = (response) => {
|
|
|
65
66
|
if (jsonEndIndex !== -1) {
|
|
66
67
|
jsonString = jsonString.substring(0, jsonEndIndex + 1);
|
|
67
68
|
}
|
|
69
|
+
// sanity check that the extracted string is valid JSON
|
|
70
|
+
try {
|
|
71
|
+
JSON.parse(jsonString);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
jsonString = '';
|
|
75
|
+
}
|
|
68
76
|
return jsonString;
|
|
69
77
|
};
|
|
70
78
|
exports.extractJsonMetadata = extractJsonMetadata;
|
|
@@ -171,7 +179,12 @@ const findBlockIndices = (input, startIndex) => {
|
|
|
171
179
|
const blockStart = input.indexOf(BLOCK_START, startIndex);
|
|
172
180
|
if (blockStart === -1)
|
|
173
181
|
return null;
|
|
174
|
-
const
|
|
182
|
+
const languageStart = blockStart + BLOCK_START.length;
|
|
183
|
+
const languageEnd = input.indexOf('\n', languageStart);
|
|
184
|
+
if (languageEnd === -1)
|
|
185
|
+
return null;
|
|
186
|
+
const currentStart = input.indexOf(BLOCK_CURRENT, startIndex);
|
|
187
|
+
const filePathStart = currentStart + BLOCK_CURRENT.length;
|
|
175
188
|
const filePathEnd = input.indexOf('\n', filePathStart);
|
|
176
189
|
const dividerIndex = input.indexOf(BLOCK_DIVIDER, filePathEnd);
|
|
177
190
|
if (dividerIndex === -1)
|
|
@@ -180,7 +193,8 @@ const findBlockIndices = (input, startIndex) => {
|
|
|
180
193
|
if (blockEnd === -1)
|
|
181
194
|
return null;
|
|
182
195
|
return {
|
|
183
|
-
start:
|
|
196
|
+
start: languageStart,
|
|
197
|
+
current: currentStart,
|
|
184
198
|
filePathEnd,
|
|
185
199
|
divider: dividerIndex,
|
|
186
200
|
end: blockEnd,
|
|
@@ -198,10 +212,11 @@ exports.findBlockIndices = findBlockIndices;
|
|
|
198
212
|
* @returns {CurrentNewBlock} An object containing the extracted file path, current content, and new content.
|
|
199
213
|
*/
|
|
200
214
|
const extractBlock = (input, indices) => {
|
|
201
|
-
const
|
|
215
|
+
const language = input.slice(indices.start, indices.current).trim();
|
|
216
|
+
const filePath = input.slice(indices.current + BLOCK_CURRENT.length, indices.filePathEnd).trim();
|
|
202
217
|
const currentContent = input.slice(indices.filePathEnd + 1, indices.divider).trim();
|
|
203
218
|
const newContent = input.slice(indices.divider + BLOCK_DIVIDER.length, indices.end).trim();
|
|
204
|
-
return { filePath, currentContent, newContent };
|
|
219
|
+
return { language, filePath, currentContent, newContent };
|
|
205
220
|
};
|
|
206
221
|
exports.extractBlock = extractBlock;
|
|
207
222
|
/**
|
|
@@ -211,22 +226,25 @@ exports.extractBlock = extractBlock;
|
|
|
211
226
|
* Each block contains information about file paths, current content, and new content.
|
|
212
227
|
*
|
|
213
228
|
* The blocks are defined by specific delimiters:
|
|
229
|
+
* - Setup: '```lang'
|
|
214
230
|
* - Start: '<<<<<<< CURRENT'
|
|
215
231
|
* - Divider: '======='
|
|
216
232
|
* - End: '>>>>>>> NEW'
|
|
233
|
+
* - Finish: '```'
|
|
217
234
|
*
|
|
218
235
|
* @param {string} [input] - The input string containing CURRENT/NEW blocks.
|
|
219
236
|
* @returns {CurrentNewBlock[]} An array of CurrentNewBlock objects, each representing a parsed block.
|
|
220
237
|
* If the input is undefined or empty, an empty array is returned.
|
|
221
238
|
*
|
|
222
239
|
* @example
|
|
223
|
-
* const input =
|
|
240
|
+
* const input = "
|
|
241
|
+
* ```typescript
|
|
224
242
|
* <<<<<<< CURRENT path/to/file.ts
|
|
225
243
|
* const oldCode = 'old'
|
|
226
244
|
* =======
|
|
227
245
|
* const newCode = 'new'
|
|
228
246
|
* >>>>>>> NEW
|
|
229
|
-
*
|
|
247
|
+
* ```"
|
|
230
248
|
* const blocks = extractCurrentNewBlocks(input)
|
|
231
249
|
* // blocks will contain one CurrentNewBlock object with the parsed information
|
|
232
250
|
*/
|
|
@@ -297,6 +315,10 @@ const searchReplaceString = (currentContent, block) => {
|
|
|
297
315
|
if (block.currentContent.trim() === '') {
|
|
298
316
|
return block.newContent;
|
|
299
317
|
}
|
|
318
|
+
// check if you can replace the entire block without changing indentation
|
|
319
|
+
if (currentContent.includes(block.currentContent)) {
|
|
320
|
+
return currentContent.replace(block.currentContent, block.newContent);
|
|
321
|
+
}
|
|
300
322
|
// 2) split currentContent and block.currentContent into new lines and trim() all the lines, then put back the new lines
|
|
301
323
|
const currentLines = currentContent.split('\n').map((line) => line.trim());
|
|
302
324
|
const blockLines = block.currentContent.split('\n').map((line) => line.trim());
|