claude-mpm 4.20.3__py3-none-any.whl → 5.1.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (520) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +35 -6
  3. claude_mpm/agents/OUTPUT_STYLE.md +3 -48
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +1241 -667
  5. claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +1322 -0
  6. claude_mpm/agents/WORKFLOW.md +75 -2
  7. claude_mpm/agents/__init__.py +6 -0
  8. claude_mpm/agents/agent_loader.py +1 -4
  9. claude_mpm/agents/base_agent.json +6 -3
  10. claude_mpm/agents/base_agent_loader.py +10 -35
  11. claude_mpm/agents/frontmatter_validator.py +1 -1
  12. claude_mpm/agents/templates/circuit-breakers.md +1254 -0
  13. claude_mpm/agents/templates/context-management-examples.md +544 -0
  14. claude_mpm/agents/templates/{pm_red_flags.md → pm-red-flags.md} +89 -19
  15. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  16. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  17. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  18. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  19. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  20. claude_mpm/cli/__init__.py +37 -2
  21. claude_mpm/cli/commands/__init__.py +2 -0
  22. claude_mpm/cli/commands/agent_source.py +774 -0
  23. claude_mpm/cli/commands/agent_state_manager.py +188 -30
  24. claude_mpm/cli/commands/agents.py +959 -36
  25. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  26. claude_mpm/cli/commands/agents_discover.py +338 -0
  27. claude_mpm/cli/commands/aggregate.py +1 -1
  28. claude_mpm/cli/commands/analyze.py +3 -3
  29. claude_mpm/cli/commands/auto_configure.py +537 -239
  30. claude_mpm/cli/commands/cleanup.py +1 -1
  31. claude_mpm/cli/commands/config.py +7 -4
  32. claude_mpm/cli/commands/configure.py +924 -45
  33. claude_mpm/cli/commands/configure_agent_display.py +4 -4
  34. claude_mpm/cli/commands/configure_navigation.py +63 -46
  35. claude_mpm/cli/commands/debug.py +12 -12
  36. claude_mpm/cli/commands/doctor.py +10 -2
  37. claude_mpm/cli/commands/hook_errors.py +277 -0
  38. claude_mpm/cli/commands/local_deploy.py +1 -4
  39. claude_mpm/cli/commands/mcp_install_commands.py +1 -1
  40. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  41. claude_mpm/cli/commands/mpm_init/core.py +573 -0
  42. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  43. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  44. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  45. claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
  46. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  47. claude_mpm/cli/commands/mpm_init_handler.py +67 -1
  48. claude_mpm/cli/commands/postmortem.py +401 -0
  49. claude_mpm/cli/commands/run.py +125 -167
  50. claude_mpm/cli/commands/skill_source.py +694 -0
  51. claude_mpm/cli/commands/skills.py +835 -44
  52. claude_mpm/cli/executor.py +78 -3
  53. claude_mpm/cli/interactive/agent_wizard.py +1032 -47
  54. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  55. claude_mpm/cli/parsers/agents_parser.py +256 -4
  56. claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
  57. claude_mpm/cli/parsers/base_parser.py +53 -0
  58. claude_mpm/cli/parsers/config_parser.py +96 -43
  59. claude_mpm/cli/parsers/mpm_init_parser.py +42 -0
  60. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  61. claude_mpm/cli/parsers/skills_parser.py +145 -0
  62. claude_mpm/cli/parsers/source_parser.py +138 -0
  63. claude_mpm/cli/startup.py +564 -108
  64. claude_mpm/cli/startup_display.py +480 -0
  65. claude_mpm/cli/utils.py +1 -1
  66. claude_mpm/cli_module/commands.py +1 -1
  67. claude_mpm/commands/{mpm-auto-configure.md → mpm-agents-auto-configure.md} +9 -0
  68. claude_mpm/commands/mpm-agents-detect.md +9 -0
  69. claude_mpm/commands/{mpm-agents.md → mpm-agents-list.md} +9 -0
  70. claude_mpm/commands/mpm-agents-recommend.md +9 -0
  71. claude_mpm/commands/{mpm-config.md → mpm-config-view.md} +9 -0
  72. claude_mpm/commands/mpm-doctor.md +9 -0
  73. claude_mpm/commands/mpm-help.md +17 -2
  74. claude_mpm/commands/mpm-init.md +28 -3
  75. claude_mpm/commands/mpm-monitor.md +9 -0
  76. claude_mpm/commands/mpm-postmortem.md +123 -0
  77. claude_mpm/commands/mpm-session-resume.md +381 -0
  78. claude_mpm/commands/mpm-status.md +9 -0
  79. claude_mpm/commands/{mpm-organize.md → mpm-ticket-organize.md} +9 -0
  80. claude_mpm/commands/mpm-ticket-view.md +552 -0
  81. claude_mpm/commands/mpm-version.md +9 -0
  82. claude_mpm/commands/mpm.md +11 -0
  83. claude_mpm/config/agent_presets.py +488 -0
  84. claude_mpm/config/agent_sources.py +325 -0
  85. claude_mpm/config/skill_presets.py +392 -0
  86. claude_mpm/config/skill_sources.py +590 -0
  87. claude_mpm/constants.py +13 -0
  88. claude_mpm/core/api_validator.py +1 -1
  89. claude_mpm/core/claude_runner.py +19 -35
  90. claude_mpm/core/config.py +24 -0
  91. claude_mpm/core/constants.py +1 -1
  92. claude_mpm/core/framework/__init__.py +3 -16
  93. claude_mpm/core/framework/loaders/file_loader.py +54 -101
  94. claude_mpm/core/framework/loaders/instruction_loader.py +25 -5
  95. claude_mpm/core/framework/processors/metadata_processor.py +1 -1
  96. claude_mpm/core/hook_error_memory.py +381 -0
  97. claude_mpm/core/hook_manager.py +41 -2
  98. claude_mpm/core/interactive_session.py +131 -10
  99. claude_mpm/core/interfaces.py +56 -1
  100. claude_mpm/core/logger.py +3 -1
  101. claude_mpm/core/oneshot_session.py +110 -8
  102. claude_mpm/core/protocols/__init__.py +23 -0
  103. claude_mpm/core/protocols/runner_protocol.py +103 -0
  104. claude_mpm/core/protocols/session_protocol.py +131 -0
  105. claude_mpm/core/shared/singleton_manager.py +11 -4
  106. claude_mpm/core/system_context.py +38 -0
  107. claude_mpm/core/unified_config.py +22 -0
  108. claude_mpm/dashboard/static/css/activity.css +69 -69
  109. claude_mpm/dashboard/static/css/connection-status.css +10 -10
  110. claude_mpm/dashboard/static/css/dashboard.css +15 -15
  111. claude_mpm/dashboard/static/js/components/activity-tree.js +178 -178
  112. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +101 -101
  113. claude_mpm/dashboard/static/js/components/agent-inference.js +31 -31
  114. claude_mpm/dashboard/static/js/components/build-tracker.js +59 -59
  115. claude_mpm/dashboard/static/js/components/code-simple.js +107 -107
  116. claude_mpm/dashboard/static/js/components/connection-debug.js +101 -101
  117. claude_mpm/dashboard/static/js/components/diff-viewer.js +113 -113
  118. claude_mpm/dashboard/static/js/components/event-viewer.js +12 -12
  119. claude_mpm/dashboard/static/js/components/file-change-tracker.js +57 -57
  120. claude_mpm/dashboard/static/js/components/file-change-viewer.js +74 -74
  121. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +6 -6
  122. claude_mpm/dashboard/static/js/components/file-viewer.js +42 -42
  123. claude_mpm/dashboard/static/js/components/module-viewer.js +27 -27
  124. claude_mpm/dashboard/static/js/components/session-manager.js +14 -14
  125. claude_mpm/dashboard/static/js/components/socket-manager.js +1 -1
  126. claude_mpm/dashboard/static/js/components/ui-state-manager.js +14 -14
  127. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +110 -110
  128. claude_mpm/dashboard/static/js/components/working-directory.js +8 -8
  129. claude_mpm/dashboard/static/js/connection-manager.js +76 -76
  130. claude_mpm/dashboard/static/js/dashboard.js +76 -58
  131. claude_mpm/dashboard/static/js/extension-error-handler.js +22 -22
  132. claude_mpm/dashboard/static/js/socket-client.js +138 -121
  133. claude_mpm/dashboard/templates/code_simple.html +23 -23
  134. claude_mpm/dashboard/templates/index.html +18 -18
  135. claude_mpm/experimental/cli_enhancements.py +1 -5
  136. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  137. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  138. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  139. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  140. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  141. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  142. claude_mpm/hooks/claude_hooks/event_handlers.py +3 -1
  143. claude_mpm/hooks/claude_hooks/hook_handler.py +24 -7
  144. claude_mpm/hooks/claude_hooks/installer.py +45 -0
  145. claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
  146. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  147. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  148. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  149. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  150. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  151. claude_mpm/hooks/failure_learning/__init__.py +2 -8
  152. claude_mpm/hooks/failure_learning/failure_detection_hook.py +1 -6
  153. claude_mpm/hooks/failure_learning/fix_detection_hook.py +1 -6
  154. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +1 -6
  155. claude_mpm/hooks/kuzu_response_hook.py +1 -5
  156. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  157. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  158. claude_mpm/models/git_repository.py +198 -0
  159. claude_mpm/scripts/claude-hook-handler.sh +3 -3
  160. claude_mpm/scripts/start_activity_logging.py +3 -1
  161. claude_mpm/services/agents/agent_builder.py +45 -9
  162. claude_mpm/services/agents/agent_preset_service.py +238 -0
  163. claude_mpm/services/agents/agent_selection_service.py +484 -0
  164. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  165. claude_mpm/services/agents/cache_git_manager.py +621 -0
  166. claude_mpm/services/agents/deployment/agent_deployment.py +126 -2
  167. claude_mpm/services/agents/deployment/agent_discovery_service.py +105 -73
  168. claude_mpm/services/agents/deployment/agent_format_converter.py +1 -1
  169. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -5
  170. claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
  171. claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
  172. claude_mpm/services/agents/deployment/agent_template_builder.py +236 -15
  173. claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
  174. claude_mpm/services/agents/deployment/async_agent_deployment.py +2 -1
  175. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
  176. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +115 -15
  177. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
  178. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +1 -4
  179. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +363 -0
  180. claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
  181. claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -46
  182. claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
  183. claude_mpm/services/agents/git_source_manager.py +629 -0
  184. claude_mpm/services/agents/loading/framework_agent_loader.py +9 -12
  185. claude_mpm/services/agents/local_template_manager.py +50 -10
  186. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  187. claude_mpm/services/agents/sources/__init__.py +13 -0
  188. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  189. claude_mpm/services/agents/sources/git_source_sync_service.py +1087 -0
  190. claude_mpm/services/agents/startup_sync.py +239 -0
  191. claude_mpm/services/agents/toolchain_detector.py +474 -0
  192. claude_mpm/services/analysis/__init__.py +25 -0
  193. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  194. claude_mpm/services/analysis/postmortem_service.py +765 -0
  195. claude_mpm/services/cli/session_pause_manager.py +504 -0
  196. claude_mpm/services/cli/session_resume_helper.py +36 -16
  197. claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
  198. claude_mpm/services/command_deployment_service.py +200 -6
  199. claude_mpm/services/core/base.py +31 -11
  200. claude_mpm/services/core/interfaces/__init__.py +1 -3
  201. claude_mpm/services/core/interfaces/health.py +1 -4
  202. claude_mpm/services/core/interfaces.py +56 -1
  203. claude_mpm/services/core/models/__init__.py +2 -11
  204. claude_mpm/services/core/models/agent_config.py +3 -0
  205. claude_mpm/services/core/models/process.py +4 -0
  206. claude_mpm/services/diagnostics/checks/__init__.py +4 -0
  207. claude_mpm/services/diagnostics/checks/agent_check.py +0 -2
  208. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  209. claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
  210. claude_mpm/services/diagnostics/checks/mcp_check.py +0 -1
  211. claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
  212. claude_mpm/services/diagnostics/checks/monitor_check.py +0 -1
  213. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  214. claude_mpm/services/diagnostics/diagnostic_runner.py +9 -0
  215. claude_mpm/services/diagnostics/doctor_reporter.py +40 -10
  216. claude_mpm/services/diagnostics/models.py +21 -0
  217. claude_mpm/services/event_bus/direct_relay.py +3 -3
  218. claude_mpm/services/event_bus/event_bus.py +36 -3
  219. claude_mpm/services/event_bus/relay.py +23 -7
  220. claude_mpm/services/events/consumers/logging.py +1 -2
  221. claude_mpm/services/git/__init__.py +21 -0
  222. claude_mpm/services/git/git_operations_service.py +494 -0
  223. claude_mpm/services/github/__init__.py +21 -0
  224. claude_mpm/services/github/github_cli_service.py +397 -0
  225. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -5
  226. claude_mpm/services/infrastructure/monitoring/aggregator.py +1 -6
  227. claude_mpm/services/infrastructure/monitoring/resources.py +1 -1
  228. claude_mpm/services/instructions/__init__.py +9 -0
  229. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  230. claude_mpm/services/local_ops/__init__.py +5 -13
  231. claude_mpm/services/local_ops/health_checks/__init__.py +1 -3
  232. claude_mpm/services/local_ops/health_manager.py +1 -4
  233. claude_mpm/services/local_ops/process_manager.py +1 -1
  234. claude_mpm/services/local_ops/resource_monitor.py +2 -2
  235. claude_mpm/services/mcp_config_manager.py +75 -145
  236. claude_mpm/services/mcp_gateway/auto_configure.py +31 -25
  237. claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
  238. claude_mpm/services/mcp_gateway/core/process_pool.py +41 -26
  239. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +1 -6
  240. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -2
  241. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
  242. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +26 -21
  243. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +6 -2
  244. claude_mpm/services/mcp_service_verifier.py +6 -3
  245. claude_mpm/services/memory/failure_tracker.py +19 -4
  246. claude_mpm/services/memory/optimizer.py +1 -1
  247. claude_mpm/services/model/model_router.py +8 -9
  248. claude_mpm/services/monitor/daemon.py +29 -9
  249. claude_mpm/services/monitor/daemon_manager.py +96 -19
  250. claude_mpm/services/monitor/server.py +2 -2
  251. claude_mpm/services/native_agent_converter.py +356 -0
  252. claude_mpm/services/port_manager.py +1 -1
  253. claude_mpm/services/pr/__init__.py +14 -0
  254. claude_mpm/services/pr/pr_template_service.py +329 -0
  255. claude_mpm/services/project/documentation_manager.py +2 -1
  256. claude_mpm/services/project/project_organizer.py +4 -0
  257. claude_mpm/services/project/toolchain_analyzer.py +3 -1
  258. claude_mpm/services/runner_configuration_service.py +17 -3
  259. claude_mpm/services/self_upgrade_service.py +165 -7
  260. claude_mpm/services/session_management_service.py +16 -4
  261. claude_mpm/services/skills/__init__.py +18 -0
  262. claude_mpm/services/skills/git_skill_source_manager.py +1169 -0
  263. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  264. claude_mpm/services/skills_config.py +547 -0
  265. claude_mpm/services/skills_deployer.py +955 -0
  266. claude_mpm/services/socketio/handlers/connection.py +1 -1
  267. claude_mpm/services/socketio/handlers/git.py +2 -2
  268. claude_mpm/services/socketio/server/core.py +1 -4
  269. claude_mpm/services/socketio/server/main.py +1 -3
  270. claude_mpm/services/system_instructions_service.py +1 -3
  271. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +0 -3
  272. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +0 -1
  273. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +1 -1
  274. claude_mpm/services/unified/deployment_strategies/vercel.py +1 -5
  275. claude_mpm/services/unified/unified_deployment.py +1 -5
  276. claude_mpm/services/version_control/conflict_resolution.py +6 -4
  277. claude_mpm/services/visualization/__init__.py +1 -5
  278. claude_mpm/services/visualization/mermaid_generator.py +2 -3
  279. claude_mpm/skills/__init__.py +3 -3
  280. claude_mpm/skills/agent_skills_injector.py +42 -49
  281. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  282. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +17 -10
  283. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +92 -39
  284. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +13 -12
  285. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +5 -3
  286. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +19 -12
  287. claude_mpm/skills/bundled/performance-profiling.md +6 -0
  288. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +6 -6
  289. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +13 -9
  290. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +8 -8
  291. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +37 -15
  292. claude_mpm/skills/skills_registry.py +44 -48
  293. claude_mpm/skills/skills_service.py +117 -108
  294. claude_mpm/templates/questions/__init__.py +38 -0
  295. claude_mpm/templates/questions/base.py +193 -0
  296. claude_mpm/templates/questions/pr_strategy.py +311 -0
  297. claude_mpm/templates/questions/project_init.py +385 -0
  298. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  299. claude_mpm/tools/__main__.py +8 -8
  300. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  301. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  302. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  303. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  304. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  305. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  306. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  307. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  308. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  309. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  310. claude_mpm/utils/agent_dependency_loader.py +80 -13
  311. claude_mpm/utils/agent_filters.py +288 -0
  312. claude_mpm/utils/dependency_cache.py +3 -1
  313. claude_mpm/utils/gitignore.py +244 -0
  314. claude_mpm/utils/log_cleanup.py +3 -3
  315. claude_mpm/utils/migration.py +372 -0
  316. claude_mpm/utils/progress.py +387 -0
  317. claude_mpm/utils/robust_installer.py +3 -5
  318. claude_mpm/utils/structured_questions.py +619 -0
  319. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/METADATA +496 -65
  320. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/RECORD +328 -416
  321. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -17
  322. claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +0 -3
  323. claude_mpm/agents/templates/agent-manager.json +0 -273
  324. claude_mpm/agents/templates/agentic-coder-optimizer.json +0 -248
  325. claude_mpm/agents/templates/api_qa.json +0 -180
  326. claude_mpm/agents/templates/circuit_breakers.md +0 -638
  327. claude_mpm/agents/templates/clerk-ops.json +0 -235
  328. claude_mpm/agents/templates/code_analyzer.json +0 -101
  329. claude_mpm/agents/templates/content-agent.json +0 -358
  330. claude_mpm/agents/templates/dart_engineer.json +0 -307
  331. claude_mpm/agents/templates/data_engineer.json +0 -225
  332. claude_mpm/agents/templates/documentation.json +0 -211
  333. claude_mpm/agents/templates/engineer.json +0 -210
  334. claude_mpm/agents/templates/gcp_ops_agent.json +0 -253
  335. claude_mpm/agents/templates/golang_engineer.json +0 -270
  336. claude_mpm/agents/templates/imagemagick.json +0 -264
  337. claude_mpm/agents/templates/java_engineer.json +0 -346
  338. claude_mpm/agents/templates/local_ops_agent.json +0 -1840
  339. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
  340. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md +0 -400
  341. claude_mpm/agents/templates/memory_manager.json +0 -158
  342. claude_mpm/agents/templates/nextjs_engineer.json +0 -285
  343. claude_mpm/agents/templates/ops.json +0 -185
  344. claude_mpm/agents/templates/php-engineer.json +0 -281
  345. claude_mpm/agents/templates/product_owner.json +0 -338
  346. claude_mpm/agents/templates/project_organizer.json +0 -140
  347. claude_mpm/agents/templates/prompt-engineer.json +0 -737
  348. claude_mpm/agents/templates/python_engineer.json +0 -387
  349. claude_mpm/agents/templates/qa.json +0 -242
  350. claude_mpm/agents/templates/react_engineer.json +0 -238
  351. claude_mpm/agents/templates/refactoring_engineer.json +0 -276
  352. claude_mpm/agents/templates/research.json +0 -188
  353. claude_mpm/agents/templates/ruby-engineer.json +0 -280
  354. claude_mpm/agents/templates/rust_engineer.json +0 -275
  355. claude_mpm/agents/templates/security.json +0 -202
  356. claude_mpm/agents/templates/svelte-engineer.json +0 -225
  357. claude_mpm/agents/templates/ticketing.json +0 -177
  358. claude_mpm/agents/templates/typescript_engineer.json +0 -285
  359. claude_mpm/agents/templates/vercel_ops_agent.json +0 -412
  360. claude_mpm/agents/templates/version_control.json +0 -157
  361. claude_mpm/agents/templates/web_qa.json +0 -399
  362. claude_mpm/agents/templates/web_ui.json +0 -189
  363. claude_mpm/cli/commands/mpm_init.py +0 -2093
  364. claude_mpm/commands/mpm-tickets.md +0 -102
  365. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
  366. claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +0 -188
  367. claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +0 -156
  368. claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +0 -38
  369. claude_mpm/dashboard/react/components/shared/FilterBar.module.css +0 -92
  370. claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +0 -248
  371. claude_mpm/dashboard/static/archive/activity_dashboard_test.html +0 -61
  372. claude_mpm/dashboard/static/archive/test_activity_connection.html +0 -179
  373. claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +0 -68
  374. claude_mpm/dashboard/static/archive/test_dashboard.html +0 -409
  375. claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +0 -519
  376. claude_mpm/dashboard/static/archive/test_dashboard_verification.html +0 -181
  377. claude_mpm/dashboard/static/archive/test_file_data.html +0 -315
  378. claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +0 -243
  379. claude_mpm/dashboard/static/archive/test_file_tree_fix.html +0 -234
  380. claude_mpm/dashboard/static/archive/test_file_tree_rename.html +0 -117
  381. claude_mpm/dashboard/static/archive/test_file_tree_tab.html +0 -115
  382. claude_mpm/dashboard/static/archive/test_file_viewer.html +0 -224
  383. claude_mpm/dashboard/static/archive/test_final_activity.html +0 -220
  384. claude_mpm/dashboard/static/archive/test_tab_fix.html +0 -139
  385. claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +0 -1
  386. claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
  387. claude_mpm/dashboard/static/built/components/agent-hierarchy.js +0 -777
  388. claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
  389. claude_mpm/dashboard/static/built/components/build-tracker.js +0 -333
  390. claude_mpm/dashboard/static/built/components/code-simple.js +0 -857
  391. claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +0 -353
  392. claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +0 -235
  393. claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +0 -409
  394. claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +0 -435
  395. claude_mpm/dashboard/static/built/components/code-tree.js +0 -2
  396. claude_mpm/dashboard/static/built/components/code-viewer.js +0 -2
  397. claude_mpm/dashboard/static/built/components/connection-debug.js +0 -654
  398. claude_mpm/dashboard/static/built/components/diff-viewer.js +0 -891
  399. claude_mpm/dashboard/static/built/components/event-processor.js +0 -2
  400. claude_mpm/dashboard/static/built/components/event-viewer.js +0 -2
  401. claude_mpm/dashboard/static/built/components/export-manager.js +0 -2
  402. claude_mpm/dashboard/static/built/components/file-change-tracker.js +0 -443
  403. claude_mpm/dashboard/static/built/components/file-change-viewer.js +0 -690
  404. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
  405. claude_mpm/dashboard/static/built/components/file-viewer.js +0 -2
  406. claude_mpm/dashboard/static/built/components/hud-library-loader.js +0 -2
  407. claude_mpm/dashboard/static/built/components/hud-manager.js +0 -2
  408. claude_mpm/dashboard/static/built/components/hud-visualizer.js +0 -2
  409. claude_mpm/dashboard/static/built/components/module-viewer.js +0 -2
  410. claude_mpm/dashboard/static/built/components/nav-bar.js +0 -145
  411. claude_mpm/dashboard/static/built/components/page-structure.js +0 -429
  412. claude_mpm/dashboard/static/built/components/session-manager.js +0 -2
  413. claude_mpm/dashboard/static/built/components/socket-manager.js +0 -2
  414. claude_mpm/dashboard/static/built/components/ui-state-manager.js +0 -2
  415. claude_mpm/dashboard/static/built/components/unified-data-viewer.js +0 -2
  416. claude_mpm/dashboard/static/built/components/working-directory.js +0 -2
  417. claude_mpm/dashboard/static/built/connection-manager.js +0 -536
  418. claude_mpm/dashboard/static/built/dashboard.js +0 -2
  419. claude_mpm/dashboard/static/built/extension-error-handler.js +0 -164
  420. claude_mpm/dashboard/static/built/react/events.js +0 -30
  421. claude_mpm/dashboard/static/built/shared/dom-helpers.js +0 -396
  422. claude_mpm/dashboard/static/built/shared/event-bus.js +0 -330
  423. claude_mpm/dashboard/static/built/shared/event-filter-service.js +0 -540
  424. claude_mpm/dashboard/static/built/shared/logger.js +0 -385
  425. claude_mpm/dashboard/static/built/shared/page-structure.js +0 -249
  426. claude_mpm/dashboard/static/built/shared/tooltip-service.js +0 -253
  427. claude_mpm/dashboard/static/built/socket-client.js +0 -2
  428. claude_mpm/dashboard/static/built/tab-isolation-fix.js +0 -185
  429. claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +0 -1
  430. claude_mpm/dashboard/static/dist/components/activity-tree.js +0 -2
  431. claude_mpm/dashboard/static/dist/components/agent-inference.js +0 -2
  432. claude_mpm/dashboard/static/dist/components/code-tree.js +0 -2
  433. claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
  434. claude_mpm/dashboard/static/dist/components/event-processor.js +0 -2
  435. claude_mpm/dashboard/static/dist/components/event-viewer.js +0 -2
  436. claude_mpm/dashboard/static/dist/components/export-manager.js +0 -2
  437. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +0 -2
  438. claude_mpm/dashboard/static/dist/components/file-viewer.js +0 -2
  439. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +0 -2
  440. claude_mpm/dashboard/static/dist/components/hud-manager.js +0 -2
  441. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +0 -2
  442. claude_mpm/dashboard/static/dist/components/module-viewer.js +0 -2
  443. claude_mpm/dashboard/static/dist/components/session-manager.js +0 -2
  444. claude_mpm/dashboard/static/dist/components/socket-manager.js +0 -2
  445. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +0 -2
  446. claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +0 -2
  447. claude_mpm/dashboard/static/dist/components/working-directory.js +0 -2
  448. claude_mpm/dashboard/static/dist/dashboard.js +0 -2
  449. claude_mpm/dashboard/static/dist/react/events.js +0 -30
  450. claude_mpm/dashboard/static/dist/socket-client.js +0 -2
  451. claude_mpm/dashboard/static/events.html +0 -607
  452. claude_mpm/dashboard/static/index.html +0 -635
  453. claude_mpm/dashboard/static/js/shared/dom-helpers.js +0 -396
  454. claude_mpm/dashboard/static/js/shared/event-bus.js +0 -330
  455. claude_mpm/dashboard/static/js/shared/logger.js +0 -385
  456. claude_mpm/dashboard/static/js/shared/tooltip-service.js +0 -253
  457. claude_mpm/dashboard/static/js/stores/dashboard-store.js +0 -562
  458. claude_mpm/dashboard/static/legacy/activity.html +0 -736
  459. claude_mpm/dashboard/static/legacy/agents.html +0 -786
  460. claude_mpm/dashboard/static/legacy/files.html +0 -747
  461. claude_mpm/dashboard/static/legacy/tools.html +0 -831
  462. claude_mpm/dashboard/static/monitors.html +0 -431
  463. claude_mpm/dashboard/static/production/events.html +0 -659
  464. claude_mpm/dashboard/static/production/main.html +0 -698
  465. claude_mpm/dashboard/static/production/monitors.html +0 -483
  466. claude_mpm/dashboard/static/test-archive/dashboard.html +0 -635
  467. claude_mpm/dashboard/static/test-archive/debug-events.html +0 -147
  468. claude_mpm/dashboard/static/test-archive/test-navigation.html +0 -256
  469. claude_mpm/dashboard/static/test-archive/test-react-exports.html +0 -180
  470. claude_mpm/dashboard/static/test-archive/test_debug.html +0 -25
  471. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +0 -75
  472. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +0 -184
  473. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +0 -107
  474. claude_mpm/skills/bundled/collaboration/requesting-code-review/code-reviewer.md +0 -146
  475. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +0 -118
  476. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +0 -177
  477. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +0 -119
  478. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +0 -148
  479. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +0 -483
  480. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +0 -452
  481. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +0 -449
  482. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +0 -411
  483. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +0 -14
  484. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +0 -58
  485. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +0 -68
  486. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +0 -69
  487. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +0 -175
  488. claude_mpm/skills/bundled/debugging/verification-before-completion/references/common-failures.md +0 -213
  489. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +0 -314
  490. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +0 -227
  491. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +0 -74
  492. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +0 -32
  493. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +0 -47
  494. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +0 -65
  495. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +0 -30
  496. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +0 -16
  497. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +0 -328
  498. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +0 -602
  499. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +0 -915
  500. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +0 -916
  501. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +0 -752
  502. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +0 -209
  503. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +0 -123
  504. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +0 -145
  505. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +0 -543
  506. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +0 -741
  507. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +0 -470
  508. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +0 -458
  509. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +0 -639
  510. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +0 -304
  511. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +0 -96
  512. claude_mpm/tools/code_tree_analyzer.py +0 -1825
  513. /claude_mpm/agents/templates/{git_file_tracking.md → git-file-tracking.md} +0 -0
  514. /claude_mpm/agents/templates/{pm_examples.md → pm-examples.md} +0 -0
  515. /claude_mpm/agents/templates/{response_format.md → response-format.md} +0 -0
  516. /claude_mpm/agents/templates/{validation_templates.md → validation-templates.md} +0 -0
  517. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/WHEEL +0 -0
  518. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/entry_points.txt +0 -0
  519. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/licenses/LICENSE +0 -0
  520. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,576 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Environment variable validation script.
