cloving 0.3.18 → 0.3.19

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.
Files changed (94) hide show
  1. package/.DS_Store +0 -0
  2. package/.aider.chat.history.md +16978 -0
  3. package/.aider.input.history +15 -0
  4. package/.aider.tags.cache.v3/cache.db +0 -0
  5. package/.aider.tags.cache.v3/cache.db-shm +0 -0
  6. package/.aider.tags.cache.v3/cache.db-wal +0 -0
  7. package/.cursorrules +77 -0
  8. package/.github/workflows/auto-release.yml +83 -0
  9. package/.github/workflows/ci.yml +32 -0
  10. package/.github/workflows/npm-publish.yml +34 -0
  11. package/.gitignore +67 -0
  12. package/.husky/_/.gitignore +1 -0
  13. package/.husky/_/applypatch-msg +2 -0
  14. package/.husky/_/commit-msg +2 -0
  15. package/.husky/_/h +22 -0
  16. package/.husky/_/husky.sh +9 -0
  17. package/.husky/_/post-applypatch +2 -0
  18. package/.husky/_/post-checkout +2 -0
  19. package/.husky/_/post-commit +2 -0
  20. package/.husky/_/post-merge +2 -0
  21. package/.husky/_/post-rewrite +2 -0
  22. package/.husky/_/pre-applypatch +2 -0
  23. package/.husky/_/pre-auto-gc +2 -0
  24. package/.husky/_/pre-commit +2 -0
  25. package/.husky/_/pre-merge-commit +2 -0
  26. package/.husky/_/pre-push +2 -0
  27. package/.husky/_/pre-rebase +2 -0
  28. package/.husky/_/prepare-commit-msg +2 -0
  29. package/.husky/pre-commit +1 -0
  30. package/.husky/pre-push +1 -0
  31. package/.prettierrc.json +7 -0
  32. package/.tool-versions +2 -0
  33. package/SECURITY.md +15 -0
  34. package/cloving.json +67 -0
  35. package/dist/managers/CommitManager.js +8 -2
  36. package/dist/package.json +1 -1
  37. package/jest.config.js +11 -0
  38. package/package.json +1 -1
  39. package/src/cloving_gpt/adapters/azureopenai.ts +83 -0
  40. package/src/cloving_gpt/adapters/claude.ts +140 -0
  41. package/src/cloving_gpt/adapters/gemini.ts +146 -0
  42. package/src/cloving_gpt/adapters/index.ts +43 -0
  43. package/src/cloving_gpt/adapters/mistral.ts +142 -0
  44. package/src/cloving_gpt/adapters/ollama.ts +136 -0
  45. package/src/cloving_gpt/adapters/openai.ts +113 -0
  46. package/src/cloving_gpt/index.ts +229 -0
  47. package/src/commands/chat.ts +12 -0
  48. package/src/commands/config.ts +192 -0
  49. package/src/commands/generate/code.ts +18 -0
  50. package/src/commands/generate/commit.ts +9 -0
  51. package/src/commands/generate/context.ts +93 -0
  52. package/src/commands/generate/docs.ts +9 -0
  53. package/src/commands/generate/review.ts +9 -0
  54. package/src/commands/generate/shell.ts +9 -0
  55. package/src/commands/generate/unit_tests.ts +9 -0
  56. package/src/commands/init.ts +9 -0
  57. package/src/commands/models.ts +21 -0
  58. package/src/commands/proxy.ts +9 -0
  59. package/src/commands/tokens.ts +82 -0
  60. package/src/index.ts +197 -0
  61. package/src/managers/BlockManager.ts +126 -0
  62. package/src/managers/ChatManager.ts +755 -0
  63. package/src/managers/ChunkManager.ts +31 -0
  64. package/src/managers/CodeManager.ts +226 -0
  65. package/src/managers/CommitManager.ts +71 -0
  66. package/src/managers/DocsManager.ts +101 -0
  67. package/src/managers/InitManager.ts +263 -0
  68. package/src/managers/ProxyManager.ts +240 -0
  69. package/src/managers/ReviewManager.ts +154 -0
  70. package/src/managers/ShellManager.ts +172 -0
  71. package/src/managers/StreamManager.ts +353 -0
  72. package/src/managers/UnitTestManager.ts +293 -0
  73. package/src/utils/config_utils.ts +271 -0
  74. package/src/utils/git_utils.ts +230 -0
  75. package/src/utils/model_utils.ts +3 -0
  76. package/src/utils/prompt_utils.ts +375 -0
  77. package/src/utils/prompts/CODEGEN_COULDNT_APPLY.md +5 -0
  78. package/src/utils/prompts/CODEGEN_EXAMPLES.md +82 -0
  79. package/src/utils/prompts/CODEGEN_INSTRUCTIONS.md +43 -0
  80. package/src/utils/prompts/DOCS_INSTRUCTIONS.md +9 -0
  81. package/src/utils/prompts/INIT_INSTRUCTIONS.md +132 -0
  82. package/src/utils/prompts/REVIEW_INSTRUCTIONS.md +49 -0
  83. package/src/utils/prompts/SHELL_INSTRUCTIONS.md +15 -0
  84. package/src/utils/prompts/SPECIAL_FILES.md +66 -0
  85. package/src/utils/prompts/index.ts +37 -0
  86. package/src/utils/string_utils.ts +552 -0
  87. package/src/utils/types.ts +127 -0
  88. package/tests/commands/generate/unit_tests.test.ts +27 -0
  89. package/tests/utils/git_utils.test.ts +116 -0
  90. package/tests/utils/model_utils.test.ts +27 -0
  91. package/tests/utils/prompt_utils.test.ts +33 -0
  92. package/tests/utils/string_utils.test.ts +560 -0
  93. package/tsconfig.json +14 -0
  94. package/yarn.lock +5823 -0
