codereviewerai 1.0.0
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 +336 -0
- package/bin/awesomediagns.js +9 -0
- package/dist/ai/provider.js +157 -0
- package/dist/ai/provider.js.map +1 -0
- package/dist/config/manager.js +94 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/wizard.js +89 -0
- package/dist/config/wizard.js.map +1 -0
- package/dist/core/context.js +121 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/reviewer.js +108 -0
- package/dist/core/reviewer.js.map +1 -0
- package/dist/core/watcher.js +75 -0
- package/dist/core/watcher.js.map +1 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/dist/ui/chat.js +88 -0
- package/dist/ui/chat.js.map +1 -0
- package/dist/ui/home.js +54 -0
- package/dist/ui/home.js.map +1 -0
- package/package.json +52 -0
- package/src/ai/provider.ts +170 -0
- package/src/config/manager.ts +120 -0
- package/src/config/wizard.ts +93 -0
- package/src/core/context.ts +139 -0
- package/src/core/reviewer.ts +127 -0
- package/src/core/watcher.ts +86 -0
- package/src/index.ts +109 -0
- package/src/ui/chat.ts +111 -0
- package/src/ui/home.ts +60 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { ConfigManager } from './manager.js';
|
|
4
|
+
export class ConfigWizard {
|
|
5
|
+
manager;
|
|
6
|
+
constructor() {
|
|
7
|
+
this.manager = new ConfigManager();
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The main setup flow for a new user
|
|
11
|
+
*/
|
|
12
|
+
async runSetup() {
|
|
13
|
+
console.log(chalk.cyan.bold('\n✨ codereviewer.ai Setup Wizard ✨'));
|
|
14
|
+
console.log(chalk.gray('Let\'s configure your AI preferences.\n'));
|
|
15
|
+
const answers = await inquirer.prompt([
|
|
16
|
+
{
|
|
17
|
+
type: 'list',
|
|
18
|
+
name: 'provider',
|
|
19
|
+
message: 'Select your preferred AI Provider:',
|
|
20
|
+
choices: [
|
|
21
|
+
{ name: 'Google Gemini (Fast & Large Context)', value: 'gemini' },
|
|
22
|
+
{ name: 'OpenAI (GPT-4o)', value: 'openai' },
|
|
23
|
+
{ name: 'Anthropic (Claude 3.5 Sonnet)', value: 'claude' }
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: 'password',
|
|
28
|
+
name: 'apiKey',
|
|
29
|
+
message: 'Enter your API Key:',
|
|
30
|
+
mask: '*',
|
|
31
|
+
validate: (input) => input.length > 0 || 'API Key is required.'
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
type: 'list',
|
|
35
|
+
name: 'reviewDepth',
|
|
36
|
+
message: 'Default Review Depth:',
|
|
37
|
+
choices: [
|
|
38
|
+
{ name: 'Quick (Focus on critical bugs)', value: 'quick' },
|
|
39
|
+
{ name: 'Deep (Full architectural analysis)', value: 'deep' }
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: 'list',
|
|
44
|
+
name: 'mode',
|
|
45
|
+
message: 'Operation Mode:',
|
|
46
|
+
choices: [
|
|
47
|
+
{ name: 'Manual (Review when I run the command)', value: 'manual' },
|
|
48
|
+
{ name: 'Auto (Review every time I save a file)', value: 'auto' }
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
]);
|
|
52
|
+
// Map models based on the provider chosen
|
|
53
|
+
let defaultModel = 'gemini-1.5-pro';
|
|
54
|
+
if (answers.provider === 'openai')
|
|
55
|
+
defaultModel = 'gpt-4o';
|
|
56
|
+
if (answers.provider === 'claude')
|
|
57
|
+
defaultModel = 'claude-3-5-sonnet-20240620';
|
|
58
|
+
// Save everything to the manager
|
|
59
|
+
this.manager.setFullConfig({
|
|
60
|
+
...answers,
|
|
61
|
+
model: defaultModel,
|
|
62
|
+
includeContext: true,
|
|
63
|
+
maxContextMessages: 10
|
|
64
|
+
});
|
|
65
|
+
console.log(chalk.green.bold('\n✅ Configuration successful!'));
|
|
66
|
+
console.log(chalk.gray('You can now run ') + chalk.white.bold('awd review') + chalk.gray(' to start your first review.\n'));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Allows reconfiguring a specific setting without a full reset
|
|
70
|
+
*/
|
|
71
|
+
async reconfigure(type) {
|
|
72
|
+
if (type === 'provider') {
|
|
73
|
+
const { provider, apiKey } = await inquirer.prompt([
|
|
74
|
+
{ type: 'list', name: 'provider', message: 'New Provider:', choices: ['gemini', 'openai', 'claude'] },
|
|
75
|
+
{ type: 'password', name: 'apiKey', message: 'New API Key:' }
|
|
76
|
+
]);
|
|
77
|
+
this.manager.setKey('provider', provider);
|
|
78
|
+
this.manager.setKey('apiKey', apiKey);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const { mode } = await inquirer.prompt([
|
|
82
|
+
{ type: 'list', name: 'mode', message: 'Switch Mode:', choices: ['manual', 'auto'] }
|
|
83
|
+
]);
|
|
84
|
+
this.manager.setKey('mode', mode);
|
|
85
|
+
}
|
|
86
|
+
console.log(chalk.green(`✅ ${type} updated successfully.`));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=wizard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../src/config/wizard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
export class ContextManager {
|
|
5
|
+
contextDir;
|
|
6
|
+
historyFile;
|
|
7
|
+
chatFile;
|
|
8
|
+
constructor() {
|
|
9
|
+
// This looks for the local project folder created by ConfigManager
|
|
10
|
+
this.contextDir = path.join(process.cwd(), '.awesomediagns');
|
|
11
|
+
this.historyFile = path.join(this.contextDir, 'history', 'reviews.json');
|
|
12
|
+
this.chatFile = path.join(this.contextDir, 'history', 'chat.json');
|
|
13
|
+
this.ensureDirectories();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Ensures the local .awesomediagns folder exists before writing
|
|
17
|
+
*/
|
|
18
|
+
ensureDirectories() {
|
|
19
|
+
const historyDir = path.join(this.contextDir, 'history');
|
|
20
|
+
if (!fs.existsSync(historyDir)) {
|
|
21
|
+
try {
|
|
22
|
+
fs.mkdirSync(historyDir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
// If not in a project, we don't crash, but we can't save context
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (!fs.existsSync(this.historyFile)) {
|
|
30
|
+
fs.writeFileSync(this.historyFile, JSON.stringify([], null, 2));
|
|
31
|
+
}
|
|
32
|
+
if (!fs.existsSync(this.chatFile)) {
|
|
33
|
+
fs.writeFileSync(this.chatFile, JSON.stringify([], null, 2));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Gets previous review data for a specific file to give AI "memory"
|
|
38
|
+
*/
|
|
39
|
+
async getContext(filePath) {
|
|
40
|
+
try {
|
|
41
|
+
const history = this.loadHistory();
|
|
42
|
+
const fileHistory = history
|
|
43
|
+
.filter((entry) => entry.file === filePath)
|
|
44
|
+
.slice(-3); // Last 3 reviews for this specific file
|
|
45
|
+
return {
|
|
46
|
+
previousReviews: fileHistory.map((entry) => ({
|
|
47
|
+
timestamp: entry.timestamp,
|
|
48
|
+
score: entry.score,
|
|
49
|
+
summary: entry.review.summary
|
|
50
|
+
}))
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
return { previousReviews: [] };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Saves a new review into the local project history
|
|
59
|
+
*/
|
|
60
|
+
async addToContext(filePath, code, review) {
|
|
61
|
+
try {
|
|
62
|
+
const history = this.loadHistory();
|
|
63
|
+
const entry = {
|
|
64
|
+
file: filePath,
|
|
65
|
+
timestamp: new Date().toISOString(),
|
|
66
|
+
code: code.length > 500 ? code.substring(0, 500) + '...' : code,
|
|
67
|
+
review,
|
|
68
|
+
score: review.score || 0
|
|
69
|
+
};
|
|
70
|
+
history.push(entry);
|
|
71
|
+
// Limit to last 50 reviews to keep file size small
|
|
72
|
+
const limitedHistory = history.slice(-50);
|
|
73
|
+
fs.writeFileSync(this.historyFile, JSON.stringify(limitedHistory, null, 2));
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.error(chalk.red('Failed to save review context locally.'));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Conversation History for the AI Chat mode
|
|
81
|
+
*/
|
|
82
|
+
async getChatHistory() {
|
|
83
|
+
if (!fs.existsSync(this.chatFile))
|
|
84
|
+
return [];
|
|
85
|
+
try {
|
|
86
|
+
const data = fs.readFileSync(this.chatFile, 'utf-8');
|
|
87
|
+
return JSON.parse(data);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async saveChatHistory(messages) {
|
|
94
|
+
try {
|
|
95
|
+
fs.writeFileSync(this.chatFile, JSON.stringify(messages, null, 2));
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error(chalk.red('Failed to save chat history.'));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async getHistory(limit = 10) {
|
|
102
|
+
const history = this.loadHistory();
|
|
103
|
+
return history.slice(-limit).reverse();
|
|
104
|
+
}
|
|
105
|
+
async clearHistory() {
|
|
106
|
+
fs.writeFileSync(this.historyFile, JSON.stringify([], null, 2));
|
|
107
|
+
fs.writeFileSync(this.chatFile, JSON.stringify([], null, 2));
|
|
108
|
+
}
|
|
109
|
+
loadHistory() {
|
|
110
|
+
try {
|
|
111
|
+
if (!fs.existsSync(this.historyFile))
|
|
112
|
+
return [];
|
|
113
|
+
const data = fs.readFileSync(this.historyFile, 'utf-8');
|
|
114
|
+
return JSON.parse(data);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import boxen from 'boxen';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
// FIX: Named import for simpleGit is required in ESM/TS
|
|
7
|
+
import { simpleGit } from 'simple-git';
|
|
8
|
+
import { AIProvider } from '../ai/provider.js';
|
|
9
|
+
import { ContextManager } from './context.js';
|
|
10
|
+
export class ReviewEngine {
|
|
11
|
+
configManager;
|
|
12
|
+
aiProvider;
|
|
13
|
+
contextManager;
|
|
14
|
+
git;
|
|
15
|
+
constructor(configManager) {
|
|
16
|
+
this.configManager = configManager;
|
|
17
|
+
this.aiProvider = new AIProvider(configManager);
|
|
18
|
+
this.contextManager = new ContextManager();
|
|
19
|
+
// FIX: Standard initialization call
|
|
20
|
+
this.git = simpleGit();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Reviews a specific file by reading its current content
|
|
24
|
+
*/
|
|
25
|
+
async reviewFile(filePath) {
|
|
26
|
+
const spinner = ora(`Reading ${path.basename(filePath)}...`).start();
|
|
27
|
+
try {
|
|
28
|
+
const fullPath = path.resolve(process.cwd(), filePath);
|
|
29
|
+
if (!fs.existsSync(fullPath)) {
|
|
30
|
+
spinner.fail(chalk.red(`File not found: ${filePath}`));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const code = fs.readFileSync(fullPath, 'utf-8');
|
|
34
|
+
// Optimization: Get the actual changes to reduce AI token usage
|
|
35
|
+
const diff = await this.git.diff([filePath]);
|
|
36
|
+
spinner.text = 'AI is analyzing your changes...';
|
|
37
|
+
const context = await this.contextManager.getContext(filePath);
|
|
38
|
+
// Logic: If there is a diff, review the diff. Otherwise, review the whole file.
|
|
39
|
+
const review = await this.aiProvider.reviewCode(diff || code, filePath, context);
|
|
40
|
+
spinner.succeed(chalk.green('Review complete!'));
|
|
41
|
+
this.displayReview(filePath, review);
|
|
42
|
+
await this.contextManager.addToContext(filePath, code, review);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
spinner.fail(chalk.red('Review failed: ' + error.message));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Reviews only files that are currently in the Git Staging Area
|
|
50
|
+
*/
|
|
51
|
+
async reviewStaged() {
|
|
52
|
+
const spinner = ora('Checking staged files...').start();
|
|
53
|
+
try {
|
|
54
|
+
const status = await this.git.status();
|
|
55
|
+
const stagedFiles = status.staged;
|
|
56
|
+
if (stagedFiles.length === 0) {
|
|
57
|
+
spinner.info(chalk.yellow('No staged files found. Use "git add" first.'));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
spinner.succeed(chalk.green(`Found ${stagedFiles.length} staged file(s)`));
|
|
61
|
+
for (const file of stagedFiles) {
|
|
62
|
+
console.log(chalk.cyan(`\n📄 File: ${file}`));
|
|
63
|
+
// Ensure file is a string before passing
|
|
64
|
+
await this.reviewFile(file);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
spinner.fail(chalk.red('Git Error: ' + error.message));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
displayReview(filePath, review) {
|
|
72
|
+
// Safe check for the score to avoid crashes if the AI returns a string
|
|
73
|
+
const score = parseInt(review.score) || 0;
|
|
74
|
+
const scoreColor = score >= 8 ? chalk.green : score >= 5 ? chalk.yellow : chalk.red;
|
|
75
|
+
let content = `${chalk.bold('Summary:')} ${review.summary}\n`;
|
|
76
|
+
content += `${chalk.bold('Score:')} ${scoreColor(score + '/10')}\n\n`;
|
|
77
|
+
if (review.issues && review.issues.length > 0) {
|
|
78
|
+
content += `${chalk.red.bold('🚀 Issues Found:')}\n`;
|
|
79
|
+
review.issues.forEach((issue) => {
|
|
80
|
+
content += `${chalk.yellow('•')} [Line ${issue.line || '?'}] ${issue.msg}\n`;
|
|
81
|
+
if (issue.fix)
|
|
82
|
+
content += ` ${chalk.gray('Suggested Fix:')} ${chalk.italic(issue.fix)}\n`;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
content += chalk.green('✅ No critical issues found. Great job!\n');
|
|
87
|
+
}
|
|
88
|
+
if (review.optimizations && Array.isArray(review.optimizations)) {
|
|
89
|
+
content += `\n${chalk.blue.bold('⚡ Optimizations:')}\n`;
|
|
90
|
+
review.optimizations.forEach((opt) => {
|
|
91
|
+
content += `${chalk.blue('→')} ${opt}\n`;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
console.log(boxen(content, {
|
|
95
|
+
title: filePath,
|
|
96
|
+
titleAlignment: 'center',
|
|
97
|
+
padding: 1,
|
|
98
|
+
margin: 1,
|
|
99
|
+
borderStyle: 'round',
|
|
100
|
+
borderColor: 'cyan'
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
async clearHistory() {
|
|
104
|
+
await this.contextManager.clearHistory();
|
|
105
|
+
console.log(chalk.green('✅ Local history cleared.'));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=reviewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewer.js","sourceRoot":"","sources":["../../src/core/reviewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { watch } from 'chokidar'; // Fixed import
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { ReviewEngine } from './reviewer.js';
|
|
5
|
+
export class FileWatcher {
|
|
6
|
+
// Fixed: Using the explicitly imported FSWatcher type
|
|
7
|
+
watcher = null;
|
|
8
|
+
reviewer;
|
|
9
|
+
configManager;
|
|
10
|
+
constructor(configManager) {
|
|
11
|
+
this.configManager = configManager;
|
|
12
|
+
this.reviewer = new ReviewEngine(configManager);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Starts the background process to watch for file changes
|
|
16
|
+
*/
|
|
17
|
+
async start() {
|
|
18
|
+
// Clear terminal for a clean "Watch Mode" UI
|
|
19
|
+
console.clear();
|
|
20
|
+
console.log(chalk.bold.green('👀 codereviewer.ai is now watching your code...'));
|
|
21
|
+
console.log(chalk.gray('Press Ctrl+C to stop the watcher.\n'));
|
|
22
|
+
// Fixed: Use the watch() function directly
|
|
23
|
+
this.watcher = watch(process.cwd(), {
|
|
24
|
+
ignored: [
|
|
25
|
+
/(^|[\/\\])\../, // ignore dotfiles (.git, .awesomediagns)
|
|
26
|
+
'**/node_modules/**',
|
|
27
|
+
'**/dist/**',
|
|
28
|
+
'**/package-lock.json'
|
|
29
|
+
],
|
|
30
|
+
persistent: true,
|
|
31
|
+
ignoreInitial: true,
|
|
32
|
+
awaitWriteFinish: {
|
|
33
|
+
stabilityThreshold: 500,
|
|
34
|
+
pollInterval: 100
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
// Event listener for saved changes
|
|
38
|
+
this.watcher.on('change', async (filePath) => {
|
|
39
|
+
const fileName = path.basename(filePath);
|
|
40
|
+
const ext = path.extname(filePath);
|
|
41
|
+
const supportedExtensions = ['.ts', '.js', '.py', '.go', '.cpp', '.java', '.tsx', '.jsx'];
|
|
42
|
+
if (supportedExtensions.includes(ext)) {
|
|
43
|
+
console.log(chalk.cyan(`\n💾 Change detected in: ${fileName}`));
|
|
44
|
+
// Trigger the review engine
|
|
45
|
+
try {
|
|
46
|
+
await this.reviewer.reviewFile(filePath);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error(chalk.red('Review failed during auto-watch.'));
|
|
50
|
+
}
|
|
51
|
+
console.log(chalk.gray('\nWaiting for next change...'));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
this.watcher.on('error', (error) => {
|
|
55
|
+
console.error(chalk.red(`Watcher error: ${error.message}`));
|
|
56
|
+
});
|
|
57
|
+
// Handle process termination to clean up the watcher
|
|
58
|
+
process.on('SIGINT', () => {
|
|
59
|
+
this.stop();
|
|
60
|
+
// Give the close() promise a moment to resolve before exiting
|
|
61
|
+
setTimeout(() => process.exit(0), 100);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Stops the watcher safely
|
|
66
|
+
*/
|
|
67
|
+
stop() {
|
|
68
|
+
if (this.watcher) {
|
|
69
|
+
this.watcher.close().then(() => {
|
|
70
|
+
console.log(chalk.yellow('\n🛑 Watcher stopped. Goodbye!'));
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/core/watcher.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { homePage } from './ui/home.js'; // Note the .js extension for ESM
|
|
4
|
+
import { ConfigWizard } from './config/wizard.js';
|
|
5
|
+
import { ConfigManager } from './config/manager.js';
|
|
6
|
+
import { ReviewEngine } from './core/reviewer.js';
|
|
7
|
+
import { FileWatcher } from './core/watcher.js';
|
|
8
|
+
import { ChatInterface } from './ui/chat.js';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
// Fix for __dirname in ESM
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const packageJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf8'));
|
|
15
|
+
const program = new Command();
|
|
16
|
+
const configManager = new ConfigManager();
|
|
17
|
+
const configWizard = new ConfigWizard();
|
|
18
|
+
program
|
|
19
|
+
.name('awd')
|
|
20
|
+
.description('codereviewer.ai - AI-powered code review for developers')
|
|
21
|
+
.version(packageJson.version)
|
|
22
|
+
.alias('awesomediagns');
|
|
23
|
+
// --- 1. Home / Help ---
|
|
24
|
+
program
|
|
25
|
+
.command('home')
|
|
26
|
+
.description('Display the AwesomeDiagns home screen')
|
|
27
|
+
.action(async () => {
|
|
28
|
+
await homePage.displayWelcome();
|
|
29
|
+
homePage.displayQuickHelp();
|
|
30
|
+
});
|
|
31
|
+
// --- 2. Configuration ---
|
|
32
|
+
program
|
|
33
|
+
.command('init')
|
|
34
|
+
.description('Initialize your AI provider and API keys')
|
|
35
|
+
.action(async () => {
|
|
36
|
+
await configWizard.runSetup();
|
|
37
|
+
});
|
|
38
|
+
program
|
|
39
|
+
.command('config')
|
|
40
|
+
.description('View or update current configuration')
|
|
41
|
+
.option('-s, --show', 'Show current config')
|
|
42
|
+
.option('-r, --reset', 'Clear all settings')
|
|
43
|
+
.action(async (options) => {
|
|
44
|
+
if (options.show) {
|
|
45
|
+
configManager.displayConfig();
|
|
46
|
+
}
|
|
47
|
+
else if (options.reset) {
|
|
48
|
+
configManager.clearConfig();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
await configWizard.runSetup();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// --- 3. Code Review ---
|
|
55
|
+
program
|
|
56
|
+
.command('review [file]')
|
|
57
|
+
.description('Review staged changes or a specific file')
|
|
58
|
+
.option('-s, --staged', 'Review only files in git staging area', true)
|
|
59
|
+
.action(async (file, options) => {
|
|
60
|
+
if (!configManager.isConfigured()) {
|
|
61
|
+
console.log(chalk.red('\n❌ Not configured! Run: ') + chalk.white('awd init'));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const reviewer = new ReviewEngine(configManager);
|
|
65
|
+
if (file) {
|
|
66
|
+
await reviewer.reviewFile(file);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
await reviewer.reviewStaged();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
// --- 4. Auto-Mode (Watcher) ---
|
|
73
|
+
program
|
|
74
|
+
.command('watch')
|
|
75
|
+
.description('Start real-time auto-review mode (on save)')
|
|
76
|
+
.action(async () => {
|
|
77
|
+
if (!configManager.isConfigured())
|
|
78
|
+
return;
|
|
79
|
+
const watcher = new FileWatcher(configManager);
|
|
80
|
+
await watcher.start();
|
|
81
|
+
});
|
|
82
|
+
// --- 5. Interactive Chat ---
|
|
83
|
+
program
|
|
84
|
+
.command('chat')
|
|
85
|
+
.description('Start a conversation with the AI about your code')
|
|
86
|
+
.action(async () => {
|
|
87
|
+
const chat = new ChatInterface(configManager);
|
|
88
|
+
await chat.start();
|
|
89
|
+
});
|
|
90
|
+
// --- Default Action ---
|
|
91
|
+
// If the user just types 'awd', show the home page
|
|
92
|
+
program.action(async () => {
|
|
93
|
+
await homePage.displayWelcome();
|
|
94
|
+
homePage.displayQuickHelp();
|
|
95
|
+
});
|
|
96
|
+
// Handle unknown commands
|
|
97
|
+
program.on('command:*', () => {
|
|
98
|
+
console.error(chalk.red('\nInvalid command: %s\nSee --help for a list of available commands.'), program.args.join(' '));
|
|
99
|
+
process.exit(1);
|
|
100
|
+
});
|
|
101
|
+
program.parse(process.argv);
|
|
102
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/ui/chat.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { AIProvider } from '../ai/provider.js';
|
|
5
|
+
import { ContextManager } from '../core/context.js';
|
|
6
|
+
export class ChatInterface {
|
|
7
|
+
configManager;
|
|
8
|
+
aiProvider;
|
|
9
|
+
contextManager;
|
|
10
|
+
conversationHistory = [];
|
|
11
|
+
constructor(configManager) {
|
|
12
|
+
this.configManager = configManager;
|
|
13
|
+
this.aiProvider = new AIProvider(configManager);
|
|
14
|
+
this.contextManager = new ContextManager();
|
|
15
|
+
}
|
|
16
|
+
async start() {
|
|
17
|
+
console.clear();
|
|
18
|
+
console.log(chalk.cyan.bold('╔════════════════════════════════════════════╗'));
|
|
19
|
+
console.log(chalk.cyan.bold('║') + chalk.bold.white(' 💬 codereviewer.ai Chat Mode ') + chalk.cyan.bold('║'));
|
|
20
|
+
console.log(chalk.cyan.bold('╚════════════════════════════════════════════╝\n'));
|
|
21
|
+
console.log(chalk.gray('Type your questions about the code or reviews.'));
|
|
22
|
+
console.log(chalk.gray('Commands: "exit" to quit, "clear" to reset history.\n'));
|
|
23
|
+
// Load existing history
|
|
24
|
+
this.conversationHistory = await this.contextManager.getChatHistory();
|
|
25
|
+
if (this.conversationHistory.length > 0) {
|
|
26
|
+
console.log(chalk.yellow(`📖 Loaded ${this.conversationHistory.length} previous messages.\n`));
|
|
27
|
+
this.displayLastExchange();
|
|
28
|
+
}
|
|
29
|
+
await this.chatLoop();
|
|
30
|
+
}
|
|
31
|
+
async chatLoop() {
|
|
32
|
+
while (true) {
|
|
33
|
+
// Fix: Inquirer v9+ requires this specific handling for async loops
|
|
34
|
+
const answers = await inquirer.prompt([
|
|
35
|
+
{
|
|
36
|
+
type: 'input',
|
|
37
|
+
name: 'userInput',
|
|
38
|
+
message: chalk.green('You:'),
|
|
39
|
+
validate: (input) => input.trim().length > 0 || 'Please enter a message.'
|
|
40
|
+
}
|
|
41
|
+
]);
|
|
42
|
+
const userInput = answers.userInput;
|
|
43
|
+
const command = userInput.trim().toLowerCase();
|
|
44
|
+
if (command === 'exit' || command === 'quit') {
|
|
45
|
+
await this.contextManager.saveChatHistory(this.conversationHistory);
|
|
46
|
+
console.log(chalk.yellow('\n👋 Chat session saved. Goodbye!'));
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
if (command === 'clear') {
|
|
50
|
+
this.conversationHistory = [];
|
|
51
|
+
await this.contextManager.saveChatHistory([]);
|
|
52
|
+
console.log(chalk.red('🗑️ Chat history cleared.\n'));
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
await this.handleResponse(userInput);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async handleResponse(message) {
|
|
59
|
+
const spinner = ora('AI is thinking...').start();
|
|
60
|
+
try {
|
|
61
|
+
this.conversationHistory.push({ role: 'user', content: message });
|
|
62
|
+
// Ensure your AIProvider.ts actually has the .chat() method!
|
|
63
|
+
const response = await this.aiProvider.chat(message, this.conversationHistory);
|
|
64
|
+
spinner.stop();
|
|
65
|
+
console.log(`\n${chalk.cyan.bold('AI:')} ${chalk.white(response)}\n`);
|
|
66
|
+
this.conversationHistory.push({ role: 'assistant', content: response });
|
|
67
|
+
// Keep context window manageable (e.g., last 20 messages)
|
|
68
|
+
if (this.conversationHistory.length > 20) {
|
|
69
|
+
this.conversationHistory = this.conversationHistory.slice(-20);
|
|
70
|
+
}
|
|
71
|
+
await this.contextManager.saveChatHistory(this.conversationHistory);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
spinner.fail(chalk.red('Error: ' + (error.message || 'Unknown AI error')));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
displayLastExchange() {
|
|
78
|
+
const lastTwo = this.conversationHistory.slice(-2);
|
|
79
|
+
lastTwo.forEach(msg => {
|
|
80
|
+
const label = msg.role === 'user' ? chalk.green('You:') : chalk.cyan.bold('AI:');
|
|
81
|
+
// Clean display of previous chat content
|
|
82
|
+
const preview = msg.content.length > 100 ? msg.content.substring(0, 100) + '...' : msg.content;
|
|
83
|
+
console.log(`${label} ${chalk.gray(preview)}`);
|
|
84
|
+
});
|
|
85
|
+
console.log(chalk.gray('————————————————————————————————─────────────\n'));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/ui/chat.ts"],"names":[],"mappings":"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"}
|