claude-mpm 4.1.4__py3-none-any.whl → 4.1.6__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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/templates/research.json +39 -13
- claude_mpm/cli/__init__.py +2 -0
- claude_mpm/cli/commands/__init__.py +2 -0
- claude_mpm/cli/commands/configure.py +1221 -0
- claude_mpm/cli/commands/configure_tui.py +1921 -0
- claude_mpm/cli/commands/tickets.py +365 -784
- claude_mpm/cli/parsers/base_parser.py +7 -0
- claude_mpm/cli/parsers/configure_parser.py +119 -0
- claude_mpm/cli/startup_logging.py +39 -12
- claude_mpm/constants.py +1 -0
- claude_mpm/core/output_style_manager.py +24 -0
- claude_mpm/core/socketio_pool.py +35 -3
- claude_mpm/core/unified_agent_registry.py +46 -15
- claude_mpm/dashboard/static/css/connection-status.css +370 -0
- claude_mpm/dashboard/static/js/components/connection-debug.js +654 -0
- claude_mpm/dashboard/static/js/connection-manager.js +536 -0
- claude_mpm/dashboard/templates/index.html +11 -0
- claude_mpm/hooks/claude_hooks/services/__init__.py +3 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +190 -0
- claude_mpm/services/agents/deployment/agent_discovery_service.py +12 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +172 -233
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +575 -0
- claude_mpm/services/agents/deployment/agent_operation_service.py +573 -0
- claude_mpm/services/agents/deployment/agent_record_service.py +419 -0
- claude_mpm/services/agents/deployment/agent_state_service.py +381 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +4 -2
- claude_mpm/services/diagnostics/checks/__init__.py +2 -0
- claude_mpm/services/diagnostics/checks/instructions_check.py +418 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +15 -2
- claude_mpm/services/event_bus/direct_relay.py +173 -0
- claude_mpm/services/infrastructure/__init__.py +31 -5
- claude_mpm/services/infrastructure/monitoring/__init__.py +43 -0
- claude_mpm/services/infrastructure/monitoring/aggregator.py +437 -0
- claude_mpm/services/infrastructure/monitoring/base.py +130 -0
- claude_mpm/services/infrastructure/monitoring/legacy.py +203 -0
- claude_mpm/services/infrastructure/monitoring/network.py +218 -0
- claude_mpm/services/infrastructure/monitoring/process.py +342 -0
- claude_mpm/services/infrastructure/monitoring/resources.py +243 -0
- claude_mpm/services/infrastructure/monitoring/service.py +367 -0
- claude_mpm/services/infrastructure/monitoring.py +67 -1030
- claude_mpm/services/project/analyzer.py +13 -4
- claude_mpm/services/project/analyzer_refactored.py +450 -0
- claude_mpm/services/project/analyzer_v2.py +566 -0
- claude_mpm/services/project/architecture_analyzer.py +461 -0
- claude_mpm/services/project/dependency_analyzer.py +462 -0
- claude_mpm/services/project/language_analyzer.py +265 -0
- claude_mpm/services/project/metrics_collector.py +410 -0
- claude_mpm/services/socketio/handlers/connection_handler.py +345 -0
- claude_mpm/services/socketio/server/broadcaster.py +32 -1
- claude_mpm/services/socketio/server/connection_manager.py +516 -0
- claude_mpm/services/socketio/server/core.py +63 -0
- claude_mpm/services/socketio/server/eventbus_integration.py +20 -9
- claude_mpm/services/socketio/server/main.py +27 -1
- claude_mpm/services/ticket_manager.py +5 -1
- claude_mpm/services/ticket_services/__init__.py +26 -0
- claude_mpm/services/ticket_services/crud_service.py +328 -0
- claude_mpm/services/ticket_services/formatter_service.py +290 -0
- claude_mpm/services/ticket_services/search_service.py +324 -0
- claude_mpm/services/ticket_services/validation_service.py +303 -0
- claude_mpm/services/ticket_services/workflow_service.py +244 -0
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/METADATA +3 -1
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/RECORD +67 -46
- claude_mpm/agents/OUTPUT_STYLE.md +0 -73
- claude_mpm/agents/backups/INSTRUCTIONS.md +0 -352
- claude_mpm/agents/templates/OPTIMIZATION_REPORT.md +0 -156
- claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +0 -79
- claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +0 -68
- claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +0 -77
- claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +0 -78
- claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +0 -67
- claude_mpm/agents/templates/backup/research_agent_2025011_234551.json +0 -88
- claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +0 -72
- claude_mpm/agents/templates/backup/research_memory_efficient.json +0 -88
- claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +0 -78
- claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +0 -62
- claude_mpm/agents/templates/vercel_ops_instructions.md +0 -582
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.4.dist-info → claude_mpm-4.1.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Architecture Analyzer Service
|
|
4
|
+
=============================
|
|
5
|
+
|
|
6
|
+
WHY: Separates architectural pattern detection from the main analyzer to follow
|
|
7
|
+
single responsibility principle. Identifies project architecture, structure
|
|
8
|
+
patterns, and organization principles.
|
|
9
|
+
|
|
10
|
+
DECISION: Create a focused service for architecture analysis that can
|
|
11
|
+
identify patterns like MVC, microservices, layered architecture, etc.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
import re
|
|
16
|
+
from dataclasses import asdict, dataclass
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Dict, List
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class ArchitectureInfo:
|
|
23
|
+
"""Container for architecture analysis results."""
|
|
24
|
+
|
|
25
|
+
architecture_type: str
|
|
26
|
+
patterns_detected: List[str]
|
|
27
|
+
main_modules: List[str]
|
|
28
|
+
key_directories: List[str]
|
|
29
|
+
entry_points: List[str]
|
|
30
|
+
api_patterns: List[str]
|
|
31
|
+
configuration_patterns: List[str]
|
|
32
|
+
project_terminology: List[str]
|
|
33
|
+
|
|
34
|
+
def to_dict(self) -> Dict:
|
|
35
|
+
"""Convert to dictionary."""
|
|
36
|
+
return asdict(self)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ArchitectureAnalyzerService:
|
|
40
|
+
"""Analyzes project architecture and structural patterns.
|
|
41
|
+
|
|
42
|
+
WHY: Understanding project architecture helps agents work within
|
|
43
|
+
established patterns and maintain architectural consistency.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# Common architectural directories
|
|
47
|
+
ARCHITECTURE_INDICATORS = {
|
|
48
|
+
"mvc": ["models", "views", "controllers"],
|
|
49
|
+
"mvvm": ["models", "views", "viewmodels"],
|
|
50
|
+
"layered": ["presentation", "business", "data", "domain"],
|
|
51
|
+
"hexagonal": ["domain", "application", "infrastructure", "adapters"],
|
|
52
|
+
"clean": ["entities", "usecases", "interfaces", "frameworks"],
|
|
53
|
+
"microservices": ["services", "api-gateway", "service-discovery"],
|
|
54
|
+
"modular": ["modules", "packages", "components"],
|
|
55
|
+
"plugin": ["plugins", "extensions", "addons"],
|
|
56
|
+
"event_driven": ["events", "handlers", "listeners", "publishers"],
|
|
57
|
+
"serverless": ["functions", "lambdas", "handlers"],
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Entry point patterns by language/framework
|
|
61
|
+
ENTRY_POINT_PATTERNS = {
|
|
62
|
+
"python": [
|
|
63
|
+
"main.py",
|
|
64
|
+
"app.py",
|
|
65
|
+
"server.py",
|
|
66
|
+
"run.py",
|
|
67
|
+
"__main__.py",
|
|
68
|
+
"wsgi.py",
|
|
69
|
+
],
|
|
70
|
+
"javascript": ["index.js", "main.js", "app.js", "server.js", "index.ts"],
|
|
71
|
+
"java": ["Main.java", "Application.java", "App.java"],
|
|
72
|
+
"go": ["main.go", "cmd/*/main.go"],
|
|
73
|
+
"rust": ["main.rs", "lib.rs"],
|
|
74
|
+
"ruby": ["app.rb", "application.rb", "config.ru"],
|
|
75
|
+
"php": ["index.php", "app.php"],
|
|
76
|
+
"csharp": ["Program.cs", "Startup.cs"],
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# API pattern indicators
|
|
80
|
+
API_INDICATORS = {
|
|
81
|
+
"rest": ["routes", "endpoints", "resources", "api/v", "/api/"],
|
|
82
|
+
"graphql": ["schema.graphql", "resolvers", "typeDefs", "graphql"],
|
|
83
|
+
"grpc": [".proto", "grpc", "protobuf", "rpc"],
|
|
84
|
+
"websocket": ["ws://", "wss://", "socket.io", "websocket"],
|
|
85
|
+
"soap": [".wsdl", "soap", "xml-rpc"],
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Configuration file patterns
|
|
89
|
+
CONFIG_PATTERNS = {
|
|
90
|
+
"yaml": [".yaml", ".yml"],
|
|
91
|
+
"json": [".json", "config.json", "settings.json"],
|
|
92
|
+
"toml": [".toml", "pyproject.toml", "Cargo.toml"],
|
|
93
|
+
"ini": [".ini", ".cfg", "setup.cfg"],
|
|
94
|
+
"env": [".env", ".env.example", ".env.local"],
|
|
95
|
+
"xml": [".xml", "pom.xml", "web.xml"],
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
def __init__(self, working_directory: Path):
|
|
99
|
+
"""Initialize the architecture analyzer service.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
working_directory: Project root directory
|
|
103
|
+
"""
|
|
104
|
+
self.working_directory = working_directory
|
|
105
|
+
self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
|
|
106
|
+
|
|
107
|
+
def analyze_architecture(self) -> ArchitectureInfo:
|
|
108
|
+
"""Analyze project architecture and structure.
|
|
109
|
+
|
|
110
|
+
WHY: Understanding architecture helps maintain consistency
|
|
111
|
+
and work within established patterns.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
ArchitectureInfo with analysis results
|
|
115
|
+
"""
|
|
116
|
+
info = ArchitectureInfo(
|
|
117
|
+
architecture_type="unknown",
|
|
118
|
+
patterns_detected=[],
|
|
119
|
+
main_modules=[],
|
|
120
|
+
key_directories=[],
|
|
121
|
+
entry_points=[],
|
|
122
|
+
api_patterns=[],
|
|
123
|
+
configuration_patterns=[],
|
|
124
|
+
project_terminology=[],
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Analyze directory structure
|
|
128
|
+
self._analyze_directory_patterns(info)
|
|
129
|
+
|
|
130
|
+
# Detect entry points
|
|
131
|
+
self._detect_entry_points(info)
|
|
132
|
+
|
|
133
|
+
# Detect API patterns
|
|
134
|
+
self._detect_api_patterns(info)
|
|
135
|
+
|
|
136
|
+
# Detect configuration patterns
|
|
137
|
+
self._detect_config_patterns(info)
|
|
138
|
+
|
|
139
|
+
# Extract project terminology
|
|
140
|
+
self._extract_terminology(info)
|
|
141
|
+
|
|
142
|
+
# Infer architecture type
|
|
143
|
+
self._infer_architecture_type(info)
|
|
144
|
+
|
|
145
|
+
return info
|
|
146
|
+
|
|
147
|
+
def detect_design_patterns(self) -> List[str]:
|
|
148
|
+
"""Detect design patterns used in the project.
|
|
149
|
+
|
|
150
|
+
WHY: Understanding design patterns helps maintain
|
|
151
|
+
consistent implementation approaches.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
List of detected design pattern names
|
|
155
|
+
"""
|
|
156
|
+
patterns = []
|
|
157
|
+
|
|
158
|
+
# Sample some source files
|
|
159
|
+
source_files = self._get_sample_source_files()
|
|
160
|
+
|
|
161
|
+
pattern_indicators = {
|
|
162
|
+
"singleton": [r"getInstance\(\)", r"_instance\s*=", r"@singleton"],
|
|
163
|
+
"factory": [r"Factory", r"create\w+\(\)", r"@factory"],
|
|
164
|
+
"observer": [r"subscribe\(", r"notify\(", r"addEventListener"],
|
|
165
|
+
"strategy": [r"Strategy", r"setStrategy\(", r"execute\("],
|
|
166
|
+
"decorator": [r"@\w+", r"Decorator", r"wrapper"],
|
|
167
|
+
"repository": [r"Repository", r"find\w+By", r"save\("],
|
|
168
|
+
"dependency_injection": [r"@inject", r"@autowired", r"container\."],
|
|
169
|
+
"mvc": [r"Controller", r"Model", r"View"],
|
|
170
|
+
"middleware": [r"middleware", r"use\(", r"next\("],
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
for file_path in source_files:
|
|
174
|
+
try:
|
|
175
|
+
content = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
176
|
+
|
|
177
|
+
for pattern_name, indicators in pattern_indicators.items():
|
|
178
|
+
if any(re.search(ind, content) for ind in indicators):
|
|
179
|
+
if pattern_name not in patterns:
|
|
180
|
+
patterns.append(pattern_name)
|
|
181
|
+
|
|
182
|
+
except Exception as e:
|
|
183
|
+
self.logger.debug(f"Error detecting patterns in {file_path}: {e}")
|
|
184
|
+
|
|
185
|
+
return patterns
|
|
186
|
+
|
|
187
|
+
def analyze_module_structure(self) -> Dict[str, List[str]]:
|
|
188
|
+
"""Analyze module organization and dependencies.
|
|
189
|
+
|
|
190
|
+
WHY: Module structure reveals how code is organized
|
|
191
|
+
and helps understand component relationships.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Dictionary mapping modules to their components
|
|
195
|
+
"""
|
|
196
|
+
modules = {}
|
|
197
|
+
|
|
198
|
+
# Look for common module directories
|
|
199
|
+
module_dirs = ["src", "lib", "app", "modules", "packages", "components"]
|
|
200
|
+
|
|
201
|
+
for module_dir in module_dirs:
|
|
202
|
+
module_path = self.working_directory / module_dir
|
|
203
|
+
if module_path.exists() and module_path.is_dir():
|
|
204
|
+
# Get immediate subdirectories as modules
|
|
205
|
+
for subdir in module_path.iterdir():
|
|
206
|
+
if subdir.is_dir() and not subdir.name.startswith("."):
|
|
207
|
+
module_name = subdir.name
|
|
208
|
+
|
|
209
|
+
# Get module components
|
|
210
|
+
components = []
|
|
211
|
+
for item in subdir.iterdir():
|
|
212
|
+
if item.is_file():
|
|
213
|
+
components.append(item.name)
|
|
214
|
+
elif item.is_dir() and not item.name.startswith("."):
|
|
215
|
+
components.append(f"{item.name}/")
|
|
216
|
+
|
|
217
|
+
if components:
|
|
218
|
+
modules[module_name] = components[:10] # Limit to 10
|
|
219
|
+
|
|
220
|
+
return modules
|
|
221
|
+
|
|
222
|
+
def _analyze_directory_patterns(self, info: ArchitectureInfo) -> None:
|
|
223
|
+
"""Analyze directory structure for architectural patterns."""
|
|
224
|
+
existing_dirs = set()
|
|
225
|
+
|
|
226
|
+
# Collect all directory names
|
|
227
|
+
for dirpath, dirnames, _ in self.working_directory.walk():
|
|
228
|
+
for dirname in dirnames:
|
|
229
|
+
if not dirname.startswith("."):
|
|
230
|
+
existing_dirs.add(dirname.lower())
|
|
231
|
+
|
|
232
|
+
# Check for architectural patterns
|
|
233
|
+
for arch_type, indicators in self.ARCHITECTURE_INDICATORS.items():
|
|
234
|
+
matches = sum(1 for ind in indicators if ind in existing_dirs)
|
|
235
|
+
if matches >= len(indicators) * 0.6: # 60% match threshold
|
|
236
|
+
info.patterns_detected.append(arch_type)
|
|
237
|
+
|
|
238
|
+
# Identify key directories
|
|
239
|
+
important_dirs = [
|
|
240
|
+
"src",
|
|
241
|
+
"lib",
|
|
242
|
+
"app",
|
|
243
|
+
"components",
|
|
244
|
+
"services",
|
|
245
|
+
"models",
|
|
246
|
+
"views",
|
|
247
|
+
"controllers",
|
|
248
|
+
"routes",
|
|
249
|
+
"api",
|
|
250
|
+
"tests",
|
|
251
|
+
"docs",
|
|
252
|
+
"config",
|
|
253
|
+
"utils",
|
|
254
|
+
"helpers",
|
|
255
|
+
"core",
|
|
256
|
+
"modules",
|
|
257
|
+
"packages",
|
|
258
|
+
]
|
|
259
|
+
|
|
260
|
+
info.key_directories = [
|
|
261
|
+
d for d in important_dirs if (self.working_directory / d).exists()
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
# Identify main modules (top-level important directories)
|
|
265
|
+
for key_dir in ["src", "lib", "app"]:
|
|
266
|
+
key_path = self.working_directory / key_dir
|
|
267
|
+
if key_path.exists() and key_path.is_dir():
|
|
268
|
+
subdirs = [
|
|
269
|
+
d.name
|
|
270
|
+
for d in key_path.iterdir()
|
|
271
|
+
if d.is_dir() and not d.name.startswith(".")
|
|
272
|
+
]
|
|
273
|
+
info.main_modules.extend(subdirs[:5]) # Top 5 modules
|
|
274
|
+
|
|
275
|
+
def _detect_entry_points(self, info: ArchitectureInfo) -> None:
|
|
276
|
+
"""Detect project entry points."""
|
|
277
|
+
entry_points = []
|
|
278
|
+
|
|
279
|
+
for patterns in self.ENTRY_POINT_PATTERNS.values():
|
|
280
|
+
for pattern in patterns:
|
|
281
|
+
# Handle glob patterns
|
|
282
|
+
if "*" in pattern:
|
|
283
|
+
for match in self.working_directory.glob(pattern):
|
|
284
|
+
if match.is_file():
|
|
285
|
+
rel_path = str(match.relative_to(self.working_directory))
|
|
286
|
+
entry_points.append(rel_path)
|
|
287
|
+
else:
|
|
288
|
+
# Check direct path and in src/
|
|
289
|
+
for base in ["", "src/", "app/", "lib/"]:
|
|
290
|
+
entry_path = self.working_directory / base / pattern
|
|
291
|
+
if entry_path.exists() and entry_path.is_file():
|
|
292
|
+
rel_path = str(
|
|
293
|
+
entry_path.relative_to(self.working_directory)
|
|
294
|
+
)
|
|
295
|
+
entry_points.append(rel_path)
|
|
296
|
+
|
|
297
|
+
info.entry_points = list(set(entry_points))[:10] # Limit to 10
|
|
298
|
+
|
|
299
|
+
def _detect_api_patterns(self, info: ArchitectureInfo) -> None:
|
|
300
|
+
"""Detect API patterns and styles."""
|
|
301
|
+
api_patterns = []
|
|
302
|
+
|
|
303
|
+
# Check directory structure
|
|
304
|
+
for api_type, indicators in self.API_INDICATORS.items():
|
|
305
|
+
for indicator in indicators:
|
|
306
|
+
# Check for directories
|
|
307
|
+
if "/" in indicator:
|
|
308
|
+
if any(
|
|
309
|
+
indicator in str(p)
|
|
310
|
+
for p in self.working_directory.rglob("*")
|
|
311
|
+
if p.is_dir()
|
|
312
|
+
):
|
|
313
|
+
api_patterns.append(api_type.upper())
|
|
314
|
+
break
|
|
315
|
+
|
|
316
|
+
# Check for files
|
|
317
|
+
elif "." in indicator:
|
|
318
|
+
if list(self.working_directory.rglob(f"*{indicator}")):
|
|
319
|
+
api_patterns.append(api_type.upper())
|
|
320
|
+
break
|
|
321
|
+
|
|
322
|
+
# Check source files for API patterns
|
|
323
|
+
source_files = self._get_sample_source_files(limit=10)
|
|
324
|
+
for file_path in source_files:
|
|
325
|
+
try:
|
|
326
|
+
content = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
327
|
+
|
|
328
|
+
# REST API patterns
|
|
329
|
+
if any(
|
|
330
|
+
p in content for p in ["@app.route", "@router.", "@Get(", "@Post("]
|
|
331
|
+
):
|
|
332
|
+
api_patterns.append("REST")
|
|
333
|
+
|
|
334
|
+
# GraphQL patterns
|
|
335
|
+
if any(p in content for p in ["graphql", "resolver", "typeDefs"]):
|
|
336
|
+
api_patterns.append("GraphQL")
|
|
337
|
+
|
|
338
|
+
except Exception as e:
|
|
339
|
+
self.logger.debug(f"Error detecting API patterns in {file_path}: {e}")
|
|
340
|
+
|
|
341
|
+
info.api_patterns = list(set(api_patterns))
|
|
342
|
+
|
|
343
|
+
def _detect_config_patterns(self, info: ArchitectureInfo) -> None:
|
|
344
|
+
"""Detect configuration file patterns."""
|
|
345
|
+
config_patterns = []
|
|
346
|
+
|
|
347
|
+
for config_type, extensions in self.CONFIG_PATTERNS.items():
|
|
348
|
+
for ext in extensions:
|
|
349
|
+
if list(self.working_directory.rglob(f"*{ext}")):
|
|
350
|
+
config_patterns.append(config_type)
|
|
351
|
+
break
|
|
352
|
+
|
|
353
|
+
info.configuration_patterns = config_patterns
|
|
354
|
+
|
|
355
|
+
def _extract_terminology(self, info: ArchitectureInfo) -> None:
|
|
356
|
+
"""Extract project-specific terminology."""
|
|
357
|
+
terminology = set()
|
|
358
|
+
|
|
359
|
+
# Extract from project name
|
|
360
|
+
project_words = re.findall(r"[A-Z][a-z]+|[a-z]+", self.working_directory.name)
|
|
361
|
+
terminology.update(project_words)
|
|
362
|
+
|
|
363
|
+
# Extract from main modules
|
|
364
|
+
for module in info.main_modules:
|
|
365
|
+
words = re.findall(r"[A-Z][a-z]+|[a-z]+", module)
|
|
366
|
+
terminology.update(words)
|
|
367
|
+
|
|
368
|
+
# Extract from key directories
|
|
369
|
+
for directory in info.key_directories:
|
|
370
|
+
words = re.findall(r"[A-Z][a-z]+|[a-z]+", directory)
|
|
371
|
+
terminology.update(words)
|
|
372
|
+
|
|
373
|
+
# Filter out common words
|
|
374
|
+
common_words = {
|
|
375
|
+
"src",
|
|
376
|
+
"lib",
|
|
377
|
+
"app",
|
|
378
|
+
"main",
|
|
379
|
+
"test",
|
|
380
|
+
"tests",
|
|
381
|
+
"docs",
|
|
382
|
+
"config",
|
|
383
|
+
"utils",
|
|
384
|
+
"helpers",
|
|
385
|
+
"core",
|
|
386
|
+
"base",
|
|
387
|
+
"common",
|
|
388
|
+
"shared",
|
|
389
|
+
"public",
|
|
390
|
+
"private",
|
|
391
|
+
"static",
|
|
392
|
+
"assets",
|
|
393
|
+
"build",
|
|
394
|
+
"dist",
|
|
395
|
+
"node",
|
|
396
|
+
"modules",
|
|
397
|
+
"vendor",
|
|
398
|
+
"bin",
|
|
399
|
+
"obj",
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
domain_terms = [
|
|
403
|
+
term
|
|
404
|
+
for term in terminology
|
|
405
|
+
if len(term) > 3 and term.lower() not in common_words
|
|
406
|
+
]
|
|
407
|
+
|
|
408
|
+
info.project_terminology = sorted(domain_terms)[:15] # Top 15 terms
|
|
409
|
+
|
|
410
|
+
def _infer_architecture_type(self, info: ArchitectureInfo) -> None:
|
|
411
|
+
"""Infer the overall architecture type."""
|
|
412
|
+
# Check detected patterns
|
|
413
|
+
if "microservices" in info.patterns_detected:
|
|
414
|
+
info.architecture_type = "Microservices Architecture"
|
|
415
|
+
elif "hexagonal" in info.patterns_detected:
|
|
416
|
+
info.architecture_type = "Hexagonal Architecture"
|
|
417
|
+
elif "clean" in info.patterns_detected:
|
|
418
|
+
info.architecture_type = "Clean Architecture"
|
|
419
|
+
elif "mvc" in info.patterns_detected:
|
|
420
|
+
info.architecture_type = "MVC Architecture"
|
|
421
|
+
elif "layered" in info.patterns_detected:
|
|
422
|
+
info.architecture_type = "Layered Architecture"
|
|
423
|
+
elif "event_driven" in info.patterns_detected:
|
|
424
|
+
info.architecture_type = "Event-Driven Architecture"
|
|
425
|
+
elif "serverless" in info.patterns_detected:
|
|
426
|
+
info.architecture_type = "Serverless Architecture"
|
|
427
|
+
elif "modular" in info.patterns_detected:
|
|
428
|
+
info.architecture_type = "Modular Architecture"
|
|
429
|
+
elif info.api_patterns:
|
|
430
|
+
if "REST" in info.api_patterns:
|
|
431
|
+
info.architecture_type = "REST API Service"
|
|
432
|
+
elif "GraphQL" in info.api_patterns:
|
|
433
|
+
info.architecture_type = "GraphQL Service"
|
|
434
|
+
else:
|
|
435
|
+
info.architecture_type = "API Service"
|
|
436
|
+
elif "api" in info.key_directories:
|
|
437
|
+
info.architecture_type = "API-First Architecture"
|
|
438
|
+
elif any(fw in info.key_directories for fw in ["components", "views"]):
|
|
439
|
+
info.architecture_type = "Component-Based Architecture"
|
|
440
|
+
else:
|
|
441
|
+
info.architecture_type = "Standard Application Architecture"
|
|
442
|
+
|
|
443
|
+
def _get_sample_source_files(self, limit: int = 20) -> List[Path]:
|
|
444
|
+
"""Get a sample of source files for analysis."""
|
|
445
|
+
extensions = [".py", ".js", ".ts", ".java", ".go", ".rs", ".rb", ".php", ".cs"]
|
|
446
|
+
source_files = []
|
|
447
|
+
|
|
448
|
+
for ext in extensions:
|
|
449
|
+
files = list(self.working_directory.rglob(f"*{ext}"))
|
|
450
|
+
# Filter out vendor directories
|
|
451
|
+
files = [
|
|
452
|
+
f
|
|
453
|
+
for f in files
|
|
454
|
+
if not any(
|
|
455
|
+
part in [".git", "node_modules", "vendor", "__pycache__"]
|
|
456
|
+
for part in f.parts
|
|
457
|
+
)
|
|
458
|
+
]
|
|
459
|
+
source_files.extend(files[:3]) # Take up to 3 files per extension
|
|
460
|
+
|
|
461
|
+
return source_files[:limit]
|