claude-mpm 4.21.3__py3-none-any.whl → 5.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_PM.md +12 -0
- claude_mpm/agents/OUTPUT_STYLE.md +3 -48
- claude_mpm/agents/PM_INSTRUCTIONS.md +632 -334
- claude_mpm/agents/WORKFLOW.md +75 -2
- claude_mpm/agents/__init__.py +6 -0
- claude_mpm/agents/agent_loader.py +1 -4
- claude_mpm/agents/base_agent.json +6 -3
- claude_mpm/agents/frontmatter_validator.py +1 -1
- claude_mpm/agents/templates/{circuit_breakers.md → circuit-breakers.md} +370 -3
- claude_mpm/agents/templates/context-management-examples.md +544 -0
- claude_mpm/agents/templates/{pm_red_flags.md → pm-red-flags.md} +89 -19
- claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
- claude_mpm/agents/templates/research-gate-examples.md +669 -0
- claude_mpm/agents/templates/structured-questions-examples.md +615 -0
- claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
- claude_mpm/agents/templates/ticketing-examples.md +277 -0
- claude_mpm/cli/__init__.py +38 -2
- claude_mpm/cli/commands/agent_source.py +774 -0
- claude_mpm/cli/commands/agent_state_manager.py +125 -20
- claude_mpm/cli/commands/agents.py +684 -13
- claude_mpm/cli/commands/agents_cleanup.py +210 -0
- claude_mpm/cli/commands/agents_discover.py +338 -0
- claude_mpm/cli/commands/aggregate.py +1 -1
- claude_mpm/cli/commands/analyze.py +3 -3
- claude_mpm/cli/commands/auto_configure.py +2 -6
- claude_mpm/cli/commands/cleanup.py +1 -1
- claude_mpm/cli/commands/config.py +7 -4
- claude_mpm/cli/commands/configure.py +478 -44
- claude_mpm/cli/commands/configure_agent_display.py +4 -4
- claude_mpm/cli/commands/configure_navigation.py +63 -46
- claude_mpm/cli/commands/debug.py +12 -12
- claude_mpm/cli/commands/doctor.py +10 -2
- claude_mpm/cli/commands/hook_errors.py +277 -0
- claude_mpm/cli/commands/local_deploy.py +1 -4
- claude_mpm/cli/commands/mcp_install_commands.py +1 -1
- claude_mpm/cli/commands/mpm_init/core.py +50 -2
- claude_mpm/cli/commands/mpm_init/git_activity.py +10 -10
- claude_mpm/cli/commands/mpm_init/prompts.py +6 -6
- claude_mpm/cli/commands/run.py +124 -128
- claude_mpm/cli/commands/skill_source.py +694 -0
- claude_mpm/cli/commands/skills.py +435 -1
- claude_mpm/cli/executor.py +78 -3
- claude_mpm/cli/interactive/agent_wizard.py +919 -41
- claude_mpm/cli/parsers/agent_source_parser.py +171 -0
- claude_mpm/cli/parsers/agents_parser.py +173 -4
- claude_mpm/cli/parsers/base_parser.py +49 -0
- claude_mpm/cli/parsers/config_parser.py +96 -43
- claude_mpm/cli/parsers/skill_source_parser.py +169 -0
- claude_mpm/cli/parsers/skills_parser.py +138 -0
- claude_mpm/cli/parsers/source_parser.py +138 -0
- claude_mpm/cli/startup.py +499 -84
- claude_mpm/cli/startup_display.py +480 -0
- claude_mpm/cli/utils.py +1 -1
- claude_mpm/cli_module/commands.py +1 -1
- claude_mpm/commands/{mpm-auto-configure.md → mpm-agents-auto-configure.md} +9 -0
- claude_mpm/commands/mpm-agents-detect.md +9 -0
- claude_mpm/commands/{mpm-agents.md → mpm-agents-list.md} +9 -0
- claude_mpm/commands/mpm-agents-recommend.md +9 -0
- claude_mpm/commands/{mpm-config.md → mpm-config-view.md} +9 -0
- claude_mpm/commands/mpm-doctor.md +9 -0
- claude_mpm/commands/mpm-help.md +11 -2
- claude_mpm/commands/mpm-init.md +27 -2
- claude_mpm/commands/mpm-monitor.md +9 -0
- claude_mpm/commands/{mpm-resume.md → mpm-session-resume.md} +9 -0
- claude_mpm/commands/mpm-status.md +9 -0
- claude_mpm/commands/{mpm-organize.md → mpm-ticket-organize.md} +9 -0
- claude_mpm/commands/mpm-ticket-view.md +552 -0
- claude_mpm/commands/mpm-version.md +9 -0
- claude_mpm/commands/mpm.md +10 -0
- claude_mpm/config/agent_presets.py +258 -0
- claude_mpm/config/agent_sources.py +325 -0
- claude_mpm/config/skill_sources.py +590 -0
- claude_mpm/constants.py +12 -0
- claude_mpm/core/api_validator.py +1 -1
- claude_mpm/core/claude_runner.py +17 -10
- claude_mpm/core/config.py +24 -0
- claude_mpm/core/constants.py +1 -1
- claude_mpm/core/framework/__init__.py +3 -16
- claude_mpm/core/framework/loaders/instruction_loader.py +25 -5
- claude_mpm/core/framework/processors/metadata_processor.py +1 -1
- claude_mpm/core/hook_error_memory.py +381 -0
- claude_mpm/core/hook_manager.py +41 -2
- claude_mpm/core/interactive_session.py +112 -5
- claude_mpm/core/logger.py +3 -1
- claude_mpm/core/oneshot_session.py +94 -4
- claude_mpm/dashboard/static/css/activity.css +69 -69
- claude_mpm/dashboard/static/css/connection-status.css +10 -10
- claude_mpm/dashboard/static/css/dashboard.css +15 -15
- claude_mpm/dashboard/static/js/components/activity-tree.js +178 -178
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +101 -101
- claude_mpm/dashboard/static/js/components/agent-inference.js +31 -31
- claude_mpm/dashboard/static/js/components/build-tracker.js +59 -59
- claude_mpm/dashboard/static/js/components/code-simple.js +107 -107
- claude_mpm/dashboard/static/js/components/connection-debug.js +101 -101
- claude_mpm/dashboard/static/js/components/diff-viewer.js +113 -113
- claude_mpm/dashboard/static/js/components/event-viewer.js +12 -12
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +57 -57
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +74 -74
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +6 -6
- claude_mpm/dashboard/static/js/components/file-viewer.js +42 -42
- claude_mpm/dashboard/static/js/components/module-viewer.js +27 -27
- claude_mpm/dashboard/static/js/components/session-manager.js +14 -14
- claude_mpm/dashboard/static/js/components/socket-manager.js +1 -1
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +14 -14
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +110 -110
- claude_mpm/dashboard/static/js/components/working-directory.js +8 -8
- claude_mpm/dashboard/static/js/connection-manager.js +76 -76
- claude_mpm/dashboard/static/js/dashboard.js +76 -58
- claude_mpm/dashboard/static/js/extension-error-handler.js +22 -22
- claude_mpm/dashboard/static/js/socket-client.js +138 -121
- claude_mpm/dashboard/templates/code_simple.html +23 -23
- claude_mpm/dashboard/templates/index.html +18 -18
- claude_mpm/experimental/cli_enhancements.py +1 -5
- claude_mpm/hooks/claude_hooks/event_handlers.py +3 -1
- claude_mpm/hooks/claude_hooks/hook_handler.py +24 -7
- claude_mpm/hooks/claude_hooks/installer.py +45 -0
- claude_mpm/hooks/failure_learning/__init__.py +2 -8
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +1 -6
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +1 -6
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +1 -6
- claude_mpm/hooks/kuzu_response_hook.py +1 -5
- claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
- claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
- claude_mpm/models/git_repository.py +198 -0
- claude_mpm/scripts/claude-hook-handler.sh +3 -3
- claude_mpm/scripts/start_activity_logging.py +3 -1
- claude_mpm/services/agents/agent_builder.py +45 -9
- claude_mpm/services/agents/agent_preset_service.py +238 -0
- claude_mpm/services/agents/agent_selection_service.py +484 -0
- claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +126 -2
- claude_mpm/services/agents/deployment/agent_discovery_service.py +105 -73
- claude_mpm/services/agents/deployment/agent_format_converter.py +1 -1
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
- claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
- claude_mpm/services/agents/deployment/agent_template_builder.py +236 -15
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
- claude_mpm/services/agents/deployment/async_agent_deployment.py +2 -1
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +115 -15
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +1 -4
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +363 -0
- claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -46
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
- claude_mpm/services/agents/git_source_manager.py +629 -0
- claude_mpm/services/agents/loading/framework_agent_loader.py +9 -12
- claude_mpm/services/agents/local_template_manager.py +50 -10
- claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
- claude_mpm/services/agents/sources/__init__.py +13 -0
- claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
- claude_mpm/services/agents/sources/git_source_sync_service.py +1055 -0
- claude_mpm/services/agents/startup_sync.py +239 -0
- claude_mpm/services/agents/toolchain_detector.py +474 -0
- claude_mpm/services/cli/session_pause_manager.py +1 -1
- claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
- claude_mpm/services/command_deployment_service.py +92 -1
- claude_mpm/services/core/interfaces/__init__.py +1 -3
- claude_mpm/services/core/interfaces/health.py +1 -4
- claude_mpm/services/core/models/__init__.py +2 -11
- claude_mpm/services/diagnostics/checks/__init__.py +4 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +0 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
- claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
- claude_mpm/services/diagnostics/checks/mcp_check.py +0 -1
- claude_mpm/services/diagnostics/checks/monitor_check.py +0 -1
- claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +9 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +40 -10
- claude_mpm/services/event_bus/direct_relay.py +3 -3
- claude_mpm/services/event_bus/event_bus.py +36 -3
- claude_mpm/services/events/consumers/logging.py +1 -2
- claude_mpm/services/git/__init__.py +21 -0
- claude_mpm/services/git/git_operations_service.py +494 -0
- claude_mpm/services/github/__init__.py +21 -0
- claude_mpm/services/github/github_cli_service.py +397 -0
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -5
- claude_mpm/services/infrastructure/monitoring/aggregator.py +1 -6
- claude_mpm/services/infrastructure/monitoring/resources.py +1 -1
- claude_mpm/services/instructions/__init__.py +9 -0
- claude_mpm/services/instructions/instruction_cache_service.py +374 -0
- claude_mpm/services/local_ops/__init__.py +3 -13
- claude_mpm/services/local_ops/health_checks/__init__.py +1 -3
- claude_mpm/services/local_ops/health_manager.py +1 -4
- claude_mpm/services/local_ops/process_manager.py +1 -1
- claude_mpm/services/local_ops/resource_monitor.py +2 -2
- claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +1 -6
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -2
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +6 -2
- claude_mpm/services/memory/optimizer.py +1 -1
- claude_mpm/services/model/model_router.py +8 -9
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/server.py +2 -2
- claude_mpm/services/native_agent_converter.py +356 -0
- claude_mpm/services/port_manager.py +1 -1
- claude_mpm/services/pr/__init__.py +14 -0
- claude_mpm/services/pr/pr_template_service.py +329 -0
- claude_mpm/services/project/documentation_manager.py +2 -1
- claude_mpm/services/project/toolchain_analyzer.py +3 -1
- claude_mpm/services/runner_configuration_service.py +1 -0
- claude_mpm/services/self_upgrade_service.py +165 -7
- claude_mpm/services/skills/__init__.py +18 -0
- claude_mpm/services/skills/git_skill_source_manager.py +1169 -0
- claude_mpm/services/skills/skill_discovery_service.py +568 -0
- claude_mpm/services/skills_config.py +547 -0
- claude_mpm/services/skills_deployer.py +955 -0
- claude_mpm/services/socketio/handlers/connection.py +1 -1
- claude_mpm/services/socketio/handlers/git.py +2 -2
- claude_mpm/services/socketio/server/core.py +1 -4
- claude_mpm/services/socketio/server/main.py +1 -3
- claude_mpm/services/system_instructions_service.py +1 -3
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +0 -3
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +0 -1
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +1 -1
- claude_mpm/services/unified/deployment_strategies/vercel.py +1 -5
- claude_mpm/services/unified/unified_deployment.py +1 -5
- claude_mpm/services/version_control/conflict_resolution.py +6 -4
- claude_mpm/services/visualization/__init__.py +1 -5
- claude_mpm/services/visualization/mermaid_generator.py +2 -3
- claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
- claude_mpm/skills/bundled/performance-profiling.md +6 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +2 -2
- claude_mpm/skills/skills_registry.py +0 -1
- claude_mpm/templates/questions/__init__.py +38 -0
- claude_mpm/templates/questions/base.py +193 -0
- claude_mpm/templates/questions/pr_strategy.py +311 -0
- claude_mpm/templates/questions/project_init.py +385 -0
- claude_mpm/templates/questions/ticket_mgmt.py +394 -0
- claude_mpm/tools/__main__.py +8 -8
- claude_mpm/tools/code_tree_analyzer/analysis.py +1 -1
- claude_mpm/utils/agent_dependency_loader.py +80 -13
- claude_mpm/utils/dependency_cache.py +3 -1
- claude_mpm/utils/gitignore.py +241 -0
- claude_mpm/utils/log_cleanup.py +3 -3
- claude_mpm/utils/progress.py +383 -0
- claude_mpm/utils/robust_installer.py +3 -5
- claude_mpm/utils/structured_questions.py +619 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/METADATA +429 -59
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/RECORD +252 -425
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -17
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +0 -3
- claude_mpm/agents/templates/agent-manager.json +0 -273
- claude_mpm/agents/templates/agentic-coder-optimizer.json +0 -248
- claude_mpm/agents/templates/api_qa.json +0 -180
- claude_mpm/agents/templates/clerk-ops.json +0 -235
- claude_mpm/agents/templates/code_analyzer.json +0 -101
- claude_mpm/agents/templates/content-agent.json +0 -358
- claude_mpm/agents/templates/dart_engineer.json +0 -307
- claude_mpm/agents/templates/data_engineer.json +0 -225
- claude_mpm/agents/templates/documentation.json +0 -211
- claude_mpm/agents/templates/engineer.json +0 -210
- claude_mpm/agents/templates/gcp_ops_agent.json +0 -253
- claude_mpm/agents/templates/golang_engineer.json +0 -270
- claude_mpm/agents/templates/imagemagick.json +0 -264
- claude_mpm/agents/templates/java_engineer.json +0 -346
- claude_mpm/agents/templates/local_ops_agent.json +0 -1840
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md +0 -400
- claude_mpm/agents/templates/memory_manager.json +0 -158
- claude_mpm/agents/templates/nextjs_engineer.json +0 -285
- claude_mpm/agents/templates/ops.json +0 -185
- claude_mpm/agents/templates/php-engineer.json +0 -287
- claude_mpm/agents/templates/product_owner.json +0 -338
- claude_mpm/agents/templates/project_organizer.json +0 -140
- claude_mpm/agents/templates/prompt-engineer.json +0 -737
- claude_mpm/agents/templates/python_engineer.json +0 -387
- claude_mpm/agents/templates/qa.json +0 -242
- claude_mpm/agents/templates/react_engineer.json +0 -238
- claude_mpm/agents/templates/refactoring_engineer.json +0 -276
- claude_mpm/agents/templates/research.json +0 -188
- claude_mpm/agents/templates/ruby-engineer.json +0 -280
- claude_mpm/agents/templates/rust_engineer.json +0 -275
- claude_mpm/agents/templates/security.json +0 -202
- claude_mpm/agents/templates/svelte-engineer.json +0 -225
- claude_mpm/agents/templates/ticketing.json +0 -177
- claude_mpm/agents/templates/typescript_engineer.json +0 -285
- claude_mpm/agents/templates/vercel_ops_agent.json +0 -412
- claude_mpm/agents/templates/version_control.json +0 -157
- claude_mpm/agents/templates/web_qa.json +0 -399
- claude_mpm/agents/templates/web_ui.json +0 -189
- claude_mpm/commands/mpm-tickets.md +0 -102
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
- claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +0 -188
- claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +0 -156
- claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +0 -38
- claude_mpm/dashboard/react/components/shared/FilterBar.module.css +0 -92
- claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +0 -248
- claude_mpm/dashboard/static/archive/activity_dashboard_test.html +0 -61
- claude_mpm/dashboard/static/archive/test_activity_connection.html +0 -179
- claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +0 -68
- claude_mpm/dashboard/static/archive/test_dashboard.html +0 -409
- claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +0 -519
- claude_mpm/dashboard/static/archive/test_dashboard_verification.html +0 -181
- claude_mpm/dashboard/static/archive/test_file_data.html +0 -315
- claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +0 -243
- claude_mpm/dashboard/static/archive/test_file_tree_fix.html +0 -234
- claude_mpm/dashboard/static/archive/test_file_tree_rename.html +0 -117
- claude_mpm/dashboard/static/archive/test_file_tree_tab.html +0 -115
- claude_mpm/dashboard/static/archive/test_file_viewer.html +0 -224
- claude_mpm/dashboard/static/archive/test_final_activity.html +0 -220
- claude_mpm/dashboard/static/archive/test_tab_fix.html +0 -139
- claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +0 -1
- claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
- claude_mpm/dashboard/static/built/components/agent-hierarchy.js +0 -777
- claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
- claude_mpm/dashboard/static/built/components/build-tracker.js +0 -333
- claude_mpm/dashboard/static/built/components/code-simple.js +0 -857
- claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/built/components/code-tree.js +0 -2
- claude_mpm/dashboard/static/built/components/code-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/connection-debug.js +0 -654
- claude_mpm/dashboard/static/built/components/diff-viewer.js +0 -891
- claude_mpm/dashboard/static/built/components/event-processor.js +0 -2
- claude_mpm/dashboard/static/built/components/event-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/export-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/file-change-tracker.js +0 -443
- claude_mpm/dashboard/static/built/components/file-change-viewer.js +0 -690
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
- claude_mpm/dashboard/static/built/components/file-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/hud-library-loader.js +0 -2
- claude_mpm/dashboard/static/built/components/hud-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/hud-visualizer.js +0 -2
- claude_mpm/dashboard/static/built/components/module-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/nav-bar.js +0 -145
- claude_mpm/dashboard/static/built/components/page-structure.js +0 -429
- claude_mpm/dashboard/static/built/components/session-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/socket-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/unified-data-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/working-directory.js +0 -2
- claude_mpm/dashboard/static/built/connection-manager.js +0 -536
- claude_mpm/dashboard/static/built/dashboard.js +0 -2
- claude_mpm/dashboard/static/built/extension-error-handler.js +0 -164
- claude_mpm/dashboard/static/built/react/events.js +0 -30
- claude_mpm/dashboard/static/built/shared/dom-helpers.js +0 -396
- claude_mpm/dashboard/static/built/shared/event-bus.js +0 -330
- claude_mpm/dashboard/static/built/shared/event-filter-service.js +0 -540
- claude_mpm/dashboard/static/built/shared/logger.js +0 -385
- claude_mpm/dashboard/static/built/shared/page-structure.js +0 -249
- claude_mpm/dashboard/static/built/shared/tooltip-service.js +0 -253
- claude_mpm/dashboard/static/built/socket-client.js +0 -2
- claude_mpm/dashboard/static/built/tab-isolation-fix.js +0 -185
- claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +0 -1
- claude_mpm/dashboard/static/dist/components/activity-tree.js +0 -2
- claude_mpm/dashboard/static/dist/components/agent-inference.js +0 -2
- claude_mpm/dashboard/static/dist/components/code-tree.js +0 -2
- claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/event-processor.js +0 -2
- claude_mpm/dashboard/static/dist/components/event-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/export-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +0 -2
- claude_mpm/dashboard/static/dist/components/file-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +0 -2
- claude_mpm/dashboard/static/dist/components/module-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/session-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/socket-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/working-directory.js +0 -2
- claude_mpm/dashboard/static/dist/dashboard.js +0 -2
- claude_mpm/dashboard/static/dist/react/events.js +0 -30
- claude_mpm/dashboard/static/dist/socket-client.js +0 -2
- claude_mpm/dashboard/static/events.html +0 -607
- claude_mpm/dashboard/static/index.html +0 -635
- claude_mpm/dashboard/static/js/shared/dom-helpers.js +0 -396
- claude_mpm/dashboard/static/js/shared/event-bus.js +0 -330
- claude_mpm/dashboard/static/js/shared/logger.js +0 -385
- claude_mpm/dashboard/static/js/shared/tooltip-service.js +0 -253
- claude_mpm/dashboard/static/js/stores/dashboard-store.js +0 -562
- claude_mpm/dashboard/static/legacy/activity.html +0 -736
- claude_mpm/dashboard/static/legacy/agents.html +0 -786
- claude_mpm/dashboard/static/legacy/files.html +0 -747
- claude_mpm/dashboard/static/legacy/tools.html +0 -831
- claude_mpm/dashboard/static/monitors.html +0 -431
- claude_mpm/dashboard/static/production/events.html +0 -659
- claude_mpm/dashboard/static/production/main.html +0 -698
- claude_mpm/dashboard/static/production/monitors.html +0 -483
- claude_mpm/dashboard/static/test-archive/dashboard.html +0 -635
- claude_mpm/dashboard/static/test-archive/debug-events.html +0 -147
- claude_mpm/dashboard/static/test-archive/test-navigation.html +0 -256
- claude_mpm/dashboard/static/test-archive/test-react-exports.html +0 -180
- claude_mpm/dashboard/static/test-archive/test_debug.html +0 -25
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +0 -79
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +0 -178
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +0 -577
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +0 -467
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +0 -537
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +0 -730
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +0 -112
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +0 -146
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +0 -412
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +0 -81
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +0 -362
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +0 -312
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +0 -152
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +0 -668
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +0 -587
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +0 -438
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +0 -391
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +0 -119
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +0 -148
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +0 -483
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +0 -452
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +0 -449
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +0 -411
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +0 -14
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +0 -58
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +0 -68
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +0 -69
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +0 -131
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +0 -325
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +0 -490
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +0 -425
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +0 -499
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +0 -86
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +0 -43
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +0 -47
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +0 -65
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +0 -30
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +0 -16
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +0 -160
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +0 -412
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +0 -602
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +0 -915
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +0 -916
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +0 -752
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +0 -1237
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +0 -189
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +0 -500
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +0 -464
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +0 -619
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +0 -437
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +0 -231
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +0 -170
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +0 -602
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +0 -821
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +0 -742
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +0 -726
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +0 -764
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +0 -831
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +0 -226
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +0 -901
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +0 -901
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +0 -775
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +0 -937
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +0 -770
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +0 -961
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +0 -119
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +0 -253
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +0 -145
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +0 -543
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +0 -741
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +0 -470
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +0 -458
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +0 -639
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +0 -140
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +0 -572
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +0 -411
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +0 -569
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +0 -695
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +0 -184
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +0 -459
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +0 -479
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +0 -687
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +0 -758
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +0 -868
- /claude_mpm/agents/templates/{git_file_tracking.md → git-file-tracking.md} +0 -0
- /claude_mpm/agents/templates/{pm_examples.md → pm-examples.md} +0 -0
- /claude_mpm/agents/templates/{response_format.md → response-format.md} +0 -0
- /claude_mpm/agents/templates/{validation_templates.md → validation-templates.md} +0 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.0.2.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()
|
|
@@ -433,6 +433,12 @@ def sort_items(items):
|
|
|
433
433
|
|
|
434
434
|
### Load Testing
|
|
435
435
|
|
|
436
|
+
> **Note:** Locust is an optional dependency. Install it separately if you need load testing capabilities:
|
|
437
|
+
> ```bash
|
|
438
|
+
> pip install "claude-mpm[agents-load-testing]"
|
|
439
|
+
> ```
|
|
440
|
+
> Or install locust directly: `pip install locust>=2.15.0`
|
|
441
|
+
|
|
436
442
|
```python
|
|
437
443
|
# Using locust for load testing
|
|
438
444
|
from locust import HttpUser, task, between
|
|
@@ -84,7 +84,7 @@ def main():
|
|
|
84
84
|
try:
|
|
85
85
|
# Start all servers
|
|
86
86
|
for i, server in enumerate(servers):
|
|
87
|
-
print(f"Starting server {i+1}/{len(servers)}: {server['cmd']}")
|
|
87
|
+
print(f"Starting server {i + 1}/{len(servers)}: {server['cmd']}")
|
|
88
88
|
|
|
89
89
|
# Use shell=True to support commands with cd and &&
|
|
90
90
|
process = subprocess.Popen(
|
|
@@ -121,7 +121,7 @@ def main():
|
|
|
121
121
|
except subprocess.TimeoutExpired:
|
|
122
122
|
process.kill()
|
|
123
123
|
process.wait()
|
|
124
|
-
print(f"Server {i+1} stopped")
|
|
124
|
+
print(f"Server {i + 1} stopped")
|
|
125
125
|
print("All servers stopped")
|
|
126
126
|
|
|
127
127
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Structured question templates for common PM workflows.
|
|
2
|
+
|
|
3
|
+
This package provides reusable question templates that PM agents can use to gather
|
|
4
|
+
user input in a structured way. Templates are pre-configured QuestionSet objects
|
|
5
|
+
that can be customized based on context.
|
|
6
|
+
|
|
7
|
+
Available Templates:
|
|
8
|
+
- PR Strategy: Questions about PR workflow, draft preferences, auto-merge
|
|
9
|
+
- Project Initialization: Questions about project type, language, frameworks
|
|
10
|
+
- Ticket Management: Questions about ticket prioritization and scope
|
|
11
|
+
|
|
12
|
+
Example Usage:
|
|
13
|
+
>>> from claude_mpm.templates.questions.pr_strategy import PRWorkflowTemplate
|
|
14
|
+
>>> template = PRWorkflowTemplate(num_tickets=3)
|
|
15
|
+
>>> question_set = template.build()
|
|
16
|
+
>>> params = question_set.to_ask_user_question_params()
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from claude_mpm.templates.questions.base import ConditionalTemplate, QuestionTemplate
|
|
20
|
+
from claude_mpm.templates.questions.pr_strategy import PRWorkflowTemplate
|
|
21
|
+
from claude_mpm.templates.questions.project_init import (
|
|
22
|
+
DevelopmentWorkflowTemplate,
|
|
23
|
+
ProjectTypeTemplate,
|
|
24
|
+
)
|
|
25
|
+
from claude_mpm.templates.questions.ticket_mgmt import (
|
|
26
|
+
TicketPrioritizationTemplate,
|
|
27
|
+
TicketScopeTemplate,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"ConditionalTemplate",
|
|
32
|
+
"DevelopmentWorkflowTemplate",
|
|
33
|
+
"PRWorkflowTemplate",
|
|
34
|
+
"ProjectTypeTemplate",
|
|
35
|
+
"QuestionTemplate",
|
|
36
|
+
"TicketPrioritizationTemplate",
|
|
37
|
+
"TicketScopeTemplate",
|
|
38
|
+
]
|