UNPKG

scai

Version:

> AI-powered CLI tool for commit messages **and** pull request reviews — using local models.

256 lines (254 loc) • 9.16 kB
#!/usr/bin/env node import { createRequire } from 'module'; const require = createRequire(import.meta.url); const { version } = require('../package.json'); import { Command } from "commander"; import { Config } from './config.js'; import { suggestCommitMessage } from "./commands/CommitSuggesterCmd.js"; import { handleRefactor } from "./commands/RefactorCmd.js"; import { generateTests } from "./commands/TestGenCmd.js"; import { bootstrap } from './modelSetup.js'; import { summarizeFile } from "./commands/SummaryCmd.js"; import { handleStandaloneChangelogUpdate } from './commands/ChangeLogUpdateCmd.js'; import { runModulePipelineFromCLI } from './commands/ModulePipelineCmd.js'; import { runIndexCommand } from './commands/IndexCmd.js'; import { resetDatabase } from './commands/ResetDbCmd.js'; import { runFindCommand } from './commands/FindCmd.js'; import { startDaemon } from './commands/DaemonCmd.js'; import { runStopDaemonCommand } from "./commands/StopDaemonCmd.js"; import { runAskCommand } from './commands/AskCmd.js'; import { runBackupCommand } from './commands/BackupCmd.js'; import { runMigrateCommand } from "./commands/MigrateCmd.js"; import { runInspectCommand } from "./commands/InspectCmd.js"; import { reviewPullRequestCmd } from "./commands/ReviewCmd.js"; import { promptForToken } from "./github/token.js"; import { validateGitHubTokenAgainstRepo } from "./github/githubAuthCheck.js"; import { checkGit } from "./commands/GitCmd.js"; import { runInteractiveSwitch } from "./commands/SwitchCmd.js"; import { execSync } from "child_process"; import { fileURLToPath } from "url"; import { dirname, resolve } from "path"; // šŸŽ›ļø CLI Setup const cmd = new Command('scai') .version(version) .option('--model <model>', 'Set the model to use (e.g., codellama:34b)') .option('--lang <lang>', 'Set the target language (ts, java, rust)'); // šŸ”§ Main command group cmd .command('init') .description('Initialize the model and download required models') .action(async () => { await bootstrap(); console.log('āœ… Model initialization completed!'); }); // šŸ”§ Group: Git-related commands const git = cmd.command('git').description('Git utilities'); git .command('review') .description('Review an open pull request using AI') .option('-a, --all', 'Show all PRs requiring a review (not just for the current user)', false) .action(async (cmd) => { const showAll = cmd.all; await reviewPullRequestCmd('main', showAll); }); git .command('commit') .description('Suggest a commit message from staged changes and optionally commit') .option('-l, --changelog', 'Generate and optionally stage a changelog entry') .action((options) => suggestCommitMessage(options)); git .command('check') .description('Check Git working directory and branch status') .action(() => { checkGit(); }); // Add auth-related commands const auth = cmd.command('auth').description('GitHub authentication commands'); auth .command('check') .description('Check if GitHub authentication is set up and valid') .action(async () => { try { const token = Config.getGitHubToken(); if (!token) { console.log('āŒ GitHub authentication not found. Please set your token.'); return; } const result = await validateGitHubTokenAgainstRepo(); console.log(result); } catch (err) { console.error(typeof err === 'string' ? err : err.message); } }); auth .command('reset') .description('Reset GitHub authentication credentials') .action(() => { Config.setGitHubToken(''); console.log('šŸ”„ GitHub authentication has been reset.'); const token = Config.getGitHubToken(); console.log(token ? 'āŒ Token still exists in the configuration.' : 'āœ… Token successfully removed.'); }); auth .command('set') .description('Set your GitHub Personal Access Token') .action(async () => { const token = await promptForToken(); Config.setGitHubToken(token.trim()); console.log('šŸ”‘ GitHub token set successfully.'); }); // šŸ› ļø Group: `gen` commands for content generation const gen = cmd.command('gen').description('Generate code-related output'); gen .command('comm <file>') .description('Write comments for the given file') .option('-a, --apply', 'Apply the refactored version to the original file') .action((file, options) => handleRefactor(file, options)); gen .command('changelog') .description('Update or create the CHANGELOG.md based on current Git diff') .action(async () => { await handleStandaloneChangelogUpdate(); }); gen .command('summ [file]') .description('Print a summary of the given file to the terminal') .action((file) => summarizeFile(file)); gen .command('tests <file>') .description('Generate a Jest test file for the specified JS/TS module') .action((file) => generateTests(file)); // āš™ļø Group: Configuration settings const config = cmd.command('config').description('Manage SCAI configuration'); config .command('set-model <model>') .description('Set the model to use') .action((model) => { Config.setModel(model); Config.show(); }); config .command('set-lang <lang>') .description('Set the programming language') .action((lang) => { Config.setLanguage(lang); Config.show(); }); config .command('show') .option('--raw', 'Show full raw config') .description('Display current configuration') .action((options) => { if (options.raw) { console.log(JSON.stringify(Config.getRaw(), null, 2)); } else { Config.show(); } }); const index = cmd.command('index').description('index operations'); index .command('start') .description('Index supported files in the configured index directory') .action(runIndexCommand); index .command('set <dir>') .description('Set and activate index directory') .action((dir) => { Config.setIndexDir(dir); Config.show(); }); index .command('list') .description('List all indexed repositories') .action(() => { Config.printAllRepos(); // šŸ‘ˆ simple and clean }); index .command('switch') .description('Switch active repository (by interactive list only)') .action(() => { runInteractiveSwitch(); }); // This will help resolve the current directory in an ES Module cmd .command('check-db') .description('Run the dbcheck script to check the database status') .action(() => { const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Go up two levels from dist/commands → dist → then into dist/scripts/dbcheck.js const scriptPath = resolve(__dirname, '..', 'dist/scripts', 'dbcheck.js'); console.log(`šŸš€ Running database check script: ${scriptPath}`); try { execSync(`node "${scriptPath}"`, { stdio: 'inherit' }); } catch (err) { console.error('āŒ Error running dbcheck script:', err instanceof Error ? err.message : err); } }); cmd .command('backup') .description('Backup the current .scai folder') .action(runBackupCommand); cmd .command('find <query>') .description('Search indexed files by keyword') .action(runFindCommand); cmd .command('ask [question...]') .description('Ask a question based on indexed files') .action((questionParts) => { const fullQuery = questionParts?.join(' '); runAskCommand(fullQuery); }); cmd .command('daemon') .description('Run background summarization of indexed files') .action(async () => { await startDaemon(); }); cmd .command('stop-daemon') .description('Stop the background summarizer daemon') .action(runStopDaemonCommand); cmd .command('migrate') .description('Run DB migration scripts') .action(runMigrateCommand); cmd .command('inspect') .argument('<filepath>', 'Path to the file to inspect') .description('Inspect a specific file and print its indexed summary and functions') .action(async (filepath) => { await runInspectCommand(filepath); }); cmd .command('reset-db') .description('Delete and reset the SQLite database') .action(() => resetDatabase()); cmd .command('pipe') .description('Run a module pipeline on a given file') .argument('<file>', 'Target file') .option('-m, --modules <modules>', 'Comma-separated list of modules to run (e.g., comments,cleanup,summary)') .action((file, options) => { if (!options.modules) { console.error('āŒ You must specify modules with -m or --modules'); process.exit(1); } runModulePipelineFromCLI(file, options); }); cmd.addHelpText('after', ` 🚨 Alpha Features: - The "index", "daemon", "stop-daemon", "reset-db" commands are considered alpha features. - These commands are in active development and may change in the future. šŸ’” Use with caution and expect possible changes or instability. `); cmd.parse(process.argv); const opts = cmd.opts(); if (opts.model) Config.setModel(opts.model); if (opts.lang) Config.setLanguage(opts.lang);