claude-mpm 5.1.8__py3-none-any.whl → 5.4.22__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/{PM_INSTRUCTIONS_TEACH.md → CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md} +721 -41
- claude_mpm/agents/PM_INSTRUCTIONS.md +290 -34
- claude_mpm/agents/agent_loader.py +13 -44
- claude_mpm/agents/frontmatter_validator.py +68 -0
- claude_mpm/agents/templates/circuit-breakers.md +138 -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 +8 -17
- claude_mpm/cli/commands/agents.py +169 -31
- claude_mpm/cli/commands/auto_configure.py +210 -25
- claude_mpm/cli/commands/config.py +88 -2
- claude_mpm/cli/commands/configure.py +1111 -161
- claude_mpm/cli/commands/configure_agent_display.py +15 -6
- claude_mpm/cli/commands/mpm_init/core.py +160 -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/skills.py +214 -189
- claude_mpm/cli/commands/summarize.py +413 -0
- claude_mpm/cli/executor.py +11 -3
- claude_mpm/cli/parsers/agents_parser.py +54 -9
- claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
- claude_mpm/cli/parsers/base_parser.py +5 -0
- claude_mpm/cli/parsers/config_parser.py +153 -83
- claude_mpm/cli/parsers/skills_parser.py +3 -2
- claude_mpm/cli/startup.py +550 -94
- claude_mpm/commands/mpm-config.md +265 -0
- claude_mpm/commands/mpm-help.md +14 -95
- claude_mpm/commands/mpm-organize.md +500 -0
- claude_mpm/config/agent_sources.py +27 -0
- claude_mpm/core/framework/formatters/content_formatter.py +3 -13
- claude_mpm/core/framework/loaders/agent_loader.py +8 -5
- claude_mpm/core/framework_loader.py +4 -2
- claude_mpm/core/logger.py +13 -0
- claude_mpm/core/output_style_manager.py +173 -43
- claude_mpm/core/socketio_pool.py +3 -3
- claude_mpm/core/unified_agent_registry.py +134 -16
- 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 +6 -0
- claude_mpm/hooks/claude_hooks/installer.py +33 -10
- claude_mpm/hooks/claude_hooks/memory_integration.py +26 -9
- claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +4 -0
- claude_mpm/hooks/memory_integration_hook.py +46 -1
- claude_mpm/init.py +0 -19
- claude_mpm/models/agent_definition.py +7 -0
- 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_recommendation_service.py +278 -0
- claude_mpm/services/agents/agent_review_service.py +280 -0
- claude_mpm/services/agents/deployment/agent_discovery_service.py +2 -3
- claude_mpm/services/agents/deployment/agent_template_builder.py +4 -2
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +188 -12
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +531 -55
- claude_mpm/services/agents/git_source_manager.py +34 -0
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
- claude_mpm/services/agents/sources/git_source_sync_service.py +8 -1
- 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/event_bus/config.py +3 -1
- claude_mpm/services/git/git_operations_service.py +93 -8
- claude_mpm/services/monitor/daemon.py +9 -2
- claude_mpm/services/monitor/daemon_manager.py +39 -3
- claude_mpm/services/monitor/server.py +225 -19
- 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 +32 -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/event_normalizer.py +15 -1
- claude_mpm/services/socketio/server/core.py +160 -21
- claude_mpm/services/version_control/git_operations.py +103 -0
- claude_mpm/utils/agent_filters.py +17 -44
- {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/METADATA +47 -84
- {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/RECORD +86 -176
- claude_mpm-5.4.22.dist-info/entry_points.txt +5 -0
- claude_mpm-5.4.22.dist-info/licenses/LICENSE +94 -0
- claude_mpm-5.4.22.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_ENGINEER.md +0 -658
- 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.json +0 -31
- 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.1.8.dist-info/entry_points.txt +0 -10
- claude_mpm-5.1.8.dist-info/licenses/LICENSE +0 -21
- /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
- {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/WHEEL +0 -0
- {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.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,14 @@ 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
|
+
|
|
144
153
|
# Handle auto-configure command with lazy import
|
|
145
154
|
if command == "auto-configure":
|
|
146
155
|
# Lazy import to avoid loading unless needed
|
|
@@ -228,9 +237,8 @@ def execute_command(command: str, args) -> int:
|
|
|
228
237
|
CLICommands.MEMORY.value: manage_memory,
|
|
229
238
|
CLICommands.MONITOR.value: manage_monitor,
|
|
230
239
|
CLICommands.DASHBOARD.value: manage_dashboard,
|
|
231
|
-
# Configuration management commands
|
|
232
|
-
#
|
|
233
|
-
CLICommands.CONFIG.value: manage_configure, # Alias to configure
|
|
240
|
+
# Configuration management commands
|
|
241
|
+
CLICommands.CONFIG.value: manage_config, # Unified config with subcommands
|
|
234
242
|
CLICommands.CONFIGURE.value: manage_configure, # Interactive configuration TUI
|
|
235
243
|
CLICommands.AGGREGATE.value: aggregate_command,
|
|
236
244
|
CLICommands.ANALYZE_CODE.value: manage_analyze_code,
|
|
@@ -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
|
# ============================================================================
|
|
@@ -118,141 +118,3 @@ Examples:
|
|
|
118
118
|
)
|
|
119
119
|
|
|
120
120
|
return auto_configure_parser
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def add_agents_detect_subparser(agents_subparsers) -> argparse.ArgumentParser:
|
|
124
|
-
"""
|
|
125
|
-
Add the agents detect subparser for toolchain detection.
|
|
126
|
-
|
|
127
|
-
WHY: Allows users to see what toolchain is detected without making changes,
|
|
128
|
-
useful for debugging and verification.
|
|
129
|
-
|
|
130
|
-
Args:
|
|
131
|
-
agents_subparsers: The agents subparsers object
|
|
132
|
-
|
|
133
|
-
Returns:
|
|
134
|
-
The configured detect subparser
|
|
135
|
-
"""
|
|
136
|
-
detect_parser = agents_subparsers.add_parser(
|
|
137
|
-
"detect",
|
|
138
|
-
help="Detect project toolchain without deploying",
|
|
139
|
-
description="""
|
|
140
|
-
Detect and display project toolchain without making any changes.
|
|
141
|
-
|
|
142
|
-
This command analyzes your project to detect:
|
|
143
|
-
• Programming languages and versions
|
|
144
|
-
• Frameworks and libraries
|
|
145
|
-
• Deployment targets and platforms
|
|
146
|
-
|
|
147
|
-
Useful for debugging toolchain detection and verifying what would be
|
|
148
|
-
detected before running auto-configure.
|
|
149
|
-
""",
|
|
150
|
-
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
151
|
-
epilog="""
|
|
152
|
-
Examples:
|
|
153
|
-
# Detect toolchain in current directory
|
|
154
|
-
claude-mpm agents detect
|
|
155
|
-
|
|
156
|
-
# Detect with verbose output showing evidence
|
|
157
|
-
claude-mpm agents detect --verbose
|
|
158
|
-
|
|
159
|
-
# JSON output for scripting
|
|
160
|
-
claude-mpm agents detect --json
|
|
161
|
-
|
|
162
|
-
# Detect specific project
|
|
163
|
-
claude-mpm agents detect --project-path /path/to/project
|
|
164
|
-
""",
|
|
165
|
-
)
|
|
166
|
-
add_common_arguments(detect_parser)
|
|
167
|
-
|
|
168
|
-
detect_parser.add_argument(
|
|
169
|
-
"--project-path",
|
|
170
|
-
type=Path,
|
|
171
|
-
metavar="PATH",
|
|
172
|
-
help="Project path to analyze (default: current directory)",
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
return detect_parser
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
def add_agents_recommend_subparser(
|
|
179
|
-
agents_subparsers,
|
|
180
|
-
) -> argparse.ArgumentParser:
|
|
181
|
-
"""
|
|
182
|
-
Add the agents recommend subparser for agent recommendations.
|
|
183
|
-
|
|
184
|
-
WHY: Allows users to see what agents would be recommended without deploying,
|
|
185
|
-
useful for reviewing recommendations before committing to deployment.
|
|
186
|
-
|
|
187
|
-
Args:
|
|
188
|
-
agents_subparsers: The agents subparsers object
|
|
189
|
-
|
|
190
|
-
Returns:
|
|
191
|
-
The configured recommend subparser
|
|
192
|
-
"""
|
|
193
|
-
recommend_parser = agents_subparsers.add_parser(
|
|
194
|
-
"recommend",
|
|
195
|
-
help="Show recommended agents without deploying",
|
|
196
|
-
description="""
|
|
197
|
-
Show recommended agents based on project toolchain without deploying.
|
|
198
|
-
|
|
199
|
-
This command analyzes your project toolchain and recommends appropriate
|
|
200
|
-
agents with detailed reasoning for each recommendation. No changes are
|
|
201
|
-
made to your project.
|
|
202
|
-
|
|
203
|
-
Useful for:
|
|
204
|
-
• Reviewing recommendations before deployment
|
|
205
|
-
• Understanding why agents are recommended
|
|
206
|
-
• Adjusting confidence thresholds
|
|
207
|
-
""",
|
|
208
|
-
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
209
|
-
epilog="""
|
|
210
|
-
Examples:
|
|
211
|
-
# Show recommendations with reasoning
|
|
212
|
-
claude-mpm agents recommend
|
|
213
|
-
|
|
214
|
-
# Require 90% confidence for recommendations
|
|
215
|
-
claude-mpm agents recommend --min-confidence 0.9
|
|
216
|
-
|
|
217
|
-
# JSON output for scripting
|
|
218
|
-
claude-mpm agents recommend --json
|
|
219
|
-
|
|
220
|
-
# Hide detailed reasoning
|
|
221
|
-
claude-mpm agents recommend --no-reasoning
|
|
222
|
-
|
|
223
|
-
# Recommend for specific project
|
|
224
|
-
claude-mpm agents recommend --project-path /path/to/project
|
|
225
|
-
""",
|
|
226
|
-
)
|
|
227
|
-
add_common_arguments(recommend_parser)
|
|
228
|
-
|
|
229
|
-
recommend_parser.add_argument(
|
|
230
|
-
"--project-path",
|
|
231
|
-
type=Path,
|
|
232
|
-
metavar="PATH",
|
|
233
|
-
help="Project path to analyze (default: current directory)",
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
recommend_parser.add_argument(
|
|
237
|
-
"--min-confidence",
|
|
238
|
-
type=float,
|
|
239
|
-
default=0.8,
|
|
240
|
-
metavar="FLOAT",
|
|
241
|
-
help="Minimum confidence threshold for recommendations (0.0-1.0, default: 0.8)",
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
recommend_parser.add_argument(
|
|
245
|
-
"--show-reasoning",
|
|
246
|
-
action="store_true",
|
|
247
|
-
default=True,
|
|
248
|
-
help="Show detailed reasoning for recommendations (default)",
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
recommend_parser.add_argument(
|
|
252
|
-
"--no-reasoning",
|
|
253
|
-
dest="show_reasoning",
|
|
254
|
-
action="store_false",
|
|
255
|
-
help="Hide detailed reasoning for recommendations",
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
return recommend_parser
|
|
@@ -594,6 +594,11 @@ def create_parser(
|
|
|
594
594
|
action="store_true",
|
|
595
595
|
help="Skip confirmation prompts",
|
|
596
596
|
)
|
|
597
|
+
|
|
598
|
+
# Add summarize command
|
|
599
|
+
from ..commands.summarize import add_summarize_parser
|
|
600
|
+
|
|
601
|
+
add_summarize_parser(subparsers)
|
|
597
602
|
except ImportError:
|
|
598
603
|
# Commands module may not be available during testing or refactoring
|
|
599
604
|
pass
|