Skip to content

Commit d930a8c

Browse files
committed
refactor(explorer): integrate modular utils architecture
Wire up all utility modules with barrel exports and update consumers: Architecture changes: - Create utils/index.ts barrel export for clean imports - Update explorer/index.ts to import from modular utils - Maintain backward compatibility via re-exports Integration: - Add CLI support with 'dev explore' command - Implement pattern and similar subcommands - Connect Explorer agent to CLI interface Documentation: - Add comprehensive Explorer README with usage examples - Document all exploration capabilities and CLI usage Testing: - Add 33 integration tests for ExplorerAgent - Total: 99 tests across all utils modules - 100% coverage on utilities, 85.57% on explorer core This completes the modular refactoring, providing: - Clean separation of concerns (metadata → filters/relationships → analysis) - Tree-shakeable exports for optimal bundling - Self-contained modules ready for extraction - Production-ready CLI interface Closes #11
1 parent 1af3d51 commit d930a8c

File tree

7 files changed

+1962
-12
lines changed

7 files changed

+1962
-12
lines changed

packages/cli/src/cli.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import chalk from 'chalk';
44
import { Command } from 'commander';
55
import { cleanCommand } from './commands/clean.js';
6+
import { exploreCommand } from './commands/explore.js';
67
import { indexCommand } from './commands/index.js';
78
import { initCommand } from './commands/init.js';
89
import { searchCommand } from './commands/search.js';
@@ -20,6 +21,7 @@ program
2021
program.addCommand(initCommand);
2122
program.addCommand(indexCommand);
2223
program.addCommand(searchCommand);
24+
program.addCommand(exploreCommand);
2325
program.addCommand(updateCommand);
2426
program.addCommand(statsCommand);
2527
program.addCommand(cleanCommand);
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { RepositoryIndexer } from '@lytics/dev-agent-core';
2+
import chalk from 'chalk';
3+
import { Command } from 'commander';
4+
import ora from 'ora';
5+
import { loadConfig } from '../utils/config.js';
6+
import { logger } from '../utils/logger.js';
7+
8+
const explore = new Command('explore').description('🔍 Explore and analyze code patterns');
9+
10+
// Pattern search subcommand
11+
explore
12+
.command('pattern')
13+
.description('Search for code patterns using semantic search')
14+
.argument('<query>', 'Pattern to search for')
15+
.option('-l, --limit <number>', 'Number of results', '10')
16+
.option('-t, --threshold <number>', 'Similarity threshold (0-1)', '0.7')
17+
.action(async (query: string, options) => {
18+
const spinner = ora('Searching for patterns...').start();
19+
20+
try {
21+
const config = await loadConfig();
22+
if (!config) {
23+
spinner.fail('No config found');
24+
logger.error('Run "dev init" first');
25+
process.exit(1);
26+
return;
27+
}
28+
29+
const indexer = new RepositoryIndexer(config);
30+
await indexer.initialize();
31+
32+
spinner.text = `Searching: "${query}"`;
33+
const results = await indexer.search(query, {
34+
limit: Number.parseInt(options.limit, 10),
35+
scoreThreshold: Number.parseFloat(options.threshold),
36+
});
37+
38+
spinner.succeed(`Found ${results.length} results`);
39+
40+
if (results.length === 0) {
41+
logger.warn('No patterns found');
42+
await indexer.close();
43+
return;
44+
}
45+
46+
console.log(chalk.cyan(`\n📊 Pattern Results for: "${query}"\n`));
47+
48+
for (const [i, result] of results.entries()) {
49+
const meta = result.metadata as {
50+
path: string;
51+
name?: string;
52+
type: string;
53+
startLine?: number;
54+
};
55+
56+
console.log(chalk.white(`${i + 1}. ${meta.name || meta.type}`));
57+
console.log(chalk.gray(` ${meta.path}${meta.startLine ? `:${meta.startLine}` : ''}`));
58+
console.log(chalk.green(` ${(result.score * 100).toFixed(1)}% match\n`));
59+
}
60+
61+
await indexer.close();
62+
} catch (error) {
63+
spinner.fail('Pattern search failed');
64+
logger.error((error as Error).message);
65+
process.exit(1);
66+
}
67+
});
68+
69+
// Similar code subcommand
70+
explore
71+
.command('similar')
72+
.description('Find code similar to a file')
73+
.argument('<file>', 'File path')
74+
.option('-l, --limit <number>', 'Number of results', '5')
75+
.action(async (file: string, options) => {
76+
const spinner = ora('Finding similar code...').start();
77+
78+
try {
79+
const config = await loadConfig();
80+
if (!config) {
81+
spinner.fail('No config found');
82+
logger.error('Run "dev init" first');
83+
process.exit(1);
84+
return;
85+
}
86+
87+
const indexer = new RepositoryIndexer(config);
88+
await indexer.initialize();
89+
90+
const results = await indexer.search(file, {
91+
limit: Number.parseInt(options.limit, 10) + 1,
92+
scoreThreshold: 0.7,
93+
});
94+
95+
// Filter out the file itself
96+
const similar = results
97+
.filter((r) => {
98+
const meta = r.metadata as { path: string };
99+
return !meta.path.includes(file);
100+
})
101+
.slice(0, Number.parseInt(options.limit, 10));
102+
103+
spinner.succeed(`Found ${similar.length} similar files`);
104+
105+
if (similar.length === 0) {
106+
logger.warn('No similar code found');
107+
await indexer.close();
108+
return;
109+
}
110+
111+
console.log(chalk.cyan(`\n🔗 Similar to: ${file}\n`));
112+
113+
for (const [i, result] of similar.entries()) {
114+
const meta = result.metadata as {
115+
path: string;
116+
type: string;
117+
};
118+
119+
console.log(chalk.white(`${i + 1}. ${meta.path}`));
120+
console.log(chalk.green(` ${(result.score * 100).toFixed(1)}% similar\n`));
121+
}
122+
123+
await indexer.close();
124+
} catch (error) {
125+
spinner.fail('Similar code search failed');
126+
logger.error((error as Error).message);
127+
process.exit(1);
128+
}
129+
});
130+
131+
export { explore as exploreCommand };

0 commit comments

Comments
 (0)