claude-mpm 5.0.9__py3-none-any.whl → 5.4.41__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/__init__.py +4 -0
- claude_mpm/agents/BASE_AGENT.md +164 -0
- claude_mpm/agents/{PM_INSTRUCTIONS_TEACH.md → CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md} +721 -41
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +468 -468
- claude_mpm/agents/WORKFLOW.md +5 -254
- claude_mpm/agents/agent_loader.py +13 -44
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/frontmatter_validator.py +70 -2
- claude_mpm/agents/templates/circuit-breakers.md +431 -45
- claude_mpm/cli/__init__.py +0 -1
- claude_mpm/cli/__main__.py +4 -0
- claude_mpm/cli/chrome_devtools_installer.py +175 -0
- claude_mpm/cli/commands/agent_state_manager.py +18 -27
- claude_mpm/cli/commands/agents.py +175 -37
- claude_mpm/cli/commands/auto_configure.py +723 -236
- claude_mpm/cli/commands/config.py +88 -2
- claude_mpm/cli/commands/configure.py +1262 -157
- claude_mpm/cli/commands/configure_agent_display.py +25 -6
- claude_mpm/cli/commands/mpm_init/core.py +225 -46
- claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
- claude_mpm/cli/commands/postmortem.py +1 -1
- claude_mpm/cli/commands/profile.py +277 -0
- claude_mpm/cli/commands/skills.py +214 -189
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/executor.py +21 -3
- claude_mpm/cli/interactive/agent_wizard.py +85 -10
- claude_mpm/cli/parsers/agents_parser.py +54 -9
- claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
- claude_mpm/cli/parsers/base_parser.py +12 -0
- claude_mpm/cli/parsers/config_parser.py +153 -83
- claude_mpm/cli/parsers/profile_parser.py +148 -0
- claude_mpm/cli/parsers/skills_parser.py +3 -2
- claude_mpm/cli/startup.py +879 -149
- claude_mpm/commands/mpm-config.md +28 -0
- claude_mpm/commands/mpm-doctor.md +9 -22
- claude_mpm/commands/mpm-help.md +5 -287
- claude_mpm/commands/mpm-init.md +81 -507
- claude_mpm/commands/mpm-monitor.md +15 -402
- claude_mpm/commands/mpm-organize.md +120 -0
- claude_mpm/commands/mpm-postmortem.md +6 -108
- claude_mpm/commands/mpm-session-resume.md +12 -363
- claude_mpm/commands/mpm-status.md +5 -69
- claude_mpm/commands/mpm-ticket-view.md +52 -495
- claude_mpm/commands/mpm-version.md +5 -107
- claude_mpm/config/agent_sources.py +27 -0
- claude_mpm/core/config.py +2 -4
- claude_mpm/core/framework/formatters/content_formatter.py +3 -13
- claude_mpm/core/framework/loaders/agent_loader.py +8 -5
- claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
- claude_mpm/core/framework_loader.py +4 -2
- claude_mpm/core/logger.py +13 -0
- claude_mpm/core/optimized_startup.py +59 -0
- claude_mpm/core/output_style_manager.py +173 -43
- claude_mpm/core/shared/config_loader.py +1 -1
- claude_mpm/core/socketio_pool.py +3 -3
- claude_mpm/core/unified_agent_registry.py +134 -16
- claude_mpm/core/unified_config.py +22 -0
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
- claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
- claude_mpm/dashboard/static/svelte-build/index.html +36 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
- claude_mpm/hooks/claude_hooks/hook_handler.py +155 -1
- claude_mpm/hooks/claude_hooks/installer.py +33 -10
- claude_mpm/hooks/claude_hooks/memory_integration.py +28 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +30 -6
- claude_mpm/hooks/memory_integration_hook.py +46 -1
- claude_mpm/init.py +63 -19
- claude_mpm/models/agent_definition.py +7 -0
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/claude-hook-handler.sh +58 -18
- claude_mpm/scripts/launch_monitor.py +93 -13
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/agent_recommendation_service.py +278 -0
- claude_mpm/services/agents/agent_review_service.py +280 -0
- claude_mpm/services/agents/cache_git_manager.py +6 -6
- claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -5
- claude_mpm/services/agents/deployment/agent_template_builder.py +5 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +320 -29
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +546 -68
- claude_mpm/services/agents/git_source_manager.py +36 -2
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
- claude_mpm/services/agents/recommender.py +5 -3
- claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
- claude_mpm/services/agents/sources/git_source_sync_service.py +13 -6
- claude_mpm/services/agents/startup_sync.py +22 -2
- claude_mpm/services/agents/toolchain_detector.py +10 -6
- claude_mpm/services/analysis/__init__.py +11 -1
- claude_mpm/services/analysis/clone_detector.py +1030 -0
- claude_mpm/services/command_deployment_service.py +81 -10
- claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
- claude_mpm/services/event_bus/config.py +3 -1
- claude_mpm/services/git/git_operations_service.py +101 -16
- claude_mpm/services/monitor/daemon.py +9 -2
- claude_mpm/services/monitor/daemon_manager.py +39 -3
- claude_mpm/services/monitor/management/lifecycle.py +8 -1
- claude_mpm/services/monitor/server.py +698 -22
- claude_mpm/services/pm_skills_deployer.py +676 -0
- claude_mpm/services/profile_manager.py +331 -0
- claude_mpm/services/project/project_organizer.py +4 -0
- claude_mpm/services/self_upgrade_service.py +120 -12
- claude_mpm/services/skills/__init__.py +3 -0
- claude_mpm/services/skills/git_skill_source_manager.py +130 -2
- claude_mpm/services/skills/selective_skill_deployer.py +704 -0
- claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
- claude_mpm/services/skills_deployer.py +126 -9
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +51 -6
- claude_mpm/services/socketio/server/core.py +386 -108
- claude_mpm/services/version_control/git_operations.py +103 -0
- claude_mpm/skills/skill_manager.py +92 -3
- claude_mpm/utils/agent_dependency_loader.py +14 -2
- claude_mpm/utils/agent_filters.py +17 -44
- claude_mpm/utils/gitignore.py +3 -0
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +47 -3
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/METADATA +57 -87
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/RECORD +160 -211
- claude_mpm-5.4.41.dist-info/entry_points.txt +5 -0
- claude_mpm-5.4.41.dist-info/licenses/LICENSE +94 -0
- claude_mpm-5.4.41.dist-info/licenses/LICENSE-FAQ.md +153 -0
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
- claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
- claude_mpm/agents/BASE_OPS.md +0 -219
- claude_mpm/agents/BASE_PM.md +0 -480
- claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
- claude_mpm/agents/BASE_QA.md +0 -167
- claude_mpm/agents/BASE_RESEARCH.md +0 -53
- claude_mpm/agents/base_agent_loader.py +0 -601
- claude_mpm/cli/commands/agents_detect.py +0 -380
- claude_mpm/cli/commands/agents_recommend.py +0 -309
- claude_mpm/cli/ticket_cli.py +0 -35
- claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
- claude_mpm/commands/mpm-agents-detect.md +0 -177
- claude_mpm/commands/mpm-agents-list.md +0 -131
- claude_mpm/commands/mpm-agents-recommend.md +0 -223
- claude_mpm/commands/mpm-config-view.md +0 -150
- claude_mpm/commands/mpm-ticket-organize.md +0 -304
- claude_mpm/dashboard/analysis_runner.py +0 -455
- claude_mpm/dashboard/index.html +0 -13
- claude_mpm/dashboard/open_dashboard.py +0 -66
- claude_mpm/dashboard/static/css/activity.css +0 -1958
- claude_mpm/dashboard/static/css/connection-status.css +0 -370
- claude_mpm/dashboard/static/css/dashboard.css +0 -4701
- claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
- claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
- claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
- claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
- claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
- claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
- claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
- claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
- claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
- claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
- claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
- claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
- claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
- claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
- claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
- claude_mpm/dashboard/static/js/connection-manager.js +0 -536
- claude_mpm/dashboard/static/js/dashboard.js +0 -1914
- claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
- claude_mpm/dashboard/static/js/socket-client.js +0 -1474
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
- claude_mpm/dashboard/static/socket.io.min.js +0 -7
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
- claude_mpm/dashboard/templates/code_simple.html +0 -153
- claude_mpm/dashboard/templates/index.html +0 -606
- claude_mpm/dashboard/test_dashboard.html +0 -372
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/scripts/mcp_server.py +0 -75
- claude_mpm/scripts/mcp_wrapper.py +0 -39
- claude_mpm/services/mcp_gateway/__init__.py +0 -159
- claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
- claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
- claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
- claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
- claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
- claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
- claude_mpm/services/mcp_gateway/core/base.py +0 -312
- claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
- claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
- claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
- claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
- claude_mpm/services/mcp_gateway/main.py +0 -589
- claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
- claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
- claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
- claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
- claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
- claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
- claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
- claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
- /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/WHEEL +0 -0
- {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Document Summarization Command.
|
|
3
|
+
|
|
4
|
+
Shell-based alternative to MCP document_summarizer tool.
|
|
5
|
+
Provides algorithmic summarization without ML dependencies.
|
|
6
|
+
|
|
7
|
+
Design Decision: Uses simple text processing techniques:
|
|
8
|
+
- Brief: First paragraph extraction
|
|
9
|
+
- Detailed: Key sentence extraction based on position and length
|
|
10
|
+
- Bullet Points: Convert to markdown bullet list
|
|
11
|
+
- Executive: Opening + conclusion extraction
|
|
12
|
+
|
|
13
|
+
Why: Lightweight, fast, no dependencies, works offline.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import re
|
|
18
|
+
from enum import Enum
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Optional
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SummaryStyle(str, Enum):
|
|
24
|
+
"""Summary output styles."""
|
|
25
|
+
|
|
26
|
+
BRIEF = "brief"
|
|
27
|
+
DETAILED = "detailed"
|
|
28
|
+
BULLET_POINTS = "bullet_points"
|
|
29
|
+
EXECUTIVE = "executive"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class OutputFormat(str, Enum):
|
|
33
|
+
"""Output format types."""
|
|
34
|
+
|
|
35
|
+
TEXT = "text"
|
|
36
|
+
JSON = "json"
|
|
37
|
+
MARKDOWN = "markdown"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class DocumentSummarizer:
|
|
41
|
+
"""
|
|
42
|
+
Algorithmic document summarizer.
|
|
43
|
+
|
|
44
|
+
Design Decision: Use simple heuristics instead of ML:
|
|
45
|
+
- Position-based extraction (opening, closing paragraphs)
|
|
46
|
+
- Length-based filtering (key sentences)
|
|
47
|
+
- Structure detection (headings, lists)
|
|
48
|
+
|
|
49
|
+
Trade-offs:
|
|
50
|
+
- Performance: O(n) single pass vs. complex NLP models
|
|
51
|
+
- Accuracy: ~70% vs. ~90% for ML models
|
|
52
|
+
- Simplicity: Zero dependencies vs. heavy ML packages
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, max_words: int = 150):
|
|
56
|
+
"""Initialize summarizer with word limit."""
|
|
57
|
+
self.max_words = max_words
|
|
58
|
+
|
|
59
|
+
def summarize(
|
|
60
|
+
self, content: str, style: SummaryStyle, lines_limit: Optional[int] = None
|
|
61
|
+
) -> str:
|
|
62
|
+
"""
|
|
63
|
+
Summarize document content.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
content: Document text to summarize
|
|
67
|
+
style: Summary style (brief, detailed, bullet_points, executive)
|
|
68
|
+
lines_limit: Optional line limit (reads first N lines only)
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Summary text
|
|
72
|
+
|
|
73
|
+
Complexity: O(n) where n is content length
|
|
74
|
+
"""
|
|
75
|
+
# Apply line limit if specified
|
|
76
|
+
if lines_limit:
|
|
77
|
+
content = self._limit_lines(content, lines_limit)
|
|
78
|
+
|
|
79
|
+
# Route to style-specific summarizer
|
|
80
|
+
summarizers = {
|
|
81
|
+
SummaryStyle.BRIEF: self._summarize_brief,
|
|
82
|
+
SummaryStyle.DETAILED: self._summarize_detailed,
|
|
83
|
+
SummaryStyle.BULLET_POINTS: self._summarize_bullet_points,
|
|
84
|
+
SummaryStyle.EXECUTIVE: self._summarize_executive,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
summary = summarizers[style](content)
|
|
88
|
+
return self._truncate_to_word_limit(summary)
|
|
89
|
+
|
|
90
|
+
def _limit_lines(self, content: str, limit: int) -> str:
|
|
91
|
+
"""Limit content to first N lines."""
|
|
92
|
+
lines = content.split("\n")
|
|
93
|
+
return "\n".join(lines[:limit])
|
|
94
|
+
|
|
95
|
+
def _truncate_to_word_limit(self, text: str) -> str:
|
|
96
|
+
"""Truncate text to max_words limit."""
|
|
97
|
+
words = text.split()
|
|
98
|
+
if len(words) <= self.max_words:
|
|
99
|
+
return text
|
|
100
|
+
|
|
101
|
+
# Truncate and add ellipsis
|
|
102
|
+
truncated = " ".join(words[: self.max_words])
|
|
103
|
+
return f"{truncated}..."
|
|
104
|
+
|
|
105
|
+
def _summarize_brief(self, content: str) -> str:
|
|
106
|
+
"""
|
|
107
|
+
Brief summary: Extract first paragraph.
|
|
108
|
+
|
|
109
|
+
Heuristic: First non-empty paragraph usually introduces document.
|
|
110
|
+
"""
|
|
111
|
+
paragraphs = self._extract_paragraphs(content)
|
|
112
|
+
if not paragraphs:
|
|
113
|
+
return content.strip()
|
|
114
|
+
|
|
115
|
+
return paragraphs[0]
|
|
116
|
+
|
|
117
|
+
def _summarize_detailed(self, content: str) -> str:
|
|
118
|
+
"""
|
|
119
|
+
Detailed summary: Extract key sentences.
|
|
120
|
+
|
|
121
|
+
Heuristics:
|
|
122
|
+
- First paragraph (introduction)
|
|
123
|
+
- Sentences with important markers (however, therefore, important)
|
|
124
|
+
- Last paragraph (conclusion)
|
|
125
|
+
"""
|
|
126
|
+
paragraphs = self._extract_paragraphs(content)
|
|
127
|
+
if not paragraphs:
|
|
128
|
+
return content.strip()
|
|
129
|
+
|
|
130
|
+
key_sentences = []
|
|
131
|
+
|
|
132
|
+
# Add first paragraph
|
|
133
|
+
if paragraphs:
|
|
134
|
+
key_sentences.append(paragraphs[0])
|
|
135
|
+
|
|
136
|
+
# Add sentences with key markers from middle paragraphs
|
|
137
|
+
if len(paragraphs) > 2:
|
|
138
|
+
key_markers = [
|
|
139
|
+
"however",
|
|
140
|
+
"therefore",
|
|
141
|
+
"important",
|
|
142
|
+
"note",
|
|
143
|
+
"critical",
|
|
144
|
+
"key",
|
|
145
|
+
"must",
|
|
146
|
+
"should",
|
|
147
|
+
"recommended",
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
for para in paragraphs[1:-1]:
|
|
151
|
+
sentences = self._split_sentences(para)
|
|
152
|
+
for sentence in sentences:
|
|
153
|
+
if any(marker in sentence.lower() for marker in key_markers):
|
|
154
|
+
key_sentences.append(sentence)
|
|
155
|
+
break # One sentence per paragraph max
|
|
156
|
+
|
|
157
|
+
# Add last paragraph
|
|
158
|
+
if len(paragraphs) > 1:
|
|
159
|
+
key_sentences.append(paragraphs[-1])
|
|
160
|
+
|
|
161
|
+
return " ".join(key_sentences)
|
|
162
|
+
|
|
163
|
+
def _summarize_bullet_points(self, content: str) -> str:
|
|
164
|
+
"""
|
|
165
|
+
Bullet point summary: Convert paragraphs to markdown list.
|
|
166
|
+
|
|
167
|
+
Heuristic: Each paragraph becomes a bullet point.
|
|
168
|
+
"""
|
|
169
|
+
paragraphs = self._extract_paragraphs(content)
|
|
170
|
+
if not paragraphs:
|
|
171
|
+
return content.strip()
|
|
172
|
+
|
|
173
|
+
# Take key paragraphs (first, middle with markers, last)
|
|
174
|
+
key_paragraphs = []
|
|
175
|
+
|
|
176
|
+
# Always include first
|
|
177
|
+
if paragraphs:
|
|
178
|
+
key_paragraphs.append(paragraphs[0])
|
|
179
|
+
|
|
180
|
+
# Include middle paragraphs with key content
|
|
181
|
+
if len(paragraphs) > 2:
|
|
182
|
+
key_markers = ["however", "therefore", "important", "note", "critical"]
|
|
183
|
+
for para in paragraphs[1:-1]:
|
|
184
|
+
if any(marker in para.lower() for marker in key_markers):
|
|
185
|
+
# Take first sentence only for bullet point
|
|
186
|
+
first_sentence = self._split_sentences(para)[0]
|
|
187
|
+
key_paragraphs.append(first_sentence)
|
|
188
|
+
|
|
189
|
+
# Include last if different from first
|
|
190
|
+
if len(paragraphs) > 1:
|
|
191
|
+
key_paragraphs.append(paragraphs[-1])
|
|
192
|
+
|
|
193
|
+
# Format as markdown bullets
|
|
194
|
+
bullets = [f"- {para}" for para in key_paragraphs]
|
|
195
|
+
return "\n".join(bullets)
|
|
196
|
+
|
|
197
|
+
def _summarize_executive(self, content: str) -> str:
|
|
198
|
+
"""
|
|
199
|
+
Executive summary: Opening + conclusion.
|
|
200
|
+
|
|
201
|
+
Heuristic: First and last paragraphs capture overview and conclusion.
|
|
202
|
+
"""
|
|
203
|
+
paragraphs = self._extract_paragraphs(content)
|
|
204
|
+
if not paragraphs:
|
|
205
|
+
return content.strip()
|
|
206
|
+
|
|
207
|
+
if len(paragraphs) == 1:
|
|
208
|
+
return paragraphs[0]
|
|
209
|
+
|
|
210
|
+
# Opening paragraph + conclusion paragraph
|
|
211
|
+
return f"{paragraphs[0]}\n\n{paragraphs[-1]}"
|
|
212
|
+
|
|
213
|
+
def _extract_paragraphs(self, content: str) -> list[str]:
|
|
214
|
+
"""
|
|
215
|
+
Extract paragraphs from content.
|
|
216
|
+
|
|
217
|
+
Filters out:
|
|
218
|
+
- Empty lines
|
|
219
|
+
- Short lines (< 40 chars, likely headers/formatting artifacts)
|
|
220
|
+
- Code blocks (lines with multiple indentation)
|
|
221
|
+
- Lines that look like code (contain def, class, =, {, etc.)
|
|
222
|
+
"""
|
|
223
|
+
# Split on double newlines for paragraph boundaries
|
|
224
|
+
raw_paragraphs = re.split(r"\n\s*\n", content)
|
|
225
|
+
|
|
226
|
+
paragraphs = []
|
|
227
|
+
for para in raw_paragraphs:
|
|
228
|
+
# Clean and normalize whitespace
|
|
229
|
+
para = " ".join(para.split())
|
|
230
|
+
|
|
231
|
+
# Skip empty or very short paragraphs (likely headers)
|
|
232
|
+
if len(para) < 40:
|
|
233
|
+
continue
|
|
234
|
+
|
|
235
|
+
# Skip code blocks (heuristic: contains code-like patterns)
|
|
236
|
+
code_indicators = ["def ", "class ", " = ", "{", "}", "return ", "import "]
|
|
237
|
+
if any(indicator in para for indicator in code_indicators):
|
|
238
|
+
continue
|
|
239
|
+
|
|
240
|
+
paragraphs.append(para)
|
|
241
|
+
|
|
242
|
+
return paragraphs
|
|
243
|
+
|
|
244
|
+
def _split_sentences(self, text: str) -> list[str]:
|
|
245
|
+
"""
|
|
246
|
+
Split text into sentences.
|
|
247
|
+
|
|
248
|
+
Simple heuristic: Split on '. ' but handle common abbreviations.
|
|
249
|
+
"""
|
|
250
|
+
# Handle common abbreviations to avoid false splits
|
|
251
|
+
text = text.replace("Dr.", "Dr<DOT>")
|
|
252
|
+
text = text.replace("Mr.", "Mr<DOT>")
|
|
253
|
+
text = text.replace("Mrs.", "Mrs<DOT>")
|
|
254
|
+
text = text.replace("e.g.", "e<DOT>g<DOT>")
|
|
255
|
+
text = text.replace("i.e.", "i<DOT>e<DOT>")
|
|
256
|
+
|
|
257
|
+
# Split on sentence boundaries
|
|
258
|
+
sentences = re.split(r"(?<=[.!?])\s+", text)
|
|
259
|
+
|
|
260
|
+
# Restore abbreviations
|
|
261
|
+
sentences = [s.replace("<DOT>", ".") for s in sentences]
|
|
262
|
+
|
|
263
|
+
return [s.strip() for s in sentences if s.strip()]
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def format_output(summary: str, output_format: OutputFormat, file_path: Path) -> str:
|
|
267
|
+
"""
|
|
268
|
+
Format summary output.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
summary: Summary text
|
|
272
|
+
output_format: Output format (text, json, markdown)
|
|
273
|
+
file_path: Original file path for metadata
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
Formatted output string
|
|
277
|
+
"""
|
|
278
|
+
if output_format == OutputFormat.TEXT:
|
|
279
|
+
return summary
|
|
280
|
+
|
|
281
|
+
if output_format == OutputFormat.JSON:
|
|
282
|
+
result = {
|
|
283
|
+
"file": str(file_path),
|
|
284
|
+
"summary": summary,
|
|
285
|
+
"word_count": len(summary.split()),
|
|
286
|
+
}
|
|
287
|
+
return json.dumps(result, indent=2)
|
|
288
|
+
|
|
289
|
+
if output_format == OutputFormat.MARKDOWN:
|
|
290
|
+
return f"# Summary: {file_path.name}\n\n{summary}\n"
|
|
291
|
+
|
|
292
|
+
return summary
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def summarize_command(args) -> int:
|
|
296
|
+
"""
|
|
297
|
+
Execute summarize command.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
args: Parsed command line arguments with:
|
|
301
|
+
- file_path: Path to file to summarize
|
|
302
|
+
- style: Summary style
|
|
303
|
+
- max_words: Maximum words in summary
|
|
304
|
+
- output: Output format
|
|
305
|
+
- lines: Optional line limit
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
Exit code (0 for success, 1 for error)
|
|
309
|
+
"""
|
|
310
|
+
file_path = Path(args.file_path)
|
|
311
|
+
|
|
312
|
+
# Validate file exists
|
|
313
|
+
if not file_path.exists():
|
|
314
|
+
print(f"Error: File not found: {file_path}")
|
|
315
|
+
return 1
|
|
316
|
+
|
|
317
|
+
if not file_path.is_file():
|
|
318
|
+
print(f"Error: Not a file: {file_path}")
|
|
319
|
+
return 1
|
|
320
|
+
|
|
321
|
+
try:
|
|
322
|
+
# Read file content
|
|
323
|
+
content = file_path.read_text(encoding="utf-8")
|
|
324
|
+
|
|
325
|
+
# Create summarizer
|
|
326
|
+
summarizer = DocumentSummarizer(max_words=args.max_words)
|
|
327
|
+
|
|
328
|
+
# Generate summary
|
|
329
|
+
summary = summarizer.summarize(
|
|
330
|
+
content, style=SummaryStyle(args.style), lines_limit=args.lines
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
# Format output
|
|
334
|
+
output = format_output(summary, OutputFormat(args.output), file_path)
|
|
335
|
+
|
|
336
|
+
# Print result
|
|
337
|
+
print(output)
|
|
338
|
+
|
|
339
|
+
return 0
|
|
340
|
+
|
|
341
|
+
except UnicodeDecodeError:
|
|
342
|
+
print(f"Error: Cannot read file (not valid UTF-8): {file_path}")
|
|
343
|
+
return 1
|
|
344
|
+
except Exception as e:
|
|
345
|
+
print(f"Error: {e}")
|
|
346
|
+
return 1
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def add_summarize_parser(subparsers) -> None:
|
|
350
|
+
"""
|
|
351
|
+
Add summarize subcommand parser.
|
|
352
|
+
|
|
353
|
+
Args:
|
|
354
|
+
subparsers: Subparsers object from argparse
|
|
355
|
+
"""
|
|
356
|
+
parser = subparsers.add_parser(
|
|
357
|
+
"summarize",
|
|
358
|
+
help="Summarize document content (shell-based alternative to MCP document_summarizer)",
|
|
359
|
+
description="""
|
|
360
|
+
Algorithmic document summarization without ML dependencies.
|
|
361
|
+
|
|
362
|
+
Styles:
|
|
363
|
+
brief - First paragraph only (quick overview)
|
|
364
|
+
detailed - Key sentences from opening, middle, closing
|
|
365
|
+
bullet_points - Markdown bullet list of key points
|
|
366
|
+
executive - Opening + conclusion (for quick decisions)
|
|
367
|
+
|
|
368
|
+
Examples:
|
|
369
|
+
claude-mpm summarize README.md
|
|
370
|
+
claude-mpm summarize docs/guide.md --style detailed --max-words 200
|
|
371
|
+
claude-mpm summarize src/main.py --style bullet_points --output markdown
|
|
372
|
+
claude-mpm summarize large.txt --lines 100 --style brief
|
|
373
|
+
""",
|
|
374
|
+
formatter_class=lambda prog: __import__("argparse").RawDescriptionHelpFormatter(
|
|
375
|
+
prog, max_help_position=40
|
|
376
|
+
),
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
# Required arguments
|
|
380
|
+
parser.add_argument("file_path", type=str, help="Path to file to summarize")
|
|
381
|
+
|
|
382
|
+
# Optional arguments
|
|
383
|
+
parser.add_argument(
|
|
384
|
+
"--style",
|
|
385
|
+
type=str,
|
|
386
|
+
choices=["brief", "detailed", "bullet_points", "executive"],
|
|
387
|
+
default="brief",
|
|
388
|
+
help="Summary style (default: brief)",
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
parser.add_argument(
|
|
392
|
+
"--max-words",
|
|
393
|
+
type=int,
|
|
394
|
+
default=150,
|
|
395
|
+
help="Maximum words in summary (default: 150)",
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
parser.add_argument(
|
|
399
|
+
"--output",
|
|
400
|
+
type=str,
|
|
401
|
+
choices=["text", "json", "markdown"],
|
|
402
|
+
default="text",
|
|
403
|
+
help="Output format (default: text)",
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
parser.add_argument(
|
|
407
|
+
"--lines",
|
|
408
|
+
type=int,
|
|
409
|
+
default=None,
|
|
410
|
+
help="Limit to first N lines of file (default: no limit)",
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
parser.set_defaults(command="summarize")
|
claude_mpm/cli/executor.py
CHANGED
|
@@ -24,6 +24,7 @@ from .commands import (
|
|
|
24
24
|
show_info,
|
|
25
25
|
)
|
|
26
26
|
from .commands.analyze_code import manage_analyze_code
|
|
27
|
+
from .commands.config import manage_config
|
|
27
28
|
from .commands.dashboard import manage_dashboard
|
|
28
29
|
from .commands.skills import manage_skills
|
|
29
30
|
from .commands.upgrade import upgrade
|
|
@@ -141,6 +142,24 @@ def execute_command(command: str, args) -> int:
|
|
|
141
142
|
result = agent_source_command(args)
|
|
142
143
|
return result if result is not None else 0
|
|
143
144
|
|
|
145
|
+
# Handle summarize command with lazy import
|
|
146
|
+
if command == "summarize":
|
|
147
|
+
# Lazy import to avoid loading unless needed
|
|
148
|
+
from .commands.summarize import summarize_command
|
|
149
|
+
|
|
150
|
+
result = summarize_command(args)
|
|
151
|
+
return result if result is not None else 0
|
|
152
|
+
|
|
153
|
+
# Handle profile command with lazy import
|
|
154
|
+
if command == "profile":
|
|
155
|
+
# Lazy import to avoid loading unless needed
|
|
156
|
+
from .commands.profile import ProfileCommand
|
|
157
|
+
|
|
158
|
+
cmd = ProfileCommand()
|
|
159
|
+
result = cmd.run(args)
|
|
160
|
+
# Convert CommandResult to exit code
|
|
161
|
+
return result.exit_code if result else 0
|
|
162
|
+
|
|
144
163
|
# Handle auto-configure command with lazy import
|
|
145
164
|
if command == "auto-configure":
|
|
146
165
|
# Lazy import to avoid loading unless needed
|
|
@@ -228,9 +247,8 @@ def execute_command(command: str, args) -> int:
|
|
|
228
247
|
CLICommands.MEMORY.value: manage_memory,
|
|
229
248
|
CLICommands.MONITOR.value: manage_monitor,
|
|
230
249
|
CLICommands.DASHBOARD.value: manage_dashboard,
|
|
231
|
-
# Configuration management commands
|
|
232
|
-
#
|
|
233
|
-
CLICommands.CONFIG.value: manage_configure, # Alias to configure
|
|
250
|
+
# Configuration management commands
|
|
251
|
+
CLICommands.CONFIG.value: manage_config, # Unified config with subcommands
|
|
234
252
|
CLICommands.CONFIGURE.value: manage_configure, # Interactive configuration TUI
|
|
235
253
|
CLICommands.AGGREGATE.value: aggregate_command,
|
|
236
254
|
CLICommands.ANALYZE_CODE.value: manage_analyze_code,
|
|
@@ -6,6 +6,7 @@ local agents with user-friendly prompts, intelligent defaults, and validation.
|
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
8
|
import re
|
|
9
|
+
import shutil
|
|
9
10
|
import sys
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Any, Dict, List, Optional, Tuple
|
|
@@ -61,6 +62,50 @@ class AgentWizard:
|
|
|
61
62
|
self.source_manager = None
|
|
62
63
|
self.discovery_enabled = False
|
|
63
64
|
|
|
65
|
+
@staticmethod
|
|
66
|
+
def _calculate_column_widths(
|
|
67
|
+
terminal_width: int, columns: Dict[str, int]
|
|
68
|
+
) -> Dict[str, int]:
|
|
69
|
+
"""Calculate dynamic column widths based on terminal size.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
terminal_width: Current terminal width in characters
|
|
73
|
+
columns: Dict mapping column names to minimum widths
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Dict mapping column names to calculated widths
|
|
77
|
+
|
|
78
|
+
Design:
|
|
79
|
+
- Ensures minimum widths are respected
|
|
80
|
+
- Distributes extra space proportionally
|
|
81
|
+
- Handles narrow terminals gracefully (minimum 80 chars)
|
|
82
|
+
"""
|
|
83
|
+
# Ensure minimum terminal width
|
|
84
|
+
min_terminal_width = 80
|
|
85
|
+
terminal_width = max(terminal_width, min_terminal_width)
|
|
86
|
+
|
|
87
|
+
# Calculate total minimum width needed
|
|
88
|
+
total_min_width = sum(columns.values())
|
|
89
|
+
|
|
90
|
+
# Account for spacing between columns
|
|
91
|
+
overhead = len(columns) + 1
|
|
92
|
+
available_width = terminal_width - overhead
|
|
93
|
+
|
|
94
|
+
# If we have extra space, distribute proportionally
|
|
95
|
+
if available_width > total_min_width:
|
|
96
|
+
extra_space = available_width - total_min_width
|
|
97
|
+
total_weight = sum(columns.values())
|
|
98
|
+
|
|
99
|
+
result = {}
|
|
100
|
+
for col_name, min_width in columns.items():
|
|
101
|
+
# Distribute extra space based on minimum width proportion
|
|
102
|
+
proportion = min_width / total_weight
|
|
103
|
+
extra = int(extra_space * proportion)
|
|
104
|
+
result[col_name] = min_width + extra
|
|
105
|
+
return result
|
|
106
|
+
# Terminal too narrow, use minimum widths
|
|
107
|
+
return columns.copy()
|
|
108
|
+
|
|
64
109
|
def run_interactive_create(self) -> Tuple[bool, str]:
|
|
65
110
|
"""Run interactive agent creation wizard.
|
|
66
111
|
|
|
@@ -259,25 +304,55 @@ class AgentWizard:
|
|
|
259
304
|
print("❌ Invalid choice. Please try again.")
|
|
260
305
|
continue
|
|
261
306
|
|
|
262
|
-
# Show existing agents in a table
|
|
307
|
+
# Show existing agents in a table with dynamic widths
|
|
263
308
|
print(f"\n📋 Found {len(all_agents)} agent(s):\n")
|
|
309
|
+
|
|
310
|
+
# Calculate dynamic column widths based on terminal size
|
|
311
|
+
terminal_width = shutil.get_terminal_size().columns
|
|
312
|
+
min_widths = {
|
|
313
|
+
"#": 4,
|
|
314
|
+
"Agent ID": 30,
|
|
315
|
+
"Name": 20,
|
|
316
|
+
"Source": 15,
|
|
317
|
+
"Status": 10,
|
|
318
|
+
}
|
|
319
|
+
widths = self._calculate_column_widths(terminal_width, min_widths)
|
|
320
|
+
|
|
321
|
+
# Print header with dynamic widths
|
|
264
322
|
print(
|
|
265
|
-
f"{'#':<
|
|
323
|
+
f"{'#':<{widths['#']}} "
|
|
324
|
+
f"{'Agent ID':<{widths['Agent ID']}} "
|
|
325
|
+
f"{'Name':<{widths['Name']}} "
|
|
326
|
+
f"{'Source':<{widths['Source']}} "
|
|
327
|
+
f"{'Status':<{widths['Status']}}"
|
|
266
328
|
)
|
|
267
|
-
|
|
329
|
+
separator_width = sum(widths.values()) + len(widths) - 1
|
|
330
|
+
print("-" * separator_width)
|
|
268
331
|
|
|
269
332
|
for i, agent in enumerate(all_agents, 1):
|
|
270
333
|
agent_id = agent["agent_id"]
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
334
|
+
# Truncate to fit dynamic width
|
|
335
|
+
if len(agent_id) > widths["Agent ID"]:
|
|
336
|
+
agent_id = agent_id[: widths["Agent ID"] - 1] + "…"
|
|
337
|
+
|
|
338
|
+
name = agent["name"]
|
|
339
|
+
if len(name) > widths["Name"]:
|
|
340
|
+
name = name[: widths["Name"] - 1] + "…"
|
|
341
|
+
|
|
274
342
|
source_label = (
|
|
275
|
-
f"[{agent['source_type']}] {agent['source_identifier']}"
|
|
343
|
+
f"[{agent['source_type']}] {agent['source_identifier']}"
|
|
276
344
|
)
|
|
345
|
+
if len(source_label) > widths["Source"]:
|
|
346
|
+
source_label = source_label[: widths["Source"] - 1] + "…"
|
|
347
|
+
|
|
277
348
|
status = "✓ Deployed" if agent["deployed"] else "Available"
|
|
278
349
|
|
|
279
350
|
print(
|
|
280
|
-
f"{i:<
|
|
351
|
+
f"{i:<{widths['#']}} "
|
|
352
|
+
f"{agent_id:<{widths['Agent ID']}} "
|
|
353
|
+
f"{name:<{widths['Name']}} "
|
|
354
|
+
f"{source_label:<{widths['Source']}} "
|
|
355
|
+
f"{status:<{widths['Status']}}"
|
|
281
356
|
)
|
|
282
357
|
|
|
283
358
|
# Build menu choices with arrow-key navigation
|
|
@@ -1299,7 +1374,7 @@ class AgentWizard:
|
|
|
1299
1374
|
Path.home()
|
|
1300
1375
|
/ ".claude-mpm"
|
|
1301
1376
|
/ "cache"
|
|
1302
|
-
/ "
|
|
1377
|
+
/ "agents"
|
|
1303
1378
|
/ "bobmatnyc"
|
|
1304
1379
|
/ "claude-mpm-agents"
|
|
1305
1380
|
/ "AUTO-DEPLOY-INDEX.md"
|
|
@@ -1344,7 +1419,7 @@ class AgentWizard:
|
|
|
1344
1419
|
Path.home()
|
|
1345
1420
|
/ ".claude-mpm"
|
|
1346
1421
|
/ "cache"
|
|
1347
|
-
/ "
|
|
1422
|
+
/ "agents"
|
|
1348
1423
|
/ "bobmatnyc"
|
|
1349
1424
|
/ "claude-mpm-agents"
|
|
1350
1425
|
/ "AUTO-DEPLOY-INDEX.md"
|
|
@@ -406,15 +406,6 @@ Available commands:
|
|
|
406
406
|
help="Show descriptions and metadata for each agent",
|
|
407
407
|
)
|
|
408
408
|
|
|
409
|
-
# Auto-configuration commands (TSK-0054 Phase 5)
|
|
410
|
-
from .auto_configure_parser import (
|
|
411
|
-
add_agents_detect_subparser,
|
|
412
|
-
add_agents_recommend_subparser,
|
|
413
|
-
)
|
|
414
|
-
|
|
415
|
-
add_agents_detect_subparser(agents_subparsers)
|
|
416
|
-
add_agents_recommend_subparser(agents_subparsers)
|
|
417
|
-
|
|
418
409
|
# Phase 3: Agent Selection Modes (single-tier deployment)
|
|
419
410
|
# Minimal configuration - deploy 6 core agents
|
|
420
411
|
deploy_minimal_parser = agents_subparsers.add_parser(
|
|
@@ -444,6 +435,60 @@ Available commands:
|
|
|
444
435
|
help="Show what would be deployed without actually deploying",
|
|
445
436
|
)
|
|
446
437
|
|
|
438
|
+
# ============================================================================
|
|
439
|
+
# Collection-Based Agent Management Commands
|
|
440
|
+
# ============================================================================
|
|
441
|
+
# Purpose: Enable collection-based agent selection and deployment
|
|
442
|
+
# Commands: list-collections, deploy-collection, list-by-collection
|
|
443
|
+
# NEW: Enhanced agent matching with collection_id support
|
|
444
|
+
# ============================================================================
|
|
445
|
+
|
|
446
|
+
# list-collections: List all available agent collections
|
|
447
|
+
agents_subparsers.add_parser(
|
|
448
|
+
"list-collections",
|
|
449
|
+
help="List all available agent collections",
|
|
450
|
+
description="Display all agent collections with agent counts and collection metadata",
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
# deploy-collection: Deploy all agents from a specific collection
|
|
454
|
+
deploy_collection_parser = agents_subparsers.add_parser(
|
|
455
|
+
"deploy-collection",
|
|
456
|
+
help="Deploy all agents from a specific collection",
|
|
457
|
+
description="Deploy all agents from a named collection (e.g., 'bobmatnyc/claude-mpm-agents')",
|
|
458
|
+
)
|
|
459
|
+
deploy_collection_parser.add_argument(
|
|
460
|
+
"collection_id",
|
|
461
|
+
help="Collection ID in format 'owner/repo-name' (e.g., 'bobmatnyc/claude-mpm-agents')",
|
|
462
|
+
)
|
|
463
|
+
deploy_collection_parser.add_argument(
|
|
464
|
+
"--force",
|
|
465
|
+
"-f",
|
|
466
|
+
action="store_true",
|
|
467
|
+
help="Force redeployment even if agents are already deployed",
|
|
468
|
+
)
|
|
469
|
+
deploy_collection_parser.add_argument(
|
|
470
|
+
"--dry-run",
|
|
471
|
+
action="store_true",
|
|
472
|
+
help="Show what would be deployed without actually deploying",
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
# list-by-collection: List agents filtered by collection
|
|
476
|
+
list_by_collection_parser = agents_subparsers.add_parser(
|
|
477
|
+
"list-by-collection",
|
|
478
|
+
help="List agents from a specific collection",
|
|
479
|
+
description="Display agents from a specific collection with metadata",
|
|
480
|
+
)
|
|
481
|
+
list_by_collection_parser.add_argument(
|
|
482
|
+
"collection_id",
|
|
483
|
+
help="Collection ID to filter by (e.g., 'bobmatnyc/claude-mpm-agents')",
|
|
484
|
+
)
|
|
485
|
+
list_by_collection_parser.add_argument(
|
|
486
|
+
"--format",
|
|
487
|
+
choices=["table", "json", "yaml"],
|
|
488
|
+
default="table",
|
|
489
|
+
help="Output format (default: table)",
|
|
490
|
+
)
|
|
491
|
+
|
|
447
492
|
# ============================================================================
|
|
448
493
|
# Cache Git Management Commands (claude-mpm Issue 1M-442 Phase 2)
|
|
449
494
|
# ============================================================================
|