claude-mpm 4.15.6__py3-none-any.whl → 4.21.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +272 -23
- claude_mpm/agents/PM_INSTRUCTIONS.md +49 -0
- claude_mpm/agents/agent_loader.py +4 -4
- claude_mpm/agents/templates/engineer.json +5 -1
- claude_mpm/agents/templates/php-engineer.json +10 -4
- claude_mpm/agents/templates/python_engineer.json +8 -3
- claude_mpm/agents/templates/rust_engineer.json +12 -7
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/cli/commands/__init__.py +2 -0
- claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
- claude_mpm/cli/commands/mpm_init/core.py +525 -0
- claude_mpm/cli/commands/mpm_init/display.py +341 -0
- claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
- claude_mpm/cli/commands/mpm_init/modes.py +397 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
- claude_mpm/cli/commands/mpm_init_cli.py +396 -0
- claude_mpm/cli/commands/mpm_init_handler.py +67 -1
- claude_mpm/cli/commands/skills.py +488 -0
- claude_mpm/cli/executor.py +2 -0
- claude_mpm/cli/parsers/base_parser.py +7 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +42 -0
- claude_mpm/cli/parsers/skills_parser.py +137 -0
- claude_mpm/cli/startup.py +57 -0
- claude_mpm/commands/mpm-auto-configure.md +52 -0
- claude_mpm/commands/mpm-help.md +6 -0
- claude_mpm/commands/mpm-init.md +112 -6
- claude_mpm/commands/mpm-resume.md +372 -0
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +2 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/constants.py +12 -0
- claude_mpm/core/config.py +42 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/interfaces.py +56 -1
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/hooks/__init__.py +8 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/session_resume_hook.py +121 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/auto_config_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/recommender.py +47 -0
- claude_mpm/services/cli/resume_service.py +617 -0
- claude_mpm/services/cli/session_manager.py +87 -0
- claude_mpm/services/cli/session_pause_manager.py +504 -0
- claude_mpm/services/cli/session_resume_helper.py +372 -0
- claude_mpm/services/core/base.py +26 -11
- claude_mpm/services/core/interfaces.py +56 -1
- claude_mpm/services/core/models/agent_config.py +3 -0
- claude_mpm/services/core/models/process.py +4 -0
- claude_mpm/services/core/path_resolver.py +1 -1
- claude_mpm/services/diagnostics/models.py +21 -0
- claude_mpm/services/event_bus/relay.py +23 -7
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +2 -0
- claude_mpm/services/mcp_config_manager.py +7 -131
- claude_mpm/services/mcp_gateway/auto_configure.py +31 -25
- claude_mpm/services/mcp_gateway/core/process_pool.py +19 -10
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +26 -21
- claude_mpm/services/memory/failure_tracker.py +19 -4
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/unified/deployment_strategies/local.py +1 -1
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/agent_skills_injector.py +324 -0
- claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +97 -9
- claude_mpm/skills/skills_registry.py +348 -0
- claude_mpm/skills/skills_service.py +739 -0
- claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
- claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
- claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
- claude_mpm/tools/code_tree_analyzer/core.py +380 -0
- claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
- claude_mpm/tools/code_tree_analyzer/events.py +168 -0
- claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
- claude_mpm/tools/code_tree_analyzer/models.py +39 -0
- claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
- claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
- claude_mpm/utils/agent_dependency_loader.py +2 -2
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/METADATA +211 -33
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/RECORD +206 -64
- claude_mpm/agents/INSTRUCTIONS_OLD_DEPRECATED.md +0 -602
- claude_mpm/cli/commands/mpm_init.py +0 -2008
- claude_mpm/tools/code_tree_analyzer.py +0 -1825
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.15.6.dist-info → claude_mpm-4.21.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Code Tree Analyzer Core
|
|
4
|
+
=======================
|
|
5
|
+
|
|
6
|
+
Main orchestrator that coordinates all code tree analysis operations.
|
|
7
|
+
|
|
8
|
+
WHY: Provides a unified interface for analyzing codebases with multiple
|
|
9
|
+
languages, handling caching and incremental processing.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import time
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
from ...core.logging_config import get_logger
|
|
17
|
+
from ..code_tree_events import CodeTreeEventEmitter
|
|
18
|
+
from .analysis import FileAnalyzer
|
|
19
|
+
from .cache import CacheManager
|
|
20
|
+
from .discovery import DiscoveryManager
|
|
21
|
+
from .events import EventManager
|
|
22
|
+
from .gitignore import GitignoreManager
|
|
23
|
+
from .models import CodeNode
|
|
24
|
+
from .multilang_analyzer import MultiLanguageAnalyzer
|
|
25
|
+
from .python_analyzer import PythonAnalyzer
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class CodeTreeAnalyzer:
|
|
29
|
+
"""Main analyzer that coordinates language-specific analyzers."""
|
|
30
|
+
|
|
31
|
+
# Define code file extensions at class level for directory filtering
|
|
32
|
+
CODE_EXTENSIONS: ClassVar[set] = {
|
|
33
|
+
".py",
|
|
34
|
+
".js",
|
|
35
|
+
".jsx",
|
|
36
|
+
".ts",
|
|
37
|
+
".tsx",
|
|
38
|
+
".mjs",
|
|
39
|
+
".cjs",
|
|
40
|
+
".java",
|
|
41
|
+
".cpp",
|
|
42
|
+
".c",
|
|
43
|
+
".h",
|
|
44
|
+
".hpp",
|
|
45
|
+
".cs",
|
|
46
|
+
".go",
|
|
47
|
+
".rs",
|
|
48
|
+
".rb",
|
|
49
|
+
".php",
|
|
50
|
+
".swift",
|
|
51
|
+
".kt",
|
|
52
|
+
".scala",
|
|
53
|
+
".r",
|
|
54
|
+
".m",
|
|
55
|
+
".mm",
|
|
56
|
+
".sh",
|
|
57
|
+
".bash",
|
|
58
|
+
".zsh",
|
|
59
|
+
".fish",
|
|
60
|
+
".ps1",
|
|
61
|
+
".bat",
|
|
62
|
+
".cmd",
|
|
63
|
+
".sql",
|
|
64
|
+
".html",
|
|
65
|
+
".css",
|
|
66
|
+
".scss",
|
|
67
|
+
".sass",
|
|
68
|
+
".less",
|
|
69
|
+
".xml",
|
|
70
|
+
".json",
|
|
71
|
+
".yaml",
|
|
72
|
+
".yml",
|
|
73
|
+
".toml",
|
|
74
|
+
".ini",
|
|
75
|
+
".cfg",
|
|
76
|
+
".conf",
|
|
77
|
+
".md",
|
|
78
|
+
".rst",
|
|
79
|
+
".txt",
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# File extensions to language mapping
|
|
83
|
+
LANGUAGE_MAP: ClassVar[dict] = {
|
|
84
|
+
".py": "python",
|
|
85
|
+
".js": "javascript",
|
|
86
|
+
".jsx": "javascript",
|
|
87
|
+
".ts": "typescript",
|
|
88
|
+
".tsx": "typescript",
|
|
89
|
+
".mjs": "javascript",
|
|
90
|
+
".cjs": "javascript",
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
def __init__(
|
|
94
|
+
self,
|
|
95
|
+
emit_events: bool = True,
|
|
96
|
+
cache_dir: Optional[Path] = None,
|
|
97
|
+
emitter: Optional[CodeTreeEventEmitter] = None,
|
|
98
|
+
):
|
|
99
|
+
"""Initialize the code tree analyzer.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
emit_events: Whether to emit Socket.IO events
|
|
103
|
+
cache_dir: Directory for caching analysis results
|
|
104
|
+
emitter: Optional event emitter to use (creates one if not provided)
|
|
105
|
+
"""
|
|
106
|
+
self.logger = get_logger(__name__)
|
|
107
|
+
self.emit_events = emit_events
|
|
108
|
+
self.cache_dir = cache_dir or Path.home() / ".claude-mpm" / "code-cache"
|
|
109
|
+
|
|
110
|
+
# Use provided emitter or create one
|
|
111
|
+
if emitter:
|
|
112
|
+
self.emitter = emitter
|
|
113
|
+
elif emit_events:
|
|
114
|
+
self.emitter = CodeTreeEventEmitter(use_stdout=True)
|
|
115
|
+
else:
|
|
116
|
+
self.emitter = None
|
|
117
|
+
|
|
118
|
+
# Initialize managers
|
|
119
|
+
self.gitignore_manager = GitignoreManager()
|
|
120
|
+
self.cache_manager = CacheManager(self.cache_dir)
|
|
121
|
+
self.event_manager = EventManager(self.emitter)
|
|
122
|
+
|
|
123
|
+
# Initialize language analyzers
|
|
124
|
+
self.python_analyzer = PythonAnalyzer(self.emitter)
|
|
125
|
+
self.multi_lang_analyzer = MultiLanguageAnalyzer(self.emitter)
|
|
126
|
+
|
|
127
|
+
# For JavaScript/TypeScript
|
|
128
|
+
self.javascript_analyzer = self.multi_lang_analyzer
|
|
129
|
+
self.generic_analyzer = self.multi_lang_analyzer
|
|
130
|
+
|
|
131
|
+
# Initialize discovery and file analysis managers
|
|
132
|
+
self.discovery_manager = DiscoveryManager(self.gitignore_manager, self.emitter)
|
|
133
|
+
self.file_analyzer = FileAnalyzer(
|
|
134
|
+
self.python_analyzer,
|
|
135
|
+
self.multi_lang_analyzer,
|
|
136
|
+
self.cache_manager,
|
|
137
|
+
self.event_manager,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Load cache
|
|
141
|
+
self.cache_manager.load()
|
|
142
|
+
|
|
143
|
+
def analyze_directory(
|
|
144
|
+
self,
|
|
145
|
+
directory: Path,
|
|
146
|
+
languages: Optional[List[str]] = None,
|
|
147
|
+
ignore_patterns: Optional[List[str]] = None,
|
|
148
|
+
max_depth: Optional[int] = None,
|
|
149
|
+
) -> Dict[str, Any]:
|
|
150
|
+
"""Analyze a directory and build code tree.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
directory: Directory to analyze
|
|
154
|
+
languages: Languages to include (None for all)
|
|
155
|
+
ignore_patterns: Patterns to ignore
|
|
156
|
+
max_depth: Maximum directory depth
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Dictionary containing the code tree and statistics
|
|
160
|
+
"""
|
|
161
|
+
if self.emitter:
|
|
162
|
+
self.emitter.start()
|
|
163
|
+
|
|
164
|
+
start_time = time.time()
|
|
165
|
+
all_nodes = []
|
|
166
|
+
files_processed = 0
|
|
167
|
+
total_files = 0
|
|
168
|
+
|
|
169
|
+
# Collect files to process
|
|
170
|
+
files_to_process = []
|
|
171
|
+
for ext, lang in self.LANGUAGE_MAP.items():
|
|
172
|
+
if languages and lang not in languages:
|
|
173
|
+
continue
|
|
174
|
+
|
|
175
|
+
for file_path in directory.rglob(f"*{ext}"):
|
|
176
|
+
# Use gitignore manager for filtering with directory as working dir
|
|
177
|
+
if self.gitignore_manager.should_ignore(file_path, directory):
|
|
178
|
+
continue
|
|
179
|
+
|
|
180
|
+
# Also check additional patterns
|
|
181
|
+
if ignore_patterns and any(
|
|
182
|
+
p in str(file_path) for p in ignore_patterns
|
|
183
|
+
):
|
|
184
|
+
continue
|
|
185
|
+
|
|
186
|
+
# Check max depth
|
|
187
|
+
if max_depth:
|
|
188
|
+
depth = len(file_path.relative_to(directory).parts) - 1
|
|
189
|
+
if depth > max_depth:
|
|
190
|
+
continue
|
|
191
|
+
|
|
192
|
+
files_to_process.append((file_path, lang))
|
|
193
|
+
|
|
194
|
+
total_files = len(files_to_process)
|
|
195
|
+
|
|
196
|
+
# Process files
|
|
197
|
+
for file_path, language in files_to_process:
|
|
198
|
+
# Check cache
|
|
199
|
+
cache_key = self.cache_manager.get_cache_key(file_path)
|
|
200
|
+
|
|
201
|
+
if cached_nodes := self.cache_manager.get(cache_key):
|
|
202
|
+
nodes = cached_nodes
|
|
203
|
+
self.logger.debug(f"Using cached results for {file_path}")
|
|
204
|
+
else:
|
|
205
|
+
# Emit file start event
|
|
206
|
+
if self.emitter:
|
|
207
|
+
self.emitter.emit_file_start(str(file_path), language)
|
|
208
|
+
|
|
209
|
+
file_start = time.time()
|
|
210
|
+
|
|
211
|
+
# Analyze based on language
|
|
212
|
+
if language == "python":
|
|
213
|
+
nodes = self.python_analyzer.analyze_file(file_path)
|
|
214
|
+
else:
|
|
215
|
+
nodes = self.multi_lang_analyzer.analyze_file(file_path, language)
|
|
216
|
+
|
|
217
|
+
# If no nodes found and we have a valid language, emit basic file info
|
|
218
|
+
if not nodes and language != "unknown":
|
|
219
|
+
self.logger.debug(
|
|
220
|
+
f"No AST nodes found for {file_path}, using basic discovery"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
# Cache results
|
|
224
|
+
self.cache_manager.set(cache_key, nodes)
|
|
225
|
+
|
|
226
|
+
# Emit file complete event
|
|
227
|
+
if self.emitter:
|
|
228
|
+
self.emitter.emit_file_complete(
|
|
229
|
+
str(file_path), len(nodes), time.time() - file_start
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
all_nodes.extend(nodes)
|
|
233
|
+
files_processed += 1
|
|
234
|
+
|
|
235
|
+
# Emit progress
|
|
236
|
+
if self.emitter and files_processed % 10 == 0:
|
|
237
|
+
self.emitter.emit_progress(
|
|
238
|
+
files_processed, total_files, f"Processing {file_path.name}"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# Build tree structure
|
|
242
|
+
tree = self._build_tree(all_nodes, directory)
|
|
243
|
+
|
|
244
|
+
# Calculate statistics
|
|
245
|
+
duration = time.time() - start_time
|
|
246
|
+
stats = {
|
|
247
|
+
"files_processed": files_processed,
|
|
248
|
+
"total_nodes": len(all_nodes),
|
|
249
|
+
"duration": duration,
|
|
250
|
+
"classes": sum(1 for n in all_nodes if n.node_type == "class"),
|
|
251
|
+
"functions": sum(
|
|
252
|
+
1 for n in all_nodes if n.node_type in ("function", "method")
|
|
253
|
+
),
|
|
254
|
+
"imports": sum(1 for n in all_nodes if n.node_type == "import"),
|
|
255
|
+
"languages": list(
|
|
256
|
+
{n.language for n in all_nodes if hasattr(n, "language")}
|
|
257
|
+
),
|
|
258
|
+
"avg_complexity": (
|
|
259
|
+
sum(n.complexity for n in all_nodes) / len(all_nodes)
|
|
260
|
+
if all_nodes
|
|
261
|
+
else 0
|
|
262
|
+
),
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
# Save cache
|
|
266
|
+
self.cache_manager.save()
|
|
267
|
+
|
|
268
|
+
# Stop emitter
|
|
269
|
+
if self.emitter:
|
|
270
|
+
self.emitter.stop()
|
|
271
|
+
|
|
272
|
+
return {"tree": tree, "nodes": all_nodes, "stats": stats}
|
|
273
|
+
|
|
274
|
+
def _build_tree(self, nodes: List[CodeNode], root_dir: Path) -> Dict[str, Any]:
|
|
275
|
+
"""Build hierarchical tree structure from flat nodes list."""
|
|
276
|
+
tree = {
|
|
277
|
+
"name": root_dir.name,
|
|
278
|
+
"type": "directory",
|
|
279
|
+
"path": str(root_dir),
|
|
280
|
+
"children": [],
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
# Group nodes by file
|
|
284
|
+
files_map = {}
|
|
285
|
+
for node in nodes:
|
|
286
|
+
if node.file_path not in files_map:
|
|
287
|
+
files_map[node.file_path] = {
|
|
288
|
+
"name": Path(node.file_path).name,
|
|
289
|
+
"type": "file",
|
|
290
|
+
"path": node.file_path,
|
|
291
|
+
"children": [],
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
# Add node to file
|
|
295
|
+
node_dict = {
|
|
296
|
+
"name": node.name,
|
|
297
|
+
"type": node.node_type,
|
|
298
|
+
"line_start": node.line_start,
|
|
299
|
+
"line_end": node.line_end,
|
|
300
|
+
"complexity": node.complexity,
|
|
301
|
+
"has_docstring": node.has_docstring,
|
|
302
|
+
"decorators": node.decorators,
|
|
303
|
+
"signature": node.signature,
|
|
304
|
+
}
|
|
305
|
+
files_map[node.file_path]["children"].append(node_dict)
|
|
306
|
+
|
|
307
|
+
# Build directory structure
|
|
308
|
+
for file_path, file_node in files_map.items():
|
|
309
|
+
rel_path = Path(file_path).relative_to(root_dir)
|
|
310
|
+
parts = rel_path.parts
|
|
311
|
+
|
|
312
|
+
current = tree
|
|
313
|
+
for part in parts[:-1]:
|
|
314
|
+
# Find or create directory
|
|
315
|
+
dir_node = None
|
|
316
|
+
for child in current["children"]:
|
|
317
|
+
if child["type"] == "directory" and child["name"] == part:
|
|
318
|
+
dir_node = child
|
|
319
|
+
break
|
|
320
|
+
|
|
321
|
+
if not dir_node:
|
|
322
|
+
dir_node = {"name": part, "type": "directory", "children": []}
|
|
323
|
+
current["children"].append(dir_node)
|
|
324
|
+
|
|
325
|
+
current = dir_node
|
|
326
|
+
|
|
327
|
+
# Add file to current directory
|
|
328
|
+
current["children"].append(file_node)
|
|
329
|
+
|
|
330
|
+
return tree
|
|
331
|
+
|
|
332
|
+
def discover_top_level(
|
|
333
|
+
self, directory: Path, ignore_patterns: Optional[List[str]] = None
|
|
334
|
+
) -> Dict[str, Any]:
|
|
335
|
+
"""Discover only top-level directories and files for lazy loading.
|
|
336
|
+
|
|
337
|
+
Args:
|
|
338
|
+
directory: Root directory to discover
|
|
339
|
+
ignore_patterns: Patterns to ignore
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
Dictionary with top-level structure
|
|
343
|
+
"""
|
|
344
|
+
return self.discovery_manager.discover_top_level(directory, ignore_patterns)
|
|
345
|
+
|
|
346
|
+
def discover_directory(
|
|
347
|
+
self, dir_path: str, ignore_patterns: Optional[List[str]] = None
|
|
348
|
+
) -> Dict[str, Any]:
|
|
349
|
+
"""Discover contents of a specific directory for lazy loading.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
dir_path: Directory path to discover
|
|
353
|
+
ignore_patterns: Patterns to ignore
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
Dictionary with directory contents
|
|
357
|
+
"""
|
|
358
|
+
return self.discovery_manager.discover_directory(dir_path, ignore_patterns)
|
|
359
|
+
|
|
360
|
+
def analyze_file(self, file_path: str) -> Dict[str, Any]:
|
|
361
|
+
"""Analyze a specific file and return its AST structure.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
file_path: Path to file to analyze
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
Dictionary with file analysis results
|
|
368
|
+
"""
|
|
369
|
+
return self.file_analyzer.analyze_file(file_path)
|
|
370
|
+
|
|
371
|
+
@property
|
|
372
|
+
def supported_extensions(self):
|
|
373
|
+
"""Get list of supported file extensions."""
|
|
374
|
+
return {".py", ".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"}
|
|
375
|
+
|
|
376
|
+
# Backward compatibility: Expose cache property
|
|
377
|
+
@property
|
|
378
|
+
def cache(self):
|
|
379
|
+
"""Get cache dictionary for backward compatibility."""
|
|
380
|
+
return self.cache_manager.cache
|