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,127 @@
|
|
|
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, SimpleGit } from 'simple-git';
|
|
8
|
+
import { ConfigManager } from '../config/manager.js';
|
|
9
|
+
import { AIProvider } from '../ai/provider.js';
|
|
10
|
+
import { ContextManager } from './context.js';
|
|
11
|
+
|
|
12
|
+
export class ReviewEngine {
|
|
13
|
+
private configManager: ConfigManager;
|
|
14
|
+
private aiProvider: AIProvider;
|
|
15
|
+
private contextManager: ContextManager;
|
|
16
|
+
private git: SimpleGit;
|
|
17
|
+
|
|
18
|
+
constructor(configManager: ConfigManager) {
|
|
19
|
+
this.configManager = configManager;
|
|
20
|
+
this.aiProvider = new AIProvider(configManager);
|
|
21
|
+
this.contextManager = new ContextManager();
|
|
22
|
+
// FIX: Standard initialization call
|
|
23
|
+
this.git = simpleGit();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Reviews a specific file by reading its current content
|
|
28
|
+
*/
|
|
29
|
+
async reviewFile(filePath: string): Promise<void> {
|
|
30
|
+
const spinner = ora(`Reading ${path.basename(filePath)}...`).start();
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const fullPath = path.resolve(process.cwd(), filePath);
|
|
34
|
+
if (!fs.existsSync(fullPath)) {
|
|
35
|
+
spinner.fail(chalk.red(`File not found: ${filePath}`));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const code = fs.readFileSync(fullPath, 'utf-8');
|
|
40
|
+
|
|
41
|
+
// Optimization: Get the actual changes to reduce AI token usage
|
|
42
|
+
const diff = await this.git.diff([filePath]);
|
|
43
|
+
|
|
44
|
+
spinner.text = 'AI is analyzing your changes...';
|
|
45
|
+
|
|
46
|
+
const context = await this.contextManager.getContext(filePath);
|
|
47
|
+
|
|
48
|
+
// Logic: If there is a diff, review the diff. Otherwise, review the whole file.
|
|
49
|
+
const review = await this.aiProvider.reviewCode(diff || code, filePath, context);
|
|
50
|
+
|
|
51
|
+
spinner.succeed(chalk.green('Review complete!'));
|
|
52
|
+
this.displayReview(filePath, review);
|
|
53
|
+
|
|
54
|
+
await this.contextManager.addToContext(filePath, code, review);
|
|
55
|
+
|
|
56
|
+
} catch (error: any) {
|
|
57
|
+
spinner.fail(chalk.red('Review failed: ' + error.message));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Reviews only files that are currently in the Git Staging Area
|
|
63
|
+
*/
|
|
64
|
+
async reviewStaged(): Promise<void> {
|
|
65
|
+
const spinner = ora('Checking staged files...').start();
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const status = await this.git.status();
|
|
69
|
+
const stagedFiles = status.staged;
|
|
70
|
+
|
|
71
|
+
if (stagedFiles.length === 0) {
|
|
72
|
+
spinner.info(chalk.yellow('No staged files found. Use "git add" first.'));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
spinner.succeed(chalk.green(`Found ${stagedFiles.length} staged file(s)`));
|
|
77
|
+
|
|
78
|
+
for (const file of stagedFiles) {
|
|
79
|
+
console.log(chalk.cyan(`\nš File: ${file}`));
|
|
80
|
+
// Ensure file is a string before passing
|
|
81
|
+
await this.reviewFile(file as string);
|
|
82
|
+
}
|
|
83
|
+
} catch (error: any) {
|
|
84
|
+
spinner.fail(chalk.red('Git Error: ' + error.message));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private displayReview(filePath: string, review: any): void {
|
|
89
|
+
// Safe check for the score to avoid crashes if the AI returns a string
|
|
90
|
+
const score = parseInt(review.score) || 0;
|
|
91
|
+
const scoreColor = score >= 8 ? chalk.green : score >= 5 ? chalk.yellow : chalk.red;
|
|
92
|
+
|
|
93
|
+
let content = `${chalk.bold('Summary:')} ${review.summary}\n`;
|
|
94
|
+
content += `${chalk.bold('Score:')} ${scoreColor(score + '/10')}\n\n`;
|
|
95
|
+
|
|
96
|
+
if (review.issues && review.issues.length > 0) {
|
|
97
|
+
content += `${chalk.red.bold('š Issues Found:')}\n`;
|
|
98
|
+
review.issues.forEach((issue: any) => {
|
|
99
|
+
content += `${chalk.yellow('ā¢')} [Line ${issue.line || '?'}] ${issue.msg}\n`;
|
|
100
|
+
if (issue.fix) content += ` ${chalk.gray('Suggested Fix:')} ${chalk.italic(issue.fix)}\n`;
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
content += chalk.green('ā
No critical issues found. Great job!\n');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (review.optimizations && Array.isArray(review.optimizations)) {
|
|
107
|
+
content += `\n${chalk.blue.bold('ā” Optimizations:')}\n`;
|
|
108
|
+
review.optimizations.forEach((opt: string) => {
|
|
109
|
+
content += `${chalk.blue('ā')} ${opt}\n`;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log(boxen(content, {
|
|
114
|
+
title: filePath,
|
|
115
|
+
titleAlignment: 'center',
|
|
116
|
+
padding: 1,
|
|
117
|
+
margin: 1,
|
|
118
|
+
borderStyle: 'round',
|
|
119
|
+
borderColor: 'cyan'
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async clearHistory(): Promise<void> {
|
|
124
|
+
await this.contextManager.clearHistory();
|
|
125
|
+
console.log(chalk.green('ā
Local history cleared.'));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { watch, FSWatcher } from 'chokidar'; // Fixed import
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { ConfigManager } from '../config/manager.js';
|
|
5
|
+
import { ReviewEngine } from './reviewer.js';
|
|
6
|
+
|
|
7
|
+
export class FileWatcher {
|
|
8
|
+
// Fixed: Using the explicitly imported FSWatcher type
|
|
9
|
+
private watcher: FSWatcher | null = null;
|
|
10
|
+
private reviewer: ReviewEngine;
|
|
11
|
+
private configManager: ConfigManager;
|
|
12
|
+
|
|
13
|
+
constructor(configManager: ConfigManager) {
|
|
14
|
+
this.configManager = configManager;
|
|
15
|
+
this.reviewer = new ReviewEngine(configManager);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Starts the background process to watch for file changes
|
|
20
|
+
*/
|
|
21
|
+
async start(): Promise<void> {
|
|
22
|
+
// Clear terminal for a clean "Watch Mode" UI
|
|
23
|
+
console.clear();
|
|
24
|
+
console.log(chalk.bold.green('š codereviewer.ai is now watching your code...'));
|
|
25
|
+
console.log(chalk.gray('Press Ctrl+C to stop the watcher.\n'));
|
|
26
|
+
|
|
27
|
+
// Fixed: Use the watch() function directly
|
|
28
|
+
this.watcher = watch(process.cwd(), {
|
|
29
|
+
ignored: [
|
|
30
|
+
/(^|[\/\\])\../, // ignore dotfiles (.git, .awesomediagns)
|
|
31
|
+
'**/node_modules/**',
|
|
32
|
+
'**/dist/**',
|
|
33
|
+
'**/package-lock.json'
|
|
34
|
+
],
|
|
35
|
+
persistent: true,
|
|
36
|
+
ignoreInitial: true,
|
|
37
|
+
awaitWriteFinish: {
|
|
38
|
+
stabilityThreshold: 500,
|
|
39
|
+
pollInterval: 100
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Event listener for saved changes
|
|
44
|
+
this.watcher.on('change', async (filePath: string) => {
|
|
45
|
+
const fileName = path.basename(filePath);
|
|
46
|
+
const ext = path.extname(filePath);
|
|
47
|
+
|
|
48
|
+
const supportedExtensions = ['.ts', '.js', '.py', '.go', '.cpp', '.java', '.tsx', '.jsx'];
|
|
49
|
+
|
|
50
|
+
if (supportedExtensions.includes(ext)) {
|
|
51
|
+
console.log(chalk.cyan(`\nš¾ Change detected in: ${fileName}`));
|
|
52
|
+
|
|
53
|
+
// Trigger the review engine
|
|
54
|
+
try {
|
|
55
|
+
await this.reviewer.reviewFile(filePath);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(chalk.red('Review failed during auto-watch.'));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log(chalk.gray('\nWaiting for next change...'));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
this.watcher.on('error', (error: unknown) => {
|
|
65
|
+
console.error(chalk.red(`Watcher error: ${(error as Error).message}`));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Handle process termination to clean up the watcher
|
|
69
|
+
process.on('SIGINT', () => {
|
|
70
|
+
this.stop();
|
|
71
|
+
// Give the close() promise a moment to resolve before exiting
|
|
72
|
+
setTimeout(() => process.exit(0), 100);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Stops the watcher safely
|
|
78
|
+
*/
|
|
79
|
+
stop(): void {
|
|
80
|
+
if (this.watcher) {
|
|
81
|
+
this.watcher.close().then(() => {
|
|
82
|
+
console.log(chalk.yellow('\nš Watcher stopped. Goodbye!'));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
|
|
13
|
+
// Fix for __dirname in ESM
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const packageJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf8'));
|
|
16
|
+
|
|
17
|
+
const program = new Command();
|
|
18
|
+
const configManager = new ConfigManager();
|
|
19
|
+
const configWizard = new ConfigWizard();
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.name('awd')
|
|
23
|
+
.description('codereviewer.ai - AI-powered code review for developers')
|
|
24
|
+
.version(packageJson.version)
|
|
25
|
+
.alias('awesomediagns');
|
|
26
|
+
|
|
27
|
+
// --- 1. Home / Help ---
|
|
28
|
+
program
|
|
29
|
+
.command('home')
|
|
30
|
+
.description('Display the AwesomeDiagns home screen')
|
|
31
|
+
.action(async () => {
|
|
32
|
+
await homePage.displayWelcome();
|
|
33
|
+
homePage.displayQuickHelp();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// --- 2. Configuration ---
|
|
37
|
+
program
|
|
38
|
+
.command('init')
|
|
39
|
+
.description('Initialize your AI provider and API keys')
|
|
40
|
+
.action(async () => {
|
|
41
|
+
await configWizard.runSetup();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
program
|
|
45
|
+
.command('config')
|
|
46
|
+
.description('View or update current configuration')
|
|
47
|
+
.option('-s, --show', 'Show current config')
|
|
48
|
+
.option('-r, --reset', 'Clear all settings')
|
|
49
|
+
.action(async (options) => {
|
|
50
|
+
if (options.show) {
|
|
51
|
+
configManager.displayConfig();
|
|
52
|
+
} else if (options.reset) {
|
|
53
|
+
configManager.clearConfig();
|
|
54
|
+
} else {
|
|
55
|
+
await configWizard.runSetup();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// --- 3. Code Review ---
|
|
60
|
+
program
|
|
61
|
+
.command('review [file]')
|
|
62
|
+
.description('Review staged changes or a specific file')
|
|
63
|
+
.option('-s, --staged', 'Review only files in git staging area', true)
|
|
64
|
+
.action(async (file, options) => {
|
|
65
|
+
if (!configManager.isConfigured()) {
|
|
66
|
+
console.log(chalk.red('\nā Not configured! Run: ') + chalk.white('awd init'));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const reviewer = new ReviewEngine(configManager);
|
|
70
|
+
if (file) {
|
|
71
|
+
await reviewer.reviewFile(file);
|
|
72
|
+
} else {
|
|
73
|
+
await reviewer.reviewStaged();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// --- 4. Auto-Mode (Watcher) ---
|
|
78
|
+
program
|
|
79
|
+
.command('watch')
|
|
80
|
+
.description('Start real-time auto-review mode (on save)')
|
|
81
|
+
.action(async () => {
|
|
82
|
+
if (!configManager.isConfigured()) return;
|
|
83
|
+
const watcher = new FileWatcher(configManager);
|
|
84
|
+
await watcher.start();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// --- 5. Interactive Chat ---
|
|
88
|
+
program
|
|
89
|
+
.command('chat')
|
|
90
|
+
.description('Start a conversation with the AI about your code')
|
|
91
|
+
.action(async () => {
|
|
92
|
+
const chat = new ChatInterface(configManager);
|
|
93
|
+
await chat.start();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// --- Default Action ---
|
|
97
|
+
// If the user just types 'awd', show the home page
|
|
98
|
+
program.action(async () => {
|
|
99
|
+
await homePage.displayWelcome();
|
|
100
|
+
homePage.displayQuickHelp();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Handle unknown commands
|
|
104
|
+
program.on('command:*', () => {
|
|
105
|
+
console.error(chalk.red('\nInvalid command: %s\nSee --help for a list of available commands.'), program.args.join(' '));
|
|
106
|
+
process.exit(1);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
program.parse(process.argv);
|
package/src/ui/chat.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { ConfigManager } from '../config/manager.js';
|
|
5
|
+
import { AIProvider } from '../ai/provider.js';
|
|
6
|
+
import { ContextManager } from '../core/context.js';
|
|
7
|
+
// Note: We import ChatMessage as a type if your TS version requires it
|
|
8
|
+
import type { ChatMessage } from '../core/context.js';
|
|
9
|
+
|
|
10
|
+
export class ChatInterface {
|
|
11
|
+
private configManager: ConfigManager;
|
|
12
|
+
private aiProvider: AIProvider;
|
|
13
|
+
private contextManager: ContextManager;
|
|
14
|
+
private conversationHistory: ChatMessage[] = [];
|
|
15
|
+
|
|
16
|
+
constructor(configManager: ConfigManager) {
|
|
17
|
+
this.configManager = configManager;
|
|
18
|
+
this.aiProvider = new AIProvider(configManager);
|
|
19
|
+
this.contextManager = new ContextManager();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async start(): Promise<void> {
|
|
23
|
+
console.clear();
|
|
24
|
+
console.log(chalk.cyan.bold('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
25
|
+
console.log(chalk.cyan.bold('ā') + chalk.bold.white(' š¬ codereviewer.ai Chat Mode ') + chalk.cyan.bold('ā'));
|
|
26
|
+
console.log(chalk.cyan.bold('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
27
|
+
|
|
28
|
+
console.log(chalk.gray('Type your questions about the code or reviews.'));
|
|
29
|
+
console.log(chalk.gray('Commands: "exit" to quit, "clear" to reset history.\n'));
|
|
30
|
+
|
|
31
|
+
// Load existing history
|
|
32
|
+
this.conversationHistory = await this.contextManager.getChatHistory();
|
|
33
|
+
|
|
34
|
+
if (this.conversationHistory.length > 0) {
|
|
35
|
+
console.log(chalk.yellow(`š Loaded ${this.conversationHistory.length} previous messages.\n`));
|
|
36
|
+
this.displayLastExchange();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await this.chatLoop();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private async chatLoop(): Promise<void> {
|
|
43
|
+
while (true) {
|
|
44
|
+
// Fix: Inquirer v9+ requires this specific handling for async loops
|
|
45
|
+
const answers = await inquirer.prompt([
|
|
46
|
+
{
|
|
47
|
+
type: 'input',
|
|
48
|
+
name: 'userInput',
|
|
49
|
+
message: chalk.green('You:'),
|
|
50
|
+
validate: (input: string) => input.trim().length > 0 || 'Please enter a message.'
|
|
51
|
+
}
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
const userInput = answers.userInput;
|
|
55
|
+
const command = userInput.trim().toLowerCase();
|
|
56
|
+
|
|
57
|
+
if (command === 'exit' || command === 'quit') {
|
|
58
|
+
await this.contextManager.saveChatHistory(this.conversationHistory);
|
|
59
|
+
console.log(chalk.yellow('\nš Chat session saved. Goodbye!'));
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (command === 'clear') {
|
|
64
|
+
this.conversationHistory = [];
|
|
65
|
+
await this.contextManager.saveChatHistory([]);
|
|
66
|
+
console.log(chalk.red('šļø Chat history cleared.\n'));
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
await this.handleResponse(userInput);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private async handleResponse(message: string): Promise<void> {
|
|
75
|
+
const spinner = ora('AI is thinking...').start();
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
this.conversationHistory.push({ role: 'user', content: message });
|
|
79
|
+
|
|
80
|
+
// Ensure your AIProvider.ts actually has the .chat() method!
|
|
81
|
+
const response = await this.aiProvider.chat(message, this.conversationHistory);
|
|
82
|
+
|
|
83
|
+
spinner.stop();
|
|
84
|
+
|
|
85
|
+
console.log(`\n${chalk.cyan.bold('AI:')} ${chalk.white(response)}\n`);
|
|
86
|
+
|
|
87
|
+
this.conversationHistory.push({ role: 'assistant', content: response });
|
|
88
|
+
|
|
89
|
+
// Keep context window manageable (e.g., last 20 messages)
|
|
90
|
+
if (this.conversationHistory.length > 20) {
|
|
91
|
+
this.conversationHistory = this.conversationHistory.slice(-20);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await this.contextManager.saveChatHistory(this.conversationHistory);
|
|
95
|
+
|
|
96
|
+
} catch (error: any) {
|
|
97
|
+
spinner.fail(chalk.red('Error: ' + (error.message || 'Unknown AI error')));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private displayLastExchange(): void {
|
|
102
|
+
const lastTwo = this.conversationHistory.slice(-2);
|
|
103
|
+
lastTwo.forEach(msg => {
|
|
104
|
+
const label = msg.role === 'user' ? chalk.green('You:') : chalk.cyan.bold('AI:');
|
|
105
|
+
// Clean display of previous chat content
|
|
106
|
+
const preview = msg.content.length > 100 ? msg.content.substring(0, 100) + '...' : msg.content;
|
|
107
|
+
console.log(`${label} ${chalk.gray(preview)}`);
|
|
108
|
+
});
|
|
109
|
+
console.log(chalk.gray('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
110
|
+
}
|
|
111
|
+
}
|
package/src/ui/home.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import figlet from 'figlet';
|
|
3
|
+
import gradient from 'gradient-string';
|
|
4
|
+
|
|
5
|
+
export const homePage = {
|
|
6
|
+
/**
|
|
7
|
+
* Displays the high-tech matrix-style header
|
|
8
|
+
*/
|
|
9
|
+
displayWelcome: async () => {
|
|
10
|
+
// Ensure the terminal is clear for the professional 'splash' effect
|
|
11
|
+
console.clear();
|
|
12
|
+
|
|
13
|
+
// Fix: Store the color in a constant for cleaner reuse
|
|
14
|
+
const matrixGreen = chalk.hex('#00FF41');
|
|
15
|
+
|
|
16
|
+
// Your specific ASCII Art - Wrapped in a raw string to protect backslashes
|
|
17
|
+
console.log(matrixGreen.bold(`
|
|
18
|
+
āāāāāāā āāāāāāā āāāāāāā āāāāāāāāāāāāāāā āāāāāāāāāāā āāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāā
|
|
19
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā
|
|
20
|
+
āāā āāā āāāāāā āāāāāāāāā āāāāāāāāāāāāāā āāā āāāāāāāāāāāā āāā āā āāāāāāāāā āāāāāāāā
|
|
21
|
+
āāā āāā āāāāāā āāāāāāāāā āāāāāāāāāāāāāā āāāā āāāāāāāāāāāāā āāāāāāāāāāāāāāāā āāāāāāāā
|
|
22
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā āāāāāāāāāāā āāāāāāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā āāā
|
|
23
|
+
āāāāāāā āāāāāāā āāāāāāā āāāāāāāāāāā āāāāāāāāāāā āāāāā āāāāāāāāāāā āāāāāāāā āāāāāāāāāāā āāā.ai
|
|
24
|
+
`));
|
|
25
|
+
|
|
26
|
+
// Adding a subtle subtitle using gradient
|
|
27
|
+
try {
|
|
28
|
+
const subHeader = figlet.textSync('CODEREVIEWER', {
|
|
29
|
+
font: 'Small',
|
|
30
|
+
horizontalLayout: 'default',
|
|
31
|
+
verticalLayout: 'default',
|
|
32
|
+
});
|
|
33
|
+
console.log(gradient(['#00FF41', '#008F11']).multiline(subHeader));
|
|
34
|
+
} catch (err) {
|
|
35
|
+
// Fallback if figlet fails
|
|
36
|
+
console.log(matrixGreen.bold(' --- CODEREVIEWER.AI --- '));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log(chalk.gray('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
40
|
+
console.log(chalk.white(' Advanced AI Analysis ⢠Performance Optimization ⢠Security Audit'));
|
|
41
|
+
console.log(chalk.gray('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Shows a clean list of available commands
|
|
46
|
+
*/
|
|
47
|
+
displayQuickHelp: () => {
|
|
48
|
+
console.log(chalk.bold.white('š GETTING STARTED'));
|
|
49
|
+
console.log(` ${chalk.green('awd init')} ${chalk.gray('ā Setup your API keys and provider')}`);
|
|
50
|
+
console.log(` ${chalk.green('awd review')} ${chalk.gray('ā Review staged changes in Git')}`);
|
|
51
|
+
console.log(` ${chalk.green('awd watch')} ${chalk.gray('ā Enable real-time auto-review mode')}`);
|
|
52
|
+
console.log(` ${chalk.green('awd chat')} ${chalk.gray('ā Discuss results with the AI assistant')}\n`);
|
|
53
|
+
|
|
54
|
+
console.log(chalk.bold.white('āļø SYSTEM'));
|
|
55
|
+
console.log(` ${chalk.green('awd status')} ${chalk.gray('ā Show current configuration')}`);
|
|
56
|
+
console.log(` ${chalk.green('awd history')} ${chalk.gray('ā View previous review scores')}\n`);
|
|
57
|
+
|
|
58
|
+
console.log(chalk.hex('#00FF41')('Ready for input...'));
|
|
59
|
+
}
|
|
60
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"declaration": false
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*"],
|
|
17
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
18
|
+
}
|