PRIX / lib /src /cli.js
yamxxx1's picture
Upload 117 files
a2fe16e verified
Raw
History Blame
8.07 kB
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.main = main;
const options_1 = require("./options");
const prompts_1 = require("./prompts");
const bot_1 = require("./bot");
const local_context_1 = require("./local-context");
const console_reporter_1 = require("./console-reporter");
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const HELP_TEXT = `
PRIX CLI - Local AI PR Reviewer
Usage:
prix-cli [options]
Options:
--staged Review staged files (git diff --cached)
--diff <ref> Review files changed since given git ref
--files <paths> Review specific files (comma-separated)
--model <name> LLM model to use (default: llama-3.1-8b-instant)
--min-confidence <n> Minimum confidence threshold (0-100)
--min-severity <lvl> Minimum severity to report (critical|major|minor|info)
--disable-review Skip code review, only generate summary
--disable-notes Skip release notes generation
--max-files <n> Maximum files to review (0 = unlimited)
--path-filters <p> Path filters (comma-separated, e.g., "src/**,lib/**")
--system-message <m> Additional system message
--language <lang> Output language (default: en-US)
--output <fmt> Output format: console (default) or json
--help, -h Show this help message
Examples:
prix-cli --staged Review staged changes
prix-cli --diff HEAD~1 Review changes since last commit
prix-cli --files src/app.ts,lib/util.ts Review specific files
prix-cli --min-severity major Only show major/critical issues
Pre-commit Hook:
Add to .git/hooks/pre-commit:
npx prix-cli --staged --output console
`;
function parseArgs(argv) {
const args = {};
for (let i = 2; i < argv.length; i++) {
const arg = argv[i];
switch (arg) {
case '--staged':
args.staged = true;
break;
case '--diff':
args.diff = argv[++i];
break;
case '--files':
args.files = argv[++i].split(',');
break;
case '--model':
args.model = argv[++i];
break;
case '--min-confidence':
args.minConfidence = parseInt(argv[++i], 10);
break;
case '--min-severity':
args.minSeverity = argv[++i];
break;
case '--disable-review':
args.disableReview = true;
break;
case '--disable-notes':
args.disableReleaseNotes = true;
break;
case '--max-files':
args.maxFiles = parseInt(argv[++i], 10);
break;
case '--path-filters':
args.pathFilters = argv[++i].split(',');
break;
case '--system-message':
args.systemMessage = argv[++i];
break;
case '--language':
args.language = argv[++i];
break;
case '--output':
args.output = argv[++i];
break;
case '--help':
case '-h':
args.help = true;
break;
}
}
return args;
}
function getStagedFiles() {
try {
const output = (0, child_process_1.execSync)('git diff --cached --name-only', {
encoding: 'utf8',
cwd: process.cwd()
});
return output.split('\n').filter(f => f.trim());
}
catch (e) {
console.error('Failed to get staged files:', e);
return [];
}
}
function getChangedFiles(sinceRef) {
try {
const output = (0, child_process_1.execSync)(`git diff --name-only ${sinceRef}`, {
encoding: 'utf8',
cwd: process.cwd()
});
return output.split('\n').filter(f => f.trim());
}
catch (e) {
console.error(`Failed to get changed files since ${sinceRef}:`, e);
return [];
}
}
async function runLocalReview(args) {
const info = console.log;
const error = console.error;
info('๐Ÿ” PRIX CLI - Starting local code review...\n');
if (!process.env.GROQ_API_KEY && !process.env.AI_API_KEY) {
error('โŒ Error: GROQ_API_KEY or AI_API_KEY environment variable is required');
return 1;
}
let filesToReview = [];
if (args.staged) {
filesToReview = getStagedFiles();
info(`๐Ÿ“‹ Reviewing ${filesToReview.length} staged files\n`);
}
else if (args.diff) {
filesToReview = getChangedFiles(args.diff);
info(`๐Ÿ“‹ Reviewing ${filesToReview.length} files changed since ${args.diff}\n`);
}
else if (args.files) {
filesToReview = args.files.filter(f => (0, fs_1.existsSync)(f));
info(`๐Ÿ“‹ Reviewing ${filesToReview.length} specified files\n`);
}
else {
error('โŒ Error: Must specify --staged, --diff <ref>, or --files <paths>');
return 1;
}
if (filesToReview.length === 0) {
info('โœ… No files to review');
return 0;
}
const options = new options_1.Options(false, args.disableReview || false, args.disableReleaseNotes || false, args.maxFiles?.toString() || '0', false, false, args.pathFilters || null, args.systemMessage || '', args.model || 'llama-3.1-8b-instant', 'llama-3.3-70b-versatile', '0.0', '3', '120000', '6', '6', process.env.API_BASE_URL || 'https://api.groq.com/openai/v1', args.language || 'en-US', false, args.minSeverity || 'minor', args.minConfidence?.toString() || '0', 'false', 'true');
const prompts = new prompts_1.Prompts();
const localContext = new local_context_1.LocalContextEngine(filesToReview);
const reporter = new console_reporter_1.LocalConsoleReporter();
info('๐Ÿค– Initializing AI models...');
let lightBot = null;
let heavyBot = null;
try {
lightBot = new bot_1.Bot(options, new options_1.AIOptions(options.lightModel, options.lightTokenLimits, options.modelTemperature));
}
catch (e) {
error(`โŒ Failed to initialize light model: ${e}`);
return 1;
}
try {
heavyBot = new bot_1.Bot(options, new options_1.AIOptions(options.heavyModel, options.heavyTokenLimits, options.modelTemperature));
}
catch (e) {
error(`โŒ Failed to initialize heavy model: ${e}`);
return 1;
}
info('โœ… AI models initialized\n');
try {
await localContext.initialize();
const findings = await localContext.runReview(lightBot, heavyBot, options, prompts);
reporter.printFindings(findings, {
output: args.output || 'console',
minSeverity: options.minimumSeverity,
minConfidence: options.minConfidence
});
const critical = findings.filter(f => f.severity === 'critical').length;
const major = findings.filter(f => f.severity === 'major').length;
info(`\n๐Ÿ“Š Summary: ${critical} critical, ${major} major, ${findings.length} total findings`);
if (critical > 0) {
info('\nโš ๏ธ Critical issues found! Consider fixing before committing.');
return 1;
}
else if (major > 0) {
info('\nโ„น๏ธ Major issues found. Review recommended before committing.');
return 0;
}
else {
info('\nโœ… No significant issues found.');
return 0;
}
}
catch (e) {
error(`\nโŒ Review failed: ${e}`);
return 1;
}
}
async function main(argv) {
const args = parseArgs(argv);
if (args.help) {
console.log(HELP_TEXT);
return 0;
}
return runLocalReview(args);
}
if (require.main === module) {
main(process.argv)
.then(code => {
process.exit(code);
})
.catch(e => {
console.error('Fatal error:', e);
process.exit(1);
});
}
//# sourceMappingURL=cli.js.map