claude-mpm 5.6.17__py3-none-any.whl → 5.6.33__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/commander.py +7 -7
- claude_mpm/cli/parsers/commander_parser.py +2 -2
- claude_mpm/cli/startup.py +36 -19
- claude_mpm/commander/chat/cli.py +38 -3
- claude_mpm/commander/config.py +5 -3
- claude_mpm/commander/daemon.py +9 -0
- claude_mpm/commander/frameworks/base.py +4 -1
- claude_mpm/commander/instance_manager.py +124 -11
- claude_mpm/core/claude_runner.py +22 -13
- claude_mpm/core/config.py +3 -3
- claude_mpm/core/config_constants.py +74 -9
- claude_mpm/core/constants.py +56 -12
- claude_mpm/core/interactive_session.py +5 -4
- claude_mpm/core/logging_utils.py +4 -2
- claude_mpm/core/network_config.py +148 -0
- claude_mpm/core/oneshot_session.py +7 -6
- claude_mpm/core/output_style_manager.py +5 -2
- claude_mpm/core/socketio_pool.py +13 -5
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.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__/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/auto_pause_handler.py +1 -1
- claude_mpm/hooks/claude_hooks/event_handlers.py +262 -89
- claude_mpm/hooks/claude_hooks/hook_handler.py +81 -32
- claude_mpm/hooks/claude_hooks/installer.py +90 -28
- claude_mpm/hooks/claude_hooks/memory_integration.py +1 -1
- claude_mpm/hooks/claude_hooks/response_tracking.py +1 -1
- claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.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__/container.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.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 +2 -2
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +2 -2
- claude_mpm/hooks/claude_hooks/services/container.py +310 -0
- claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +2 -2
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +2 -2
- claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
- claude_mpm/hooks/templates/pre_tool_use_template.py +6 -6
- claude_mpm/scripts/claude-hook-handler.sh +3 -3
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/command_deployment_service.py +44 -26
- claude_mpm/services/hook_installer_service.py +77 -8
- claude_mpm/services/pm_skills_deployer.py +3 -2
- {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/METADATA +1 -1
- {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/RECORD +56 -78
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.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-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc +0 -0
- {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/WHEEL +0 -0
- {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/top_level.txt +0 -0
|
@@ -44,11 +44,14 @@ class ConfigConstants:
|
|
|
44
44
|
"startup": 60,
|
|
45
45
|
"graceful_shutdown": 30,
|
|
46
46
|
},
|
|
47
|
-
# Ports
|
|
47
|
+
# Ports (updated to use network_config.NetworkPorts defaults)
|
|
48
48
|
"ports": {
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
49
|
+
"monitor_default": 8765, # NetworkPorts.MONITOR_DEFAULT
|
|
50
|
+
"commander_default": 8766, # NetworkPorts.COMMANDER_DEFAULT
|
|
51
|
+
"dashboard_default": 8767, # NetworkPorts.DASHBOARD_DEFAULT
|
|
52
|
+
"socketio_default": 8768, # NetworkPorts.SOCKETIO_DEFAULT
|
|
53
|
+
"socketio_range_start": 8765, # NetworkPorts.PORT_RANGE_START
|
|
54
|
+
"socketio_range_end": 8785, # NetworkPorts.PORT_RANGE_END
|
|
52
55
|
},
|
|
53
56
|
# Cache settings
|
|
54
57
|
"cache": {
|
|
@@ -134,23 +137,70 @@ class ConfigConstants:
|
|
|
134
137
|
Get port value by type.
|
|
135
138
|
|
|
136
139
|
Args:
|
|
137
|
-
port_type: Type of port (e.g., 'socketio_default')
|
|
140
|
+
port_type: Type of port (e.g., 'socketio_default', 'monitor_default')
|
|
138
141
|
|
|
139
142
|
Returns:
|
|
140
143
|
Port number
|
|
141
144
|
"""
|
|
142
145
|
try:
|
|
146
|
+
# Try to get from unified config first
|
|
143
147
|
config = cls._get_config_service().config
|
|
144
148
|
|
|
149
|
+
if port_type == "monitor_default":
|
|
150
|
+
return (
|
|
151
|
+
config.network.monitor_port
|
|
152
|
+
if hasattr(config.network, "monitor_port")
|
|
153
|
+
else 8765
|
|
154
|
+
)
|
|
155
|
+
if port_type == "commander_default":
|
|
156
|
+
return (
|
|
157
|
+
config.network.commander_port
|
|
158
|
+
if hasattr(config.network, "commander_port")
|
|
159
|
+
else 8766
|
|
160
|
+
)
|
|
161
|
+
if port_type == "dashboard_default":
|
|
162
|
+
return (
|
|
163
|
+
config.network.dashboard_port
|
|
164
|
+
if hasattr(config.network, "dashboard_port")
|
|
165
|
+
else 8767
|
|
166
|
+
)
|
|
145
167
|
if port_type == "socketio_default":
|
|
146
|
-
return
|
|
168
|
+
return (
|
|
169
|
+
config.network.socketio_port
|
|
170
|
+
if hasattr(config.network, "socketio_port")
|
|
171
|
+
else 8768
|
|
172
|
+
)
|
|
147
173
|
if port_type == "socketio_range_start":
|
|
148
|
-
return
|
|
174
|
+
return (
|
|
175
|
+
config.network.socketio_port_range[0]
|
|
176
|
+
if hasattr(config.network, "socketio_port_range")
|
|
177
|
+
else 8765
|
|
178
|
+
)
|
|
149
179
|
if port_type == "socketio_range_end":
|
|
150
|
-
return
|
|
180
|
+
return (
|
|
181
|
+
config.network.socketio_port_range[1]
|
|
182
|
+
if hasattr(config.network, "socketio_port_range")
|
|
183
|
+
else 8785
|
|
184
|
+
)
|
|
151
185
|
return cls.DEFAULT_VALUES["ports"].get(port_type, 8765)
|
|
152
186
|
except Exception:
|
|
153
|
-
|
|
187
|
+
# Fallback to network_config.NetworkPorts or DEFAULT_VALUES
|
|
188
|
+
try:
|
|
189
|
+
from .network_config import NetworkPorts
|
|
190
|
+
|
|
191
|
+
port_map = {
|
|
192
|
+
"monitor_default": NetworkPorts.MONITOR_DEFAULT,
|
|
193
|
+
"commander_default": NetworkPorts.COMMANDER_DEFAULT,
|
|
194
|
+
"dashboard_default": NetworkPorts.DASHBOARD_DEFAULT,
|
|
195
|
+
"socketio_default": NetworkPorts.SOCKETIO_DEFAULT,
|
|
196
|
+
"socketio_range_start": NetworkPorts.PORT_RANGE_START,
|
|
197
|
+
"socketio_range_end": NetworkPorts.PORT_RANGE_END,
|
|
198
|
+
}
|
|
199
|
+
return port_map.get(
|
|
200
|
+
port_type, cls.DEFAULT_VALUES["ports"].get(port_type, 8765)
|
|
201
|
+
)
|
|
202
|
+
except Exception:
|
|
203
|
+
return cls.DEFAULT_VALUES["ports"].get(port_type, 8765)
|
|
154
204
|
|
|
155
205
|
@classmethod
|
|
156
206
|
def get_cache_setting(cls, setting_name: str) -> Any:
|
|
@@ -304,6 +354,21 @@ def get_socketio_port() -> int:
|
|
|
304
354
|
return ConfigConstants.get_port("socketio_default")
|
|
305
355
|
|
|
306
356
|
|
|
357
|
+
def get_monitor_port() -> int:
|
|
358
|
+
"""Get default monitor port."""
|
|
359
|
+
return ConfigConstants.get_port("monitor_default")
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def get_commander_port() -> int:
|
|
363
|
+
"""Get default commander port."""
|
|
364
|
+
return ConfigConstants.get_port("commander_default")
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def get_dashboard_port() -> int:
|
|
368
|
+
"""Get default dashboard port."""
|
|
369
|
+
return ConfigConstants.get_port("dashboard_default")
|
|
370
|
+
|
|
371
|
+
|
|
307
372
|
def get_cache_size() -> float:
|
|
308
373
|
"""Get default cache size in MB."""
|
|
309
374
|
return ConfigConstants.get_cache_setting("max_size_mb")
|
claude_mpm/core/constants.py
CHANGED
|
@@ -38,12 +38,36 @@ class SystemLimits:
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class NetworkConfig:
|
|
41
|
-
"""Network-related configuration constants.
|
|
41
|
+
"""Network-related configuration constants.
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
NOTE: Port defaults are now centralized in network_config.NetworkPorts.
|
|
44
|
+
This class maintains backward compatibility but delegates to NetworkPorts.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
# Import from network_config for single source of truth
|
|
48
|
+
# Lazy import to avoid circular dependencies
|
|
49
|
+
@property
|
|
50
|
+
def SOCKETIO_PORT_RANGE(self) -> Tuple[int, int]:
|
|
51
|
+
from .network_config import NetworkPorts
|
|
52
|
+
|
|
53
|
+
return (NetworkPorts.PORT_RANGE_START, NetworkPorts.PORT_RANGE_END)
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def DEFAULT_SOCKETIO_PORT(self) -> int:
|
|
57
|
+
from .network_config import NetworkPorts
|
|
58
|
+
|
|
59
|
+
return NetworkPorts.SOCKETIO_DEFAULT
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def DEFAULT_DASHBOARD_PORT(self) -> int:
|
|
63
|
+
from .network_config import NetworkPorts
|
|
64
|
+
|
|
65
|
+
return NetworkPorts.DASHBOARD_DEFAULT
|
|
66
|
+
|
|
67
|
+
# Port ranges (module-level for backward compatibility)
|
|
68
|
+
SOCKETIO_PORT_RANGE: Tuple[int, int] = (8765, 8785) # Will be updated at runtime
|
|
69
|
+
DEFAULT_SOCKETIO_PORT = 8768 # Updated to match new default
|
|
70
|
+
DEFAULT_DASHBOARD_PORT = 8767 # Updated to match new default
|
|
47
71
|
|
|
48
72
|
# Connection timeouts (seconds)
|
|
49
73
|
CONNECTION_TIMEOUT = 5.0
|
|
@@ -303,18 +327,38 @@ DEFAULT_TIMEOUT = TimeoutConfig.DEFAULT_TIMEOUT
|
|
|
303
327
|
|
|
304
328
|
|
|
305
329
|
class NetworkPorts:
|
|
306
|
-
"""Network port configuration.
|
|
330
|
+
"""Network port configuration.
|
|
331
|
+
|
|
332
|
+
DEPRECATED: Use claude_mpm.core.network_config.NetworkPorts instead.
|
|
333
|
+
This class is maintained for backward compatibility.
|
|
334
|
+
"""
|
|
335
|
+
|
|
336
|
+
# Import from network_config for single source of truth
|
|
337
|
+
@classmethod
|
|
338
|
+
def _get_config(cls):
|
|
339
|
+
from .network_config import NetworkPorts as NewNetworkPorts
|
|
340
|
+
|
|
341
|
+
return NewNetworkPorts
|
|
342
|
+
|
|
343
|
+
# Delegate to new NetworkPorts
|
|
344
|
+
@property
|
|
345
|
+
def DEFAULT_SOCKETIO(self) -> int:
|
|
346
|
+
return self._get_config().SOCKETIO_DEFAULT
|
|
347
|
+
|
|
348
|
+
@property
|
|
349
|
+
def DEFAULT_DASHBOARD(self) -> int:
|
|
350
|
+
return self._get_config().DASHBOARD_DEFAULT
|
|
307
351
|
|
|
308
|
-
#
|
|
309
|
-
DEFAULT_SOCKETIO =
|
|
310
|
-
DEFAULT_DASHBOARD =
|
|
311
|
-
PORT_RANGE_START =
|
|
312
|
-
PORT_RANGE_END =
|
|
352
|
+
# Keep class-level attributes for compatibility
|
|
353
|
+
DEFAULT_SOCKETIO = 8768 # Updated to match network_config
|
|
354
|
+
DEFAULT_DASHBOARD = 8767 # Updated to match network_config
|
|
355
|
+
PORT_RANGE_START = 8765
|
|
356
|
+
PORT_RANGE_END = 8785
|
|
313
357
|
|
|
314
358
|
@classmethod
|
|
315
359
|
def get_port_range(cls) -> range:
|
|
316
360
|
"""Get the valid port range."""
|
|
317
|
-
return
|
|
361
|
+
return cls._get_config().get_port_range()
|
|
318
362
|
|
|
319
363
|
|
|
320
364
|
class ProjectPaths:
|
|
@@ -143,11 +143,12 @@ class InteractiveSession:
|
|
|
143
143
|
Tuple of (success, environment_dict)
|
|
144
144
|
"""
|
|
145
145
|
try:
|
|
146
|
-
#
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
# NOTE: System agents are deployed via reconciliation during startup.
|
|
147
|
+
# The reconciliation process respects user configuration and handles
|
|
148
|
+
# both native and custom mode deployment. No need to call setup_agents() here.
|
|
149
149
|
|
|
150
|
-
# Deploy project-specific agents
|
|
150
|
+
# Deploy project-specific agents from .claude-mpm/agents/
|
|
151
|
+
# This is separate from system agents and handles user-defined agents
|
|
151
152
|
self.runner.deploy_project_agents_to_claude()
|
|
152
153
|
|
|
153
154
|
# Build command
|
claude_mpm/core/logging_utils.py
CHANGED
|
@@ -121,8 +121,10 @@ class LoggerFactory:
|
|
|
121
121
|
root_logger.setLevel(desired_level)
|
|
122
122
|
# else: root logger is suppressed (CRITICAL+1), keep it suppressed
|
|
123
123
|
|
|
124
|
-
#
|
|
125
|
-
root_logger.handlers = [
|
|
124
|
+
# Preserve FileHandlers (e.g., hooks logging), only remove StreamHandlers
|
|
125
|
+
root_logger.handlers = [
|
|
126
|
+
h for h in root_logger.handlers if isinstance(h, logging.FileHandler)
|
|
127
|
+
]
|
|
126
128
|
|
|
127
129
|
# CRITICAL FIX: Don't add handlers if logging is suppressed
|
|
128
130
|
# If root logger is at CRITICAL+1 (startup suppression), don't add any handlers
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Centralized network port configuration for Claude MPM.
|
|
2
|
+
|
|
3
|
+
This module provides the single source of truth for all network port defaults
|
|
4
|
+
and environment variable names used throughout the MPM system.
|
|
5
|
+
|
|
6
|
+
WHY: Previously, port defaults were hardcoded in multiple locations (config.py,
|
|
7
|
+
constants.py, commander/config.py, CLI parsers), leading to inconsistencies and
|
|
8
|
+
difficulty maintaining different defaults per service.
|
|
9
|
+
|
|
10
|
+
USAGE:
|
|
11
|
+
from claude_mpm.core.network_config import NetworkPorts
|
|
12
|
+
|
|
13
|
+
# Get default ports
|
|
14
|
+
monitor_port = NetworkPorts.MONITOR_DEFAULT
|
|
15
|
+
commander_port = NetworkPorts.COMMANDER_DEFAULT
|
|
16
|
+
|
|
17
|
+
# Get from environment with fallback
|
|
18
|
+
port = NetworkPorts.get_monitor_port()
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
from typing import Optional
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class NetworkPorts:
|
|
26
|
+
"""Network port configuration with different defaults for each service.
|
|
27
|
+
|
|
28
|
+
Service Default Ports:
|
|
29
|
+
- Monitor: 8765 (user's preferred default)
|
|
30
|
+
- Commander: 8766
|
|
31
|
+
- Dashboard: 8767
|
|
32
|
+
- SocketIO: 8768
|
|
33
|
+
|
|
34
|
+
Port Range: 8765-8785 (21 ports available)
|
|
35
|
+
|
|
36
|
+
Environment Variables:
|
|
37
|
+
- CLAUDE_MPM_MONITOR_PORT: Override monitor port
|
|
38
|
+
- CLAUDE_MPM_COMMANDER_PORT: Override commander port
|
|
39
|
+
- CLAUDE_MPM_DASHBOARD_PORT: Override dashboard port
|
|
40
|
+
- CLAUDE_MPM_SOCKETIO_PORT: Override socketio port
|
|
41
|
+
- CLAUDE_MPM_DEFAULT_HOST: Override default host (default: 127.0.0.1)
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
# Default ports for each service
|
|
45
|
+
MONITOR_DEFAULT = 8765
|
|
46
|
+
COMMANDER_DEFAULT = 8766
|
|
47
|
+
DASHBOARD_DEFAULT = 8767
|
|
48
|
+
SOCKETIO_DEFAULT = 8768
|
|
49
|
+
|
|
50
|
+
# Port range configuration
|
|
51
|
+
PORT_RANGE_START = 8765
|
|
52
|
+
PORT_RANGE_END = 8785
|
|
53
|
+
|
|
54
|
+
# Default host
|
|
55
|
+
DEFAULT_HOST = "127.0.0.1"
|
|
56
|
+
|
|
57
|
+
# Environment variable names
|
|
58
|
+
ENV_MONITOR_PORT = "CLAUDE_MPM_MONITOR_PORT"
|
|
59
|
+
ENV_COMMANDER_PORT = "CLAUDE_MPM_COMMANDER_PORT"
|
|
60
|
+
ENV_DASHBOARD_PORT = "CLAUDE_MPM_DASHBOARD_PORT"
|
|
61
|
+
ENV_SOCKETIO_PORT = "CLAUDE_MPM_SOCKETIO_PORT"
|
|
62
|
+
ENV_DEFAULT_HOST = "CLAUDE_MPM_DEFAULT_HOST"
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def get_monitor_port(cls, default: Optional[int] = None) -> int:
|
|
66
|
+
"""Get monitor port from environment or default.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
default: Optional override default (if not provided, uses MONITOR_DEFAULT)
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Port number from environment or default
|
|
73
|
+
"""
|
|
74
|
+
if default is None:
|
|
75
|
+
default = cls.MONITOR_DEFAULT
|
|
76
|
+
return int(os.getenv(cls.ENV_MONITOR_PORT, default))
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def get_commander_port(cls, default: Optional[int] = None) -> int:
|
|
80
|
+
"""Get commander port from environment or default.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
default: Optional override default (if not provided, uses COMMANDER_DEFAULT)
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Port number from environment or default
|
|
87
|
+
"""
|
|
88
|
+
if default is None:
|
|
89
|
+
default = cls.COMMANDER_DEFAULT
|
|
90
|
+
return int(os.getenv(cls.ENV_COMMANDER_PORT, default))
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def get_dashboard_port(cls, default: Optional[int] = None) -> int:
|
|
94
|
+
"""Get dashboard port from environment or default.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
default: Optional override default (if not provided, uses DASHBOARD_DEFAULT)
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Port number from environment or default
|
|
101
|
+
"""
|
|
102
|
+
if default is None:
|
|
103
|
+
default = cls.DASHBOARD_DEFAULT
|
|
104
|
+
return int(os.getenv(cls.ENV_DASHBOARD_PORT, default))
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def get_socketio_port(cls, default: Optional[int] = None) -> int:
|
|
108
|
+
"""Get socketio port from environment or default.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
default: Optional override default (if not provided, uses SOCKETIO_DEFAULT)
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Port number from environment or default
|
|
115
|
+
"""
|
|
116
|
+
if default is None:
|
|
117
|
+
default = cls.SOCKETIO_DEFAULT
|
|
118
|
+
return int(os.getenv(cls.ENV_SOCKETIO_PORT, default))
|
|
119
|
+
|
|
120
|
+
@classmethod
|
|
121
|
+
def get_default_host(cls) -> str:
|
|
122
|
+
"""Get default host from environment or default.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
Host address from environment or DEFAULT_HOST
|
|
126
|
+
"""
|
|
127
|
+
return os.getenv(cls.ENV_DEFAULT_HOST, cls.DEFAULT_HOST)
|
|
128
|
+
|
|
129
|
+
@classmethod
|
|
130
|
+
def get_port_range(cls) -> range:
|
|
131
|
+
"""Get the valid port range.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Range object from PORT_RANGE_START to PORT_RANGE_END (inclusive)
|
|
135
|
+
"""
|
|
136
|
+
return range(cls.PORT_RANGE_START, cls.PORT_RANGE_END + 1)
|
|
137
|
+
|
|
138
|
+
@classmethod
|
|
139
|
+
def is_port_in_range(cls, port: int) -> bool:
|
|
140
|
+
"""Check if port is within valid range.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
port: Port number to check
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
True if port is in valid range, False otherwise
|
|
147
|
+
"""
|
|
148
|
+
return cls.PORT_RANGE_START <= port <= cls.PORT_RANGE_END
|
|
@@ -11,7 +11,7 @@ defines the interface it needs.
|
|
|
11
11
|
|
|
12
12
|
import contextlib
|
|
13
13
|
import os
|
|
14
|
-
import subprocess
|
|
14
|
+
import subprocess # nosec B404
|
|
15
15
|
import tempfile
|
|
16
16
|
import time
|
|
17
17
|
import uuid
|
|
@@ -86,11 +86,12 @@ class OneshotSession:
|
|
|
86
86
|
Returns:
|
|
87
87
|
True if successful, False otherwise
|
|
88
88
|
"""
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
# NOTE: System agents are deployed via reconciliation during startup.
|
|
90
|
+
# The reconciliation process respects user configuration and handles
|
|
91
|
+
# both native and custom mode deployment. No need to call setup_agents() here.
|
|
92
92
|
|
|
93
|
-
# Deploy project-specific agents
|
|
93
|
+
# Deploy project-specific agents from .claude-mpm/agents/
|
|
94
|
+
# This is separate from system agents and handles user-defined agents
|
|
94
95
|
self.runner.deploy_project_agents_to_claude()
|
|
95
96
|
|
|
96
97
|
return True
|
|
@@ -225,7 +226,7 @@ class OneshotSession:
|
|
|
225
226
|
if len(cmd) > 5:
|
|
226
227
|
self.logger.debug(f"Command has {len(cmd)} arguments total")
|
|
227
228
|
|
|
228
|
-
result = subprocess.run(
|
|
229
|
+
result = subprocess.run( # nosec B603
|
|
229
230
|
cmd, capture_output=True, text=True, env=env, check=False
|
|
230
231
|
)
|
|
231
232
|
|
|
@@ -358,8 +358,11 @@ class OutputStyleManager:
|
|
|
358
358
|
|
|
359
359
|
# Only set activeOutputStyle if:
|
|
360
360
|
# 1. No active style is set (first deployment), OR
|
|
361
|
-
# 2.
|
|
362
|
-
|
|
361
|
+
# 2. Current style is "default" (not a real user preference), OR
|
|
362
|
+
# 3. This is a fresh install (file didn't exist before deployment)
|
|
363
|
+
should_activate = (
|
|
364
|
+
current_style is None or current_style == "default" or is_fresh_install
|
|
365
|
+
)
|
|
363
366
|
|
|
364
367
|
if should_activate and current_style != style_name:
|
|
365
368
|
settings["activeOutputStyle"] = style_name
|
claude_mpm/core/socketio_pool.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
1
|
"""Socket.IO connection pool for efficient client connection management.
|
|
3
2
|
|
|
4
3
|
This module provides a connection pool to reuse Socket.IO client connections,
|
|
@@ -31,12 +30,21 @@ except ImportError:
|
|
|
31
30
|
# Import constants for configuration
|
|
32
31
|
try:
|
|
33
32
|
from claude_mpm.core.constants import NetworkConfig
|
|
33
|
+
from claude_mpm.core.network_config import NetworkPorts
|
|
34
34
|
except ImportError:
|
|
35
35
|
# Fallback if constants module not available
|
|
36
|
+
class NetworkPorts:
|
|
37
|
+
MONITOR_DEFAULT = 8765
|
|
38
|
+
COMMANDER_DEFAULT = 8766
|
|
39
|
+
DASHBOARD_DEFAULT = 8767
|
|
40
|
+
SOCKETIO_DEFAULT = 8768
|
|
41
|
+
PORT_RANGE_START = 8765
|
|
42
|
+
PORT_RANGE_END = 8785
|
|
43
|
+
|
|
36
44
|
class NetworkConfig:
|
|
37
|
-
DEFAULT_DASHBOARD_PORT =
|
|
45
|
+
DEFAULT_DASHBOARD_PORT = 8767
|
|
38
46
|
SOCKETIO_PORT_RANGE = (8765, 8785)
|
|
39
|
-
DEFAULT_SOCKETIO_PORT =
|
|
47
|
+
DEFAULT_SOCKETIO_PORT = 8768
|
|
40
48
|
|
|
41
49
|
socketio = None
|
|
42
50
|
|
|
@@ -309,7 +317,7 @@ class SocketIOConnectionPool:
|
|
|
309
317
|
self.server_url = f"http://localhost:{port}"
|
|
310
318
|
self.logger.debug(f"Detected Socket.IO server on port {port}")
|
|
311
319
|
return
|
|
312
|
-
except Exception:
|
|
320
|
+
except Exception: # nosec B112 - intentional: skip ports that fail
|
|
313
321
|
continue
|
|
314
322
|
|
|
315
323
|
# Fall back to default
|
|
@@ -579,7 +587,7 @@ class SocketIOConnectionPool:
|
|
|
579
587
|
loop.stop()
|
|
580
588
|
loop.run_until_complete(loop.shutdown_asyncgens())
|
|
581
589
|
loop.close()
|
|
582
|
-
except Exception:
|
|
590
|
+
except Exception: # nosec B110 - intentional: cleanup best-effort
|
|
583
591
|
pass
|
|
584
592
|
|
|
585
593
|
async def _connect_client(self, client: socketio.AsyncClient):
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -56,7 +56,7 @@ except ImportError:
|
|
|
56
56
|
logger = get_logger(__name__)
|
|
57
57
|
|
|
58
58
|
# Debug mode
|
|
59
|
-
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "
|
|
59
|
+
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "false").lower() == "true"
|
|
60
60
|
|
|
61
61
|
# Warning messages for threshold crossings
|
|
62
62
|
THRESHOLD_WARNINGS = {
|