@opichi/smartcode
Version:
Universal code intelligence MCP server - analyze any codebase with TypeScript excellence and multi-language support
309 lines (298 loc) • 13.9 kB
JavaScript
import { z } from "zod";
import { CodebaseIndexer } from '../indexer/index.js';
import { CodeKnowledgeGraph } from '../knowledge/graph.js';
import { CodeAnalyzer } from '../knowledge/analyzer.js';
import { CodeVectorStore } from '../indexer/qdrant.js';
import { CodeEmbedder } from '../indexer/embedder.js';
export class SemanticTools {
indexer;
graph;
analyzer;
vectorStore;
embedder;
isInitialized = false;
constructor() {
this.indexer = new CodebaseIndexer();
this.graph = new CodeKnowledgeGraph();
this.analyzer = new CodeAnalyzer(this.graph);
this.vectorStore = new CodeVectorStore();
this.embedder = new CodeEmbedder();
}
async initialize() {
if (this.isInitialized)
return;
console.log('Initializing semantic tools...');
await Promise.all([
this.indexer.initialize(),
this.embedder.initialize()
]);
this.isInitialized = true;
console.log('Semantic tools initialized');
}
registerTools(server) {
// Semantic search tool
server.tool("find_similar_code", "Find code similar to a description using semantic search", {
description: z.string().describe("Description of the code you're looking for"),
limit: z.number().optional().default(10).describe("Maximum number of results"),
node_type: z.enum(['function', 'class', 'variable', 'any']).optional().default('any').describe("Type of code nodes to search")
}, async ({ description, limit, node_type }) => {
try {
await this.ensureIndexed();
// Generate embedding for the query
const queryEmbedding = await this.embedder.embedQuery(description);
// Search in vector store
const filter = node_type !== 'any' ? { must: [{ key: 'type', match: { value: node_type } }] } : undefined;
const results = await this.vectorStore.searchSimilar(queryEmbedding, limit, filter);
if (results.length === 0) {
return {
content: [{
type: "text",
text: `No similar code found for: "${description}"`
}]
};
}
const output = results.map(result => `**${result.node.name}** (${result.node.type}) - Score: ${result.score.toFixed(3)}
File: ${result.node.filePath}:${result.node.startLine}
Context: ${result.context}
\`\`\`
${result.node.content.split('\n').slice(0, 5).join('\n')}${result.node.content.split('\n').length > 5 ? '\n...' : ''}
\`\`\``).join('\n\n---\n\n');
return {
content: [{
type: "text",
text: `Found ${results.length} similar code snippets for "${description}":\n\n${output}`
}]
};
}
catch (error) {
return {
content: [{
type: "text",
text: `Error searching for similar code: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
});
// Impact analysis tool
server.tool("analyze_impact", "Analyze the impact of changing a specific code component", {
file_path: z.string().describe("Path to the file containing the code"),
node_name: z.string().describe("Name of the function, class, or variable to analyze"),
change_description: z.string().optional().describe("Description of the planned change")
}, async ({ file_path, node_name, change_description }) => {
try {
await this.ensureIndexed();
// Find the node
const nodes = await this.vectorStore.searchByFile(file_path);
const targetNode = nodes.find(n => n.name === node_name);
if (!targetNode) {
return {
content: [{
type: "text",
text: `Node "${node_name}" not found in ${file_path}`
}]
};
}
// Perform impact analysis
const impact = this.analyzer.analyzeImpact(targetNode.id);
const output = `# Impact Analysis for ${node_name}
**Risk Level:** ${impact.riskLevel.toUpperCase()}
## Directly Affected (${impact.directlyAffected.length} components):
${impact.directlyAffected.map(node => `- ${node.name} (${node.type}) in ${node.filePath}:${node.startLine}`).join('\n')}
## Indirectly Affected (${impact.indirectlyAffected.length} components):
${impact.indirectlyAffected.slice(0, 10).map(node => `- ${node.name} (${node.type}) in ${node.filePath}:${node.startLine}`).join('\n')}${impact.indirectlyAffected.length > 10 ? `\n... and ${impact.indirectlyAffected.length - 10} more` : ''}
## Recommendations:
${impact.suggestions.map(suggestion => `- ${suggestion}`).join('\n')}
${change_description ? `\n## Planned Change:
${change_description}` : ''}`;
return {
content: [{
type: "text",
text: output
}]
};
}
catch (error) {
return {
content: [{
type: "text",
text: `Error analyzing impact: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
});
// Implementation suggestion tool
server.tool("suggest_implementation", "Get implementation suggestions based on existing code patterns", {
feature_description: z.string().describe("Description of the feature to implement"),
context_files: z.array(z.string()).optional().describe("Related files for context")
}, async ({ feature_description, context_files }) => {
try {
await this.ensureIndexed();
// Get context nodes if files provided
let contextNodes = [];
if (context_files) {
for (const filePath of context_files) {
const fileNodes = await this.vectorStore.searchByFile(filePath);
contextNodes.push(...fileNodes);
}
}
// Get implementation suggestions
const suggestions = this.analyzer.suggestImplementation(feature_description, contextNodes);
if (suggestions.length === 0) {
return {
content: [{
type: "text",
text: `No implementation suggestions found for: "${feature_description}"`
}]
};
}
const output = `# Implementation Suggestions for "${feature_description}"
${suggestions.map((suggestion, index) => `
## ${index + 1}. ${suggestion.description}
**Type:** ${suggestion.type}
**Confidence:** ${(suggestion.confidence * 100).toFixed(1)}%
**Reasoning:** ${suggestion.reasoning}
${suggestion.code ? `\`\`\`
${suggestion.code}
\`\`\`` : ''}
${suggestion.filePath ? `**Reference:** ${suggestion.filePath}` : ''}
`).join('\n---\n')}`;
return {
content: [{
type: "text",
text: output
}]
};
}
catch (error) {
return {
content: [{
type: "text",
text: `Error generating suggestions: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
});
// Architecture overview tool
server.tool("get_component_architecture", "Get a comprehensive overview of the codebase architecture and patterns", {
focus: z.enum(['overview', 'patterns', 'components', 'statistics']).optional().default('overview').describe("What aspect to focus on")
}, async ({ focus }) => {
try {
await this.ensureIndexed();
const overview = this.analyzer.getArchitecturalOverview();
let output = '';
if (focus === 'overview' || focus === 'components') {
output += '# Architectural Components\n\n';
for (const [componentType, nodes] of overview.components.entries()) {
if (nodes.length > 0) {
output += `## ${componentType.charAt(0).toUpperCase() + componentType.slice(1)} (${nodes.length})\n`;
nodes.slice(0, 10).forEach(node => {
output += `- ${node.name} in ${node.filePath}:${node.startLine}\n`;
});
if (nodes.length > 10) {
output += `... and ${nodes.length - 10} more\n`;
}
output += '\n';
}
}
}
if (focus === 'overview' || focus === 'patterns') {
output += '# Detected Patterns\n\n';
if (overview.patterns.length === 0) {
output += 'No architectural patterns detected.\n\n';
}
else {
overview.patterns.forEach(pattern => {
output += `## ${pattern.name}
**Type:** ${pattern.type}
**Confidence:** ${(pattern.confidence * 100).toFixed(1)}%
**Description:** ${pattern.description}
**Components:** ${pattern.components.length}
`;
});
}
}
if (focus === 'overview' || focus === 'statistics') {
output += '# Statistics\n\n';
const stats = overview.statistics;
output += `- **Total Nodes:** ${stats.totalNodes}
- **Functions:** ${stats.nodesByType.functions}
- **Classes:** ${stats.nodesByType.classes}
- **Variables:** ${stats.nodesByType.variables}
- **Patterns Detected:** ${stats.patternsDetected}
- **Average Complexity:** ${stats.averageComplexity.toFixed(1)}
`;
}
return {
content: [{
type: "text",
text: output
}]
};
}
catch (error) {
return {
content: [{
type: "text",
text: `Error getting architecture overview: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
});
// Index project tool
server.tool("index_project", "Index the current project for semantic analysis (run this first)", {
project_path: z.string().optional().default('.').describe("Path to the project to index"),
watch: z.boolean().optional().default(false).describe("Start watching for file changes")
}, async ({ project_path, watch }) => {
try {
await this.initialize();
console.log(`Starting to index project: ${project_path}`);
await this.indexer.indexProject(project_path);
// Build knowledge graph
const nodes = await this.vectorStore.searchByType('function');
const classes = await this.vectorStore.searchByType('class');
const variables = await this.vectorStore.searchByType('variable');
this.graph.addNodes([...nodes, ...classes, ...variables]);
this.graph.buildRelationships();
// Analyze patterns
await this.analyzer.analyzeCodebase();
if (watch) {
await this.indexer.startWatching(project_path);
}
return {
content: [{
type: "text",
text: `✅ Successfully indexed project at ${project_path}
- Parsed ${nodes.length + classes.length + variables.length} code nodes
- Built knowledge graph with relationships
- Detected architectural patterns
${watch ? '- Started file watching for real-time updates' : ''}
The semantic brain is now ready! Try:
- find_similar_code: Search for code by description
- analyze_impact: See what breaks when you change something
- suggest_implementation: Get implementation ideas
- get_component_architecture: Understand your system`
}]
};
}
catch (error) {
return {
content: [{
type: "text",
text: `Error indexing project: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
});
}
async ensureIndexed() {
if (!this.isInitialized) {
throw new Error('Semantic tools not initialized. Run index_project first.');
}
// Check if we have any data
const testNodes = await this.vectorStore.searchByType('function');
if (testNodes.length === 0) {
throw new Error('No indexed data found. Run index_project first.');
}
}
}
//# sourceMappingURL=semantic.js.map