claude-mpm 3.9.9__py3-none-any.whl → 4.0.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.
Files changed (411) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +2 -2
  3. claude_mpm/__main__.py +3 -2
  4. claude_mpm/agents/__init__.py +85 -79
  5. claude_mpm/agents/agent_loader.py +464 -1003
  6. claude_mpm/agents/agent_loader_integration.py +45 -45
  7. claude_mpm/agents/agents_metadata.py +29 -30
  8. claude_mpm/agents/async_agent_loader.py +156 -138
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/base_agent_loader.py +179 -151
  11. claude_mpm/agents/frontmatter_validator.py +229 -130
  12. claude_mpm/agents/schema/agent_schema.json +1 -1
  13. claude_mpm/agents/system_agent_config.py +213 -147
  14. claude_mpm/agents/templates/__init__.py +13 -13
  15. claude_mpm/agents/templates/code_analyzer.json +2 -2
  16. claude_mpm/agents/templates/data_engineer.json +1 -1
  17. claude_mpm/agents/templates/documentation.json +23 -11
  18. claude_mpm/agents/templates/engineer.json +22 -6
  19. claude_mpm/agents/templates/memory_manager.json +155 -0
  20. claude_mpm/agents/templates/ops.json +2 -2
  21. claude_mpm/agents/templates/project_organizer.json +1 -1
  22. claude_mpm/agents/templates/qa.json +1 -1
  23. claude_mpm/agents/templates/refactoring_engineer.json +222 -0
  24. claude_mpm/agents/templates/research.json +20 -14
  25. claude_mpm/agents/templates/security.json +1 -1
  26. claude_mpm/agents/templates/ticketing.json +1 -1
  27. claude_mpm/agents/templates/version_control.json +1 -1
  28. claude_mpm/agents/templates/web_qa.json +3 -1
  29. claude_mpm/agents/templates/web_ui.json +2 -2
  30. claude_mpm/cli/__init__.py +90 -49
  31. claude_mpm/cli/__main__.py +3 -2
  32. claude_mpm/cli/commands/__init__.py +21 -18
  33. claude_mpm/cli/commands/agents.py +279 -247
  34. claude_mpm/cli/commands/aggregate.py +138 -157
  35. claude_mpm/cli/commands/cleanup.py +147 -147
  36. claude_mpm/cli/commands/config.py +93 -76
  37. claude_mpm/cli/commands/info.py +17 -16
  38. claude_mpm/cli/commands/mcp.py +143 -762
  39. claude_mpm/cli/commands/mcp_command_router.py +139 -0
  40. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  41. claude_mpm/cli/commands/mcp_install_commands.py +20 -0
  42. claude_mpm/cli/commands/mcp_server_commands.py +175 -0
  43. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  44. claude_mpm/cli/commands/memory.py +239 -203
  45. claude_mpm/cli/commands/monitor.py +203 -81
  46. claude_mpm/cli/commands/run.py +380 -429
  47. claude_mpm/cli/commands/run_config_checker.py +160 -0
  48. claude_mpm/cli/commands/socketio_monitor.py +235 -0
  49. claude_mpm/cli/commands/tickets.py +305 -197
  50. claude_mpm/cli/parser.py +24 -1150
  51. claude_mpm/cli/parsers/__init__.py +29 -0
  52. claude_mpm/cli/parsers/agents_parser.py +136 -0
  53. claude_mpm/cli/parsers/base_parser.py +331 -0
  54. claude_mpm/cli/parsers/config_parser.py +85 -0
  55. claude_mpm/cli/parsers/mcp_parser.py +152 -0
  56. claude_mpm/cli/parsers/memory_parser.py +138 -0
  57. claude_mpm/cli/parsers/monitor_parser.py +104 -0
  58. claude_mpm/cli/parsers/run_parser.py +147 -0
  59. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  60. claude_mpm/cli/ticket_cli.py +7 -3
  61. claude_mpm/cli/utils.py +55 -37
  62. claude_mpm/cli_module/__init__.py +6 -6
  63. claude_mpm/cli_module/args.py +188 -140
  64. claude_mpm/cli_module/commands.py +79 -70
  65. claude_mpm/cli_module/migration_example.py +38 -60
  66. claude_mpm/config/__init__.py +32 -25
  67. claude_mpm/config/agent_config.py +151 -119
  68. claude_mpm/config/experimental_features.py +217 -0
  69. claude_mpm/config/paths.py +94 -208
  70. claude_mpm/config/socketio_config.py +84 -73
  71. claude_mpm/constants.py +36 -18
  72. claude_mpm/core/__init__.py +9 -6
  73. claude_mpm/core/agent_name_normalizer.py +68 -71
  74. claude_mpm/core/agent_registry.py +372 -521
  75. claude_mpm/core/agent_session_manager.py +74 -63
  76. claude_mpm/core/base_service.py +116 -87
  77. claude_mpm/core/cache.py +119 -153
  78. claude_mpm/core/claude_runner.py +425 -1120
  79. claude_mpm/core/config.py +263 -168
  80. claude_mpm/core/config_aliases.py +69 -61
  81. claude_mpm/core/config_constants.py +292 -0
  82. claude_mpm/core/constants.py +57 -99
  83. claude_mpm/core/container.py +211 -178
  84. claude_mpm/core/exceptions.py +233 -89
  85. claude_mpm/core/factories.py +92 -54
  86. claude_mpm/core/framework_loader.py +378 -220
  87. claude_mpm/core/hook_manager.py +198 -83
  88. claude_mpm/core/hook_performance_config.py +136 -0
  89. claude_mpm/core/injectable_service.py +61 -55
  90. claude_mpm/core/interactive_session.py +165 -155
  91. claude_mpm/core/interfaces.py +221 -195
  92. claude_mpm/core/lazy.py +96 -96
  93. claude_mpm/core/logger.py +133 -107
  94. claude_mpm/core/logging_config.py +185 -157
  95. claude_mpm/core/minimal_framework_loader.py +20 -15
  96. claude_mpm/core/mixins.py +30 -29
  97. claude_mpm/core/oneshot_session.py +215 -181
  98. claude_mpm/core/optimized_agent_loader.py +134 -138
  99. claude_mpm/core/optimized_startup.py +159 -157
  100. claude_mpm/core/pm_hook_interceptor.py +85 -72
  101. claude_mpm/core/service_registry.py +103 -101
  102. claude_mpm/core/session_manager.py +97 -87
  103. claude_mpm/core/socketio_pool.py +212 -158
  104. claude_mpm/core/tool_access_control.py +58 -51
  105. claude_mpm/core/types.py +46 -24
  106. claude_mpm/core/typing_utils.py +166 -82
  107. claude_mpm/core/unified_agent_registry.py +721 -0
  108. claude_mpm/core/unified_config.py +550 -0
  109. claude_mpm/core/unified_paths.py +549 -0
  110. claude_mpm/dashboard/index.html +1 -1
  111. claude_mpm/dashboard/open_dashboard.py +51 -17
  112. claude_mpm/dashboard/static/css/dashboard.css +27 -8
  113. claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
  114. claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
  115. claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
  116. claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
  117. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
  118. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
  119. claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
  120. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
  121. claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
  122. claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
  123. claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
  124. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
  125. claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
  126. claude_mpm/dashboard/static/dist/dashboard.js +2 -0
  127. claude_mpm/dashboard/static/dist/socket-client.js +2 -0
  128. claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
  129. claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
  130. claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
  131. claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
  132. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
  133. claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
  134. claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
  135. claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
  136. claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
  137. claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
  138. claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
  139. claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
  140. claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
  141. claude_mpm/dashboard/static/js/dashboard.js +178 -453
  142. claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
  143. claude_mpm/dashboard/static/js/socket-client.js +120 -54
  144. claude_mpm/dashboard/templates/index.html +40 -50
  145. claude_mpm/experimental/cli_enhancements.py +60 -58
  146. claude_mpm/generators/__init__.py +1 -1
  147. claude_mpm/generators/agent_profile_generator.py +75 -65
  148. claude_mpm/hooks/__init__.py +1 -1
  149. claude_mpm/hooks/base_hook.py +33 -28
  150. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  151. claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
  152. claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
  153. claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
  154. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
  155. claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
  156. claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
  157. claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
  158. claude_mpm/hooks/memory_integration_hook.py +140 -100
  159. claude_mpm/hooks/tool_call_interceptor.py +89 -76
  160. claude_mpm/hooks/validation_hooks.py +57 -49
  161. claude_mpm/init.py +145 -121
  162. claude_mpm/models/__init__.py +9 -9
  163. claude_mpm/models/agent_definition.py +33 -23
  164. claude_mpm/models/agent_session.py +228 -200
  165. claude_mpm/scripts/__init__.py +1 -1
  166. claude_mpm/scripts/socketio_daemon.py +192 -75
  167. claude_mpm/scripts/socketio_server_manager.py +328 -0
  168. claude_mpm/scripts/start_activity_logging.py +25 -22
  169. claude_mpm/services/__init__.py +68 -43
  170. claude_mpm/services/agent_capabilities_service.py +271 -0
  171. claude_mpm/services/agents/__init__.py +23 -32
  172. claude_mpm/services/agents/deployment/__init__.py +3 -3
  173. claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
  174. claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
  175. claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
  176. claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
  177. claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
  178. claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
  179. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
  180. claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
  181. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
  182. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
  183. claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
  184. claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
  185. claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
  186. claude_mpm/services/agents/deployment/agent_validator.py +352 -0
  187. claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
  188. claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
  189. claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
  190. claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
  191. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  192. claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
  193. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  194. claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
  195. claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
  196. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  197. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  198. claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
  199. claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
  200. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  201. claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
  202. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  203. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  204. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  205. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  206. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
  207. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  208. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  209. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
  210. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
  211. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
  212. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
  213. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
  214. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  215. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
  216. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  217. claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
  218. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
  219. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  220. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  221. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  222. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  223. claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
  224. claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
  225. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  226. claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
  227. claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
  228. claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
  229. claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
  230. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  231. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  232. claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
  233. claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
  234. claude_mpm/services/agents/loading/__init__.py +2 -2
  235. claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
  236. claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
  237. claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
  238. claude_mpm/services/agents/management/__init__.py +2 -2
  239. claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
  240. claude_mpm/services/agents/management/agent_management_service.py +209 -156
  241. claude_mpm/services/agents/memory/__init__.py +9 -6
  242. claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
  243. claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
  244. claude_mpm/services/agents/memory/analyzer.py +430 -0
  245. claude_mpm/services/agents/memory/content_manager.py +376 -0
  246. claude_mpm/services/agents/memory/template_generator.py +468 -0
  247. claude_mpm/services/agents/registry/__init__.py +7 -10
  248. claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
  249. claude_mpm/services/agents/registry/modification_tracker.py +351 -285
  250. claude_mpm/services/async_session_logger.py +187 -153
  251. claude_mpm/services/claude_session_logger.py +87 -72
  252. claude_mpm/services/command_handler_service.py +217 -0
  253. claude_mpm/services/communication/__init__.py +3 -2
  254. claude_mpm/services/core/__init__.py +50 -97
  255. claude_mpm/services/core/base.py +60 -53
  256. claude_mpm/services/core/interfaces/__init__.py +188 -0
  257. claude_mpm/services/core/interfaces/agent.py +351 -0
  258. claude_mpm/services/core/interfaces/communication.py +343 -0
  259. claude_mpm/services/core/interfaces/infrastructure.py +413 -0
  260. claude_mpm/services/core/interfaces/service.py +434 -0
  261. claude_mpm/services/core/interfaces.py +19 -944
  262. claude_mpm/services/event_aggregator.py +208 -170
  263. claude_mpm/services/exceptions.py +387 -308
  264. claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
  265. claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
  266. claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
  267. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
  268. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
  269. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
  270. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
  271. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
  272. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  273. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  274. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  275. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  276. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
  277. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  278. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  279. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
  280. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
  281. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  282. claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
  283. claude_mpm/services/hook_service.py +106 -114
  284. claude_mpm/services/infrastructure/__init__.py +7 -5
  285. claude_mpm/services/infrastructure/context_preservation.py +571 -0
  286. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  287. claude_mpm/services/infrastructure/logging.py +83 -76
  288. claude_mpm/services/infrastructure/monitoring.py +547 -404
  289. claude_mpm/services/mcp_gateway/__init__.py +40 -23
  290. claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
  291. claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
  292. claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
  293. claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
  294. claude_mpm/services/mcp_gateway/core/__init__.py +14 -21
  295. claude_mpm/services/mcp_gateway/core/base.py +80 -67
  296. claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
  297. claude_mpm/services/mcp_gateway/core/interfaces.py +97 -93
  298. claude_mpm/services/mcp_gateway/main.py +307 -127
  299. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +100 -101
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  302. claude_mpm/services/mcp_gateway/server/__init__.py +4 -4
  303. claude_mpm/services/mcp_gateway/server/{mcp_server.py → mcp_gateway.py} +149 -153
  304. claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
  305. claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
  306. claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
  307. claude_mpm/services/mcp_gateway/tools/base_adapter.py +110 -121
  308. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
  309. claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
  310. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
  311. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
  312. claude_mpm/services/memory/__init__.py +2 -2
  313. claude_mpm/services/memory/builder.py +451 -362
  314. claude_mpm/services/memory/cache/__init__.py +2 -2
  315. claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
  316. claude_mpm/services/memory/cache/simple_cache.py +107 -93
  317. claude_mpm/services/memory/indexed_memory.py +195 -193
  318. claude_mpm/services/memory/optimizer.py +267 -234
  319. claude_mpm/services/memory/router.py +571 -263
  320. claude_mpm/services/memory_hook_service.py +237 -0
  321. claude_mpm/services/port_manager.py +223 -0
  322. claude_mpm/services/project/__init__.py +3 -3
  323. claude_mpm/services/project/analyzer.py +451 -305
  324. claude_mpm/services/project/registry.py +262 -240
  325. claude_mpm/services/recovery_manager.py +287 -231
  326. claude_mpm/services/response_tracker.py +87 -67
  327. claude_mpm/services/runner_configuration_service.py +587 -0
  328. claude_mpm/services/session_management_service.py +304 -0
  329. claude_mpm/services/socketio/__init__.py +4 -4
  330. claude_mpm/services/socketio/client_proxy.py +174 -0
  331. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  332. claude_mpm/services/socketio/handlers/base.py +44 -30
  333. claude_mpm/services/socketio/handlers/connection.py +145 -65
  334. claude_mpm/services/socketio/handlers/file.py +123 -108
  335. claude_mpm/services/socketio/handlers/git.py +607 -373
  336. claude_mpm/services/socketio/handlers/hook.py +170 -0
  337. claude_mpm/services/socketio/handlers/memory.py +4 -4
  338. claude_mpm/services/socketio/handlers/project.py +4 -4
  339. claude_mpm/services/socketio/handlers/registry.py +53 -38
  340. claude_mpm/services/socketio/server/__init__.py +18 -0
  341. claude_mpm/services/socketio/server/broadcaster.py +252 -0
  342. claude_mpm/services/socketio/server/core.py +399 -0
  343. claude_mpm/services/socketio/server/main.py +323 -0
  344. claude_mpm/services/socketio_client_manager.py +160 -133
  345. claude_mpm/services/socketio_server.py +36 -1885
  346. claude_mpm/services/subprocess_launcher_service.py +316 -0
  347. claude_mpm/services/system_instructions_service.py +258 -0
  348. claude_mpm/services/ticket_manager.py +20 -534
  349. claude_mpm/services/utility_service.py +285 -0
  350. claude_mpm/services/version_control/__init__.py +18 -21
  351. claude_mpm/services/version_control/branch_strategy.py +20 -10
  352. claude_mpm/services/version_control/conflict_resolution.py +37 -13
  353. claude_mpm/services/version_control/git_operations.py +52 -21
  354. claude_mpm/services/version_control/semantic_versioning.py +92 -53
  355. claude_mpm/services/version_control/version_parser.py +145 -125
  356. claude_mpm/services/version_service.py +270 -0
  357. claude_mpm/storage/__init__.py +9 -0
  358. claude_mpm/storage/state_storage.py +552 -0
  359. claude_mpm/ticket_wrapper.py +2 -2
  360. claude_mpm/utils/__init__.py +2 -2
  361. claude_mpm/utils/agent_dependency_loader.py +453 -243
  362. claude_mpm/utils/config_manager.py +157 -118
  363. claude_mpm/utils/console.py +1 -1
  364. claude_mpm/utils/dependency_cache.py +102 -107
  365. claude_mpm/utils/dependency_manager.py +52 -47
  366. claude_mpm/utils/dependency_strategies.py +131 -96
  367. claude_mpm/utils/environment_context.py +110 -102
  368. claude_mpm/utils/error_handler.py +75 -55
  369. claude_mpm/utils/file_utils.py +80 -67
  370. claude_mpm/utils/framework_detection.py +12 -11
  371. claude_mpm/utils/import_migration_example.py +12 -60
  372. claude_mpm/utils/imports.py +48 -45
  373. claude_mpm/utils/path_operations.py +100 -93
  374. claude_mpm/utils/robust_installer.py +172 -164
  375. claude_mpm/utils/session_logging.py +30 -23
  376. claude_mpm/utils/subprocess_utils.py +99 -61
  377. claude_mpm/validation/__init__.py +1 -1
  378. claude_mpm/validation/agent_validator.py +151 -111
  379. claude_mpm/validation/frontmatter_validator.py +92 -71
  380. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +51 -2
  381. claude_mpm-4.0.3.dist-info/RECORD +402 -0
  382. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
  383. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
  384. claude_mpm/config/memory_guardian_config.py +0 -325
  385. claude_mpm/core/config_paths.py +0 -150
  386. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  387. claude_mpm/deployment_paths.py +0 -261
  388. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  389. claude_mpm/models/state_models.py +0 -433
  390. claude_mpm/services/agent/__init__.py +0 -24
  391. claude_mpm/services/agent/deployment.py +0 -2548
  392. claude_mpm/services/agent/management.py +0 -598
  393. claude_mpm/services/agent/registry.py +0 -813
  394. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  395. claude_mpm/services/communication/socketio.py +0 -1935
  396. claude_mpm/services/communication/websocket.py +0 -479
  397. claude_mpm/services/framework_claude_md_generator.py +0 -624
  398. claude_mpm/services/health_monitor.py +0 -893
  399. claude_mpm/services/infrastructure/memory_guardian.py +0 -770
  400. claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +0 -444
  401. claude_mpm/services/optimized_hook_service.py +0 -542
  402. claude_mpm/services/project_analyzer.py +0 -864
  403. claude_mpm/services/project_registry.py +0 -608
  404. claude_mpm/services/standalone_socketio_server.py +0 -1300
  405. claude_mpm/services/ticket_manager_di.py +0 -318
  406. claude_mpm/services/ticketing_service_original.py +0 -510
  407. claude_mpm/utils/paths.py +0 -395
  408. claude_mpm/utils/platform_memory.py +0 -524
  409. claude_mpm-3.9.9.dist-info/RECORD +0 -293
  410. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
  411. {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
@@ -23,55 +23,55 @@ This service analyzes:
23
23
  """
24
24
 
25
25
  import json
26
+ import logging
26
27
  import re
28
+ from collections import Counter, defaultdict
29
+ from dataclasses import asdict, dataclass
27
30
  from pathlib import Path
28
- from typing import Dict, List, Optional, Any, Set, Tuple
29
- import logging
30
- from dataclasses import dataclass, asdict
31
- from collections import defaultdict, Counter
31
+ from typing import Any, Dict, List, Optional, Set, Tuple
32
32
 
33
33
  from claude_mpm.core.config import Config
34
- from claude_mpm.utils.paths import PathResolver
35
34
  from claude_mpm.core.interfaces import ProjectAnalyzerInterface
35
+ from claude_mpm.core.unified_paths import get_path_manager
36
36
 
37
37
 
38
38
  @dataclass
39
39
  class ProjectCharacteristics:
40
40
  """Structured representation of project characteristics."""
41
-
41
+
42
42
  # Core project info
43
43
  project_name: str
44
44
  primary_language: Optional[str]
45
45
  languages: List[str]
46
46
  frameworks: List[str]
47
-
47
+
48
48
  # Architecture and structure
49
49
  architecture_type: str
50
50
  main_modules: List[str]
51
51
  key_directories: List[str]
52
52
  entry_points: List[str]
53
-
53
+
54
54
  # Development practices
55
55
  testing_framework: Optional[str]
56
56
  test_patterns: List[str]
57
57
  package_manager: Optional[str]
58
58
  build_tools: List[str]
59
-
59
+
60
60
  # Integrations and dependencies
61
61
  databases: List[str]
62
62
  web_frameworks: List[str]
63
63
  api_patterns: List[str]
64
64
  key_dependencies: List[str]
65
-
65
+
66
66
  # Project-specific patterns
67
67
  code_conventions: List[str]
68
68
  configuration_patterns: List[str]
69
69
  project_terminology: List[str]
70
-
70
+
71
71
  # Documentation and structure
72
72
  documentation_files: List[str]
73
73
  important_configs: List[str]
74
-
74
+
75
75
  def to_dict(self) -> Dict[str, Any]:
76
76
  """Convert to dictionary for JSON serialization."""
77
77
  return asdict(self)
@@ -79,79 +79,83 @@ class ProjectCharacteristics:
79
79
 
80
80
  class ProjectAnalyzer(ProjectAnalyzerInterface):
81
81
  """Analyzes project characteristics for context-aware memory creation.
82
-
82
+
83
83
  WHY: Generic agent memories aren't helpful for specific projects. This analyzer
84
84
  extracts project-specific characteristics that enable agents to create relevant,
85
85
  actionable memories with proper context.
86
-
86
+
87
87
  DESIGN DECISION: Uses a combination of file pattern analysis, content parsing,
88
88
  and directory structure analysis to build comprehensive project understanding
89
89
  without requiring external tools or API calls.
90
90
  """
91
-
91
+
92
92
  # Common configuration files and their indicators
93
93
  CONFIG_FILE_PATTERNS = {
94
- 'package.json': 'node_js',
95
- 'requirements.txt': 'python',
96
- 'pyproject.toml': 'python',
97
- 'setup.py': 'python',
98
- 'Cargo.toml': 'rust',
99
- 'pom.xml': 'java',
100
- 'build.gradle': 'java',
101
- 'composer.json': 'php',
102
- 'Gemfile': 'ruby',
103
- 'go.mod': 'go',
104
- 'CMakeLists.txt': 'cpp',
105
- 'Makefile': 'c_cpp',
94
+ "package.json": "node_js",
95
+ "requirements.txt": "python",
96
+ "pyproject.toml": "python",
97
+ "setup.py": "python",
98
+ "Cargo.toml": "rust",
99
+ "pom.xml": "java",
100
+ "build.gradle": "java",
101
+ "composer.json": "php",
102
+ "Gemfile": "ruby",
103
+ "go.mod": "go",
104
+ "CMakeLists.txt": "cpp",
105
+ "Makefile": "c_cpp",
106
106
  }
107
-
107
+
108
108
  # Framework detection patterns
109
109
  FRAMEWORK_PATTERNS = {
110
- 'flask': ['from flask', 'Flask(', 'app.route'],
111
- 'django': ['from django', 'DJANGO_SETTINGS', 'django.contrib'],
112
- 'fastapi': ['from fastapi', 'FastAPI(', '@app.'],
113
- 'express': ['express()', 'app.get(', 'app.post('],
114
- 'react': ['import React', 'from react', 'ReactDOM'],
115
- 'vue': ['Vue.createApp', 'new Vue(', 'vue-'],
116
- 'angular': ['@Component', '@Injectable', 'Angular'],
117
- 'spring': ['@SpringBootApplication', '@RestController', 'Spring'],
118
- 'rails': ['Rails.application', 'ApplicationController'],
110
+ "flask": ["from flask", "Flask(", "app.route"],
111
+ "django": ["from django", "DJANGO_SETTINGS", "django.contrib"],
112
+ "fastapi": ["from fastapi", "FastAPI(", "@app."],
113
+ "express": ["express()", "app.get(", "app.post("],
114
+ "react": ["import React", "from react", "ReactDOM"],
115
+ "vue": ["Vue.createApp", "new Vue(", "vue-"],
116
+ "angular": ["@Component", "@Injectable", "Angular"],
117
+ "spring": ["@SpringBootApplication", "@RestController", "Spring"],
118
+ "rails": ["Rails.application", "ApplicationController"],
119
119
  }
120
-
120
+
121
121
  # Database detection patterns
122
122
  DATABASE_PATTERNS = {
123
- 'postgresql': ['psycopg2', 'postgresql:', 'postgres:', 'pg_'],
124
- 'mysql': ['mysql-connector', 'mysql:', 'MySQLdb'],
125
- 'sqlite': ['sqlite3', 'sqlite:', '.db', '.sqlite'],
126
- 'mongodb': ['pymongo', 'mongodb:', 'mongoose'],
127
- 'redis': ['redis:', 'redis-py', 'RedisClient'],
128
- 'elasticsearch': ['elasticsearch:', 'elastic'],
123
+ "postgresql": ["psycopg2", "postgresql:", "postgres:", "pg_"],
124
+ "mysql": ["mysql-connector", "mysql:", "MySQLdb"],
125
+ "sqlite": ["sqlite3", "sqlite:", ".db", ".sqlite"],
126
+ "mongodb": ["pymongo", "mongodb:", "mongoose"],
127
+ "redis": ["redis:", "redis-py", "RedisClient"],
128
+ "elasticsearch": ["elasticsearch:", "elastic"],
129
129
  }
130
-
131
- def __init__(self, config: Optional[Config] = None, working_directory: Optional[Path] = None):
130
+
131
+ def __init__(
132
+ self, config: Optional[Config] = None, working_directory: Optional[Path] = None
133
+ ):
132
134
  """Initialize the project analyzer.
133
-
135
+
134
136
  Args:
135
137
  config: Optional Config object
136
138
  working_directory: Optional working directory path. If not provided, uses current.
137
139
  """
138
140
  self.config = config or Config()
139
- self.working_directory = working_directory or PathResolver.get_project_root()
141
+ self.working_directory = (
142
+ working_directory or get_path_manager().get_project_root()
143
+ )
140
144
  self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
141
-
145
+
142
146
  # Cache for analysis results
143
147
  self._analysis_cache: Optional[ProjectCharacteristics] = None
144
148
  self._cache_timestamp: Optional[float] = None
145
-
149
+
146
150
  def analyze_project(self, force_refresh: bool = False) -> ProjectCharacteristics:
147
151
  """Analyze the current project and return characteristics.
148
-
152
+
149
153
  WHY: Comprehensive project analysis enables agents to create memories
150
154
  that are specific to the actual project context, tech stack, and patterns.
151
-
155
+
152
156
  Args:
153
157
  force_refresh: If True, ignores cache and performs fresh analysis
154
-
158
+
155
159
  Returns:
156
160
  ProjectCharacteristics: Structured project analysis results
157
161
  """
@@ -160,12 +164,13 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
160
164
  if not force_refresh and self._analysis_cache and self._cache_timestamp:
161
165
  # Cache is valid for 5 minutes
162
166
  import time
167
+
163
168
  if time.time() - self._cache_timestamp < 300:
164
169
  self.logger.debug("Using cached project analysis")
165
170
  return self._analysis_cache
166
-
171
+
167
172
  self.logger.info(f"Analyzing project at: {self.working_directory}")
168
-
173
+
169
174
  # Initialize characteristics with basic info
170
175
  characteristics = ProjectCharacteristics(
171
176
  project_name=self.working_directory.name,
@@ -188,9 +193,9 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
188
193
  configuration_patterns=[],
189
194
  project_terminology=[],
190
195
  documentation_files=[],
191
- important_configs=[]
196
+ important_configs=[],
192
197
  )
193
-
198
+
194
199
  # Perform various analyses
195
200
  self._analyze_config_files(characteristics)
196
201
  self._analyze_directory_structure(characteristics)
@@ -200,15 +205,18 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
200
205
  self._analyze_documentation(characteristics)
201
206
  self._infer_architecture_type(characteristics)
202
207
  self._extract_project_terminology(characteristics)
203
-
208
+
204
209
  # Cache the results
205
210
  self._analysis_cache = characteristics
206
211
  import time
212
+
207
213
  self._cache_timestamp = time.time()
208
-
209
- self.logger.info(f"Project analysis complete: {characteristics.primary_language} project with {len(characteristics.frameworks)} frameworks")
214
+
215
+ self.logger.info(
216
+ f"Project analysis complete: {characteristics.primary_language} project with {len(characteristics.frameworks)} frameworks"
217
+ )
210
218
  return characteristics
211
-
219
+
212
220
  except Exception as e:
213
221
  self.logger.error(f"Error analyzing project: {e}")
214
222
  # Return minimal characteristics on error
@@ -233,142 +241,174 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
233
241
  configuration_patterns=[],
234
242
  project_terminology=[],
235
243
  documentation_files=[],
236
- important_configs=[]
244
+ important_configs=[],
237
245
  )
238
-
246
+
239
247
  def _analyze_config_files(self, characteristics: ProjectCharacteristics) -> None:
240
248
  """Analyze configuration files to determine tech stack.
241
-
249
+
242
250
  WHY: Configuration files are the most reliable indicators of project
243
251
  technology stack and dependencies. They provide definitive information
244
252
  about what technologies are actually used.
245
-
253
+
246
254
  Args:
247
255
  characteristics: ProjectCharacteristics object to update
248
256
  """
249
257
  config_files = []
250
258
  languages_found = set()
251
-
259
+
252
260
  for config_file, language in self.CONFIG_FILE_PATTERNS.items():
253
261
  config_path = self.working_directory / config_file
254
262
  if config_path.exists():
255
263
  config_files.append(config_file)
256
264
  languages_found.add(language)
257
- characteristics.important_configs.append(str(config_path.relative_to(self.working_directory)))
258
-
265
+ characteristics.important_configs.append(
266
+ str(config_path.relative_to(self.working_directory))
267
+ )
268
+
259
269
  # Parse specific config files for more details
260
270
  try:
261
- if config_file == 'package.json':
271
+ if config_file == "package.json":
262
272
  self._parse_package_json(config_path, characteristics)
263
- elif config_file in ['requirements.txt', 'pyproject.toml']:
273
+ elif config_file in ["requirements.txt", "pyproject.toml"]:
264
274
  self._parse_python_dependencies(config_path, characteristics)
265
- elif config_file == 'Cargo.toml':
275
+ elif config_file == "Cargo.toml":
266
276
  self._parse_cargo_toml(config_path, characteristics)
267
277
  except Exception as e:
268
278
  self.logger.warning(f"Error parsing {config_file}: {e}")
269
-
279
+
270
280
  # Set primary language (prefer more specific indicators)
271
- language_priority = ['python', 'node_js', 'rust', 'java', 'go', 'php', 'ruby']
281
+ language_priority = ["python", "node_js", "rust", "java", "go", "php", "ruby"]
272
282
  for lang in language_priority:
273
283
  if lang in languages_found:
274
284
  characteristics.primary_language = lang
275
285
  break
276
-
286
+
277
287
  characteristics.languages = list(languages_found)
278
-
288
+
279
289
  # Determine package manager
280
- if 'package.json' in config_files:
281
- if (self.working_directory / 'yarn.lock').exists():
282
- characteristics.package_manager = 'yarn'
283
- elif (self.working_directory / 'pnpm-lock.yaml').exists():
284
- characteristics.package_manager = 'pnpm'
290
+ if "package.json" in config_files:
291
+ if (self.working_directory / "yarn.lock").exists():
292
+ characteristics.package_manager = "yarn"
293
+ elif (self.working_directory / "pnpm-lock.yaml").exists():
294
+ characteristics.package_manager = "pnpm"
285
295
  else:
286
- characteristics.package_manager = 'npm'
287
- elif 'requirements.txt' in config_files or 'pyproject.toml' in config_files:
288
- characteristics.package_manager = 'pip'
289
- elif 'Cargo.toml' in config_files:
290
- characteristics.package_manager = 'cargo'
291
-
292
- def _parse_package_json(self, package_path: Path, characteristics: ProjectCharacteristics) -> None:
296
+ characteristics.package_manager = "npm"
297
+ elif "requirements.txt" in config_files or "pyproject.toml" in config_files:
298
+ characteristics.package_manager = "pip"
299
+ elif "Cargo.toml" in config_files:
300
+ characteristics.package_manager = "cargo"
301
+
302
+ def _parse_package_json(
303
+ self, package_path: Path, characteristics: ProjectCharacteristics
304
+ ) -> None:
293
305
  """Parse package.json for Node.js project details."""
294
306
  try:
295
- with open(package_path, 'r') as f:
307
+ with open(package_path, "r") as f:
296
308
  package_data = json.load(f)
297
-
309
+
298
310
  # Extract dependencies
299
311
  all_deps = {}
300
- all_deps.update(package_data.get('dependencies', {}))
301
- all_deps.update(package_data.get('devDependencies', {}))
302
-
312
+ all_deps.update(package_data.get("dependencies", {}))
313
+ all_deps.update(package_data.get("devDependencies", {}))
314
+
303
315
  # Identify frameworks and tools
304
316
  for dep_name in all_deps.keys():
305
317
  dep_lower = dep_name.lower()
306
-
318
+
307
319
  # Web frameworks
308
- if any(fw in dep_lower for fw in ['express', 'koa', 'hapi']):
320
+ if any(fw in dep_lower for fw in ["express", "koa", "hapi"]):
309
321
  characteristics.web_frameworks.append(dep_name)
310
- elif any(fw in dep_lower for fw in ['react', 'vue', 'angular', 'svelte']):
322
+ elif any(
323
+ fw in dep_lower for fw in ["react", "vue", "angular", "svelte"]
324
+ ):
311
325
  characteristics.frameworks.append(dep_name)
312
- elif any(db in dep_lower for db in ['mysql', 'postgres', 'mongodb', 'redis']):
326
+ elif any(
327
+ db in dep_lower for db in ["mysql", "postgres", "mongodb", "redis"]
328
+ ):
313
329
  characteristics.databases.append(dep_name)
314
- elif any(test in dep_lower for test in ['jest', 'mocha', 'cypress', 'playwright']):
330
+ elif any(
331
+ test in dep_lower
332
+ for test in ["jest", "mocha", "cypress", "playwright"]
333
+ ):
315
334
  if not characteristics.testing_framework:
316
335
  characteristics.testing_framework = dep_name
317
-
336
+
318
337
  characteristics.key_dependencies.append(dep_name)
319
-
338
+
320
339
  # Check scripts for build tools
321
- scripts = package_data.get('scripts', {})
340
+ scripts = package_data.get("scripts", {})
322
341
  for script_name, script_cmd in scripts.items():
323
- if any(tool in script_cmd for tool in ['webpack', 'rollup', 'vite', 'parcel']):
342
+ if any(
343
+ tool in script_cmd
344
+ for tool in ["webpack", "rollup", "vite", "parcel"]
345
+ ):
324
346
  characteristics.build_tools.append(script_name)
325
-
347
+
326
348
  except Exception as e:
327
349
  self.logger.warning(f"Error parsing package.json: {e}")
328
-
329
- def _parse_python_dependencies(self, deps_path: Path, characteristics: ProjectCharacteristics) -> None:
350
+
351
+ def _parse_python_dependencies(
352
+ self, deps_path: Path, characteristics: ProjectCharacteristics
353
+ ) -> None:
330
354
  """Parse Python dependency files."""
331
355
  try:
332
- if deps_path.name == 'requirements.txt':
356
+ if deps_path.name == "requirements.txt":
333
357
  content = deps_path.read_text()
334
- deps = [line.strip().split('=')[0].split('>')[0].split('<')[0]
335
- for line in content.splitlines()
336
- if line.strip() and not line.startswith('#')]
337
- elif deps_path.name == 'pyproject.toml':
358
+ deps = [
359
+ line.strip().split("=")[0].split(">")[0].split("<")[0]
360
+ for line in content.splitlines()
361
+ if line.strip() and not line.startswith("#")
362
+ ]
363
+ elif deps_path.name == "pyproject.toml":
338
364
  try:
339
365
  import tomllib
340
366
  except ImportError:
341
367
  try:
342
368
  import tomli as tomllib
343
369
  except ImportError:
344
- self.logger.warning(f"TOML parsing not available for {deps_path}")
370
+ self.logger.warning(
371
+ f"TOML parsing not available for {deps_path}"
372
+ )
345
373
  return
346
- with open(deps_path, 'rb') as f:
374
+ with open(deps_path, "rb") as f:
347
375
  data = tomllib.load(f)
348
- deps = list(data.get('project', {}).get('dependencies', []))
349
- deps.extend(list(data.get('tool', {}).get('poetry', {}).get('dependencies', {}).keys()))
376
+ deps = list(data.get("project", {}).get("dependencies", []))
377
+ deps.extend(
378
+ list(
379
+ data.get("tool", {})
380
+ .get("poetry", {})
381
+ .get("dependencies", {})
382
+ .keys()
383
+ )
384
+ )
350
385
  else:
351
386
  return
352
-
387
+
353
388
  # Identify frameworks and tools
354
389
  for dep in deps:
355
390
  dep_lower = dep.lower()
356
-
391
+
357
392
  # Web frameworks
358
- if dep_lower in ['flask', 'django', 'fastapi', 'tornado']:
393
+ if dep_lower in ["flask", "django", "fastapi", "tornado"]:
359
394
  characteristics.web_frameworks.append(dep)
360
- elif dep_lower in ['pytest', 'unittest2', 'nose']:
395
+ elif dep_lower in ["pytest", "unittest2", "nose"]:
361
396
  if not characteristics.testing_framework:
362
397
  characteristics.testing_framework = dep
363
- elif any(db in dep_lower for db in ['psycopg2', 'mysql', 'sqlite', 'redis', 'mongo']):
398
+ elif any(
399
+ db in dep_lower
400
+ for db in ["psycopg2", "mysql", "sqlite", "redis", "mongo"]
401
+ ):
364
402
  characteristics.databases.append(dep)
365
-
403
+
366
404
  characteristics.key_dependencies.append(dep)
367
-
405
+
368
406
  except Exception as e:
369
407
  self.logger.warning(f"Error parsing Python dependencies: {e}")
370
-
371
- def _parse_cargo_toml(self, cargo_path: Path, characteristics: ProjectCharacteristics) -> None:
408
+
409
+ def _parse_cargo_toml(
410
+ self, cargo_path: Path, characteristics: ProjectCharacteristics
411
+ ) -> None:
372
412
  """Parse Cargo.toml for Rust project details."""
373
413
  try:
374
414
  try:
@@ -379,244 +419,309 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
379
419
  except ImportError:
380
420
  self.logger.warning(f"TOML parsing not available for {cargo_path}")
381
421
  return
382
- with open(cargo_path, 'rb') as f:
422
+ with open(cargo_path, "rb") as f:
383
423
  cargo_data = tomllib.load(f)
384
-
385
- deps = cargo_data.get('dependencies', {})
424
+
425
+ deps = cargo_data.get("dependencies", {})
386
426
  for dep_name in deps.keys():
387
427
  characteristics.key_dependencies.append(dep_name)
388
-
428
+
389
429
  # Identify common Rust frameworks
390
- if dep_name in ['actix-web', 'warp', 'rocket']:
430
+ if dep_name in ["actix-web", "warp", "rocket"]:
391
431
  characteristics.web_frameworks.append(dep_name)
392
- elif dep_name in ['tokio', 'async-std']:
432
+ elif dep_name in ["tokio", "async-std"]:
393
433
  characteristics.frameworks.append(dep_name)
394
-
434
+
395
435
  except Exception as e:
396
436
  self.logger.warning(f"Error parsing Cargo.toml: {e}")
397
-
398
- def _analyze_directory_structure(self, characteristics: ProjectCharacteristics) -> None:
437
+
438
+ def _analyze_directory_structure(
439
+ self, characteristics: ProjectCharacteristics
440
+ ) -> None:
399
441
  """Analyze directory structure for architecture patterns.
400
-
442
+
401
443
  WHY: Directory structure reveals architectural decisions and project
402
444
  organization patterns that agents should understand and follow.
403
-
445
+
404
446
  Args:
405
447
  characteristics: ProjectCharacteristics object to update
406
448
  """
407
449
  # Common important directories to look for
408
450
  important_dirs = [
409
- 'src', 'lib', 'app', 'components', 'services', 'models', 'views',
410
- 'controllers', 'routes', 'api', 'web', 'static', 'templates',
411
- 'tests', 'test', '__tests__', 'spec', 'docs', 'documentation',
412
- 'config', 'configs', 'settings', 'utils', 'helpers', 'core',
413
- 'modules', 'packages', 'plugins', 'extensions'
451
+ "src",
452
+ "lib",
453
+ "app",
454
+ "components",
455
+ "services",
456
+ "models",
457
+ "views",
458
+ "controllers",
459
+ "routes",
460
+ "api",
461
+ "web",
462
+ "static",
463
+ "templates",
464
+ "tests",
465
+ "test",
466
+ "__tests__",
467
+ "spec",
468
+ "docs",
469
+ "documentation",
470
+ "config",
471
+ "configs",
472
+ "settings",
473
+ "utils",
474
+ "helpers",
475
+ "core",
476
+ "modules",
477
+ "packages",
478
+ "plugins",
479
+ "extensions",
414
480
  ]
415
-
481
+
416
482
  # Check which directories exist
417
483
  existing_dirs = []
418
484
  for dir_name in important_dirs:
419
485
  dir_path = self.working_directory / dir_name
420
486
  if dir_path.exists() and dir_path.is_dir():
421
487
  existing_dirs.append(dir_name)
422
-
488
+
423
489
  # Special handling for certain directories
424
- if dir_name in ['src', 'lib', 'app']:
490
+ if dir_name in ["src", "lib", "app"]:
425
491
  # These are likely main module directories
426
- characteristics.main_modules.extend(self._get_subdirectories(dir_path))
427
-
492
+ characteristics.main_modules.extend(
493
+ self._get_subdirectories(dir_path)
494
+ )
495
+
428
496
  characteristics.key_directories = existing_dirs
429
-
497
+
430
498
  # Look for entry points
431
499
  entry_point_patterns = [
432
- 'main.py', 'app.py', 'server.py', 'index.js', 'main.js',
433
- 'app.js', 'server.js', 'main.rs', 'lib.rs', 'Main.java',
434
- 'main.go', 'index.php', 'application.rb'
500
+ "main.py",
501
+ "app.py",
502
+ "server.py",
503
+ "index.js",
504
+ "main.js",
505
+ "app.js",
506
+ "server.js",
507
+ "main.rs",
508
+ "lib.rs",
509
+ "Main.java",
510
+ "main.go",
511
+ "index.php",
512
+ "application.rb",
435
513
  ]
436
-
514
+
437
515
  for pattern in entry_point_patterns:
438
516
  entry_path = self.working_directory / pattern
439
517
  if entry_path.exists():
440
518
  characteristics.entry_points.append(pattern)
441
-
519
+
442
520
  # Also check in src/ directory
443
- src_entry_path = self.working_directory / 'src' / pattern
521
+ src_entry_path = self.working_directory / "src" / pattern
444
522
  if src_entry_path.exists():
445
- characteristics.entry_points.append(f'src/{pattern}')
446
-
523
+ characteristics.entry_points.append(f"src/{pattern}")
524
+
447
525
  def _get_subdirectories(self, path: Path, max_depth: int = 2) -> List[str]:
448
526
  """Get subdirectory names up to a certain depth."""
449
527
  subdirs = []
450
528
  try:
451
529
  for item in path.iterdir():
452
- if item.is_dir() and not item.name.startswith('.'):
530
+ if item.is_dir() and not item.name.startswith("."):
453
531
  subdirs.append(item.name)
454
532
  if max_depth > 1:
455
533
  for subitem in item.iterdir():
456
- if subitem.is_dir() and not subitem.name.startswith('.'):
534
+ if subitem.is_dir() and not subitem.name.startswith("."):
457
535
  subdirs.append(f"{item.name}/{subitem.name}")
458
536
  except PermissionError:
459
537
  pass
460
538
  return subdirs[:10] # Limit to prevent overwhelming output
461
-
539
+
462
540
  def _analyze_source_code(self, characteristics: ProjectCharacteristics) -> None:
463
541
  """Analyze source code files for patterns and conventions.
464
-
542
+
465
543
  WHY: Source code contains the actual implementation patterns that agents
466
544
  should understand and follow. This analysis extracts coding conventions
467
545
  and architectural patterns from the codebase.
468
-
546
+
469
547
  Args:
470
548
  characteristics: ProjectCharacteristics object to update
471
549
  """
472
550
  source_extensions = {
473
- '.py': 'python',
474
- '.js': 'javascript',
475
- '.ts': 'typescript',
476
- '.jsx': 'react',
477
- '.tsx': 'react',
478
- '.rs': 'rust',
479
- '.java': 'java',
480
- '.go': 'go',
481
- '.php': 'php',
482
- '.rb': 'ruby',
483
- '.cpp': 'cpp',
484
- '.cc': 'cpp',
485
- '.c': 'c'
551
+ ".py": "python",
552
+ ".js": "javascript",
553
+ ".ts": "typescript",
554
+ ".jsx": "react",
555
+ ".tsx": "react",
556
+ ".rs": "rust",
557
+ ".java": "java",
558
+ ".go": "go",
559
+ ".php": "php",
560
+ ".rb": "ruby",
561
+ ".cpp": "cpp",
562
+ ".cc": "cpp",
563
+ ".c": "c",
486
564
  }
487
-
565
+
488
566
  # Find source files
489
567
  source_files = []
490
568
  languages_found = set()
491
-
569
+
492
570
  for ext, lang in source_extensions.items():
493
- files = list(self.working_directory.rglob(f'*{ext}'))
571
+ files = list(self.working_directory.rglob(f"*{ext}"))
494
572
  # Filter out node_modules, .git, etc.
495
- files = [f for f in files if not any(part.startswith('.') or part == 'node_modules'
496
- for part in f.parts)]
573
+ files = [
574
+ f
575
+ for f in files
576
+ if not any(
577
+ part.startswith(".") or part == "node_modules" for part in f.parts
578
+ )
579
+ ]
497
580
  source_files.extend(files)
498
581
  if files:
499
582
  languages_found.add(lang)
500
-
583
+
501
584
  # Update languages found
502
- characteristics.languages.extend([lang for lang in languages_found
503
- if lang not in characteristics.languages])
504
-
585
+ characteristics.languages.extend(
586
+ [lang for lang in languages_found if lang not in characteristics.languages]
587
+ )
588
+
505
589
  # Analyze a sample of source files for patterns
506
590
  sample_files = source_files[:20] # Don't analyze too many files
507
-
591
+
508
592
  framework_mentions = Counter()
509
593
  pattern_mentions = Counter()
510
-
594
+
511
595
  for file_path in sample_files:
512
596
  try:
513
- content = file_path.read_text(encoding='utf-8', errors='ignore')
514
-
597
+ content = file_path.read_text(encoding="utf-8", errors="ignore")
598
+
515
599
  # Look for framework patterns
516
600
  for framework, patterns in self.FRAMEWORK_PATTERNS.items():
517
601
  if any(pattern in content for pattern in patterns):
518
602
  framework_mentions[framework] += 1
519
-
603
+
520
604
  # Look for database patterns
521
605
  for db, patterns in self.DATABASE_PATTERNS.items():
522
606
  if any(pattern in content for pattern in patterns):
523
607
  if db not in characteristics.databases:
524
608
  characteristics.databases.append(db)
525
-
609
+
526
610
  # Look for common patterns
527
- if 'class ' in content and 'def __init__' in content:
528
- pattern_mentions['object_oriented'] += 1
529
- if '@app.route' in content or 'app.get(' in content:
530
- pattern_mentions['web_routes'] += 1
531
- if 'async def' in content or 'async function' in content:
532
- pattern_mentions['async_programming'] += 1
533
- if 'import pytest' in content or 'describe(' in content:
534
- pattern_mentions['unit_testing'] += 1
535
-
611
+ if "class " in content and "def __init__" in content:
612
+ pattern_mentions["object_oriented"] += 1
613
+ if "@app.route" in content or "app.get(" in content:
614
+ pattern_mentions["web_routes"] += 1
615
+ if "async def" in content or "async function" in content:
616
+ pattern_mentions["async_programming"] += 1
617
+ if "import pytest" in content or "describe(" in content:
618
+ pattern_mentions["unit_testing"] += 1
619
+
536
620
  except Exception as e:
537
621
  self.logger.debug(f"Error analyzing {file_path}: {e}")
538
622
  continue
539
-
623
+
540
624
  # Add discovered frameworks
541
625
  for framework, count in framework_mentions.most_common(5):
542
626
  if framework not in characteristics.frameworks:
543
627
  characteristics.frameworks.append(framework)
544
-
628
+
545
629
  # Add coding conventions based on patterns found
546
630
  for pattern, count in pattern_mentions.most_common():
547
631
  if count >= 2: # Pattern appears in multiple files
548
- characteristics.code_conventions.append(pattern.replace('_', ' ').title())
549
-
632
+ characteristics.code_conventions.append(
633
+ pattern.replace("_", " ").title()
634
+ )
635
+
550
636
  def _analyze_dependencies(self, characteristics: ProjectCharacteristics) -> None:
551
637
  """Analyze dependencies for integration patterns.
552
-
638
+
553
639
  Args:
554
640
  characteristics: ProjectCharacteristics object to update
555
641
  """
556
642
  # This is partially covered by config file analysis
557
643
  # Here we can add more sophisticated dependency analysis
558
-
644
+
559
645
  # Look for common integration patterns in dependencies
560
646
  api_indicators = [
561
- 'requests', 'axios', 'fetch', 'http', 'urllib',
562
- 'rest', 'graphql', 'grpc', 'soap'
647
+ "requests",
648
+ "axios",
649
+ "fetch",
650
+ "http",
651
+ "urllib",
652
+ "rest",
653
+ "graphql",
654
+ "grpc",
655
+ "soap",
563
656
  ]
564
-
657
+
565
658
  for dep in characteristics.key_dependencies:
566
659
  dep_lower = dep.lower()
567
660
  for indicator in api_indicators:
568
661
  if indicator in dep_lower:
569
- if 'REST API' not in characteristics.api_patterns:
570
- characteristics.api_patterns.append('REST API')
662
+ if "REST API" not in characteristics.api_patterns:
663
+ characteristics.api_patterns.append("REST API")
571
664
  break
572
-
573
- def _analyze_testing_patterns(self, characteristics: ProjectCharacteristics) -> None:
665
+
666
+ def _analyze_testing_patterns(
667
+ self, characteristics: ProjectCharacteristics
668
+ ) -> None:
574
669
  """Analyze testing patterns and frameworks.
575
-
670
+
576
671
  Args:
577
672
  characteristics: ProjectCharacteristics object to update
578
673
  """
579
- test_dirs = ['tests', 'test', '__tests__', 'spec']
674
+ test_dirs = ["tests", "test", "__tests__", "spec"]
580
675
  test_patterns = []
581
-
676
+
582
677
  for test_dir in test_dirs:
583
678
  test_path = self.working_directory / test_dir
584
679
  if test_path.exists() and test_path.is_dir():
585
680
  test_patterns.append(f"Tests in /{test_dir}/ directory")
586
-
681
+
587
682
  # Look for test files to understand patterns
588
- test_files = list(test_path.rglob('*.py')) + list(test_path.rglob('*.js')) + list(test_path.rglob('*.ts'))
589
-
683
+ test_files = (
684
+ list(test_path.rglob("*.py"))
685
+ + list(test_path.rglob("*.js"))
686
+ + list(test_path.rglob("*.ts"))
687
+ )
688
+
590
689
  for test_file in test_files[:5]: # Sample a few test files
591
690
  try:
592
- content = test_file.read_text(encoding='utf-8', errors='ignore')
593
-
594
- if 'def test_' in content:
691
+ content = test_file.read_text(encoding="utf-8", errors="ignore")
692
+
693
+ if "def test_" in content:
595
694
  test_patterns.append("Python unittest pattern")
596
- if 'describe(' in content and 'it(' in content:
695
+ if "describe(" in content and "it(" in content:
597
696
  test_patterns.append("BDD test pattern")
598
- if '@pytest.fixture' in content:
697
+ if "@pytest.fixture" in content:
599
698
  test_patterns.append("pytest fixtures")
600
- if 'beforeEach(' in content or 'beforeAll(' in content:
699
+ if "beforeEach(" in content or "beforeAll(" in content:
601
700
  test_patterns.append("Setup/teardown patterns")
602
-
701
+
603
702
  except Exception:
604
703
  continue
605
-
704
+
606
705
  characteristics.test_patterns = list(set(test_patterns))
607
-
706
+
608
707
  def _analyze_documentation(self, characteristics: ProjectCharacteristics) -> None:
609
708
  """Analyze documentation files.
610
-
709
+
611
710
  Args:
612
711
  characteristics: ProjectCharacteristics object to update
613
712
  """
614
713
  doc_patterns = [
615
- 'README.md', 'README.rst', 'README.txt',
616
- 'CONTRIBUTING.md', 'CHANGELOG.md', 'HISTORY.md',
617
- 'docs/', 'documentation/', 'wiki/'
714
+ "README.md",
715
+ "README.rst",
716
+ "README.txt",
717
+ "CONTRIBUTING.md",
718
+ "CHANGELOG.md",
719
+ "HISTORY.md",
720
+ "docs/",
721
+ "documentation/",
722
+ "wiki/",
618
723
  ]
619
-
724
+
620
725
  doc_files = []
621
726
  for pattern in doc_patterns:
622
727
  doc_path = self.working_directory / pattern
@@ -625,214 +730,255 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
625
730
  doc_files.append(pattern)
626
731
  elif doc_path.is_dir():
627
732
  # Find markdown files in doc directories
628
- md_files = list(doc_path.rglob('*.md'))[:10]
629
- doc_files.extend([str(f.relative_to(self.working_directory)) for f in md_files])
630
-
733
+ md_files = list(doc_path.rglob("*.md"))[:10]
734
+ doc_files.extend(
735
+ [str(f.relative_to(self.working_directory)) for f in md_files]
736
+ )
737
+
631
738
  characteristics.documentation_files = doc_files
632
-
739
+
633
740
  def _infer_architecture_type(self, characteristics: ProjectCharacteristics) -> None:
634
741
  """Infer architecture type based on discovered patterns.
635
-
742
+
636
743
  Args:
637
744
  characteristics: ProjectCharacteristics object to update
638
745
  """
639
746
  # Simple architecture inference based on patterns
640
- if any(fw in characteristics.web_frameworks for fw in ['flask', 'django', 'express', 'fastapi']):
641
- if 'api' in characteristics.key_directories:
747
+ if any(
748
+ fw in characteristics.web_frameworks
749
+ for fw in ["flask", "django", "express", "fastapi"]
750
+ ):
751
+ if "api" in characteristics.key_directories:
642
752
  characteristics.architecture_type = "REST API Service"
643
753
  else:
644
754
  characteristics.architecture_type = "Web Application"
645
- elif 'services' in characteristics.key_directories:
755
+ elif "services" in characteristics.key_directories:
646
756
  characteristics.architecture_type = "Service-Oriented Architecture"
647
- elif 'modules' in characteristics.key_directories or 'packages' in characteristics.key_directories:
757
+ elif (
758
+ "modules" in characteristics.key_directories
759
+ or "packages" in characteristics.key_directories
760
+ ):
648
761
  characteristics.architecture_type = "Modular Architecture"
649
- elif characteristics.primary_language == 'python' and 'cli' in characteristics.main_modules:
762
+ elif (
763
+ characteristics.primary_language == "python"
764
+ and "cli" in characteristics.main_modules
765
+ ):
650
766
  characteristics.architecture_type = "CLI Application"
651
- elif any('react' in fw.lower() for fw in characteristics.frameworks):
767
+ elif any("react" in fw.lower() for fw in characteristics.frameworks):
652
768
  characteristics.architecture_type = "Single Page Application"
653
769
  else:
654
770
  characteristics.architecture_type = "Standard Application"
655
-
656
- def _extract_project_terminology(self, characteristics: ProjectCharacteristics) -> None:
771
+
772
+ def _extract_project_terminology(
773
+ self, characteristics: ProjectCharacteristics
774
+ ) -> None:
657
775
  """Extract project-specific terminology from various sources.
658
-
776
+
659
777
  WHY: Projects often have domain-specific terminology that agents should
660
778
  understand and use consistently.
661
-
779
+
662
780
  Args:
663
781
  characteristics: ProjectCharacteristics object to update
664
782
  """
665
783
  terminology = set()
666
-
784
+
667
785
  # Extract from project name
668
- project_words = re.findall(r'[A-Z][a-z]+|[a-z]+', characteristics.project_name)
786
+ project_words = re.findall(r"[A-Z][a-z]+|[a-z]+", characteristics.project_name)
669
787
  terminology.update(project_words)
670
-
788
+
671
789
  # Extract from directory names
672
790
  for dir_name in characteristics.key_directories:
673
- words = re.findall(r'[A-Z][a-z]+|[a-z]+', dir_name)
791
+ words = re.findall(r"[A-Z][a-z]+|[a-z]+", dir_name)
674
792
  terminology.update(words)
675
-
793
+
676
794
  # Extract from main modules
677
795
  for module in characteristics.main_modules:
678
- words = re.findall(r'[A-Z][a-z]+|[a-z]+', module)
796
+ words = re.findall(r"[A-Z][a-z]+|[a-z]+", module)
679
797
  terminology.update(words)
680
-
798
+
681
799
  # Filter out common words and keep domain-specific terms
682
800
  common_words = {
683
- 'src', 'lib', 'app', 'main', 'test', 'tests', 'docs', 'config',
684
- 'utils', 'helpers', 'core', 'base', 'common', 'shared', 'public',
685
- 'private', 'static', 'assets', 'build', 'dist', 'node', 'modules'
801
+ "src",
802
+ "lib",
803
+ "app",
804
+ "main",
805
+ "test",
806
+ "tests",
807
+ "docs",
808
+ "config",
809
+ "utils",
810
+ "helpers",
811
+ "core",
812
+ "base",
813
+ "common",
814
+ "shared",
815
+ "public",
816
+ "private",
817
+ "static",
818
+ "assets",
819
+ "build",
820
+ "dist",
821
+ "node",
822
+ "modules",
686
823
  }
687
-
688
- domain_terms = [term for term in terminology
689
- if len(term) > 3 and term.lower() not in common_words]
690
-
691
- characteristics.project_terminology = list(set(domain_terms))[:10] # Limit to most relevant
692
-
824
+
825
+ domain_terms = [
826
+ term
827
+ for term in terminology
828
+ if len(term) > 3 and term.lower() not in common_words
829
+ ]
830
+
831
+ characteristics.project_terminology = list(set(domain_terms))[
832
+ :10
833
+ ] # Limit to most relevant
834
+
693
835
  def get_project_context_summary(self) -> str:
694
836
  """Get a concise summary of project context for memory templates.
695
-
837
+
696
838
  WHY: Provides a formatted summary specifically designed for inclusion
697
839
  in agent memory templates, focusing on the most relevant characteristics.
698
-
840
+
699
841
  Returns:
700
842
  str: Formatted project context summary
701
843
  """
702
844
  characteristics = self.analyze_project()
703
-
845
+
704
846
  summary_parts = []
705
-
847
+
706
848
  # Basic project info
707
849
  lang_info = characteristics.primary_language or "mixed"
708
850
  if characteristics.languages and len(characteristics.languages) > 1:
709
- lang_info = f"{lang_info} (with {', '.join(characteristics.languages[1:3])})"
710
-
711
- summary_parts.append(f"{characteristics.project_name}: {lang_info} {characteristics.architecture_type.lower()}")
712
-
851
+ lang_info = (
852
+ f"{lang_info} (with {', '.join(characteristics.languages[1:3])})"
853
+ )
854
+
855
+ summary_parts.append(
856
+ f"{characteristics.project_name}: {lang_info} {characteristics.architecture_type.lower()}"
857
+ )
858
+
713
859
  # Key directories and modules
714
860
  if characteristics.main_modules:
715
861
  modules_str = ", ".join(characteristics.main_modules[:4])
716
862
  summary_parts.append(f"- Main modules: {modules_str}")
717
-
863
+
718
864
  # Frameworks and tools
719
865
  if characteristics.frameworks or characteristics.web_frameworks:
720
866
  all_frameworks = characteristics.frameworks + characteristics.web_frameworks
721
867
  frameworks_str = ", ".join(all_frameworks[:3])
722
868
  summary_parts.append(f"- Uses: {frameworks_str}")
723
-
869
+
724
870
  # Testing
725
871
  if characteristics.testing_framework:
726
872
  summary_parts.append(f"- Testing: {characteristics.testing_framework}")
727
873
  elif characteristics.test_patterns:
728
874
  summary_parts.append(f"- Testing: {characteristics.test_patterns[0]}")
729
-
875
+
730
876
  # Key patterns
731
877
  if characteristics.code_conventions:
732
878
  patterns_str = ", ".join(characteristics.code_conventions[:2])
733
879
  summary_parts.append(f"- Key patterns: {patterns_str}")
734
-
880
+
735
881
  return "\n".join(summary_parts)
736
-
882
+
737
883
  def get_important_files_for_context(self) -> List[str]:
738
884
  """Get list of important files that should be considered for memory context.
739
-
885
+
740
886
  WHY: Instead of hardcoding which files to analyze for memory creation,
741
887
  this method dynamically determines the most relevant files based on
742
888
  the actual project structure.
743
-
889
+
744
890
  Returns:
745
891
  List[str]: List of file paths relative to project root
746
892
  """
747
893
  characteristics = self.analyze_project()
748
894
  important_files = []
749
-
895
+
750
896
  # Always include standard documentation
751
- standard_docs = ['README.md', 'CONTRIBUTING.md', 'CHANGELOG.md']
897
+ standard_docs = ["README.md", "CONTRIBUTING.md", "CHANGELOG.md"]
752
898
  for doc in standard_docs:
753
899
  if (self.working_directory / doc).exists():
754
900
  important_files.append(doc)
755
-
901
+
756
902
  # Include configuration files
757
903
  important_files.extend(characteristics.important_configs)
758
-
904
+
759
905
  # Include project-specific documentation
760
906
  important_files.extend(characteristics.documentation_files[:5])
761
-
907
+
762
908
  # Include entry points
763
909
  important_files.extend(characteristics.entry_points)
764
-
910
+
765
911
  # Look for architecture documentation
766
- arch_patterns = ['ARCHITECTURE.md', 'docs/architecture.md', 'docs/STRUCTURE.md']
912
+ arch_patterns = ["ARCHITECTURE.md", "docs/architecture.md", "docs/STRUCTURE.md"]
767
913
  for pattern in arch_patterns:
768
914
  if (self.working_directory / pattern).exists():
769
915
  important_files.append(pattern)
770
-
916
+
771
917
  # Remove duplicates and return
772
918
  return list(set(important_files))
773
-
919
+
774
920
  # ================================================================================
775
921
  # Interface Adapter Methods
776
922
  # ================================================================================
777
923
  # These methods adapt the existing implementation to comply with ProjectAnalyzerInterface
778
-
924
+
779
925
  def detect_technology_stack(self) -> List[str]:
780
926
  """Detect technologies used in the project.
781
-
927
+
782
928
  WHY: This adapter method provides interface compliance by extracting
783
929
  technology information from the analyzed project characteristics.
784
-
930
+
785
931
  Returns:
786
932
  List of detected technologies
787
933
  """
788
934
  characteristics = self.analyze_project()
789
-
935
+
790
936
  technologies = []
791
937
  technologies.extend(characteristics.languages)
792
938
  technologies.extend(characteristics.frameworks)
793
939
  technologies.extend(characteristics.web_frameworks)
794
940
  technologies.extend(characteristics.databases)
795
-
941
+
796
942
  # Add package manager as technology
797
943
  if characteristics.package_manager:
798
944
  technologies.append(characteristics.package_manager)
799
-
945
+
800
946
  # Add build tools
801
947
  technologies.extend(characteristics.build_tools)
802
-
948
+
803
949
  # Remove duplicates
804
950
  return list(set(technologies))
805
-
951
+
806
952
  def analyze_code_patterns(self) -> Dict[str, Any]:
807
953
  """Analyze code patterns and conventions.
808
-
954
+
809
955
  WHY: This adapter method provides interface compliance by extracting
810
956
  pattern information from the project characteristics.
811
-
957
+
812
958
  Returns:
813
959
  Dictionary of pattern analysis results
814
960
  """
815
961
  characteristics = self.analyze_project()
816
-
962
+
817
963
  return {
818
964
  "code_conventions": characteristics.code_conventions,
819
965
  "test_patterns": characteristics.test_patterns,
820
966
  "api_patterns": characteristics.api_patterns,
821
967
  "configuration_patterns": characteristics.configuration_patterns,
822
- "architecture_type": characteristics.architecture_type
968
+ "architecture_type": characteristics.architecture_type,
823
969
  }
824
-
970
+
825
971
  def get_project_structure(self) -> Dict[str, Any]:
826
972
  """Get project directory structure analysis.
827
-
973
+
828
974
  WHY: This adapter method provides interface compliance by organizing
829
975
  structural information from the project characteristics.
830
-
976
+
831
977
  Returns:
832
978
  Dictionary representing project structure
833
979
  """
834
980
  characteristics = self.analyze_project()
835
-
981
+
836
982
  return {
837
983
  "project_name": characteristics.project_name,
838
984
  "main_modules": characteristics.main_modules,
@@ -840,25 +986,25 @@ class ProjectAnalyzer(ProjectAnalyzerInterface):
840
986
  "entry_points": characteristics.entry_points,
841
987
  "documentation_files": characteristics.documentation_files,
842
988
  "important_configs": characteristics.important_configs,
843
- "architecture_type": characteristics.architecture_type
989
+ "architecture_type": characteristics.architecture_type,
844
990
  }
845
-
991
+
846
992
  def identify_entry_points(self) -> List[Path]:
847
993
  """Identify project entry points.
848
-
994
+
849
995
  WHY: This adapter method provides interface compliance by converting
850
996
  string entry points to Path objects as expected by the interface.
851
-
997
+
852
998
  Returns:
853
999
  List of entry point paths
854
1000
  """
855
1001
  characteristics = self.analyze_project()
856
-
1002
+
857
1003
  # Convert string paths to Path objects
858
1004
  entry_paths = []
859
1005
  for entry_point in characteristics.entry_points:
860
1006
  entry_path = self.working_directory / entry_point
861
1007
  if entry_path.exists():
862
1008
  entry_paths.append(entry_path)
863
-
864
- return entry_paths
1009
+
1010
+ return entry_paths