@@ -0,0 +1,375 @@
1
+ /**
2
+ * @module prompt_utils
3
+ * @description Provides utility functions for generating prompts, handling files, and running commands.
4
+ */
5
+
6
+ import fs from 'fs'
7
+ import path from 'path'
8
+ import { execSync, spawn } from 'child_process'
9
+ import { isBinaryFile } from 'isbinaryfile'
10
+ import colors from 'colors'
11
+ import { join } from 'path'
12
+
13
+ import { getNearestClovingConfig } from './config_utils'
14
+ import {
15
+ REVIEW_INSTRUCTIONS,
16
+ DOCS_INSTRUCTIONS,
17
+ CODEGEN_INSTRUCTIONS,
18
+ SPECIAL_FILES,
19
+ SHELL_INSTRUCTIONS,
20
+ CODEGEN_EXAMPLES,
21
+ } from './prompts'
22
+
23
+ import type { ClovingGPTOptions } from './types'
24
+
25
+ /**
26
+ * Retrieves the package version from package.json.
27
+ * @returns {string} The version of the package.
28
+ */
29
+ export const getPackageVersion = () => {
30
+ const packagePath = join(__dirname, '..', 'package.json')
31
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'))
32
+ return packageJson.version
33
+ }
34
+
35
+ /**
36
+ * Renders a context file as a string.
37
+ * @param {Record<string, unknown> | string} contextFile - The context file to render.
38
+ * @returns {string} The rendered string representation of the context file.
39
+ */
40
+ const renderAsString = (contextFile: Record<string, unknown> | string): string => {
41
+ if (typeof contextFile === 'string') {
42
+ return contextFile
43
+ }
44
+ return JSON.stringify(contextFile, null, 2)
45
+ }
46
+
47
+ /**
48
+ * Generates a prompt for code generation based on context files and special files.
49
+ * @param {Record<string, string>} contextFilesContent - The content of context files.
50
+ * @returns {string} The generated prompt for code generation.
51
+ */
52
+ export const generateCodegenPrompt = (contextFilesContent: Record<string, string>): string => {
53
+ const specialFileContents = collectSpecialFileContents()
54
+ // detect if specialFileContents[file] is a string or an object
55
+ const specialFiles = Object.keys(specialFileContents)
56
+ .map(
57
+ (file) =>
58
+ `### Contents of **${file}**\n\n\`\`\`\n${renderAsString(specialFileContents[file])}\n\`\`\`\n\n`,
59
+ )
60
+ .join('\n')
61
+ const contextFileContents = Object.keys(contextFilesContent)
62
+ .map(
63
+ (file) => `### Contents of **${file}**\n\n\`\`\`\n${contextFilesContent[file]}\n\`\`\`\n\n`,
64
+ )
65
+ .join('\n')
66
+
67
+ const prompt = `${CODEGEN_INSTRUCTIONS}
68
+
69
+ ## Description of App
70
+
71
+ \`\`\`json
72
+ ${JSON.stringify(getNearestClovingConfig().config, null, 2)}
73
+ \`\`\`
74
+
75
+ ## Special Files
76
+
77
+ ${specialFiles.length > 0 ? specialFiles : 'No special files provided.'}
78
+
79
+ ## Context Files
80
+
81
+ ${contextFileContents.length > 0 ? contextFileContents : 'No context files provided.'}
82
+
83
+ ## Directory structure
84
+
85
+ ${Object.keys(contextFilesContent).join('\n')}
86
+
87
+ ${CODEGEN_INSTRUCTIONS}
88
+
89
+ ${CODEGEN_EXAMPLES}`
90
+ return prompt
91
+ }
92
+
93
+ /**
94
+ * Generates a prompt for documentation generation based on context files and special files.
95
+ * @param {Record<string, string>} contextFilesContent - The content of context files.
96
+ * @returns {string} The generated prompt for documentation generation.
97
+ */
98
+ export const generateDocsPrompt = (contextFilesContent: Record<string, string>): string => {
99
+ const specialFileContents = collectSpecialFileContents()
100
+ const specialFiles = Object.keys(specialFileContents)
101
+ .map(
102
+ (file) =>
103
+ `### Contents of **${file}**\n\n\`\`\`\n${renderAsString(specialFileContents[file])}\n\`\`\`\n\n`,
104
+ )
105
+ .join('\n')
106
+ const contextFileContents = Object.keys(contextFilesContent)
107
+ .map(
108
+ (file) => `### Contents of **${file}**\n\n\`\`\`\n${contextFilesContent[file]}\n\`\`\`\n\n`,
109
+ )
110
+ .join('\n')
111
+
112
+ const prompt = `${DOCS_INSTRUCTIONS}
113
+
114
+ ${CODEGEN_INSTRUCTIONS}
115
+
116
+ ${CODEGEN_EXAMPLES}
117
+
118
+ ## Description of App
119
+
120
+ \`\`\`json
121
+ ${JSON.stringify(getNearestClovingConfig().config, null, 2)}
122
+ \`\`\`
123
+
124
+ ## Special Files
125
+
126
+ ${specialFiles.length > 0 ? specialFiles : 'No special files provided.'}
127
+
128
+ ## Context Files
129
+
130
+ ${contextFileContents.length > 0 ? contextFileContents : 'No context files provided.'}
131
+
132
+ ## Directory structure
133
+
134
+ ${Object.keys(contextFilesContent).join('\n')}
135
+
136
+ ${DOCS_INSTRUCTIONS}`
137
+
138
+ return prompt
139
+ }
140
+
141
+ /**
142
+ * Generates a prompt for shell commands based on the current shell and OS.
143
+ * @returns {string} The generated prompt for shell commands.
144
+ */
145
+ export const generateShellPrompt = (): string => {
146
+ const shell = execSync('echo $SHELL').toString().trim()
147
+ const os = execSync('echo $OSTYPE').toString().trim()
148
+ return `${SHELL_INSTRUCTIONS}\n\n## Context\n\nShell: ${shell}\n\nOS: ${os}`
149
+ }
150
+
151
+ export const generateReviewPrompt = (
152
+ options: ClovingGPTOptions,
153
+ contextFiles: Record<string, string>,
154
+ ): string => {
155
+ let prompt = `${REVIEW_INSTRUCTIONS}`
156
+ if (options.files) {
157
+ const contextFileContents = Object.keys(contextFiles)
158
+ .map((file) => `### Contents of ${file}\n\n${contextFiles[file]}\n\n`)
159
+ .join('\n')
160
+
161
+ prompt += `### Description of App
162
+
163
+ ${JSON.stringify(getNearestClovingConfig().config, null, 2)}
164
+
165
+ ${contextFileContents}
166
+
167
+ ### Request
168
+
169
+ I would like you to explain the code and document a description of it.
170
+ List any bugs in the new code as well as recommended fixes for those bugs with code examples.
171
+ Format the output of this code review in Markdown format.`
172
+ } else {
173
+ prompt += `### Request
174
+
175
+ Do not use any data from the example response structure, only use the structure.
176
+ I would like you to explain why these change are being made and document a description of these changes.
177
+ Also list any bugs in the new code as well as recommended fixes for those bugs with code examples.
178
+ Format the output of this code review in Markdown format.`
179
+ }
180
+
181
+ return prompt
182
+ }
183
+
184
+ /**
185
+ * Collects the contents of special files.
186
+ * @returns {Record<string, string | Record<string, unknown>>} An object containing the contents of special files.
187
+ */
188
+ export const collectSpecialFileContents = (): Record<string, string | Record<string, unknown>> => {
189
+ const specialFileContents: Record<string, string | Record<string, unknown>> = {}
190
+ for (const file of SPECIAL_FILES) {
191
+ if (fs.existsSync(file)) {
192
+ try {
193
+ const content = fs.readFileSync(file, 'utf-8')
194
+ specialFileContents[file] = file.endsWith('.json') ? JSON.parse(content) : content
195
+ } catch (error) {
196
+ specialFileContents[file] = fs.readFileSync(file, 'utf-8')
197
+ }
198
+ }
199
+ }
200
+ return specialFileContents
201
+ }
202
+
203
+ /**
204
+ * Checks if any special files exist in the current directory.
205
+ * @returns {boolean} True if any special files exist, false otherwise.
206
+ */
207
+ export const checkForSpecialFiles = (): boolean => SPECIAL_FILES.some((file) => fs.existsSync(file))
208
+
209
+ /**
210
+ * Recursively gets all non-binary files in a directory.
211
+ * @param {string} dir - The directory to search.
212
+ * @returns {Promise<string[]>} A promise that resolves with an array of file paths.
213
+ */
214
+ export const getAllFilesInDirectory = async (dir: string): Promise<string[]> => {
215
+ const subdirs = await fs.promises.readdir(dir)
216
+ const files = await Promise.all(
217
+ subdirs.map(async (subdir) => {
218
+ const res = path.resolve(dir, subdir)
219
+ if (subdir === 'node_modules' || subdir === '.git' || subdir === '.DS_Store') {
220
+ return []
221
+ }
222
+ const stat = await fs.promises.stat(res)
223
+ if (stat.isDirectory()) {
224
+ return getAllFilesInDirectory(res)
225
+ } else {
226
+ const isBinary = await isBinaryFile(res)
227
+ return isBinary ? [] : res
228
+ }
229
+ }),
230
+ )
231
+ return files.flat()
232
+ }
233
+
234
+ /**
235
+ * Generates a list of files in the current directory and its subdirectories.
236
+ * @returns {Promise<string[]>} A promise that resolves with an array of file paths.
237
+ */
238
+ export const generateFileList = async (): Promise<string[]> => {
239
+ try {
240
+ const lsOutput = await runCommand('ls', [])
241
+ const findOutput = await runCommand('find', ['.'])
242
+ const cleanedFindOutput = findOutput.map((file) =>
243
+ file.startsWith('./') ? file.slice(2) : file,
244
+ )
245
+ const files = [...lsOutput, ...cleanedFindOutput]
246
+ const uniqueFiles = Array.from(new Set(files))
247
+ return uniqueFiles.filter(
248
+ (file) =>
249
+ file && !file.includes('.git') && !file.includes('node_modules') && !file.includes('tmp'),
250
+ )
251
+ } catch (error) {
252
+ console.error('Error generating file list:', (error as Error).message)
253
+ return []
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Runs a shell command and returns its output.
259
+ * @param {string} command - The command to run.
260
+ * @param {string[]} args - The arguments for the command.
261
+ * @returns {Promise<string[]>} A promise that resolves with an array of output lines.
262
+ */
263
+ export const runCommand = (command: string, args: string[]): Promise<string[]> => {
264
+ return new Promise((resolve, reject) => {
265
+ const process = spawn(command, args)
266
+ const output: string[] = []
267
+
268
+ process.stdout.on('data', (data) => {
269
+ output.push(data.toString())
270
+ })
271
+
272
+ process.stderr.on('data', (data) => {
273
+ console.error(`stderr: ${data}`)
274
+ })
275
+
276
+ process.on('close', (code) => {
277
+ if (code !== 0) {
278
+ reject(new Error(`${command} process exited with code ${code}`))
279
+ } else {
280
+ resolve(output.join('').trim().split('\n'))
281
+ }
282
+ })
283
+ })
284
+ }
285
+
286
+ /**
287
+ * Fetches available models using the 'cloving models' command.
288
+ * @returns {Promise<string[]>} A promise that resolves with an array of available models.
289
+ */
290
+ export const fetchModels = async (): Promise<string[]> => {
291
+ try {
292
+ const modelsOutput = await runCommand('cloving', ['models'])
293
+ return modelsOutput
294
+ } catch (error) {
295
+ console.error('Error fetching models:', (error as Error).message)
296
+ return []
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Reads the content of a file.
302
+ * @param {string} file - The path to the file.
303
+ * @returns {string} The content of the file.
304
+ */
305
+ export const readFileContent = (file: string): string => {
306
+ try {
307
+ return fs.readFileSync(file, 'utf-8')
308
+ } catch (error) {
309
+ console.error('Error reading file content:', (error as Error).message)
310
+ return ''
311
+ }
312
+ }
313
+
314
+ const addFileToContext = async (
315
+ filePath: string,
316
+ contextFiles: Record<string, string>,
317
+ baseDir: string,
318
+ ): Promise<void> => {
319
+ const relativePath = path.relative(baseDir, filePath)
320
+ if (await isBinaryFile(filePath)) {
321
+ return
322
+ }
323
+ const content = await fs.promises.readFile(filePath, 'utf-8')
324
+ contextFiles[relativePath] = content
325
+ }
326
+
327
+ const addDirectoryToContext = async (
328
+ dirPath: string,
329
+ contextFiles: Record<string, string>,
330
+ baseDir: string,
331
+ ): Promise<void> => {
332
+ const entries = await fs.promises.readdir(dirPath, { withFileTypes: true })
333
+ for (const entry of entries) {
334
+ const fullPath = path.join(dirPath, entry.name)
335
+ if (entry.isDirectory()) {
336
+ if (entry.name !== 'node_modules' && entry.name !== '.git') {
337
+ await addDirectoryToContext(fullPath, contextFiles, baseDir)
338
+ }
339
+ } else {
340
+ await addFileToContext(fullPath, contextFiles, baseDir)
341
+ }
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Adds a file or directory to the context.
347
+ * @param {string} contextFile - The path to the file or directory to add.
348
+ * @param {Record<string, string>} contextFiles - The current context files.
349
+ * @param {Record<string, any>} options - Additional options.
350
+ * @returns {Promise<Record<string, string>>} A promise that resolves with the updated context files.
351
+ */
352
+ export const addFileOrDirectoryToContext = async (
353
+ contextFile: string,
354
+ contextFiles: Record<string, string>,
355
+ options: Record<string, any>,
356
+ ): Promise<Record<string, string>> => {
357
+ const filePath = path.resolve(contextFile)
358
+ const baseDir = process.cwd()
359
+
360
+ try {
361
+ const stats = await fs.promises.stat(filePath)
362
+ if (stats.isDirectory()) {
363
+ await addDirectoryToContext(filePath, contextFiles, baseDir)
364
+ } else if (stats.isFile()) {
365
+ await addFileToContext(filePath, contextFiles, baseDir)
366
+ }
367
+ } catch (error) {
368
+ console.error(
369
+ colors.red(`${colors.bold('Error')}: File or directory "${contextFile}" does not exist`),
370
+ )
371
+ process.exit(1)
372
+ }
373
+
374
+ return contextFiles
375
+ }
@@ -0,0 +1,5 @@
1
+ ## Code Generation Failed
2
+
3
+ Some of the provided code blocks could not be applied, please match the existing code with a few more lines of context and make sure it is a character for character exact match. Never use "rest of the existing code" or "rest of the code" in your response, instead break the code block into smaller blocks.
4
+
5
+ ## Details
@@ -0,0 +1,82 @@
1
+ ### Example 1: Changing a Variable
2
+
3
+ ```typescript
4
+ <<<<<<< CURRENT path/to/file.ts
5
+ const myVariable = 'exact'
6
+ const oldVariable = 1
7
+ =======
8
+ const myVariable = 'exact'
9
+ const newVariable = 2
10
+ >>>>>>> NEW
11
+ ```
12
+
13
+ ### Example 2: Create a New File
14
+
15
+ ```ruby
16
+ <<<<<<< CURRENT path/to/newfile.rb
17
+ =======
18
+ def new_function
19
+ puts 'Hello, world!'
20
+ end
21
+ >>>>>>> NEW
22
+ ```
23
+
24
+ ### Example 3: Moving a Function
25
+
26
+ Removing it from path/to/file.py
27
+
28
+ ```python
29
+ <<<<<<< CURRENT path/to/file.py
30
+ def old_function():
31
+ return 'Old function'
32
+ =======
33
+ >>>>>>> NEW
34
+ ```
35
+
36
+ Adding it to path/to/newfile.py
37
+
38
+ ```python
39
+ <<<<<<< CURRENT path/to/newfile.py
40
+ def existing_function():
41
+ return 'Existing function'
42
+
43
+ =======
44
+ def existing_function():
45
+ return 'Existing function'
46
+
47
+ def old_function():
48
+ return 'Old function'
49
+ >>>>>>> NEW
50
+ ```
51
+
52
+ ### Example 4: Removing a Function
53
+
54
+ ```java
55
+ <<<<<<< CURRENT path/to/file.java
56
+ public void oldFunction() {
57
+ System.out.println("Old function")
58
+ }
59
+ =======
60
+ >>>>>>> NEW
61
+ ```
62
+
63
+ ### Example 5: Replace a file
64
+
65
+ This will replace the entire contents of **path/to/file.rb** with the new content:
66
+
67
+ ```ruby
68
+ <<<<<<< CURRENT path/to/file.rb
69
+ =======
70
+ def new_function
71
+ puts 'Hello, world!'
72
+ end
73
+ >>>>>>> NEW
74
+ ```
75
+
76
+ ## Don't Invent Code That Isn't Provided in Context
77
+
78
+ A file might be referenced by just the file name without the full path, but the code must be provided in the *Context Files* section.
79
+
80
+ Unless you believe you are creating a whole new file, never ever under any circumstances make up code in the CURRENT block that was not provided to you in the *Context Files* section.
81
+
82
+ If a required file hasn't been provided in the *Context Files* section, stop everything and ask the user to provide it in the context by adding -f path/to/file to the command or add path/to/file in the interactive chat.
@@ -0,0 +1,43 @@
1
+ # AI Code Generation Instructions
2
+
3
+ ## General Guidelines
4
+
5
+ 1. **Respond as an expert software developer.**
6
+ 2. **Follow best practices and the latest standards found in the **Description of App** section.**
7
+ 3. **Adhere to existing conventions and libraries in the codebase.**
8
+
9
+ ## Request Handling
10
+
11
+ 1. **Try to understand the request, but if anything is unclear, ask questions.**
12
+ 2. **Decide if you need to propose edits to existing files not in the chat.**
13
+ - If yes, provide the full path names and ask the user to add them.
14
+ - Wait for user approval before proceeding.
15
+ 3. **Propose changes using *CURRENT/NEW* Blocks.**
16
+ 4. **Show the smallest possible *CURRENT* section that uniquely identifies the code.**
17
+ 5. **To move code, use two *CURRENT/NEW* blocks: one to remove and one to add.**
18
+ 6. **For new files or to replace an existing file, the *CURRENT* block is empty.**
19
+
20
+ ## *CURRENT/NEW* Block Format
21
+
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
+
25
+ ```typescript
26
+ 2. **Next line: seven <, CURRENT, and the file path like this:**
27
+ <<<<<<< CURRENT path/to/file.ts
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:**
30
+ =======
31
+ 5. **Add the new code.**
32
+ 6. **End with seven > and NEW like this:**
33
+ >>>>>>> NEW
34
+ 7. **Close the block with three backticks like this:**
35
+ ```
36
+
37
+ ## Don't Invent Code That Isn't Provided in Context
38
+
39
+ A file might be referenced by just the file name without the full path, but the code must be provided in the *Context Files* section.
40
+
41
+ Unless you believe you are creating a whole new file, never ever under any circumstances make up code in the CURRENT block that was not provided to you in the *Context Files* section.
42
+
43
+ If a required file hasn't been provided in the *Context Files* section, stop everything and ask the user to provide it in the context by adding -f path/to/file to the command or add path/to/file in the interactive chat.
@@ -0,0 +1,9 @@
1
+ ## Documentation Instructions
2
+
3
+ Add documentation to the files in context. Provide the updated files with added documentation using the CURRENT/NEW block format. Only include the parts of the files that have changed.
4
+ Add or update documentation comments for each function, class, and module definition as appropriate. Use the standard documentation format for the respective language (e.g., JSDoc for JavaScript/TypeScript, docstrings for Python, etc.).
5
+
6
+ ### Note
7
+
8
+ Whenever possible, break up the changes into pieces and make sure every change is in its own CURRENT / NEW block.
9
+ Do not allow empty CURRENT blocks and if you add content to the CURRENT block, you also have to add the same content to the NEW block.`
@@ -0,0 +1,132 @@
1
+ # Initialization Instructions
2
+
3
+ You are an AI assistant helping to initialize a project by analyzing its structure and technologies.
4
+
5
+ Please return JSON-formatted metadata about the project, including:
6
+
7
+ - The programming language(s) used
8
+ - The detected framework(s) (if any)
9
+ - The version of the language(s)
10
+
11
+ Here is a typescript interface for the expected response:
12
+
13
+ ```typescript
14
+ interface LanguageConfig {
15
+ name: string
16
+ version?: string
17
+ primary?: boolean
18
+ directory: string
19
+ extension: string
20
+ }
21
+
22
+ interface FrameworkConfig {
23
+ name: string
24
+ type: string
25
+ version?: string
26
+ primary?: boolean
27
+ directory?: string
28
+ extension?: string
29
+ }
30
+
31
+ interface TestingFrameworkConfig {
32
+ name: string
33
+ type: string
34
+ version?: string
35
+ directory?: string
36
+ runCommand?: string
37
+ }
38
+
39
+ interface BuildToolConfig {
40
+ name: string
41
+ type: string
42
+ version?: string
43
+ }
44
+
45
+ interface LinterConfig {
46
+ name: string
47
+ version?: string
48
+ type?: string
49
+ }
50
+
51
+ interface DatabaseConfig {
52
+ name: string
53
+ primary?: boolean
54
+ }
55
+
56
+ export interface ClovingfileConfig {
57
+ languages: LanguageConfig[]
58
+ frameworks: FrameworkConfig[]
59
+ testingFrameworks?: TestingFrameworkConfig[]
60
+ buildTools: BuildToolConfig[]
61
+ packageManager: string
62
+ linters: LinterConfig[]
63
+ databases?: DatabaseConfig[]
64
+ projectType: string
65
+ }
66
+ ```
67
+
68
+ Here is an example response:
69
+
70
+ ```json
71
+ {
72
+ "languages": [
73
+ {
74
+ "name": "TypeScript",
75
+ "version": "~> 5.5.3",
76
+ "primary": true,
77
+ "directory": "src",
78
+ "extension": ".ts"
79
+ },
80
+ {
81
+ "name": "JavaScript",
82
+ "version": "ES6+",
83
+ "directory": "src",
84
+ "extension": ".js"
85
+ }
86
+ ],
87
+ "frameworks": [
88
+ {
89
+ "name": "Node.js",
90
+ "type": "Runtime environment",
91
+ "primary": true,
92
+ "directory": "src",
93
+ "extension": ".js"
94
+ }
95
+ ],
96
+ "testingFrameworks": [
97
+ {
98
+ "name": "Jest",
99
+ "type": "Testing framework",
100
+ "version": "29.7.0",
101
+ "directory": "tests",
102
+ "runCommand": "yarn test"
103
+ }
104
+ ],
105
+ "buildTools": [
106
+ {
107
+ "name": "TypeScript Compiler (tsc)",
108
+ "type": "Transpiler"
109
+ },
110
+ {
111
+ "name": "Vite",
112
+ "type": "Build tool",
113
+ "version": "5.3.3"
114
+ }
115
+ ],
116
+ "packageManager": "Yarn",
117
+ "linters": [
118
+ {
119
+ "name": "ESLint",
120
+ "version": "9.6.0"
121
+ }
122
+ ],
123
+ "databases": [
124
+ {
125
+ "name": "MongoDB",
126
+ "version": "5.0.3",
127
+ "primary": true
128
+ }
129
+ ],
130
+ "projectType": "Command-line tool"
131
+ }
132
+ ```
@@ -0,0 +1,49 @@
1
+ ### Example of a well-structured response
2
+
3
+ # Code Review: Enhanced Code Generation and File Handling
4
+
5
+ ## Changes Overview
6
+
7
+ These changes primarily focus on improving the code generation process and adding more robust file handling capabilities. The main modifications include:
8
+
9
+ 1. Enhancing the code generation prompt with a structured example response.
10
+ 2. Implementing a new function to extract file names and contents from the generated code.
11
+ 3. Adding a new option to save generated code directly to files.
12
+ 4. Improving the copy-to-clipboard functionality to allow copying individual files.
13
+ 5. Removing an unused import in the review.ts file.
14
+
15
+ ## Reason for Changes
16
+
17
+ The changes aim to enhance the usability and flexibility of the code generation tool by providing clearer prompts, better file management, and more control over the generated code.
18
+
19
+ ## Detailed Description
20
+
21
+ 1. **Enhanced Code Generation Prompt** - The `generateCodePrompt` function now includes a structured example of a well-formatted response. This helps guide the AI to produce more consistent and usable output, making it easier to parse and use the generated code.
22
+ 2. **File Extraction Function** - A new function `extractFilesAndContent` has been added to parse the raw code command and extract individual file names and their contents. This enables more granular control over the generated code, allowing for file-specific operations.
23
+ 3. **Save to File Option** - A new 'Save Source Code to Files' option has been added to the user action menu. This feature allows users to save generated code directly to files in the appropriate directory structure.
24
+ 4. **Improved Copy to Clipboard** - The 'Copy Source Code to Clipboard' option has been enhanced to allow users to choose specific files to copy, rather than copying all generated code at once.
25
+ 5. **Removed Unused Import** - The unused import of `execFileSync` from 'child_process' has been removed from the review.ts file, improving code cleanliness.
26
+
27
+ ## Potential Bugs and Recommended Fixes
28
+
29
+ ### 1. Possible undefined access in `extractFilesAndContent`
30
+
31
+ ```typescript
32
+ const contentMatch = regex.exec(rawCodeCommand)
33
+ if (contentMatch) {
34
+ files.push(fileName)
35
+ let content = contentMatch[1]
36
+ // ...
37
+ }
38
+ ```
39
+
40
+ There's a potential for `contentMatch[1]` to be undefined if the regex doesn't capture any groups. To fix this, add a null check:
41
+
42
+ ```typescript
43
+ const contentMatch = regex.exec(rawCodeCommand)
44
+ if (contentMatch && contentMatch[1]) {
45
+ files.push(fileName)
46
+ let content = contentMatch[1]
47
+ // ...
48
+ }
49
+ ```