claude-mpm 4.2.6__py3-none-any.whl → 4.2.9__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/cli/commands/dashboard.py +27 -14
- claude_mpm/cli/parser.py +79 -2
- claude_mpm/dashboard/static/css/code-tree.css +22 -2
- claude_mpm/dashboard/static/css/dashboard.css +15 -1
- claude_mpm/dashboard/static/js/components/code-tree.js +90 -35
- claude_mpm/dashboard/templates/index.html +9 -1
- claude_mpm/services/agents/deployment/agent_format_converter.py +3 -3
- claude_mpm/services/agents/deployment/agent_template_builder.py +3 -4
- claude_mpm/services/dashboard/stable_server.py +542 -47
- claude_mpm/services/socketio/client_proxy.py +20 -12
- claude_mpm/services/socketio/dashboard_server.py +4 -4
- claude_mpm/services/socketio/monitor_client.py +4 -6
- claude_mpm/services/socketio/monitor_server.py +2 -2
- {claude_mpm-4.2.6.dist-info → claude_mpm-4.2.9.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.6.dist-info → claude_mpm-4.2.9.dist-info}/RECORD +20 -20
- {claude_mpm-4.2.6.dist-info → claude_mpm-4.2.9.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.6.dist-info → claude_mpm-4.2.9.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.6.dist-info → claude_mpm-4.2.9.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.6.dist-info → claude_mpm-4.2.9.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.2.
|
|
1
|
+
4.2.9
|
|
@@ -102,37 +102,45 @@ class DashboardCommand(BaseCommand):
|
|
|
102
102
|
},
|
|
103
103
|
)
|
|
104
104
|
return CommandResult.error_result("Failed to start dashboard in background")
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
# Run in foreground mode
|
|
107
107
|
server_started = False
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
# Try stable server first (or if explicitly requested)
|
|
110
110
|
if use_stable:
|
|
111
111
|
try:
|
|
112
|
-
self.logger.info(
|
|
112
|
+
self.logger.info(
|
|
113
|
+
"Starting stable dashboard server (no monitor dependency)..."
|
|
114
|
+
)
|
|
113
115
|
print(f"Starting stable dashboard server on {host}:{port}...")
|
|
114
116
|
print("Press Ctrl+C to stop the server")
|
|
115
117
|
print("\n✅ Using stable server - works without monitor service\n")
|
|
116
|
-
|
|
118
|
+
|
|
117
119
|
# Create and run the stable server
|
|
118
120
|
from ...services.dashboard.stable_server import StableDashboardServer
|
|
121
|
+
|
|
119
122
|
stable_server = StableDashboardServer(host=host, port=port, debug=debug)
|
|
120
|
-
|
|
123
|
+
|
|
121
124
|
# Set up signal handlers for graceful shutdown
|
|
122
125
|
def signal_handler(signum, frame):
|
|
123
126
|
print("\nShutting down dashboard server...")
|
|
124
127
|
sys.exit(0)
|
|
125
|
-
|
|
128
|
+
|
|
126
129
|
signal.signal(signal.SIGINT, signal_handler)
|
|
127
130
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
128
|
-
|
|
131
|
+
|
|
129
132
|
# Run the server (blocking)
|
|
130
|
-
|
|
133
|
+
result = stable_server.run()
|
|
134
|
+
if result:
|
|
135
|
+
# Server ran successfully and stopped normally
|
|
131
136
|
server_started = True
|
|
132
137
|
return CommandResult.success_result("Dashboard server stopped")
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
138
|
+
# Server failed to start (e.g., couldn't find templates)
|
|
139
|
+
server_started = False
|
|
140
|
+
self.logger.warning(
|
|
141
|
+
"Stable server failed to start, trying advanced server..."
|
|
142
|
+
)
|
|
143
|
+
|
|
136
144
|
except KeyboardInterrupt:
|
|
137
145
|
print("\nDashboard server stopped by user")
|
|
138
146
|
return CommandResult.success_result("Dashboard server stopped")
|
|
@@ -142,12 +150,16 @@ class DashboardCommand(BaseCommand):
|
|
|
142
150
|
print(f"\n⚠️ Stable server failed: {e}")
|
|
143
151
|
print("Attempting fallback to advanced server...")
|
|
144
152
|
else:
|
|
145
|
-
return CommandResult.error_result(
|
|
146
|
-
|
|
153
|
+
return CommandResult.error_result(
|
|
154
|
+
f"Failed to start stable dashboard: {e}"
|
|
155
|
+
)
|
|
156
|
+
|
|
147
157
|
# Fallback to advanced DashboardServer if stable server failed or not requested
|
|
148
158
|
if not server_started and not getattr(args, "stable_only", False):
|
|
149
159
|
try:
|
|
150
|
-
self.logger.info(
|
|
160
|
+
self.logger.info(
|
|
161
|
+
"Attempting to start advanced dashboard server with monitor..."
|
|
162
|
+
)
|
|
151
163
|
print(f"\nStarting advanced dashboard server on {host}:{port}...")
|
|
152
164
|
print("Note: This requires monitor service on port 8766")
|
|
153
165
|
print("Press Ctrl+C to stop the server")
|
|
@@ -194,6 +206,7 @@ class DashboardCommand(BaseCommand):
|
|
|
194
206
|
error_msg += " - Try running with --stable flag for standalone mode\n"
|
|
195
207
|
error_msg += " - Use --debug flag for more details\n"
|
|
196
208
|
return CommandResult.error_result(error_msg)
|
|
209
|
+
return None
|
|
197
210
|
|
|
198
211
|
def _stop_dashboard(self, args) -> CommandResult:
|
|
199
212
|
"""Stop the dashboard server."""
|
claude_mpm/cli/parser.py
CHANGED
|
@@ -19,8 +19,85 @@ REFACTORING NOTE: The original 961-line create_parser function has been split in
|
|
|
19
19
|
- parsers/mcp_parser.py: MCP Gateway commands
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
import argparse
|
|
23
|
+
import sys
|
|
24
|
+
from typing import List, Optional
|
|
25
|
+
|
|
26
|
+
# Try to import from the new modular structure with helpful error handling
|
|
27
|
+
try:
|
|
28
|
+
from .parsers import add_common_arguments, create_parser, preprocess_args
|
|
29
|
+
except ImportError as e:
|
|
30
|
+
# Provide a helpful error message for users with outdated installations
|
|
31
|
+
error_msg = f"""
|
|
32
|
+
╔══════════════════════════════════════════════════════════════════╗
|
|
33
|
+
║ Claude MPM Import Error ║
|
|
34
|
+
╠══════════════════════════════════════════════════════════════════╣
|
|
35
|
+
║ ║
|
|
36
|
+
║ Unable to import required modules: {e!s} ║
|
|
37
|
+
║ ║
|
|
38
|
+
║ This typically happens when: ║
|
|
39
|
+
║ • The installation is outdated or incomplete ║
|
|
40
|
+
║ • Files are missing from your installation ║
|
|
41
|
+
║ • You're using an old cached version from pipx ║
|
|
42
|
+
║ ║
|
|
43
|
+
║ ┌─────────────────────────────────────────────────────────┐ ║
|
|
44
|
+
║ │ To fix this issue, please try one of these solutions: │ ║
|
|
45
|
+
║ └─────────────────────────────────────────────────────────┘ ║
|
|
46
|
+
║ ║
|
|
47
|
+
║ 1. If installed with pipx (recommended): ║
|
|
48
|
+
║ ➜ pipx reinstall claude-mpm ║
|
|
49
|
+
║ ║
|
|
50
|
+
║ 2. If installed with pip: ║
|
|
51
|
+
║ ➜ pip install --upgrade --force-reinstall claude-mpm ║
|
|
52
|
+
║ ║
|
|
53
|
+
║ 3. For development installations: ║
|
|
54
|
+
║ ➜ pip install -e . --force-reinstall ║
|
|
55
|
+
║ ║
|
|
56
|
+
║ 4. Clear pipx cache and reinstall (if pipx issues persist): ║
|
|
57
|
+
║ ➜ pipx uninstall claude-mpm ║
|
|
58
|
+
║ ➜ pipx install claude-mpm ║
|
|
59
|
+
║ ║
|
|
60
|
+
╚══════════════════════════════════════════════════════════════════╝
|
|
61
|
+
"""
|
|
62
|
+
print(error_msg, file=sys.stderr)
|
|
63
|
+
|
|
64
|
+
# Provide minimal fallback functionality to at least show help
|
|
65
|
+
def create_parser(version: str = "Unknown") -> argparse.ArgumentParser:
|
|
66
|
+
"""Emergency fallback parser that shows reinstallation instructions."""
|
|
67
|
+
parser = argparse.ArgumentParser(
|
|
68
|
+
prog="claude-mpm",
|
|
69
|
+
description="Claude Multi-Agent Project Manager (Installation Error - Please Reinstall)",
|
|
70
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
71
|
+
epilog="""
|
|
72
|
+
This installation appears to be incomplete or outdated.
|
|
73
|
+
Please reinstall using one of the methods shown above.
|
|
74
|
+
""",
|
|
75
|
+
)
|
|
76
|
+
parser.add_argument(
|
|
77
|
+
"--version",
|
|
78
|
+
action="version",
|
|
79
|
+
version=f"{version} (installation error - please reinstall)",
|
|
80
|
+
)
|
|
81
|
+
return parser
|
|
82
|
+
|
|
83
|
+
def add_common_arguments(parser: argparse.ArgumentParser) -> None:
|
|
84
|
+
"""Emergency fallback - no common arguments available."""
|
|
85
|
+
|
|
86
|
+
def preprocess_args(args: Optional[List[str]] = None) -> List[str]:
|
|
87
|
+
"""Emergency fallback - return args unchanged."""
|
|
88
|
+
return args if args is not None else sys.argv[1:]
|
|
89
|
+
|
|
90
|
+
# Exit with error code to indicate the problem
|
|
91
|
+
# Don't exit immediately - let the user see --help if requested
|
|
92
|
+
import atexit
|
|
93
|
+
|
|
94
|
+
atexit.register(
|
|
95
|
+
lambda: (
|
|
96
|
+
sys.exit(1)
|
|
97
|
+
if "--help" not in sys.argv and "--version" not in sys.argv
|
|
98
|
+
else None
|
|
99
|
+
)
|
|
100
|
+
)
|
|
24
101
|
|
|
25
102
|
# Re-export for backward compatibility
|
|
26
103
|
__all__ = ["add_common_arguments", "create_parser", "preprocess_args"]
|
|
@@ -7,6 +7,15 @@
|
|
|
7
7
|
background: #f8f9fa;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/* Split Container for Tree and Content */
|
|
11
|
+
.code-split-container {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex: 1;
|
|
14
|
+
gap: 10px;
|
|
15
|
+
padding: 10px;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
/* Advanced Options - Always Visible */
|
|
11
20
|
.code-advanced-options-visible {
|
|
12
21
|
background: white;
|
|
@@ -454,16 +463,27 @@
|
|
|
454
463
|
|
|
455
464
|
/* Code Tree Container */
|
|
456
465
|
.code-tree-container {
|
|
457
|
-
flex:
|
|
466
|
+
flex: 0 0 50%;
|
|
458
467
|
background: white;
|
|
459
468
|
border-radius: 8px;
|
|
460
469
|
padding: 20px;
|
|
461
470
|
position: relative;
|
|
462
|
-
overflow:
|
|
471
|
+
overflow: auto;
|
|
463
472
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
464
473
|
border-left: 1px solid #e2e8f0;
|
|
465
474
|
}
|
|
466
475
|
|
|
476
|
+
/* Code Content Area */
|
|
477
|
+
.code-module-data-content {
|
|
478
|
+
flex: 1;
|
|
479
|
+
background: white;
|
|
480
|
+
border-radius: 8px;
|
|
481
|
+
padding: 20px;
|
|
482
|
+
overflow: auto;
|
|
483
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
484
|
+
border: 1px solid #e2e8f0;
|
|
485
|
+
}
|
|
486
|
+
|
|
467
487
|
/* Visual hierarchy improvements */
|
|
468
488
|
.code-tree-container:focus-within {
|
|
469
489
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
@@ -2814,7 +2814,8 @@ button:disabled:hover {
|
|
|
2814
2814
|
color: #f1fa8c;
|
|
2815
2815
|
}
|
|
2816
2816
|
|
|
2817
|
-
.file-content-code .number
|
|
2817
|
+
.file-content-code .number,
|
|
2818
|
+
.source-line .number {
|
|
2818
2819
|
color: #bd93f9;
|
|
2819
2820
|
}
|
|
2820
2821
|
|
|
@@ -2826,6 +2827,19 @@ button:disabled:hover {
|
|
|
2826
2827
|
color: #8be9fd;
|
|
2827
2828
|
}
|
|
2828
2829
|
|
|
2830
|
+
/* JSON-specific syntax highlighting */
|
|
2831
|
+
.file-content-code .json-key,
|
|
2832
|
+
.source-line .json-key {
|
|
2833
|
+
color: #8be9fd;
|
|
2834
|
+
font-weight: 600;
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
.file-content-code .literal,
|
|
2838
|
+
.source-line .literal {
|
|
2839
|
+
color: #ff79c6;
|
|
2840
|
+
font-weight: 600;
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2829
2843
|
.file-content-code .selector {
|
|
2830
2844
|
color: #ff79c6;
|
|
2831
2845
|
}
|
|
@@ -4378,7 +4378,13 @@ class CodeTree {
|
|
|
4378
4378
|
* Initialize the structured data integration
|
|
4379
4379
|
*/
|
|
4380
4380
|
initializeStructuredData() {
|
|
4381
|
-
|
|
4381
|
+
// Try to find the Code tab content area first
|
|
4382
|
+
this.structuredDataContent = document.getElementById('code-module-data-content');
|
|
4383
|
+
|
|
4384
|
+
// Fall back to Events tab content area for backward compatibility
|
|
4385
|
+
if (!this.structuredDataContent) {
|
|
4386
|
+
this.structuredDataContent = document.getElementById('module-data-content');
|
|
4387
|
+
}
|
|
4382
4388
|
|
|
4383
4389
|
if (!this.structuredDataContent) {
|
|
4384
4390
|
console.warn('Structured data content element not found');
|
|
@@ -4928,7 +4934,7 @@ main();
|
|
|
4928
4934
|
/**
|
|
4929
4935
|
* Apply basic syntax highlighting
|
|
4930
4936
|
*/
|
|
4931
|
-
applySyntaxHighlighting(content) {
|
|
4937
|
+
applySyntaxHighlighting(content, fileType = 'text') {
|
|
4932
4938
|
// First, properly escape HTML entities
|
|
4933
4939
|
let highlighted = content
|
|
4934
4940
|
.replace(/&/g, '&')
|
|
@@ -4938,39 +4944,88 @@ main();
|
|
|
4938
4944
|
// Store markers for where we'll insert spans
|
|
4939
4945
|
const replacements = [];
|
|
4940
4946
|
|
|
4941
|
-
//
|
|
4942
|
-
const
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4947
|
+
// Check if this is JSON content
|
|
4948
|
+
const isJson = fileType === 'json' || this.currentFilePath?.endsWith('.json');
|
|
4949
|
+
|
|
4950
|
+
if (isJson) {
|
|
4951
|
+
// JSON-specific highlighting
|
|
4952
|
+
// JSON property names (keys)
|
|
4953
|
+
const jsonKeys = /"([^"]+)"(?=\s*:)/g;
|
|
4954
|
+
let match;
|
|
4955
|
+
while ((match = jsonKeys.exec(highlighted)) !== null) {
|
|
4956
|
+
replacements.push({
|
|
4957
|
+
start: match.index,
|
|
4958
|
+
end: match.index + match[0].length,
|
|
4959
|
+
replacement: `<span class="json-key">${match[0]}</span>`
|
|
4960
|
+
});
|
|
4961
|
+
}
|
|
4962
|
+
|
|
4963
|
+
// JSON strings (values)
|
|
4964
|
+
const jsonStrings = /:\s*"([^"]*)"/g;
|
|
4965
|
+
while ((match = jsonStrings.exec(highlighted)) !== null) {
|
|
4966
|
+
const colonIndex = match[0].indexOf('"');
|
|
4967
|
+
replacements.push({
|
|
4968
|
+
start: match.index + colonIndex,
|
|
4969
|
+
end: match.index + match[0].length,
|
|
4970
|
+
replacement: `<span class="string">"${match[1]}"</span>`
|
|
4971
|
+
});
|
|
4972
|
+
}
|
|
4973
|
+
|
|
4974
|
+
// JSON numbers
|
|
4975
|
+
const jsonNumbers = /:\s*(-?\d+\.?\d*)/g;
|
|
4976
|
+
while ((match = jsonNumbers.exec(highlighted)) !== null) {
|
|
4977
|
+
const numberStart = match[0].indexOf(match[1]);
|
|
4978
|
+
replacements.push({
|
|
4979
|
+
start: match.index + numberStart,
|
|
4980
|
+
end: match.index + match[0].length,
|
|
4981
|
+
replacement: `<span class="number">${match[1]}</span>`
|
|
4982
|
+
});
|
|
4983
|
+
}
|
|
4984
|
+
|
|
4985
|
+
// JSON booleans and null
|
|
4986
|
+
const jsonLiterals = /\b(true|false|null)\b/g;
|
|
4987
|
+
while ((match = jsonLiterals.exec(highlighted)) !== null) {
|
|
4988
|
+
replacements.push({
|
|
4989
|
+
start: match.index,
|
|
4990
|
+
end: match.index + match[0].length,
|
|
4991
|
+
replacement: `<span class="literal">${match[0]}</span>`
|
|
4992
|
+
});
|
|
4993
|
+
}
|
|
4994
|
+
} else {
|
|
4995
|
+
// Python and JavaScript keywords (combined)
|
|
4996
|
+
const keywords = /\b(def|class|import|from|if|else|elif|for|while|try|except|finally|with|as|return|yield|lambda|async|await|function|const|let|var|catch|export)\b/g;
|
|
4997
|
+
|
|
4998
|
+
// Find all matches first without replacing
|
|
4999
|
+
let match;
|
|
5000
|
+
|
|
5001
|
+
// Keywords
|
|
5002
|
+
while ((match = keywords.exec(highlighted)) !== null) {
|
|
5003
|
+
replacements.push({
|
|
5004
|
+
start: match.index,
|
|
5005
|
+
end: match.index + match[0].length,
|
|
5006
|
+
replacement: `<span class="keyword">${match[0]}</span>`
|
|
5007
|
+
});
|
|
5008
|
+
}
|
|
5009
|
+
|
|
5010
|
+
// Strings - simple pattern for now
|
|
5011
|
+
const stringPattern = /(["'`])([^"'`]*?)\1/g;
|
|
5012
|
+
while ((match = stringPattern.exec(highlighted)) !== null) {
|
|
5013
|
+
replacements.push({
|
|
5014
|
+
start: match.index,
|
|
5015
|
+
end: match.index + match[0].length,
|
|
5016
|
+
replacement: `<span class="string">${match[0]}</span>`
|
|
5017
|
+
});
|
|
5018
|
+
}
|
|
5019
|
+
|
|
5020
|
+
// Comments
|
|
5021
|
+
const commentPattern = /(#.*$|\/\/.*$)/gm;
|
|
5022
|
+
while ((match = commentPattern.exec(highlighted)) !== null) {
|
|
5023
|
+
replacements.push({
|
|
5024
|
+
start: match.index,
|
|
5025
|
+
end: match.index + match[0].length,
|
|
5026
|
+
replacement: `<span class="comment">${match[0]}</span>`
|
|
5027
|
+
});
|
|
5028
|
+
}
|
|
4974
5029
|
}
|
|
4975
5030
|
|
|
4976
5031
|
// Sort replacements by start position (reverse order to not mess up indices)
|
|
@@ -388,7 +388,8 @@
|
|
|
388
388
|
<!-- Code Tab -->
|
|
389
389
|
<div class="tab-content" id="code-tab">
|
|
390
390
|
<div class="code-container">
|
|
391
|
-
<div
|
|
391
|
+
<div class="code-split-container">
|
|
392
|
+
<div id="code-tree-container" class="code-tree-container">
|
|
392
393
|
<!-- Top-left corner: Language selector -->
|
|
393
394
|
<div class="tree-corner-controls top-left">
|
|
394
395
|
<div class="control-group">
|
|
@@ -453,6 +454,13 @@
|
|
|
453
454
|
</div>
|
|
454
455
|
</div>
|
|
455
456
|
</div>
|
|
457
|
+
<!-- Code Content Area -->
|
|
458
|
+
<div id="code-module-data-content" class="code-module-data-content">
|
|
459
|
+
<div class="module-empty">
|
|
460
|
+
<p>Select a file from the tree to view its content</p>
|
|
461
|
+
</div>
|
|
462
|
+
</div>
|
|
463
|
+
</div>
|
|
456
464
|
</div>
|
|
457
465
|
</div>
|
|
458
466
|
|
|
@@ -129,13 +129,13 @@ class AgentFormatConverter:
|
|
|
129
129
|
if isinstance(tools_line, str):
|
|
130
130
|
if tools_line.startswith("[") and tools_line.endswith("]"):
|
|
131
131
|
# Already in list format
|
|
132
|
-
|
|
132
|
+
pass
|
|
133
133
|
else:
|
|
134
134
|
# Convert comma-separated to list
|
|
135
135
|
tools = [tool.strip() for tool in tools_line.split(",")]
|
|
136
|
-
|
|
136
|
+
str(tools).replace("'", '"')
|
|
137
137
|
else:
|
|
138
|
-
|
|
138
|
+
pass
|
|
139
139
|
|
|
140
140
|
# Extract additional fields
|
|
141
141
|
model = self.extract_yaml_field(yaml_content, "model") or "sonnet"
|
|
@@ -265,7 +265,7 @@ class AgentTemplateBuilder:
|
|
|
265
265
|
has_core_tools = len(agent_tools.intersection(core_tools)) >= 5
|
|
266
266
|
|
|
267
267
|
# Include tools field only if agent is clearly restricted (missing core tools or very few tools)
|
|
268
|
-
|
|
268
|
+
not has_core_tools or len(agent_tools) < 6
|
|
269
269
|
|
|
270
270
|
# Build YAML frontmatter using Claude Code's compatible format
|
|
271
271
|
# ONLY include fields that Claude Code recognizes
|
|
@@ -587,7 +587,7 @@ tools:
|
|
|
587
587
|
|
|
588
588
|
# Combine enhanced description with examples
|
|
589
589
|
if examples:
|
|
590
|
-
description_parts = [enhanced_description, ""
|
|
590
|
+
description_parts = [enhanced_description, "", *examples]
|
|
591
591
|
else:
|
|
592
592
|
description_parts = [enhanced_description]
|
|
593
593
|
|
|
@@ -611,9 +611,8 @@ tools:
|
|
|
611
611
|
|
|
612
612
|
# Remove redundant spaces around punctuation
|
|
613
613
|
single_line = re.sub(r"\s+([,.!?;:])", r"\1", single_line)
|
|
614
|
-
|
|
614
|
+
return re.sub(r"([,.!?;:])\s+", r"\1 ", single_line)
|
|
615
615
|
|
|
616
|
-
return single_line
|
|
617
616
|
|
|
618
617
|
def _create_enhanced_description(
|
|
619
618
|
self,
|