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
- // when getting ` , just add it to the buffer until we get a char that isn't `
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 codeParts = this.parseCodeBuffer();
70
- if (codeParts) {
71
- const { language, currentStart, newEnd, currentCode, newCode } = codeParts;
67
+ const currentNewBlock = this.parseCodeBuffer();
68
+ if (currentNewBlock) {
72
69
  this.emit('codeBlock', {
73
- language,
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('content', this.codeBuffer);
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 {{ language: string, currentStart: string, newEnd: string, current: string, newCode: string, afterCode: string }}
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 lines = this.codeBuffer.split('\n');
101
- const language = lines[0].trim().slice(3); // Remove '```' from the language line
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
- process.stdout.write(colors_1.default.gray.bold(`\`\`\`${codeBlock.language} \n`));
625
- process.stdout.write(colors_1.default.gray.bold(`${codeBlock.currentStart}\n`));
626
- process.stdout.write((0, cli_highlight_1.default)(codeBlock.currentCode, { language: codeBlock.language }));
627
- process.stdout.write(colors_1.default.gray.bold('\n=======\n'));
628
- process.stdout.write((0, cli_highlight_1.default)(codeBlock.newCode, { language: codeBlock.language }));
629
- process.stdout.write(colors_1.default.gray.bold('\n>>>>>>> NEW\n```'));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloving",
3
- "version": "0.3.6",
3
+ "version": "0.3.9",
4
4
  "packageManager": "yarn@1.22.22",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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<<<<<<< CURRENT';
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 filePathStart = blockStart + BLOCK_START.length;
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: blockStart,
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 filePath = input.slice(indices.start + BLOCK_START.length, indices.filePathEnd).trim();
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());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloving",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "packageManager": "yarn@1.22.22",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",