4
+
5
+ This script validates .env files for:
6
+ - Structure (valid key-value format, no duplicates, proper quoting)
7
+ - Completeness (compare with .env.example)
8
+ - Naming conventions (UPPERCASE_WITH_UNDERSCORES)
9
+ - Framework-specific rules (Next.js, Express, Flask, etc.)
10
+
11
+ Security: NEVER logs actual secret values.
12
+ """
13
+
14
+ import argparse
15
+ import json
16
+ import re
17
+ import sys
18
+ from pathlib import Path
19
+ from typing import Dict, List, Optional
20
+
21
+
22
+ class ValidationError:
23
+ """Represents a validation error."""
24
+
25
+ def __init__(
26
+ self, line: Optional[int], key: str, message: str, severity: str = "error"
27
+ ):
28
+ self.line = line
29
+ self.key = key
30
+ self.message = message
31
+ self.severity = severity # "error" or "warning"
32
+
33
+ def to_dict(self) -> Dict:
34
+ return {
35
+ "line": self.line,
36
+ "key": self.key,
37
+ "message": self.message,
38
+ "severity": self.severity,
39
+ }
40
+
41
+ def __str__(self) -> str:
42
+ prefix = "❌" if self.severity == "error" else "⚠️ "
43
+ line_info = f"Line {self.line}: " if self.line else ""
44
+ return f"{prefix} {line_info}{self.key}: {self.message}"
45
+
46
+
47
+ class EnvValidator:
48
+ """Validates environment variable files."""
49
+
50
+ # Valid variable name pattern: UPPERCASE_WITH_UNDERSCORES
51
+ VALID_NAME_PATTERN = re.compile(r"^[A-Z][A-Z0-9_]*$")
52
+
53
+ # Framework-specific prefixes
54
+ FRAMEWORK_PREFIXES = {
55
+ "nextjs": ["NEXT_PUBLIC_", "NEXT_"],
56
+ "vite": ["VITE_"],
57
+ "react": ["REACT_APP_"],
58
+ }
59
+
60
+ # Secret indicators (variables that should never be in NEXT_PUBLIC_, etc.)
61
+ SECRET_INDICATORS = ["secret", "key", "password", "token", "private", "api_key"]
62
+
63
+ def __init__(self, framework: Optional[str] = None, strict: bool = False):
64
+ self.framework = framework
65
+ self.strict = strict
66
+ self.errors: List[ValidationError] = []
67
+ self.warnings: List[ValidationError] = []
68
+
69
+ def parse_env_file(self, env_file: Path) -> Dict[str, str]:
70
+ """Parse .env file safely. Returns dict of key-value pairs."""
71
+ vars_dict = {}
72
+
73
+ with open(env_file) as f:
74
+ for line_num, line in enumerate(f, 1):
75
+ line = line.strip()
76
+
77
+ # Skip empty lines and comments
78
+ if not line or line.startswith("#"):
79
+ continue
80
+
81
+ # Check for valid format
82
+ if "=" not in line:
83
+ self.errors.append(
84
+ ValidationError(
85
+ line_num,
86
+ "",
87
+ f"Invalid format (missing =): {line[:50]}",
88
+ "error",
89
+ )
90
+ )
91
+ continue
92
+
93
+ # Split on first = only
94
+ key, value = line.split("=", 1)
95
+ key = key.strip()
96
+
97
+ # Remove quotes from value
98
+ value = value.strip()
99
+ if value and value[0] == value[-1] and value[0] in ('"', "'"):
100
+ value = value[1:-1]
101
+
102
+ vars_dict[key] = value
103
+
104
+ return vars_dict
105
+
106
+ def validate_structure(self, env_file: Path) -> List[ValidationError]:
107
+ """Validate basic file structure."""
108
+ errors = []
109
+
110
+ with open(env_file) as f:
111
+ for line_num, line in enumerate(f, 1):
112
+ line = line.strip()
113
+
114
+ # Skip empty lines and comments
115
+ if not line or line.startswith("#"):
116
+ continue
117
+
118
+ # Check for inline comments (warning)
119
+ if "#" in line and not line.startswith("#"):
120
+ key_value = line.split("#", 1)[0]
121
+ if "=" in key_value:
122
+ key, value = key_value.split("=", 1)
123
+ # Check if # is inside quotes
124
+ value = value.strip()
125
+ if not (value.startswith('"') or value.startswith("'")):
126
+ errors.append(
127
+ ValidationError(
128
+ line_num,
129
+ key.strip(),
130
+ "Possible inline comment (not all parsers support this)",
131
+ "warning",
132
+ )
133
+ )
134
+
135
+ # Check format
136
+ if "=" not in line:
137
+ errors.append(
138
+ ValidationError(
139
+ line_num,
140
+ "",
141
+ f"Invalid format (missing =): {line[:50]}",
142
+ "error",
143
+ )
144
+ )
145
+ continue
146
+
147
+ key, value = line.split("=", 1)
148
+ key = key.strip()
149
+
150
+ # Validate key name
151
+ if not self.VALID_NAME_PATTERN.match(key):
152
+ errors.append(
153
+ ValidationError(
154
+ line_num,
155
+ key,
156
+ "Invalid naming (use UPPERCASE_WITH_UNDERSCORES)",
157
+ "error",
158
+ )
159
+ )
160
+
161
+ # Check for spaces without quotes
162
+ value = value.strip()
163
+ if value and " " in value:
164
+ if not (value.startswith('"') or value.startswith("'")):
165
+ errors.append(
166
+ ValidationError(
167
+ line_num,
168
+ key,
169
+ "Value with spaces should be quoted",
170
+ "warning",
171
+ )
172
+ )
173
+
174
+ return errors
175
+
176
+ def check_duplicates(self, env_file: Path) -> Dict[str, List[int]]:
177
+ """Find duplicate keys and their line numbers."""
178
+ keys: Dict[str, List[int]] = {}
179
+
180
+ with open(env_file) as f:
181
+ for line_num, line in enumerate(f, 1):
182
+ line = line.strip()
183
+ if not line or line.startswith("#"):
184
+ continue
185
+
186
+ if "=" in line:
187
+ key = line.split("=", 1)[0].strip()
188
+ if key in keys:
189
+ keys[key].append(line_num)
190
+ else:
191
+ keys[key] = [line_num]
192
+
193
+ # Return only duplicates
194
+ duplicates = {k: v for k, v in keys.items() if len(v) > 1}
195
+
196
+ # Add errors for duplicates
197
+ for key, lines in duplicates.items():
198
+ self.errors.append(
199
+ ValidationError(
200
+ None,
201
+ key,
202
+ f"Duplicate key found on lines: {', '.join(map(str, lines))}",
203
+ "error",
204
+ )
205
+ )
206
+
207
+ return duplicates
208
+
209
+ def compare_env_files(self, env_file: Path, example_file: Path) -> Dict:
210
+ """Compare .env against .env.example."""
211
+ if not example_file.exists():
212
+ self.warnings.append(
213
+ ValidationError(
214
+ None, "", f".env.example not found: {example_file}", "warning"
215
+ )
216
+ )
217
+ return {"missing": set(), "extra": set(), "common": set()}
218
+
219
+ env_vars = set(self.parse_env_file(env_file).keys())
220
+ example_vars = set(self.parse_env_file(example_file).keys())
221
+
222
+ missing = example_vars - env_vars
223
+ extra = env_vars - example_vars
224
+ common = env_vars & example_vars
225
+
226
+ # Add errors for missing required variables
227
+ for var in missing:
228
+ self.errors.append(
229
+ ValidationError(
230
+ None,
231
+ var,
232
+ "Required variable missing (defined in .env.example)",
233
+ "error",
234
+ )
235
+ )
236
+
237
+ # Add warnings for undocumented variables
238
+ for var in extra:
239
+ self.warnings.append(
240
+ ValidationError(
241
+ None, var, "Variable not documented in .env.example", "warning"
242
+ )
243
+ )
244
+
245
+ return {"missing": missing, "extra": extra, "common": common}
246
+
247
+ def validate_framework_specific(self, env_file: Path) -> List[ValidationError]:
248
+ """Validate framework-specific rules."""
249
+ errors = []
250
+ vars_dict = self.parse_env_file(env_file)
251
+
252
+ if self.framework == "nextjs":
253
+ errors.extend(self._validate_nextjs(vars_dict))
254
+ elif self.framework == "vite":
255
+ errors.extend(self._validate_vite(vars_dict))
256
+ elif self.framework == "react":
257
+ errors.extend(self._validate_react(vars_dict))
258
+ elif self.framework == "nodejs":
259
+ errors.extend(self._validate_nodejs(vars_dict))
260
+ elif self.framework == "flask":
261
+ errors.extend(self._validate_flask(vars_dict))
262
+
263
+ return errors
264
+
265
+ def _validate_nextjs(self, vars_dict: Dict[str, str]) -> List[ValidationError]:
266
+ """Validate Next.js environment variables."""
267
+ errors = []
268
+
269
+ for key, value in vars_dict.items():
270
+ # Check for secrets in NEXT_PUBLIC_ vars
271
+ if key.startswith("NEXT_PUBLIC_"):
272
+ if any(
273
+ indicator in key.lower() for indicator in self.SECRET_INDICATORS
274
+ ):
275
+ errors.append(
276
+ ValidationError(
277
+ None,
278
+ key,
279
+ "SECURITY: Secret in NEXT_PUBLIC_ variable (exposed to browser)",
280
+ "error",
281
+ )
282
+ )
283
+
284
+ # Check for API URLs without NEXT_PUBLIC_ prefix
285
+ if "api" in key.lower() and "url" in key.lower():
286
+ if not key.startswith("NEXT_PUBLIC_") and not key.endswith("_SECRET"):
287
+ errors.append(
288
+ ValidationError(
289
+ None,
290
+ key,
291
+ "API URL without NEXT_PUBLIC_ prefix (not accessible client-side)",
292
+ "warning",
293
+ )
294
+ )
295
+
296
+ return errors
297
+
298
+ def _validate_vite(self, vars_dict: Dict[str, str]) -> List[ValidationError]:
299
+ """Validate Vite environment variables."""
300
+ errors = []
301
+
302
+ for key in vars_dict:
303
+ # Check for secrets in VITE_ vars
304
+ if key.startswith("VITE_"):
305
+ if any(
306
+ indicator in key.lower() for indicator in self.SECRET_INDICATORS
307
+ ):
308
+ errors.append(
309
+ ValidationError(
310
+ None,
311
+ key,
312
+ "SECURITY: Secret in VITE_ variable (exposed to browser)",
313
+ "error",
314
+ )
315
+ )
316
+
317
+ # Warn about non-VITE_ vars
318
+ elif key not in ["NODE_ENV", "PORT"]:
319
+ errors.append(
320
+ ValidationError(
321
+ None,
322
+ key,
323
+ "Variable not prefixed with VITE_ (not accessible in client code)",
324
+ "warning",
325
+ )
326
+ )
327
+
328
+ return errors
329
+
330
+ def _validate_react(self, vars_dict: Dict[str, str]) -> List[ValidationError]:
331
+ """Validate Create React App environment variables."""
332
+ errors = []
333
+
334
+ for key in vars_dict:
335
+ # Check for secrets in REACT_APP_ vars
336
+ if key.startswith("REACT_APP_"):
337
+ if any(
338
+ indicator in key.lower() for indicator in self.SECRET_INDICATORS
339
+ ):
340
+ errors.append(
341
+ ValidationError(
342
+ None,
343
+ key,
344
+ "SECURITY: Secret in REACT_APP_ variable (exposed to browser)",
345
+ "error",
346
+ )
347
+ )
348
+
349
+ return errors
350
+
351
+ def _validate_nodejs(self, vars_dict: Dict[str, str]) -> List[ValidationError]:
352
+ """Validate Node.js environment variables."""
353
+ errors = []
354
+
355
+ # Check NODE_ENV value
356
+ if "NODE_ENV" in vars_dict:
357
+ valid_values = ["development", "production", "test"]
358
+ if vars_dict["NODE_ENV"] not in valid_values:
359
+ # SECURITY: Never expose actual variable values in error messages
360
+ # to prevent accidental secret leakage in logs/CI output
361
+ errors.append(
362
+ ValidationError(
363
+ None,
364
+ "NODE_ENV",
365
+ f"Invalid value for NODE_ENV, expected one of {valid_values}",
366
+ "error",
367
+ )
368
+ )
369
+
370
+ # Check PORT is numeric
371
+ if "PORT" in vars_dict:
372
+ try:
373
+ port = int(vars_dict["PORT"])
374
+ if not (1 <= port <= 65535):
375
+ errors.append(
376
+ ValidationError(
377
+ None, "PORT", "PORT must be between 1 and 65535", "error"
378
+ )
379
+ )
380
+ except ValueError:
381
+ errors.append(
382
+ ValidationError(None, "PORT", "PORT must be numeric", "error")
383
+ )
384
+
385
+ return errors
386
+
387
+ def _validate_flask(self, vars_dict: Dict[str, str]) -> List[ValidationError]:
388
+ """Validate Flask environment variables."""
389
+ errors = []
390
+
391
+ # Check required vars
392
+ required = ["FLASK_APP", "SECRET_KEY"]
393
+ for var in required:
394
+ if var not in vars_dict:
395
+ errors.append(
396
+ ValidationError(
397
+ None, var, "Required Flask variable missing", "error"
398
+ )
399
+ )
400
+
401
+ # Check FLASK_APP ends with .py
402
+ if "FLASK_APP" in vars_dict:
403
+ if not vars_dict["FLASK_APP"].endswith(".py"):
404
+ errors.append(
405
+ ValidationError(
406
+ None,
407
+ "FLASK_APP",
408
+ "FLASK_APP should point to a .py file",
409
+ "warning",
410
+ )
411
+ )
412
+
413
+ # Check FLASK_ENV value
414
+ if "FLASK_ENV" in vars_dict:
415
+ valid_values = ["development", "production"]
416
+ if vars_dict["FLASK_ENV"] not in valid_values:
417
+ errors.append(
418
+ ValidationError(
419
+ None,
420
+ "FLASK_ENV",
421
+ f"Invalid value, expected one of {valid_values}",
422
+ "error",
423
+ )
424
+ )
425
+
426
+ return errors
427
+
428
+ def validate(self, env_file: Path, example_file: Optional[Path] = None) -> Dict:
429
+ """Run all validations. Returns summary dict."""
430
+ self.errors = []
431
+ self.warnings = []
432
+
433
+ # 1. Structure validation
434
+ structure_errors = self.validate_structure(env_file)
435
+ self.errors.extend([e for e in structure_errors if e.severity == "error"])
436
+ self.warnings.extend([e for e in structure_errors if e.severity == "warning"])
437
+
438
+ # 2. Check duplicates
439
+ self.check_duplicates(env_file)
440
+
441
+ # 3. Compare with .env.example
442
+ if example_file:
443
+ self.compare_env_files(env_file, example_file)
444
+
445
+ # 4. Framework-specific validation
446
+ if self.framework:
447
+ framework_errors = self.validate_framework_specific(env_file)
448
+ self.errors.extend([e for e in framework_errors if e.severity == "error"])
449
+ self.warnings.extend(
450
+ [e for e in framework_errors if e.severity == "warning"]
451
+ )
452
+
453
+ return {
454
+ "valid": len(self.errors) == 0,
455
+ "errors": self.errors,
456
+ "warnings": self.warnings,
457
+ "error_count": len(self.errors),
458
+ "warning_count": len(self.warnings),
459
+ }
460
+
461
+
462
+ def generate_example(env_file: Path, output_file: Path) -> None:
463
+ """Generate .env.example from .env file (with values removed)."""
464
+ with open(env_file) as f:
465
+ lines = f.readlines()
466
+
467
+ with open(output_file, "w") as f:
468
+ for line in lines:
469
+ line = line.strip()
470
+
471
+ # Keep comments and empty lines
472
+ if not line or line.startswith("#"):
473
+ f.write(line + "\n")
474
+ continue
475
+
476
+ # Replace values with placeholders
477
+ if "=" in line:
478
+ key, _ = line.split("=", 1)
479
+ f.write(f"{key}=your-{key.lower().replace('_', '-')}-here\n")
480
+
481
+ print(f"✅ Generated {output_file}")
482
+
483
+
484
+ def main():
485
+ parser = argparse.ArgumentParser(description="Validate environment variable files")
486
+ parser.add_argument("file", type=Path, help="Path to .env file to validate")
487
+ parser.add_argument(
488
+ "--compare-with",
489
+ type=Path,
490
+ help="Compare with .env.example file",
491
+ metavar="FILE",
492
+ )
493
+ parser.add_argument(
494
+ "--framework",
495
+ choices=["nextjs", "vite", "react", "nodejs", "flask", "generic"],
496
+ help="Framework-specific validation",
497
+ )
498
+ parser.add_argument(
499
+ "--strict", action="store_true", help="Treat warnings as errors"
500
+ )
501
+ parser.add_argument("--json", action="store_true", help="Output results as JSON")
502
+ parser.add_argument(
503
+ "--quiet", action="store_true", help="Only show errors, not warnings"
504
+ )
505
+ parser.add_argument(
506
+ "--generate-example",
507
+ type=Path,
508
+ help="Generate .env.example file",
509
+ metavar="OUTPUT",
510
+ )
511
+
512
+ args = parser.parse_args()
513
+
514
+ # Check input file exists
515
+ if not args.file.exists():
516
+ print(f"❌ Error: File not found: {args.file}")
517
+ sys.exit(2)
518
+
519
+ # Generate example if requested
520
+ if args.generate_example:
521
+ generate_example(args.file, args.generate_example)
522
+ return
523
+
524
+ # Run validation
525
+ validator = EnvValidator(framework=args.framework, strict=args.strict)
526
+ result = validator.validate(args.file, example_file=args.compare_with)
527
+
528
+ # Output results
529
+ if args.json:
530
+ output = {
531
+ "valid": result["valid"],
532
+ "file": str(args.file),
533
+ "errors": [e.to_dict() for e in result["errors"]],
534
+ "warnings": [w.to_dict() for w in result["warnings"]],
535
+ }
536
+ print(json.dumps(output, indent=2))
537
+ else:
538
+ print(f"\n🔍 Validating: {args.file}")
539
+ if args.framework:
540
+ print(f"📦 Framework: {args.framework}")
541
+ print()
542
+
543
+ # Show errors
544
+ if result["errors"]:
545
+ print("❌ Errors:")
546
+ for error in result["errors"]:
547
+ print(f" {error}")
548
+ print()
549
+
550
+ # Show warnings (unless quiet)
551
+ if result["warnings"] and not args.quiet:
552
+ print("⚠️ Warnings:")
553
+ for warning in result["warnings"]:
554
+ print(f" {warning}")
555
+ print()
556
+
557
+ # Summary
558
+ if result["valid"]:
559
+ print("✅ Validation passed!")
560
+ else:
561
+ print(f"❌ Validation failed: {result['error_count']} error(s)")
562
+
563
+ if not args.quiet:
564
+ print(
565
+ f"📊 Summary: {result['error_count']} errors, {result['warning_count']} warnings"
566
+ )
567
+
568
+ # Exit code
569
+ if result["errors"] or (args.strict and result["warnings"]):
570
+ sys.exit(1)
571
+ else:
572
+ sys.exit(0)
573
+
574
+
575
+ if __name__ == "__main__":
576
+ main()
@@ -2,7 +2,7 @@
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  from contextlib import AsyncExitStack
5
- from typing import Any
5
+ from typing import Any, Optional
6
6
 
7
7
  from mcp import ClientSession, StdioServerParameters
8
8
  from mcp.client.sse import sse_client
@@ -73,7 +73,12 @@ class MCPConnection(ABC):
73
73
  class MCPConnectionStdio(MCPConnection):
74
74
  """MCP connection using standard input/output."""
75
75
 
76
- def __init__(self, command: str, args: list[str] = None, env: dict[str, str] = None):
76
+ def __init__(
77
+ self,
78
+ command: str,
79
+ args: Optional[list[str]] = None,
80
+ env: Optional[dict[str, str]] = None,
81
+ ):
77
82
  super().__init__()
78
83
  self.command = command
79
84
  self.args = args or []
@@ -88,7 +93,7 @@ class MCPConnectionStdio(MCPConnection):
88
93
  class MCPConnectionSSE(MCPConnection):
89
94
  """MCP connection using Server-Sent Events."""
90
95
 
91
- def __init__(self, url: str, headers: dict[str, str] = None):
96
+ def __init__(self, url: str, headers: Optional[dict[str, str]] = None):
92
97
  super().__init__()
93
98
  self.url = url
94
99
  self.headers = headers or {}
@@ -100,7 +105,7 @@ class MCPConnectionSSE(MCPConnection):
100
105
  class MCPConnectionHTTP(MCPConnection):
101
106
  """MCP connection using Streamable HTTP."""
102
107
 
103
- def __init__(self, url: str, headers: dict[str, str] = None):
108
+ def __init__(self, url: str, headers: Optional[dict[str, str]] = None):
104
109
  super().__init__()
105
110
  self.url = url
106
111
  self.headers = headers or {}
@@ -111,11 +116,11 @@ class MCPConnectionHTTP(MCPConnection):
111
116
 
112
117
  def create_connection(
113
118
  transport: str,
114
- command: str = None,
115
- args: list[str] = None,
116
- env: dict[str, str] = None,
117
- url: str = None,
118
- headers: dict[str, str] = None,
119
+ command: Optional[str] = None,
120
+ args: Optional[list[str]] = None,
121
+ env: Optional[dict[str, str]] = None,
122
+ url: Optional[str] = None,
123
+ headers: Optional[dict[str, str]] = None,
119
124
  ) -> MCPConnection:
120
125
  """Factory function to create the appropriate MCP connection.
121
126
 
@@ -147,4 +152,6 @@ def create_connection(
147
152
  raise ValueError("URL is required for http transport")
148
153
  return MCPConnectionHTTP(url=url, headers=headers)
149
154
 
150
- raise ValueError(f"Unsupported transport type: {transport}. Use 'stdio', 'sse', or 'http'")
155
+ raise ValueError(
156
+ f"Unsupported transport type: {transport}. Use 'stdio', 'sse', or 'http'"
157
+ )