cloving 0.1.19 → 0.1.21

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.
@@ -13,6 +13,9 @@ const mistral_1 = require("./adapters/mistral");
13
13
  const ollama_1 = require("./adapters/ollama");
14
14
  const gemini_1 = require("./adapters/gemini");
15
15
  const config_utils_1 = require("../utils/config_utils");
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const os_1 = __importDefault(require("os"));
18
+ const path_1 = __importDefault(require("path"));
16
19
  class ClovingGPT {
17
20
  constructor(options) {
18
21
  const { model: partialModel } = options;
@@ -52,51 +55,53 @@ class ClovingGPT {
52
55
  }
53
56
  async reviewPrompt(prompt, endpoint) {
54
57
  if (this.silent)
55
- return;
58
+ return prompt;
56
59
  const tokenCount = Math.ceil(prompt.length / 4).toLocaleString();
57
60
  const reviewPrompt = await (0, prompts_1.confirm)({
58
- message: `Do you want to review the ~${tokenCount} token prompt before sending it to ${endpoint}?`,
61
+ message: `Do you want to review/edit the ~${tokenCount} token prompt before sending it to ${endpoint}?`,
59
62
  default: true
60
63
  });
61
64
  if (reviewPrompt) {
62
- const less = (0, child_process_1.spawn)('less', ['-R'], { stdio: ['pipe', process_1.default.stdout, process_1.default.stderr] });
63
- less.stdin.write(prompt);
64
- less.stdin.end();
65
- await new Promise((resolve, reject) => {
66
- less.on('close', async (code) => {
65
+ const tempFile = path_1.default.join(os_1.default.tmpdir(), `cloving_prompt_${Date.now()}.txt`);
66
+ fs_1.default.writeFileSync(tempFile, prompt);
67
+ const editor = process_1.default.env.EDITOR || 'nano';
68
+ const editProcess = (0, child_process_1.spawn)(editor, [tempFile], { stdio: 'inherit' });
69
+ return new Promise((resolve, reject) => {
70
+ editProcess.on('close', async (code) => {
67
71
  if (code !== 0) {
68
- console.error('less command exited with an error');
69
- reject(new Error('Less command failed'));
72
+ console.error(`${editor} exited with code ${code}`);
73
+ fs_1.default.unlinkSync(tempFile);
74
+ reject(new Error(`Editor exited with non-zero code`));
70
75
  return;
71
76
  }
72
- const confirmContinue = await (0, prompts_1.confirm)({
73
- message: 'Do you want to continue?',
74
- default: true
75
- });
76
- if (!confirmContinue) {
77
- console.error('Operation cancelled');
78
- process_1.default.exit(1);
77
+ const editedPrompt = fs_1.default.readFileSync(tempFile, 'utf-8').trim();
78
+ fs_1.default.unlinkSync(tempFile);
79
+ if (editedPrompt === '') {
80
+ console.log('Prompt is empty.');
81
+ resolve(null);
82
+ return;
79
83
  }
80
- resolve();
84
+ resolve(editedPrompt);
81
85
  });
82
- less.stdin.on('error', (err) => {
83
- if (isNodeError(err) && err.code === 'EPIPE') {
84
- resolve();
85
- }
86
- else {
87
- console.error('Pipeline error:', err);
88
- reject(err);
89
- }
86
+ editProcess.on('error', (err) => {
87
+ console.error('Error launching editor:', err);
88
+ fs_1.default.unlinkSync(tempFile);
89
+ reject(err);
90
90
  });
91
91
  });
92
92
  }
93
+ return prompt;
93
94
  }
94
95
  async generateText(request) {
95
96
  request.temperature || (request.temperature = this.temperature);
96
97
  const endpoint = this.adapter.getEndpoint();
97
98
  const payload = this.adapter.getPayload(request);
98
99
  const headers = this.adapter.getHeaders(this.apiKey);
99
- await this.reviewPrompt(request.prompt, endpoint);
100
+ const reviewedPrompt = await this.reviewPrompt(request.prompt, endpoint);
101
+ if (reviewedPrompt === null) {
102
+ throw new Error('Operation cancelled by user');
103
+ }
104
+ request.prompt = reviewedPrompt;
100
105
  try {
101
106
  const response = await axios_1.default.post(endpoint, payload, { headers });
102
107
  return this.adapter.extractResponse(response.data);
@@ -111,7 +116,4 @@ class ClovingGPT {
111
116
  }
112
117
  }
113
118
  }
114
- function isNodeError(error) {
115
- return error instanceof Error && 'code' in error;
116
- }
117
119
  exports.default = ClovingGPT;
@@ -16,7 +16,11 @@ const generateCodePrompt = (prompt, files, contextFiles, previousCode) => {
16
16
  const specialFileContents = (0, command_utils_1.collectSpecialFileContents)();
17
17
  const specialFiles = Object.keys(specialFileContents).map((file) => `### Contents of ${file}\n\n${JSON.stringify(specialFileContents[file], null, 2)}\n\n`).join('\n');
18
18
  const contextFileContents = Object.keys(contextFiles).map((file) => `### Contents of ${file}\n\n${contextFiles[file]}\n\n`).join('\n');
19
- let promptText = `### Description of App
19
+ let promptText = `### Request
20
+
21
+ Generate code that does the following: ${prompt}
22
+
23
+ ### Description of App
20
24
 
21
25
  ${JSON.stringify((0, config_utils_1.getClovingConfig)(), null, 2)}
22
26
 
@@ -17,7 +17,60 @@ const review = async (options) => {
17
17
  let { prompt, files } = options;
18
18
  options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
19
19
  const gpt = new cloving_gpt_1.default(options);
20
- let promptText = '';
20
+ let promptText = `### Prompt
21
+
22
+ ${prompt || 'Please provide a code review.'}
23
+
24
+ ### Example of a well-structured response
25
+
26
+ # Code Review: Enhanced Code Generation and File Handling
27
+
28
+ ## Changes Overview
29
+
30
+ These changes primarily focus on improving the code generation process and adding more robust file handling capabilities. The main modifications include:
31
+
32
+ 1. Enhancing the code generation prompt with a structured example response.
33
+ 2. Implementing a new function to extract file names and contents from the generated code.
34
+ 3. Adding a new option to save generated code directly to files.
35
+ 4. Improving the copy-to-clipboard functionality to allow copying individual files.
36
+ 5. Removing an unused import in the review.ts file.
37
+
38
+ ## Reason for Changes
39
+
40
+ 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.
41
+
42
+ ## Detailed Description
43
+
44
+ 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.
45
+ 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.
46
+ 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.
47
+ 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.
48
+ 5. **Removed Unused Import** - The unused import of \`execFileSync\` from 'child_process' has been removed from the review.ts file, improving code cleanliness.
49
+
50
+ ## Potential Bugs and Recommended Fixes
51
+
52
+ ### 1. Possible undefined access in \`extractFilesAndContent\`
53
+
54
+ \`\`\`typescript
55
+ const contentMatch = regex.exec(rawCodeCommand)
56
+ if (contentMatch) {
57
+ files.push(fileName)
58
+ let content = contentMatch[1]
59
+ // ...
60
+ }
61
+ \`\`\`
62
+
63
+ 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:
64
+
65
+ \`\`\`typescript
66
+ const contentMatch = regex.exec(rawCodeCommand)
67
+ if (contentMatch && contentMatch[1]) {
68
+ files.push(fileName)
69
+ let content = contentMatch[1]
70
+ // ...
71
+ }
72
+ \`\`\`
73
+ `;
21
74
  let contextFiles = {};
22
75
  try {
23
76
  // Define the prompt for analysis
@@ -42,7 +95,8 @@ const review = async (options) => {
42
95
  }
43
96
  }
44
97
  const contextFileContents = Object.keys(contextFiles).map((file) => `### Contents of ${file}\n\n${contextFiles[file]}\n\n`).join('\n');
45
- promptText = `### Description of App
98
+ promptText += `
99
+ ### Description of App
46
100
 
47
101
  ${JSON.stringify((0, config_utils_1.getClovingConfig)(), null, 2)}
48
102
 
@@ -56,57 +110,17 @@ ${contextFileContents}
56
110
  ${gitDiff}
57
111
  ==== end diff =====`;
58
112
  }
59
- promptText += `
60
-
61
- ### Example of a well-structured response
62
-
63
- # Code Review: Enhanced Code Generation and File Handling
64
-
65
- ## Changes Overview
66
-
67
- These changes primarily focus on improving the code generation process and adding more robust file handling capabilities. The main modifications include:
68
-
69
- 1. Enhancing the code generation prompt with a structured example response.
70
- 2. Implementing a new function to extract file names and contents from the generated code.
71
- 3. Adding a new option to save generated code directly to files.
72
- 4. Improving the copy-to-clipboard functionality to allow copying individual files.
73
- 5. Removing an unused import in the review.ts file.
74
-
75
- ## Reason for Changes
76
-
77
- 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.
78
-
79
- ## Detailed Description
80
-
81
- 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.
82
- 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.
83
- 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.
84
- 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.
85
- 5. **Removed Unused Import** - The unused import of \`execFileSync\` from 'child_process' has been removed from the review.ts file, improving code cleanliness.
86
-
87
- ## Potential Bugs and Recommended Fixes
88
-
89
- ### 1. Possible undefined access in \`extractFilesAndContent\`
90
-
91
- \`\`\`typescript
92
- const contentMatch = regex.exec(rawCodeCommand)
93
- if (contentMatch) {
94
- files.push(fileName)
95
- let content = contentMatch[1]
96
- // ...
97
- }
98
- \`\`\`
113
+ if (files) {
114
+ promptText += `
99
115
 
100
- 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:
116
+ ### Request
101
117
 
102
- \`\`\`typescript
103
- const contentMatch = regex.exec(rawCodeCommand)
104
- if (contentMatch && contentMatch[1]) {
105
- files.push(fileName)
106
- let content = contentMatch[1]
107
- // ...
108
- }
109
- \`\`\`
118
+ I would like you to explain the code and document a description of it.
119
+ List any bugs in the new code as well as recommended fixes for those bugs with code examples.
120
+ Format the output of this code review in Markdown format.`;
121
+ }
122
+ else {
123
+ promptText += `
110
124
 
111
125
  ### Request
112
126
 
@@ -114,10 +128,12 @@ Do not use any data from the example response structure, only use the structure.
114
128
  I would like you to explain why these change are being made and document a description of these changes.
115
129
  Also list any bugs in the new code as well as recommended fixes for those bugs with code examples.
116
130
  Format the output of this code review in Markdown format.`;
131
+ }
117
132
  if (prompt) {
118
133
  promptText += `
119
134
 
120
135
  ### Additional Context
136
+
121
137
  ${prompt}`;
122
138
  }
123
139
  // get the analysis
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloving",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "packageManager": "yarn@1.22.22",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -51,6 +51,7 @@
51
51
  "eslint-plugin-promise": "^7.0.0",
52
52
  "ignore": "^5.3.1",
53
53
  "ini": "^4.1.3",
54
+ "isbinaryfile": "^5.0.2",
54
55
  "nock": "^13.5.4",
55
56
  "vite": "^5.3.5",
56
57
  "vite-node": "^2.0.5"
@@ -8,6 +8,7 @@ const child_process_1 = require("child_process");
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const config_utils_1 = require("./config_utils");
11
+ const isbinaryfile_1 = require("isbinaryfile");
11
12
  exports.SPECIAL_FILES = [
12
13
  'package.json', 'Gemfile', 'requirements.txt', 'Pipfile', 'pyproject.toml', 'pom.xml', 'build.gradle',
13
14
  '.csproj', 'packages.config', 'composer.json', 'CMakeLists.txt', 'conanfile.txt', 'conanfile.py',
@@ -37,10 +38,17 @@ const getAllFilesInDirectory = async (dir) => {
37
38
  const subdirs = await fs_1.default.promises.readdir(dir);
38
39
  const files = await Promise.all(subdirs.map(async (subdir) => {
39
40
  const res = path_1.default.resolve(dir, subdir);
40
- if (subdir === 'node_modules' || subdir === '.git') {
41
+ if (subdir === 'node_modules' || subdir === '.git' || subdir === '.DS_Store') {
41
42
  return [];
42
43
  }
43
- return (await fs_1.default.promises.stat(res)).isDirectory() ? (0, exports.getAllFilesInDirectory)(res) : res;
44
+ const stat = await fs_1.default.promises.stat(res);
45
+ if (stat.isDirectory()) {
46
+ return (0, exports.getAllFilesInDirectory)(res);
47
+ }
48
+ else {
49
+ const isBinary = await (0, isbinaryfile_1.isBinaryFile)(res);
50
+ return isBinary ? [] : res;
51
+ }
44
52
  }));
45
53
  return files.flat();
46
54
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloving",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "packageManager": "yarn@1.22.22",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -51,6 +51,7 @@
51
51
  "eslint-plugin-promise": "^7.0.0",
52
52
  "ignore": "^5.3.1",
53
53
  "ini": "^4.1.3",
54
+ "isbinaryfile": "^5.0.2",
54
55
  "nock": "^13.5.4",
55
56
  "vite": "^5.3.5",
56
57
  "vite-node": "^2.0.5"