scai
Version:
> **AI-powered CLI for local code analysis, commit message suggestions, and natural-language queries.** 100% local, private, GDPR-friendly, made in Denmark/EU with ā¤ļø.
80 lines (79 loc) ⢠2.77 kB
JavaScript
import fs from 'fs';
import readline from 'readline';
import chalk from 'chalk';
import { searchFiles } from '../db/fileIndex.js';
import { sanitizeQueryForFts } from '../utils/sanitizeQuery.js';
import { NUM_TOPFILES, RELATED_FILES_LIMIT, getIndexDir } from '../constants.js';
import { MainAgent } from '../agents/MainAgent.js';
import { buildLightContext } from '../utils/buildContextualPrompt.js';
export async function runAskCommand(query) {
// STEP 0: Get user query
if (!query)
query = await promptOnce('š¬ Ask your question:\n');
query = query.trim();
if (!query) {
console.error('ā No question provided.\nš Usage: scai ask "your question"');
return;
}
console.log(`š Using index root: ${getIndexDir()}`);
// STEP 1: FTS Search
const safeQuery = sanitizeQueryForFts(query);
const start = Date.now();
const results = await searchFiles(safeQuery, RELATED_FILES_LIMIT);
console.log(`ā±ļø searchFiles took ${Date.now() - start}ms and returned ${results.length} result(s)`);
if (results.length === 0) {
console.log(chalk.redBright('ā No results found.'));
return;
}
// STEP 2: Build topFiles (with code)
const topResults = results.slice(0, NUM_TOPFILES);
const topFiles = topResults.map(r => {
let code = '';
try {
code = fs.readFileSync(r.path, 'utf-8');
}
catch (err) {
console.warn(`ā ļø Failed to read file: ${r.path}`);
}
return {
path: r.path,
summary: r.summary ?? undefined,
code,
};
});
console.log(chalk.greenBright(`šÆ Selected top ${topFiles.length} file(s):`));
topFiles.forEach(f => console.log(` ā ${f.path}`));
// STEP 3: Related files (all results except topFiles)
const relatedFiles = results.slice(NUM_TOPFILES).map(f => ({
id: f.id,
path: f.path,
summary: f.summary ?? undefined,
}));
// STEP 4: Build context prompt
const promptArgs = {
topFiles,
relatedFiles,
query,
};
const context = await buildLightContext(promptArgs);
// STEP 5: Run agent
try {
console.log('\nš¤ Launching autonomous agent...');
const agent = new MainAgent(context);
await agent.run();
}
catch (err) {
console.error('ā Autonomous agent run failed:', err);
}
}
// helper
function promptOnce(promptText) {
return new Promise(resolve => {
console.log(promptText);
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
rl.question('> ', answer => {
rl.close();
resolve(answer.trim());
});
});
}