Add codebase indexing system (Milestone 4)

- Add project type detection (Node.js, Python, Rust, Go, generic)
- Add file scanner with ignore patterns and hash tracking
- Add TypeScript/JavaScript parser (exports, imports, classes, functions)
- Add Python parser (imports, classes, functions, __all__)
- Add relationship mapper for import dependencies
- Add architecture summary generation with tech stack detection
- Add incremental update support via file hash comparison
- Add CLI command: cortex index [path] [--update] [--dry-run]
- Add MCP tools: memory_index, memory_components
This commit is contained in:
2026-02-03 10:53:26 +01:00
parent 9490cd1db4
commit 056a02d936
12 changed files with 1061 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
import { Command } from 'commander';
import chalk from 'chalk';
import { indexProject } from '../../core/indexer';
export const indexCommand = new Command('index')
.description('Index a codebase to create component nodes')
.argument('[path]', 'Path to index', '.')
.option('--update', 'Only update changed files (incremental)')
.option('--dry-run', 'Preview what would be indexed without making changes')
.option('--depth <n>', 'Maximum directory depth', '10')
.option('--lang <language>', 'Only index specific language (ts, js, py)')
.option('--ignore <patterns>', 'Additional ignore patterns (comma-separated)')
.action(async (inputPath: string, opts) => {
const startTime = Date.now();
if (opts.dryRun) {
console.log(chalk.yellow('Dry run mode - no changes will be made\n'));
}
console.log(chalk.cyan(`Indexing ${inputPath}...`));
try {
const result = await indexProject(inputPath, {
update: opts.update,
dryRun: opts.dryRun,
maxDepth: parseInt(opts.depth),
language: opts.lang,
ignore: opts.ignore?.split(',').map((s: string) => s.trim()),
});
const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
console.log();
console.log(chalk.green(`✓ Indexed ${result.projectName} (${result.projectType})`));
console.log();
console.log(` Files scanned: ${result.files.length}`);
console.log(` Components created: ${result.componentsCreated}`);
console.log(` Components updated: ${result.componentsUpdated}`);
console.log(` Components removed: ${result.componentsRemoved}`);
console.log(` Relationships: ${result.relationshipsCreated}`);
if (result.architectureNodeId) {
console.log(` Architecture node: ${result.architectureNodeId.slice(0, 8)}`);
}
console.log();
console.log(chalk.dim(`Completed in ${elapsed}s`));
if (opts.dryRun && result.files.length > 0) {
console.log();
console.log(chalk.yellow('Files that would be indexed:'));
for (const file of result.files.slice(0, 20)) {
console.log(` ${file}`);
}
if (result.files.length > 20) {
console.log(chalk.dim(` ... and ${result.files.length - 20} more`));
}
}
} catch (err: any) {
console.error(chalk.red(`Error: ${err.message}`));
process.exit(1);
}
});

View File

@@ -16,6 +16,7 @@ import { diffCommand } from './commands/diff';
import { restoreCommand } from './commands/restore';
import { captureCommand, captureHookCommand, configCommand } from './commands/capture';
import { contextCommand, contextHookCommand } from './commands/context';
import { indexCommand } from './commands/index-cmd';
import { closeDb } from '../core/db';
const program = new Command();
@@ -44,6 +45,7 @@ program.addCommand(captureHookCommand);
program.addCommand(contextCommand);
program.addCommand(contextHookCommand);
program.addCommand(configCommand);
program.addCommand(indexCommand);
program.hook('postAction', () => {
closeDb();