Update mcp_codebase.py

This commit is contained in:
2025-11-14 00:35:41 +00:00
parent e12d386b8f
commit 269206a7f2
+138 -137
View File
@@ -2096,83 +2096,117 @@ def build_indexes():
block_type = m.get("block_type", "")
component_name = m.get("component_name")
# Skip empty/invalid nodes
if not name or node_type == "unknown":
continue
# Ensure file node exists
file_node_id = f"file::{fpath}"
graph.add_node(file_node_id, type="File", path=fpath, lang=lang)
# Create node ID with language
node_id = f"{lang}::{node_type}::{fpath}::{name}"
# Base attributes for all nodes
base_attrs = {
"name": name,
"file": fpath,
"line": m.get("line"),
"lang": lang # Always include language
}
# Create appropriate node based on type
if node_type in ["function", "method", "constructor"]:
# Function-like entities
if node_type == "method" and "class" in m:
# Method belongs to a class
# Method belongs to a class - use compound ID
node_id = f"{lang}::{node_type}::{fpath}::{m['class']}.{name}"
graph.add_node(node_id, type=node_type, name=name, file=fpath,
class_name=m.get("class"), line=m.get("line"),
return_type=m.get("return_type"), parameters=m.get("parameters", []))
graph.add_node(node_id, **base_attrs, type=node_type,
class_name=m.get("class"),
return_type=m.get("return_type"),
parameters=m.get("parameters", []))
# Connect method to its class
class_node_id = f"{lang}::class::{fpath}::{m['class']}"
graph.add_edge(class_node_id, node_id, "contains")
# Connect return type if available
return_type = m.get("return_type")
if return_type and return_type != "void":
# Try to find return type class/interface
for type_id, type_data in graph.find_nodes(name=return_type):
graph.add_edge(node_id, type_id, "returns")
else:
# Regular function
node_id = f"{lang}::{node_type}::{fpath}::{name}"
graph.add_node(node_id, type=node_type, name=name, file=fpath, line=m.get("line"),
return_type=m.get("return_type"), parameters=m.get("parameters", []))
graph.add_node(node_id, **base_attrs, type=node_type,
return_type=m.get("return_type"),
parameters=m.get("parameters", []))
graph.add_edge(file_node_id, node_id, "contains")
elif node_type in ["class", "struct", "interface", "enum"]:
# Type definitions
node_id = f"{lang}::{node_type}::{fpath}::{name}"
graph.add_node(node_id, type=node_type, name=name, file=fpath, line=m.get("line"),
extends=m.get("extends"), implements=m.get("implements", []))
graph.add_node(node_id, **base_attrs, type=node_type,
extends=m.get("extends"),
implements=m.get("implements", []),
fields=m.get("fields", []), # Store fields as metadata, not separate nodes
variants=m.get("variants", [])) # For enums
graph.add_edge(file_node_id, node_id, "contains")
# Inheritance relationships
extends_class = m.get("extends")
if extends_class:
# Try to find the parent class node
for parent_id, parent_data in graph.find_nodes(type="class", name=extends_class):
for parent_id, parent_data in graph.find_nodes(name=extends_class):
graph.add_edge(node_id, parent_id, "extends")
# Interface implementation
implements_interfaces = m.get("implements", [])
for interface_name in implements_interfaces:
for interface_id, interface_data in graph.find_nodes(type="interface", name=interface_name):
for interface_id, interface_data in graph.find_nodes(name=interface_name):
graph.add_edge(node_id, interface_id, "implements")
elif node_type == "field":
# Class/struct fields
node_id = f"{lang}::field::{fpath}::{name}"
graph.add_node(node_id, type=node_type, name=name, file=fpath, line=m.get("line"),
field_type=m.get("field_type"))
# If we have class context, connect to class
if "class" in m:
class_node_id = f"{lang}::class::{fpath}::{m['class']}"
graph.add_edge(class_node_id, node_id, "contains")
else:
graph.add_edge(file_node_id, node_id, "contains")
# Bevy-specific: Plugin implementation detection
if node_type == "struct" and name.endswith("Plugin"):
graph.add_node(node_id, **base_attrs, type=node_type, is_bevy_plugin=True)
field_type = m.get("field_type")
if field_type and field_type != "unknown":
# Try to find the field type class
for type_id, type_data in graph.find_nodes(name=field_type):
graph.add_edge(node_id, type_id, "type_reference")
elif node_type == "impl":
# Implementation blocks
target = m.get("target", "unknown")
node_id = f"{lang}::{node_type}::{fpath}::{target}"
elif node_type in ["style", "markup", "code_block"]:
# Code blocks and stylistic elements
block_type = m.get("block_type", node_type)
node_id = f"{lang}::{block_type}::{fpath}::{name}"
graph.add_node(node_id, type=node_type, name=name, file=fpath,
line=m.get("line"), block_type=block_type)
graph.add_node(node_id, **base_attrs, type=node_type,
target=target,
traits=m.get("traits", []),
methods=m.get("methods", []))
graph.add_edge(file_node_id, node_id, "contains")
# Connect to target type
for target_id, target_data in graph.find_nodes(name=target):
graph.add_edge(node_id, target_id, "implements_for")
# Connect to implemented traits
for trait_name in m.get("traits", []):
for trait_id, trait_data in graph.find_nodes(name=trait_name):
graph.add_edge(node_id, trait_id, "implements")
# Bevy-specific: Plugin detection
if target.endswith("Plugin"):
graph.add_node(node_id, **base_attrs, type=node_type, is_bevy_plugin_impl=True)
elif node_type == "trait":
# Traits
graph.add_node(node_id, **base_attrs, type=node_type,
methods=m.get("methods", []))
graph.add_edge(file_node_id, node_id, "contains")
elif node_type == "module":
# Modules
graph.add_node(node_id, **base_attrs, type=node_type)
graph.add_edge(file_node_id, node_id, "contains")
else:
# Generic code element fallback
node_id = f"{lang}::{node_type}::{fpath}::{name}"
graph.add_node(node_id, type=node_type, name=name, file=fpath, line=m.get("line"))
graph.add_node(node_id, **base_attrs, type=node_type)
graph.add_edge(file_node_id, node_id, "contains")
# Handle imports if present
@@ -2183,115 +2217,82 @@ def build_indexes():
for call in m.get("calls", []):
graph.add_edge(node_id, call, "calls")
# Go-specific relationships
if lang == "go":
if node_type == "method":
# Connect method to its receiver type
receiver_type = m.get("receiver_base_type")
if receiver_type:
# Try to find the receiver type (struct/interface)
for type_id, type_data in graph.find_nodes(type="struct", name=receiver_type):
graph.add_edge(type_id, node_id, "has_method")
for type_id, type_data in graph.find_nodes(type="interface", name=receiver_type):
graph.add_edge(type_id, node_id, "has_method")
elif node_type == "struct":
# Connect struct to its fields (if we had field type info)
fields = m.get("fields", [])
# Could potentially connect fields to their types if we extract field types
elif node_type == "interface":
# Connect interface to its required methods
interface_methods = m.get("interface_methods", [])
# This helps identify what types implement this interface
elif lang == "svelte" and component_name:
# Create component node if it doesn't exist
component_node_id = f"svelte::component::{fpath}::{component_name}"
if component_node_id not in graph.graph:
graph.add_node(component_node_id, type="component", name=component_name,
file=fpath, language="svelte")
graph.add_edge(file_node_id, component_node_id, "contains")
# Connect different parts to the component
if node_type in ["script", "script_module", "style", "markup"]:
graph.add_edge(component_node_id, node_id, "contains")
# Component props and interface
if node_type == "prop":
graph.add_edge(component_node_id, node_id, "has_prop")
# Component usage relationships
if node_type == "markup":
used_components = m.get("used_components", [])
for used_comp in used_components:
# Try to find the used component in the graph
for comp_id, comp_data in graph.find_nodes(type="component", name=used_comp):
graph.add_edge(component_node_id, comp_id, "uses_component")
# Event handler relationships
event_handlers = m.get("event_handlers", [])
for event in event_handlers:
graph.add_edge(component_node_id, f"event::{event}", "handles_event")
# Svelte script relationships (TypeScript)
elif lang == "typescript" and block_type in ["script", "script_module"]:
# Connect TypeScript declarations to their Svelte component
if component_name:
component_node_id = f"svelte::component::{fpath}::{component_name}"
graph.add_edge(component_node_id, node_id, "contains")
# Import relationships
for imp in m.get("imports", []):
# Try to resolve imports to other components/files
if imp.endswith('.svelte'):
imported_component = Path(imp).stem
if imported_component[0].islower():
imported_component = imported_component[0].upper() + imported_component[1:]
# Look for the imported component
for comp_id, comp_data in graph.find_nodes(type="component", name=imported_component):
graph.add_edge(node_id, comp_id, "imports")
elif lang == "rust":
# Rust-specific relationships
if lang == "rust":
if node_type == "struct":
# Connect struct to its fields
# Connect struct fields as metadata, not separate nodes
fields = m.get("fields", [])
for field in fields:
graph.add_edge(node_id, f"rust::field::{fpath}::{name}.{field}", "has_field")
# Store field info as node attribute instead of creating separate nodes
if "field_types" not in graph.nodes[node_id]:
graph.nodes[node_id]["field_types"] = []
graph.nodes[node_id]["field_types"].append(field)
elif node_type == "enum":
# Connect enum to its variants
# Connect enum variants as metadata
variants = m.get("variants", [])
for variant in variants:
graph.add_edge(node_id, f"rust::variant::{fpath}::{name}::{variant}", "has_variant")
elif node_type == "trait":
# Connect trait to its required methods
methods = m.get("methods", [])
for method in methods:
graph.add_edge(node_id, f"rust::trait_method::{name}::{method}", "requires_method")
elif node_type == "impl":
# Connect impl block to its target type
target = m.get("target")
if target:
# Try to find the target struct/enum
for target_id, target_data in graph.find_nodes(name=target):
graph.add_edge(node_id, target_id, "implements_for")
# Connect impl block to implemented traits
traits = m.get("traits", [])
for trait_name in traits:
for trait_id, trait_data in graph.find_nodes(type="trait", name=trait_name):
graph.add_edge(node_id, trait_id, "implements")
if "variants" not in graph.nodes[node_id]:
graph.nodes[node_id]["variants"] = []
graph.nodes[node_id]["variants"].append(variant)
elif node_type == "function":
# Connect function to its return type
return_type = m.get("return_type")
if return_type:
# Try to find return type in graph
for type_id, type_data in graph.find_nodes(name=return_type):
graph.add_edge(node_id, type_id, "returns")
# Connect function parameters to their types
parameters = m.get("parameters", [])
for param in parameters:
# Extract type from "Type param_name" format
param_parts = param.split()
if len(param_parts) >= 2:
param_type = param_parts[0]
if param_type not in ['self', '&self', '&mut self', 'mut']:
for type_id, type_data in graph.find_nodes(name=param_type):
graph.add_edge(node_id, type_id, "uses_parameter")
# Bevy-specific relationship detection
if lang == "rust" and node_type == "function":
# Detect Bevy system functions
function_name = name.lower()
if any(keyword in function_name for keyword in ['system', 'plugin', 'build', 'update']):
graph.nodes[node_id]["is_bevy_system"] = True
# Detect query parameters for system dependencies
parameters = m.get("parameters", [])
for param in parameters:
if 'Query' in param:
graph.nodes[node_id]["has_bevy_query"] = True
if 'Res<' in param or 'ResMut<' in param:
graph.nodes[node_id]["has_bevy_resource"] = True
if 'Commands' in param:
graph.nodes[node_id]["has_bevy_commands"] = True
# Second pass for Bevy-specific relationships
bevy_connections = 0
for node_id, node_data in graph.graph.nodes(data=True):
if node_data.get('lang') == 'rust':
# Connect Plugin impls to their build functions
if node_data.get('type') == 'impl' and node_data.get('is_bevy_plugin_impl'):
plugin_struct = node_data.get('target')
if plugin_struct:
# Find the build method in this impl
for method_id, method_data in graph.find_nodes(type="method", class_name=plugin_struct):
if method_data.get('name') == 'build':
graph.add_edge(node_id, method_id, "defines_plugin")
bevy_connections += 1
# Connect systems to their plugins
elif node_data.get('is_bevy_system'):
# Try to find which plugin this system belongs to
file_path = node_data.get('file', '')
if file_path:
# Look for plugins in the same file
for plugin_id, plugin_data in graph.find_nodes(type="struct", file=file_path):
if plugin_data.get('name', '').endswith('Plugin'):
graph.add_edge(plugin_id, node_id, "contains_system")
bevy_connections += 1
if bevy_connections > 0:
logger.info(f"Added {bevy_connections} Bevy-specific relationships")
logger.info("Building method parameter type relationships...")
param_connections = 0
for node_id, node_data in graph.graph.nodes(data=True):