cloving 0.1.3 → 0.1.7
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/README.md +117 -36
- package/dist/cloving_gpt/index.js +14 -10
- package/dist/commands/commit.js +2 -2
- package/dist/commands/config.js +33 -6
- package/dist/commands/generate/commit.js +44 -0
- package/dist/commands/generate/review.js +57 -0
- package/dist/commands/generate/unit_tests.js +125 -0
- package/dist/commands/init.js +7 -12
- package/dist/commands/project/build.js +88 -0
- package/dist/commands/project/complete.js +12 -0
- package/dist/commands/project/init.js +76 -0
- package/dist/commands/project/plan.js +108 -0
- package/dist/commands/review.js +2 -2
- package/dist/commands/unit_tests.js +2 -2
- package/dist/index.js +58 -20
- package/dist/utils/command_utils.js +1 -48
- package/dist/utils/config_utils.js +168 -0
- package/dist/utils/git_utils.js +34 -22
- package/dist/utils/string_utils.js +36 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
Here's the updated README.md incorporating the latest changes:
|
|
2
|
+
|
|
1
3
|
# Cloving
|
|
2
4
|
|
|
3
|
-
Cloving is an innovative tool designed to seamlessly integrate AI into various aspects of the developer workflow. It
|
|
5
|
+
Cloving is an innovative CLI tool designed to seamlessly integrate AI into various aspects of the developer workflow. It enhances productivity and code quality by leveraging AI for tasks such as generating commit messages, conducting code reviews, creating unit tests, and even assisting with entire project lifecycles.
|
|
4
6
|
|
|
5
7
|
## Features
|
|
6
8
|
|
|
@@ -9,15 +11,43 @@ Cloving is an innovative tool designed to seamlessly integrate AI into various a
|
|
|
9
11
|
- **AI-assisted unit test generation**
|
|
10
12
|
- **Seamless integration with existing development workflows**
|
|
11
13
|
- **Customizable AI prompts for different tasks**
|
|
14
|
+
- **Project initialization, planning, and building with AI assistance**
|
|
15
|
+
- **Support for multiple AI models including OpenAI, Claude, and Ollama**
|
|
12
16
|
|
|
13
17
|
## Prerequisites
|
|
14
18
|
|
|
15
19
|
- Node.js (version 20 or higher)
|
|
16
20
|
- Git
|
|
17
|
-
- API access to AI chat models (e.g., OpenAI GPT-
|
|
21
|
+
- API access to AI chat models (e.g., OpenAI GPT-4, Claude, Ollama, etc.)
|
|
18
22
|
|
|
19
23
|
## Installation
|
|
20
24
|
|
|
25
|
+
You have three options to install and use Cloving:
|
|
26
|
+
|
|
27
|
+
### 1. Global Installation via npm
|
|
28
|
+
|
|
29
|
+
Install Cloving globally using npm:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install cloving -g
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This allows you to run `cloving` commands from anywhere in your terminal.
|
|
36
|
+
|
|
37
|
+
### 2. Run with npx
|
|
38
|
+
|
|
39
|
+
You can use npx to run Cloving without installing it globally:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx cloving [command]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This method downloads and executes Cloving on-the-fly, ensuring you always use the latest version.
|
|
46
|
+
|
|
47
|
+
### 3. Clone and Install from Source
|
|
48
|
+
|
|
49
|
+
For development or to use the latest unreleased features:
|
|
50
|
+
|
|
21
51
|
1. Clone this repository:
|
|
22
52
|
```bash
|
|
23
53
|
git clone https://github.com/cloving-ai/cloving-cli.git
|
|
@@ -34,76 +64,127 @@ Cloving is an innovative tool designed to seamlessly integrate AI into various a
|
|
|
34
64
|
yarn link
|
|
35
65
|
```
|
|
36
66
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
67
|
+
After installation, configure Cloving with your API key and preferred model:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
cloving config
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Choose the installation method that best suits your needs and workflow. The global npm installation is recommended for most users, while npx is great for one-off usage or trying out Cloving. Cloning from source is ideal for contributors or those who want the absolute latest features.
|
|
41
74
|
|
|
42
75
|
## Usage
|
|
43
76
|
|
|
44
77
|
Cloving provides several commands to help integrate AI into your development workflow:
|
|
45
78
|
|
|
46
|
-
###
|
|
79
|
+
### Configuration
|
|
47
80
|
|
|
48
|
-
|
|
81
|
+
Configure Cloving with your API key and model:
|
|
49
82
|
```bash
|
|
50
|
-
cloving
|
|
83
|
+
cloving config
|
|
51
84
|
```
|
|
52
|
-
This will generate an AI-powered commit message based on your recent changes, allow you to review and edit it, and then commit your changes.
|
|
53
85
|
|
|
54
|
-
###
|
|
86
|
+
### Initialization
|
|
55
87
|
|
|
56
|
-
|
|
88
|
+
Set up Cloving in the current project:
|
|
57
89
|
```bash
|
|
58
|
-
cloving
|
|
90
|
+
cloving init
|
|
59
91
|
```
|
|
92
|
+
Options:
|
|
93
|
+
- `-s, --silent`: Run without asking for confirmation of submitting prompts
|
|
94
|
+
- `-m, --model <model>`: Select the model to use
|
|
60
95
|
|
|
61
|
-
###
|
|
96
|
+
### Listing Available Models
|
|
62
97
|
|
|
63
|
-
|
|
98
|
+
List the available AI models:
|
|
64
99
|
```bash
|
|
65
|
-
cloving
|
|
100
|
+
cloving models
|
|
66
101
|
```
|
|
67
102
|
|
|
68
|
-
###
|
|
103
|
+
### Generating Commit Messages
|
|
69
104
|
|
|
70
|
-
|
|
105
|
+
Generate an AI-powered commit message:
|
|
71
106
|
```bash
|
|
72
|
-
cloving
|
|
107
|
+
cloving commit
|
|
108
|
+
```
|
|
109
|
+
or
|
|
110
|
+
```bash
|
|
111
|
+
cloving generate commit
|
|
73
112
|
```
|
|
113
|
+
Options:
|
|
114
|
+
- `-s, --silent`: Run without asking for confirmation
|
|
115
|
+
- `-m, --model <model>`: Select the model to use
|
|
74
116
|
|
|
75
|
-
###
|
|
117
|
+
### Generating Unit Tests
|
|
76
118
|
|
|
77
|
-
|
|
119
|
+
Generate unit tests for changes or specific files:
|
|
78
120
|
```bash
|
|
79
|
-
cloving
|
|
121
|
+
cloving generate unit-tests
|
|
80
122
|
```
|
|
123
|
+
Options:
|
|
124
|
+
- `-s, --silent`: Run without asking for confirmation
|
|
125
|
+
- `-f, --files <filenames...>`: Specify filenames for the unit tests
|
|
126
|
+
- `-m, --model <model>`: Select the model to use
|
|
81
127
|
|
|
82
|
-
###
|
|
128
|
+
### Code Reviews
|
|
83
129
|
|
|
84
|
-
|
|
130
|
+
Get an AI-powered code review:
|
|
85
131
|
```bash
|
|
86
|
-
cloving
|
|
132
|
+
cloving generate review
|
|
87
133
|
```
|
|
134
|
+
Options:
|
|
135
|
+
- `-s, --silent`: Run without asking for confirmation
|
|
136
|
+
- `-m, --model <model>`: Select the model to use
|
|
137
|
+
|
|
138
|
+
### Project Commands
|
|
139
|
+
|
|
140
|
+
Cloving now includes commands for managing entire projects:
|
|
141
|
+
|
|
142
|
+
- Initialize a new project inside a git branch:
|
|
143
|
+
```bash
|
|
144
|
+
cloving project init
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- Plan the steps to complete the project:
|
|
148
|
+
```bash
|
|
149
|
+
cloving project plan
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
- Generate code to build the project:
|
|
153
|
+
```bash
|
|
154
|
+
cloving project build
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- Clean up and finalize the project:
|
|
158
|
+
```bash
|
|
159
|
+
cloving project complete
|
|
160
|
+
```
|
|
88
161
|
|
|
89
162
|
## Command Line Options
|
|
90
163
|
|
|
91
164
|
Usage: `cloving [options] [command]`
|
|
92
165
|
|
|
93
|
-
Integrate AI into your development workflow for generating commit messages, code reviews, and unit tests.
|
|
94
|
-
|
|
95
166
|
Options:
|
|
96
|
-
- `-V, --version
|
|
97
|
-
- `-h, --help
|
|
167
|
+
- `-V, --version`: Output the version number
|
|
168
|
+
- `-h, --help`: Display help for command
|
|
98
169
|
|
|
99
170
|
Commands:
|
|
100
|
-
- `
|
|
101
|
-
- `
|
|
102
|
-
- `models
|
|
103
|
-
- `
|
|
104
|
-
- `
|
|
105
|
-
- `
|
|
106
|
-
- `
|
|
171
|
+
- `config`: Configure Cloving with your API key and models to use
|
|
172
|
+
- `init`: Setup Cloving in the current directory
|
|
173
|
+
- `models`: List available models
|
|
174
|
+
- `commit`: Alias for cloving generate commit
|
|
175
|
+
- `generate`: Generate various items like unit-tests and code reviews
|
|
176
|
+
- `commit`: Generate a commit message and commit the changes
|
|
177
|
+
- `unit-tests`: Generate unit tests
|
|
178
|
+
- `review`: Review the code for committed changes
|
|
179
|
+
- `project`: Commands for managing Cloving projects
|
|
180
|
+
- `init`: Setup a new Cloving project inside a git branch
|
|
181
|
+
- `plan`: Plan the steps to complete the project
|
|
182
|
+
- `build`: Generate code to build the project
|
|
183
|
+
- `complete`: Clean up and finalize the project
|
|
184
|
+
|
|
185
|
+
Most commands support the following options:
|
|
186
|
+
- `-s, --silent`: Run the command without asking for confirmation of submitting prompts
|
|
187
|
+
- `-m, --model <model>`: Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)
|
|
107
188
|
|
|
108
189
|
## Contributing
|
|
109
190
|
|
|
@@ -11,20 +11,24 @@ const claude_1 = require("./adapters/claude");
|
|
|
11
11
|
const openai_1 = require("./adapters/openai");
|
|
12
12
|
const gpt4all_1 = require("./adapters/gpt4all");
|
|
13
13
|
const ollama_1 = require("./adapters/ollama");
|
|
14
|
-
const
|
|
14
|
+
const config_utils_1 = require("../utils/config_utils");
|
|
15
15
|
class ClovingGPT {
|
|
16
16
|
constructor(options = { silent: false }) {
|
|
17
|
-
const
|
|
18
|
-
|
|
17
|
+
const { model: partialModel } = options;
|
|
18
|
+
const config = (0, config_utils_1.getConfig)(options);
|
|
19
|
+
if (!config || !config.models) {
|
|
19
20
|
console.log('No cloving configuration found. Please run: cloving config');
|
|
20
21
|
process_1.default.exit(1);
|
|
21
22
|
}
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
const primaryModel = (0, config_utils_1.getPrimaryModel)(partialModel);
|
|
24
|
+
if (!primaryModel) {
|
|
25
|
+
console.log('No primary model found in the configuration. Please run: cloving config');
|
|
26
|
+
process_1.default.exit(1);
|
|
27
|
+
}
|
|
28
|
+
const { provider, model, config: modelConfig } = primaryModel;
|
|
29
|
+
this.apiKey = modelConfig.apiKey;
|
|
30
|
+
this.silent = options.silent || modelConfig.silent;
|
|
31
|
+
switch (provider) {
|
|
28
32
|
case 'claude':
|
|
29
33
|
this.adapter = new claude_1.ClaudeAdapter(model);
|
|
30
34
|
break;
|
|
@@ -38,7 +42,7 @@ class ClovingGPT {
|
|
|
38
42
|
this.adapter = new ollama_1.OllamaAdapter(model);
|
|
39
43
|
break;
|
|
40
44
|
default:
|
|
41
|
-
throw new Error(`Unsupported provider: ${
|
|
45
|
+
throw new Error(`Unsupported provider: ${provider}`);
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
async askUserToConfirm(prompt, message) {
|
package/dist/commands/commit.js
CHANGED
|
@@ -8,10 +8,10 @@ const path_1 = __importDefault(require("path"));
|
|
|
8
8
|
const child_process_1 = require("child_process");
|
|
9
9
|
const git_utils_1 = require("../utils/git_utils");
|
|
10
10
|
const string_utils_1 = require("../utils/string_utils");
|
|
11
|
-
const
|
|
11
|
+
const config_utils_1 = require("../utils/config_utils");
|
|
12
12
|
const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
|
|
13
13
|
const generateAndCommitMessage = async (options) => {
|
|
14
|
-
options.silent = (0,
|
|
14
|
+
options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
|
|
15
15
|
const gpt = new cloving_gpt_1.default(options);
|
|
16
16
|
try {
|
|
17
17
|
// Generate the prompt for commit message
|
package/dist/commands/config.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.config = void 0;
|
|
4
|
+
const config_utils_1 = require("../utils/config_utils");
|
|
4
5
|
const command_utils_1 = require("../utils/command_utils");
|
|
5
6
|
const config = async () => {
|
|
6
|
-
let currentConfig = (0,
|
|
7
|
+
let currentConfig = (0, config_utils_1.getConfig)({});
|
|
7
8
|
// Ensure models is initialized properly
|
|
8
9
|
if (!currentConfig.models) {
|
|
9
10
|
currentConfig.models = {};
|
|
@@ -23,17 +24,43 @@ const config = async () => {
|
|
|
23
24
|
}
|
|
24
25
|
const selectedModel = models[modelIndex];
|
|
25
26
|
const apiKey = await (0, command_utils_1.promptUser)(`Enter your API key for ${selectedModel}: `);
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
if (
|
|
29
|
-
currentConfig.
|
|
27
|
+
const [provider, ...modelParts] = selectedModel.split(':');
|
|
28
|
+
const model = modelParts.join(':');
|
|
29
|
+
if (!currentConfig.models[provider]) {
|
|
30
|
+
currentConfig.models[provider] = {};
|
|
31
|
+
}
|
|
32
|
+
const setAsPrimary = await (0, command_utils_1.promptUser)('Do you want to use this model as a primary model? [Yn]: ');
|
|
33
|
+
const primary = setAsPrimary.toLowerCase() === 'y' || setAsPrimary === '';
|
|
34
|
+
const priorityNumber = await (0, command_utils_1.promptUser)('Enter the priority for this model (0-100, higher priority will be used as long as the prompt fits the context token limit): [' + (primary ? 100 : 0) + ']');
|
|
35
|
+
const priority = primary ? 100 : parseInt(priorityNumber, 10);
|
|
36
|
+
const silentResponse = await (0, command_utils_1.promptUser)('Do you want to review all prompts before they are sent to this model? [Yn]: ');
|
|
37
|
+
const silent = !(silentResponse.toLowerCase() === 'y' || silentResponse === '');
|
|
38
|
+
const trustResponse = await (0, command_utils_1.promptUser)('Do you trust this model with sensitive information? [Yn]: ');
|
|
39
|
+
const trust = trustResponse.toLowerCase() === 'y' || trustResponse === '';
|
|
40
|
+
const modelConfig = {
|
|
41
|
+
apiKey,
|
|
42
|
+
primary,
|
|
43
|
+
priority,
|
|
44
|
+
silent,
|
|
45
|
+
trust,
|
|
46
|
+
};
|
|
47
|
+
currentConfig.models[provider][model] = modelConfig;
|
|
48
|
+
if (primary) {
|
|
49
|
+
// Ensure only one primary model
|
|
50
|
+
for (const p in currentConfig.models) {
|
|
51
|
+
for (const m in currentConfig.models[p]) {
|
|
52
|
+
if (p !== provider || m !== model) {
|
|
53
|
+
currentConfig.models[p][m].primary = false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
30
57
|
}
|
|
31
58
|
const anotherModel = await (0, command_utils_1.promptUser)('Do you want to configure another model? [Yn]: ');
|
|
32
59
|
if (anotherModel.toLowerCase() !== 'y' && anotherModel !== '') {
|
|
33
60
|
continueConfig = false;
|
|
34
61
|
}
|
|
35
62
|
}
|
|
36
|
-
(0,
|
|
63
|
+
(0, config_utils_1.saveConfig)(currentConfig);
|
|
37
64
|
};
|
|
38
65
|
exports.config = config;
|
|
39
66
|
exports.default = exports.config;
|
|
@@ -0,0 +1,44 @@
|
|
|
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 fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const git_utils_1 = require("../../utils/git_utils");
|
|
10
|
+
const string_utils_1 = require("../../utils/string_utils");
|
|
11
|
+
const config_utils_1 = require("../../utils/config_utils");
|
|
12
|
+
const cloving_gpt_1 = __importDefault(require("../../cloving_gpt"));
|
|
13
|
+
const generateAndCommitMessage = async (options) => {
|
|
14
|
+
options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
|
|
15
|
+
const gpt = new cloving_gpt_1.default(options);
|
|
16
|
+
try {
|
|
17
|
+
// Generate the prompt for commit message
|
|
18
|
+
const prompt = (0, git_utils_1.generateCommitMessagePrompt)();
|
|
19
|
+
// Instantiate ClovingGPT and get the commit message
|
|
20
|
+
const rawCommitMessage = await gpt.generateText({ prompt });
|
|
21
|
+
// Clean the commit message using extractMarkdown
|
|
22
|
+
const commitMessage = (0, string_utils_1.extractMarkdown)(rawCommitMessage);
|
|
23
|
+
// Write the commit message to a temporary file
|
|
24
|
+
const tempCommitFilePath = path_1.default.join('.git', 'SUGGESTED_COMMIT_EDITMSG');
|
|
25
|
+
fs_1.default.writeFileSync(tempCommitFilePath, commitMessage);
|
|
26
|
+
// Commit the changes using the generated commit message
|
|
27
|
+
try {
|
|
28
|
+
(0, child_process_1.execFileSync)('git', ['commit', '-a', '--edit', '--file', tempCommitFilePath], { stdio: 'inherit' });
|
|
29
|
+
}
|
|
30
|
+
catch (commitError) {
|
|
31
|
+
// If commit is canceled (non-zero exit), handle it here
|
|
32
|
+
console.log('Commit was canceled or failed.');
|
|
33
|
+
}
|
|
34
|
+
// Remove the temporary file using fs
|
|
35
|
+
fs_1.default.unlink(tempCommitFilePath, (err) => {
|
|
36
|
+
if (err)
|
|
37
|
+
throw err;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error('Could not generate commit message');
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
exports.default = generateAndCommitMessage;
|
|
@@ -0,0 +1,57 @@
|
|
|
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 child_process_1 = require("child_process");
|
|
7
|
+
const cli_highlight_1 = __importDefault(require("cli-highlight"));
|
|
8
|
+
const cloving_gpt_1 = __importDefault(require("../../cloving_gpt"));
|
|
9
|
+
const git_utils_1 = require("../../utils/git_utils");
|
|
10
|
+
const string_utils_1 = require("../../utils/string_utils");
|
|
11
|
+
const config_utils_1 = require("../../utils/config_utils");
|
|
12
|
+
const string_utils_2 = require("../../utils/string_utils");
|
|
13
|
+
const command_utils_1 = require("../../utils/command_utils");
|
|
14
|
+
const review = async (options) => {
|
|
15
|
+
options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
|
|
16
|
+
const gpt = new cloving_gpt_1.default(options);
|
|
17
|
+
try {
|
|
18
|
+
// Define the prompt for analysis
|
|
19
|
+
const gitDiff = await (0, git_utils_1.getGitDiff)();
|
|
20
|
+
const prompt = `Explain why the change is being made and document a description of these changes.
|
|
21
|
+
Also list any bugs in the new code as well as recommended fixes for those bugs with code examples.
|
|
22
|
+
Format the output of this code review in Markdown format.
|
|
23
|
+
|
|
24
|
+
${gitDiff}`;
|
|
25
|
+
// get the analysis
|
|
26
|
+
const analysis = await gpt.generateText({ prompt });
|
|
27
|
+
const markdown = (0, string_utils_1.extractMarkdown)(analysis);
|
|
28
|
+
// Print the analysis to the console
|
|
29
|
+
(0, string_utils_2.parseMarkdownInstructions)(markdown).map(code => {
|
|
30
|
+
if (code.trim().startsWith('```')) {
|
|
31
|
+
const lines = code.split('\n');
|
|
32
|
+
const language = code.match(/```(\w+)/)?.[1] || 'plaintext';
|
|
33
|
+
console.log(lines[0]);
|
|
34
|
+
console.log((0, cli_highlight_1.default)(lines.slice(1, -1).join('\n'), { language }));
|
|
35
|
+
console.log(lines.slice(-1)[0]);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
console.log((0, cli_highlight_1.default)(code, { language: 'markdown' }));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
// Prompt the user to copy the analysis to the clipboard
|
|
42
|
+
const answer = await (0, command_utils_1.promptUser)('Do you want to copy the analysis to the clipboard? [Y/n] ');
|
|
43
|
+
if (answer.toLowerCase() === 'y' || answer === '') {
|
|
44
|
+
try {
|
|
45
|
+
(0, child_process_1.execFileSync)('pbcopy', { input: markdown });
|
|
46
|
+
console.log('Analysis copied to clipboard');
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error('Error: pbcopy command not found. Unable to copy to clipboard.');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error('Error during analysis:', error.message);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
exports.default = review;
|
|
@@ -0,0 +1,125 @@
|
|
|
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 fs_1 = require("fs");
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const cli_highlight_1 = __importDefault(require("cli-highlight"));
|
|
9
|
+
const git_utils_1 = require("../../utils/git_utils");
|
|
10
|
+
const config_utils_1 = require("../../utils/config_utils");
|
|
11
|
+
const cloving_gpt_1 = __importDefault(require("../../cloving_gpt"));
|
|
12
|
+
const extractChangedFiles = (gitDiff) => {
|
|
13
|
+
const fileRegex = /diff --git a\/(.+?) b\/(.+?)\n/g;
|
|
14
|
+
const files = new Set();
|
|
15
|
+
let match;
|
|
16
|
+
while ((match = fileRegex.exec(gitDiff)) !== null) {
|
|
17
|
+
files.add(match[1]);
|
|
18
|
+
}
|
|
19
|
+
return Array.from(files);
|
|
20
|
+
};
|
|
21
|
+
const generatePrompt = (files, srcFiles, testFiles, gitDiff) => {
|
|
22
|
+
const filesList = files.length > 0 ? files.join('\n') : 'No files provided';
|
|
23
|
+
const diffSection = gitDiff ? `Here is my git diff:\n\n==== begin git diff ====\n${gitDiff}\n==== end git diff ====\n` : '';
|
|
24
|
+
return `Here is a list of code files I want to generate unit tests for:
|
|
25
|
+
|
|
26
|
+
==== begin list of files ====
|
|
27
|
+
${filesList}
|
|
28
|
+
==== end list of files ====
|
|
29
|
+
|
|
30
|
+
Here is a list of all my source files:
|
|
31
|
+
|
|
32
|
+
==== begin list of source files ====
|
|
33
|
+
${srcFiles}
|
|
34
|
+
==== end list of source files ====
|
|
35
|
+
|
|
36
|
+
Here is a list of all my test files:
|
|
37
|
+
|
|
38
|
+
==== begin list of test files ====
|
|
39
|
+
${testFiles}
|
|
40
|
+
==== end list of test files ====
|
|
41
|
+
|
|
42
|
+
${diffSection}
|
|
43
|
+
|
|
44
|
+
Please enumerate all the files in the provided list${gitDiff ? ' and git diff' : ''} as well as the file names of anything that these files interact with.
|
|
45
|
+
|
|
46
|
+
Also, list any test files that might be relevant to these files.
|
|
47
|
+
|
|
48
|
+
Give me this output format for your answer:
|
|
49
|
+
|
|
50
|
+
## files
|
|
51
|
+
|
|
52
|
+
app/models/foo.rb
|
|
53
|
+
app/views/baz/bar.html.erb
|
|
54
|
+
|
|
55
|
+
## relevant test files
|
|
56
|
+
|
|
57
|
+
test/models/foo_test.rb
|
|
58
|
+
test/controllers/baz_controller_test.rb`;
|
|
59
|
+
};
|
|
60
|
+
const unitTests = async (options) => {
|
|
61
|
+
const { files } = options;
|
|
62
|
+
const gpt = new cloving_gpt_1.default(options);
|
|
63
|
+
const allSrcFiles = await (0, config_utils_1.getAllFiles)(options, true);
|
|
64
|
+
const testingDirectory = (0, config_utils_1.getTestingDirectory)();
|
|
65
|
+
if (allSrcFiles.length === 0 || !testingDirectory) {
|
|
66
|
+
console.error('Could not find any source files to generate unit tests. Please run: cloving init. Then try again.');
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
const testFiles = (0, child_process_1.execFileSync)('find', [testingDirectory, '-type', 'f']).toString().trim();
|
|
70
|
+
let contextFiles;
|
|
71
|
+
if (files) {
|
|
72
|
+
const prompt = generatePrompt(files, allSrcFiles.join('\n'), testFiles);
|
|
73
|
+
contextFiles = await gpt.generateText({ prompt });
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const gitDiff = await (0, git_utils_1.getGitDiff)();
|
|
77
|
+
const changedFiles = extractChangedFiles(gitDiff);
|
|
78
|
+
const prompt = generatePrompt(changedFiles, allSrcFiles.join('\n'), testFiles, gitDiff);
|
|
79
|
+
contextFiles = await gpt.generateText({ prompt });
|
|
80
|
+
}
|
|
81
|
+
// Initialize variables
|
|
82
|
+
const lines = [];
|
|
83
|
+
const context = [];
|
|
84
|
+
// Read each line of the context files
|
|
85
|
+
contextFiles.split('\n').forEach((line) => {
|
|
86
|
+
if (line.trim()) {
|
|
87
|
+
lines.push(line.trim());
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
for (const codeFile of lines) {
|
|
91
|
+
if (await fs_1.promises?.stat(codeFile).then(stat => stat.isFile()).catch(() => false)) {
|
|
92
|
+
const fileContents = await fs_1.promises.readFile(codeFile, 'utf-8');
|
|
93
|
+
context.push(`### **Contents of ${codeFile}**\n\n${fileContents}\n\n### **End of ${codeFile}**`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Generate the message for unit test creation
|
|
97
|
+
let analysis = '';
|
|
98
|
+
if ((files || []).length > 0) {
|
|
99
|
+
const message = `please create unit tests for these files:
|
|
100
|
+
|
|
101
|
+
## begin list of files
|
|
102
|
+
${(files || []).join('\n')}
|
|
103
|
+
## end list of files
|
|
104
|
+
|
|
105
|
+
## context
|
|
106
|
+
${context.join('\n\n')}`;
|
|
107
|
+
// Get the model and analysis using ClovingGPT
|
|
108
|
+
analysis = await gpt.generateText({ prompt: message });
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const message = `please create unit tests for these changes:
|
|
112
|
+
|
|
113
|
+
## begin diff
|
|
114
|
+
${await (0, git_utils_1.getGitDiff)()}
|
|
115
|
+
## end diff
|
|
116
|
+
|
|
117
|
+
## context
|
|
118
|
+
|
|
119
|
+
${context.join('\n\n')}`;
|
|
120
|
+
// Get the model and analysis using ClovingGPT
|
|
121
|
+
analysis = await gpt.generateText({ prompt: message });
|
|
122
|
+
}
|
|
123
|
+
console.log((0, cli_highlight_1.default)(analysis));
|
|
124
|
+
};
|
|
125
|
+
exports.default = unitTests;
|
package/dist/commands/init.js
CHANGED
|
@@ -7,14 +7,14 @@ exports.init = void 0;
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const os_1 = __importDefault(require("os"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const string_utils_1 = require("../utils/string_utils");
|
|
11
10
|
const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
|
|
12
11
|
const ignore_1 = __importDefault(require("ignore"));
|
|
13
|
-
const
|
|
12
|
+
const string_utils_1 = require("../utils/string_utils");
|
|
13
|
+
const config_utils_1 = require("../utils/config_utils");
|
|
14
14
|
const command_utils_1 = require("../utils/command_utils");
|
|
15
15
|
// Main function for the describe command
|
|
16
16
|
const init = async (options) => {
|
|
17
|
-
options.silent = (0,
|
|
17
|
+
options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
|
|
18
18
|
const gpt = new cloving_gpt_1.default(options);
|
|
19
19
|
const specialFileContents = (0, command_utils_1.collectSpecialFileContents)();
|
|
20
20
|
const specialFileNames = Object.keys(specialFileContents).map(file => ' - ' + file);
|
|
@@ -38,8 +38,8 @@ technologies used. This will provide better context for future Cloving requests.
|
|
|
38
38
|
`);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
const config = (0,
|
|
42
|
-
if (!config || !config?.
|
|
41
|
+
const config = (0, config_utils_1.getConfig)(options);
|
|
42
|
+
if (!config || !config?.models) {
|
|
43
43
|
console.error('No cloving configuration found. Please run `cloving config`');
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
@@ -128,7 +128,7 @@ interface DatabaseConfig {
|
|
|
128
128
|
primary?: boolean
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
export interface
|
|
131
|
+
export interface ClovingfileConfig {
|
|
132
132
|
languages: LanguageConfig[]
|
|
133
133
|
frameworks: FrameworkConfig[]
|
|
134
134
|
testingFrameworks?: TestingFrameworkConfig[]
|
|
@@ -201,13 +201,8 @@ Here is an example response:
|
|
|
201
201
|
],
|
|
202
202
|
"projectType": "Command-line tool",
|
|
203
203
|
}`;
|
|
204
|
-
if (process.env.DEBUG === '1') {
|
|
205
|
-
(0, string_utils_1.estimateTokens)(prompt).then(tokenCount => {
|
|
206
|
-
console.log(`Estimated token count: ${tokenCount}`);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
204
|
const aiChatResponse = await gpt.generateText({ prompt });
|
|
210
|
-
const cleanAiChatResponse = (0,
|
|
205
|
+
const cleanAiChatResponse = (0, string_utils_1.extractJsonMetadata)(aiChatResponse);
|
|
211
206
|
fs_1.default.writeFileSync(tempFilePath, cleanAiChatResponse);
|
|
212
207
|
// Save the AI chat response to cloving.json
|
|
213
208
|
fs_1.default.writeFileSync('cloving.json', cleanAiChatResponse);
|