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,568 @@
|
|
|
1
|
+
"""Service for discovering and parsing skills from Git repositories.
|
|
2
|
+
|
|
3
|
+
Skills are stored as Markdown files with YAML frontmatter. This service handles:
|
|
4
|
+
- Discovery of skill files in repository cache
|
|
5
|
+
- Parsing of YAML frontmatter for metadata
|
|
6
|
+
- Extraction of skill content (body)
|
|
7
|
+
- Detection of bundled resources (scripts/, references/, assets/)
|
|
8
|
+
|
|
9
|
+
Design Decision: YAML Frontmatter Format
|
|
10
|
+
|
|
11
|
+
Rationale: YAML frontmatter is a well-established pattern for metadata in
|
|
12
|
+
Markdown files (used by Jekyll, Hugo, MkDocs). It provides clean separation
|
|
13
|
+
between metadata and content, with excellent library support.
|
|
14
|
+
|
|
15
|
+
Trade-offs:
|
|
16
|
+
- Standardization: Widely recognized format
|
|
17
|
+
- Parsing Complexity: Requires regex + YAML parsing
|
|
18
|
+
- Extensibility: Easy to add new metadata fields
|
|
19
|
+
|
|
20
|
+
Example Skill File:
|
|
21
|
+
---
|
|
22
|
+
name: code-review
|
|
23
|
+
description: Comprehensive code review skill
|
|
24
|
+
skill_version: 1.0.0
|
|
25
|
+
tags: [review, quality, best-practices]
|
|
26
|
+
agent_types: [engineer, qa]
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
# Code Review Skill
|
|
30
|
+
|
|
31
|
+
When reviewing code, check for:
|
|
32
|
+
- Code quality and style
|
|
33
|
+
- Security vulnerabilities
|
|
34
|
+
...
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
import re
|
|
38
|
+
from dataclasses import dataclass
|
|
39
|
+
from pathlib import Path
|
|
40
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
41
|
+
|
|
42
|
+
import yaml
|
|
43
|
+
|
|
44
|
+
from claude_mpm.core.logging_config import get_logger
|
|
45
|
+
|
|
46
|
+
logger = get_logger(__name__)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class SkillMetadata:
|
|
51
|
+
"""Metadata extracted from skill file.
|
|
52
|
+
|
|
53
|
+
Attributes:
|
|
54
|
+
name: Skill name (human-readable)
|
|
55
|
+
description: Brief description of skill purpose
|
|
56
|
+
skill_version: Version string (e.g., "1.0.0")
|
|
57
|
+
tags: List of tags for categorization
|
|
58
|
+
agent_types: Optional list of agent types this skill applies to
|
|
59
|
+
source_file: Path to skill file
|
|
60
|
+
resources: Optional list of bundled resource paths
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
>>> metadata = SkillMetadata(
|
|
64
|
+
... name="code-review",
|
|
65
|
+
... description="Comprehensive code review",
|
|
66
|
+
... skill_version="1.0.0",
|
|
67
|
+
... tags=["review", "quality"],
|
|
68
|
+
... agent_types=["engineer"],
|
|
69
|
+
... source_file=Path("skills/code-review.md"),
|
|
70
|
+
... resources=[]
|
|
71
|
+
... )
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
name: str
|
|
75
|
+
description: str
|
|
76
|
+
skill_version: str
|
|
77
|
+
tags: List[str]
|
|
78
|
+
agent_types: Optional[List[str]]
|
|
79
|
+
source_file: Path
|
|
80
|
+
resources: Optional[List[Path]]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class SkillDiscoveryService:
|
|
84
|
+
"""Discovers and parses skills from Git repositories.
|
|
85
|
+
|
|
86
|
+
Skills Format:
|
|
87
|
+
- Markdown files with YAML frontmatter
|
|
88
|
+
- Frontmatter contains metadata (name, description, version, tags)
|
|
89
|
+
- Body contains skill instructions/prompt
|
|
90
|
+
- Optional bundled resources in scripts/, references/, assets/
|
|
91
|
+
|
|
92
|
+
Design Pattern: Service with Single Responsibility
|
|
93
|
+
|
|
94
|
+
This service focuses solely on discovery and parsing. Syncing, caching,
|
|
95
|
+
and priority resolution are handled by GitSkillSourceManager.
|
|
96
|
+
|
|
97
|
+
Example:
|
|
98
|
+
>>> service = SkillDiscoveryService(Path("~/.claude-mpm/cache/skills/system"))
|
|
99
|
+
>>> skills = service.discover_skills()
|
|
100
|
+
>>> for skill in skills:
|
|
101
|
+
... print(f"{skill['name']}: {skill['description']}")
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
def __init__(self, skills_dir: Path):
|
|
105
|
+
"""Initialize skill discovery service.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
skills_dir: Directory containing skill files
|
|
109
|
+
"""
|
|
110
|
+
self.skills_dir = skills_dir
|
|
111
|
+
self.logger = get_logger(__name__)
|
|
112
|
+
|
|
113
|
+
def discover_skills(self) -> List[Dict[str, Any]]:
|
|
114
|
+
"""Discover all skills in directory.
|
|
115
|
+
|
|
116
|
+
Scans directory RECURSIVELY for SKILL.md files and parses each as a skill.
|
|
117
|
+
This supports nested Git repository structures while deploying to flat structure.
|
|
118
|
+
|
|
119
|
+
Nested Repository Structure:
|
|
120
|
+
collaboration/
|
|
121
|
+
dispatching-parallel-agents/SKILL.md
|
|
122
|
+
brainstorming/SKILL.md
|
|
123
|
+
debugging/
|
|
124
|
+
systematic-debugging/SKILL.md
|
|
125
|
+
|
|
126
|
+
Deployed Flat Structure:
|
|
127
|
+
collaboration-dispatching-parallel-agents/SKILL.md
|
|
128
|
+
collaboration-brainstorming/SKILL.md
|
|
129
|
+
debugging-systematic-debugging/SKILL.md
|
|
130
|
+
|
|
131
|
+
Skips files that can't be parsed or are missing required fields.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
List of skill dictionaries:
|
|
135
|
+
[
|
|
136
|
+
{
|
|
137
|
+
"skill_id": str, # Normalized skill ID
|
|
138
|
+
"name": str, # Human-readable name
|
|
139
|
+
"description": str, # Brief description
|
|
140
|
+
"skill_version": str, # Version string
|
|
141
|
+
"tags": List[str], # Tags for categorization
|
|
142
|
+
"agent_types": List[str], # Applicable agent types (optional)
|
|
143
|
+
"content": str, # Skill body content
|
|
144
|
+
"source_file": str, # Path to skill file
|
|
145
|
+
"resources": List[str], # Bundled resource paths (optional)
|
|
146
|
+
"deployment_name": str, # Flattened deployment directory name
|
|
147
|
+
"relative_path": str # Relative path from skills_dir to SKILL.md
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
Example:
|
|
152
|
+
>>> service = SkillDiscoveryService(Path("cache/skills/system"))
|
|
153
|
+
>>> skills = service.discover_skills()
|
|
154
|
+
>>> print(f"Found {len(skills)} skills")
|
|
155
|
+
"""
|
|
156
|
+
skills = []
|
|
157
|
+
|
|
158
|
+
if not self.skills_dir.exists():
|
|
159
|
+
self.logger.debug(f"Skills directory does not exist: {self.skills_dir}")
|
|
160
|
+
return skills
|
|
161
|
+
|
|
162
|
+
# Find all SKILL.md files recursively (Claude Code standard naming)
|
|
163
|
+
skill_md_files = list(self.skills_dir.rglob("SKILL.md"))
|
|
164
|
+
|
|
165
|
+
# Also find legacy *.md files in top-level directory for backward compatibility
|
|
166
|
+
legacy_md_files = [
|
|
167
|
+
f
|
|
168
|
+
for f in self.skills_dir.glob("*.md")
|
|
169
|
+
if f.name != "SKILL.md" and f.name.lower() != "readme.md"
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
all_skill_files = skill_md_files + legacy_md_files
|
|
173
|
+
|
|
174
|
+
self.logger.debug(
|
|
175
|
+
f"Found {len(skill_md_files)} SKILL.md files recursively "
|
|
176
|
+
f"and {len(legacy_md_files)} legacy .md files in {self.skills_dir}"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Track deployment names to detect collisions
|
|
180
|
+
deployment_names = {}
|
|
181
|
+
|
|
182
|
+
for skill_file in all_skill_files:
|
|
183
|
+
try:
|
|
184
|
+
# Calculate deployment name from path
|
|
185
|
+
deployment_name = self._calculate_deployment_name(skill_file)
|
|
186
|
+
|
|
187
|
+
# Detect name collisions
|
|
188
|
+
if deployment_name in deployment_names:
|
|
189
|
+
self.logger.warning(
|
|
190
|
+
f"Deployment name collision: '{deployment_name}' would be created by both:\n"
|
|
191
|
+
f" - {deployment_names[deployment_name]}\n"
|
|
192
|
+
f" - {skill_file}\n"
|
|
193
|
+
f"Skipping {skill_file} to avoid overwrite."
|
|
194
|
+
)
|
|
195
|
+
continue
|
|
196
|
+
|
|
197
|
+
skill_dict = self._parse_skill_file(skill_file)
|
|
198
|
+
if skill_dict:
|
|
199
|
+
# Add deployment metadata
|
|
200
|
+
skill_dict["deployment_name"] = deployment_name
|
|
201
|
+
skill_dict["relative_path"] = str(
|
|
202
|
+
skill_file.relative_to(self.skills_dir)
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
skills.append(skill_dict)
|
|
206
|
+
deployment_names[deployment_name] = skill_file
|
|
207
|
+
self.logger.debug(
|
|
208
|
+
f"Successfully parsed skill: {skill_file.name} -> {deployment_name}"
|
|
209
|
+
)
|
|
210
|
+
else:
|
|
211
|
+
self.logger.warning(
|
|
212
|
+
f"Failed to parse skill (missing required fields): {skill_file}"
|
|
213
|
+
)
|
|
214
|
+
except Exception as e:
|
|
215
|
+
self.logger.warning(f"Failed to parse skill {skill_file}: {e}")
|
|
216
|
+
|
|
217
|
+
self.logger.info(f"Discovered {len(skills)} skills from {self.skills_dir.name}")
|
|
218
|
+
return skills
|
|
219
|
+
|
|
220
|
+
def _parse_skill_file(self, skill_file: Path) -> Optional[Dict[str, Any]]:
|
|
221
|
+
"""Parse a skill Markdown file with YAML frontmatter.
|
|
222
|
+
|
|
223
|
+
Expected Format:
|
|
224
|
+
---
|
|
225
|
+
name: skill-name
|
|
226
|
+
description: Brief description
|
|
227
|
+
skill_version: 1.0.0
|
|
228
|
+
tags: [tag1, tag2]
|
|
229
|
+
agent_types: [engineer, qa] # Optional
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
# Skill Content
|
|
233
|
+
|
|
234
|
+
Skill instructions and prompt here...
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
skill_file: Path to skill .md file
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Skill dictionary or None if parsing fails
|
|
241
|
+
|
|
242
|
+
Error Handling:
|
|
243
|
+
- Returns None if frontmatter is missing
|
|
244
|
+
- Returns None if required fields are missing (name, description)
|
|
245
|
+
- Uses defaults for optional fields (tags=[], agent_types=None)
|
|
246
|
+
- Logs warnings for parsing errors
|
|
247
|
+
"""
|
|
248
|
+
try:
|
|
249
|
+
content = skill_file.read_text(encoding="utf-8")
|
|
250
|
+
except Exception as e:
|
|
251
|
+
self.logger.error(f"Failed to read file {skill_file}: {e}")
|
|
252
|
+
return None
|
|
253
|
+
|
|
254
|
+
# Extract YAML frontmatter and body
|
|
255
|
+
try:
|
|
256
|
+
frontmatter, body = self._extract_frontmatter(content)
|
|
257
|
+
except Exception as e:
|
|
258
|
+
self.logger.warning(f"No valid frontmatter in {skill_file.name}: {e}")
|
|
259
|
+
return None
|
|
260
|
+
|
|
261
|
+
# Validate required fields
|
|
262
|
+
if "name" not in frontmatter:
|
|
263
|
+
self.logger.warning(f"Missing 'name' field in {skill_file.name}")
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
if "description" not in frontmatter:
|
|
267
|
+
self.logger.warning(f"Missing 'description' field in {skill_file.name}")
|
|
268
|
+
return None
|
|
269
|
+
|
|
270
|
+
# Extract metadata with defaults
|
|
271
|
+
name = frontmatter["name"]
|
|
272
|
+
description = frontmatter["description"]
|
|
273
|
+
skill_version = frontmatter.get("skill_version", "1.0.0")
|
|
274
|
+
tags = frontmatter.get("tags", [])
|
|
275
|
+
agent_types = frontmatter.get("agent_types", None)
|
|
276
|
+
|
|
277
|
+
# Ensure tags is a list
|
|
278
|
+
if isinstance(tags, str):
|
|
279
|
+
tags = [tags]
|
|
280
|
+
elif not isinstance(tags, list):
|
|
281
|
+
tags = []
|
|
282
|
+
|
|
283
|
+
# Ensure agent_types is a list (if present)
|
|
284
|
+
if agent_types is not None:
|
|
285
|
+
if isinstance(agent_types, str):
|
|
286
|
+
agent_types = [agent_types]
|
|
287
|
+
elif not isinstance(agent_types, list):
|
|
288
|
+
agent_types = None
|
|
289
|
+
|
|
290
|
+
# Generate skill_id from name (lowercase, replace spaces/underscores with hyphens)
|
|
291
|
+
skill_id = self._generate_skill_id(name)
|
|
292
|
+
|
|
293
|
+
# Find bundled resources
|
|
294
|
+
resources = self._find_bundled_resources(skill_file)
|
|
295
|
+
|
|
296
|
+
# Build skill dictionary
|
|
297
|
+
skill_dict = {
|
|
298
|
+
"skill_id": skill_id,
|
|
299
|
+
"name": name,
|
|
300
|
+
"description": description,
|
|
301
|
+
"skill_version": skill_version,
|
|
302
|
+
"tags": tags,
|
|
303
|
+
"content": body.strip(),
|
|
304
|
+
"source_file": str(skill_file),
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
# Add optional fields
|
|
308
|
+
if agent_types is not None:
|
|
309
|
+
skill_dict["agent_types"] = agent_types
|
|
310
|
+
|
|
311
|
+
if resources:
|
|
312
|
+
skill_dict["resources"] = [str(r) for r in resources]
|
|
313
|
+
|
|
314
|
+
return skill_dict
|
|
315
|
+
|
|
316
|
+
def _extract_frontmatter(self, content: str) -> Tuple[Dict[str, Any], str]:
|
|
317
|
+
"""Extract YAML frontmatter and body from Markdown.
|
|
318
|
+
|
|
319
|
+
Frontmatter must be at the start of the file, delimited by "---".
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
content: Markdown file content
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
Tuple of (frontmatter_dict, body_content)
|
|
326
|
+
|
|
327
|
+
Raises:
|
|
328
|
+
ValueError: If no valid frontmatter found
|
|
329
|
+
|
|
330
|
+
Frontmatter Format:
|
|
331
|
+
---
|
|
332
|
+
key: value
|
|
333
|
+
list: [item1, item2]
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
Body content here...
|
|
337
|
+
|
|
338
|
+
Example:
|
|
339
|
+
>>> content = "---\\nname: test\\n---\\nBody"
|
|
340
|
+
>>> frontmatter, body = service._extract_frontmatter(content)
|
|
341
|
+
>>> frontmatter["name"]
|
|
342
|
+
'test'
|
|
343
|
+
>>> body
|
|
344
|
+
'Body'
|
|
345
|
+
"""
|
|
346
|
+
# Use regex to extract frontmatter between --- markers
|
|
347
|
+
# Pattern: Start of string, ---, content, ---, rest
|
|
348
|
+
pattern = r"^---\s*\n(.*?)\n---\s*\n(.*)$"
|
|
349
|
+
match = re.match(pattern, content, re.DOTALL)
|
|
350
|
+
|
|
351
|
+
if not match:
|
|
352
|
+
raise ValueError("No valid YAML frontmatter found")
|
|
353
|
+
|
|
354
|
+
frontmatter_text = match.group(1)
|
|
355
|
+
body = match.group(2)
|
|
356
|
+
|
|
357
|
+
# Parse YAML
|
|
358
|
+
try:
|
|
359
|
+
frontmatter = yaml.safe_load(frontmatter_text)
|
|
360
|
+
except yaml.YAMLError as e:
|
|
361
|
+
raise ValueError(f"Invalid YAML in frontmatter: {e}") from e
|
|
362
|
+
|
|
363
|
+
if not isinstance(frontmatter, dict):
|
|
364
|
+
raise ValueError("Frontmatter must be a YAML dictionary")
|
|
365
|
+
|
|
366
|
+
return frontmatter, body
|
|
367
|
+
|
|
368
|
+
def _calculate_deployment_name(self, skill_file: Path) -> str:
|
|
369
|
+
"""Calculate flat deployment name from nested skill path.
|
|
370
|
+
|
|
371
|
+
Flattens nested Git repository structure into hyphen-separated name
|
|
372
|
+
suitable for Claude Code's flat skill directory structure.
|
|
373
|
+
|
|
374
|
+
Path Flattening Algorithm:
|
|
375
|
+
1. Get relative path from skills_dir to skill file
|
|
376
|
+
2. Extract all parent directory names (excluding the final skill directory)
|
|
377
|
+
3. Join path components with hyphens
|
|
378
|
+
4. Normalize to lowercase, remove special characters
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
skill_file: Path to SKILL.md or skill markdown file
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
Flattened deployment directory name
|
|
385
|
+
|
|
386
|
+
Examples:
|
|
387
|
+
>>> # Nested repository structure
|
|
388
|
+
>>> skill_file = Path("cache/skills/system/collaboration/dispatching-parallel-agents/SKILL.md")
|
|
389
|
+
>>> name = service._calculate_deployment_name(skill_file)
|
|
390
|
+
>>> name
|
|
391
|
+
'collaboration-dispatching-parallel-agents'
|
|
392
|
+
|
|
393
|
+
>>> # Single-level structure (legacy)
|
|
394
|
+
>>> skill_file = Path("cache/skills/system/code-review.md")
|
|
395
|
+
>>> name = service._calculate_deployment_name(skill_file)
|
|
396
|
+
>>> name
|
|
397
|
+
'code-review'
|
|
398
|
+
|
|
399
|
+
>>> # Deep nesting
|
|
400
|
+
>>> skill_file = Path("cache/skills/system/aws/s3/bucket-ops/SKILL.md")
|
|
401
|
+
>>> name = service._calculate_deployment_name(skill_file)
|
|
402
|
+
>>> name
|
|
403
|
+
'aws-s3-bucket-ops'
|
|
404
|
+
"""
|
|
405
|
+
# Get relative path from skills_dir to skill file
|
|
406
|
+
try:
|
|
407
|
+
relative_path = skill_file.relative_to(self.skills_dir)
|
|
408
|
+
except ValueError:
|
|
409
|
+
# Fallback: skill_file is not under skills_dir
|
|
410
|
+
# Use just the filename
|
|
411
|
+
self.logger.warning(
|
|
412
|
+
f"Skill file {skill_file} is not under {self.skills_dir}, "
|
|
413
|
+
f"using filename as deployment name"
|
|
414
|
+
)
|
|
415
|
+
return skill_file.stem
|
|
416
|
+
|
|
417
|
+
# Get all path parts (directories + filename)
|
|
418
|
+
parts = list(relative_path.parts)
|
|
419
|
+
|
|
420
|
+
# Handle different structures:
|
|
421
|
+
# 1. SKILL.md case: collaboration/dispatching-parallel-agents/SKILL.md
|
|
422
|
+
# -> Take parent directories: ['collaboration', 'dispatching-parallel-agents']
|
|
423
|
+
# 2. Legacy .md case: code-review.md
|
|
424
|
+
# -> Take just filename stem: ['code-review']
|
|
425
|
+
|
|
426
|
+
if skill_file.name == "SKILL.md":
|
|
427
|
+
# SKILL.md case: use all parent directories as deployment name
|
|
428
|
+
# Remove the final 'SKILL.md' part
|
|
429
|
+
deployment_parts = parts[:-1]
|
|
430
|
+
|
|
431
|
+
if not deployment_parts:
|
|
432
|
+
# Edge case: SKILL.md at top level
|
|
433
|
+
# Use parent directory name or 'skill'
|
|
434
|
+
deployment_parts = ["skill"]
|
|
435
|
+
else:
|
|
436
|
+
# Legacy .md case: use filename stem
|
|
437
|
+
deployment_parts = [skill_file.stem]
|
|
438
|
+
|
|
439
|
+
# Join with hyphens and normalize
|
|
440
|
+
deployment_name = "-".join(deployment_parts)
|
|
441
|
+
|
|
442
|
+
# Normalize: lowercase, remove special chars, collapse hyphens
|
|
443
|
+
deployment_name = deployment_name.lower()
|
|
444
|
+
deployment_name = deployment_name.replace("_", "-")
|
|
445
|
+
deployment_name = re.sub(r"[^a-z0-9-]+", "", deployment_name)
|
|
446
|
+
deployment_name = re.sub(r"-+", "-", deployment_name)
|
|
447
|
+
return deployment_name.strip("-")
|
|
448
|
+
|
|
449
|
+
def _generate_skill_id(self, name: str) -> str:
|
|
450
|
+
"""Generate skill ID from name.
|
|
451
|
+
|
|
452
|
+
Converts name to lowercase, replaces spaces/underscores with hyphens,
|
|
453
|
+
removes non-alphanumeric characters, and collapses multiple hyphens.
|
|
454
|
+
|
|
455
|
+
Args:
|
|
456
|
+
name: Human-readable skill name
|
|
457
|
+
|
|
458
|
+
Returns:
|
|
459
|
+
Normalized skill ID
|
|
460
|
+
|
|
461
|
+
Example:
|
|
462
|
+
>>> service._generate_skill_id("Code Review")
|
|
463
|
+
'code-review'
|
|
464
|
+
>>> service._generate_skill_id("Python_Style-Check!")
|
|
465
|
+
'python-style-check'
|
|
466
|
+
"""
|
|
467
|
+
# 1. Convert to lowercase
|
|
468
|
+
skill_id = name.lower()
|
|
469
|
+
|
|
470
|
+
# 2. Replace spaces and underscores with hyphens
|
|
471
|
+
skill_id = skill_id.replace(" ", "-").replace("_", "-")
|
|
472
|
+
|
|
473
|
+
# 3. Remove any characters that aren't alphanumeric or hyphens
|
|
474
|
+
skill_id = re.sub(r"[^a-z0-9-]+", "", skill_id)
|
|
475
|
+
|
|
476
|
+
# 4. Collapse multiple consecutive hyphens into one
|
|
477
|
+
skill_id = re.sub(r"-+", "-", skill_id)
|
|
478
|
+
|
|
479
|
+
# 5. Remove leading/trailing hyphens
|
|
480
|
+
return skill_id.strip("-")
|
|
481
|
+
|
|
482
|
+
def _find_bundled_resources(self, skill_file: Path) -> List[Path]:
|
|
483
|
+
"""Find bundled resources for a skill.
|
|
484
|
+
|
|
485
|
+
Resources are in parallel directories:
|
|
486
|
+
skills/
|
|
487
|
+
skill-name.md
|
|
488
|
+
scripts/
|
|
489
|
+
skill-name/
|
|
490
|
+
helper.sh
|
|
491
|
+
references/
|
|
492
|
+
skill-name/
|
|
493
|
+
docs.md
|
|
494
|
+
assets/
|
|
495
|
+
skill-name/
|
|
496
|
+
image.png
|
|
497
|
+
|
|
498
|
+
Args:
|
|
499
|
+
skill_file: Path to skill .md file
|
|
500
|
+
|
|
501
|
+
Returns:
|
|
502
|
+
List of resource file paths
|
|
503
|
+
|
|
504
|
+
Example:
|
|
505
|
+
>>> skill_file = Path("cache/skills/system/code-review.md")
|
|
506
|
+
>>> resources = service._find_bundled_resources(skill_file)
|
|
507
|
+
>>> print(resources)
|
|
508
|
+
[Path('cache/skills/system/scripts/code-review/helper.sh')]
|
|
509
|
+
"""
|
|
510
|
+
resources = []
|
|
511
|
+
|
|
512
|
+
# Derive skill name from filename (without .md extension)
|
|
513
|
+
skill_name = skill_file.stem
|
|
514
|
+
|
|
515
|
+
# Get parent directory (where skills/ is located)
|
|
516
|
+
parent_dir = skill_file.parent
|
|
517
|
+
|
|
518
|
+
# Check for resource directories
|
|
519
|
+
resource_dirs = ["scripts", "references", "assets"]
|
|
520
|
+
|
|
521
|
+
for resource_dir_name in resource_dirs:
|
|
522
|
+
resource_dir = parent_dir / resource_dir_name / skill_name
|
|
523
|
+
|
|
524
|
+
if resource_dir.exists() and resource_dir.is_dir():
|
|
525
|
+
# Find all files in resource directory (recursively)
|
|
526
|
+
for resource_file in resource_dir.rglob("*"):
|
|
527
|
+
if resource_file.is_file():
|
|
528
|
+
resources.append(resource_file)
|
|
529
|
+
|
|
530
|
+
if resources:
|
|
531
|
+
self.logger.debug(
|
|
532
|
+
f"Found {len(resources)} bundled resources for {skill_name}"
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
return resources
|
|
536
|
+
|
|
537
|
+
def get_skill_metadata(self, skill_name: str) -> Optional[SkillMetadata]:
|
|
538
|
+
"""Get metadata for a specific skill.
|
|
539
|
+
|
|
540
|
+
Args:
|
|
541
|
+
skill_name: Name of the skill to retrieve
|
|
542
|
+
|
|
543
|
+
Returns:
|
|
544
|
+
SkillMetadata if found, None otherwise
|
|
545
|
+
|
|
546
|
+
Example:
|
|
547
|
+
>>> service = SkillDiscoveryService(Path("cache/skills/system"))
|
|
548
|
+
>>> metadata = service.get_skill_metadata("code-review")
|
|
549
|
+
>>> if metadata:
|
|
550
|
+
... print(f"{metadata.name}: {metadata.description}")
|
|
551
|
+
"""
|
|
552
|
+
for md_file in self.skills_dir.glob("*.md"):
|
|
553
|
+
skill_dict = self._parse_skill_file(md_file)
|
|
554
|
+
if skill_dict and skill_dict["name"] == skill_name:
|
|
555
|
+
return SkillMetadata(
|
|
556
|
+
name=skill_dict["name"],
|
|
557
|
+
description=skill_dict["description"],
|
|
558
|
+
skill_version=skill_dict["skill_version"],
|
|
559
|
+
tags=skill_dict["tags"],
|
|
560
|
+
agent_types=skill_dict.get("agent_types"),
|
|
561
|
+
source_file=Path(skill_dict["source_file"]),
|
|
562
|
+
resources=[Path(r) for r in skill_dict.get("resources", [])],
|
|
563
|
+
)
|
|
564
|
+
return None
|
|
565
|
+
|
|
566
|
+
def __repr__(self) -> str:
|
|
567
|
+
"""Return string representation."""
|
|
568
|
+
return f"SkillDiscoveryService(skills_dir='{self.skills_dir}')"
|