cloving 0.3.1 ā 0.3.3
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/dist/index.js +2 -9
- package/dist/managers/ChatManager.js +88 -33
- package/dist/package.json +1 -1
- package/dist/utils/command_utils.js +23 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,8 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
|
-
const fs_1 = require("fs");
|
|
9
|
-
const path_1 = require("path");
|
|
10
8
|
const config_1 = __importDefault(require("./commands/config"));
|
|
11
9
|
const init_1 = __importDefault(require("./commands/init"));
|
|
12
10
|
const proxy_1 = __importDefault(require("./commands/proxy"));
|
|
@@ -19,17 +17,12 @@ const commit_1 = __importDefault(require("./commands/generate/commit"));
|
|
|
19
17
|
const context_1 = __importDefault(require("./commands/generate/context"));
|
|
20
18
|
const unit_tests_1 = __importDefault(require("./commands/generate/unit_tests"));
|
|
21
19
|
const review_1 = __importDefault(require("./commands/generate/review"));
|
|
22
|
-
|
|
23
|
-
const getPackageVersion = () => {
|
|
24
|
-
const packagePath = (0, path_1.join)(__dirname, 'package.json');
|
|
25
|
-
const packageJson = JSON.parse((0, fs_1.readFileSync)(packagePath, 'utf8'));
|
|
26
|
-
return packageJson.version;
|
|
27
|
-
};
|
|
20
|
+
const command_utils_1 = require("./utils/command_utils");
|
|
28
21
|
const program = new commander_1.Command();
|
|
29
22
|
program
|
|
30
23
|
.name('cloving')
|
|
31
24
|
.description('Integrate AI into your development workflow for generating commit messages, code reviews, and unit tests.')
|
|
32
|
-
.version(getPackageVersion());
|
|
25
|
+
.version((0, command_utils_1.getPackageVersion)());
|
|
33
26
|
program
|
|
34
27
|
.command('config')
|
|
35
28
|
.description('Configure cloving with your API key and models to use')
|
|
@@ -7,6 +7,8 @@ const copy_paste_1 = __importDefault(require("copy-paste"));
|
|
|
7
7
|
const readline_1 = __importDefault(require("readline"));
|
|
8
8
|
const child_process_1 = require("child_process");
|
|
9
9
|
const colors_1 = __importDefault(require("colors"));
|
|
10
|
+
const axios_1 = __importDefault(require("axios"));
|
|
11
|
+
const cli_highlight_1 = __importDefault(require("cli-highlight"));
|
|
10
12
|
const CommitManager_1 = __importDefault(require("./CommitManager"));
|
|
11
13
|
const ChunkManager_1 = __importDefault(require("./ChunkManager"));
|
|
12
14
|
const ReviewManager_1 = __importDefault(require("./ReviewManager"));
|
|
@@ -42,6 +44,8 @@ class ChatManager {
|
|
|
42
44
|
this.contextFiles = {};
|
|
43
45
|
this.prompt = '';
|
|
44
46
|
this.isProcessing = false;
|
|
47
|
+
this.isSilent = false;
|
|
48
|
+
this.isSilent = options.silent || false;
|
|
45
49
|
options.stream = true;
|
|
46
50
|
options.silent = true;
|
|
47
51
|
this.gpt = new cloving_gpt_1.default(options);
|
|
@@ -59,6 +63,7 @@ class ChatManager {
|
|
|
59
63
|
* @returns {Promise<void>}
|
|
60
64
|
*/
|
|
61
65
|
async initialize() {
|
|
66
|
+
await this.checkForLatestVersion();
|
|
62
67
|
await this.loadContextFiles();
|
|
63
68
|
console.log(`\nš š š ${colors_1.default.bold('Welcome to Cloving REPL')} š š š\n`);
|
|
64
69
|
this.displayAvailableCommands();
|
|
@@ -81,6 +86,27 @@ class ChatManager {
|
|
|
81
86
|
console.log(` - ${colors_1.default.yellow(colors_1.default.bold('help'))} Display this help message`);
|
|
82
87
|
console.log(` - ${colors_1.default.yellow(colors_1.default.bold('exit'))} Quit this session`);
|
|
83
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Checks for the latest version of the app from GitHub and compares it with the current version.
|
|
91
|
+
* If a new version is available, it notifies the user.
|
|
92
|
+
* @private
|
|
93
|
+
* @returns {Promise<void>}
|
|
94
|
+
*/
|
|
95
|
+
async checkForLatestVersion() {
|
|
96
|
+
try {
|
|
97
|
+
const response = await axios_1.default.get('https://api.github.com/repos/cloving-ai/cloving-cli/releases/latest');
|
|
98
|
+
const latestVersion = response.data.tag_name;
|
|
99
|
+
const currentVersion = `v${(0, command_utils_1.getPackageVersion)()}`;
|
|
100
|
+
if (latestVersion !== currentVersion) {
|
|
101
|
+
console.log(colors_1.default.bgWhite.black(`\n š A new version of Cloving is available: ${latestVersion} `));
|
|
102
|
+
console.log(colors_1.default.bgWhite.black(` You are currently using version: ${currentVersion} `));
|
|
103
|
+
console.log(colors_1.default.bgWhite.black(` To upgrade, run: ${colors_1.default.bgWhite.black.bold('npm install -g cloving@latest')} `));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
// ignore errors
|
|
108
|
+
}
|
|
109
|
+
}
|
|
84
110
|
/**
|
|
85
111
|
* Sets up event listeners for the readline interface and process input.
|
|
86
112
|
* @private
|
|
@@ -313,6 +339,7 @@ class ChatManager {
|
|
|
313
339
|
try {
|
|
314
340
|
this.contextFiles = await (0, command_utils_1.addFileOrDirectoryToContext)(filePath, this.contextFiles, this.options);
|
|
315
341
|
console.log(`\nAdded ${colors_1.default.bold(colors_1.default.green(filePath))} to this chat session's context`);
|
|
342
|
+
this.refreshContext();
|
|
316
343
|
}
|
|
317
344
|
catch (error) {
|
|
318
345
|
console.error(`Failed to add ${colors_1.default.bold(colors_1.default.red(filePath))} to this chat session's context:`, error);
|
|
@@ -323,6 +350,11 @@ class ChatManager {
|
|
|
323
350
|
}
|
|
324
351
|
this.rl.prompt();
|
|
325
352
|
}
|
|
353
|
+
refreshContext() {
|
|
354
|
+
const updatedSystemPrompt = (0, command_utils_1.generateCodegenPrompt)(this.contextFiles);
|
|
355
|
+
this.chatHistory[0] = { role: 'user', content: updatedSystemPrompt };
|
|
356
|
+
this.chatHistory[1] = { role: 'assistant', content: 'What would you like to do?' };
|
|
357
|
+
}
|
|
326
358
|
isRemoveCommand(command) {
|
|
327
359
|
return command.startsWith('rm ');
|
|
328
360
|
}
|
|
@@ -461,8 +493,50 @@ class ChatManager {
|
|
|
461
493
|
this.isProcessing = true;
|
|
462
494
|
this.chunkManager = new ChunkManager_1.default();
|
|
463
495
|
try {
|
|
464
|
-
this.
|
|
496
|
+
this.refreshContext();
|
|
465
497
|
this.prompt = this.generatePrompt(input);
|
|
498
|
+
this.addChatHistory(this.prompt);
|
|
499
|
+
if (!this.isSilent) {
|
|
500
|
+
const fullPrompt = this.chatHistory.map(m => {
|
|
501
|
+
const content = m.content.split('\n').map(line => {
|
|
502
|
+
if (line.startsWith('###')) {
|
|
503
|
+
return colors_1.default.red.bold(line);
|
|
504
|
+
}
|
|
505
|
+
else if (line.startsWith('##')) {
|
|
506
|
+
return colors_1.default.yellow.bold(line);
|
|
507
|
+
}
|
|
508
|
+
return line;
|
|
509
|
+
}).join('\n');
|
|
510
|
+
return m.role === 'user' ? `${colors_1.default.yellow.bold('## User Prompt')}\n\n${content}` : `${colors_1.default.green.bold('## š Cloving\'s Response š')}\n\n${content}`;
|
|
511
|
+
}).join('\n\n');
|
|
512
|
+
// Review the prompt using the REPL
|
|
513
|
+
const tokenCount = Math.ceil(fullPrompt.length / 4).toLocaleString();
|
|
514
|
+
console.log(`The generated prompt is approximately ${tokenCount} tokens long. Would you like to review the prompt before sending it? ${colors_1.default.gray('(Y/n)')}`);
|
|
515
|
+
const reviewPrompt = await new Promise((resolve) => {
|
|
516
|
+
this.rl.question(colors_1.default.green.bold('cloving> '), (answer) => {
|
|
517
|
+
resolve(answer.trim().toLowerCase());
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
if (reviewPrompt === 'y' || reviewPrompt === '') {
|
|
521
|
+
console.log(colors_1.default.gray.bold('\n---------------------- PROMPT START ----------------------\n'));
|
|
522
|
+
const promptParts = fullPrompt.split('\n```');
|
|
523
|
+
const highlightedPrompt = promptParts.map((part, index) => index % 2 === 1 ? (0, cli_highlight_1.default)(part, { language: 'typescript' }) : part).join('\n```');
|
|
524
|
+
console.log(highlightedPrompt);
|
|
525
|
+
console.log(colors_1.default.gray.bold('\n---------------------- PROMPT END ----------------------\n'));
|
|
526
|
+
console.log(`Do you want to proceed with this prompt? ${colors_1.default.gray('(Y/n)')}`);
|
|
527
|
+
const confirmPrompt = await new Promise((resolve) => {
|
|
528
|
+
this.rl.question(colors_1.default.green.bold('cloving> '), (answer) => {
|
|
529
|
+
resolve(answer.trim().toLowerCase());
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
if (confirmPrompt !== 'y' && confirmPrompt !== '') {
|
|
533
|
+
console.log('Operation cancelled by user.');
|
|
534
|
+
this.isProcessing = false;
|
|
535
|
+
this.rl.prompt();
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
466
540
|
const responseStream = await this.gpt.streamText({ prompt: this.prompt, messages: this.chatHistory });
|
|
467
541
|
let accumulatedContent = '';
|
|
468
542
|
this.handleResponseStream(responseStream, accumulatedContent);
|
|
@@ -471,12 +545,7 @@ class ChatManager {
|
|
|
471
545
|
this.handleError(err);
|
|
472
546
|
}
|
|
473
547
|
}
|
|
474
|
-
|
|
475
|
-
if (this.chatHistory.length === 0) {
|
|
476
|
-
const systemPrompt = (0, command_utils_1.generateCodegenPrompt)(this.contextFiles);
|
|
477
|
-
this.chatHistory.push({ role: 'user', content: systemPrompt });
|
|
478
|
-
this.chatHistory.push({ role: 'assistant', content: 'What would you like to do?' });
|
|
479
|
-
}
|
|
548
|
+
addChatHistory(input) {
|
|
480
549
|
this.chatHistory.push({ role: 'user', content: input });
|
|
481
550
|
}
|
|
482
551
|
handleResponseStream(responseStream, accumulatedContent) {
|
|
@@ -510,16 +579,16 @@ class ChatManager {
|
|
|
510
579
|
this.isProcessing = false;
|
|
511
580
|
process.stdout.write(`
|
|
512
581
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
582
|
+
You can follow up with another request or:
|
|
583
|
+
- type ${colors_1.default.yellow(colors_1.default.bold('"save"'))} to save all the changes to files
|
|
584
|
+
- type ${colors_1.default.yellow(colors_1.default.bold('"commit"'))} to commit the changes to git with a AI - generated message
|
|
585
|
+
- type ${colors_1.default.yellow(colors_1.default.bold('"copy"'))} to copy the last response to clipboard
|
|
586
|
+
- type ${colors_1.default.yellow(colors_1.default.bold('"review"'))} to start a code review
|
|
587
|
+
- type ${colors_1.default.yellow(colors_1.default.bold('"add <file-path>"'))} to add a file to the chat context
|
|
588
|
+
- type ${colors_1.default.yellow(colors_1.default.bold('"rm <pattern>"'))} to remove files from the chat context
|
|
589
|
+
- type ${colors_1.default.yellow(colors_1.default.bold('"ls <pattern>"'))} to list files in the chat context
|
|
590
|
+
- type ${colors_1.default.yellow(colors_1.default.bold('"git <command>"'))} to run a git command
|
|
591
|
+
- type ${colors_1.default.yellow(colors_1.default.bold('"exit"'))} to quit this session
|
|
523
592
|
`);
|
|
524
593
|
this.rl.prompt();
|
|
525
594
|
}
|
|
@@ -542,7 +611,7 @@ class ChatManager {
|
|
|
542
611
|
break;
|
|
543
612
|
}
|
|
544
613
|
const promptTokens = Math.ceil(this.prompt.length / 4).toLocaleString();
|
|
545
|
-
console.error(`Error processing a ${promptTokens} token prompt
|
|
614
|
+
console.error(`Error processing a ${promptTokens} token prompt: `, errorMessage, `(${errorNumber}) \n`);
|
|
546
615
|
this.isProcessing = false;
|
|
547
616
|
this.rl.prompt();
|
|
548
617
|
}
|
|
@@ -570,27 +639,13 @@ class ChatManager {
|
|
|
570
639
|
* accurate and relevant responses.
|
|
571
640
|
*/
|
|
572
641
|
generatePrompt(prompt) {
|
|
573
|
-
const contextFileContents = Object.keys(this.contextFiles)
|
|
574
|
-
.map((file) => `### Contents of ${file}\n\n${this.contextFiles[file]}\n\n`)
|
|
575
|
-
.join('\n');
|
|
576
|
-
const allButLast = this.chatHistory.slice(0, -1).map(msg => `${msg.role.toUpperCase()}: ${msg.content}`).join('\n\n');
|
|
577
642
|
return `### Request
|
|
578
643
|
|
|
579
644
|
${prompt}
|
|
580
645
|
|
|
581
|
-
${contextFileContents}
|
|
582
|
-
|
|
583
|
-
### Full Chat History Context
|
|
584
|
-
|
|
585
|
-
${allButLast}
|
|
586
|
-
|
|
587
|
-
### Current Request
|
|
588
|
-
|
|
589
|
-
${prompt}
|
|
590
|
-
|
|
591
646
|
### Note
|
|
592
647
|
|
|
593
|
-
Whenever possible, break up the changes into pieces and make sure every change is in its own CURRENT/NEW block.`;
|
|
648
|
+
Whenever possible, break up the changes into pieces and make sure every change is in its own CURRENT / NEW block.`;
|
|
594
649
|
}
|
|
595
650
|
handleClose() {
|
|
596
651
|
console.log('Goodbye!');
|
package/dist/package.json
CHANGED
|
@@ -3,20 +3,37 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.addFileOrDirectoryToContext = exports.readFileContent = exports.fetchModels = exports.runCommand = exports.generateFileList = exports.getAllFilesInDirectory = exports.checkForSpecialFiles = exports.collectSpecialFileContents = exports.generateShellPrompt = exports.generateCodegenPrompt = exports.SPECIAL_FILES = void 0;
|
|
6
|
+
exports.addFileOrDirectoryToContext = exports.readFileContent = exports.fetchModels = exports.runCommand = exports.generateFileList = exports.getAllFilesInDirectory = exports.checkForSpecialFiles = exports.collectSpecialFileContents = exports.generateShellPrompt = exports.generateCodegenPrompt = exports.getPackageVersion = exports.SPECIAL_FILES = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const child_process_1 = require("child_process");
|
|
10
10
|
const isbinaryfile_1 = require("isbinaryfile");
|
|
11
11
|
const colors_1 = __importDefault(require("colors"));
|
|
12
|
+
const path_2 = require("path");
|
|
12
13
|
const config_utils_1 = require("./config_utils");
|
|
13
14
|
exports.SPECIAL_FILES = [
|
|
14
15
|
'package.json', 'Gemfile', 'requirements.txt', 'Pipfile', 'pyproject.toml', 'pom.xml', 'build.gradle',
|
|
15
16
|
'.csproj', 'packages.config', 'composer.json', 'CMakeLists.txt', 'conanfile.txt', 'conanfile.py',
|
|
16
17
|
'go.mod', 'Cargo.toml', 'Package.swift', 'build.gradle.kts', 'Podfile', 'Cartfile', 'cpanfile',
|
|
17
18
|
'DESCRIPTION', 'mix.exs', 'build.sbt', 'pubspec.yaml', 'stack.yaml', 'cabal.project', 'Project.toml',
|
|
18
|
-
'rockspec', 'rebar.config', 'project.clj', 'tsconfig.json'
|
|
19
|
+
'rockspec', 'rebar.config', 'project.clj', 'tsconfig.json', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yaml',
|
|
20
|
+
'.eslintrc.yml', '.eslintrc', '.prettierrc', '.prettierrc.js', '.prettierrc.json', '.prettierrc.yaml',
|
|
21
|
+
'.prettierrc.yml', '.prettierrc', '.stylelintrc', '.stylelintrc.json', '.stylelintrc.yaml', '.stylelintrc.yml',
|
|
22
|
+
'.stylelintrc', 'jest.config.js', 'jest.config.json', 'jest.config.ts', 'jest.config.cjs', 'jest.config.mjs',
|
|
23
|
+
'webpack.config.js', 'webpack.config.ts', 'webpack.config.cjs', 'webpack.config.mjs', 'webpack.config.common.js',
|
|
19
24
|
];
|
|
25
|
+
const getPackageVersion = () => {
|
|
26
|
+
const packagePath = (0, path_2.join)(__dirname, '..', 'package.json');
|
|
27
|
+
const packageJson = JSON.parse(fs_1.default.readFileSync(packagePath, 'utf8'));
|
|
28
|
+
return packageJson.version;
|
|
29
|
+
};
|
|
30
|
+
exports.getPackageVersion = getPackageVersion;
|
|
31
|
+
const renderAsString = (contextFile) => {
|
|
32
|
+
if (typeof contextFile === 'string') {
|
|
33
|
+
return contextFile;
|
|
34
|
+
}
|
|
35
|
+
return JSON.stringify(contextFile, null, 2);
|
|
36
|
+
};
|
|
20
37
|
const generateCodegenPrompt = (contextFilesContent) => {
|
|
21
38
|
const instructions = `## AI Code Generation Instructions
|
|
22
39
|
|
|
@@ -52,13 +69,16 @@ const generateCodegenPrompt = (contextFilesContent) => {
|
|
|
52
69
|
7. **Close the block with three backticks.**
|
|
53
70
|
\`\`\``;
|
|
54
71
|
const specialFileContents = (0, exports.collectSpecialFileContents)();
|
|
55
|
-
|
|
72
|
+
// detect if specialFileContents[file] is a string or an object
|
|
73
|
+
const specialFiles = Object.keys(specialFileContents).map((file) => `### Contents of **${file}**\n\n\`\`\`\n${renderAsString(specialFileContents[file])}\n\`\`\`\n\n`).join('\n');
|
|
56
74
|
const contextFileContents = Object.keys(contextFilesContent).map((file) => `### Contents of **${file}**\n\n\`\`\`\n${contextFilesContent[file]}\n\`\`\`\n\n`).join('\n');
|
|
57
75
|
const prompt = `${instructions}
|
|
58
76
|
|
|
59
77
|
## Description of App
|
|
60
78
|
|
|
79
|
+
\`\`\`json
|
|
61
80
|
${JSON.stringify((0, config_utils_1.getClovingConfig)(), null, 2)}
|
|
81
|
+
\`\`\`
|
|
62
82
|
|
|
63
83
|
## Special Files
|
|
64
84
|
|