claude-mpm 4.20.3__py3-none-any.whl → 4.25.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_PM.md +23 -6
- claude_mpm/agents/OUTPUT_STYLE.md +3 -48
- claude_mpm/agents/PM_INSTRUCTIONS.md +1783 -34
- claude_mpm/agents/WORKFLOW.md +75 -2
- claude_mpm/agents/base_agent.json +6 -3
- claude_mpm/agents/frontmatter_validator.py +1 -1
- claude_mpm/agents/templates/api_qa.json +5 -2
- claude_mpm/agents/templates/circuit_breakers.md +108 -2
- claude_mpm/agents/templates/documentation.json +33 -6
- claude_mpm/agents/templates/javascript_engineer_agent.json +380 -0
- claude_mpm/agents/templates/php-engineer.json +10 -4
- claude_mpm/agents/templates/pm_red_flags.md +89 -19
- claude_mpm/agents/templates/project_organizer.json +7 -3
- claude_mpm/agents/templates/qa.json +2 -1
- claude_mpm/agents/templates/react_engineer.json +1 -0
- claude_mpm/agents/templates/research.json +82 -12
- claude_mpm/agents/templates/security.json +4 -4
- claude_mpm/agents/templates/tauri_engineer.json +274 -0
- claude_mpm/agents/templates/ticketing.json +10 -6
- claude_mpm/agents/templates/version_control.json +4 -2
- claude_mpm/agents/templates/web_qa.json +2 -1
- claude_mpm/cli/README.md +253 -0
- claude_mpm/cli/__init__.py +11 -1
- claude_mpm/cli/commands/aggregate.py +1 -1
- claude_mpm/cli/commands/analyze.py +3 -3
- claude_mpm/cli/commands/cleanup.py +1 -1
- claude_mpm/cli/commands/configure_agent_display.py +4 -4
- claude_mpm/cli/commands/debug.py +12 -12
- claude_mpm/cli/commands/hook_errors.py +277 -0
- claude_mpm/cli/commands/mcp_install_commands.py +1 -1
- claude_mpm/cli/commands/mcp_install_commands.py.backup +284 -0
- claude_mpm/cli/commands/mpm_init/README.md +365 -0
- claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
- claude_mpm/cli/commands/mpm_init/core.py +573 -0
- claude_mpm/cli/commands/mpm_init/display.py +341 -0
- claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
- claude_mpm/cli/commands/mpm_init/modes.py +397 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
- claude_mpm/cli/commands/mpm_init_cli.py +396 -0
- claude_mpm/cli/commands/mpm_init_handler.py +67 -1
- claude_mpm/cli/commands/run.py +124 -128
- claude_mpm/cli/commands/skills.py +522 -34
- claude_mpm/cli/executor.py +56 -0
- claude_mpm/cli/interactive/agent_wizard.py +5 -5
- claude_mpm/cli/parsers/base_parser.py +28 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +42 -0
- claude_mpm/cli/parsers/skills_parser.py +138 -0
- claude_mpm/cli/startup.py +111 -8
- 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/cli_module/refactoring_guide.md +253 -0
- claude_mpm/commands/mpm-help.md +3 -0
- claude_mpm/commands/mpm-init.md +19 -3
- claude_mpm/commands/mpm-resume.md +372 -0
- claude_mpm/commands/mpm-tickets.md +56 -7
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_capabilities.yaml +658 -0
- claude_mpm/config/async_logging_config.yaml +145 -0
- claude_mpm/constants.py +12 -0
- claude_mpm/core/.claude-mpm/logs/hooks_20250730.log +34 -0
- claude_mpm/core/api_validator.py +1 -1
- claude_mpm/core/claude_runner.py +14 -1
- claude_mpm/core/config.py +8 -0
- claude_mpm/core/constants.py +1 -1
- 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 +48 -3
- claude_mpm/core/interfaces.py +56 -1
- claude_mpm/core/logger.py +3 -1
- claude_mpm/core/oneshot_session.py +39 -0
- claude_mpm/d2/.gitignore +22 -0
- claude_mpm/d2/ARCHITECTURE_COMPARISON.md +273 -0
- claude_mpm/d2/FLASK_INTEGRATION.md +156 -0
- claude_mpm/d2/IMPLEMENTATION_SUMMARY.md +452 -0
- claude_mpm/d2/QUICKSTART.md +186 -0
- claude_mpm/d2/README.md +232 -0
- claude_mpm/d2/STORE_FIX_SUMMARY.md +167 -0
- claude_mpm/d2/SVELTE5_STORES_GUIDE.md +180 -0
- claude_mpm/d2/TESTING.md +288 -0
- claude_mpm/d2/index.html +118 -0
- claude_mpm/d2/package.json +19 -0
- claude_mpm/d2/src/App.svelte +110 -0
- claude_mpm/d2/src/components/Header.svelte +153 -0
- claude_mpm/d2/src/components/MainContent.svelte +74 -0
- claude_mpm/d2/src/components/Sidebar.svelte +85 -0
- claude_mpm/d2/src/components/tabs/EventsTab.svelte +326 -0
- claude_mpm/d2/src/lib/socketio.js +144 -0
- claude_mpm/d2/src/main.js +7 -0
- claude_mpm/d2/src/stores/events.js +114 -0
- claude_mpm/d2/src/stores/socket.js +108 -0
- claude_mpm/d2/src/stores/theme.js +65 -0
- claude_mpm/d2/svelte.config.js +12 -0
- claude_mpm/d2/vite.config.js +15 -0
- claude_mpm/dashboard/.claude-mpm/memories/README.md +36 -0
- claude_mpm/dashboard/BUILD_NUMBER +1 -0
- claude_mpm/dashboard/README.md +121 -0
- claude_mpm/dashboard/VERSION +1 -0
- claude_mpm/dashboard/react/components/DataInspector/DataInspector.tsx +273 -0
- claude_mpm/dashboard/react/components/ErrorBoundary.tsx +75 -0
- claude_mpm/dashboard/react/components/EventViewer/EventViewer.tsx +141 -0
- claude_mpm/dashboard/react/components/shared/ConnectionStatus.tsx +36 -0
- claude_mpm/dashboard/react/components/shared/FilterBar.tsx +89 -0
- claude_mpm/dashboard/react/contexts/DashboardContext.tsx +215 -0
- claude_mpm/dashboard/react/entries/events.tsx +165 -0
- claude_mpm/dashboard/react/hooks/useEvents.ts +191 -0
- claude_mpm/dashboard/react/hooks/useSocket.ts +225 -0
- claude_mpm/dashboard/static/built/REFACTORING_SUMMARY.md +170 -0
- claude_mpm/dashboard/static/built/components/activity-tree.js.map +1 -0
- claude_mpm/dashboard/static/built/components/agent-hierarchy.js +101 -101
- claude_mpm/dashboard/static/built/components/agent-inference.js.map +1 -0
- claude_mpm/dashboard/static/built/components/build-tracker.js +59 -59
- claude_mpm/dashboard/static/built/components/code-simple.js +107 -107
- claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +29 -29
- claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +24 -24
- claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +27 -27
- claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +25 -25
- claude_mpm/dashboard/static/built/components/code-tree.js.map +1 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/connection-debug.js +101 -101
- claude_mpm/dashboard/static/built/components/diff-viewer.js +113 -113
- claude_mpm/dashboard/static/built/components/event-processor.js.map +1 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/export-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/file-change-tracker.js +57 -57
- claude_mpm/dashboard/static/built/components/file-change-viewer.js +74 -74
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js.map +1 -0
- claude_mpm/dashboard/static/built/components/file-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/hud-library-loader.js.map +1 -0
- claude_mpm/dashboard/static/built/components/hud-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/hud-visualizer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/module-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/session-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/socket-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/ui-state-manager.js.map +1 -0
- claude_mpm/dashboard/static/built/components/unified-data-viewer.js.map +1 -0
- claude_mpm/dashboard/static/built/components/working-directory.js.map +1 -0
- claude_mpm/dashboard/static/built/connection-manager.js +76 -76
- claude_mpm/dashboard/static/built/dashboard.js.map +1 -0
- claude_mpm/dashboard/static/built/extension-error-handler.js +22 -22
- claude_mpm/dashboard/static/built/react/events.js.map +1 -0
- claude_mpm/dashboard/static/built/shared/dom-helpers.js +9 -9
- claude_mpm/dashboard/static/built/shared/event-bus.js +5 -5
- claude_mpm/dashboard/static/built/shared/logger.js +16 -16
- claude_mpm/dashboard/static/built/shared/tooltip-service.js +6 -6
- claude_mpm/dashboard/static/built/socket-client.js.map +1 -0
- 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/index.html +22 -22
- claude_mpm/dashboard/static/js/REFACTORING_SUMMARY.md +170 -0
- 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/shared/dom-helpers.js +9 -9
- claude_mpm/dashboard/static/js/shared/event-bus.js +5 -5
- claude_mpm/dashboard/static/js/shared/logger.js +16 -16
- claude_mpm/dashboard/static/js/shared/tooltip-service.js +6 -6
- claude_mpm/dashboard/static/js/socket-client.js +138 -121
- claude_mpm/dashboard/static/navigation-test-results.md +118 -0
- claude_mpm/dashboard/static/production/main.html +21 -21
- claude_mpm/dashboard/static/test-archive/dashboard.html +22 -22
- claude_mpm/dashboard/templates/.claude-mpm/memories/README.md +36 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/engineer_agent.md +39 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/version_control_agent.md +38 -0
- claude_mpm/dashboard/templates/code_simple.html +23 -23
- claude_mpm/dashboard/templates/index.html +18 -18
- claude_mpm/hooks/README.md +143 -0
- 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/templates/README.md +180 -0
- claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
- claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
- claude_mpm/hooks/templates/settings.json.example +147 -0
- claude_mpm/schemas/agent_schema.json +596 -0
- claude_mpm/schemas/frontmatter_schema.json +165 -0
- claude_mpm/scripts/claude-hook-handler.sh +3 -3
- claude_mpm/scripts/start_activity_logging.py +3 -1
- claude_mpm/services/agents/deployment/agent_format_converter.py +1 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
- claude_mpm/services/agents/loading/framework_agent_loader.py +8 -8
- claude_mpm/services/agents/local_template_manager.py +3 -1
- claude_mpm/services/cli/session_pause_manager.py +504 -0
- claude_mpm/services/cli/session_resume_helper.py +36 -16
- claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
- claude_mpm/services/core/base.py +26 -11
- claude_mpm/services/core/interfaces.py +56 -1
- claude_mpm/services/core/models/agent_config.py +3 -0
- claude_mpm/services/core/models/process.py +4 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +0 -2
- 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/doctor_reporter.py +6 -4
- claude_mpm/services/diagnostics/models.py +21 -0
- claude_mpm/services/event_bus/README.md +244 -0
- claude_mpm/services/event_bus/direct_relay.py +3 -3
- claude_mpm/services/event_bus/event_bus.py +36 -3
- claude_mpm/services/event_bus/relay.py +23 -7
- claude_mpm/services/events/README.md +303 -0
- claude_mpm/services/events/consumers/logging.py +1 -2
- claude_mpm/services/framework_claude_md_generator/README.md +119 -0
- claude_mpm/services/infrastructure/monitoring/resources.py +1 -1
- claude_mpm/services/local_ops/__init__.py +2 -0
- 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/README.md +185 -0
- claude_mpm/services/mcp_gateway/auto_configure.py +31 -25
- claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
- claude_mpm/services/mcp_gateway/core/process_pool.py +19 -10
- 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/external_mcp_services.py +26 -21
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +6 -2
- claude_mpm/services/memory/failure_tracker.py +19 -4
- 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/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_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/connection.py.backup +217 -0
- claude_mpm/services/socketio/handlers/git.py +2 -2
- claude_mpm/services/socketio/handlers/hook.py.backup +154 -0
- claude_mpm/services/static/.gitkeep +2 -0
- 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/version_control/VERSION +1 -0
- claude_mpm/services/version_control/conflict_resolution.py +6 -4
- claude_mpm/services/visualization/mermaid_generator.py +2 -3
- claude_mpm/skills/__init__.py +3 -3
- claude_mpm/skills/agent_skills_injector.py +42 -49
- claude_mpm/skills/bundled/.gitkeep +2 -0
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +4 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +108 -114
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +46 -41
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +36 -73
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +100 -125
- claude_mpm/skills/bundled/debugging/root-cause-tracing/find-polluter.sh +63 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +28 -72
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +11 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +272 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
- claude_mpm/skills/bundled/main/artifacts-builder/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +13 -1
- claude_mpm/skills/bundled/main/artifacts-builder/scripts/bundle-artifact.sh +54 -0
- claude_mpm/skills/bundled/main/artifacts-builder/scripts/init-artifact.sh +322 -0
- claude_mpm/skills/bundled/main/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- claude_mpm/skills/bundled/main/internal-comms/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +11 -0
- claude_mpm/skills/bundled/main/mcp-builder/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +109 -277
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +17 -10
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +92 -39
- claude_mpm/skills/bundled/main/mcp-builder/scripts/example_evaluation.xml +22 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/requirements.txt +2 -0
- claude_mpm/skills/bundled/main/skill-creator/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +135 -155
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +13 -12
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +5 -3
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +19 -12
- claude_mpm/skills/bundled/performance-profiling.md +6 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +21 -25
- claude_mpm/skills/bundled/testing/condition-based-waiting/example.ts +158 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +86 -250
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/LICENSE.txt +202 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +145 -57
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +6 -6
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +13 -9
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +8 -8
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +37 -15
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/skills_registry.py +44 -48
- claude_mpm/skills/skills_service.py +117 -108
- claude_mpm/templates/questions/EXAMPLES.md +501 -0
- claude_mpm/templates/questions/__init__.py +43 -0
- claude_mpm/templates/questions/base.py +193 -0
- claude_mpm/templates/questions/pr_strategy.py +314 -0
- claude_mpm/templates/questions/project_init.py +388 -0
- claude_mpm/templates/questions/ticket_mgmt.py +397 -0
- claude_mpm/tools/README_SOCKETIO_DEBUG.md +224 -0
- claude_mpm/tools/__main__.py +8 -8
- claude_mpm/tools/code_tree_analyzer/README.md +64 -0
- claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
- claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
- claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
- claude_mpm/tools/code_tree_analyzer/core.py +380 -0
- claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
- claude_mpm/tools/code_tree_analyzer/events.py +168 -0
- claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
- claude_mpm/tools/code_tree_analyzer/models.py +39 -0
- claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
- claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
- claude_mpm/utils/agent_dependency_loader.py +3 -3
- 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/robust_installer.py +3 -5
- claude_mpm/utils/structured_questions.py +619 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/METADATA +218 -31
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/RECORD +409 -246
- 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/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/cli/commands/mpm_init.py +0 -2093
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
- 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/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/test-archive/test_debug.html +0 -25
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/common-failures.md +0 -213
- claude_mpm/tools/code_tree_analyzer.py +0 -1825
- /claude_mpm/skills/bundled/collaboration/requesting-code-review/{code-reviewer.md → references/code-reviewer-template.md} +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/WHEEL +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-4.25.10.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,831 @@
|
|
|
1
|
+
# Testing and Debugging Reference
|
|
2
|
+
|
|
3
|
+
## Unit Testing
|
|
4
|
+
|
|
5
|
+
EspoCRM supports PHPUnit for testing.
|
|
6
|
+
|
|
7
|
+
### Test Setup
|
|
8
|
+
|
|
9
|
+
Install PHPUnit in your extension:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
composer require --dev phpunit/phpunit
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Create `phpunit.xml`:
|
|
16
|
+
|
|
17
|
+
```xml
|
|
18
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
19
|
+
<phpunit
|
|
20
|
+
bootstrap="tests/bootstrap.php"
|
|
21
|
+
colors="true"
|
|
22
|
+
convertErrorsToExceptions="true"
|
|
23
|
+
convertNoticesToExceptions="true"
|
|
24
|
+
convertWarningsToExceptions="true"
|
|
25
|
+
stopOnFailure="false">
|
|
26
|
+
<testsuites>
|
|
27
|
+
<testsuite name="Unit Tests">
|
|
28
|
+
<directory>tests/unit</directory>
|
|
29
|
+
</testsuite>
|
|
30
|
+
<testsuite name="Integration Tests">
|
|
31
|
+
<directory>tests/integration</directory>
|
|
32
|
+
</testsuite>
|
|
33
|
+
</testsuites>
|
|
34
|
+
</phpunit>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Unit Test Example
|
|
38
|
+
|
|
39
|
+
Create `tests/unit/MyServiceTest.php`:
|
|
40
|
+
|
|
41
|
+
```php
|
|
42
|
+
<?php
|
|
43
|
+
namespace Espo\Modules\MyModule\Tests\Unit;
|
|
44
|
+
|
|
45
|
+
use PHPUnit\Framework\TestCase;
|
|
46
|
+
use Espo\Modules\MyModule\Services\MyEntity;
|
|
47
|
+
use Espo\ORM\EntityManager;
|
|
48
|
+
use Espo\Core\Acl;
|
|
49
|
+
use Espo\Entities\User;
|
|
50
|
+
|
|
51
|
+
class MyServiceTest extends TestCase
|
|
52
|
+
{
|
|
53
|
+
private MyEntity $service;
|
|
54
|
+
private EntityManager $entityManager;
|
|
55
|
+
private Acl $acl;
|
|
56
|
+
private User $user;
|
|
57
|
+
|
|
58
|
+
protected function setUp(): void
|
|
59
|
+
{
|
|
60
|
+
parent::setUp();
|
|
61
|
+
|
|
62
|
+
// Create mocks
|
|
63
|
+
$this->entityManager = $this->createMock(EntityManager::class);
|
|
64
|
+
$this->acl = $this->createMock(Acl::class);
|
|
65
|
+
$this->user = $this->createMock(User::class);
|
|
66
|
+
|
|
67
|
+
// Create service with mocked dependencies
|
|
68
|
+
$this->service = new MyEntity();
|
|
69
|
+
|
|
70
|
+
// Inject dependencies via reflection (if needed)
|
|
71
|
+
$reflection = new \ReflectionClass($this->service);
|
|
72
|
+
$property = $reflection->getProperty('entityManager');
|
|
73
|
+
$property->setAccessible(true);
|
|
74
|
+
$property->setValue($this->service, $this->entityManager);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public function testCalculateTotal(): void
|
|
78
|
+
{
|
|
79
|
+
// Arrange
|
|
80
|
+
$entity = $this->createMock(\Espo\ORM\Entity::class);
|
|
81
|
+
|
|
82
|
+
$entity->method('get')
|
|
83
|
+
->willReturnMap([
|
|
84
|
+
['quantity', null, 5],
|
|
85
|
+
['unitPrice', null, 10.50]
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
// Act
|
|
89
|
+
$total = $this->service->calculateTotal($entity);
|
|
90
|
+
|
|
91
|
+
// Assert
|
|
92
|
+
$this->assertEquals(52.50, $total);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public function testValidateThrowsExceptionForInvalidData(): void
|
|
96
|
+
{
|
|
97
|
+
// Arrange
|
|
98
|
+
$entity = $this->createMock(\Espo\ORM\Entity::class);
|
|
99
|
+
$entity->method('get')
|
|
100
|
+
->willReturn(-100);
|
|
101
|
+
|
|
102
|
+
// Assert
|
|
103
|
+
$this->expectException(\Espo\Core\Exceptions\BadRequest::class);
|
|
104
|
+
$this->expectExceptionMessage('Amount cannot be negative');
|
|
105
|
+
|
|
106
|
+
// Act
|
|
107
|
+
$this->service->validate($entity);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public function testCreateEntitySetsDefaults(): void
|
|
111
|
+
{
|
|
112
|
+
// Arrange
|
|
113
|
+
$entity = $this->createMock(\Espo\ORM\Entity::class);
|
|
114
|
+
|
|
115
|
+
$this->user->method('getId')
|
|
116
|
+
->willReturn('user-123');
|
|
117
|
+
|
|
118
|
+
$entity->expects($this->once())
|
|
119
|
+
->method('set')
|
|
120
|
+
->with('assignedUserId', 'user-123');
|
|
121
|
+
|
|
122
|
+
// Act
|
|
123
|
+
$this->service->setDefaults($entity);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Integration Test Example
|
|
129
|
+
|
|
130
|
+
Create `tests/integration/HookTest.php`:
|
|
131
|
+
|
|
132
|
+
```php
|
|
133
|
+
<?php
|
|
134
|
+
namespace Espo\Modules\MyModule\Tests\Integration;
|
|
135
|
+
|
|
136
|
+
use PHPUnit\Framework\TestCase;
|
|
137
|
+
use Espo\Core\Container;
|
|
138
|
+
use Espo\ORM\EntityManager;
|
|
139
|
+
|
|
140
|
+
class HookTest extends TestCase
|
|
141
|
+
{
|
|
142
|
+
private Container $container;
|
|
143
|
+
private EntityManager $entityManager;
|
|
144
|
+
|
|
145
|
+
protected function setUp(): void
|
|
146
|
+
{
|
|
147
|
+
parent::setUp();
|
|
148
|
+
|
|
149
|
+
// Load EspoCRM container (requires EspoCRM installation)
|
|
150
|
+
require_once 'bootstrap.php';
|
|
151
|
+
|
|
152
|
+
$this->container = $GLOBALS['container'];
|
|
153
|
+
$this->entityManager = $this->container->get('entityManager');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public function testAccountHookUpdatesRelatedContacts(): void
|
|
157
|
+
{
|
|
158
|
+
// Create test account
|
|
159
|
+
$account = $this->entityManager->getNewEntity('Account');
|
|
160
|
+
$account->set('name', 'Test Account');
|
|
161
|
+
$this->entityManager->saveEntity($account);
|
|
162
|
+
|
|
163
|
+
// Create related contact
|
|
164
|
+
$contact = $this->entityManager->getNewEntity('Contact');
|
|
165
|
+
$contact->set([
|
|
166
|
+
'firstName' => 'John',
|
|
167
|
+
'lastName' => 'Doe',
|
|
168
|
+
'accountId' => $account->getId()
|
|
169
|
+
]);
|
|
170
|
+
$this->entityManager->saveEntity($contact);
|
|
171
|
+
|
|
172
|
+
// Update account status
|
|
173
|
+
$account->set('status', 'Inactive');
|
|
174
|
+
$this->entityManager->saveEntity($account);
|
|
175
|
+
|
|
176
|
+
// Refresh contact
|
|
177
|
+
$contact = $this->entityManager->getEntityById('Contact', $contact->getId());
|
|
178
|
+
|
|
179
|
+
// Assert hook updated contact
|
|
180
|
+
$this->assertEquals('Inactive', $contact->get('accountStatus'));
|
|
181
|
+
|
|
182
|
+
// Cleanup
|
|
183
|
+
$this->entityManager->removeEntity($contact);
|
|
184
|
+
$this->entityManager->removeEntity($account);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Running Tests
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Run all tests
|
|
193
|
+
vendor/bin/phpunit
|
|
194
|
+
|
|
195
|
+
# Run specific test file
|
|
196
|
+
vendor/bin/phpunit tests/unit/MyServiceTest.php
|
|
197
|
+
|
|
198
|
+
# Run specific test method
|
|
199
|
+
vendor/bin/phpunit --filter testCalculateTotal
|
|
200
|
+
|
|
201
|
+
# Run with coverage
|
|
202
|
+
vendor/bin/phpunit --coverage-html coverage
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Debugging Techniques
|
|
206
|
+
|
|
207
|
+
### Enable Debug Mode
|
|
208
|
+
|
|
209
|
+
Edit `data/config.php`:
|
|
210
|
+
|
|
211
|
+
```php
|
|
212
|
+
<?php
|
|
213
|
+
return [
|
|
214
|
+
// ... other config ...
|
|
215
|
+
'logger' => [
|
|
216
|
+
'level' => 'DEBUG', // Change from 'WARNING' to 'DEBUG'
|
|
217
|
+
'maxFileNumber' => 30,
|
|
218
|
+
],
|
|
219
|
+
'isDeveloperMode' => true, // Enable developer mode
|
|
220
|
+
];
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Logging
|
|
224
|
+
|
|
225
|
+
```php
|
|
226
|
+
<?php
|
|
227
|
+
namespace Espo\Modules\MyModule\Services;
|
|
228
|
+
|
|
229
|
+
use Espo\Core\Utils\Log;
|
|
230
|
+
|
|
231
|
+
class MyService
|
|
232
|
+
{
|
|
233
|
+
public function __construct(private Log $log) {}
|
|
234
|
+
|
|
235
|
+
public function processData(array $data): void
|
|
236
|
+
{
|
|
237
|
+
// Debug logging
|
|
238
|
+
$this->log->debug('Processing data', ['data' => $data]);
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
// ... processing ...
|
|
242
|
+
|
|
243
|
+
$this->log->info('Data processed successfully', ['count' => count($data)]);
|
|
244
|
+
} catch (\Throwable $e) {
|
|
245
|
+
$this->log->error('Failed to process data: ' . $e->getMessage(), [
|
|
246
|
+
'exception' => $e,
|
|
247
|
+
'trace' => $e->getTraceAsString()
|
|
248
|
+
]);
|
|
249
|
+
|
|
250
|
+
throw $e;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
public function debugQuery(): void
|
|
255
|
+
{
|
|
256
|
+
$query = $this->entityManager
|
|
257
|
+
->getQueryBuilder()
|
|
258
|
+
->select()
|
|
259
|
+
->from('Account')
|
|
260
|
+
->where(['type' => 'Customer'])
|
|
261
|
+
->build();
|
|
262
|
+
|
|
263
|
+
// Log the SQL query
|
|
264
|
+
$sql = $this->entityManager->getQueryComposer()->compose($query);
|
|
265
|
+
$this->log->debug('SQL Query', ['sql' => $sql]);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Check Logs
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
# Today's log
|
|
274
|
+
tail -f data/logs/espo-$(date +%Y-%m-%d).log
|
|
275
|
+
|
|
276
|
+
# Search logs
|
|
277
|
+
grep "ERROR" data/logs/espo-*.log
|
|
278
|
+
|
|
279
|
+
# Filter by component
|
|
280
|
+
grep "MyService" data/logs/espo-*.log
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### XDebug Setup
|
|
284
|
+
|
|
285
|
+
Install XDebug PHP extension:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# Ubuntu/Debian
|
|
289
|
+
sudo apt-get install php-xdebug
|
|
290
|
+
|
|
291
|
+
# macOS (Homebrew)
|
|
292
|
+
brew install php-xdebug
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Configure XDebug in `php.ini`:
|
|
296
|
+
|
|
297
|
+
```ini
|
|
298
|
+
[xdebug]
|
|
299
|
+
zend_extension=xdebug.so
|
|
300
|
+
xdebug.mode=debug
|
|
301
|
+
xdebug.start_with_request=yes
|
|
302
|
+
xdebug.client_host=127.0.0.1
|
|
303
|
+
xdebug.client_port=9003
|
|
304
|
+
xdebug.idekey=PHPSTORM
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Step Debugging with PhpStorm
|
|
308
|
+
|
|
309
|
+
1. Set breakpoints in code
|
|
310
|
+
2. Click "Start Listening for PHP Debug Connections"
|
|
311
|
+
3. Trigger the code path (API call, scheduled job, etc.)
|
|
312
|
+
4. PhpStorm will pause at breakpoints
|
|
313
|
+
|
|
314
|
+
### Debug API Requests
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# Using curl with verbose output
|
|
318
|
+
curl -v -X GET \
|
|
319
|
+
'http://espocrm.local/api/v1/Account/123' \
|
|
320
|
+
-H 'X-Api-Key: your-api-key'
|
|
321
|
+
|
|
322
|
+
# Debug POST request
|
|
323
|
+
curl -v -X POST \
|
|
324
|
+
'http://espocrm.local/api/v1/Account' \
|
|
325
|
+
-H 'Content-Type: application/json' \
|
|
326
|
+
-H 'X-Api-Key: your-api-key' \
|
|
327
|
+
-d '{
|
|
328
|
+
"name": "Test Account",
|
|
329
|
+
"type": "Customer"
|
|
330
|
+
}'
|
|
331
|
+
|
|
332
|
+
# Save response to file for analysis
|
|
333
|
+
curl -X GET \
|
|
334
|
+
'http://espocrm.local/api/v1/Account' \
|
|
335
|
+
-H 'X-Api-Key: your-api-key' \
|
|
336
|
+
-o response.json
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Browser DevTools for Frontend Debugging
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
// Add console logging in custom views
|
|
343
|
+
define('custom:views/my-view', ['view'], function (Dep) {
|
|
344
|
+
return Dep.extend({
|
|
345
|
+
setup: function () {
|
|
346
|
+
Dep.prototype.setup.call(this);
|
|
347
|
+
|
|
348
|
+
console.log('View setup', {
|
|
349
|
+
model: this.model.attributes,
|
|
350
|
+
options: this.options
|
|
351
|
+
});
|
|
352
|
+
},
|
|
353
|
+
|
|
354
|
+
afterRender: function () {
|
|
355
|
+
Dep.prototype.afterRender.call(this);
|
|
356
|
+
|
|
357
|
+
console.log('View rendered', {
|
|
358
|
+
el: this.$el,
|
|
359
|
+
modelId: this.model.id
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Debug AJAX requests
|
|
366
|
+
this.ajaxPostRequest('Account/action/myAction', data)
|
|
367
|
+
.then(response => {
|
|
368
|
+
console.log('Response received', response);
|
|
369
|
+
})
|
|
370
|
+
.catch(xhr => {
|
|
371
|
+
console.error('Request failed', {
|
|
372
|
+
status: xhr.status,
|
|
373
|
+
response: xhr.responseJSON,
|
|
374
|
+
error: xhr.responseText
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Database Debugging
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
# Connect to MySQL
|
|
383
|
+
mysql -u espocrm_user -p espocrm_db
|
|
384
|
+
|
|
385
|
+
# Enable query logging
|
|
386
|
+
SET GLOBAL general_log = 'ON';
|
|
387
|
+
SET GLOBAL log_output = 'TABLE';
|
|
388
|
+
|
|
389
|
+
# View query log
|
|
390
|
+
SELECT * FROM mysql.general_log
|
|
391
|
+
WHERE command_type = 'Query'
|
|
392
|
+
ORDER BY event_time DESC
|
|
393
|
+
LIMIT 100;
|
|
394
|
+
|
|
395
|
+
# Disable query logging
|
|
396
|
+
SET GLOBAL general_log = 'OFF';
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### SQL Query Analysis
|
|
400
|
+
|
|
401
|
+
```php
|
|
402
|
+
// Log query execution time
|
|
403
|
+
$startTime = microtime(true);
|
|
404
|
+
|
|
405
|
+
$result = $this->entityManager
|
|
406
|
+
->getRDBRepository('Account')
|
|
407
|
+
->where(['type' => 'Customer'])
|
|
408
|
+
->find();
|
|
409
|
+
|
|
410
|
+
$executionTime = microtime(true) - $startTime;
|
|
411
|
+
|
|
412
|
+
$this->log->debug('Query execution time', [
|
|
413
|
+
'time' => $executionTime,
|
|
414
|
+
'count' => count($result)
|
|
415
|
+
]);
|
|
416
|
+
|
|
417
|
+
// Explain query
|
|
418
|
+
$query = $this->entityManager
|
|
419
|
+
->getQueryBuilder()
|
|
420
|
+
->select()
|
|
421
|
+
->from('Account')
|
|
422
|
+
->where(['type' => 'Customer'])
|
|
423
|
+
->build();
|
|
424
|
+
|
|
425
|
+
$sql = $this->entityManager->getQueryComposer()->compose($query);
|
|
426
|
+
|
|
427
|
+
$pdo = $this->entityManager->getPDO();
|
|
428
|
+
$sth = $pdo->prepare('EXPLAIN ' . $sql);
|
|
429
|
+
$sth->execute();
|
|
430
|
+
|
|
431
|
+
$explain = $sth->fetchAll(\PDO::FETCH_ASSOC);
|
|
432
|
+
$this->log->debug('Query explain', ['explain' => $explain]);
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## Performance Optimization
|
|
436
|
+
|
|
437
|
+
### Use STH Collections for Large Datasets
|
|
438
|
+
|
|
439
|
+
```php
|
|
440
|
+
// ❌ WRONG - Loads all records into memory
|
|
441
|
+
$contacts = $this->entityManager
|
|
442
|
+
->getRDBRepository('Contact')
|
|
443
|
+
->find();
|
|
444
|
+
|
|
445
|
+
foreach ($contacts as $contact) {
|
|
446
|
+
// Process
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// ✅ CORRECT - Streams records one at a time
|
|
450
|
+
$sthCollection = $this->entityManager
|
|
451
|
+
->getRDBRepository('Contact')
|
|
452
|
+
->sth()
|
|
453
|
+
->find();
|
|
454
|
+
|
|
455
|
+
foreach ($sthCollection as $contact) {
|
|
456
|
+
// Process without loading all into memory
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Batch Operations
|
|
461
|
+
|
|
462
|
+
```php
|
|
463
|
+
// ❌ WRONG - One query per update
|
|
464
|
+
$accounts = $this->entityManager
|
|
465
|
+
->getRDBRepository('Account')
|
|
466
|
+
->where(['type' => 'Customer'])
|
|
467
|
+
->find();
|
|
468
|
+
|
|
469
|
+
foreach ($accounts as $account) {
|
|
470
|
+
$account->set('updated', true);
|
|
471
|
+
$this->entityManager->saveEntity($account); // Individual query
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// ✅ CORRECT - Batch update with single query
|
|
475
|
+
$this->entityManager
|
|
476
|
+
->getQueryBuilder()
|
|
477
|
+
->update()
|
|
478
|
+
->in('Account')
|
|
479
|
+
->set(['updated' => true])
|
|
480
|
+
->where(['type' => 'Customer'])
|
|
481
|
+
->build()
|
|
482
|
+
->execute();
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Query Optimization
|
|
486
|
+
|
|
487
|
+
```php
|
|
488
|
+
// ❌ WRONG - N+1 queries
|
|
489
|
+
$opportunities = $this->entityManager
|
|
490
|
+
->getRDBRepository('Opportunity')
|
|
491
|
+
->find();
|
|
492
|
+
|
|
493
|
+
foreach ($opportunities as $opportunity) {
|
|
494
|
+
// Each iteration makes a query for account
|
|
495
|
+
$account = $this->entityManager
|
|
496
|
+
->getEntityById('Account', $opportunity->get('accountId'));
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// ✅ CORRECT - Single query with JOIN
|
|
500
|
+
$opportunities = $this->entityManager
|
|
501
|
+
->getRDBRepository('Opportunity')
|
|
502
|
+
->distinct()
|
|
503
|
+
->join('account')
|
|
504
|
+
->select(['*', 'account.name AS accountName'])
|
|
505
|
+
->find();
|
|
506
|
+
|
|
507
|
+
foreach ($opportunities as $opportunity) {
|
|
508
|
+
// Account name already loaded
|
|
509
|
+
$accountName = $opportunity->get('accountName');
|
|
510
|
+
}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Caching
|
|
514
|
+
|
|
515
|
+
```php
|
|
516
|
+
use Espo\Core\Utils\DataCache;
|
|
517
|
+
|
|
518
|
+
class MyService
|
|
519
|
+
{
|
|
520
|
+
public function __construct(private DataCache $dataCache) {}
|
|
521
|
+
|
|
522
|
+
public function getExpensiveData(): array
|
|
523
|
+
{
|
|
524
|
+
$cacheKey = 'myExpensiveData';
|
|
525
|
+
|
|
526
|
+
// Try to get from cache
|
|
527
|
+
if ($this->dataCache->has($cacheKey)) {
|
|
528
|
+
return $this->dataCache->get($cacheKey);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Calculate if not cached
|
|
532
|
+
$data = $this->performExpensiveCalculation();
|
|
533
|
+
|
|
534
|
+
// Store in cache for 1 hour
|
|
535
|
+
$this->dataCache->store($cacheKey, $data, 3600);
|
|
536
|
+
|
|
537
|
+
return $data;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
private function performExpensiveCalculation(): array
|
|
541
|
+
{
|
|
542
|
+
// Expensive operation
|
|
543
|
+
return [];
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Profiling with Xdebug
|
|
549
|
+
|
|
550
|
+
```php
|
|
551
|
+
// Enable profiling in php.ini
|
|
552
|
+
xdebug.mode=profile
|
|
553
|
+
xdebug.output_dir=/tmp/xdebug
|
|
554
|
+
xdebug.start_with_request=trigger
|
|
555
|
+
|
|
556
|
+
// Trigger with request parameter
|
|
557
|
+
// http://espocrm.local/api/v1/Account?XDEBUG_PROFILE=1
|
|
558
|
+
|
|
559
|
+
// Analyze with tools like:
|
|
560
|
+
// - KCachegrind (Linux)
|
|
561
|
+
// - QCachegrind (macOS/Windows)
|
|
562
|
+
// - PhpStorm built-in profiler
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
## Common Pitfalls and Solutions
|
|
566
|
+
|
|
567
|
+
### Pitfall 1: Infinite Hook Loops
|
|
568
|
+
|
|
569
|
+
**Problem:**
|
|
570
|
+
```php
|
|
571
|
+
// Hook triggers itself infinitely
|
|
572
|
+
class MyHook implements AfterSave {
|
|
573
|
+
public function afterSave(Entity $entity, array $options): void {
|
|
574
|
+
$entity->set('updated', true);
|
|
575
|
+
$this->entityManager->saveEntity($entity); // Triggers hook again!
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Solution:**
|
|
581
|
+
```php
|
|
582
|
+
class MyHook implements AfterSave {
|
|
583
|
+
public function afterSave(Entity $entity, array $options): void {
|
|
584
|
+
// Check if already processing
|
|
585
|
+
if (!empty($options['skipHooks'])) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
$entity->set('updated', true);
|
|
590
|
+
$this->entityManager->saveEntity($entity, ['skipHooks' => true]);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
### Pitfall 2: Missing Cache Rebuild
|
|
596
|
+
|
|
597
|
+
**Problem:**
|
|
598
|
+
- Metadata changes not reflected
|
|
599
|
+
- New classes not found
|
|
600
|
+
|
|
601
|
+
**Solution:**
|
|
602
|
+
```bash
|
|
603
|
+
# Always rebuild after metadata or class changes
|
|
604
|
+
bin/command rebuild
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
### Pitfall 3: Type Mismatches
|
|
608
|
+
|
|
609
|
+
**Problem:**
|
|
610
|
+
```php
|
|
611
|
+
// Method expects string, gets null
|
|
612
|
+
public function process(string $id): void {
|
|
613
|
+
// $id is null, causes error
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
**Solution:**
|
|
618
|
+
```php
|
|
619
|
+
// Use nullable types
|
|
620
|
+
public function process(?string $id): void {
|
|
621
|
+
if (!$id) {
|
|
622
|
+
throw new BadRequest('ID is required');
|
|
623
|
+
}
|
|
624
|
+
// Process
|
|
625
|
+
}
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Pitfall 4: Container Dependency
|
|
629
|
+
|
|
630
|
+
**Problem:**
|
|
631
|
+
```php
|
|
632
|
+
// Tight coupling to Container
|
|
633
|
+
class MyService {
|
|
634
|
+
public function __construct(private Container $container) {}
|
|
635
|
+
}
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
**Solution:**
|
|
639
|
+
```php
|
|
640
|
+
// Inject specific dependencies
|
|
641
|
+
class MyService {
|
|
642
|
+
public function __construct(
|
|
643
|
+
private EntityManager $entityManager,
|
|
644
|
+
private Metadata $metadata
|
|
645
|
+
) {}
|
|
646
|
+
}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Pitfall 5: Not Using Transactions
|
|
650
|
+
|
|
651
|
+
**Problem:**
|
|
652
|
+
```php
|
|
653
|
+
// Partial updates on error
|
|
654
|
+
$entity1->set('status', 'Processing');
|
|
655
|
+
$this->entityManager->saveEntity($entity1);
|
|
656
|
+
|
|
657
|
+
// Error occurs here
|
|
658
|
+
throw new \Exception('Error');
|
|
659
|
+
|
|
660
|
+
// entity2 never updated, data inconsistent
|
|
661
|
+
$entity2->set('status', 'Complete');
|
|
662
|
+
$this->entityManager->saveEntity($entity2);
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
**Solution:**
|
|
666
|
+
```php
|
|
667
|
+
use Espo\ORM\TransactionManager;
|
|
668
|
+
|
|
669
|
+
// Atomic operation
|
|
670
|
+
$this->transactionManager->run(function () {
|
|
671
|
+
$entity1->set('status', 'Processing');
|
|
672
|
+
$this->entityManager->saveEntity($entity1);
|
|
673
|
+
|
|
674
|
+
// If error occurs, both changes rolled back
|
|
675
|
+
if ($error) {
|
|
676
|
+
throw new \Exception('Error');
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
$entity2->set('status', 'Complete');
|
|
680
|
+
$this->entityManager->saveEntity($entity2);
|
|
681
|
+
});
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### Pitfall 6: Direct PDO Usage
|
|
685
|
+
|
|
686
|
+
**Problem:**
|
|
687
|
+
```php
|
|
688
|
+
// Bypassing ORM
|
|
689
|
+
$pdo = $this->entityManager->getPDO();
|
|
690
|
+
$pdo->query("INSERT INTO account (name) VALUES ('Test')");
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
**Solution:**
|
|
694
|
+
```php
|
|
695
|
+
// Use ORM
|
|
696
|
+
$account = $this->entityManager->getNewEntity('Account');
|
|
697
|
+
$account->set('name', 'Test');
|
|
698
|
+
$this->entityManager->saveEntity($account);
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### Pitfall 7: Memory Exhaustion
|
|
702
|
+
|
|
703
|
+
**Problem:**
|
|
704
|
+
```php
|
|
705
|
+
// Loading 100k records into memory
|
|
706
|
+
$contacts = $this->entityManager
|
|
707
|
+
->getRDBRepository('Contact')
|
|
708
|
+
->find(); // Memory exhausted!
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
**Solution:**
|
|
712
|
+
```php
|
|
713
|
+
// Use STH collection
|
|
714
|
+
$sthCollection = $this->entityManager
|
|
715
|
+
->getRDBRepository('Contact')
|
|
716
|
+
->sth()
|
|
717
|
+
->find();
|
|
718
|
+
|
|
719
|
+
foreach ($sthCollection as $contact) {
|
|
720
|
+
// Process one at a time
|
|
721
|
+
}
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
## Error Handling Best Practices
|
|
725
|
+
|
|
726
|
+
### Use Specific Exceptions
|
|
727
|
+
|
|
728
|
+
```php
|
|
729
|
+
use Espo\Core\Exceptions\{
|
|
730
|
+
BadRequest,
|
|
731
|
+
Forbidden,
|
|
732
|
+
NotFound,
|
|
733
|
+
Conflict,
|
|
734
|
+
Error
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
class MyService {
|
|
738
|
+
public function process(string $id): Entity {
|
|
739
|
+
// Validate input
|
|
740
|
+
if (!$id) {
|
|
741
|
+
throw new BadRequest('ID is required');
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// Check existence
|
|
745
|
+
$entity = $this->entityManager->getEntityById('Account', $id);
|
|
746
|
+
if (!$entity) {
|
|
747
|
+
throw new NotFound('Account not found');
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Check permissions
|
|
751
|
+
if (!$this->acl->check($entity, 'edit')) {
|
|
752
|
+
throw new Forbidden('No edit access');
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Check business rules
|
|
756
|
+
if ($entity->get('locked')) {
|
|
757
|
+
throw new Conflict('Account is locked');
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// Process...
|
|
761
|
+
return $entity;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
### Try-Catch Patterns
|
|
767
|
+
|
|
768
|
+
```php
|
|
769
|
+
// Catch and log
|
|
770
|
+
try {
|
|
771
|
+
$this->performRiskyOperation();
|
|
772
|
+
} catch (\Throwable $e) {
|
|
773
|
+
$this->log->error('Operation failed: ' . $e->getMessage(), [
|
|
774
|
+
'exception' => $e
|
|
775
|
+
]);
|
|
776
|
+
throw $e; // Re-throw
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// Catch and convert
|
|
780
|
+
try {
|
|
781
|
+
$result = $this->externalApi->call();
|
|
782
|
+
} catch (\GuzzleHttp\Exception\RequestException $e) {
|
|
783
|
+
throw new Error('External API failed: ' . $e->getMessage());
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// Catch specific, let others propagate
|
|
787
|
+
try {
|
|
788
|
+
$this->operation();
|
|
789
|
+
} catch (NotFound $e) {
|
|
790
|
+
// Handle not found specifically
|
|
791
|
+
return $this->createDefault();
|
|
792
|
+
}
|
|
793
|
+
// Other exceptions propagate up
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
## Debugging Checklist
|
|
797
|
+
|
|
798
|
+
When something doesn't work:
|
|
799
|
+
|
|
800
|
+
1. **Check Logs**
|
|
801
|
+
- `data/logs/espo-YYYY-MM-DD.log`
|
|
802
|
+
- PHP error logs
|
|
803
|
+
|
|
804
|
+
2. **Verify Cache Rebuild**
|
|
805
|
+
- `bin/command rebuild`
|
|
806
|
+
|
|
807
|
+
3. **Check Permissions**
|
|
808
|
+
- File permissions (files should be writable)
|
|
809
|
+
- ACL permissions (user has access)
|
|
810
|
+
|
|
811
|
+
4. **Validate Metadata**
|
|
812
|
+
- JSON syntax correct
|
|
813
|
+
- Required fields present
|
|
814
|
+
|
|
815
|
+
5. **Check Database**
|
|
816
|
+
- Table exists
|
|
817
|
+
- Columns exist
|
|
818
|
+
- Indexes present
|
|
819
|
+
|
|
820
|
+
6. **Test API Directly**
|
|
821
|
+
- Use curl or Postman
|
|
822
|
+
- Check request/response
|
|
823
|
+
|
|
824
|
+
7. **Enable Debug Mode**
|
|
825
|
+
- `'logger' => ['level' => 'DEBUG']`
|
|
826
|
+
- `'isDeveloperMode' => true`
|
|
827
|
+
|
|
828
|
+
8. **Use XDebug**
|
|
829
|
+
- Set breakpoints
|
|
830
|
+
- Step through code
|
|
831
|
+
- Inspect variables
|